<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Hi Douglas,</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Thanks for letting me know. Do you know what compiler is that /usr/local/bin/c++? I think adding an std::move should fix the issue but I'd like to beable to reproduce the issue to make sure it will fix the issue.</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Best regards,</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Thomas<br>
</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> douglas.yung@sony.com <douglas.yung@sony.com><br>
<b>Sent:</b> 24 July 2019 08:23<br>
<b>To:</b> Thomas Preud'homme <thomasp@graphcore.ai><br>
<b>Cc:</b> llvm-commits@lists.llvm.org <llvm-commits@lists.llvm.org><br>
<b>Subject:</b> RE: [llvm] r366860 - FileCheck [8/12]: Define numeric var from expr</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">Hi Thomas,<br>
<br>
Your commit is causing build failures on quite a few of the build bots:<br>
<br>
<a href="http://lab.llvm.org:8011/builders/clang-cmake-aarch64-quick/builds/19358">http://lab.llvm.org:8011/builders/clang-cmake-aarch64-quick/builds/19358</a><br>
<br>
[4/2175] Building CXX object lib/Support/CMakeFiles/LLVMSupport.dir/FileCheck.cpp.o<br>
FAILED: lib/Support/CMakeFiles/LLVMSupport.dir/FileCheck.cpp.o <br>
/usr/local/bin/c++   -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Ilib/Support -I/home/buildslave/buildslave/clang-cmake-aarch64-quick/llvm/lib/Support -I/usr/include/libxml2 -Iinclude -I/home/buildslave/buildslave/clang-cmake-aarch64-quick/llvm/include
 -fPIC -fvisibility-inlines-hidden -Werror=date-time -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wno-maybe-uninitialized -Wno-noexcept-type -Wdelete-non-virtual-dtor
 -Wno-comment -fdiagnostics-color -ffunction-sections -fdata-sections -O3    -UNDEBUG  -fno-exceptions -fno-rtti -MMD -MT lib/Support/CMakeFiles/LLVMSupport.dir/FileCheck.cpp.o -MF lib/Support/CMakeFiles/LLVMSupport.dir/FileCheck.cpp.o.d -o lib/Support/CMakeFiles/LLVMSupport.dir/FileCheck.cpp.o
 -c /home/buildslave/buildslave/clang-cmake-aarch64-quick/llvm/lib/Support/FileCheck.cpp<br>
/home/buildslave/buildslave/clang-cmake-aarch64-quick/llvm/lib/Support/FileCheck.cpp: In static member function ‘static llvm::Expected<std::unique_ptr<llvm::FileCheckExpressionAST> > llvm::FileCheckPattern::parseNumericSubstitutionBlock(llvm::StringRef, llvm::Optional<llvm::FileCheckNumericVariable*>&,
 bool, llvm::Optional<long unsigned int>, llvm::FileCheckPatternContext*, const llvm::SourceMgr&)’:<br>
/home/buildslave/buildslave/clang-cmake-aarch64-quick/llvm/lib/Support/FileCheck.cpp:345:10: error: could not convert ‘ExpressionAST’ from ‘std::unique_ptr<llvm::FileCheckExpressionAST>’ to ‘llvm::Expected<std::unique_ptr<llvm::FileCheckExpressionAST> >’<br>
   return ExpressionAST;<br>
          ^~~~~~~~~~~~~<br>
<br>
Can you take a look?<br>
<br>
Douglas Yung<br>
<br>
-----Original Message-----<br>
From: llvm-commits <llvm-commits-bounces@lists.llvm.org> On Behalf Of Thomas Preud'homme via llvm-commits<br>
Sent: Tuesday, July 23, 2019 15:42<br>
To: llvm-commits@lists.llvm.org<br>
Subject: [llvm] r366860 - FileCheck [8/12]: Define numeric var from expr<br>
<br>
Author: thopre<br>
Date: Tue Jul 23 15:41:38 2019<br>
New Revision: 366860<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=366860&view=rev">http://llvm.org/viewvc/llvm-project?rev=366860&view=rev</a><br>
Log:<br>
FileCheck [8/12]: Define numeric var from expr<br>
<br>
Summary:<br>
This patch is part of a patch series to add support for FileCheck<br>
numeric expressions. This specific patch lift the restriction for a<br>
numeric expression to either be a variable definition or a numeric<br>
expression to try to match.<br>
<br>
This commit allows a numeric variable to be set to the result of the<br>
evaluation of a numeric expression after it has been matched<br>
successfully. When it happens, the variable is allowed to be used on<br>
the same line since its value is known at match time.<br>
<br>
It also makes use of this possibility to reuse the parsing code to<br>
parse a command-line definition by crafting a mirror string of the<br>
-D option with the equal sign replaced by a colon sign, e.g. for option<br>
'-D#NUMVAL=10' it creates the string<br>
'-D#NUMVAL=10 (parsed as [[#NUMVAL:10]])' where the numeric expression<br>
is parsed to define NUMVAL. This result in a few tests needing updating<br>
for the location diagnostics on top of the tests for the new feature.<br>
<br>
It also enables empty numeric expression which match any number without<br>
defining a variable. This is done here rather than in commit #5 of the<br>
patch series because it requires to dissociate automatic regex insertion<br>
in RegExStr from variable definition which would make commit #5 even<br>
bigger than it already is.<br>
<br>
Copyright:<br>
    - Linaro (changes up to diff 183612 of revision D55940)<br>
    - GraphCore (changes in later versions of revision D55940 and<br>
                 in new revision created off D55940)<br>
<br>
Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk<br>
<br>
Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield<br>
<br>
Tags: #llvm<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D60388">https://reviews.llvm.org/D60388</a><br>
<br>
Modified:<br>
    llvm/trunk/docs/CommandGuide/FileCheck.rst<br>
    llvm/trunk/include/llvm/Support/FileCheck.h<br>
    llvm/trunk/lib/Support/FileCheck.cpp<br>
    llvm/trunk/test/FileCheck/numeric-defines-diagnostics.txt<br>
    llvm/trunk/test/FileCheck/numeric-defines.txt<br>
    llvm/trunk/test/FileCheck/numeric-expression.txt<br>
    llvm/trunk/unittests/Support/FileCheckTest.cpp<br>
<br>
Modified: llvm/trunk/docs/CommandGuide/FileCheck.rst<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=366860&r1=366859&r2=366860&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=366860&r1=366859&r2=366860&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/docs/CommandGuide/FileCheck.rst (original)<br>
+++ llvm/trunk/docs/CommandGuide/FileCheck.rst Tue Jul 23 15:41:38 2019<br>
@@ -107,12 +107,12 @@ and from the command line.<br>
   Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be<br>
   used in ``CHECK:`` lines.<br>
 <br>
-.. option:: -D#<NUMVAR>=<VALUE EXPRESSION><br>
+.. option:: -D#<NUMVAR>=<NUMERIC EXPRESSION><br>
 <br>
   Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating<br>
-  ``<VALUE EXPRESSION>`` that can be used in ``CHECK:`` lines. See section<br>
-  ``FileCheck Numeric Variables and Expressions`` for details on the format<br>
-  and meaning of ``<VALUE EXPRESSION>``.<br>
+  ``<NUMERIC EXPRESSION>`` that can be used in ``CHECK:`` lines. See section<br>
+  ``FileCheck Numeric Variables and Expressions`` for details on supported<br>
+  numeric expressions.<br>
 <br>
 .. option:: -version<br>
 <br>
@@ -625,11 +625,27 @@ but would not match the text:<br>
 <br>
 due to ``7`` being unequal to ``5 + 1``.<br>
 <br>
