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#= +.. option:: -D#= Sets a filecheck numeric variable ``VAR`` to the result of evaluating - ```` that can be used in ``CHECK:`` lines. See section - ``FileCheck Numeric Variables and Expressions`` for details on the format - and meaning of . + ```` that can be used in ``CHECK:`` lines. See section + ``FileCheck Numeric Variables and Expressions`` for details on supported + numeric expressions. .. option:: -version @@ -614,12 +614,20 @@ 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 +``[[#%,: ]]`` with each element as +described previously. + In the same way as for pattern variables, ``--enable-var-scope`` only consider global numeric variables that start with ``$`` and undefined local variables at the beginning of each CHECK-LABEL block. 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 @@ -95,6 +95,12 @@ /// Name of the numeric variable. StringRef Name; + /// Pointer to numeric expression defining this numeric variable. Only null + /// for pseudo variable whose value is known at parse time (e.g. @LINE pseudo + /// variable). If numeric expression is empty NumExpr points to a + /// FileCheckNumExpr with a null AST. + std::shared_ptr NumExpr; + /// Whether variable is defined and thus Value is set. bool Defined; @@ -106,22 +112,33 @@ unsigned DefLineNumber; public: - /// Constructor for a variable \p Name defined at line \p DefLineNumber. - FileCheckNumExprVar(StringRef Name, unsigned DefLineNumber) - : Name(Name), Defined(false), DefLineNumber(DefLineNumber) {} + /// Constructor for a variable \p Name defined at line \p DefLineNumber to + /// the numeric expression represented by NumExpr. + FileCheckNumExprVar(StringRef Name, std::shared_ptr NumExpr, + unsigned DefLineNumber) + : Name(Name), NumExpr(NumExpr), Defined(false), + DefLineNumber(DefLineNumber) {} /// Constructor for numeric variable \p Name with a known \p Value at parse /// time (e.g. the @LINE numeric variable). FileCheckNumExprVar(StringRef Name, uint64_t Value) - : Name(Name), Defined(true), Value(Value) {} + : Name(Name), NumExpr(nullptr), Defined(true), Value(Value) {} /// Return name of that numeric variable. StringRef getName() const { return Name; } + /// Return numeric expression associated with this numeric variable. + std::shared_ptr getNumExpr() const { return NumExpr; } + /// Evaluate the value of the expression represented by this AST. Therefore, - /// return this variable's value. + /// return this variable's value or the value of its associated numeric + /// expression if any. llvm::Optional eval() const; + /// Return whether this variable's value is known at match time, when + /// performing the substitutions. + bool isMatchTimeKnown() const; + /// Append numeric variable's name to UndefVarNames if undefined. void appendUndefVarNames(std::vector &UndefVarNames) const; @@ -394,8 +411,6 @@ FileCheckPatternContext *GetContext() const { return Context; } static bool parseVariable(StringRef Str, bool &IsPseudo, unsigned &TrailIdx); - bool parseNumericVariable(StringRef &Expr, StringRef &Name, bool IsDefinition, - bool AcceptFail, const SourceMgr &SM) const; std::shared_ptr parseNumericExpression(StringRef Expr, std::shared_ptr &NumVarDef, @@ -422,6 +437,8 @@ /// Numeric expression parsing helpers. enum AllowedOperand { LegacyVar, LegacyLiteral, Any }; + bool parseNumericVariable(StringRef &Expr, StringRef &Name, bool IsDefinition, + bool AcceptFail, const SourceMgr &SM) const; std::shared_ptr parseNumericOperand(StringRef &Expr, enum AllowedOperand AO, const SourceMgr &SM) const; 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 @@ -25,11 +25,23 @@ using namespace llvm; /// Evaluate the value of the expression represented by this AST. Therefore, -/// return this variable's value. +/// return this variable's value or the value of its associated numeric +/// expression if any. llvm::Optional FileCheckNumExprVar::eval() const { - if (!Defined) - return llvm::None; - return Value; + if (Defined) + return Value; + + assert(NumExpr != nullptr); + if (NumExpr->getAST() != nullptr) + return NumExpr->getAST()->eval(); + + return llvm::None; +} + +/// Return whether this variable's value is known at match time, when +/// performing the substitutions. +bool FileCheckNumExprVar::isMatchTimeKnown() const { + return NumExpr != nullptr && NumExpr->getAST() != nullptr; } /// Append numeric variable's name to UndefVarNames if undefined. @@ -228,7 +240,8 @@ } std::shared_ptr NumVar = git->second; - if (!IsPseudo && NumVar->getDefLineNumber() == LineNumber) { + if (!IsPseudo && NumVar->getDefLineNumber() == LineNumber && + !NumVar->isMatchTimeKnown()) { SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error, "Numeric variable '" + NumVar->getName() + "' defined on the same line"); @@ -340,40 +353,19 @@ StringRef Expr, std::shared_ptr &NumVarDef, bool Legacy, const SourceMgr &SM) const { std::shared_ptr NumExprAST; + StringRef DefExpr = StringRef(); - // Parse numeric variable definition. NumVarDef.reset(); + // 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); - - skipWhitespace(DefExpr); - StringRef Name; - if (parseNumericVariable(DefExpr, Name, true /*IsDefinition*/, - false /*AcceptFail*/, SM)) - // Invalid variable definition. Error reporting done in parsing function. - return nullptr; - - NumVarDef = std::make_shared(Name, this->LineNumber); + DefExpr = Expr.substr(0, DefEnd); + Expr = Expr.substr(DefEnd + 1); + } - skipWhitespace(DefExpr); - if (!DefExpr.empty()) { - SM.PrintMessage(SMLoc::getFromPointer(DefExpr.data()), - SourceMgr::DK_Error, - "Invalid numeric variable definition"); - return nullptr; - } - skipWhitespace(UseExpr); - 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. - skipWhitespace(Expr); + // Parse numeric expression itself. + skipWhitespace(Expr); + 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); @@ -394,7 +386,30 @@ } } - return std::make_shared(NumExprAST); + auto NumExpr = std::make_shared(NumExprAST); + + // Parse numeric variable definition. + if (!DefExpr.empty()) { + skipWhitespace(DefExpr); + StringRef Name; + if (parseNumericVariable(DefExpr, Name, true /*IsDefinition*/, + false /*AcceptFail*/, SM)) + // Invalid variable definition. Error reporting done in parsing function. + return nullptr; + + NumVarDef = + std::make_shared(Name, NumExpr, this->LineNumber); + + skipWhitespace(DefExpr); + if (!DefExpr.empty()) { + SM.PrintMessage(SMLoc::getFromPointer(DefExpr.data()), + SourceMgr::DK_Error, + "Invalid numeric variable definition"); + return nullptr; + } + } + + return NumExpr; } /// Parses the given string into the Pattern. @@ -496,8 +511,10 @@ // which is a substitution of foo's value. Variable names themselves must // be of the form "[a-zA-Z_][0-9a-zA-Z_]*", otherwise we reject it. This is // to catch some common errors. Numeric expressions also have the - // definition and substitution modes and numeric variable names have the - // same restriction as their pattern variable counterpart. + // definition and substitution modes but the two modes can also be combined + // to set a variable to the evaluation of a numeric expression. Numeric + // variable names have the same restriction as their pattern variable + // counterpart. if (PatternStr.startswith("[[")) { StringRef MatchStr = PatternStr.substr(2); bool IsNumExpr = MatchStr.consume_front("#"); @@ -518,10 +535,11 @@ PatternStr = PatternStr.substr(End + 4 + (int)IsNumExpr); bool IsVarDef; + bool SubstNeeded; bool Legacy = false; StringRef DefName; StringRef SubstStr; - StringRef MatchRegexp; + StringRef MatchRegexp = StringRef(); unsigned SubstInsertIdx = RegExStr.size(); std::shared_ptr NumVarDef; std::shared_ptr NumExpr; @@ -549,6 +567,7 @@ size_t DefSepIdx = Trailer.find(":"); IsVarDef = (DefSepIdx != StringRef::npos); Legacy = IsNumExpr = IsPseudo; + SubstNeeded = !IsVarDef; if (IsVarDef) { if ((IsPseudo || !Trailer.consume_front(":"))) { @@ -579,16 +598,51 @@ if (NumExpr == nullptr) return true; IsNumExpr = true; - if (NumVarDef != nullptr) { - IsVarDef = true; + IsVarDef = NumVarDef != nullptr; + SubstNeeded = NumExpr->getAST() != nullptr; + if (IsVarDef) DefName = NumVarDef->getName(); - MatchRegexp = StringRef("[0-9]+"); - } else + if (SubstNeeded) SubstStr = MatchStr; + else + MatchRegexp = StringRef("[0-9]+"); } + // Handle variable definition: [[:(...)]] and [[#(...):(...)]]. + if (IsVarDef) { + RegExStr += '('; + ++SubstInsertIdx; + + if (IsNumExpr) { + struct FileCheckNumExprMatch NumExprDef = {NumVarDef, 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] = NumVarDef; + } 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; + } + + ++CurParen; + } + + if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM)) + return true; + + if (IsVarDef) + RegExStr += ')'; + // Handle variable use: [[foo]] and [[#]]. - 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. @@ -611,35 +665,7 @@ : FileCheckPatternSubst(Context, SubstStr, SubstInsertIdx); Substs.push_back(Subst); } - continue; - } - - // Handle variable definition: [[:(...)]] and [[#(...):(...)]]. - if (IsNumExpr) { - struct FileCheckNumExprMatch NumExprDef = {NumVarDef, 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] = NumVarDef; - } 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. @@ -1821,50 +1847,54 @@ return true; CmdlineVariablesDefined = true; - // Dummy pattern to call parseNumericVariable + // Dummy pattern to call parseNumericExpression FileCheckPattern P(Check::CheckPlain, this, 0); bool ErrorFound = false; for (const auto &CmdlineDef : CmdlineDefines) { - // Numeric variable definition. + // Numeric variable definition. Same format as numeric expression with + // variable definition where ':' is replaced by '=' if (CmdlineDef[0] == '#') { + // Copy command-line definition text with leading '#' stripped and + // replace '=' by ':' to be able to reuse ParseNumericExpression. // Create a buffer with fake command line content in order to display // parsing diagnostic with location information and point to the // command-line option with invalid syntax. std::string Prefix = "-D"; - std::string DiagCmdline = Prefix + CmdlineDef; + std::string Suffix1 = " (parsed as: [["; + std::string Suffix2 = CmdlineDef; + size_t EqIdx = Suffix2.find('='); + Suffix2[EqIdx] = ':'; + std::string Suffix3 = "]])"; + std::string DiagCmdline = + Prefix + CmdlineDef + Suffix1 + Suffix2 + Suffix3; std::unique_ptr CmdLine = MemoryBuffer::getMemBufferCopy(DiagCmdline, "command line"); - StringRef DiagCmdlineDefRef = CmdLine->getBuffer().substr(Prefix.size()); + StringRef DiagCmdlineDefRef = CmdLine->getBuffer(); SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc()); - // Parse numeric variable definition. - size_t EqIdx = CmdlineDef.find('='); - StringRef Expr = DiagCmdlineDefRef.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"); + // Now parse to both check syntax is correct and create the necessary + // class instance. + size_t NumExprStartIdx = + Prefix.size() + CmdlineDef.size() + Suffix1.size() + 1; + StringRef CmdlineDefRef = + DiagCmdlineDefRef.substr(NumExprStartIdx).drop_back(Suffix3.size()); + std::shared_ptr NumVarDef; + std::shared_ptr NumExpr = + P.parseNumericExpression(CmdlineDefRef, NumVarDef, false, SM); + if (NumExpr == nullptr || NumVarDef == nullptr) { ErrorFound = true; continue; } - - StringRef CmdlineVal = DiagCmdlineDefRef.substr(EqIdx + 1); - uint64_t Val; - if (CmdlineVal.getAsInteger(10, Val)) { - SM.PrintMessage(SMLoc::getFromPointer(CmdlineVal.data()), + llvm::Optional OptValue = NumExpr->getAST()->eval(); + if (!OptValue.hasValue()) { + SM.PrintMessage(SMLoc::getFromPointer(CmdlineDefRef.data()), SourceMgr::DK_Error, - "Invalid value in numeric variable definition '" + - CmdlineVal + "'"); + "Unable to represent numeric value"); ErrorFound = true; continue; } - std::shared_ptr NumVarDef = - std::make_shared(CmdlineName, (unsigned)0); - NumVarDef->setValue(Val); + NumVarDef->setValue(OptValue.getValue()); // Record this variable definition. GlobalNumericVariableTable[NumVarDef->getName()] = NumVarDef; diff --git a/llvm/test/FileCheck/defines.txt b/llvm/test/FileCheck/defines.txt --- a/llvm/test/FileCheck/defines.txt +++ b/llvm/test/FileCheck/defines.txt @@ -12,14 +12,13 @@ ; RUN: not FileCheck -D@VALUE=10 -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix ERRCLIPSEUDO ; RUN: not FileCheck -D'VALUE + 2=10' -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix ERRCLITRAIL -; 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 | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG -; RUN: not FileCheck -D#NUMVAL=12 -check-prefix NUMNOT -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NOT-NUMERRMSG -; RUN: FileCheck -D#NUMVAL=8 -check-prefixes NUMNOT -input-file %s %s +; RUN: FileCheck -D#NUMVAL1=8 -D#NUMVAL2='NUMVAL1 + 4' -check-prefix CHECKNUM -input-file %s %s +; RUN: not FileCheck -D#NUMVAL2=8 -check-prefix CHECKNUM -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG +; RUN: not FileCheck -D#NUMVAL2=12 -check-prefix NUMNOT -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NOT-NUMERRMSG +; RUN: FileCheck -D#NUMVAL2=8 -check-prefixes NUMNOT -input-file %s %s ; RUN: not FileCheck -D#10VALUE=10 -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NUMERRCLIFMT ; RUN: not FileCheck -D#@VALUE=10 -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NUMERRCLIPSEUDO ; RUN: not FileCheck -D#'VALUE + 2=10' -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NUMERRCLITRAIL -; RUN: not FileCheck -D#VALUE1=3 -D#VALUE2='VALUE1 + 2' -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NUMERRCLIEXPR Value = 10 ; CHECK: Value = [[VALUE]] @@ -58,30 +57,26 @@ ; ERRCLITRAIL-NEXT: {{^ \^$}} Numeric value #2 = 12 -; CHECKNUM: Numeric value #2 = [[#NUMVAL]] -; NUMNOT-NOT: Numeric value #2 = [[#NUMVAL]] +; 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" -; NUMERRCLIFMT: command line:1:4: error: Invalid variable name -; NUMERRCLIFMT-NEXT: -D#10VALUE=10 -; NUMERRCLIFMT-NEXT: {{^ \^$}} +; NUMERRCLIFMT: command line:1:30: error: Invalid variable name +; NUMERRCLIFMT-NEXT: -D#10VALUE=10 (parsed as: {{\[\[#10VALUE:10\]\]}}) +; NUMERRCLIFMT-NEXT: {{^ \^$}} -; NUMERRCLIPSEUDO: command line:1:4: error: Invalid pseudo numeric variable -; NUMERRCLIPSEUDO-NEXT: -D#@VALUE=10 -; NUMERRCLIPSEUDO-NEXT: {{^ \^$}} +; NUMERRCLIPSEUDO: command line:1:29: error: Invalid pseudo numeric variable +; NUMERRCLIPSEUDO-NEXT: -D#@VALUE=10 (parsed as: {{\[\[#@VALUE:10\]\]}}) +; NUMERRCLIPSEUDO-NEXT: {{^ \^$}} -; NUMERRCLITRAIL: command line:1:4: error: Invalid variable name -; NUMERRCLITRAIL-NEXT: -D#VALUE + 2=10 -; NUMERRCLITRAIL-NEXT: {{^ \^$}} - -; NUMERRCLIEXPR: command line:1:11: error: Invalid value in numeric variable definition 'VALUE1 + 2' -; NUMERRCLIEXPR-NEXT: -D#VALUE2=VALUE1 + 2 -; NUMERRCLIEXPR-NEXT: {{^ \^$}} +; NUMERRCLITRAIL: command line:1:38: error: Invalid numeric variable definition +; NUMERRCLITRAIL-NEXT: -D#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 @@ -7,6 +7,7 @@ ; RUN: not FileCheck -check-prefixes CONFLICT,CONFLICT3,CONFLICT4 -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix INPUT-NUM-CONFLICT %s ; RUN: not FileCheck -DPATVAR=foobar -check-prefixes CONFLICT,CONFLICT4 -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix INPUT-NUM-CONFLICT %s ; RUN: not FileCheck -DPATVAR=foobar -D#PATVAR=42 -check-prefix CONFLICT -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix CLI-NUM-CONFLICT %s +; RUN: not FileCheck -check-prefix DEF-EXPR-FAIL -input-file %s %s ; We ensure we attemt to match all lines with digits by using CHECK-NEXT @@ -78,6 +79,22 @@ ; 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 UNDEF VAR USE UNDEFVAR: 11 @@ -118,6 +135,16 @@ ; 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: command line:1:4: error: Pattern variable with name 'PATVAR' already exists +; CLI-NUM-CONFLICT: command line:1:29: error: Pattern variable with name 'PATVAR' already exists ; CLI-NUM-CONFLICT-NEXT: -D#PATVAR=42 -; CLI-NUM-CONFLICT-NEXT: {{^ \^$}} +; CLI-NUM-CONFLICT-NEXT: {{^ \^$}} + + +; Verify that when variable is set to an expression the expression is still +; checked +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]]