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 @@ -608,7 +608,8 @@ would match ``mov r5, 0xF0F0`` and set ``REG`` to the value ``5`` and ``IMM`` to the value ``0xF0F0``. -The syntax of a numeric substitution is ``[[#%,]]`` where: +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 @@ -618,6 +619,12 @@ used. In case of conflict between matching formats of several numeric variables the format specifier is mandatory. +* ```` is the matching constraint describing how the value to match + must relate to the value of the numeric expression. The only currently + accepted constraint is ``==`` for an exact match and is the default if + ```` is not provided. No matching constraint must be specified + when the ```` is empty. + * ```` is an expression. An expression is in turn recursively defined as: @@ -666,10 +673,11 @@ to check that a value is synthesized rather than moved around. A numeric variable can also be defined to the result of a numeric expression, -in which case the numeric expression 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 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. The ``--enable-var-scope`` option has the same effect on numeric variables as on string variables. 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 @@ -275,6 +275,13 @@ // FileCheck input canonicalization. constexpr StringLiteral SpaceChars = " \t"; +// Parsing helper function that strips the string in 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(); @@ -457,7 +464,7 @@ size_t FormatSpecEnd = Expr.find(','); if (FormatSpecEnd != StringRef::npos) { Expr = Expr.ltrim(SpaceChars); - if (!Expr.consume_front("%")) + if (stripFront(Expr, "%", /*Optional=*/false)) return FileCheckErrorDiagnostic::get( SM, Expr, "invalid matching format specification in expression"); @@ -483,7 +490,7 @@ } Expr = Expr.ltrim(SpaceChars); - if (!Expr.consume_front(",")) + if (stripFront(Expr, ",", /*Optional=*/false)) return FileCheckErrorDiagnostic::get( SM, Expr, "invalid matching format specification in expression"); } @@ -495,10 +502,19 @@ Expr = Expr.substr(DefEnd + 1); } + // Parse matching constraint. + Expr = Expr.ltrim(SpaceChars); + StringRef ConstraintExpr = Expr; + if (stripFront(Expr, "==", /*Optional=*/true)) + return FileCheckErrorDiagnostic::get(SM, Expr, "invalid matching constraint"); + // Parse the expression itself. Expr = Expr.ltrim(SpaceChars); StringRef UseExpr = Expr; - if (!Expr.empty()) { + if (Expr.empty()) { + if (Expr.size() != ConstraintExpr.size()) + return FileCheckErrorDiagnostic::get(SM, Expr, "Empty numeric expression should not have a matching constraint"); + } else { // The first operand in a legacy @LINE expression is always the @LINE // pseudo variable. AllowedOperand AO = 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 @@ -177,6 +177,15 @@ CHECK-LABEL: USE IMPL FMT IMPL MATCH UNSIGNED IMM CHECK-NEXT: [[#VAR1+0x8000000000000000]] +; Numeric expressions in default matching format and explicit matching rule using +; variables defined on other lines +USE DEF FMT EXPL MATCH +11 +11 +; CHECK-LABEL: USE DEF FMT EXPL MATCH +; CHECK-NEXT: [[#==VAR1]] +; CHECK-NEXT: [[# == VAR1]] + ; Numeric expressions with matching format using variables defined on other ; lines. USE CONV FMT IMPL MATCH @@ -421,3 +430,27 @@ UNDERFLOW-MSG: numeric-expression.txt:[[#@LINE-1]]:29: error: Unable to substitute variable or numeric expression UNDERFLOW-MSG-NEXT: {{U}}NDERFLOW-NEXT: TINYVAR: {{\[\[#%d,TINYVAR:-0x8000000000000000-0x8000000000000000\]\]}} UNDERFLOW-MSG-NEXT: {{^}} ^{{$}} + +; Empty numeric expression with matching constraint. +RUN: not FileCheck --check-prefix EMPTY-NUMEXPR-CONSTRAINT --input-file %s %s 2>&1 \ +RUN: | FileCheck --check-prefix EMPTY-NUMEXPR-CONSTRAINT-MSG --strict-whitespace %s + +EMPTY NUMEXPR USE WITH CONSTRAINT +18 +EMPTY-NUMEXPR-CONSTRAINT-LABEL: EMPTY NUMEXPR USE WITH CONSTRAINT +EMPTY-NUMEXPR-CONSTRAINT-NEXT: [[# ==]] +EMPTY-NUMEXPR-CONSTRAINT-MSG: numeric-expression.txt:[[#@LINE-1]]:38: error: Empty numeric expression should not have a matching constraint +EMPTY-NUMEXPR-CONSTRAINT-MSG-NEXT: {{E}}MPTY-NUMEXPR-CONSTRAINT-NEXT: {{\[\[# ==\]\]}} +EMPTY-NUMEXPR-CONSTRAINT-MSG-NEXT: {{^}} ^{{$}} + +; Empty numeric expression with matching constraint. +RUN: not FileCheck --check-prefix EMPTY-NUMDEF-CONSTRAINT --input-file %s %s 2>&1 \ +RUN: | FileCheck --check-prefix EMPTY-NUMDEF-CONSTRAINT-MSG %s + +EMPTY NUMEXPR DEF WITH CONSTRAINT +18 +EMPTY-NUMDEF-CONSTRAINT-LABEL: EMPTY NUMEXPR CONSTRAINT +EMPTY-NUMDEF-CONSTRAINT-NEXT: [[#VARDEF: ==]] +EMPTY-NUMDEF-CONSTRAINT-MSG: numeric-expression.txt:[[#@LINE-1]]:44: error: Empty numeric expression should not have a matching constraint +EMPTY-NUMDEF-CONSTRAINT-MSG-NEXT: {{E}}MPTY-NUMDEF-CONSTRAINT-NEXT: {{\[\[#VARDEF: ==\]\]}} +EMPTY-NUMDEF-CONSTRAINT-MSG-NEXT: {{^}} ^{{$}}