+The syntax also supports an empty expression, equivalent to writing {{[0-9]+}},<br>
+for cases where the input must contain a numeric value but the value itself<br>
+does not matter:<br>
+<br>
+.. code-block:: gas<br>
+<br>
+    ; CHECK-NOT: mov r0, r[[#]]<br>
+<br>
+to check that a value is synthesized rather than moved around.<br>
+<br>
+A numeric variable can also be defined to the result of a numeric expression,<br>
+in which case the numeric expression is checked and if verified the variable is<br>
+assigned to the value. The unified syntax for both defining numeric variables<br>
+and checking a numeric expression is thus ``[[#<NUMVAR>: <expr>]]`` with each<br>
+element as described previously.<br>
+<br>
 The ``--enable-var-scope`` option has the same effect on numeric variables as<br>
 on string variables.<br>
 <br>
 Important note: In its current implementation, an expression cannot use a<br>
-numeric variable defined on the same line.<br>
+numeric variable with a non-empty expression defined on the same line.<br>
 <br>
 FileCheck Pseudo Numeric Variables<br>
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>
<br>
Modified: llvm/trunk/include/llvm/Support/FileCheck.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileCheck.h?rev=366860&r1=366859&r2=366860&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileCheck.h?rev=366860&r1=366859&r2=366860&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/FileCheck.h (original)<br>
+++ llvm/trunk/include/llvm/Support/FileCheck.h Tue Jul 23 15:41:38 2019<br>
@@ -94,6 +94,11 @@ private:<br>
   /// Name of the numeric variable.<br>
   StringRef Name;<br>
 <br>
+  /// Pointer to expression defining this numeric variable. Null for pseudo<br>
+  /// variable whose value is known at parse time (e.g. @LINE pseudo variable)<br>
+  /// or cleared local variable.<br>
+  FileCheckExpressionAST *ExpressionAST;<br>
+<br>
   /// Value of numeric variable, if defined, or None otherwise.<br>
   Optional<uint64_t> Value;<br>
 <br>
@@ -104,10 +109,14 @@ private:<br>
 <br>
 public:<br>
   /// Constructor for a variable \p Name defined at line \p DefLineNumber or<br>
-  /// defined before input is parsed if DefLineNumber is None.<br>
+  /// defined before input is parsed if \p DefLineNumber is None. If not null,<br>
+  /// the value set with setValue must match the result of evaluating<br>
+  /// \p ExpressionAST.<br>
   FileCheckNumericVariable(StringRef Name,<br>
-                           Optional<size_t> DefLineNumber = None)<br>
-      : Name(Name), DefLineNumber(DefLineNumber) {}<br>
+                           Optional<size_t> DefLineNumber = None,<br>
+                           FileCheckExpressionAST *ExpressionAST = nullptr)<br>
+      : Name(Name), ExpressionAST(ExpressionAST), DefLineNumber(DefLineNumber) {<br>
+  }<br>
 <br>
   /// \returns name of this numeric variable.<br>
   StringRef getName() const { return Name; }<br>
@@ -115,12 +124,25 @@ public:<br>
   /// \returns this variable's value.<br>
   Optional<uint64_t> getValue() const { return Value; }<br>
 <br>
-  /// Sets value of this numeric variable to \p NewValue.<br>
-  void setValue(uint64_t NewValue) { Value = NewValue; }<br>
+  /// \returns the pointer to the expression defining this numeric variable, if<br>
+  /// any, or null otherwise.<br>
+  FileCheckExpressionAST *getExpressionAST() const { return ExpressionAST; }<br>
+<br>
+  /// \returns whether this variable's value is known when performing the<br>
+  /// substitutions of the line where it is defined.<br>
+  bool isValueKnownAtMatchTime() const;<br>
+<br>
+  /// Sets value of this numeric variable to \p NewValue. Triggers an assertion<br>
+  /// failure if the variable is defined by an expression and the expression<br>
+  /// cannot be evaluated to be equal to \p NewValue.<br>
+  void setValue(uint64_t NewValue);<br>
 <br>
   /// Clears value of this numeric variable, regardless of whether it is<br>
   /// currently defined or not.<br>
-  void clearValue() { Value = None; }<br>
+  void clearValue() {<br>
+    Value = None;<br>
+    ExpressionAST = nullptr;<br>
+  }<br>
 <br>
   /// \returns the line number where this variable is defined, if any, or None<br>
   /// if defined before input is parsed.<br>
@@ -507,27 +529,22 @@ public:<br>
   /// \p Str from the variable name.<br>
   static Expected<VariableProperties> parseVariable(StringRef &Str,<br>
                                                     const SourceMgr &SM);<br>
-  /// Parses \p Expr for the name of a numeric variable to be defined at line<br>
-  /// \p LineNumber or before input is parsed if \p LineNumber is None.<br>
-  /// \returns a pointer to the class instance representing that variable,<br>
-  /// creating it if needed, or an error holding a diagnostic against \p SM<br>
-  /// should defining such a variable be invalid.<br>
-  static Expected<FileCheckNumericVariable *> parseNumericVariableDefinition(<br>
-      StringRef &Expr, FileCheckPatternContext *Context,<br>
-      Optional<size_t> LineNumber, const SourceMgr &SM);<br>
-  /// Parses \p Expr for a numeric substitution block. Parameter<br>
+  /// Parses \p Expr for a numeric substitution block at line \p LineNumber,<br>
+  /// or before input is parsed if \p LineNumber is None. Parameter<br>
   /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE<br>
-  /// expression. \returns a pointer to the class instance representing the AST<br>
-  /// of the expression whose value must be substituted, or an error holding a<br>
-  /// diagnostic against \p SM if parsing fails. If substitution was<br>
-  /// successful, sets \p DefinedNumericVariable to point to the class<br>
-  /// representing the numeric variable being defined in this numeric<br>
+  /// expression and \p Context points to the class instance holding the live<br>
+  /// string and numeric variables. \returns a pointer to the class instance<br>
+  /// representing the AST of the expression whose value must be substitued, or<br>
+  /// an error holding a diagnostic against \p SM if parsing fails. If<br>
+  /// substitution was successful, sets \p DefinedNumericVariable to point to<br>
+  /// the class representing the numeric variable defined in this numeric<br>
   /// substitution block, or None if this block does not define any variable.<br>
-  Expected<std::unique_ptr<FileCheckExpressionAST>><br>
+  static Expected<std::unique_ptr<FileCheckExpressionAST>><br>
   parseNumericSubstitutionBlock(<br>
       StringRef Expr,<br>
       Optional<FileCheckNumericVariable *> &DefinedNumericVariable,<br>
-      bool IsLegacyLineExpr, const SourceMgr &SM) const;<br>
+      bool IsLegacyLineExpr, Optional<size_t> LineNumber,<br>
+      FileCheckPatternContext *Context, const SourceMgr &SM);<br>
   /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern<br>
   /// instance accordingly.<br>
   ///<br>
@@ -581,28 +598,49 @@ private:<br>
   /// was not found.<br>
   size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);<br>
 <br>
-  /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use.<br>
-  /// \returns the pointer to the class instance representing that variable if<br>
-  /// successful, or an error holding a diagnostic against \p SM otherwise.<br>
-  Expected<std::unique_ptr<FileCheckNumericVariableUse>><br>
+  /// Parses \p Expr for the name of a numeric variable to be defined at line<br>
+  /// \p LineNumber, or before input is parsed if \p LineNumber is None.<br>
+  /// \returns a pointer to the class instance representing that variable,<br>
+  /// creating it if needed, or an error holding a diagnostic against \p SM<br>
+  /// should defining such a variable be invalid.<br>
+  static Expected<FileCheckNumericVariable *> parseNumericVariableDefinition(<br>
+      StringRef &Expr, FileCheckPatternContext *Context,<br>
+      Optional<size_t> LineNumber, FileCheckExpressionAST *ExpressionAST,<br>
+      const SourceMgr &SM);<br>
+  /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use<br>
+  /// at line \p LineNumber, or before input is parsed if \p LineNumber is<br>
+  /// None. Parameter \p Context points to the class instance holding the live<br>
+  /// string and numeric variables. \returns the pointer to the class instance<br>
+  /// representing that variable if successful, or an error holding a<br>
+  /// diagnostic against \p SM otherwise.<br>
+  static Expected<std::unique_ptr<FileCheckNumericVariableUse>><br>
   parseNumericVariableUse(StringRef Name, bool IsPseudo,<br>
-                          const SourceMgr &SM) const;<br>
+                          Optional<size_t> LineNumber,<br>
+                          FileCheckPatternContext *Context,<br>
+                          const SourceMgr &SM);<br>
   enum class AllowedOperand { LineVar, Literal, Any };<br>
-  /// Parses \p Expr for use of a numeric operand. Accepts both literal values<br>
-  /// and numeric variables, depending on the value of \p AO. \returns the<br>
-  /// class representing that operand in the AST of the expression or an error<br>
-  /// holding a diagnostic against \p SM otherwise.<br>
-  Expected<std::unique_ptr<FileCheckExpressionAST>><br>
+  /// Parses \p Expr for use of a numeric operand at line \p LineNumber, or<br>
+  /// before input is parsed if \p LineNumber is None. Accepts both literal<br>
+  /// values and numeric variables, depending on the value of \p AO. Parameter<br>
+  /// \p Context points to the class instance holding the live string and<br>
+  /// numeric variables. \returns the class representing that operand in the<br>
+  /// AST of the expression or an error holding a diagnostic against \p SM<br>
+  /// otherwise.<br>
+  static Expected<std::unique_ptr<FileCheckExpressionAST>><br>
   parseNumericOperand(StringRef &Expr, AllowedOperand AO,<br>
-                      const SourceMgr &SM) const;<br>
-  /// Parses \p Expr for a binary operation. The left operand of this binary<br>
+                      Optional<size_t> LineNumber,<br>
+                      FileCheckPatternContext *Context, const SourceMgr &SM);<br>
+  /// Parses \p Expr for a binary operation at line \p LineNumber, or before<br>
+  /// input is parsed if \p LineNumber is None. The left operand of this binary<br>
   /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether<br>
-  /// we are parsing a legacy @LINE expression. \returns the class representing<br>
-  /// the binary operation in the AST of the expression, or an error holding a<br>
-  /// diagnostic against \p SM otherwise.<br>
-  Expected<std::unique_ptr<FileCheckExpressionAST>><br>
+  /// we are parsing a legacy @LINE expression. Parameter \p Context points to<br>
+  /// the class instance holding the live string and numeric variables.<br>
+  /// \returns the class representing the binary operation in the AST of the<br>
+  /// expression, or an error holding a diagnostic against \p SM otherwise.<br>
+  static Expected<std::unique_ptr<FileCheckExpressionAST>><br>
   parseBinop(StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,<br>
-             bool IsLegacyLineExpr, const SourceMgr &SM) const;<br>
+             bool IsLegacyLineExpr, Optional<size_t> LineNumber,<br>
+             FileCheckPatternContext *Context, const SourceMgr &SM);<br>
 };<br>
 <br>
 //===----------------------------------------------------------------------===//<br>
<br>
Modified: llvm/trunk/lib/Support/FileCheck.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FileCheck.cpp?rev=366860&r1=366859&r2=366860&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FileCheck.cpp?rev=366860&r1=366859&r2=366860&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Support/FileCheck.cpp (original)<br>
+++ llvm/trunk/lib/Support/FileCheck.cpp Tue Jul 23 15:41:38 2019<br>
@@ -24,11 +24,38 @@<br>
 <br>
 using namespace llvm;<br>
 <br>
