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 supported - numeric expressions. + Sets a filecheck numeric variable ``VAR`` 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. .. option:: -version @@ -575,22 +575,38 @@ This allows to capture numeric relations between two numbers in a text to check, such as the need for consecutive registers to be used. -The syntax to define a numeric variable is ``[[#:]]`` where ``NUMVAR`` -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``. + +* ``NUMVAR`` 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, 42`` and set ``REG`` to the value ``5``. +would match ``mov r5, 0xF0F0`` and set ``REG`` to the value ``5`` and ``IMM`` +to the value ``61680``. The syntax to check a numeric expression constraint is -``[[#]]`` where: - -``>`` is a numeric expression whose operands are either numeric - variables previously defined or integer literals. Currently supported +``[[#%:]]`` 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. + +* ``>`` is a numeric expression whose operands are either numeric + variables previously defined or integer immediates. Currently supported numeric operations are ``+`` and ``-``. A single numeric variable or integer literal is also accepted. @@ -599,20 +615,24 @@ .. code-block:: llvm ; CHECK: add r[[#REG:]], r[[#REG]], r[[#REG+1]] + ; CHECK: copying from 0x[[#%x,ADDR:] to 0x[[#ADDR + 8]] The above example would match the lines: .. code-block:: llvm add r5, r5, r6 + copying from 0xa0463440 to 0xa0463448 but would not match the lines: .. code-block:: llvm add r5, r5, r7 + copying from 0xa0463440 to 0xa0463444 -due to ``7`` being unequal to ``5 + 1``. +Due to ``7`` being unequal to ``5 + 1`` and ``a0463444`` being unequal to +``a0463440 + 8``. 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,54 @@ // Numeric expression 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. + llvm::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 +96,11 @@ /// Evaluate the value of the expression represented by this AST. virtual llvm::Optional eval() const = 0; + /// Return 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; + /// Append names of undefined variables used in the expression represented by /// this AST. Must be overriden in any subclass representing an expression /// that can contain a variable. @@ -68,6 +121,9 @@ /// Evaluate the value of the expression represented by this AST. Therefore, /// return the literal's value. llvm::Optional eval() const { return Value; } + + /// Return implicit format of this AST, therefore FmtNone. + FileCheckNumExprFmt getImplicitFmt() const { return FmtNone; } }; /// Class representing a numeric expression and its matching format. @@ -76,14 +132,26 @@ /// 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. - FileCheckNumExpr(std::shared_ptr AST) : AST(AST) {} + /// 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); /// Return 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(); } + + /// Return 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 @@ -139,6 +207,9 @@ /// performing the substitutions. bool isMatchTimeKnown() const; + /// Return implicit format of this numeric variable. + FileCheckNumExprFmt getImplicitFmt() const; + /// Append numeric variable's name to UndefVarNames if undefined. void appendUndefVarNames(std::vector &UndefVarNames) const; @@ -181,6 +252,11 @@ /// evaluating the left and right operands. llvm::Optional eval() const; + /// Return 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; + /// Append names of undefined variables used in any of the operands of this /// binary operation. void appendUndefVarNames(std::vector &UndefVarNames) const; @@ -292,10 +368,11 @@ /// Structure representing the definition of a numeric variable in a pattern. /// It holds the parenthesized capture number and the pointer to the class -/// representing the numeric variable whose value is being defined. +/// instance holding the value and matching format of the numeric variable +/// being defined. 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. std::shared_ptr NumVarDef; /// Parenthesized capture number for this numeric variable definition. 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,61 @@ using namespace llvm; +/// Define format equality: formats are equal if all bits are identical. +bool FileCheckNumExprFmt::operator==(const FileCheckNumExprFmt &other) { + return Valid == other.Valid && Hex == other.Hex && Cap == other.Cap; +} + +/// Return wildcard regexp StringRef to match any value in the format +/// represented by this instance. +StringRef FileCheckNumExprFmt::getWildcardRegex() const { + assert(Valid && !Conflict && "Trying to match value with invalid format"); + if (Hex) { + if (Cap) + return StringRef("[[:digit:]A-F]+"); + else + return StringRef("[[:digit:]a-f]+"); + } else + return StringRef("[[:digit:]]+"); +} + +/// Return the string representation of \p Value in the format represented by +/// this instance. +std::string FileCheckNumExprFmt::getMatchingString(uint64_t Value) const { + assert(Valid && !Conflict && "Trying to match value with invalid format"); + if (Hex) + return utohexstr(Value, !Cap); + else + return utostr(Value); +} + +/// 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. +llvm::Optional +FileCheckNumExprFmt::valueFromStringRepr(StringRef StrVal) const { + unsigned Radix = Hex ? 16 : 10; + uint64_t Value; + + if (StrVal.getAsInteger(Radix, Value)) + return llvm::None; + + return Value; +} + +/// 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::FileCheckNumExpr(std::shared_ptr AST, + FileCheckNumExprFmt Fmt) + : AST(AST) { + if (Fmt.Valid) + this->Fmt = Fmt; + else + this->Fmt = FmtUnsigned; +} + /// Evaluate the value of the expression represented by this AST. Therefore, /// return this variable's value or the value of its associated numeric /// expression if any. @@ -44,6 +99,14 @@ return NumExpr != nullptr && NumExpr->getAST() != nullptr; } +/// Return implicit format of this numeric variable. +FileCheckNumExprFmt FileCheckNumExprVar::getImplicitFmt() const { + if (NumExpr == nullptr) + return FmtNone; + + return NumExpr->getEffectiveFmt(); +} + /// Append numeric variable's name to UndefVarNames if undefined. void FileCheckNumExprVar::appendUndefVarNames( std::vector &UndefVarNames) const { @@ -86,6 +149,20 @@ return EvalBinop(OptOpl.getValue(), OptOpr.getValue()); } +/// Return 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 FileCheckASTBinop::getImplicitFmt() const { + FileCheckNumExprFmt LFmt = Opl->getImplicitFmt(); + FileCheckNumExprFmt RFmt = Opr->getImplicitFmt(); + + FileCheckNumExprFmt Fmt = (LFmt.Valid) ? LFmt : RFmt; + if (LFmt.Valid && RFmt.Valid && LFmt != RFmt) + Fmt.Conflict = 1; + + return Fmt; +} + /// Append names of undefined variables used in any of the operands of this /// binary operation. void FileCheckASTBinop::appendUndefVarNames( @@ -106,7 +183,8 @@ llvm::Optional EvaluatedValue = NumExpr->getAST()->eval(); if (!EvaluatedValue.hasValue()) return llvm::None; - return utostr(EvaluatedValue.getValue()); + FileCheckNumExprFmt Fmt = NumExpr->getEffectiveFmt(); + return Fmt.getMatchingString(EvaluatedValue.getValue()); } else { // Look up the value and escape it so that we can put it into the // regex. @@ -174,6 +252,15 @@ /// Parsing helper function that strips all leading whitespace from \p s. static inline void skipWhitespace(StringRef &s) { s = s.ltrim(" \t"); } +/// Parsing helper function that strips the string in \p SkipStr from \p s. +/// Returns true if string \p SkipStr was not in \p s and \p Optional was +/// false. Returns false otherwise. +static bool Skip(StringRef &s, const StringRef &SkipStr, bool Optional) { + if (!s.consume_front(SkipStr) && !Optional) + return true; + return false; +} + /// Parsing helper function that strips the first character in \p s and returns /// it. static char next(StringRef &s) { @@ -275,8 +362,9 @@ // Otherwise, parse it as a literal. if (AO != LegacyLiteral && AO != Any) return nullptr; + unsigned Radix = (AO == LegacyLiteral) ? 10 : 0; uint64_t LiteralValue; - if (Expr.consumeInteger(10, LiteralValue)) + if (Expr.consumeInteger(Radix, LiteralValue)) return nullptr; return std::make_shared(LiteralValue); } @@ -354,6 +442,46 @@ bool Legacy, const SourceMgr &SM) const { std::shared_ptr NumExprAST; StringRef DefExpr = StringRef(); + FileCheckNumExprFmt ExplicitFmt = FmtNone; + + // Parse format specifier. + size_t FmtSpecEnd = Expr.find(','); + if (FmtSpecEnd != StringRef::npos) { + skipWhitespace(Expr); + if (Skip(Expr, "%", false /*Optional*/)) { + SM.PrintMessage( + SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error, + "Invalid matching format specification in numeric expression"); + return nullptr; + } + + // Check for unknown matching format specifier and set matching format in + // class instance representing this numeric expression. + SMLoc fmtloc = SMLoc::getFromPointer(Expr.data()); + switch (next(Expr)) { + case 'u': + ExplicitFmt = FmtUnsigned; + break; + case 'x': + ExplicitFmt = FmtLowHex; + break; + case 'X': + ExplicitFmt = FmtCapHex; + break; + default: + SM.PrintMessage(fmtloc, SourceMgr::DK_Error, + "Invalid format specifier in numeric expression"); + return nullptr; + } + + skipWhitespace(Expr); + if (Skip(Expr, ",", false /*Optional*/)) { + SM.PrintMessage( + SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error, + "Invalid matching format specification in numeric expression"); + return nullptr; + } + } NumVarDef.reset(); // Save variable definition expression if any. @@ -365,6 +493,7 @@ // Parse numeric expression itself. skipWhitespace(Expr); + StringRef UseExpr = Expr; if (!Expr.empty()) { // First operand in legacy numeric expression is the @LINE pseudo variable. enum AllowedOperand AO = Legacy ? LegacyVar : Any; @@ -386,7 +515,21 @@ } } - auto NumExpr = std::make_shared(NumExprAST); + 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) { + SM.PrintMessage( + SMLoc::getFromPointer(UseExpr.data()), SourceMgr::DK_Error, + "Variables with conflicting format specifier: need an explicit one"); + return nullptr; + } else + Fmt = ImplicitFmt; + + auto NumExpr = std::make_shared(NumExprAST, Fmt); // Parse numeric variable definition. if (!DefExpr.empty()) { @@ -604,8 +747,10 @@ DefName = NumVarDef->getName(); if (SubstNeeded) SubstStr = MatchStr; - else - MatchRegexp = StringRef("[0-9]+"); + else { + FileCheckNumExprFmt Fmt = NumExpr->getEffectiveFmt(); + MatchRegexp = Fmt.getWildcardRegex(); + } } // Handle variable definition: [[:(...)]] and [[#(...):(...)]]. @@ -784,12 +929,14 @@ NumericVariableDef.second.NumVarDef; StringRef MatchedValue = MatchInfo[CaptureParen]; - uint64_t Val; - if (MatchedValue.getAsInteger(10, Val)) { + assert(NumVarDef->getNumExpr() != nullptr); + FileCheckNumExprFmt Fmt = NumVarDef->getNumExpr()->getEffectiveFmt(); + llvm::Optional OptValue = Fmt.valueFromStringRepr(MatchedValue); + if (!OptValue.hasValue()) { SM.PrintMessage(SMLoc::getFromPointer(MatchedValue.data()), SourceMgr::DK_Error, "Unable to represent numeric value"); } - if (NumVarDef->setValue(Val)) + if (NumVarDef->setValue(OptValue.getValue())) assert(false && "Numeric variable redefined"); } 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 @@ -8,17 +8,17 @@ ; RUN: not FileCheck -D= -input-file %s %s 2>&1 | FileCheck %s -check-prefix ERRCLIVAR2 ; RUN: FileCheck -DVALUE= -check-prefix EMPTY -input-file %s %s 2>&1 -; RUN: not FileCheck -D10VALUE=10 -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix ERRCLIFMT +; RUN: not FileCheck -D10VALUE=10 -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix ERRCLINAME ; 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#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: 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 | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG +; RUN: not FileCheck -D#%X,NUMVAL1=8 -D#NUMVAL2=NUMVAL1+4 -check-prefix NUMNOT -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NOT-NUMERRMSG +; RUN: FileCheck -D#%X,NUMVAL1=8 -D#NUMVAL2=NUMVAL1+6 -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 NUMERRCLINAME ; 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#,VALUE=10 -input-file %s %s 2>&1 | FileCheck %s --strict-whitespace -check-prefix NUMERRCLIFMT Value = 10 ; CHECK: Value = [[VALUE]] @@ -44,9 +44,9 @@ Empty value = @@ ; EMPTY: Empty value = @[[VALUE]]@ -; ERRCLIFMT: command line:1:3: error: Invalid name in pattern variable definition '10VALUE' -; ERRCLIFMT-NEXT: -D10VALUE=10 -; ERRCLIFMT-NEXT: {{^ \^$}} +; ERRCLINAME: command line:1:3: error: Invalid name in pattern variable definition '10VALUE' +; ERRCLINAME-NEXT: -D10VALUE=10 +; ERRCLINAME-NEXT: {{^ \^$}} ; ERRCLIPSEUDO: command line:1:3: error: Invalid name in pattern variable definition '@VALUE' ; ERRCLIPSEUDO-NEXT: -D@VALUE=10 @@ -56,22 +56,22 @@ ; ERRCLITRAIL-NEXT: -DVALUE + 2=10 ; ERRCLITRAIL-NEXT: {{^ \^$}} -Numeric value #2 = 12 +Numeric value #2 = C ; 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 "NUMVAL2" equal to "8" +; NUMERRMSG: defines.txt:1:1: note: with numeric expression "NUMVAL2" equal to "E" ; 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 "NUMVAL2" equal to "12" +; NOT-NUMERRMSG: defines.txt:[[#NUMVALLINE:@LINE-10]]:1: note: found here +; NOT-NUMERRMSG: defines.txt:[[#NUMVALLINE]]:1: note: with numeric expression "NUMVAL2" equal to "C" -; NUMERRCLIFMT: command line:1:30: error: Invalid variable name -; NUMERRCLIFMT-NEXT: -D#10VALUE=10 (parsed as: {{\[\[#10VALUE:10\]\]}}) -; NUMERRCLIFMT-NEXT: {{^ \^$}} +; NUMERRCLINAME: command line:1:30: error: Invalid variable name +; NUMERRCLINAME-NEXT: -D#10VALUE=10 (parsed as: {{\[\[#10VALUE:10\]\]}}) +; NUMERRCLINAME-NEXT: {{^ \^$}} ; NUMERRCLIPSEUDO: command line:1:29: error: Invalid pseudo numeric variable ; NUMERRCLIPSEUDO-NEXT: -D#@VALUE=10 (parsed as: {{\[\[#@VALUE:10\]\]}}) @@ -80,3 +80,7 @@ ; NUMERRCLITRAIL: command line:1:38: error: Invalid numeric variable definition ; NUMERRCLITRAIL-NEXT: -D#VALUE + 2=10 (parsed as: {{\[\[#VALUE \+ 2:10\]\]}}) ; NUMERRCLITRAIL-NEXT: {{^ \^$}} + +; NUMERRCLIFMT: command line:1:29: error: Invalid matching format specification in numeric expression +; NUMERRCLIFMT-NEXT: -D#,VALUE=10 (parsed as: {{\[\[#,VALUE:10\]\]}}) +; NUMERRCLIFMT-NEXT: {{^ \^$}} 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 BAD10 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR10 %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 pattern 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]]:19: 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 pattern 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]]:19: 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-expression.txt b/llvm/test/FileCheck/numeric-expression.txt --- a/llvm/test/FileCheck/numeric-expression.txt +++ b/llvm/test/FileCheck/numeric-expression.txt @@ -1,4 +1,6 @@ ; RUN: FileCheck -input-file %s %s +; RUN: not FileCheck -check-prefixes ERR,INVALID-FMT-SPEC1 -input-file %s %s 2>&1 | FileCheck -check-prefix INVALID-FMT-SPEC-MSG1 %s +; RUN: not FileCheck -check-prefixes ERR,INVALID-FMT-SPEC2 -input-file %s %s 2>&1 | FileCheck -check-prefix INVALID-FMT-SPEC-MSG2 %s ; RUN: not FileCheck -check-prefix UNDEF-USE -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix UNDEF-USE-MSG %s ; RUN: not FileCheck -check-prefixes CHECK,INVAL-OP -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix INVAL-OP-MSG %s ; RUN: not FileCheck -check-prefixes CONFLICT,CONFLICT1,CONFLICT2 -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix INPUT-PAT-CONFLICT %s @@ -8,75 +10,189 @@ ; 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 +; RUN: not FileCheck -check-prefixes CHECK,FMT-CONFLICT -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix FMT-CONFLICT-MSG %s ; We ensure we attemt to match all lines with digits by using CHECK-NEXT ; directives for the checks to ensure each line of input is covered. -; 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 in alternate spacing -DEF ALT SPC +;; Numeric variable definition with default matching format in alternate spacing +DEF DEFAULT FMT ALT SPC 11 11 11 -; CHECK-LABEL: DEF ALT SPC +; CHECK-LABEL: DEF DEFAULT FMT ALT 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 in alternate spacing +DEF FMT ALT SPC +c +c +c +c +c +; CHECK-LABEL: DEF FMT ALT 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 -; CHECK-LABEL: USE -; CHECK-NEXT: [[#VAR1]] -; CHECK-NEXT: [[#VAR1+1]] -; CHECK-NEXT: [[#VAR1-1]] +c +d +b +1a +D +E +C +1B +; 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]] -; Numeric expressions using variables defined on other lines in alternate -; spacing -USE ALT SPC +; Numeric expressions in explicit matching format and default matching rule using +; variables defined on other lines in alternate spacing +USE EXPL FMT IMPL MATCH ALT SPC +11 11 11 12 12 12 12 +12 +12 +10 +10 10 10 10 10 -; CHECK-LABEL: USE ALT 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 ]] +; CHECK-LABEL: USE EXPL FMT IMPL MATCH ALT 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 +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]]:39: 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]]:39: 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 @@ -148,3 +264,13 @@ ; DEF-EXPR-FAIL-LABEL: DEF EXPR WRONG MATCH ; DEF-EXPR-FAIL-NEXT: [[# VAR20:]] ; DEF-EXPR-FAIL-NEXT: [[# VAR42: VAR20+22]] + + +; Conflicting implicit format +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]]:25: error: Variables with conflicting format specifier: need an explicit one +; FMT-CONFLICT-MSG-NEXT: {{F}}MT-CONFLICT-NEXT: {{\[\[#VAR1 \+ VAR2\]\]}} +; FMT-CONFLICT-MSG-NEXT: {{^ \^$}}