LLVM: lib/FileCheck/FileCheck.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

24#include

25#include

26#include

27#include

28#include

29

30using namespace llvm;

31

44 }

46}

47

50

51 auto CreatePrecisionRegex = [&](StringRef S) {

52 return (Twine(AlternateFormPrefix) + S + Twine('{') + Twine(Precision) +

53 "}")

54 .str();

55 };

56

59 if (Precision)

60 return CreatePrecisionRegex("([1-9][0-9]*)?[0-9]");

61 return std::string("[0-9]+");

63 if (Precision)

64 return CreatePrecisionRegex("-?([1-9][0-9]*)?[0-9]");

65 return std::string("-?[0-9]+");

67 if (Precision)

68 return CreatePrecisionRegex("([1-9A-F][0-9A-F]*)?[0-9A-F]");

69 return (Twine(AlternateFormPrefix) + Twine("[0-9A-F]+")).str();

71 if (Precision)

72 return CreatePrecisionRegex("([1-9a-f][0-9a-f]*)?[0-9a-f]");

73 return (Twine(AlternateFormPrefix) + Twine("[0-9a-f]+")).str();

74 default:

76 "trying to match value with invalid format");

77 }

78}

79

83 return make_error();

84

85 unsigned Radix;

86 bool UpperCase = false;

92 Radix = 10;

93 break;

95 UpperCase = true;

96 Radix = 16;

97 break;

99 Radix = 16;

100 UpperCase = false;

101 break;

102 default:

104 "trying to match value with invalid format");

105 }

106 IntValue.abs().toString(AbsoluteValueStr, Radix, false,

107 false,

108 UpperCase);

109

111

112 if (Precision > AbsoluteValueStr.size()) {

113 unsigned LeadingZeros = Precision - AbsoluteValueStr.size();

114 return (Twine(SignPrefix) + Twine(AlternateFormPrefix) +

115 std::string(LeadingZeros, '0') + AbsoluteValueStr)

116 .str();

117 }

118

119 return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + AbsoluteValueStr)

120 .str();

121}

122

126}

127

131 APInt Result = AbsVal;

132 if (Negative)

133 Result.negate();

134 return Result;

135}

136

140 bool Negative = StrVal.consume_front("-");

142 bool MissingFormPrefix =

143 !ValueIsSigned && AlternateForm && !StrVal.consume_front("0x");

144 (void)MissingFormPrefix;

145 assert(!MissingFormPrefix && "missing alternate form prefix");

146 APInt ResultValue;

147 [[maybe_unused]] bool ParseFailure =

148 StrVal.getAsInteger(Hex ? 16 : 10, ResultValue);

149

150

151

152 assert(!ParseFailure && "unable to represent numeric value");

153 return toSigned(ResultValue, Negative);

154}

155

157 const APInt &RightOperand, bool &Overflow) {

158 return LeftOperand.sadd_ov(RightOperand, Overflow);

159}

160

162 const APInt &RightOperand, bool &Overflow) {

163 return LeftOperand.ssub_ov(RightOperand, Overflow);

164}

165

167 const APInt &RightOperand, bool &Overflow) {

168 return LeftOperand.smul_ov(RightOperand, Overflow);

169}

170

172 const APInt &RightOperand, bool &Overflow) {

173

174 if (RightOperand.isZero())

175 return make_error();

176

177 return LeftOperand.sdiv_ov(RightOperand, Overflow);

178}

179

181 const APInt &RightOperand, bool &Overflow) {

182 Overflow = false;

183 return LeftOperand.slt(RightOperand) ? RightOperand : LeftOperand;

184}

185

187 const APInt &RightOperand, bool &Overflow) {

188 Overflow = false;

189 if (cantFail(exprMax(LeftOperand, RightOperand, Overflow)) == LeftOperand)

190 return RightOperand;

191

192 return LeftOperand;

193}

194

196 std::optional Value = Variable->getValue();

199

201}

202

206

207

208

209 if (!MaybeLeftOp || !MaybeRightOp) {

211 if (!MaybeLeftOp)

213 if (!MaybeRightOp)

215 return std::move(Err);

216 }

217

218 APInt LeftOp = *MaybeLeftOp;

219 APInt RightOp = *MaybeRightOp;

220 bool Overflow;

221

222 unsigned LeftBitWidth = LeftOp.getBitWidth();

223 unsigned RightBitWidth = RightOp.getBitWidth();

224 unsigned NewBitWidth = std::max(LeftBitWidth, RightBitWidth);

225 LeftOp = LeftOp.sext(NewBitWidth);

226 RightOp = RightOp.sext(NewBitWidth);

227 do {

228 Expected MaybeResult = EvalBinop(LeftOp, RightOp, Overflow);

229 if (!MaybeResult)

231

232 if (!Overflow)

233 return MaybeResult;

234

236 LeftOp = LeftOp.sext(NewBitWidth);

237 RightOp = RightOp.sext(NewBitWidth);

238 } while (true);

239}

240

245 if (!LeftFormat || !RightFormat) {

247 if (!LeftFormat)

249 if (!RightFormat)

251 return std::move(Err);

252 }

253

256 *LeftFormat != *RightFormat)

259 "implicit format conflict between '" + LeftOperand->getExpressionStr() +

260 "' (" + LeftFormat->toString() + ") and '" +

261 RightOperand->getExpressionStr() + "' (" + RightFormat->toString() +

262 "), need an explicit format specifier");

263

265 : *RightFormat;

266}

267

269 assert(ExpressionPointer->getAST() != nullptr &&

270 "Substituting empty expression");

271 Expected EvaluatedValue = ExpressionPointer->getAST()->eval();

272 if (!EvaluatedValue)

273 return EvaluatedValue.takeError();

275 return Format.getMatchingString(*EvaluatedValue);

276}

277

279

281 if (!VarVal)

284}

285

287

290 if (Str.empty())

292

293 size_t I = 0;

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

295

296

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

298 ++I;

299

300 if (I == Str.size())

303 (IsPseudo ? "pseudo " : "global ") +

304 "variable name");

305

308

309 for (size_t E = Str.size(); I != E; ++I)

310

311 if (Str[I] != '_' && !isAlnum(Str[I]))

312 break;

313

315 Str = Str.substr(I);

317}

318

319

320

322

323

327 return C;

328}

329

335

338 std::optional<size_t> LineNumber, ExpressionFormat ImplicitFormat,

341 if (!ParseVarResult)

342 return ParseVarResult.takeError();

344

345 if (ParseVarResult->IsPseudo)

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

348

349

350

351 if (Context->DefinedVariableTable.contains(Name))

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

354

356 if (!Expr.empty())

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

359

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

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

363 DefinedNumericVariable = VarTableIter->second;

364 if (DefinedNumericVariable->getImplicitFormat() != ImplicitFormat)

366 SM, Expr, "format different from previous variable definition");

367 } else

368 DefinedNumericVariable =

369 Context->makeNumericVariable(Name, ImplicitFormat, LineNumber);

370

371 return DefinedNumericVariable;

372}

373

375 StringRef Name, bool IsPseudo, std::optional<size_t> LineNumber,

377 if (IsPseudo && Name != "@LINE")

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

380

381

382

383

384

385

386

387

388

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

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

393 else {

397 }

398

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

403 "numeric variable '" + Name +

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

405

407}

408

410 StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint,

414 if (AO != AllowedOperand::Any)

416 SM, Expr, "parenthesized expression not permitted here");

417 return parseParenExpr(Expr, LineNumber, Context, SM);

418 }

419

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

421

424 if (ParseVarResult) {

425

427 if (AO != AllowedOperand::Any)

429 "unexpected function call");

430

431 return parseCallExpr(Expr, ParseVarResult->Name, LineNumber, Context,

432 SM);

433 }

434

435 return parseNumericVariableUse(ParseVarResult->Name,

436 ParseVarResult->IsPseudo, LineNumber,

437 Context, SM);

438 }

439

440 if (AO == AllowedOperand::LineVar)

441 return ParseVarResult.takeError();

442

444 }

445

446

450 if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0,

451 LiteralValue)) {

453 return std::make_unique(SaveExpr.drop_back(Expr.size()),

454 LiteralValue);

455 }

457 SM, SaveExpr,