+bool FileCheckNumericVariable::isValueKnownAtMatchTime() const {<br>
+  if (Value)<br>
+    return true;<br>
+<br>
+  return ExpressionAST != nullptr;<br>
+}<br>
+<br>
+void FileCheckNumericVariable::setValue(uint64_t NewValue) {<br>
+  if (ExpressionAST != nullptr) {<br>
+    // Caller is expected to call setValue only if substitution was successful.<br>
+    assert(NewValue == cantFail(ExpressionAST->eval(),<br>
+                                "Failed to evaluate associated expression when "<br>
+                                "sanity checking value") &&<br>
+           "Value being set to different from variable evaluation");<br>
+  }<br>
+  Value = NewValue;<br>
+  // Clear pointer to AST to ensure it is not used after the numeric<br>
+  // substitution defining this variable is processed since it's the<br>
+  // substitution that owns the pointer.<br>
+  ExpressionAST = nullptr;<br>
+}<br>
+<br>
 Expected<uint64_t> FileCheckNumericVariableUse::eval() const {<br>
   Optional<uint64_t> Value = NumericVariable->getValue();<br>
   if (Value)<br>
     return *Value;<br>
-  return make_error<FileCheckUndefVarError>(Name);<br>
+<br>
+  FileCheckExpressionAST *ExpressionAST = NumericVariable->getExpressionAST();<br>
+  if (!ExpressionAST)<br>
+    return make_error<FileCheckUndefVarError>(Name);<br>
+<br>
+  return ExpressionAST->eval();<br>
 }<br>
 <br>
 Expected<uint64_t> FileCheckASTBinop::eval() const {<br>
@@ -114,7 +141,8 @@ char FileCheckNotFoundError::ID = 0;<br>
 Expected<FileCheckNumericVariable *><br>
 FileCheckPattern::parseNumericVariableDefinition(<br>
     StringRef &Expr, FileCheckPatternContext *Context,<br>
-    Optional<size_t> LineNumber, const SourceMgr &SM) {<br>
+    Optional<size_t> LineNumber, FileCheckExpressionAST *ExpressionAST,<br>
+    const SourceMgr &SM) {<br>
   Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);<br>
   if (!ParseVarResult)<br>
     return ParseVarResult.takeError();<br>
@@ -141,14 +169,17 @@ FileCheckPattern::parseNumericVariableDe<br>
   if (VarTableIter != Context->GlobalNumericVariableTable.end())<br>
     DefinedNumericVariable = VarTableIter->second;<br>
   else<br>
-    DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber);<br>
+    DefinedNumericVariable =<br>
+        Context->makeNumericVariable(Name, LineNumber, ExpressionAST);<br>
 <br>
   return DefinedNumericVariable;<br>
 }<br>
 <br>
 Expected<std::unique_ptr<FileCheckNumericVariableUse>><br>
 FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,<br>
-                                          const SourceMgr &SM) const {<br>
+                                          Optional<size_t> LineNumber,<br>
+                                          FileCheckPatternContext *Context,<br>
+                                          const SourceMgr &SM) {<br>
   if (IsPseudo && !Name.equals("@LINE"))<br>
     return FileCheckErrorDiagnostic::get(<br>
         SM, Name, "invalid pseudo numeric variable '" + Name + "'");<br>
@@ -171,24 +202,29 @@ FileCheckPattern::parseNumericVariableUs<br>
   }<br>
 <br>
   Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber();<br>
-  if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)<br>
+  if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber &&<br>
+      !NumericVariable->isValueKnownAtMatchTime())<br>
     return FileCheckErrorDiagnostic::get(<br>
         SM, Name,<br>
-        "numeric variable '" + Name + "' defined on the same line as used");<br>
+        "numeric variable '" + Name +<br>
+            "' defined from input on the same line as used");<br>
 <br>
   return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);<br>
 }<br>
 <br>
 Expected<std::unique_ptr<FileCheckExpressionAST>><br>
 FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,<br>
