xref: /llvm-project/llvm/utils/FileCheck/FileCheck.cpp (revision dfd2b6f07fc40a190335f580d8a965bbebfe94df)
1 //===- FileCheck.cpp - Check that File's Contents match what is expected --===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // FileCheck does a line-by line check of a file that validates whether it
10 // contains the expected content.  This is useful for regression tests etc.
11 //
12 // This program exits with an exit status of 2 on error, exit status of 0 if
13 // the file matched the expected contents, and exit status of 1 if it did not
14 // contain the expected contents.
15 //
16 //===----------------------------------------------------------------------===//
17 
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/InitLLVM.h"
20 #include "llvm/Support/Process.h"
21 #include "llvm/Support/WithColor.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "llvm/Support/FileCheck.h"
24 #include <cmath>
25 using namespace llvm;
26 
27 static cl::extrahelp FileCheckOptsEnv(
28     "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"
29     "from the command line.\n");
30 
31 static cl::opt<std::string>
32     CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
33 
34 static cl::opt<std::string>
35     InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
36                   cl::init("-"), cl::value_desc("filename"));
37 
38 static cl::list<std::string> CheckPrefixes(
39     "check-prefix",
40     cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
41 static cl::alias CheckPrefixesAlias(
42     "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
43     cl::NotHidden,
44     cl::desc(
45         "Alias for -check-prefix permitting multiple comma separated values"));
46 
47 static cl::opt<bool> NoCanonicalizeWhiteSpace(
48     "strict-whitespace",
49     cl::desc("Do not treat all horizontal whitespace as equivalent"));
50 
51 static cl::opt<bool> IgnoreCase(
52     "ignore-case",
53     cl::desc("Use case-insensitive matching"));
54 
55 static cl::list<std::string> ImplicitCheckNot(
56     "implicit-check-not",
57     cl::desc("Add an implicit negative check with this pattern to every\n"
58              "positive check. This can be used to ensure that no instances of\n"
59              "this pattern occur which are not matched by a positive pattern"),
60     cl::value_desc("pattern"));
61 
62 static cl::list<std::string>
63     GlobalDefines("D", cl::AlwaysPrefix,
64                   cl::desc("Define a variable to be used in capture patterns."),
65                   cl::value_desc("VAR=VALUE"));
66 
67 static cl::opt<bool> AllowEmptyInput(
68     "allow-empty", cl::init(false),
69     cl::desc("Allow the input file to be empty. This is useful when making\n"
70              "checks that some error message does not occur, for example."));
71 
72 static cl::opt<bool> MatchFullLines(
73     "match-full-lines", cl::init(false),
74     cl::desc("Require all positive matches to cover an entire input line.\n"
75              "Allows leading and trailing whitespace if --strict-whitespace\n"
76              "is not also passed."));
77 
78 static cl::opt<bool> EnableVarScope(
79     "enable-var-scope", cl::init(false),
80     cl::desc("Enables scope for regex variables. Variables with names that\n"
81              "do not start with '$' will be reset at the beginning of\n"
82              "each CHECK-LABEL block."));
83 
84 static cl::opt<bool> AllowDeprecatedDagOverlap(
85     "allow-deprecated-dag-overlap", cl::init(false),
86     cl::desc("Enable overlapping among matches in a group of consecutive\n"
87              "CHECK-DAG directives.  This option is deprecated and is only\n"
88              "provided for convenience as old tests are migrated to the new\n"
89              "non-overlapping CHECK-DAG implementation.\n"));
90 
91 static cl::opt<bool> Verbose(
92     "v", cl::init(false),
93     cl::desc("Print directive pattern matches, or add them to the input dump\n"
94              "if enabled.\n"));
95 
96 static cl::opt<bool> VerboseVerbose(
97     "vv", cl::init(false),
98     cl::desc("Print information helpful in diagnosing internal FileCheck\n"
99              "issues, or add it to the input dump if enabled.  Implies\n"
100              "-v.\n"));
101 static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";
102 
103 static cl::opt<bool> DumpInputOnFailure(
104     "dump-input-on-failure",
105     cl::init(std::getenv(DumpInputEnv) && *std::getenv(DumpInputEnv)),
106     cl::desc("Dump original input to stderr before failing.\n"
107              "The value can be also controlled using\n"
108              "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"
109              "This option is deprecated in favor of -dump-input=fail.\n"));
110 
111 enum DumpInputValue {
112   DumpInputDefault,
113   DumpInputHelp,
114   DumpInputNever,
115   DumpInputFail,
116   DumpInputAlways
117 };
118 
119 static cl::opt<DumpInputValue> DumpInput(
120     "dump-input", cl::init(DumpInputDefault),
121     cl::desc("Dump input to stderr, adding annotations representing\n"
122              " currently enabled diagnostics\n"),
123     cl::value_desc("mode"),
124     cl::values(clEnumValN(DumpInputHelp, "help",
125                           "Explain dump format and quit"),
126                clEnumValN(DumpInputNever, "never", "Never dump input"),
127                clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
128                clEnumValN(DumpInputAlways, "always", "Always dump input")));
129 
130 typedef cl::list<std::string>::const_iterator prefix_iterator;
131 
132 
133 
134 
135 
136 
137 
138 static void DumpCommandLine(int argc, char **argv) {
139   errs() << "FileCheck command line: ";
140   for (int I = 0; I < argc; I++)
141     errs() << " " << argv[I];
142   errs() << "\n";
143 }
144 
145 struct MarkerStyle {
146   /// The starting char (before tildes) for marking the line.
147   char Lead;
148   /// What color to use for this annotation.
149   raw_ostream::Colors Color;
150   /// A note to follow the marker, or empty string if none.
151   std::string Note;
152   MarkerStyle() {}
153   MarkerStyle(char Lead, raw_ostream::Colors Color,
154               const std::string &Note = "")
155       : Lead(Lead), Color(Color), Note(Note) {}
156 };
157 
158 static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
159   switch (MatchTy) {
160   case FileCheckDiag::MatchFoundAndExpected:
161     return MarkerStyle('^', raw_ostream::GREEN);
162   case FileCheckDiag::MatchFoundButExcluded:
163     return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
164   case FileCheckDiag::MatchFoundButWrongLine:
165     return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
166   case FileCheckDiag::MatchFoundButDiscarded:
167     return MarkerStyle('!', raw_ostream::CYAN,
168                        "discard: overlaps earlier match");
169   case FileCheckDiag::MatchNoneAndExcluded:
170     return MarkerStyle('X', raw_ostream::GREEN);
171   case FileCheckDiag::MatchNoneButExpected:
172     return MarkerStyle('X', raw_ostream::RED, "error: no match found");
173   case FileCheckDiag::MatchFuzzy:
174     return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");
175   }
176   llvm_unreachable_internal("unexpected match type");
177 }
178 
179 static void DumpInputAnnotationHelp(raw_ostream &OS) {
180   OS << "The following description was requested by -dump-input=help to\n"
181      << "explain the input annotations printed by -dump-input=always and\n"
182      << "-dump-input=fail:\n\n";
183 
184   // Labels for input lines.
185   OS << "  - ";
186   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
187   OS << "     labels line number L of the input file\n";
188 
189   // Labels for annotation lines.
190   OS << "  - ";
191   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
192   OS << "    labels the only match result for a pattern of type T from "
193      << "line L of\n"
194      << "           the check file\n";
195   OS << "  - ";
196   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
197   OS << "  labels the Nth match result for a pattern of type T from line "
198      << "L of\n"
199      << "           the check file\n";
200 
201   // Markers on annotation lines.
202   OS << "  - ";
203   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
204   OS << "    marks good match (reported if -v)\n"
205      << "  - ";
206   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
207   OS << "    marks bad match, such as:\n"
208      << "           - CHECK-NEXT on same line as previous match (error)\n"
209      << "           - CHECK-NOT found (error)\n"
210      << "           - CHECK-DAG overlapping match (discarded, reported if "
211      << "-vv)\n"
212      << "  - ";
213   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
214   OS << "    marks search range when no match is found, such as:\n"
215      << "           - CHECK-NEXT not found (error)\n"
216      << "           - CHECK-NOT not found (success, reported if -vv)\n"
217      << "           - CHECK-DAG not found after discarded matches (error)\n"
218      << "  - ";
219   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
220   OS << "      marks fuzzy match when no match is found\n";
221 
222   // Colors.
223   OS << "  - colors ";
224   WithColor(OS, raw_ostream::GREEN, true) << "success";
225   OS << ", ";
226   WithColor(OS, raw_ostream::RED, true) << "error";
227   OS << ", ";
228   WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
229   OS << ", ";
230   WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
231   OS << ", ";
232   WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
233   OS << "\n\n"
234      << "If you are not seeing color above or in input dumps, try: -color\n";
235 }
236 
237 /// An annotation for a single input line.
238 struct InputAnnotation {
239   /// The check file line (one-origin indexing) where the directive that
240   /// produced this annotation is located.
241   unsigned CheckLine;
242   /// The index of the match result for this check.
243   unsigned CheckDiagIndex;
244   /// The label for this annotation.
245   std::string Label;
246   /// What input line (one-origin indexing) this annotation marks.  This might
247   /// be different from the starting line of the original diagnostic if this is
248   /// a non-initial fragment of a diagnostic that has been broken across
249   /// multiple lines.
250   unsigned InputLine;
251   /// The column range (one-origin indexing, open end) in which to to mark the
252   /// input line.  If InputEndCol is UINT_MAX, treat it as the last column
253   /// before the newline.
254   unsigned InputStartCol, InputEndCol;
255   /// The marker to use.
256   MarkerStyle Marker;
257   /// Whether this annotation represents a good match for an expected pattern.
258   bool FoundAndExpectedMatch;
259 };
260 
261 /// Get an abbreviation for the check type.
262 std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
263   switch (Ty) {
264   case Check::CheckPlain:
265     if (Ty.getCount() > 1)
266       return "count";
267     return "check";
268   case Check::CheckNext:
269     return "next";
270   case Check::CheckSame:
271     return "same";
272   case Check::CheckNot:
273     return "not";
274   case Check::CheckDAG:
275     return "dag";
276   case Check::CheckLabel:
277     return "label";
278   case Check::CheckEmpty:
279     return "empty";
280   case Check::CheckEOF:
281     return "eof";
282   case Check::CheckBadNot:
283     return "bad-not";
284   case Check::CheckBadCount:
285     return "bad-count";
286   case Check::CheckNone:
287     llvm_unreachable("invalid FileCheckType");
288   }
289   llvm_unreachable("unknown FileCheckType");
290 }
291 
292 static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
293                                   std::vector<InputAnnotation> &Annotations,
294                                   unsigned &LabelWidth) {
295   // How many diagnostics has the current check seen so far?
296   unsigned CheckDiagCount = 0;
297   // What's the widest label?
298   LabelWidth = 0;
299   for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
300        ++DiagItr) {
301     InputAnnotation A;
302 
303     // Build label, which uniquely identifies this check result.
304     A.CheckLine = DiagItr->CheckLine;
305     llvm::raw_string_ostream Label(A.Label);
306     Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"
307           << DiagItr->CheckLine;
308     A.CheckDiagIndex = UINT_MAX;
309     auto DiagNext = std::next(DiagItr);
310     if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
311         DiagItr->CheckLine == DiagNext->CheckLine)
312       A.CheckDiagIndex = CheckDiagCount++;
313     else if (CheckDiagCount) {
314       A.CheckDiagIndex = CheckDiagCount;
315       CheckDiagCount = 0;
316     }
317     if (A.CheckDiagIndex != UINT_MAX)
318       Label << "'" << A.CheckDiagIndex;
319     else
320       A.CheckDiagIndex = 0;
321     Label.flush();
322     LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
323 
324     A.Marker = GetMarker(DiagItr->MatchTy);
325     A.FoundAndExpectedMatch =
326         DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
327 
328     // Compute the mark location, and break annotation into multiple
329     // annotations if it spans multiple lines.
330     A.InputLine = DiagItr->InputStartLine;
331     A.InputStartCol = DiagItr->InputStartCol;
332     if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
333       // Sometimes ranges are empty in order to indicate a specific point, but
334       // that would mean nothing would be marked, so adjust the range to
335       // include the following character.
336       A.InputEndCol =
337           std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
338       Annotations.push_back(A);
339     } else {
340       assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
341              "expected input range not to be inverted");
342       A.InputEndCol = UINT_MAX;
343       Annotations.push_back(A);
344       for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
345            L <= E; ++L) {
346         // If a range ends before the first column on a line, then it has no
347         // characters on that line, so there's nothing to render.
348         if (DiagItr->InputEndCol == 1 && L == E)
349           break;
350         InputAnnotation B;
351         B.CheckLine = A.CheckLine;
352         B.CheckDiagIndex = A.CheckDiagIndex;
353         B.Label = A.Label;
354         B.InputLine = L;
355         B.Marker = A.Marker;
356         B.Marker.Lead = '~';
357         B.Marker.Note = "";
358         B.InputStartCol = 1;
359         if (L != E)
360           B.InputEndCol = UINT_MAX;
361         else
362           B.InputEndCol = DiagItr->InputEndCol;
363         B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
364         Annotations.push_back(B);
365       }
366     }
367   }
368 }
369 
370 static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
371                                StringRef InputFileText,
372                                std::vector<InputAnnotation> &Annotations,
373                                unsigned LabelWidth) {
374   OS << "Full input was:\n<<<<<<\n";
375 
376   // Sort annotations.
377   //
378   // First, sort in the order of input lines to make it easier to find relevant
379   // annotations while iterating input lines in the implementation below.
380   // FileCheck diagnostics are not always reported and recorded in the order of
381   // input lines due to, for example, CHECK-DAG and CHECK-NOT.
382   //
383   // Second, for annotations for the same input line, sort in the order of the
384   // FileCheck directive's line in the check file (where there's at most one
385   // directive per line) and then by the index of the match result for that
386   // directive.  The rationale of this choice is that, for any input line, this
387   // sort establishes a total order of annotations that, with respect to match
388   // results, is consistent across multiple lines, thus making match results
389   // easier to track from one line to the next when they span multiple lines.
390   std::sort(Annotations.begin(), Annotations.end(),
391             [](const InputAnnotation &A, const InputAnnotation &B) {
392               if (A.InputLine != B.InputLine)
393                 return A.InputLine < B.InputLine;
394               if (A.CheckLine != B.CheckLine)
395                 return A.CheckLine < B.CheckLine;
396               // FIXME: Sometimes CHECK-LABEL reports its match twice with
397               // other diagnostics in between, and then diag index incrementing
398               // fails to work properly, and then this assert fails.  We should
399               // suppress one of those diagnostics or do a better job of
400               // computing this index.  For now, we just produce a redundant
401               // CHECK-LABEL annotation.
402               // assert(A.CheckDiagIndex != B.CheckDiagIndex &&
403               //        "expected diagnostic indices to be unique within a "
404               //        " check line");
405               return A.CheckDiagIndex < B.CheckDiagIndex;
406             });
407 
408   // Compute the width of the label column.
409   const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
410                       *InputFileEnd = InputFileText.bytes_end();
411   unsigned LineCount = InputFileText.count('\n');
412   if (InputFileEnd[-1] != '\n')
413     ++LineCount;
414   unsigned LineNoWidth = std::log10(LineCount) + 1;
415   // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
416   // on input lines and (2) to the right of the (left-aligned) labels on
417   // annotation lines so that input lines and annotation lines are more
418   // visually distinct.  For example, the spaces on the annotation lines ensure
419   // that input line numbers and check directive line numbers never align
420   // horizontally.  Those line numbers might not even be for the same file.
421   // One space would be enough to achieve that, but more makes it even easier
422   // to see.
423   LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
424 
425   // Print annotated input lines.
426   auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
427   for (unsigned Line = 1;
428        InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
429        ++Line) {
430     const unsigned char *InputFileLine = InputFilePtr;
431 
432     // Print right-aligned line number.
433     WithColor(OS, raw_ostream::BLACK, true)
434         << format_decimal(Line, LabelWidth) << ": ";
435 
436     // For the case where -v and colors are enabled, find the annotations for
437     // good matches for expected patterns in order to highlight everything
438     // else in the line.  There are no such annotations if -v is disabled.
439     std::vector<InputAnnotation> FoundAndExpectedMatches;
440     if (Req.Verbose && WithColor(OS).colorsEnabled()) {
441       for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
442            ++I) {
443         if (I->FoundAndExpectedMatch)
444           FoundAndExpectedMatches.push_back(*I);
445       }
446     }
447 
448     // Print numbered line with highlighting where there are no matches for
449     // expected patterns.
450     bool Newline = false;
451     {
452       WithColor COS(OS);
453       bool InMatch = false;
454       if (Req.Verbose)
455         COS.changeColor(raw_ostream::CYAN, true, true);
456       for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
457         bool WasInMatch = InMatch;
458         InMatch = false;
459         for (auto M : FoundAndExpectedMatches) {
460           if (M.InputStartCol <= Col && Col < M.InputEndCol) {
461             InMatch = true;
462             break;
463           }
464         }
465         if (!WasInMatch && InMatch)
466           COS.resetColor();
467         else if (WasInMatch && !InMatch)
468           COS.changeColor(raw_ostream::CYAN, true, true);
469         if (*InputFilePtr == '\n')
470           Newline = true;
471         else
472           COS << *InputFilePtr;
473         ++InputFilePtr;
474       }
475     }
476     OS << '\n';
477     unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
478 
479     // Print any annotations.
480     while (AnnotationItr != AnnotationEnd &&
481            AnnotationItr->InputLine == Line) {
482       WithColor COS(OS, AnnotationItr->Marker.Color, true);
483       // The two spaces below are where the ": " appears on input lines.
484       COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";
485       unsigned Col;
486       for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
487         COS << ' ';
488       COS << AnnotationItr->Marker.Lead;
489       // If InputEndCol=UINT_MAX, stop at InputLineWidth.
490       for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
491            ++Col)
492         COS << '~';
493       const std::string &Note = AnnotationItr->Marker.Note;
494       if (!Note.empty()) {
495         // Put the note at the end of the input line.  If we were to instead
496         // put the note right after the marker, subsequent annotations for the
497         // same input line might appear to mark this note instead of the input
498         // line.
499         for (; Col <= InputLineWidth; ++Col)
500           COS << ' ';
501         COS << ' ' << Note;
502       }
503       COS << '\n';
504       ++AnnotationItr;
505     }
506   }
507 
508   OS << ">>>>>>\n";
509 }
510 
511 int main(int argc, char **argv) {
512   // Enable use of ANSI color codes because FileCheck is using them to
513   // highlight text.
514   llvm::sys::Process::UseANSIEscapeCodes(true);
515 
516   InitLLVM X(argc, argv);
517   cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
518                               "FILECHECK_OPTS");
519   if (DumpInput == DumpInputHelp) {
520     DumpInputAnnotationHelp(outs());
521     return 0;
522   }
523   if (CheckFilename.empty()) {
524     errs() << "<check-file> not specified\n";
525     return 2;
526   }
527 
528   FileCheckRequest Req;
529   for (auto Prefix : CheckPrefixes)
530     Req.CheckPrefixes.push_back(Prefix);
531 
532   for (auto CheckNot : ImplicitCheckNot)
533     Req.ImplicitCheckNot.push_back(CheckNot);
534 
535   bool GlobalDefineError = false;
536   for (auto G : GlobalDefines) {
537     size_t EqIdx = G.find('=');
538     if (EqIdx == std::string::npos) {
539       errs() << "Missing equal sign in command-line definition '-D" << G
540              << "'\n";
541       GlobalDefineError = true;
542       continue;
543     }
544     if (EqIdx == 0) {
545       errs() << "Missing variable name in command-line definition '-D" << G
546              << "'\n";
547       GlobalDefineError = true;
548       continue;
549     }
550     Req.GlobalDefines.push_back(G);
551   }
552   if (GlobalDefineError)
553     return 2;
554 
555   Req.AllowEmptyInput = AllowEmptyInput;
556   Req.EnableVarScope = EnableVarScope;
557   Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
558   Req.Verbose = Verbose;
559   Req.VerboseVerbose = VerboseVerbose;
560   Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
561   Req.MatchFullLines = MatchFullLines;
562   Req.IgnoreCase = IgnoreCase;
563 
564   if (VerboseVerbose)
565     Req.Verbose = true;
566 
567   FileCheck FC(Req);
568   if (!FC.ValidateCheckPrefixes()) {
569     errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
570               "start with a letter and contain only alphanumeric characters, "
571               "hyphens and underscores\n";
572     return 2;
573   }
574 
575   Regex PrefixRE = FC.buildCheckPrefixRegex();
576   std::string REError;
577   if (!PrefixRE.isValid(REError)) {
578     errs() << "Unable to combine check-prefix strings into a prefix regular "
579               "expression! This is likely a bug in FileCheck's verification of "
580               "the check-prefix strings. Regular expression parsing failed "
581               "with the following error: "
582            << REError << "\n";
583     return 2;
584   }
585 
586   SourceMgr SM;
587 
588   // Read the expected strings from the check file.
589   ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
590       MemoryBuffer::getFileOrSTDIN(CheckFilename);
591   if (std::error_code EC = CheckFileOrErr.getError()) {
592     errs() << "Could not open check file '" << CheckFilename
593            << "': " << EC.message() << '\n';
594     return 2;
595   }
596   MemoryBuffer &CheckFile = *CheckFileOrErr.get();
597 
598   SmallString<4096> CheckFileBuffer;
599   StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
600 
601   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
602                             CheckFileText, CheckFile.getBufferIdentifier()),
603                         SMLoc());
604 
605   if (FC.readCheckFile(SM, CheckFileText, PrefixRE))
606     return 2;
607 
608   // Open the file to check and add it to SourceMgr.
609   ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
610       MemoryBuffer::getFileOrSTDIN(InputFilename);
611   if (std::error_code EC = InputFileOrErr.getError()) {
612     errs() << "Could not open input file '" << InputFilename
613            << "': " << EC.message() << '\n';
614     return 2;
615   }
616   MemoryBuffer &InputFile = *InputFileOrErr.get();
617 
618   if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
619     errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
620     DumpCommandLine(argc, argv);
621     return 2;
622   }
623 
624   SmallString<4096> InputFileBuffer;
625   StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
626 
627   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
628                             InputFileText, InputFile.getBufferIdentifier()),
629                         SMLoc());
630 
631   if (DumpInput == DumpInputDefault)
632     DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;
633 
634   std::vector<FileCheckDiag> Diags;
635   int ExitCode = FC.checkInput(SM, InputFileText,
636                                DumpInput == DumpInputNever ? nullptr : &Diags)
637                      ? EXIT_SUCCESS
638                      : 1;
639   if (DumpInput == DumpInputAlways ||
640       (ExitCode == 1 && DumpInput == DumpInputFail)) {
641     errs() << "\n"
642            << "Input file: "
643            << (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())
644            << "\n"
645            << "Check file: " << CheckFilename << "\n"
646            << "\n"
647            << "-dump-input=help describes the format of the following dump.\n"
648            << "\n";
649     std::vector<InputAnnotation> Annotations;
650     unsigned LabelWidth;
651     BuildInputAnnotations(Diags, Annotations, LabelWidth);
652     DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
653   }
654 
655   return ExitCode;
656 }
657