458 Twine("invalid ") +

459 (MaybeInvalidConstraint ? "matching constraint or " : "") +

460 "operand format");

461}

462

464Pattern::parseParenExpr(StringRef &Expr, std::optional<size_t> LineNumber,

468

469

472 if (Expr.empty())

474

475

477 Expr, AllowedOperand::Any, false, LineNumber,

478 Context, SM);

480 while (SubExprResult && !Expr.empty() && !Expr.starts_with(")")) {

482 SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false,

483 LineNumber, Context, SM);

485 }

486 if (!SubExprResult)

487 return SubExprResult;

488

491 "missing ')' at end of nested expression");

492 }

493 return SubExprResult;

494}

495

498 std::unique_ptr LeftOp,

499 bool IsLegacyLineExpr, std::optional<size_t> LineNumber,

502 if (RemainingExpr.empty())

503 return std::move(LeftOp);

504

505

506

511 case '+':

513 break;

514 case '-':

516 break;

517 default:

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

520 }

521

522

524 if (RemainingExpr.empty())

526 "missing operand in expression");

527

528 AllowedOperand AO =

529 IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any;

531 parseNumericOperand(RemainingExpr, AO, false,

532 LineNumber, Context, SM);

533 if (!RightOpResult)

534 return RightOpResult;

535

537 return std::make_unique(Expr, EvalBinop, std::move(LeftOp),

538 std::move(*RightOpResult));

539}

540

543 std::optional<size_t> LineNumber,

547

556

557 if (!OptFunc)

559 SM, FuncName, Twine("call to undefined function '") + FuncName + "'");

560

563

564

569

570

573 Expr, AllowedOperand::Any, false, LineNumber,

574 Context, SM);

575 while (Arg && !Expr.empty()) {

577

579 break;

580

581

582 Arg = parseBinop(OuterBinOpExpr, Expr, std::move(*Arg), false, LineNumber,

583 Context, SM);

584 }

585

586

587 if (!Arg)

589 Args.push_back(std::move(*Arg));

590

591

594 break;

595

599 }

600

603 "missing ')' at end of call expression");

604

605 const unsigned NumArgs = Args.size();

606 if (NumArgs == 2)

607 return std::make_unique(Expr, *OptFunc, std::move(Args[0]),

608 std::move(Args[1]));

609

610

612 Twine("function '") + FuncName +

613 Twine("' takes 2 arguments but ") +

614 Twine(NumArgs) + " given");

615}

616

618 StringRef Expr, std::optional<NumericVariable *> &DefinedNumericVariable,

619 bool IsLegacyLineExpr, std::optional<size_t> LineNumber,

621 std::unique_ptr ExpressionASTPointer = nullptr;

623 DefinedNumericVariable = std::nullopt;

625 unsigned Precision = 0;

626

627

628 size_t FormatSpecEnd = Expr.find(',');

629 size_t FunctionStart = Expr.find('(');

630 if (FormatSpecEnd != StringRef::npos && FormatSpecEnd < FunctionStart) {

632 Expr = Expr.drop_front(FormatSpecEnd + 1);

636 SM, FormatExpr,

637 "invalid matching format specification in expression");

638

639

641 bool AlternateForm = FormatExpr.consume_front("#");

642

643

647 "invalid precision in format specifier");

648 }

649

650 if (!FormatExpr.empty()) {

651

652

654 switch (popFront(FormatExpr)) {

655 case 'u':

656 ExplicitFormat =

658 break;

659 case 'd':

660 ExplicitFormat =

662 break;

663 case 'x':

665 Precision, AlternateForm);

666 break;

667 case 'X':

669 Precision, AlternateForm);

670 break;

671 default:

673 "invalid format specifier in expression");

674 }

675 }

676

680 SM, AlternateFormFlagLoc,

681 "alternate form only supported for hex values");

682

684 if (!FormatExpr.empty())

686 SM, FormatExpr,

687 "invalid matching format specification in expression");

688 }

689

690

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

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

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

695 }

696

697

699 bool HasParsedValidConstraint = Expr.consume_front("==");

700

701

703 if (Expr.empty()) {

704 if (HasParsedValidConstraint)

706 SM, Expr, "empty numeric expression should not have a constraint");

707 } else {

710

711

712 AllowedOperand AO =

713 IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;

715 Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM);

718 IsLegacyLineExpr, LineNumber, Context, SM);

719

722 SM, Expr,

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

724 }

727 ExpressionASTPointer = std::move(*ParseResult);

728 }

729

730

731

732

733

735 if (ExplicitFormat)

736 Format = ExplicitFormat;

737 else if (ExpressionASTPointer) {

739 ExpressionASTPointer->getImplicitFormat(SM);

740 if (!ImplicitFormat)

741 return ImplicitFormat.takeError();

742 Format = *ImplicitFormat;

743 }

746

747 std::unique_ptr ExpressionPointer =

748 std::make_unique(std::move(ExpressionASTPointer), Format);

749

750

754 DefExpr, Context, LineNumber, ExpressionPointer->getFormat(), SM);

755

759 }

760

761 return std::move(ExpressionPointer);

762}

763

768

770

772

773 PatternStr = PatternStr.rtrim(" \t");

774

775

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

779 return true;

780 }

781

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

786 ":'");

787 return true;

788 }

789

791 RegExStr = "(\n$)";

792 return false;

793 }

794

795

797 FixedStr = PatternStr;

798 return false;

799 }

800

801

802 if (!MatchFullLinesHere &&

803 (PatternStr.size() < 2 ||

804 (!PatternStr.contains("{{") && !PatternStr.contains("[[")))) {

805 FixedStr = PatternStr;

806 return false;

807 }

808

809 if (MatchFullLinesHere) {

810 RegExStr += '^';

812 RegExStr += " *";

813 }

814

815

816

817 unsigned CurParen = 1;

818

819

820

821 while (!PatternStr.empty()) {

822

824

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

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

830 return true;

831 }

832

833

834

835

836

837 bool HasAlternation = PatternStr.contains('|');

838 if (HasAlternation) {

839 RegExStr += '(';

840 ++CurParen;

841 }

842

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

844 return true;

845 if (HasAlternation)

846 RegExStr += ')';

847

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

849 continue;

850 }

851

852

853

854

855

856

857

858

859

860

861

864

865

866 size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);

869

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

874 return true;

875 }

876

877

878

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

880

881 bool IsDefinition = false;

882 bool SubstNeeded = false;

883

884

885 bool IsLegacyLineExpr = false;

889 std::string WildcardRegexp;

890 size_t SubstInsertIdx = RegExStr.size();

891

892

893 if (!IsNumBlock) {

894 size_t VarEndIdx = MatchStr.find(':');

899 return true;

900 }

901

902

903 StringRef OrigMatchStr = MatchStr;

906 if (!ParseVarResult) {

908 return true;

909 }

911 bool IsPseudo = ParseVarResult->IsPseudo;

912

914 SubstNeeded = !IsDefinition;

915 if (IsDefinition) {

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

919 "invalid name in string variable definition");

920 return true;

921 }

922

923

924

925 if (Context->GlobalNumericVariableTable.contains(Name)) {

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

929 return true;

930 }

931 DefName = Name;

932 MatchRegexp = MatchStr;

933 } else {

934 if (IsPseudo) {

935 MatchStr = OrigMatchStr;

936 IsLegacyLineExpr = IsNumBlock = true;

937 } else {

938 if (!MatchStr.empty()) {

941 "invalid name in string variable use");

942 return true;

943 }

944 SubstStr = Name;

945 }

946 }

947 }

948

949

950 std::unique_ptr ExpressionPointer;

951 std::optional<NumericVariable *> DefinedNumericVariable;

952 if (IsNumBlock) {

955 IsLegacyLineExpr, LineNumber, Context,

956 SM);

959 return true;

960 }

961 ExpressionPointer = std::move(*ParseResult);

962 SubstNeeded = ExpressionPointer->getAST() != nullptr;

963 if (DefinedNumericVariable) {

964 IsDefinition = true;

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

966 }

967 if (SubstNeeded)

968 SubstStr = MatchStr;

969 else {

971 WildcardRegexp = cantFail(Format.getWildcardRegex());

972 MatchRegexp = WildcardRegexp;

973 }