-                                      const SourceMgr &SM) const {<br>
+                                      Optional<size_t> LineNumber,<br>
+                                      FileCheckPatternContext *Context,<br>
+                                      const SourceMgr &SM) {<br>
   if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {<br>
     // Try to parse as a numeric variable use.<br>
     Expected<FileCheckPattern::VariableProperties> ParseVarResult =<br>
         parseVariable(Expr, SM);<br>
     if (ParseVarResult)<br>
       return parseNumericVariableUse(ParseVarResult->Name,<br>
-                                     ParseVarResult->IsPseudo, SM);<br>
+                                     ParseVarResult->IsPseudo, LineNumber,<br>
+                                     Context, SM);<br>
     if (AO == AllowedOperand::LineVar)<br>
       return ParseVarResult.takeError();<br>
     // Ignore the error and retry parsing as a literal.<br>
@@ -212,10 +248,10 @@ static uint64_t sub(uint64_t LeftOp, uin<br>
   return LeftOp - RightOp;<br>
 }<br>
 <br>
-Expected<std::unique_ptr<FileCheckExpressionAST>><br>
-FileCheckPattern::parseBinop(StringRef &Expr,<br>
-                             std::unique_ptr<FileCheckExpressionAST> LeftOp,<br>
-                             bool IsLegacyLineExpr, const SourceMgr &SM) const {<br>
+Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop(<br>
+    StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,<br>
+    bool IsLegacyLineExpr, Optional<size_t> LineNumber,<br>
+    FileCheckPatternContext *Context, const SourceMgr &SM) {<br>
   Expr = Expr.ltrim(SpaceChars);<br>
   if (Expr.empty())<br>
     return std::move(LeftOp);<br>
@@ -246,7 +282,7 @@ FileCheckPattern::parseBinop(StringRef &<br>
   AllowedOperand AO =<br>
       IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;<br>
   Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =<br>
-      parseNumericOperand(Expr, AO, SM);<br>
+      parseNumericOperand(Expr, AO, LineNumber, Context, SM);<br>
   if (!RightOpResult)<br>
     return RightOpResult;<br>
 <br>
@@ -259,50 +295,54 @@ Expected<std::unique_ptr<FileCheckExpres<br>
 FileCheckPattern::parseNumericSubstitutionBlock(<br>
     StringRef Expr,<br>
     Optional<FileCheckNumericVariable *> &DefinedNumericVariable,<br>
-    bool IsLegacyLineExpr, const SourceMgr &SM) const {<br>
-  // Parse the numeric variable definition.<br>
+    bool IsLegacyLineExpr, Optional<size_t> LineNumber,<br>
+    FileCheckPatternContext *Context, const SourceMgr &SM) {<br>
+  std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr;<br>
+  StringRef DefExpr = StringRef();<br>
   DefinedNumericVariable = None;<br>
+  // Save variable definition expression if any.<br>
   size_t DefEnd = Expr.find(':');<br>
   if (DefEnd != StringRef::npos) {<br>
-    StringRef DefExpr = Expr.substr(0, DefEnd);<br>
-    StringRef UseExpr = Expr.substr(DefEnd + 1);<br>
+    DefExpr = Expr.substr(0, DefEnd);<br>
+    Expr = Expr.substr(DefEnd + 1);<br>
+  }<br>
 <br>
-    UseExpr = UseExpr.ltrim(SpaceChars);<br>
-    if (!UseExpr.empty())<br>
-      return FileCheckErrorDiagnostic::get(<br>
-          SM, UseExpr,<br>
-          "unexpected string after variable definition: '" + UseExpr + "'");<br>
+  // Parse the expression itself.<br>
+  Expr = Expr.ltrim(SpaceChars);<br>
+  if (!Expr.empty()) {<br>
+    // The first operand in a legacy @LINE expression is always the @LINE<br>
+    // pseudo variable.<br>
+    AllowedOperand AO =<br>
+        IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;<br>
+    Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =<br>
+        parseNumericOperand(Expr, AO, LineNumber, Context, SM);<br>
+    while (ParseResult && !Expr.empty()) {<br>
+      ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr,<br>
+                               LineNumber, Context, SM);<br>
+      // Legacy @LINE expressions only allow 2 operands.<br>
+      if (ParseResult && IsLegacyLineExpr && !Expr.empty())<br>
+        return FileCheckErrorDiagnostic::get(<br>
+            SM, Expr,<br>
+            "unexpected characters at end of expression '" + Expr + "'");<br>
+    }<br>
+    if (!ParseResult)<br>
+      return ParseResult;<br>
+    ExpressionAST = std::move(*ParseResult);<br>
+  }<br>
 <br>
+  // Parse the numeric variable definition.<br>
+  if (DefEnd != StringRef::npos) {<br>
     DefExpr = DefExpr.ltrim(SpaceChars);<br>
     Expected<FileCheckNumericVariable *> ParseResult =<br>
-        parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);<br>
+        parseNumericVariableDefinition(DefExpr, Context, LineNumber,<br>
+                                       ExpressionAST.get(), SM);<br>
+<br>
     if (!ParseResult)<br>
       return ParseResult.takeError();<br>
     DefinedNumericVariable = *ParseResult;<br>
-<br>
-    return nullptr;<br>
   }<br>
 <br>
-  // Parse the expression itself.<br>
-  Expr = Expr.ltrim(SpaceChars);<br>
-  // The first operand in a legacy @LINE expression is always the @LINE pseudo<br>
-  // variable.<br>
-  AllowedOperand AO =<br>
-      IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;<br>
-  Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =<br>
-      parseNumericOperand(Expr, AO, SM);<br>
-  while (ParseResult && !Expr.empty()) {<br>
-    ParseResult =<br>
-        parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, SM);<br>
-    // Legacy @LINE expressions only allow 2 operands.<br>
-    if (ParseResult && IsLegacyLineExpr && !Expr.empty())<br>
-      return FileCheckErrorDiagnostic::get(<br>
-          SM, Expr,<br>
-          "unexpected characters at end of expression '" + Expr + "'");<br>
-  }<br>
-  if (!ParseResult)<br>
-    return ParseResult;<br>
-  return std::move(*ParseResult);<br>
+  return ExpressionAST;<br>
 }<br>
 <br>
 bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,<br>
@@ -385,14 +425,15 @@ bool FileCheckPattern::parsePattern(Stri<br>
       continue;<br>
     }<br>
 <br>
-    // String and numeric substitution blocks. String substitution blocks come<br>
+    // String and numeric substitution blocks. Pattern substitution blocks come<br>
     // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some<br>
     // other regex) and assigns it to the string variable 'foo'. The latter<br>
-    // substitutes foo's value. Numeric substitution blocks work the same way<br>
-    // as string ones, but start with a '#' sign after the double brackets.<br>
-    // Both string and numeric variable names must satisfy the regular<br>
-    // expression "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch<br>
-    // some common errors.<br>
+    // substitutes foo's value. Numeric substitution blocks recognize the same<br>
+    // form as string ones, but start with a '#' sign after the double<br>
+    // brackets. They also accept a combined form which sets a numeric variable<br>
+    // to the evaluation of an expression. Both string and numeric variable<br>
+    // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be<br>
+    // valid, as this helps catch some common errors.<br>
     if (PatternStr.startswith("[[")) {<br>
       StringRef UnparsedPatternStr = PatternStr.substr(2);<br>
       // Find the closing bracket pair ending the match.  End is going to be an<br>
@@ -413,6 +454,7 @@ bool FileCheckPattern::parsePattern(Stri<br>
       PatternStr = UnparsedPatternStr.substr(End + 2);<br>
 <br>
       bool IsDefinition = false;<br>
+      bool SubstNeeded = false;<br>
       // Whether the substitution block is a legacy use of @LINE with string<br>
       // substitution block syntax.<br>
       bool IsLegacyLineExpr = false;<br>
@@ -443,6 +485,7 @@ bool FileCheckPattern::parsePattern(Stri<br>
         bool IsPseudo = ParseVarResult->IsPseudo;<br>
 <br>
         IsDefinition = (VarEndIdx != StringRef::npos);<br>
+        SubstNeeded = !IsDefinition;<br>
         if (IsDefinition) {<br>
           if ((IsPseudo || !MatchStr.consume_front(":"))) {<br>
             SM.PrintMessage(SMLoc::getFromPointer(Name.data()),<br>
@@ -477,22 +520,61 @@ bool FileCheckPattern::parsePattern(Stri<br>
       if (IsNumBlock) {<br>
         Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =<br>
             parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,<br>
-                                          IsLegacyLineExpr, SM);<br>
+                                          IsLegacyLineExpr, LineNumber, Context,<br>
+                                          SM);<br>
         if (!ParseResult) {<br>
           logAllUnhandledErrors(ParseResult.takeError(), errs());<br>
           return true;<br>
         }<br>
         ExpressionAST = std::move(*ParseResult);<br>
+        SubstNeeded = ExpressionAST != nullptr;<br>
         if (DefinedNumericVariable) {<br>
           IsDefinition = true;<br>
           DefName = (*DefinedNumericVariable)->getName();<br>
-          MatchRegexp = StringRef("[0-9]+");<br>
-        } else<br>
+        }<br>
+        if (SubstNeeded)<br>
           SubstStr = MatchStr;<br>
+        else<br>
+          MatchRegexp = "[0-9]+";<br>
+      }<br>
+<br>
+      // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].<br>
+      if (IsDefinition) {<br>
+        RegExStr += '(';<br>
+        ++SubstInsertIdx;<br>
+<br>
+        if (IsNumBlock) {<br>
+          FileCheckNumericVariableMatch NumericVariableDefinition = {<br>
+              *DefinedNumericVariable, CurParen};<br>
+          NumericVariableDefs[DefName] = NumericVariableDefinition;<br>
+          // This store is done here rather than in match() to allow<br>
+          // parseNumericVariableUse() to get the pointer to the class instance<br>
+          // of the right variable definition corresponding to a given numeric<br>
+          // variable use.<br>
+          Context->GlobalNumericVariableTable[DefName] =<br>
+              *DefinedNumericVariable;<br>
+        } else {<br>
+          VariableDefs[DefName] = CurParen;<br>
+          // Mark string variable as defined to detect collisions between<br>
+          // string and numeric variables in parseNumericVariableUse() and<br>
+          // defineCmdlineVariables() when the latter is created later than the<br>
+          // former. We cannot reuse GlobalVariableTable for this by populating<br>
+          // it with an empty string since we would then lose the ability to<br>
+          // detect the use of an undefined variable in match().<br>
+          Context->DefinedVariableTable[DefName] = true;<br>
+        }<br>
+<br>
+        ++CurParen;<br>
       }<br>
 <br>
+      if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))<br>
+        return true;<br>
+<br>
+      if (IsDefinition)<br>
+        RegExStr += ')';<br>
+<br>
       // Handle substitutions: [[foo]] and [[#<foo expr>]].<br>
-      if (!IsDefinition) {<br>
+      if (SubstNeeded) {<br>
         // Handle substitution of string variables that were defined earlier on<br>
         // the same line by emitting a backreference. Expressions do not<br>
         // support substituting a numeric variable defined on the same line.<br>
@@ -515,37 +597,7 @@ bool FileCheckPattern::parsePattern(Stri<br>
                   : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);<br>
           Substitutions.push_back(Substitution);<br>
         }<br>
-        continue;<br>
-      }<br>
-<br>
-      // Handle variable definitions: [[<def>:(...)]] and<br>
-      // [[#(...)<def>:(...)]].<br>
-      if (IsNumBlock) {<br>
-        FileCheckNumericVariableMatch NumericVariableDefinition = {<br>
-            *DefinedNumericVariable, CurParen};<br>
-        NumericVariableDefs[DefName] = NumericVariableDefinition;<br>
-        // This store is done here rather than in match() to allow<br>
-        // parseNumericVariableUse() to get the pointer to the class instance<br>
-        // of the right variable definition corresponding to a given numeric<br>
-        // variable use.<br>
-        Context->GlobalNumericVariableTable[DefName] = *DefinedNumericVariable;<br>
-      } else {<br>
-        VariableDefs[DefName] = CurParen;<br>
-        // Mark the string variable as defined to detect collisions between<br>
-        // string and numeric variables in parseNumericVariableUse() and<br>
-        // DefineCmdlineVariables() when the latter is created later than the<br>
-        // former. We cannot reuse GlobalVariableTable for this by populating<br>
-        // it with an empty string since we would then lose the ability to<br>
-        // detect the use of an undefined variable in match().<br>
-        Context->DefinedVariableTable[DefName] = true;<br>
       }<br>
-      RegExStr += '(';<br>
-      ++CurParen;<br>
-<br>
-      if (AddRegExToRegEx(MatchRegexp, CurParen, SM))<br>
-        return true;<br>
-<br>
-      RegExStr += ')';<br>
     }<br>
 <br>
     // Handle fixed string matches.<br>
@@ -1745,11 +1797,32 @@ Error FileCheckPatternContext::defineCmd<br>
   unsigned I = 0;<br>
   Error Errs = Error::success();<br>
   std::string CmdlineDefsDiag;<br>
-  StringRef Prefix1 = "Global define #";<br>
-  StringRef Prefix2 = ": ";<br>
-  for (StringRef CmdlineDef : CmdlineDefines)<br>
-    CmdlineDefsDiag +=<br>
-        (Prefix1 + Twine(++I) + Prefix2 + CmdlineDef + "\n").str();<br>
+  SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;<br>
+  for (StringRef CmdlineDef : CmdlineDefines) {<br>
+    std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();<br>
+    size_t EqIdx = CmdlineDef.find('=');<br>
+    if (EqIdx == StringRef::npos) {<br>
+      CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));<br>
+      continue;<br>
+    }<br>
+    // Numeric variable definition.<br>
+    if (CmdlineDef[0] == '#') {<br>
+      // Append a copy of the command-line definition adapted to use the same<br>
+      // format as in the input file to be able to reuse<br>
+      // parseNumericSubstitutionBlock.<br>
+      CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();<br>
+      std::string SubstitutionStr = CmdlineDef;<br>
+      SubstitutionStr[EqIdx] = ':';<br>
+      CmdlineDefsIndices.push_back(<br>
+          std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));<br>
+      CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();<br>
+    } else {<br>
+      CmdlineDefsDiag += DefPrefix;<br>
+      CmdlineDefsIndices.push_back(<br>
+          std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));<br>
+      CmdlineDefsDiag += (CmdlineDef + "\n").str();<br>
+    }<br>
+  }<br>
 <br>
   // Create a buffer with fake command line content in order to display<br>
   // parsing diagnostic with location information and point to the<br>
@@ -1759,14 +1832,10 @@ Error FileCheckPatternContext::defineCmd<br>
   StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();<br>
   SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());<br>
 <br>
