[FileCheck] Implement --ignore-case option.

The FileCheck utility is enhanced to support a `--ignore-case`
option. This is useful in cases where the output of Unix tools
differs in case (e.g. case not specified by Posix).

Reviewers: Bigcheese, jakehehrlich, rupprecht, espindola, alexshap, jhenderson, MaskRay

Differential Revision: https://reviews.llvm.org/D68146

llvm-svn: 374339
diff --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst
index e8b324d..7d8ecaa 100644
--- a/llvm/docs/CommandGuide/FileCheck.rst
+++ b/llvm/docs/CommandGuide/FileCheck.rst
@@ -1,701 +1,706 @@
-FileCheck - Flexible pattern matching file verifier
-===================================================
-
-.. program:: FileCheck
-
-SYNOPSIS
---------
-
-:program:`FileCheck` *match-filename* [*--check-prefix=XXX*] [*--strict-whitespace*]
-
-DESCRIPTION
------------
-
-:program:`FileCheck` reads two files (one from standard input, and one
-specified on the command line) and uses one to verify the other.  This
-behavior is particularly useful for the testsuite, which wants to verify that
-the output of some tool (e.g. :program:`llc`) contains the expected information
-(for example, a movsd from esp or whatever is interesting).  This is similar to
-using :program:`grep`, but it is optimized for matching multiple different
-inputs in one file in a specific order.
-
-The ``match-filename`` file specifies the file that contains the patterns to
-match.  The file to verify is read from standard input unless the
-:option:`--input-file` option is used.
-
-OPTIONS
--------
-
-Options are parsed from the environment variable ``FILECHECK_OPTS``
-and from the command line.
-
-.. option:: -help
-
- Print a summary of command line options.
-
-.. option:: --check-prefix prefix
-
- FileCheck searches the contents of ``match-filename`` for patterns to
- match.  By default, these patterns are prefixed with "``CHECK:``".
- If you'd like to use a different prefix (e.g. because the same input
- file is checking multiple different tool or options), the
- :option:`--check-prefix` argument allows you to specify one or more
- prefixes to match. Multiple prefixes are useful for tests which might
- change for different run options, but most lines remain the same.
-
-.. option:: --check-prefixes prefix1,prefix2,...
-
- An alias of :option:`--check-prefix` that allows multiple prefixes to be
- specified as a comma separated list.
-
-.. option:: --input-file filename
-
-  File to check (defaults to stdin).
-
-.. option:: --match-full-lines
-
- By default, FileCheck allows matches of anywhere on a line. This
- option will require all positive matches to cover an entire
- line. Leading and trailing whitespace is ignored, unless
- :option:`--strict-whitespace` is also specified. (Note: negative
- matches from ``CHECK-NOT`` are not affected by this option!)
-
- Passing this option is equivalent to inserting ``{{^ *}}`` or
- ``{{^}}`` before, and ``{{ *$}}`` or ``{{$}}`` after every positive
- check pattern.
-
-.. option:: --strict-whitespace
-
- By default, FileCheck canonicalizes input horizontal whitespace (spaces and
- tabs) which causes it to ignore these differences (a space will match a tab).
- The :option:`--strict-whitespace` argument disables this behavior. End-of-line
- sequences are canonicalized to UNIX-style ``\n`` in all modes.
-
-.. option:: --implicit-check-not check-pattern
-
-  Adds implicit negative checks for the specified patterns between positive
-  checks. The option allows writing stricter tests without stuffing them with
-  ``CHECK-NOT``\ s.
-
-  For example, "``--implicit-check-not warning:``" can be useful when testing
-  diagnostic messages from tools that don't have an option similar to ``clang
-  -verify``. With this option FileCheck will verify that input does not contain
-  warnings not covered by any ``CHECK:`` patterns.
-
-.. option:: --dump-input <mode>
-
-  Dump input to stderr, adding annotations representing currently enabled
-  diagnostics.  Do this either 'always', on 'fail', or 'never'.  Specify 'help'
-  to explain the dump format and quit.
-
-.. option:: --dump-input-on-failure
-
-  When the check fails, dump all of the original input.  This option is
-  deprecated in favor of `--dump-input=fail`.
-
-.. option:: --enable-var-scope
-
-  Enables scope for regex variables.
-
-  Variables with names that start with ``$`` are considered global and
-  remain set throughout the file.
-
-  All other variables get undefined after each encountered ``CHECK-LABEL``.
-
-.. option:: -D<VAR=VALUE>
-
-  Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be
-  used in ``CHECK:`` lines.
-
-.. option:: -D#<NUMVAR>=<NUMERIC EXPRESSION>
-
-  Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating
-  ``<NUMERIC EXPRESSION>`` that can be used in ``CHECK:`` lines. See section
-  ``FileCheck Numeric Variables and Expressions`` for details on supported
-  numeric expressions.
-
-.. option:: -version
-
- Show the version number of this program.
-
-.. option:: -v
-
-  Print good directive pattern matches.  However, if ``-input-dump=fail`` or
-  ``-input-dump=always``, add those matches as input annotations instead.
-
-.. option:: -vv
-
-  Print information helpful in diagnosing internal FileCheck issues, such as
-  discarded overlapping ``CHECK-DAG:`` matches, implicit EOF pattern matches,
-  and ``CHECK-NOT:`` patterns that do not have matches.  Implies ``-v``.
-  However, if ``-input-dump=fail`` or ``-input-dump=always``, just add that
-  information as input annotations instead.
-
-.. option:: --allow-deprecated-dag-overlap
-
-  Enable overlapping among matches in a group of consecutive ``CHECK-DAG:``
-  directives.  This option is deprecated and is only provided for convenience
-  as old tests are migrated to the new non-overlapping ``CHECK-DAG:``
-  implementation.
-
-.. option:: --color
-
-  Use colors in output (autodetected by default).
-
-EXIT STATUS
------------
-
-If :program:`FileCheck` verifies that the file matches the expected contents,
-it exits with 0.  Otherwise, if not, or if an error occurs, it will exit with a
-non-zero value.
-
-TUTORIAL
---------
-
-FileCheck is typically used from LLVM regression tests, being invoked on the RUN
-line of the test.  A simple example of using FileCheck from a RUN line looks
-like this:
-
-.. code-block:: llvm
-
-   ; RUN: llvm-as < %s | llc -march=x86-64 | FileCheck %s
-
-This syntax says to pipe the current file ("``%s``") into ``llvm-as``, pipe
-that into ``llc``, then pipe the output of ``llc`` into ``FileCheck``.  This
-means that FileCheck will be verifying its standard input (the llc output)
-against the filename argument specified (the original ``.ll`` file specified by
-"``%s``").  To see how this works, let's look at the rest of the ``.ll`` file
-(after the RUN line):
-
-.. code-block:: llvm
-
-   define void @sub1(i32* %p, i32 %v) {
-   entry:
-   ; CHECK: sub1:
-   ; CHECK: subl
-           %0 = tail call i32 @llvm.atomic.load.sub.i32.p0i32(i32* %p, i32 %v)
-           ret void
-   }
-
-   define void @inc4(i64* %p) {
-   entry:
-   ; CHECK: inc4:
-   ; CHECK: incq
-           %0 = tail call i64 @llvm.atomic.load.add.i64.p0i64(i64* %p, i64 1)
-           ret void
-   }
-
-Here you can see some "``CHECK:``" lines specified in comments.  Now you can
-see how the file is piped into ``llvm-as``, then ``llc``, and the machine code
-output is what we are verifying.  FileCheck checks the machine code output to
-verify that it matches what the "``CHECK:``" lines specify.
-
-The syntax of the "``CHECK:``" lines is very simple: they are fixed strings that
-must occur in order.  FileCheck defaults to ignoring horizontal whitespace
-differences (e.g. a space is allowed to match a tab) but otherwise, the contents
-of the "``CHECK:``" line is required to match some thing in the test file exactly.
-
-One nice thing about FileCheck (compared to grep) is that it allows merging
-test cases together into logical groups.  For example, because the test above
-is checking for the "``sub1:``" and "``inc4:``" labels, it will not match
-unless there is a "``subl``" in between those labels.  If it existed somewhere
-else in the file, that would not count: "``grep subl``" matches if "``subl``"
-exists anywhere in the file.
-
-The FileCheck -check-prefix option
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The FileCheck `-check-prefix` option allows multiple test
-configurations to be driven from one `.ll` file.  This is useful in many
-circumstances, for example, testing different architectural variants with
-:program:`llc`.  Here's a simple example:
-
-.. code-block:: llvm
-
-   ; RUN: llvm-as < %s | llc -mtriple=i686-apple-darwin9 -mattr=sse41 \
-   ; RUN:              | FileCheck %s -check-prefix=X32
-   ; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 -mattr=sse41 \
-   ; RUN:              | FileCheck %s -check-prefix=X64
-
-   define <4 x i32> @pinsrd_1(i32 %s, <4 x i32> %tmp) nounwind {
-           %tmp1 = insertelement <4 x i32>; %tmp, i32 %s, i32 1
-           ret <4 x i32> %tmp1
-   ; X32: pinsrd_1:
-   ; X32:    pinsrd $1, 4(%esp), %xmm0
-
-   ; X64: pinsrd_1:
-   ; X64:    pinsrd $1, %edi, %xmm0
-   }
-
-In this case, we're testing that we get the expected code generation with
-both 32-bit and 64-bit code generation.
-
-The "CHECK-NEXT:" directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Sometimes you want to match lines and would like to verify that matches
-happen on exactly consecutive lines with no other lines in between them.  In
-this case, you can use "``CHECK:``" and "``CHECK-NEXT:``" directives to specify
-this.  If you specified a custom check prefix, just use "``<PREFIX>-NEXT:``".
-For example, something like this works as you'd expect:
-
-.. code-block:: llvm
-
-   define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) {
- 	%tmp3 = load <2 x double>* %A, align 16
- 	%tmp7 = insertelement <2 x double> undef, double %B, i32 0
- 	%tmp9 = shufflevector <2 x double> %tmp3,
-                               <2 x double> %tmp7,
-                               <2 x i32> < i32 0, i32 2 >
- 	store <2 x double> %tmp9, <2 x double>* %r, align 16
- 	ret void
-
-   ; CHECK:          t2:
-   ; CHECK: 	        movl	8(%esp), %eax
-   ; CHECK-NEXT: 	movapd	(%eax), %xmm0
-   ; CHECK-NEXT: 	movhpd	12(%esp), %xmm0
-   ; CHECK-NEXT: 	movl	4(%esp), %eax
-   ; CHECK-NEXT: 	movapd	%xmm0, (%eax)
-   ; CHECK-NEXT: 	ret
-   }
-
-"``CHECK-NEXT:``" directives reject the input unless there is exactly one
-newline between it and the previous directive.  A "``CHECK-NEXT:``" cannot be
-the first directive in a file.
-
-The "CHECK-SAME:" directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Sometimes you want to match lines and would like to verify that matches happen
-on the same line as the previous match.  In this case, you can use "``CHECK:``"
-and "``CHECK-SAME:``" directives to specify this.  If you specified a custom
-check prefix, just use "``<PREFIX>-SAME:``".
-
-"``CHECK-SAME:``" is particularly powerful in conjunction with "``CHECK-NOT:``"
-(described below).
-
-For example, the following works like you'd expect:
-
-.. code-block:: llvm
-
-   !0 = !DILocation(line: 5, scope: !1, inlinedAt: !2)
-
-   ; CHECK:       !DILocation(line: 5,
-   ; CHECK-NOT:               column:
-   ; CHECK-SAME:              scope: ![[SCOPE:[0-9]+]]
-
-"``CHECK-SAME:``" directives reject the input if there are any newlines between
-it and the previous directive.  A "``CHECK-SAME:``" cannot be the first
-directive in a file.
-
-The "CHECK-EMPTY:" directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you need to check that the next line has nothing on it, not even whitespace,
-you can use the "``CHECK-EMPTY:``" directive.
-
-.. code-block:: llvm
-
-   declare void @foo()
-
-   declare void @bar()
-   ; CHECK: foo
-   ; CHECK-EMPTY:
-   ; CHECK-NEXT: bar
-
-Just like "``CHECK-NEXT:``" the directive will fail if there is more than one
-newline before it finds the next blank line, and it cannot be the first
-directive in a file.
-
-The "CHECK-NOT:" directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The "``CHECK-NOT:``" directive is used to verify that a string doesn't occur
-between two matches (or before the first match, or after the last match).  For
-example, to verify that a load is removed by a transformation, a test like this
-can be used:
-
-.. code-block:: llvm
-
-   define i8 @coerce_offset0(i32 %V, i32* %P) {
-     store i32 %V, i32* %P
-
-     %P2 = bitcast i32* %P to i8*
-     %P3 = getelementptr i8* %P2, i32 2
-
-     %A = load i8* %P3
-     ret i8 %A
-   ; CHECK: @coerce_offset0
-   ; CHECK-NOT: load
-   ; CHECK: ret i8
-   }
-
-The "CHECK-COUNT:" directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you need to match multiple lines with the same pattern over and over again
-you can repeat a plain ``CHECK:`` as many times as needed. If that looks too
-boring you can instead use a counted check "``CHECK-COUNT-<num>:``", where
-``<num>`` is a positive decimal number. It will match the pattern exactly
-``<num>`` times, no more and no less. If you specified a custom check prefix,
-just use "``<PREFIX>-COUNT-<num>:``" for the same effect.
-Here is a simple example:
-
-.. code-block:: text
-
-   Loop at depth 1
-   Loop at depth 1
-   Loop at depth 1
-   Loop at depth 1
-     Loop at depth 2
-       Loop at depth 3
-
-   ; CHECK-COUNT-6: Loop at depth {{[0-9]+}}
-   ; CHECK-NOT:     Loop at depth {{[0-9]+}}
-
-The "CHECK-DAG:" directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If it's necessary to match strings that don't occur in a strictly sequential
-order, "``CHECK-DAG:``" could be used to verify them between two matches (or
-before the first match, or after the last match). For example, clang emits
-vtable globals in reverse order. Using ``CHECK-DAG:``, we can keep the checks
-in the natural order:
-
-.. code-block:: c++
-
-    // RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
-
-    struct Foo { virtual void method(); };
-    Foo f;  // emit vtable
-    // CHECK-DAG: @_ZTV3Foo =
-
-    struct Bar { virtual void method(); };
-    Bar b;
-    // CHECK-DAG: @_ZTV3Bar =
-
-``CHECK-NOT:`` directives could be mixed with ``CHECK-DAG:`` directives to
-exclude strings between the surrounding ``CHECK-DAG:`` directives. As a result,
-the surrounding ``CHECK-DAG:`` directives cannot be reordered, i.e. all
-occurrences matching ``CHECK-DAG:`` before ``CHECK-NOT:`` must not fall behind
-occurrences matching ``CHECK-DAG:`` after ``CHECK-NOT:``. For example,
-
-.. code-block:: llvm
-
-   ; CHECK-DAG: BEFORE
-   ; CHECK-NOT: NOT
-   ; CHECK-DAG: AFTER
-
-This case will reject input strings where ``BEFORE`` occurs after ``AFTER``.
-
-With captured variables, ``CHECK-DAG:`` is able to match valid topological
-orderings of a DAG with edges from the definition of a variable to its use.
-It's useful, e.g., when your test cases need to match different output
-sequences from the instruction scheduler. For example,
-
-.. code-block:: llvm
-
-   ; CHECK-DAG: add [[REG1:r[0-9]+]], r1, r2
-   ; CHECK-DAG: add [[REG2:r[0-9]+]], r3, r4
-   ; CHECK:     mul r5, [[REG1]], [[REG2]]
-
-In this case, any order of that two ``add`` instructions will be allowed.
-
-If you are defining `and` using variables in the same ``CHECK-DAG:`` block,
-be aware that the definition rule can match `after` its use.
-
-So, for instance, the code below will pass:
-
-.. code-block:: text
-
-  ; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]
-  ; CHECK-DAG: vmov.32 [[REG2]][1]
-  vmov.32 d0[1]
-  vmov.32 d0[0]
-
-While this other code, will not:
-
-.. code-block:: text
-
-  ; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]
-  ; CHECK-DAG: vmov.32 [[REG2]][1]
-  vmov.32 d1[1]
-  vmov.32 d0[0]
-
-While this can be very useful, it's also dangerous, because in the case of
-register sequence, you must have a strong order (read before write, copy before
-use, etc). If the definition your test is looking for doesn't match (because
-of a bug in the compiler), it may match further away from the use, and mask
-real bugs away.
-
-In those cases, to enforce the order, use a non-DAG directive between DAG-blocks.
-
-A ``CHECK-DAG:`` directive skips matches that overlap the matches of any
-preceding ``CHECK-DAG:`` directives in the same ``CHECK-DAG:`` block.  Not only
-is this non-overlapping behavior consistent with other directives, but it's
-also necessary to handle sets of non-unique strings or patterns.  For example,
-the following directives look for unordered log entries for two tasks in a
-parallel program, such as the OpenMP runtime:
-
-.. code-block:: text
-
-    // CHECK-DAG: [[THREAD_ID:[0-9]+]]: task_begin
-    // CHECK-DAG: [[THREAD_ID]]: task_end
-    //
-    // CHECK-DAG: [[THREAD_ID:[0-9]+]]: task_begin
-    // CHECK-DAG: [[THREAD_ID]]: task_end
-
-The second pair of directives is guaranteed not to match the same log entries
-as the first pair even though the patterns are identical and even if the text
-of the log entries is identical because the thread ID manages to be reused.
-
-The "CHECK-LABEL:" directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Sometimes in a file containing multiple tests divided into logical blocks, one
-or more ``CHECK:`` directives may inadvertently succeed by matching lines in a
-later block. While an error will usually eventually be generated, the check
-flagged as causing the error may not actually bear any relationship to the
-actual source of the problem.
-
-In order to produce better error messages in these cases, the "``CHECK-LABEL:``"
-directive can be used. It is treated identically to a normal ``CHECK``
-directive except that FileCheck makes an additional assumption that a line
-matched by the directive cannot also be matched by any other check present in
-``match-filename``; this is intended to be used for lines containing labels or
-other unique identifiers. Conceptually, the presence of ``CHECK-LABEL`` divides
-the input stream into separate blocks, each of which is processed independently,
-preventing a ``CHECK:`` directive in one block matching a line in another block.
-If ``--enable-var-scope`` is in effect, all local variables are cleared at the
-beginning of the block.
-
-For example,
-
-.. code-block:: llvm
-
-  define %struct.C* @C_ctor_base(%struct.C* %this, i32 %x) {
-  entry:
-  ; CHECK-LABEL: C_ctor_base:
-  ; CHECK: mov [[SAVETHIS:r[0-9]+]], r0
-  ; CHECK: bl A_ctor_base
-  ; CHECK: mov r0, [[SAVETHIS]]
-    %0 = bitcast %struct.C* %this to %struct.A*
-    %call = tail call %struct.A* @A_ctor_base(%struct.A* %0)
-    %1 = bitcast %struct.C* %this to %struct.B*
-    %call2 = tail call %struct.B* @B_ctor_base(%struct.B* %1, i32 %x)
-    ret %struct.C* %this
-  }
-
-  define %struct.D* @D_ctor_base(%struct.D* %this, i32 %x) {
-  entry:
-  ; CHECK-LABEL: D_ctor_base:
-
-The use of ``CHECK-LABEL:`` directives in this case ensures that the three
-``CHECK:`` directives only accept lines corresponding to the body of the
-``@C_ctor_base`` function, even if the patterns match lines found later in
-the file. Furthermore, if one of these three ``CHECK:`` directives fail,
-FileCheck will recover by continuing to the next block, allowing multiple test
-failures to be detected in a single invocation.
-
-There is no requirement that ``CHECK-LABEL:`` directives contain strings that
-correspond to actual syntactic labels in a source or output language: they must
-simply uniquely match a single line in the file being verified.
-
-``CHECK-LABEL:`` directives cannot contain variable definitions or uses.
-
-FileCheck Regex Matching Syntax
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-All FileCheck directives take a pattern to match.
-For most uses of FileCheck, fixed string matching is perfectly sufficient.  For
-some things, a more flexible form of matching is desired.  To support this,
-FileCheck allows you to specify regular expressions in matching strings,
-surrounded by double braces: ``{{yourregex}}``. FileCheck implements a POSIX
-regular expression matcher; it supports Extended POSIX regular expressions
-(ERE). Because we want to use fixed string matching for a majority of what we
-do, FileCheck has been designed to support mixing and matching fixed string
-matching with regular expressions.  This allows you to write things like this:
-
-.. code-block:: llvm
-
-   ; CHECK: movhpd	{{[0-9]+}}(%esp), {{%xmm[0-7]}}
-
-In this case, any offset from the ESP register will be allowed, and any xmm
-register will be allowed.
-
-Because regular expressions are enclosed with double braces, they are
-visually distinct, and you don't need to use escape characters within the double
-braces like you would in C.  In the rare case that you want to match double
-braces explicitly from the input, you can use something ugly like
-``{{[}][}]}}`` as your pattern.  Or if you are using the repetition count
-syntax, for example ``[[:xdigit:]]{8}`` to match exactly 8 hex digits, you
-would need to add parentheses like this ``{{([[:xdigit:]]{8})}}`` to avoid
-confusion with FileCheck's closing double-brace.
-
-FileCheck String Substitution Blocks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It is often useful to match a pattern and then verify that it occurs again
-later in the file.  For codegen tests, this can be useful to allow any
-register, but verify that that register is used consistently later.  To do
-this, :program:`FileCheck` supports string substitution blocks that allow
-string variables to be defined and substituted into patterns.  Here is a simple
-example:
-
-.. code-block:: llvm
-
-   ; CHECK: test5:
-   ; CHECK:    notw	[[REGISTER:%[a-z]+]]
-   ; CHECK:    andw	{{.*}}[[REGISTER]]
-
-The first check line matches a regex ``%[a-z]+`` and captures it into the
-string variable ``REGISTER``.  The second line verifies that whatever is in
-``REGISTER`` occurs later in the file after an "``andw``". :program:`FileCheck`
-string substitution blocks are always contained in ``[[ ]]`` pairs, and string
-variable names can be formed with the regex ``[a-zA-Z_][a-zA-Z0-9_]*``.  If a
-colon follows the name, then it is a definition of the variable; otherwise, it
-is a substitution.
-
-:program:`FileCheck` variables can be defined multiple times, and substitutions
-always get the latest value.  Variables can also be substituted later on the
-same line they were defined on. For example:
-
-.. code-block:: llvm
-
-    ; CHECK: op [[REG:r[0-9]+]], [[REG]]
-
-Can be useful if you want the operands of ``op`` to be the same register,
-and don't care exactly which register it is.
-
-If ``--enable-var-scope`` is in effect, variables with names that
-start with ``$`` are considered to be global. All others variables are
-local.  All local variables get undefined at the beginning of each
-CHECK-LABEL block. Global variables are not affected by CHECK-LABEL.
-This makes it easier to ensure that individual tests are not affected
-by variables set in preceding tests.
-
-FileCheck Numeric Substitution Blocks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-:program:`FileCheck` also supports numeric substitution blocks that allow
-defining numeric variables and checking for numeric values that satisfy a
-numeric expression constraint based on those variables via a numeric
-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 ``[[#<NUMVAR>:]]`` where
-``<NUMVAR>`` is the name of the numeric variable to define to the matching
-value.
-
-For example:
-
-.. code-block:: llvm
-
-    ; CHECK: mov r[[#REG:]], 42
-
-would match ``mov r5, 42`` and set ``REG`` to the value ``5``.
-
-The syntax of a numeric substitution is ``[[#<expr>]]`` where ``<expr>`` is an
-expression. An expression is recursively defined as:
-
-* a numeric operand, or
-* an expression followed by an operator and a numeric operand.
-
-A numeric operand is a previously defined numeric variable, or an integer
-literal. The supported operators are ``+`` and ``-``. Spaces are accepted
-before, after and between any of these elements.
-
-For example:
-
-.. code-block:: llvm
-
-    ; CHECK: load r[[#REG:]], [r0]
-    ; CHECK: load r[[#REG+1]], [r1]
-
-The above example would match the text:
-
-.. code-block:: gas
-
-    load r5, [r0]
-    load r6, [r1]
-
-but would not match the text:
-
-.. code-block:: gas
-
-    load r5, [r0]
-    load r7, [r1]
-
-due to ``7`` being unequal to ``5 + 1``.
-
-The syntax also supports an empty expression, equivalent to writing {{[0-9]+}},
-for cases where the input must contain a numeric value but the value itself
-does not matter:
-
-.. code-block:: gas
-
-    ; CHECK-NOT: mov r0, r[[#]]
-
-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 ``[[#<NUMVAR>: <expr>]]`` with each
-element as described previously.
-
-The ``--enable-var-scope`` option has the same effect on numeric variables as
-on string variables.
-
-Important note: In its current implementation, an expression cannot use a
-numeric variable defined earlier in the same CHECK directive.
-
-FileCheck Pseudo Numeric Variables
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Sometimes there's a need to verify output that contains line numbers of the
-match file, e.g. when testing compiler diagnostics.  This introduces a certain
-fragility of the match file structure, as "``CHECK:``" lines contain absolute
-line numbers in the same file, which have to be updated whenever line numbers
-change due to text addition or deletion.
-
-To support this case, FileCheck expressions understand the ``@LINE`` pseudo
-numeric variable which evaluates to the line number of the CHECK pattern where
-it is found.
-
-This way match patterns can be put near the relevant test lines and include
-relative line number references, for example:
-
-.. code-block:: c++
-
-   // CHECK: test.cpp:[[# @LINE + 4]]:6: error: expected ';' after top level declarator
-   // CHECK-NEXT: {{^int a}}
-   // CHECK-NEXT: {{^     \^}}
-   // CHECK-NEXT: {{^     ;}}
-   int a
-
-To support legacy uses of ``@LINE`` as a special string variable,
-:program:`FileCheck` also accepts the following uses of ``@LINE`` with string
-substitution block syntax: ``[[@LINE]]``, ``[[@LINE+<offset>]]`` and
-``[[@LINE-<offset>]]`` without any spaces inside the brackets and where
-``offset`` is an integer.
-
-Matching Newline Characters
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To match newline characters in regular expressions the character class
-``[[:space:]]`` can be used. For example, the following pattern:
-
-.. code-block:: c++
-
-   // CHECK: DW_AT_location [DW_FORM_sec_offset] ([[DLOC:0x[0-9a-f]+]]){{[[:space:]].*}}"intd"
-
-matches output of the form (from llvm-dwarfdump):
-
-.. code-block:: text
-
-       DW_AT_location [DW_FORM_sec_offset]   (0x00000233)
-       DW_AT_name [DW_FORM_strp]  ( .debug_str[0x000000c9] = "intd")
-
-letting us set the :program:`FileCheck` variable ``DLOC`` to the desired value 
-``0x00000233``, extracted from the line immediately preceding "``intd``".
+FileCheck - Flexible pattern matching file verifier

+===================================================

+

+.. program:: FileCheck

+

+SYNOPSIS

+--------

+

+:program:`FileCheck` *match-filename* [*--check-prefix=XXX*] [*--strict-whitespace*]

+

+DESCRIPTION

+-----------

+

+:program:`FileCheck` reads two files (one from standard input, and one

+specified on the command line) and uses one to verify the other.  This

+behavior is particularly useful for the testsuite, which wants to verify that

+the output of some tool (e.g. :program:`llc`) contains the expected information

+(for example, a movsd from esp or whatever is interesting).  This is similar to

+using :program:`grep`, but it is optimized for matching multiple different

+inputs in one file in a specific order.

+

+The ``match-filename`` file specifies the file that contains the patterns to

+match.  The file to verify is read from standard input unless the

+:option:`--input-file` option is used.

+

+OPTIONS

+-------

+

+Options are parsed from the environment variable ``FILECHECK_OPTS``

+and from the command line.

+

+.. option:: -help

+

+ Print a summary of command line options.

+

+.. option:: --check-prefix prefix

+

+ FileCheck searches the contents of ``match-filename`` for patterns to

+ match.  By default, these patterns are prefixed with "``CHECK:``".

+ If you'd like to use a different prefix (e.g. because the same input

+ file is checking multiple different tool or options), the

+ :option:`--check-prefix` argument allows you to specify one or more

+ prefixes to match. Multiple prefixes are useful for tests which might

+ change for different run options, but most lines remain the same.

+

+.. option:: --check-prefixes prefix1,prefix2,...

+

+ An alias of :option:`--check-prefix` that allows multiple prefixes to be

+ specified as a comma separated list.

+

+.. option:: --input-file filename

+

+  File to check (defaults to stdin).

+

+.. option:: --match-full-lines

+

+ By default, FileCheck allows matches of anywhere on a line. This

+ option will require all positive matches to cover an entire

+ line. Leading and trailing whitespace is ignored, unless

+ :option:`--strict-whitespace` is also specified. (Note: negative

+ matches from ``CHECK-NOT`` are not affected by this option!)

+

+ Passing this option is equivalent to inserting ``{{^ *}}`` or

+ ``{{^}}`` before, and ``{{ *$}}`` or ``{{$}}`` after every positive

+ check pattern.

+

+.. option:: --strict-whitespace

+

+ By default, FileCheck canonicalizes input horizontal whitespace (spaces and

+ tabs) which causes it to ignore these differences (a space will match a tab).

+ The :option:`--strict-whitespace` argument disables this behavior. End-of-line

+ sequences are canonicalized to UNIX-style ``\n`` in all modes.

+

+.. option:: --ignore-case

+

+  By default, FileCheck uses case-sensitive matching. This option causes

+  FileCheck to use case-insensitive matching.

+

+.. option:: --implicit-check-not check-pattern

+

+  Adds implicit negative checks for the specified patterns between positive

+  checks. The option allows writing stricter tests without stuffing them with

+  ``CHECK-NOT``\ s.

+

+  For example, "``--implicit-check-not warning:``" can be useful when testing

+  diagnostic messages from tools that don't have an option similar to ``clang

+  -verify``. With this option FileCheck will verify that input does not contain

+  warnings not covered by any ``CHECK:`` patterns.

+

+.. option:: --dump-input <mode>

+

+  Dump input to stderr, adding annotations representing currently enabled

+  diagnostics.  Do this either 'always', on 'fail', or 'never'.  Specify 'help'

+  to explain the dump format and quit.

+

+.. option:: --dump-input-on-failure

+

+  When the check fails, dump all of the original input.  This option is

+  deprecated in favor of `--dump-input=fail`.

+

+.. option:: --enable-var-scope

+

+  Enables scope for regex variables.

+

+  Variables with names that start with ``$`` are considered global and

+  remain set throughout the file.

+

+  All other variables get undefined after each encountered ``CHECK-LABEL``.

+

+.. option:: -D<VAR=VALUE>

+

+  Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be

+  used in ``CHECK:`` lines.

+

+.. option:: -D#<NUMVAR>=<NUMERIC EXPRESSION>

+

+  Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating

+  ``<NUMERIC EXPRESSION>`` that can be used in ``CHECK:`` lines. See section

+  ``FileCheck Numeric Variables and Expressions`` for details on supported

+  numeric expressions.

+

+.. option:: -version

+

+ Show the version number of this program.

+

+.. option:: -v

+

+  Print good directive pattern matches.  However, if ``-input-dump=fail`` or

+  ``-input-dump=always``, add those matches as input annotations instead.

+

+.. option:: -vv

+

+  Print information helpful in diagnosing internal FileCheck issues, such as

+  discarded overlapping ``CHECK-DAG:`` matches, implicit EOF pattern matches,

+  and ``CHECK-NOT:`` patterns that do not have matches.  Implies ``-v``.

+  However, if ``-input-dump=fail`` or ``-input-dump=always``, just add that

+  information as input annotations instead.

+

+.. option:: --allow-deprecated-dag-overlap

+

+  Enable overlapping among matches in a group of consecutive ``CHECK-DAG:``

+  directives.  This option is deprecated and is only provided for convenience

+  as old tests are migrated to the new non-overlapping ``CHECK-DAG:``

+  implementation.

+

+.. option:: --color

+

+  Use colors in output (autodetected by default).

+

+EXIT STATUS

+-----------

+

+If :program:`FileCheck` verifies that the file matches the expected contents,

+it exits with 0.  Otherwise, if not, or if an error occurs, it will exit with a

+non-zero value.

+

+TUTORIAL

+--------

+

+FileCheck is typically used from LLVM regression tests, being invoked on the RUN

+line of the test.  A simple example of using FileCheck from a RUN line looks

+like this:

+

+.. code-block:: llvm

+

+   ; RUN: llvm-as < %s | llc -march=x86-64 | FileCheck %s

+

+This syntax says to pipe the current file ("``%s``") into ``llvm-as``, pipe

+that into ``llc``, then pipe the output of ``llc`` into ``FileCheck``.  This

+means that FileCheck will be verifying its standard input (the llc output)

+against the filename argument specified (the original ``.ll`` file specified by

+"``%s``").  To see how this works, let's look at the rest of the ``.ll`` file

+(after the RUN line):

+

+.. code-block:: llvm

+

+   define void @sub1(i32* %p, i32 %v) {

+   entry:

+   ; CHECK: sub1:

+   ; CHECK: subl

+           %0 = tail call i32 @llvm.atomic.load.sub.i32.p0i32(i32* %p, i32 %v)

+           ret void

+   }

+

+   define void @inc4(i64* %p) {

+   entry:

+   ; CHECK: inc4:

+   ; CHECK: incq

+           %0 = tail call i64 @llvm.atomic.load.add.i64.p0i64(i64* %p, i64 1)

+           ret void

+   }

+

+Here you can see some "``CHECK:``" lines specified in comments.  Now you can

+see how the file is piped into ``llvm-as``, then ``llc``, and the machine code

+output is what we are verifying.  FileCheck checks the machine code output to

+verify that it matches what the "``CHECK:``" lines specify.

+

+The syntax of the "``CHECK:``" lines is very simple: they are fixed strings that

+must occur in order.  FileCheck defaults to ignoring horizontal whitespace

+differences (e.g. a space is allowed to match a tab) but otherwise, the contents

+of the "``CHECK:``" line is required to match some thing in the test file exactly.

+

+One nice thing about FileCheck (compared to grep) is that it allows merging

+test cases together into logical groups.  For example, because the test above

+is checking for the "``sub1:``" and "``inc4:``" labels, it will not match

+unless there is a "``subl``" in between those labels.  If it existed somewhere

+else in the file, that would not count: "``grep subl``" matches if "``subl``"

+exists anywhere in the file.

+

+The FileCheck -check-prefix option

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+The FileCheck `-check-prefix` option allows multiple test

+configurations to be driven from one `.ll` file.  This is useful in many

+circumstances, for example, testing different architectural variants with

+:program:`llc`.  Here's a simple example:

+

+.. code-block:: llvm

+

+   ; RUN: llvm-as < %s | llc -mtriple=i686-apple-darwin9 -mattr=sse41 \

+   ; RUN:              | FileCheck %s -check-prefix=X32

+   ; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 -mattr=sse41 \

+   ; RUN:              | FileCheck %s -check-prefix=X64

+

+   define <4 x i32> @pinsrd_1(i32 %s, <4 x i32> %tmp) nounwind {

+           %tmp1 = insertelement <4 x i32>; %tmp, i32 %s, i32 1

+           ret <4 x i32> %tmp1

+   ; X32: pinsrd_1:

+   ; X32:    pinsrd $1, 4(%esp), %xmm0

+

+   ; X64: pinsrd_1:

+   ; X64:    pinsrd $1, %edi, %xmm0

+   }

+

+In this case, we're testing that we get the expected code generation with

+both 32-bit and 64-bit code generation.

+

+The "CHECK-NEXT:" directive

+~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+Sometimes you want to match lines and would like to verify that matches

+happen on exactly consecutive lines with no other lines in between them.  In

+this case, you can use "``CHECK:``" and "``CHECK-NEXT:``" directives to specify

+this.  If you specified a custom check prefix, just use "``<PREFIX>-NEXT:``".

+For example, something like this works as you'd expect:

+

+.. code-block:: llvm

+

+   define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) {

+ 	%tmp3 = load <2 x double>* %A, align 16

+ 	%tmp7 = insertelement <2 x double> undef, double %B, i32 0

+ 	%tmp9 = shufflevector <2 x double> %tmp3,

+                               <2 x double> %tmp7,

+                               <2 x i32> < i32 0, i32 2 >

+ 	store <2 x double> %tmp9, <2 x double>* %r, align 16

+ 	ret void

+

+   ; CHECK:          t2:

+   ; CHECK: 	        movl	8(%esp), %eax

+   ; CHECK-NEXT: 	movapd	(%eax), %xmm0

+   ; CHECK-NEXT: 	movhpd	12(%esp), %xmm0

+   ; CHECK-NEXT: 	movl	4(%esp), %eax

+   ; CHECK-NEXT: 	movapd	%xmm0, (%eax)

+   ; CHECK-NEXT: 	ret

+   }

+

+"``CHECK-NEXT:``" directives reject the input unless there is exactly one

+newline between it and the previous directive.  A "``CHECK-NEXT:``" cannot be

+the first directive in a file.

+

+The "CHECK-SAME:" directive

+~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+Sometimes you want to match lines and would like to verify that matches happen

+on the same line as the previous match.  In this case, you can use "``CHECK:``"

+and "``CHECK-SAME:``" directives to specify this.  If you specified a custom

+check prefix, just use "``<PREFIX>-SAME:``".

+

+"``CHECK-SAME:``" is particularly powerful in conjunction with "``CHECK-NOT:``"

+(described below).

+

+For example, the following works like you'd expect:

+

+.. code-block:: llvm

+

+   !0 = !DILocation(line: 5, scope: !1, inlinedAt: !2)

+

+   ; CHECK:       !DILocation(line: 5,

+   ; CHECK-NOT:               column:

+   ; CHECK-SAME:              scope: ![[SCOPE:[0-9]+]]

+

+"``CHECK-SAME:``" directives reject the input if there are any newlines between

+it and the previous directive.  A "``CHECK-SAME:``" cannot be the first

+directive in a file.

+

+The "CHECK-EMPTY:" directive

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+If you need to check that the next line has nothing on it, not even whitespace,

+you can use the "``CHECK-EMPTY:``" directive.

+

+.. code-block:: llvm

+

+   declare void @foo()

+

+   declare void @bar()

+   ; CHECK: foo

+   ; CHECK-EMPTY:

+   ; CHECK-NEXT: bar

+

+Just like "``CHECK-NEXT:``" the directive will fail if there is more than one

+newline before it finds the next blank line, and it cannot be the first

+directive in a file.

+

+The "CHECK-NOT:" directive

+~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+The "``CHECK-NOT:``" directive is used to verify that a string doesn't occur

+between two matches (or before the first match, or after the last match).  For

+example, to verify that a load is removed by a transformation, a test like this

+can be used:

+

+.. code-block:: llvm

+

+   define i8 @coerce_offset0(i32 %V, i32* %P) {

+     store i32 %V, i32* %P

+

+     %P2 = bitcast i32* %P to i8*

+     %P3 = getelementptr i8* %P2, i32 2

+

+     %A = load i8* %P3

+     ret i8 %A

+   ; CHECK: @coerce_offset0

+   ; CHECK-NOT: load

+   ; CHECK: ret i8

+   }

+

+The "CHECK-COUNT:" directive

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+If you need to match multiple lines with the same pattern over and over again

+you can repeat a plain ``CHECK:`` as many times as needed. If that looks too

+boring you can instead use a counted check "``CHECK-COUNT-<num>:``", where

+``<num>`` is a positive decimal number. It will match the pattern exactly

+``<num>`` times, no more and no less. If you specified a custom check prefix,

+just use "``<PREFIX>-COUNT-<num>:``" for the same effect.

+Here is a simple example:

+

+.. code-block:: text

+

+   Loop at depth 1

+   Loop at depth 1

+   Loop at depth 1

+   Loop at depth 1

+     Loop at depth 2

+       Loop at depth 3

+

+   ; CHECK-COUNT-6: Loop at depth {{[0-9]+}}

+   ; CHECK-NOT:     Loop at depth {{[0-9]+}}

+

+The "CHECK-DAG:" directive

+~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+If it's necessary to match strings that don't occur in a strictly sequential

+order, "``CHECK-DAG:``" could be used to verify them between two matches (or

+before the first match, or after the last match). For example, clang emits

+vtable globals in reverse order. Using ``CHECK-DAG:``, we can keep the checks

+in the natural order:

+

+.. code-block:: c++

+

+    // RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s

+

+    struct Foo { virtual void method(); };

+    Foo f;  // emit vtable

+    // CHECK-DAG: @_ZTV3Foo =

+

+    struct Bar { virtual void method(); };

+    Bar b;

+    // CHECK-DAG: @_ZTV3Bar =

+

+``CHECK-NOT:`` directives could be mixed with ``CHECK-DAG:`` directives to

+exclude strings between the surrounding ``CHECK-DAG:`` directives. As a result,

+the surrounding ``CHECK-DAG:`` directives cannot be reordered, i.e. all

+occurrences matching ``CHECK-DAG:`` before ``CHECK-NOT:`` must not fall behind

+occurrences matching ``CHECK-DAG:`` after ``CHECK-NOT:``. For example,

+

+.. code-block:: llvm

+

+   ; CHECK-DAG: BEFORE

+   ; CHECK-NOT: NOT

+   ; CHECK-DAG: AFTER

+

+This case will reject input strings where ``BEFORE`` occurs after ``AFTER``.

+

+With captured variables, ``CHECK-DAG:`` is able to match valid topological

+orderings of a DAG with edges from the definition of a variable to its use.

+It's useful, e.g., when your test cases need to match different output

+sequences from the instruction scheduler. For example,

+

+.. code-block:: llvm

+

+   ; CHECK-DAG: add [[REG1:r[0-9]+]], r1, r2

+   ; CHECK-DAG: add [[REG2:r[0-9]+]], r3, r4

+   ; CHECK:     mul r5, [[REG1]], [[REG2]]

+

+In this case, any order of that two ``add`` instructions will be allowed.

+

+If you are defining `and` using variables in the same ``CHECK-DAG:`` block,

+be aware that the definition rule can match `after` its use.

+

+So, for instance, the code below will pass:

+

+.. code-block:: text

+

+  ; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]

+  ; CHECK-DAG: vmov.32 [[REG2]][1]

+  vmov.32 d0[1]

+  vmov.32 d0[0]

+

+While this other code, will not:

+

+.. code-block:: text

+

+  ; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]

+  ; CHECK-DAG: vmov.32 [[REG2]][1]

+  vmov.32 d1[1]

+  vmov.32 d0[0]

+

+While this can be very useful, it's also dangerous, because in the case of

+register sequence, you must have a strong order (read before write, copy before

+use, etc). If the definition your test is looking for doesn't match (because

+of a bug in the compiler), it may match further away from the use, and mask

+real bugs away.

+

+In those cases, to enforce the order, use a non-DAG directive between DAG-blocks.

+

+A ``CHECK-DAG:`` directive skips matches that overlap the matches of any

+preceding ``CHECK-DAG:`` directives in the same ``CHECK-DAG:`` block.  Not only

+is this non-overlapping behavior consistent with other directives, but it's

+also necessary to handle sets of non-unique strings or patterns.  For example,

+the following directives look for unordered log entries for two tasks in a

+parallel program, such as the OpenMP runtime:

+

+.. code-block:: text

+

+    // CHECK-DAG: [[THREAD_ID:[0-9]+]]: task_begin

+    // CHECK-DAG: [[THREAD_ID]]: task_end

+    //

+    // CHECK-DAG: [[THREAD_ID:[0-9]+]]: task_begin

+    // CHECK-DAG: [[THREAD_ID]]: task_end

+

+The second pair of directives is guaranteed not to match the same log entries

+as the first pair even though the patterns are identical and even if the text

+of the log entries is identical because the thread ID manages to be reused.

+

+The "CHECK-LABEL:" directive

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+Sometimes in a file containing multiple tests divided into logical blocks, one

+or more ``CHECK:`` directives may inadvertently succeed by matching lines in a

+later block. While an error will usually eventually be generated, the check

+flagged as causing the error may not actually bear any relationship to the

+actual source of the problem.

+

+In order to produce better error messages in these cases, the "``CHECK-LABEL:``"

+directive can be used. It is treated identically to a normal ``CHECK``

+directive except that FileCheck makes an additional assumption that a line

+matched by the directive cannot also be matched by any other check present in

+``match-filename``; this is intended to be used for lines containing labels or

+other unique identifiers. Conceptually, the presence of ``CHECK-LABEL`` divides

+the input stream into separate blocks, each of which is processed independently,

+preventing a ``CHECK:`` directive in one block matching a line in another block.

+If ``--enable-var-scope`` is in effect, all local variables are cleared at the

+beginning of the block.

+

+For example,

+

+.. code-block:: llvm

+

+  define %struct.C* @C_ctor_base(%struct.C* %this, i32 %x) {

+  entry:

+  ; CHECK-LABEL: C_ctor_base:

+  ; CHECK: mov [[SAVETHIS:r[0-9]+]], r0

+  ; CHECK: bl A_ctor_base

+  ; CHECK: mov r0, [[SAVETHIS]]

+    %0 = bitcast %struct.C* %this to %struct.A*

+    %call = tail call %struct.A* @A_ctor_base(%struct.A* %0)

+    %1 = bitcast %struct.C* %this to %struct.B*

+    %call2 = tail call %struct.B* @B_ctor_base(%struct.B* %1, i32 %x)

+    ret %struct.C* %this

+  }

+

+  define %struct.D* @D_ctor_base(%struct.D* %this, i32 %x) {

+  entry:

+  ; CHECK-LABEL: D_ctor_base:

+

+The use of ``CHECK-LABEL:`` directives in this case ensures that the three

+``CHECK:`` directives only accept lines corresponding to the body of the

+``@C_ctor_base`` function, even if the patterns match lines found later in

+the file. Furthermore, if one of these three ``CHECK:`` directives fail,

+FileCheck will recover by continuing to the next block, allowing multiple test

+failures to be detected in a single invocation.

+

+There is no requirement that ``CHECK-LABEL:`` directives contain strings that

+correspond to actual syntactic labels in a source or output language: they must

+simply uniquely match a single line in the file being verified.

+

+``CHECK-LABEL:`` directives cannot contain variable definitions or uses.

+

+FileCheck Regex Matching Syntax

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+All FileCheck directives take a pattern to match.

+For most uses of FileCheck, fixed string matching is perfectly sufficient.  For

+some things, a more flexible form of matching is desired.  To support this,

+FileCheck allows you to specify regular expressions in matching strings,

+surrounded by double braces: ``{{yourregex}}``. FileCheck implements a POSIX

+regular expression matcher; it supports Extended POSIX regular expressions

+(ERE). Because we want to use fixed string matching for a majority of what we

+do, FileCheck has been designed to support mixing and matching fixed string

+matching with regular expressions.  This allows you to write things like this:

+

+.. code-block:: llvm

+

+   ; CHECK: movhpd	{{[0-9]+}}(%esp), {{%xmm[0-7]}}

+

+In this case, any offset from the ESP register will be allowed, and any xmm

+register will be allowed.

+

+Because regular expressions are enclosed with double braces, they are

+visually distinct, and you don't need to use escape characters within the double

+braces like you would in C.  In the rare case that you want to match double

+braces explicitly from the input, you can use something ugly like

+``{{[}][}]}}`` as your pattern.  Or if you are using the repetition count

+syntax, for example ``[[:xdigit:]]{8}`` to match exactly 8 hex digits, you

+would need to add parentheses like this ``{{([[:xdigit:]]{8})}}`` to avoid

+confusion with FileCheck's closing double-brace.

+

+FileCheck String Substitution Blocks

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+It is often useful to match a pattern and then verify that it occurs again

+later in the file.  For codegen tests, this can be useful to allow any

+register, but verify that that register is used consistently later.  To do

+this, :program:`FileCheck` supports string substitution blocks that allow

+string variables to be defined and substituted into patterns.  Here is a simple

+example:

+

+.. code-block:: llvm

+

+   ; CHECK: test5:

+   ; CHECK:    notw	[[REGISTER:%[a-z]+]]

+   ; CHECK:    andw	{{.*}}[[REGISTER]]

+

+The first check line matches a regex ``%[a-z]+`` and captures it into the

+string variable ``REGISTER``.  The second line verifies that whatever is in

+``REGISTER`` occurs later in the file after an "``andw``". :program:`FileCheck`

+string substitution blocks are always contained in ``[[ ]]`` pairs, and string

+variable names can be formed with the regex ``[a-zA-Z_][a-zA-Z0-9_]*``.  If a

+colon follows the name, then it is a definition of the variable; otherwise, it

+is a substitution.

+

+:program:`FileCheck` variables can be defined multiple times, and substitutions

+always get the latest value.  Variables can also be substituted later on the

+same line they were defined on. For example:

+

+.. code-block:: llvm

+

+    ; CHECK: op [[REG:r[0-9]+]], [[REG]]

+

+Can be useful if you want the operands of ``op`` to be the same register,

+and don't care exactly which register it is.

+

+If ``--enable-var-scope`` is in effect, variables with names that

+start with ``$`` are considered to be global. All others variables are

+local.  All local variables get undefined at the beginning of each

+CHECK-LABEL block. Global variables are not affected by CHECK-LABEL.

+This makes it easier to ensure that individual tests are not affected

+by variables set in preceding tests.

+

+FileCheck Numeric Substitution Blocks

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+:program:`FileCheck` also supports numeric substitution blocks that allow

+defining numeric variables and checking for numeric values that satisfy a

+numeric expression constraint based on those variables via a numeric

+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 ``[[#<NUMVAR>:]]`` where

+``<NUMVAR>`` is the name of the numeric variable to define to the matching

+value.

+

+For example:

+

+.. code-block:: llvm

+

+    ; CHECK: mov r[[#REG:]], 42

+

+would match ``mov r5, 42`` and set ``REG`` to the value ``5``.

+

+The syntax of a numeric substitution is ``[[#<expr>]]`` where ``<expr>`` is an

+expression. An expression is recursively defined as:

+

+* a numeric operand, or

+* an expression followed by an operator and a numeric operand.

+

+A numeric operand is a previously defined numeric variable, or an integer

+literal. The supported operators are ``+`` and ``-``. Spaces are accepted

+before, after and between any of these elements.

+

+For example:

+

+.. code-block:: llvm

+

+    ; CHECK: load r[[#REG:]], [r0]

+    ; CHECK: load r[[#REG+1]], [r1]

+

+The above example would match the text:

+

+.. code-block:: gas

+

+    load r5, [r0]

+    load r6, [r1]

+

+but would not match the text:

+

+.. code-block:: gas

+

+    load r5, [r0]

+    load r7, [r1]

+

+due to ``7`` being unequal to ``5 + 1``.

+

+The syntax also supports an empty expression, equivalent to writing {{[0-9]+}},

+for cases where the input must contain a numeric value but the value itself

+does not matter:

+

+.. code-block:: gas

+

+    ; CHECK-NOT: mov r0, r[[#]]

+

+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 ``[[#<NUMVAR>: <expr>]]`` with each

+element as described previously.

+

+The ``--enable-var-scope`` option has the same effect on numeric variables as

+on string variables.

+

+Important note: In its current implementation, an expression cannot use a

+numeric variable defined earlier in the same CHECK directive.

+

+FileCheck Pseudo Numeric Variables

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+Sometimes there's a need to verify output that contains line numbers of the

+match file, e.g. when testing compiler diagnostics.  This introduces a certain

+fragility of the match file structure, as "``CHECK:``" lines contain absolute

+line numbers in the same file, which have to be updated whenever line numbers

+change due to text addition or deletion.

+

+To support this case, FileCheck expressions understand the ``@LINE`` pseudo

+numeric variable which evaluates to the line number of the CHECK pattern where

+it is found.

+

+This way match patterns can be put near the relevant test lines and include

+relative line number references, for example:

+

+.. code-block:: c++

+

+   // CHECK: test.cpp:[[# @LINE + 4]]:6: error: expected ';' after top level declarator

+   // CHECK-NEXT: {{^int a}}

+   // CHECK-NEXT: {{^     \^}}

+   // CHECK-NEXT: {{^     ;}}

+   int a

+

+To support legacy uses of ``@LINE`` as a special string variable,

+:program:`FileCheck` also accepts the following uses of ``@LINE`` with string

+substitution block syntax: ``[[@LINE]]``, ``[[@LINE+<offset>]]`` and

+``[[@LINE-<offset>]]`` without any spaces inside the brackets and where

+``offset`` is an integer.

+

+Matching Newline Characters

+~~~~~~~~~~~~~~~~~~~~~~~~~~~

+

+To match newline characters in regular expressions the character class

+``[[:space:]]`` can be used. For example, the following pattern:

+

+.. code-block:: c++

+

+   // CHECK: DW_AT_location [DW_FORM_sec_offset] ([[DLOC:0x[0-9a-f]+]]){{[[:space:]].*}}"intd"

+

+matches output of the form (from llvm-dwarfdump):

+

+.. code-block:: text

+

+       DW_AT_location [DW_FORM_sec_offset]   (0x00000233)

+       DW_AT_name [DW_FORM_strp]  ( .debug_str[0x000000c9] = "intd")

+

+letting us set the :program:`FileCheck` variable ``DLOC`` to the desired value 

+``0x00000233``, extracted from the line immediately preceding "``intd``".

diff --git a/llvm/include/llvm/Support/FileCheck.h b/llvm/include/llvm/Support/FileCheck.h
index 5c6585e..dc6dc74 100644
--- a/llvm/include/llvm/Support/FileCheck.h
+++ b/llvm/include/llvm/Support/FileCheck.h
@@ -1,180 +1,181 @@
-//==-- llvm/Support/FileCheck.h ---------------------------*- C++ -*-==//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-/// \file This file has some utilities to use FileCheck as an API
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_SUPPORT_FILECHECK_H
-#define LLVM_SUPPORT_FILECHECK_H
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Regex.h"
-#include "llvm/Support/SourceMgr.h"
-#include <string>
-#include <vector>
-
-namespace llvm {
-
-/// Contains info about various FileCheck options.
-struct FileCheckRequest {
-  std::vector<std::string> CheckPrefixes;
-  bool NoCanonicalizeWhiteSpace = false;
-  std::vector<std::string> ImplicitCheckNot;
-  std::vector<std::string> GlobalDefines;
-  bool AllowEmptyInput = false;
-  bool MatchFullLines = false;
-  bool EnableVarScope = false;
-  bool AllowDeprecatedDagOverlap = false;
-  bool Verbose = false;
-  bool VerboseVerbose = false;
-};
-
-//===----------------------------------------------------------------------===//
-// Summary of a FileCheck diagnostic.
-//===----------------------------------------------------------------------===//
-
-namespace Check {
-
-enum FileCheckKind {
-  CheckNone = 0,
-  CheckPlain,
-  CheckNext,
-  CheckSame,
-  CheckNot,
-  CheckDAG,
-  CheckLabel,
-  CheckEmpty,
-
-  /// Indicates the pattern only matches the end of file. This is used for
-  /// trailing CHECK-NOTs.
-  CheckEOF,
-
-  /// Marks when parsing found a -NOT check combined with another CHECK suffix.
-  CheckBadNot,
-
-  /// Marks when parsing found a -COUNT directive with invalid count value.
-  CheckBadCount
-};
-
-class FileCheckType {
-  FileCheckKind Kind;
-  int Count; ///< optional Count for some checks
-
-public:
-  FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {}
-  FileCheckType(const FileCheckType &) = default;
-
-  operator FileCheckKind() const { return Kind; }
-
-  int getCount() const { return Count; }
-  FileCheckType &setCount(int C);
-
-  // \returns a description of \p Prefix.
-  std::string getDescription(StringRef Prefix) const;
-};
-} // namespace Check
-
-struct FileCheckDiag {
-  /// What is the FileCheck directive for this diagnostic?
-  Check::FileCheckType CheckTy;
-  /// Where is the FileCheck directive for this diagnostic?
-  unsigned CheckLine, CheckCol;
-  /// What type of match result does this diagnostic describe?
-  ///
-  /// A directive's supplied pattern is said to be either expected or excluded
-  /// depending on whether the pattern must have or must not have a match in
-  /// order for the directive to succeed.  For example, a CHECK directive's
-  /// pattern is expected, and a CHECK-NOT directive's pattern is excluded.
-  /// All match result types whose names end with "Excluded" are for excluded
-  /// patterns, and all others are for expected patterns.
-  ///
-  /// There might be more than one match result for a single pattern.  For
-  /// example, there might be several discarded matches
-  /// (MatchFoundButDiscarded) before either a good match
-  /// (MatchFoundAndExpected) or a failure to match (MatchNoneButExpected),
-  /// and there might be a fuzzy match (MatchFuzzy) after the latter.
-  enum MatchType {
-    /// Indicates a good match for an expected pattern.
-    MatchFoundAndExpected,
-    /// Indicates a match for an excluded pattern.
-    MatchFoundButExcluded,
-    /// Indicates a match for an expected pattern, but the match is on the
-    /// wrong line.
-    MatchFoundButWrongLine,
-    /// Indicates a discarded match for an expected pattern.
-    MatchFoundButDiscarded,
-    /// Indicates no match for an excluded pattern.
-    MatchNoneAndExcluded,
-    /// Indicates no match for an expected pattern, but this might follow good
-    /// matches when multiple matches are expected for the pattern, or it might
-    /// follow discarded matches for the pattern.
-    MatchNoneButExpected,
-    /// Indicates a fuzzy match that serves as a suggestion for the next
-    /// intended match for an expected pattern with too few or no good matches.
-    MatchFuzzy,
-  } MatchTy;
-  /// The search range if MatchTy is MatchNoneAndExcluded or
-  /// MatchNoneButExpected, or the match range otherwise.
-  unsigned InputStartLine;
-  unsigned InputStartCol;
-  unsigned InputEndLine;
-  unsigned InputEndCol;
-  FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,
-                SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange);
-};
-
-class FileCheckPatternContext;
-struct FileCheckString;
-
-/// FileCheck class takes the request and exposes various methods that
-/// use information from the request.
-class FileCheck {
-  FileCheckRequest Req;
-  std::unique_ptr<FileCheckPatternContext> PatternContext;
-  // C++17 TODO: make this a plain std::vector.
-  std::unique_ptr<std::vector<FileCheckString>> CheckStrings;
-
-public:
-  explicit FileCheck(FileCheckRequest Req);
-  ~FileCheck();
-
-  // Combines the check prefixes into a single regex so that we can efficiently
-  // scan for any of the set.
-  //
-  // The semantics are that the longest-match wins which matches our regex
-  // library.
-  Regex buildCheckPrefixRegex();
-
-  /// Reads the check file from \p Buffer and records the expected strings it
-  /// contains. Errors are reported against \p SM.
-  ///
-  /// Only expected strings whose prefix is one of those listed in \p PrefixRE
-  /// are recorded. \returns true in case of an error, false otherwise.
-  bool readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE);
-
-  bool ValidateCheckPrefixes();
-
-  /// Canonicalizes whitespaces in the file. Line endings are replaced with
-  /// UNIX-style '\n'.
-  StringRef CanonicalizeFile(MemoryBuffer &MB,
-                             SmallVectorImpl<char> &OutputBuffer);
-
-  /// Checks the input to FileCheck provided in the \p Buffer against the
-  /// expected strings read from the check file and record diagnostics emitted
-  /// in \p Diags. Errors are recorded against \p SM.
-  ///
-  /// \returns false if the input fails to satisfy the checks.
-  bool checkInput(SourceMgr &SM, StringRef Buffer,
-                  std::vector<FileCheckDiag> *Diags = nullptr);
-};
-
-} // namespace llvm
-
-#endif
+//==-- llvm/Support/FileCheck.h ---------------------------*- C++ -*-==//

+//

+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.

+// See https://llvm.org/LICENSE.txt for license information.

+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

+//

+//===----------------------------------------------------------------------===//

+//

+/// \file This file has some utilities to use FileCheck as an API

+//

+//===----------------------------------------------------------------------===//

+

+#ifndef LLVM_SUPPORT_FILECHECK_H

+#define LLVM_SUPPORT_FILECHECK_H

+

+#include "llvm/ADT/StringRef.h"

+#include "llvm/Support/MemoryBuffer.h"

+#include "llvm/Support/Regex.h"

+#include "llvm/Support/SourceMgr.h"

+#include <string>

+#include <vector>

+

+namespace llvm {

+

+/// Contains info about various FileCheck options.

+struct FileCheckRequest {

+  std::vector<std::string> CheckPrefixes;

+  bool NoCanonicalizeWhiteSpace = false;

+  std::vector<std::string> ImplicitCheckNot;

+  std::vector<std::string> GlobalDefines;

+  bool AllowEmptyInput = false;

+  bool MatchFullLines = false;

+  bool IgnoreCase = false;

+  bool EnableVarScope = false;

+  bool AllowDeprecatedDagOverlap = false;

+  bool Verbose = false;

+  bool VerboseVerbose = false;

+};

+

+//===----------------------------------------------------------------------===//

+// Summary of a FileCheck diagnostic.

+//===----------------------------------------------------------------------===//

+

+namespace Check {

+

+enum FileCheckKind {

+  CheckNone = 0,

+  CheckPlain,

+  CheckNext,

+  CheckSame,

+  CheckNot,

+  CheckDAG,

+  CheckLabel,

+  CheckEmpty,

+

+  /// Indicates the pattern only matches the end of file. This is used for

+  /// trailing CHECK-NOTs.

+  CheckEOF,

+

+  /// Marks when parsing found a -NOT check combined with another CHECK suffix.

+  CheckBadNot,

+

+  /// Marks when parsing found a -COUNT directive with invalid count value.

+  CheckBadCount

+};

+

+class FileCheckType {

+  FileCheckKind Kind;

+  int Count; ///< optional Count for some checks

+

+public:

+  FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {}

+  FileCheckType(const FileCheckType &) = default;

+

+  operator FileCheckKind() const { return Kind; }

+

+  int getCount() const { return Count; }

+  FileCheckType &setCount(int C);

+

+  // \returns a description of \p Prefix.

+  std::string getDescription(StringRef Prefix) const;

+};

+} // namespace Check

+

+struct FileCheckDiag {

+  /// What is the FileCheck directive for this diagnostic?

+  Check::FileCheckType CheckTy;

+  /// Where is the FileCheck directive for this diagnostic?

+  unsigned CheckLine, CheckCol;

+  /// What type of match result does this diagnostic describe?

+  ///

+  /// A directive's supplied pattern is said to be either expected or excluded

+  /// depending on whether the pattern must have or must not have a match in

+  /// order for the directive to succeed.  For example, a CHECK directive's

+  /// pattern is expected, and a CHECK-NOT directive's pattern is excluded.

+  /// All match result types whose names end with "Excluded" are for excluded

+  /// patterns, and all others are for expected patterns.

+  ///

+  /// There might be more than one match result for a single pattern.  For

+  /// example, there might be several discarded matches

+  /// (MatchFoundButDiscarded) before either a good match

+  /// (MatchFoundAndExpected) or a failure to match (MatchNoneButExpected),

+  /// and there might be a fuzzy match (MatchFuzzy) after the latter.

+  enum MatchType {

+    /// Indicates a good match for an expected pattern.

+    MatchFoundAndExpected,

+    /// Indicates a match for an excluded pattern.

+    MatchFoundButExcluded,

+    /// Indicates a match for an expected pattern, but the match is on the

+    /// wrong line.

+    MatchFoundButWrongLine,

+    /// Indicates a discarded match for an expected pattern.

+    MatchFoundButDiscarded,

+    /// Indicates no match for an excluded pattern.

+    MatchNoneAndExcluded,

+    /// Indicates no match for an expected pattern, but this might follow good

+    /// matches when multiple matches are expected for the pattern, or it might

+    /// follow discarded matches for the pattern.

+    MatchNoneButExpected,

+    /// Indicates a fuzzy match that serves as a suggestion for the next

+    /// intended match for an expected pattern with too few or no good matches.

+    MatchFuzzy,

+  } MatchTy;

+  /// The search range if MatchTy is MatchNoneAndExcluded or

+  /// MatchNoneButExpected, or the match range otherwise.

+  unsigned InputStartLine;

+  unsigned InputStartCol;

+  unsigned InputEndLine;

+  unsigned InputEndCol;

+  FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,

+                SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange);

+};

+

+class FileCheckPatternContext;

+struct FileCheckString;

+

+/// FileCheck class takes the request and exposes various methods that

+/// use information from the request.

+class FileCheck {

+  FileCheckRequest Req;

+  std::unique_ptr<FileCheckPatternContext> PatternContext;

+  // C++17 TODO: make this a plain std::vector.

+  std::unique_ptr<std::vector<FileCheckString>> CheckStrings;

+

+public:

+  explicit FileCheck(FileCheckRequest Req);

+  ~FileCheck();

+

+  // Combines the check prefixes into a single regex so that we can efficiently

+  // scan for any of the set.

+  //

+  // The semantics are that the longest-match wins which matches our regex

+  // library.

+  Regex buildCheckPrefixRegex();

+

+  /// Reads the check file from \p Buffer and records the expected strings it

+  /// contains. Errors are reported against \p SM.

+  ///

+  /// Only expected strings whose prefix is one of those listed in \p PrefixRE

+  /// are recorded. \returns true in case of an error, false otherwise.

+  bool readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE);

+

+  bool ValidateCheckPrefixes();

+

+  /// Canonicalizes whitespaces in the file. Line endings are replaced with

+  /// UNIX-style '\n'.

+  StringRef CanonicalizeFile(MemoryBuffer &MB,

+                             SmallVectorImpl<char> &OutputBuffer);

+

+  /// Checks the input to FileCheck provided in the \p Buffer against the

+  /// expected strings read from the check file and record diagnostics emitted

+  /// in \p Diags. Errors are recorded against \p SM.

+  ///

+  /// \returns false if the input fails to satisfy the checks.

+  bool checkInput(SourceMgr &SM, StringRef Buffer,

+                  std::vector<FileCheckDiag> *Diags = nullptr);

+};

+

+} // namespace llvm

+

+#endif

diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
index c3f537b..fb4bbba 100644
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -1,1985 +1,1990 @@
-//===- FileCheck.cpp - Check that File's Contents match what is expected --===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// FileCheck does a line-by line check of a file that validates whether it
-// contains the expected content.  This is useful for regression tests etc.
-//
-// This file implements most of the API that will be used by the FileCheck utility
-// as well as various unittests.
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/FileCheck.h"
-#include "FileCheckImpl.h"
-#include "llvm/ADT/StringSet.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/FormatVariadic.h"
-#include <cstdint>
-#include <list>
-#include <tuple>
-#include <utility>
-
-using namespace llvm;
-
-Expected<uint64_t> FileCheckNumericVariableUse::eval() const {
-  Optional<uint64_t> Value = NumericVariable->getValue();
-  if (Value)
-    return *Value;
-
-  return make_error<FileCheckUndefVarError>(Name);
-}
-
-Expected<uint64_t> FileCheckASTBinop::eval() const {
-  Expected<uint64_t> LeftOp = LeftOperand->eval();
-  Expected<uint64_t> RightOp = RightOperand->eval();
-
-  // Bubble up any error (e.g. undefined variables) in the recursive
-  // evaluation.
-  if (!LeftOp || !RightOp) {
-    Error Err = Error::success();
-    if (!LeftOp)
-      Err = joinErrors(std::move(Err), LeftOp.takeError());
-    if (!RightOp)
-      Err = joinErrors(std::move(Err), RightOp.takeError());
-    return std::move(Err);
-  }
-
-  return EvalBinop(*LeftOp, *RightOp);
-}
-
-Expected<std::string> FileCheckNumericSubstitution::getResult() const {
-  Expected<uint64_t> EvaluatedValue = ExpressionAST->eval();
-  if (!EvaluatedValue)
-    return EvaluatedValue.takeError();
-  return utostr(*EvaluatedValue);
-}
-
-Expected<std::string> FileCheckStringSubstitution::getResult() const {
-  // Look up the value and escape it so that we can put it into the regex.
-  Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr);
-  if (!VarVal)
-    return VarVal.takeError();
-  return Regex::escape(*VarVal);
-}
-
-bool FileCheckPattern::isValidVarNameStart(char C) {
-  return C == '_' || isalpha(C);
-}
-
-Expected<FileCheckPattern::VariableProperties>
-FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
-  if (Str.empty())
-    return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name");
-
-  bool ParsedOneChar = false;
-  unsigned I = 0;
-  bool IsPseudo = Str[0] == '@';
-
-  // Global vars start with '$'.
-  if (Str[0] == '$' || IsPseudo)
-    ++I;
-
-  for (unsigned E = Str.size(); I != E; ++I) {
-    if (!ParsedOneChar && !isValidVarNameStart(Str[I]))
-      return FileCheckErrorDiagnostic::get(SM, Str, "invalid variable name");
-
-    // Variable names are composed of alphanumeric characters and underscores.
-    if (Str[I] != '_' && !isalnum(Str[I]))
-      break;
-    ParsedOneChar = true;
-  }
-
-  StringRef Name = Str.take_front(I);
-  Str = Str.substr(I);
-  return VariableProperties {Name, IsPseudo};
-}
-
-// StringRef holding all characters considered as horizontal whitespaces by
-// FileCheck input canonicalization.
-constexpr StringLiteral SpaceChars = " \t";
-
-// Parsing helper function that strips the first character in S and returns it.
-static char popFront(StringRef &S) {
-  char C = S.front();
-  S = S.drop_front();
-  return C;
-}
-
-char FileCheckUndefVarError::ID = 0;
-char FileCheckErrorDiagnostic::ID = 0;
-char FileCheckNotFoundError::ID = 0;
-
-Expected<FileCheckNumericVariable *>
-FileCheckPattern::parseNumericVariableDefinition(
-    StringRef &Expr, FileCheckPatternContext *Context,
-    Optional<size_t> LineNumber, const SourceMgr &SM) {
-  Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
-  if (!ParseVarResult)
-    return ParseVarResult.takeError();
-  StringRef Name = ParseVarResult->Name;
-
-  if (ParseVarResult->IsPseudo)
-    return FileCheckErrorDiagnostic::get(
-        SM, Name, "definition of pseudo numeric variable unsupported");
-
-  // Detect collisions between string and numeric variables when the latter
-  // is created later than the former.
-  if (Context->DefinedVariableTable.find(Name) !=
-      Context->DefinedVariableTable.end())
-    return FileCheckErrorDiagnostic::get(
-        SM, Name, "string variable with name '" + Name + "' already exists");
-
-  Expr = Expr.ltrim(SpaceChars);
-  if (!Expr.empty())
-    return FileCheckErrorDiagnostic::get(
-        SM, Expr, "unexpected characters after numeric variable name");
-
-  FileCheckNumericVariable *DefinedNumericVariable;
-  auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
-  if (VarTableIter != Context->GlobalNumericVariableTable.end())
-    DefinedNumericVariable = VarTableIter->second;
-  else
-    DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber);
-
-  return DefinedNumericVariable;
-}
-
-Expected<std::unique_ptr<FileCheckNumericVariableUse>>
-FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
-                                          Optional<size_t> LineNumber,
-                                          FileCheckPatternContext *Context,
-                                          const SourceMgr &SM) {
-  if (IsPseudo && !Name.equals("@LINE"))
-    return FileCheckErrorDiagnostic::get(
-        SM, Name, "invalid pseudo numeric variable '" + Name + "'");
-
-  // Numeric variable definitions and uses are parsed in the order in which
-  // they appear in the CHECK patterns. For each definition, the pointer to the
-  // class instance of the corresponding numeric variable definition is stored
-  // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer
-  // we get below is null, it means no such variable was defined before. When
-  // that happens, we create a dummy variable so that parsing can continue. All
-  // uses of undefined variables, whether string or numeric, are then diagnosed
-  // in printSubstitutions() after failing to match.
-  auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
-  FileCheckNumericVariable *NumericVariable;
-  if (VarTableIter != Context->GlobalNumericVariableTable.end())
-    NumericVariable = VarTableIter->second;
-  else {
-    NumericVariable = Context->makeNumericVariable(Name);
-    Context->GlobalNumericVariableTable[Name] = NumericVariable;
-  }
-
-  Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber();
-  if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)
-    return FileCheckErrorDiagnostic::get(
-        SM, Name,
-        "numeric variable '" + Name +
-            "' defined earlier in the same CHECK directive");
-
-  return std::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);
-}
-
-Expected<std::unique_ptr<FileCheckExpressionAST>>
-FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
-                                      Optional<size_t> LineNumber,
-                                      FileCheckPatternContext *Context,
-                                      const SourceMgr &SM) {
-  if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
-    // Try to parse as a numeric variable use.
-    Expected<FileCheckPattern::VariableProperties> ParseVarResult =
-        parseVariable(Expr, SM);
-    if (ParseVarResult)
-      return parseNumericVariableUse(ParseVarResult->Name,
-                                     ParseVarResult->IsPseudo, LineNumber,
-                                     Context, SM);
-    if (AO == AllowedOperand::LineVar)
-      return ParseVarResult.takeError();
-    // Ignore the error and retry parsing as a literal.
-    consumeError(ParseVarResult.takeError());
-  }
-
-  // Otherwise, parse it as a literal.
-  uint64_t LiteralValue;
-  if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))
-    return std::make_unique<FileCheckExpressionLiteral>(LiteralValue);
-
-  return FileCheckErrorDiagnostic::get(SM, Expr,
-                                       "invalid operand format '" + Expr + "'");
-}
-
-static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
-  return LeftOp + RightOp;
-}
-
-static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
-  return LeftOp - RightOp;
-}
-
-Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop(
-    StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,
-    bool IsLegacyLineExpr, Optional<size_t> LineNumber,
-    FileCheckPatternContext *Context, const SourceMgr &SM) {
-  Expr = Expr.ltrim(SpaceChars);
-  if (Expr.empty())
-    return std::move(LeftOp);
-
-  // Check if this is a supported operation and select a function to perform
-  // it.
-  SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());
-  char Operator = popFront(Expr);
-  binop_eval_t EvalBinop;
-  switch (Operator) {
-  case '+':
-    EvalBinop = add;
-    break;
-  case '-':
-    EvalBinop = sub;
-    break;
-  default:
-    return FileCheckErrorDiagnostic::get(
-        SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'");
-  }
-
-  // Parse right operand.
-  Expr = Expr.ltrim(SpaceChars);
-  if (Expr.empty())
-    return FileCheckErrorDiagnostic::get(SM, Expr,
-                                         "missing operand in expression");
-  // The second operand in a legacy @LINE expression is always a literal.
-  AllowedOperand AO =
-      IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
-  Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =
-      parseNumericOperand(Expr, AO, LineNumber, Context, SM);
-  if (!RightOpResult)
-    return RightOpResult;
-
-  Expr = Expr.ltrim(SpaceChars);
-  return std::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp),
-                                              std::move(*RightOpResult));
-}
-
-Expected<std::unique_ptr<FileCheckExpressionAST>>
-FileCheckPattern::parseNumericSubstitutionBlock(
-    StringRef Expr,
-    Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
-    bool IsLegacyLineExpr, Optional<size_t> LineNumber,
-    FileCheckPatternContext *Context, const SourceMgr &SM) {
-  std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr;
-  StringRef DefExpr = StringRef();
-  DefinedNumericVariable = None;
-  // Save variable definition expression if any.
-  size_t DefEnd = Expr.find(':');
-  if (DefEnd != StringRef::npos) {
-    DefExpr = Expr.substr(0, DefEnd);
-    Expr = Expr.substr(DefEnd + 1);
-  }
-
-  // Parse the expression itself.
-  Expr = Expr.ltrim(SpaceChars);
-  if (!Expr.empty()) {
-    // The first operand in a legacy @LINE expression is always the @LINE
-    // pseudo variable.
-    AllowedOperand AO =
-        IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
-    Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
-        parseNumericOperand(Expr, AO, LineNumber, Context, SM);
-    while (ParseResult && !Expr.empty()) {
-      ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr,
-                               LineNumber, Context, SM);
-      // Legacy @LINE expressions only allow 2 operands.
-      if (ParseResult && IsLegacyLineExpr && !Expr.empty())
-        return FileCheckErrorDiagnostic::get(
-            SM, Expr,
-            "unexpected characters at end of expression '" + Expr + "'");
-    }
-    if (!ParseResult)
-      return ParseResult;
-    ExpressionAST = std::move(*ParseResult);
-  }
-
-  // Parse the numeric variable definition.
-  if (DefEnd != StringRef::npos) {
-    DefExpr = DefExpr.ltrim(SpaceChars);
-    Expected<FileCheckNumericVariable *> ParseResult =
-        parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);
-
-    if (!ParseResult)
-      return ParseResult.takeError();
-    DefinedNumericVariable = *ParseResult;
-  }
-
-  return std::move(ExpressionAST);
-}
-
-bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
-                                    SourceMgr &SM,
-                                    const FileCheckRequest &Req) {
-  bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
-
-  PatternLoc = SMLoc::getFromPointer(PatternStr.data());
-
-  if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
-    // Ignore trailing whitespace.
-    while (!PatternStr.empty() &&
-           (PatternStr.back() == ' ' || PatternStr.back() == '\t'))
-      PatternStr = PatternStr.substr(0, PatternStr.size() - 1);
-
-  // Check that there is something on the line.
-  if (PatternStr.empty() && CheckTy != Check::CheckEmpty) {
-    SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
-                    "found empty check string with prefix '" + Prefix + ":'");
-    return true;
-  }
-
-  if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) {
-    SM.PrintMessage(
-        PatternLoc, SourceMgr::DK_Error,
-        "found non-empty check string for empty check with prefix '" + Prefix +
-            ":'");
-    return true;
-  }
-
-  if (CheckTy == Check::CheckEmpty) {
-    RegExStr = "(\n$)";
-    return false;
-  }
-
-  // Check to see if this is a fixed string, or if it has regex pieces.
-  if (!MatchFullLinesHere &&
-      (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&
-                                 PatternStr.find("[[") == StringRef::npos))) {
-    FixedStr = PatternStr;
-    return false;
-  }
-
-  if (MatchFullLinesHere) {
-    RegExStr += '^';
-    if (!Req.NoCanonicalizeWhiteSpace)
-      RegExStr += " *";
-  }
-
-  // Paren value #0 is for the fully matched string.  Any new parenthesized
-  // values add from there.
-  unsigned CurParen = 1;
-
-  // Otherwise, there is at least one regex piece.  Build up the regex pattern
-  // by escaping scary characters in fixed strings, building up one big regex.
-  while (!PatternStr.empty()) {
-    // RegEx matches.
-    if (PatternStr.startswith("{{")) {
-      // This is the start of a regex match.  Scan for the }}.
-      size_t End = PatternStr.find("}}");
-      if (End == StringRef::npos) {
-        SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
-                        SourceMgr::DK_Error,
-                        "found start of regex string with no end '}}'");
-        return true;
-      }
-
-      // Enclose {{}} patterns in parens just like [[]] even though we're not
-      // capturing the result for any purpose.  This is required in case the
-      // expression contains an alternation like: CHECK:  abc{{x|z}}def.  We
-      // want this to turn into: "abc(x|z)def" not "abcx|zdef".
-      RegExStr += '(';
-      ++CurParen;
-
-      if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM))
-        return true;
-      RegExStr += ')';
-
-      PatternStr = PatternStr.substr(End + 2);
-      continue;
-    }
-
-    // String and numeric substitution blocks. Pattern substitution blocks come
-    // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some
-    // other regex) and assigns it to the string variable 'foo'. The latter
-    // substitutes foo's value. Numeric substitution blocks recognize the same
-    // form as string ones, but start with a '#' sign after the double
-    // brackets. They also accept a combined form which sets a numeric variable
-    // to the evaluation of an expression. Both string and numeric variable
-    // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be
-    // valid, as this helps catch some common errors.
-    if (PatternStr.startswith("[[")) {
-      StringRef UnparsedPatternStr = PatternStr.substr(2);
-      // Find the closing bracket pair ending the match.  End is going to be an
-      // offset relative to the beginning of the match string.
-      size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);
-      StringRef MatchStr = UnparsedPatternStr.substr(0, End);
-      bool IsNumBlock = MatchStr.consume_front("#");
-
-      if (End == StringRef::npos) {
-        SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
-                        SourceMgr::DK_Error,
-                        "Invalid substitution block, no ]] found");
-        return true;
-      }
-      // Strip the substitution block we are parsing. End points to the start
-      // of the "]]" closing the expression so account for it in computing the
-      // index of the first unparsed character.
-      PatternStr = UnparsedPatternStr.substr(End + 2);
-
-      bool IsDefinition = false;
-      bool SubstNeeded = false;
-      // Whether the substitution block is a legacy use of @LINE with string
-      // substitution block syntax.
-      bool IsLegacyLineExpr = false;
-      StringRef DefName;
-      StringRef SubstStr;
-      StringRef MatchRegexp;
-      size_t SubstInsertIdx = RegExStr.size();
-
-      // Parse string variable or legacy @LINE expression.
-      if (!IsNumBlock) {
-        size_t VarEndIdx = MatchStr.find(":");
-        size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
-        if (SpacePos != StringRef::npos) {
-          SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos),
-                          SourceMgr::DK_Error, "unexpected whitespace");
-          return true;
-        }
-
-        // Get the name (e.g. "foo") and verify it is well formed.
-        StringRef OrigMatchStr = MatchStr;
-        Expected<FileCheckPattern::VariableProperties> ParseVarResult =
-            parseVariable(MatchStr, SM);
-        if (!ParseVarResult) {
-          logAllUnhandledErrors(ParseVarResult.takeError(), errs());
-          return true;
-        }
-        StringRef Name = ParseVarResult->Name;
-        bool IsPseudo = ParseVarResult->IsPseudo;
-
-        IsDefinition = (VarEndIdx != StringRef::npos);
-        SubstNeeded = !IsDefinition;
-        if (IsDefinition) {
-          if ((IsPseudo || !MatchStr.consume_front(":"))) {
-            SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
-                            SourceMgr::DK_Error,
-                            "invalid name in string variable definition");
-            return true;
-          }
-
-          // Detect collisions between string and numeric variables when the
-          // former is created later than the latter.
-          if (Context->GlobalNumericVariableTable.find(Name) !=
-              Context->GlobalNumericVariableTable.end()) {
-            SM.PrintMessage(
-                SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
-                "numeric variable with name '" + Name + "' already exists");
-            return true;
-          }
-          DefName = Name;
-          MatchRegexp = MatchStr;
-        } else {
-          if (IsPseudo) {
-            MatchStr = OrigMatchStr;
-            IsLegacyLineExpr = IsNumBlock = true;
-          } else
-            SubstStr = Name;
-        }
-      }
-
-      // Parse numeric substitution block.
-      std::unique_ptr<FileCheckExpressionAST> ExpressionAST;
-      Optional<FileCheckNumericVariable *> DefinedNumericVariable;
-      if (IsNumBlock) {
-        Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
-            parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
-                                          IsLegacyLineExpr, LineNumber, Context,
-                                          SM);
-        if (!ParseResult) {
-          logAllUnhandledErrors(ParseResult.takeError(), errs());
-          return true;
-        }
-        ExpressionAST = std::move(*ParseResult);
-        SubstNeeded = ExpressionAST != nullptr;
-        if (DefinedNumericVariable) {
-          IsDefinition = true;
-          DefName = (*DefinedNumericVariable)->getName();
-        }
-        if (SubstNeeded)
-          SubstStr = MatchStr;
-        else
-          MatchRegexp = "[0-9]+";
-      }
-
-      // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].
-      if (IsDefinition) {
-        RegExStr += '(';
-        ++SubstInsertIdx;
-
-        if (IsNumBlock) {
-          FileCheckNumericVariableMatch NumericVariableDefinition = {
-              *DefinedNumericVariable, CurParen};
-          NumericVariableDefs[DefName] = NumericVariableDefinition;
-          // This store is done here rather than in match() to allow
-          // parseNumericVariableUse() to get the pointer to the class instance
-          // of the right variable definition corresponding to a given numeric
-          // variable use.
-          Context->GlobalNumericVariableTable[DefName] =
-              *DefinedNumericVariable;
-        } else {
-          VariableDefs[DefName] = CurParen;
-          // Mark string variable as defined to detect collisions between
-          // string and numeric variables in parseNumericVariableUse() and
-          // defineCmdlineVariables() when the latter is created later than the
-          // former. We cannot reuse GlobalVariableTable for this by populating
-          // it with an empty string since we would then lose the ability to
-          // detect the use of an undefined variable in match().
-          Context->DefinedVariableTable[DefName] = true;
-        }
-
-        ++CurParen;
-      }
-
-      if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))
-        return true;
-
-      if (IsDefinition)
-        RegExStr += ')';
-
-      // Handle substitutions: [[foo]] and [[#<foo expr>]].
-      if (SubstNeeded) {
-        // Handle substitution of string variables that were defined earlier on
-        // the same line by emitting a backreference. Expressions do not
-        // support substituting a numeric variable defined on the same line.
-        if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) {
-          unsigned CaptureParenGroup = VariableDefs[SubstStr];
-          if (CaptureParenGroup < 1 || CaptureParenGroup > 9) {
-            SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()),
-                            SourceMgr::DK_Error,
-                            "Can't back-reference more than 9 variables");
-            return true;
-          }
-          AddBackrefToRegEx(CaptureParenGroup);
-        } else {
-          // Handle substitution of string variables ([[<var>]]) defined in
-          // previous CHECK patterns, and substitution of expressions.
-          FileCheckSubstitution *Substitution =
-              IsNumBlock
-                  ? Context->makeNumericSubstitution(
-                        SubstStr, std::move(ExpressionAST), SubstInsertIdx)
-                  : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
-          Substitutions.push_back(Substitution);
-        }
-      }
-    }
-
-    // Handle fixed string matches.
-    // Find the end, which is the start of the next regex.
-    size_t FixedMatchEnd = PatternStr.find("{{");
-    FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));
-    RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd));
-    PatternStr = PatternStr.substr(FixedMatchEnd);
-  }
-
-  if (MatchFullLinesHere) {
-    if (!Req.NoCanonicalizeWhiteSpace)
-      RegExStr += " *";
-    RegExStr += '$';
-  }
-
-  return false;
-}
-
-bool FileCheckPattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) {
-  Regex R(RS);
-  std::string Error;
-  if (!R.isValid(Error)) {
-    SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error,
-                    "invalid regex: " + Error);
-    return true;
-  }
-
-  RegExStr += RS.str();
-  CurParen += R.getNumMatches();
-  return false;
-}
-
-void FileCheckPattern::AddBackrefToRegEx(unsigned BackrefNum) {
-  assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number");
-  std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum);
-  RegExStr += Backref;
-}
-
-Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
-                                         const SourceMgr &SM) const {
-  // If this is the EOF pattern, match it immediately.
-  if (CheckTy == Check::CheckEOF) {
-    MatchLen = 0;
-    return Buffer.size();
-  }
-
-  // If this is a fixed string pattern, just match it now.
-  if (!FixedStr.empty()) {
-    MatchLen = FixedStr.size();
-    size_t Pos = Buffer.find(FixedStr);
-    if (Pos == StringRef::npos)
-      return make_error<FileCheckNotFoundError>();
-    return Pos;
-  }
-
-  // Regex match.
-
-  // If there are substitutions, we need to create a temporary string with the
-  // actual value.
-  StringRef RegExToMatch = RegExStr;
-  std::string TmpStr;
-  if (!Substitutions.empty()) {
-    TmpStr = RegExStr;
-    if (LineNumber)
-      Context->LineVariable->setValue(*LineNumber);
-
-    size_t InsertOffset = 0;
-    // Substitute all string variables and expressions whose values are only
-    // now known. Use of string variables defined on the same line are handled
-    // by back-references.
-    for (const auto &Substitution : Substitutions) {
-      // Substitute and check for failure (e.g. use of undefined variable).
-      Expected<std::string> Value = Substitution->getResult();
-      if (!Value)
-        return Value.takeError();
-
-      // Plop it into the regex at the adjusted offset.
-      TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
-                    Value->begin(), Value->end());
-      InsertOffset += Value->size();
-    }
-
-    // Match the newly constructed regex.
-    RegExToMatch = TmpStr;
-  }
-
-  SmallVector<StringRef, 4> MatchInfo;
-  if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo))
-    return make_error<FileCheckNotFoundError>();
-
-  // Successful regex match.
-  assert(!MatchInfo.empty() && "Didn't get any match");
-  StringRef FullMatch = MatchInfo[0];
-
-  // If this defines any string variables, remember their values.
-  for (const auto &VariableDef : VariableDefs) {
-    assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
-    Context->GlobalVariableTable[VariableDef.first] =
-        MatchInfo[VariableDef.second];
-  }
-
-  // If this defines any numeric variables, remember their values.
-  for (const auto &NumericVariableDef : NumericVariableDefs) {
-    const FileCheckNumericVariableMatch &NumericVariableMatch =
-        NumericVariableDef.getValue();
-    unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup;
-    assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error");
-    FileCheckNumericVariable *DefinedNumericVariable =
-        NumericVariableMatch.DefinedNumericVariable;
-
-    StringRef MatchedValue = MatchInfo[CaptureParenGroup];
-    uint64_t Val;
-    if (MatchedValue.getAsInteger(10, Val))
-      return FileCheckErrorDiagnostic::get(SM, MatchedValue,
-                                           "Unable to represent numeric value");
-    DefinedNumericVariable->setValue(Val);
-  }
-
-  // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
-  // the required preceding newline, which is consumed by the pattern in the
-  // case of CHECK-EMPTY but not CHECK-NEXT.
-  size_t MatchStartSkip = CheckTy == Check::CheckEmpty;
-  MatchLen = FullMatch.size() - MatchStartSkip;
-  return FullMatch.data() - Buffer.data() + MatchStartSkip;
-}
-
-unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const {
-  // Just compute the number of matching characters. For regular expressions, we
-  // just compare against the regex itself and hope for the best.
-  //
-  // FIXME: One easy improvement here is have the regex lib generate a single
-  // example regular expression which matches, and use that as the example
-  // string.
-  StringRef ExampleString(FixedStr);
-  if (ExampleString.empty())
-    ExampleString = RegExStr;
-
-  // Only compare up to the first line in the buffer, or the string size.
-  StringRef BufferPrefix = Buffer.substr(0, ExampleString.size());
-  BufferPrefix = BufferPrefix.split('\n').first;
-  return BufferPrefix.edit_distance(ExampleString);
-}
-
-void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
-                                          SMRange MatchRange) const {
-  // Print what we know about substitutions.
-  if (!Substitutions.empty()) {
-    for (const auto &Substitution : Substitutions) {
-      SmallString<256> Msg;
-      raw_svector_ostream OS(Msg);
-      Expected<std::string> MatchedValue = Substitution->getResult();
-
-      // Substitution failed or is not known at match time, print the undefined
-      // variables it uses.
-      if (!MatchedValue) {
-        bool UndefSeen = false;
-        handleAllErrors(MatchedValue.takeError(),
-                        [](const FileCheckNotFoundError &E) {},
-                        // Handled in PrintNoMatch().
-                        [](const FileCheckErrorDiagnostic &E) {},
-                        [&](const FileCheckUndefVarError &E) {
-                          if (!UndefSeen) {
-                            OS << "uses undefined variable(s):";
-                            UndefSeen = true;
-                          }
-                          OS << " ";
-                          E.log(OS);
-                        });
-      } else {
-        // Substitution succeeded. Print substituted value.
-        OS << "with \"";
-        OS.write_escaped(Substitution->getFromString()) << "\" equal to \"";
-        OS.write_escaped(*MatchedValue) << "\"";
-      }
-
-      if (MatchRange.isValid())
-        SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(),
-                        {MatchRange});
-      else
-        SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
-                        SourceMgr::DK_Note, OS.str());
-    }
-  }
-}
-
-static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,
-                                  const SourceMgr &SM, SMLoc Loc,
-                                  Check::FileCheckType CheckTy,
-                                  StringRef Buffer, size_t Pos, size_t Len,
-                                  std::vector<FileCheckDiag> *Diags,
-                                  bool AdjustPrevDiag = false) {
-  SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);
-  SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);
-  SMRange Range(Start, End);
-  if (Diags) {
-    if (AdjustPrevDiag)
-      Diags->rbegin()->MatchTy = MatchTy;
-    else
-      Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
-  }
-  return Range;
-}
-
-void FileCheckPattern::printFuzzyMatch(
-    const SourceMgr &SM, StringRef Buffer,
-    std::vector<FileCheckDiag> *Diags) const {
-  // Attempt to find the closest/best fuzzy match.  Usually an error happens
-  // because some string in the output didn't exactly match. In these cases, we
-  // would like to show the user a best guess at what "should have" matched, to
-  // save them having to actually check the input manually.
-  size_t NumLinesForward = 0;
-  size_t Best = StringRef::npos;
-  double BestQuality = 0;
-
-  // Use an arbitrary 4k limit on how far we will search.
-  for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) {
-    if (Buffer[i] == '\n')
-      ++NumLinesForward;
-
-    // Patterns have leading whitespace stripped, so skip whitespace when
-    // looking for something which looks like a pattern.
-    if (Buffer[i] == ' ' || Buffer[i] == '\t')
-      continue;
-
-    // Compute the "quality" of this match as an arbitrary combination of the
-    // match distance and the number of lines skipped to get to this match.
-    unsigned Distance = computeMatchDistance(Buffer.substr(i));
-    double Quality = Distance + (NumLinesForward / 100.);
-
-    if (Quality < BestQuality || Best == StringRef::npos) {
-      Best = i;
-      BestQuality = Quality;
-    }
-  }
-
-  // Print the "possible intended match here" line if we found something
-  // reasonable and not equal to what we showed in the "scanning from here"
-  // line.
-  if (Best && Best != StringRef::npos && BestQuality < 50) {
-    SMRange MatchRange =
-        ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(),
-                           getCheckTy(), Buffer, Best, 0, Diags);
-    SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note,
-                    "possible intended match here");
-
-    // FIXME: If we wanted to be really friendly we would show why the match
-    // failed, as it can be hard to spot simple one character differences.
-  }
-}
-
-Expected<StringRef>
-FileCheckPatternContext::getPatternVarValue(StringRef VarName) {
-  auto VarIter = GlobalVariableTable.find(VarName);
-  if (VarIter == GlobalVariableTable.end())
-    return make_error<FileCheckUndefVarError>(VarName);
-
-  return VarIter->second;
-}
-
-template <class... Types>
-FileCheckNumericVariable *
-FileCheckPatternContext::makeNumericVariable(Types... args) {
-  NumericVariables.push_back(
-      std::make_unique<FileCheckNumericVariable>(args...));
-  return NumericVariables.back().get();
-}
-
-FileCheckSubstitution *
-FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
-                                                size_t InsertIdx) {
-  Substitutions.push_back(
-      std::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx));
-  return Substitutions.back().get();
-}
-
-FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(
-    StringRef ExpressionStr,
-    std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) {
-  Substitutions.push_back(std::make_unique<FileCheckNumericSubstitution>(
-      this, ExpressionStr, std::move(ExpressionAST), InsertIdx));
-  return Substitutions.back().get();
-}
-
-size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {
-  // Offset keeps track of the current offset within the input Str
-  size_t Offset = 0;
-  // [...] Nesting depth
-  size_t BracketDepth = 0;
-
-  while (!Str.empty()) {
-    if (Str.startswith("]]") && BracketDepth == 0)
-      return Offset;
-    if (Str[0] == '\\') {
-      // Backslash escapes the next char within regexes, so skip them both.
-      Str = Str.substr(2);
-      Offset += 2;
-    } else {
-      switch (Str[0]) {
-      default:
-        break;
-      case '[':
-        BracketDepth++;
-        break;
-      case ']':
-        if (BracketDepth == 0) {
-          SM.PrintMessage(SMLoc::getFromPointer(Str.data()),
-                          SourceMgr::DK_Error,
-                          "missing closing \"]\" for regex variable");
-          exit(1);
-        }
-        BracketDepth--;
-        break;
-      }
-      Str = Str.substr(1);
-      Offset++;
-    }
-  }
-
-  return StringRef::npos;
-}
-
-StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB,
-                                      SmallVectorImpl<char> &OutputBuffer) {
-  OutputBuffer.reserve(MB.getBufferSize());
-
-  for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd();
-       Ptr != End; ++Ptr) {
-    // Eliminate trailing dosish \r.
-    if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') {
-      continue;
-    }
-
-    // If current char is not a horizontal whitespace or if horizontal
-    // whitespace canonicalization is disabled, dump it to output as is.
-    if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) {
-      OutputBuffer.push_back(*Ptr);
-      continue;
-    }
-
-    // Otherwise, add one space and advance over neighboring space.
-    OutputBuffer.push_back(' ');
-    while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t'))
-      ++Ptr;
-  }
-
-  // Add a null byte and then return all but that byte.
-  OutputBuffer.push_back('\0');
-  return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1);
-}
-
-FileCheckDiag::FileCheckDiag(const SourceMgr &SM,
-                             const Check::FileCheckType &CheckTy,
-                             SMLoc CheckLoc, MatchType MatchTy,
-                             SMRange InputRange)
-    : CheckTy(CheckTy), MatchTy(MatchTy) {
-  auto Start = SM.getLineAndColumn(InputRange.Start);
-  auto End = SM.getLineAndColumn(InputRange.End);
-  InputStartLine = Start.first;
-  InputStartCol = Start.second;
-  InputEndLine = End.first;
-  InputEndCol = End.second;
-  Start = SM.getLineAndColumn(CheckLoc);
-  CheckLine = Start.first;
-  CheckCol = Start.second;
-}
-
-static bool IsPartOfWord(char c) {
-  return (isalnum(c) || c == '-' || c == '_');
-}
-
-Check::FileCheckType &Check::FileCheckType::setCount(int C) {
-  assert(Count > 0 && "zero and negative counts are not supported");
-  assert((C == 1 || Kind == CheckPlain) &&
-         "count supported only for plain CHECK directives");
-  Count = C;
-  return *this;
-}
-
-std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
-  switch (Kind) {
-  case Check::CheckNone:
-    return "invalid";
-  case Check::CheckPlain:
-    if (Count > 1)
-      return Prefix.str() + "-COUNT";
-    return Prefix;
-  case Check::CheckNext:
-    return Prefix.str() + "-NEXT";
-  case Check::CheckSame:
-    return Prefix.str() + "-SAME";
-  case Check::CheckNot:
-    return Prefix.str() + "-NOT";
-  case Check::CheckDAG:
-    return Prefix.str() + "-DAG";
-  case Check::CheckLabel:
-    return Prefix.str() + "-LABEL";
-  case Check::CheckEmpty:
-    return Prefix.str() + "-EMPTY";
-  case Check::CheckEOF:
-    return "implicit EOF";
-  case Check::CheckBadNot:
-    return "bad NOT";
-  case Check::CheckBadCount:
-    return "bad COUNT";
-  }
-  llvm_unreachable("unknown FileCheckType");
-}
-
-static std::pair<Check::FileCheckType, StringRef>
-FindCheckType(StringRef Buffer, StringRef Prefix) {
-  if (Buffer.size() <= Prefix.size())
-    return {Check::CheckNone, StringRef()};
-
-  char NextChar = Buffer[Prefix.size()];
-
-  StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
-  // Verify that the : is present after the prefix.
-  if (NextChar == ':')
-    return {Check::CheckPlain, Rest};
-
-  if (NextChar != '-')
-    return {Check::CheckNone, StringRef()};
-
-  if (Rest.consume_front("COUNT-")) {
-    int64_t Count;
-    if (Rest.consumeInteger(10, Count))
-      // Error happened in parsing integer.
-      return {Check::CheckBadCount, Rest};
-    if (Count <= 0 || Count > INT32_MAX)
-      return {Check::CheckBadCount, Rest};
-    if (!Rest.consume_front(":"))
-      return {Check::CheckBadCount, Rest};
-    return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest};
-  }
-
-  if (Rest.consume_front("NEXT:"))
-    return {Check::CheckNext, Rest};
-
-  if (Rest.consume_front("SAME:"))
-    return {Check::CheckSame, Rest};
-
-  if (Rest.consume_front("NOT:"))
-    return {Check::CheckNot, Rest};
-
-  if (Rest.consume_front("DAG:"))
-    return {Check::CheckDAG, Rest};
-
-  if (Rest.consume_front("LABEL:"))
-    return {Check::CheckLabel, Rest};
-
-  if (Rest.consume_front("EMPTY:"))
-    return {Check::CheckEmpty, Rest};
-
-  // You can't combine -NOT with another suffix.
-  if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
-      Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
-      Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||
-      Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))
-    return {Check::CheckBadNot, Rest};
-
-  return {Check::CheckNone, Rest};
-}
-
-// From the given position, find the next character after the word.
-static size_t SkipWord(StringRef Str, size_t Loc) {
-  while (Loc < Str.size() && IsPartOfWord(Str[Loc]))
-    ++Loc;
-  return Loc;
-}
-
-/// Searches the buffer for the first prefix in the prefix regular expression.
-///
-/// This searches the buffer using the provided regular expression, however it
-/// enforces constraints beyond that:
-/// 1) The found prefix must not be a suffix of something that looks like
-///    a valid prefix.
-/// 2) The found prefix must be followed by a valid check type suffix using \c
-///    FindCheckType above.
-///
-/// \returns a pair of StringRefs into the Buffer, which combines:
-///   - the first match of the regular expression to satisfy these two is
-///   returned,
-///     otherwise an empty StringRef is returned to indicate failure.
-///   - buffer rewound to the location right after parsed suffix, for parsing
-///     to continue from
-///
-/// If this routine returns a valid prefix, it will also shrink \p Buffer to
-/// start at the beginning of the returned prefix, increment \p LineNumber for
-/// each new line consumed from \p Buffer, and set \p CheckTy to the type of
-/// check found by examining the suffix.
-///
-/// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy
-/// is unspecified.
-static std::pair<StringRef, StringRef>
-FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
-                        unsigned &LineNumber, Check::FileCheckType &CheckTy) {
-  SmallVector<StringRef, 2> Matches;
-
-  while (!Buffer.empty()) {
-    // Find the first (longest) match using the RE.
-    if (!PrefixRE.match(Buffer, &Matches))
-      // No match at all, bail.
-      return {StringRef(), StringRef()};
-
-    StringRef Prefix = Matches[0];
-    Matches.clear();
-
-    assert(Prefix.data() >= Buffer.data() &&
-           Prefix.data() < Buffer.data() + Buffer.size() &&
-           "Prefix doesn't start inside of buffer!");
-    size_t Loc = Prefix.data() - Buffer.data();
-    StringRef Skipped = Buffer.substr(0, Loc);
-    Buffer = Buffer.drop_front(Loc);
-    LineNumber += Skipped.count('\n');
-
-    // Check that the matched prefix isn't a suffix of some other check-like
-    // word.
-    // FIXME: This is a very ad-hoc check. it would be better handled in some
-    // other way. Among other things it seems hard to distinguish between
-    // intentional and unintentional uses of this feature.
-    if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {
-      // Now extract the type.
-      StringRef AfterSuffix;
-      std::tie(CheckTy, AfterSuffix) = FindCheckType(Buffer, Prefix);
-
-      // If we've found a valid check type for this prefix, we're done.
-      if (CheckTy != Check::CheckNone)
-        return {Prefix, AfterSuffix};
-    }
-
-    // If we didn't successfully find a prefix, we need to skip this invalid
-    // prefix and continue scanning. We directly skip the prefix that was
-    // matched and any additional parts of that check-like word.
-    Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size()));
-  }
-
-  // We ran out of buffer while skipping partial matches so give up.
-  return {StringRef(), StringRef()};
-}
-
-void FileCheckPatternContext::createLineVariable() {
-  assert(!LineVariable && "@LINE pseudo numeric variable already created");
-  StringRef LineName = "@LINE";
-  LineVariable = makeNumericVariable(LineName);
-  GlobalNumericVariableTable[LineName] = LineVariable;
-}
-
-FileCheck::FileCheck(FileCheckRequest Req)
-    : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()),
-      CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {}
-
-FileCheck::~FileCheck() = default;
-
-bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
-                              Regex &PrefixRE) {
-  Error DefineError =
-      PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM);
-  if (DefineError) {
-    logAllUnhandledErrors(std::move(DefineError), errs());
-    return true;
-  }
-
-  PatternContext->createLineVariable();
-
-  std::vector<FileCheckPattern> ImplicitNegativeChecks;
-  for (const auto &PatternString : Req.ImplicitCheckNot) {
-    // Create a buffer with fake command line content in order to display the
-    // command line option responsible for the specific implicit CHECK-NOT.
-    std::string Prefix = "-implicit-check-not='";
-    std::string Suffix = "'";
-    std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy(
-        Prefix + PatternString + Suffix, "command line");
-
-    StringRef PatternInBuffer =
-        CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
-    SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
-
-    ImplicitNegativeChecks.push_back(
-        FileCheckPattern(Check::CheckNot, PatternContext.get()));
-    ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,
-                                               "IMPLICIT-CHECK", SM, Req);
-  }
-
-  std::vector<FileCheckPattern> DagNotMatches = ImplicitNegativeChecks;
-
-  // LineNumber keeps track of the line on which CheckPrefix instances are
-  // found.
-  unsigned LineNumber = 1;
-
-  while (1) {
-    Check::FileCheckType CheckTy;
-
-    // See if a prefix occurs in the memory buffer.
-    StringRef UsedPrefix;
-    StringRef AfterSuffix;
-    std::tie(UsedPrefix, AfterSuffix) =
-        FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber, CheckTy);
-    if (UsedPrefix.empty())
-      break;
-    assert(UsedPrefix.data() == Buffer.data() &&
-           "Failed to move Buffer's start forward, or pointed prefix outside "
-           "of the buffer!");
-    assert(AfterSuffix.data() >= Buffer.data() &&
-           AfterSuffix.data() < Buffer.data() + Buffer.size() &&
-           "Parsing after suffix doesn't start inside of buffer!");
-
-    // Location to use for error messages.
-    const char *UsedPrefixStart = UsedPrefix.data();
-
-    // Skip the buffer to the end of parsed suffix (or just prefix, if no good
-    // suffix was processed).
-    Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size())
-                                 : AfterSuffix;
-
-    // Complain about useful-looking but unsupported suffixes.
-    if (CheckTy == Check::CheckBadNot) {
-      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
-                      "unsupported -NOT combo on prefix '" + UsedPrefix + "'");
-      return true;
-    }
-
-    // Complain about invalid count specification.
-    if (CheckTy == Check::CheckBadCount) {
-      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
-                      "invalid count in -COUNT specification on prefix '" +
-                          UsedPrefix + "'");
-      return true;
-    }
-
-    // Okay, we found the prefix, yay. Remember the rest of the line, but ignore
-    // leading whitespace.
-    if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
-      Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
-
-    // Scan ahead to the end of line.
-    size_t EOL = Buffer.find_first_of("\n\r");
-
-    // Remember the location of the start of the pattern, for diagnostics.
-    SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
-
-    // Parse the pattern.
-    FileCheckPattern P(CheckTy, PatternContext.get(), LineNumber);
-    if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req))
-      return true;
-
-    // Verify that CHECK-LABEL lines do not define or use variables
-    if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {
-      SM.PrintMessage(
-          SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error,
-          "found '" + UsedPrefix + "-LABEL:'"
-                                   " with variable definition or use");
-      return true;
-    }
-
-    Buffer = Buffer.substr(EOL);
-
-    // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
-    if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
-         CheckTy == Check::CheckEmpty) &&
-        CheckStrings->empty()) {
-      StringRef Type = CheckTy == Check::CheckNext
-                           ? "NEXT"
-                           : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";
-      SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
-                      SourceMgr::DK_Error,
-                      "found '" + UsedPrefix + "-" + Type +
-                          "' without previous '" + UsedPrefix + ": line");
-      return true;
-    }
-
-    // Handle CHECK-DAG/-NOT.
-    if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {
-      DagNotMatches.push_back(P);
-      continue;
-    }
-
-    // Okay, add the string we captured to the output vector and move on.
-    CheckStrings->emplace_back(P, UsedPrefix, PatternLoc);
-    std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);
-    DagNotMatches = ImplicitNegativeChecks;
-  }
-
-  // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
-  // prefix as a filler for the error message.
-  if (!DagNotMatches.empty()) {
-    CheckStrings->emplace_back(
-        FileCheckPattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1),
-        *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
-    std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);
-  }
-
-  if (CheckStrings->empty()) {
-    errs() << "error: no check strings found with prefix"
-           << (Req.CheckPrefixes.size() > 1 ? "es " : " ");
-    auto I = Req.CheckPrefixes.begin();
-    auto E = Req.CheckPrefixes.end();
-    if (I != E) {
-      errs() << "\'" << *I << ":'";
-      ++I;
-    }
-    for (; I != E; ++I)
-      errs() << ", \'" << *I << ":'";
-
-    errs() << '\n';
-    return true;
-  }
-
-  return false;
-}
-
-static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
-                       StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,
-                       int MatchedCount, StringRef Buffer, size_t MatchPos,
-                       size_t MatchLen, const FileCheckRequest &Req,
-                       std::vector<FileCheckDiag> *Diags) {
-  bool PrintDiag = true;
-  if (ExpectedMatch) {
-    if (!Req.Verbose)
-      return;
-    if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)
-      return;
-    // Due to their verbosity, we don't print verbose diagnostics here if we're
-    // gathering them for a different rendering, but we always print other
-    // diagnostics.
-    PrintDiag = !Diags;
-  }
-  SMRange MatchRange = ProcessMatchResult(
-      ExpectedMatch ? FileCheckDiag::MatchFoundAndExpected
-                    : FileCheckDiag::MatchFoundButExcluded,
-      SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags);
-  if (!PrintDiag)
-    return;
-
-  std::string Message = formatv("{0}: {1} string found in input",
-                                Pat.getCheckTy().getDescription(Prefix),
-                                (ExpectedMatch ? "expected" : "excluded"))
-                            .str();
-  if (Pat.getCount() > 1)
-    Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
-
-  SM.PrintMessage(
-      Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
-  SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",
-                  {MatchRange});
-  Pat.printSubstitutions(SM, Buffer, MatchRange);
-}
-
-static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
-                       const FileCheckString &CheckStr, int MatchedCount,
-                       StringRef Buffer, size_t MatchPos, size_t MatchLen,
-                       FileCheckRequest &Req,
-                       std::vector<FileCheckDiag> *Diags) {
-  PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
-             MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags);
-}
-
-static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
-                         StringRef Prefix, SMLoc Loc,
-                         const FileCheckPattern &Pat, int MatchedCount,
-                         StringRef Buffer, bool VerboseVerbose,
-                         std::vector<FileCheckDiag> *Diags, Error MatchErrors) {
-  assert(MatchErrors && "Called on successful match");
-  bool PrintDiag = true;
-  if (!ExpectedMatch) {
-    if (!VerboseVerbose) {
-      consumeError(std::move(MatchErrors));
-      return;
-    }
-    // Due to their verbosity, we don't print verbose diagnostics here if we're
-    // gathering them for a different rendering, but we always print other
-    // diagnostics.
-    PrintDiag = !Diags;
-  }
-
-  // If the current position is at the end of a line, advance to the start of
-  // the next line.
-  Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));
-  SMRange SearchRange = ProcessMatchResult(
-      ExpectedMatch ? FileCheckDiag::MatchNoneButExpected
-                    : FileCheckDiag::MatchNoneAndExcluded,
-      SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags);
-  if (!PrintDiag) {
-    consumeError(std::move(MatchErrors));
-    return;
-  }
-
-  MatchErrors =
-      handleErrors(std::move(MatchErrors),
-                   [](const FileCheckErrorDiagnostic &E) { E.log(errs()); });
-
-  // No problem matching the string per se.
-  if (!MatchErrors)
-    return;
-  consumeError(std::move(MatchErrors));
-
-  // Print "not found" diagnostic.
-  std::string Message = formatv("{0}: {1} string not found in input",
-                                Pat.getCheckTy().getDescription(Prefix),
-                                (ExpectedMatch ? "expected" : "excluded"))
-                            .str();
-  if (Pat.getCount() > 1)
-    Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
-  SM.PrintMessage(
-      Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message);
-
-  // Print the "scanning from here" line.
-  SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");
-
-  // Allow the pattern to print additional information if desired.
-  Pat.printSubstitutions(SM, Buffer);
-
-  if (ExpectedMatch)
-    Pat.printFuzzyMatch(SM, Buffer, Diags);
-}
-
-static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
-                         const FileCheckString &CheckStr, int MatchedCount,
-                         StringRef Buffer, bool VerboseVerbose,
-                         std::vector<FileCheckDiag> *Diags, Error MatchErrors) {
-  PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
-               MatchedCount, Buffer, VerboseVerbose, Diags,
-               std::move(MatchErrors));
-}
-
-/// Counts the number of newlines in the specified range.
-static unsigned CountNumNewlinesBetween(StringRef Range,
-                                        const char *&FirstNewLine) {
-  unsigned NumNewLines = 0;
-  while (1) {
-    // Scan for newline.
-    Range = Range.substr(Range.find_first_of("\n\r"));
-    if (Range.empty())
-      return NumNewLines;
-
-    ++NumNewLines;
-
-    // Handle \n\r and \r\n as a single newline.
-    if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') &&
-        (Range[0] != Range[1]))
-      Range = Range.substr(1);
-    Range = Range.substr(1);
-
-    if (NumNewLines == 1)
-      FirstNewLine = Range.begin();
-  }
-}
-
-size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
-                              bool IsLabelScanMode, size_t &MatchLen,
-                              FileCheckRequest &Req,
-                              std::vector<FileCheckDiag> *Diags) const {
-  size_t LastPos = 0;
-  std::vector<const FileCheckPattern *> NotStrings;
-
-  // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL
-  // bounds; we have not processed variable definitions within the bounded block
-  // yet so cannot handle any final CHECK-DAG yet; this is handled when going
-  // over the block again (including the last CHECK-LABEL) in normal mode.
-  if (!IsLabelScanMode) {
-    // Match "dag strings" (with mixed "not strings" if any).
-    LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);
-    if (LastPos == StringRef::npos)
-      return StringRef::npos;
-  }
-
-  // Match itself from the last position after matching CHECK-DAG.
-  size_t LastMatchEnd = LastPos;
-  size_t FirstMatchPos = 0;
-  // Go match the pattern Count times. Majority of patterns only match with
-  // count 1 though.
-  assert(Pat.getCount() != 0 && "pattern count can not be zero");
-  for (int i = 1; i <= Pat.getCount(); i++) {
-    StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
-    size_t CurrentMatchLen;
-    // get a match at current start point
-    Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM);
-
-    // report
-    if (!MatchResult) {
-      PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags,
-                   MatchResult.takeError());
-      return StringRef::npos;
-    }
-    size_t MatchPos = *MatchResult;
-    PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,
-               Diags);
-    if (i == 1)
-      FirstMatchPos = LastPos + MatchPos;
-
-    // move start point after the match
-    LastMatchEnd += MatchPos + CurrentMatchLen;
-  }
-  // Full match len counts from first match pos.
-  MatchLen = LastMatchEnd - FirstMatchPos;
-
-  // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
-  // or CHECK-NOT
-  if (!IsLabelScanMode) {
-    size_t MatchPos = FirstMatchPos - LastPos;
-    StringRef MatchBuffer = Buffer.substr(LastPos);
-    StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
-
-    // If this check is a "CHECK-NEXT", verify that the previous match was on
-    // the previous line (i.e. that there is one newline between them).
-    if (CheckNext(SM, SkippedRegion)) {
-      ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,
-                         Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
-                         Diags, Req.Verbose);
-      return StringRef::npos;
-    }
-
-    // If this check is a "CHECK-SAME", verify that the previous match was on
-    // the same line (i.e. that there is no newline between them).
-    if (CheckSame(SM, SkippedRegion)) {
-      ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,
-                         Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
-                         Diags, Req.Verbose);
-      return StringRef::npos;
-    }
-
-    // If this match had "not strings", verify that they don't exist in the
-    // skipped region.
-    if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
-      return StringRef::npos;
-  }
-
-  return FirstMatchPos;
-}
-
-bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
-  if (Pat.getCheckTy() != Check::CheckNext &&
-      Pat.getCheckTy() != Check::CheckEmpty)
-    return false;
-
-  Twine CheckName =
-      Prefix +
-      Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT");
-
-  // Count the number of newlines between the previous match and this one.
-  const char *FirstNewLine = nullptr;
-  unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
-
-  if (NumNewLines == 0) {
-    SM.PrintMessage(Loc, SourceMgr::DK_Error,
-                    CheckName + ": is on the same line as previous match");
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
-                    "'next' match was here");
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
-                    "previous match ended here");
-    return true;
-  }
-
-  if (NumNewLines != 1) {
-    SM.PrintMessage(Loc, SourceMgr::DK_Error,
-                    CheckName +
-                        ": is not on the line after the previous match");
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
-                    "'next' match was here");
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
-                    "previous match ended here");
-    SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note,
-                    "non-matching line after previous match is here");
-    return true;
-  }
-
-  return false;
-}
-
-bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
-  if (Pat.getCheckTy() != Check::CheckSame)
-    return false;
-
-  // Count the number of newlines between the previous match and this one.
-  const char *FirstNewLine = nullptr;
-  unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
-
-  if (NumNewLines != 0) {
-    SM.PrintMessage(Loc, SourceMgr::DK_Error,
-                    Prefix +
-                        "-SAME: is not on the same line as the previous match");
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
-                    "'next' match was here");
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
-                    "previous match ended here");
-    return true;
-  }
-
-  return false;
-}
-
-bool FileCheckString::CheckNot(
-    const SourceMgr &SM, StringRef Buffer,
-    const std::vector<const FileCheckPattern *> &NotStrings,
-    const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const {
-  for (const FileCheckPattern *Pat : NotStrings) {
-    assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
-
-    size_t MatchLen = 0;
-    Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM);
-
-    if (!MatchResult) {
-      PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
-                   Req.VerboseVerbose, Diags, MatchResult.takeError());
-      continue;
-    }
-    size_t Pos = *MatchResult;
-
-    PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,
-               Req, Diags);
-
-    return true;
-  }
-
-  return false;
-}
-
-size_t
-FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
-                          std::vector<const FileCheckPattern *> &NotStrings,
-                          const FileCheckRequest &Req,
-                          std::vector<FileCheckDiag> *Diags) const {
-  if (DagNotStrings.empty())
-    return 0;
-
-  // The start of the search range.
-  size_t StartPos = 0;
-
-  struct MatchRange {
-    size_t Pos;
-    size_t End;
-  };
-  // A sorted list of ranges for non-overlapping CHECK-DAG matches.  Match
-  // ranges are erased from this list once they are no longer in the search
-  // range.
-  std::list<MatchRange> MatchRanges;
-
-  // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG
-  // group, so we don't use a range-based for loop here.
-  for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();
-       PatItr != PatEnd; ++PatItr) {
-    const FileCheckPattern &Pat = *PatItr;
-    assert((Pat.getCheckTy() == Check::CheckDAG ||
-            Pat.getCheckTy() == Check::CheckNot) &&
-           "Invalid CHECK-DAG or CHECK-NOT!");
-
-    if (Pat.getCheckTy() == Check::CheckNot) {
-      NotStrings.push_back(&Pat);
-      continue;
-    }
-
-    assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");
-
-    // CHECK-DAG always matches from the start.
-    size_t MatchLen = 0, MatchPos = StartPos;
-
-    // Search for a match that doesn't overlap a previous match in this
-    // CHECK-DAG group.
-    for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
-      StringRef MatchBuffer = Buffer.substr(MatchPos);
-      Expected<size_t> MatchResult = Pat.match(MatchBuffer, MatchLen, SM);
-      // With a group of CHECK-DAGs, a single mismatching means the match on
-      // that group of CHECK-DAGs fails immediately.
-      if (!MatchResult) {
-        PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
-                     Req.VerboseVerbose, Diags, MatchResult.takeError());
-        return StringRef::npos;
-      }
-      size_t MatchPosBuf = *MatchResult;
-      // Re-calc it as the offset relative to the start of the original string.
-      MatchPos += MatchPosBuf;
-      if (Req.VerboseVerbose)
-        PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
-                   MatchLen, Req, Diags);
-      MatchRange M{MatchPos, MatchPos + MatchLen};
-      if (Req.AllowDeprecatedDagOverlap) {
-        // We don't need to track all matches in this mode, so we just maintain
-        // one match range that encompasses the current CHECK-DAG group's
-        // matches.
-        if (MatchRanges.empty())
-          MatchRanges.insert(MatchRanges.end(), M);
-        else {
-          auto Block = MatchRanges.begin();
-          Block->Pos = std::min(Block->Pos, M.Pos);
-          Block->End = std::max(Block->End, M.End);
-        }
-        break;
-      }
-      // Iterate previous matches until overlapping match or insertion point.
-      bool Overlap = false;
-      for (; MI != ME; ++MI) {
-        if (M.Pos < MI->End) {
-          // !Overlap => New match has no overlap and is before this old match.
-          // Overlap => New match overlaps this old match.
-          Overlap = MI->Pos < M.End;
-          break;
-        }
-      }
-      if (!Overlap) {
-        // Insert non-overlapping match into list.
-        MatchRanges.insert(MI, M);
-        break;
-      }
-      if (Req.VerboseVerbose) {
-        // Due to their verbosity, we don't print verbose diagnostics here if
-        // we're gathering them for a different rendering, but we always print
-        // other diagnostics.
-        if (!Diags) {
-          SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos);
-          SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End);
-          SMRange OldRange(OldStart, OldEnd);
-          SM.PrintMessage(OldStart, SourceMgr::DK_Note,
-                          "match discarded, overlaps earlier DAG match here",
-                          {OldRange});
-        } else
-          Diags->rbegin()->MatchTy = FileCheckDiag::MatchFoundButDiscarded;
-      }
-      MatchPos = MI->End;
-    }
-    if (!Req.VerboseVerbose)
-      PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
-                 MatchLen, Req, Diags);
-
-    // Handle the end of a CHECK-DAG group.
-    if (std::next(PatItr) == PatEnd ||
-        std::next(PatItr)->getCheckTy() == Check::CheckNot) {
-      if (!NotStrings.empty()) {
-        // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to
-        // CHECK-DAG, verify that there are no 'not' strings occurred in that
-        // region.
-        StringRef SkippedRegion =
-            Buffer.slice(StartPos, MatchRanges.begin()->Pos);
-        if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
-          return StringRef::npos;
-        // Clear "not strings".
-        NotStrings.clear();
-      }
-      // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the
-      // end of this CHECK-DAG group's match range.
-      StartPos = MatchRanges.rbegin()->End;
-      // Don't waste time checking for (impossible) overlaps before that.
-      MatchRanges.clear();
-    }
-  }
-
-  return StartPos;
-}
-
-// A check prefix must contain only alphanumeric, hyphens and underscores.
-static bool ValidateCheckPrefix(StringRef CheckPrefix) {
-  static const Regex Validator("^[a-zA-Z0-9_-]*$");
-  return Validator.match(CheckPrefix);
-}
-
-bool FileCheck::ValidateCheckPrefixes() {
-  StringSet<> PrefixSet;
-
-  for (StringRef Prefix : Req.CheckPrefixes) {
-    // Reject empty prefixes.
-    if (Prefix == "")
-      return false;
-
-    if (!PrefixSet.insert(Prefix).second)
-      return false;
-
-    if (!ValidateCheckPrefix(Prefix))
-      return false;
-  }
-
-  return true;
-}
-
-Regex FileCheck::buildCheckPrefixRegex() {
-  // I don't think there's a way to specify an initial value for cl::list,
-  // so if nothing was specified, add the default
-  if (Req.CheckPrefixes.empty())
-    Req.CheckPrefixes.push_back("CHECK");
-
-  // We already validated the contents of CheckPrefixes so just concatenate
-  // them as alternatives.
-  SmallString<32> PrefixRegexStr;
-  for (StringRef Prefix : Req.CheckPrefixes) {
-    if (Prefix != Req.CheckPrefixes.front())
-      PrefixRegexStr.push_back('|');
-
-    PrefixRegexStr.append(Prefix);
-  }
-
-  return Regex(PrefixRegexStr);
-}
-
-Error FileCheckPatternContext::defineCmdlineVariables(
-    std::vector<std::string> &CmdlineDefines, SourceMgr &SM) {
-  assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&
-         "Overriding defined variable with command-line variable definitions");
-
-  if (CmdlineDefines.empty())
-    return Error::success();
-
-  // Create a string representing the vector of command-line definitions. Each
-  // definition is on its own line and prefixed with a definition number to
-  // clarify which definition a given diagnostic corresponds to.
-  unsigned I = 0;
-  Error Errs = Error::success();
-  std::string CmdlineDefsDiag;
-  SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;
-  for (StringRef CmdlineDef : CmdlineDefines) {
-    std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();
-    size_t EqIdx = CmdlineDef.find('=');
-    if (EqIdx == StringRef::npos) {
-      CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));
-      continue;
-    }
-    // Numeric variable definition.
-    if (CmdlineDef[0] == '#') {
-      // Append a copy of the command-line definition adapted to use the same
-      // format as in the input file to be able to reuse
-      // parseNumericSubstitutionBlock.
-      CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();
-      std::string SubstitutionStr = CmdlineDef;
-      SubstitutionStr[EqIdx] = ':';
-      CmdlineDefsIndices.push_back(
-          std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));
-      CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();
-    } else {
-      CmdlineDefsDiag += DefPrefix;
-      CmdlineDefsIndices.push_back(
-          std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));
-      CmdlineDefsDiag += (CmdlineDef + "\n").str();
-    }
-  }
-
-  // Create a buffer with fake command line content in order to display
-  // parsing diagnostic with location information and point to the
-  // global definition with invalid syntax.
-  std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer =
-      MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines");
-  StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
-  SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());
-
-  for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {
-    StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,
-                                                     CmdlineDefIndices.second);
-    if (CmdlineDef.empty()) {
-      Errs = joinErrors(
-          std::move(Errs),
-          FileCheckErrorDiagnostic::get(
-              SM, CmdlineDef, "missing equal sign in global definition"));
-      continue;
-    }
-
-    // Numeric variable definition.
-    if (CmdlineDef[0] == '#') {
-      // Now parse the definition both to check that the syntax is correct and
-      // to create the necessary class instance.
-      StringRef CmdlineDefExpr = CmdlineDef.substr(1);
-      Optional<FileCheckNumericVariable *> DefinedNumericVariable;
-      Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionASTResult =
-          FileCheckPattern::parseNumericSubstitutionBlock(
-              CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);
-      if (!ExpressionASTResult) {
-        Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError());
-        continue;
-      }
-      std::unique_ptr<FileCheckExpressionAST> ExpressionAST =
-          std::move(*ExpressionASTResult);
-      // Now evaluate the expression whose value this variable should be set
-      // to, since the expression of a command-line variable definition should
-      // only use variables defined earlier on the command-line. If not, this
-      // is an error and we report it.
-      Expected<uint64_t> Value = ExpressionAST->eval();
-      if (!Value) {
-        Errs = joinErrors(std::move(Errs), Value.takeError());
-        continue;
-      }
-
-      assert(DefinedNumericVariable && "No variable defined");
-      (*DefinedNumericVariable)->setValue(*Value);
-
-      // Record this variable definition.
-      GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =
-          *DefinedNumericVariable;
-    } else {
-      // String variable definition.
-      std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
-      StringRef CmdlineName = CmdlineNameVal.first;
-      StringRef OrigCmdlineName = CmdlineName;
-      Expected<FileCheckPattern::VariableProperties> ParseVarResult =
-          FileCheckPattern::parseVariable(CmdlineName, SM);
-      if (!ParseVarResult) {
-        Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());
-        continue;
-      }
-      // Check that CmdlineName does not denote a pseudo variable is only
-      // composed of the parsed numeric variable. This catches cases like
-      // "FOO+2" in a "FOO+2=10" definition.
-      if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {
-        Errs = joinErrors(std::move(Errs),
-                          FileCheckErrorDiagnostic::get(
-                              SM, OrigCmdlineName,
-                              "invalid name in string variable definition '" +
-                                  OrigCmdlineName + "'"));
-        continue;
-      }
-      StringRef Name = ParseVarResult->Name;
-
-      // Detect collisions between string and numeric variables when the former
-      // is created later than the latter.
-      if (GlobalNumericVariableTable.find(Name) !=
-          GlobalNumericVariableTable.end()) {
-        Errs = joinErrors(std::move(Errs), FileCheckErrorDiagnostic::get(
-                                               SM, Name,
-                                               "numeric variable with name '" +
-                                                   Name + "' already exists"));
-        continue;
-      }
-      GlobalVariableTable.insert(CmdlineNameVal);
-      // Mark the string variable as defined to detect collisions between
-      // string and numeric variables in defineCmdlineVariables when the latter
-      // is created later than the former. We cannot reuse GlobalVariableTable
-      // for this by populating it with an empty string since we would then
-      // lose the ability to detect the use of an undefined variable in
-      // match().
-      DefinedVariableTable[Name] = true;
-    }
-  }
-
-  return Errs;
-}
-
-void FileCheckPatternContext::clearLocalVars() {
-  SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars;
-  for (const StringMapEntry<StringRef> &Var : GlobalVariableTable)
-    if (Var.first()[0] != '$')
-      LocalPatternVars.push_back(Var.first());
-
-  // Numeric substitution reads the value of a variable directly, not via
-  // GlobalNumericVariableTable. Therefore, we clear local variables by
-  // clearing their value which will lead to a numeric substitution failure. We
-  // also mark the variable for removal from GlobalNumericVariableTable since
-  // this is what defineCmdlineVariables checks to decide that no global
-  // variable has been defined.
-  for (const auto &Var : GlobalNumericVariableTable)
-    if (Var.first()[0] != '$') {
-      Var.getValue()->clearValue();
-      LocalNumericVars.push_back(Var.first());
-    }
-
-  for (const auto &Var : LocalPatternVars)
-    GlobalVariableTable.erase(Var);
-  for (const auto &Var : LocalNumericVars)
-    GlobalNumericVariableTable.erase(Var);
-}
-
-bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer,
-                           std::vector<FileCheckDiag> *Diags) {
-  bool ChecksFailed = false;
-
-  unsigned i = 0, j = 0, e = CheckStrings->size();
-  while (true) {
-    StringRef CheckRegion;
-    if (j == e) {
-      CheckRegion = Buffer;
-    } else {
-      const FileCheckString &CheckLabelStr = (*CheckStrings)[j];
-      if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) {
-        ++j;
-        continue;
-      }
-
-      // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
-      size_t MatchLabelLen = 0;
-      size_t MatchLabelPos =
-          CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);
-      if (MatchLabelPos == StringRef::npos)
-        // Immediately bail if CHECK-LABEL fails, nothing else we can do.
-        return false;
-
-      CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
-      Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);
-      ++j;
-    }
-
-    // Do not clear the first region as it's the one before the first
-    // CHECK-LABEL and it would clear variables defined on the command-line
-    // before they get used.
-    if (i != 0 && Req.EnableVarScope)
-      PatternContext->clearLocalVars();
-
-    for (; i != j; ++i) {
-      const FileCheckString &CheckStr = (*CheckStrings)[i];
-
-      // Check each string within the scanned region, including a second check
-      // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
-      size_t MatchLen = 0;
-      size_t MatchPos =
-          CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);
-
-      if (MatchPos == StringRef::npos) {
-        ChecksFailed = true;
-        i = j;
-        break;
-      }
-
-      CheckRegion = CheckRegion.substr(MatchPos + MatchLen);
-    }
-
-    if (j == e)
-      break;
-  }
-
-  // Success if no checks failed.
-  return !ChecksFailed;
-}
+//===- FileCheck.cpp - Check that File's Contents match what is expected --===//