974 }

975

976

977 if (IsDefinition) {

978 RegExStr += '(';

979 ++SubstInsertIdx;

980

981 if (IsNumBlock) {

982 NumericVariableMatch NumericVariableDefinition = {

983 *DefinedNumericVariable, CurParen};

984 NumericVariableDefs[DefName] = NumericVariableDefinition;

985

986

987

988

989 Context->GlobalNumericVariableTable[DefName] =

990 *DefinedNumericVariable;

991 } else {

992 VariableDefs[DefName] = CurParen;

993

994

995

996

997

998

999 Context->DefinedVariableTable[DefName] = true;

1000 }

1001

1002 ++CurParen;

1003 }

1004

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

1006 return true;

1007

1008 if (IsDefinition)

1009 RegExStr += ')';

1010

1011

1012 if (SubstNeeded) {

1013

1014

1015

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

1017 unsigned CaptureParenGroup = VariableDefs[SubstStr];

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

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

1022 return true;

1023 }

1024 AddBackrefToRegEx(CaptureParenGroup);

1025 } else {

1026

1027

1029 IsNumBlock

1030 ? Context->makeNumericSubstitution(

1031 SubstStr, std::move(ExpressionPointer), SubstInsertIdx)

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

1034 }

1035 }

1036

1037 continue;

1038 }

1039

1040

1041

1042 size_t FixedMatchEnd =

1043 std::min(PatternStr.find("{{", 1), PatternStr.find("[[", 1));

1045 PatternStr = PatternStr.substr(FixedMatchEnd);

1046 }

1047

1048 if (MatchFullLinesHere) {

1050 RegExStr += " *";

1051 RegExStr += '$';

1052 }

1053

1054 return false;

1055}

1056

1057bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) {

1059 std::string Error;

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

1062 "invalid regex: " + Error);

1063 return true;

1064 }

1065

1066 RegExStr += RS.str();

1067 CurParen += R.getNumMatches();

1068 return false;

1069}

1070

1071void Pattern::AddBackrefToRegEx(unsigned BackrefNum) {

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

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

1074 RegExStr += Backref;

1075}

1076

1079

1082

1083

1084 if (!FixedStr.empty()) {

1085 size_t Pos =

1088 return make_error();

1090 }

1091

1092

1093

1094

1095

1096 StringRef RegExToMatch = RegExStr;

1097 std::string TmpStr;

1098 if (!Substitutions.empty()) {

1099 TmpStr = RegExStr;

1100 if (LineNumber)

1101 Context->LineVariable->setValue(

1102 APInt(sizeof(*LineNumber) * 8, *LineNumber));

1103

1104 size_t InsertOffset = 0;

1105

1106

1107

1109 for (const auto &Substitution : Substitutions) {

1110

1113

1114

1115

1118 Value.takeError(),

1120 return ErrorDiagnostic::get(

1121 SM, Substitution->getFromString(),

1122 "unable to substitute variable or "

1123 "numeric expression: overflow error");

1124 },

1126 return ErrorDiagnostic::get(SM, E.getVarName(),

1127 E.message());

1128 }));

1129 continue;

1130 }

1131

1132

1135 InsertOffset += Value->size();

1136 }

1137 if (Errs)

1138 return std::move(Errs);

1139

1140

1141 RegExToMatch = TmpStr;

1142 }

1143

1146 if (IgnoreCase)

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

1149 return make_error();

1150

1151

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

1153 StringRef FullMatch = MatchInfo[0];

1154

1155

1156 for (const auto &VariableDef : VariableDefs) {

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

1158 Context->GlobalVariableTable[VariableDef.first] =

1159 MatchInfo[VariableDef.second];

1160 }

1161

1162

1163

1164

1167 TheMatch.Pos = FullMatch.data() - Buffer.data() + MatchStartSkip;

1168 TheMatch.Len = FullMatch.size() - MatchStartSkip;

1169

1170

1171 for (const auto &NumericVariableDef : NumericVariableDefs) {

1172 const NumericVariableMatch &NumericVariableMatch =

1173 NumericVariableDef.getValue();

1174 unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup;

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

1177 NumericVariableMatch.DefinedNumericVariable;

1178

1179 StringRef MatchedValue = MatchInfo[CaptureParenGroup];

1182 DefinedNumericVariable->setValue(Value, MatchedValue);

1183 }

1184

1186}

1187

1188unsigned Pattern::computeMatchDistance(StringRef Buffer) const {

1189

1190

1191

1192

1193

1194

1195 StringRef ExampleString(FixedStr);

1196 if (ExampleString.empty())

1197 ExampleString = RegExStr;

1198

1199

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

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

1202 return BufferPrefix.edit_distance(ExampleString);

1203}

1204

1208 std::vector *Diags) const {

1209

1210 if (!Substitutions.empty()) {

1211 for (const auto &Substitution : Substitutions) {

1214

1216

1217 if (!MatchedValue) {

1219 continue;

1220 }

1221

1222 OS << "with \"";

1225

1226

1227

1228

1229

1230 if (Diags)

1231 Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy,

1233 else

1235 }

1236 }

1237}

1238

1241 std::vector *Diags) const {

1242 if (VariableDefs.empty() && NumericVariableDefs.empty())

1243 return;

1244

1245 struct VarCapture {

1248 };

1250 for (const auto &VariableDef : VariableDefs) {

1251 VarCapture VC;

1252 VC.Name = VariableDef.first;

1253 StringRef Value = Context->GlobalVariableTable[VC.Name];

1258 }

1259 for (const auto &VariableDef : NumericVariableDefs) {

1260 VarCapture VC;

1261 VC.Name = VariableDef.getKey();

1262 std::optional StrValue =

1263 VariableDef.getValue().DefinedNumericVariable->getStringValue();

1264 if (!StrValue)

1265 continue;

1270 }

1271

1272

1273 llvm::sort(VarCaptures, [](const VarCapture &A, const VarCapture &B) {

1274 if (&A == &B)

1275 return false;

1276 assert(A.Range.Start != B.Range.Start &&

1277 "unexpected overlapping variable captures");

1278 return A.Range.Start.getPointer() < B.Range.Start.getPointer();

1279 });

1280

1281 for (const VarCapture &VC : VarCaptures) {

1284 OS << "captured var \"" << VC.Name << "\"";

1285 if (Diags)

1286 Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, VC.Range, OS.str());

1287 else

1289 }

1290}

1291

1295 StringRef Buffer, size_t Pos, size_t Len,

1296 std::vector *Diags,

1297 bool AdjustPrevDiags = false) {

1301 if (Diags) {

1302 if (AdjustPrevDiags) {

1303 SMLoc CheckLoc = Diags->rbegin()->CheckLoc;

1304 for (auto I = Diags->rbegin(), E = Diags->rend();

1305 I != E && I->CheckLoc == CheckLoc; ++I)

1306 I->MatchTy = MatchTy;

1307 } else

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

1309 }

1311}

1312

1314 std::vector *Diags) const {

1315

1316

1317

1318

1319 size_t NumLinesForward = 0;

1321 double BestQuality = 0;

1322

1323

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

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

1326 ++NumLinesForward;

1327

1328

1329

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

1331 continue;

1332

1333

1334

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

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

1337

1339 Best = i;

1340 BestQuality = Quality;

1341 }

1342 }

1343

1344

1345

1346

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

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

1352 "possible intended match here");

1353

1354

1355

1356 }

1357}

1358

1361 auto VarIter = GlobalVariableTable.find(VarName);

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

1363 return make_error(VarName);

1364

1365 return VarIter->second;

1366}

1367

1368template <class... Types>

1369NumericVariable *FileCheckPatternContext::makeNumericVariable(Types... args) {

1370 NumericVariables.push_back(std::make_unique(args...));

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

1372}

1373

1375FileCheckPatternContext::makeStringSubstitution(StringRef VarName,

1376 size_t InsertIdx) {

1377 Substitutions.push_back(

1378 std::make_unique(this, VarName, InsertIdx));

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

1380}

1381

1382Substitution *FileCheckPatternContext::makeNumericSubstitution(

1384 size_t InsertIdx) {

1385 Substitutions.push_back(std::make_unique(

1386 this, ExpressionStr, std::move(Expression), InsertIdx));

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

1388}

