diff --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst
--- a/llvm/docs/CommandGuide/FileCheck.rst
+++ b/llvm/docs/CommandGuide/FileCheck.rst
@@ -105,12 +105,12 @@
   Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be
   used in ``CHECK:`` lines.
 
-.. option:: -D#<NUMVAR>=<VALUE EXPRESSION>
+.. option:: -D#<NUMVAR>=<NUMERIC EXPRESSION>
 
   Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating
-  ``<VALUE EXPRESSION>`` that can be used in ``CHECK:`` lines. See section
-  ``FileCheck Numeric Variables and Expressions`` for details on the format
-  and meaning of ``<VALUE EXPRESSION>``.
+  ``<NUMERIC EXPRESSION>`` that can be used in ``CHECK:`` lines. See section
+  ``FileCheck Numeric Variables and Expressions`` for details on supported
+  numeric expressions.
 
 .. option:: -version
 
@@ -614,11 +614,19 @@
 
 due to ``7`` being unequal to ``5 + 1``.
 
+A numeric variable can also be defined to the result of a numeric expression,
+in which case the numeric expression constraint is checked and if verified the
+variable is assigned to the value. The unified syntax for both defining numeric
+variables and checking a numeric expression is thus
+``[[#%<fmtspec>,<NUMVAR>: <constraint> <expr>]]`` with each element as
+described previously.
+
 The ``--enable-var-scope`` option has the same effect on numeric variables as
 on pattern variables.
 
 Important note: In its current implementation, a numeric expression cannot use
-a numeric variable defined on the same line.
+a numeric variable with a non-empty numeric expression constraint defined on
+the same line.
 
 FileCheck Pseudo Numeric Variables
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/llvm/include/llvm/Support/FileCheck.h b/llvm/include/llvm/Support/FileCheck.h
--- a/llvm/include/llvm/Support/FileCheck.h
+++ b/llvm/include/llvm/Support/FileCheck.h
@@ -96,6 +96,12 @@
   /// Name of the numeric variable.
   StringRef Name;
 
+  /// Pointer to numeric expression defining this numeric variable. Null for
+  /// pseudo variable whose value is known at parse time (e.g. @LINE pseudo
+  /// variable) or cleared local variable. If numeric expression is empty
+  /// NumExpr points to a FileCheckNumExpr with a null AST.
+  FileCheckNumExpr *NumExpr;
+
   /// Value of numeric variable, if defined, or None otherwise.
   llvm::Optional<uint64_t> Value;
 
@@ -104,21 +110,32 @@
   unsigned DefLineNumber;
 
 public:
-  /// Constructor for a variable \p Name defined at line \p DefLineNumber.
-  FileCheckNumericVariable(StringRef Name, unsigned DefLineNumber)
-      : Name(Name), Value(llvm::None), DefLineNumber(DefLineNumber) {}
+  /// Constructor for a variable \p Name defined at line \p DefLineNumber to
+  /// the numeric expression represented by NumExpr.
+  FileCheckNumericVariable(StringRef Name, FileCheckNumExpr *NumExpr,
+                           unsigned DefLineNumber)
+      : Name(Name), NumExpr(NumExpr), Value(llvm::None),
+        DefLineNumber(DefLineNumber) {}
 
   /// Constructor for numeric variable \p Name with a known \p Value at parse
   /// time (e.g. the @LINE numeric variable).
-  FileCheckNumericVariable(StringRef Name, uint64_t Value)
-      : Name(Name), Value(Value) {}
+  explicit FileCheckNumericVariable(StringRef Name, uint64_t Value)
+      : Name(Name), NumExpr(nullptr), Value(Value) {}
 
   /// \returns name of that numeric variable.
   StringRef getName() const { return Name; }
 
+  /// \returns numeric expression associated with this numeric variable.
+  FileCheckNumExpr *getNumExpr() const { return NumExpr; }
+
   /// Evaluates and returns the value of the expression represented by this
-  /// AST. Therefore, \returns this variable's value.
-  llvm::Optional<uint64_t> eval() const { return Value; }
+  /// AST. Therefore, \returns this variable's value or the value of its
+  /// associated numeric expression, if any.
+  llvm::Optional<uint64_t> eval() const;
+
+  /// \returns whether this variable's value is known at match time, when
+  /// performing the substitutions.
+  bool isMatchTimeKnown() const;
 
   /// Appends numeric variable's name to UndefVarNames if undefined.
   void appendUndefVarNames(std::vector<StringRef> &UndefVarNames) const;
@@ -411,13 +428,6 @@
   /// character that is part of the variable name. Otherwise, only
   /// \returns true.
   static bool parseVariable(StringRef Str, bool &IsPseudo, unsigned &TrailIdx);
-  /// Parses \p Expr for use or definition (if \p IsDefinition is true) of a
-  /// numeric variable. \returns whether parsing fails in which case errors are
-  /// reported on \p SM, unless \p AcceptFail is true and the error is in
-  /// parsing the variable name. Otherwise, sets \p Name to the name of the
-  /// parsed numeric variable.
-  bool parseNumericVariable(StringRef &Expr, StringRef &Name, bool IsDefinition,
-                            bool AcceptFail, const SourceMgr &SM) const;
   /// Parses \p Expr for a numeric expression. Parameter \p Legacy indicates
   /// whether Expr should be a legacy numeric expression. \p returns the class
   /// representing the AST of numeric expression or nullptr if parsing fails
@@ -482,6 +492,13 @@
   size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
 
   enum AllowedOperand { LegacyVar, LegacyLiteral, Any };
+  /// Parses \p Expr for use or definition (if \p IsDefinition is true) of a
+  /// numeric variable. \returns whether parsing fails in which case errors are
+  /// reported on \p SM, unless \p AcceptFail is true and the error is in
+  /// parsing the variable name. Otherwise, sets \p Name to the name of the
+  /// parsed numeric variable.
+  bool parseNumericVariable(StringRef &Expr, StringRef &Name, bool IsDefinition,
+                            bool AcceptFail, const SourceMgr &SM) const;
   /// Parses \p Expr for use of a numeric operand. Accepts both literal values
   /// and numeric variables, depending on the value of \p AllowedOperandFlag.
   /// \returns the class representing that operand in the AST of the numeric
diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -24,6 +24,23 @@
 
 using namespace llvm;
 
+llvm::Optional<uint64_t> FileCheckNumericVariable::eval() const {
+  if (Value)
+    return Value;
+
+  if (NumExpr == nullptr || NumExpr->getAST() == nullptr)
+    return llvm::None;
+
+  return NumExpr->getAST()->eval();
+}
+
+bool FileCheckNumericVariable::isMatchTimeKnown() const {
+  if (Value)
+    return true;
+
+  return NumExpr != nullptr && NumExpr->getAST() != nullptr;
+}
+
 void FileCheckNumericVariable::appendUndefVarNames(
     std::vector<StringRef> &UndefVarNames) const {
   if (!Value)
@@ -41,6 +58,7 @@
   if (!Value)
     return true;
   Value = llvm::None;
+  NumExpr = nullptr;
   return false;
 }
 
@@ -187,7 +205,8 @@
   }
 
   FileCheckNumericVariable *NumericVariable = VarTableIter->second.get();
-  if (!IsPseudo && NumericVariable->getDefLineNumber() == LineNumber) {
+  if (!IsPseudo && NumericVariable->getDefLineNumber() == LineNumber &&
+      !NumericVariable->isMatchTimeKnown()) {
     SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
                     "numeric variable '" + NumericVariable->getName() +
                         "' defined on the same line");
@@ -287,42 +306,19 @@
     StringRef Expr, FileCheckNumericVariable *&DefinedNumericVariable,
     bool Legacy, const SourceMgr &SM) const {
   std::shared_ptr<FileCheckNumExprAST> NumExprAST;
+  StringRef DefExpr = StringRef();
 
-  // Parse numeric variable definition.
   DefinedNumericVariable = nullptr;
+  // Save variable definition expression if any.
   size_t DefEnd = Expr.find(':');
   if (DefEnd != StringRef::npos) {
-    StringRef DefExpr = Expr.substr(0, DefEnd);
-    StringRef UseExpr = Expr = Expr.substr(DefEnd + 1);
-
-    DefExpr = DefExpr.ltrim(SpaceChars);
-    StringRef Name;
-    if (parseNumericVariable(DefExpr, Name, true /*IsDefinition*/,
-                             false /*AcceptFail*/, SM)) {
-      // Invalid variable definition. Error reporting done in parsing function.
-      return nullptr;
-    }
-
-    DefinedNumericVariable =
-        new FileCheckNumericVariable(Name, this->LineNumber);
+    DefExpr = Expr.substr(0, DefEnd);
+    Expr = Expr.substr(DefEnd + 1);
+  }
 
-    DefExpr = DefExpr.ltrim(SpaceChars);
-    if (!DefExpr.empty()) {
-      SM.PrintMessage(SMLoc::getFromPointer(DefExpr.data()),
-                      SourceMgr::DK_Error,
-                      "invalid numeric variable definition");
-      return nullptr;
-    }
-    UseExpr = UseExpr.ltrim(SpaceChars);
-    if (!UseExpr.empty()) {
-      SM.PrintMessage(
-          SMLoc::getFromPointer(UseExpr.data()), SourceMgr::DK_Error,
-          "unexpected string after variable definition: '" + UseExpr + "'");
-      return nullptr;
-    }
-  } else {
-    // Parse numeric expression itself.
-    Expr = Expr.ltrim(SpaceChars);
+  // Parse numeric expression itself.
+  Expr = Expr.ltrim(SpaceChars);
+  if (!Expr.empty()) {
     // First operand in legacy numeric expression is the @LINE pseudo variable.
     enum AllowedOperand AO = Legacy ? LegacyVar : Any;
     NumExprAST = parseNumericOperand(Expr, AO, SM);
@@ -343,7 +339,31 @@
     }
   }
 
-  return Context->makeNumExpr(NumExprAST);
+  FileCheckNumExpr *NumExpr = Context->makeNumExpr(NumExprAST);
+
+  // Parse numeric variable definition.
+  if (!DefExpr.empty()) {
+    DefExpr = DefExpr.ltrim(SpaceChars);
+    StringRef Name;
+    if (parseNumericVariable(DefExpr, Name, true /*IsDefinition*/,
+                             false /*AcceptFail*/, SM)) {
+      // Invalid variable definition. Error reporting done in parsing function.
+      return nullptr;
+    }
+
+    DefinedNumericVariable =
+        new FileCheckNumericVariable(Name, NumExpr, this->LineNumber);
+
+    DefExpr = DefExpr.ltrim(SpaceChars);
+    if (!DefExpr.empty()) {
+      SM.PrintMessage(SMLoc::getFromPointer(DefExpr.data()),
+                      SourceMgr::DK_Error,
+                      "invalid numeric variable definition");
+      return nullptr;
+    }
+  }
+
+  return NumExpr;
 }
 
 bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