+//

+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.

+// See https://llvm.org/LICENSE.txt for license information.

+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

+//

+//===----------------------------------------------------------------------===//

+//

+// FileCheck does a line-by line check of a file that validates whether it

+// contains the expected content.  This is useful for regression tests etc.

+//

+// This file implements most of the API that will be used by the FileCheck utility

+// as well as various unittests.

+//===----------------------------------------------------------------------===//

+

+#include "llvm/Support/FileCheck.h"

+#include "FileCheckImpl.h"

+#include "llvm/ADT/StringSet.h"

+#include "llvm/ADT/Twine.h"

+#include "llvm/Support/FormatVariadic.h"

+#include <cstdint>

+#include <list>

+#include <tuple>

+#include <utility>

+

+using namespace llvm;

+

+Expected<uint64_t> FileCheckNumericVariableUse::eval() const {

+  Optional<uint64_t> Value = NumericVariable->getValue();

+  if (Value)

+    return *Value;

+

+  return make_error<FileCheckUndefVarError>(Name);

+}

+

+Expected<uint64_t> FileCheckASTBinop::eval() const {

+  Expected<uint64_t> LeftOp = LeftOperand->eval();

+  Expected<uint64_t> RightOp = RightOperand->eval();

+

+  // Bubble up any error (e.g. undefined variables) in the recursive

+  // evaluation.

+  if (!LeftOp || !RightOp) {

+    Error Err = Error::success();

+    if (!LeftOp)

+      Err = joinErrors(std::move(Err), LeftOp.takeError());

+    if (!RightOp)

+      Err = joinErrors(std::move(Err), RightOp.takeError());

+    return std::move(Err);

+  }

+

+  return EvalBinop(*LeftOp, *RightOp);

+}