1389

1391

1393

1394 size_t BracketDepth = 0;

1395

1396 while (!Str.empty()) {

1397 if (Str.starts_with("]]") && BracketDepth == 0)

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

1400

1401 Str = Str.substr(2);

1403 } else {

1404 switch (Str[0]) {

1405 default:

1406 break;

1407 case '[':

1408 BracketDepth++;

1409 break;

1410 case ']':

1411 if (BracketDepth == 0) {

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

1415 exit(1);

1416 }

1417 BracketDepth--;

1418 break;

1419 }

1420 Str = Str.substr(1);

1422 }

1423 }

1424

1426}

1427

1431

1434

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

1436 continue;

1437 }

1438

1439

1440

1443 continue;

1444 }

1445

1446

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

1450 }

1451

1452

1455}

1456

1461 : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy), Note(Note) {

1468}

1469

1471 return (isAlnum(c) || c == '-' || c == '_');

1472}

1473

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

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

1478 Count = C;

1479 return *this;

1480}

1481

1483 if (Modifiers.none())

1484 return "";

1485 std::string Ret;

1487 OS << '{';

1488 if (isLiteralMatch())

1489 OS << "LITERAL";

1490 OS << '}';

1491 return Ret;

1492}

1493

1495

1496 auto WithModifiers = [this, Prefix](StringRef Str) -> std::string {

1497 return (Prefix + Str + getModifiersDescription()).str();

1498 };

1499

1500 switch (Kind) {

1502 return "invalid";

1504 return "misspelled";

1506 if (Count > 1)

1507 return WithModifiers("-COUNT");

1508 return WithModifiers("");

1510 return WithModifiers("-NEXT");

1512 return WithModifiers("-SAME");

1514 return WithModifiers("-NOT");

1516 return WithModifiers("-DAG");

1518 return WithModifiers("-LABEL");

1520 return WithModifiers("-EMPTY");

1522 return std::string(Prefix);

1524 return "implicit EOF";

1526 return "bad NOT";

1528 return "bad COUNT";

1529 }

1531}

1532

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

1535 bool &Misspelled) {

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

1538

1540

1544

1546 }

1547

1549 -> std::pair<Check::FileCheckType, StringRef> {

1551 return {Ret, Rest};

1554

1555

1556 do {

1557

1558 Rest = Rest.ltrim();

1560 Ret.setLiteralMatch();

1561 else

1563

1564 Rest = Rest.ltrim();

1568 return {Ret, Rest};

1569 };

1570

1571

1574 if (Rest.front() == '{')

1576

1578 Misspelled = true;

1581

1583 int64_t Count;

1585

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

1589 if (Rest.front() != ':' && Rest.front() != '{')

1591 return ConsumeModifiers(

1593 }

1594

1595

1601

1604

1607

1610

1613

1616

1619

1621}

1622

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

1625 bool Misspelled = false;

1626 auto Res = FindCheckType(Req, Buffer, Prefix, Misspelled);

1629 return Res;

1630}

1631

1632

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

1635 ++Loc;

1636 return Loc;

1637}

1638

1641

1647 }

1651}

1652

1654

1657

1660 : Input(Input) {

1661 for (StringRef Prefix : CheckPrefixes)

1662 Prefixes.push_back({Prefix, Input.find(Prefix)});

1663 for (StringRef Prefix : CommentPrefixes)

1664 Prefixes.push_back({Prefix, Input.find(Prefix)});

1665

1666

1668 [](auto A, auto B) { return A.first.size() > B.first.size(); });

1669 }

1670

1671

1672

1675 Buffer.data() + Buffer.size() == Input.data() + Input.size() &&

1676 "Buffer must be suffix of Input");

1677

1680 for (auto &[Prefix, Pos] : Prefixes) {

1681

1682 if (Pos < From)

1683 Pos = Input.find(Prefix, From);

1684

1686 (Match.empty() || size_t(Match.data() - Input.data()) > Pos))

1688 }

1690 }

1691};

1692

1693

1694

1695

1696

1697

1698

1699

1700

1701

1702

1703

1704

1705

1706

1707

1708

1709

1710

1711

1712

1713

1714

1715

1716static std::pair<StringRef, StringRef>

1718 StringRef &Buffer, unsigned &LineNumber,

1720 while (!Buffer.empty()) {

1721

1723 if (Prefix.empty())

1724

1726

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

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

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

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

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

1734

1735

1736

1737

1738

1739

1741

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

1744

1745

1747 return {Prefix, AfterSuffix};

1748 }

1749

1750

1751

1752

1754 }

1755

1756

1758}

1759

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

1763 LineVariable = makeNumericVariable(

1765 GlobalNumericVariableTable[LineName] = LineVariable;

1766}

1767

1770

1772

1775 std::pair<unsigned, unsigned> *ImpPatBufferIDRange) {

1776 if (ImpPatBufferIDRange)

1777 ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0;

1778

1779 Error DefineError =

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

1781 if (DefineError) {

1783 return true;

1784 }

1785

1786 PatternContext->createLineVariable();

1787

1788 std::vectorFileCheckString::DagNotPrefixInfo ImplicitNegativeChecks;

1790

1791

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

1793 std::string Suffix = "'";

1795 (Prefix + PatternString + Suffix).str(), "command line");

1796

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

1800 if (ImpPatBufferIDRange) {

1801 if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) {

1802 ImpPatBufferIDRange->first = BufferID;

1803 ImpPatBufferIDRange->second = BufferID + 1;

1804 } else {

1805 assert(BufferID == ImpPatBufferIDRange->second &&

1806 "expected consecutive source buffer IDs");

1807 ++ImpPatBufferIDRange->second;

1808 }

1809 }

1810

1811 ImplicitNegativeChecks.emplace_back(

1814 ImplicitNegativeChecks.back().DagNotPat.parsePattern(

1815 PatternInBuffer, "IMPLICIT-CHECK", SM, Req);

1816 }

1817

1818 std::vectorFileCheckString::DagNotPrefixInfo DagNotMatches =

1819 ImplicitNegativeChecks;

1820

1821

1822 unsigned LineNumber = 1;

1823

1826 std::set PrefixesNotFound(Req.CheckPrefixes.begin(),

1828 const size_t DistinctPrefixes = PrefixesNotFound.size();

1829 while (true) {

1831

1832

1835 std::tie(UsedPrefix, AfterSuffix) =

1837 if (UsedPrefix.empty())

1838 break;

1840 PrefixesNotFound.erase(UsedPrefix);

1841

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

1844 "of the buffer!");

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

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

1848

1849

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

1851

1852

1853

1855 : AfterSuffix;

1856

1857

1860 AfterSuffix.data() - UsedPrefix.data());

1863 "misspelled directive '" + UsedDirective + "'");

1864 return true;

1865 }

1866

1867

1870 "unsupported -NOT combo on prefix '" + UsedPrefix + "'");

1871 return true;

1872 }

1873

1874

1877 "invalid count in -COUNT specification on prefix '" +

1878 UsedPrefix + "'");

1879 return true;

1880 }

1881

1882

1883

1886

1887

1889

1890

1892

1893

1895 Buffer = Buffer.substr(EOL);

1896

1897

1899 continue;

1900

1901

1902 Pattern P(CheckTy, PatternContext.get(), LineNumber);

1903 if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req))

1904 return true;

1905

1906

1910 "found '" + UsedPrefix + "-LABEL:'"

1911 " with variable definition or use");

1912 return true;

1913 }

1914

1915

1918 CheckStrings.empty()) {

1920 ? "NEXT"

1924 "found '" + UsedPrefix + "-" + Type +

1925 "' without previous '" + UsedPrefix + ": line");

1926 return true;

1927 }

1928

1929

1931 DagNotMatches.emplace_back(P, UsedPrefix);

1932 continue;

1933 }

1934

1935

1936 CheckStrings.emplace_back(P, UsedPrefix, PatternLoc);

1937 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);

1938 DagNotMatches = ImplicitNegativeChecks;

1939 }

1940

1941

1942

1943 const bool NoPrefixesFound = PrefixesNotFound.size() == DistinctPrefixes;

1944 const bool SomePrefixesUnexpectedlyNotUsed =