@@ -437,10 +457,11 @@
     // 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 also have the definition and substitution forms.
-    // Both pattern and numeric variables must satisfy the regular expression
-    // "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch some common
-    // errors.
+    // the double brackets and also have the definition and substitution forms
+    // and the two forms can be combined to set a variable to the evaluation of
+    // a numeric expression. Both pattern and numeric variables must satisfy
+    // the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this
+    // helps catch some common errors.
     if (PatternStr.startswith("[[")) {
       StringRef UnparsedPatternStr = PatternStr.substr(2);
       // Find the closing bracket pair ending the match.  End is going to be an
@@ -463,10 +484,11 @@
       PatternStr = UnparsedPatternStr.substr(End + 2);
 
       bool IsVarDef;
+      bool SubstNeeded;
       bool Legacy = false;
       StringRef DefName;
       StringRef SubstStr;
-      StringRef MatchRegexp;
+      StringRef MatchRegexp = StringRef();
       size_t SubstInsertIdx = RegExStr.size();
       FileCheckNumericVariable *DefinedNumericVariable;
       FileCheckNumExpr *NumExpr;
@@ -494,6 +516,7 @@
         StringRef Trailer = MatchStr.substr(TrailIdx);
         IsVarDef = (VarEndIdx != StringRef::npos);
         Legacy = IsNumExpr = IsPseudo;
+        SubstNeeded = !IsVarDef;
 
         if (IsVarDef) {
           if ((IsPseudo || !Trailer.consume_front(":"))) {
@@ -525,16 +548,53 @@
         if (NumExpr == nullptr)
           return true;
         IsNumExpr = true;
-        if (DefinedNumericVariable != nullptr) {
-          IsVarDef = true;
+        IsVarDef = DefinedNumericVariable != nullptr;
+        SubstNeeded = NumExpr->getAST() != nullptr;
+        if (IsVarDef)
           DefName = DefinedNumericVariable->getName();
-          MatchRegexp = StringRef("[0-9]+");
-        } else
+        if (SubstNeeded)
           SubstStr = MatchStr;
+        else
+          MatchRegexp = StringRef("[0-9]+");
+      }
+
+      // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].
+      if (IsVarDef) {
+        RegExStr += '(';
+        ++SubstInsertIdx;
+
+        if (IsNumExpr) {
+          struct FileCheckNumExprMatch NumExprDef = {DefinedNumericVariable,
+                                                     CurParen};
+          NumericVariableDefs[DefName] = NumExprDef;
+          // This store is done here rather than in match() to allow
+          // ParseNumericVariable() to get the pointer to the class instance
+          // of the right variable definition corresponding to a given numeric
+          // variable use.
+          Context->GlobalNumericVariableTable[DefName] =
+              std::shared_ptr<FileCheckNumericVariable>(DefinedNumericVariable);
+        } else {
+          VariableDefs[DefName] = CurParen;
+          // Mark pattern variable as defined to detect collision between
+          // pattern and numeric variables in ParseNumericVariable and
+          // 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 loose the ability to
+          // detect use of undefined variable in match().
+          Context->DefinedVariableTable[DefName] = true;
+        }
+
+        ++CurParen;
       }
 
+      if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))
+        return true;
+
+      if (IsVarDef)
+        RegExStr += ')';
+
       // Handle variable use: [[foo]] and [[#<foo expr>]].