+

+Expected<std::string> FileCheckNumericSubstitution::getResult() const {

+  Expected<uint64_t> EvaluatedValue = ExpressionAST->eval();

+  if (!EvaluatedValue)

+    return EvaluatedValue.takeError();

+  return utostr(*EvaluatedValue);

+}

+

+Expected<std::string> FileCheckStringSubstitution::getResult() const {

+  // Look up the value and escape it so that we can put it into the regex.

+  Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr);

+  if (!VarVal)

+    return VarVal.takeError();

+  return Regex::escape(*VarVal);

+}

+

+bool FileCheckPattern::isValidVarNameStart(char C) {

+  return C == '_' || isalpha(C);

+}

+

+Expected<FileCheckPattern::VariableProperties>

+FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) {

+  if (Str.empty())

+    return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name");

+

+  bool ParsedOneChar = false;

+  unsigned I = 0;

+  bool IsPseudo = Str[0] == '@';

+

+  // Global vars start with '$'.

+  if (Str[0] == '$' || IsPseudo)

+    ++I;

+

+  for (unsigned E = Str.size(); I != E; ++I) {

+    if (!ParsedOneChar && !isValidVarNameStart(Str[I]))

+      return FileCheckErrorDiagnostic::get(SM, Str, "invalid variable name");

+

+    // Variable names are composed of alphanumeric characters and underscores.

+    if (Str[I] != '_' && !isalnum(Str[I]))

+      break;

+    ParsedOneChar = true;

+  }

+

+  StringRef Name = Str.take_front(I);

+  Str = Str.substr(I);

+  return VariableProperties {Name, IsPseudo};

+}