1946 if ((NoPrefixesFound || SomePrefixesUnexpectedlyNotUsed) &&

1948 errs() << "error: no check strings found with prefix"

1949 << (PrefixesNotFound.size() > 1 ? "es " : " ");

1950 bool First = true;

1951 for (StringRef MissingPrefix : PrefixesNotFound) {

1953 errs() << ", ";

1954 errs() << "\'" << MissingPrefix << ":'";

1956 }

1957 errs() << '\n';

1958 return true;

1959 }

1960

1961

1962

1963 if (!DagNotMatches.empty()) {

1964 CheckStrings.emplace_back(

1967 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);

1968 }

1969

1970 return false;

1971}

1972

1973

1974

1977 int MatchedCount, StringRef Buffer,

1980 std::vector *Diags) {

1981

1982 bool HasError = !ExpectedMatch || MatchResult.TheError;

1983 bool PrintDiag = true;

1984 if (!HasError) {

1989

1990

1991

1992 PrintDiag = !Diags;

1993 }

1994

1995

2000 Buffer, MatchResult.TheMatch->Pos,

2001 MatchResult.TheMatch->Len, Diags);

2002 if (Diags) {

2005 }

2006 if (!PrintDiag) {

2007 assert(!HasError && "expected to report more diagnostics for error");

2009 }

2010

2011

2012 std::string Message = formatv("{0}: {1} string found in input",

2014 (ExpectedMatch ? "expected" : "excluded"))

2015 .str();

2017 Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();

2021 {MatchRange});

2022

2023

2026

2027

2028

2029

2032 E.log(errs());

2033 if (Diags) {

2034 Diags->emplace_back(SM, Pat.getCheckTy(), Loc,

2035 FileCheckDiag::MatchFoundErrorNote,

2036 E.getRange(), E.getMessage().str());

2037 }

2038 });

2040}

2041

2042

2043

2044

2047 int MatchedCount, StringRef Buffer, Error MatchError,

2048 bool VerboseVerbose,

2049 std::vector *Diags) {

2050

2051 bool HasError = ExpectedMatch;

2052 bool HasPatternError = false;

2058 std::move(MatchError),

2060 HasError = HasPatternError = true;

2063 if (Diags)

2065 },

2066

2068

2069

2070 bool PrintDiag = true;

2071 if (!HasError) {

2072 if (!VerboseVerbose)

2074

2075

2076

2077 PrintDiag = !Diags;

2078 }

2079

2080

2081

2082

2083

2084

2085

2086

2088 Buffer, 0, Buffer.size(), Diags);

2089 if (Diags) {

2091 for (StringRef ErrorMsg : ErrorMsgs)

2092 Diags->emplace_back(SM, Pat.getCheckTy(), Loc, MatchTy, NoteRange,

2093 ErrorMsg);

2095 }

2096 if (!PrintDiag) {

2097 assert(!HasError && "expected to report more diagnostics for error");

2099 }

2100

2101

2102

2103 if (!HasPatternError) {

2104 std::string Message = formatv("{0}: {1} string not found in input",

2106 (ExpectedMatch ? "expected" : "excluded"))

2107 .str();

2109 Message +=

2110 formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();

2113 Message);

2115 "scanning from here");

2116 }

2117

2118

2119

2121 if (ExpectedMatch)

2124}

2125

2126

2127

2130 int MatchedCount, StringRef Buffer,

2133 std::vector *Diags) {

2135 return printMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer,

2136 std::move(MatchResult), Req, Diags);

2137 return printNoMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer,

2139 Diags);

2140}

2141

2142

2144 const char *&FirstNewLine) {

2145 unsigned NumNewLines = 0;

2146 while (true) {

2147

2149 if (Range.empty())

2150 return NumNewLines;

2151

2152 ++NumNewLines;

2153

2154

2155 if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') &&

2159

2160 if (NumNewLines == 1)

2161 FirstNewLine = Range.begin();

2162 }

2163}

2164

2166 bool IsLabelScanMode, size_t &MatchLen,

2168 std::vector *Diags) const {

2169 size_t LastPos = 0;

2170 std::vector<const DagNotPrefixInfo *> NotStrings;

2171

2172

2173

2174

2175

2176 if (!IsLabelScanMode) {

2177

2178 LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);

2181 }

2182

2183

2184 size_t LastMatchEnd = LastPos;

2185 size_t FirstMatchPos = 0;

2186

2187

2189 for (int i = 1; i <= Pat.getCount(); i++) {

2191

2193

2194

2196 Pat, i, MatchBuffer,

2197 std::move(MatchResult), Req, Diags)) {

2200 }

2201

2202 size_t MatchPos = MatchResult.TheMatch->Pos;

2203 if (i == 1)

2204 FirstMatchPos = LastPos + MatchPos;

2205

2206

2207 LastMatchEnd += MatchPos + MatchResult.TheMatch->Len;

2208 }

2209

2210 MatchLen = LastMatchEnd - FirstMatchPos;

2211

2212

2213

2214 if (!IsLabelScanMode) {

2215 size_t MatchPos = FirstMatchPos - LastPos;

2217 StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);

2218

2219

2220

2221 if (CheckNext(SM, SkippedRegion)) {

2223 Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,

2226 }

2227

2228

2229

2230 if (CheckSame(SM, SkippedRegion)) {

2232 Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,

2235 }

2236

2237

2238

2239 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))

2241 }

2242

2243 return FirstMatchPos;

2244}

2245

2249 return false;

2250

2251 Twine CheckName =

2254

2255

2256 const char *FirstNewLine = nullptr;

2258

2259 if (NumNewLines == 0) {

2261 CheckName + ": is on the same line as previous match");

2263 "'next' match was here");

2265 "previous match ended here");

2266 return true;

2267 }

2268

2269 if (NumNewLines != 1) {

2271 CheckName +

2272 ": is not on the line after the previous match");

2274 "'next' match was here");

2276 "previous match ended here");

2278 "non-matching line after previous match is here");

2279 return true;

2280 }

2281

2282 return false;

2283}

2284

2287 return false;

2288

2289

2290 const char *FirstNewLine = nullptr;

2292

2293 if (NumNewLines != 0) {

2296 "-SAME: is not on the same line as the previous match");

2298 "'next' match was here");

2300 "previous match ended here");

2301 return true;

2302 }

2303

2304 return false;

2305}

2306

2309 const std::vector<const DagNotPrefixInfo *> &NotStrings,

2310 const FileCheckRequest &Req, std::vector *Diags) const {

2311 bool DirectiveFail = false;

2312 for (auto NotInfo : NotStrings) {

2314 "Expect CHECK-NOT!");

2317 false, SM, NotInfo->DagNotPrefix,

2318 NotInfo->DagNotPat.getLoc(), NotInfo->DagNotPat, 1, Buffer,

2319 std::move(MatchResult), Req, Diags)) {

2321 DirectiveFail = true;

2322 continue;

2323 }

2324 }

2325 return DirectiveFail;

2326}

2327

2328size_t

2330 std::vector<const DagNotPrefixInfo *> &NotStrings,

2332 std::vector *Diags) const {

2334 return 0;

2335

2336

2337 size_t StartPos = 0;

2338

2339 struct MatchRange {

2340 size_t Pos;

2341 size_t End;

2342 };

2343

2344

2345

2346 std::list MatchRanges;

2347

2348

2349

2351 PatItr != PatEnd; ++PatItr) {

2352 const Pattern &Pat = PatItr->DagNotPat;

2353 const StringRef DNPrefix = PatItr->DagNotPrefix;

2356 "Invalid CHECK-DAG or CHECK-NOT!");

2357

2359 NotStrings.push_back(&*PatItr);

2360 continue;

2361 }

2362

2364

2365

2366 size_t MatchLen = 0, MatchPos = StartPos;

2367

2368

2369

2370 for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {

2373

2374

2378 std::move(MatchResult), Req, Diags)) {

2382 }

2383 }

2384 MatchLen = MatchResult.TheMatch->Len;

2385

2386

2387 MatchPos += MatchResult.TheMatch->Pos;

2388 MatchRange M{MatchPos, MatchPos + MatchLen};

2390

2391

2392

2393 if (MatchRanges.empty())

2394 MatchRanges.insert(MatchRanges.end(), M);