-  SmallVector<StringRef, 4> CmdlineDefsDiagVec;<br>
-  CmdlineDefsDiagRef.split(CmdlineDefsDiagVec, '\n', -1 /*MaxSplit*/,<br>
-                           false /*KeepEmpty*/);<br>
-  for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) {<br>
-    unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size();<br>
-    StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart);<br>
-    size_t EqIdx = CmdlineDef.find('=');<br>
-    if (EqIdx == StringRef::npos) {<br>
+  for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {<br>
+    StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,<br>
+                                                     CmdlineDefIndices.second);<br>
+    if (CmdlineDef.empty()) {<br>
       Errs = joinErrors(<br>
           std::move(Errs),<br>
           FileCheckErrorDiagnostic::get(<br>
@@ -1776,31 +1845,35 @@ Error FileCheckPatternContext::defineCmd<br>
 <br>
     // Numeric variable definition.<br>
     if (CmdlineDef[0] == '#') {<br>
-      StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);<br>
-      Expected<FileCheckNumericVariable *> ParseResult =<br>
-          FileCheckPattern::parseNumericVariableDefinition(CmdlineName, this,<br>
-                                                           None, SM);<br>
-      if (!ParseResult) {<br>
-        Errs = joinErrors(std::move(Errs), ParseResult.takeError());<br>
+      // Now parse the definition both to check that the syntax is correct and<br>
+      // to create the necessary class instance.<br>
+      StringRef CmdlineDefExpr = CmdlineDef.substr(1);<br>
+      Optional<FileCheckNumericVariable *> DefinedNumericVariable;<br>
+      Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionASTResult =<br>
+          FileCheckPattern::parseNumericSubstitutionBlock(<br>
+              CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);<br>
+      if (!ExpressionASTResult) {<br>
+        Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError());<br>
         continue;<br>
       }<br>
-<br>
-      StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1);<br>
-      uint64_t Val;<br>
-      if (CmdlineVal.getAsInteger(10, Val)) {<br>
-        Errs = joinErrors(std::move(Errs),<br>
-                          FileCheckErrorDiagnostic::get(<br>
-                              SM, CmdlineVal,<br>
-                              "invalid value in numeric variable definition '" +<br>
-                                  CmdlineVal + "'"));<br>
+      std::unique_ptr<FileCheckExpressionAST> ExpressionAST =<br>
+          std::move(*ExpressionASTResult);<br>
+      // Now evaluate the expression whose value this variable should be set<br>
+      // to, since the expression of a command-line variable definition should<br>
+      // only use variables defined earlier on the command-line. If not, this<br>
+      // is an error and we report it.<br>
+      Expected<uint64_t> Value = ExpressionAST->eval();<br>
+      if (!Value) {<br>
+        Errs = joinErrors(std::move(Errs), Value.takeError());<br>
         continue;<br>
       }<br>
-      FileCheckNumericVariable *DefinedNumericVariable = *ParseResult;<br>
-      DefinedNumericVariable->setValue(Val);<br>
+<br>
+      assert(DefinedNumericVariable && "No variable defined");<br>
+      (*DefinedNumericVariable)->setValue(*Value);<br>
 <br>
       // Record this variable definition.<br>
-      GlobalNumericVariableTable[DefinedNumericVariable->getName()] =<br>
-          DefinedNumericVariable;<br>
+      GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =<br>
+          *DefinedNumericVariable;<br>
     } else {<br>
       // String variable definition.<br>
       std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');<br>
@@ -1837,7 +1910,7 @@ Error FileCheckPatternContext::defineCmd<br>
       }<br>
       GlobalVariableTable.insert(CmdlineNameVal);<br>
       // Mark the string variable as defined to detect collisions between<br>
-      // string and numeric variables in DefineCmdlineVariables when the latter<br>
+      // string and numeric variables in defineCmdlineVariables when the latter<br>
       // is created later than the former. We cannot reuse GlobalVariableTable<br>
       // for this by populating it with an empty string since we would then<br>
       // lose the ability to detect the use of an undefined variable in<br>
<br>
Modified: llvm/trunk/test/FileCheck/numeric-defines-diagnostics.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/numeric-defines-diagnostics.txt?rev=366860&r1=366859&r2=366860&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/numeric-defines-diagnostics.txt?rev=366860&r1=366859&r2=366860&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/FileCheck/numeric-defines-diagnostics.txt (original)<br>
+++ llvm/trunk/test/FileCheck/numeric-defines-diagnostics.txt Tue Jul 23 15:41:38 2019<br>
@@ -4,30 +4,22 @@<br>
 RUN: not FileCheck -D#10VALUE=10 --input-file %s %s 2>&1 \<br>
 RUN:   | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIFMT<br>
 <br>
-NUMERRCLIFMT: Global defines:1:20: error: invalid variable name<br>
-NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10<br>
-NUMERRCLIFMT-NEXT: {{^                   \^$}}<br>
+NUMERRCLIFMT: Global defines:1:46: error: invalid variable name<br>
+NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10 (parsed as: {{\[\[#10VALUE:10\]\]}})<br>
+NUMERRCLIFMT-NEXT: {{^                                             \^$}}<br>
 <br>
 ; Invalid definition of pseudo variable.<br>
 RUN: not FileCheck -D#@VALUE=10 --input-file %s %s 2>&1 \<br>
 RUN:   | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIPSEUDO<br>
 <br>
-NUMERRCLIPSEUDO: Global defines:1:20: error: definition of pseudo numeric variable unsupported<br>
-NUMERRCLIPSEUDO-NEXT: Global define #1: #@VALUE=10<br>
-NUMERRCLIPSEUDO-NEXT: {{^                   \^$}}<br>
+NUMERRCLIPSEUDO: Global defines:1:45: error: definition of pseudo numeric variable unsupported<br>
+NUMERRCLIPSEUDO-NEXT: Global define #1: #@VALUE=10 (parsed as: {{\[\[#@VALUE:10\]\]}})<br>
+NUMERRCLIPSEUDO-NEXT: {{^                                            \^$}}<br>
 <br>
 ; Invalid definition of an expression.<br>
 RUN: not FileCheck -D#VALUE+2=10 --input-file %s %s 2>&1 \<br>
 RUN:   | FileCheck %s --strict-whitespace --check-prefix NUMERRCLITRAIL<br>
 <br>
-NUMERRCLITRAIL: Global defines:1:25: error: unexpected characters after numeric variable name<br>
-NUMERRCLITRAIL-NEXT: Global define #1: #VALUE+2=10<br>
-NUMERRCLITRAIL-NEXT: {{^                        \^$}}<br>
-<br>
-; Invalid value: numeric expression instead of literal.<br>
-RUN: not FileCheck -D#VALUE1=3 -D#VALUE2='VALUE1 + 2' --input-file %s %s 2>&1 \<br>
-RUN:   | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIEXPR<br>
-<br>
-NUMERRCLIEXPR: Global defines:2:27: error: invalid value in numeric variable definition 'VALUE1 + 2'<br>
-NUMERRCLIEXPR-NEXT: Global define #2: #VALUE2=VALUE1 + 2<br>
-NUMERRCLIEXPR-NEXT: {{^                          \^$}}<br>
+NUMERRCLITRAIL: Global defines:1:51: error: unexpected characters after numeric variable name<br>
+NUMERRCLITRAIL-NEXT: Global define #1: #VALUE+2=10 (parsed as: {{\[\[#VALUE\+2:10\]\]}})<br>
+NUMERRCLITRAIL-NEXT: {{^                                                  \^$}}<br>
<br>
Modified: llvm/trunk/test/FileCheck/numeric-defines.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/numeric-defines.txt?rev=366860&r1=366859&r2=366860&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/numeric-defines.txt?rev=366860&r1=366859&r2=366860&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/FileCheck/numeric-defines.txt (original)<br>
+++ llvm/trunk/test/FileCheck/numeric-defines.txt Tue Jul 23 15:41:38 2019<br>
@@ -1,22 +1,38 @@<br>
 ; Test functionality of -D# option: numeric variables are defined to the right<br>
 ; value and CHECK directives using them match as expected given the value set.<br>
 <br>
-RUN: FileCheck -D#NUMVAL=12 --check-prefix CHECKNUM --input-file %s %s<br>
-RUN: not FileCheck -D#NUMVAL=8 --check-prefix CHECKNUM --input-file %s %s 2>&1 \<br>
-RUN:   | FileCheck %s --strict-whitespace --check-prefix NUMERRMSG<br>
-RUN: not FileCheck -D#NUMVAL=12 --check-prefix NUMNOT --input-file %s %s 2>&1 \<br>
-RUN:   | FileCheck %s --strict-whitespace --check-prefix NOT-NUMERRMSG<br>
-RUN: FileCheck -D#NUMVAL=8 --check-prefixes NUMNOT --input-file %s %s<br>
-<br>
-Numeric value = 12<br>
-CHECKNUM: Numeric value = [[#NUMVAL]]<br>
-NUMNOT-NOT: Numeric value = [[#NUMVAL]]<br>
-<br>
-NUMERRMSG: defines.txt:[[#@LINE-3]]:11: error: CHECKNUM: expected string not found in input<br>
-NUMERRMSG: defines.txt:1:1: note: scanning from here<br>
-NUMERRMSG: defines.txt:1:1: note: with "NUMVAL" equal to "8"<br>
-NUMERRMSG: defines.txt:[[#@LINE-7]]:1: note: possible intended match here<br>
-<br>
-NOT-NUMERRMSG: defines.txt:[[#@LINE-7]]:13: error: {{NUMNOT}}-NOT: excluded string found in input<br>
-NOT-NUMERRMSG: defines.txt:[[#@LINE-10]]:1: note: found here<br>
-NOT-NUMERRMSG: defines.txt:[[#@LINE-11]]:1: note: with "NUMVAL" equal to "12"<br>
+RUN: FileCheck -D#NUMVAL1=8 -D#NUMVAL2='NUMVAL1 + 4' -check-prefixes CHECKNUM1,CHECKNUM2 -input-file %s %s<br>
+RUN: not FileCheck -D#NUMVAL1=7 -D#NUMVAL2=12 -check-prefix CHECKNUM1 -input-file %s %s 2>&1 \<br>
+RUN:   | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG1<br>
+RUN: not FileCheck -D#NUMVAL1=8 -D#NUMVAL2=8 -check-prefix CHECKNUM2 -input-file %s %s 2>&1 \<br>
+RUN:   | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG2<br>
+RUN: not FileCheck -D#NUMVAL1=8 -D#NUMVAL2=8 -check-prefix NUMNOT -input-file %s %s 2>&1 \<br>
+RUN:   | FileCheck %s --strict-whitespace -check-prefixes NOT-NUMERRMSG1<br>
+RUN: not FileCheck -D#NUMVAL1=7 -D#NUMVAL2=12 -check-prefix NUMNOT -input-file %s %s 2>&1 \<br>
+RUN:   | FileCheck %s --strict-whitespace -check-prefixes NOT-NUMERRMSG2<br>
+RUN: FileCheck -D#NUMVAL1=7 -D#NUMVAL2=8 -check-prefixes NUMNOT -input-file %s %s<br>
+<br>
+Numeric value #1 = 8<br>
+Numeric value #2 = 12<br>
+CHECKNUM1: Numeric value #1 = [[#NUMVAL1]]<br>
+CHECKNUM2: Numeric value #2 = [[#NUMVAL2]]<br>
+NUMNOT-NOT: Numeric value #1 = [[#NUMVAL1]]<br>
+NUMNOT-NOT: Numeric value #2 = [[#NUMVAL2]]<br>
+<br>
+NUMERRMSG1: defines.txt:[[#@LINE-5]]:12: error: CHECKNUM1: expected string not found in input<br>
+NUMERRMSG1: defines.txt:1:1: note: scanning from here<br>
+NUMERRMSG1: defines.txt:1:1: note: with "NUMVAL1" equal to "7"<br>
+NUMERRMSG1: defines.txt:[[#@LINE-10]]:1: note: possible intended match here<br>
+<br>
+NUMERRMSG2: defines.txt:[[#@LINE-9]]:12: error: CHECKNUM2: expected string not found in input<br>
+NUMERRMSG2: defines.txt:1:1: note: scanning from here<br>
+NUMERRMSG2: defines.txt:1:1: note: with "NUMVAL2" equal to "8"<br>
+NUMERRMSG2: defines.txt:[[#@LINE-14]]:1: note: possible intended match here<br>
+<br>
+NOT-NUMERRMSG1: defines.txt:[[#@LINE-13]]:13: error: {{NUMNOT}}-NOT: excluded string found in input<br>
+NOT-NUMERRMSG1: defines.txt:[[#@LINE-18]]:1: note: found here<br>
+NOT-NUMERRMSG1: defines.txt:[[#@LINE-19]]:1: note: with "NUMVAL1" equal to "8"<br>
+<br>
+NOT-NUMERRMSG2: defines.txt:[[#@LINE-16]]:13: error: {{NUMNOT}}-NOT: excluded string found in input<br>
+NOT-NUMERRMSG2: defines.txt:[[#@LINE-21]]:1: note: found here<br>
+NOT-NUMERRMSG2: defines.txt:[[#@LINE-22]]:1: note: with "NUMVAL2" equal to "12"<br>
<br>
Modified: llvm/trunk/test/FileCheck/numeric-expression.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/numeric-expression.txt?rev=366860&r1=366859&r2=366860&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/numeric-expression.txt?rev=366860&r1=366859&r2=366860&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/FileCheck/numeric-expression.txt (original)<br>
+++ llvm/trunk/test/FileCheck/numeric-expression.txt Tue Jul 23 15:41:38 2019<br>
@@ -82,6 +82,20 @@ CHECK-LABEL: USE MULTI VAR<br>
 CHECK-NEXT: [[#VAR2:]]<br>
 CHECK-NEXT: [[#VAR1+VAR2]]<br>
 <br>
+; Numeric expression using a variable defined from a numeric expression.<br>
+DEF EXPR GOOD MATCH<br>
+42<br>
+41 43<br>
+; CHECK-LABEL: DEF EXPR GOOD MATCH<br>
+; CHECK-NEXT: [[# VAR42:VAR1+31]]<br>
+; CHECK-NEXT: [[# VAR41: VAR42-1]] [[# VAR41 + 2]]<br>
+<br>
+; Empty numeric expression.<br>
+EMPTY NUM EXPR<br>
+foo 104 bar<br>
+; CHECK-LABEL: EMPTY NUM EXPR<br>
+; CHECK-NEXT: foo [[#]] bar<br>
+<br>
 ; Numeric expression using undefined variables.<br>
 RUN: not FileCheck --check-prefix UNDEF-USE --input-file %s %s 2>&1 \<br>
 RUN:   | FileCheck --strict-whitespace --check-prefix UNDEF-USE-MSG %s<br>
@@ -145,9 +159,9 @@ CLI-STR-CONFLICT-NEXT: {{^<br>
 INPUT-NUM-CONFLICT: numeric-expression.txt:[[#@LINE-7]]:22: error: string variable with name 'STRVAR' already exists<br>
 INPUT-NUM-CONFLICT-NEXT: CONFLICT4: redef2 {{\[\[#STRVAR:\]\]}}<br>
 INPUT-NUM-CONFLICT-NEXT: {{^                     \^$}}<br>
-CLI-NUM-CONFLICT: Global defines:2:20: error: string variable with name 'STRVAR' already exists<br>
-CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42<br>
-CLI-NUM-CONFLICT-NEXT: {{^                   \^$}}<br>
+CLI-NUM-CONFLICT: Global defines:2:45: error: string variable with name 'STRVAR' already exists<br>
+CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42 (parsed as: {{\[\[#STRVAR:42\]\]}})<br>
+CLI-NUM-CONFLICT-NEXT: {{^                                            \^$}}<br>
 <br>
 ; Numeric variable definition with too big value.<br>
 RUN: not FileCheck --check-prefix BIGVAL --input-file %s %s 2>&1 \<br>
@@ -160,3 +174,18 @@ BIGVAL-NEXT: NUMVAR: [[#NUMVAR:]]<br>
 BIGVAL-MSG: numeric-expression.txt:[[#@LINE-3]]:9: error: Unable to represent numeric value<br>
 BIGVAL-MSG-NEXT: {{N}}UMVAR: 10000000000000000000000<br>
 BIGVAL-MSG-NEXT: {{^        \^$}}<br>
+<br>
+; Verify that when a variable is set to an expression the expression is still<br>
+; checked.<br>
+RUN: not FileCheck --check-prefix DEF-EXPR-FAIL --input-file %s %s 2>&1 \<br>
+RUN:   | FileCheck --strict-whitespace --check-prefix DEF-EXPR-FAIL-MSG %s<br>
+<br>
+DEF EXPR WRONG MATCH<br>
+20<br>
+43<br>
+DEF-EXPR-FAIL-LABEL: DEF EXPR WRONG MATCH<br>
+DEF-EXPR-FAIL-NEXT: [[# VAR20:]]<br>
+DEF-EXPR-FAIL-NEXT: [[# VAR42: VAR20+22]]<br>
+DEF-EXPR-FAIL-MSG: numeric-expression.txt:[[#@LINE-1]]:21: error: {{D}}EF-EXPR-FAIL-NEXT: is not on the line after the previous match<br>
+DEF-EXPR-FAIL-MSG-NEXT: {{D}}EF-EXPR-FAIL-NEXT: {{\[\[# VAR42: VAR20\+22\]\]}}<br>
+DEF-EXPR-FAIL-MSG-NEXT: {{^                    \^$}}<br>
<br>
Modified: llvm/trunk/unittests/Support/FileCheckTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/FileCheckTest.cpp?rev=366860&r1=366859&r2=366860&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/FileCheckTest.cpp?rev=366860&r1=366859&r2=366860&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/Support/FileCheckTest.cpp (original)<br>
+++ llvm/trunk/unittests/Support/FileCheckTest.cpp Tue Jul 23 15:41:38 2019<br>
@@ -49,15 +49,21 @@ expectUndefErrors(std::unordered_set<std<br>
   EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames);<br>
 }<br>
 <br>
+// Return whether Err contains any FileCheckUndefVarError whose associated name<br>
+// is not ExpectedUndefVarName.<br>
 static void expectUndefError(const Twine &ExpectedUndefVarName, Error Err) {<br>
   expectUndefErrors({ExpectedUndefVarName.str()}, std::move(Err));<br>
 }<br>
 <br>
+uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }<br>
+<br>
 TEST_F(FileCheckTest, NumericVariable) {<br>
-  // Undefined variable: getValue and eval fail, error returned by eval holds<br>
-  // the name of the undefined variable.<br>
+  // Undefined variable: isValueKnownAtMatchTime returns false, getValue and<br>
+  // eval fail, error returned by eval holds the name of the undefined<br>
+  // variable.<br>
   FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1);<br>
   EXPECT_EQ("FOO", FooVar.getName());<br>
+  EXPECT_FALSE(FooVar.isValueKnownAtMatchTime());<br>
   FileCheckNumericVariableUse FooVarUse =<br>
       FileCheckNumericVariableUse("FOO", &FooVar);<br>
   EXPECT_FALSE(FooVar.getValue());<br>
@@ -67,7 +73,9 @@ TEST_F(FileCheckTest, NumericVariable) {<br>
 <br>
   FooVar.setValue(42);<br>
 <br>
-  // Defined variable: getValue and eval return value set.<br>
+  // Defined variable: isValueKnownAtMatchTime returns true, getValue and eval<br>
+  // return value set.<br>
+  EXPECT_TRUE(FooVar.isValueKnownAtMatchTime());<br>
   Optional<uint64_t> Value = FooVar.getValue();<br>
   EXPECT_TRUE(bool(Value));<br>
   EXPECT_EQ(42U, *Value);<br>
@@ -75,24 +83,51 @@ TEST_F(FileCheckTest, NumericVariable) {<br>
   EXPECT_TRUE(bool(EvalResult));<br>
   EXPECT_EQ(42U, *EvalResult);<br>
 <br>
+  // Variable defined by numeric expression: isValueKnownAtMatchTime<br>
+  // returns true, getValue and eval return value of expression, setValue<br>
+  // clears expression.<br>
+  std::unique_ptr<FileCheckNumericVariableUse> FooVarUsePtr =<br>
+      llvm::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);<br>
+  std::unique_ptr<FileCheckExpressionLiteral> One =<br>
+      llvm::make_unique<FileCheckExpressionLiteral>(1);<br>
+  FileCheckASTBinop Binop =<br>
+      FileCheckASTBinop(doAdd, std::move(FooVarUsePtr), std::move(One));<br>
+  FileCheckNumericVariable FoobarExprVar =<br>
+      FileCheckNumericVariable("FOOBAR", 2, &Binop);<br>
+  EXPECT_TRUE(FoobarExprVar.isValueKnownAtMatchTime());<br>
+  EXPECT_FALSE(FoobarExprVar.getValue());<br>
+  FileCheckNumericVariableUse FoobarExprVarUse =<br>
+      FileCheckNumericVariableUse("FOOBAR", &FoobarExprVar);<br>
+  EvalResult = FoobarExprVarUse.eval();<br>
+  EXPECT_TRUE(bool(EvalResult));<br>
+  EXPECT_EQ(43U, *EvalResult);<br>
+  EXPECT_TRUE(FoobarExprVar.getExpressionAST());<br>
+  FoobarExprVar.setValue(43);<br>
+  EXPECT_FALSE(FoobarExprVar.getExpressionAST());<br>
+  FoobarExprVar = FileCheckNumericVariable("FOOBAR", 2, &Binop);<br>
+  EXPECT_TRUE(FoobarExprVar.getExpressionAST());<br>
+<br>
   // Clearing variable: getValue and eval fail. Error returned by eval holds<br>
   // the name of the cleared variable.<br>
   FooVar.clearValue();<br>
-  Value = FooVar.getValue();<br>
-  EXPECT_FALSE(Value);<br>
+  FoobarExprVar.clearValue();<br>
+  EXPECT_FALSE(FoobarExprVar.getExpressionAST());<br>
+  EXPECT_FALSE(FooVar.getValue());<br>
+  EXPECT_FALSE(FoobarExprVar.getValue());<br>
   EvalResult = FooVarUse.eval();<br>
   EXPECT_FALSE(EvalResult);<br>
   expectUndefError("FOO", EvalResult.takeError());<br>
+  EvalResult = FoobarExprVarUse.eval();<br>
+  EXPECT_FALSE(EvalResult);<br>
+  expectUndefError("FOOBAR", EvalResult.takeError());<br>
 }<br>
 <br>
-uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }<br>
-<br>
 TEST_F(FileCheckTest, Binop) {<br>
-  FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO");<br>
+  FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1);<br>
   FooVar.setValue(42);<br>
   std::unique_ptr<FileCheckNumericVariableUse> FooVarUse =<br>
       llvm::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);<br>
-  FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR");<br>
+  FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR", 2);<br>
   BarVar.setValue(18);<br>
   std::unique_ptr<FileCheckNumericVariableUse> BarVarUse =<br>
       llvm::make_unique<FileCheckNumericVariableUse>("BAR", &BarVar);<br>
@@ -237,19 +272,13 @@ public:<br>
     P = FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);<br>
   }<br>
 <br>
-  bool parseNumVarDefExpect(StringRef Expr) {<br>
-    StringRef ExprBufferRef = bufferize(SM, Expr);<br>
-    return errorToBool(FileCheckPattern::parseNumericVariableDefinition(<br>
-                           ExprBufferRef, &Context, LineNumber, SM)<br>
-                           .takeError());<br>
-  }<br>
-<br>
   bool parseSubstExpect(StringRef Expr) {<br>
     StringRef ExprBufferRef = bufferize(SM, Expr);<br>
     Optional<FileCheckNumericVariable *> DefinedNumericVariable;<br>
-    return errorToBool(P.parseNumericSubstitutionBlock(<br>
-                            ExprBufferRef, DefinedNumericVariable, false, SM)<br>
-                           .takeError());<br>
+    return errorToBool(<br>
+        P.parseNumericSubstitutionBlock(ExprBufferRef, DefinedNumericVariable,<br>
+                                        false, LineNumber - 1, &Context, SM)<br>
+            .takeError());<br>
   }<br>
 <br>
   bool parsePatternExpect(StringRef Pattern) {<br>
@@ -264,19 +293,6 @@ public:<br>
   }<br>
 };<br>
 <br>
-TEST_F(FileCheckTest, ParseNumericVariableDefinition) {<br>
-  PatternTester Tester;<br>
-<br>
-  // Invalid definition of pseudo.<br>
-  EXPECT_TRUE(Tester.parseNumVarDefExpect("@LINE"));<br>
-<br>
-  // Conflict with pattern variable.<br>
-  EXPECT_TRUE(Tester.parseNumVarDefExpect("BAR"));<br>
-<br>
-  // Defined variable.<br>
-  EXPECT_FALSE(Tester.parseNumVarDefExpect("FOO"));<br>
-}<br>
-<br>
 TEST_F(FileCheckTest, ParseExpr) {<br>
   PatternTester Tester;<br>
 <br>
@@ -287,17 +303,18 @@ TEST_F(FileCheckTest, ParseExpr) {<br>
   EXPECT_TRUE(Tester.parseSubstExpect("@FOO:"));<br>
   EXPECT_TRUE(Tester.parseSubstExpect("@LINE:"));<br>
 <br>
+  // Conflict with pattern variable.<br>
+  EXPECT_TRUE(Tester.parseSubstExpect("BAR:"));<br>
+<br>
   // Garbage after name of variable being defined.<br>
   EXPECT_TRUE(Tester.parseSubstExpect("VAR GARBAGE:"));<br>
 <br>
-  // Variable defined to numeric expression.<br>
-  EXPECT_TRUE(Tester.parseSubstExpect("VAR1: FOO"));<br>
-<br>
   // Acceptable variable definition.<br>
   EXPECT_FALSE(Tester.parseSubstExpect("VAR1:"));<br>
   EXPECT_FALSE(Tester.parseSubstExpect("  VAR2:"));<br>
   EXPECT_FALSE(Tester.parseSubstExpect("VAR3  :"));<br>
   EXPECT_FALSE(Tester.parseSubstExpect("VAR3:  "));<br>
+  EXPECT_FALSE(Tester.parsePatternExpect("[[#FOOBAR: FOO+1]]"));<br>
 <br>
   // Numeric expression.<br>
 <br>
@@ -310,9 +327,21 @@ TEST_F(FileCheckTest, ParseExpr) {<br>
   EXPECT_FALSE(Tester.parseSubstExpect("FOO"));<br>
   EXPECT_FALSE(Tester.parseSubstExpect("UNDEF"));<br>
 <br>
-  // Use variable defined on same line.<br>
-  EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:]]"));<br>
-  EXPECT_TRUE(Tester.parseSubstExpect("LINE1VAR"));<br>
+  // Valid empty expression.<br>
+  EXPECT_FALSE(Tester.parseSubstExpect(""));<br>
+<br>
+  // Valid use of variable defined on the same line from expression. Note that<br>
+  // the same pattern object is used for the parsePatternExpect and<br>
+  // parseSubstExpect since no initNextPattern is called, thus appearing as<br>
+  // being on the same line from the pattern's point of view.<br>
+  EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:FOO+1]]"));<br>
+  EXPECT_FALSE(Tester.parseSubstExpect("LINE1VAR"));<br>
+<br>
+  // Invalid use of variable defined on same line from input. As above, the<br>
+  // absence of a call to initNextPattern makes it appear to be on the same<br>
+  // line from the pattern's point of view.<br>
+  EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE2VAR:]]"));<br>
+  EXPECT_TRUE(Tester.parseSubstExpect("LINE2VAR"));<br>
 <br>
   // Unsupported operator.<br>
   EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2"));<br>
@@ -323,6 +352,7 @@ TEST_F(FileCheckTest, ParseExpr) {<br>
   // Valid expression.<br>
   EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5"));<br>
   EXPECT_FALSE(Tester.parseSubstExpect("FOO+4"));<br>
+  EXPECT_FALSE(Tester.parseSubstExpect("FOOBAR"));<br>
   Tester.initNextPattern();<br>
   EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+FOO]]"));<br>
   EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+3-FOO]]"));<br>
@@ -354,7 +384,6 @@ TEST_F(FileCheckTest, ParsePattern) {<br>
   EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));<br>
   EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));<br>
   EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));<br>
-  EXPECT_TRUE(Tester.parsePatternExpect("[[#YUP:@LINE]]"));<br>
 <br>
   // Valid numeric expressions and numeric variable definition.<br>
   EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]"));<br>
@@ -365,9 +394,16 @@ TEST_F(FileCheckTest, ParsePattern) {<br>
 TEST_F(FileCheckTest, Match) {<br>
   PatternTester Tester;<br>
 <br>
+  // Check matching an empty expression only matches a number.<br>
+  Tester.parsePatternExpect("[[#]]");<br>
+  EXPECT_TRUE(Tester.matchExpect("FAIL"));<br>
+  EXPECT_FALSE(Tester.matchExpect("18"));<br>
+<br>
   // Check matching a definition only matches a number.<br>
+  Tester.initNextPattern();<br>
   Tester.parsePatternExpect("[[#NUMVAR:]]");<br>
   EXPECT_TRUE(Tester.matchExpect("FAIL"));<br>
+  EXPECT_TRUE(Tester.matchExpect(""));<br>
   EXPECT_FALSE(Tester.matchExpect("18"));<br>
 <br>
   // Check matching the variable defined matches the correct number only<br>
@@ -381,16 +417,16 @@ TEST_F(FileCheckTest, Match) {<br>
   // the correct value for @LINE.<br>
   Tester.initNextPattern();<br>
   EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));<br>
-  // Ok, @LINE is 4 now.<br>
-  EXPECT_FALSE(Tester.matchExpect("4"));<br>
+  // Ok, @LINE is 5 now.<br>
+  EXPECT_FALSE(Tester.matchExpect("5"));<br>
   Tester.initNextPattern();<br>
-  // @LINE is now 5, match with substitution failure.<br>
+  // @LINE is now 6, match with substitution failure.<br>
   EXPECT_FALSE(Tester.parsePatternExpect("[[#UNKNOWN]]"));<br>
   EXPECT_TRUE(Tester.matchExpect("FOO"));<br>
   Tester.initNextPattern();<br>
-  // Check that @LINE is 6 as expected.<br>
+  // Check that @LINE is 7 as expected.<br>
   EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));<br>
-  EXPECT_FALSE(Tester.matchExpect("6"));<br>
+  EXPECT_FALSE(Tester.matchExpect("7"));<br>
 }<br>
 <br>
 TEST_F(FileCheckTest, Substitution) {<br>
@@ -410,9 +446,9 @@ TEST_F(FileCheckTest, Substitution) {<br>
 <br>
   // Substitutions of defined pseudo and non-pseudo numeric variables return<br>
   // the right value.<br>
-  FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE");<br>
+  FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 1);<br>
+  FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 1);<br>
   LineVar.setValue(42);<br>
-  FileCheckNumericVariable NVar = FileCheckNumericVariable("N");<br>
   NVar.setValue(10);<br>
   auto LineVarUse =<br>
       llvm::make_unique<FileCheckNumericVariableUse>("@LINE", &LineVar);<br>
@@ -494,22 +530,29 @@ TEST_F(FileCheckTest, FileCheckContext)<br>
 <br>
   // Define local variables from command-line.<br>
   GlobalDefines.clear();<br>
+  // Clear local variables to remove dummy numeric variable x that<br>
+  // parseNumericSubstitutionBlock would have created and stored in<br>
+  // GlobalNumericVariableTable.<br>
+  Cxt.clearLocalVars();<br>
   GlobalDefines.emplace_back(std::string("LocalVar=FOO"));<br>
   GlobalDefines.emplace_back(std::string("EmptyVar="));<br>
-  GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));<br>
+  GlobalDefines.emplace_back(std::string("#LocalNumVar1=18"));<br>
+  GlobalDefines.emplace_back(std::string("#LocalNumVar2=LocalNumVar1+2"));<br>
   EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));<br>
 <br>
   // Check defined variables are present and undefined is absent.<br>
   StringRef LocalVarStr = "LocalVar";<br>
-  StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar");<br>
+  StringRef LocalNumVar1Ref = bufferize(SM, "LocalNumVar1");<br>
+  StringRef LocalNumVar2Ref = bufferize(SM, "LocalNumVar2");<br>
   StringRef EmptyVarStr = "EmptyVar";<br>
   StringRef UnknownVarStr = "UnknownVar";<br>
   Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);<br>
   FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);<br>
   Optional<FileCheckNumericVariable *> DefinedNumericVariable;<br>
   Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionAST =<br>
-      P.parseNumericSubstitutionBlock(LocalNumVarRef, DefinedNumericVariable,<br>
-                                      /*IsLegacyLineExpr=*/false, SM);<br>
+      P.parseNumericSubstitutionBlock(LocalNumVar1Ref, DefinedNumericVariable,<br>
+                                      /*IsLegacyLineExpr=*/false,<br>
+                                      /*LineNumber=*/1, &Cxt, SM);<br>
   EXPECT_TRUE(bool(LocalVar));<br>
   EXPECT_EQ(*LocalVar, "FOO");<br>
   Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);<br>
@@ -518,6 +561,14 @@ TEST_F(FileCheckTest, FileCheckContext)<br>
   Expected<uint64_t> ExpressionVal = (*ExpressionAST)->eval();<br>
   EXPECT_TRUE(bool(ExpressionVal));<br>
   EXPECT_EQ(*ExpressionVal, 18U);<br>
+  ExpressionAST =<br>
+      P.parseNumericSubstitutionBlock(LocalNumVar2Ref, DefinedNumericVariable,<br>
+                                      /*IsLegacyLineExpr=*/false,<br>
+                                      /*LineNumber=*/1, &Cxt, SM);<br>
+  EXPECT_TRUE(bool(ExpressionAST));<br>
+  ExpressionVal = (*ExpressionAST)->eval();<br>
+  EXPECT_TRUE(bool(ExpressionVal));<br>
+  EXPECT_EQ(*ExpressionVal, 20U);<br>
   EXPECT_TRUE(bool(EmptyVar));<br>
   EXPECT_EQ(*EmptyVar, "");<br>
   EXPECT_TRUE(errorToBool(UnknownVar.takeError()));<br>
@@ -533,7 +584,14 @@ TEST_F(FileCheckTest, FileCheckContext)<br>
   EXPECT_TRUE(errorToBool((*ExpressionAST)->eval().takeError()));<br>
   P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);<br>
   ExpressionAST = P.parseNumericSubstitutionBlock(<br>
-      LocalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);<br>
+      LocalNumVar1Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,<br>
+      /*LineNumber=*/2, &Cxt, SM);<br>
+  EXPECT_TRUE(bool(ExpressionAST));<br>
+  ExpressionVal = (*ExpressionAST)->eval();<br>
+  EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));<br>
+  ExpressionAST = P.parseNumericSubstitutionBlock(<br>
+      LocalNumVar2Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,<br>
+      /*LineNumber=*/2, &Cxt, SM);<br>
   EXPECT_TRUE(bool(ExpressionAST));<br>
   ExpressionVal = (*ExpressionAST)->eval();<br>
   EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));<br>
@@ -554,7 +612,8 @@ TEST_F(FileCheckTest, FileCheckContext)<br>
   EXPECT_EQ(*GlobalVar, "BAR");<br>
   P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);<br>
   ExpressionAST = P.parseNumericSubstitutionBlock(<br>
-      GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);<br>
+      GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,<br>
+      /*LineNumber=*/3, &Cxt, SM);<br>
   EXPECT_TRUE(bool(ExpressionAST));<br>
   ExpressionVal = (*ExpressionAST)->eval();<br>
   EXPECT_TRUE(bool(ExpressionVal));<br>
@@ -565,7 +624,8 @@ TEST_F(FileCheckTest, FileCheckContext)<br>
   EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));<br>
   P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);<br>
   ExpressionAST = P.parseNumericSubstitutionBlock(<br>
-      GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);<br>
+      GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,<br>
+      /*LineNumber=*/4, &Cxt, SM);<br>
   EXPECT_TRUE(bool(ExpressionAST));<br>
   ExpressionVal = (*ExpressionAST)->eval();<br>
   EXPECT_TRUE(bool(ExpressionVal));<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
llvm-commits@lists.llvm.org<br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</div>
</span></font></div>
<br>
<br>
<font size="1">** We have updated our privacy policy, which contains important information about how we collect and process your personal data. To read the policy, please click
<a href="http://www.graphcore.ai/privacy">here</a> **<br>
<br>
This email and its attachments are intended solely for the addressed recipients and may contain confidential or legally privileged information.<br>
If you are not the intended recipient you must not copy, distribute or disseminate this email in any way; to do so may be unlawful.<br>
<br>
Any personal data/special category personal data herein are processed in accordance with UK data protection legislation.<br>
All associated feasible security measures are in place. Further details are available from the Privacy Notice on the website and/or from the Company.<br>
<br>
Graphcore Limited (registered in England and Wales with registration number 10185006) is registered at 107 Cheapside, London, UK, EC2V 6DN.<br>
This message was scanned for viruses upon transmission. However Graphcore accepts no liability for any such transmission.<br>
<font></font></font>
</body>
</html>