+

+// StringRef holding all characters considered as horizontal whitespaces by

+// FileCheck input canonicalization.

+constexpr StringLiteral SpaceChars = " \t";

+

+// Parsing helper function that strips the first character in S and returns it.

+static char popFront(StringRef &S) {

+  char C = S.front();

+  S = S.drop_front();

+  return C;

+}

+

+char FileCheckUndefVarError::ID = 0;

+char FileCheckErrorDiagnostic::ID = 0;

+char FileCheckNotFoundError::ID = 0;

+

+Expected<FileCheckNumericVariable *>

+FileCheckPattern::parseNumericVariableDefinition(

+    StringRef &Expr, FileCheckPatternContext *Context,

+    Optional<size_t> LineNumber, const SourceMgr &SM) {

+  Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);

+  if (!ParseVarResult)

+    return ParseVarResult.takeError();

+  StringRef Name = ParseVarResult->Name;

+

+  if (ParseVarResult->IsPseudo)

+    return FileCheckErrorDiagnostic::get(

+        SM, Name, "definition of pseudo numeric variable unsupported");

+

+  // Detect collisions between string and numeric variables when the latter

+  // is created later than the former.

+  if (Context->DefinedVariableTable.find(Name) !=

+      Context->DefinedVariableTable.end())

+    return FileCheckErrorDiagnostic::get(

+        SM, Name, "string variable with name '" + Name + "' already exists");

+

+  Expr = Expr.ltrim(SpaceChars);

+  if (!Expr.empty())

+    return FileCheckErrorDiagnostic::get(

+        SM, Expr, "unexpected characters after numeric variable name");

+

+  FileCheckNumericVariable *DefinedNumericVariable;

+  auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);

+  if (VarTableIter != Context->GlobalNumericVariableTable.end())

+    DefinedNumericVariable = VarTableIter->second;

+  else

+    DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber);

+

+  return DefinedNumericVariable;

+}

+

+Expected<std::unique_ptr<FileCheckNumericVariableUse>>

+FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,

+                                          Optional<size_t> LineNumber,

+                                          FileCheckPatternContext *Context,

+                                          const SourceMgr &SM) {

+  if (IsPseudo && !Name.equals("@LINE"))

+    return FileCheckErrorDiagnostic::get(

+        SM, Name, "invalid pseudo numeric variable '" + Name + "'");

+

+  // Numeric variable definitions and uses are parsed in the order in which

+  // they appear in the CHECK patterns. For each definition, the pointer to the

+  // class instance of the corresponding numeric variable definition is stored

+  // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer

+  // we get below is null, it means no such variable was defined before. When

+  // that happens, we create a dummy variable so that parsing can continue. All

+  // uses of undefined variables, whether string or numeric, are then diagnosed

+  // in printSubstitutions() after failing to match.

+  auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);

+  FileCheckNumericVariable *NumericVariable;

+  if (VarTableIter != Context->GlobalNumericVariableTable.end())

+    NumericVariable = VarTableIter->second;

+  else {

+    NumericVariable = Context->makeNumericVariable(Name);

+    Context->GlobalNumericVariableTable[Name] = NumericVariable;

+  }

+

+  Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber();

+  if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)

+    return FileCheckErrorDiagnostic::get(

+        SM, Name,

+        "numeric variable '" + Name +

+            "' defined earlier in the same CHECK directive");

+

+  return std::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);

+}

+

+Expected<std::unique_ptr<FileCheckExpressionAST>>

+FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,

+                                      Optional<size_t> LineNumber,

+                                      FileCheckPatternContext *Context,

+                                      const SourceMgr &SM) {

+  if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {

+    // Try to parse as a numeric variable use.

+    Expected<FileCheckPattern::VariableProperties> ParseVarResult =

+        parseVariable(Expr, SM);

+    if (ParseVarResult)

+      return parseNumericVariableUse(ParseVarResult->Name,

+                                     ParseVarResult->IsPseudo, LineNumber,

+                                     Context, SM);

+    if (AO == AllowedOperand::LineVar)

+      return ParseVarResult.takeError();

+    // Ignore the error and retry parsing as a literal.

+    consumeError(ParseVarResult.takeError());

+  }

+

+  // Otherwise, parse it as a literal.

+  uint64_t LiteralValue;

+  if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))

+    return std::make_unique<FileCheckExpressionLiteral>(LiteralValue);

+

+  return FileCheckErrorDiagnostic::get(SM, Expr,

+                                       "invalid operand format '" + Expr + "'");

+}

+

+static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {

+  return LeftOp + RightOp;

+}

+

+static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {

+  return LeftOp - RightOp;

+}

+

+Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop(

+    StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,

+    bool IsLegacyLineExpr, Optional<size_t> LineNumber,

+    FileCheckPatternContext *Context, const SourceMgr &SM) {

+  Expr = Expr.ltrim(SpaceChars);

+  if (Expr.empty())

+    return std::move(LeftOp);

+

+  // Check if this is a supported operation and select a function to perform

+  // it.

+  SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());

+  char Operator = popFront(Expr);

+  binop_eval_t EvalBinop;

+  switch (Operator) {

+  case '+':

+    EvalBinop = add;

+    break;

+  case '-':

+    EvalBinop = sub;

+    break;

+  default:

+    return FileCheckErrorDiagnostic::get(

+        SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'");

+  }

+

+  // Parse right operand.

+  Expr = Expr.ltrim(SpaceChars);

+  if (Expr.empty())

+    return FileCheckErrorDiagnostic::get(SM, Expr,

+                                         "missing operand in expression");

+  // The second operand in a legacy @LINE expression is always a literal.

+  AllowedOperand AO =

+      IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;

+  Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =

+      parseNumericOperand(Expr, AO, LineNumber, Context, SM);

+  if (!RightOpResult)

+    return RightOpResult;

+

+  Expr = Expr.ltrim(SpaceChars);

+  return std::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp),

+                                              std::move(*RightOpResult));

+}

+

+Expected<std::unique_ptr<FileCheckExpressionAST>>

+FileCheckPattern::parseNumericSubstitutionBlock(

+    StringRef Expr,

+    Optional<FileCheckNumericVariable *> &DefinedNumericVariable,

+    bool IsLegacyLineExpr, Optional<size_t> LineNumber,

+    FileCheckPatternContext *Context, const SourceMgr &SM) {

+  std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr;

+  StringRef DefExpr = StringRef();

+  DefinedNumericVariable = None;

+  // Save variable definition expression if any.

+  size_t DefEnd = Expr.find(':');

+  if (DefEnd != StringRef::npos) {

+    DefExpr = Expr.substr(0, DefEnd);

+    Expr = Expr.substr(DefEnd + 1);

+  }

+

+  // Parse the expression itself.

+  Expr = Expr.ltrim(SpaceChars);

+  if (!Expr.empty()) {

+    // The first operand in a legacy @LINE expression is always the @LINE

+    // pseudo variable.

+    AllowedOperand AO =

+        IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;

+    Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =

+        parseNumericOperand(Expr, AO, LineNumber, Context, SM);

+    while (ParseResult && !Expr.empty()) {

+      ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr,

+                               LineNumber, Context, SM);

+      // Legacy @LINE expressions only allow 2 operands.

+      if (ParseResult && IsLegacyLineExpr && !Expr.empty())

+        return FileCheckErrorDiagnostic::get(

+            SM, Expr,

+            "unexpected characters at end of expression '" + Expr + "'");

+    }

+    if (!ParseResult)

+      return ParseResult;

+    ExpressionAST = std::move(*ParseResult);

+  }

+

+  // Parse the numeric variable definition.

+  if (DefEnd != StringRef::npos) {

+    DefExpr = DefExpr.ltrim(SpaceChars);

+    Expected<FileCheckNumericVariable *> ParseResult =

+        parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);

+

+    if (!ParseResult)

+      return ParseResult.takeError();

+    DefinedNumericVariable = *ParseResult;

+  }

+

+  return std::move(ExpressionAST);

+}

+

+bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,

+                                    SourceMgr &SM,

+                                    const FileCheckRequest &Req) {

+  bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;

+  IgnoreCase = Req.IgnoreCase;

+

+  PatternLoc = SMLoc::getFromPointer(PatternStr.data());

+

+  if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))

+    // Ignore trailing whitespace.

+    while (!PatternStr.empty() &&

+           (PatternStr.back() == ' ' || PatternStr.back() == '\t'))

+      PatternStr = PatternStr.substr(0, PatternStr.size() - 1);

+

+  // Check that there is something on the line.

+  if (PatternStr.empty() && CheckTy != Check::CheckEmpty) {

+    SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,

+                    "found empty check string with prefix '" + Prefix + ":'");

+    return true;

+  }

+

+  if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) {

+    SM.PrintMessage(

+        PatternLoc, SourceMgr::DK_Error,

+        "found non-empty check string for empty check with prefix '" + Prefix +

+            ":'");

+    return true;

+  }

+

+  if (CheckTy == Check::CheckEmpty) {

+    RegExStr = "(\n$)";

+    return false;

+  }

+

+  // Check to see if this is a fixed string, or if it has regex pieces.

+  if (!MatchFullLinesHere &&

+      (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&

+                                 PatternStr.find("[[") == StringRef::npos))) {

+    FixedStr = PatternStr;

+    return false;

+  }

+

+  if (MatchFullLinesHere) {

+    RegExStr += '^';

+    if (!Req.NoCanonicalizeWhiteSpace)

+      RegExStr += " *";

+  }

+

+  // Paren value #0 is for the fully matched string.  Any new parenthesized

+  // values add from there.

+  unsigned CurParen = 1;

+

+  // Otherwise, there is at least one regex piece.  Build up the regex pattern

+  // by escaping scary characters in fixed strings, building up one big regex.

+  while (!PatternStr.empty()) {

+    // RegEx matches.

+    if (PatternStr.startswith("{{")) {

+      // This is the start of a regex match.  Scan for the }}.

+      size_t End = PatternStr.find("}}");

+      if (End == StringRef::npos) {

+        SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),

+                        SourceMgr::DK_Error,

+                        "found start of regex string with no end '}}'");

+        return true;

+      }

+

+      // Enclose {{}} patterns in parens just like [[]] even though we're not

+      // capturing the result for any purpose.  This is required in case the

+      // expression contains an alternation like: CHECK:  abc{{x|z}}def.  We

+      // want this to turn into: "abc(x|z)def" not "abcx|zdef".

+      RegExStr += '(';

+      ++CurParen;

+

+      if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM))

+        return true;

+      RegExStr += ')';

+

+      PatternStr = PatternStr.substr(End + 2);

+      continue;

+    }

+

+    // String and numeric substitution blocks. Pattern substitution blocks come

+    // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some

+    // other regex) and assigns it to the string variable 'foo'. The latter

+    // substitutes foo's value. Numeric substitution blocks recognize the same

+    // form as string ones, but start with a '#' sign after the double

+    // brackets. They also accept a combined form which sets a numeric variable

+    // to the evaluation of an expression. Both string and numeric variable

+    // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be

+    // valid, as this helps catch some common errors.

+    if (PatternStr.startswith("[[")) {

+      StringRef UnparsedPatternStr = PatternStr.substr(2);

+      // Find the closing bracket pair ending the match.  End is going to be an

+      // offset relative to the beginning of the match string.

+      size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);

+      StringRef MatchStr = UnparsedPatternStr.substr(0, End);

+      bool IsNumBlock = MatchStr.consume_front("#");

+

+      if (End == StringRef::npos) {

+        SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),

+                        SourceMgr::DK_Error,

+                        "Invalid substitution block, no ]] found");

+        return true;

+      }

+      // Strip the substitution block we are parsing. End points to the start

+      // of the "]]" closing the expression so account for it in computing the

+      // index of the first unparsed character.

+      PatternStr = UnparsedPatternStr.substr(End + 2);

+

+      bool IsDefinition = false;

+      bool SubstNeeded = false;

+      // Whether the substitution block is a legacy use of @LINE with string

+      // substitution block syntax.

+      bool IsLegacyLineExpr = false;

+      StringRef DefName;

+      StringRef SubstStr;

+      StringRef MatchRegexp;

+      size_t SubstInsertIdx = RegExStr.size();