-      if (!IsVarDef) {
+      if (SubstNeeded) {
         // Handle use of pattern variables that were defined earlier on the
         // same line by emitting a backreference. Numeric expressions do not
         // support using a numeric variable defined on the same line.
@@ -557,37 +617,7 @@
                                                        SubstInsertIdx);
           Substitutions.push_back(Substitution);
         }
-        continue;
       }
-
-      // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].
-      if (IsNumExpr) {
-        struct FileCheckNumExprMatch NumExprDef = {DefinedNumericVariable,
-                                                   CurParen};
-        NumericVariableDefs[DefName] = NumExprDef;
-        // This store is done here rather than in match() to allow
-        // parseNumericVariable() to get the pointer to the class instance
-        // of the right variable definition corresponding to a given numeric
-        // variable use.
-        Context->GlobalNumericVariableTable[DefName] =
-            std::shared_ptr<FileCheckNumericVariable>(DefinedNumericVariable);
-      } else {
-        VariableDefs[DefName] = CurParen;
-        // Mark pattern variable as defined to detect collision between pattern
-        // and numeric variable in parseNumericVariable and
-        // 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 loose the ability to
-        // detect use of undefined variable in match().
-        Context->DefinedVariableTable[DefName] = true;
-      }
-      RegExStr += '(';
-      ++CurParen;
-
-      if (AddRegExToRegEx(MatchRegexp, CurParen, SM))
-        return true;
-
-      RegExStr += ')';
     }
 
     // Handle fixed string matches.
