]> granicus.if.org Git - llvm/commitdiff
Revert "[FileCheck] Implement --ignore-case option."
authorDmitri Gribenko <gribozavr@gmail.com>
Thu, 10 Oct 2019 14:27:14 +0000 (14:27 +0000)
committerDmitri Gribenko <gribozavr@gmail.com>
Thu, 10 Oct 2019 14:27:14 +0000 (14:27 +0000)
This reverts commit r374339. It broke tests:
http://lab.llvm.org:8011/builders/clang-x86_64-debian-fast/builds/19066

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374359 91177308-0d34-0410-b5e6-96231b3b80d8

docs/CommandGuide/FileCheck.rst
include/llvm/Support/FileCheck.h
lib/Support/FileCheck.cpp
lib/Support/FileCheckImpl.h
test/FileCheck/check-ignore-case.txt [deleted file]
utils/FileCheck/FileCheck.cpp

index 7d8ecaa7bfa6d8bda8467324295604928bee033d..e8b324d080dfa95c397ff71e7d21d1078ab37b2d 100644 (file)
-FileCheck - Flexible pattern matching file verifier\r
-===================================================\r
-\r
-.. program:: FileCheck\r
-\r
-SYNOPSIS\r
---------\r
-\r
-:program:`FileCheck` *match-filename* [*--check-prefix=XXX*] [*--strict-whitespace*]\r
-\r
-DESCRIPTION\r
------------\r
-\r
-:program:`FileCheck` reads two files (one from standard input, and one\r
-specified on the command line) and uses one to verify the other.  This\r
-behavior is particularly useful for the testsuite, which wants to verify that\r
-the output of some tool (e.g. :program:`llc`) contains the expected information\r
-(for example, a movsd from esp or whatever is interesting).  This is similar to\r
-using :program:`grep`, but it is optimized for matching multiple different\r
-inputs in one file in a specific order.\r
-\r
-The ``match-filename`` file specifies the file that contains the patterns to\r
-match.  The file to verify is read from standard input unless the\r
-:option:`--input-file` option is used.\r
-\r
-OPTIONS\r
--------\r
-\r
-Options are parsed from the environment variable ``FILECHECK_OPTS``\r
-and from the command line.\r
-\r
-.. option:: -help\r
-\r
- Print a summary of command line options.\r
-\r
-.. option:: --check-prefix prefix\r
-\r
- FileCheck searches the contents of ``match-filename`` for patterns to\r
- match.  By default, these patterns are prefixed with "``CHECK:``".\r
- If you'd like to use a different prefix (e.g. because the same input\r
- file is checking multiple different tool or options), the\r
- :option:`--check-prefix` argument allows you to specify one or more\r
- prefixes to match. Multiple prefixes are useful for tests which might\r
- change for different run options, but most lines remain the same.\r
-\r
-.. option:: --check-prefixes prefix1,prefix2,...\r
-\r
- An alias of :option:`--check-prefix` that allows multiple prefixes to be\r
- specified as a comma separated list.\r
-\r
-.. option:: --input-file filename\r
-\r
-  File to check (defaults to stdin).\r
-\r
-.. option:: --match-full-lines\r
-\r
- By default, FileCheck allows matches of anywhere on a line. This\r
- option will require all positive matches to cover an entire\r
- line. Leading and trailing whitespace is ignored, unless\r
- :option:`--strict-whitespace` is also specified. (Note: negative\r
- matches from ``CHECK-NOT`` are not affected by this option!)\r
-\r
- Passing this option is equivalent to inserting ``{{^ *}}`` or\r
- ``{{^}}`` before, and ``{{ *$}}`` or ``{{$}}`` after every positive\r
- check pattern.\r
-\r
-.. option:: --strict-whitespace\r
-\r
- By default, FileCheck canonicalizes input horizontal whitespace (spaces and\r
- tabs) which causes it to ignore these differences (a space will match a tab).\r
- The :option:`--strict-whitespace` argument disables this behavior. End-of-line\r
- sequences are canonicalized to UNIX-style ``\n`` in all modes.\r
-\r
-.. option:: --ignore-case\r
-\r
-  By default, FileCheck uses case-sensitive matching. This option causes\r
-  FileCheck to use case-insensitive matching.\r
-\r
-.. option:: --implicit-check-not check-pattern\r
-\r
-  Adds implicit negative checks for the specified patterns between positive\r
-  checks. The option allows writing stricter tests without stuffing them with\r
-  ``CHECK-NOT``\ s.\r
-\r
-  For example, "``--implicit-check-not warning:``" can be useful when testing\r
-  diagnostic messages from tools that don't have an option similar to ``clang\r
-  -verify``. With this option FileCheck will verify that input does not contain\r
-  warnings not covered by any ``CHECK:`` patterns.\r
-\r
-.. option:: --dump-input <mode>\r
-\r
-  Dump input to stderr, adding annotations representing currently enabled\r
-  diagnostics.  Do this either 'always', on 'fail', or 'never'.  Specify 'help'\r
-  to explain the dump format and quit.\r
-\r
-.. option:: --dump-input-on-failure\r
-\r
-  When the check fails, dump all of the original input.  This option is\r
-  deprecated in favor of `--dump-input=fail`.\r
-\r
-.. option:: --enable-var-scope\r
-\r
-  Enables scope for regex variables.\r
-\r
-  Variables with names that start with ``$`` are considered global and\r
-  remain set throughout the file.\r
-\r
-  All other variables get undefined after each encountered ``CHECK-LABEL``.\r
-\r
-.. option:: -D<VAR=VALUE>\r
-\r
-  Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be\r
-  used in ``CHECK:`` lines.\r
-\r
-.. option:: -D#<NUMVAR>=<NUMERIC EXPRESSION>\r
-\r
-  Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating\r
-  ``<NUMERIC EXPRESSION>`` that can be used in ``CHECK:`` lines. See section\r
-  ``FileCheck Numeric Variables and Expressions`` for details on supported\r
-  numeric expressions.\r
-\r
-.. option:: -version\r
-\r
- Show the version number of this program.\r
-\r
-.. option:: -v\r
-\r
-  Print good directive pattern matches.  However, if ``-input-dump=fail`` or\r
-  ``-input-dump=always``, add those matches as input annotations instead.\r
-\r
-.. option:: -vv\r
-\r
-  Print information helpful in diagnosing internal FileCheck issues, such as\r
-  discarded overlapping ``CHECK-DAG:`` matches, implicit EOF pattern matches,\r
-  and ``CHECK-NOT:`` patterns that do not have matches.  Implies ``-v``.\r
-  However, if ``-input-dump=fail`` or ``-input-dump=always``, just add that\r
-  information as input annotations instead.\r
-\r
-.. option:: --allow-deprecated-dag-overlap\r
-\r
-  Enable overlapping among matches in a group of consecutive ``CHECK-DAG:``\r
-  directives.  This option is deprecated and is only provided for convenience\r
-  as old tests are migrated to the new non-overlapping ``CHECK-DAG:``\r
-  implementation.\r
-\r
-.. option:: --color\r
-\r
-  Use colors in output (autodetected by default).\r
-\r
-EXIT STATUS\r
------------\r
-\r
-If :program:`FileCheck` verifies that the file matches the expected contents,\r
-it exits with 0.  Otherwise, if not, or if an error occurs, it will exit with a\r
-non-zero value.\r
-\r
-TUTORIAL\r
---------\r
-\r
-FileCheck is typically used from LLVM regression tests, being invoked on the RUN\r
-line of the test.  A simple example of using FileCheck from a RUN line looks\r
-like this:\r
-\r
-.. code-block:: llvm\r
-\r
-   ; RUN: llvm-as < %s | llc -march=x86-64 | FileCheck %s\r
-\r
-This syntax says to pipe the current file ("``%s``") into ``llvm-as``, pipe\r
-that into ``llc``, then pipe the output of ``llc`` into ``FileCheck``.  This\r
-means that FileCheck will be verifying its standard input (the llc output)\r
-against the filename argument specified (the original ``.ll`` file specified by\r
-"``%s``").  To see how this works, let's look at the rest of the ``.ll`` file\r
-(after the RUN line):\r
-\r
-.. code-block:: llvm\r
-\r
-   define void @sub1(i32* %p, i32 %v) {\r
-   entry:\r
-   ; CHECK: sub1:\r
-   ; CHECK: subl\r
-           %0 = tail call i32 @llvm.atomic.load.sub.i32.p0i32(i32* %p, i32 %v)\r
-           ret void\r
-   }\r
-\r
-   define void @inc4(i64* %p) {\r
-   entry:\r
-   ; CHECK: inc4:\r
-   ; CHECK: incq\r
-           %0 = tail call i64 @llvm.atomic.load.add.i64.p0i64(i64* %p, i64 1)\r
-           ret void\r
-   }\r
-\r
-Here you can see some "``CHECK:``" lines specified in comments.  Now you can\r
-see how the file is piped into ``llvm-as``, then ``llc``, and the machine code\r
-output is what we are verifying.  FileCheck checks the machine code output to\r
-verify that it matches what the "``CHECK:``" lines specify.\r
-\r
-The syntax of the "``CHECK:``" lines is very simple: they are fixed strings that\r
-must occur in order.  FileCheck defaults to ignoring horizontal whitespace\r
-differences (e.g. a space is allowed to match a tab) but otherwise, the contents\r
-of the "``CHECK:``" line is required to match some thing in the test file exactly.\r
-\r
-One nice thing about FileCheck (compared to grep) is that it allows merging\r
-test cases together into logical groups.  For example, because the test above\r
-is checking for the "``sub1:``" and "``inc4:``" labels, it will not match\r
-unless there is a "``subl``" in between those labels.  If it existed somewhere\r
-else in the file, that would not count: "``grep subl``" matches if "``subl``"\r
-exists anywhere in the file.\r
-\r
-The FileCheck -check-prefix option\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-The FileCheck `-check-prefix` option allows multiple test\r
-configurations to be driven from one `.ll` file.  This is useful in many\r
-circumstances, for example, testing different architectural variants with\r
-:program:`llc`.  Here's a simple example:\r
-\r
-.. code-block:: llvm\r
-\r
-   ; RUN: llvm-as < %s | llc -mtriple=i686-apple-darwin9 -mattr=sse41 \\r
-   ; RUN:              | FileCheck %s -check-prefix=X32\r
-   ; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 -mattr=sse41 \\r
-   ; RUN:              | FileCheck %s -check-prefix=X64\r
-\r
-   define <4 x i32> @pinsrd_1(i32 %s, <4 x i32> %tmp) nounwind {\r
-           %tmp1 = insertelement <4 x i32>; %tmp, i32 %s, i32 1\r
-           ret <4 x i32> %tmp1\r
-   ; X32: pinsrd_1:\r
-   ; X32:    pinsrd $1, 4(%esp), %xmm0\r
-\r
-   ; X64: pinsrd_1:\r
-   ; X64:    pinsrd $1, %edi, %xmm0\r
-   }\r
-\r
-In this case, we're testing that we get the expected code generation with\r
-both 32-bit and 64-bit code generation.\r
-\r
-The "CHECK-NEXT:" directive\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-Sometimes you want to match lines and would like to verify that matches\r
-happen on exactly consecutive lines with no other lines in between them.  In\r
-this case, you can use "``CHECK:``" and "``CHECK-NEXT:``" directives to specify\r
-this.  If you specified a custom check prefix, just use "``<PREFIX>-NEXT:``".\r
-For example, something like this works as you'd expect:\r
-\r
-.. code-block:: llvm\r
-\r
-   define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) {\r
-       %tmp3 = load <2 x double>* %A, align 16\r
-       %tmp7 = insertelement <2 x double> undef, double %B, i32 0\r
-       %tmp9 = shufflevector <2 x double> %tmp3,\r
-                               <2 x double> %tmp7,\r
-                               <2 x i32> < i32 0, i32 2 >\r
-       store <2 x double> %tmp9, <2 x double>* %r, align 16\r
-       ret void\r
-\r
-   ; CHECK:          t2:\r
-   ; CHECK:            movl    8(%esp), %eax\r
-   ; CHECK-NEXT:       movapd  (%eax), %xmm0\r
-   ; CHECK-NEXT:       movhpd  12(%esp), %xmm0\r
-   ; CHECK-NEXT:       movl    4(%esp), %eax\r
-   ; CHECK-NEXT:       movapd  %xmm0, (%eax)\r
-   ; CHECK-NEXT:       ret\r
-   }\r
-\r
-"``CHECK-NEXT:``" directives reject the input unless there is exactly one\r
-newline between it and the previous directive.  A "``CHECK-NEXT:``" cannot be\r
-the first directive in a file.\r
-\r
-The "CHECK-SAME:" directive\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-Sometimes you want to match lines and would like to verify that matches happen\r
-on the same line as the previous match.  In this case, you can use "``CHECK:``"\r
-and "``CHECK-SAME:``" directives to specify this.  If you specified a custom\r
-check prefix, just use "``<PREFIX>-SAME:``".\r
-\r
-"``CHECK-SAME:``" is particularly powerful in conjunction with "``CHECK-NOT:``"\r
-(described below).\r
-\r
-For example, the following works like you'd expect:\r
-\r
-.. code-block:: llvm\r
-\r
-   !0 = !DILocation(line: 5, scope: !1, inlinedAt: !2)\r
-\r
-   ; CHECK:       !DILocation(line: 5,\r
-   ; CHECK-NOT:               column:\r
-   ; CHECK-SAME:              scope: ![[SCOPE:[0-9]+]]\r
-\r
-"``CHECK-SAME:``" directives reject the input if there are any newlines between\r
-it and the previous directive.  A "``CHECK-SAME:``" cannot be the first\r
-directive in a file.\r
-\r
-The "CHECK-EMPTY:" directive\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-If you need to check that the next line has nothing on it, not even whitespace,\r
-you can use the "``CHECK-EMPTY:``" directive.\r
-\r
-.. code-block:: llvm\r
-\r
-   declare void @foo()\r
-\r
-   declare void @bar()\r
-   ; CHECK: foo\r
-   ; CHECK-EMPTY:\r
-   ; CHECK-NEXT: bar\r
-\r
-Just like "``CHECK-NEXT:``" the directive will fail if there is more than one\r
-newline before it finds the next blank line, and it cannot be the first\r
-directive in a file.\r
-\r
-The "CHECK-NOT:" directive\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-The "``CHECK-NOT:``" directive is used to verify that a string doesn't occur\r
-between two matches (or before the first match, or after the last match).  For\r
-example, to verify that a load is removed by a transformation, a test like this\r
-can be used:\r
-\r
-.. code-block:: llvm\r
-\r
-   define i8 @coerce_offset0(i32 %V, i32* %P) {\r
-     store i32 %V, i32* %P\r
-\r
-     %P2 = bitcast i32* %P to i8*\r
-     %P3 = getelementptr i8* %P2, i32 2\r
-\r
-     %A = load i8* %P3\r
-     ret i8 %A\r
-   ; CHECK: @coerce_offset0\r
-   ; CHECK-NOT: load\r
-   ; CHECK: ret i8\r
-   }\r
-\r
-The "CHECK-COUNT:" directive\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-If you need to match multiple lines with the same pattern over and over again\r
-you can repeat a plain ``CHECK:`` as many times as needed. If that looks too\r
-boring you can instead use a counted check "``CHECK-COUNT-<num>:``", where\r
-``<num>`` is a positive decimal number. It will match the pattern exactly\r
-``<num>`` times, no more and no less. If you specified a custom check prefix,\r
-just use "``<PREFIX>-COUNT-<num>:``" for the same effect.\r
-Here is a simple example:\r
-\r
-.. code-block:: text\r
-\r
-   Loop at depth 1\r
-   Loop at depth 1\r
-   Loop at depth 1\r
-   Loop at depth 1\r
-     Loop at depth 2\r
-       Loop at depth 3\r
-\r
-   ; CHECK-COUNT-6: Loop at depth {{[0-9]+}}\r
-   ; CHECK-NOT:     Loop at depth {{[0-9]+}}\r
-\r
-The "CHECK-DAG:" directive\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-If it's necessary to match strings that don't occur in a strictly sequential\r
-order, "``CHECK-DAG:``" could be used to verify them between two matches (or\r
-before the first match, or after the last match). For example, clang emits\r
-vtable globals in reverse order. Using ``CHECK-DAG:``, we can keep the checks\r
-in the natural order:\r
-\r
-.. code-block:: c++\r
-\r
-    // RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s\r
-\r
-    struct Foo { virtual void method(); };\r
-    Foo f;  // emit vtable\r
-    // CHECK-DAG: @_ZTV3Foo =\r
-\r
-    struct Bar { virtual void method(); };\r
-    Bar b;\r
-    // CHECK-DAG: @_ZTV3Bar =\r
-\r
-``CHECK-NOT:`` directives could be mixed with ``CHECK-DAG:`` directives to\r
-exclude strings between the surrounding ``CHECK-DAG:`` directives. As a result,\r
-the surrounding ``CHECK-DAG:`` directives cannot be reordered, i.e. all\r
-occurrences matching ``CHECK-DAG:`` before ``CHECK-NOT:`` must not fall behind\r
-occurrences matching ``CHECK-DAG:`` after ``CHECK-NOT:``. For example,\r
-\r
-.. code-block:: llvm\r
-\r
-   ; CHECK-DAG: BEFORE\r
-   ; CHECK-NOT: NOT\r
-   ; CHECK-DAG: AFTER\r
-\r
-This case will reject input strings where ``BEFORE`` occurs after ``AFTER``.\r
-\r
-With captured variables, ``CHECK-DAG:`` is able to match valid topological\r
-orderings of a DAG with edges from the definition of a variable to its use.\r
-It's useful, e.g., when your test cases need to match different output\r
-sequences from the instruction scheduler. For example,\r
-\r
-.. code-block:: llvm\r
-\r
-   ; CHECK-DAG: add [[REG1:r[0-9]+]], r1, r2\r
-   ; CHECK-DAG: add [[REG2:r[0-9]+]], r3, r4\r
-   ; CHECK:     mul r5, [[REG1]], [[REG2]]\r
-\r
-In this case, any order of that two ``add`` instructions will be allowed.\r
-\r
-If you are defining `and` using variables in the same ``CHECK-DAG:`` block,\r
-be aware that the definition rule can match `after` its use.\r
-\r
-So, for instance, the code below will pass:\r
-\r
-.. code-block:: text\r
-\r
-  ; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]\r
-  ; CHECK-DAG: vmov.32 [[REG2]][1]\r
-  vmov.32 d0[1]\r
-  vmov.32 d0[0]\r
-\r
-While this other code, will not:\r
-\r
-.. code-block:: text\r
-\r
-  ; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]\r
-  ; CHECK-DAG: vmov.32 [[REG2]][1]\r
-  vmov.32 d1[1]\r
-  vmov.32 d0[0]\r
-\r
-While this can be very useful, it's also dangerous, because in the case of\r
-register sequence, you must have a strong order (read before write, copy before\r
-use, etc). If the definition your test is looking for doesn't match (because\r
-of a bug in the compiler), it may match further away from the use, and mask\r
-real bugs away.\r
-\r
-In those cases, to enforce the order, use a non-DAG directive between DAG-blocks.\r
-\r
-A ``CHECK-DAG:`` directive skips matches that overlap the matches of any\r
-preceding ``CHECK-DAG:`` directives in the same ``CHECK-DAG:`` block.  Not only\r
-is this non-overlapping behavior consistent with other directives, but it's\r
-also necessary to handle sets of non-unique strings or patterns.  For example,\r
-the following directives look for unordered log entries for two tasks in a\r
-parallel program, such as the OpenMP runtime:\r
-\r
-.. code-block:: text\r
-\r
-    // CHECK-DAG: [[THREAD_ID:[0-9]+]]: task_begin\r
-    // CHECK-DAG: [[THREAD_ID]]: task_end\r
-    //\r
-    // CHECK-DAG: [[THREAD_ID:[0-9]+]]: task_begin\r
-    // CHECK-DAG: [[THREAD_ID]]: task_end\r
-\r
-The second pair of directives is guaranteed not to match the same log entries\r
-as the first pair even though the patterns are identical and even if the text\r
-of the log entries is identical because the thread ID manages to be reused.\r
-\r
-The "CHECK-LABEL:" directive\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-Sometimes in a file containing multiple tests divided into logical blocks, one\r
-or more ``CHECK:`` directives may inadvertently succeed by matching lines in a\r
-later block. While an error will usually eventually be generated, the check\r
-flagged as causing the error may not actually bear any relationship to the\r
-actual source of the problem.\r
-\r
-In order to produce better error messages in these cases, the "``CHECK-LABEL:``"\r
-directive can be used. It is treated identically to a normal ``CHECK``\r
-directive except that FileCheck makes an additional assumption that a line\r
-matched by the directive cannot also be matched by any other check present in\r
-``match-filename``; this is intended to be used for lines containing labels or\r
-other unique identifiers. Conceptually, the presence of ``CHECK-LABEL`` divides\r
-the input stream into separate blocks, each of which is processed independently,\r
-preventing a ``CHECK:`` directive in one block matching a line in another block.\r
-If ``--enable-var-scope`` is in effect, all local variables are cleared at the\r
-beginning of the block.\r
-\r
-For example,\r
-\r
-.. code-block:: llvm\r
-\r
-  define %struct.C* @C_ctor_base(%struct.C* %this, i32 %x) {\r
-  entry:\r
-  ; CHECK-LABEL: C_ctor_base:\r
-  ; CHECK: mov [[SAVETHIS:r[0-9]+]], r0\r
-  ; CHECK: bl A_ctor_base\r
-  ; CHECK: mov r0, [[SAVETHIS]]\r
-    %0 = bitcast %struct.C* %this to %struct.A*\r
-    %call = tail call %struct.A* @A_ctor_base(%struct.A* %0)\r
-    %1 = bitcast %struct.C* %this to %struct.B*\r
-    %call2 = tail call %struct.B* @B_ctor_base(%struct.B* %1, i32 %x)\r
-    ret %struct.C* %this\r
-  }\r
-\r
-  define %struct.D* @D_ctor_base(%struct.D* %this, i32 %x) {\r
-  entry:\r
-  ; CHECK-LABEL: D_ctor_base:\r
-\r
-The use of ``CHECK-LABEL:`` directives in this case ensures that the three\r
-``CHECK:`` directives only accept lines corresponding to the body of the\r
-``@C_ctor_base`` function, even if the patterns match lines found later in\r
-the file. Furthermore, if one of these three ``CHECK:`` directives fail,\r
-FileCheck will recover by continuing to the next block, allowing multiple test\r
-failures to be detected in a single invocation.\r
-\r
-There is no requirement that ``CHECK-LABEL:`` directives contain strings that\r
-correspond to actual syntactic labels in a source or output language: they must\r
-simply uniquely match a single line in the file being verified.\r
-\r
-``CHECK-LABEL:`` directives cannot contain variable definitions or uses.\r
-\r
-FileCheck Regex Matching Syntax\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-All FileCheck directives take a pattern to match.\r
-For most uses of FileCheck, fixed string matching is perfectly sufficient.  For\r
-some things, a more flexible form of matching is desired.  To support this,\r
-FileCheck allows you to specify regular expressions in matching strings,\r
-surrounded by double braces: ``{{yourregex}}``. FileCheck implements a POSIX\r
-regular expression matcher; it supports Extended POSIX regular expressions\r
-(ERE). Because we want to use fixed string matching for a majority of what we\r
-do, FileCheck has been designed to support mixing and matching fixed string\r
-matching with regular expressions.  This allows you to write things like this:\r
-\r
-.. code-block:: llvm\r
-\r
-   ; CHECK: movhpd     {{[0-9]+}}(%esp), {{%xmm[0-7]}}\r
-\r
-In this case, any offset from the ESP register will be allowed, and any xmm\r
-register will be allowed.\r
-\r
-Because regular expressions are enclosed with double braces, they are\r
-visually distinct, and you don't need to use escape characters within the double\r
-braces like you would in C.  In the rare case that you want to match double\r
-braces explicitly from the input, you can use something ugly like\r
-``{{[}][}]}}`` as your pattern.  Or if you are using the repetition count\r
-syntax, for example ``[[:xdigit:]]{8}`` to match exactly 8 hex digits, you\r
-would need to add parentheses like this ``{{([[:xdigit:]]{8})}}`` to avoid\r
-confusion with FileCheck's closing double-brace.\r
-\r
-FileCheck String Substitution Blocks\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-It is often useful to match a pattern and then verify that it occurs again\r
-later in the file.  For codegen tests, this can be useful to allow any\r
-register, but verify that that register is used consistently later.  To do\r
-this, :program:`FileCheck` supports string substitution blocks that allow\r
-string variables to be defined and substituted into patterns.  Here is a simple\r
-example:\r
-\r
-.. code-block:: llvm\r
-\r
-   ; CHECK: test5:\r
-   ; CHECK:    notw    [[REGISTER:%[a-z]+]]\r
-   ; CHECK:    andw    {{.*}}[[REGISTER]]\r
-\r
-The first check line matches a regex ``%[a-z]+`` and captures it into the\r
-string variable ``REGISTER``.  The second line verifies that whatever is in\r
-``REGISTER`` occurs later in the file after an "``andw``". :program:`FileCheck`\r
-string substitution blocks are always contained in ``[[ ]]`` pairs, and string\r
-variable names can be formed with the regex ``[a-zA-Z_][a-zA-Z0-9_]*``.  If a\r
-colon follows the name, then it is a definition of the variable; otherwise, it\r
-is a substitution.\r
-\r
-:program:`FileCheck` variables can be defined multiple times, and substitutions\r
-always get the latest value.  Variables can also be substituted later on the\r
-same line they were defined on. For example:\r
-\r
-.. code-block:: llvm\r
-\r
-    ; CHECK: op [[REG:r[0-9]+]], [[REG]]\r
-\r
-Can be useful if you want the operands of ``op`` to be the same register,\r
-and don't care exactly which register it is.\r
-\r
-If ``--enable-var-scope`` is in effect, variables with names that\r
-start with ``$`` are considered to be global. All others variables are\r
-local.  All local variables get undefined at the beginning of each\r
-CHECK-LABEL block. Global variables are not affected by CHECK-LABEL.\r
-This makes it easier to ensure that individual tests are not affected\r
-by variables set in preceding tests.\r
-\r
-FileCheck Numeric Substitution Blocks\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-:program:`FileCheck` also supports numeric substitution blocks that allow\r
-defining numeric variables and checking for numeric values that satisfy a\r
-numeric expression constraint based on those variables via a numeric\r
-substitution. This allows ``CHECK:`` directives to verify a numeric relation\r
-between two numbers, such as the need for consecutive registers to be used.\r
-\r
-The syntax to define a numeric variable is ``[[#<NUMVAR>:]]`` where\r
-``<NUMVAR>`` is the name of the numeric variable to define to the matching\r
-value.\r
-\r
-For example:\r
-\r
-.. code-block:: llvm\r
-\r
-    ; CHECK: mov r[[#REG:]], 42\r
-\r
-would match ``mov r5, 42`` and set ``REG`` to the value ``5``.\r
-\r
-The syntax of a numeric substitution is ``[[#<expr>]]`` where ``<expr>`` is an\r
-expression. An expression is recursively defined as:\r
-\r
-* a numeric operand, or\r
-* an expression followed by an operator and a numeric operand.\r
-\r
-A numeric operand is a previously defined numeric variable, or an integer\r
-literal. The supported operators are ``+`` and ``-``. Spaces are accepted\r
-before, after and between any of these elements.\r
-\r
-For example:\r
-\r
-.. code-block:: llvm\r
-\r
-    ; CHECK: load r[[#REG:]], [r0]\r
-    ; CHECK: load r[[#REG+1]], [r1]\r
-\r
-The above example would match the text:\r
-\r
-.. code-block:: gas\r
-\r
-    load r5, [r0]\r
-    load r6, [r1]\r
-\r
-but would not match the text:\r
-\r
-.. code-block:: gas\r
-\r
-    load r5, [r0]\r
-    load r7, [r1]\r
-\r
-due to ``7`` being unequal to ``5 + 1``.\r
-\r
-The syntax also supports an empty expression, equivalent to writing {{[0-9]+}},\r
-for cases where the input must contain a numeric value but the value itself\r
-does not matter:\r
-\r
-.. code-block:: gas\r
-\r
-    ; CHECK-NOT: mov r0, r[[#]]\r
-\r
-to check that a value is synthesized rather than moved around.\r
-\r
-A numeric variable can also be defined to the result of a numeric expression,\r
-in which case the numeric expression is checked and if verified the variable is\r
-assigned to the value. The unified syntax for both defining numeric variables\r
-and checking a numeric expression is thus ``[[#<NUMVAR>: <expr>]]`` with each\r
-element as described previously.\r
-\r
-The ``--enable-var-scope`` option has the same effect on numeric variables as\r
-on string variables.\r
-\r
-Important note: In its current implementation, an expression cannot use a\r
-numeric variable defined earlier in the same CHECK directive.\r
-\r
-FileCheck Pseudo Numeric Variables\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-Sometimes there's a need to verify output that contains line numbers of the\r
-match file, e.g. when testing compiler diagnostics.  This introduces a certain\r
-fragility of the match file structure, as "``CHECK:``" lines contain absolute\r
-line numbers in the same file, which have to be updated whenever line numbers\r
-change due to text addition or deletion.\r
-\r
-To support this case, FileCheck expressions understand the ``@LINE`` pseudo\r
-numeric variable which evaluates to the line number of the CHECK pattern where\r
-it is found.\r
-\r
-This way match patterns can be put near the relevant test lines and include\r
-relative line number references, for example:\r
-\r
-.. code-block:: c++\r
-\r
-   // CHECK: test.cpp:[[# @LINE + 4]]:6: error: expected ';' after top level declarator\r
-   // CHECK-NEXT: {{^int a}}\r
-   // CHECK-NEXT: {{^     \^}}\r
-   // CHECK-NEXT: {{^     ;}}\r
-   int a\r
-\r
-To support legacy uses of ``@LINE`` as a special string variable,\r
-:program:`FileCheck` also accepts the following uses of ``@LINE`` with string\r
-substitution block syntax: ``[[@LINE]]``, ``[[@LINE+<offset>]]`` and\r
-``[[@LINE-<offset>]]`` without any spaces inside the brackets and where\r
-``offset`` is an integer.\r
-\r
-Matching Newline Characters\r
-~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
-\r
-To match newline characters in regular expressions the character class\r
-``[[:space:]]`` can be used. For example, the following pattern:\r
-\r
-.. code-block:: c++\r
-\r
-   // CHECK: DW_AT_location [DW_FORM_sec_offset] ([[DLOC:0x[0-9a-f]+]]){{[[:space:]].*}}"intd"\r
-\r
-matches output of the form (from llvm-dwarfdump):\r
-\r
-.. code-block:: text\r
-\r
-       DW_AT_location [DW_FORM_sec_offset]   (0x00000233)\r
-       DW_AT_name [DW_FORM_strp]  ( .debug_str[0x000000c9] = "intd")\r
-\r
-letting us set the :program:`FileCheck` variable ``DLOC`` to the desired value \r
-``0x00000233``, extracted from the line immediately preceding "``intd``".\r
+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``".
index dc6dc7496af1fb03490e4e2fa783715014fb376b..5c6585ed76f758727cfac83e287f09364394c10b 100644 (file)
-//==-- llvm/Support/FileCheck.h ---------------------------*- C++ -*-==//\r
-//\r
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.\r
-// See https://llvm.org/LICENSE.txt for license information.\r
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\r
-//\r
-//===----------------------------------------------------------------------===//\r
-//\r
-/// \file This file has some utilities to use FileCheck as an API\r
-//\r
-//===----------------------------------------------------------------------===//\r
-\r
-#ifndef LLVM_SUPPORT_FILECHECK_H\r
-#define LLVM_SUPPORT_FILECHECK_H\r
-\r
-#include "llvm/ADT/StringRef.h"\r
-#include "llvm/Support/MemoryBuffer.h"\r
-#include "llvm/Support/Regex.h"\r
-#include "llvm/Support/SourceMgr.h"\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace llvm {\r
-\r
-/// Contains info about various FileCheck options.\r
-struct FileCheckRequest {\r
-  std::vector<std::string> CheckPrefixes;\r
-  bool NoCanonicalizeWhiteSpace = false;\r
-  std::vector<std::string> ImplicitCheckNot;\r
-  std::vector<std::string> GlobalDefines;\r
-  bool AllowEmptyInput = false;\r
-  bool MatchFullLines = false;\r
-  bool IgnoreCase = false;\r
-  bool EnableVarScope = false;\r
-  bool AllowDeprecatedDagOverlap = false;\r
-  bool Verbose = false;\r
-  bool VerboseVerbose = false;\r
-};\r
-\r
-//===----------------------------------------------------------------------===//\r
-// Summary of a FileCheck diagnostic.\r
-//===----------------------------------------------------------------------===//\r
-\r
-namespace Check {\r
-\r
-enum FileCheckKind {\r
-  CheckNone = 0,\r
-  CheckPlain,\r
-  CheckNext,\r
-  CheckSame,\r
-  CheckNot,\r
-  CheckDAG,\r
-  CheckLabel,\r
-  CheckEmpty,\r
-\r
-  /// Indicates the pattern only matches the end of file. This is used for\r
-  /// trailing CHECK-NOTs.\r
-  CheckEOF,\r
-\r
-  /// Marks when parsing found a -NOT check combined with another CHECK suffix.\r
-  CheckBadNot,\r
-\r
-  /// Marks when parsing found a -COUNT directive with invalid count value.\r
-  CheckBadCount\r
-};\r
-\r
-class FileCheckType {\r
-  FileCheckKind Kind;\r
-  int Count; ///< optional Count for some checks\r
-\r
-public:\r
-  FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {}\r
-  FileCheckType(const FileCheckType &) = default;\r
-\r
-  operator FileCheckKind() const { return Kind; }\r
-\r
-  int getCount() const { return Count; }\r
-  FileCheckType &setCount(int C);\r
-\r
-  // \returns a description of \p Prefix.\r
-  std::string getDescription(StringRef Prefix) const;\r
-};\r
-} // namespace Check\r
-\r
-struct FileCheckDiag {\r
-  /// What is the FileCheck directive for this diagnostic?\r
-  Check::FileCheckType CheckTy;\r
-  /// Where is the FileCheck directive for this diagnostic?\r
-  unsigned CheckLine, CheckCol;\r
-  /// What type of match result does this diagnostic describe?\r
-  ///\r
-  /// A directive's supplied pattern is said to be either expected or excluded\r
-  /// depending on whether the pattern must have or must not have a match in\r
-  /// order for the directive to succeed.  For example, a CHECK directive's\r
-  /// pattern is expected, and a CHECK-NOT directive's pattern is excluded.\r
-  /// All match result types whose names end with "Excluded" are for excluded\r
-  /// patterns, and all others are for expected patterns.\r
-  ///\r
-  /// There might be more than one match result for a single pattern.  For\r
-  /// example, there might be several discarded matches\r
-  /// (MatchFoundButDiscarded) before either a good match\r
-  /// (MatchFoundAndExpected) or a failure to match (MatchNoneButExpected),\r
-  /// and there might be a fuzzy match (MatchFuzzy) after the latter.\r
-  enum MatchType {\r
-    /// Indicates a good match for an expected pattern.\r
-    MatchFoundAndExpected,\r
-    /// Indicates a match for an excluded pattern.\r
-    MatchFoundButExcluded,\r
-    /// Indicates a match for an expected pattern, but the match is on the\r
-    /// wrong line.\r
-    MatchFoundButWrongLine,\r
-    /// Indicates a discarded match for an expected pattern.\r
-    MatchFoundButDiscarded,\r
-    /// Indicates no match for an excluded pattern.\r
-    MatchNoneAndExcluded,\r
-    /// Indicates no match for an expected pattern, but this might follow good\r
-    /// matches when multiple matches are expected for the pattern, or it might\r
-    /// follow discarded matches for the pattern.\r
-    MatchNoneButExpected,\r
-    /// Indicates a fuzzy match that serves as a suggestion for the next\r
-    /// intended match for an expected pattern with too few or no good matches.\r
-    MatchFuzzy,\r
-  } MatchTy;\r
-  /// The search range if MatchTy is MatchNoneAndExcluded or\r
-  /// MatchNoneButExpected, or the match range otherwise.\r
-  unsigned InputStartLine;\r
-  unsigned InputStartCol;\r
-  unsigned InputEndLine;\r
-  unsigned InputEndCol;\r
-  FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,\r
-                SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange);\r
-};\r
-\r
-class FileCheckPatternContext;\r
-struct FileCheckString;\r
-\r
-/// FileCheck class takes the request and exposes various methods that\r
-/// use information from the request.\r
-class FileCheck {\r
-  FileCheckRequest Req;\r
-  std::unique_ptr<FileCheckPatternContext> PatternContext;\r
-  // C++17 TODO: make this a plain std::vector.\r
-  std::unique_ptr<std::vector<FileCheckString>> CheckStrings;\r
-\r
-public:\r
-  explicit FileCheck(FileCheckRequest Req);\r
-  ~FileCheck();\r
-\r
-  // Combines the check prefixes into a single regex so that we can efficiently\r
-  // scan for any of the set.\r
-  //\r
-  // The semantics are that the longest-match wins which matches our regex\r
-  // library.\r
-  Regex buildCheckPrefixRegex();\r
-\r
-  /// Reads the check file from \p Buffer and records the expected strings it\r
-  /// contains. Errors are reported against \p SM.\r
-  ///\r
-  /// Only expected strings whose prefix is one of those listed in \p PrefixRE\r
-  /// are recorded. \returns true in case of an error, false otherwise.\r
-  bool readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE);\r
-\r
-  bool ValidateCheckPrefixes();\r
-\r
-  /// Canonicalizes whitespaces in the file. Line endings are replaced with\r
-  /// UNIX-style '\n'.\r
-  StringRef CanonicalizeFile(MemoryBuffer &MB,\r
-                             SmallVectorImpl<char> &OutputBuffer);\r
-\r
-  /// Checks the input to FileCheck provided in the \p Buffer against the\r
-  /// expected strings read from the check file and record diagnostics emitted\r
-  /// in \p Diags. Errors are recorded against \p SM.\r
-  ///\r
-  /// \returns false if the input fails to satisfy the checks.\r
-  bool checkInput(SourceMgr &SM, StringRef Buffer,\r
-                  std::vector<FileCheckDiag> *Diags = nullptr);\r
-};\r
-\r
-} // namespace llvm\r
-\r
-#endif\r
+//==-- 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
index fb4bbba033b544c19f143c702aff9a6d359487ed..c3f537b35243ec303165e5c9827f65215020d153 100644 (file)
-//===- FileCheck.cpp - Check that File's Contents match what is expected --===//\r
-//\r
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.\r
-// See https://llvm.org/LICENSE.txt for license information.\r
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\r
-//\r
-//===----------------------------------------------------------------------===//\r
-//\r
-// FileCheck does a line-by line check of a file that validates whether it\r
-// contains the expected content.  This is useful for regression tests etc.\r
-//\r
-// This file implements most of the API that will be used by the FileCheck utility\r
-// as well as various unittests.\r
-//===----------------------------------------------------------------------===//\r
-\r
-#include "llvm/Support/FileCheck.h"\r
-#include "FileCheckImpl.h"\r
-#include "llvm/ADT/StringSet.h"\r
-#include "llvm/ADT/Twine.h"\r
-#include "llvm/Support/FormatVariadic.h"\r
-#include <cstdint>\r
-#include <list>\r
-#include <tuple>\r
-#include <utility>\r
-\r
-using namespace llvm;\r
-\r
-Expected<uint64_t> FileCheckNumericVariableUse::eval() const {\r
-  Optional<uint64_t> Value = NumericVariable->getValue();\r
-  if (Value)\r
-    return *Value;\r
-\r
-  return make_error<FileCheckUndefVarError>(Name);\r
-}\r
-\r
-Expected<uint64_t> FileCheckASTBinop::eval() const {\r
-  Expected<uint64_t> LeftOp = LeftOperand->eval();\r
-  Expected<uint64_t> RightOp = RightOperand->eval();\r
-\r
-  // Bubble up any error (e.g. undefined variables) in the recursive\r
-  // evaluation.\r
-  if (!LeftOp || !RightOp) {\r
-    Error Err = Error::success();\r
-    if (!LeftOp)\r
-      Err = joinErrors(std::move(Err), LeftOp.takeError());\r
-    if (!RightOp)\r
-      Err = joinErrors(std::move(Err), RightOp.takeError());\r
-    return std::move(Err);\r
-  }\r
-\r
-  return EvalBinop(*LeftOp, *RightOp);\r
-}\r
-\r
-Expected<std::string> FileCheckNumericSubstitution::getResult() const {\r
-  Expected<uint64_t> EvaluatedValue = ExpressionAST->eval();\r
-  if (!EvaluatedValue)\r
-    return EvaluatedValue.takeError();\r
-  return utostr(*EvaluatedValue);\r
-}\r
-\r
-Expected<std::string> FileCheckStringSubstitution::getResult() const {\r
-  // Look up the value and escape it so that we can put it into the regex.\r
-  Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr);\r
-  if (!VarVal)\r
-    return VarVal.takeError();\r
-  return Regex::escape(*VarVal);\r
-}\r
-\r
-bool FileCheckPattern::isValidVarNameStart(char C) {\r
-  return C == '_' || isalpha(C);\r
-}\r
-\r
-Expected<FileCheckPattern::VariableProperties>\r
-FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) {\r
-  if (Str.empty())\r
-    return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name");\r
-\r
-  bool ParsedOneChar = false;\r
-  unsigned I = 0;\r
-  bool IsPseudo = Str[0] == '@';\r
-\r
-  // Global vars start with '$'.\r
-  if (Str[0] == '$' || IsPseudo)\r
-    ++I;\r
-\r
-  for (unsigned E = Str.size(); I != E; ++I) {\r
-    if (!ParsedOneChar && !isValidVarNameStart(Str[I]))\r
-      return FileCheckErrorDiagnostic::get(SM, Str, "invalid variable name");\r
-\r
-    // Variable names are composed of alphanumeric characters and underscores.\r
-    if (Str[I] != '_' && !isalnum(Str[I]))\r
-      break;\r
-    ParsedOneChar = true;\r
-  }\r
-\r
-  StringRef Name = Str.take_front(I);\r
-  Str = Str.substr(I);\r
-  return VariableProperties {Name, IsPseudo};\r
-}\r
-\r
-// StringRef holding all characters considered as horizontal whitespaces by\r
-// FileCheck input canonicalization.\r
-constexpr StringLiteral SpaceChars = " \t";\r
-\r
-// Parsing helper function that strips the first character in S and returns it.\r
-static char popFront(StringRef &S) {\r
-  char C = S.front();\r
-  S = S.drop_front();\r
-  return C;\r
-}\r
-\r
-char FileCheckUndefVarError::ID = 0;\r
-char FileCheckErrorDiagnostic::ID = 0;\r
-char FileCheckNotFoundError::ID = 0;\r
-\r
-Expected<FileCheckNumericVariable *>\r
-FileCheckPattern::parseNumericVariableDefinition(\r
-    StringRef &Expr, FileCheckPatternContext *Context,\r
-    Optional<size_t> LineNumber, const SourceMgr &SM) {\r
-  Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);\r
-  if (!ParseVarResult)\r
-    return ParseVarResult.takeError();\r
-  StringRef Name = ParseVarResult->Name;\r
-\r
-  if (ParseVarResult->IsPseudo)\r
-    return FileCheckErrorDiagnostic::get(\r
-        SM, Name, "definition of pseudo numeric variable unsupported");\r
-\r
-  // Detect collisions between string and numeric variables when the latter\r
-  // is created later than the former.\r
-  if (Context->DefinedVariableTable.find(Name) !=\r
-      Context->DefinedVariableTable.end())\r
-    return FileCheckErrorDiagnostic::get(\r
-        SM, Name, "string variable with name '" + Name + "' already exists");\r
-\r
-  Expr = Expr.ltrim(SpaceChars);\r
-  if (!Expr.empty())\r
-    return FileCheckErrorDiagnostic::get(\r
-        SM, Expr, "unexpected characters after numeric variable name");\r
-\r
-  FileCheckNumericVariable *DefinedNumericVariable;\r
-  auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);\r
-  if (VarTableIter != Context->GlobalNumericVariableTable.end())\r
-    DefinedNumericVariable = VarTableIter->second;\r
-  else\r
-    DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber);\r
-\r
-  return DefinedNumericVariable;\r
-}\r
-\r
-Expected<std::unique_ptr<FileCheckNumericVariableUse>>\r
-FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,\r
-                                          Optional<size_t> LineNumber,\r
-                                          FileCheckPatternContext *Context,\r
-                                          const SourceMgr &SM) {\r
-  if (IsPseudo && !Name.equals("@LINE"))\r
-    return FileCheckErrorDiagnostic::get(\r
-        SM, Name, "invalid pseudo numeric variable '" + Name + "'");\r
-\r
-  // Numeric variable definitions and uses are parsed in the order in which\r
-  // they appear in the CHECK patterns. For each definition, the pointer to the\r
-  // class instance of the corresponding numeric variable definition is stored\r
-  // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer\r
-  // we get below is null, it means no such variable was defined before. When\r
-  // that happens, we create a dummy variable so that parsing can continue. All\r
-  // uses of undefined variables, whether string or numeric, are then diagnosed\r
-  // in printSubstitutions() after failing to match.\r
-  auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);\r
-  FileCheckNumericVariable *NumericVariable;\r
-  if (VarTableIter != Context->GlobalNumericVariableTable.end())\r
-    NumericVariable = VarTableIter->second;\r
-  else {\r
-    NumericVariable = Context->makeNumericVariable(Name);\r
-    Context->GlobalNumericVariableTable[Name] = NumericVariable;\r
-  }\r
-\r
-  Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber();\r
-  if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)\r
-    return FileCheckErrorDiagnostic::get(\r
-        SM, Name,\r
-        "numeric variable '" + Name +\r
-            "' defined earlier in the same CHECK directive");\r
-\r
-  return std::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);\r
-}\r
-\r
-Expected<std::unique_ptr<FileCheckExpressionAST>>\r
-FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,\r
-                                      Optional<size_t> LineNumber,\r
-                                      FileCheckPatternContext *Context,\r
-                                      const SourceMgr &SM) {\r
-  if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {\r
-    // Try to parse as a numeric variable use.\r
-    Expected<FileCheckPattern::VariableProperties> ParseVarResult =\r
-        parseVariable(Expr, SM);\r
-    if (ParseVarResult)\r
-      return parseNumericVariableUse(ParseVarResult->Name,\r
-                                     ParseVarResult->IsPseudo, LineNumber,\r
-                                     Context, SM);\r
-    if (AO == AllowedOperand::LineVar)\r
-      return ParseVarResult.takeError();\r
-    // Ignore the error and retry parsing as a literal.\r
-    consumeError(ParseVarResult.takeError());\r
-  }\r
-\r
-  // Otherwise, parse it as a literal.\r
-  uint64_t LiteralValue;\r
-  if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))\r
-    return std::make_unique<FileCheckExpressionLiteral>(LiteralValue);\r
-\r
-  return FileCheckErrorDiagnostic::get(SM, Expr,\r
-                                       "invalid operand format '" + Expr + "'");\r
-}\r
-\r
-static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {\r
-  return LeftOp + RightOp;\r
-}\r
-\r
-static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {\r
-  return LeftOp - RightOp;\r
-}\r
-\r
-Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop(\r
-    StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,\r
-    bool IsLegacyLineExpr, Optional<size_t> LineNumber,\r
-    FileCheckPatternContext *Context, const SourceMgr &SM) {\r
-  Expr = Expr.ltrim(SpaceChars);\r
-  if (Expr.empty())\r
-    return std::move(LeftOp);\r
-\r
-  // Check if this is a supported operation and select a function to perform\r
-  // it.\r
-  SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());\r
-  char Operator = popFront(Expr);\r
-  binop_eval_t EvalBinop;\r
-  switch (Operator) {\r
-  case '+':\r
-    EvalBinop = add;\r
-    break;\r
-  case '-':\r
-    EvalBinop = sub;\r
-    break;\r
-  default:\r
-    return FileCheckErrorDiagnostic::get(\r
-        SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'");\r
-  }\r
-\r
-  // Parse right operand.\r
-  Expr = Expr.ltrim(SpaceChars);\r
-  if (Expr.empty())\r
-    return FileCheckErrorDiagnostic::get(SM, Expr,\r
-                                         "missing operand in expression");\r
-  // The second operand in a legacy @LINE expression is always a literal.\r
-  AllowedOperand AO =\r
-      IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;\r
-  Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =\r
-      parseNumericOperand(Expr, AO, LineNumber, Context, SM);\r
-  if (!RightOpResult)\r
-    return RightOpResult;\r
-\r
-  Expr = Expr.ltrim(SpaceChars);\r
-  return std::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp),\r
-                                              std::move(*RightOpResult));\r
-}\r
-\r
-Expected<std::unique_ptr<FileCheckExpressionAST>>\r
-FileCheckPattern::parseNumericSubstitutionBlock(\r
-    StringRef Expr,\r
-    Optional<FileCheckNumericVariable *> &DefinedNumericVariable,\r
-    bool IsLegacyLineExpr, Optional<size_t> LineNumber,\r
-    FileCheckPatternContext *Context, const SourceMgr &SM) {\r
-  std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr;\r
-  StringRef DefExpr = StringRef();\r
-  DefinedNumericVariable = None;\r
-  // Save variable definition expression if any.\r
-  size_t DefEnd = Expr.find(':');\r
-  if (DefEnd != StringRef::npos) {\r
-    DefExpr = Expr.substr(0, DefEnd);\r
-    Expr = Expr.substr(DefEnd + 1);\r
-  }\r
-\r
-  // Parse the expression itself.\r
-  Expr = Expr.ltrim(SpaceChars);\r
-  if (!Expr.empty()) {\r
-    // The first operand in a legacy @LINE expression is always the @LINE\r
-    // pseudo variable.\r
-    AllowedOperand AO =\r
-        IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;\r
-    Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =\r
-        parseNumericOperand(Expr, AO, LineNumber, Context, SM);\r
-    while (ParseResult && !Expr.empty()) {\r
-      ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr,\r
-                               LineNumber, Context, SM);\r
-      // Legacy @LINE expressions only allow 2 operands.\r
-      if (ParseResult && IsLegacyLineExpr && !Expr.empty())\r
-        return FileCheckErrorDiagnostic::get(\r
-            SM, Expr,\r
-            "unexpected characters at end of expression '" + Expr + "'");\r
-    }\r
-    if (!ParseResult)\r
-      return ParseResult;\r
-    ExpressionAST = std::move(*ParseResult);\r
-  }\r
-\r
-  // Parse the numeric variable definition.\r
-  if (DefEnd != StringRef::npos) {\r
-    DefExpr = DefExpr.ltrim(SpaceChars);\r
-    Expected<FileCheckNumericVariable *> ParseResult =\r
-        parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);\r
-\r
-    if (!ParseResult)\r
-      return ParseResult.takeError();\r
-    DefinedNumericVariable = *ParseResult;\r
-  }\r
-\r
-  return std::move(ExpressionAST);\r
-}\r
-\r
-bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,\r
-                                    SourceMgr &SM,\r
-                                    const FileCheckRequest &Req) {\r
-  bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;\r
-  IgnoreCase = Req.IgnoreCase;\r
-\r
-  PatternLoc = SMLoc::getFromPointer(PatternStr.data());\r
-\r
-  if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))\r
-    // Ignore trailing whitespace.\r
-    while (!PatternStr.empty() &&\r
-           (PatternStr.back() == ' ' || PatternStr.back() == '\t'))\r
-      PatternStr = PatternStr.substr(0, PatternStr.size() - 1);\r
-\r
-  // Check that there is something on the line.\r
-  if (PatternStr.empty() && CheckTy != Check::CheckEmpty) {\r
-    SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,\r
-                    "found empty check string with prefix '" + Prefix + ":'");\r
-    return true;\r
-  }\r
-\r
-  if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) {\r
-    SM.PrintMessage(\r
-        PatternLoc, SourceMgr::DK_Error,\r
-        "found non-empty check string for empty check with prefix '" + Prefix +\r
-            ":'");\r
-    return true;\r
-  }\r
-\r
-  if (CheckTy == Check::CheckEmpty) {\r
-    RegExStr = "(\n$)";\r
-    return false;\r
-  }\r
-\r
-  // Check to see if this is a fixed string, or if it has regex pieces.\r
-  if (!MatchFullLinesHere &&\r
-      (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&\r
-                                 PatternStr.find("[[") == StringRef::npos))) {\r
-    FixedStr = PatternStr;\r
-    return false;\r
-  }\r
-\r
-  if (MatchFullLinesHere) {\r
-    RegExStr += '^';\r
-    if (!Req.NoCanonicalizeWhiteSpace)\r
-      RegExStr += " *";\r
-  }\r
-\r
-  // Paren value #0 is for the fully matched string.  Any new parenthesized\r
-  // values add from there.\r
-  unsigned CurParen = 1;\r
-\r
-  // Otherwise, there is at least one regex piece.  Build up the regex pattern\r
-  // by escaping scary characters in fixed strings, building up one big regex.\r
-  while (!PatternStr.empty()) {\r
-    // RegEx matches.\r
-    if (PatternStr.startswith("{{")) {\r
-      // This is the start of a regex match.  Scan for the }}.\r
-      size_t End = PatternStr.find("}}");\r
-      if (End == StringRef::npos) {\r
-        SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),\r
-                        SourceMgr::DK_Error,\r
-                        "found start of regex string with no end '}}'");\r
-        return true;\r
-      }\r
-\r
-      // Enclose {{}} patterns in parens just like [[]] even though we're not\r
-      // capturing the result for any purpose.  This is required in case the\r
-      // expression contains an alternation like: CHECK:  abc{{x|z}}def.  We\r
-      // want this to turn into: "abc(x|z)def" not "abcx|zdef".\r
-      RegExStr += '(';\r
-      ++CurParen;\r
-\r
-      if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM))\r
-        return true;\r
-      RegExStr += ')';\r
-\r
-      PatternStr = PatternStr.substr(End + 2);\r
-      continue;\r
-    }\r
-\r
-    // String and numeric substitution blocks. Pattern substitution blocks come\r
-    // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some\r
-    // other regex) and assigns it to the string variable 'foo'. The latter\r
-    // substitutes foo's value. Numeric substitution blocks recognize the same\r
-    // form as string ones, but start with a '#' sign after the double\r
-    // brackets. They also accept a combined form which sets a numeric variable\r
-    // to the evaluation of an expression. Both string and numeric variable\r
-    // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be\r
-    // valid, as this helps catch some common errors.\r
-    if (PatternStr.startswith("[[")) {\r
-      StringRef UnparsedPatternStr = PatternStr.substr(2);\r
-      // Find the closing bracket pair ending the match.  End is going to be an\r
-      // offset relative to the beginning of the match string.\r
-      size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);\r
-      StringRef MatchStr = UnparsedPatternStr.substr(0, End);\r
-      bool IsNumBlock = MatchStr.consume_front("#");\r
-\r
-      if (End == StringRef::npos) {\r
-        SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),\r
-                        SourceMgr::DK_Error,\r
-                        "Invalid substitution block, no ]] found");\r
-        return true;\r
-      }\r
-      // Strip the substitution block we are parsing. End points to the start\r
-      // of the "]]" closing the expression so account for it in computing the\r
-      // index of the first unparsed character.\r
-      PatternStr = UnparsedPatternStr.substr(End + 2);\r
-\r
-      bool IsDefinition = false;\r
-      bool SubstNeeded = false;\r
-      // Whether the substitution block is a legacy use of @LINE with string\r
-      // substitution block syntax.\r
-      bool IsLegacyLineExpr = false;\r
-      StringRef DefName;\r
-      StringRef SubstStr;\r
-      StringRef MatchRegexp;\r
-      size_t SubstInsertIdx = RegExStr.size();\r
-\r
-      // Parse string variable or legacy @LINE expression.\r
-      if (!IsNumBlock) {\r
-        size_t VarEndIdx = MatchStr.find(":");\r
-        size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");\r
-        if (SpacePos != StringRef::npos) {\r
-          SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos),\r
-                          SourceMgr::DK_Error, "unexpected whitespace");\r
-          return true;\r
-        }\r
-\r
-        // Get the name (e.g. "foo") and verify it is well formed.\r
-        StringRef OrigMatchStr = MatchStr;\r
-        Expected<FileCheckPattern::VariableProperties> ParseVarResult =\r
-            parseVariable(MatchStr, SM);\r
-        if (!ParseVarResult) {\r
-          logAllUnhandledErrors(ParseVarResult.takeError(), errs());\r
-          return true;\r
-        }\r
-        StringRef Name = ParseVarResult->Name;\r
-        bool IsPseudo = ParseVarResult->IsPseudo;\r
-\r
-        IsDefinition = (VarEndIdx != StringRef::npos);\r
-        SubstNeeded = !IsDefinition;\r
-        if (IsDefinition) {\r
-          if ((IsPseudo || !MatchStr.consume_front(":"))) {\r
-            SM.PrintMessage(SMLoc::getFromPointer(Name.data()),\r
-                            SourceMgr::DK_Error,\r
-                            "invalid name in string variable definition");\r
-            return true;\r
-          }\r
-\r
-          // Detect collisions between string and numeric variables when the\r
-          // former is created later than the latter.\r
-          if (Context->GlobalNumericVariableTable.find(Name) !=\r
-              Context->GlobalNumericVariableTable.end()) {\r
-            SM.PrintMessage(\r
-                SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,\r
-                "numeric variable with name '" + Name + "' already exists");\r
-            return true;\r
-          }\r
-          DefName = Name;\r
-          MatchRegexp = MatchStr;\r
-        } else {\r
-          if (IsPseudo) {\r
-            MatchStr = OrigMatchStr;\r
-            IsLegacyLineExpr = IsNumBlock = true;\r
-          } else\r
-            SubstStr = Name;\r
-        }\r
-      }\r
-\r
-      // Parse numeric substitution block.\r
-      std::unique_ptr<FileCheckExpressionAST> ExpressionAST;\r
-      Optional<FileCheckNumericVariable *> DefinedNumericVariable;\r
-      if (IsNumBlock) {\r
-        Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =\r
-            parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,\r
-                                          IsLegacyLineExpr, LineNumber, Context,\r
-                                          SM);\r
-        if (!ParseResult) {\r
-          logAllUnhandledErrors(ParseResult.takeError(), errs());\r
-          return true;\r
-        }\r
-        ExpressionAST = std::move(*ParseResult);\r
-        SubstNeeded = ExpressionAST != nullptr;\r
-        if (DefinedNumericVariable) {\r
-          IsDefinition = true;\r
-          DefName = (*DefinedNumericVariable)->getName();\r
-        }\r
-        if (SubstNeeded)\r
-          SubstStr = MatchStr;\r
-        else\r
-          MatchRegexp = "[0-9]+";\r
-      }\r
-\r
-      // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].\r
-      if (IsDefinition) {\r
-        RegExStr += '(';\r
-        ++SubstInsertIdx;\r
-\r
-        if (IsNumBlock) {\r
-          FileCheckNumericVariableMatch NumericVariableDefinition = {\r
-              *DefinedNumericVariable, CurParen};\r
-          NumericVariableDefs[DefName] = NumericVariableDefinition;\r
-          // This store is done here rather than in match() to allow\r
-          // parseNumericVariableUse() to get the pointer to the class instance\r
-          // of the right variable definition corresponding to a given numeric\r
-          // variable use.\r
-          Context->GlobalNumericVariableTable[DefName] =\r
-              *DefinedNumericVariable;\r
-        } else {\r
-          VariableDefs[DefName] = CurParen;\r
-          // Mark string variable as defined to detect collisions between\r
-          // string and numeric variables in parseNumericVariableUse() and\r
-          // defineCmdlineVariables() when the latter is created later than the\r
-          // former. We cannot reuse GlobalVariableTable for this by populating\r
-          // it with an empty string since we would then lose the ability to\r
-          // detect the use of an undefined variable in match().\r
-          Context->DefinedVariableTable[DefName] = true;\r
-        }\r
-\r
-        ++CurParen;\r
-      }\r
-\r
-      if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))\r
-        return true;\r
-\r
-      if (IsDefinition)\r
-        RegExStr += ')';\r
-\r
-      // Handle substitutions: [[foo]] and [[#<foo expr>]].\r
-      if (SubstNeeded) {\r
-        // Handle substitution of string variables that were defined earlier on\r
-        // the same line by emitting a backreference. Expressions do not\r
-        // support substituting a numeric variable defined on the same line.\r
-        if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) {\r
-          unsigned CaptureParenGroup = VariableDefs[SubstStr];\r
-          if (CaptureParenGroup < 1 || CaptureParenGroup > 9) {\r
-            SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()),\r
-                            SourceMgr::DK_Error,\r
-                            "Can't back-reference more than 9 variables");\r
-            return true;\r
-          }\r
-          AddBackrefToRegEx(CaptureParenGroup);\r
-        } else {\r
-          // Handle substitution of string variables ([[<var>]]) defined in\r
-          // previous CHECK patterns, and substitution of expressions.\r
-          FileCheckSubstitution *Substitution =\r
-              IsNumBlock\r
-                  ? Context->makeNumericSubstitution(\r
-                        SubstStr, std::move(ExpressionAST), SubstInsertIdx)\r
-                  : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);\r
-          Substitutions.push_back(Substitution);\r
-        }\r
-      }\r
-    }\r
-\r
-    // Handle fixed string matches.\r
-    // Find the end, which is the start of the next regex.\r
-    size_t FixedMatchEnd = PatternStr.find("{{");\r
-    FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));\r
-    RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd));\r
-    PatternStr = PatternStr.substr(FixedMatchEnd);\r
-  }\r
-\r
-  if (MatchFullLinesHere) {\r
-    if (!Req.NoCanonicalizeWhiteSpace)\r
-      RegExStr += " *";\r
-    RegExStr += '$';\r
-  }\r
-\r
-  return false;\r
-}\r
-\r
-bool FileCheckPattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) {\r
-  Regex R(RS);\r
-  std::string Error;\r
-  if (!R.isValid(Error)) {\r
-    SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error,\r
-                    "invalid regex: " + Error);\r
-    return true;\r
-  }\r
-\r
-  RegExStr += RS.str();\r
-  CurParen += R.getNumMatches();\r
-  return false;\r
-}\r
-\r
-void FileCheckPattern::AddBackrefToRegEx(unsigned BackrefNum) {\r
-  assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number");\r
-  std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum);\r
-  RegExStr += Backref;\r
-}\r
-\r
-Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,\r
-                                         const SourceMgr &SM) const {\r
-  // If this is the EOF pattern, match it immediately.\r
-  if (CheckTy == Check::CheckEOF) {\r
-    MatchLen = 0;\r
-    return Buffer.size();\r
-  }\r
-\r
-  // If this is a fixed string pattern, just match it now.\r
-  if (!FixedStr.empty()) {\r
-    MatchLen = FixedStr.size();\r
-    size_t Pos = IgnoreCase ? Buffer.find_lower(FixedStr)\r
-                            : Buffer.find(FixedStr);\r
-    if (Pos == StringRef::npos)\r
-      return make_error<FileCheckNotFoundError>();\r
-    return Pos;\r
-  }\r
-\r
-  // Regex match.\r
-\r
-  // If there are substitutions, we need to create a temporary string with the\r
-  // actual value.\r
-  StringRef RegExToMatch = RegExStr;\r
-  std::string TmpStr;\r
-  if (!Substitutions.empty()) {\r
-    TmpStr = RegExStr;\r
-    if (LineNumber)\r
-      Context->LineVariable->setValue(*LineNumber);\r
-\r
-    size_t InsertOffset = 0;\r
-    // Substitute all string variables and expressions whose values are only\r
-    // now known. Use of string variables defined on the same line are handled\r
-    // by back-references.\r
-    for (const auto &Substitution : Substitutions) {\r
-      // Substitute and check for failure (e.g. use of undefined variable).\r
-      Expected<std::string> Value = Substitution->getResult();\r
-      if (!Value)\r
-        return Value.takeError();\r
-\r
-      // Plop it into the regex at the adjusted offset.\r
-      TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,\r
-                    Value->begin(), Value->end());\r
-      InsertOffset += Value->size();\r
-    }\r
-\r
-    // Match the newly constructed regex.\r
-    RegExToMatch = TmpStr;\r
-  }\r
-\r
-  SmallVector<StringRef, 4> MatchInfo;\r
-  unsigned int Flags = Regex::Newline;\r
-  if (IgnoreCase)\r
-    Flags |= Regex::IgnoreCase;\r
-  if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo))\r
-    return make_error<FileCheckNotFoundError>();\r
-\r
-  // Successful regex match.\r
-  assert(!MatchInfo.empty() && "Didn't get any match");\r
-  StringRef FullMatch = MatchInfo[0];\r
-\r
-  // If this defines any string variables, remember their values.\r
-  for (const auto &VariableDef : VariableDefs) {\r
-    assert(VariableDef.second < MatchInfo.size() && "Internal paren error");\r
-    Context->GlobalVariableTable[VariableDef.first] =\r
-        MatchInfo[VariableDef.second];\r
-  }\r
-\r
-  // If this defines any numeric variables, remember their values.\r
-  for (const auto &NumericVariableDef : NumericVariableDefs) {\r
-    const FileCheckNumericVariableMatch &NumericVariableMatch =\r
-        NumericVariableDef.getValue();\r
-    unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup;\r
-    assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error");\r
-    FileCheckNumericVariable *DefinedNumericVariable =\r
-        NumericVariableMatch.DefinedNumericVariable;\r
-\r
-    StringRef MatchedValue = MatchInfo[CaptureParenGroup];\r
-    uint64_t Val;\r
-    if (MatchedValue.getAsInteger(10, Val))\r
-      return FileCheckErrorDiagnostic::get(SM, MatchedValue,\r
-                                           "Unable to represent numeric value");\r
-    DefinedNumericVariable->setValue(Val);\r
-  }\r
-\r
-  // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after\r
-  // the required preceding newline, which is consumed by the pattern in the\r
-  // case of CHECK-EMPTY but not CHECK-NEXT.\r
-  size_t MatchStartSkip = CheckTy == Check::CheckEmpty;\r
-  MatchLen = FullMatch.size() - MatchStartSkip;\r
-  return FullMatch.data() - Buffer.data() + MatchStartSkip;\r
-}\r
-\r
-unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const {\r
-  // Just compute the number of matching characters. For regular expressions, we\r
-  // just compare against the regex itself and hope for the best.\r
-  //\r
-  // FIXME: One easy improvement here is have the regex lib generate a single\r
-  // example regular expression which matches, and use that as the example\r
-  // string.\r
-  StringRef ExampleString(FixedStr);\r
-  if (ExampleString.empty())\r
-    ExampleString = RegExStr;\r
-\r
-  // Only compare up to the first line in the buffer, or the string size.\r
-  StringRef BufferPrefix = Buffer.substr(0, ExampleString.size());\r
-  BufferPrefix = BufferPrefix.split('\n').first;\r
-  return BufferPrefix.edit_distance(ExampleString);\r
-}\r
-\r
-void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,\r
-                                          SMRange MatchRange) const {\r
-  // Print what we know about substitutions.\r
-  if (!Substitutions.empty()) {\r
-    for (const auto &Substitution : Substitutions) {\r
-      SmallString<256> Msg;\r
-      raw_svector_ostream OS(Msg);\r
-      Expected<std::string> MatchedValue = Substitution->getResult();\r
-\r
-      // Substitution failed or is not known at match time, print the undefined\r
-      // variables it uses.\r
-      if (!MatchedValue) {\r
-        bool UndefSeen = false;\r
-        handleAllErrors(MatchedValue.takeError(),\r
-                        [](const FileCheckNotFoundError &E) {},\r
-                        // Handled in PrintNoMatch().\r
-                        [](const FileCheckErrorDiagnostic &E) {},\r
-                        [&](const FileCheckUndefVarError &E) {\r
-                          if (!UndefSeen) {\r
-                            OS << "uses undefined variable(s):";\r
-                            UndefSeen = true;\r
-                          }\r
-                          OS << " ";\r
-                          E.log(OS);\r
-                        });\r
-      } else {\r
-        // Substitution succeeded. Print substituted value.\r
-        OS << "with \"";\r
-        OS.write_escaped(Substitution->getFromString()) << "\" equal to \"";\r
-        OS.write_escaped(*MatchedValue) << "\"";\r
-      }\r
-\r
-      if (MatchRange.isValid())\r
-        SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(),\r
-                        {MatchRange});\r
-      else\r
-        SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),\r
-                        SourceMgr::DK_Note, OS.str());\r
-    }\r
-  }\r
-}\r
-\r
-static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,\r
-                                  const SourceMgr &SM, SMLoc Loc,\r
-                                  Check::FileCheckType CheckTy,\r
-                                  StringRef Buffer, size_t Pos, size_t Len,\r
-                                  std::vector<FileCheckDiag> *Diags,\r
-                                  bool AdjustPrevDiag = false) {\r
-  SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);\r
-  SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);\r
-  SMRange Range(Start, End);\r
-  if (Diags) {\r
-    if (AdjustPrevDiag)\r
-      Diags->rbegin()->MatchTy = MatchTy;\r
-    else\r
-      Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);\r
-  }\r
-  return Range;\r
-}\r
-\r
-void FileCheckPattern::printFuzzyMatch(\r
-    const SourceMgr &SM, StringRef Buffer,\r
-    std::vector<FileCheckDiag> *Diags) const {\r
-  // Attempt to find the closest/best fuzzy match.  Usually an error happens\r
-  // because some string in the output didn't exactly match. In these cases, we\r
-  // would like to show the user a best guess at what "should have" matched, to\r
-  // save them having to actually check the input manually.\r
-  size_t NumLinesForward = 0;\r
-  size_t Best = StringRef::npos;\r
-  double BestQuality = 0;\r
-\r
-  // Use an arbitrary 4k limit on how far we will search.\r
-  for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) {\r
-    if (Buffer[i] == '\n')\r
-      ++NumLinesForward;\r
-\r
-    // Patterns have leading whitespace stripped, so skip whitespace when\r
-    // looking for something which looks like a pattern.\r
-    if (Buffer[i] == ' ' || Buffer[i] == '\t')\r
-      continue;\r
-\r
-    // Compute the "quality" of this match as an arbitrary combination of the\r
-    // match distance and the number of lines skipped to get to this match.\r
-    unsigned Distance = computeMatchDistance(Buffer.substr(i));\r
-    double Quality = Distance + (NumLinesForward / 100.);\r
-\r
-    if (Quality < BestQuality || Best == StringRef::npos) {\r
-      Best = i;\r
-      BestQuality = Quality;\r
-    }\r
-  }\r
-\r
-  // Print the "possible intended match here" line if we found something\r
-  // reasonable and not equal to what we showed in the "scanning from here"\r
-  // line.\r
-  if (Best && Best != StringRef::npos && BestQuality < 50) {\r
-    SMRange MatchRange =\r
-        ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(),\r
-                           getCheckTy(), Buffer, Best, 0, Diags);\r
-    SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note,\r
-                    "possible intended match here");\r
-\r
-    // FIXME: If we wanted to be really friendly we would show why the match\r
-    // failed, as it can be hard to spot simple one character differences.\r
-  }\r
-}\r
-\r
-Expected<StringRef>\r
-FileCheckPatternContext::getPatternVarValue(StringRef VarName) {\r
-  auto VarIter = GlobalVariableTable.find(VarName);\r
-  if (VarIter == GlobalVariableTable.end())\r
-    return make_error<FileCheckUndefVarError>(VarName);\r
-\r
-  return VarIter->second;\r
-}\r
-\r
-template <class... Types>\r
-FileCheckNumericVariable *\r
-FileCheckPatternContext::makeNumericVariable(Types... args) {\r
-  NumericVariables.push_back(\r
-      std::make_unique<FileCheckNumericVariable>(args...));\r
-  return NumericVariables.back().get();\r
-}\r
-\r
-FileCheckSubstitution *\r
-FileCheckPatternContext::makeStringSubstitution(StringRef VarName,\r
-                                                size_t InsertIdx) {\r
-  Substitutions.push_back(\r
-      std::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx));\r
-  return Substitutions.back().get();\r
-}\r
-\r
-FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(\r
-    StringRef ExpressionStr,\r
-    std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) {\r
-  Substitutions.push_back(std::make_unique<FileCheckNumericSubstitution>(\r
-      this, ExpressionStr, std::move(ExpressionAST), InsertIdx));\r
-  return Substitutions.back().get();\r
-}\r
-\r
-size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {\r
-  // Offset keeps track of the current offset within the input Str\r
-  size_t Offset = 0;\r
-  // [...] Nesting depth\r
-  size_t BracketDepth = 0;\r
-\r
-  while (!Str.empty()) {\r
-    if (Str.startswith("]]") && BracketDepth == 0)\r
-      return Offset;\r
-    if (Str[0] == '\\') {\r
-      // Backslash escapes the next char within regexes, so skip them both.\r
-      Str = Str.substr(2);\r
-      Offset += 2;\r
-    } else {\r
-      switch (Str[0]) {\r
-      default:\r
-        break;\r
-      case '[':\r
-        BracketDepth++;\r
-        break;\r
-      case ']':\r
-        if (BracketDepth == 0) {\r
-          SM.PrintMessage(SMLoc::getFromPointer(Str.data()),\r
-                          SourceMgr::DK_Error,\r
-                          "missing closing \"]\" for regex variable");\r
-          exit(1);\r
-        }\r
-        BracketDepth--;\r
-        break;\r
-      }\r
-      Str = Str.substr(1);\r
-      Offset++;\r
-    }\r
-  }\r
-\r
-  return StringRef::npos;\r
-}\r
-\r
-StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB,\r
-                                      SmallVectorImpl<char> &OutputBuffer) {\r
-  OutputBuffer.reserve(MB.getBufferSize());\r
-\r
-  for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd();\r
-       Ptr != End; ++Ptr) {\r
-    // Eliminate trailing dosish \r.\r
-    if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') {\r
-      continue;\r
-    }\r
-\r
-    // If current char is not a horizontal whitespace or if horizontal\r
-    // whitespace canonicalization is disabled, dump it to output as is.\r
-    if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) {\r
-      OutputBuffer.push_back(*Ptr);\r
-      continue;\r
-    }\r
-\r
-    // Otherwise, add one space and advance over neighboring space.\r
-    OutputBuffer.push_back(' ');\r
-    while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t'))\r
-      ++Ptr;\r
-  }\r
-\r
-  // Add a null byte and then return all but that byte.\r
-  OutputBuffer.push_back('\0');\r
-  return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1);\r
-}\r
-\r
-FileCheckDiag::FileCheckDiag(const SourceMgr &SM,\r
-                             const Check::FileCheckType &CheckTy,\r
-                             SMLoc CheckLoc, MatchType MatchTy,\r
-                             SMRange InputRange)\r
-    : CheckTy(CheckTy), MatchTy(MatchTy) {\r
-  auto Start = SM.getLineAndColumn(InputRange.Start);\r
-  auto End = SM.getLineAndColumn(InputRange.End);\r
-  InputStartLine = Start.first;\r
-  InputStartCol = Start.second;\r
-  InputEndLine = End.first;\r
-  InputEndCol = End.second;\r
-  Start = SM.getLineAndColumn(CheckLoc);\r
-  CheckLine = Start.first;\r
-  CheckCol = Start.second;\r
-}\r
-\r
-static bool IsPartOfWord(char c) {\r
-  return (isalnum(c) || c == '-' || c == '_');\r
-}\r
-\r
-Check::FileCheckType &Check::FileCheckType::setCount(int C) {\r
-  assert(Count > 0 && "zero and negative counts are not supported");\r
-  assert((C == 1 || Kind == CheckPlain) &&\r
-         "count supported only for plain CHECK directives");\r
-  Count = C;\r
-  return *this;\r
-}\r
-\r
-std::string Check::FileCheckType::getDescription(StringRef Prefix) const {\r
-  switch (Kind) {\r
-  case Check::CheckNone:\r
-    return "invalid";\r
-  case Check::CheckPlain:\r
-    if (Count > 1)\r
-      return Prefix.str() + "-COUNT";\r
-    return Prefix;\r
-  case Check::CheckNext:\r
-    return Prefix.str() + "-NEXT";\r
-  case Check::CheckSame:\r
-    return Prefix.str() + "-SAME";\r
-  case Check::CheckNot:\r
-    return Prefix.str() + "-NOT";\r
-  case Check::CheckDAG:\r
-    return Prefix.str() + "-DAG";\r
-  case Check::CheckLabel:\r
-    return Prefix.str() + "-LABEL";\r
-  case Check::CheckEmpty:\r
-    return Prefix.str() + "-EMPTY";\r
-  case Check::CheckEOF:\r
-    return "implicit EOF";\r
-  case Check::CheckBadNot:\r
-    return "bad NOT";\r
-  case Check::CheckBadCount:\r
-    return "bad COUNT";\r
-  }\r
-  llvm_unreachable("unknown FileCheckType");\r
-}\r
-\r
-static std::pair<Check::FileCheckType, StringRef>\r
-FindCheckType(StringRef Buffer, StringRef Prefix) {\r
-  if (Buffer.size() <= Prefix.size())\r
-    return {Check::CheckNone, StringRef()};\r
-\r
-  char NextChar = Buffer[Prefix.size()];\r
-\r
-  StringRef Rest = Buffer.drop_front(Prefix.size() + 1);\r
-  // Verify that the : is present after the prefix.\r
-  if (NextChar == ':')\r
-    return {Check::CheckPlain, Rest};\r
-\r
-  if (NextChar != '-')\r
-    return {Check::CheckNone, StringRef()};\r
-\r
-  if (Rest.consume_front("COUNT-")) {\r
-    int64_t Count;\r
-    if (Rest.consumeInteger(10, Count))\r
-      // Error happened in parsing integer.\r
-      return {Check::CheckBadCount, Rest};\r
-    if (Count <= 0 || Count > INT32_MAX)\r
-      return {Check::CheckBadCount, Rest};\r
-    if (!Rest.consume_front(":"))\r
-      return {Check::CheckBadCount, Rest};\r
-    return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest};\r
-  }\r
-\r
-  if (Rest.consume_front("NEXT:"))\r
-    return {Check::CheckNext, Rest};\r
-\r
-  if (Rest.consume_front("SAME:"))\r
-    return {Check::CheckSame, Rest};\r
-\r
-  if (Rest.consume_front("NOT:"))\r
-    return {Check::CheckNot, Rest};\r
-\r
-  if (Rest.consume_front("DAG:"))\r
-    return {Check::CheckDAG, Rest};\r
-\r
-  if (Rest.consume_front("LABEL:"))\r
-    return {Check::CheckLabel, Rest};\r
-\r
-  if (Rest.consume_front("EMPTY:"))\r
-    return {Check::CheckEmpty, Rest};\r
-\r
-  // You can't combine -NOT with another suffix.\r
-  if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||\r
-      Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||\r
-      Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||\r
-      Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))\r
-    return {Check::CheckBadNot, Rest};\r
-\r
-  return {Check::CheckNone, Rest};\r
-}\r
-\r
-// From the given position, find the next character after the word.\r
-static size_t SkipWord(StringRef Str, size_t Loc) {\r
-  while (Loc < Str.size() && IsPartOfWord(Str[Loc]))\r
-    ++Loc;\r
-  return Loc;\r
-}\r
-\r
-/// Searches the buffer for the first prefix in the prefix regular expression.\r
-///\r
-/// This searches the buffer using the provided regular expression, however it\r
-/// enforces constraints beyond that:\r
-/// 1) The found prefix must not be a suffix of something that looks like\r
-///    a valid prefix.\r
-/// 2) The found prefix must be followed by a valid check type suffix using \c\r
-///    FindCheckType above.\r
-///\r
-/// \returns a pair of StringRefs into the Buffer, which combines:\r
-///   - the first match of the regular expression to satisfy these two is\r
-///   returned,\r
-///     otherwise an empty StringRef is returned to indicate failure.\r
-///   - buffer rewound to the location right after parsed suffix, for parsing\r
-///     to continue from\r
-///\r
-/// If this routine returns a valid prefix, it will also shrink \p Buffer to\r
-/// start at the beginning of the returned prefix, increment \p LineNumber for\r
-/// each new line consumed from \p Buffer, and set \p CheckTy to the type of\r
-/// check found by examining the suffix.\r
-///\r
-/// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy\r
-/// is unspecified.\r
-static std::pair<StringRef, StringRef>\r
-FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,\r
-                        unsigned &LineNumber, Check::FileCheckType &CheckTy) {\r
-  SmallVector<StringRef, 2> Matches;\r
-\r
-  while (!Buffer.empty()) {\r
-    // Find the first (longest) match using the RE.\r
-    if (!PrefixRE.match(Buffer, &Matches))\r
-      // No match at all, bail.\r
-      return {StringRef(), StringRef()};\r
-\r
-    StringRef Prefix = Matches[0];\r
-    Matches.clear();\r
-\r
-    assert(Prefix.data() >= Buffer.data() &&\r
-           Prefix.data() < Buffer.data() + Buffer.size() &&\r
-           "Prefix doesn't start inside of buffer!");\r
-    size_t Loc = Prefix.data() - Buffer.data();\r
-    StringRef Skipped = Buffer.substr(0, Loc);\r
-    Buffer = Buffer.drop_front(Loc);\r
-    LineNumber += Skipped.count('\n');\r
-\r
-    // Check that the matched prefix isn't a suffix of some other check-like\r
-    // word.\r
-    // FIXME: This is a very ad-hoc check. it would be better handled in some\r
-    // other way. Among other things it seems hard to distinguish between\r
-    // intentional and unintentional uses of this feature.\r
-    if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {\r
-      // Now extract the type.\r
-      StringRef AfterSuffix;\r
-      std::tie(CheckTy, AfterSuffix) = FindCheckType(Buffer, Prefix);\r
-\r
-      // If we've found a valid check type for this prefix, we're done.\r
-      if (CheckTy != Check::CheckNone)\r
-        return {Prefix, AfterSuffix};\r
-    }\r
-\r
-    // If we didn't successfully find a prefix, we need to skip this invalid\r
-    // prefix and continue scanning. We directly skip the prefix that was\r
-    // matched and any additional parts of that check-like word.\r
-    Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size()));\r
-  }\r
-\r
-  // We ran out of buffer while skipping partial matches so give up.\r
-  return {StringRef(), StringRef()};\r
-}\r
-\r
-void FileCheckPatternContext::createLineVariable() {\r
-  assert(!LineVariable && "@LINE pseudo numeric variable already created");\r
-  StringRef LineName = "@LINE";\r
-  LineVariable = makeNumericVariable(LineName);\r
-  GlobalNumericVariableTable[LineName] = LineVariable;\r
-}\r
-\r
-FileCheck::FileCheck(FileCheckRequest Req)\r
-    : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()),\r
-      CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {}\r
-\r
-FileCheck::~FileCheck() = default;\r
-\r
-bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,\r
-                              Regex &PrefixRE) {\r
-  Error DefineError =\r
-      PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM);\r
-  if (DefineError) {\r
-    logAllUnhandledErrors(std::move(DefineError), errs());\r
-    return true;\r
-  }\r
-\r
-  PatternContext->createLineVariable();\r
-\r
-  std::vector<FileCheckPattern> ImplicitNegativeChecks;\r
-  for (const auto &PatternString : Req.ImplicitCheckNot) {\r
-    // Create a buffer with fake command line content in order to display the\r
-    // command line option responsible for the specific implicit CHECK-NOT.\r
-    std::string Prefix = "-implicit-check-not='";\r
-    std::string Suffix = "'";\r
-    std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy(\r
-        Prefix + PatternString + Suffix, "command line");\r
-\r
-    StringRef PatternInBuffer =\r
-        CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());\r
-    SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());\r
-\r
-    ImplicitNegativeChecks.push_back(\r
-        FileCheckPattern(Check::CheckNot, PatternContext.get()));\r
-    ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,\r
-                                               "IMPLICIT-CHECK", SM, Req);\r
-  }\r
-\r
-  std::vector<FileCheckPattern> DagNotMatches = ImplicitNegativeChecks;\r
-\r
-  // LineNumber keeps track of the line on which CheckPrefix instances are\r
-  // found.\r
-  unsigned LineNumber = 1;\r
-\r
-  while (1) {\r
-    Check::FileCheckType CheckTy;\r
-\r
-    // See if a prefix occurs in the memory buffer.\r
-    StringRef UsedPrefix;\r
-    StringRef AfterSuffix;\r
-    std::tie(UsedPrefix, AfterSuffix) =\r
-        FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber, CheckTy);\r
-    if (UsedPrefix.empty())\r
-      break;\r
-    assert(UsedPrefix.data() == Buffer.data() &&\r
-           "Failed to move Buffer's start forward, or pointed prefix outside "\r
-           "of the buffer!");\r
-    assert(AfterSuffix.data() >= Buffer.data() &&\r
-           AfterSuffix.data() < Buffer.data() + Buffer.size() &&\r
-           "Parsing after suffix doesn't start inside of buffer!");\r
-\r
-    // Location to use for error messages.\r
-    const char *UsedPrefixStart = UsedPrefix.data();\r
-\r
-    // Skip the buffer to the end of parsed suffix (or just prefix, if no good\r
-    // suffix was processed).\r
-    Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size())\r
-                                 : AfterSuffix;\r
-\r
-    // Complain about useful-looking but unsupported suffixes.\r
-    if (CheckTy == Check::CheckBadNot) {\r
-      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,\r
-                      "unsupported -NOT combo on prefix '" + UsedPrefix + "'");\r
-      return true;\r
-    }\r
-\r
-    // Complain about invalid count specification.\r
-    if (CheckTy == Check::CheckBadCount) {\r
-      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,\r
-                      "invalid count in -COUNT specification on prefix '" +\r
-                          UsedPrefix + "'");\r
-      return true;\r
-    }\r
-\r
-    // Okay, we found the prefix, yay. Remember the rest of the line, but ignore\r
-    // leading whitespace.\r
-    if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))\r
-      Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));\r
-\r
-    // Scan ahead to the end of line.\r
-    size_t EOL = Buffer.find_first_of("\n\r");\r
-\r
-    // Remember the location of the start of the pattern, for diagnostics.\r
-    SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());\r
-\r
-    // Parse the pattern.\r
-    FileCheckPattern P(CheckTy, PatternContext.get(), LineNumber);\r
-    if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req))\r
-      return true;\r
-\r
-    // Verify that CHECK-LABEL lines do not define or use variables\r
-    if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {\r
-      SM.PrintMessage(\r
-          SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error,\r
-          "found '" + UsedPrefix + "-LABEL:'"\r
-                                   " with variable definition or use");\r
-      return true;\r
-    }\r
-\r
-    Buffer = Buffer.substr(EOL);\r
-\r
-    // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.\r
-    if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||\r
-         CheckTy == Check::CheckEmpty) &&\r
-        CheckStrings->empty()) {\r
-      StringRef Type = CheckTy == Check::CheckNext\r
-                           ? "NEXT"\r
-                           : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";\r
-      SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),\r
-                      SourceMgr::DK_Error,\r
-                      "found '" + UsedPrefix + "-" + Type +\r
-                          "' without previous '" + UsedPrefix + ": line");\r
-      return true;\r
-    }\r
-\r
-    // Handle CHECK-DAG/-NOT.\r
-    if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {\r
-      DagNotMatches.push_back(P);\r
-      continue;\r
-    }\r
-\r
-    // Okay, add the string we captured to the output vector and move on.\r
-    CheckStrings->emplace_back(P, UsedPrefix, PatternLoc);\r
-    std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);\r
-    DagNotMatches = ImplicitNegativeChecks;\r
-  }\r
-\r
-  // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first\r
-  // prefix as a filler for the error message.\r
-  if (!DagNotMatches.empty()) {\r
-    CheckStrings->emplace_back(\r
-        FileCheckPattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1),\r
-        *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));\r
-    std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);\r
-  }\r
-\r
-  if (CheckStrings->empty()) {\r
-    errs() << "error: no check strings found with prefix"\r
-           << (Req.CheckPrefixes.size() > 1 ? "es " : " ");\r
-    auto I = Req.CheckPrefixes.begin();\r
-    auto E = Req.CheckPrefixes.end();\r
-    if (I != E) {\r
-      errs() << "\'" << *I << ":'";\r
-      ++I;\r
-    }\r
-    for (; I != E; ++I)\r
-      errs() << ", \'" << *I << ":'";\r
-\r
-    errs() << '\n';\r
-    return true;\r
-  }\r
-\r
-  return false;\r
-}\r
-\r
-static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,\r
-                       StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,\r
-                       int MatchedCount, StringRef Buffer, size_t MatchPos,\r
-                       size_t MatchLen, const FileCheckRequest &Req,\r
-                       std::vector<FileCheckDiag> *Diags) {\r
-  bool PrintDiag = true;\r
-  if (ExpectedMatch) {\r
-    if (!Req.Verbose)\r
-      return;\r
-    if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)\r
-      return;\r
-    // Due to their verbosity, we don't print verbose diagnostics here if we're\r
-    // gathering them for a different rendering, but we always print other\r
-    // diagnostics.\r
-    PrintDiag = !Diags;\r
-  }\r
-  SMRange MatchRange = ProcessMatchResult(\r
-      ExpectedMatch ? FileCheckDiag::MatchFoundAndExpected\r
-                    : FileCheckDiag::MatchFoundButExcluded,\r
-      SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags);\r
-  if (!PrintDiag)\r
-    return;\r
-\r
-  std::string Message = formatv("{0}: {1} string found in input",\r
-                                Pat.getCheckTy().getDescription(Prefix),\r
-                                (ExpectedMatch ? "expected" : "excluded"))\r
-                            .str();\r
-  if (Pat.getCount() > 1)\r
-    Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();\r
-\r
-  SM.PrintMessage(\r
-      Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);\r
-  SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",\r
-                  {MatchRange});\r
-  Pat.printSubstitutions(SM, Buffer, MatchRange);\r
-}\r
-\r
-static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,\r
-                       const FileCheckString &CheckStr, int MatchedCount,\r
-                       StringRef Buffer, size_t MatchPos, size_t MatchLen,\r
-                       FileCheckRequest &Req,\r
-                       std::vector<FileCheckDiag> *Diags) {\r
-  PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,\r
-             MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags);\r
-}\r
-\r
-static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,\r
-                         StringRef Prefix, SMLoc Loc,\r
-                         const FileCheckPattern &Pat, int MatchedCount,\r
-                         StringRef Buffer, bool VerboseVerbose,\r
-                         std::vector<FileCheckDiag> *Diags, Error MatchErrors) {\r
-  assert(MatchErrors && "Called on successful match");\r
-  bool PrintDiag = true;\r
-  if (!ExpectedMatch) {\r
-    if (!VerboseVerbose) {\r
-      consumeError(std::move(MatchErrors));\r
-      return;\r
-    }\r
-    // Due to their verbosity, we don't print verbose diagnostics here if we're\r
-    // gathering them for a different rendering, but we always print other\r
-    // diagnostics.\r
-    PrintDiag = !Diags;\r
-  }\r
-\r
-  // If the current position is at the end of a line, advance to the start of\r
-  // the next line.\r
-  Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));\r
-  SMRange SearchRange = ProcessMatchResult(\r
-      ExpectedMatch ? FileCheckDiag::MatchNoneButExpected\r
-                    : FileCheckDiag::MatchNoneAndExcluded,\r
-      SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags);\r
-  if (!PrintDiag) {\r
-    consumeError(std::move(MatchErrors));\r
-    return;\r
-  }\r
-\r
-  MatchErrors =\r
-      handleErrors(std::move(MatchErrors),\r
-                   [](const FileCheckErrorDiagnostic &E) { E.log(errs()); });\r
-\r
-  // No problem matching the string per se.\r
-  if (!MatchErrors)\r
-    return;\r
-  consumeError(std::move(MatchErrors));\r
-\r
-  // Print "not found" diagnostic.\r
-  std::string Message = formatv("{0}: {1} string not found in input",\r
-                                Pat.getCheckTy().getDescription(Prefix),\r
-                                (ExpectedMatch ? "expected" : "excluded"))\r
-                            .str();\r
-  if (Pat.getCount() > 1)\r
-    Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();\r
-  SM.PrintMessage(\r
-      Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message);\r
-\r
-  // Print the "scanning from here" line.\r
-  SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");\r
-\r
-  // Allow the pattern to print additional information if desired.\r
-  Pat.printSubstitutions(SM, Buffer);\r
-\r
-  if (ExpectedMatch)\r
-    Pat.printFuzzyMatch(SM, Buffer, Diags);\r
-}\r
-\r
-static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,\r
-                         const FileCheckString &CheckStr, int MatchedCount,\r
-                         StringRef Buffer, bool VerboseVerbose,\r
-                         std::vector<FileCheckDiag> *Diags, Error MatchErrors) {\r
-  PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,\r
-               MatchedCount, Buffer, VerboseVerbose, Diags,\r
-               std::move(MatchErrors));\r
-}\r
-\r
-/// Counts the number of newlines in the specified range.\r
-static unsigned CountNumNewlinesBetween(StringRef Range,\r
-                                        const char *&FirstNewLine) {\r
-  unsigned NumNewLines = 0;\r
-  while (1) {\r
-    // Scan for newline.\r
-    Range = Range.substr(Range.find_first_of("\n\r"));\r
-    if (Range.empty())\r
-      return NumNewLines;\r
-\r
-    ++NumNewLines;\r
-\r
-    // Handle \n\r and \r\n as a single newline.\r
-    if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') &&\r
-        (Range[0] != Range[1]))\r
-      Range = Range.substr(1);\r
-    Range = Range.substr(1);\r
-\r
-    if (NumNewLines == 1)\r
-      FirstNewLine = Range.begin();\r
-  }\r
-}\r
-\r
-size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,\r
-                              bool IsLabelScanMode, size_t &MatchLen,\r
-                              FileCheckRequest &Req,\r
-                              std::vector<FileCheckDiag> *Diags) const {\r
-  size_t LastPos = 0;\r
-  std::vector<const FileCheckPattern *> NotStrings;\r
-\r
-  // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL\r
-  // bounds; we have not processed variable definitions within the bounded block\r
-  // yet so cannot handle any final CHECK-DAG yet; this is handled when going\r
-  // over the block again (including the last CHECK-LABEL) in normal mode.\r
-  if (!IsLabelScanMode) {\r
-    // Match "dag strings" (with mixed "not strings" if any).\r
-    LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);\r
-    if (LastPos == StringRef::npos)\r
-      return StringRef::npos;\r
-  }\r
-\r
-  // Match itself from the last position after matching CHECK-DAG.\r
-  size_t LastMatchEnd = LastPos;\r
-  size_t FirstMatchPos = 0;\r
-  // Go match the pattern Count times. Majority of patterns only match with\r
-  // count 1 though.\r
-  assert(Pat.getCount() != 0 && "pattern count can not be zero");\r
-  for (int i = 1; i <= Pat.getCount(); i++) {\r
-    StringRef MatchBuffer = Buffer.substr(LastMatchEnd);\r
-    size_t CurrentMatchLen;\r
-    // get a match at current start point\r
-    Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM);\r
-\r
-    // report\r
-    if (!MatchResult) {\r
-      PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags,\r
-                   MatchResult.takeError());\r
-      return StringRef::npos;\r
-    }\r
-    size_t MatchPos = *MatchResult;\r
-    PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,\r
-               Diags);\r
-    if (i == 1)\r
-      FirstMatchPos = LastPos + MatchPos;\r
-\r
-    // move start point after the match\r
-    LastMatchEnd += MatchPos + CurrentMatchLen;\r
-  }\r
-  // Full match len counts from first match pos.\r
-  MatchLen = LastMatchEnd - FirstMatchPos;\r
-\r
-  // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT\r
-  // or CHECK-NOT\r
-  if (!IsLabelScanMode) {\r
-    size_t MatchPos = FirstMatchPos - LastPos;\r
-    StringRef MatchBuffer = Buffer.substr(LastPos);\r
-    StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);\r
-\r
-    // If this check is a "CHECK-NEXT", verify that the previous match was on\r
-    // the previous line (i.e. that there is one newline between them).\r
-    if (CheckNext(SM, SkippedRegion)) {\r
-      ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,\r
-                         Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,\r
-                         Diags, Req.Verbose);\r
-      return StringRef::npos;\r
-    }\r
-\r
-    // If this check is a "CHECK-SAME", verify that the previous match was on\r
-    // the same line (i.e. that there is no newline between them).\r
-    if (CheckSame(SM, SkippedRegion)) {\r
-      ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,\r
-                         Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,\r
-                         Diags, Req.Verbose);\r
-      return StringRef::npos;\r
-    }\r
-\r
-    // If this match had "not strings", verify that they don't exist in the\r
-    // skipped region.\r
-    if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))\r
-      return StringRef::npos;\r
-  }\r
-\r
-  return FirstMatchPos;\r
-}\r
-\r
-bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {\r
-  if (Pat.getCheckTy() != Check::CheckNext &&\r
-      Pat.getCheckTy() != Check::CheckEmpty)\r
-    return false;\r
-\r
-  Twine CheckName =\r
-      Prefix +\r
-      Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT");\r
-\r
-  // Count the number of newlines between the previous match and this one.\r
-  const char *FirstNewLine = nullptr;\r
-  unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);\r
-\r
-  if (NumNewLines == 0) {\r
-    SM.PrintMessage(Loc, SourceMgr::DK_Error,\r
-                    CheckName + ": is on the same line as previous match");\r
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,\r
-                    "'next' match was here");\r
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,\r
-                    "previous match ended here");\r
-    return true;\r
-  }\r
-\r
-  if (NumNewLines != 1) {\r
-    SM.PrintMessage(Loc, SourceMgr::DK_Error,\r
-                    CheckName +\r
-                        ": is not on the line after the previous match");\r
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,\r
-                    "'next' match was here");\r
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,\r
-                    "previous match ended here");\r
-    SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note,\r
-                    "non-matching line after previous match is here");\r
-    return true;\r
-  }\r
-\r
-  return false;\r
-}\r
-\r
-bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {\r
-  if (Pat.getCheckTy() != Check::CheckSame)\r
-    return false;\r
-\r
-  // Count the number of newlines between the previous match and this one.\r
-  const char *FirstNewLine = nullptr;\r
-  unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);\r
-\r
-  if (NumNewLines != 0) {\r
-    SM.PrintMessage(Loc, SourceMgr::DK_Error,\r
-                    Prefix +\r
-                        "-SAME: is not on the same line as the previous match");\r
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,\r
-                    "'next' match was here");\r
-    SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,\r
-                    "previous match ended here");\r
-    return true;\r
-  }\r
-\r
-  return false;\r
-}\r
-\r
-bool FileCheckString::CheckNot(\r
-    const SourceMgr &SM, StringRef Buffer,\r
-    const std::vector<const FileCheckPattern *> &NotStrings,\r
-    const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const {\r
-  for (const FileCheckPattern *Pat : NotStrings) {\r
-    assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");\r
-\r
-    size_t MatchLen = 0;\r
-    Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM);\r
-\r
-    if (!MatchResult) {\r
-      PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,\r
-                   Req.VerboseVerbose, Diags, MatchResult.takeError());\r
-      continue;\r
-    }\r
-    size_t Pos = *MatchResult;\r
-\r
-    PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,\r
-               Req, Diags);\r
-\r
-    return true;\r
-  }\r
-\r
-  return false;\r
-}\r
-\r
-size_t\r
-FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,\r
-                          std::vector<const FileCheckPattern *> &NotStrings,\r
-                          const FileCheckRequest &Req,\r
-                          std::vector<FileCheckDiag> *Diags) const {\r
-  if (DagNotStrings.empty())\r
-    return 0;\r
-\r
-  // The start of the search range.\r
-  size_t StartPos = 0;\r
-\r
-  struct MatchRange {\r
-    size_t Pos;\r
-    size_t End;\r
-  };\r
-  // A sorted list of ranges for non-overlapping CHECK-DAG matches.  Match\r
-  // ranges are erased from this list once they are no longer in the search\r
-  // range.\r
-  std::list<MatchRange> MatchRanges;\r
-\r
-  // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG\r
-  // group, so we don't use a range-based for loop here.\r
-  for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();\r
-       PatItr != PatEnd; ++PatItr) {\r
-    const FileCheckPattern &Pat = *PatItr;\r
-    assert((Pat.getCheckTy() == Check::CheckDAG ||\r
-            Pat.getCheckTy() == Check::CheckNot) &&\r
-           "Invalid CHECK-DAG or CHECK-NOT!");\r
-\r
-    if (Pat.getCheckTy() == Check::CheckNot) {\r
-      NotStrings.push_back(&Pat);\r
-      continue;\r
-    }\r
-\r
-    assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");\r
-\r
-    // CHECK-DAG always matches from the start.\r
-    size_t MatchLen = 0, MatchPos = StartPos;\r
-\r
-    // Search for a match that doesn't overlap a previous match in this\r
-    // CHECK-DAG group.\r
-    for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {\r
-      StringRef MatchBuffer = Buffer.substr(MatchPos);\r
-      Expected<size_t> MatchResult = Pat.match(MatchBuffer, MatchLen, SM);\r
-      // With a group of CHECK-DAGs, a single mismatching means the match on\r
-      // that group of CHECK-DAGs fails immediately.\r
-      if (!MatchResult) {\r
-        PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,\r
-                     Req.VerboseVerbose, Diags, MatchResult.takeError());\r
-        return StringRef::npos;\r
-      }\r
-      size_t MatchPosBuf = *MatchResult;\r
-      // Re-calc it as the offset relative to the start of the original string.\r
-      MatchPos += MatchPosBuf;\r
-      if (Req.VerboseVerbose)\r
-        PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,\r
-                   MatchLen, Req, Diags);\r
-      MatchRange M{MatchPos, MatchPos + MatchLen};\r
-      if (Req.AllowDeprecatedDagOverlap) {\r
-        // We don't need to track all matches in this mode, so we just maintain\r
-        // one match range that encompasses the current CHECK-DAG group's\r
-        // matches.\r
-        if (MatchRanges.empty())\r
-          MatchRanges.insert(MatchRanges.end(), M);\r
-        else {\r
-          auto Block = MatchRanges.begin();\r
-          Block->Pos = std::min(Block->Pos, M.Pos);\r
-          Block->End = std::max(Block->End, M.End);\r
-        }\r
-        break;\r
-      }\r
-      // Iterate previous matches until overlapping match or insertion point.\r
-      bool Overlap = false;\r
-      for (; MI != ME; ++MI) {\r
-        if (M.Pos < MI->End) {\r
-          // !Overlap => New match has no overlap and is before this old match.\r
-          // Overlap => New match overlaps this old match.\r
-          Overlap = MI->Pos < M.End;\r
-          break;\r
-        }\r
-      }\r
-      if (!Overlap) {\r
-        // Insert non-overlapping match into list.\r
-        MatchRanges.insert(MI, M);\r
-        break;\r
-      }\r
-      if (Req.VerboseVerbose) {\r
-        // Due to their verbosity, we don't print verbose diagnostics here if\r
-        // we're gathering them for a different rendering, but we always print\r
-        // other diagnostics.\r
-        if (!Diags) {\r
-          SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos);\r
-          SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End);\r
-          SMRange OldRange(OldStart, OldEnd);\r
-          SM.PrintMessage(OldStart, SourceMgr::DK_Note,\r
-                          "match discarded, overlaps earlier DAG match here",\r
-                          {OldRange});\r
-        } else\r
-          Diags->rbegin()->MatchTy = FileCheckDiag::MatchFoundButDiscarded;\r
-      }\r
-      MatchPos = MI->End;\r
-    }\r
-    if (!Req.VerboseVerbose)\r
-      PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,\r
-                 MatchLen, Req, Diags);\r
-\r
-    // Handle the end of a CHECK-DAG group.\r
-    if (std::next(PatItr) == PatEnd ||\r
-        std::next(PatItr)->getCheckTy() == Check::CheckNot) {\r
-      if (!NotStrings.empty()) {\r
-        // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to\r
-        // CHECK-DAG, verify that there are no 'not' strings occurred in that\r
-        // region.\r
-        StringRef SkippedRegion =\r
-            Buffer.slice(StartPos, MatchRanges.begin()->Pos);\r
-        if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))\r
-          return StringRef::npos;\r
-        // Clear "not strings".\r
-        NotStrings.clear();\r
-      }\r
-      // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the\r
-      // end of this CHECK-DAG group's match range.\r
-      StartPos = MatchRanges.rbegin()->End;\r
-      // Don't waste time checking for (impossible) overlaps before that.\r
-      MatchRanges.clear();\r
-    }\r
-  }\r
-\r
-  return StartPos;\r
-}\r
-\r
-// A check prefix must contain only alphanumeric, hyphens and underscores.\r
-static bool ValidateCheckPrefix(StringRef CheckPrefix) {\r
-  static const Regex Validator("^[a-zA-Z0-9_-]*$");\r
-  return Validator.match(CheckPrefix);\r
-}\r
-\r
-bool FileCheck::ValidateCheckPrefixes() {\r
-  StringSet<> PrefixSet;\r
-\r
-  for (StringRef Prefix : Req.CheckPrefixes) {\r
-    // Reject empty prefixes.\r
-    if (Prefix == "")\r
-      return false;\r
-\r
-    if (!PrefixSet.insert(Prefix).second)\r
-      return false;\r
-\r
-    if (!ValidateCheckPrefix(Prefix))\r
-      return false;\r
-  }\r
-\r
-  return true;\r
-}\r
-\r
-Regex FileCheck::buildCheckPrefixRegex() {\r
-  // I don't think there's a way to specify an initial value for cl::list,\r
-  // so if nothing was specified, add the default\r
-  if (Req.CheckPrefixes.empty())\r
-    Req.CheckPrefixes.push_back("CHECK");\r
-\r
-  // We already validated the contents of CheckPrefixes so just concatenate\r
-  // them as alternatives.\r
-  SmallString<32> PrefixRegexStr;\r
-  for (StringRef Prefix : Req.CheckPrefixes) {\r
-    if (Prefix != Req.CheckPrefixes.front())\r
-      PrefixRegexStr.push_back('|');\r
-\r
-    PrefixRegexStr.append(Prefix);\r
-  }\r
-\r
-  return Regex(PrefixRegexStr);\r
-}\r
-\r
-Error FileCheckPatternContext::defineCmdlineVariables(\r
-    std::vector<std::string> &CmdlineDefines, SourceMgr &SM) {\r
-  assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&\r
-         "Overriding defined variable with command-line variable definitions");\r
-\r
-  if (CmdlineDefines.empty())\r
-    return Error::success();\r
-\r
-  // Create a string representing the vector of command-line definitions. Each\r
-  // definition is on its own line and prefixed with a definition number to\r
-  // clarify which definition a given diagnostic corresponds to.\r
-  unsigned I = 0;\r
-  Error Errs = Error::success();\r
-  std::string CmdlineDefsDiag;\r
-  SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;\r
-  for (StringRef CmdlineDef : CmdlineDefines) {\r
-    std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();\r
-    size_t EqIdx = CmdlineDef.find('=');\r
-    if (EqIdx == StringRef::npos) {\r
-      CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));\r
-      continue;\r
-    }\r
-    // Numeric variable definition.\r
-    if (CmdlineDef[0] == '#') {\r
-      // Append a copy of the command-line definition adapted to use the same\r
-      // format as in the input file to be able to reuse\r
-      // parseNumericSubstitutionBlock.\r
-      CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();\r
-      std::string SubstitutionStr = CmdlineDef;\r
-      SubstitutionStr[EqIdx] = ':';\r
-      CmdlineDefsIndices.push_back(\r
-          std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));\r
-      CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();\r
-    } else {\r
-      CmdlineDefsDiag += DefPrefix;\r
-      CmdlineDefsIndices.push_back(\r
-          std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));\r
-      CmdlineDefsDiag += (CmdlineDef + "\n").str();\r
-    }\r
-  }\r
-\r
-  // Create a buffer with fake command line content in order to display\r
-  // parsing diagnostic with location information and point to the\r
-  // global definition with invalid syntax.\r
-  std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer =\r
-      MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines");\r
-  StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();\r
-  SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());\r
-\r
-  for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {\r
-    StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,\r
-                                                     CmdlineDefIndices.second);\r
-    if (CmdlineDef.empty()) {\r
-      Errs = joinErrors(\r
-          std::move(Errs),\r
-          FileCheckErrorDiagnostic::get(\r
-              SM, CmdlineDef, "missing equal sign in global definition"));\r
-      continue;\r
-    }\r
-\r
-    // Numeric variable definition.\r
-    if (CmdlineDef[0] == '#') {\r
-      // Now parse the definition both to check that the syntax is correct and\r
-      // to create the necessary class instance.\r
-      StringRef CmdlineDefExpr = CmdlineDef.substr(1);\r
-      Optional<FileCheckNumericVariable *> DefinedNumericVariable;\r
-      Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionASTResult =\r
-          FileCheckPattern::parseNumericSubstitutionBlock(\r
-              CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);\r
-      if (!ExpressionASTResult) {\r
-        Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError());\r
-        continue;\r
-      }\r
-      std::unique_ptr<FileCheckExpressionAST> ExpressionAST =\r
-          std::move(*ExpressionASTResult);\r
-      // Now evaluate the expression whose value this variable should be set\r
-      // to, since the expression of a command-line variable definition should\r
-      // only use variables defined earlier on the command-line. If not, this\r
-      // is an error and we report it.\r
-      Expected<uint64_t> Value = ExpressionAST->eval();\r
-      if (!Value) {\r
-        Errs = joinErrors(std::move(Errs), Value.takeError());\r
-        continue;\r
-      }\r
-\r
-      assert(DefinedNumericVariable && "No variable defined");\r
-      (*DefinedNumericVariable)->setValue(*Value);\r
-\r
-      // Record this variable definition.\r
-      GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =\r
-          *DefinedNumericVariable;\r
-    } else {\r
-      // String variable definition.\r
-      std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');\r
-      StringRef CmdlineName = CmdlineNameVal.first;\r
-      StringRef OrigCmdlineName = CmdlineName;\r
-      Expected<FileCheckPattern::VariableProperties> ParseVarResult =\r
-          FileCheckPattern::parseVariable(CmdlineName, SM);\r
-      if (!ParseVarResult) {\r
-        Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());\r
-        continue;\r
-      }\r
-      // Check that CmdlineName does not denote a pseudo variable is only\r
-      // composed of the parsed numeric variable. This catches cases like\r
-      // "FOO+2" in a "FOO+2=10" definition.\r
-      if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {\r
-        Errs = joinErrors(std::move(Errs),\r
-                          FileCheckErrorDiagnostic::get(\r
-                              SM, OrigCmdlineName,\r
-                              "invalid name in string variable definition '" +\r
-                                  OrigCmdlineName + "'"));\r
-        continue;\r
-      }\r
-      StringRef Name = ParseVarResult->Name;\r
-\r
-      // Detect collisions between string and numeric variables when the former\r
-      // is created later than the latter.\r
-      if (GlobalNumericVariableTable.find(Name) !=\r
-          GlobalNumericVariableTable.end()) {\r
-        Errs = joinErrors(std::move(Errs), FileCheckErrorDiagnostic::get(\r
-                                               SM, Name,\r
-                                               "numeric variable with name '" +\r
-                                                   Name + "' already exists"));\r
-        continue;\r
-      }\r
-      GlobalVariableTable.insert(CmdlineNameVal);\r
-      // Mark the string variable as defined to detect collisions between\r
-      // string and numeric variables in defineCmdlineVariables when the latter\r
-      // is created later than the former. We cannot reuse GlobalVariableTable\r
-      // for this by populating it with an empty string since we would then\r
-      // lose the ability to detect the use of an undefined variable in\r
-      // match().\r
-      DefinedVariableTable[Name] = true;\r
-    }\r
-  }\r
-\r
-  return Errs;\r
-}\r
-\r
-void FileCheckPatternContext::clearLocalVars() {\r
-  SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars;\r
-  for (const StringMapEntry<StringRef> &Var : GlobalVariableTable)\r
-    if (Var.first()[0] != '$')\r
-      LocalPatternVars.push_back(Var.first());\r
-\r
-  // Numeric substitution reads the value of a variable directly, not via\r
-  // GlobalNumericVariableTable. Therefore, we clear local variables by\r
-  // clearing their value which will lead to a numeric substitution failure. We\r
-  // also mark the variable for removal from GlobalNumericVariableTable since\r
-  // this is what defineCmdlineVariables checks to decide that no global\r
-  // variable has been defined.\r
-  for (const auto &Var : GlobalNumericVariableTable)\r
-    if (Var.first()[0] != '$') {\r
-      Var.getValue()->clearValue();\r
-      LocalNumericVars.push_back(Var.first());\r
-    }\r
-\r
-  for (const auto &Var : LocalPatternVars)\r
-    GlobalVariableTable.erase(Var);\r
-  for (const auto &Var : LocalNumericVars)\r
-    GlobalNumericVariableTable.erase(Var);\r
-}\r
-\r
-bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer,\r
-                           std::vector<FileCheckDiag> *Diags) {\r
-  bool ChecksFailed = false;\r
-\r
-  unsigned i = 0, j = 0, e = CheckStrings->size();\r
-  while (true) {\r
-    StringRef CheckRegion;\r
-    if (j == e) {\r
-      CheckRegion = Buffer;\r
-    } else {\r
-      const FileCheckString &CheckLabelStr = (*CheckStrings)[j];\r
-      if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) {\r
-        ++j;\r
-        continue;\r
-      }\r
-\r
-      // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG\r
-      size_t MatchLabelLen = 0;\r
-      size_t MatchLabelPos =\r
-          CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);\r
-      if (MatchLabelPos == StringRef::npos)\r
-        // Immediately bail if CHECK-LABEL fails, nothing else we can do.\r
-        return false;\r
-\r
-      CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);\r
-      Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);\r
-      ++j;\r
-    }\r
-\r
-    // Do not clear the first region as it's the one before the first\r
-    // CHECK-LABEL and it would clear variables defined on the command-line\r
-    // before they get used.\r
-    if (i != 0 && Req.EnableVarScope)\r
-      PatternContext->clearLocalVars();\r
-\r
-    for (; i != j; ++i) {\r
-      const FileCheckString &CheckStr = (*CheckStrings)[i];\r
-\r
-      // Check each string within the scanned region, including a second check\r
-      // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)\r
-      size_t MatchLen = 0;\r
-      size_t MatchPos =\r
-          CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);\r
-\r
-      if (MatchPos == StringRef::npos) {\r
-        ChecksFailed = true;\r
-        i = j;\r
-        break;\r
-      }\r
-\r
-      CheckRegion = CheckRegion.substr(MatchPos + MatchLen);\r
-    }\r
-\r
-    if (j == e)\r
-      break;\r
-  }\r
-\r
-  // Success if no checks failed.\r
-  return !ChecksFailed;\r
-}\r
+//===- 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;
+}
index 6581612a8e44cbbf0ca6a2dfe73fa6c15ab30e0a..001b3589d5fdcb65bf21f9f003f3fb02b75f8b0f 100644 (file)
-//===-- FileCheckImpl.h - Private FileCheck Interface ------------*- C++ -*-==//\r
-//\r
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.\r
-// See https://llvm.org/LICENSE.txt for license information.\r
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\r
-//\r
-//===----------------------------------------------------------------------===//\r
-//\r
-// This file defines the private interfaces of FileCheck. Its purpose is to\r
-// allow unit testing of FileCheck and to separate the interface from the\r
-// implementation. It is only meant to be used by FileCheck.\r
-//\r
-//===----------------------------------------------------------------------===//\r
-\r
-#ifndef LLVM_LIB_SUPPORT_FILECHECKIMPL_H\r
-#define LLVM_LIB_SUPPORT_FILECHECKIMPL_H\r
-\r
-#include "llvm/ADT/Optional.h"\r
-#include "llvm/ADT/StringMap.h"\r
-#include "llvm/ADT/StringRef.h"\r
-#include "llvm/Support/Error.h"\r
-#include "llvm/Support/SourceMgr.h"\r
-#include <map>\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace llvm {\r
-\r
-//===----------------------------------------------------------------------===//\r
-// Numeric substitution handling code.\r
-//===----------------------------------------------------------------------===//\r
-\r
-/// Base class representing the AST of a given expression.\r
-class FileCheckExpressionAST {\r
-public:\r
-  virtual ~FileCheckExpressionAST() = default;\r
-\r
-  /// Evaluates and \returns the value of the expression represented by this\r
-  /// AST or an error if evaluation fails.\r
-  virtual Expected<uint64_t> eval() const = 0;\r
-};\r
-\r
-/// Class representing an unsigned literal in the AST of an expression.\r
-class FileCheckExpressionLiteral : public FileCheckExpressionAST {\r
-private:\r
-  /// Actual value of the literal.\r
-  uint64_t Value;\r
-\r
-public:\r
-  /// Constructs a literal with the specified value.\r
-  FileCheckExpressionLiteral(uint64_t Val) : Value(Val) {}\r
-\r
-  /// \returns the literal's value.\r
-  Expected<uint64_t> eval() const { return Value; }\r
-};\r
-\r
-/// Class to represent an undefined variable error, which quotes that\r
-/// variable's name when printed.\r
-class FileCheckUndefVarError : public ErrorInfo<FileCheckUndefVarError> {\r
-private:\r
-  StringRef VarName;\r
-\r
-public:\r
-  static char ID;\r
-\r
-  FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}\r
-\r
-  StringRef getVarName() const { return VarName; }\r
-\r
-  std::error_code convertToErrorCode() const override {\r
-    return inconvertibleErrorCode();\r
-  }\r
-\r
-  /// Print name of variable associated with this error.\r
-  void log(raw_ostream &OS) const override {\r
-    OS << "\"";\r
-    OS.write_escaped(VarName) << "\"";\r
-  }\r
-};\r
-\r
-/// Class representing a numeric variable and its associated current value.\r
-class FileCheckNumericVariable {\r
-private:\r
-  /// Name of the numeric variable.\r
-  StringRef Name;\r
-\r
-  /// Value of numeric variable, if defined, or None otherwise.\r
-  Optional<uint64_t> Value;\r
-\r
-  /// Line number where this variable is defined, or None if defined before\r
-  /// input is parsed. Used to determine whether a variable is defined on the\r
-  /// same line as a given use.\r
-  Optional<size_t> DefLineNumber;\r
-\r
-public:\r
-  /// Constructor for a variable \p Name defined at line \p DefLineNumber or\r
-  /// defined before input is parsed if \p DefLineNumber is None.\r
-  explicit FileCheckNumericVariable(StringRef Name,\r
-                                    Optional<size_t> DefLineNumber = None)\r
-      : Name(Name), DefLineNumber(DefLineNumber) {}\r
-\r
-  /// \returns name of this numeric variable.\r
-  StringRef getName() const { return Name; }\r
-\r
-  /// \returns this variable's value.\r
-  Optional<uint64_t> getValue() const { return Value; }\r
-\r
-  /// Sets value of this numeric variable to \p NewValue.\r
-  void setValue(uint64_t NewValue) { Value = NewValue; }\r
-\r
-  /// Clears value of this numeric variable, regardless of whether it is\r
-  /// currently defined or not.\r
-  void clearValue() { Value = None; }\r
-\r
-  /// \returns the line number where this variable is defined, if any, or None\r
-  /// if defined before input is parsed.\r
-  Optional<size_t> getDefLineNumber() { return DefLineNumber; }\r
-};\r
-\r
-/// Class representing the use of a numeric variable in the AST of an\r
-/// expression.\r
-class FileCheckNumericVariableUse : public FileCheckExpressionAST {\r
-private:\r
-  /// Name of the numeric variable.\r
-  StringRef Name;\r
-\r
-  /// Pointer to the class instance for the variable this use is about.\r
-  FileCheckNumericVariable *NumericVariable;\r
-\r
-public:\r
-  FileCheckNumericVariableUse(StringRef Name,\r
-                              FileCheckNumericVariable *NumericVariable)\r
-      : Name(Name), NumericVariable(NumericVariable) {}\r
-\r
-  /// \returns the value of the variable referenced by this instance.\r
-  Expected<uint64_t> eval() const;\r
-};\r
-\r
-/// Type of functions evaluating a given binary operation.\r
-using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);\r
-\r
-/// Class representing a single binary operation in the AST of an expression.\r
-class FileCheckASTBinop : public FileCheckExpressionAST {\r
-private:\r
-  /// Left operand.\r
-  std::unique_ptr<FileCheckExpressionAST> LeftOperand;\r
-\r
-  /// Right operand.\r
-  std::unique_ptr<FileCheckExpressionAST> RightOperand;\r
-\r
-  /// Pointer to function that can evaluate this binary operation.\r
-  binop_eval_t EvalBinop;\r
-\r
-public:\r
-  FileCheckASTBinop(binop_eval_t EvalBinop,\r
-                    std::unique_ptr<FileCheckExpressionAST> LeftOp,\r
-                    std::unique_ptr<FileCheckExpressionAST> RightOp)\r
-      : EvalBinop(EvalBinop) {\r
-    LeftOperand = std::move(LeftOp);\r
-    RightOperand = std::move(RightOp);\r
-  }\r
-\r
-  /// Evaluates the value of the binary operation represented by this AST,\r
-  /// using EvalBinop on the result of recursively evaluating the operands.\r
-  /// \returns the expression value or an error if an undefined numeric\r
-  /// variable is used in one of the operands.\r
-  Expected<uint64_t> eval() const;\r
-};\r
-\r
-class FileCheckPatternContext;\r
-\r
-/// Class representing a substitution to perform in the RegExStr string.\r
-class FileCheckSubstitution {\r
-protected:\r
-  /// Pointer to a class instance holding, among other things, the table with\r
-  /// the values of live string variables at the start of any given CHECK line.\r
-  /// Used for substituting string variables with the text they were defined\r
-  /// as. Expressions are linked to the numeric variables they use at\r
-  /// parse time and directly access the value of the numeric variable to\r
-  /// evaluate their value.\r
-  FileCheckPatternContext *Context;\r
-\r
-  /// The string that needs to be substituted for something else. For a\r
-  /// string variable this is its name, otherwise this is the whole expression.\r
-  StringRef FromStr;\r
-\r
-  // Index in RegExStr of where to do the substitution.\r
-  size_t InsertIdx;\r
-\r
-public:\r
-  FileCheckSubstitution(FileCheckPatternContext *Context, StringRef VarName,\r
-                        size_t InsertIdx)\r
-      : Context(Context), FromStr(VarName), InsertIdx(InsertIdx) {}\r
-\r
-  virtual ~FileCheckSubstitution() = default;\r
-\r
-  /// \returns the string to be substituted for something else.\r
-  StringRef getFromString() const { return FromStr; }\r
-\r
-  /// \returns the index where the substitution is to be performed in RegExStr.\r
-  size_t getIndex() const { return InsertIdx; }\r
-\r
-  /// \returns a string containing the result of the substitution represented\r
-  /// by this class instance or an error if substitution failed.\r
-  virtual Expected<std::string> getResult() const = 0;\r
-};\r
-\r
-class FileCheckStringSubstitution : public FileCheckSubstitution {\r
-public:\r
-  FileCheckStringSubstitution(FileCheckPatternContext *Context,\r
-                              StringRef VarName, size_t InsertIdx)\r
-      : FileCheckSubstitution(Context, VarName, InsertIdx) {}\r
-\r
-  /// \returns the text that the string variable in this substitution matched\r
-  /// when defined, or an error if the variable is undefined.\r
-  Expected<std::string> getResult() const override;\r
-};\r
-\r
-class FileCheckNumericSubstitution : public FileCheckSubstitution {\r
-private:\r
-  /// Pointer to the class representing the expression whose value is to be\r
-  /// substituted.\r
-  std::unique_ptr<FileCheckExpressionAST> ExpressionAST;\r
-\r
-public:\r
-  FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr,\r
-                               std::unique_ptr<FileCheckExpressionAST> ExprAST,\r
-                               size_t InsertIdx)\r
-      : FileCheckSubstitution(Context, Expr, InsertIdx) {\r
-    ExpressionAST = std::move(ExprAST);\r
-  }\r
-\r
-  /// \returns a string containing the result of evaluating the expression in\r
-  /// this substitution, or an error if evaluation failed.\r
-  Expected<std::string> getResult() const override;\r
-};\r
-\r
-//===----------------------------------------------------------------------===//\r
-// Pattern handling code.\r
-//===----------------------------------------------------------------------===//\r
-\r
-struct FileCheckDiag;\r
-\r
-/// Class holding the FileCheckPattern global state, shared by all patterns:\r
-/// tables holding values of variables and whether they are defined or not at\r
-/// any given time in the matching process.\r
-class FileCheckPatternContext {\r
-  friend class FileCheckPattern;\r
-\r
-private:\r
-  /// When matching a given pattern, this holds the value of all the string\r
-  /// variables defined in previous patterns. In a pattern, only the last\r
-  /// definition for a given variable is recorded in this table.\r
-  /// Back-references are used for uses after any the other definition.\r
-  StringMap<StringRef> GlobalVariableTable;\r
-\r
-  /// Map of all string variables defined so far. Used at parse time to detect\r
-  /// a name conflict between a numeric variable and a string variable when\r
-  /// the former is defined on a later line than the latter.\r
-  StringMap<bool> DefinedVariableTable;\r
-\r
-  /// When matching a given pattern, this holds the pointers to the classes\r
-  /// representing the numeric variables defined in previous patterns. When\r
-  /// matching a pattern all definitions for that pattern are recorded in the\r
-  /// NumericVariableDefs table in the FileCheckPattern instance of that\r
-  /// pattern.\r
-  StringMap<FileCheckNumericVariable *> GlobalNumericVariableTable;\r
-\r
-  /// Pointer to the class instance representing the @LINE pseudo variable for\r
-  /// easily updating its value.\r
-  FileCheckNumericVariable *LineVariable = nullptr;\r
-\r
-  /// Vector holding pointers to all parsed numeric variables. Used to\r
-  /// automatically free them once they are guaranteed to no longer be used.\r
-  std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;\r
-\r
-  /// Vector holding pointers to all substitutions. Used to automatically free\r
-  /// them once they are guaranteed to no longer be used.\r
-  std::vector<std::unique_ptr<FileCheckSubstitution>> Substitutions;\r
-\r
-public:\r
-  /// \returns the value of string variable \p VarName or an error if no such\r
-  /// variable has been defined.\r
-  Expected<StringRef> getPatternVarValue(StringRef VarName);\r
-\r
-  /// Defines string and numeric variables from definitions given on the\r
-  /// command line, passed as a vector of [#]VAR=VAL strings in\r
-  /// \p CmdlineDefines. \returns an error list containing diagnostics against\r
-  /// \p SM for all definition parsing failures, if any, or Success otherwise.\r
-  Error defineCmdlineVariables(std::vector<std::string> &CmdlineDefines,\r
-                               SourceMgr &SM);\r
-\r
-  /// Create @LINE pseudo variable. Value is set when pattern are being\r
-  /// matched.\r
-  void createLineVariable();\r
-\r
-  /// Undefines local variables (variables whose name does not start with a '$'\r
-  /// sign), i.e. removes them from GlobalVariableTable and from\r
-  /// GlobalNumericVariableTable and also clears the value of numeric\r
-  /// variables.\r
-  void clearLocalVars();\r
-\r
-private:\r
-  /// Makes a new numeric variable and registers it for destruction when the\r
-  /// context is destroyed.\r
-  template <class... Types>\r
-  FileCheckNumericVariable *makeNumericVariable(Types... args);\r
-\r
-  /// Makes a new string substitution and registers it for destruction when the\r
-  /// context is destroyed.\r
-  FileCheckSubstitution *makeStringSubstitution(StringRef VarName,\r
-                                                size_t InsertIdx);\r
-\r
-  /// Makes a new numeric substitution and registers it for destruction when\r
-  /// the context is destroyed.\r
-  FileCheckSubstitution *\r
-  makeNumericSubstitution(StringRef ExpressionStr,\r
-                          std::unique_ptr<FileCheckExpressionAST> ExpressionAST,\r
-                          size_t InsertIdx);\r
-};\r
-\r
-/// Class to represent an error holding a diagnostic with location information\r
-/// used when printing it.\r
-class FileCheckErrorDiagnostic : public ErrorInfo<FileCheckErrorDiagnostic> {\r
-private:\r
-  SMDiagnostic Diagnostic;\r
-\r
-public:\r
-  static char ID;\r
-\r
-  FileCheckErrorDiagnostic(SMDiagnostic &&Diag) : Diagnostic(Diag) {}\r
-\r
-  std::error_code convertToErrorCode() const override {\r
-    return inconvertibleErrorCode();\r
-  }\r
-\r
-  /// Print diagnostic associated with this error when printing the error.\r
-  void log(raw_ostream &OS) const override { Diagnostic.print(nullptr, OS); }\r
-\r
-  static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg) {\r
-    return make_error<FileCheckErrorDiagnostic>(\r
-        SM.GetMessage(Loc, SourceMgr::DK_Error, ErrMsg));\r
-  }\r
-\r
-  static Error get(const SourceMgr &SM, StringRef Buffer, const Twine &ErrMsg) {\r
-    return get(SM, SMLoc::getFromPointer(Buffer.data()), ErrMsg);\r
-  }\r
-};\r
-\r
-class FileCheckNotFoundError : public ErrorInfo<FileCheckNotFoundError> {\r
-public:\r
-  static char ID;\r
-\r
-  std::error_code convertToErrorCode() const override {\r
-    return inconvertibleErrorCode();\r
-  }\r
-\r
-  /// Print diagnostic associated with this error when printing the error.\r
-  void log(raw_ostream &OS) const override {\r
-    OS << "String not found in input";\r
-  }\r
-};\r
-\r
-class FileCheckPattern {\r
-  SMLoc PatternLoc;\r
-\r
-  /// A fixed string to match as the pattern or empty if this pattern requires\r
-  /// a regex match.\r
-  StringRef FixedStr;\r
-\r
-  /// A regex string to match as the pattern or empty if this pattern requires\r
-  /// a fixed string to match.\r
-  std::string RegExStr;\r
-\r
-  /// Entries in this vector represent a substitution of a string variable or\r
-  /// an expression in the RegExStr regex at match time. For example, in the\r
-  /// case of a CHECK directive with the pattern "foo[[bar]]baz[[#N+1]]",\r
-  /// RegExStr will contain "foobaz" and we'll get two entries in this vector\r
-  /// that tells us to insert the value of string variable "bar" at offset 3\r
-  /// and the value of expression "N+1" at offset 6.\r
-  std::vector<FileCheckSubstitution *> Substitutions;\r
-\r
-  /// Maps names of string variables defined in a pattern to the number of\r
-  /// their parenthesis group in RegExStr capturing their last definition.\r
-  ///\r
-  /// E.g. for the pattern "foo[[bar:.*]]baz([[bar]][[QUUX]][[bar:.*]])",\r
-  /// RegExStr will be "foo(.*)baz(\1<quux value>(.*))" where <quux value> is\r
-  /// the value captured for QUUX on the earlier line where it was defined, and\r
-  /// VariableDefs will map "bar" to the third parenthesis group which captures\r
-  /// the second definition of "bar".\r
-  ///\r
-  /// Note: uses std::map rather than StringMap to be able to get the key when\r
-  /// iterating over values.\r
-  std::map<StringRef, unsigned> VariableDefs;\r
-\r
-  /// Structure representing the definition of a numeric variable in a pattern.\r
-  /// It holds the pointer to the class representing the numeric variable whose\r
-  /// value is being defined and the number of the parenthesis group in\r
-  /// RegExStr to capture that value.\r
-  struct FileCheckNumericVariableMatch {\r
-    /// Pointer to class representing the numeric variable whose value is being\r
-    /// defined.\r
-    FileCheckNumericVariable *DefinedNumericVariable;\r
-\r
-    /// Number of the parenthesis group in RegExStr that captures the value of\r
-    /// this numeric variable definition.\r
-    unsigned CaptureParenGroup;\r
-  };\r
-\r
-  /// Holds the number of the parenthesis group in RegExStr and pointer to the\r
-  /// corresponding FileCheckNumericVariable class instance of all numeric\r
-  /// variable definitions. Used to set the matched value of all those\r
-  /// variables.\r
-  StringMap<FileCheckNumericVariableMatch> NumericVariableDefs;\r
-\r
-  /// Pointer to a class instance holding the global state shared by all\r
-  /// patterns:\r
-  /// - separate tables with the values of live string and numeric variables\r
-  ///   respectively at the start of any given CHECK line;\r
-  /// - table holding whether a string variable has been defined at any given\r
-  ///   point during the parsing phase.\r
-  FileCheckPatternContext *Context;\r
-\r
-  Check::FileCheckType CheckTy;\r
-\r
-  /// Line number for this CHECK pattern or None if it is an implicit pattern.\r
-  /// Used to determine whether a variable definition is made on an earlier\r
-  /// line to the one with this CHECK.\r
-  Optional<size_t> LineNumber;\r
-\r
-  /// Ignore case while matching if set to true.\r
-  bool IgnoreCase = false;\r
-\r
-public:\r
-  FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context,\r
-                   Optional<size_t> Line = None)\r
-      : Context(Context), CheckTy(Ty), LineNumber(Line) {}\r
-\r
-  /// \returns the location in source code.\r
-  SMLoc getLoc() const { return PatternLoc; }\r
-\r
-  /// \returns the pointer to the global state for all patterns in this\r
-  /// FileCheck instance.\r
-  FileCheckPatternContext *getContext() const { return Context; }\r
-\r
-  /// \returns whether \p C is a valid first character for a variable name.\r
-  static bool isValidVarNameStart(char C);\r
-\r
-  /// Parsing information about a variable.\r
-  struct VariableProperties {\r
-    StringRef Name;\r
-    bool IsPseudo;\r
-  };\r
-\r
-  /// Parses the string at the start of \p Str for a variable name. \returns\r
-  /// a VariableProperties structure holding the variable name and whether it\r
-  /// is the name of a pseudo variable, or an error holding a diagnostic\r
-  /// against \p SM if parsing fail. If parsing was successful, also strips\r
-  /// \p Str from the variable name.\r
-  static Expected<VariableProperties> parseVariable(StringRef &Str,\r
-                                                    const SourceMgr &SM);\r
-  /// Parses \p Expr for a numeric substitution block at line \p LineNumber,\r
-  /// or before input is parsed if \p LineNumber is None. Parameter\r
-  /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE\r
-  /// expression and \p Context points to the class instance holding the live\r
-  /// string and numeric variables. \returns a pointer to the class instance\r
-  /// representing the AST of the expression whose value must be substitued, or\r
-  /// an error holding a diagnostic against \p SM if parsing fails. If\r
-  /// substitution was successful, sets \p DefinedNumericVariable to point to\r
-  /// the class representing the numeric variable defined in this numeric\r
-  /// substitution block, or None if this block does not define any variable.\r
-  static Expected<std::unique_ptr<FileCheckExpressionAST>>\r
-  parseNumericSubstitutionBlock(\r
-      StringRef Expr,\r
-      Optional<FileCheckNumericVariable *> &DefinedNumericVariable,\r
-      bool IsLegacyLineExpr, Optional<size_t> LineNumber,\r
-      FileCheckPatternContext *Context, const SourceMgr &SM);\r
-  /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern\r
-  /// instance accordingly.\r
-  ///\r
-  /// \p Prefix provides which prefix is being matched, \p Req describes the\r
-  /// global options that influence the parsing such as whitespace\r
-  /// canonicalization, \p SM provides the SourceMgr used for error reports.\r
-  /// \returns true in case of an error, false otherwise.\r
-  bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,\r
-                    const FileCheckRequest &Req);\r
-  /// Matches the pattern string against the input buffer \p Buffer\r
-  ///\r
-  /// \returns the position that is matched or an error indicating why matching\r
-  /// failed. If there is a match, updates \p MatchLen with the size of the\r
-  /// matched string.\r
-  ///\r
-  /// The GlobalVariableTable StringMap in the FileCheckPatternContext class\r
-  /// instance provides the current values of FileCheck string variables and\r
-  /// is updated if this match defines new values. Likewise, the\r
-  /// GlobalNumericVariableTable StringMap in the same class provides the\r
-  /// current values of FileCheck numeric variables and is updated if this\r
-  /// match defines new numeric values.\r
-  Expected<size_t> match(StringRef Buffer, size_t &MatchLen,\r
-                         const SourceMgr &SM) const;\r
-  /// Prints the value of successful substitutions or the name of the undefined\r
-  /// string or numeric variables preventing a successful substitution.\r
-  void printSubstitutions(const SourceMgr &SM, StringRef Buffer,\r
-                          SMRange MatchRange = None) const;\r
-  void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,\r
-                       std::vector<FileCheckDiag> *Diags) const;\r
-\r
-  bool hasVariable() const {\r
-    return !(Substitutions.empty() && VariableDefs.empty());\r
-  }\r
-\r
-  Check::FileCheckType getCheckTy() const { return CheckTy; }\r
-\r
-  int getCount() const { return CheckTy.getCount(); }\r
-\r
-private:\r
-  bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);\r
-  void AddBackrefToRegEx(unsigned BackrefNum);\r
-  /// Computes an arbitrary estimate for the quality of matching this pattern\r
-  /// at the start of \p Buffer; a distance of zero should correspond to a\r
-  /// perfect match.\r
-  unsigned computeMatchDistance(StringRef Buffer) const;\r
-  /// Finds the closing sequence of a regex variable usage or definition.\r
-  ///\r
-  /// \p Str has to point in the beginning of the definition (right after the\r
-  /// opening sequence). \p SM holds the SourceMgr used for error repporting.\r
-  ///  \returns the offset of the closing sequence within Str, or npos if it\r
-  /// was not found.\r
-  size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);\r
-\r
-  /// Parses \p Expr for the name of a numeric variable to be defined at line\r
-  /// \p LineNumber, or before input is parsed if \p LineNumber is None.\r
-  /// \returns a pointer to the class instance representing that variable,\r
-  /// creating it if needed, or an error holding a diagnostic against \p SM\r
-  /// should defining such a variable be invalid.\r
-  static Expected<FileCheckNumericVariable *> parseNumericVariableDefinition(\r
-      StringRef &Expr, FileCheckPatternContext *Context,\r
-      Optional<size_t> LineNumber, const SourceMgr &SM);\r
-  /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use\r
-  /// at line \p LineNumber, or before input is parsed if \p LineNumber is\r
-  /// None. Parameter \p Context points to the class instance holding the live\r
-  /// string and numeric variables. \returns the pointer to the class instance\r
-  /// representing that variable if successful, or an error holding a\r
-  /// diagnostic against \p SM otherwise.\r
-  static Expected<std::unique_ptr<FileCheckNumericVariableUse>>\r
-  parseNumericVariableUse(StringRef Name, bool IsPseudo,\r
-                          Optional<size_t> LineNumber,\r
-                          FileCheckPatternContext *Context,\r
-                          const SourceMgr &SM);\r
-  enum class AllowedOperand { LineVar, Literal, Any };\r
-  /// Parses \p Expr for use of a numeric operand at line \p LineNumber, or\r
-  /// before input is parsed if \p LineNumber is None. Accepts both literal\r
-  /// values and numeric variables, depending on the value of \p AO. Parameter\r
-  /// \p Context points to the class instance holding the live string and\r
-  /// numeric variables. \returns the class representing that operand in the\r
-  /// AST of the expression or an error holding a diagnostic against \p SM\r
-  /// otherwise.\r
-  static Expected<std::unique_ptr<FileCheckExpressionAST>>\r
-  parseNumericOperand(StringRef &Expr, AllowedOperand AO,\r
-                      Optional<size_t> LineNumber,\r
-                      FileCheckPatternContext *Context, const SourceMgr &SM);\r
-  /// Parses \p Expr for a binary operation at line \p LineNumber, or before\r
-  /// input is parsed if \p LineNumber is None. The left operand of this binary\r
-  /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether\r
-  /// we are parsing a legacy @LINE expression. Parameter \p Context points to\r
-  /// the class instance holding the live string and numeric variables.\r
-  /// \returns the class representing the binary operation in the AST of the\r
-  /// expression, or an error holding a diagnostic against \p SM otherwise.\r
-  static Expected<std::unique_ptr<FileCheckExpressionAST>>\r
-  parseBinop(StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,\r
-             bool IsLegacyLineExpr, Optional<size_t> LineNumber,\r
-             FileCheckPatternContext *Context, const SourceMgr &SM);\r
-};\r
-\r
-//===----------------------------------------------------------------------===//\r
-// Check Strings.\r
-//===----------------------------------------------------------------------===//\r
-\r
-/// A check that we found in the input file.\r
-struct FileCheckString {\r
-  /// The pattern to match.\r
-  FileCheckPattern Pat;\r
-\r
-  /// Which prefix name this check matched.\r
-  StringRef Prefix;\r
-\r
-  /// The location in the match file that the check string was specified.\r
-  SMLoc Loc;\r
-\r
-  /// All of the strings that are disallowed from occurring between this match\r
-  /// string and the previous one (or start of file).\r
-  std::vector<FileCheckPattern> DagNotStrings;\r
-\r
-  FileCheckString(const FileCheckPattern &P, StringRef S, SMLoc L)\r
-      : Pat(P), Prefix(S), Loc(L) {}\r
-\r
-  /// Matches check string and its "not strings" and/or "dag strings".\r
-  size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,\r
-               size_t &MatchLen, FileCheckRequest &Req,\r
-               std::vector<FileCheckDiag> *Diags) const;\r
-\r
-  /// Verifies that there is a single line in the given \p Buffer. Errors are\r
-  /// reported against \p SM.\r
-  bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;\r
-  /// Verifies that there is no newline in the given \p Buffer. Errors are\r
-  /// reported against \p SM.\r
-  bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;\r
-  /// Verifies that none of the strings in \p NotStrings are found in the given\r
-  /// \p Buffer. Errors are reported against \p SM and diagnostics recorded in\r
-  /// \p Diags according to the verbosity level set in \p Req.\r
-  bool CheckNot(const SourceMgr &SM, StringRef Buffer,\r
-                const std::vector<const FileCheckPattern *> &NotStrings,\r
-                const FileCheckRequest &Req,\r
-                std::vector<FileCheckDiag> *Diags) const;\r
-  /// Matches "dag strings" and their mixed "not strings".\r
-  size_t CheckDag(const SourceMgr &SM, StringRef Buffer,\r
-                  std::vector<const FileCheckPattern *> &NotStrings,\r
-                  const FileCheckRequest &Req,\r
-                  std::vector<FileCheckDiag> *Diags) const;\r
-};\r
-\r
-} // namespace llvm\r
-\r
-#endif\r
+//===-- 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
diff --git a/test/FileCheck/check-ignore-case.txt b/test/FileCheck/check-ignore-case.txt
deleted file mode 100644 (file)
index 8721c3f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-## Check that a full line is matched case insensitively.\r
-# RUN: FileCheck --ignore-case --match-full-lines --check-prefix=FULL --input-file=%s %s\r
-\r
-## Check that a regular expression matches case insensitively.\r
-# RUN: FileCheck --ignore-case --check-prefix=REGEX --input-file=%s %s\r
-\r
-## Check that a pattern from command line matches case insensitively.\r
-# RUN: FileCheck --ignore-case --check-prefix=PAT --DPATTERN="THIS is the" --input-file=%s %s\r
-\r
-## Check that COUNT and NEXT work case insensitively.\r
-# RUN: FileCheck --ignore-case --check-prefix=CNT --input-file=%s %s\r
-\r
-## Check that match on same line works case insensitively.\r
-# RUN: FileCheck --ignore-case --check-prefix=LINE --input-file=%s %s\r
-\r
-## Check that option --implicit-not works case insensitively.\r
-# RUN: sed '/^#/d' %s | FileCheck --implicit-check-not=sTrInG %s\r
-# RUN: sed '/^#/d' %s | not FileCheck --ignore-case --implicit-check-not=sTrInG %s 2>&1 | FileCheck --check-prefix=ERROR %s\r
-\r
-this is the STRING to be matched\r
-\r
-# FULL: tHis iS The String TO be matched\r
-# REGEX: s{{TRing}}\r
-# PAT: [[PATTERN]] string\r
-\r
-Loop 1\r
-lOop 2\r
-loOp 3\r
-looP 4\r
-loop 5\r
-LOOP 6\r
-BREAK\r
-\r
-# CNT-COUNT-6: LOop {{[0-9]}}\r
-# CNT-NOT: loop\r
-# CNT-NEXT: break\r
-\r
-One Line To Match\r
-\r
-# LINE: {{o}}ne line\r
-# LINE-SAME: {{t}}o match\r
-\r
-# ERROR: command line:1:{{[0-9]+]}}: error: CHECK-NOT: excluded string found in input\r
-# ERROR-NEXT: -implicit-check-not='sTrInG'\r
-# ERROR: note: found here\r
index 4d2cd1930d681d6d29c0ccf3cd5c87348e9a9dad..8718be28ac9978b7b88b58859aa1ee63c66a3e05 100644 (file)
-//===- FileCheck.cpp - Check that File's Contents match what is expected --===//\r
-//\r
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.\r
-// See https://llvm.org/LICENSE.txt for license information.\r
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\r
-//\r
-//===----------------------------------------------------------------------===//\r
-//\r
-// FileCheck does a line-by line check of a file that validates whether it\r
-// contains the expected content.  This is useful for regression tests etc.\r
-//\r
-// This program exits with an exit status of 2 on error, exit status of 0 if\r
-// the file matched the expected contents, and exit status of 1 if it did not\r
-// contain the expected contents.\r
-//\r
-//===----------------------------------------------------------------------===//\r
-\r
-#include "llvm/Support/CommandLine.h"\r
-#include "llvm/Support/InitLLVM.h"\r
-#include "llvm/Support/Process.h"\r
-#include "llvm/Support/WithColor.h"\r
-#include "llvm/Support/raw_ostream.h"\r
-#include "llvm/Support/FileCheck.h"\r
-#include <cmath>\r
-using namespace llvm;\r
-\r
-static cl::extrahelp FileCheckOptsEnv(\r
-    "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"\r
-    "from the command line.\n");\r
-\r
-static cl::opt<std::string>\r
-    CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);\r
-\r
-static cl::opt<std::string>\r
-    InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),\r
-                  cl::init("-"), cl::value_desc("filename"));\r
-\r
-static cl::list<std::string> CheckPrefixes(\r
-    "check-prefix",\r
-    cl::desc("Prefix to use from check file (defaults to 'CHECK')"));\r
-static cl::alias CheckPrefixesAlias(\r
-    "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,\r
-    cl::NotHidden,\r
-    cl::desc(\r
-        "Alias for -check-prefix permitting multiple comma separated values"));\r
-\r
-static cl::opt<bool> NoCanonicalizeWhiteSpace(\r
-    "strict-whitespace",\r
-    cl::desc("Do not treat all horizontal whitespace as equivalent"));\r
-\r
-static cl::opt<bool> IgnoreCase(\r
-    "ignore-case",\r
-    cl::desc("Use case-insensitive matching"));\r
-\r
-static cl::list<std::string> ImplicitCheckNot(\r
-    "implicit-check-not",\r
-    cl::desc("Add an implicit negative check with this pattern to every\n"\r
-             "positive check. This can be used to ensure that no instances of\n"\r
-             "this pattern occur which are not matched by a positive pattern"),\r
-    cl::value_desc("pattern"));\r
-\r
-static cl::list<std::string>\r
-    GlobalDefines("D", cl::AlwaysPrefix,\r
-                  cl::desc("Define a variable to be used in capture patterns."),\r
-                  cl::value_desc("VAR=VALUE"));\r
-\r
-static cl::opt<bool> AllowEmptyInput(\r
-    "allow-empty", cl::init(false),\r
-    cl::desc("Allow the input file to be empty. This is useful when making\n"\r
-             "checks that some error message does not occur, for example."));\r
-\r
-static cl::opt<bool> MatchFullLines(\r
-    "match-full-lines", cl::init(false),\r
-    cl::desc("Require all positive matches to cover an entire input line.\n"\r
-             "Allows leading and trailing whitespace if --strict-whitespace\n"\r
-             "is not also passed."));\r
-\r
-static cl::opt<bool> EnableVarScope(\r
-    "enable-var-scope", cl::init(false),\r
-    cl::desc("Enables scope for regex variables. Variables with names that\n"\r
-             "do not start with '$' will be reset at the beginning of\n"\r
-             "each CHECK-LABEL block."));\r
-\r
-static cl::opt<bool> AllowDeprecatedDagOverlap(\r
-    "allow-deprecated-dag-overlap", cl::init(false),\r
-    cl::desc("Enable overlapping among matches in a group of consecutive\n"\r
-             "CHECK-DAG directives.  This option is deprecated and is only\n"\r
-             "provided for convenience as old tests are migrated to the new\n"\r
-             "non-overlapping CHECK-DAG implementation.\n"));\r
-\r
-static cl::opt<bool> Verbose(\r
-    "v", cl::init(false),\r
-    cl::desc("Print directive pattern matches, or add them to the input dump\n"\r
-             "if enabled.\n"));\r
-\r
-static cl::opt<bool> VerboseVerbose(\r
-    "vv", cl::init(false),\r
-    cl::desc("Print information helpful in diagnosing internal FileCheck\n"\r
-             "issues, or add it to the input dump if enabled.  Implies\n"\r
-             "-v.\n"));\r
-static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";\r
-\r
-static cl::opt<bool> DumpInputOnFailure(\r
-    "dump-input-on-failure",\r
-    cl::init(std::getenv(DumpInputEnv) && *std::getenv(DumpInputEnv)),\r
-    cl::desc("Dump original input to stderr before failing.\n"\r
-             "The value can be also controlled using\n"\r
-             "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"\r
-             "This option is deprecated in favor of -dump-input=fail.\n"));\r
-\r
-enum DumpInputValue {\r
-  DumpInputDefault,\r
-  DumpInputHelp,\r
-  DumpInputNever,\r
-  DumpInputFail,\r
-  DumpInputAlways\r
-};\r
-\r
-static cl::opt<DumpInputValue> DumpInput(\r
-    "dump-input", cl::init(DumpInputDefault),\r
-    cl::desc("Dump input to stderr, adding annotations representing\n"\r
-             " currently enabled diagnostics\n"),\r
-    cl::value_desc("mode"),\r
-    cl::values(clEnumValN(DumpInputHelp, "help",\r
-                          "Explain dump format and quit"),\r
-               clEnumValN(DumpInputNever, "never", "Never dump input"),\r
-               clEnumValN(DumpInputFail, "fail", "Dump input on failure"),\r
-               clEnumValN(DumpInputAlways, "always", "Always dump input")));\r
-\r
-typedef cl::list<std::string>::const_iterator prefix_iterator;\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-static void DumpCommandLine(int argc, char **argv) {\r
-  errs() << "FileCheck command line: ";\r
-  for (int I = 0; I < argc; I++)\r
-    errs() << " " << argv[I];\r
-  errs() << "\n";\r
-}\r
-\r
-struct MarkerStyle {\r
-  /// The starting char (before tildes) for marking the line.\r
-  char Lead;\r
-  /// What color to use for this annotation.\r
-  raw_ostream::Colors Color;\r
-  /// A note to follow the marker, or empty string if none.\r
-  std::string Note;\r
-  MarkerStyle() {}\r
-  MarkerStyle(char Lead, raw_ostream::Colors Color,\r
-              const std::string &Note = "")\r
-      : Lead(Lead), Color(Color), Note(Note) {}\r
-};\r
-\r
-static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {\r
-  switch (MatchTy) {\r
-  case FileCheckDiag::MatchFoundAndExpected:\r
-    return MarkerStyle('^', raw_ostream::GREEN);\r
-  case FileCheckDiag::MatchFoundButExcluded:\r
-    return MarkerStyle('!', raw_ostream::RED, "error: no match expected");\r
-  case FileCheckDiag::MatchFoundButWrongLine:\r
-    return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");\r
-  case FileCheckDiag::MatchFoundButDiscarded:\r
-    return MarkerStyle('!', raw_ostream::CYAN,\r
-                       "discard: overlaps earlier match");\r
-  case FileCheckDiag::MatchNoneAndExcluded:\r
-    return MarkerStyle('X', raw_ostream::GREEN);\r
-  case FileCheckDiag::MatchNoneButExpected:\r
-    return MarkerStyle('X', raw_ostream::RED, "error: no match found");\r
-  case FileCheckDiag::MatchFuzzy:\r
-    return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");\r
-  }\r
-  llvm_unreachable_internal("unexpected match type");\r
-}\r
-\r
-static void DumpInputAnnotationHelp(raw_ostream &OS) {\r
-  OS << "The following description was requested by -dump-input=help to\n"\r
-     << "explain the input annotations printed by -dump-input=always and\n"\r
-     << "-dump-input=fail:\n\n";\r
-\r
-  // Labels for input lines.\r
-  OS << "  - ";\r
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";\r
-  OS << "     labels line number L of the input file\n";\r
-\r
-  // Labels for annotation lines.\r
-  OS << "  - ";\r
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";\r
-  OS << "    labels the only match result for a pattern of type T from "\r
-     << "line L of\n"\r
-     << "           the check file\n";\r
-  OS << "  - ";\r
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";\r
-  OS << "  labels the Nth match result for a pattern of type T from line "\r
-     << "L of\n"\r
-     << "           the check file\n";\r
-\r
-  // Markers on annotation lines.\r
-  OS << "  - ";\r
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";\r
-  OS << "    marks good match (reported if -v)\n"\r
-     << "  - ";\r
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";\r
-  OS << "    marks bad match, such as:\n"\r
-     << "           - CHECK-NEXT on same line as previous match (error)\n"\r
-     << "           - CHECK-NOT found (error)\n"\r
-     << "           - CHECK-DAG overlapping match (discarded, reported if "\r
-     << "-vv)\n"\r
-     << "  - ";\r
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";\r
-  OS << "    marks search range when no match is found, such as:\n"\r
-     << "           - CHECK-NEXT not found (error)\n"\r
-     << "           - CHECK-NOT not found (success, reported if -vv)\n"\r
-     << "           - CHECK-DAG not found after discarded matches (error)\n"\r
-     << "  - ";\r
-  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";\r
-  OS << "      marks fuzzy match when no match is found\n";\r
-\r
-  // Colors.\r
-  OS << "  - colors ";\r
-  WithColor(OS, raw_ostream::GREEN, true) << "success";\r
-  OS << ", ";\r
-  WithColor(OS, raw_ostream::RED, true) << "error";\r
-  OS << ", ";\r
-  WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";\r
-  OS << ", ";\r
-  WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";\r
-  OS << ", ";\r
-  WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";\r
-  OS << "\n\n"\r
-     << "If you are not seeing color above or in input dumps, try: -color\n";\r
-}\r
-\r
-/// An annotation for a single input line.\r
-struct InputAnnotation {\r
-  /// The check file line (one-origin indexing) where the directive that\r
-  /// produced this annotation is located.\r
-  unsigned CheckLine;\r
-  /// The index of the match result for this check.\r
-  unsigned CheckDiagIndex;\r
-  /// The label for this annotation.\r
-  std::string Label;\r
-  /// What input line (one-origin indexing) this annotation marks.  This might\r
-  /// be different from the starting line of the original diagnostic if this is\r
-  /// a non-initial fragment of a diagnostic that has been broken across\r
-  /// multiple lines.\r
-  unsigned InputLine;\r
-  /// The column range (one-origin indexing, open end) in which to to mark the\r
-  /// input line.  If InputEndCol is UINT_MAX, treat it as the last column\r
-  /// before the newline.\r
-  unsigned InputStartCol, InputEndCol;\r
-  /// The marker to use.\r
-  MarkerStyle Marker;\r
-  /// Whether this annotation represents a good match for an expected pattern.\r
-  bool FoundAndExpectedMatch;\r
-};\r
-\r
-/// Get an abbreviation for the check type.\r
-std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {\r
-  switch (Ty) {\r
-  case Check::CheckPlain:\r
-    if (Ty.getCount() > 1)\r
-      return "count";\r
-    return "check";\r
-  case Check::CheckNext:\r
-    return "next";\r
-  case Check::CheckSame:\r
-    return "same";\r
-  case Check::CheckNot:\r
-    return "not";\r
-  case Check::CheckDAG:\r
-    return "dag";\r
-  case Check::CheckLabel:\r
-    return "label";\r
-  case Check::CheckEmpty:\r
-    return "empty";\r
-  case Check::CheckEOF:\r
-    return "eof";\r
-  case Check::CheckBadNot:\r
-    return "bad-not";\r
-  case Check::CheckBadCount:\r
-    return "bad-count";\r
-  case Check::CheckNone:\r
-    llvm_unreachable("invalid FileCheckType");\r
-  }\r
-  llvm_unreachable("unknown FileCheckType");\r
-}\r
-\r
-static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,\r
-                                  std::vector<InputAnnotation> &Annotations,\r
-                                  unsigned &LabelWidth) {\r
-  // How many diagnostics has the current check seen so far?\r
-  unsigned CheckDiagCount = 0;\r
-  // What's the widest label?\r
-  LabelWidth = 0;\r
-  for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;\r
-       ++DiagItr) {\r
-    InputAnnotation A;\r
-\r
-    // Build label, which uniquely identifies this check result.\r
-    A.CheckLine = DiagItr->CheckLine;\r
-    llvm::raw_string_ostream Label(A.Label);\r
-    Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"\r
-          << DiagItr->CheckLine;\r
-    A.CheckDiagIndex = UINT_MAX;\r
-    auto DiagNext = std::next(DiagItr);\r
-    if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&\r
-        DiagItr->CheckLine == DiagNext->CheckLine)\r
-      A.CheckDiagIndex = CheckDiagCount++;\r
-    else if (CheckDiagCount) {\r
-      A.CheckDiagIndex = CheckDiagCount;\r
-      CheckDiagCount = 0;\r
-    }\r
-    if (A.CheckDiagIndex != UINT_MAX)\r
-      Label << "'" << A.CheckDiagIndex;\r
-    else\r
-      A.CheckDiagIndex = 0;\r
-    Label.flush();\r
-    LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());\r
-\r
-    A.Marker = GetMarker(DiagItr->MatchTy);\r
-    A.FoundAndExpectedMatch =\r
-        DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;\r
-\r
-    // Compute the mark location, and break annotation into multiple\r
-    // annotations if it spans multiple lines.\r
-    A.InputLine = DiagItr->InputStartLine;\r
-    A.InputStartCol = DiagItr->InputStartCol;\r
-    if (DiagItr->InputStartLine == DiagItr->InputEndLine) {\r
-      // Sometimes ranges are empty in order to indicate a specific point, but\r
-      // that would mean nothing would be marked, so adjust the range to\r
-      // include the following character.\r
-      A.InputEndCol =\r
-          std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);\r
-      Annotations.push_back(A);\r
-    } else {\r
-      assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&\r
-             "expected input range not to be inverted");\r
-      A.InputEndCol = UINT_MAX;\r
-      Annotations.push_back(A);\r
-      for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;\r
-           L <= E; ++L) {\r
-        // If a range ends before the first column on a line, then it has no\r
-        // characters on that line, so there's nothing to render.\r
-        if (DiagItr->InputEndCol == 1 && L == E)\r
-          break;\r
-        InputAnnotation B;\r
-        B.CheckLine = A.CheckLine;\r
-        B.CheckDiagIndex = A.CheckDiagIndex;\r
-        B.Label = A.Label;\r
-        B.InputLine = L;\r
-        B.Marker = A.Marker;\r
-        B.Marker.Lead = '~';\r
-        B.Marker.Note = "";\r
-        B.InputStartCol = 1;\r
-        if (L != E)\r
-          B.InputEndCol = UINT_MAX;\r
-        else\r
-          B.InputEndCol = DiagItr->InputEndCol;\r
-        B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;\r
-        Annotations.push_back(B);\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
-static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,\r
-                               StringRef InputFileText,\r
-                               std::vector<InputAnnotation> &Annotations,\r
-                               unsigned LabelWidth) {\r
-  OS << "Full input was:\n<<<<<<\n";\r
-\r
-  // Sort annotations.\r
-  //\r
-  // First, sort in the order of input lines to make it easier to find relevant\r
-  // annotations while iterating input lines in the implementation below.\r
-  // FileCheck diagnostics are not always reported and recorded in the order of\r
-  // input lines due to, for example, CHECK-DAG and CHECK-NOT.\r
-  //\r
-  // Second, for annotations for the same input line, sort in the order of the\r
-  // FileCheck directive's line in the check file (where there's at most one\r
-  // directive per line) and then by the index of the match result for that\r
-  // directive.  The rationale of this choice is that, for any input line, this\r
-  // sort establishes a total order of annotations that, with respect to match\r
-  // results, is consistent across multiple lines, thus making match results\r
-  // easier to track from one line to the next when they span multiple lines.\r
-  std::sort(Annotations.begin(), Annotations.end(),\r
-            [](const InputAnnotation &A, const InputAnnotation &B) {\r
-              if (A.InputLine != B.InputLine)\r
-                return A.InputLine < B.InputLine;\r
-              if (A.CheckLine != B.CheckLine)\r
-                return A.CheckLine < B.CheckLine;\r
-              // FIXME: Sometimes CHECK-LABEL reports its match twice with\r
-              // other diagnostics in between, and then diag index incrementing\r
-              // fails to work properly, and then this assert fails.  We should\r
-              // suppress one of those diagnostics or do a better job of\r
-              // computing this index.  For now, we just produce a redundant\r
-              // CHECK-LABEL annotation.\r
-              // assert(A.CheckDiagIndex != B.CheckDiagIndex &&\r
-              //        "expected diagnostic indices to be unique within a "\r
-              //        " check line");\r
-              return A.CheckDiagIndex < B.CheckDiagIndex;\r
-            });\r
-\r
-  // Compute the width of the label column.\r
-  const unsigned char *InputFilePtr = InputFileText.bytes_begin(),\r
-                      *InputFileEnd = InputFileText.bytes_end();\r
-  unsigned LineCount = InputFileText.count('\n');\r
-  if (InputFileEnd[-1] != '\n')\r
-    ++LineCount;\r
-  unsigned LineNoWidth = std::log10(LineCount) + 1;\r
-  // +3 below adds spaces (1) to the left of the (right-aligned) line numbers\r
-  // on input lines and (2) to the right of the (left-aligned) labels on\r
-  // annotation lines so that input lines and annotation lines are more\r
-  // visually distinct.  For example, the spaces on the annotation lines ensure\r
-  // that input line numbers and check directive line numbers never align\r
-  // horizontally.  Those line numbers might not even be for the same file.\r
-  // One space would be enough to achieve that, but more makes it even easier\r
-  // to see.\r
-  LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;\r
-\r
-  // Print annotated input lines.\r
-  auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();\r
-  for (unsigned Line = 1;\r
-       InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;\r
-       ++Line) {\r
-    const unsigned char *InputFileLine = InputFilePtr;\r
-\r
-    // Print right-aligned line number.\r
-    WithColor(OS, raw_ostream::BLACK, true)\r
-        << format_decimal(Line, LabelWidth) << ": ";\r
-\r
-    // For the case where -v and colors are enabled, find the annotations for\r
-    // good matches for expected patterns in order to highlight everything\r
-    // else in the line.  There are no such annotations if -v is disabled.\r
-    std::vector<InputAnnotation> FoundAndExpectedMatches;\r
-    if (Req.Verbose && WithColor(OS).colorsEnabled()) {\r
-      for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;\r
-           ++I) {\r
-        if (I->FoundAndExpectedMatch)\r
-          FoundAndExpectedMatches.push_back(*I);\r
-      }\r
-    }\r
-\r
-    // Print numbered line with highlighting where there are no matches for\r
-    // expected patterns.\r
-    bool Newline = false;\r
-    {\r
-      WithColor COS(OS);\r
-      bool InMatch = false;\r
-      if (Req.Verbose)\r
-        COS.changeColor(raw_ostream::CYAN, true, true);\r
-      for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {\r
-        bool WasInMatch = InMatch;\r
-        InMatch = false;\r
-        for (auto M : FoundAndExpectedMatches) {\r
-          if (M.InputStartCol <= Col && Col < M.InputEndCol) {\r
-            InMatch = true;\r
-            break;\r
-          }\r
-        }\r
-        if (!WasInMatch && InMatch)\r
-          COS.resetColor();\r
-        else if (WasInMatch && !InMatch)\r
-          COS.changeColor(raw_ostream::CYAN, true, true);\r
-        if (*InputFilePtr == '\n')\r
-          Newline = true;\r
-        else\r
-          COS << *InputFilePtr;\r
-        ++InputFilePtr;\r
-      }\r
-    }\r
-    OS << '\n';\r
-    unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;\r
-\r
-    // Print any annotations.\r
-    while (AnnotationItr != AnnotationEnd &&\r
-           AnnotationItr->InputLine == Line) {\r
-      WithColor COS(OS, AnnotationItr->Marker.Color, true);\r
-      // The two spaces below are where the ": " appears on input lines.\r
-      COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";\r
-      unsigned Col;\r
-      for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)\r
-        COS << ' ';\r
-      COS << AnnotationItr->Marker.Lead;\r
-      // If InputEndCol=UINT_MAX, stop at InputLineWidth.\r
-      for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;\r
-           ++Col)\r
-        COS << '~';\r
-      const std::string &Note = AnnotationItr->Marker.Note;\r
-      if (!Note.empty()) {\r
-        // Put the note at the end of the input line.  If we were to instead\r
-        // put the note right after the marker, subsequent annotations for the\r
-        // same input line might appear to mark this note instead of the input\r
-        // line.\r
-        for (; Col <= InputLineWidth; ++Col)\r
-          COS << ' ';\r
-        COS << ' ' << Note;\r
-      }\r
-      COS << '\n';\r
-      ++AnnotationItr;\r
-    }\r
-  }\r
-\r
-  OS << ">>>>>>\n";\r
-}\r
-\r
-int main(int argc, char **argv) {\r
-  // Enable use of ANSI color codes because FileCheck is using them to\r
-  // highlight text.\r
-  llvm::sys::Process::UseANSIEscapeCodes(true);\r
-\r
-  InitLLVM X(argc, argv);\r
-  cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,\r
-                              "FILECHECK_OPTS");\r
-  if (DumpInput == DumpInputHelp) {\r
-    DumpInputAnnotationHelp(outs());\r
-    return 0;\r
-  }\r
-  if (CheckFilename.empty()) {\r
-    errs() << "<check-file> not specified\n";\r
-    return 2;\r
-  }\r
-\r
-  FileCheckRequest Req;\r
-  for (auto Prefix : CheckPrefixes)\r
-    Req.CheckPrefixes.push_back(Prefix);\r
-\r
-  for (auto CheckNot : ImplicitCheckNot)\r
-    Req.ImplicitCheckNot.push_back(CheckNot);\r
-\r
-  bool GlobalDefineError = false;\r
-  for (auto G : GlobalDefines) {\r
-    size_t EqIdx = G.find('=');\r
-    if (EqIdx == std::string::npos) {\r
-      errs() << "Missing equal sign in command-line definition '-D" << G\r
-             << "'\n";\r
-      GlobalDefineError = true;\r
-      continue;\r
-    }\r
-    if (EqIdx == 0) {\r
-      errs() << "Missing variable name in command-line definition '-D" << G\r
-             << "'\n";\r
-      GlobalDefineError = true;\r
-      continue;\r
-    }\r
-    Req.GlobalDefines.push_back(G);\r
-  }\r
-  if (GlobalDefineError)\r
-    return 2;\r
-\r
-  Req.AllowEmptyInput = AllowEmptyInput;\r
-  Req.EnableVarScope = EnableVarScope;\r
-  Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;\r
-  Req.Verbose = Verbose;\r
-  Req.VerboseVerbose = VerboseVerbose;\r
-  Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;\r
-  Req.MatchFullLines = MatchFullLines;\r
-  Req.IgnoreCase = IgnoreCase;\r
-\r
-  if (VerboseVerbose)\r
-    Req.Verbose = true;\r
-\r
-  FileCheck FC(Req);\r
-  if (!FC.ValidateCheckPrefixes()) {\r
-    errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "\r
-              "start with a letter and contain only alphanumeric characters, "\r
-              "hyphens and underscores\n";\r
-    return 2;\r
-  }\r
-\r
-  Regex PrefixRE = FC.buildCheckPrefixRegex();\r
-  std::string REError;\r
-  if (!PrefixRE.isValid(REError)) {\r
-    errs() << "Unable to combine check-prefix strings into a prefix regular "\r
-              "expression! This is likely a bug in FileCheck's verification of "\r
-              "the check-prefix strings. Regular expression parsing failed "\r
-              "with the following error: "\r
-           << REError << "\n";\r
-    return 2;\r
-  }\r
-\r
-  SourceMgr SM;\r
-\r
-  // Read the expected strings from the check file.\r
-  ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =\r
-      MemoryBuffer::getFileOrSTDIN(CheckFilename);\r
-  if (std::error_code EC = CheckFileOrErr.getError()) {\r
-    errs() << "Could not open check file '" << CheckFilename\r
-           << "': " << EC.message() << '\n';\r
-    return 2;\r
-  }\r
-  MemoryBuffer &CheckFile = *CheckFileOrErr.get();\r
-\r
-  SmallString<4096> CheckFileBuffer;\r
-  StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);\r
-\r
-  SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(\r
-                            CheckFileText, CheckFile.getBufferIdentifier()),\r
-                        SMLoc());\r
-\r
-  if (FC.readCheckFile(SM, CheckFileText, PrefixRE))\r
-    return 2;\r
-\r
-  // Open the file to check and add it to SourceMgr.\r
-  ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =\r
-      MemoryBuffer::getFileOrSTDIN(InputFilename);\r
-  if (std::error_code EC = InputFileOrErr.getError()) {\r
-    errs() << "Could not open input file '" << InputFilename\r
-           << "': " << EC.message() << '\n';\r
-    return 2;\r
-  }\r
-  MemoryBuffer &InputFile = *InputFileOrErr.get();\r
-\r
-  if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {\r
-    errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";\r
-    DumpCommandLine(argc, argv);\r
-    return 2;\r
-  }\r
-\r
-  SmallString<4096> InputFileBuffer;\r
-  StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);\r
-\r
-  SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(\r
-                            InputFileText, InputFile.getBufferIdentifier()),\r
-                        SMLoc());\r
-\r
-  if (DumpInput == DumpInputDefault)\r
-    DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;\r
-\r
-  std::vector<FileCheckDiag> Diags;\r
-  int ExitCode = FC.checkInput(SM, InputFileText,\r
-                               DumpInput == DumpInputNever ? nullptr : &Diags)\r
-                     ? EXIT_SUCCESS\r
-                     : 1;\r
-  if (DumpInput == DumpInputAlways ||\r
-      (ExitCode == 1 && DumpInput == DumpInputFail)) {\r
-    errs() << "\n"\r
-           << "Input file: "\r
-           << (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())\r
-           << "\n"\r
-           << "Check file: " << CheckFilename << "\n"\r
-           << "\n"\r
-           << "-dump-input=help describes the format of the following dump.\n"\r
-           << "\n";\r
-    std::vector<InputAnnotation> Annotations;\r
-    unsigned LabelWidth;\r
-    BuildInputAnnotations(Diags, Annotations, LabelWidth);\r
-    DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);\r
-  }\r
-\r
-  return ExitCode;\r
-}\r
+//===- 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;
+}