+

+      // Parse string variable or legacy @LINE expression.

+      if (!IsNumBlock) {

+        size_t VarEndIdx = MatchStr.find(":");

+        size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");

+        if (SpacePos != StringRef::npos) {

+          SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos),

+                          SourceMgr::DK_Error, "unexpected whitespace");

+          return true;

+        }

+

+        // Get the name (e.g. "foo") and verify it is well formed.

+        StringRef OrigMatchStr = MatchStr;

+        Expected<FileCheckPattern::VariableProperties> ParseVarResult =

+            parseVariable(MatchStr, SM);

+        if (!ParseVarResult) {

+          logAllUnhandledErrors(ParseVarResult.takeError(), errs());

+          return true;

+        }

+        StringRef Name = ParseVarResult->Name;

+        bool IsPseudo = ParseVarResult->IsPseudo;

+

+        IsDefinition = (VarEndIdx != StringRef::npos);

+        SubstNeeded = !IsDefinition;

+        if (IsDefinition) {

+          if ((IsPseudo || !MatchStr.consume_front(":"))) {

+            SM.PrintMessage(SMLoc::getFromPointer(Name.data()),

+                            SourceMgr::DK_Error,

+                            "invalid name in string variable definition");

+            return true;

+          }

+

+          // Detect collisions between string and numeric variables when the

+          // former is created later than the latter.

+          if (Context->GlobalNumericVariableTable.find(Name) !=

+              Context->GlobalNumericVariableTable.end()) {

+            SM.PrintMessage(

+                SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,

+                "numeric variable with name '" + Name + "' already exists");

+            return true;

+          }

+          DefName = Name;

+          MatchRegexp = MatchStr;

+        } else {

+          if (IsPseudo) {

+            MatchStr = OrigMatchStr;

+            IsLegacyLineExpr = IsNumBlock = true;

+          } else

+            SubstStr = Name;

+        }

+      }

+

+      // Parse numeric substitution block.

+      std::unique_ptr<FileCheckExpressionAST> ExpressionAST;

+      Optional<FileCheckNumericVariable *> DefinedNumericVariable;

+      if (IsNumBlock) {

+        Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =

+            parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,

+                                          IsLegacyLineExpr, LineNumber, Context,

+                                          SM);

+        if (!ParseResult) {

+          logAllUnhandledErrors(ParseResult.takeError(), errs());

+          return true;

+        }

+        ExpressionAST = std::move(*ParseResult);

+        SubstNeeded = ExpressionAST != nullptr;

+        if (DefinedNumericVariable) {

+          IsDefinition = true;

+          DefName = (*DefinedNumericVariable)->getName();

+        }

+        if (SubstNeeded)

+          SubstStr = MatchStr;

+        else

+          MatchRegexp = "[0-9]+";

+      }

+

+      // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].

+      if (IsDefinition) {

+        RegExStr += '(';

+        ++SubstInsertIdx;

+

+        if (IsNumBlock) {

+          FileCheckNumericVariableMatch NumericVariableDefinition = {

+              *DefinedNumericVariable, CurParen};

+          NumericVariableDefs[DefName] = NumericVariableDefinition;

+          // This store is done here rather than in match() to allow

+          // parseNumericVariableUse() to get the pointer to the class instance

+          // of the right variable definition corresponding to a given numeric

+          // variable use.

+          Context->GlobalNumericVariableTable[DefName] =

+              *DefinedNumericVariable;

+        } else {

+          VariableDefs[DefName] = CurParen;

+          // Mark string variable as defined to detect collisions between

+          // string and numeric variables in parseNumericVariableUse() and

+          // defineCmdlineVariables() when the latter is created later than the

+          // former. We cannot reuse GlobalVariableTable for this by populating

+          // it with an empty string since we would then lose the ability to

+          // detect the use of an undefined variable in match().

+          Context->DefinedVariableTable[DefName] = true;

+        }

+

+        ++CurParen;

+      }

+

+      if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))

+        return true;

+

+      if (IsDefinition)

+        RegExStr += ')';

+

+      // Handle substitutions: [[foo]] and [[#<foo expr>]].

+      if (SubstNeeded) {

+        // Handle substitution of string variables that were defined earlier on

+        // the same line by emitting a backreference. Expressions do not

+        // support substituting a numeric variable defined on the same line.

+        if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) {

+          unsigned CaptureParenGroup = VariableDefs[SubstStr];

+          if (CaptureParenGroup < 1 || CaptureParenGroup > 9) {

+            SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()),

+                            SourceMgr::DK_Error,

+                            "Can't back-reference more than 9 variables");

+            return true;

+          }

+          AddBackrefToRegEx(CaptureParenGroup);

+        } else {

+          // Handle substitution of string variables ([[<var>]]) defined in

+          // previous CHECK patterns, and substitution of expressions.

+          FileCheckSubstitution *Substitution =

+              IsNumBlock

+                  ? Context->makeNumericSubstitution(

+                        SubstStr, std::move(ExpressionAST), SubstInsertIdx)

+                  : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);

+          Substitutions.push_back(Substitution);

+        }

+      }

+    }

+

+    // Handle fixed string matches.

+    // Find the end, which is the start of the next regex.

+    size_t FixedMatchEnd = PatternStr.find("{{");

+    FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));

+    RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd));

+    PatternStr = PatternStr.substr(FixedMatchEnd);

+  }

+

+  if (MatchFullLinesHere) {

+    if (!Req.NoCanonicalizeWhiteSpace)

+      RegExStr += " *";

+    RegExStr += '$';

+  }

+

+  return false;

+}

+

+bool FileCheckPattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) {

+  Regex R(RS);

+  std::string Error;

+  if (!R.isValid(Error)) {

+    SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error,

+                    "invalid regex: " + Error);

+    return true;

+  }

+

+  RegExStr += RS.str();

+  CurParen += R.getNumMatches();

+  return false;

+}

+

+void FileCheckPattern::AddBackrefToRegEx(unsigned BackrefNum) {

+  assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number");

+  std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum);

+  RegExStr += Backref;

+}

+

+Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,

+                                         const SourceMgr &SM) const {

+  // If this is the EOF pattern, match it immediately.

+  if (CheckTy == Check::CheckEOF) {

+    MatchLen = 0;

+    return Buffer.size();

+  }

+

+  // If this is a fixed string pattern, just match it now.

+  if (!FixedStr.empty()) {

+    MatchLen = FixedStr.size();

+    size_t Pos = IgnoreCase ? Buffer.find_lower(FixedStr)

+                            : Buffer.find(FixedStr);

+    if (Pos == StringRef::npos)

+      return make_error<FileCheckNotFoundError>();

+    return Pos;

+  }

+

+  // Regex match.

+

+  // If there are substitutions, we need to create a temporary string with the

+  // actual value.

+  StringRef RegExToMatch = RegExStr;

+  std::string TmpStr;

+  if (!Substitutions.empty()) {

+    TmpStr = RegExStr;

+    if (LineNumber)

+      Context->LineVariable->setValue(*LineNumber);

+

+    size_t InsertOffset = 0;

+    // Substitute all string variables and expressions whose values are only

+    // now known. Use of string variables defined on the same line are handled

+    // by back-references.

+    for (const auto &Substitution : Substitutions) {

+      // Substitute and check for failure (e.g. use of undefined variable).

+      Expected<std::string> Value = Substitution->getResult();

+      if (!Value)

+        return Value.takeError();

+

+      // Plop it into the regex at the adjusted offset.

+      TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,

+                    Value->begin(), Value->end());

+      InsertOffset += Value->size();

+    }

+

+    // Match the newly constructed regex.

+    RegExToMatch = TmpStr;

+  }

+

+  SmallVector<StringRef, 4> MatchInfo;

+  unsigned int Flags = Regex::Newline;

+  if (IgnoreCase)

+    Flags |= Regex::IgnoreCase;

+  if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo))

+    return make_error<FileCheckNotFoundError>();

+

+  // Successful regex match.

+  assert(!MatchInfo.empty() && "Didn't get any match");

+  StringRef FullMatch = MatchInfo[0];

+

+  // If this defines any string variables, remember their values.

+  for (const auto &VariableDef : VariableDefs) {

+    assert(VariableDef.second < MatchInfo.size() && "Internal paren error");

+    Context->GlobalVariableTable[VariableDef.first] =

+        MatchInfo[VariableDef.second];

+  }

+

+  // If this defines any numeric variables, remember their values.

+  for (const auto &NumericVariableDef : NumericVariableDefs) {

+    const FileCheckNumericVariableMatch &NumericVariableMatch =

+        NumericVariableDef.getValue();

+    unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup;

+    assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error");

+    FileCheckNumericVariable *DefinedNumericVariable =

+        NumericVariableMatch.DefinedNumericVariable;

+

+    StringRef MatchedValue = MatchInfo[CaptureParenGroup];

+    uint64_t Val;

+    if (MatchedValue.getAsInteger(10, Val))

+      return FileCheckErrorDiagnostic::get(SM, MatchedValue,

+                                           "Unable to represent numeric value");

+    DefinedNumericVariable->setValue(Val);

+  }

+

+  // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after

+  // the required preceding newline, which is consumed by the pattern in the

+  // case of CHECK-EMPTY but not CHECK-NEXT.

+  size_t MatchStartSkip = CheckTy == Check::CheckEmpty;

+  MatchLen = FullMatch.size() - MatchStartSkip;

+  return FullMatch.data() - Buffer.data() + MatchStartSkip;

+}

+

+unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const {

+  // Just compute the number of matching characters. For regular expressions, we

+  // just compare against the regex itself and hope for the best.

+  //

+  // FIXME: One easy improvement here is have the regex lib generate a single

+  // example regular expression which matches, and use that as the example

+  // string.

+  StringRef ExampleString(FixedStr);

+  if (ExampleString.empty())

+    ExampleString = RegExStr;

+

+  // Only compare up to the first line in the buffer, or the string size.

+  StringRef BufferPrefix = Buffer.substr(0, ExampleString.size());

+  BufferPrefix = BufferPrefix.split('\n').first;

+  return BufferPrefix.edit_distance(ExampleString);

+}

+

+void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,

+                                          SMRange MatchRange) const {

+  // Print what we know about substitutions.

+  if (!Substitutions.empty()) {

+    for (const auto &Substitution : Substitutions) {

+      SmallString<256> Msg;

+      raw_svector_ostream OS(Msg);

+      Expected<std::string> MatchedValue = Substitution->getResult();

+

+      // Substitution failed or is not known at match time, print the undefined

+      // variables it uses.

+      if (!MatchedValue) {

+        bool UndefSeen = false;

+        handleAllErrors(MatchedValue.takeError(),

+                        [](const FileCheckNotFoundError &E) {},

+                        // Handled in PrintNoMatch().

+                        [](const FileCheckErrorDiagnostic &E) {},

+                        [&](const FileCheckUndefVarError &E) {

+                          if (!UndefSeen) {

+                            OS << "uses undefined variable(s):";

+                            UndefSeen = true;

+                          }

+                          OS << " ";

+                          E.log(OS);

+                        });

+      } else {

+        // Substitution succeeded. Print substituted value.

+        OS << "with \"";

+        OS.write_escaped(Substitution->getFromString()) << "\" equal to \"";

+        OS.write_escaped(*MatchedValue) << "\"";

+      }

+

+      if (MatchRange.isValid())

+        SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(),

+                        {MatchRange});

+      else

+        SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),

+                        SourceMgr::DK_Note, OS.str());

+    }

+  }

+}

+

+static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,

+                                  const SourceMgr &SM, SMLoc Loc,

+                                  Check::FileCheckType CheckTy,

+                                  StringRef Buffer, size_t Pos, size_t Len,

+                                  std::vector<FileCheckDiag> *Diags,

+                                  bool AdjustPrevDiag = false) {

+  SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);

+  SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);

+  SMRange Range(Start, End);

+  if (Diags) {

+    if (AdjustPrevDiag)

+      Diags->rbegin()->MatchTy = MatchTy;

+    else

+      Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);

+  }

+  return Range;

+}

+

+void FileCheckPattern::printFuzzyMatch(

+    const SourceMgr &SM, StringRef Buffer,

+    std::vector<FileCheckDiag> *Diags) const {

+  // Attempt to find the closest/best fuzzy match.  Usually an error happens

+  // because some string in the output didn't exactly match. In these cases, we

+  // would like to show the user a best guess at what "should have" matched, to

+  // save them having to actually check the input manually.

+  size_t NumLinesForward = 0;

+  size_t Best = StringRef::npos;

+  double BestQuality = 0;

+

+  // Use an arbitrary 4k limit on how far we will search.

+  for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) {

+    if (Buffer[i] == '\n')

+      ++NumLinesForward;

+

+    // Patterns have leading whitespace stripped, so skip whitespace when

+    // looking for something which looks like a pattern.

+    if (Buffer[i] == ' ' || Buffer[i] == '\t')

+      continue;

+

+    // Compute the "quality" of this match as an arbitrary combination of the

+    // match distance and the number of lines skipped to get to this match.

+    unsigned Distance = computeMatchDistance(Buffer.substr(i));

+    double Quality = Distance + (NumLinesForward / 100.);

+

+    if (Quality < BestQuality || Best == StringRef::npos) {

+      Best = i;

+      BestQuality = Quality;

+    }

+  }

+

+  // Print the "possible intended match here" line if we found something

+  // reasonable and not equal to what we showed in the "scanning from here"

+  // line.

+  if (Best && Best != StringRef::npos && BestQuality < 50) {

+    SMRange MatchRange =

+        ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(),

+                           getCheckTy(), Buffer, Best, 0, Diags);

+    SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note,

+                    "possible intended match here");

+

+    // FIXME: If we wanted to be really friendly we would show why the match

+    // failed, as it can be hard to spot simple one character differences.

+  }

+}

+

+Expected<StringRef>

+FileCheckPatternContext::getPatternVarValue(StringRef VarName) {

+  auto VarIter = GlobalVariableTable.find(VarName);

+  if (VarIter == GlobalVariableTable.end())

+    return make_error<FileCheckUndefVarError>(VarName);

+

+  return VarIter->second;

+}

+

+template <class... Types>

+FileCheckNumericVariable *

+FileCheckPatternContext::makeNumericVariable(Types... args) {

+  NumericVariables.push_back(

+      std::make_unique<FileCheckNumericVariable>(args...));

+  return NumericVariables.back().get();

+}

+

+FileCheckSubstitution *

+FileCheckPatternContext::makeStringSubstitution(StringRef VarName,

+                                                size_t InsertIdx) {

+  Substitutions.push_back(

+      std::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx));

+  return Substitutions.back().get();

+}

+

+FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(

+    StringRef ExpressionStr,

+    std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) {

+  Substitutions.push_back(std::make_unique<FileCheckNumericSubstitution>(

+      this, ExpressionStr, std::move(ExpressionAST), InsertIdx));

+  return Substitutions.back().get();

+}

+

+size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {

+  // Offset keeps track of the current offset within the input Str

+  size_t Offset = 0;

+  // [...] Nesting depth

+  size_t BracketDepth = 0;

+

+  while (!Str.empty()) {

+    if (Str.startswith("]]") && BracketDepth == 0)

+      return Offset;

+    if (Str[0] == '\\') {

+      // Backslash escapes the next char within regexes, so skip them both.

+      Str = Str.substr(2);

+      Offset += 2;

+    } else {

+      switch (Str[0]) {

+      default:

+        break;

+      case '[':

+        BracketDepth++;

+        break;

+      case ']':

+        if (BracketDepth == 0) {

+          SM.PrintMessage(SMLoc::getFromPointer(Str.data()),

+                          SourceMgr::DK_Error,

+                          "missing closing \"]\" for regex variable");

+          exit(1);

+        }

+        BracketDepth--;

+        break;

+      }

+      Str = Str.substr(1);

+      Offset++;

+    }

+  }

+

+  return StringRef::npos;

+}

+

+StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB,

+                                      SmallVectorImpl<char> &OutputBuffer) {

+  OutputBuffer.reserve(MB.getBufferSize());

+

+  for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd();

+       Ptr != End; ++Ptr) {

+    // Eliminate trailing dosish \r.

+    if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') {

+      continue;

+    }

+

+    // If current char is not a horizontal whitespace or if horizontal

+    // whitespace canonicalization is disabled, dump it to output as is.

+    if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) {

+      OutputBuffer.push_back(*Ptr);

+      continue;

+    }

+

+    // Otherwise, add one space and advance over neighboring space.

+    OutputBuffer.push_back(' ');

+    while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t'))

+      ++Ptr;

+  }

+

+  // Add a null byte and then return all but that byte.

+  OutputBuffer.push_back('\0');

+  return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1);

+}

+

+FileCheckDiag::FileCheckDiag(const SourceMgr &SM,

+                             const Check::FileCheckType &CheckTy,

+                             SMLoc CheckLoc, MatchType MatchTy,

+                             SMRange InputRange)

+    : CheckTy(CheckTy), MatchTy(MatchTy) {

+  auto Start = SM.getLineAndColumn(InputRange.Start);

+  auto End = SM.getLineAndColumn(InputRange.End);

+  InputStartLine = Start.first;

+  InputStartCol = Start.second;

+  InputEndLine = End.first;

+  InputEndCol = End.second;

+  Start = SM.getLineAndColumn(CheckLoc);

+  CheckLine = Start.first;

+  CheckCol = Start.second;

+}

+

+static bool IsPartOfWord(char c) {

+  return (isalnum(c) || c == '-' || c == '_');

+}

+

+Check::FileCheckType &Check::FileCheckType::setCount(int C) {

+  assert(Count > 0 && "zero and negative counts are not supported");

+  assert((C == 1 || Kind == CheckPlain) &&

+         "count supported only for plain CHECK directives");

+  Count = C;

+  return *this;

+}

+

+std::string Check::FileCheckType::getDescription(StringRef Prefix) const {

+  switch (Kind) {

+  case Check::CheckNone:

+    return "invalid";

+  case Check::CheckPlain:

+    if (Count > 1)

+      return Prefix.str() + "-COUNT";

+    return Prefix;

+  case Check::CheckNext:

+    return Prefix.str() + "-NEXT";

+  case Check::CheckSame:

+    return Prefix.str() + "-SAME";

+  case Check::CheckNot:

+    return Prefix.str() + "-NOT";

+  case Check::CheckDAG:

+    return Prefix.str() + "-DAG";

+  case Check::CheckLabel:

+    return Prefix.str() + "-LABEL";

+  case Check::CheckEmpty:

+    return Prefix.str() + "-EMPTY";

+  case Check::CheckEOF:

+    return "implicit EOF";

+  case Check::CheckBadNot:

+    return "bad NOT";

+  case Check::CheckBadCount:

+    return "bad COUNT";

+  }

+  llvm_unreachable("unknown FileCheckType");

+}

+

+static std::pair<Check::FileCheckType, StringRef>

+FindCheckType(StringRef Buffer, StringRef Prefix) {

+  if (Buffer.size() <= Prefix.size())

+    return {Check::CheckNone, StringRef()};

+

+  char NextChar = Buffer[Prefix.size()];

+

+  StringRef Rest = Buffer.drop_front(Prefix.size() + 1);

+  // Verify that the : is present after the prefix.

+  if (NextChar == ':')

+    return {Check::CheckPlain, Rest};

+

+  if (NextChar != '-')

+    return {Check::CheckNone, StringRef()};

+

+  if (Rest.consume_front("COUNT-")) {

+    int64_t Count;

+    if (Rest.consumeInteger(10, Count))

+      // Error happened in parsing integer.

+      return {Check::CheckBadCount, Rest};

+    if (Count <= 0 || Count > INT32_MAX)

+      return {Check::CheckBadCount, Rest};

+    if (!Rest.consume_front(":"))

+      return {Check::CheckBadCount, Rest};

+    return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest};

+  }

+

+  if (Rest.consume_front("NEXT:"))

+    return {Check::CheckNext, Rest};

+

+  if (Rest.consume_front("SAME:"))

+    return {Check::CheckSame, Rest};

+

+  if (Rest.consume_front("NOT:"))

+    return {Check::CheckNot, Rest};

+

+  if (Rest.consume_front("DAG:"))

+    return {Check::CheckDAG, Rest};

+

+  if (Rest.consume_front("LABEL:"))

+    return {Check::CheckLabel, Rest};

+

+  if (Rest.consume_front("EMPTY:"))

+    return {Check::CheckEmpty, Rest};

+

+  // You can't combine -NOT with another suffix.

+  if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||

+      Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||

+      Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||

+      Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))

+    return {Check::CheckBadNot, Rest};

+

+  return {Check::CheckNone, Rest};

+}

+

+// From the given position, find the next character after the word.

+static size_t SkipWord(StringRef Str, size_t Loc) {

+  while (Loc < Str.size() && IsPartOfWord(Str[Loc]))

+    ++Loc;

+  return Loc;

+}

+

+/// Searches the buffer for the first prefix in the prefix regular expression.

+///

+/// This searches the buffer using the provided regular expression, however it

+/// enforces constraints beyond that:

+/// 1) The found prefix must not be a suffix of something that looks like

+///    a valid prefix.

+/// 2) The found prefix must be followed by a valid check type suffix using \c

+///    FindCheckType above.

+///

+/// \returns a pair of StringRefs into the Buffer, which combines:

+///   - the first match of the regular expression to satisfy these two is

+///   returned,

+///     otherwise an empty StringRef is returned to indicate failure.

+///   - buffer rewound to the location right after parsed suffix, for parsing

+///     to continue from

+///

+/// If this routine returns a valid prefix, it will also shrink \p Buffer to

+/// start at the beginning of the returned prefix, increment \p LineNumber for

+/// each new line consumed from \p Buffer, and set \p CheckTy to the type of

+/// check found by examining the suffix.

+///

+/// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy

+/// is unspecified.

+static std::pair<StringRef, StringRef>

+FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,

+                        unsigned &LineNumber, Check::FileCheckType &CheckTy) {

+  SmallVector<StringRef, 2> Matches;

+

+  while (!Buffer.empty()) {

+    // Find the first (longest) match using the RE.

+    if (!PrefixRE.match(Buffer, &Matches))

+      // No match at all, bail.

+      return {StringRef(), StringRef()};

+

+    StringRef Prefix = Matches[0];

+    Matches.clear();

+

+    assert(Prefix.data() >= Buffer.data() &&

+           Prefix.data() < Buffer.data() + Buffer.size() &&

+           "Prefix doesn't start inside of buffer!");

+    size_t Loc = Prefix.data() - Buffer.data();

+    StringRef Skipped = Buffer.substr(0, Loc);

+    Buffer = Buffer.drop_front(Loc);

+    LineNumber += Skipped.count('\n');

+

+    // Check that the matched prefix isn't a suffix of some other check-like

+    // word.

+    // FIXME: This is a very ad-hoc check. it would be better handled in some

+    // other way. Among other things it seems hard to distinguish between

+    // intentional and unintentional uses of this feature.

+    if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {

+      // Now extract the type.

+      StringRef AfterSuffix;

+      std::tie(CheckTy, AfterSuffix) = FindCheckType(Buffer, Prefix);

+

+      // If we've found a valid check type for this prefix, we're done.

+      if (CheckTy != Check::CheckNone)

+        return {Prefix, AfterSuffix};

+    }

+

+    // If we didn't successfully find a prefix, we need to skip this invalid

+    // prefix and continue scanning. We directly skip the prefix that was

+    // matched and any additional parts of that check-like word.

+    Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size()));

+  }

+

+  // We ran out of buffer while skipping partial matches so give up.

+  return {StringRef(), StringRef()};

+}

+

+void FileCheckPatternContext::createLineVariable() {

+  assert(!LineVariable && "@LINE pseudo numeric variable already created");

+  StringRef LineName = "@LINE";

+  LineVariable = makeNumericVariable(LineName);

+  GlobalNumericVariableTable[LineName] = LineVariable;

+}

+

+FileCheck::FileCheck(FileCheckRequest Req)

+    : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()),

+      CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {}

+

+FileCheck::~FileCheck() = default;

+

+bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,

+                              Regex &PrefixRE) {

+  Error DefineError =

+      PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM);

+  if (DefineError) {

+    logAllUnhandledErrors(std::move(DefineError), errs());

+    return true;

+  }

+

+  PatternContext->createLineVariable();

+

+  std::vector<FileCheckPattern> ImplicitNegativeChecks;

+  for (const auto &PatternString : Req.ImplicitCheckNot) {

+    // Create a buffer with fake command line content in order to display the

+    // command line option responsible for the specific implicit CHECK-NOT.

+    std::string Prefix = "-implicit-check-not='";

+    std::string Suffix = "'";

+    std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy(

+        Prefix + PatternString + Suffix, "command line");

+

+    StringRef PatternInBuffer =

+        CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());

+    SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());

+

+    ImplicitNegativeChecks.push_back(

+        FileCheckPattern(Check::CheckNot, PatternContext.get()));

+    ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,

+                                               "IMPLICIT-CHECK", SM, Req);

+  }

+

+  std::vector<FileCheckPattern> DagNotMatches = ImplicitNegativeChecks;

+

+  // LineNumber keeps track of the line on which CheckPrefix instances are

+  // found.

+  unsigned LineNumber = 1;

+

+  while (1) {

+    Check::FileCheckType CheckTy;

+

+    // See if a prefix occurs in the memory buffer.

+    StringRef UsedPrefix;

+    StringRef AfterSuffix;

+    std::tie(UsedPrefix, AfterSuffix) =

+        FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber, CheckTy);

+    if (UsedPrefix.empty())

+      break;

+    assert(UsedPrefix.data() == Buffer.data() &&

+           "Failed to move Buffer's start forward, or pointed prefix outside "

+           "of the buffer!");

+    assert(AfterSuffix.data() >= Buffer.data() &&

+           AfterSuffix.data() < Buffer.data() + Buffer.size() &&

+           "Parsing after suffix doesn't start inside of buffer!");

+

+    // Location to use for error messages.

+    const char *UsedPrefixStart = UsedPrefix.data();

+

+    // Skip the buffer to the end of parsed suffix (or just prefix, if no good

+    // suffix was processed).

+    Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size())

+                                 : AfterSuffix;

+

+    // Complain about useful-looking but unsupported suffixes.

+    if (CheckTy == Check::CheckBadNot) {

+      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,

+                      "unsupported -NOT combo on prefix '" + UsedPrefix + "'");

+      return true;

+    }

+

+    // Complain about invalid count specification.

+    if (CheckTy == Check::CheckBadCount) {

+      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,

+                      "invalid count in -COUNT specification on prefix '" +

+                          UsedPrefix + "'");

+      return true;

+    }

+

+    // Okay, we found the prefix, yay. Remember the rest of the line, but ignore

+    // leading whitespace.

+    if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))

+      Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));

+

+    // Scan ahead to the end of line.

+    size_t EOL = Buffer.find_first_of("\n\r");

+

+    // Remember the location of the start of the pattern, for diagnostics.

+    SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());

+

+    // Parse the pattern.

+    FileCheckPattern P(CheckTy, PatternContext.get(), LineNumber);

+    if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req))

+      return true;

+

+    // Verify that CHECK-LABEL lines do not define or use variables

+    if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {

+      SM.PrintMessage(

+          SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error,

+          "found '" + UsedPrefix + "-LABEL:'"

+                                   " with variable definition or use");

+      return true;

+    }

+

+    Buffer = Buffer.substr(EOL);

+

+    // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.

+    if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||

+         CheckTy == Check::CheckEmpty) &&

+        CheckStrings->empty()) {

+      StringRef Type = CheckTy == Check::CheckNext

+                           ? "NEXT"

+                           : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";

+      SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),

+                      SourceMgr::DK_Error,

+                      "found '" + UsedPrefix + "-" + Type +

+                          "' without previous '" + UsedPrefix + ": line");

+      return true;

+    }

+

+    // Handle CHECK-DAG/-NOT.

+    if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {

+      DagNotMatches.push_back(P);

+      continue;

+    }

+

+    // Okay, add the string we captured to the output vector and move on.

+    CheckStrings->emplace_back(P, UsedPrefix, PatternLoc);

+    std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);

+    DagNotMatches = ImplicitNegativeChecks;

+  }

+

+  // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first

+  // prefix as a filler for the error message.

+  if (!DagNotMatches.empty()) {

+    CheckStrings->emplace_back(

+        FileCheckPattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1),

+        *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));

+    std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);

+  }

+

+  if (CheckStrings->empty()) {

+    errs() << "error: no check strings found with prefix"

+           << (Req.CheckPrefixes.size() > 1 ? "es " : " ");

+    auto I = Req.CheckPrefixes.begin();

+    auto E = Req.CheckPrefixes.end();

+    if (I != E) {

+      errs() << "\'" << *I << ":'";

+      ++I;

+    }

+    for (; I != E; ++I)

+      errs() << ", \'" << *I << ":'";

+

+    errs() << '\n';

+    return true;

+  }

+

+  return false;

+}

+

+static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,

+                       StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,

+                       int MatchedCount, StringRef Buffer, size_t MatchPos,

+                       size_t MatchLen, const FileCheckRequest &Req,

+                       std::vector<FileCheckDiag> *Diags) {

+  bool PrintDiag = true;

+  if (ExpectedMatch) {

+    if (!Req.Verbose)

+      return;

+    if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)

+      return;

+    // Due to their verbosity, we don't print verbose diagnostics here if we're

+    // gathering them for a different rendering, but we always print other

+    // diagnostics.

+    PrintDiag = !Diags;

+  }

+  SMRange MatchRange = ProcessMatchResult(

+      ExpectedMatch ? FileCheckDiag::MatchFoundAndExpected

+                    : FileCheckDiag::MatchFoundButExcluded,

+      SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags);

+  if (!PrintDiag)

+    return;

+

+  std::string Message = formatv("{0}: {1} string found in input",

+                                Pat.getCheckTy().getDescription(Prefix),

+                                (ExpectedMatch ? "expected" : "excluded"))

+                            .str();

+  if (Pat.getCount() > 1)

+    Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();

+

+  SM.PrintMessage(

+      Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);

+  SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",

+                  {MatchRange});

+  Pat.printSubstitutions(SM, Buffer, MatchRange);

+}

+

+static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,

+                       const FileCheckString &CheckStr, int MatchedCount,

+                       StringRef Buffer, size_t MatchPos, size_t MatchLen,

+                       FileCheckRequest &Req,

+                       std::vector<FileCheckDiag> *Diags) {

+  PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,

+             MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags);

+}

+

+static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,

+                         StringRef Prefix, SMLoc Loc,

+                         const FileCheckPattern &Pat, int MatchedCount,

+                         StringRef Buffer, bool VerboseVerbose,

+                         std::vector<FileCheckDiag> *Diags, Error MatchErrors) {

+  assert(MatchErrors && "Called on successful match");

+  bool PrintDiag = true;

+  if (!ExpectedMatch) {

+    if (!VerboseVerbose) {

+      consumeError(std::move(MatchErrors));

+      return;

+    }

+    // Due to their verbosity, we don't print verbose diagnostics here if we're

+    // gathering them for a different rendering, but we always print other

+    // diagnostics.

+    PrintDiag = !Diags;

+  }

+

+  // If the current position is at the end of a line, advance to the start of

+  // the next line.

+  Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));

+  SMRange SearchRange = ProcessMatchResult(

+      ExpectedMatch ? FileCheckDiag::MatchNoneButExpected

+                    : FileCheckDiag::MatchNoneAndExcluded,

+      SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags);

+  if (!PrintDiag) {

+    consumeError(std::move(MatchErrors));

+    return;

+  }

+

+  MatchErrors =

+      handleErrors(std::move(MatchErrors),

+                   [](const FileCheckErrorDiagnostic &E) { E.log(errs()); });

+

+  // No problem matching the string per se.

+  if (!MatchErrors)

+    return;

+  consumeError(std::move(MatchErrors));

+

+  // Print "not found" diagnostic.

+  std::string Message = formatv("{0}: {1} string not found in input",

+                                Pat.getCheckTy().getDescription(Prefix),

+                                (ExpectedMatch ? "expected" : "excluded"))

+                            .str();

+  if (Pat.getCount() > 1)

+    Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();

+  SM.PrintMessage(

+      Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message);

+

+  // Print the "scanning from here" line.

+  SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");

+

+  // Allow the pattern to print additional information if desired.

+  Pat.printSubstitutions(SM, Buffer);

+

+  if (ExpectedMatch)

+    Pat.printFuzzyMatch(SM, Buffer, Diags);

+}

+

+static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,

+                         const FileCheckString &CheckStr, int MatchedCount,

+                         StringRef Buffer, bool VerboseVerbose,

+                         std::vector<FileCheckDiag> *Diags, Error MatchErrors) {

+  PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,

+               MatchedCount, Buffer, VerboseVerbose, Diags,

+               std::move(MatchErrors));

+}

+

+/// Counts the number of newlines in the specified range.

+static unsigned CountNumNewlinesBetween(StringRef Range,

+                                        const char *&FirstNewLine) {

+  unsigned NumNewLines = 0;

+  while (1) {

+    // Scan for newline.

+    Range = Range.substr(Range.find_first_of("\n\r"));

+    if (Range.empty())

+      return NumNewLines;

+

+    ++NumNewLines;

+

+    // Handle \n\r and \r\n as a single newline.

+    if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') &&

+        (Range[0] != Range[1]))

+      Range = Range.substr(1);

+    Range = Range.substr(1);

+

+    if (NumNewLines == 1)

+      FirstNewLine = Range.begin();

+  }

+}

+

+size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,

+                              bool IsLabelScanMode, size_t &MatchLen,

+                              FileCheckRequest &Req,

+                              std::vector<FileCheckDiag> *Diags) const {

+  size_t LastPos = 0;

+  std::vector<const FileCheckPattern *> NotStrings;

+

+  // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL

+  // bounds; we have not processed variable definitions within the bounded block

+  // yet so cannot handle any final CHECK-DAG yet; this is handled when going

+  // over the block again (including the last CHECK-LABEL) in normal mode.

+  if (!IsLabelScanMode) {

+    // Match "dag strings" (with mixed "not strings" if any).

+    LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);

+    if (LastPos == StringRef::npos)

+      return StringRef::npos;

+  }

+

+  // Match itself from the last position after matching CHECK-DAG.

+  size_t LastMatchEnd = LastPos;

+  size_t FirstMatchPos = 0;

+  // Go match the pattern Count times. Majority of patterns only match with

+  // count 1 though.

+  assert(Pat.getCount() != 0 && "pattern count can not be zero");

+  for (int i = 1; i <= Pat.getCount(); i++) {

+    StringRef MatchBuffer = Buffer.substr(LastMatchEnd);

+    size_t CurrentMatchLen;

+    // get a match at current start point

+    Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM);

+

+    // report

+    if (!MatchResult) {

+      PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags,

+                   MatchResult.takeError());

+      return StringRef::npos;

+    }

+    size_t MatchPos = *MatchResult;

+    PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,

+               Diags);

+    if (i == 1)

+      FirstMatchPos = LastPos + MatchPos;

+

+    // move start point after the match

+    LastMatchEnd += MatchPos + CurrentMatchLen;

+  }

+  // Full match len counts from first match pos.

+  MatchLen = LastMatchEnd - FirstMatchPos;

+

+  // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT

+  // or CHECK-NOT

+  if (!IsLabelScanMode) {

+    size_t MatchPos = FirstMatchPos - LastPos;

+    StringRef MatchBuffer = Buffer.substr(LastPos);

+    StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);

+

+    // If this check is a "CHECK-NEXT", verify that the previous match was on

+    // the previous line (i.e. that there is one newline between them).

+    if (CheckNext(SM, SkippedRegion)) {

+      ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,

+                         Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,

+                         Diags, Req.Verbose);

+      return StringRef::npos;

+    }

+

+    // If this check is a "CHECK-SAME", verify that the previous match was on

+    // the same line (i.e. that there is no newline between them).

+    if (CheckSame(SM, SkippedRegion)) {

+      ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,

+                         Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,

+                         Diags, Req.Verbose);

+      return StringRef::npos;

+    }

+

+    // If this match had "not strings", verify that they don't exist in the

+    // skipped region.

+    if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))

+      return StringRef::npos;

+  }

+

+  return FirstMatchPos;

+}

+

+bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {

+  if (Pat.getCheckTy() != Check::CheckNext &&

+      Pat.getCheckTy() != Check::CheckEmpty)

+    return false;

+

+  Twine CheckName =

+      Prefix +

+      Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT");

+

+  // Count the number of newlines between the previous match and this one.

+  const char *FirstNewLine = nullptr;

+  unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);

+

+  if (NumNewLines == 0) {

+    SM.PrintMessage(Loc, SourceMgr::DK_Error,

+                    CheckName + ": is on the same line as previous match");

+    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,

+                    "'next' match was here");

+    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,

+                    "previous match ended here");

+    return true;

+  }

+

+  if (NumNewLines != 1) {

+    SM.PrintMessage(Loc, SourceMgr::DK_Error,

+                    CheckName +

+                        ": is not on the line after the previous match");

+    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,

+                    "'next' match was here");