@@ -1737,9 +1767,37 @@
   std::string CmdlineDefsDiag;
   StringRef Prefix1 = "Global define #";
   StringRef Prefix2 = ": ";
-  for (StringRef CmdlineDef : CmdlineDefines)
-    CmdlineDefsDiag +=
-        (Prefix1 + Twine(++I) + Prefix2 + CmdlineDef + "\n").str();
+  StringRef Suffix1 = " (parsed as: [[";
+  StringRef Suffix3 = "]])";
+  SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;
+  for (StringRef CmdlineDef : CmdlineDefines) {
+    StringRef DefNo = Twine(++I).str();
+    size_t EqIdx = CmdlineDef.find('=');
+    if (EqIdx == StringRef::npos) {
+      llvm::outs() << "Missing equal sign in global definition '" << CmdlineDef
+                   << "'";
+      CmdlineDefsIndices.push_back(std::make_pair(0, 0));
+      ErrorFound = true;
+      continue;
+    }
+    // Numeric variable definition.
+    if (CmdlineDef[0] == '#') {
+      // Append a copy command-line definition adapted to use the same format
+      // as in the input file to be able to reuse ParseNumericExpression.
+      CmdlineDefsDiag +=
+          (Prefix1 + DefNo + Prefix2 + CmdlineDef + Suffix1).str();
+      std::string Suffix2 = CmdlineDef;
+      Suffix2[EqIdx] = ':';
+      CmdlineDefsIndices.push_back(
+          std::make_pair(CmdlineDefsDiag.size(), Suffix2.size()));
+      CmdlineDefsDiag += (Suffix2 + Suffix3 + "\n").str();
+    } else {
+      CmdlineDefsDiag += (Prefix1 + DefNo + Prefix2).str();
+      CmdlineDefsIndices.push_back(
+          std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));
+      CmdlineDefsDiag += (CmdlineDef + "\n").str();
+    }
+  }
 
   // Create a buffer with fake command line content in order to display
   // parsing diagnostic with location information and point to the
