llvm.org GIT mirror llvm / 178504b
Add new directive called CHECK-LABEL to FileCheck. CHECK-LABEL is meant to be used in place on CHECK on lines containing identifiers or other unique labels (they need not actually be labels in the source or output language, though.) This is used to break up the input stream into separate blocks delineated by CHECK-LABEL lines, each of which is checked independently. This greatly improves the accuracy of errors and fix-it hints in many cases, and allows for FileCheck to recover from errors in one block by continuing to subsequent blocks. Some tests will be converted to use this new directive in forthcoming patches. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@186162 91177308-0d34-0410-b5e6-96231b3b80d8 Stephen Lin 6 years ago
3 changed file(s) with 202 addition(s) and 37 deletion(s). Raw diff Collapse all Expand all
242242
243243 This case will reject input strings where ``BEFORE`` occurs after ``AFTER``.
244244
245 The "CHECK-LABEL:" directive
246 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
247
248 Sometimes in a file containing multiple tests divided into logical blocks, one
249 or more ``CHECK:`` directives may inadvertently succeed by matching lines in a
250 later block. While an error will usually eventually be generated, the check
251 flagged as causing the error may not actually bear any relationship to the
252 actual source of the problem.
253
254 In order to produce better error messages in these cases, the "``CHECK-LABEL:``"
255 directive can be used. It is treated identically to a normal ``CHECK``
256 directive except that the FileCheck utility makes an additional assumption that
257 a line matched by the directive cannot also be matched by any other check
258 present in ``match-filename``; this is intended to be used for lines containing
259 labels or other unique identifiers. Conceptually, the presence of
260 ``CHECK-LABEL`` divides the input stream into separate blocks, each of which is
261 processed independently, preventing a ``CHECK:`` directive in one block
262 matching a line in another block. For example,
263
264 .. code-block:: llvm
265
266 define %struct.C* @C_ctor_base(%struct.C* %this, i32 %x) {
267 entry:
268 ; CHECK-LABEL: C_ctor_base:
269 ; CHECK: mov [[SAVETHIS:r[0-9]+]], r0
270 ; CHECK: bl A_ctor_base
271 ; CHECK: mov r0, [[SAVETHIS]]
272 %0 = bitcast %struct.C* %this to %struct.A*
273 %call = tail call %struct.A* @A_ctor_base(%struct.A* %0)
274 %1 = bitcast %struct.C* %this to %struct.B*
275 %call2 = tail call %struct.B* @B_ctor_base(%struct.B* %1, i32 %x)
276 ret %struct.C* %this
277 }
278
279 define %struct.D* @D_ctor_base(%struct.D* %this, i32 %x) {
280 entry:
281 ; CHECK-LABEL: D_ctor_base:
282
283 The use of ``CHECK-LABEL:`` directives in this case ensures that the three
284 ``CHECK:`` directives only accept lines corresponding to the body of the
285 ``@C_ctor_base`` function, even if the patterns match lines found later in
286 the file.
287
288 There is no requirement that ``CHECK-LABEL:`` directives contain strings that
289 correspond to actual syntactic labels in a source or output language: they must
290 simply uniquely match a single line in the file being verified.
291
292 ``CHECK-LABEL:`` directives cannot contain variable definitions or uses.
293
245294 FileCheck Pattern Matching Syntax
246295 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
247296
0 ; RUN: FileCheck -input-file %s %s -check-prefix=CHECKOK
1 ; RUN: not FileCheck -input-file %s %s -check-prefix=CHECKFAIL 2>&1 | FileCheck %s -check-prefix=CHECKERROR
2
3 label0:
4 a
5 b
6
7 label1:
8 b
9 c
10
11 label2:
12 a
13 c
14
15 ; CHECKOK-LABEL: {{^}}label0:
16 ; CHECKOK: {{^}}a
17 ; CHECKOK: {{^}}b
18
19 ; CHECKOK-LABEL: {{^}}label1:
20 ; CHECKOK: {{^}}b
21 ; CHECKOK: {{^}}c
22
23 ; CHECKOK-LABEL: {{^}}label2:
24 ; CHECKOK: {{^}}a
25 ; CHECKOK: {{^}}c
26
27 ; CHECKFAIL-LABEL: {{^}}label0:
28 ; CHECKFAIL: {{^}}a
29 ; CHECKFAIL: {{^}}b
30 ; CHECKFAIL: {{^}}c
31
32 ; CHECKERROR: expected string not found in input
33 ; CHECKERROR-NEXT: CHECKFAIL: {{[{][{]\^[}][}]}}c
34
35 ; CHECKFAIL-LABEL: {{^}}label1:
36 ; CHECKFAIL: {{^}}a
37 ; CHECKFAIL: {{^}}b
38 ; CHECKFAIL: {{^}}c
39
40 ; CHECKERROR: expected string not found in input
41 ; CHECKERROR-NEXT: CHECKFAIL: {{[{][{]\^[}][}]}}a
42
43 ; CHECKFAIL-LABEL: {{^}}label2:
44 ; CHECKFAIL: {{^}}a
45 ; CHECKFAIL: {{^}}b
46 ; CHECKFAIL: {{^}}c
47
48 ; CHECKERROR: expected string not found in input
49 ; CHECKERROR-NEXT: CHECKFAIL: {{[{][{]\^[}][}]}}b
50
113113 /// involving this pattern.
114114 void PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
115115 const StringMap &VariableTable) const;
116
117 bool hasVariable() const { return !(VariableUses.empty() &&
118 VariableDefs.empty()); }
116119
117120 void setMatchNot(bool Not) { MatchNot = Not; }
118121 bool getMatchNot() const { return MatchNot; }
593596 /// to a CHECK: directive.
594597 bool IsCheckNext;
595598
599 /// IsCheckLabel - This is true if this is a CHECK-LABEL: directive (as
600 /// opposed to a CHECK: directive.
601 bool IsCheckLabel;
602
596603 /// DagNotStrings - These are all of the strings that are disallowed from
597604 /// occurring between this match string and the previous one (or start of
598605 /// file).
599606 std::vector DagNotStrings;
600607
601 CheckString(const Pattern &P, SMLoc L, bool isCheckNext)
602 : Pat(P), Loc(L), IsCheckNext(isCheckNext) {}
608 CheckString(const Pattern &P, SMLoc L, bool isCheckNext, bool isCheckLabel)
609 : Pat(P), Loc(L), IsCheckNext(isCheckNext), IsCheckLabel(isCheckLabel) {}
603610
604611 /// Check - Match check string and its "not strings" and/or "dag strings".
605 size_t Check(const SourceMgr &SM, StringRef Buffer, size_t &MatchLen,
606 StringMap &VariableTable) const;
612 size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabel,
613 size_t &MatchLen, StringMap &VariableTable) const;
607614
608615 /// CheckNext - Verify there is a single line in the given buffer.
609616 bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
702709
703710 // When we find a check prefix, keep track of whether we find CHECK: or
704711 // CHECK-NEXT:
705 bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false;
712 bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false,
713 IsCheckLabel = false;
706714
707715 // Verify that the : is present after the prefix.
708716 if (Buffer[CheckPrefix.size()] == ':') {
719727 memcmp(Buffer.data()+CheckPrefix.size(), "-DAG:", 5) == 0) {
720728 Buffer = Buffer.substr(CheckPrefix.size()+5);
721729 IsCheckDag = true;
730 } else if (Buffer.size() > CheckPrefix.size()+7 &&
731 memcmp(Buffer.data()+CheckPrefix.size(), "-LABEL:", 7) == 0) {
732 Buffer = Buffer.substr(CheckPrefix.size()+7);
733 IsCheckLabel = true;
722734 } else {
723735 Buffer = Buffer.substr(1);
724736 continue;
738750 Pattern P;
739751 if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber))
740752 return true;
753
754 // Verify that CHECK-LABEL lines do not define or use variables
755 if (IsCheckLabel && P.hasVariable()) {
756 SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
757 SourceMgr::DK_Error,
758 "found '"+CheckPrefix+"-LABEL:' with variable definition"
759 " or use'");
760 return true;
761 }
741762
742763 P.setMatchNot(IsCheckNot);
743764 P.setMatchDag(IsCheckDag);
762783 // Okay, add the string we captured to the output vector and move on.
763784 CheckStrings.push_back(CheckString(P,
764785 PatternLoc,
765 IsCheckNext));
786 IsCheckNext,
787 IsCheckLabel));
766788 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
767789 }
768790
770792 if (!DagNotMatches.empty()) {
771793 CheckStrings.push_back(CheckString(Pattern(true),
772794 SMLoc::getFromPointer(Buffer.data()),
795 false,
773796 false));
774797 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
775798 }
828851 }
829852
830853 size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
831 size_t &MatchLen,
854 bool IsLabel, size_t &MatchLen,
832855 StringMap &VariableTable) const {
833856 size_t LastPos = 0;
834857 std::vector NotStrings;
835858
836 // Match "dag strings" (with mixed "not strings" if any).
837 LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable);
838 if (LastPos == StringRef::npos)
839 return StringRef::npos;
859 if (!IsLabel) {
860 // Match "dag strings" (with mixed "not strings" if any).
861 LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable);
862 if (LastPos == StringRef::npos)
863 return StringRef::npos;
864 }
840865
841866 // Match itself from the last position after matching CHECK-DAG.
842867 StringRef MatchBuffer = Buffer.substr(LastPos);
847872 }
848873 MatchPos += LastPos;
849874
850 StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
851
852 // If this check is a "CHECK-NEXT", verify that the previous match was on
853 // the previous line (i.e. that there is one newline between them).
854 if (CheckNext(SM, SkippedRegion))
855 return StringRef::npos;
856
857 // If this match had "not strings", verify that they don't exist in the
858 // skipped region.
859 if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
860 return StringRef::npos;
875 if (!IsLabel) {
876 StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
877
878 // If this check is a "CHECK-NEXT", verify that the previous match was on
879 // the previous line (i.e. that there is one newline between them).
880 if (CheckNext(SM, SkippedRegion))
881 return StringRef::npos;
882
883 // If this match had "not strings", verify that they don't exist in the
884 // skipped region.
885 if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
886 return StringRef::npos;
887 }
861888
862889 return MatchPos;
863890 }
10391066 // file.
10401067 StringRef Buffer = F->getBuffer();
10411068
1042 for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) {
1043 const CheckString &CheckStr = CheckStrings[StrNo];
1044
1045 // Find StrNo in the file.
1046 size_t MatchLen = 0;
1047 size_t MatchPos = CheckStr.Check(SM, Buffer, MatchLen, VariableTable);
1048
1049 if (MatchPos == StringRef::npos)
1050 return 1;
1051
1052 Buffer = Buffer.substr(MatchPos + MatchLen);
1053 }
1054
1055 return 0;
1056 }
1069 bool hasError = false;
1070
1071 unsigned i = 0, j = 0, e = CheckStrings.size();
1072
1073 while (true) {
1074 StringRef CheckRegion;
1075 if (j == e) {
1076 CheckRegion = Buffer;
1077 } else {
1078 const CheckString &CheckLabelStr = CheckStrings[j];
1079 if (!CheckLabelStr.IsCheckLabel) {
1080 ++j;
1081 continue;
1082 }
1083
1084 // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
1085 size_t MatchLabelLen = 0;
1086 size_t MatchLabelPos = CheckLabelStr.Check(SM, Buffer, true,
1087 MatchLabelLen, VariableTable);
1088 if (MatchLabelPos == StringRef::npos) {
1089 hasError = true;
1090 break;
1091 }
1092
1093 CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
1094 Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);
1095 ++j;
1096 }
1097
1098 for ( ; i != j; ++i) {
1099 const CheckString &CheckStr = CheckStrings[i];
1100
1101 // Check each string within the scanned region, including a second check
1102 // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
1103 size_t MatchLen = 0;
1104 size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen,
1105 VariableTable);
1106
1107 if (MatchPos == StringRef::npos) {
1108 hasError = true;
1109 i = j;
1110 break;
1111 }
1112
1113 CheckRegion = CheckRegion.substr(MatchPos + MatchLen);
1114 }
1115
1116 if (j == e)
1117 break;
1118 }
1119
1120 return hasError ? 1 : 0;
1121 }