+    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,

+                    "previous match ended here");

+    SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note,

+                    "non-matching line after previous match is here");

+    return true;

+  }

+

+  return false;

+}

+

+bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {

+  if (Pat.getCheckTy() != Check::CheckSame)

+    return false;

+

+  // Count the number of newlines between the previous match and this one.

+  const char *FirstNewLine = nullptr;

+  unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);

+

+  if (NumNewLines != 0) {

+    SM.PrintMessage(Loc, SourceMgr::DK_Error,

+                    Prefix +

+                        "-SAME: is not on the same line as the previous match");

+    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,

+                    "'next' match was here");

+    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,

+                    "previous match ended here");

+    return true;

+  }

+

+  return false;

+}

+

+bool FileCheckString::CheckNot(

+    const SourceMgr &SM, StringRef Buffer,

+    const std::vector<const FileCheckPattern *> &NotStrings,

+    const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const {

+  for (const FileCheckPattern *Pat : NotStrings) {

+    assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");

+

+    size_t MatchLen = 0;

+    Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM);

+

+    if (!MatchResult) {

+      PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,

+                   Req.VerboseVerbose, Diags, MatchResult.takeError());

+      continue;

+    }

+    size_t Pos = *MatchResult;

+

+    PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,

+               Req, Diags);

+

+    return true;

+  }

+

+  return false;

+}

+

+size_t

+FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,

+                          std::vector<const FileCheckPattern *> &NotStrings,

+                          const FileCheckRequest &Req,

+                          std::vector<FileCheckDiag> *Diags) const {

+  if (DagNotStrings.empty())

+    return 0;

+

+  // The start of the search range.

+  size_t StartPos = 0;

+

+  struct MatchRange {

+    size_t Pos;

+    size_t End;

+  };

+  // A sorted list of ranges for non-overlapping CHECK-DAG matches.  Match

+  // ranges are erased from this list once they are no longer in the search

+  // range.

+  std::list<MatchRange> MatchRanges;

+

+  // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG

+  // group, so we don't use a range-based for loop here.

+  for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();

+       PatItr != PatEnd; ++PatItr) {

+    const FileCheckPattern &Pat = *PatItr;

+    assert((Pat.getCheckTy() == Check::CheckDAG ||

+            Pat.getCheckTy() == Check::CheckNot) &&

+           "Invalid CHECK-DAG or CHECK-NOT!");

+

+    if (Pat.getCheckTy() == Check::CheckNot) {

+      NotStrings.push_back(&Pat);

+      continue;

+    }

+

+    assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");

+

+    // CHECK-DAG always matches from the start.

+    size_t MatchLen = 0, MatchPos = StartPos;

+

+    // Search for a match that doesn't overlap a previous match in this

+    // CHECK-DAG group.

+    for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {

+      StringRef MatchBuffer = Buffer.substr(MatchPos);

+      Expected<size_t> MatchResult = Pat.match(MatchBuffer, MatchLen, SM);

+      // With a group of CHECK-DAGs, a single mismatching means the match on

+      // that group of CHECK-DAGs fails immediately.

+      if (!MatchResult) {

+        PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,

+                     Req.VerboseVerbose, Diags, MatchResult.takeError());

+        return StringRef::npos;

+      }

+      size_t MatchPosBuf = *MatchResult;

+      // Re-calc it as the offset relative to the start of the original string.

+      MatchPos += MatchPosBuf;

+      if (Req.VerboseVerbose)

+        PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,

+                   MatchLen, Req, Diags);

+      MatchRange M{MatchPos, MatchPos + MatchLen};

+      if (Req.AllowDeprecatedDagOverlap) {

+        // We don't need to track all matches in this mode, so we just maintain

+        // one match range that encompasses the current CHECK-DAG group's

+        // matches.

+        if (MatchRanges.empty())

+          MatchRanges.insert(MatchRanges.end(), M);

+        else {

+          auto Block = MatchRanges.begin();

+          Block->Pos = std::min(Block->Pos, M.Pos);

+          Block->End = std::max(Block->End, M.End);

+        }

+        break;

+      }

+      // Iterate previous matches until overlapping match or insertion point.

+      bool Overlap = false;

+      for (; MI != ME; ++MI) {

+        if (M.Pos < MI->End) {

+          // !Overlap => New match has no overlap and is before this old match.

+          // Overlap => New match overlaps this old match.

+          Overlap = MI->Pos < M.End;

+          break;

+        }

+      }

+      if (!Overlap) {

+        // Insert non-overlapping match into list.

+        MatchRanges.insert(MI, M);

+        break;

+      }

+      if (Req.VerboseVerbose) {

+        // Due to their verbosity, we don't print verbose diagnostics here if

+        // we're gathering them for a different rendering, but we always print

+        // other diagnostics.

+        if (!Diags) {

+          SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos);

+          SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End);

+          SMRange OldRange(OldStart, OldEnd);

+          SM.PrintMessage(OldStart, SourceMgr::DK_Note,

+                          "match discarded, overlaps earlier DAG match here",

+                          {OldRange});

+        } else

+          Diags->rbegin()->MatchTy = FileCheckDiag::MatchFoundButDiscarded;

+      }

+      MatchPos = MI->End;

+    }

+    if (!Req.VerboseVerbose)

+      PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,

+                 MatchLen, Req, Diags);

+

+    // Handle the end of a CHECK-DAG group.

+    if (std::next(PatItr) == PatEnd ||

+        std::next(PatItr)->getCheckTy() == Check::CheckNot) {

+      if (!NotStrings.empty()) {

+        // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to

+        // CHECK-DAG, verify that there are no 'not' strings occurred in that

+        // region.

+        StringRef SkippedRegion =

+            Buffer.slice(StartPos, MatchRanges.begin()->Pos);

+        if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))

+          return StringRef::npos;

+        // Clear "not strings".

+        NotStrings.clear();

+      }

+      // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the

+      // end of this CHECK-DAG group's match range.

+      StartPos = MatchRanges.rbegin()->End;

+      // Don't waste time checking for (impossible) overlaps before that.

+      MatchRanges.clear();

+    }

+  }

+

+  return StartPos;

+}

+

+// A check prefix must contain only alphanumeric, hyphens and underscores.

+static bool ValidateCheckPrefix(StringRef CheckPrefix) {

+  static const Regex Validator("^[a-zA-Z0-9_-]*$");

+  return Validator.match(CheckPrefix);

+}

+

+bool FileCheck::ValidateCheckPrefixes() {

+  StringSet<> PrefixSet;

+

+  for (StringRef Prefix : Req.CheckPrefixes) {

+    // Reject empty prefixes.

+    if (Prefix == "")

+      return false;

+

+    if (!PrefixSet.insert(Prefix).second)

+      return false;

+

+    if (!ValidateCheckPrefix(Prefix))

+      return false;

+  }

+

+  return true;

+}

+

+Regex FileCheck::buildCheckPrefixRegex() {

+  // I don't think there's a way to specify an initial value for cl::list,

+  // so if nothing was specified, add the default

+  if (Req.CheckPrefixes.empty())

+    Req.CheckPrefixes.push_back("CHECK");

+

+  // We already validated the contents of CheckPrefixes so just concatenate

+  // them as alternatives.

+  SmallString<32> PrefixRegexStr;

+  for (StringRef Prefix : Req.CheckPrefixes) {

+    if (Prefix != Req.CheckPrefixes.front())

+      PrefixRegexStr.push_back('|');

+

+    PrefixRegexStr.append(Prefix);

+  }

+

+  return Regex(PrefixRegexStr);

+}

+

+Error FileCheckPatternContext::defineCmdlineVariables(

+    std::vector<std::string> &CmdlineDefines, SourceMgr &SM) {

+  assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&

+         "Overriding defined variable with command-line variable definitions");

+

+  if (CmdlineDefines.empty())

+    return Error::success();

+

+  // Create a string representing the vector of command-line definitions. Each

+  // definition is on its own line and prefixed with a definition number to

+  // clarify which definition a given diagnostic corresponds to.

+  unsigned I = 0;

+  Error Errs = Error::success();

+  std::string CmdlineDefsDiag;

+  SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;

+  for (StringRef CmdlineDef : CmdlineDefines) {

+    std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();

+    size_t EqIdx = CmdlineDef.find('=');

+    if (EqIdx == StringRef::npos) {

+      CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));

+      continue;

+    }

+    // Numeric variable definition.

+    if (CmdlineDef[0] == '#') {

+      // Append a copy of the command-line definition adapted to use the same

+      // format as in the input file to be able to reuse

+      // parseNumericSubstitutionBlock.

+      CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();

+      std::string SubstitutionStr = CmdlineDef;

+      SubstitutionStr[EqIdx] = ':';

+      CmdlineDefsIndices.push_back(

+          std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));

+      CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();

+    } else {

+      CmdlineDefsDiag += DefPrefix;

+      CmdlineDefsIndices.push_back(

+          std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));

+      CmdlineDefsDiag += (CmdlineDef + "\n").str();

+    }

+  }

+

+  // Create a buffer with fake command line content in order to display

+  // parsing diagnostic with location information and point to the

+  // global definition with invalid syntax.

+  std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer =

+      MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines");

+  StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();

+  SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());

+

+  for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {

+    StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,

+                                                     CmdlineDefIndices.second);

+    if (CmdlineDef.empty()) {

+      Errs = joinErrors(

+          std::move(Errs),

+          FileCheckErrorDiagnostic::get(

+              SM, CmdlineDef, "missing equal sign in global definition"));

+      continue;

+    }

+

+    // Numeric variable definition.

+    if (CmdlineDef[0] == '#') {

+      // Now parse the definition both to check that the syntax is correct and

+      // to create the necessary class instance.

+      StringRef CmdlineDefExpr = CmdlineDef.substr(1);

+      Optional<FileCheckNumericVariable *> DefinedNumericVariable;

+      Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionASTResult =

+          FileCheckPattern::parseNumericSubstitutionBlock(

+              CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);

+      if (!ExpressionASTResult) {

+        Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError());

+        continue;

+      }

+      std::unique_ptr<FileCheckExpressionAST> ExpressionAST =

+          std::move(*ExpressionASTResult);

+      // Now evaluate the expression whose value this variable should be set

+      // to, since the expression of a command-line variable definition should

+      // only use variables defined earlier on the command-line. If not, this

+      // is an error and we report it.

+      Expected<uint64_t> Value = ExpressionAST->eval();

+      if (!Value) {

+        Errs = joinErrors(std::move(Errs), Value.takeError());

+        continue;

+      }

+

+      assert(DefinedNumericVariable && "No variable defined");

+      (*DefinedNumericVariable)->setValue(*Value);

+

+      // Record this variable definition.

+      GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =

+          *DefinedNumericVariable;

+    } else {

+      // String variable definition.

+      std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');

+      StringRef CmdlineName = CmdlineNameVal.first;

+      StringRef OrigCmdlineName = CmdlineName;

+      Expected<FileCheckPattern::VariableProperties> ParseVarResult =

+          FileCheckPattern::parseVariable(CmdlineName, SM);

+      if (!ParseVarResult) {

+        Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());

+        continue;

+      }

+      // Check that CmdlineName does not denote a pseudo variable is only

+      // composed of the parsed numeric variable. This catches cases like

+      // "FOO+2" in a "FOO+2=10" definition.

+      if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {

+        Errs = joinErrors(std::move(Errs),

+                          FileCheckErrorDiagnostic::get(

+                              SM, OrigCmdlineName,

+                              "invalid name in string variable definition '" +

+                                  OrigCmdlineName + "'"));

+        continue;

+      }

+      StringRef Name = ParseVarResult->Name;

+

+      // Detect collisions between string and numeric variables when the former

+      // is created later than the latter.

+      if (GlobalNumericVariableTable.find(Name) !=

+          GlobalNumericVariableTable.end()) {

+        Errs = joinErrors(std::move(Errs), FileCheckErrorDiagnostic::get(

+                                               SM, Name,

+                                               "numeric variable with name '" +

+                                                   Name + "' already exists"));

+        continue;

+      }

+      GlobalVariableTable.insert(CmdlineNameVal);

+      // Mark the string variable as defined to detect collisions between

+      // string and numeric variables in defineCmdlineVariables when the latter

+      // is created later than the former. We cannot reuse GlobalVariableTable

+      // for this by populating it with an empty string since we would then

+      // lose the ability to detect the use of an undefined variable in

+      // match().

+      DefinedVariableTable[Name] = true;

+    }

+  }

+

+  return Errs;

+}

+

+void FileCheckPatternContext::clearLocalVars() {

+  SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars;

+  for (const StringMapEntry<StringRef> &Var : GlobalVariableTable)

+    if (Var.first()[0] != '$')

+      LocalPatternVars.push_back(Var.first());

+

+  // Numeric substitution reads the value of a variable directly, not via

+  // GlobalNumericVariableTable. Therefore, we clear local variables by

+  // clearing their value which will lead to a numeric substitution failure. We

+  // also mark the variable for removal from GlobalNumericVariableTable since

+  // this is what defineCmdlineVariables checks to decide that no global

+  // variable has been defined.

+  for (const auto &Var : GlobalNumericVariableTable)

+    if (Var.first()[0] != '$') {

+      Var.getValue()->clearValue();

+      LocalNumericVars.push_back(Var.first());

+    }

+

+  for (const auto &Var : LocalPatternVars)

+    GlobalVariableTable.erase(Var);

+  for (const auto &Var : LocalNumericVars)

+    GlobalNumericVariableTable.erase(Var);

+}

+

+bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer,

+                           std::vector<FileCheckDiag> *Diags) {

+  bool ChecksFailed = false;

+

+  unsigned i = 0, j = 0, e = CheckStrings->size();

+  while (true) {

+    StringRef CheckRegion;

+    if (j == e) {

+      CheckRegion = Buffer;

+    } else {

+      const FileCheckString &CheckLabelStr = (*CheckStrings)[j];

+      if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) {

+        ++j;

+        continue;

+      }

+

+      // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG

+      size_t MatchLabelLen = 0;

+      size_t MatchLabelPos =

+          CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);

+      if (MatchLabelPos == StringRef::npos)

+        // Immediately bail if CHECK-LABEL fails, nothing else we can do.

+        return false;

+

+      CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);

+      Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);

+      ++j;

+    }

+

+    // Do not clear the first region as it's the one before the first

+    // CHECK-LABEL and it would clear variables defined on the command-line

+    // before they get used.

+    if (i != 0 && Req.EnableVarScope)

+      PatternContext->clearLocalVars();

+

+    for (; i != j; ++i) {

+      const FileCheckString &CheckStr = (*CheckStrings)[i];

+

+      // Check each string within the scanned region, including a second check

+      // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)

+      size_t MatchLen = 0;

+      size_t MatchPos =

+          CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);

+

+      if (MatchPos == StringRef::npos) {

+        ChecksFailed = true;

+        i = j;

+        break;

+      }

+

+      CheckRegion = CheckRegion.substr(MatchPos + MatchLen);

+    }

+

+    if (j == e)

+      break;

+  }

+

+  // Success if no checks failed.

+  return !ChecksFailed;

+}

diff --git a/llvm/lib/Support/FileCheckImpl.h b/llvm/lib/Support/FileCheckImpl.h
index 001b358..6581612 100644
--- a/llvm/lib/Support/FileCheckImpl.h
+++ b/llvm/lib/Support/FileCheckImpl.h
@@ -1,621 +1,624 @@
-//===-- FileCheckImpl.h - Private FileCheck Interface ------------*- C++ -*-==//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the private interfaces of FileCheck. Its purpose is to
-// allow unit testing of FileCheck and to separate the interface from the
-// implementation. It is only meant to be used by FileCheck.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIB_SUPPORT_FILECHECKIMPL_H
-#define LLVM_LIB_SUPPORT_FILECHECKIMPL_H
-
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/SourceMgr.h"
-#include <map>
-#include <string>
-#include <vector>
-
-namespace llvm {
-
-//===----------------------------------------------------------------------===//
-// Numeric substitution handling code.
-//===----------------------------------------------------------------------===//
-
-/// Base class representing the AST of a given expression.
-class FileCheckExpressionAST {
-public:
-  virtual ~FileCheckExpressionAST() = default;
-
-  /// Evaluates and \returns the value of the expression represented by this
-  /// AST or an error if evaluation fails.
-  virtual Expected<uint64_t> eval() const = 0;
-};
-
-/// Class representing an unsigned literal in the AST of an expression.
-class FileCheckExpressionLiteral : public FileCheckExpressionAST {
-private:
-  /// Actual value of the literal.
-  uint64_t Value;
-
-public:
-  /// Constructs a literal with the specified value.
-  FileCheckExpressionLiteral(uint64_t Val) : Value(Val) {}
-
-  /// \returns the literal's value.
-  Expected<uint64_t> eval() const { return Value; }
-};
-
-/// Class to represent an undefined variable error, which quotes that
-/// variable's name when printed.
-class FileCheckUndefVarError : public ErrorInfo<FileCheckUndefVarError> {
-private:
-  StringRef VarName;
-
-public:
-  static char ID;
-
-  FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}
-
-  StringRef getVarName() const { return VarName; }
-
-  std::error_code convertToErrorCode() const override {
-    return inconvertibleErrorCode();
-  }
-
-  /// Print name of variable associated with this error.
-  void log(raw_ostream &OS) const override {
-    OS << "\"";
-    OS.write_escaped(VarName) << "\"";
-  }
-};
-
-/// Class representing a numeric variable and its associated current value.
-class FileCheckNumericVariable {
-private:
-  /// Name of the numeric variable.
-  StringRef Name;
-
-  /// Value of numeric variable, if defined, or None otherwise.
-  Optional<uint64_t> Value;
-
-  /// Line number where this variable is defined, or None if defined before
-  /// input is parsed. Used to determine whether a variable is defined on the
-  /// same line as a given use.
-  Optional<size_t> DefLineNumber;
-
-public:
-  /// Constructor for a variable \p Name defined at line \p DefLineNumber or
-  /// defined before input is parsed if \p DefLineNumber is None.
-  explicit FileCheckNumericVariable(StringRef Name,
-                                    Optional<size_t> DefLineNumber = None)
-      : Name(Name), DefLineNumber(DefLineNumber) {}
-
-  /// \returns name of this numeric variable.
-  StringRef getName() const { return Name; }
-
-  /// \returns this variable's value.
-  Optional<uint64_t> getValue() const { return Value; }
-
-  /// Sets value of this numeric variable to \p NewValue.
-  void setValue(uint64_t NewValue) { Value = NewValue; }
-
-  /// Clears value of this numeric variable, regardless of whether it is
-  /// currently defined or not.
-  void clearValue() { Value = None; }
-
-  /// \returns the line number where this variable is defined, if any, or None
-  /// if defined before input is parsed.
-  Optional<size_t> getDefLineNumber() { return DefLineNumber; }
-};
-
-/// Class representing the use of a numeric variable in the AST of an
-/// expression.
-class FileCheckNumericVariableUse : public FileCheckExpressionAST {
-private:
-  /// Name of the numeric variable.
-  StringRef Name;
-
-  /// Pointer to the class instance for the variable this use is about.
-  FileCheckNumericVariable *NumericVariable;
-
-public:
-  FileCheckNumericVariableUse(StringRef Name,
-                              FileCheckNumericVariable *NumericVariable)
-      : Name(Name), NumericVariable(NumericVariable) {}
-
-  /// \returns the value of the variable referenced by this instance.
-  Expected<uint64_t> eval() const;
-};
-
-/// Type of functions evaluating a given binary operation.
-using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
-
-/// Class representing a single binary operation in the AST of an expression.
-class FileCheckASTBinop : public FileCheckExpressionAST {
-private:
-  /// Left operand.
-  std::unique_ptr<FileCheckExpressionAST> LeftOperand;
-
-  /// Right operand.
-  std::unique_ptr<FileCheckExpressionAST> RightOperand;
-
-  /// Pointer to function that can evaluate this binary operation.
-  binop_eval_t EvalBinop;
-
-public:
-  FileCheckASTBinop(binop_eval_t EvalBinop,
-                    std::unique_ptr<FileCheckExpressionAST> LeftOp,
-                    std::unique_ptr<FileCheckExpressionAST> RightOp)
-      : EvalBinop(EvalBinop) {
-    LeftOperand = std::move(LeftOp);
-    RightOperand = std::move(RightOp);
-  }
-
-  /// Evaluates the value of the binary operation represented by this AST,
-  /// using EvalBinop on the result of recursively evaluating the operands.
-  /// \returns the expression value or an error if an undefined numeric
-  /// variable is used in one of the operands.
-  Expected<uint64_t> eval() const;
-};
-
-class FileCheckPatternContext;
-
-/// Class representing a substitution to perform in the RegExStr string.
-class FileCheckSubstitution {
-protected:
-  /// Pointer to a class instance holding, among other things, the table with
-  /// the values of live string variables at the start of any given CHECK line.
-  /// Used for substituting string variables with the text they were defined
-  /// as. Expressions are linked to the numeric variables they use at
-  /// parse time and directly access the value of the numeric variable to
-  /// evaluate their value.
-  FileCheckPatternContext *Context;
-
-  /// The string that needs to be substituted for something else. For a
-  /// string variable this is its name, otherwise this is the whole expression.
-  StringRef FromStr;
-
-  // Index in RegExStr of where to do the substitution.
-  size_t InsertIdx;
-
-public:
-  FileCheckSubstitution(FileCheckPatternContext *Context, StringRef VarName,
-                        size_t InsertIdx)
-      : Context(Context), FromStr(VarName), InsertIdx(InsertIdx) {}
-
-  virtual ~FileCheckSubstitution() = default;
-
-  /// \returns the string to be substituted for something else.
-  StringRef getFromString() const { return FromStr; }
-
-  /// \returns the index where the substitution is to be performed in RegExStr.
-  size_t getIndex() const { return InsertIdx; }
-
-  /// \returns a string containing the result of the substitution represented
-  /// by this class instance or an error if substitution failed.
-  virtual Expected<std::string> getResult() const = 0;
-};
-
-class FileCheckStringSubstitution : public FileCheckSubstitution {
-public:
-  FileCheckStringSubstitution(FileCheckPatternContext *Context,
-                              StringRef VarName, size_t InsertIdx)
-      : FileCheckSubstitution(Context, VarName, InsertIdx) {}
-
-  /// \returns the text that the string variable in this substitution matched
-  /// when defined, or an error if the variable is undefined.
-  Expected<std::string> getResult() const override;
-};
-
-class FileCheckNumericSubstitution : public FileCheckSubstitution {
-private:
-  /// Pointer to the class representing the expression whose value is to be
-  /// substituted.
-  std::unique_ptr<FileCheckExpressionAST> ExpressionAST;
-
-public:
-  FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr,
-                               std::unique_ptr<FileCheckExpressionAST> ExprAST,
-                               size_t InsertIdx)
-      : FileCheckSubstitution(Context, Expr, InsertIdx) {
-    ExpressionAST = std::move(ExprAST);
-  }
-
-  /// \returns a string containing the result of evaluating the expression in
-  /// this substitution, or an error if evaluation failed.
-  Expected<std::string> getResult() const override;
-};
-
-//===----------------------------------------------------------------------===//
-// Pattern handling code.
-//===----------------------------------------------------------------------===//
-
-struct FileCheckDiag;
-
-/// Class holding the FileCheckPattern global state, shared by all patterns:
-/// tables holding values of variables and whether they are defined or not at
-/// any given time in the matching process.
-class FileCheckPatternContext {
-  friend class FileCheckPattern;
-
-private:
-  /// When matching a given pattern, this holds the value of all the string
-  /// variables defined in previous patterns. In a pattern, only the last
-  /// definition for a given variable is recorded in this table.
-  /// Back-references are used for uses after any the other definition.
-  StringMap<StringRef> GlobalVariableTable;
-
-  /// Map of all string variables defined so far. Used at parse time to detect
-  /// a name conflict between a numeric variable and a string variable when
-  /// the former is defined on a later line than the latter.
-  StringMap<bool> DefinedVariableTable;
-
-  /// When matching a given pattern, this holds the pointers to the classes
-  /// representing the numeric variables defined in previous patterns. When
-  /// matching a pattern all definitions for that pattern are recorded in the
-  /// NumericVariableDefs table in the FileCheckPattern instance of that
-  /// pattern.
-  StringMap<FileCheckNumericVariable *> GlobalNumericVariableTable;
-
-  /// Pointer to the class instance representing the @LINE pseudo variable for
-  /// easily updating its value.
-  FileCheckNumericVariable *LineVariable = nullptr;
-
-  /// Vector holding pointers to all parsed numeric variables. Used to
-  /// automatically free them once they are guaranteed to no longer be used.
-  std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;
-
-  /// Vector holding pointers to all substitutions. Used to automatically free
-  /// them once they are guaranteed to no longer be used.
-  std::vector<std::unique_ptr<FileCheckSubstitution>> Substitutions;
-
-public:
-  /// \returns the value of string variable \p VarName or an error if no such
-  /// variable has been defined.
-  Expected<StringRef> getPatternVarValue(StringRef VarName);
-
-  /// Defines string and numeric variables from definitions given on the
-  /// command line, passed as a vector of [#]VAR=VAL strings in
-  /// \p CmdlineDefines. \returns an error list containing diagnostics against
-  /// \p SM for all definition parsing failures, if any, or Success otherwise.
-  Error defineCmdlineVariables(std::vector<std::string> &CmdlineDefines,
-                               SourceMgr &SM);
-
-  /// Create @LINE pseudo variable. Value is set when pattern are being
-  /// matched.
-  void createLineVariable();
-
-  /// Undefines local variables (variables whose name does not start with a '$'
-  /// sign), i.e. removes them from GlobalVariableTable and from
-  /// GlobalNumericVariableTable and also clears the value of numeric
-  /// variables.
-  void clearLocalVars();
-
-private:
-  /// Makes a new numeric variable and registers it for destruction when the
-  /// context is destroyed.
-  template <class... Types>
-  FileCheckNumericVariable *makeNumericVariable(Types... args);
-
-  /// Makes a new string substitution and registers it for destruction when the
-  /// context is destroyed.
-  FileCheckSubstitution *makeStringSubstitution(StringRef VarName,
-                                                size_t InsertIdx);
-
-  /// Makes a new numeric substitution and registers it for destruction when
-  /// the context is destroyed.
-  FileCheckSubstitution *
-  makeNumericSubstitution(StringRef ExpressionStr,
-                          std::unique_ptr<FileCheckExpressionAST> ExpressionAST,
-                          size_t InsertIdx);
-};
-
-/// Class to represent an error holding a diagnostic with location information
-/// used when printing it.
-class FileCheckErrorDiagnostic : public ErrorInfo<FileCheckErrorDiagnostic> {
-private:
-  SMDiagnostic Diagnostic;
-
-public:
-  static char ID;
-
-  FileCheckErrorDiagnostic(SMDiagnostic &&Diag) : Diagnostic(Diag) {}
-
-  std::error_code convertToErrorCode() const override {
-    return inconvertibleErrorCode();
-  }
-
-  /// Print diagnostic associated with this error when printing the error.
-  void log(raw_ostream &OS) const override { Diagnostic.print(nullptr, OS); }
-
-  static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg) {
-    return make_error<FileCheckErrorDiagnostic>(
-        SM.GetMessage(Loc, SourceMgr::DK_Error, ErrMsg));
-  }
-
-  static Error get(const SourceMgr &SM, StringRef Buffer, const Twine &ErrMsg) {
-    return get(SM, SMLoc::getFromPointer(Buffer.data()), ErrMsg);
-  }
-};
-
-class FileCheckNotFoundError : public ErrorInfo<FileCheckNotFoundError> {
-public:
-  static char ID;
-
-  std::error_code convertToErrorCode() const override {
-    return inconvertibleErrorCode();
-  }
-
-  /// Print diagnostic associated with this error when printing the error.
-  void log(raw_ostream &OS) const override {
-    OS << "String not found in input";
-  }
-};
-
-class FileCheckPattern {
-  SMLoc PatternLoc;
-
-  /// A fixed string to match as the pattern or empty if this pattern requires
-  /// a regex match.
-  StringRef FixedStr;
-
-  /// A regex string to match as the pattern or empty if this pattern requires
-  /// a fixed string to match.
-  std::string RegExStr;
-
-  /// Entries in this vector represent a substitution of a string variable or
-  /// an expression in the RegExStr regex at match time. For example, in the
-  /// case of a CHECK directive with the pattern "foo[[bar]]baz[[#N+1]]",
-  /// RegExStr will contain "foobaz" and we'll get two entries in this vector
-  /// that tells us to insert the value of string variable "bar" at offset 3
-  /// and the value of expression "N+1" at offset 6.
-  std::vector<FileCheckSubstitution *> Substitutions;
-
-  /// Maps names of string variables defined in a pattern to the number of
-  /// their parenthesis group in RegExStr capturing their last definition.
-  ///
-  /// E.g. for the pattern "foo[[bar:.*]]baz([[bar]][[QUUX]][[bar:.*]])",
-  /// RegExStr will be "foo(.*)baz(\1<quux value>(.*))" where <quux value> is
-  /// the value captured for QUUX on the earlier line where it was defined, and
-  /// VariableDefs will map "bar" to the third parenthesis group which captures
-  /// the second definition of "bar".
-  ///
-  /// Note: uses std::map rather than StringMap to be able to get the key when
-  /// iterating over values.
-  std::map<StringRef, unsigned> 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.
-  struct FileCheckNumericVariableMatch {
-    /// Pointer to class representing the numeric variable whose value is being
-    /// defined.
-    FileCheckNumericVariable *DefinedNumericVariable;
-
-    /// Number of the parenthesis group in RegExStr that captures the value of
-    /// this numeric variable definition.
-    unsigned CaptureParenGroup;
-  };
-
-  /// Holds the number of the parenthesis group in RegExStr and pointer to the
-  /// corresponding FileCheckNumericVariable class instance of all numeric
-  /// variable definitions. Used to set the matched value of all those
-  /// variables.
-  StringMap<FileCheckNumericVariableMatch> NumericVariableDefs;
-
-  /// Pointer to a class instance holding the global state shared by all
-  /// patterns:
-  /// - separate tables with the values of live string and numeric variables
-  ///   respectively at the start of any given CHECK line;
-  /// - table holding whether a string variable has been defined at any given
-  ///   point during the parsing phase.
-  FileCheckPatternContext *Context;
-
-  Check::FileCheckType CheckTy;
-
-  /// Line number for this CHECK pattern or None if it is an implicit pattern.
-  /// Used to determine whether a variable definition is made on an earlier
-  /// line to the one with this CHECK.
-  Optional<size_t> LineNumber;
-
-public:
-  FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context,
-                   Optional<size_t> Line = None)
-      : Context(Context), CheckTy(Ty), LineNumber(Line) {}
-
-  /// \returns the location in source code.
-  SMLoc getLoc() const { return PatternLoc; }
-
-  /// \returns the pointer to the global state for all patterns in this
-  /// FileCheck instance.
-  FileCheckPatternContext *getContext() const { return Context; }
-
-  /// \returns whether \p C is a valid first character for a variable name.
-  static bool isValidVarNameStart(char C);
-
-  /// Parsing information about a variable.
-  struct VariableProperties {
-    StringRef Name;
-    bool IsPseudo;
-  };
-
-  /// Parses the string at the start of \p Str for a variable name. \returns
-  /// a VariableProperties structure holding the variable name and whether it
-  /// is the name of a pseudo variable, or an error holding a diagnostic
-  /// against \p SM if parsing fail. If parsing was successful, also strips
-  /// \p Str from the variable name.
-  static Expected<VariableProperties> parseVariable(StringRef &Str,
-                                                    const SourceMgr &SM);
-  /// Parses \p Expr for a numeric substitution block at line \p LineNumber,
-  /// or before input is parsed if \p LineNumber is None. Parameter
-  /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE
-  /// expression 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 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<std::unique_ptr<FileCheckExpressionAST>>
-  parseNumericSubstitutionBlock(
-      StringRef Expr,
-      Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
-      bool IsLegacyLineExpr, Optional<size_t> LineNumber,
-      FileCheckPatternContext *Context, const SourceMgr &SM);
-  /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
-  /// instance accordingly.
-  ///
-  /// \p Prefix provides which prefix is being matched, \p Req describes the
-  /// global options that influence the parsing such as whitespace
-  /// canonicalization, \p SM provides the SourceMgr used for error reports.
-  /// \returns true in case of an error, false otherwise.
-  bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
-                    const FileCheckRequest &Req);
-  /// Matches the pattern string against the input buffer \p Buffer
-  ///
-  /// \returns the position that is matched or an error indicating why matching
-  /// failed. If there is a match, updates \p MatchLen with the size of the
-  /// matched string.
-  ///
-  /// The GlobalVariableTable StringMap in the FileCheckPatternContext class
-  /// instance provides the current values of FileCheck string variables and
-  /// is updated if this match defines new values. Likewise, the
-  /// GlobalNumericVariableTable StringMap in the same class provides the
-  /// current values of FileCheck numeric variables and is updated if this
-  /// match defines new numeric values.
-  Expected<size_t> match(StringRef Buffer, size_t &MatchLen,
-                         const SourceMgr &SM) const;
-  /// Prints the value of successful substitutions or the name of the undefined
-  /// string or numeric variables preventing a successful substitution.
-  void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
-                          SMRange MatchRange = None) const;
-  void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
-                       std::vector<FileCheckDiag> *Diags) const;
-
-  bool hasVariable() const {
-    return !(Substitutions.empty() && VariableDefs.empty());
-  }
-
-  Check::FileCheckType getCheckTy() const { return CheckTy; }
-
-  int getCount() const { return CheckTy.getCount(); }
-
-private:
-  bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
-  void AddBackrefToRegEx(unsigned BackrefNum);
-  /// Computes an arbitrary estimate for the quality of matching this pattern
-  /// at the start of \p Buffer; a distance of zero should correspond to a
-  /// perfect match.
-  unsigned computeMatchDistance(StringRef Buffer) const;
-  /// Finds the closing sequence of a regex variable usage or definition.
-  ///
-  /// \p Str has to point in the beginning of the definition (right after the
-  /// opening sequence). \p SM holds the SourceMgr used for error repporting.
-  ///  \returns the offset of the closing sequence within Str, or npos if it
-  /// was not found.
-  size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
-
-  /// Parses \p Expr for the name of a numeric variable to be defined at line
-  /// \p LineNumber, or before input is parsed if \p LineNumber is None.
-  /// \returns a pointer to the class instance representing that variable,
-  /// creating it if needed, or an error holding a diagnostic against \p SM
-  /// should defining such a variable be invalid.
-  static Expected<FileCheckNumericVariable *> parseNumericVariableDefinition(
-      StringRef &Expr, FileCheckPatternContext *Context,
-      Optional<size_t> LineNumber, const SourceMgr &SM);
-  /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use
-  /// at line \p LineNumber, or before input is parsed if \p LineNumber is
-  /// None. Parameter \p Context points to the class instance holding the live
-  /// string and numeric variables. \returns the pointer to the class instance
-  /// representing that variable if successful, or an error holding a
-  /// diagnostic against \p SM otherwise.
-  static Expected<std::unique_ptr<FileCheckNumericVariableUse>>
-  parseNumericVariableUse(StringRef Name, bool IsPseudo,
-                          Optional<size_t> LineNumber,
-                          FileCheckPatternContext *Context,
-                          const SourceMgr &SM);
-  enum class AllowedOperand { LineVar, Literal, Any };
-  /// Parses \p Expr for use of a numeric operand at line \p LineNumber, or
-  /// before input is parsed if \p LineNumber is None. Accepts both literal
-  /// values and numeric variables, depending on the value of \p AO. Parameter
-  /// \p Context points to the class instance holding the live string and
-  /// numeric variables. \returns the class representing that operand in the
-  /// AST of the expression or an error holding a diagnostic against \p SM
-  /// otherwise.
-  static Expected<std::unique_ptr<FileCheckExpressionAST>>
-  parseNumericOperand(StringRef &Expr, AllowedOperand AO,
-                      Optional<size_t> LineNumber,
-                      FileCheckPatternContext *Context, const SourceMgr &SM);
-  /// Parses \p Expr for a binary operation at line \p LineNumber, or before
-  /// input is parsed if \p LineNumber is None. The left operand of this binary
-  /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether
-  /// we are parsing a legacy @LINE expression. Parameter \p Context points to
-  /// the class instance holding the live string and numeric variables.
-  /// \returns the class representing the binary operation in the AST of the
-  /// expression, or an error holding a diagnostic against \p SM otherwise.
-  static Expected<std::unique_ptr<FileCheckExpressionAST>>
-  parseBinop(StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,
-             bool IsLegacyLineExpr, Optional<size_t> LineNumber,
-             FileCheckPatternContext *Context, const SourceMgr &SM);
-};
-
-//===----------------------------------------------------------------------===//
-// Check Strings.
-//===----------------------------------------------------------------------===//
-
-/// A check that we found in the input file.
-struct FileCheckString {
-  /// The pattern to match.
-  FileCheckPattern Pat;
-
-  /// Which prefix name this check matched.
-  StringRef Prefix;
-
-  /// The location in the match file that the check string was specified.
-  SMLoc Loc;
-
-  /// All of the strings that are disallowed from occurring between this match
-  /// string and the previous one (or start of file).
-  std::vector<FileCheckPattern> DagNotStrings;
-
-  FileCheckString(const FileCheckPattern &P, StringRef S, SMLoc L)
-      : Pat(P), Prefix(S), Loc(L) {}
-
-  /// Matches check string and its "not strings" and/or "dag strings".
-  size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
-               size_t &MatchLen, FileCheckRequest &Req,
-               std::vector<FileCheckDiag> *Diags) const;
-
-  /// Verifies that there is a single line in the given \p Buffer. Errors are
-  /// reported against \p SM.
-  bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
-  /// Verifies that there is no newline in the given \p Buffer. Errors are
-  /// reported against \p SM.
-  bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;
-  /// Verifies that none of the strings in \p NotStrings are found in the given
-  /// \p Buffer. Errors are reported against \p SM and diagnostics recorded in
-  /// \p Diags according to the verbosity level set in \p Req.
-  bool CheckNot(const SourceMgr &SM, StringRef Buffer,
-                const std::vector<const FileCheckPattern *> &NotStrings,
-                const FileCheckRequest &Req,
-                std::vector<FileCheckDiag> *Diags) const;
-  /// Matches "dag strings" and their mixed "not strings".
-  size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
-                  std::vector<const FileCheckPattern *> &NotStrings,
-                  const FileCheckRequest &Req,
-                  std::vector<FileCheckDiag> *Diags) const;
-};
-
-} // namespace llvm
-
-#endif
+//===-- FileCheckImpl.h - Private FileCheck Interface ------------*- C++ -*-==//