2395 else {

2396 auto Block = MatchRanges.begin();

2397 Block->Pos = std::min(Block->Pos, M.Pos);

2398 Block->End = std::max(Block->End, M.End);

2399 }

2400 break;

2401 }

2402

2403 bool Overlap = false;

2404 for (; MI != ME; ++MI) {

2405 if (M.Pos < MI->End) {

2406

2407

2408 Overlap = MI->Pos < M.End;

2409 break;

2410 }

2411 }

2412 if (!Overlap) {

2413

2414 MatchRanges.insert(MI, M);

2415 break;

2416 }

2418

2419

2420

2421 if (!Diags) {

2424 SMRange OldRange(OldStart, OldEnd);

2426 "match discarded, overlaps earlier DAG match here",

2427 {OldRange});

2428 } else {

2429 SMLoc CheckLoc = Diags->rbegin()->CheckLoc;

2430 for (auto I = Diags->rbegin(), E = Diags->rend();

2431 I != E && I->CheckLoc == CheckLoc; ++I)

2433 }

2434 }

2435 MatchPos = MI->End;

2436 }

2439 true, SM, DNPrefix, Pat.getLoc(), Pat, 1, Buffer,

2441 Diags));

2442

2443

2444 if (std::next(PatItr) == PatEnd ||

2445 std::next(PatItr)->DagNotPat.getCheckTy() == Check::CheckNot) {

2446 if (!NotStrings.empty()) {

2447

2448

2449

2451 Buffer.slice(StartPos, MatchRanges.begin()->Pos);

2452 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))

2454

2455 NotStrings.clear();

2456 }

2457

2458

2459 StartPos = MatchRanges.rbegin()->End;

2460

2461 MatchRanges.clear();

2462 }

2463 }

2464

2465 return StartPos;

2466}

2467

2470 for (StringRef Prefix : SuppliedPrefixes) {

2471 if (Prefix.empty()) {

2472 errs() << "error: supplied " << Kind << " prefix must not be the empty "

2473 << "string\n";

2474 return false;

2475 }

2476 static const Regex Validator("^[a-zA-Z0-9_-]*$");

2477 if (!Validator.match(Prefix)) {

2478 errs() << "error: supplied " << Kind << " prefix must start with a "

2479 << "letter and contain only alphanumeric characters, hyphens, and "

2480 << "underscores: '" << Prefix << "'\n";

2481 return false;

2482 }

2483 if (!UniquePrefixes.insert(Prefix).second) {

2484 errs() << "error: supplied " << Kind << " prefix must be unique among "

2485 << "check and comment prefixes: '" << Prefix << "'\n";

2486 return false;

2487 }

2488 }

2489 return true;

2490}

2491

2494

2497 UniquePrefixes.insert(Prefix);

2498 }

2501 UniquePrefixes.insert(Prefix);

2502 }

2503

2504

2506 return false;

2508 return false;

2509 return true;

2510}

2511

2514 assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&

2515 "Overriding defined variable with command-line variable definitions");

2516

2517 if (CmdlineDefines.empty())

2519

2520

2521

2522

2523 unsigned I = 0;

2525 std::string CmdlineDefsDiag;

2527 for (StringRef CmdlineDef : CmdlineDefines) {

2528 std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();

2529 size_t EqIdx = CmdlineDef.find('=');

2531 CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));

2532 continue;

2533 }

2534

2535 if (CmdlineDef[0] == '#') {

2536

2537

2538

2539 CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();

2540 std::string SubstitutionStr = std::string(CmdlineDef);

2541 SubstitutionStr[EqIdx] = ':';

2543 std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));

2544 CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();

2545 } else {

2546 CmdlineDefsDiag += DefPrefix;

2548 std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));

2549 CmdlineDefsDiag += (CmdlineDef + "\n").str();

2550 }

2551 }

2552

2553

2554

2555

2556 std::unique_ptr CmdLineDefsDiagBuffer =

2558 StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();

2560

2561 for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {

2562 StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,

2563 CmdlineDefIndices.second);

2564 if (CmdlineDef.empty()) {

2566 std::move(Errs),

2568 "missing equal sign in global definition"));

2569 continue;

2570 }

2571

2572

2573 if (CmdlineDef[0] == '#') {

2574

2575

2577 std::optional<NumericVariable *> DefinedNumericVariable;

2580 DefinedNumericVariable, false,

2581 std::nullopt, this, SM);

2582 if (!ExpressionResult) {

2584 continue;

2585 }

2586 std::unique_ptr Expression = std::move(*ExpressionResult);

2587

2588

2589

2590

2594 continue;

2595 }

2596

2597 assert(DefinedNumericVariable && "No variable defined");

2598 (*DefinedNumericVariable)->setValue(*Value);

2599

2600

2601 GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =

2602 *DefinedNumericVariable;

2603 } else {

2604

2605 std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');

2606 StringRef CmdlineName = CmdlineNameVal.first;

2607 StringRef OrigCmdlineName = CmdlineName;

2610 if (!ParseVarResult) {

2612 continue;

2613 }

2614

2615

2616

2617 if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {

2620 SM, OrigCmdlineName,

2621 "invalid name in string variable definition '" +

2622 OrigCmdlineName + "'"));

2623 continue;

2624 }

2626

2627

2628

2629 if (GlobalNumericVariableTable.contains(Name)) {

2632 "numeric variable with name '" +

2633 Name + "' already exists"));

2634 continue;

2635 }

2636 GlobalVariableTable.insert(CmdlineNameVal);

2637

2638

2639

2640

2641

2642

2643 DefinedVariableTable[Name] = true;

2644 }

2645 }

2646

2647 return Errs;

2648}

2649

2653 if (Var.first()[0] != '$')

2654 LocalPatternVars.push_back(Var.first());

2655

2656

2657

2658

2659

2660

2661

2662 for (const auto &Var : GlobalNumericVariableTable)

2663 if (Var.first()[0] != '$') {

2664 Var.getValue()->clearValue();

2665 LocalNumericVars.push_back(Var.first());

2666 }

2667

2668 for (const auto &Var : LocalPatternVars)

2669 GlobalVariableTable.erase(Var);

2670 for (const auto &Var : LocalNumericVars)

2671 GlobalNumericVariableTable.erase(Var);

2672}

2673

2675 std::vector *Diags) {

2676 bool ChecksFailed = false;

2677

2678 unsigned i = 0, j = 0, e = CheckStrings.size();

2679 while (true) {

2681 if (j == e) {

2682 CheckRegion = Buffer;

2683 } else {

2686 ++j;

2687 continue;

2688 }

2689

2690

2691 size_t MatchLabelLen = 0;

2692 size_t MatchLabelPos =

2693 CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);

2695

2696 return false;

2697

2698 CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);

2699 Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);

2700 ++j;

2701 }

2702

2703

2704

2705

2707 PatternContext->clearLocalVars();

2708

2709 for (; i != j; ++i) {

2711

2712

2713

2714 size_t MatchLen = 0;

2715 size_t MatchPos =

2716 CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);

2717

2719 ChecksFailed = true;

2720 i = j;

2721 break;

2722 }

2723

2724 CheckRegion = CheckRegion.substr(MatchPos + MatchLen);

2725 }

2726

2727 if (j == e)

2728 break;

2729 }

2730

2731

2732 return !ChecksFailed;

2733}

BlockVerifier::State From

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static std::pair< StringRef, StringRef > FindFirstMatchingPrefix(const FileCheckRequest &Req, PrefixMatcher &Matcher, StringRef &Buffer, unsigned &LineNumber, Check::FileCheckType &CheckTy)

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

static size_t SkipWord(StringRef Str, size_t Loc)

static char popFront(StringRef &S)

constexpr StringLiteral SpaceChars

static Error reportMatchResult(bool ExpectedMatch, const SourceMgr &SM, StringRef Prefix, SMLoc Loc, const Pattern &Pat, int MatchedCount, StringRef Buffer, Pattern::MatchResult MatchResult, const FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags)

Returns either (1) ErrorSuccess if there was no error, or (2) ErrorReported if an error was reported.

static Error printNoMatch(bool ExpectedMatch, const SourceMgr &SM, StringRef Prefix, SMLoc Loc, const Pattern &Pat, int MatchedCount, StringRef Buffer, Error MatchError, bool VerboseVerbose, std::vector< FileCheckDiag > *Diags)