@@ -1749,66 +1807,41 @@
   StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
   SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());
 
-  // Dummy pattern to call parseNumericVariable.
+  // Dummy pattern to call parseNumericExpression.
   FileCheckPattern P(Check::CheckPlain, this, 0);
 
-  SmallVector<StringRef, 4> CmdlineDefsDiagVec;
-  CmdlineDefsDiagRef.split(CmdlineDefsDiagVec, '\n', -1 /*MaxSplit*/,
-                           false /*KeepEmpty*/);
-  for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) {
-    unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size();
-    StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart);
-    size_t EqIdx = CmdlineDef.find('=');
-    if (EqIdx == StringRef::npos) {
-      SM.PrintMessage(SMLoc::getFromPointer(CmdlineDef.data()),
-                      SourceMgr::DK_Error,
-                      "Missing equal sign in global definition");
-      ErrorFound = true;
+  for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {
+    StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,
+                                                     CmdlineDefIndices.second);
+    // Error already handled in previous loop, skip this.
+    if (CmdlineDef.empty())
       continue;
-    }
 
     // Numeric variable definition.
     if (CmdlineDef[0] == '#') {
-      StringRef Expr = CmdlineDef.substr(1, EqIdx - 1);
-      StringRef CmdlineName;
-      SMLoc CmdlineNameLoc = SMLoc::getFromPointer(Expr.data());
-      if (P.parseNumericVariable(Expr, CmdlineName, true /*IsDefinition*/,
-                                 false /*AcceptFail*/, SM) ||
-          !Expr.empty()) {
-        SM.PrintMessage(CmdlineNameLoc, SourceMgr::DK_Error,
-                        "invalid variable name");
-        ErrorFound = true;
-        continue;
-      }
-
-      // Detect collision between pattern and numeric variable 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");
+      // Now parse to both check syntax is correct and create the necessary
+      // class instance.
+      StringRef CmdlineDefExpr = CmdlineDef.substr(1);
+      FileCheckNumericVariable *DefinedNumericVariable;
+      FileCheckNumExpr *NumExpr = P.parseNumericExpression(
+          CmdlineDefExpr, DefinedNumericVariable, false, SM);
+      if (NumExpr == nullptr || DefinedNumericVariable == nullptr) {
         ErrorFound = true;
         continue;
       }
-
-      StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1);
-      uint64_t Val;
-      if (CmdlineVal.getAsInteger(10, Val)) {
-        SM.PrintMessage(SMLoc::getFromPointer(CmdlineVal.data()),
+      llvm::Optional<uint64_t> Value = NumExpr->getAST()->eval();
+      if (!Value) {
+        SM.PrintMessage(SMLoc::getFromPointer(CmdlineDefExpr.data()),
                         SourceMgr::DK_Error,
-                        "invalid value in numeric variable definition '" +
-                            CmdlineVal + "'");
+                        "unable to represent numeric value");
         ErrorFound = true;
         continue;
       }
-      auto DefinedNumericVariable =
-          std::make_shared<FileCheckNumericVariable>(CmdlineName, (unsigned)0);
-      DefinedNumericVariable->setValue(Val);
+      DefinedNumericVariable->setValue(*Value);
 
       // Record this variable definition.
       GlobalNumericVariableTable[DefinedNumericVariable->getName()] =
-          DefinedNumericVariable;
+          std::shared_ptr<FileCheckNumericVariable>(DefinedNumericVariable);
     } else {
       // Pattern variable definition.
       std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
diff --git a/llvm/test/FileCheck/numeric-defines.txt b/llvm/test/FileCheck/numeric-defines.txt
--- a/llvm/test/FileCheck/numeric-defines.txt
+++ b/llvm/test/FileCheck/numeric-defines.txt
@@ -1,47 +1,40 @@
-; RUN: FileCheck -D#NUMVAL=12 -check-prefix CHECKNUM -input-file %s %s
-; RUN: not FileCheck -D#NUMVAL=8 -check-prefix CHECKNUM -input-file %s %s 2>&1 \
+; RUN: FileCheck -D#NUMVAL1=8 -D#NUMVAL2='NUMVAL1 + 4' -check-prefix CHECKNUM -input-file %s %s
+; RUN: not FileCheck -D#NUMVAL2=8 -check-prefix CHECKNUM -input-file %s %s 2>&1 \
 ; RUN:   | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG
-; RUN: not FileCheck -D#NUMVAL=12 -check-prefix NUMNOT -input-file %s %s 2>&1 \
+; RUN: not FileCheck -D#NUMVAL2=12 -check-prefix NUMNOT -input-file %s %s 2>&1 \
 ; RUN:   | FileCheck %s --strict-whitespace -check-prefix NOT-NUMERRMSG
-; RUN: FileCheck -D#NUMVAL=8 -check-prefixes NUMNOT -input-file %s %s
+; RUN: FileCheck -D#NUMVAL2=8 -check-prefixes NUMNOT -input-file %s %s
 
-Numeric value = 12
-; CHECKNUM: Numeric value = [[#NUMVAL]]
-; NUMNOT-NOT: Numeric value = [[#NUMVAL]]
+Numeric value #2 = 12
+; CHECKNUM: Numeric value #2 = [[#NUMVAL2]]
+; NUMNOT-NOT: Numeric value #2 = [[#NUMVAL2]]
 
 ; NUMERRMSG: defines.txt:[[#@LINE-3]]:13: error: CHECKNUM: expected string not found in input
 ; NUMERRMSG: defines.txt:1:1: note: scanning from here
-; NUMERRMSG: defines.txt:1:1: note: with numeric expression "NUMVAL" equal to "8"
+; NUMERRMSG: defines.txt:1:1: note: with numeric expression "NUMVAL2" equal to "8"
 ; NUMERRMSG: defines.txt:[[#@LINE-7]]:1: note: possible intended match here
 
 ; NOT-NUMERRMSG: defines.txt:[[#@LINE-7]]:15: error: {{NUMNOT}}-NOT: excluded string found in input
 ; NOT-NUMERRMSG: defines.txt:[[#@LINE-10]]:1: note: found here
-; NOT-NUMERRMSG: defines.txt:[[#@LINE-11]]:1: note: with numeric expression "NUMVAL" equal to "12"
+; NOT-NUMERRMSG: defines.txt:[[#@LINE-11]]:1: note: with numeric expression "NUMVAL2" equal to "12"
 
 ; RUN: not FileCheck -D#10VALUE=10 -input-file %s %s 2>&1 \
 ; RUN:   | FileCheck %s --strict-whitespace -check-prefix NUMERRCLIFMT
 
-; NUMERRCLIFMT: Global defines:1:20: error: invalid variable name
-; NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10
-; NUMERRCLIFMT-NEXT: {{^                   \^$}}
+; NUMERRCLIFMT: Global defines:1:46: error: invalid variable name
+; NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10 (parsed as: {{\[\[#10VALUE:10\]\]}})
+; NUMERRCLIFMT-NEXT: {{^                                             \^$}}
 
 ; RUN: not FileCheck -D#@VALUE=10 -input-file %s %s 2>&1 \
 ; RUN:   | FileCheck %s --strict-whitespace -check-prefix NUMERRCLIPSEUDO
 
-; NUMERRCLIPSEUDO: Global defines:1:20: error: invalid pseudo numeric variable
-; NUMERRCLIPSEUDO-NEXT: Global define #1: #@VALUE=10
-; NUMERRCLIPSEUDO-NEXT: {{^                   \^$}}
+; NUMERRCLIPSEUDO: Global defines:1:45: error: invalid pseudo numeric variable
+; NUMERRCLIPSEUDO-NEXT: Global define #1: #@VALUE=10 (parsed as: {{\[\[#@VALUE:10\]\]}})
+; NUMERRCLIPSEUDO-NEXT: {{^                                            \^$}}
 
 ; RUN: not FileCheck -D#'VALUE + 2=10' -input-file %s %s 2>&1 \
 : RUN:   | FileCheck %s --strict-whitespace -check-prefix NUMERRCLITRAIL
 
-; NUMERRCLITRAIL: Global defines:1:20: error: invalid variable name
-; NUMERRCLITRAIL-NEXT: Global define #1: #VALUE + 2=10
-; NUMERRCLITRAIL-NEXT: {{^                   \^$}}
-
-; RUN: not FileCheck -D#VALUE1=3 -D#VALUE2='VALUE1 + 2' -input-file %s %s 2>&1 \
-; RUN:   | FileCheck %s --strict-whitespace -check-prefix NUMERRCLIEXPR
-
-; NUMERRCLIEXPR: Global defines:2:27: error: invalid value in numeric variable definition 'VALUE1 + 2'
-; NUMERRCLIEXPR-NEXT: Global define #2: #VALUE2=VALUE1 + 2
-; NUMERRCLIEXPR-NEXT: {{^                          \^$}}
+; NUMERRCLITRAIL: Global defines:1:54: error: invalid numeric variable definition
+; NUMERRCLITRAIL-NEXT: Global define #1: #VALUE + 2=10 (parsed as: {{\[\[#VALUE \+ 2:10\]\]}})
+; NUMERRCLITRAIL-NEXT: {{^                                                     \^$}}
diff --git a/llvm/test/FileCheck/numeric-expression.txt b/llvm/test/FileCheck/numeric-expression.txt
--- a/llvm/test/FileCheck/numeric-expression.txt
+++ b/llvm/test/FileCheck/numeric-expression.txt
@@ -62,6 +62,20 @@
 ; CHECK-LABEL: USE UNSIGNED IMM
 ; CHECK-NEXT: [[#VAR1+9223372036854775808]]
 
+; Numeric expression using a variable defined from a numeric expression
+DEF EXPR GOOD MATCH
+42
+41 43
+; CHECK-LABEL: DEF EXPR GOOD MATCH
+; CHECK-NEXT: [[# VAR42:VAR1+31]]
+; CHECK-NEXT: [[# VAR41: VAR42-1]] [[# VAR41 + 2]]
+
+; Empty numeric expression
+EMPTY NUM EXPR
+foo 104 bar
+; CHECK-LABEL: EMPTY NUM EXPR
+; CHECK-NEXT: foo [[#]] bar
+
 ; Numeric expression using undefined variable
 ; RUN: not FileCheck -check-prefix UNDEF-USE -input-file %s %s 2>&1 \
 ; RUN:   | FileCheck --strict-whitespace -check-prefix UNDEF-USE-MSG %s
@@ -119,6 +133,17 @@
 ; INPUT-NUM-CONFLICT: numeric-expression.txt:[[#@LINE-7]]:24: error: pattern variable with name 'PATVAR' already exists
 ; INPUT-NUM-CONFLICT-NEXT: ; CONFLICT4: redef2 {{\[\[#PATVAR:\]\]}}
 ; INPUT-NUM-CONFLICT-NEXT: {{^                       \^$}}
-; CLI-NUM-CONFLICT: Global defines:2:20: error: pattern variable with name 'PATVAR' already exists
-; CLI-NUM-CONFLICT-NEXT: Global define #2: #PATVAR=42
-; CLI-NUM-CONFLICT-NEXT: {{^                   \^$}}
+; CLI-NUM-CONFLICT: Global defines:2:45: error: pattern variable with name 'PATVAR' already exists
+; CLI-NUM-CONFLICT-NEXT: Global define #2: #PATVAR=42 (parsed as: {{\[\[#PATVAR:42\]\]}})
+; CLI-NUM-CONFLICT-NEXT: {{^                                            \^$}}
+
+; Verify that when variable is set to an expression the expression is still
+; checked
+; RUN: not FileCheck -check-prefix DEF-EXPR-FAIL -input-file %s %s
+
+DEF EXPR WRONG MATCH
+20
+43
+; DEF-EXPR-FAIL-LABEL: DEF EXPR WRONG MATCH
+; DEF-EXPR-FAIL-NEXT: [[# VAR20:]]
+; DEF-EXPR-FAIL-NEXT: [[# VAR42: VAR20+22]]
diff --git a/llvm/unittests/Support/FileCheckTest.cpp b/llvm/unittests/Support/FileCheckTest.cpp
--- a/llvm/unittests/Support/FileCheckTest.cpp
+++ b/llvm/unittests/Support/FileCheckTest.cpp
@@ -15,8 +15,10 @@
 class FileCheckTest : public ::testing::Test {};
 
 TEST_F(FileCheckTest, NumericVariableValueGetClearSet) {
+  auto NumVarExpr = FileCheckNumExpr(nullptr);
   FileCheckNumericVariable FooVar =
-      FileCheckNumericVariable("FOO", (uint64_t)42);
+      FileCheckNumericVariable("FOO", &NumVarExpr, 1);
+  FooVar.setValue((uint64_t)42);
 
   // Defined variable: getValue returns a value, setValue fails.
   llvm::Optional<uint64_t> Value = FooVar.eval();
@@ -40,8 +42,14 @@
 uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
 
 TEST_F(FileCheckTest, BinopEvalUndef) {
-  auto FooVar = std::make_shared<FileCheckNumericVariable>("FOO", (uint64_t)42);
-  auto BarVar = std::make_shared<FileCheckNumericVariable>("BAR", (uint64_t)18);
+  auto FooNumExpr = FileCheckNumExpr(nullptr);
+  auto FooVar =
+      std::make_shared<FileCheckNumericVariable>("FOO", &FooNumExpr, 1);
+  FooVar->setValue((uint64_t)42);
+  auto BarNumExpr = FileCheckNumExpr(nullptr);
+  auto BarVar =
+      std::make_shared<FileCheckNumericVariable>("BAR", &BarNumExpr, 2);
+  BarVar->setValue((uint64_t)18);
   auto Binop = new FileCheckASTBinop(doAdd, FooVar, BarVar);
 
   // Defined variable: eval returns right value, no undef variable returned.
@@ -183,13 +191,6 @@
   }
 
 public:
-  bool parseNumVarExpect(StringRef Expr, bool isDefinition) {
-    StringRef ExprBufferRef = bufferize(SM, Expr);
-    StringRef Name;
-    return P.parseNumericVariable(ExprBufferRef, Name, isDefinition,
-                                  false /*AcceptFail*/, SM);
-  }
-
   bool parseExprExpect(StringRef Expr) {
     StringRef ExprBufferRef = bufferize(SM, Expr);
     FileCheckNumericVariable *DefinedNumericVariable;
@@ -209,6 +210,7 @@
   }
 };
 
+#if 0
 TEST_F(FileCheckTest, ParseNumericVariable) {
   PatternTester Tester;
 
@@ -237,6 +239,7 @@
   // Defined variable.
   EXPECT_FALSE(Tester.parseNumVarExpect("FOO", false /*isDefinition*/));
 }
+#endif
 
 TEST_F(FileCheckTest, ParseExpr) {
   PatternTester Tester;
@@ -251,9 +254,6 @@
   // Garbage after name of variable being defined.
   EXPECT_TRUE(Tester.parseExprExpect("VAR GARBAGE:"));
 
-  // Variable defined to numeric expression.
-  EXPECT_TRUE(Tester.parseExprExpect("VAR1: FOO"));
-
   // Acceptable variable definition.
   EXPECT_FALSE(Tester.parseExprExpect("VAR1:"));
   EXPECT_FALSE(Tester.parseExprExpect("  VAR2:"));
@@ -314,7 +314,6 @@
   EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
   EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
   EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
-  EXPECT_TRUE(Tester.parsePatternExpect("[[#YUP:@LINE]]"));
 
   // Valid numeric expressions and numeric variable definition.
   EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]"));
@@ -351,18 +350,17 @@
   EXPECT_FALSE(Substitution.getResult());
 
   // Substitution of defined numeric variable returns the right value.
-  auto LineVar =
-      std::make_shared<FileCheckNumericVariable>("@LINE", (uint64_t)42);
-  auto Zero = std::make_shared<FileCheckNumExprLiteral>(0);
-  auto Binop = std::make_shared<FileCheckASTBinop>(doAdd, LineVar, Zero);
-  FileCheckNumExpr NumExpr = FileCheckNumExpr(Binop);
-  Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12);
+  auto NumVarExpr = FileCheckNumExpr(nullptr);
+  auto NumVar = std::make_shared<FileCheckNumericVariable>("N", &NumVarExpr, 1);
+  NumVar->setValue(42);
+  FileCheckNumExpr NumExpr = FileCheckNumExpr(NumVar);
+  Substitution = FileCheckPatternSubstitution(&Context, "N", &NumExpr, 12);
   llvm::Optional<std::string> Value = Substitution.getResult();
   EXPECT_TRUE(Value);
   EXPECT_EQ("42", *Value);
 
   // Substitution of undefined numeric variable fails.
-  LineVar->clearValue();
+  NumVar->clearValue();
   EXPECT_FALSE(Substitution.getResult());
 
   // Substitution of defined pattern variable returns the right value.