+//

+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.

+// See https://llvm.org/LICENSE.txt for license information.

+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

+//

+//===----------------------------------------------------------------------===//

+//

+// This file defines the private interfaces of FileCheck. Its purpose is to

+// allow unit testing of FileCheck and to separate the interface from the

+// implementation. It is only meant to be used by FileCheck.

+//

+//===----------------------------------------------------------------------===//

+

+#ifndef LLVM_LIB_SUPPORT_FILECHECKIMPL_H

+#define LLVM_LIB_SUPPORT_FILECHECKIMPL_H

+

+#include "llvm/ADT/Optional.h"

+#include "llvm/ADT/StringMap.h"

+#include "llvm/ADT/StringRef.h"

+#include "llvm/Support/Error.h"

+#include "llvm/Support/SourceMgr.h"

+#include <map>

+#include <string>

+#include <vector>

+

+namespace llvm {

+

+//===----------------------------------------------------------------------===//

+// Numeric substitution handling code.

+//===----------------------------------------------------------------------===//

+

+/// Base class representing the AST of a given expression.

+class FileCheckExpressionAST {

+public:

+  virtual ~FileCheckExpressionAST() = default;

+

+  /// Evaluates and \returns the value of the expression represented by this

+  /// AST or an error if evaluation fails.

+  virtual Expected<uint64_t> eval() const = 0;

+};

+

+/// Class representing an unsigned literal in the AST of an expression.

+class FileCheckExpressionLiteral : public FileCheckExpressionAST {

+private:

+  /// Actual value of the literal.

+  uint64_t Value;

+

+public:

+  /// Constructs a literal with the specified value.

+  FileCheckExpressionLiteral(uint64_t Val) : Value(Val) {}

+

+  /// \returns the literal's value.

+  Expected<uint64_t> eval() const { return Value; }

+};

+

+/// Class to represent an undefined variable error, which quotes that

+/// variable's name when printed.

+class FileCheckUndefVarError : public ErrorInfo<FileCheckUndefVarError> {

+private:

+  StringRef VarName;

+

+public:

+  static char ID;

+

+  FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}

+

+  StringRef getVarName() const { return VarName; }

+

+  std::error_code convertToErrorCode() const override {

+    return inconvertibleErrorCode();

+  }

+

+  /// Print name of variable associated with this error.

+  void log(raw_ostream &OS) const override {

+    OS << "\"";

+    OS.write_escaped(VarName) << "\"";

+  }

+};

+

+/// Class representing a numeric variable and its associated current value.

+class FileCheckNumericVariable {

+private:

+  /// Name of the numeric variable.

+  StringRef Name;

+

+  /// Value of numeric variable, if defined, or None otherwise.

+  Optional<uint64_t> Value;

+

+  /// Line number where this variable is defined, or None if defined before

+  /// input is parsed. Used to determine whether a variable is defined on the

+  /// same line as a given use.

+  Optional<size_t> DefLineNumber;

+

+public:

+  /// Constructor for a variable \p Name defined at line \p DefLineNumber or

+  /// defined before input is parsed if \p DefLineNumber is None.

+  explicit FileCheckNumericVariable(StringRef Name,

+                                    Optional<size_t> DefLineNumber = None)

+      : Name(Name), DefLineNumber(DefLineNumber) {}

+

+  /// \returns name of this numeric variable.

+  StringRef getName() const { return Name; }

+

+  /// \returns this variable's value.

+  Optional<uint64_t> getValue() const { return Value; }

+

+  /// Sets value of this numeric variable to \p NewValue.

+  void setValue(uint64_t NewValue) { Value = NewValue; }

+

+  /// Clears value of this numeric variable, regardless of whether it is

+  /// currently defined or not.

+  void clearValue() { Value = None; }

+

+  /// \returns the line number where this variable is defined, if any, or None

+  /// if defined before input is parsed.

+  Optional<size_t> getDefLineNumber() { return DefLineNumber; }

+};

+

+/// Class representing the use of a numeric variable in the AST of an

+/// expression.

+class FileCheckNumericVariableUse : public FileCheckExpressionAST {

+private:

+  /// Name of the numeric variable.

+  StringRef Name;

+

+  /// Pointer to the class instance for the variable this use is about.

+  FileCheckNumericVariable *NumericVariable;

+

+public:

+  FileCheckNumericVariableUse(StringRef Name,

+                              FileCheckNumericVariable *NumericVariable)

+      : Name(Name), NumericVariable(NumericVariable) {}

+

+  /// \returns the value of the variable referenced by this instance.

+  Expected<uint64_t> eval() const;

+};

+

+/// Type of functions evaluating a given binary operation.

+using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);

+

+/// Class representing a single binary operation in the AST of an expression.

+class FileCheckASTBinop : public FileCheckExpressionAST {

+private:

+  /// Left operand.

+  std::unique_ptr<FileCheckExpressionAST> LeftOperand;

+

+  /// Right operand.

+  std::unique_ptr<FileCheckExpressionAST> RightOperand;

+

+  /// Pointer to function that can evaluate this binary operation.

+  binop_eval_t EvalBinop;

+

+public:

+  FileCheckASTBinop(binop_eval_t EvalBinop,

+                    std::unique_ptr<FileCheckExpressionAST> LeftOp,

+                    std::unique_ptr<FileCheckExpressionAST> RightOp)

+      : EvalBinop(EvalBinop) {

+    LeftOperand = std::move(LeftOp);

+    RightOperand = std::move(RightOp);

+  }

+

+  /// Evaluates the value of the binary operation represented by this AST,

+  /// using EvalBinop on the result of recursively evaluating the operands.

+  /// \returns the expression value or an error if an undefined numeric

+  /// variable is used in one of the operands.

+  Expected<uint64_t> eval() const;

+};

+

+class FileCheckPatternContext;

+

+/// Class representing a substitution to perform in the RegExStr string.

+class FileCheckSubstitution {

+protected:

+  /// Pointer to a class instance holding, among other things, the table with

+  /// the values of live string variables at the start of any given CHECK line.

+  /// Used for substituting string variables with the text they were defined

+  /// as. Expressions are linked to the numeric variables they use at

+  /// parse time and directly access the value of the numeric variable to

+  /// evaluate their value.

+  FileCheckPatternContext *Context;

+

+  /// The string that needs to be substituted for something else. For a

+  /// string variable this is its name, otherwise this is the whole expression.

+  StringRef FromStr;

+

+  // Index in RegExStr of where to do the substitution.

+  size_t InsertIdx;

+

+public:

+  FileCheckSubstitution(FileCheckPatternContext *Context, StringRef VarName,

+                        size_t InsertIdx)

+      : Context(Context), FromStr(VarName), InsertIdx(InsertIdx) {}

+

+  virtual ~FileCheckSubstitution() = default;

+

+  /// \returns the string to be substituted for something else.

+  StringRef getFromString() const { return FromStr; }

+

+  /// \returns the index where the substitution is to be performed in RegExStr.

+  size_t getIndex() const { return InsertIdx; }

+

+  /// \returns a string containing the result of the substitution represented

+  /// by this class instance or an error if substitution failed.

+  virtual Expected<std::string> getResult() const = 0;

+};

+

+class FileCheckStringSubstitution : public FileCheckSubstitution {

+public:

+  FileCheckStringSubstitution(FileCheckPatternContext *Context,

+                              StringRef VarName, size_t InsertIdx)

+      : FileCheckSubstitution(Context, VarName, InsertIdx) {}

+

+  /// \returns the text that the string variable in this substitution matched

+  /// when defined, or an error if the variable is undefined.

+  Expected<std::string> getResult() const override;

+};

+

+class FileCheckNumericSubstitution : public FileCheckSubstitution {

+private:

+  /// Pointer to the class representing the expression whose value is to be

+  /// substituted.

+  std::unique_ptr<FileCheckExpressionAST> ExpressionAST;

+

+public:

+  FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr,

+                               std::unique_ptr<FileCheckExpressionAST> ExprAST,

+                               size_t InsertIdx)

+      : FileCheckSubstitution(Context, Expr, InsertIdx) {

+    ExpressionAST = std::move(ExprAST);

+  }

+

+  /// \returns a string containing the result of evaluating the expression in

+  /// this substitution, or an error if evaluation failed.

+  Expected<std::string> getResult() const override;

+};

+

+//===----------------------------------------------------------------------===//

+// Pattern handling code.

+//===----------------------------------------------------------------------===//

+

+struct FileCheckDiag;

+

+/// Class holding the FileCheckPattern global state, shared by all patterns:

+/// tables holding values of variables and whether they are defined or not at

+/// any given time in the matching process.

+class FileCheckPatternContext {

+  friend class FileCheckPattern;

+

+private:

+  /// When matching a given pattern, this holds the value of all the string

+  /// variables defined in previous patterns. In a pattern, only the last

+  /// definition for a given variable is recorded in this table.

+  /// Back-references are used for uses after any the other definition.

+  StringMap<StringRef> GlobalVariableTable;

+

+  /// Map of all string variables defined so far. Used at parse time to detect

+  /// a name conflict between a numeric variable and a string variable when

+  /// the former is defined on a later line than the latter.

+  StringMap<bool> DefinedVariableTable;

+

+  /// When matching a given pattern, this holds the pointers to the classes

+  /// representing the numeric variables defined in previous patterns. When

+  /// matching a pattern all definitions for that pattern are recorded in the

+  /// NumericVariableDefs table in the FileCheckPattern instance of that

+  /// pattern.

+  StringMap<FileCheckNumericVariable *> GlobalNumericVariableTable;

+

+  /// Pointer to the class instance representing the @LINE pseudo variable for

+  /// easily updating its value.

+  FileCheckNumericVariable *LineVariable = nullptr;

+

+  /// Vector holding pointers to all parsed numeric variables. Used to

+  /// automatically free them once they are guaranteed to no longer be used.

+  std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;

+

+  /// Vector holding pointers to all substitutions. Used to automatically free

+  /// them once they are guaranteed to no longer be used.

+  std::vector<std::unique_ptr<FileCheckSubstitution>> Substitutions;

+

+public:

+  /// \returns the value of string variable \p VarName or an error if no such

+  /// variable has been defined.

+  Expected<StringRef> getPatternVarValue(StringRef VarName);

+

+  /// Defines string and numeric variables from definitions given on the

+  /// command line, passed as a vector of [#]VAR=VAL strings in

+  /// \p CmdlineDefines. \returns an error list containing diagnostics against

+  /// \p SM for all definition parsing failures, if any, or Success otherwise.

+  Error defineCmdlineVariables(std::vector<std::string> &CmdlineDefines,

+                               SourceMgr &SM);

+

+  /// Create @LINE pseudo variable. Value is set when pattern are being

+  /// matched.

+  void createLineVariable();

+

+  /// Undefines local variables (variables whose name does not start with a '$'

+  /// sign), i.e. removes them from GlobalVariableTable and from

+  /// GlobalNumericVariableTable and also clears the value of numeric

+  /// variables.

+  void clearLocalVars();

+

+private:

+  /// Makes a new numeric variable and registers it for destruction when the

+  /// context is destroyed.

+  template <class... Types>

+  FileCheckNumericVariable *makeNumericVariable(Types... args);

+

+  /// Makes a new string substitution and registers it for destruction when the

+  /// context is destroyed.

+  FileCheckSubstitution *makeStringSubstitution(StringRef VarName,

+                                                size_t InsertIdx);

+

+  /// Makes a new numeric substitution and registers it for destruction when

+  /// the context is destroyed.

+  FileCheckSubstitution *

+  makeNumericSubstitution(StringRef ExpressionStr,

+                          std::unique_ptr<FileCheckExpressionAST> ExpressionAST,

+                          size_t InsertIdx);

+};

+

+/// Class to represent an error holding a diagnostic with location information

+/// used when printing it.

+class FileCheckErrorDiagnostic : public ErrorInfo<FileCheckErrorDiagnostic> {

+private:

+  SMDiagnostic Diagnostic;

+

+public:

+  static char ID;

+

+  FileCheckErrorDiagnostic(SMDiagnostic &&Diag) : Diagnostic(Diag) {}

+

+  std::error_code convertToErrorCode() const override {

+    return inconvertibleErrorCode();

+  }

+

+  /// Print diagnostic associated with this error when printing the error.

+  void log(raw_ostream &OS) const override { Diagnostic.print(nullptr, OS); }

+

+  static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg) {

+    return make_error<FileCheckErrorDiagnostic>(

+        SM.GetMessage(Loc, SourceMgr::DK_Error, ErrMsg));

+  }

+

+  static Error get(const SourceMgr &SM, StringRef Buffer, const Twine &ErrMsg) {

+    return get(SM, SMLoc::getFromPointer(Buffer.data()), ErrMsg);

+  }

+};

+

+class FileCheckNotFoundError : public ErrorInfo<FileCheckNotFoundError> {

+public:

+  static char ID;

+

+  std::error_code convertToErrorCode() const override {

+    return inconvertibleErrorCode();

+  }

+

+  /// Print diagnostic associated with this error when printing the error.

+  void log(raw_ostream &OS) const override {

+    OS << "String not found in input";

+  }

+};

+

+class FileCheckPattern {

+  SMLoc PatternLoc;

+

+  /// A fixed string to match as the pattern or empty if this pattern requires

+  /// a regex match.

+  StringRef FixedStr;

+

+  /// A regex string to match as the pattern or empty if this pattern requires

+  /// a fixed string to match.

+  std::string RegExStr;

+

+  /// Entries in this vector represent a substitution of a string variable or

+  /// an expression in the RegExStr regex at match time. For example, in the

+  /// case of a CHECK directive with the pattern "foo[[bar]]baz[[#N+1]]",

+  /// RegExStr will contain "foobaz" and we'll get two entries in this vector

+  /// that tells us to insert the value of string variable "bar" at offset 3

+  /// and the value of expression "N+1" at offset 6.

+  std::vector<FileCheckSubstitution *> Substitutions;

+

+  /// Maps names of string variables defined in a pattern to the number of

+  /// their parenthesis group in RegExStr capturing their last definition.

+  ///

+  /// E.g. for the pattern "foo[[bar:.*]]baz([[bar]][[QUUX]][[bar:.*]])",

+  /// RegExStr will be "foo(.*)baz(\1<quux value>(.*))" where <quux value> is

+  /// the value captured for QUUX on the earlier line where it was defined, and

+  /// VariableDefs will map "bar" to the third parenthesis group which captures

+  /// the second definition of "bar".

+  ///

+  /// Note: uses std::map rather than StringMap to be able to get the key when

+  /// iterating over values.

+  std::map<StringRef, unsigned> 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.

+  struct FileCheckNumericVariableMatch {

+    /// Pointer to class representing the numeric variable whose value is being

+    /// defined.

+    FileCheckNumericVariable *DefinedNumericVariable;

+

+    /// Number of the parenthesis group in RegExStr that captures the value of

+    /// this numeric variable definition.

+    unsigned CaptureParenGroup;

+  };

+

+  /// Holds the number of the parenthesis group in RegExStr and pointer to the

+  /// corresponding FileCheckNumericVariable class instance of all numeric

+  /// variable definitions. Used to set the matched value of all those

+  /// variables.

+  StringMap<FileCheckNumericVariableMatch> NumericVariableDefs;

+

+  /// Pointer to a class instance holding the global state shared by all

+  /// patterns:

+  /// - separate tables with the values of live string and numeric variables

+  ///   respectively at the start of any given CHECK line;

+  /// - table holding whether a string variable has been defined at any given

+  ///   point during the parsing phase.

+  FileCheckPatternContext *Context;

+

+  Check::FileCheckType CheckTy;

+

+  /// Line number for this CHECK pattern or None if it is an implicit pattern.

+  /// Used to determine whether a variable definition is made on an earlier

+  /// line to the one with this CHECK.

+  Optional<size_t> LineNumber;

+

+  /// Ignore case while matching if set to true.

+  bool IgnoreCase = false;

+

+public:

+  FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context,

+                   Optional<size_t> Line = None)

+      : Context(Context), CheckTy(Ty), LineNumber(Line) {}

+

+  /// \returns the location in source code.

+  SMLoc getLoc() const { return PatternLoc; }

+

+  /// \returns the pointer to the global state for all patterns in this

+  /// FileCheck instance.

+  FileCheckPatternContext *getContext() const { return Context; }

+

+  /// \returns whether \p C is a valid first character for a variable name.

+  static bool isValidVarNameStart(char C);

+

+  /// Parsing information about a variable.

+  struct VariableProperties {

+    StringRef Name;

+    bool IsPseudo;

+  };

+

+  /// Parses the string at the start of \p Str for a variable name. \returns

+  /// a VariableProperties structure holding the variable name and whether it

+  /// is the name of a pseudo variable, or an error holding a diagnostic

+  /// against \p SM if parsing fail. If parsing was successful, also strips

+  /// \p Str from the variable name.

+  static Expected<VariableProperties> parseVariable(StringRef &Str,

+                                                    const SourceMgr &SM);

+  /// Parses \p Expr for a numeric substitution block at line \p LineNumber,

+  /// or before input is parsed if \p LineNumber is None. Parameter

+  /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE

+  /// expression 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 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<std::unique_ptr<FileCheckExpressionAST>>

+  parseNumericSubstitutionBlock(

+      StringRef Expr,

+      Optional<FileCheckNumericVariable *> &DefinedNumericVariable,

+      bool IsLegacyLineExpr, Optional<size_t> LineNumber,

+      FileCheckPatternContext *Context, const SourceMgr &SM);

+  /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern

+  /// instance accordingly.

+  ///

+  /// \p Prefix provides which prefix is being matched, \p Req describes the

+  /// global options that influence the parsing such as whitespace

+  /// canonicalization, \p SM provides the SourceMgr used for error reports.

+  /// \returns true in case of an error, false otherwise.

+  bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,

+                    const FileCheckRequest &Req);

+  /// Matches the pattern string against the input buffer \p Buffer

+  ///

+  /// \returns the position that is matched or an error indicating why matching

+  /// failed. If there is a match, updates \p MatchLen with the size of the

+  /// matched string.

+  ///

+  /// The GlobalVariableTable StringMap in the FileCheckPatternContext class

+  /// instance provides the current values of FileCheck string variables and

+  /// is updated if this match defines new values. Likewise, the

+  /// GlobalNumericVariableTable StringMap in the same class provides the

+  /// current values of FileCheck numeric variables and is updated if this

+  /// match defines new numeric values.

+  Expected<size_t> match(StringRef Buffer, size_t &MatchLen,

+                         const SourceMgr &SM) const;

+  /// Prints the value of successful substitutions or the name of the undefined

+  /// string or numeric variables preventing a successful substitution.

+  void printSubstitutions(const SourceMgr &SM, StringRef Buffer,

+                          SMRange MatchRange = None) const;

+  void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,

+                       std::vector<FileCheckDiag> *Diags) const;

+

+  bool hasVariable() const {

+    return !(Substitutions.empty() && VariableDefs.empty());

+  }

+

+  Check::FileCheckType getCheckTy() const { return CheckTy; }

+

+  int getCount() const { return CheckTy.getCount(); }

+

+private:

+  bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);

+  void AddBackrefToRegEx(unsigned BackrefNum);

+  /// Computes an arbitrary estimate for the quality of matching this pattern

+  /// at the start of \p Buffer; a distance of zero should correspond to a

+  /// perfect match.

+  unsigned computeMatchDistance(StringRef Buffer) const;

+  /// Finds the closing sequence of a regex variable usage or definition.

+  ///

+  /// \p Str has to point in the beginning of the definition (right after the

+  /// opening sequence). \p SM holds the SourceMgr used for error repporting.

+  ///  \returns the offset of the closing sequence within Str, or npos if it

+  /// was not found.

+  size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);

+

+  /// Parses \p Expr for the name of a numeric variable to be defined at line

+  /// \p LineNumber, or before input is parsed if \p LineNumber is None.

+  /// \returns a pointer to the class instance representing that variable,

+  /// creating it if needed, or an error holding a diagnostic against \p SM

+  /// should defining such a variable be invalid.

+  static Expected<FileCheckNumericVariable *> parseNumericVariableDefinition(

+      StringRef &Expr, FileCheckPatternContext *Context,

+      Optional<size_t> LineNumber, const SourceMgr &SM);

+  /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use

+  /// at line \p LineNumber, or before input is parsed if \p LineNumber is

+  /// None. Parameter \p Context points to the class instance holding the live

+  /// string and numeric variables. \returns the pointer to the class instance

+  /// representing that variable if successful, or an error holding a

+  /// diagnostic against \p SM otherwise.

+  static Expected<std::unique_ptr<FileCheckNumericVariableUse>>

+  parseNumericVariableUse(StringRef Name, bool IsPseudo,

+                          Optional<size_t> LineNumber,

+                          FileCheckPatternContext *Context,

+                          const SourceMgr &SM);

+  enum class AllowedOperand { LineVar, Literal, Any };

+  /// Parses \p Expr for use of a numeric operand at line \p LineNumber, or

+  /// before input is parsed if \p LineNumber is None. Accepts both literal

+  /// values and numeric variables, depending on the value of \p AO. Parameter

+  /// \p Context points to the class instance holding the live string and

+  /// numeric variables. \returns the class representing that operand in the

+  /// AST of the expression or an error holding a diagnostic against \p SM

+  /// otherwise.

+  static Expected<std::unique_ptr<FileCheckExpressionAST>>

+  parseNumericOperand(StringRef &Expr, AllowedOperand AO,

+                      Optional<size_t> LineNumber,

+                      FileCheckPatternContext *Context, const SourceMgr &SM);

+  /// Parses \p Expr for a binary operation at line \p LineNumber, or before

+  /// input is parsed if \p LineNumber is None. The left operand of this binary

+  /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether

+  /// we are parsing a legacy @LINE expression. Parameter \p Context points to

+  /// the class instance holding the live string and numeric variables.

+  /// \returns the class representing the binary operation in the AST of the

+  /// expression, or an error holding a diagnostic against \p SM otherwise.

+  static Expected<std::unique_ptr<FileCheckExpressionAST>>

+  parseBinop(StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,

+             bool IsLegacyLineExpr, Optional<size_t> LineNumber,

+             FileCheckPatternContext *Context, const SourceMgr &SM);

+};

+

+//===----------------------------------------------------------------------===//

+// Check Strings.

+//===----------------------------------------------------------------------===//

+

+/// A check that we found in the input file.

+struct FileCheckString {

+  /// The pattern to match.

+  FileCheckPattern Pat;

+

+  /// Which prefix name this check matched.

+  StringRef Prefix;

+

+  /// The location in the match file that the check string was specified.

+  SMLoc Loc;

+

+  /// All of the strings that are disallowed from occurring between this match

+  /// string and the previous one (or start of file).

+  std::vector<FileCheckPattern> DagNotStrings;

+

+  FileCheckString(const FileCheckPattern &P, StringRef S, SMLoc L)

+      : Pat(P), Prefix(S), Loc(L) {}

+

+  /// Matches check string and its "not strings" and/or "dag strings".

+  size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,

+               size_t &MatchLen, FileCheckRequest &Req,

+               std::vector<FileCheckDiag> *Diags) const;

+

+  /// Verifies that there is a single line in the given \p Buffer. Errors are

+  /// reported against \p SM.

+  bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;

+  /// Verifies that there is no newline in the given \p Buffer. Errors are

+  /// reported against \p SM.

+  bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;

+  /// Verifies that none of the strings in \p NotStrings are found in the given

+  /// \p Buffer. Errors are reported against \p SM and diagnostics recorded in

+  /// \p Diags according to the verbosity level set in \p Req.

+  bool CheckNot(const SourceMgr &SM, StringRef Buffer,

+                const std::vector<const FileCheckPattern *> &NotStrings,

+                const FileCheckRequest &Req,

+                std::vector<FileCheckDiag> *Diags) const;

+  /// Matches "dag strings" and their mixed "not strings".

+  size_t CheckDag(const SourceMgr &SM, StringRef Buffer,

+                  std::vector<const FileCheckPattern *> &NotStrings,

+                  const FileCheckRequest &Req,

+                  std::vector<FileCheckDiag> *Diags) const;

+};

+

+} // namespace llvm

+

+#endif

diff --git a/llvm/test/FileCheck/check-ignore-case.txt b/llvm/test/FileCheck/check-ignore-case.txt
new file mode 100644
index 0000000..8721c3f
--- /dev/null
+++ b/llvm/test/FileCheck/check-ignore-case.txt
@@ -0,0 +1,45 @@
+## Check that a full line is matched case insensitively.

+# RUN: FileCheck --ignore-case --match-full-lines --check-prefix=FULL --input-file=%s %s

+

+## Check that a regular expression matches case insensitively.

+# RUN: FileCheck --ignore-case --check-prefix=REGEX --input-file=%s %s

+

+## Check that a pattern from command line matches case insensitively.

+# RUN: FileCheck --ignore-case --check-prefix=PAT --DPATTERN="THIS is the" --input-file=%s %s

+

+## Check that COUNT and NEXT work case insensitively.

+# RUN: FileCheck --ignore-case --check-prefix=CNT --input-file=%s %s

+

+## Check that match on same line works case insensitively.

+# RUN: FileCheck --ignore-case --check-prefix=LINE --input-file=%s %s

+

+## Check that option --implicit-not works case insensitively.

+# RUN: sed '/^#/d' %s | FileCheck --implicit-check-not=sTrInG %s

+# RUN: sed '/^#/d' %s | not FileCheck --ignore-case --implicit-check-not=sTrInG %s 2>&1 | FileCheck --check-prefix=ERROR %s

+

+this is the STRING to be matched

+

+# FULL: tHis iS The String TO be matched

+# REGEX: s{{TRing}}

+# PAT: [[PATTERN]] string

+

+Loop 1

+lOop 2

+loOp 3

+looP 4

+loop 5

+LOOP 6

+BREAK

+

+# CNT-COUNT-6: LOop {{[0-9]}}

+# CNT-NOT: loop

+# CNT-NEXT: break

+

+One Line To Match

+

+# LINE: {{o}}ne line

+# LINE-SAME: {{t}}o match

+

+# ERROR: command line:1:{{[0-9]+]}}: error: CHECK-NOT: excluded string found in input

+# ERROR-NEXT: -implicit-check-not='sTrInG'

+# ERROR: note: found here

diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp
index 8718be2..4d2cd19 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -1,651 +1,656 @@
-//===- FileCheck.cpp - Check that File's Contents match what is expected --===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// FileCheck does a line-by line check of a file that validates whether it
-// contains the expected content.  This is useful for regression tests etc.
-//
-// This program exits with an exit status of 2 on error, exit status of 0 if
-// the file matched the expected contents, and exit status of 1 if it did not
-// contain the expected contents.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/FileCheck.h"
-#include <cmath>
-using namespace llvm;
-
-static cl::extrahelp FileCheckOptsEnv(
-    "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"
-    "from the command line.\n");
-
-static cl::opt<std::string>
-    CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
-
-static cl::opt<std::string>
-    InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
-                  cl::init("-"), cl::value_desc("filename"));
-
-static cl::list<std::string> CheckPrefixes(
-    "check-prefix",
-    cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
-static cl::alias CheckPrefixesAlias(
-    "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
-    cl::NotHidden,
-    cl::desc(
-        "Alias for -check-prefix permitting multiple comma separated values"));
-
-static cl::opt<bool> NoCanonicalizeWhiteSpace(
-    "strict-whitespace",
-    cl::desc("Do not treat all horizontal whitespace as equivalent"));
-
-static cl::list<std::string> ImplicitCheckNot(
-    "implicit-check-not",
-    cl::desc("Add an implicit negative check with this pattern to every\n"
-             "positive check. This can be used to ensure that no instances of\n"
-             "this pattern occur which are not matched by a positive pattern"),
-    cl::value_desc("pattern"));
-
-static cl::list<std::string>
-    GlobalDefines("D", cl::AlwaysPrefix,
-                  cl::desc("Define a variable to be used in capture patterns."),
-                  cl::value_desc("VAR=VALUE"));
-
-static cl::opt<bool> AllowEmptyInput(
-    "allow-empty", cl::init(false),
-    cl::desc("Allow the input file to be empty. This is useful when making\n"
-             "checks that some error message does not occur, for example."));
-
-static cl::opt<bool> MatchFullLines(
-    "match-full-lines", cl::init(false),
-    cl::desc("Require all positive matches to cover an entire input line.\n"
-             "Allows leading and trailing whitespace if --strict-whitespace\n"
-             "is not also passed."));
-
-static cl::opt<bool> EnableVarScope(
-    "enable-var-scope", cl::init(false),
-    cl::desc("Enables scope for regex variables. Variables with names that\n"
-             "do not start with '$' will be reset at the beginning of\n"
-             "each CHECK-LABEL block."));
-
-static cl::opt<bool> AllowDeprecatedDagOverlap(
-    "allow-deprecated-dag-overlap", cl::init(false),
-    cl::desc("Enable overlapping among matches in a group of consecutive\n"
-             "CHECK-DAG directives.  This option is deprecated and is only\n"
-             "provided for convenience as old tests are migrated to the new\n"
-             "non-overlapping CHECK-DAG implementation.\n"));
-
-static cl::opt<bool> Verbose(
-    "v", cl::init(false),
-    cl::desc("Print directive pattern matches, or add them to the input dump\n"
-             "if enabled.\n"));
-
-static cl::opt<bool> VerboseVerbose(
-    "vv", cl::init(false),
-    cl::desc("Print information helpful in diagnosing internal FileCheck\n"
-             "issues, or add it to the input dump if enabled.  Implies\n"
-             "-v.\n"));
-static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";
-
-static cl::opt<bool> DumpInputOnFailure(
-    "dump-input-on-failure",
-    cl::init(std::getenv(DumpInputEnv) && *std::getenv(DumpInputEnv)),
-    cl::desc("Dump original input to stderr before failing.\n"
-             "The value can be also controlled using\n"
-             "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"
-             "This option is deprecated in favor of -dump-input=fail.\n"));
-
-enum DumpInputValue {
-  DumpInputDefault,
-  DumpInputHelp,
-  DumpInputNever,
-  DumpInputFail,
-  DumpInputAlways
-};
-
-static cl::opt<DumpInputValue> DumpInput(
-    "dump-input", cl::init(DumpInputDefault),
-    cl::desc("Dump input to stderr, adding annotations representing\n"
-             " currently enabled diagnostics\n"),
-    cl::value_desc("mode"),
-    cl::values(clEnumValN(DumpInputHelp, "help",
-                          "Explain dump format and quit"),
-               clEnumValN(DumpInputNever, "never", "Never dump input"),
-               clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
-               clEnumValN(DumpInputAlways, "always", "Always dump input")));
-
-typedef cl::list<std::string>::const_iterator prefix_iterator;
-
-
-
-
-
-
-
-static void DumpCommandLine(int argc, char **argv) {
-  errs() << "FileCheck command line: ";
-  for (int I = 0; I < argc; I++)
-    errs() << " " << argv[I];
-  errs() << "\n";
-}
-
-struct MarkerStyle {
-  /// The starting char (before tildes) for marking the line.
-  char Lead;
-  /// What color to use for this annotation.
-  raw_ostream::Colors Color;
-  /// A note to follow the marker, or empty string if none.
-  std::string Note;
-  MarkerStyle() {}
-  MarkerStyle(char Lead, raw_ostream::Colors Color,
-              const std::string &Note = "")
-      : Lead(Lead), Color(Color), Note(Note) {}
-};
-
-static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
-  switch (MatchTy) {
-  case FileCheckDiag::MatchFoundAndExpected:
-    return MarkerStyle('^', raw_ostream::GREEN);
-  case FileCheckDiag::MatchFoundButExcluded:
-    return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
-  case FileCheckDiag::MatchFoundButWrongLine:
-    return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
-  case FileCheckDiag::MatchFoundButDiscarded:
-    return MarkerStyle('!', raw_ostream::CYAN,
-                       "discard: overlaps earlier match");
-  case FileCheckDiag::MatchNoneAndExcluded:
-    return MarkerStyle('X', raw_ostream::GREEN);
-  case FileCheckDiag::MatchNoneButExpected:
-    return MarkerStyle('X', raw_ostream::RED, "error: no match found");
-  case FileCheckDiag::MatchFuzzy:
-    return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");
-  }
-  llvm_unreachable_internal("unexpected match type");
-}
-
-static void DumpInputAnnotationHelp(raw_ostream &OS) {
-  OS << "The following description was requested by -dump-input=help to\n"
-     << "explain the input annotations printed by -dump-input=always and\n"
-     << "-dump-input=fail:\n\n";
-
-  // Labels for input lines.
-  OS << "  - ";
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
-  OS << "     labels line number L of the input file\n";
-
-  // Labels for annotation lines.
-  OS << "  - ";
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
-  OS << "    labels the only match result for a pattern of type T from "
-     << "line L of\n"
-     << "           the check file\n";
-  OS << "  - ";
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
-  OS << "  labels the Nth match result for a pattern of type T from line "
-     << "L of\n"
-     << "           the check file\n";
-
-  // Markers on annotation lines.
-  OS << "  - ";
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
-  OS << "    marks good match (reported if -v)\n"
-     << "  - ";
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
-  OS << "    marks bad match, such as:\n"
-     << "           - CHECK-NEXT on same line as previous match (error)\n"
-     << "           - CHECK-NOT found (error)\n"
-     << "           - CHECK-DAG overlapping match (discarded, reported if "
-     << "-vv)\n"
-     << "  - ";
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
-  OS << "    marks search range when no match is found, such as:\n"
-     << "           - CHECK-NEXT not found (error)\n"
-     << "           - CHECK-NOT not found (success, reported if -vv)\n"
-     << "           - CHECK-DAG not found after discarded matches (error)\n"
-     << "  - ";
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
-  OS << "      marks fuzzy match when no match is found\n";
-
-  // Colors.
-  OS << "  - colors ";
-  WithColor(OS, raw_ostream::GREEN, true) << "success";
-  OS << ", ";
-  WithColor(OS, raw_ostream::RED, true) << "error";
-  OS << ", ";
-  WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
-  OS << ", ";
-  WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
-  OS << ", ";
-  WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
-  OS << "\n\n"
-     << "If you are not seeing color above or in input dumps, try: -color\n";
-}
-
-/// An annotation for a single input line.
-struct InputAnnotation {
-  /// The check file line (one-origin indexing) where the directive that
-  /// produced this annotation is located.
-  unsigned CheckLine;
-  /// The index of the match result for this check.
-  unsigned CheckDiagIndex;
-  /// The label for this annotation.
-  std::string Label;
-  /// What input line (one-origin indexing) this annotation marks.  This might
-  /// be different from the starting line of the original diagnostic if this is
-  /// a non-initial fragment of a diagnostic that has been broken across
-  /// multiple lines.
-  unsigned InputLine;
-  /// The column range (one-origin indexing, open end) in which to to mark the
-  /// input line.  If InputEndCol is UINT_MAX, treat it as the last column
-  /// before the newline.
-  unsigned InputStartCol, InputEndCol;
-  /// The marker to use.
-  MarkerStyle Marker;
-  /// Whether this annotation represents a good match for an expected pattern.
-  bool FoundAndExpectedMatch;
-};
-
-/// Get an abbreviation for the check type.
-std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
-  switch (Ty) {
-  case Check::CheckPlain:
-    if (Ty.getCount() > 1)
-      return "count";
-    return "check";
-  case Check::CheckNext:
-    return "next";
-  case Check::CheckSame:
-    return "same";
-  case Check::CheckNot:
-    return "not";
-  case Check::CheckDAG:
-    return "dag";
-  case Check::CheckLabel:
-    return "label";
-  case Check::CheckEmpty:
-    return "empty";
-  case Check::CheckEOF:
-    return "eof";
-  case Check::CheckBadNot:
-    return "bad-not";
-  case Check::CheckBadCount:
-    return "bad-count";
-  case Check::CheckNone:
-    llvm_unreachable("invalid FileCheckType");
-  }
-  llvm_unreachable("unknown FileCheckType");
-}
-
-static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
-                                  std::vector<InputAnnotation> &Annotations,
-                                  unsigned &LabelWidth) {
-  // How many diagnostics has the current check seen so far?
-  unsigned CheckDiagCount = 0;
-  // What's the widest label?
-  LabelWidth = 0;
-  for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
-       ++DiagItr) {
-    InputAnnotation A;
-
-    // Build label, which uniquely identifies this check result.
-    A.CheckLine = DiagItr->CheckLine;
-    llvm::raw_string_ostream Label(A.Label);
-    Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"
-          << DiagItr->CheckLine;
-    A.CheckDiagIndex = UINT_MAX;
-    auto DiagNext = std::next(DiagItr);
-    if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
-        DiagItr->CheckLine == DiagNext->CheckLine)
-      A.CheckDiagIndex = CheckDiagCount++;
-    else if (CheckDiagCount) {
-      A.CheckDiagIndex = CheckDiagCount;
-      CheckDiagCount = 0;
-    }
-    if (A.CheckDiagIndex != UINT_MAX)
-      Label << "'" << A.CheckDiagIndex;
-    else
-      A.CheckDiagIndex = 0;
-    Label.flush();
-    LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
-
-    A.Marker = GetMarker(DiagItr->MatchTy);
-    A.FoundAndExpectedMatch =
-        DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
-
-    // Compute the mark location, and break annotation into multiple
-    // annotations if it spans multiple lines.
-    A.InputLine = DiagItr->InputStartLine;
-    A.InputStartCol = DiagItr->InputStartCol;
-    if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
-      // Sometimes ranges are empty in order to indicate a specific point, but
-      // that would mean nothing would be marked, so adjust the range to
-      // include the following character.
-      A.InputEndCol =
-          std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
-      Annotations.push_back(A);
-    } else {
-      assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
-             "expected input range not to be inverted");
-      A.InputEndCol = UINT_MAX;
-      Annotations.push_back(A);
-      for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
-           L <= E; ++L) {
-        // If a range ends before the first column on a line, then it has no
-        // characters on that line, so there's nothing to render.
-        if (DiagItr->InputEndCol == 1 && L == E)
-          break;
-        InputAnnotation B;
-        B.CheckLine = A.CheckLine;
-        B.CheckDiagIndex = A.CheckDiagIndex;
-        B.Label = A.Label;
-        B.InputLine = L;
-        B.Marker = A.Marker;
-        B.Marker.Lead = '~';
-        B.Marker.Note = "";
-        B.InputStartCol = 1;
-        if (L != E)
-          B.InputEndCol = UINT_MAX;
-        else
-          B.InputEndCol = DiagItr->InputEndCol;
-        B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
-        Annotations.push_back(B);
-      }
-    }
-  }
-}
-
-static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
-                               StringRef InputFileText,
-                               std::vector<InputAnnotation> &Annotations,
-                               unsigned LabelWidth) {
-  OS << "Full input was:\n<<<<<<\n";
-
-  // Sort annotations.
-  //
-  // First, sort in the order of input lines to make it easier to find relevant
-  // annotations while iterating input lines in the implementation below.
-  // FileCheck diagnostics are not always reported and recorded in the order of
-  // input lines due to, for example, CHECK-DAG and CHECK-NOT.
-  //
-  // Second, for annotations for the same input line, sort in the order of the
-  // FileCheck directive's line in the check file (where there's at most one
-  // directive per line) and then by the index of the match result for that
-  // directive.  The rationale of this choice is that, for any input line, this
-  // sort establishes a total order of annotations that, with respect to match
-  // results, is consistent across multiple lines, thus making match results
-  // easier to track from one line to the next when they span multiple lines.
-  std::sort(Annotations.begin(), Annotations.end(),
-            [](const InputAnnotation &A, const InputAnnotation &B) {
-              if (A.InputLine != B.InputLine)
-                return A.InputLine < B.InputLine;
-              if (A.CheckLine != B.CheckLine)
-                return A.CheckLine < B.CheckLine;
-              // FIXME: Sometimes CHECK-LABEL reports its match twice with
-              // other diagnostics in between, and then diag index incrementing
-              // fails to work properly, and then this assert fails.  We should
-              // suppress one of those diagnostics or do a better job of
-              // computing this index.  For now, we just produce a redundant
-              // CHECK-LABEL annotation.
-              // assert(A.CheckDiagIndex != B.CheckDiagIndex &&
-              //        "expected diagnostic indices to be unique within a "
-              //        " check line");
-              return A.CheckDiagIndex < B.CheckDiagIndex;
-            });
-
-  // Compute the width of the label column.
-  const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
-                      *InputFileEnd = InputFileText.bytes_end();
-  unsigned LineCount = InputFileText.count('\n');
-  if (InputFileEnd[-1] != '\n')
-    ++LineCount;
-  unsigned LineNoWidth = std::log10(LineCount) + 1;
-  // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
-  // on input lines and (2) to the right of the (left-aligned) labels on
-  // annotation lines so that input lines and annotation lines are more
-  // visually distinct.  For example, the spaces on the annotation lines ensure
-  // that input line numbers and check directive line numbers never align
-  // horizontally.  Those line numbers might not even be for the same file.
-  // One space would be enough to achieve that, but more makes it even easier
-  // to see.
-  LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
-
-  // Print annotated input lines.
-  auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
-  for (unsigned Line = 1;
-       InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
-       ++Line) {
-    const unsigned char *InputFileLine = InputFilePtr;
-
-    // Print right-aligned line number.
-    WithColor(OS, raw_ostream::BLACK, true)
-        << format_decimal(Line, LabelWidth) << ": ";
-
-    // For the case where -v and colors are enabled, find the annotations for
-    // good matches for expected patterns in order to highlight everything
-    // else in the line.  There are no such annotations if -v is disabled.
-    std::vector<InputAnnotation> FoundAndExpectedMatches;
-    if (Req.Verbose && WithColor(OS).colorsEnabled()) {
-      for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
-           ++I) {
-        if (I->FoundAndExpectedMatch)
-          FoundAndExpectedMatches.push_back(*I);
-      }
-    }
-
-    // Print numbered line with highlighting where there are no matches for
-    // expected patterns.
-    bool Newline = false;
-    {
-      WithColor COS(OS);
-      bool InMatch = false;
-      if (Req.Verbose)
-        COS.changeColor(raw_ostream::CYAN, true, true);
-      for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
-        bool WasInMatch = InMatch;
-        InMatch = false;
-        for (auto M : FoundAndExpectedMatches) {
-          if (M.InputStartCol <= Col && Col < M.InputEndCol) {
-            InMatch = true;
-            break;
-          }
-        }
-        if (!WasInMatch && InMatch)
-          COS.resetColor();
-        else if (WasInMatch && !InMatch)
-          COS.changeColor(raw_ostream::CYAN, true, true);
-        if (*InputFilePtr == '\n')
-          Newline = true;
-        else
-          COS << *InputFilePtr;
-        ++InputFilePtr;
-      }
-    }
-    OS << '\n';
-    unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
-
-    // Print any annotations.
-    while (AnnotationItr != AnnotationEnd &&
-           AnnotationItr->InputLine == Line) {
-      WithColor COS(OS, AnnotationItr->Marker.Color, true);
-      // The two spaces below are where the ": " appears on input lines.
-      COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";
-      unsigned Col;
-      for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
-        COS << ' ';
-      COS << AnnotationItr->Marker.Lead;
-      // If InputEndCol=UINT_MAX, stop at InputLineWidth.
-      for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
-           ++Col)
-        COS << '~';
-      const std::string &Note = AnnotationItr->Marker.Note;
-      if (!Note.empty()) {
-        // Put the note at the end of the input line.  If we were to instead
-        // put the note right after the marker, subsequent annotations for the
-        // same input line might appear to mark this note instead of the input
-        // line.
-        for (; Col <= InputLineWidth; ++Col)
-          COS << ' ';
-        COS << ' ' << Note;
-      }
-      COS << '\n';
-      ++AnnotationItr;
-    }
-  }
-
-  OS << ">>>>>>\n";
-}
-
-int main(int argc, char **argv) {
-  // Enable use of ANSI color codes because FileCheck is using them to
-  // highlight text.
-  llvm::sys::Process::UseANSIEscapeCodes(true);
-
-  InitLLVM X(argc, argv);
-  cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
-                              "FILECHECK_OPTS");
-  if (DumpInput == DumpInputHelp) {
-    DumpInputAnnotationHelp(outs());
-    return 0;
-  }
-  if (CheckFilename.empty()) {
-    errs() << "<check-file> not specified\n";
-    return 2;
-  }
-
-  FileCheckRequest Req;
-  for (auto Prefix : CheckPrefixes)
-    Req.CheckPrefixes.push_back(Prefix);
-
-  for (auto CheckNot : ImplicitCheckNot)
-    Req.ImplicitCheckNot.push_back(CheckNot);
-
-  bool GlobalDefineError = false;
-  for (auto G : GlobalDefines) {
-    size_t EqIdx = G.find('=');
-    if (EqIdx == std::string::npos) {
-      errs() << "Missing equal sign in command-line definition '-D" << G
-             << "'\n";
-      GlobalDefineError = true;
-      continue;
-    }
-    if (EqIdx == 0) {
-      errs() << "Missing variable name in command-line definition '-D" << G
-             << "'\n";
-      GlobalDefineError = true;
-      continue;
-    }
-    Req.GlobalDefines.push_back(G);
-  }
-  if (GlobalDefineError)
-    return 2;
-
-  Req.AllowEmptyInput = AllowEmptyInput;
-  Req.EnableVarScope = EnableVarScope;
-  Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
-  Req.Verbose = Verbose;
-  Req.VerboseVerbose = VerboseVerbose;
-  Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
-  Req.MatchFullLines = MatchFullLines;
-
-  if (VerboseVerbose)
-    Req.Verbose = true;
-
-  FileCheck FC(Req);
-  if (!FC.ValidateCheckPrefixes()) {
-    errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
-              "start with a letter and contain only alphanumeric characters, "
-              "hyphens and underscores\n";
-    return 2;
-  }
-
-  Regex PrefixRE = FC.buildCheckPrefixRegex();
-  std::string REError;
-  if (!PrefixRE.isValid(REError)) {
-    errs() << "Unable to combine check-prefix strings into a prefix regular "
-              "expression! This is likely a bug in FileCheck's verification of "
-              "the check-prefix strings. Regular expression parsing failed "
-              "with the following error: "
-           << REError << "\n";
-    return 2;
-  }
-
-  SourceMgr SM;
-
-  // Read the expected strings from the check file.
-  ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
-      MemoryBuffer::getFileOrSTDIN(CheckFilename);
-  if (std::error_code EC = CheckFileOrErr.getError()) {
-    errs() << "Could not open check file '" << CheckFilename
-           << "': " << EC.message() << '\n';
-    return 2;
-  }
-  MemoryBuffer &CheckFile = *CheckFileOrErr.get();
-
-  SmallString<4096> CheckFileBuffer;
-  StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
-
-  SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
-                            CheckFileText, CheckFile.getBufferIdentifier()),
-                        SMLoc());
-
-  if (FC.readCheckFile(SM, CheckFileText, PrefixRE))
-    return 2;
-
-  // Open the file to check and add it to SourceMgr.
-  ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
-      MemoryBuffer::getFileOrSTDIN(InputFilename);
-  if (std::error_code EC = InputFileOrErr.getError()) {
-    errs() << "Could not open input file '" << InputFilename
-           << "': " << EC.message() << '\n';
-    return 2;
-  }
-  MemoryBuffer &InputFile = *InputFileOrErr.get();
-
-  if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
-    errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
-    DumpCommandLine(argc, argv);
-    return 2;
-  }
-
-  SmallString<4096> InputFileBuffer;
-  StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
-
-  SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
-                            InputFileText, InputFile.getBufferIdentifier()),
-                        SMLoc());
-
-  if (DumpInput == DumpInputDefault)
-    DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;
-
-  std::vector<FileCheckDiag> Diags;
-  int ExitCode = FC.checkInput(SM, InputFileText,
-                               DumpInput == DumpInputNever ? nullptr : &Diags)
-                     ? EXIT_SUCCESS
-                     : 1;
-  if (DumpInput == DumpInputAlways ||
-      (ExitCode == 1 && DumpInput == DumpInputFail)) {
-    errs() << "\n"
-           << "Input file: "
-           << (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())
-           << "\n"
-           << "Check file: " << CheckFilename << "\n"
-           << "\n"
-           << "-dump-input=help describes the format of the following dump.\n"
-           << "\n";
-    std::vector<InputAnnotation> Annotations;
-    unsigned LabelWidth;
-    BuildInputAnnotations(Diags, Annotations, LabelWidth);
-    DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
-  }
-
-  return ExitCode;
-}
+//===- FileCheck.cpp - Check that File's Contents match what is expected --===//

+//

+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.

+// See https://llvm.org/LICENSE.txt for license information.

+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

+//

+//===----------------------------------------------------------------------===//

+//

+// FileCheck does a line-by line check of a file that validates whether it

+// contains the expected content.  This is useful for regression tests etc.

+//

+// This program exits with an exit status of 2 on error, exit status of 0 if

+// the file matched the expected contents, and exit status of 1 if it did not

+// contain the expected contents.

+//

+//===----------------------------------------------------------------------===//

+

+#include "llvm/Support/CommandLine.h"

+#include "llvm/Support/InitLLVM.h"

+#include "llvm/Support/Process.h"

+#include "llvm/Support/WithColor.h"

+#include "llvm/Support/raw_ostream.h"

+#include "llvm/Support/FileCheck.h"

+#include <cmath>

+using namespace llvm;

+

+static cl::extrahelp FileCheckOptsEnv(

+    "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"

+    "from the command line.\n");

+

+static cl::opt<std::string>

+    CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);

+

+static cl::opt<std::string>

+    InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),

+                  cl::init("-"), cl::value_desc("filename"));

+

+static cl::list<std::string> CheckPrefixes(

+    "check-prefix",

+    cl::desc("Prefix to use from check file (defaults to 'CHECK')"));

+static cl::alias CheckPrefixesAlias(

+    "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,

+    cl::NotHidden,

+    cl::desc(

+        "Alias for -check-prefix permitting multiple comma separated values"));

+

+static cl::opt<bool> NoCanonicalizeWhiteSpace(

+    "strict-whitespace",

+    cl::desc("Do not treat all horizontal whitespace as equivalent"));

+

+static cl::opt<bool> IgnoreCase(

+    "ignore-case",

+    cl::desc("Use case-insensitive matching"));

+

+static cl::list<std::string> ImplicitCheckNot(

+    "implicit-check-not",

+    cl::desc("Add an implicit negative check with this pattern to every\n"

+             "positive check. This can be used to ensure that no instances of\n"

+             "this pattern occur which are not matched by a positive pattern"),

+    cl::value_desc("pattern"));

+

+static cl::list<std::string>

+    GlobalDefines("D", cl::AlwaysPrefix,

+                  cl::desc("Define a variable to be used in capture patterns."),

+                  cl::value_desc("VAR=VALUE"));

+

+static cl::opt<bool> AllowEmptyInput(

+    "allow-empty", cl::init(false),

+    cl::desc("Allow the input file to be empty. This is useful when making\n"

+             "checks that some error message does not occur, for example."));

+

+static cl::opt<bool> MatchFullLines(

+    "match-full-lines", cl::init(false),

+    cl::desc("Require all positive matches to cover an entire input line.\n"

+             "Allows leading and trailing whitespace if --strict-whitespace\n"

+             "is not also passed."));

+

+static cl::opt<bool> EnableVarScope(

+    "enable-var-scope", cl::init(false),

+    cl::desc("Enables scope for regex variables. Variables with names that\n"

+             "do not start with '$' will be reset at the beginning of\n"

+             "each CHECK-LABEL block."));

+

+static cl::opt<bool> AllowDeprecatedDagOverlap(

+    "allow-deprecated-dag-overlap", cl::init(false),

+    cl::desc("Enable overlapping among matches in a group of consecutive\n"

+             "CHECK-DAG directives.  This option is deprecated and is only\n"

+             "provided for convenience as old tests are migrated to the new\n"

+             "non-overlapping CHECK-DAG implementation.\n"));

+

+static cl::opt<bool> Verbose(

+    "v", cl::init(false),

+    cl::desc("Print directive pattern matches, or add them to the input dump\n"

+             "if enabled.\n"));

+

+static cl::opt<bool> VerboseVerbose(

+    "vv", cl::init(false),

+    cl::desc("Print information helpful in diagnosing internal FileCheck\n"

+             "issues, or add it to the input dump if enabled.  Implies\n"

+             "-v.\n"));

+static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";

+

+static cl::opt<bool> DumpInputOnFailure(

+    "dump-input-on-failure",

+    cl::init(std::getenv(DumpInputEnv) && *std::getenv(DumpInputEnv)),

+    cl::desc("Dump original input to stderr before failing.\n"

+             "The value can be also controlled using\n"

+             "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"

+             "This option is deprecated in favor of -dump-input=fail.\n"));

+

+enum DumpInputValue {

+  DumpInputDefault,

+  DumpInputHelp,

+  DumpInputNever,

+  DumpInputFail,

+  DumpInputAlways

+};

+

+static cl::opt<DumpInputValue> DumpInput(

+    "dump-input", cl::init(DumpInputDefault),

+    cl::desc("Dump input to stderr, adding annotations representing\n"

+             " currently enabled diagnostics\n"),

+    cl::value_desc("mode"),

+    cl::values(clEnumValN(DumpInputHelp, "help",

+                          "Explain dump format and quit"),

+               clEnumValN(DumpInputNever, "never", "Never dump input"),

+               clEnumValN(DumpInputFail, "fail", "Dump input on failure"),

+               clEnumValN(DumpInputAlways, "always", "Always dump input")));

+

+typedef cl::list<std::string>::const_iterator prefix_iterator;

+

+

+

+

+

+

+

+static void DumpCommandLine(int argc, char **argv) {

+  errs() << "FileCheck command line: ";

+  for (int I = 0; I < argc; I++)

+    errs() << " " << argv[I];

+  errs() << "\n";

+}

+

+struct MarkerStyle {

+  /// The starting char (before tildes) for marking the line.

+  char Lead;

+  /// What color to use for this annotation.

+  raw_ostream::Colors Color;

+  /// A note to follow the marker, or empty string if none.

+  std::string Note;

+  MarkerStyle() {}

+  MarkerStyle(char Lead, raw_ostream::Colors Color,

+              const std::string &Note = "")

+      : Lead(Lead), Color(Color), Note(Note) {}

+};

+

+static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {

+  switch (MatchTy) {

+  case FileCheckDiag::MatchFoundAndExpected:

+    return MarkerStyle('^', raw_ostream::GREEN);

+  case FileCheckDiag::MatchFoundButExcluded:

+    return MarkerStyle('!', raw_ostream::RED, "error: no match expected");

+  case FileCheckDiag::MatchFoundButWrongLine:

+    return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");

+  case FileCheckDiag::MatchFoundButDiscarded:

+    return MarkerStyle('!', raw_ostream::CYAN,

+                       "discard: overlaps earlier match");

+  case FileCheckDiag::MatchNoneAndExcluded:

+    return MarkerStyle('X', raw_ostream::GREEN);

+  case FileCheckDiag::MatchNoneButExpected:

+    return MarkerStyle('X', raw_ostream::RED, "error: no match found");

+  case FileCheckDiag::MatchFuzzy:

+    return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");

+  }

+  llvm_unreachable_internal("unexpected match type");

+}

+

+static void DumpInputAnnotationHelp(raw_ostream &OS) {

+  OS << "The following description was requested by -dump-input=help to\n"

+     << "explain the input annotations printed by -dump-input=always and\n"

+     << "-dump-input=fail:\n\n";

+

+  // Labels for input lines.

+  OS << "  - ";

+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";

+  OS << "     labels line number L of the input file\n";

+

+  // Labels for annotation lines.

+  OS << "  - ";

+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";

+  OS << "    labels the only match result for a pattern of type T from "

+     << "line L of\n"

+     << "           the check file\n";

+  OS << "  - ";

+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";

+  OS << "  labels the Nth match result for a pattern of type T from line "

+     << "L of\n"

+     << "           the check file\n";

+

+  // Markers on annotation lines.

+  OS << "  - ";

+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";

+  OS << "    marks good match (reported if -v)\n"

+     << "  - ";

+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";

+  OS << "    marks bad match, such as:\n"

+     << "           - CHECK-NEXT on same line as previous match (error)\n"

+     << "           - CHECK-NOT found (error)\n"

+     << "           - CHECK-DAG overlapping match (discarded, reported if "

+     << "-vv)\n"

+     << "  - ";

+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";

+  OS << "    marks search range when no match is found, such as:\n"

+     << "           - CHECK-NEXT not found (error)\n"

+     << "           - CHECK-NOT not found (success, reported if -vv)\n"

+     << "           - CHECK-DAG not found after discarded matches (error)\n"

+     << "  - ";

+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";

+  OS << "      marks fuzzy match when no match is found\n";

+

+  // Colors.

+  OS << "  - colors ";

+  WithColor(OS, raw_ostream::GREEN, true) << "success";

+  OS << ", ";

+  WithColor(OS, raw_ostream::RED, true) << "error";

+  OS << ", ";

+  WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";

+  OS << ", ";

+  WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";

+  OS << ", ";

+  WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";

+  OS << "\n\n"

+     << "If you are not seeing color above or in input dumps, try: -color\n";

+}

+

+/// An annotation for a single input line.

+struct InputAnnotation {

+  /// The check file line (one-origin indexing) where the directive that

+  /// produced this annotation is located.

+  unsigned CheckLine;

+  /// The index of the match result for this check.

+  unsigned CheckDiagIndex;

+  /// The label for this annotation.

+  std::string Label;

+  /// What input line (one-origin indexing) this annotation marks.  This might

+  /// be different from the starting line of the original diagnostic if this is

+  /// a non-initial fragment of a diagnostic that has been broken across

+  /// multiple lines.

+  unsigned InputLine;

+  /// The column range (one-origin indexing, open end) in which to to mark the

+  /// input line.  If InputEndCol is UINT_MAX, treat it as the last column

+  /// before the newline.

+  unsigned InputStartCol, InputEndCol;

+  /// The marker to use.

+  MarkerStyle Marker;

+  /// Whether this annotation represents a good match for an expected pattern.

+  bool FoundAndExpectedMatch;

+};

+

+/// Get an abbreviation for the check type.

+std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {

+  switch (Ty) {

+  case Check::CheckPlain:

+    if (Ty.getCount() > 1)

+      return "count";

+    return "check";

+  case Check::CheckNext:

+    return "next";

+  case Check::CheckSame:

+    return "same";

+  case Check::CheckNot:

+    return "not";

+  case Check::CheckDAG:

+    return "dag";

+  case Check::CheckLabel:

+    return "label";

+  case Check::CheckEmpty:

+    return "empty";

+  case Check::CheckEOF:

+    return "eof";

+  case Check::CheckBadNot:

+    return "bad-not";

+  case Check::CheckBadCount:

+    return "bad-count";

+  case Check::CheckNone:

+    llvm_unreachable("invalid FileCheckType");

+  }

+  llvm_unreachable("unknown FileCheckType");

+}

+

+static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,

+                                  std::vector<InputAnnotation> &Annotations,

+                                  unsigned &LabelWidth) {

+  // How many diagnostics has the current check seen so far?

+  unsigned CheckDiagCount = 0;

+  // What's the widest label?

+  LabelWidth = 0;

+  for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;

+       ++DiagItr) {

+    InputAnnotation A;

+

+    // Build label, which uniquely identifies this check result.

+    A.CheckLine = DiagItr->CheckLine;

+    llvm::raw_string_ostream Label(A.Label);

+    Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"

+          << DiagItr->CheckLine;

+    A.CheckDiagIndex = UINT_MAX;

+    auto DiagNext = std::next(DiagItr);

+    if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&

+        DiagItr->CheckLine == DiagNext->CheckLine)

+      A.CheckDiagIndex = CheckDiagCount++;

+    else if (CheckDiagCount) {

+      A.CheckDiagIndex = CheckDiagCount;

+      CheckDiagCount = 0;

+    }

+    if (A.CheckDiagIndex != UINT_MAX)

+      Label << "'" << A.CheckDiagIndex;

+    else

+      A.CheckDiagIndex = 0;

+    Label.flush();

+    LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());

+

+    A.Marker = GetMarker(DiagItr->MatchTy);

+    A.FoundAndExpectedMatch =

+        DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;

+

+    // Compute the mark location, and break annotation into multiple

+    // annotations if it spans multiple lines.

+    A.InputLine = DiagItr->InputStartLine;

+    A.InputStartCol = DiagItr->InputStartCol;

+    if (DiagItr->InputStartLine == DiagItr->InputEndLine) {

+      // Sometimes ranges are empty in order to indicate a specific point, but

+      // that would mean nothing would be marked, so adjust the range to

+      // include the following character.

+      A.InputEndCol =

+          std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);

+      Annotations.push_back(A);

+    } else {

+      assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&

+             "expected input range not to be inverted");

+      A.InputEndCol = UINT_MAX;

+      Annotations.push_back(A);

+      for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;

+           L <= E; ++L) {

+        // If a range ends before the first column on a line, then it has no

+        // characters on that line, so there's nothing to render.

+        if (DiagItr->InputEndCol == 1 && L == E)

+          break;

+        InputAnnotation B;

+        B.CheckLine = A.CheckLine;

+        B.CheckDiagIndex = A.CheckDiagIndex;

+        B.Label = A.Label;

+        B.InputLine = L;

+        B.Marker = A.Marker;

+        B.Marker.Lead = '~';

+        B.Marker.Note = "";

+        B.InputStartCol = 1;

+        if (L != E)

+          B.InputEndCol = UINT_MAX;

+        else

+          B.InputEndCol = DiagItr->InputEndCol;

+        B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;

+        Annotations.push_back(B);

+      }

+    }

+  }

+}

+

+static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,

+                               StringRef InputFileText,

+                               std::vector<InputAnnotation> &Annotations,

+                               unsigned LabelWidth) {

+  OS << "Full input was:\n<<<<<<\n";

+

+  // Sort annotations.

+  //

+  // First, sort in the order of input lines to make it easier to find relevant

+  // annotations while iterating input lines in the implementation below.

+  // FileCheck diagnostics are not always reported and recorded in the order of

+  // input lines due to, for example, CHECK-DAG and CHECK-NOT.

+  //

+  // Second, for annotations for the same input line, sort in the order of the

+  // FileCheck directive's line in the check file (where there's at most one

+  // directive per line) and then by the index of the match result for that

+  // directive.  The rationale of this choice is that, for any input line, this

+  // sort establishes a total order of annotations that, with respect to match

+  // results, is consistent across multiple lines, thus making match results

+  // easier to track from one line to the next when they span multiple lines.

+  std::sort(Annotations.begin(), Annotations.end(),

+            [](const InputAnnotation &A, const InputAnnotation &B) {

+              if (A.InputLine != B.InputLine)

+                return A.InputLine < B.InputLine;

+              if (A.CheckLine != B.CheckLine)

+                return A.CheckLine < B.CheckLine;

+              // FIXME: Sometimes CHECK-LABEL reports its match twice with

+              // other diagnostics in between, and then diag index incrementing

+              // fails to work properly, and then this assert fails.  We should

+              // suppress one of those diagnostics or do a better job of

+              // computing this index.  For now, we just produce a redundant

+              // CHECK-LABEL annotation.

+              // assert(A.CheckDiagIndex != B.CheckDiagIndex &&

+              //        "expected diagnostic indices to be unique within a "

+              //        " check line");

+              return A.CheckDiagIndex < B.CheckDiagIndex;

+            });

+

+  // Compute the width of the label column.

+  const unsigned char *InputFilePtr = InputFileText.bytes_begin(),

+                      *InputFileEnd = InputFileText.bytes_end();

+  unsigned LineCount = InputFileText.count('\n');

+  if (InputFileEnd[-1] != '\n')

+    ++LineCount;

+  unsigned LineNoWidth = std::log10(LineCount) + 1;

+  // +3 below adds spaces (1) to the left of the (right-aligned) line numbers

+  // on input lines and (2) to the right of the (left-aligned) labels on

+  // annotation lines so that input lines and annotation lines are more

+  // visually distinct.  For example, the spaces on the annotation lines ensure

+  // that input line numbers and check directive line numbers never align

+  // horizontally.  Those line numbers might not even be for the same file.

+  // One space would be enough to achieve that, but more makes it even easier

+  // to see.

+  LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;

+

+  // Print annotated input lines.

+  auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();

+  for (unsigned Line = 1;

+       InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;

+       ++Line) {

+    const unsigned char *InputFileLine = InputFilePtr;

+

+    // Print right-aligned line number.

+    WithColor(OS, raw_ostream::BLACK, true)

+        << format_decimal(Line, LabelWidth) << ": ";

+

+    // For the case where -v and colors are enabled, find the annotations for

+    // good matches for expected patterns in order to highlight everything

+    // else in the line.  There are no such annotations if -v is disabled.

+    std::vector<InputAnnotation> FoundAndExpectedMatches;

+    if (Req.Verbose && WithColor(OS).colorsEnabled()) {

+      for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;

+           ++I) {

+        if (I->FoundAndExpectedMatch)

+          FoundAndExpectedMatches.push_back(*I);

+      }

+    }

+

+    // Print numbered line with highlighting where there are no matches for

+    // expected patterns.

+    bool Newline = false;

+    {

+      WithColor COS(OS);

+      bool InMatch = false;

+      if (Req.Verbose)

+        COS.changeColor(raw_ostream::CYAN, true, true);

+      for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {

+        bool WasInMatch = InMatch;

+        InMatch = false;

+        for (auto M : FoundAndExpectedMatches) {

+          if (M.InputStartCol <= Col && Col < M.InputEndCol) {

+            InMatch = true;

+            break;

+          }

+        }

+        if (!WasInMatch && InMatch)

+          COS.resetColor();

+        else if (WasInMatch && !InMatch)

+          COS.changeColor(raw_ostream::CYAN, true, true);

+        if (*InputFilePtr == '\n')

+          Newline = true;

+        else

+          COS << *InputFilePtr;

+        ++InputFilePtr;

+      }

+    }

+    OS << '\n';

+    unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;

+

+    // Print any annotations.

+    while (AnnotationItr != AnnotationEnd &&

+           AnnotationItr->InputLine == Line) {

+      WithColor COS(OS, AnnotationItr->Marker.Color, true);

+      // The two spaces below are where the ": " appears on input lines.

+      COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";

+      unsigned Col;

+      for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)

+        COS << ' ';

+      COS << AnnotationItr->Marker.Lead;

+      // If InputEndCol=UINT_MAX, stop at InputLineWidth.

+      for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;

+           ++Col)

+        COS << '~';

+      const std::string &Note = AnnotationItr->Marker.Note;

+      if (!Note.empty()) {

+        // Put the note at the end of the input line.  If we were to instead

+        // put the note right after the marker, subsequent annotations for the

+        // same input line might appear to mark this note instead of the input

+        // line.

+        for (; Col <= InputLineWidth; ++Col)

+          COS << ' ';

+        COS << ' ' << Note;

+      }

+      COS << '\n';

+      ++AnnotationItr;

+    }

+  }

+

+  OS << ">>>>>>\n";

+}

+

+int main(int argc, char **argv) {

+  // Enable use of ANSI color codes because FileCheck is using them to

+  // highlight text.

+  llvm::sys::Process::UseANSIEscapeCodes(true);

+

+  InitLLVM X(argc, argv);

+  cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,

+                              "FILECHECK_OPTS");

+  if (DumpInput == DumpInputHelp) {

+    DumpInputAnnotationHelp(outs());

+    return 0;

+  }

+  if (CheckFilename.empty()) {

+    errs() << "<check-file> not specified\n";

+    return 2;

+  }

+

+  FileCheckRequest Req;

+  for (auto Prefix : CheckPrefixes)

+    Req.CheckPrefixes.push_back(Prefix);

+

+  for (auto CheckNot : ImplicitCheckNot)

+    Req.ImplicitCheckNot.push_back(CheckNot);

+

+  bool GlobalDefineError = false;

+  for (auto G : GlobalDefines) {

+    size_t EqIdx = G.find('=');

+    if (EqIdx == std::string::npos) {

+      errs() << "Missing equal sign in command-line definition '-D" << G

+             << "'\n";

+      GlobalDefineError = true;

+      continue;

+    }

+    if (EqIdx == 0) {

+      errs() << "Missing variable name in command-line definition '-D" << G

+             << "'\n";

+      GlobalDefineError = true;

+      continue;

+    }

+    Req.GlobalDefines.push_back(G);

+  }

+  if (GlobalDefineError)

+    return 2;

+

+  Req.AllowEmptyInput = AllowEmptyInput;

+  Req.EnableVarScope = EnableVarScope;

+  Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;

+  Req.Verbose = Verbose;

+  Req.VerboseVerbose = VerboseVerbose;

+  Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;

+  Req.MatchFullLines = MatchFullLines;

+  Req.IgnoreCase = IgnoreCase;

+

+  if (VerboseVerbose)

+    Req.Verbose = true;

+

+  FileCheck FC(Req);

+  if (!FC.ValidateCheckPrefixes()) {

+    errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "

+              "start with a letter and contain only alphanumeric characters, "

+              "hyphens and underscores\n";

+    return 2;

+  }

+

+  Regex PrefixRE = FC.buildCheckPrefixRegex();

+  std::string REError;

+  if (!PrefixRE.isValid(REError)) {

+    errs() << "Unable to combine check-prefix strings into a prefix regular "

+              "expression! This is likely a bug in FileCheck's verification of "

+              "the check-prefix strings. Regular expression parsing failed "

+              "with the following error: "

+           << REError << "\n";

+    return 2;

+  }

+

+  SourceMgr SM;

+

+  // Read the expected strings from the check file.

+  ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =

+      MemoryBuffer::getFileOrSTDIN(CheckFilename);

+  if (std::error_code EC = CheckFileOrErr.getError()) {

+    errs() << "Could not open check file '" << CheckFilename

+           << "': " << EC.message() << '\n';

+    return 2;

+  }

+  MemoryBuffer &CheckFile = *CheckFileOrErr.get();

+

+  SmallString<4096> CheckFileBuffer;

+  StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);

+

+  SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(

+                            CheckFileText, CheckFile.getBufferIdentifier()),

+                        SMLoc());

+

+  if (FC.readCheckFile(SM, CheckFileText, PrefixRE))

+    return 2;

+

+  // Open the file to check and add it to SourceMgr.

+  ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =

+      MemoryBuffer::getFileOrSTDIN(InputFilename);

+  if (std::error_code EC = InputFileOrErr.getError()) {

+    errs() << "Could not open input file '" << InputFilename

+           << "': " << EC.message() << '\n';

+    return 2;

+  }

+  MemoryBuffer &InputFile = *InputFileOrErr.get();

+

+  if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {

+    errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";

+    DumpCommandLine(argc, argv);

+    return 2;

+  }

+

+  SmallString<4096> InputFileBuffer;

+  StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);

+

+  SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(

+                            InputFileText, InputFile.getBufferIdentifier()),

+                        SMLoc());

+

+  if (DumpInput == DumpInputDefault)

+    DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;

+

+  std::vector<FileCheckDiag> Diags;

+  int ExitCode = FC.checkInput(SM, InputFileText,

+                               DumpInput == DumpInputNever ? nullptr : &Diags)

+                     ? EXIT_SUCCESS

+                     : 1;

+  if (DumpInput == DumpInputAlways ||

+      (ExitCode == 1 && DumpInput == DumpInputFail)) {

+    errs() << "\n"

+           << "Input file: "

+           << (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())

+           << "\n"

+           << "Check file: " << CheckFilename << "\n"

+           << "\n"

+           << "-dump-input=help describes the format of the following dump.\n"

+           << "\n";

+    std::vector<InputAnnotation> Annotations;

+    unsigned LabelWidth;

+    BuildInputAnnotations(Diags, Annotations, LabelWidth);

+    DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);

+  }

+

+  return ExitCode;

+}