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,10 +105,11 @@ 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 ``NUMVAR`` to the result of evaluating - ```` that can be used in ``CHECK:`` lines. See section + Sets a filecheck numeric variable ``NUMVAR`` of matching format ``FMT`` to + the result of evaluating ```` that can be used in + ``CHECK:`` lines. See section ``FileCheck Numeric Variables and Expressions`` for details on supported numeric expressions. @@ -578,22 +579,40 @@ substitution. This allows ``CHECK:`` directives to verify a numeric relation between two numbers, such as the need for consecutive registers to be used. -The syntax to define a numeric variable is ``[[#:]]`` where -```` is the name of the numeric variable to define to the matching -value. +The syntax to define a numeric variable is ``[[#%,:]]`` where: + +* ``%`` is an optional scanf-style matching format specifier to + indicate what number format to match (e.g. hex number). Currently accepted + format specifier are ``%u``, ``%x`` and ``%X``. If absent, the format + specifier defaults to ``%u``. + +* ```` is the name of the numeric variable to define to the matching + value. For example: .. code-block:: llvm - ; CHECK: mov r[[#REG:]], 42 + ; CHECK: mov r[[#REG:]], 0x[[#%X,IMM:]] + +would match ``mov r5, 0xF0F0`` and set ``REG`` to the value ``5`` and ``IMM`` +to the value ``61680``. + +The syntax of a numeric substitution is ``[[#%:]]`` where: + +* ``%`` is the same matching format specifier as for defining numeric + variables but acting as a printf-style format to indicate how a numeric + expression value should be matched against. If absent, the format specifier + is inferred from the matching format of the numeric variable(s) used by the + expression constraint if any and they are all the same, and default to ``%u`` + if no numeric variable is used. In case of conflict between matching formats + of several numeric variables the format specifier is mandatory. -would match ``mov r5, 42`` and set ``REG`` to the value ``5``. +* ``>`` is a numeric expression whose operands are either previously + defined numeric variables or integer immediates. Currently supported + numeric operations are ``+`` and ``-``. A single numeric variable or + integer literal is also accepted. -The syntax of a numeric substitution is ``[[#]]`` where ``>`` is a -numeric expression whose operands are either previously defined numeric -variables or integer literals. Currently supported numeric operations are -``+`` and ``-``. A single numeric variable or integer literal is also accepted. Spaces are accepted before, after and between the operands. For example: @@ -602,6 +621,7 @@ ; CHECK: load r[[#REG:]], [r0] ; CHECK: load r[[#REG+1]], [r1] + ; CHECK: Loading from 0x[[#%x,ADDR:] to 0x[[#ADDR + 7]] The above example would match the text: @@ -609,6 +629,7 @@ load r5, [r0] load r6, [r1] + Loading from 0xa0463440 to 0xa0463447 but would not match the text: @@ -616,8 +637,10 @@ load r5, [r0] load r7, [r1] + Loading from 0xa0463440 to 0xa0463443 -due to ``7`` being unequal to ``5 + 1``. +Due to ``7`` being unequal to ``5 + 1`` and ``a0463443`` being unequal to +``a0463440 + 7``. 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 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 @@ -40,6 +40,53 @@ // Numeric substitution handling code. //===----------------------------------------------------------------------===// +/// Bitfield representing the format a numeric expression value should be +/// printed into for matching. Used to represent both explicit format +/// specifiers as well as implicit format from using numeric variables. +struct FileCheckNumExprFmt { + /// Value should be printed as hex number. + unsigned Hex : 1; + /// Value should be printed using upper case letters, only used for hex + /// numbers. + unsigned Cap : 1; + + /// When unset, denote absence of format and thus that all of the other + /// fields are to be ignored. Used for implicit format of literals and empty + /// expressions. + unsigned Valid : 1; + + /// If set, there are several conflicting implicit formats in an expression. + unsigned Conflict : 1; + + /// Define format equality: formats are equal if all bits are identical. + bool operator==(const FileCheckNumExprFmt &other); + bool operator!=(const FileCheckNumExprFmt &other) { + return !(*this == other); + } + + /// Return wildcard regexp StringRef to match any value in the format + /// represented by this instance. + StringRef getWildcardRegex() const; + + /// Return the string representation of \p Value in the format represented by + /// this instance. + std::string getMatchingString(uint64_t Value) const; + + /// Return the value corresponding to string representation \p StrVal + /// according to the matching format represented by this instance or nothing + /// if \p StrVal does not correspond to a valid and representable value. + Optional valueFromStringRepr(StringRef StrVal) const; +}; + +/// Initializer for numeric expression without format. +const FileCheckNumExprFmt FmtNone = {0, 0, 0, 0}; +/// Initializer for numeric expression matched as unsigned value. +const FileCheckNumExprFmt FmtUnsigned = {0, 0, 1, 0}; +/// Initializer for numeric expression matched as lower case hex value. +const FileCheckNumExprFmt FmtLowHex = {1, 0, 1, 0}; +/// Initializer for numeric expression matched as capital case hex value. +const FileCheckNumExprFmt FmtCapHex = {1, 1, 1, 0}; + /// Base class representing the AST of a given numeric expression. class FileCheckNumExprAST { public: @@ -48,6 +95,11 @@ /// Evaluates and \returns the value of the expression represented by this /// AST or an error if evaluation fails. virtual Expected eval() const = 0; + + /// \returns implicit format of this AST, FmtConflict if implicit formats of + /// the AST's components conflict and Fmt none if the AST has no implicit + /// format (e.g. AST is made of a single literal). + virtual FileCheckNumExprFmt getImplicitFmt() const = 0; }; /// Class representing a literal in the AST of a numeric expression. @@ -62,6 +114,9 @@ /// \returns the literal's value. Expected eval() const { return Value; } + + /// Return implicit format of this AST, therefore FmtNone. + FileCheckNumExprFmt getImplicitFmt() const { return FmtNone; } }; /// Class to represent an undefined variable error which prints that variable's @@ -88,6 +143,34 @@ } }; +/// Class representing a numeric expression and its matching format. +class FileCheckNumExpr { +private: + /// Pointer to AST of the numeric expression. + std::shared_ptr AST; + + /// Matching format, i.e format (e.g. hex upper case letters) to use for the + /// value when matching it. + FileCheckNumExprFmt Fmt; + +public: + /// Generic constructor for a numeric expression whose equality constraint is + /// represented by \p AST and matching format is \p Fmt. If matching format + /// is unset (ie. no explicit or implicit matching format), set it to default + /// one (unsigned decimal integer). + FileCheckNumExpr(std::shared_ptr AST, + FileCheckNumExprFmt Fmt); + + /// \returns pointer to AST of the numeric expression. Pointer is guaranteed + /// to be valid as long as this object is. + FileCheckNumExprAST *getAST() const { return AST.get(); } + + /// \returns effective format of this numeric expression, ie (i) its explicit + /// format if any, (ii) its implicit format if any or (iii) the default + /// format. + FileCheckNumExprFmt getEffectiveFmt() { return Fmt; } +}; + /// Class representing a numeric variable with a given value in the AST of a /// numeric expression. Each definition of a variable gets its own instance of /// this class. Variable uses share the same instance as their respective @@ -101,7 +184,7 @@ /// 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. - std::shared_ptr NumExprAST; + FileCheckNumExpr *NumExpr; /// Value of numeric variable, if defined, or None otherwise. Optional Value; @@ -114,17 +197,20 @@ /// Constructor for a variable \p Name defined at line \p DefLineNumber to /// the numeric expression represented by NumExpr. FileCheckNumericVariable(size_t DefLineNumber, StringRef Name, - std::shared_ptr NumExprAST) - : Name(Name), NumExprAST(NumExprAST), DefLineNumber(DefLineNumber) {} + FileCheckNumExpr *NumExpr) + : Name(Name), NumExpr(NumExpr), 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), NumExprAST(nullptr), Value(Value), DefLineNumber(0) {} + : Name(Name), NumExpr(nullptr), Value(Value), DefLineNumber(0) {} /// \returns name of this numeric variable. StringRef getName() const { return Name; } + /// \returns numeric expression associated with this numeric variable. + FileCheckNumExpr *getNumExpr() const { return NumExpr; } + /// \returns this variable's value. Expected eval() const; @@ -132,6 +218,9 @@ /// performing the substitutions. bool isMatchTimeKnown() const; + /// \returns implicit format of this numeric variable. + FileCheckNumExprFmt getImplicitFmt() const; + /// Sets value of this numeric variable if not defined. \returns whether the /// variable was already defined. bool setValue(uint64_t Value); @@ -171,6 +260,11 @@ /// \returns an error if a numeric variable used is undefined, or the /// expression value otherwise. Expected eval() const; + + /// \returns implicit format of this AST, FmtConflict if implicit formats of + /// the AST's components conflict and Fmt none if the AST has no implicit + /// format (e.g. AST is made of a single literal). + FileCheckNumExprFmt getImplicitFmt() const; }; class FileCheckPatternContext; @@ -227,14 +321,12 @@ private: /// Pointer to the class representing the numeric expression whose value is /// to be substituted. - std::shared_ptr NumExprAST; + FileCheckNumExpr *NumExpr; public: FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr, - std::shared_ptr NumExprAST, - size_t InsertIdx) - : FileCheckSubstitution(Context, Expr, InsertIdx), - NumExprAST(NumExprAST) {} + FileCheckNumExpr *NumExpr, size_t InsertIdx) + : FileCheckSubstitution(Context, Expr, InsertIdx), NumExpr(NumExpr) {} /// \returns a string containing the result of evaluating the numeric /// expression in this substitution, or an error if evaluation failed. @@ -316,6 +408,11 @@ StringMap> GlobalNumericVariableTable; + /// Vector holding pointers to all parsed numeric expressions. Used to + /// automatically free the numeric expressions once they are guaranteed to no + /// longer be used. + std::vector> NumExprs; + /// Vector holding pointers to all substitutions. Used to automatically free /// them once they are guaranteed to no longer be used. std::vector> Substitutions; @@ -339,6 +436,11 @@ void clearLocalVars(); private: + /// Makes a new numeric expression instance and registers it for destruction + /// when the context is destroyed. + FileCheckNumExpr *makeNumExpr(std::shared_ptr AST, + FileCheckNumExprFmt Fmt); + /// Makes a new string substitution and registers it for destruction when the /// context is destroyed. FileCheckSubstitution *makeStringSubstitution(StringRef VarName, @@ -346,10 +448,9 @@ /// Makes a new numeric substitution and registers it for destruction when /// the context is destroyed. - FileCheckSubstitution * - makeNumericSubstitution(StringRef Expr, - std::shared_ptr NumExprAST, - size_t InsertIdx); + FileCheckSubstitution *makeNumericSubstitution(StringRef Expr, + FileCheckNumExpr *NumExpr, + size_t InsertIdx); }; /// Class to represent a parsing error, holding a diagnostic with location @@ -416,12 +517,12 @@ std::map VariableDefs; /// Structure representing the definition of a numeric variable in a pattern. - /// It holds the pointer to the class representing the numeric variable whose - /// value is being defined and the number of the parenthesis group in - /// RegExStr to capture that value. + /// It holds the pointer to the class instance holding the value and matching + /// format of the numeric variable whose value is being defined and the + /// number of the parenthesis group in RegExStr to capture that value. struct FileCheckNumExprMatch { - /// Pointer to class representing the numeric variable whose value is being - /// defined. + /// Pointer to class instance holding the value and matching format of the + /// numeric variable being defined. FileCheckNumericVariable *DefinedNumericVariable; /// Number of the parenthesis group in RegExStr that captures the value of @@ -474,14 +575,13 @@ /// where 0 indicate the command-line. Parameter \p Legacy indicates whether /// \p Expr should be a legacy numeric substitution block and \p Context /// points to the class instance holding the live string and numeric - /// variables. \returns a pointer to the class instance representing the AST - /// of the numeric expression whose value must be substitued, or an error - /// holding a diagnostic against \p SM if parsing fails. If substitution was + /// variables. \returns a pointer to the class instance representing the + /// numeric expression whose value must be substitued, or an error holding a + /// diagnostic against \p SM if parsing fails. If substitution was /// successful, sets \p DefinedNumericVariable to point to the class /// representing the numeric variable defined in this numeric substitution /// block, or None if this block does not define any variable. - static Expected> - parseNumericSubstitutionBlock( + static Expected parseNumericSubstitutionBlock( StringRef Expr, Optional &DefinedNumericVariable, bool Legacy, size_t LineNumber, FileCheckPatternContext *Context, const SourceMgr &SM); 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,28 +24,72 @@ using namespace llvm; +bool FileCheckNumExprFmt::operator==(const FileCheckNumExprFmt &other) { + return Valid == other.Valid && Hex == other.Hex && Cap == other.Cap; +} + +StringRef FileCheckNumExprFmt::getWildcardRegex() const { + assert(Valid && !Conflict && "Trying to match value with invalid format"); + if (!Hex) + return StringRef("[[:digit:]]+"); + if (Cap) + return StringRef("[[:digit:]A-F]+"); + return StringRef("[[:digit:]a-f]+"); +} + +std::string FileCheckNumExprFmt::getMatchingString(uint64_t Value) const { + assert(Valid && !Conflict && "Trying to match value with invalid format"); + if (Hex) + return utohexstr(Value, !Cap); + return utostr(Value); +} + +Optional +FileCheckNumExprFmt::valueFromStringRepr(StringRef StrVal) const { + unsigned Radix = Hex ? 16 : 10; + uint64_t Value; + + if (StrVal.getAsInteger(Radix, Value)) + return None; + + return Value; +} + +FileCheckNumExpr::FileCheckNumExpr(std::shared_ptr AST, + FileCheckNumExprFmt Fmt) + : AST(AST) { + if (Fmt.Valid) + this->Fmt = Fmt; + else + this->Fmt = FmtUnsigned; +} + Expected FileCheckNumericVariable::eval() const { if (Value) return *Value; - if (NumExprAST == nullptr) + if (NumExpr == nullptr || NumExpr->getAST() == nullptr) return make_error(Name); - return NumExprAST->eval(); + return NumExpr->getAST()->eval(); } bool FileCheckNumericVariable::isMatchTimeKnown() const { if (Value) return true; - return NumExprAST != nullptr; + return NumExpr != nullptr && NumExpr->getAST() != nullptr; +} + +FileCheckNumExprFmt FileCheckNumericVariable::getImplicitFmt() const { + return NumExpr ? NumExpr->getEffectiveFmt() : FmtNone; } bool FileCheckNumericVariable::setValue(uint64_t NewValue) { if (Value) return true; - if (NumExprAST != nullptr) { - Expected EvaluatedValue = NumExprAST->eval(); + if (NumExpr != nullptr && NumExpr->getAST() != nullptr) { + Expected EvaluatedValue = NumExpr->getAST()->eval(); if (!EvaluatedValue || *EvaluatedValue != NewValue) return true; } @@ -57,7 +101,7 @@ if (!Value) return true; Value = None; - NumExprAST = nullptr; + NumExpr = nullptr; return false; } @@ -78,11 +122,25 @@ return EvalBinop(*LeftOp, *RightOp); } +FileCheckNumExprFmt FileCheckASTBinop::getImplicitFmt() const { + FileCheckNumExprFmt LeftFmt = LeftOp->getImplicitFmt(); + FileCheckNumExprFmt RightFmt = RightOp->getImplicitFmt(); + + FileCheckNumExprFmt Fmt = (LeftFmt.Valid) ? LeftFmt : RightFmt; + if (LeftFmt.Valid && RightFmt.Valid && LeftFmt != RightFmt) + Fmt.Conflict = 1; + + return Fmt; +} + Expected FileCheckNumericSubstitution::getResult() const { - Expected EvaluatedValue = NumExprAST->eval(); + assert(NumExpr->getAST() != nullptr && + "Substituting empty numeric expression"); + Expected EvaluatedValue = NumExpr->getAST()->eval(); if (!EvaluatedValue) return EvaluatedValue.takeError(); - return utostr(*EvaluatedValue); + FileCheckNumExprFmt Fmt = NumExpr->getEffectiveFmt(); + return Fmt.getMatchingString(*EvaluatedValue); } Expected FileCheckStringSubstitution::getResult() const { @@ -130,6 +188,13 @@ // FileCheck input canonicalization. StringRef SpaceChars = " \t"; +// Parsing helper function that strips the string in \p SkipStr from S. Returns +// true if string SkipStr was not in s and Optional was false. Returns false +// otherwise. +static bool stripFront(StringRef &S, const StringRef &SkipStr, bool Optional) { + return !S.consume_front(SkipStr) && !Optional; +} + // Parsing helper function that strips the first character in S and returns it. static char popFront(StringRef &S) { char C = S.front(); @@ -216,8 +281,9 @@ if (AO == LegacyLiteral || AO == Any) { // Otherwise, parse it as a literal. + unsigned Radix = (AO == LegacyLiteral) ? 10 : 0; uint64_t LiteralValue; - if (!Expr.consumeInteger(10 /*Radix*/, LiteralValue)) + if (!Expr.consumeInteger(Radix, LiteralValue)) return std::make_shared(LiteralValue); } @@ -275,14 +341,49 @@ return std::make_shared(EvalBinop, LeftOp, RightOp); } -Expected> -FileCheckPattern::parseNumericSubstitutionBlock( +Expected FileCheckPattern::parseNumericSubstitutionBlock( StringRef Expr, Optional &DefinedNumericVariable, bool Legacy, size_t LineNumber, FileCheckPatternContext *Context, const SourceMgr &SM) { std::shared_ptr NumExprAST = nullptr; StringRef DefExpr = StringRef(); DefinedNumericVariable = None; + FileCheckNumExprFmt ExplicitFmt = FmtNone; + + // Parse format specifier. + size_t FmtSpecEnd = Expr.find(','); + if (FmtSpecEnd != StringRef::npos) { + Expr = Expr.ltrim(SpaceChars); + if (stripFront(Expr, "%", false /*Optional*/)) + return FileCheckParseError::get( + SM, Expr, + "invalid matching format specification in numeric expression"); + + // Check for unknown matching format specifier and set matching format in + // class instance representing this numeric expression. + SMLoc fmtloc = SMLoc::getFromPointer(Expr.data()); + switch (popFront(Expr)) { + case 'u': + ExplicitFmt = FmtUnsigned; + break; + case 'x': + ExplicitFmt = FmtLowHex; + break; + case 'X': + ExplicitFmt = FmtCapHex; + break; + default: + return FileCheckParseError::get( + SM, fmtloc, "invalid format specifier in numeric expression"); + } + + Expr = Expr.ltrim(SpaceChars); + if (stripFront(Expr, ",", false /*Optional*/)) + return FileCheckParseError::get( + SM, Expr, + "invalid matching format specification in numeric expression"); + } + // Save variable definition expression if any. size_t DefEnd = Expr.find(':'); if (DefEnd != StringRef::npos) { @@ -292,6 +393,7 @@ // Parse the numeric expression itself. Expr = Expr.ltrim(SpaceChars); + StringRef UseExpr = Expr; if (!Expr.empty()) { // First operand in legacy numeric expression is the @LINE pseudo variable. AllowedOperand AO = Legacy ? LegacyVar : Any; @@ -308,10 +410,25 @@ "'"); } if (!ParseResult) - return ParseResult; + return ParseResult.takeError(); NumExprAST = *ParseResult; } + FileCheckNumExprFmt Fmt, + ImplicitFmt = NumExprAST ? NumExprAST->getImplicitFmt() : FmtNone; + // Select explicit matching format if any, implicit one otherwise. Error out + // in case of conflicting implicit format without explicit format. + if (ExplicitFmt.Valid) + Fmt = ExplicitFmt; + else if (ImplicitFmt.Conflict) + return FileCheckParseError::get( + SM, UseExpr, + "variables with conflicting format specifier: need an explicit one"); + else + Fmt = ImplicitFmt; + + FileCheckNumExpr *NumExpr = Context->makeNumExpr(NumExprAST, Fmt); + // Parse the numeric variable definition. if (DefEnd != StringRef::npos) { DefExpr = DefExpr.ltrim(SpaceChars); @@ -327,10 +444,10 @@ "invalid numeric variable definition"); DefinedNumericVariable = - new FileCheckNumericVariable(LineNumber, Name, NumExprAST); + new FileCheckNumericVariable(LineNumber, Name, NumExpr); } - return NumExprAST; + return NumExpr; } bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix, @@ -509,25 +626,27 @@ } // Parse numeric substitution block. - std::shared_ptr NumExprAST; + FileCheckNumExpr *NumExpr; Optional DefinedNumericVariable; if (IsNumBlock) { - Expected> ParseResult = + Expected ParseResult = parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, Legacy, LineNumber, Context, SM); if (!ParseResult) { logAllUnhandledErrors(ParseResult.takeError(), errs()); return true; } - NumExprAST = *ParseResult; + NumExpr = *ParseResult; IsDefinition = static_cast(DefinedNumericVariable); - SubstNeeded = NumExprAST != nullptr; + SubstNeeded = NumExpr->getAST() != nullptr; if (IsDefinition) DefName = (*DefinedNumericVariable)->getName(); if (SubstNeeded) SubstStr = MatchStr; - else - MatchRegexp = StringRef("[0-9]+"); + else { + FileCheckNumExprFmt Fmt = NumExpr->getEffectiveFmt(); + MatchRegexp = Fmt.getWildcardRegex(); + } } // Handle variable definition: [[:(...)]] and [[#(...):(...)]]. @@ -586,7 +705,7 @@ // previous CHECK patterns, and substitution of numeric expressions. FileCheckSubstitution *Substitution = IsNumBlock - ? Context->makeNumericSubstitution(SubstStr, NumExprAST, + ? Context->makeNumericSubstitution(SubstStr, NumExpr, SubstInsertIdx) : Context->makeStringSubstitution(SubstStr, SubstInsertIdx); Substitutions.push_back(Substitution); @@ -704,12 +823,15 @@ NumericVariableMatch.DefinedNumericVariable; StringRef MatchedValue = MatchInfo[CaptureParenGroup]; - uint64_t Val; - if (MatchedValue.getAsInteger(10, Val)) { + assert(DefinedNumericVariable->getNumExpr() != nullptr); + FileCheckNumExprFmt Fmt = + DefinedNumericVariable->getNumExpr()->getEffectiveFmt(); + Optional Value = Fmt.valueFromStringRepr(MatchedValue); + if (!Value) { SM.PrintMessage(SMLoc::getFromPointer(MatchedValue.data()), SourceMgr::DK_Error, "Unable to represent numeric value"); } - if (DefinedNumericVariable->setValue(Val)) + if (DefinedNumericVariable->setValue(*Value)) assert(false && "Numeric variable redefined"); } @@ -854,6 +976,13 @@ return VarIter->second; } +FileCheckNumExpr * +FileCheckPatternContext::makeNumExpr(std::shared_ptr AST, + FileCheckNumExprFmt Fmt) { + NumExprs.push_back(llvm::make_unique(AST, Fmt)); + return NumExprs.back().get(); +} + FileCheckSubstitution * FileCheckPatternContext::makeStringSubstitution(StringRef VarName, size_t InsertIdx) { @@ -863,10 +992,9 @@ } FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution( - StringRef Expr, std::shared_ptr NumExprAST, - size_t InsertIdx) { + StringRef Expr, FileCheckNumExpr *NumExpr, size_t InsertIdx) { Substitutions.push_back(llvm::make_unique( - this, Expr, NumExprAST, InsertIdx)); + this, Expr, NumExpr, InsertIdx)); return Substitutions.back().get(); } @@ -1814,15 +1942,15 @@ // class instance. StringRef CmdlineDefExpr = CmdlineDef.substr(1); Optional DefinedNumericVariable; - Expected> NumExprASTResult = + Expected NumExprResult = FileCheckPattern::parseNumericSubstitutionBlock( CmdlineDefExpr, DefinedNumericVariable, false, 0, this, SM); - if (!NumExprASTResult) { - Errs = joinErrors(std::move(Errs), NumExprASTResult.takeError()); + if (!NumExprResult) { + Errs = joinErrors(std::move(Errs), NumExprResult.takeError()); continue; } - std::shared_ptr NumExprAST = *NumExprASTResult; - Expected Value = NumExprAST->eval(); + FileCheckNumExpr *NumExpr = *NumExprResult; + Expected Value = NumExpr->getAST()->eval(); if (!Value) { Errs = joinErrors( std::move(Errs), diff --git a/llvm/test/FileCheck/line-count.txt b/llvm/test/FileCheck/line-count.txt --- a/llvm/test/FileCheck/line-count.txt +++ b/llvm/test/FileCheck/line-count.txt @@ -10,57 +10,61 @@ ; RUN: not FileCheck -check-prefix BAD9 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR9 %s ; RUN: not FileCheck -check-prefix BAD10 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR10 %s ; RUN: not FileCheck -check-prefix BAD11 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR11 %s -13 -14 aaa -15 bbb -16 ccc -17 CHECK: [[@LINE-3]] {{a}}aa -18 CHECK: [[@LINE-3]] {{b}}bb -19 CHECK: [[@LINE-3]] {{c}}cc -20 foobar -21 CHECK: [[@LINE-1]] {{foo}}bar -22 -23 arst CHECK: [[@LINE]] {{a}}rst -24 -25 BAD1: [[@LINE:cant-have-regex]] -26 ERR1: line-count.txt:[[#@LINE-1]]:12: error: invalid name in string variable definition -27 -28 BAD2: [[ @LINE]] -29 ERR2: line-count.txt:[[#@LINE-1]]:12: error: unexpected whitespace -30 -31 BAD3: [[@LINE ]] -32 ERR3: line-count.txt:[[#@LINE-1]]:17: error: unexpected whitespace -33 -34 BAD4: [[ @LINE-1]] -35 ERR4: line-count.txt:[[#@LINE-1]]:12: error: unexpected whitespace -36 -37 BAD5: [[@LINE -1]] -38 ERR5: line-count.txt:[[#@LINE-1]]:17: error: unexpected whitespace -39 -40 BAD6: [[@LINE- 1]] -41 ERR6: line-count.txt:[[#@LINE-1]]:18: error: unexpected whitespace -42 -43 BAD7: [[@LINE-1 ]] -44 ERR7: line-count.txt:[[#@LINE-1]]:19: error: unexpected whitespace -45 -46 BAD8: [[@LIN]] -47 ERR8: line-count.txt:[[#@LINE-1]]:12: error: invalid pseudo numeric variable '@LIN' -48 -49 BAD9: [[@LINE*2]] -50 ERR9: line-count.txt:[[#@LINE-1]]:17: error: unsupported numeric operation '*' -51 -52 BAD10: [[@LINE-x]] -53 ERR10: line-count.txt:[[#@LINE-1]]:19: error: invalid operand format 'x' -54 -55 BAD11: [[@LINE-1x]] -56 ERR11: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of numeric expression 'x' -57 -58 CHECK: [[#@LINE]] CHECK -59 CHECK: [[# @LINE]] CHECK -60 CHECK: [[# @LINE ]] CHECK +; RUN: not FileCheck -check-prefix BAD12 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR12 %s +14 +15 aaa +16 bbb +17 ccc +18 CHECK: [[@LINE-3]] {{a}}aa +19 CHECK: [[@LINE-3]] {{b}}bb +20 CHECK: [[@LINE-3]] {{c}}cc +21 foobar +22 CHECK: [[@LINE-1]] {{foo}}bar +23 +24 arst CHECK: [[@LINE]] {{a}}rst +25 +26 BAD1: [[@LINE:cant-have-regex]] +27 ERR1: line-count.txt:[[#@LINE-1]]:12: error: invalid name in string variable definition +28 +29 BAD2: [[ @LINE]] +30 ERR2: line-count.txt:[[#@LINE-1]]:12: error: unexpected whitespace +31 +32 BAD3: [[@LINE ]] +33 ERR3: line-count.txt:[[#@LINE-1]]:17: error: unexpected whitespace +34 +35 BAD4: [[ @LINE-1]] +36 ERR4: line-count.txt:[[#@LINE-1]]:12: error: unexpected whitespace +37 +38 BAD5: [[@LINE -1]] +39 ERR5: line-count.txt:[[#@LINE-1]]:17: error: unexpected whitespace +40 +41 BAD6: [[@LINE- 1]] +42 ERR6: line-count.txt:[[#@LINE-1]]:18: error: unexpected whitespace +43 +44 BAD7: [[@LINE-1 ]] +45 ERR7: line-count.txt:[[#@LINE-1]]:19: error: unexpected whitespace +46 +47 BAD8: [[@LIN]] +48 ERR8: line-count.txt:[[#@LINE-1]]:12: error: invalid pseudo numeric variable '@LIN' +49 +50 BAD9: [[@LINE*2]] +51 ERR9: line-count.txt:[[#@LINE-1]]:17: error: unsupported numeric operation '*' +52 +53 BAD10: [[@LINE-x]] +54 ERR10: line-count.txt:[[#@LINE-1]]:19: error: invalid operand format 'x' +55 +56 BAD11: [[@LINE-1x]] +57 ERR11: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of numeric expression 'x' +58 +59 BAD12: [[@LINE-0xA]] +60 ERR12: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of numeric expression 'xA' 61 -62 CHECK: [[#@LINE-1]] -63 CHECK: [[# @LINE-1]] CHECK -64 CHECK: [[# @LINE -1]] CHECK -65 CHECK: [[# @LINE - 1]] CHECK -66 CHECK: [[# @LINE - 1 ]] CHECK +62 CHECK: [[#@LINE]] CHECK +63 CHECK: [[# @LINE]] CHECK +64 CHECK: [[# @LINE ]] CHECK +65 +66 CHECK: [[#@LINE-1]] +67 CHECK: [[# @LINE-1]] CHECK +68 CHECK: [[# @LINE -1]] CHECK +69 CHECK: [[# @LINE - 1]] CHECK +70 CHECK: [[# @LINE - 1 ]] CHECK diff --git a/llvm/test/FileCheck/numeric-defines-diagnostics.txt b/llvm/test/FileCheck/numeric-defines-diagnostics.txt --- a/llvm/test/FileCheck/numeric-defines-diagnostics.txt +++ b/llvm/test/FileCheck/numeric-defines-diagnostics.txt @@ -1,12 +1,12 @@ ; Test incorrect syntax for -D# option is correctly diagnosed. ; Invalid variable name: starts with a digit. -RUN: not FileCheck -D#10VALUE=10 --input-file %s %s 2>&1 \ -RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIFMT +RUN: not FileCheck -D#10VALUE=10 -input-file %s %s 2>&1 \ +RUN: | FileCheck %s --strict-whitespace -check-prefix NUMERRCLINAME -NUMERRCLIFMT: Global defines:1:46: error: invalid variable name -NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10 (parsed as: {{\[\[#10VALUE:10\]\]}}) -NUMERRCLIFMT-NEXT: {{^ \^$}} +NUMERRCLINAME: Global defines:1:46: error: invalid variable name +NUMERRCLINAME-NEXT: Global define #1: #10VALUE=10 (parsed as: {{\[\[#10VALUE:10\]\]}}) +NUMERRCLINAME-NEXT: {{^ \^$}} ; Invalid definition of pseudo variable. RUN: not FileCheck -D#@VALUE=10 --input-file %s %s 2>&1 \ @@ -23,3 +23,11 @@ NUMERRCLITRAIL: Global defines:1:51: error: invalid numeric variable definition NUMERRCLITRAIL-NEXT: Global define #1: #VALUE+2=10 (parsed as: {{\[\[#VALUE\+2:10\]\]}}) NUMERRCLITRAIL-NEXT: {{^ \^$}} + +; Invalid format for variable. +RUN: not FileCheck -D#,VALUE=10 -input-file %s %s 2>&1 \ +RUN: | FileCheck %s --strict-whitespace -check-prefix NUMERRCLIFMT + +NUMERRCLIFMT: Global defines:1:45: error: invalid matching format specification in numeric expression +NUMERRCLIFMT-NEXT: Global define #1: #,VALUE=10 (parsed as: {{\[\[#,VALUE:10\]\]}}) +NUMERRCLIFMT-NEXT: {{^ \^$}} 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,22 +1,22 @@ ; Test functionality of -D# option: numeric variables are defined to the right ; value and CHECK directives using them match as expected given the value set. -RUN: FileCheck -D#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 -D#%X,NUMVAL1=8 -D#NUMVAL2='NUMVAL1 + 4' -check-prefix CHECKNUM -input-file %s %s +RUN: not FileCheck -D#%X,NUMVAL1=8 -D#NUMVAL2='NUMVAL1+6' -check-prefix CHECKNUM -input-file %s %s 2>&1 \ RUN: | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG -RUN: not FileCheck -D#NUMVAL2=12 -check-prefix NUMNOT -input-file %s %s 2>&1 \ +RUN: not FileCheck -D#%X,NUMVAL1=8 -D#NUMVAL2='NUMVAL1+4' -check-prefix NUMNOT -input-file %s %s 2>&1 \ RUN: | FileCheck %s --strict-whitespace -check-prefix NOT-NUMERRMSG -RUN: FileCheck -D#NUMVAL2=8 -check-prefixes NUMNOT -input-file %s %s +RUN: FileCheck -D#%X,NUMVAL1=8 -D#NUMVAL2='NUMVAL1+6' -check-prefixes NUMNOT -input-file %s %s -Numeric value #2 = 12 +Numeric value #2 = C CHECKNUM: Numeric value #2 = [[#NUMVAL2]] NUMNOT-NOT: Numeric value #2 = [[#NUMVAL2]] NUMERRMSG: defines.txt:[[#@LINE-3]]:11: error: CHECKNUM: expected string not found in input NUMERRMSG: defines.txt:1:1: note: scanning from here -NUMERRMSG: defines.txt:1:1: note: with "NUMVAL2" equal to "8" +NUMERRMSG: defines.txt:1:1: note: with "NUMVAL2" equal to "E" NUMERRMSG: defines.txt:[[#@LINE-7]]:1: note: possible intended match here NOT-NUMERRMSG: defines.txt:[[#@LINE-7]]:13: error: {{NUMNOT}}-NOT: excluded string found in input -NOT-NUMERRMSG: defines.txt:[[#@LINE-10]]:1: note: found here -NOT-NUMERRMSG: defines.txt:[[#@LINE-11]]:1: note: with "NUMVAL2" equal to "12" +NOT-NUMERRMSG: defines.txt:[[#NUMVALLINE:@LINE-10]]:1: note: found here +NOT-NUMERRMSG: defines.txt:[[#NUMVALLINE]]:1: note: with "NUMVAL2" equal to "C" 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 @@ -2,85 +2,210 @@ ; We use CHECK-NEXT directives to force a match on all lines with digits. -; Numeric variable definition without spaces. -DEF NO SPC +; Numeric variable definition with default matching format. +DEF DEFAULT FMT 11 -CHECK-LABEL: DEF NO SPC +CHECK-LABEL: DEF DEFAULT FMT CHECK-NEXT: [[#VAR1:]] -; Numeric variable definition with different spacing. -DEF SPC +; Numeric variable definition with default matching format with different +; spacing. +DEF DEFAULT FMT SPC 11 11 11 -CHECK-LABEL: DEF SPC +CHECK-LABEL: DEF DEFAULT FMT SPC CHECK-NEXT: [[# VAR1a:]] CHECK-NEXT: [[# VAR1b :]] CHECK-NEXT: [[# VAR1c : ]] -; Numeric expressions using variables defined on other lines without spaces. -USE NO SPC +; Numeric variable definition with explicit matching format. +DEF FMT +c +D +CHECK-LABEL: DEF FMT +CHECK-NEXT: [[#%x,VAR2:]] +CHECK-NEXT: [[#%X,VAR3:]] + +; Numeric variable definition with explicit matching format with different +; spacing. +DEF FMT SPC +c +c +c +c +c +CHECK-LABEL: DEF FMT SPC +CHECK-NEXT: [[#%x, VAR2a:]] +CHECK-NEXT: [[# %x, VAR2b:]] +CHECK-NEXT: [[# %x , VAR2c:]] +CHECK-NEXT: [[# %x , VAR2d :]] +CHECK-NEXT: [[# %x , VAR2e : ]] + +; Numeric expressions in explicit matching format and default matching rule using +; variables defined on other lines. +USE DEF FMT IMPL MATCH 11 12 10 +c +d +b +1a +D +E +C +1B 11 11 11 -CHECK-LABEL: USE -CHECK-NEXT: [[#VAR1]] -CHECK-NEXT: [[#VAR1+1]] -CHECK-NEXT: [[#VAR1-1]] -CHECK-NEXT: [[#VAR1a]] -CHECK-NEXT: [[#VAR1b]] -CHECK-NEXT: [[#VAR1c]] +c +c +c +c +c +CHECK-LABEL: USE DEF FMT IMPL MATCH +CHECK-NEXT: [[#%u,VAR1]] +CHECK-NEXT: [[#%u,VAR1+1]] +CHECK-NEXT: [[#%u,VAR1-1]] +CHECK-NEXT: [[#%x,VAR2]] +CHECK-NEXT: [[#%x,VAR2+1]] +CHECK-NEXT: [[#%x,VAR2-1]] +CHECK-NEXT: [[#%x,VAR2+14]] +CHECK-NEXT: [[#%X,VAR3]] +CHECK-NEXT: [[#%X,VAR3+1]] +CHECK-NEXT: [[#%X,VAR3-1]] +CHECK-NEXT: [[#%X,VAR3+14]] +CHECK-NEXT: [[#%u,VAR1a]] +CHECK-NEXT: [[#%u,VAR1b]] +CHECK-NEXT: [[#%u,VAR1c]] +CHECK-NEXT: [[#%x,VAR2a]] +CHECK-NEXT: [[#%x,VAR2b]] +CHECK-NEXT: [[#%x,VAR2c]] +CHECK-NEXT: [[#%x,VAR2d]] +CHECK-NEXT: [[#%x,VAR2e]] -; Numeric expressions using variables defined on other lines with different -; spacing. -USE SPC +; Numeric expressions in explicit matching format and default matching rule using +; variables defined on other lines with different spacing. +USE EXPL FMT IMPL MATCH SPC +11 11 11 12 12 12 12 +12 +12 10 10 10 10 -CHECK-LABEL: USE SPC -CHECK-NEXT: [[# VAR1]] -CHECK-NEXT: [[# VAR1 ]] -CHECK-NEXT: [[# VAR1+1]] -CHECK-NEXT: [[# VAR1 +1]] -CHECK-NEXT: [[# VAR1 + 1]] -CHECK-NEXT: [[# VAR1 + 1 ]] -CHECK-NEXT: [[# VAR1-1]] -CHECK-NEXT: [[# VAR1 -1]] -CHECK-NEXT: [[# VAR1 - 1]] -CHECK-NEXT: [[# VAR1 - 1 ]] +10 +10 +CHECK-LABEL: USE EXPL FMT IMPL MATCH SPC +CHECK-NEXT: [[#%u, VAR1]] +CHECK-NEXT: [[# %u, VAR1]] +CHECK-NEXT: [[# %u, VAR1 ]] +CHECK-NEXT: [[#%u, VAR1+1]] +CHECK-NEXT: [[# %u, VAR1+1]] +CHECK-NEXT: [[# %u , VAR1+1]] +CHECK-NEXT: [[# %u , VAR1 +1]] +CHECK-NEXT: [[# %u , VAR1 + 1]] +CHECK-NEXT: [[# %u , VAR1 + 1 ]] +CHECK-NEXT: [[#%u, VAR1-1]] +CHECK-NEXT: [[# %u, VAR1-1]] +CHECK-NEXT: [[# %u , VAR1-1]] +CHECK-NEXT: [[# %u , VAR1 -1]] +CHECK-NEXT: [[# %u , VAR1 - 1]] +CHECK-NEXT: [[# %u , VAR1 - 1 ]] + +; Numeric expressions in implicit matching format and default matching rule using +; variables defined on other lines +USE IMPL FMT IMPL MATCH +11 +12 +10 +c +d +b +1a +D +E +C +1B +CHECK-LABEL: USE IMPL FMT IMPL MATCH +CHECK-NEXT: [[#VAR1]] +CHECK-NEXT: [[#VAR1+1]] +CHECK-NEXT: [[#VAR1-1]] +CHECK-NEXT: [[#VAR2]] +CHECK-NEXT: [[#VAR2+1]] +CHECK-NEXT: [[#VAR2-1]] +CHECK-NEXT: [[#VAR2+14]] +CHECK-NEXT: [[#VAR3]] +CHECK-NEXT: [[#VAR3+1]] +CHECK-NEXT: [[#VAR3-1]] +CHECK-NEXT: [[#VAR3+14]] + +; Explicit format override implicit format conflicts +VAR USE IMPL OVERRIDE FMT CONFLICT +23 +CHECK-LABEL: VAR USE IMPL OVERRIDE FMT CONFLICT +CHECK-NEXT: [[# %u, VAR1 + VAR2]] ; Numeric expressions using variables defined on the command-line and an ; immediate interpreted as an unsigned value. ; Note: 9223372036854775819 = 0x8000000000000000 + 11 -; 9223372036854775808 = 0x8000000000000000 -USE UNSIGNED IMM +USE IMPL FMT IMPL MATCH UNSIGNED IMM 9223372036854775819 -CHECK-LABEL: USE UNSIGNED IMM -CHECK-NEXT: [[#VAR1+9223372036854775808]] +CHECK-LABEL: USE IMPL FMT IMPL MATCH UNSIGNED IMM +CHECK-NEXT: [[#VAR1+0x8000000000000000]] + +; Numeric expressions with conversion matching format and implicit matching rule +; using variables defined on other lines +USE CONV FMT IMPL MATCH +b +B +12 +13 +CHECK-LABEL: USE CONV FMT IMPL MATCH +CHECK-NEXT: [[# %x, VAR1]] +CHECK-NEXT: [[# %X, VAR1]] +CHECK-NEXT: [[# %u, VAR2]] +CHECK-NEXT: [[# %u, VAR3]] + +; Numeric variable definition with unsupported matching format +RUN: not FileCheck -check-prefixes ERR,INVALID-FMT-SPEC1 -input-file %s %s 2>&1 \ +RUN: | FileCheck -check-prefix INVALID-FMT-SPEC-MSG1 %s +RUN: not FileCheck -check-prefixes ERR,INVALID-FMT-SPEC2 -input-file %s %s 2>&1 \ +RUN: | FileCheck -check-prefix INVALID-FMT-SPEC-MSG2 %s + +DEF INVALID FMT +INVVAR1=a +INVVAR2=11 +ERR-LABEL: DEF INVALID FMT +INVALID-FMT-SPEC1-NEXT: INVVAR1=[[#%c,INVVAR1:]] +INVALID-FMT-SPEC2-NEXT: INVVAR2=[[#%hhd,INVVAR2:]] +INVALID-FMT-SPEC-MSG1: numeric-expression.txt:[[#@LINE-2]]:37: error: invalid format specifier in numeric expression +INVALID-FMT-SPEC-MSG1-NEXT: {{I}}NVALID-FMT-SPEC1-NEXT: INVVAR1={{\[\[#%c,INVVAR1:\]\]}} +INVALID-FMT-SPEC-MSG1-NEXT: {{^ \^$}} +INVALID-FMT-SPEC-MSG2: numeric-expression.txt:[[#@LINE-4]]:37: error: invalid format specifier in numeric expression +INVALID-FMT-SPEC-MSG2-NEXT: {{I}}NVALID-FMT-SPEC2-NEXT: INVVAR2={{\[\[#%hhd,INVVAR2:\]\]}} +INVALID-FMT-SPEC-MSG2-NEXT: {{^ \^$}} ; 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]] +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 +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 \ @@ -153,3 +278,15 @@ DEF-EXPR-FAIL-LABEL: DEF EXPR WRONG MATCH DEF-EXPR-FAIL-NEXT: [[# VAR20:]] DEF-EXPR-FAIL-NEXT: [[# VAR42: VAR20+22]] + +; Conflicting implicit format +RUN: not FileCheck -check-prefixes CHECK,FMT-CONFLICT -input-file %s %s 2>&1 \ +RUN: | FileCheck --strict-whitespace -check-prefix FMT-CONFLICT-MSG %s + +VAR USE IMPL FMT CONFLICT +23 +FMT-CONFLICT-LABEL: VAR USE IMPL FMT CONFLICT +FMT-CONFLICT-NEXT: [[#VAR1 + VAR2]] +FMT-CONFLICT-MSG: numeric-expression.txt:[[#@LINE-1]]:23: error: variables with conflicting format specifier: need an explicit one +FMT-CONFLICT-MSG-NEXT: {{F}}MT-CONFLICT-NEXT: {{\[\[#VAR1 \+ VAR2\]\]}} +FMT-CONFLICT-MSG-NEXT: {{^ \^$}} diff --git a/llvm/test/FileCheck/string-defines-diagnostics.txt b/llvm/test/FileCheck/string-defines-diagnostics.txt --- a/llvm/test/FileCheck/string-defines-diagnostics.txt +++ b/llvm/test/FileCheck/string-defines-diagnostics.txt @@ -25,12 +25,12 @@ ERRCLIVAR2: Missing variable name in command-line definition '-D=' ; Invalid variable name: starts with a digit. -RUN: not FileCheck -D10VALUE=10 --input-file %s %s 2>&1 \ -RUN: | FileCheck %s --strict-whitespace --check-prefix ERRCLIFMT +RUN: not FileCheck -D10VALUE=10 -input-file %s %s 2>&1 \ +RUN: | FileCheck %s --strict-whitespace -check-prefix ERRCLINAME -ERRCLIFMT: Global defines:1:19: error: invalid variable name -ERRCLIFMT-NEXT: Global define #1: 10VALUE=10 -ERRCLIFMT-NEXT: {{^ \^$}} +ERRCLINAME: Global defines:1:19: error: invalid variable name +ERRCLINAME-NEXT: Global define #1: 10VALUE=10 +ERRCLINAME-NEXT: {{^ \^$}} ; Invalid definition of pseudo variable. RUN: not FileCheck -D@VALUE=10 --input-file %s %s 2>&1 \ 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 @@ -44,7 +44,9 @@ // Undefined variable: isMatchTimeKnown returns false, eval and clearValue // fail, error returned by eval holds the name of the undefined variable and // setValue works. - auto FooVar = std::make_shared(1, "FOO", nullptr); + auto NumVarExpr = FileCheckNumExpr(nullptr, FmtUnsigned); + auto FooVar = + std::make_shared(1, "FOO", &NumVarExpr); EXPECT_EQ("FOO", FooVar->getName()); EXPECT_FALSE(FooVar->isMatchTimeKnown()); Expected Value = FooVar->eval(); @@ -68,8 +70,9 @@ // true, eval returns value of expression, and setValue succeeds. auto One = std::make_shared(1); auto Binop = std::make_shared(doAdd, FooVar, One); + auto FoobarExpr = FileCheckNumExpr(Binop, FmtUnsigned); FileCheckNumericVariable FoobarVar = - FileCheckNumericVariable(2, "FOOBAR", Binop); + FileCheckNumericVariable(2, "FOOBAR", &FoobarExpr); EXPECT_TRUE(FoobarVar.isMatchTimeKnown()); Value = FoobarVar.eval(); EXPECT_TRUE(static_cast(Value)); @@ -93,9 +96,12 @@ } TEST_F(FileCheckTest, Binop) { - auto FooVar = std::make_shared(1, "FOO", nullptr); + auto DefNumExpr = FileCheckNumExpr(nullptr, FmtUnsigned); + auto FooVar = + std::make_shared(1, "FOO", &DefNumExpr); FooVar->setValue(42); - auto BarVar = std::make_shared(2, "BAR", nullptr); + auto BarVar = + std::make_shared(2, "BAR", &DefNumExpr); BarVar->setValue(18); FileCheckASTBinop Binop = FileCheckASTBinop(doAdd, FooVar, BarVar); @@ -390,15 +396,18 @@ // Substitutions of defined pseudo and non-pseudo numeric variables return // the right value. + auto DefNumExpr = FileCheckNumExpr(nullptr, FmtUnsigned); auto LineVar = - std::make_shared(1, "@LINE", nullptr); - auto NVar = std::make_shared(1, "N", nullptr); + std::make_shared(1, "@LINE", &DefNumExpr); + auto NVar = std::make_shared(1, "N", &DefNumExpr); LineVar->setValue(42); NVar->setValue(10); + FileCheckNumExpr NumExprLine = FileCheckNumExpr(LineVar, FmtUnsigned); + FileCheckNumExpr NumExprN = FileCheckNumExpr(NVar, FmtUnsigned); FileCheckNumericSubstitution SubstitutionLine = - FileCheckNumericSubstitution(&Context, "@LINE", LineVar, 12); + FileCheckNumericSubstitution(&Context, "@LINE", &NumExprLine, 12); FileCheckNumericSubstitution SubstitutionN = - FileCheckNumericSubstitution(&Context, "N", NVar, 30); + FileCheckNumericSubstitution(&Context, "N", &NumExprN, 30); SubstValue = SubstitutionLine.getResult(); EXPECT_TRUE(static_cast(SubstValue)); EXPECT_EQ("42", *SubstValue); @@ -485,16 +494,15 @@ Expected LocalVar = Cxt.getPatternVarValue(LocalVarStr); FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1); Optional DefinedNumericVariable; - Expected> NumExprAST = - P.parseNumericSubstitutionBlock(LocalNumVarRef, DefinedNumericVariable, - false /*Legacy*/, 1 /*LineNumber*/, &Cxt, - SM); + Expected NumExpr = P.parseNumericSubstitutionBlock( + LocalNumVarRef, DefinedNumericVariable, false /*Legacy*/, + 1 /*LineNumber*/, &Cxt, SM); EXPECT_TRUE(static_cast(LocalVar)); EXPECT_EQ(*LocalVar, "FOO"); Expected EmptyVar = Cxt.getPatternVarValue(EmptyVarStr); Expected UnknownVar = Cxt.getPatternVarValue(UnknownVarStr); - EXPECT_TRUE(static_cast(NumExprAST)); - Expected NumExprVal = (*NumExprAST)->eval(); + EXPECT_TRUE(static_cast(NumExpr)); + Expected NumExprVal = (*NumExpr)->getAST()->eval(); EXPECT_TRUE(static_cast(NumExprVal)); EXPECT_EQ(*NumExprVal, 18U); EXPECT_TRUE(static_cast(EmptyVar)); @@ -509,12 +517,12 @@ // local variables, if it was created before. This is important because local // variable clearing due to --enable-var-scope happens after numeric // expressions are linked to the numeric variables they use. - EXPECT_TRUE(errorToBool((*NumExprAST)->eval().takeError())); + EXPECT_TRUE(errorToBool((*NumExpr)->getAST()->eval().takeError())); P = FileCheckPattern(Check::CheckPlain, &Cxt, 2); - NumExprAST = P.parseNumericSubstitutionBlock( + NumExpr = P.parseNumericSubstitutionBlock( LocalNumVarRef, DefinedNumericVariable, false /*Legacy*/, 2 /*LineNumber*/, &Cxt, SM); - EXPECT_TRUE(errorToBool(NumExprAST.takeError())); + EXPECT_TRUE(errorToBool(NumExpr.takeError())); EmptyVar = Cxt.getPatternVarValue(EmptyVarStr); EXPECT_TRUE(errorToBool(EmptyVar.takeError())); @@ -528,11 +536,11 @@ EXPECT_TRUE(static_cast(GlobalVar)); EXPECT_EQ(*GlobalVar, "BAR"); P = FileCheckPattern(Check::CheckPlain, &Cxt, 3); - NumExprAST = P.parseNumericSubstitutionBlock( + NumExpr = P.parseNumericSubstitutionBlock( GlobalNumVarRef, DefinedNumericVariable, false /*Legacy*/, 3 /*LineNumber*/, &Cxt, SM); - EXPECT_TRUE(static_cast(NumExprAST)); - NumExprVal = (*NumExprAST)->eval(); + EXPECT_TRUE(static_cast(NumExpr)); + NumExprVal = (*NumExpr)->getAST()->eval(); EXPECT_TRUE(static_cast(NumExprVal)); EXPECT_EQ(*NumExprVal, 36U); @@ -540,11 +548,11 @@ Cxt.clearLocalVars(); EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError())); P = FileCheckPattern(Check::CheckPlain, &Cxt, 4); - NumExprAST = P.parseNumericSubstitutionBlock( + NumExpr = P.parseNumericSubstitutionBlock( GlobalNumVarRef, DefinedNumericVariable, false /*Legacy*/, 4 /*LineNumber*/, &Cxt, SM); - EXPECT_TRUE(static_cast(NumExprAST)); - NumExprVal = (*NumExprAST)->eval(); + EXPECT_TRUE(static_cast(NumExpr)); + NumExprVal = (*NumExpr)->getAST()->eval(); EXPECT_TRUE(static_cast(NumExprVal)); EXPECT_EQ(*NumExprVal, 36U); }