Returns either (1) ErrorSuccess if there was no error, or (2) ErrorReported if an error was reported,...

static std::pair< Check::FileCheckType, StringRef > FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix, bool &Misspelled)

static const char * DefaultCheckPrefixes[]

static const char * DefaultCommentPrefixes[]

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 AdjustPrevDiags=false)

static unsigned CountNumNewlinesBetween(StringRef Range, const char *&FirstNewLine)

Counts the number of newlines in the specified range.

static APInt toSigned(APInt AbsVal, bool Negative)

static Error printMatch(bool ExpectedMatch, const SourceMgr &SM, StringRef Prefix, SMLoc Loc, const Pattern &Pat, int MatchedCount, StringRef Buffer, Pattern::MatchResult MatchResult, const FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags)

Returns either (1) ErrorSuccess if there was no error or (2) ErrorReported if an error was reported,...

static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes, ArrayRef< StringRef > SuppliedPrefixes)

static void addDefaultPrefixes(FileCheckRequest &Req)

static unsigned nextAPIntBitWidth(unsigned BitWidth)

static bool IsPartOfWord(char c)

ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

StringSet - A set-like wrapper for the StringMap.

Class for arbitrary precision integers.

APInt zext(unsigned width) const

Zero extend to a new width.

APInt abs() const

Get the absolute value.

bool isZero() const

Determine if this value is zero, i.e. all bits are clear.

unsigned getBitWidth() const

Return the number of bits in the APInt.

bool isNegative() const

Determine sign of this APInt.

APInt sadd_ov(const APInt &RHS, bool &Overflow) const

APInt sdiv_ov(const APInt &RHS, bool &Overflow) const

static constexpr unsigned APINT_BITS_PER_WORD

Bits in a word.

APInt smul_ov(const APInt &RHS, bool &Overflow) const

APInt sext(unsigned width) const

Sign extend to a new width.

bool isSignBitSet() const

Determine if sign bit of this APInt is set.

bool slt(const APInt &RHS) const

Signed less than comparison.

APInt ssub_ov(const APInt &RHS, bool &Overflow) const

void toString(SmallVectorImpl< char > &Str, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false) const

Converts an APInt to a string and append it to Str.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

bool empty() const

empty - Check if the array is empty.

Expected< ExpressionFormat > getImplicitFormat(const SourceMgr &SM) const override

Expected< APInt > eval() const override

Evaluates the value of the binary operation represented by this AST, using EvalBinop on the result of...

std::string getDescription(StringRef Prefix) const

bool isLiteralMatch() const

std::string getModifiersDescription() const

FileCheckType & setCount(int C)

Class to represent an error holding a diagnostic with location information used when printing it.

StringRef getMessage() const

void log(raw_ostream &OS) const override

Print diagnostic associated with this error when printing the error.

static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg, SMRange Range=std::nullopt)

An error that has already been reported.

static Error reportedOrSuccess(bool HasErrorReported)

Lightweight error class with error context and mandatory checking.

static ErrorSuccess success()

Create a success value.

Tagged union holding either a T or a Error.

Error takeError()

Take ownership of the stored error.

virtual Expected< APInt > eval() const =0

Evaluates and.

StringRef getExpressionStr() const

Class representing an expression and its matching format.

ExpressionAST * getAST() const

Class holding the Pattern global state, shared by all patterns: tables holding values of variables an...

Error defineCmdlineVariables(ArrayRef< StringRef > CmdlineDefines, SourceMgr &SM)

Defines string and numeric variables from definitions given on the command line, passed as a vector o...

void createLineVariable()

Create @LINE pseudo variable.

Expected< StringRef > getPatternVarValue(StringRef VarName)

void clearLocalVars()

Undefines local variables (variables whose name does not start with a '$' sign), i....

bool readCheckFile(SourceMgr &SM, StringRef Buffer, std::pair< unsigned, unsigned > *ImpPatBufferIDRange=nullptr)

Reads the check file from Buffer and records the expected strings it contains.

StringRef CanonicalizeFile(MemoryBuffer &MB, SmallVectorImpl< char > &OutputBuffer)

Canonicalizes whitespaces in the file.

FileCheck(FileCheckRequest Req)

bool checkInput(SourceMgr &SM, StringRef Buffer, std::vector< FileCheckDiag > *Diags=nullptr)

Checks the input to FileCheck provided in the Buffer against the expected strings read from the check...

bool ValidateCheckPrefixes()

This interface provides simple read-only access to a block of memory, and provides simple methods for...

size_t getBufferSize() const

static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")

Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.

const char * getBufferEnd() const

const char * getBufferStart() const

Expected< std::string > getResult() const override

Expected< APInt > eval() const override

Class representing a numeric variable and its associated current value.

void setValue(APInt NewValue, std::optional< StringRef > NewStrValue=std::nullopt)

Sets value of this numeric variable to NewValue, and sets the input buffer string from which it was p...

ExpressionFormat getImplicitFormat() const

std::optional< APInt > getValue() const

std::optional< size_t > getDefLineNumber() const

This is a utility class that provides an abstraction for the common functionality between Instruction...

Class to represent an overflow error that might result when manipulating a value.

This class represents success/failure for parsing-like operations that find it important to chain tog...

static Expected< VariableProperties > parseVariable(StringRef &Str, const SourceMgr &SM)

Parses the string at the start of Str for a variable name.

MatchResult match(StringRef Buffer, const SourceMgr &SM) const

Matches the pattern string against the input buffer Buffer.

void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, std::vector< FileCheckDiag > *Diags) const

void printSubstitutions(const SourceMgr &SM, StringRef Buffer, SMRange MatchRange, FileCheckDiag::MatchType MatchTy, std::vector< FileCheckDiag > *Diags) const

Prints the value of successful substitutions.

static Expected< std::unique_ptr< Expression > > parseNumericSubstitutionBlock(StringRef Expr, std::optional< NumericVariable * > &DefinedNumericVariable, bool IsLegacyLineExpr, std::optional< size_t > LineNumber, FileCheckPatternContext *Context, const SourceMgr &SM)

Parses Expr for a numeric substitution block at line LineNumber, or before input is parsed if LineNum...

void printVariableDefs(const SourceMgr &SM, FileCheckDiag::MatchType MatchTy, std::vector< FileCheckDiag > *Diags) const

static bool isValidVarNameStart(char C)

Check::FileCheckType getCheckTy() const

bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM, const FileCheckRequest &Req)

Parses the pattern in PatternStr and initializes this Pattern instance accordingly.

@ Newline

Compile for newline-sensitive matching.

@ IgnoreCase

Compile for matching that ignores upper/lower case distinctions.

static std::string escape(StringRef String)

Turn String into a regex by escaping its special characters.

bool match(StringRef String, SmallVectorImpl< StringRef > *Matches=nullptr, std::string *Error=nullptr) const

matches - Match the regex against a given String.

Represents a location in source code.

static SMLoc getFromPointer(const char *Ptr)

Represents a range in source code.

SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void reserve(size_type N)

void push_back(const T &Elt)

pointer data()

Return a pointer to the vector's buffer, even if empty().

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.

std::pair< unsigned, unsigned > getLineAndColumn(SMLoc Loc, unsigned BufferID=0) const

Find the line and column number for the specified location in the specified file.

void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, ArrayRef< SMRange > Ranges={}, ArrayRef< SMFixIt > FixIts={}, bool ShowColors=true) const

Emit a message about the specified location with the specified string.

unsigned AddNewSourceBuffer(std::unique_ptr< MemoryBuffer > F, SMLoc IncludeLoc)

Add a new source buffer to this source manager.

A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...

StringMapEntry - This is used to represent one value that is inserted into a StringMap.

bool contains(StringRef Key) const

contains - Return true if the element is in the map, false otherwise.

StringRef - Represent a constant reference to a string, i.e.

std::pair< StringRef, StringRef > split(char Separator) const

Split into two substrings around the first occurrence of a separator character.

bool consumeInteger(unsigned Radix, T &Result)

Parse the current string as an integer of the specified radix.

std::string str() const

str - Get the contents as an std::string.

constexpr StringRef substr(size_t Start, size_t N=npos) const

Return a reference to the substring from [Start, Start + N).

bool starts_with(StringRef Prefix) const

Check if this string starts with the given Prefix.

constexpr bool empty() const

empty - Check if the string is empty.

StringRef drop_front(size_t N=1) const

Return a StringRef equal to 'this' but with the first N elements dropped.

unsigned edit_distance(StringRef Other, bool AllowReplacements=true, unsigned MaxEditDistance=0) const

Determine the edit distance between this string and another string.

char back() const

back - Get the last character in the string.

StringRef slice(size_t Start, size_t End) const

Return a reference to the substring from [Start, End).

constexpr size_t size() const

size - Get the string size.

char front() const

front - Get the first character in the string.

constexpr const char * data() const

data - Get a pointer to the start of the string (which may not be null terminated).

StringRef ltrim(char Char) const

Return string with consecutive Char characters starting from the the left removed.

bool contains(StringRef Other) const

Return true if the given string is a substring of *this, and false otherwise.

bool consume_front(StringRef Prefix)

Returns true if this StringRef has the given prefix and removes that prefix.

size_t find_first_of(char C, size_t From=0) const

Find the first character in the string that is C, or npos if not found.

StringRef rtrim(char Char) const

Return string with consecutive Char characters starting from the right removed.

StringRef take_front(size_t N=1) const

Return a StringRef equal to 'this' but with only the first N elements remaining.

size_t find(char C, size_t From=0) const

Search for the first character C in the string.

StringRef trim(char Char) const

Return string with consecutive Char characters starting from the left and right removed.

size_t find_insensitive(char C, size_t From=0) const

Search for the first character C in the string, ignoring case.

size_t count(char C) const

Return the number of occurrences of C in the string.

static constexpr size_t npos

StringRef drop_back(size_t N=1) const

Return a StringRef equal to 'this' but with the last N elements dropped.

size_t find_first_not_of(char C, size_t From=0) const

Find the first character in the string that is not C or npos if not found.

StringSet - A wrapper for StringMap that provides set-like functionality.

std::pair< typename Base::iterator, bool > insert(StringRef key)

Expected< std::string > getResult() const override

A switch()-like statement whose cases are string literals.

StringSwitch & Case(StringLiteral S, T Value)

Class representing a substitution to perform in the RegExStr string.

StringRef getFromString() const

FileCheckPatternContext * Context

Pointer to a class instance holding, among other things, the table with the values of live string var...

StringRef FromStr

The string that needs to be substituted for something else.

virtual Expected< std::string > getResult() const =0

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

The instances of the Type class are immutable: once they are created, they are never changed.

Class to represent an undefined variable error, which quotes that variable's name when printed.

LLVM Value Representation.

raw_ostream & write_escaped(StringRef Str, bool UseHexEscapes=false)

Output Str, turning '\', '\t', ' ', '"', and anything that doesn't satisfy llvm::isPrint into an esca...

A raw_ostream that writes to an std::string.

A raw_ostream that writes to an SmallVector or SmallString.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

constexpr char Args[]

Key for Kernel::Metadata::mArgs.

@ C

The default llvm calling convention, compatible with C.

@ CheckBadNot

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

@ CheckBadCount

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

@ CheckEOF

Indicates the pattern only matches the end of file.

This is an optimization pass for GlobalISel generic memory operations.

void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})

Log all errors (if any) in E to OS.

void handleAllErrors(Error E, HandlerTs &&... Handlers)

Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...

Error handleErrors(Error E, HandlerTs &&... Hs)

Pass the ErrorInfo(s) contained in E to their respective handlers.

Expected< APInt > exprAdd(const APInt &Lhs, const APInt &Rhs, bool &Overflow)

Performs operation and.

Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)

Create formatted StringError object.

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

Error joinErrors(Error E1, Error E2)

Concatenate errors.

void sort(IteratorTy Start, IteratorTy End)

Expected< APInt > exprMul(const APInt &Lhs, const APInt &Rhs, bool &Overflow)

raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

@ First

Helpers to iterate all locations in the MemoryEffectsBase class.

void cantFail(Error Err, const char *Msg=nullptr)

Report a fatal error if Err is a failure value.

constexpr unsigned BitWidth

bool is_contained(R &&Range, const E &Element)

Returns true if Element is found in Range.

Expected< APInt > exprMax(const APInt &Lhs, const APInt &Rhs, bool &Overflow)

Expected< APInt > exprDiv(const APInt &Lhs, const APInt &Rhs, bool &Overflow)

Expected< APInt > exprMin(const APInt &Lhs, const APInt &Rhs, bool &Overflow)

Expected< APInt > exprSub(const APInt &Lhs, const APInt &Rhs, bool &Overflow)

void consumeError(Error Err)

Consume a Error without doing anything.

Implement std::hash so that hash_code can be used in STL containers.

void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)

Implement std::swap in terms of BitVector swap.

StringRef match(StringRef Buffer)

Find the next match of a prefix in Buffer.

SmallVector< std::pair< StringRef, size_t > > Prefixes

Prefixes and their first occurrence past the current position.

PrefixMatcher(ArrayRef< StringRef > CheckPrefixes, ArrayRef< StringRef > CommentPrefixes, StringRef Input)

Type representing the format an expression value should be textualized into for matching.

APInt valueFromStringRepr(StringRef StrVal, const SourceMgr &SM) const

StringRef toString() const

Expected< std::string > getMatchingString(APInt Value) const

Expected< std::string > getWildcardRegex() const

@ HexLower

Value should be printed as a lowercase hex number.

@ HexUpper

Value should be printed as an uppercase hex number.

@ Signed

Value is a signed integer and should be printed as a decimal number.

@ Unsigned

Value is an unsigned integer and should be printed as a decimal number.

@ NoFormat

Denote absence of format.

unsigned InputStartLine

The search range if MatchTy starts with MatchNone, or the match range otherwise.

FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy, SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange, StringRef Note="")

MatchType

What type of match result does this diagnostic describe?

@ MatchFoundButWrongLine

Indicates a match for an expected pattern, but the match is on the wrong line.

@ MatchNoneAndExcluded

Indicates no match for an excluded pattern.

@ MatchFoundButExcluded

Indicates a match for an excluded pattern.

@ MatchFuzzy

Indicates a fuzzy match that serves as a suggestion for the next intended match for an expected patte...

@ MatchFoundButDiscarded

Indicates a discarded match for an expected pattern.

@ MatchNoneForInvalidPattern

Indicates no match due to an expected or excluded pattern that has proven to be invalid at match time...

@ MatchFoundAndExpected

Indicates a good match for an expected pattern.

@ MatchNoneButExpected

Indicates no match for an expected pattern, but this might follow good matches when multiple matches ...

Contains info about various FileCheck options.

bool IsDefaultCheckPrefix

std::vector< StringRef > GlobalDefines

bool NoCanonicalizeWhiteSpace

std::vector< StringRef > ImplicitCheckNot

std::vector< StringRef > CommentPrefixes

std::vector< StringRef > CheckPrefixes

bool AllowDeprecatedDagOverlap

A check that we found in the input file.

bool CheckNext(const SourceMgr &SM, StringRef Buffer) const

Verifies that there is a single line in the given Buffer.

Pattern Pat

The pattern to match.

bool CheckSame(const SourceMgr &SM, StringRef Buffer) const

Verifies that there is no newline in the given Buffer.

std::vector< DagNotPrefixInfo > DagNotStrings

Hold the DAG/NOT strings occurring in the input file.

SMLoc Loc

The location in the match file that the check string was specified.

StringRef Prefix

Which prefix name this check matched.

size_t CheckDag(const SourceMgr &SM, StringRef Buffer, std::vector< const DagNotPrefixInfo * > &NotStrings, const FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags) const

Matches "dag strings" and their mixed "not strings".

size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, size_t &MatchLen, FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags) const

Matches check string and its "not strings" and/or "dag strings".

bool CheckNot(const SourceMgr &SM, StringRef Buffer, const std::vector< const DagNotPrefixInfo * > &NotStrings, const FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags) const

Verifies that none of the strings in NotStrings are found in the given Buffer.

std::optional< Match > TheMatch

Parsing information about a variable.