1e8d8bef9SDimitry Andric //===- FileCheck.cpp - Check that File's Contents match what is expected --===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric // 9e8d8bef9SDimitry Andric // FileCheck does a line-by line check of a file that validates whether it 10e8d8bef9SDimitry Andric // contains the expected content. This is useful for regression tests etc. 11e8d8bef9SDimitry Andric // 12e8d8bef9SDimitry Andric // This file implements most of the API that will be used by the FileCheck utility 13e8d8bef9SDimitry Andric // as well as various unittests. 14e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 15e8d8bef9SDimitry Andric 16e8d8bef9SDimitry Andric #include "llvm/FileCheck/FileCheck.h" 17e8d8bef9SDimitry Andric #include "FileCheckImpl.h" 18e8d8bef9SDimitry Andric #include "llvm/ADT/STLExtras.h" 19e8d8bef9SDimitry Andric #include "llvm/ADT/StringSet.h" 20e8d8bef9SDimitry Andric #include "llvm/ADT/Twine.h" 21e8d8bef9SDimitry Andric #include "llvm/Support/CheckedArithmetic.h" 22e8d8bef9SDimitry Andric #include "llvm/Support/FormatVariadic.h" 23e8d8bef9SDimitry Andric #include <cstdint> 24e8d8bef9SDimitry Andric #include <list> 25e8d8bef9SDimitry Andric #include <set> 26e8d8bef9SDimitry Andric #include <tuple> 27e8d8bef9SDimitry Andric #include <utility> 28e8d8bef9SDimitry Andric 29e8d8bef9SDimitry Andric using namespace llvm; 30e8d8bef9SDimitry Andric 31e8d8bef9SDimitry Andric StringRef ExpressionFormat::toString() const { 32e8d8bef9SDimitry Andric switch (Value) { 33e8d8bef9SDimitry Andric case Kind::NoFormat: 34e8d8bef9SDimitry Andric return StringRef("<none>"); 35e8d8bef9SDimitry Andric case Kind::Unsigned: 36e8d8bef9SDimitry Andric return StringRef("%u"); 37e8d8bef9SDimitry Andric case Kind::Signed: 38e8d8bef9SDimitry Andric return StringRef("%d"); 39e8d8bef9SDimitry Andric case Kind::HexUpper: 40e8d8bef9SDimitry Andric return StringRef("%X"); 41e8d8bef9SDimitry Andric case Kind::HexLower: 42e8d8bef9SDimitry Andric return StringRef("%x"); 43e8d8bef9SDimitry Andric } 44e8d8bef9SDimitry Andric llvm_unreachable("unknown expression format"); 45e8d8bef9SDimitry Andric } 46e8d8bef9SDimitry Andric 47e8d8bef9SDimitry Andric Expected<std::string> ExpressionFormat::getWildcardRegex() const { 48fe6060f1SDimitry Andric StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef(); 49fe6060f1SDimitry Andric 50fe6060f1SDimitry Andric auto CreatePrecisionRegex = [&](StringRef S) { 51fe6060f1SDimitry Andric return (Twine(AlternateFormPrefix) + S + Twine('{') + Twine(Precision) + 52fe6060f1SDimitry Andric "}") 53fe6060f1SDimitry Andric .str(); 54e8d8bef9SDimitry Andric }; 55e8d8bef9SDimitry Andric 56e8d8bef9SDimitry Andric switch (Value) { 57e8d8bef9SDimitry Andric case Kind::Unsigned: 58e8d8bef9SDimitry Andric if (Precision) 59e8d8bef9SDimitry Andric return CreatePrecisionRegex("([1-9][0-9]*)?[0-9]"); 60e8d8bef9SDimitry Andric return std::string("[0-9]+"); 61e8d8bef9SDimitry Andric case Kind::Signed: 62e8d8bef9SDimitry Andric if (Precision) 63e8d8bef9SDimitry Andric return CreatePrecisionRegex("-?([1-9][0-9]*)?[0-9]"); 64e8d8bef9SDimitry Andric return std::string("-?[0-9]+"); 65e8d8bef9SDimitry Andric case Kind::HexUpper: 66e8d8bef9SDimitry Andric if (Precision) 67e8d8bef9SDimitry Andric return CreatePrecisionRegex("([1-9A-F][0-9A-F]*)?[0-9A-F]"); 68fe6060f1SDimitry Andric return (Twine(AlternateFormPrefix) + Twine("[0-9A-F]+")).str(); 69e8d8bef9SDimitry Andric case Kind::HexLower: 70e8d8bef9SDimitry Andric if (Precision) 71e8d8bef9SDimitry Andric return CreatePrecisionRegex("([1-9a-f][0-9a-f]*)?[0-9a-f]"); 72fe6060f1SDimitry Andric return (Twine(AlternateFormPrefix) + Twine("[0-9a-f]+")).str(); 73e8d8bef9SDimitry Andric default: 74e8d8bef9SDimitry Andric return createStringError(std::errc::invalid_argument, 75e8d8bef9SDimitry Andric "trying to match value with invalid format"); 76e8d8bef9SDimitry Andric } 77e8d8bef9SDimitry Andric } 78e8d8bef9SDimitry Andric 79e8d8bef9SDimitry Andric Expected<std::string> 80e8d8bef9SDimitry Andric ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const { 81e8d8bef9SDimitry Andric uint64_t AbsoluteValue; 82e8d8bef9SDimitry Andric StringRef SignPrefix = IntegerValue.isNegative() ? "-" : ""; 83e8d8bef9SDimitry Andric 84e8d8bef9SDimitry Andric if (Value == Kind::Signed) { 85e8d8bef9SDimitry Andric Expected<int64_t> SignedValue = IntegerValue.getSignedValue(); 86e8d8bef9SDimitry Andric if (!SignedValue) 87e8d8bef9SDimitry Andric return SignedValue.takeError(); 88e8d8bef9SDimitry Andric if (*SignedValue < 0) 89e8d8bef9SDimitry Andric AbsoluteValue = cantFail(IntegerValue.getAbsolute().getUnsignedValue()); 90e8d8bef9SDimitry Andric else 91e8d8bef9SDimitry Andric AbsoluteValue = *SignedValue; 92e8d8bef9SDimitry Andric } else { 93e8d8bef9SDimitry Andric Expected<uint64_t> UnsignedValue = IntegerValue.getUnsignedValue(); 94e8d8bef9SDimitry Andric if (!UnsignedValue) 95e8d8bef9SDimitry Andric return UnsignedValue.takeError(); 96e8d8bef9SDimitry Andric AbsoluteValue = *UnsignedValue; 97e8d8bef9SDimitry Andric } 98e8d8bef9SDimitry Andric 99e8d8bef9SDimitry Andric std::string AbsoluteValueStr; 100e8d8bef9SDimitry Andric switch (Value) { 101e8d8bef9SDimitry Andric case Kind::Unsigned: 102e8d8bef9SDimitry Andric case Kind::Signed: 103e8d8bef9SDimitry Andric AbsoluteValueStr = utostr(AbsoluteValue); 104e8d8bef9SDimitry Andric break; 105e8d8bef9SDimitry Andric case Kind::HexUpper: 106e8d8bef9SDimitry Andric case Kind::HexLower: 107e8d8bef9SDimitry Andric AbsoluteValueStr = utohexstr(AbsoluteValue, Value == Kind::HexLower); 108e8d8bef9SDimitry Andric break; 109e8d8bef9SDimitry Andric default: 110e8d8bef9SDimitry Andric return createStringError(std::errc::invalid_argument, 111e8d8bef9SDimitry Andric "trying to match value with invalid format"); 112e8d8bef9SDimitry Andric } 113e8d8bef9SDimitry Andric 114fe6060f1SDimitry Andric StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef(); 115fe6060f1SDimitry Andric 116e8d8bef9SDimitry Andric if (Precision > AbsoluteValueStr.size()) { 117e8d8bef9SDimitry Andric unsigned LeadingZeros = Precision - AbsoluteValueStr.size(); 118fe6060f1SDimitry Andric return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + 119fe6060f1SDimitry Andric std::string(LeadingZeros, '0') + AbsoluteValueStr) 120e8d8bef9SDimitry Andric .str(); 121e8d8bef9SDimitry Andric } 122e8d8bef9SDimitry Andric 123fe6060f1SDimitry Andric return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + AbsoluteValueStr) 124fe6060f1SDimitry Andric .str(); 125e8d8bef9SDimitry Andric } 126e8d8bef9SDimitry Andric 127e8d8bef9SDimitry Andric Expected<ExpressionValue> 128e8d8bef9SDimitry Andric ExpressionFormat::valueFromStringRepr(StringRef StrVal, 129e8d8bef9SDimitry Andric const SourceMgr &SM) const { 130e8d8bef9SDimitry Andric bool ValueIsSigned = Value == Kind::Signed; 131fe6060f1SDimitry Andric // Both the FileCheck utility and library only call this method with a valid 132fe6060f1SDimitry Andric // value in StrVal. This is guaranteed by the regex returned by 133fe6060f1SDimitry Andric // getWildcardRegex() above. Only underflow and overflow errors can thus 134fe6060f1SDimitry Andric // occur. However new uses of this method could be added in the future so 135fe6060f1SDimitry Andric // the error message does not make assumptions about StrVal. 136fe6060f1SDimitry Andric StringRef IntegerParseErrorStr = "unable to represent numeric value"; 137e8d8bef9SDimitry Andric if (ValueIsSigned) { 138e8d8bef9SDimitry Andric int64_t SignedValue; 139e8d8bef9SDimitry Andric 140e8d8bef9SDimitry Andric if (StrVal.getAsInteger(10, SignedValue)) 141fe6060f1SDimitry Andric return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr); 142e8d8bef9SDimitry Andric 143e8d8bef9SDimitry Andric return ExpressionValue(SignedValue); 144e8d8bef9SDimitry Andric } 145e8d8bef9SDimitry Andric 146e8d8bef9SDimitry Andric bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower; 147e8d8bef9SDimitry Andric uint64_t UnsignedValue; 148fe6060f1SDimitry Andric bool MissingFormPrefix = AlternateForm && !StrVal.consume_front("0x"); 149e8d8bef9SDimitry Andric if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue)) 150fe6060f1SDimitry Andric return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr); 151fe6060f1SDimitry Andric 152fe6060f1SDimitry Andric // Error out for a missing prefix only now that we know we have an otherwise 153fe6060f1SDimitry Andric // valid integer. For example, "-0x18" is reported above instead. 154fe6060f1SDimitry Andric if (MissingFormPrefix) 155fe6060f1SDimitry Andric return ErrorDiagnostic::get(SM, StrVal, "missing alternate form prefix"); 156e8d8bef9SDimitry Andric 157e8d8bef9SDimitry Andric return ExpressionValue(UnsignedValue); 158e8d8bef9SDimitry Andric } 159e8d8bef9SDimitry Andric 160e8d8bef9SDimitry Andric static int64_t getAsSigned(uint64_t UnsignedValue) { 161e8d8bef9SDimitry Andric // Use memcpy to reinterpret the bitpattern in Value since casting to 162e8d8bef9SDimitry Andric // signed is implementation-defined if the unsigned value is too big to be 163e8d8bef9SDimitry Andric // represented in the signed type and using an union violates type aliasing 164e8d8bef9SDimitry Andric // rules. 165e8d8bef9SDimitry Andric int64_t SignedValue; 166e8d8bef9SDimitry Andric memcpy(&SignedValue, &UnsignedValue, sizeof(SignedValue)); 167e8d8bef9SDimitry Andric return SignedValue; 168e8d8bef9SDimitry Andric } 169e8d8bef9SDimitry Andric 170e8d8bef9SDimitry Andric Expected<int64_t> ExpressionValue::getSignedValue() const { 171e8d8bef9SDimitry Andric if (Negative) 172e8d8bef9SDimitry Andric return getAsSigned(Value); 173e8d8bef9SDimitry Andric 174e8d8bef9SDimitry Andric if (Value > (uint64_t)std::numeric_limits<int64_t>::max()) 175e8d8bef9SDimitry Andric return make_error<OverflowError>(); 176e8d8bef9SDimitry Andric 177e8d8bef9SDimitry Andric // Value is in the representable range of int64_t so we can use cast. 178e8d8bef9SDimitry Andric return static_cast<int64_t>(Value); 179e8d8bef9SDimitry Andric } 180e8d8bef9SDimitry Andric 181e8d8bef9SDimitry Andric Expected<uint64_t> ExpressionValue::getUnsignedValue() const { 182e8d8bef9SDimitry Andric if (Negative) 183e8d8bef9SDimitry Andric return make_error<OverflowError>(); 184e8d8bef9SDimitry Andric 185e8d8bef9SDimitry Andric return Value; 186e8d8bef9SDimitry Andric } 187e8d8bef9SDimitry Andric 188e8d8bef9SDimitry Andric ExpressionValue ExpressionValue::getAbsolute() const { 189e8d8bef9SDimitry Andric if (!Negative) 190e8d8bef9SDimitry Andric return *this; 191e8d8bef9SDimitry Andric 192e8d8bef9SDimitry Andric int64_t SignedValue = getAsSigned(Value); 193e8d8bef9SDimitry Andric int64_t MaxInt64 = std::numeric_limits<int64_t>::max(); 194e8d8bef9SDimitry Andric // Absolute value can be represented as int64_t. 195e8d8bef9SDimitry Andric if (SignedValue >= -MaxInt64) 196e8d8bef9SDimitry Andric return ExpressionValue(-getAsSigned(Value)); 197e8d8bef9SDimitry Andric 198e8d8bef9SDimitry Andric // -X == -(max int64_t + Rem), negate each component independently. 199e8d8bef9SDimitry Andric SignedValue += MaxInt64; 200e8d8bef9SDimitry Andric uint64_t RemainingValueAbsolute = -SignedValue; 201e8d8bef9SDimitry Andric return ExpressionValue(MaxInt64 + RemainingValueAbsolute); 202e8d8bef9SDimitry Andric } 203e8d8bef9SDimitry Andric 204e8d8bef9SDimitry Andric Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand, 205e8d8bef9SDimitry Andric const ExpressionValue &RightOperand) { 206e8d8bef9SDimitry Andric if (LeftOperand.isNegative() && RightOperand.isNegative()) { 207e8d8bef9SDimitry Andric int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 208e8d8bef9SDimitry Andric int64_t RightValue = cantFail(RightOperand.getSignedValue()); 209e8d8bef9SDimitry Andric Optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue); 210e8d8bef9SDimitry Andric if (!Result) 211e8d8bef9SDimitry Andric return make_error<OverflowError>(); 212e8d8bef9SDimitry Andric 213e8d8bef9SDimitry Andric return ExpressionValue(*Result); 214e8d8bef9SDimitry Andric } 215e8d8bef9SDimitry Andric 216e8d8bef9SDimitry Andric // (-A) + B == B - A. 217e8d8bef9SDimitry Andric if (LeftOperand.isNegative()) 218e8d8bef9SDimitry Andric return RightOperand - LeftOperand.getAbsolute(); 219e8d8bef9SDimitry Andric 220e8d8bef9SDimitry Andric // A + (-B) == A - B. 221e8d8bef9SDimitry Andric if (RightOperand.isNegative()) 222e8d8bef9SDimitry Andric return LeftOperand - RightOperand.getAbsolute(); 223e8d8bef9SDimitry Andric 224e8d8bef9SDimitry Andric // Both values are positive at this point. 225e8d8bef9SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 226e8d8bef9SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 227e8d8bef9SDimitry Andric Optional<uint64_t> Result = 228e8d8bef9SDimitry Andric checkedAddUnsigned<uint64_t>(LeftValue, RightValue); 229e8d8bef9SDimitry Andric if (!Result) 230e8d8bef9SDimitry Andric return make_error<OverflowError>(); 231e8d8bef9SDimitry Andric 232e8d8bef9SDimitry Andric return ExpressionValue(*Result); 233e8d8bef9SDimitry Andric } 234e8d8bef9SDimitry Andric 235e8d8bef9SDimitry Andric Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand, 236e8d8bef9SDimitry Andric const ExpressionValue &RightOperand) { 237e8d8bef9SDimitry Andric // Result will be negative and thus might underflow. 238e8d8bef9SDimitry Andric if (LeftOperand.isNegative() && !RightOperand.isNegative()) { 239e8d8bef9SDimitry Andric int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 240e8d8bef9SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 241e8d8bef9SDimitry Andric // Result <= -1 - (max int64_t) which overflows on 1- and 2-complement. 242e8d8bef9SDimitry Andric if (RightValue > (uint64_t)std::numeric_limits<int64_t>::max()) 243e8d8bef9SDimitry Andric return make_error<OverflowError>(); 244e8d8bef9SDimitry Andric Optional<int64_t> Result = 245e8d8bef9SDimitry Andric checkedSub(LeftValue, static_cast<int64_t>(RightValue)); 246e8d8bef9SDimitry Andric if (!Result) 247e8d8bef9SDimitry Andric return make_error<OverflowError>(); 248e8d8bef9SDimitry Andric 249e8d8bef9SDimitry Andric return ExpressionValue(*Result); 250e8d8bef9SDimitry Andric } 251e8d8bef9SDimitry Andric 252e8d8bef9SDimitry Andric // (-A) - (-B) == B - A. 253e8d8bef9SDimitry Andric if (LeftOperand.isNegative()) 254e8d8bef9SDimitry Andric return RightOperand.getAbsolute() - LeftOperand.getAbsolute(); 255e8d8bef9SDimitry Andric 256e8d8bef9SDimitry Andric // A - (-B) == A + B. 257e8d8bef9SDimitry Andric if (RightOperand.isNegative()) 258e8d8bef9SDimitry Andric return LeftOperand + RightOperand.getAbsolute(); 259e8d8bef9SDimitry Andric 260e8d8bef9SDimitry Andric // Both values are positive at this point. 261e8d8bef9SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 262e8d8bef9SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 263e8d8bef9SDimitry Andric if (LeftValue >= RightValue) 264e8d8bef9SDimitry Andric return ExpressionValue(LeftValue - RightValue); 265e8d8bef9SDimitry Andric else { 266e8d8bef9SDimitry Andric uint64_t AbsoluteDifference = RightValue - LeftValue; 267e8d8bef9SDimitry Andric uint64_t MaxInt64 = std::numeric_limits<int64_t>::max(); 268e8d8bef9SDimitry Andric // Value might underflow. 269e8d8bef9SDimitry Andric if (AbsoluteDifference > MaxInt64) { 270e8d8bef9SDimitry Andric AbsoluteDifference -= MaxInt64; 271e8d8bef9SDimitry Andric int64_t Result = -MaxInt64; 272e8d8bef9SDimitry Andric int64_t MinInt64 = std::numeric_limits<int64_t>::min(); 273e8d8bef9SDimitry Andric // Underflow, tested by: 274e8d8bef9SDimitry Andric // abs(Result + (max int64_t)) > abs((min int64_t) + (max int64_t)) 275e8d8bef9SDimitry Andric if (AbsoluteDifference > static_cast<uint64_t>(-(MinInt64 - Result))) 276e8d8bef9SDimitry Andric return make_error<OverflowError>(); 277e8d8bef9SDimitry Andric Result -= static_cast<int64_t>(AbsoluteDifference); 278e8d8bef9SDimitry Andric return ExpressionValue(Result); 279e8d8bef9SDimitry Andric } 280e8d8bef9SDimitry Andric 281e8d8bef9SDimitry Andric return ExpressionValue(-static_cast<int64_t>(AbsoluteDifference)); 282e8d8bef9SDimitry Andric } 283e8d8bef9SDimitry Andric } 284e8d8bef9SDimitry Andric 285e8d8bef9SDimitry Andric Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand, 286e8d8bef9SDimitry Andric const ExpressionValue &RightOperand) { 287e8d8bef9SDimitry Andric // -A * -B == A * B 288e8d8bef9SDimitry Andric if (LeftOperand.isNegative() && RightOperand.isNegative()) 289e8d8bef9SDimitry Andric return LeftOperand.getAbsolute() * RightOperand.getAbsolute(); 290e8d8bef9SDimitry Andric 291e8d8bef9SDimitry Andric // A * -B == -B * A 292e8d8bef9SDimitry Andric if (RightOperand.isNegative()) 293e8d8bef9SDimitry Andric return RightOperand * LeftOperand; 294e8d8bef9SDimitry Andric 295e8d8bef9SDimitry Andric assert(!RightOperand.isNegative() && "Unexpected negative operand!"); 296e8d8bef9SDimitry Andric 297e8d8bef9SDimitry Andric // Result will be negative and can underflow. 298e8d8bef9SDimitry Andric if (LeftOperand.isNegative()) { 299e8d8bef9SDimitry Andric auto Result = LeftOperand.getAbsolute() * RightOperand.getAbsolute(); 300e8d8bef9SDimitry Andric if (!Result) 301e8d8bef9SDimitry Andric return Result; 302e8d8bef9SDimitry Andric 303e8d8bef9SDimitry Andric return ExpressionValue(0) - *Result; 304e8d8bef9SDimitry Andric } 305e8d8bef9SDimitry Andric 306e8d8bef9SDimitry Andric // Result will be positive and can overflow. 307e8d8bef9SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 308e8d8bef9SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 309e8d8bef9SDimitry Andric Optional<uint64_t> Result = 310e8d8bef9SDimitry Andric checkedMulUnsigned<uint64_t>(LeftValue, RightValue); 311e8d8bef9SDimitry Andric if (!Result) 312e8d8bef9SDimitry Andric return make_error<OverflowError>(); 313e8d8bef9SDimitry Andric 314e8d8bef9SDimitry Andric return ExpressionValue(*Result); 315e8d8bef9SDimitry Andric } 316e8d8bef9SDimitry Andric 317e8d8bef9SDimitry Andric Expected<ExpressionValue> llvm::operator/(const ExpressionValue &LeftOperand, 318e8d8bef9SDimitry Andric const ExpressionValue &RightOperand) { 319e8d8bef9SDimitry Andric // -A / -B == A / B 320e8d8bef9SDimitry Andric if (LeftOperand.isNegative() && RightOperand.isNegative()) 321e8d8bef9SDimitry Andric return LeftOperand.getAbsolute() / RightOperand.getAbsolute(); 322e8d8bef9SDimitry Andric 323e8d8bef9SDimitry Andric // Check for divide by zero. 324e8d8bef9SDimitry Andric if (RightOperand == ExpressionValue(0)) 325e8d8bef9SDimitry Andric return make_error<OverflowError>(); 326e8d8bef9SDimitry Andric 327e8d8bef9SDimitry Andric // Result will be negative and can underflow. 328e8d8bef9SDimitry Andric if (LeftOperand.isNegative() || RightOperand.isNegative()) 329e8d8bef9SDimitry Andric return ExpressionValue(0) - 330e8d8bef9SDimitry Andric cantFail(LeftOperand.getAbsolute() / RightOperand.getAbsolute()); 331e8d8bef9SDimitry Andric 332e8d8bef9SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 333e8d8bef9SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 334e8d8bef9SDimitry Andric return ExpressionValue(LeftValue / RightValue); 335e8d8bef9SDimitry Andric } 336e8d8bef9SDimitry Andric 337e8d8bef9SDimitry Andric Expected<ExpressionValue> llvm::max(const ExpressionValue &LeftOperand, 338e8d8bef9SDimitry Andric const ExpressionValue &RightOperand) { 339e8d8bef9SDimitry Andric if (LeftOperand.isNegative() && RightOperand.isNegative()) { 340e8d8bef9SDimitry Andric int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 341e8d8bef9SDimitry Andric int64_t RightValue = cantFail(RightOperand.getSignedValue()); 342e8d8bef9SDimitry Andric return ExpressionValue(std::max(LeftValue, RightValue)); 343e8d8bef9SDimitry Andric } 344e8d8bef9SDimitry Andric 345e8d8bef9SDimitry Andric if (!LeftOperand.isNegative() && !RightOperand.isNegative()) { 346e8d8bef9SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 347e8d8bef9SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 348e8d8bef9SDimitry Andric return ExpressionValue(std::max(LeftValue, RightValue)); 349e8d8bef9SDimitry Andric } 350e8d8bef9SDimitry Andric 351e8d8bef9SDimitry Andric if (LeftOperand.isNegative()) 352e8d8bef9SDimitry Andric return RightOperand; 353e8d8bef9SDimitry Andric 354e8d8bef9SDimitry Andric return LeftOperand; 355e8d8bef9SDimitry Andric } 356e8d8bef9SDimitry Andric 357e8d8bef9SDimitry Andric Expected<ExpressionValue> llvm::min(const ExpressionValue &LeftOperand, 358e8d8bef9SDimitry Andric const ExpressionValue &RightOperand) { 359e8d8bef9SDimitry Andric if (cantFail(max(LeftOperand, RightOperand)) == LeftOperand) 360e8d8bef9SDimitry Andric return RightOperand; 361e8d8bef9SDimitry Andric 362e8d8bef9SDimitry Andric return LeftOperand; 363e8d8bef9SDimitry Andric } 364e8d8bef9SDimitry Andric 365e8d8bef9SDimitry Andric Expected<ExpressionValue> NumericVariableUse::eval() const { 366e8d8bef9SDimitry Andric Optional<ExpressionValue> Value = Variable->getValue(); 367e8d8bef9SDimitry Andric if (Value) 368e8d8bef9SDimitry Andric return *Value; 369e8d8bef9SDimitry Andric 370e8d8bef9SDimitry Andric return make_error<UndefVarError>(getExpressionStr()); 371e8d8bef9SDimitry Andric } 372e8d8bef9SDimitry Andric 373e8d8bef9SDimitry Andric Expected<ExpressionValue> BinaryOperation::eval() const { 374e8d8bef9SDimitry Andric Expected<ExpressionValue> LeftOp = LeftOperand->eval(); 375e8d8bef9SDimitry Andric Expected<ExpressionValue> RightOp = RightOperand->eval(); 376e8d8bef9SDimitry Andric 377e8d8bef9SDimitry Andric // Bubble up any error (e.g. undefined variables) in the recursive 378e8d8bef9SDimitry Andric // evaluation. 379e8d8bef9SDimitry Andric if (!LeftOp || !RightOp) { 380e8d8bef9SDimitry Andric Error Err = Error::success(); 381e8d8bef9SDimitry Andric if (!LeftOp) 382e8d8bef9SDimitry Andric Err = joinErrors(std::move(Err), LeftOp.takeError()); 383e8d8bef9SDimitry Andric if (!RightOp) 384e8d8bef9SDimitry Andric Err = joinErrors(std::move(Err), RightOp.takeError()); 385e8d8bef9SDimitry Andric return std::move(Err); 386e8d8bef9SDimitry Andric } 387e8d8bef9SDimitry Andric 388e8d8bef9SDimitry Andric return EvalBinop(*LeftOp, *RightOp); 389e8d8bef9SDimitry Andric } 390e8d8bef9SDimitry Andric 391e8d8bef9SDimitry Andric Expected<ExpressionFormat> 392e8d8bef9SDimitry Andric BinaryOperation::getImplicitFormat(const SourceMgr &SM) const { 393e8d8bef9SDimitry Andric Expected<ExpressionFormat> LeftFormat = LeftOperand->getImplicitFormat(SM); 394e8d8bef9SDimitry Andric Expected<ExpressionFormat> RightFormat = RightOperand->getImplicitFormat(SM); 395e8d8bef9SDimitry Andric if (!LeftFormat || !RightFormat) { 396e8d8bef9SDimitry Andric Error Err = Error::success(); 397e8d8bef9SDimitry Andric if (!LeftFormat) 398e8d8bef9SDimitry Andric Err = joinErrors(std::move(Err), LeftFormat.takeError()); 399e8d8bef9SDimitry Andric if (!RightFormat) 400e8d8bef9SDimitry Andric Err = joinErrors(std::move(Err), RightFormat.takeError()); 401e8d8bef9SDimitry Andric return std::move(Err); 402e8d8bef9SDimitry Andric } 403e8d8bef9SDimitry Andric 404e8d8bef9SDimitry Andric if (*LeftFormat != ExpressionFormat::Kind::NoFormat && 405e8d8bef9SDimitry Andric *RightFormat != ExpressionFormat::Kind::NoFormat && 406e8d8bef9SDimitry Andric *LeftFormat != *RightFormat) 407e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 408e8d8bef9SDimitry Andric SM, getExpressionStr(), 409e8d8bef9SDimitry Andric "implicit format conflict between '" + LeftOperand->getExpressionStr() + 410e8d8bef9SDimitry Andric "' (" + LeftFormat->toString() + ") and '" + 411e8d8bef9SDimitry Andric RightOperand->getExpressionStr() + "' (" + RightFormat->toString() + 412e8d8bef9SDimitry Andric "), need an explicit format specifier"); 413e8d8bef9SDimitry Andric 414e8d8bef9SDimitry Andric return *LeftFormat != ExpressionFormat::Kind::NoFormat ? *LeftFormat 415e8d8bef9SDimitry Andric : *RightFormat; 416e8d8bef9SDimitry Andric } 417e8d8bef9SDimitry Andric 418e8d8bef9SDimitry Andric Expected<std::string> NumericSubstitution::getResult() const { 419e8d8bef9SDimitry Andric assert(ExpressionPointer->getAST() != nullptr && 420e8d8bef9SDimitry Andric "Substituting empty expression"); 421e8d8bef9SDimitry Andric Expected<ExpressionValue> EvaluatedValue = 422e8d8bef9SDimitry Andric ExpressionPointer->getAST()->eval(); 423e8d8bef9SDimitry Andric if (!EvaluatedValue) 424e8d8bef9SDimitry Andric return EvaluatedValue.takeError(); 425e8d8bef9SDimitry Andric ExpressionFormat Format = ExpressionPointer->getFormat(); 426e8d8bef9SDimitry Andric return Format.getMatchingString(*EvaluatedValue); 427e8d8bef9SDimitry Andric } 428e8d8bef9SDimitry Andric 429e8d8bef9SDimitry Andric Expected<std::string> StringSubstitution::getResult() const { 430e8d8bef9SDimitry Andric // Look up the value and escape it so that we can put it into the regex. 431e8d8bef9SDimitry Andric Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr); 432e8d8bef9SDimitry Andric if (!VarVal) 433e8d8bef9SDimitry Andric return VarVal.takeError(); 434e8d8bef9SDimitry Andric return Regex::escape(*VarVal); 435e8d8bef9SDimitry Andric } 436e8d8bef9SDimitry Andric 437e8d8bef9SDimitry Andric bool Pattern::isValidVarNameStart(char C) { return C == '_' || isAlpha(C); } 438e8d8bef9SDimitry Andric 439e8d8bef9SDimitry Andric Expected<Pattern::VariableProperties> 440e8d8bef9SDimitry Andric Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) { 441e8d8bef9SDimitry Andric if (Str.empty()) 442e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, Str, "empty variable name"); 443e8d8bef9SDimitry Andric 444e8d8bef9SDimitry Andric size_t I = 0; 445e8d8bef9SDimitry Andric bool IsPseudo = Str[0] == '@'; 446e8d8bef9SDimitry Andric 447e8d8bef9SDimitry Andric // Global vars start with '$'. 448e8d8bef9SDimitry Andric if (Str[0] == '$' || IsPseudo) 449e8d8bef9SDimitry Andric ++I; 450e8d8bef9SDimitry Andric 451e8d8bef9SDimitry Andric if (!isValidVarNameStart(Str[I++])) 452e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, Str, "invalid variable name"); 453e8d8bef9SDimitry Andric 454e8d8bef9SDimitry Andric for (size_t E = Str.size(); I != E; ++I) 455e8d8bef9SDimitry Andric // Variable names are composed of alphanumeric characters and underscores. 456e8d8bef9SDimitry Andric if (Str[I] != '_' && !isAlnum(Str[I])) 457e8d8bef9SDimitry Andric break; 458e8d8bef9SDimitry Andric 459e8d8bef9SDimitry Andric StringRef Name = Str.take_front(I); 460e8d8bef9SDimitry Andric Str = Str.substr(I); 461e8d8bef9SDimitry Andric return VariableProperties {Name, IsPseudo}; 462e8d8bef9SDimitry Andric } 463e8d8bef9SDimitry Andric 464e8d8bef9SDimitry Andric // StringRef holding all characters considered as horizontal whitespaces by 465e8d8bef9SDimitry Andric // FileCheck input canonicalization. 466e8d8bef9SDimitry Andric constexpr StringLiteral SpaceChars = " \t"; 467e8d8bef9SDimitry Andric 468e8d8bef9SDimitry Andric // Parsing helper function that strips the first character in S and returns it. 469e8d8bef9SDimitry Andric static char popFront(StringRef &S) { 470e8d8bef9SDimitry Andric char C = S.front(); 471e8d8bef9SDimitry Andric S = S.drop_front(); 472e8d8bef9SDimitry Andric return C; 473e8d8bef9SDimitry Andric } 474e8d8bef9SDimitry Andric 475e8d8bef9SDimitry Andric char OverflowError::ID = 0; 476e8d8bef9SDimitry Andric char UndefVarError::ID = 0; 477e8d8bef9SDimitry Andric char ErrorDiagnostic::ID = 0; 478e8d8bef9SDimitry Andric char NotFoundError::ID = 0; 479fe6060f1SDimitry Andric char ErrorReported::ID = 0; 480e8d8bef9SDimitry Andric 481e8d8bef9SDimitry Andric Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( 482e8d8bef9SDimitry Andric StringRef &Expr, FileCheckPatternContext *Context, 483e8d8bef9SDimitry Andric Optional<size_t> LineNumber, ExpressionFormat ImplicitFormat, 484e8d8bef9SDimitry Andric const SourceMgr &SM) { 485e8d8bef9SDimitry Andric Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM); 486e8d8bef9SDimitry Andric if (!ParseVarResult) 487e8d8bef9SDimitry Andric return ParseVarResult.takeError(); 488e8d8bef9SDimitry Andric StringRef Name = ParseVarResult->Name; 489e8d8bef9SDimitry Andric 490e8d8bef9SDimitry Andric if (ParseVarResult->IsPseudo) 491e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 492e8d8bef9SDimitry Andric SM, Name, "definition of pseudo numeric variable unsupported"); 493e8d8bef9SDimitry Andric 494e8d8bef9SDimitry Andric // Detect collisions between string and numeric variables when the latter 495e8d8bef9SDimitry Andric // is created later than the former. 496e8d8bef9SDimitry Andric if (Context->DefinedVariableTable.find(Name) != 497e8d8bef9SDimitry Andric Context->DefinedVariableTable.end()) 498e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 499e8d8bef9SDimitry Andric SM, Name, "string variable with name '" + Name + "' already exists"); 500e8d8bef9SDimitry Andric 501e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 502e8d8bef9SDimitry Andric if (!Expr.empty()) 503e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 504e8d8bef9SDimitry Andric SM, Expr, "unexpected characters after numeric variable name"); 505e8d8bef9SDimitry Andric 506e8d8bef9SDimitry Andric NumericVariable *DefinedNumericVariable; 507e8d8bef9SDimitry Andric auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); 508e8d8bef9SDimitry Andric if (VarTableIter != Context->GlobalNumericVariableTable.end()) { 509e8d8bef9SDimitry Andric DefinedNumericVariable = VarTableIter->second; 510e8d8bef9SDimitry Andric if (DefinedNumericVariable->getImplicitFormat() != ImplicitFormat) 511e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 512e8d8bef9SDimitry Andric SM, Expr, "format different from previous variable definition"); 513e8d8bef9SDimitry Andric } else 514e8d8bef9SDimitry Andric DefinedNumericVariable = 515e8d8bef9SDimitry Andric Context->makeNumericVariable(Name, ImplicitFormat, LineNumber); 516e8d8bef9SDimitry Andric 517e8d8bef9SDimitry Andric return DefinedNumericVariable; 518e8d8bef9SDimitry Andric } 519e8d8bef9SDimitry Andric 520e8d8bef9SDimitry Andric Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse( 521e8d8bef9SDimitry Andric StringRef Name, bool IsPseudo, Optional<size_t> LineNumber, 522e8d8bef9SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) { 523e8d8bef9SDimitry Andric if (IsPseudo && !Name.equals("@LINE")) 524e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 525e8d8bef9SDimitry Andric SM, Name, "invalid pseudo numeric variable '" + Name + "'"); 526e8d8bef9SDimitry Andric 527e8d8bef9SDimitry Andric // Numeric variable definitions and uses are parsed in the order in which 528e8d8bef9SDimitry Andric // they appear in the CHECK patterns. For each definition, the pointer to the 529e8d8bef9SDimitry Andric // class instance of the corresponding numeric variable definition is stored 530e8d8bef9SDimitry Andric // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer 531e8d8bef9SDimitry Andric // we get below is null, it means no such variable was defined before. When 532e8d8bef9SDimitry Andric // that happens, we create a dummy variable so that parsing can continue. All 533e8d8bef9SDimitry Andric // uses of undefined variables, whether string or numeric, are then diagnosed 534fe6060f1SDimitry Andric // in printNoMatch() after failing to match. 535e8d8bef9SDimitry Andric auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); 536e8d8bef9SDimitry Andric NumericVariable *NumericVariable; 537e8d8bef9SDimitry Andric if (VarTableIter != Context->GlobalNumericVariableTable.end()) 538e8d8bef9SDimitry Andric NumericVariable = VarTableIter->second; 539e8d8bef9SDimitry Andric else { 540e8d8bef9SDimitry Andric NumericVariable = Context->makeNumericVariable( 541e8d8bef9SDimitry Andric Name, ExpressionFormat(ExpressionFormat::Kind::Unsigned)); 542e8d8bef9SDimitry Andric Context->GlobalNumericVariableTable[Name] = NumericVariable; 543e8d8bef9SDimitry Andric } 544e8d8bef9SDimitry Andric 545e8d8bef9SDimitry Andric Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber(); 546e8d8bef9SDimitry Andric if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber) 547e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 548e8d8bef9SDimitry Andric SM, Name, 549e8d8bef9SDimitry Andric "numeric variable '" + Name + 550e8d8bef9SDimitry Andric "' defined earlier in the same CHECK directive"); 551e8d8bef9SDimitry Andric 552e8d8bef9SDimitry Andric return std::make_unique<NumericVariableUse>(Name, NumericVariable); 553e8d8bef9SDimitry Andric } 554e8d8bef9SDimitry Andric 555e8d8bef9SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand( 556e8d8bef9SDimitry Andric StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint, 557e8d8bef9SDimitry Andric Optional<size_t> LineNumber, FileCheckPatternContext *Context, 558e8d8bef9SDimitry Andric const SourceMgr &SM) { 559e8d8bef9SDimitry Andric if (Expr.startswith("(")) { 560e8d8bef9SDimitry Andric if (AO != AllowedOperand::Any) 561e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 562e8d8bef9SDimitry Andric SM, Expr, "parenthesized expression not permitted here"); 563e8d8bef9SDimitry Andric return parseParenExpr(Expr, LineNumber, Context, SM); 564e8d8bef9SDimitry Andric } 565e8d8bef9SDimitry Andric 566e8d8bef9SDimitry Andric if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) { 567e8d8bef9SDimitry Andric // Try to parse as a numeric variable use. 568e8d8bef9SDimitry Andric Expected<Pattern::VariableProperties> ParseVarResult = 569e8d8bef9SDimitry Andric parseVariable(Expr, SM); 570e8d8bef9SDimitry Andric if (ParseVarResult) { 571e8d8bef9SDimitry Andric // Try to parse a function call. 572e8d8bef9SDimitry Andric if (Expr.ltrim(SpaceChars).startswith("(")) { 573e8d8bef9SDimitry Andric if (AO != AllowedOperand::Any) 574e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, ParseVarResult->Name, 575e8d8bef9SDimitry Andric "unexpected function call"); 576e8d8bef9SDimitry Andric 577e8d8bef9SDimitry Andric return parseCallExpr(Expr, ParseVarResult->Name, LineNumber, Context, 578e8d8bef9SDimitry Andric SM); 579e8d8bef9SDimitry Andric } 580e8d8bef9SDimitry Andric 581e8d8bef9SDimitry Andric return parseNumericVariableUse(ParseVarResult->Name, 582e8d8bef9SDimitry Andric ParseVarResult->IsPseudo, LineNumber, 583e8d8bef9SDimitry Andric Context, SM); 584e8d8bef9SDimitry Andric } 585e8d8bef9SDimitry Andric 586e8d8bef9SDimitry Andric if (AO == AllowedOperand::LineVar) 587e8d8bef9SDimitry Andric return ParseVarResult.takeError(); 588e8d8bef9SDimitry Andric // Ignore the error and retry parsing as a literal. 589e8d8bef9SDimitry Andric consumeError(ParseVarResult.takeError()); 590e8d8bef9SDimitry Andric } 591e8d8bef9SDimitry Andric 592e8d8bef9SDimitry Andric // Otherwise, parse it as a literal. 593e8d8bef9SDimitry Andric int64_t SignedLiteralValue; 594e8d8bef9SDimitry Andric uint64_t UnsignedLiteralValue; 595e8d8bef9SDimitry Andric StringRef SaveExpr = Expr; 596e8d8bef9SDimitry Andric // Accept both signed and unsigned literal, default to signed literal. 597e8d8bef9SDimitry Andric if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0, 598e8d8bef9SDimitry Andric UnsignedLiteralValue)) 599e8d8bef9SDimitry Andric return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()), 600e8d8bef9SDimitry Andric UnsignedLiteralValue); 601e8d8bef9SDimitry Andric Expr = SaveExpr; 602e8d8bef9SDimitry Andric if (AO == AllowedOperand::Any && !Expr.consumeInteger(0, SignedLiteralValue)) 603e8d8bef9SDimitry Andric return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()), 604e8d8bef9SDimitry Andric SignedLiteralValue); 605e8d8bef9SDimitry Andric 606e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 607e8d8bef9SDimitry Andric SM, Expr, 608e8d8bef9SDimitry Andric Twine("invalid ") + 609e8d8bef9SDimitry Andric (MaybeInvalidConstraint ? "matching constraint or " : "") + 610e8d8bef9SDimitry Andric "operand format"); 611e8d8bef9SDimitry Andric } 612e8d8bef9SDimitry Andric 613e8d8bef9SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> 614e8d8bef9SDimitry Andric Pattern::parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber, 615e8d8bef9SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) { 616e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 617e8d8bef9SDimitry Andric assert(Expr.startswith("(")); 618e8d8bef9SDimitry Andric 619e8d8bef9SDimitry Andric // Parse right operand. 620e8d8bef9SDimitry Andric Expr.consume_front("("); 621e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 622e8d8bef9SDimitry Andric if (Expr.empty()) 623e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, Expr, "missing operand in expression"); 624e8d8bef9SDimitry Andric 625e8d8bef9SDimitry Andric // Note: parseNumericOperand handles nested opening parentheses. 626e8d8bef9SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> SubExprResult = parseNumericOperand( 627e8d8bef9SDimitry Andric Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber, 628e8d8bef9SDimitry Andric Context, SM); 629e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 630e8d8bef9SDimitry Andric while (SubExprResult && !Expr.empty() && !Expr.startswith(")")) { 631e8d8bef9SDimitry Andric StringRef OrigExpr = Expr; 632e8d8bef9SDimitry Andric SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false, 633e8d8bef9SDimitry Andric LineNumber, Context, SM); 634e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 635e8d8bef9SDimitry Andric } 636e8d8bef9SDimitry Andric if (!SubExprResult) 637e8d8bef9SDimitry Andric return SubExprResult; 638e8d8bef9SDimitry Andric 639e8d8bef9SDimitry Andric if (!Expr.consume_front(")")) { 640e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, Expr, 641e8d8bef9SDimitry Andric "missing ')' at end of nested expression"); 642e8d8bef9SDimitry Andric } 643e8d8bef9SDimitry Andric return SubExprResult; 644e8d8bef9SDimitry Andric } 645e8d8bef9SDimitry Andric 646e8d8bef9SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> 647e8d8bef9SDimitry Andric Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr, 648e8d8bef9SDimitry Andric std::unique_ptr<ExpressionAST> LeftOp, 649e8d8bef9SDimitry Andric bool IsLegacyLineExpr, Optional<size_t> LineNumber, 650e8d8bef9SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) { 651e8d8bef9SDimitry Andric RemainingExpr = RemainingExpr.ltrim(SpaceChars); 652e8d8bef9SDimitry Andric if (RemainingExpr.empty()) 653e8d8bef9SDimitry Andric return std::move(LeftOp); 654e8d8bef9SDimitry Andric 655e8d8bef9SDimitry Andric // Check if this is a supported operation and select a function to perform 656e8d8bef9SDimitry Andric // it. 657e8d8bef9SDimitry Andric SMLoc OpLoc = SMLoc::getFromPointer(RemainingExpr.data()); 658e8d8bef9SDimitry Andric char Operator = popFront(RemainingExpr); 659e8d8bef9SDimitry Andric binop_eval_t EvalBinop; 660e8d8bef9SDimitry Andric switch (Operator) { 661e8d8bef9SDimitry Andric case '+': 662e8d8bef9SDimitry Andric EvalBinop = operator+; 663e8d8bef9SDimitry Andric break; 664e8d8bef9SDimitry Andric case '-': 665e8d8bef9SDimitry Andric EvalBinop = operator-; 666e8d8bef9SDimitry Andric break; 667e8d8bef9SDimitry Andric default: 668e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 669e8d8bef9SDimitry Andric SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'"); 670e8d8bef9SDimitry Andric } 671e8d8bef9SDimitry Andric 672e8d8bef9SDimitry Andric // Parse right operand. 673e8d8bef9SDimitry Andric RemainingExpr = RemainingExpr.ltrim(SpaceChars); 674e8d8bef9SDimitry Andric if (RemainingExpr.empty()) 675e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, RemainingExpr, 676e8d8bef9SDimitry Andric "missing operand in expression"); 677e8d8bef9SDimitry Andric // The second operand in a legacy @LINE expression is always a literal. 678e8d8bef9SDimitry Andric AllowedOperand AO = 679e8d8bef9SDimitry Andric IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any; 680e8d8bef9SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> RightOpResult = 681e8d8bef9SDimitry Andric parseNumericOperand(RemainingExpr, AO, /*MaybeInvalidConstraint=*/false, 682e8d8bef9SDimitry Andric LineNumber, Context, SM); 683e8d8bef9SDimitry Andric if (!RightOpResult) 684e8d8bef9SDimitry Andric return RightOpResult; 685e8d8bef9SDimitry Andric 686e8d8bef9SDimitry Andric Expr = Expr.drop_back(RemainingExpr.size()); 687e8d8bef9SDimitry Andric return std::make_unique<BinaryOperation>(Expr, EvalBinop, std::move(LeftOp), 688e8d8bef9SDimitry Andric std::move(*RightOpResult)); 689e8d8bef9SDimitry Andric } 690e8d8bef9SDimitry Andric 691e8d8bef9SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> 692e8d8bef9SDimitry Andric Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName, 693e8d8bef9SDimitry Andric Optional<size_t> LineNumber, 694e8d8bef9SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) { 695e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 696e8d8bef9SDimitry Andric assert(Expr.startswith("(")); 697e8d8bef9SDimitry Andric 698e8d8bef9SDimitry Andric auto OptFunc = StringSwitch<Optional<binop_eval_t>>(FuncName) 699e8d8bef9SDimitry Andric .Case("add", operator+) 700e8d8bef9SDimitry Andric .Case("div", operator/) 701e8d8bef9SDimitry Andric .Case("max", max) 702e8d8bef9SDimitry Andric .Case("min", min) 703e8d8bef9SDimitry Andric .Case("mul", operator*) 704e8d8bef9SDimitry Andric .Case("sub", operator-) 705e8d8bef9SDimitry Andric .Default(None); 706e8d8bef9SDimitry Andric 707e8d8bef9SDimitry Andric if (!OptFunc) 708e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 709e8d8bef9SDimitry Andric SM, FuncName, Twine("call to undefined function '") + FuncName + "'"); 710e8d8bef9SDimitry Andric 711e8d8bef9SDimitry Andric Expr.consume_front("("); 712e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 713e8d8bef9SDimitry Andric 714e8d8bef9SDimitry Andric // Parse call arguments, which are comma separated. 715e8d8bef9SDimitry Andric SmallVector<std::unique_ptr<ExpressionAST>, 4> Args; 716e8d8bef9SDimitry Andric while (!Expr.empty() && !Expr.startswith(")")) { 717e8d8bef9SDimitry Andric if (Expr.startswith(",")) 718e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, Expr, "missing argument"); 719e8d8bef9SDimitry Andric 720e8d8bef9SDimitry Andric // Parse the argument, which is an arbitary expression. 721e8d8bef9SDimitry Andric StringRef OuterBinOpExpr = Expr; 722e8d8bef9SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> Arg = parseNumericOperand( 723e8d8bef9SDimitry Andric Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber, 724e8d8bef9SDimitry Andric Context, SM); 725e8d8bef9SDimitry Andric while (Arg && !Expr.empty()) { 726e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 727e8d8bef9SDimitry Andric // Have we reached an argument terminator? 728e8d8bef9SDimitry Andric if (Expr.startswith(",") || Expr.startswith(")")) 729e8d8bef9SDimitry Andric break; 730e8d8bef9SDimitry Andric 731e8d8bef9SDimitry Andric // Arg = Arg <op> <expr> 732e8d8bef9SDimitry Andric Arg = parseBinop(OuterBinOpExpr, Expr, std::move(*Arg), false, LineNumber, 733e8d8bef9SDimitry Andric Context, SM); 734e8d8bef9SDimitry Andric } 735e8d8bef9SDimitry Andric 736e8d8bef9SDimitry Andric // Prefer an expression error over a generic invalid argument message. 737e8d8bef9SDimitry Andric if (!Arg) 738e8d8bef9SDimitry Andric return Arg.takeError(); 739e8d8bef9SDimitry Andric Args.push_back(std::move(*Arg)); 740e8d8bef9SDimitry Andric 741e8d8bef9SDimitry Andric // Have we parsed all available arguments? 742e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 743e8d8bef9SDimitry Andric if (!Expr.consume_front(",")) 744e8d8bef9SDimitry Andric break; 745e8d8bef9SDimitry Andric 746e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 747e8d8bef9SDimitry Andric if (Expr.startswith(")")) 748e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, Expr, "missing argument"); 749e8d8bef9SDimitry Andric } 750e8d8bef9SDimitry Andric 751e8d8bef9SDimitry Andric if (!Expr.consume_front(")")) 752e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, Expr, 753e8d8bef9SDimitry Andric "missing ')' at end of call expression"); 754e8d8bef9SDimitry Andric 755e8d8bef9SDimitry Andric const unsigned NumArgs = Args.size(); 756e8d8bef9SDimitry Andric if (NumArgs == 2) 757e8d8bef9SDimitry Andric return std::make_unique<BinaryOperation>(Expr, *OptFunc, std::move(Args[0]), 758e8d8bef9SDimitry Andric std::move(Args[1])); 759e8d8bef9SDimitry Andric 760e8d8bef9SDimitry Andric // TODO: Support more than binop_eval_t. 761e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, FuncName, 762e8d8bef9SDimitry Andric Twine("function '") + FuncName + 763e8d8bef9SDimitry Andric Twine("' takes 2 arguments but ") + 764e8d8bef9SDimitry Andric Twine(NumArgs) + " given"); 765e8d8bef9SDimitry Andric } 766e8d8bef9SDimitry Andric 767e8d8bef9SDimitry Andric Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock( 768e8d8bef9SDimitry Andric StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable, 769e8d8bef9SDimitry Andric bool IsLegacyLineExpr, Optional<size_t> LineNumber, 770e8d8bef9SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) { 771e8d8bef9SDimitry Andric std::unique_ptr<ExpressionAST> ExpressionASTPointer = nullptr; 772e8d8bef9SDimitry Andric StringRef DefExpr = StringRef(); 773e8d8bef9SDimitry Andric DefinedNumericVariable = None; 774e8d8bef9SDimitry Andric ExpressionFormat ExplicitFormat = ExpressionFormat(); 775e8d8bef9SDimitry Andric unsigned Precision = 0; 776e8d8bef9SDimitry Andric 777e8d8bef9SDimitry Andric // Parse format specifier (NOTE: ',' is also an argument seperator). 778e8d8bef9SDimitry Andric size_t FormatSpecEnd = Expr.find(','); 779e8d8bef9SDimitry Andric size_t FunctionStart = Expr.find('('); 780e8d8bef9SDimitry Andric if (FormatSpecEnd != StringRef::npos && FormatSpecEnd < FunctionStart) { 781e8d8bef9SDimitry Andric StringRef FormatExpr = Expr.take_front(FormatSpecEnd); 782e8d8bef9SDimitry Andric Expr = Expr.drop_front(FormatSpecEnd + 1); 783e8d8bef9SDimitry Andric FormatExpr = FormatExpr.trim(SpaceChars); 784e8d8bef9SDimitry Andric if (!FormatExpr.consume_front("%")) 785e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 786e8d8bef9SDimitry Andric SM, FormatExpr, 787e8d8bef9SDimitry Andric "invalid matching format specification in expression"); 788e8d8bef9SDimitry Andric 789fe6060f1SDimitry Andric // Parse alternate form flag. 790fe6060f1SDimitry Andric SMLoc AlternateFormFlagLoc = SMLoc::getFromPointer(FormatExpr.data()); 791fe6060f1SDimitry Andric bool AlternateForm = FormatExpr.consume_front("#"); 792fe6060f1SDimitry Andric 793e8d8bef9SDimitry Andric // Parse precision. 794e8d8bef9SDimitry Andric if (FormatExpr.consume_front(".")) { 795e8d8bef9SDimitry Andric if (FormatExpr.consumeInteger(10, Precision)) 796e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, FormatExpr, 797e8d8bef9SDimitry Andric "invalid precision in format specifier"); 798e8d8bef9SDimitry Andric } 799e8d8bef9SDimitry Andric 800e8d8bef9SDimitry Andric if (!FormatExpr.empty()) { 801e8d8bef9SDimitry Andric // Check for unknown matching format specifier and set matching format in 802e8d8bef9SDimitry Andric // class instance representing this expression. 803e8d8bef9SDimitry Andric SMLoc FmtLoc = SMLoc::getFromPointer(FormatExpr.data()); 804e8d8bef9SDimitry Andric switch (popFront(FormatExpr)) { 805e8d8bef9SDimitry Andric case 'u': 806e8d8bef9SDimitry Andric ExplicitFormat = 807e8d8bef9SDimitry Andric ExpressionFormat(ExpressionFormat::Kind::Unsigned, Precision); 808e8d8bef9SDimitry Andric break; 809e8d8bef9SDimitry Andric case 'd': 810e8d8bef9SDimitry Andric ExplicitFormat = 811e8d8bef9SDimitry Andric ExpressionFormat(ExpressionFormat::Kind::Signed, Precision); 812e8d8bef9SDimitry Andric break; 813e8d8bef9SDimitry Andric case 'x': 814fe6060f1SDimitry Andric ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexLower, 815fe6060f1SDimitry Andric Precision, AlternateForm); 816e8d8bef9SDimitry Andric break; 817e8d8bef9SDimitry Andric case 'X': 818fe6060f1SDimitry Andric ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexUpper, 819fe6060f1SDimitry Andric Precision, AlternateForm); 820e8d8bef9SDimitry Andric break; 821e8d8bef9SDimitry Andric default: 822e8d8bef9SDimitry Andric return ErrorDiagnostic::get(SM, FmtLoc, 823e8d8bef9SDimitry Andric "invalid format specifier in expression"); 824e8d8bef9SDimitry Andric } 825e8d8bef9SDimitry Andric } 826e8d8bef9SDimitry Andric 827fe6060f1SDimitry Andric if (AlternateForm && ExplicitFormat != ExpressionFormat::Kind::HexLower && 828fe6060f1SDimitry Andric ExplicitFormat != ExpressionFormat::Kind::HexUpper) 829fe6060f1SDimitry Andric return ErrorDiagnostic::get( 830fe6060f1SDimitry Andric SM, AlternateFormFlagLoc, 831fe6060f1SDimitry Andric "alternate form only supported for hex values"); 832fe6060f1SDimitry Andric 833e8d8bef9SDimitry Andric FormatExpr = FormatExpr.ltrim(SpaceChars); 834e8d8bef9SDimitry Andric if (!FormatExpr.empty()) 835e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 836e8d8bef9SDimitry Andric SM, FormatExpr, 837e8d8bef9SDimitry Andric "invalid matching format specification in expression"); 838e8d8bef9SDimitry Andric } 839e8d8bef9SDimitry Andric 840e8d8bef9SDimitry Andric // Save variable definition expression if any. 841e8d8bef9SDimitry Andric size_t DefEnd = Expr.find(':'); 842e8d8bef9SDimitry Andric if (DefEnd != StringRef::npos) { 843e8d8bef9SDimitry Andric DefExpr = Expr.substr(0, DefEnd); 844e8d8bef9SDimitry Andric Expr = Expr.substr(DefEnd + 1); 845e8d8bef9SDimitry Andric } 846e8d8bef9SDimitry Andric 847e8d8bef9SDimitry Andric // Parse matching constraint. 848e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 849e8d8bef9SDimitry Andric bool HasParsedValidConstraint = false; 850e8d8bef9SDimitry Andric if (Expr.consume_front("==")) 851e8d8bef9SDimitry Andric HasParsedValidConstraint = true; 852e8d8bef9SDimitry Andric 853e8d8bef9SDimitry Andric // Parse the expression itself. 854e8d8bef9SDimitry Andric Expr = Expr.ltrim(SpaceChars); 855e8d8bef9SDimitry Andric if (Expr.empty()) { 856e8d8bef9SDimitry Andric if (HasParsedValidConstraint) 857e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 858e8d8bef9SDimitry Andric SM, Expr, "empty numeric expression should not have a constraint"); 859e8d8bef9SDimitry Andric } else { 860e8d8bef9SDimitry Andric Expr = Expr.rtrim(SpaceChars); 861e8d8bef9SDimitry Andric StringRef OuterBinOpExpr = Expr; 862e8d8bef9SDimitry Andric // The first operand in a legacy @LINE expression is always the @LINE 863e8d8bef9SDimitry Andric // pseudo variable. 864e8d8bef9SDimitry Andric AllowedOperand AO = 865e8d8bef9SDimitry Andric IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any; 866e8d8bef9SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> ParseResult = parseNumericOperand( 867e8d8bef9SDimitry Andric Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM); 868e8d8bef9SDimitry Andric while (ParseResult && !Expr.empty()) { 869e8d8bef9SDimitry Andric ParseResult = parseBinop(OuterBinOpExpr, Expr, std::move(*ParseResult), 870e8d8bef9SDimitry Andric IsLegacyLineExpr, LineNumber, Context, SM); 871e8d8bef9SDimitry Andric // Legacy @LINE expressions only allow 2 operands. 872e8d8bef9SDimitry Andric if (ParseResult && IsLegacyLineExpr && !Expr.empty()) 873e8d8bef9SDimitry Andric return ErrorDiagnostic::get( 874e8d8bef9SDimitry Andric SM, Expr, 875e8d8bef9SDimitry Andric "unexpected characters at end of expression '" + Expr + "'"); 876e8d8bef9SDimitry Andric } 877e8d8bef9SDimitry Andric if (!ParseResult) 878e8d8bef9SDimitry Andric return ParseResult.takeError(); 879e8d8bef9SDimitry Andric ExpressionASTPointer = std::move(*ParseResult); 880e8d8bef9SDimitry Andric } 881e8d8bef9SDimitry Andric 882e8d8bef9SDimitry Andric // Select format of the expression, i.e. (i) its explicit format, if any, 883e8d8bef9SDimitry Andric // otherwise (ii) its implicit format, if any, otherwise (iii) the default 884e8d8bef9SDimitry Andric // format (unsigned). Error out in case of conflicting implicit format 885e8d8bef9SDimitry Andric // without explicit format. 886e8d8bef9SDimitry Andric ExpressionFormat Format; 887e8d8bef9SDimitry Andric if (ExplicitFormat) 888e8d8bef9SDimitry Andric Format = ExplicitFormat; 889e8d8bef9SDimitry Andric else if (ExpressionASTPointer) { 890e8d8bef9SDimitry Andric Expected<ExpressionFormat> ImplicitFormat = 891e8d8bef9SDimitry Andric ExpressionASTPointer->getImplicitFormat(SM); 892e8d8bef9SDimitry Andric if (!ImplicitFormat) 893e8d8bef9SDimitry Andric return ImplicitFormat.takeError(); 894e8d8bef9SDimitry Andric Format = *ImplicitFormat; 895e8d8bef9SDimitry Andric } 896e8d8bef9SDimitry Andric if (!Format) 897e8d8bef9SDimitry Andric Format = ExpressionFormat(ExpressionFormat::Kind::Unsigned, Precision); 898e8d8bef9SDimitry Andric 899e8d8bef9SDimitry Andric std::unique_ptr<Expression> ExpressionPointer = 900e8d8bef9SDimitry Andric std::make_unique<Expression>(std::move(ExpressionASTPointer), Format); 901e8d8bef9SDimitry Andric 902e8d8bef9SDimitry Andric // Parse the numeric variable definition. 903e8d8bef9SDimitry Andric if (DefEnd != StringRef::npos) { 904e8d8bef9SDimitry Andric DefExpr = DefExpr.ltrim(SpaceChars); 905e8d8bef9SDimitry Andric Expected<NumericVariable *> ParseResult = parseNumericVariableDefinition( 906e8d8bef9SDimitry Andric DefExpr, Context, LineNumber, ExpressionPointer->getFormat(), SM); 907e8d8bef9SDimitry Andric 908e8d8bef9SDimitry Andric if (!ParseResult) 909e8d8bef9SDimitry Andric return ParseResult.takeError(); 910e8d8bef9SDimitry Andric DefinedNumericVariable = *ParseResult; 911e8d8bef9SDimitry Andric } 912e8d8bef9SDimitry Andric 913e8d8bef9SDimitry Andric return std::move(ExpressionPointer); 914e8d8bef9SDimitry Andric } 915e8d8bef9SDimitry Andric 916e8d8bef9SDimitry Andric bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, 917e8d8bef9SDimitry Andric SourceMgr &SM, const FileCheckRequest &Req) { 918e8d8bef9SDimitry Andric bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; 919e8d8bef9SDimitry Andric IgnoreCase = Req.IgnoreCase; 920e8d8bef9SDimitry Andric 921e8d8bef9SDimitry Andric PatternLoc = SMLoc::getFromPointer(PatternStr.data()); 922e8d8bef9SDimitry Andric 923e8d8bef9SDimitry Andric if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) 924e8d8bef9SDimitry Andric // Ignore trailing whitespace. 925e8d8bef9SDimitry Andric while (!PatternStr.empty() && 926e8d8bef9SDimitry Andric (PatternStr.back() == ' ' || PatternStr.back() == '\t')) 927e8d8bef9SDimitry Andric PatternStr = PatternStr.substr(0, PatternStr.size() - 1); 928e8d8bef9SDimitry Andric 929e8d8bef9SDimitry Andric // Check that there is something on the line. 930e8d8bef9SDimitry Andric if (PatternStr.empty() && CheckTy != Check::CheckEmpty) { 931e8d8bef9SDimitry Andric SM.PrintMessage(PatternLoc, SourceMgr::DK_Error, 932e8d8bef9SDimitry Andric "found empty check string with prefix '" + Prefix + ":'"); 933e8d8bef9SDimitry Andric return true; 934e8d8bef9SDimitry Andric } 935e8d8bef9SDimitry Andric 936e8d8bef9SDimitry Andric if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) { 937e8d8bef9SDimitry Andric SM.PrintMessage( 938e8d8bef9SDimitry Andric PatternLoc, SourceMgr::DK_Error, 939e8d8bef9SDimitry Andric "found non-empty check string for empty check with prefix '" + Prefix + 940e8d8bef9SDimitry Andric ":'"); 941e8d8bef9SDimitry Andric return true; 942e8d8bef9SDimitry Andric } 943e8d8bef9SDimitry Andric 944e8d8bef9SDimitry Andric if (CheckTy == Check::CheckEmpty) { 945e8d8bef9SDimitry Andric RegExStr = "(\n$)"; 946e8d8bef9SDimitry Andric return false; 947e8d8bef9SDimitry Andric } 948e8d8bef9SDimitry Andric 949e8d8bef9SDimitry Andric // If literal check, set fixed string. 950e8d8bef9SDimitry Andric if (CheckTy.isLiteralMatch()) { 951e8d8bef9SDimitry Andric FixedStr = PatternStr; 952e8d8bef9SDimitry Andric return false; 953e8d8bef9SDimitry Andric } 954e8d8bef9SDimitry Andric 955e8d8bef9SDimitry Andric // Check to see if this is a fixed string, or if it has regex pieces. 956e8d8bef9SDimitry Andric if (!MatchFullLinesHere && 957349cc55cSDimitry Andric (PatternStr.size() < 2 || 958349cc55cSDimitry Andric (!PatternStr.contains("{{") && !PatternStr.contains("[[")))) { 959e8d8bef9SDimitry Andric FixedStr = PatternStr; 960e8d8bef9SDimitry Andric return false; 961e8d8bef9SDimitry Andric } 962e8d8bef9SDimitry Andric 963e8d8bef9SDimitry Andric if (MatchFullLinesHere) { 964e8d8bef9SDimitry Andric RegExStr += '^'; 965e8d8bef9SDimitry Andric if (!Req.NoCanonicalizeWhiteSpace) 966e8d8bef9SDimitry Andric RegExStr += " *"; 967e8d8bef9SDimitry Andric } 968e8d8bef9SDimitry Andric 969e8d8bef9SDimitry Andric // Paren value #0 is for the fully matched string. Any new parenthesized 970e8d8bef9SDimitry Andric // values add from there. 971e8d8bef9SDimitry Andric unsigned CurParen = 1; 972e8d8bef9SDimitry Andric 973e8d8bef9SDimitry Andric // Otherwise, there is at least one regex piece. Build up the regex pattern 974e8d8bef9SDimitry Andric // by escaping scary characters in fixed strings, building up one big regex. 975e8d8bef9SDimitry Andric while (!PatternStr.empty()) { 976e8d8bef9SDimitry Andric // RegEx matches. 977e8d8bef9SDimitry Andric if (PatternStr.startswith("{{")) { 978e8d8bef9SDimitry Andric // This is the start of a regex match. Scan for the }}. 979e8d8bef9SDimitry Andric size_t End = PatternStr.find("}}"); 980e8d8bef9SDimitry Andric if (End == StringRef::npos) { 981e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), 982e8d8bef9SDimitry Andric SourceMgr::DK_Error, 983e8d8bef9SDimitry Andric "found start of regex string with no end '}}'"); 984e8d8bef9SDimitry Andric return true; 985e8d8bef9SDimitry Andric } 986e8d8bef9SDimitry Andric 987e8d8bef9SDimitry Andric // Enclose {{}} patterns in parens just like [[]] even though we're not 988e8d8bef9SDimitry Andric // capturing the result for any purpose. This is required in case the 989e8d8bef9SDimitry Andric // expression contains an alternation like: CHECK: abc{{x|z}}def. We 990e8d8bef9SDimitry Andric // want this to turn into: "abc(x|z)def" not "abcx|zdef". 991e8d8bef9SDimitry Andric RegExStr += '('; 992e8d8bef9SDimitry Andric ++CurParen; 993e8d8bef9SDimitry Andric 994e8d8bef9SDimitry Andric if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM)) 995e8d8bef9SDimitry Andric return true; 996e8d8bef9SDimitry Andric RegExStr += ')'; 997e8d8bef9SDimitry Andric 998e8d8bef9SDimitry Andric PatternStr = PatternStr.substr(End + 2); 999e8d8bef9SDimitry Andric continue; 1000e8d8bef9SDimitry Andric } 1001e8d8bef9SDimitry Andric 1002e8d8bef9SDimitry Andric // String and numeric substitution blocks. Pattern substitution blocks come 1003e8d8bef9SDimitry Andric // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some 1004e8d8bef9SDimitry Andric // other regex) and assigns it to the string variable 'foo'. The latter 1005e8d8bef9SDimitry Andric // substitutes foo's value. Numeric substitution blocks recognize the same 1006e8d8bef9SDimitry Andric // form as string ones, but start with a '#' sign after the double 1007e8d8bef9SDimitry Andric // brackets. They also accept a combined form which sets a numeric variable 1008e8d8bef9SDimitry Andric // to the evaluation of an expression. Both string and numeric variable 1009e8d8bef9SDimitry Andric // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be 101004eeddc0SDimitry Andric // valid, as this helps catch some common errors. If there are extra '['s 101104eeddc0SDimitry Andric // before the "[[", treat them literally. 101204eeddc0SDimitry Andric if (PatternStr.startswith("[[") && !PatternStr.startswith("[[[")) { 1013e8d8bef9SDimitry Andric StringRef UnparsedPatternStr = PatternStr.substr(2); 1014e8d8bef9SDimitry Andric // Find the closing bracket pair ending the match. End is going to be an 1015e8d8bef9SDimitry Andric // offset relative to the beginning of the match string. 1016e8d8bef9SDimitry Andric size_t End = FindRegexVarEnd(UnparsedPatternStr, SM); 1017e8d8bef9SDimitry Andric StringRef MatchStr = UnparsedPatternStr.substr(0, End); 1018e8d8bef9SDimitry Andric bool IsNumBlock = MatchStr.consume_front("#"); 1019e8d8bef9SDimitry Andric 1020e8d8bef9SDimitry Andric if (End == StringRef::npos) { 1021e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), 1022e8d8bef9SDimitry Andric SourceMgr::DK_Error, 1023e8d8bef9SDimitry Andric "Invalid substitution block, no ]] found"); 1024e8d8bef9SDimitry Andric return true; 1025e8d8bef9SDimitry Andric } 1026e8d8bef9SDimitry Andric // Strip the substitution block we are parsing. End points to the start 1027e8d8bef9SDimitry Andric // of the "]]" closing the expression so account for it in computing the 1028e8d8bef9SDimitry Andric // index of the first unparsed character. 1029e8d8bef9SDimitry Andric PatternStr = UnparsedPatternStr.substr(End + 2); 1030e8d8bef9SDimitry Andric 1031e8d8bef9SDimitry Andric bool IsDefinition = false; 1032e8d8bef9SDimitry Andric bool SubstNeeded = false; 1033e8d8bef9SDimitry Andric // Whether the substitution block is a legacy use of @LINE with string 1034e8d8bef9SDimitry Andric // substitution block syntax. 1035e8d8bef9SDimitry Andric bool IsLegacyLineExpr = false; 1036e8d8bef9SDimitry Andric StringRef DefName; 1037e8d8bef9SDimitry Andric StringRef SubstStr; 1038349cc55cSDimitry Andric StringRef MatchRegexp; 1039349cc55cSDimitry Andric std::string WildcardRegexp; 1040e8d8bef9SDimitry Andric size_t SubstInsertIdx = RegExStr.size(); 1041e8d8bef9SDimitry Andric 1042e8d8bef9SDimitry Andric // Parse string variable or legacy @LINE expression. 1043e8d8bef9SDimitry Andric if (!IsNumBlock) { 1044e8d8bef9SDimitry Andric size_t VarEndIdx = MatchStr.find(':'); 1045e8d8bef9SDimitry Andric size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t"); 1046e8d8bef9SDimitry Andric if (SpacePos != StringRef::npos) { 1047e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos), 1048e8d8bef9SDimitry Andric SourceMgr::DK_Error, "unexpected whitespace"); 1049e8d8bef9SDimitry Andric return true; 1050e8d8bef9SDimitry Andric } 1051e8d8bef9SDimitry Andric 1052e8d8bef9SDimitry Andric // Get the name (e.g. "foo") and verify it is well formed. 1053e8d8bef9SDimitry Andric StringRef OrigMatchStr = MatchStr; 1054e8d8bef9SDimitry Andric Expected<Pattern::VariableProperties> ParseVarResult = 1055e8d8bef9SDimitry Andric parseVariable(MatchStr, SM); 1056e8d8bef9SDimitry Andric if (!ParseVarResult) { 1057e8d8bef9SDimitry Andric logAllUnhandledErrors(ParseVarResult.takeError(), errs()); 1058e8d8bef9SDimitry Andric return true; 1059e8d8bef9SDimitry Andric } 1060e8d8bef9SDimitry Andric StringRef Name = ParseVarResult->Name; 1061e8d8bef9SDimitry Andric bool IsPseudo = ParseVarResult->IsPseudo; 1062e8d8bef9SDimitry Andric 1063e8d8bef9SDimitry Andric IsDefinition = (VarEndIdx != StringRef::npos); 1064e8d8bef9SDimitry Andric SubstNeeded = !IsDefinition; 1065e8d8bef9SDimitry Andric if (IsDefinition) { 1066e8d8bef9SDimitry Andric if ((IsPseudo || !MatchStr.consume_front(":"))) { 1067e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Name.data()), 1068e8d8bef9SDimitry Andric SourceMgr::DK_Error, 1069e8d8bef9SDimitry Andric "invalid name in string variable definition"); 1070e8d8bef9SDimitry Andric return true; 1071e8d8bef9SDimitry Andric } 1072e8d8bef9SDimitry Andric 1073e8d8bef9SDimitry Andric // Detect collisions between string and numeric variables when the 1074e8d8bef9SDimitry Andric // former is created later than the latter. 1075e8d8bef9SDimitry Andric if (Context->GlobalNumericVariableTable.find(Name) != 1076e8d8bef9SDimitry Andric Context->GlobalNumericVariableTable.end()) { 1077e8d8bef9SDimitry Andric SM.PrintMessage( 1078e8d8bef9SDimitry Andric SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error, 1079e8d8bef9SDimitry Andric "numeric variable with name '" + Name + "' already exists"); 1080e8d8bef9SDimitry Andric return true; 1081e8d8bef9SDimitry Andric } 1082e8d8bef9SDimitry Andric DefName = Name; 1083349cc55cSDimitry Andric MatchRegexp = MatchStr; 1084e8d8bef9SDimitry Andric } else { 1085e8d8bef9SDimitry Andric if (IsPseudo) { 1086e8d8bef9SDimitry Andric MatchStr = OrigMatchStr; 1087e8d8bef9SDimitry Andric IsLegacyLineExpr = IsNumBlock = true; 1088fe6060f1SDimitry Andric } else { 1089fe6060f1SDimitry Andric if (!MatchStr.empty()) { 1090fe6060f1SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Name.data()), 1091fe6060f1SDimitry Andric SourceMgr::DK_Error, 1092fe6060f1SDimitry Andric "invalid name in string variable use"); 1093fe6060f1SDimitry Andric return true; 1094fe6060f1SDimitry Andric } 1095e8d8bef9SDimitry Andric SubstStr = Name; 1096e8d8bef9SDimitry Andric } 1097e8d8bef9SDimitry Andric } 1098fe6060f1SDimitry Andric } 1099e8d8bef9SDimitry Andric 1100e8d8bef9SDimitry Andric // Parse numeric substitution block. 1101e8d8bef9SDimitry Andric std::unique_ptr<Expression> ExpressionPointer; 1102e8d8bef9SDimitry Andric Optional<NumericVariable *> DefinedNumericVariable; 1103e8d8bef9SDimitry Andric if (IsNumBlock) { 1104e8d8bef9SDimitry Andric Expected<std::unique_ptr<Expression>> ParseResult = 1105e8d8bef9SDimitry Andric parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, 1106e8d8bef9SDimitry Andric IsLegacyLineExpr, LineNumber, Context, 1107e8d8bef9SDimitry Andric SM); 1108e8d8bef9SDimitry Andric if (!ParseResult) { 1109e8d8bef9SDimitry Andric logAllUnhandledErrors(ParseResult.takeError(), errs()); 1110e8d8bef9SDimitry Andric return true; 1111e8d8bef9SDimitry Andric } 1112e8d8bef9SDimitry Andric ExpressionPointer = std::move(*ParseResult); 1113e8d8bef9SDimitry Andric SubstNeeded = ExpressionPointer->getAST() != nullptr; 1114e8d8bef9SDimitry Andric if (DefinedNumericVariable) { 1115e8d8bef9SDimitry Andric IsDefinition = true; 1116e8d8bef9SDimitry Andric DefName = (*DefinedNumericVariable)->getName(); 1117e8d8bef9SDimitry Andric } 1118e8d8bef9SDimitry Andric if (SubstNeeded) 1119e8d8bef9SDimitry Andric SubstStr = MatchStr; 1120e8d8bef9SDimitry Andric else { 1121e8d8bef9SDimitry Andric ExpressionFormat Format = ExpressionPointer->getFormat(); 1122349cc55cSDimitry Andric WildcardRegexp = cantFail(Format.getWildcardRegex()); 1123349cc55cSDimitry Andric MatchRegexp = WildcardRegexp; 1124e8d8bef9SDimitry Andric } 1125e8d8bef9SDimitry Andric } 1126e8d8bef9SDimitry Andric 1127e8d8bef9SDimitry Andric // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]]. 1128e8d8bef9SDimitry Andric if (IsDefinition) { 1129e8d8bef9SDimitry Andric RegExStr += '('; 1130e8d8bef9SDimitry Andric ++SubstInsertIdx; 1131e8d8bef9SDimitry Andric 1132e8d8bef9SDimitry Andric if (IsNumBlock) { 1133e8d8bef9SDimitry Andric NumericVariableMatch NumericVariableDefinition = { 1134e8d8bef9SDimitry Andric *DefinedNumericVariable, CurParen}; 1135e8d8bef9SDimitry Andric NumericVariableDefs[DefName] = NumericVariableDefinition; 1136e8d8bef9SDimitry Andric // This store is done here rather than in match() to allow 1137e8d8bef9SDimitry Andric // parseNumericVariableUse() to get the pointer to the class instance 1138e8d8bef9SDimitry Andric // of the right variable definition corresponding to a given numeric 1139e8d8bef9SDimitry Andric // variable use. 1140e8d8bef9SDimitry Andric Context->GlobalNumericVariableTable[DefName] = 1141e8d8bef9SDimitry Andric *DefinedNumericVariable; 1142e8d8bef9SDimitry Andric } else { 1143e8d8bef9SDimitry Andric VariableDefs[DefName] = CurParen; 1144e8d8bef9SDimitry Andric // Mark string variable as defined to detect collisions between 1145e8d8bef9SDimitry Andric // string and numeric variables in parseNumericVariableUse() and 1146e8d8bef9SDimitry Andric // defineCmdlineVariables() when the latter is created later than the 1147e8d8bef9SDimitry Andric // former. We cannot reuse GlobalVariableTable for this by populating 1148e8d8bef9SDimitry Andric // it with an empty string since we would then lose the ability to 1149e8d8bef9SDimitry Andric // detect the use of an undefined variable in match(). 1150e8d8bef9SDimitry Andric Context->DefinedVariableTable[DefName] = true; 1151e8d8bef9SDimitry Andric } 1152e8d8bef9SDimitry Andric 1153e8d8bef9SDimitry Andric ++CurParen; 1154e8d8bef9SDimitry Andric } 1155e8d8bef9SDimitry Andric 1156e8d8bef9SDimitry Andric if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM)) 1157e8d8bef9SDimitry Andric return true; 1158e8d8bef9SDimitry Andric 1159e8d8bef9SDimitry Andric if (IsDefinition) 1160e8d8bef9SDimitry Andric RegExStr += ')'; 1161e8d8bef9SDimitry Andric 1162e8d8bef9SDimitry Andric // Handle substitutions: [[foo]] and [[#<foo expr>]]. 1163e8d8bef9SDimitry Andric if (SubstNeeded) { 1164e8d8bef9SDimitry Andric // Handle substitution of string variables that were defined earlier on 1165e8d8bef9SDimitry Andric // the same line by emitting a backreference. Expressions do not 1166e8d8bef9SDimitry Andric // support substituting a numeric variable defined on the same line. 1167e8d8bef9SDimitry Andric if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) { 1168e8d8bef9SDimitry Andric unsigned CaptureParenGroup = VariableDefs[SubstStr]; 1169e8d8bef9SDimitry Andric if (CaptureParenGroup < 1 || CaptureParenGroup > 9) { 1170e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()), 1171e8d8bef9SDimitry Andric SourceMgr::DK_Error, 1172e8d8bef9SDimitry Andric "Can't back-reference more than 9 variables"); 1173e8d8bef9SDimitry Andric return true; 1174e8d8bef9SDimitry Andric } 1175e8d8bef9SDimitry Andric AddBackrefToRegEx(CaptureParenGroup); 1176e8d8bef9SDimitry Andric } else { 1177e8d8bef9SDimitry Andric // Handle substitution of string variables ([[<var>]]) defined in 1178e8d8bef9SDimitry Andric // previous CHECK patterns, and substitution of expressions. 1179e8d8bef9SDimitry Andric Substitution *Substitution = 1180e8d8bef9SDimitry Andric IsNumBlock 1181e8d8bef9SDimitry Andric ? Context->makeNumericSubstitution( 1182e8d8bef9SDimitry Andric SubstStr, std::move(ExpressionPointer), SubstInsertIdx) 1183e8d8bef9SDimitry Andric : Context->makeStringSubstitution(SubstStr, SubstInsertIdx); 1184e8d8bef9SDimitry Andric Substitutions.push_back(Substitution); 1185e8d8bef9SDimitry Andric } 1186e8d8bef9SDimitry Andric } 118704eeddc0SDimitry Andric 118804eeddc0SDimitry Andric continue; 1189e8d8bef9SDimitry Andric } 1190e8d8bef9SDimitry Andric 1191e8d8bef9SDimitry Andric // Handle fixed string matches. 1192e8d8bef9SDimitry Andric // Find the end, which is the start of the next regex. 119304eeddc0SDimitry Andric size_t FixedMatchEnd = 119404eeddc0SDimitry Andric std::min(PatternStr.find("{{", 1), PatternStr.find("[[", 1)); 1195e8d8bef9SDimitry Andric RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd)); 1196e8d8bef9SDimitry Andric PatternStr = PatternStr.substr(FixedMatchEnd); 1197e8d8bef9SDimitry Andric } 1198e8d8bef9SDimitry Andric 1199e8d8bef9SDimitry Andric if (MatchFullLinesHere) { 1200e8d8bef9SDimitry Andric if (!Req.NoCanonicalizeWhiteSpace) 1201e8d8bef9SDimitry Andric RegExStr += " *"; 1202e8d8bef9SDimitry Andric RegExStr += '$'; 1203e8d8bef9SDimitry Andric } 1204e8d8bef9SDimitry Andric 1205e8d8bef9SDimitry Andric return false; 1206e8d8bef9SDimitry Andric } 1207e8d8bef9SDimitry Andric 1208e8d8bef9SDimitry Andric bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) { 1209e8d8bef9SDimitry Andric Regex R(RS); 1210e8d8bef9SDimitry Andric std::string Error; 1211e8d8bef9SDimitry Andric if (!R.isValid(Error)) { 1212e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error, 1213e8d8bef9SDimitry Andric "invalid regex: " + Error); 1214e8d8bef9SDimitry Andric return true; 1215e8d8bef9SDimitry Andric } 1216e8d8bef9SDimitry Andric 1217e8d8bef9SDimitry Andric RegExStr += RS.str(); 1218e8d8bef9SDimitry Andric CurParen += R.getNumMatches(); 1219e8d8bef9SDimitry Andric return false; 1220e8d8bef9SDimitry Andric } 1221e8d8bef9SDimitry Andric 1222e8d8bef9SDimitry Andric void Pattern::AddBackrefToRegEx(unsigned BackrefNum) { 1223e8d8bef9SDimitry Andric assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number"); 1224e8d8bef9SDimitry Andric std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum); 1225e8d8bef9SDimitry Andric RegExStr += Backref; 1226e8d8bef9SDimitry Andric } 1227e8d8bef9SDimitry Andric 1228fe6060f1SDimitry Andric Pattern::MatchResult Pattern::match(StringRef Buffer, 1229e8d8bef9SDimitry Andric const SourceMgr &SM) const { 1230e8d8bef9SDimitry Andric // If this is the EOF pattern, match it immediately. 1231fe6060f1SDimitry Andric if (CheckTy == Check::CheckEOF) 1232fe6060f1SDimitry Andric return MatchResult(Buffer.size(), 0, Error::success()); 1233e8d8bef9SDimitry Andric 1234e8d8bef9SDimitry Andric // If this is a fixed string pattern, just match it now. 1235e8d8bef9SDimitry Andric if (!FixedStr.empty()) { 1236e8d8bef9SDimitry Andric size_t Pos = 1237fe6060f1SDimitry Andric IgnoreCase ? Buffer.find_insensitive(FixedStr) : Buffer.find(FixedStr); 1238e8d8bef9SDimitry Andric if (Pos == StringRef::npos) 1239e8d8bef9SDimitry Andric return make_error<NotFoundError>(); 1240fe6060f1SDimitry Andric return MatchResult(Pos, /*MatchLen=*/FixedStr.size(), Error::success()); 1241e8d8bef9SDimitry Andric } 1242e8d8bef9SDimitry Andric 1243e8d8bef9SDimitry Andric // Regex match. 1244e8d8bef9SDimitry Andric 1245e8d8bef9SDimitry Andric // If there are substitutions, we need to create a temporary string with the 1246e8d8bef9SDimitry Andric // actual value. 1247e8d8bef9SDimitry Andric StringRef RegExToMatch = RegExStr; 1248e8d8bef9SDimitry Andric std::string TmpStr; 1249e8d8bef9SDimitry Andric if (!Substitutions.empty()) { 1250e8d8bef9SDimitry Andric TmpStr = RegExStr; 1251e8d8bef9SDimitry Andric if (LineNumber) 1252e8d8bef9SDimitry Andric Context->LineVariable->setValue(ExpressionValue(*LineNumber)); 1253e8d8bef9SDimitry Andric 1254e8d8bef9SDimitry Andric size_t InsertOffset = 0; 1255e8d8bef9SDimitry Andric // Substitute all string variables and expressions whose values are only 1256e8d8bef9SDimitry Andric // now known. Use of string variables defined on the same line are handled 1257e8d8bef9SDimitry Andric // by back-references. 1258fe6060f1SDimitry Andric Error Errs = Error::success(); 1259e8d8bef9SDimitry Andric for (const auto &Substitution : Substitutions) { 1260e8d8bef9SDimitry Andric // Substitute and check for failure (e.g. use of undefined variable). 1261e8d8bef9SDimitry Andric Expected<std::string> Value = Substitution->getResult(); 1262e8d8bef9SDimitry Andric if (!Value) { 1263e8d8bef9SDimitry Andric // Convert to an ErrorDiagnostic to get location information. This is 1264fe6060f1SDimitry Andric // done here rather than printMatch/printNoMatch since now we know which 1265e8d8bef9SDimitry Andric // substitution block caused the overflow. 1266fe6060f1SDimitry Andric Errs = joinErrors(std::move(Errs), 1267fe6060f1SDimitry Andric handleErrors( 1268fe6060f1SDimitry Andric Value.takeError(), 1269fe6060f1SDimitry Andric [&](const OverflowError &E) { 1270fe6060f1SDimitry Andric return ErrorDiagnostic::get( 1271fe6060f1SDimitry Andric SM, Substitution->getFromString(), 1272e8d8bef9SDimitry Andric "unable to substitute variable or " 1273e8d8bef9SDimitry Andric "numeric expression: overflow error"); 1274fe6060f1SDimitry Andric }, 1275fe6060f1SDimitry Andric [&SM](const UndefVarError &E) { 1276fe6060f1SDimitry Andric return ErrorDiagnostic::get(SM, E.getVarName(), 1277fe6060f1SDimitry Andric E.message()); 1278fe6060f1SDimitry Andric })); 1279fe6060f1SDimitry Andric continue; 1280e8d8bef9SDimitry Andric } 1281e8d8bef9SDimitry Andric 1282e8d8bef9SDimitry Andric // Plop it into the regex at the adjusted offset. 1283e8d8bef9SDimitry Andric TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset, 1284e8d8bef9SDimitry Andric Value->begin(), Value->end()); 1285e8d8bef9SDimitry Andric InsertOffset += Value->size(); 1286e8d8bef9SDimitry Andric } 1287fe6060f1SDimitry Andric if (Errs) 1288fe6060f1SDimitry Andric return std::move(Errs); 1289e8d8bef9SDimitry Andric 1290e8d8bef9SDimitry Andric // Match the newly constructed regex. 1291e8d8bef9SDimitry Andric RegExToMatch = TmpStr; 1292e8d8bef9SDimitry Andric } 1293e8d8bef9SDimitry Andric 1294e8d8bef9SDimitry Andric SmallVector<StringRef, 4> MatchInfo; 1295e8d8bef9SDimitry Andric unsigned int Flags = Regex::Newline; 1296e8d8bef9SDimitry Andric if (IgnoreCase) 1297e8d8bef9SDimitry Andric Flags |= Regex::IgnoreCase; 1298e8d8bef9SDimitry Andric if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo)) 1299e8d8bef9SDimitry Andric return make_error<NotFoundError>(); 1300e8d8bef9SDimitry Andric 1301e8d8bef9SDimitry Andric // Successful regex match. 1302e8d8bef9SDimitry Andric assert(!MatchInfo.empty() && "Didn't get any match"); 1303e8d8bef9SDimitry Andric StringRef FullMatch = MatchInfo[0]; 1304e8d8bef9SDimitry Andric 1305e8d8bef9SDimitry Andric // If this defines any string variables, remember their values. 1306e8d8bef9SDimitry Andric for (const auto &VariableDef : VariableDefs) { 1307e8d8bef9SDimitry Andric assert(VariableDef.second < MatchInfo.size() && "Internal paren error"); 1308e8d8bef9SDimitry Andric Context->GlobalVariableTable[VariableDef.first] = 1309e8d8bef9SDimitry Andric MatchInfo[VariableDef.second]; 1310e8d8bef9SDimitry Andric } 1311e8d8bef9SDimitry Andric 1312fe6060f1SDimitry Andric // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after 1313fe6060f1SDimitry Andric // the required preceding newline, which is consumed by the pattern in the 1314fe6060f1SDimitry Andric // case of CHECK-EMPTY but not CHECK-NEXT. 1315fe6060f1SDimitry Andric size_t MatchStartSkip = CheckTy == Check::CheckEmpty; 1316fe6060f1SDimitry Andric Match TheMatch; 1317fe6060f1SDimitry Andric TheMatch.Pos = FullMatch.data() - Buffer.data() + MatchStartSkip; 1318fe6060f1SDimitry Andric TheMatch.Len = FullMatch.size() - MatchStartSkip; 1319fe6060f1SDimitry Andric 1320e8d8bef9SDimitry Andric // If this defines any numeric variables, remember their values. 1321e8d8bef9SDimitry Andric for (const auto &NumericVariableDef : NumericVariableDefs) { 1322e8d8bef9SDimitry Andric const NumericVariableMatch &NumericVariableMatch = 1323e8d8bef9SDimitry Andric NumericVariableDef.getValue(); 1324e8d8bef9SDimitry Andric unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup; 1325e8d8bef9SDimitry Andric assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error"); 1326e8d8bef9SDimitry Andric NumericVariable *DefinedNumericVariable = 1327e8d8bef9SDimitry Andric NumericVariableMatch.DefinedNumericVariable; 1328e8d8bef9SDimitry Andric 1329e8d8bef9SDimitry Andric StringRef MatchedValue = MatchInfo[CaptureParenGroup]; 1330e8d8bef9SDimitry Andric ExpressionFormat Format = DefinedNumericVariable->getImplicitFormat(); 1331e8d8bef9SDimitry Andric Expected<ExpressionValue> Value = 1332e8d8bef9SDimitry Andric Format.valueFromStringRepr(MatchedValue, SM); 1333e8d8bef9SDimitry Andric if (!Value) 1334fe6060f1SDimitry Andric return MatchResult(TheMatch, Value.takeError()); 1335e8d8bef9SDimitry Andric DefinedNumericVariable->setValue(*Value, MatchedValue); 1336e8d8bef9SDimitry Andric } 1337e8d8bef9SDimitry Andric 1338fe6060f1SDimitry Andric return MatchResult(TheMatch, Error::success()); 1339e8d8bef9SDimitry Andric } 1340e8d8bef9SDimitry Andric 1341e8d8bef9SDimitry Andric unsigned Pattern::computeMatchDistance(StringRef Buffer) const { 1342e8d8bef9SDimitry Andric // Just compute the number of matching characters. For regular expressions, we 1343e8d8bef9SDimitry Andric // just compare against the regex itself and hope for the best. 1344e8d8bef9SDimitry Andric // 1345e8d8bef9SDimitry Andric // FIXME: One easy improvement here is have the regex lib generate a single 1346e8d8bef9SDimitry Andric // example regular expression which matches, and use that as the example 1347e8d8bef9SDimitry Andric // string. 1348e8d8bef9SDimitry Andric StringRef ExampleString(FixedStr); 1349e8d8bef9SDimitry Andric if (ExampleString.empty()) 1350e8d8bef9SDimitry Andric ExampleString = RegExStr; 1351e8d8bef9SDimitry Andric 1352e8d8bef9SDimitry Andric // Only compare up to the first line in the buffer, or the string size. 1353e8d8bef9SDimitry Andric StringRef BufferPrefix = Buffer.substr(0, ExampleString.size()); 1354e8d8bef9SDimitry Andric BufferPrefix = BufferPrefix.split('\n').first; 1355e8d8bef9SDimitry Andric return BufferPrefix.edit_distance(ExampleString); 1356e8d8bef9SDimitry Andric } 1357e8d8bef9SDimitry Andric 1358e8d8bef9SDimitry Andric void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer, 1359e8d8bef9SDimitry Andric SMRange Range, 1360e8d8bef9SDimitry Andric FileCheckDiag::MatchType MatchTy, 1361e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags) const { 1362e8d8bef9SDimitry Andric // Print what we know about substitutions. 1363e8d8bef9SDimitry Andric if (!Substitutions.empty()) { 1364e8d8bef9SDimitry Andric for (const auto &Substitution : Substitutions) { 1365e8d8bef9SDimitry Andric SmallString<256> Msg; 1366e8d8bef9SDimitry Andric raw_svector_ostream OS(Msg); 1367e8d8bef9SDimitry Andric 1368fe6060f1SDimitry Andric Expected<std::string> MatchedValue = Substitution->getResult(); 1369fe6060f1SDimitry Andric // Substitution failures are handled in printNoMatch(). 1370e8d8bef9SDimitry Andric if (!MatchedValue) { 1371fe6060f1SDimitry Andric consumeError(MatchedValue.takeError()); 1372fe6060f1SDimitry Andric continue; 1373e8d8bef9SDimitry Andric } 1374fe6060f1SDimitry Andric 1375e8d8bef9SDimitry Andric OS << "with \""; 1376e8d8bef9SDimitry Andric OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; 1377e8d8bef9SDimitry Andric OS.write_escaped(*MatchedValue) << "\""; 1378e8d8bef9SDimitry Andric 1379e8d8bef9SDimitry Andric // We report only the start of the match/search range to suggest we are 1380e8d8bef9SDimitry Andric // reporting the substitutions as set at the start of the match/search. 1381e8d8bef9SDimitry Andric // Indicating a non-zero-length range might instead seem to imply that the 1382e8d8bef9SDimitry Andric // substitution matches or was captured from exactly that range. 1383e8d8bef9SDimitry Andric if (Diags) 1384e8d8bef9SDimitry Andric Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, 1385e8d8bef9SDimitry Andric SMRange(Range.Start, Range.Start), OS.str()); 1386e8d8bef9SDimitry Andric else 1387e8d8bef9SDimitry Andric SM.PrintMessage(Range.Start, SourceMgr::DK_Note, OS.str()); 1388e8d8bef9SDimitry Andric } 1389e8d8bef9SDimitry Andric } 1390e8d8bef9SDimitry Andric } 1391e8d8bef9SDimitry Andric 1392e8d8bef9SDimitry Andric void Pattern::printVariableDefs(const SourceMgr &SM, 1393e8d8bef9SDimitry Andric FileCheckDiag::MatchType MatchTy, 1394e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags) const { 1395e8d8bef9SDimitry Andric if (VariableDefs.empty() && NumericVariableDefs.empty()) 1396e8d8bef9SDimitry Andric return; 1397e8d8bef9SDimitry Andric // Build list of variable captures. 1398e8d8bef9SDimitry Andric struct VarCapture { 1399e8d8bef9SDimitry Andric StringRef Name; 1400e8d8bef9SDimitry Andric SMRange Range; 1401e8d8bef9SDimitry Andric }; 1402e8d8bef9SDimitry Andric SmallVector<VarCapture, 2> VarCaptures; 1403e8d8bef9SDimitry Andric for (const auto &VariableDef : VariableDefs) { 1404e8d8bef9SDimitry Andric VarCapture VC; 1405e8d8bef9SDimitry Andric VC.Name = VariableDef.first; 1406e8d8bef9SDimitry Andric StringRef Value = Context->GlobalVariableTable[VC.Name]; 1407e8d8bef9SDimitry Andric SMLoc Start = SMLoc::getFromPointer(Value.data()); 1408e8d8bef9SDimitry Andric SMLoc End = SMLoc::getFromPointer(Value.data() + Value.size()); 1409e8d8bef9SDimitry Andric VC.Range = SMRange(Start, End); 1410e8d8bef9SDimitry Andric VarCaptures.push_back(VC); 1411e8d8bef9SDimitry Andric } 1412e8d8bef9SDimitry Andric for (const auto &VariableDef : NumericVariableDefs) { 1413e8d8bef9SDimitry Andric VarCapture VC; 1414e8d8bef9SDimitry Andric VC.Name = VariableDef.getKey(); 1415fe6060f1SDimitry Andric Optional<StringRef> StrValue = 1416fe6060f1SDimitry Andric VariableDef.getValue().DefinedNumericVariable->getStringValue(); 1417fe6060f1SDimitry Andric if (!StrValue) 1418fe6060f1SDimitry Andric continue; 1419fe6060f1SDimitry Andric SMLoc Start = SMLoc::getFromPointer(StrValue->data()); 1420fe6060f1SDimitry Andric SMLoc End = SMLoc::getFromPointer(StrValue->data() + StrValue->size()); 1421e8d8bef9SDimitry Andric VC.Range = SMRange(Start, End); 1422e8d8bef9SDimitry Andric VarCaptures.push_back(VC); 1423e8d8bef9SDimitry Andric } 1424e8d8bef9SDimitry Andric // Sort variable captures by the order in which they matched the input. 1425e8d8bef9SDimitry Andric // Ranges shouldn't be overlapping, so we can just compare the start. 1426e8d8bef9SDimitry Andric llvm::sort(VarCaptures, [](const VarCapture &A, const VarCapture &B) { 1427*972a253aSDimitry Andric if (&A == &B) 1428*972a253aSDimitry Andric return false; 1429e8d8bef9SDimitry Andric assert(A.Range.Start != B.Range.Start && 1430e8d8bef9SDimitry Andric "unexpected overlapping variable captures"); 1431e8d8bef9SDimitry Andric return A.Range.Start.getPointer() < B.Range.Start.getPointer(); 1432e8d8bef9SDimitry Andric }); 1433e8d8bef9SDimitry Andric // Create notes for the sorted captures. 1434e8d8bef9SDimitry Andric for (const VarCapture &VC : VarCaptures) { 1435e8d8bef9SDimitry Andric SmallString<256> Msg; 1436e8d8bef9SDimitry Andric raw_svector_ostream OS(Msg); 1437e8d8bef9SDimitry Andric OS << "captured var \"" << VC.Name << "\""; 1438e8d8bef9SDimitry Andric if (Diags) 1439e8d8bef9SDimitry Andric Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, VC.Range, OS.str()); 1440e8d8bef9SDimitry Andric else 1441e8d8bef9SDimitry Andric SM.PrintMessage(VC.Range.Start, SourceMgr::DK_Note, OS.str(), VC.Range); 1442e8d8bef9SDimitry Andric } 1443e8d8bef9SDimitry Andric } 1444e8d8bef9SDimitry Andric 1445e8d8bef9SDimitry Andric static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy, 1446e8d8bef9SDimitry Andric const SourceMgr &SM, SMLoc Loc, 1447e8d8bef9SDimitry Andric Check::FileCheckType CheckTy, 1448e8d8bef9SDimitry Andric StringRef Buffer, size_t Pos, size_t Len, 1449e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags, 1450e8d8bef9SDimitry Andric bool AdjustPrevDiags = false) { 1451e8d8bef9SDimitry Andric SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos); 1452e8d8bef9SDimitry Andric SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len); 1453e8d8bef9SDimitry Andric SMRange Range(Start, End); 1454e8d8bef9SDimitry Andric if (Diags) { 1455e8d8bef9SDimitry Andric if (AdjustPrevDiags) { 1456e8d8bef9SDimitry Andric SMLoc CheckLoc = Diags->rbegin()->CheckLoc; 1457e8d8bef9SDimitry Andric for (auto I = Diags->rbegin(), E = Diags->rend(); 1458e8d8bef9SDimitry Andric I != E && I->CheckLoc == CheckLoc; ++I) 1459e8d8bef9SDimitry Andric I->MatchTy = MatchTy; 1460e8d8bef9SDimitry Andric } else 1461e8d8bef9SDimitry Andric Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range); 1462e8d8bef9SDimitry Andric } 1463e8d8bef9SDimitry Andric return Range; 1464e8d8bef9SDimitry Andric } 1465e8d8bef9SDimitry Andric 1466e8d8bef9SDimitry Andric void Pattern::printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, 1467e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags) const { 1468e8d8bef9SDimitry Andric // Attempt to find the closest/best fuzzy match. Usually an error happens 1469e8d8bef9SDimitry Andric // because some string in the output didn't exactly match. In these cases, we 1470e8d8bef9SDimitry Andric // would like to show the user a best guess at what "should have" matched, to 1471e8d8bef9SDimitry Andric // save them having to actually check the input manually. 1472e8d8bef9SDimitry Andric size_t NumLinesForward = 0; 1473e8d8bef9SDimitry Andric size_t Best = StringRef::npos; 1474e8d8bef9SDimitry Andric double BestQuality = 0; 1475e8d8bef9SDimitry Andric 1476e8d8bef9SDimitry Andric // Use an arbitrary 4k limit on how far we will search. 1477e8d8bef9SDimitry Andric for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) { 1478e8d8bef9SDimitry Andric if (Buffer[i] == '\n') 1479e8d8bef9SDimitry Andric ++NumLinesForward; 1480e8d8bef9SDimitry Andric 1481e8d8bef9SDimitry Andric // Patterns have leading whitespace stripped, so skip whitespace when 1482e8d8bef9SDimitry Andric // looking for something which looks like a pattern. 1483e8d8bef9SDimitry Andric if (Buffer[i] == ' ' || Buffer[i] == '\t') 1484e8d8bef9SDimitry Andric continue; 1485e8d8bef9SDimitry Andric 1486e8d8bef9SDimitry Andric // Compute the "quality" of this match as an arbitrary combination of the 1487e8d8bef9SDimitry Andric // match distance and the number of lines skipped to get to this match. 1488e8d8bef9SDimitry Andric unsigned Distance = computeMatchDistance(Buffer.substr(i)); 1489e8d8bef9SDimitry Andric double Quality = Distance + (NumLinesForward / 100.); 1490e8d8bef9SDimitry Andric 1491e8d8bef9SDimitry Andric if (Quality < BestQuality || Best == StringRef::npos) { 1492e8d8bef9SDimitry Andric Best = i; 1493e8d8bef9SDimitry Andric BestQuality = Quality; 1494e8d8bef9SDimitry Andric } 1495e8d8bef9SDimitry Andric } 1496e8d8bef9SDimitry Andric 1497e8d8bef9SDimitry Andric // Print the "possible intended match here" line if we found something 1498e8d8bef9SDimitry Andric // reasonable and not equal to what we showed in the "scanning from here" 1499e8d8bef9SDimitry Andric // line. 1500e8d8bef9SDimitry Andric if (Best && Best != StringRef::npos && BestQuality < 50) { 1501e8d8bef9SDimitry Andric SMRange MatchRange = 1502e8d8bef9SDimitry Andric ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(), 1503e8d8bef9SDimitry Andric getCheckTy(), Buffer, Best, 0, Diags); 1504e8d8bef9SDimitry Andric SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, 1505e8d8bef9SDimitry Andric "possible intended match here"); 1506e8d8bef9SDimitry Andric 1507e8d8bef9SDimitry Andric // FIXME: If we wanted to be really friendly we would show why the match 1508e8d8bef9SDimitry Andric // failed, as it can be hard to spot simple one character differences. 1509e8d8bef9SDimitry Andric } 1510e8d8bef9SDimitry Andric } 1511e8d8bef9SDimitry Andric 1512e8d8bef9SDimitry Andric Expected<StringRef> 1513e8d8bef9SDimitry Andric FileCheckPatternContext::getPatternVarValue(StringRef VarName) { 1514e8d8bef9SDimitry Andric auto VarIter = GlobalVariableTable.find(VarName); 1515e8d8bef9SDimitry Andric if (VarIter == GlobalVariableTable.end()) 1516e8d8bef9SDimitry Andric return make_error<UndefVarError>(VarName); 1517e8d8bef9SDimitry Andric 1518e8d8bef9SDimitry Andric return VarIter->second; 1519e8d8bef9SDimitry Andric } 1520e8d8bef9SDimitry Andric 1521e8d8bef9SDimitry Andric template <class... Types> 1522e8d8bef9SDimitry Andric NumericVariable *FileCheckPatternContext::makeNumericVariable(Types... args) { 1523e8d8bef9SDimitry Andric NumericVariables.push_back(std::make_unique<NumericVariable>(args...)); 1524e8d8bef9SDimitry Andric return NumericVariables.back().get(); 1525e8d8bef9SDimitry Andric } 1526e8d8bef9SDimitry Andric 1527e8d8bef9SDimitry Andric Substitution * 1528e8d8bef9SDimitry Andric FileCheckPatternContext::makeStringSubstitution(StringRef VarName, 1529e8d8bef9SDimitry Andric size_t InsertIdx) { 1530e8d8bef9SDimitry Andric Substitutions.push_back( 1531e8d8bef9SDimitry Andric std::make_unique<StringSubstitution>(this, VarName, InsertIdx)); 1532e8d8bef9SDimitry Andric return Substitutions.back().get(); 1533e8d8bef9SDimitry Andric } 1534e8d8bef9SDimitry Andric 1535e8d8bef9SDimitry Andric Substitution *FileCheckPatternContext::makeNumericSubstitution( 1536e8d8bef9SDimitry Andric StringRef ExpressionStr, std::unique_ptr<Expression> Expression, 1537e8d8bef9SDimitry Andric size_t InsertIdx) { 1538e8d8bef9SDimitry Andric Substitutions.push_back(std::make_unique<NumericSubstitution>( 1539e8d8bef9SDimitry Andric this, ExpressionStr, std::move(Expression), InsertIdx)); 1540e8d8bef9SDimitry Andric return Substitutions.back().get(); 1541e8d8bef9SDimitry Andric } 1542e8d8bef9SDimitry Andric 1543e8d8bef9SDimitry Andric size_t Pattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) { 1544e8d8bef9SDimitry Andric // Offset keeps track of the current offset within the input Str 1545e8d8bef9SDimitry Andric size_t Offset = 0; 1546e8d8bef9SDimitry Andric // [...] Nesting depth 1547e8d8bef9SDimitry Andric size_t BracketDepth = 0; 1548e8d8bef9SDimitry Andric 1549e8d8bef9SDimitry Andric while (!Str.empty()) { 1550e8d8bef9SDimitry Andric if (Str.startswith("]]") && BracketDepth == 0) 1551e8d8bef9SDimitry Andric return Offset; 1552e8d8bef9SDimitry Andric if (Str[0] == '\\') { 1553e8d8bef9SDimitry Andric // Backslash escapes the next char within regexes, so skip them both. 1554e8d8bef9SDimitry Andric Str = Str.substr(2); 1555e8d8bef9SDimitry Andric Offset += 2; 1556e8d8bef9SDimitry Andric } else { 1557e8d8bef9SDimitry Andric switch (Str[0]) { 1558e8d8bef9SDimitry Andric default: 1559e8d8bef9SDimitry Andric break; 1560e8d8bef9SDimitry Andric case '[': 1561e8d8bef9SDimitry Andric BracketDepth++; 1562e8d8bef9SDimitry Andric break; 1563e8d8bef9SDimitry Andric case ']': 1564e8d8bef9SDimitry Andric if (BracketDepth == 0) { 1565e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Str.data()), 1566e8d8bef9SDimitry Andric SourceMgr::DK_Error, 1567e8d8bef9SDimitry Andric "missing closing \"]\" for regex variable"); 1568e8d8bef9SDimitry Andric exit(1); 1569e8d8bef9SDimitry Andric } 1570e8d8bef9SDimitry Andric BracketDepth--; 1571e8d8bef9SDimitry Andric break; 1572e8d8bef9SDimitry Andric } 1573e8d8bef9SDimitry Andric Str = Str.substr(1); 1574e8d8bef9SDimitry Andric Offset++; 1575e8d8bef9SDimitry Andric } 1576e8d8bef9SDimitry Andric } 1577e8d8bef9SDimitry Andric 1578e8d8bef9SDimitry Andric return StringRef::npos; 1579e8d8bef9SDimitry Andric } 1580e8d8bef9SDimitry Andric 1581e8d8bef9SDimitry Andric StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB, 1582e8d8bef9SDimitry Andric SmallVectorImpl<char> &OutputBuffer) { 1583e8d8bef9SDimitry Andric OutputBuffer.reserve(MB.getBufferSize()); 1584e8d8bef9SDimitry Andric 1585e8d8bef9SDimitry Andric for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd(); 1586e8d8bef9SDimitry Andric Ptr != End; ++Ptr) { 1587e8d8bef9SDimitry Andric // Eliminate trailing dosish \r. 1588e8d8bef9SDimitry Andric if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') { 1589e8d8bef9SDimitry Andric continue; 1590e8d8bef9SDimitry Andric } 1591e8d8bef9SDimitry Andric 1592e8d8bef9SDimitry Andric // If current char is not a horizontal whitespace or if horizontal 1593e8d8bef9SDimitry Andric // whitespace canonicalization is disabled, dump it to output as is. 1594e8d8bef9SDimitry Andric if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) { 1595e8d8bef9SDimitry Andric OutputBuffer.push_back(*Ptr); 1596e8d8bef9SDimitry Andric continue; 1597e8d8bef9SDimitry Andric } 1598e8d8bef9SDimitry Andric 1599e8d8bef9SDimitry Andric // Otherwise, add one space and advance over neighboring space. 1600e8d8bef9SDimitry Andric OutputBuffer.push_back(' '); 1601e8d8bef9SDimitry Andric while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t')) 1602e8d8bef9SDimitry Andric ++Ptr; 1603e8d8bef9SDimitry Andric } 1604e8d8bef9SDimitry Andric 1605e8d8bef9SDimitry Andric // Add a null byte and then return all but that byte. 1606e8d8bef9SDimitry Andric OutputBuffer.push_back('\0'); 1607e8d8bef9SDimitry Andric return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1); 1608e8d8bef9SDimitry Andric } 1609e8d8bef9SDimitry Andric 1610e8d8bef9SDimitry Andric FileCheckDiag::FileCheckDiag(const SourceMgr &SM, 1611e8d8bef9SDimitry Andric const Check::FileCheckType &CheckTy, 1612e8d8bef9SDimitry Andric SMLoc CheckLoc, MatchType MatchTy, 1613e8d8bef9SDimitry Andric SMRange InputRange, StringRef Note) 1614e8d8bef9SDimitry Andric : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy), Note(Note) { 1615e8d8bef9SDimitry Andric auto Start = SM.getLineAndColumn(InputRange.Start); 1616e8d8bef9SDimitry Andric auto End = SM.getLineAndColumn(InputRange.End); 1617e8d8bef9SDimitry Andric InputStartLine = Start.first; 1618e8d8bef9SDimitry Andric InputStartCol = Start.second; 1619e8d8bef9SDimitry Andric InputEndLine = End.first; 1620e8d8bef9SDimitry Andric InputEndCol = End.second; 1621e8d8bef9SDimitry Andric } 1622e8d8bef9SDimitry Andric 1623e8d8bef9SDimitry Andric static bool IsPartOfWord(char c) { 1624e8d8bef9SDimitry Andric return (isAlnum(c) || c == '-' || c == '_'); 1625e8d8bef9SDimitry Andric } 1626e8d8bef9SDimitry Andric 1627e8d8bef9SDimitry Andric Check::FileCheckType &Check::FileCheckType::setCount(int C) { 1628e8d8bef9SDimitry Andric assert(Count > 0 && "zero and negative counts are not supported"); 1629e8d8bef9SDimitry Andric assert((C == 1 || Kind == CheckPlain) && 1630e8d8bef9SDimitry Andric "count supported only for plain CHECK directives"); 1631e8d8bef9SDimitry Andric Count = C; 1632e8d8bef9SDimitry Andric return *this; 1633e8d8bef9SDimitry Andric } 1634e8d8bef9SDimitry Andric 1635e8d8bef9SDimitry Andric std::string Check::FileCheckType::getModifiersDescription() const { 1636e8d8bef9SDimitry Andric if (Modifiers.none()) 1637e8d8bef9SDimitry Andric return ""; 1638e8d8bef9SDimitry Andric std::string Ret; 1639e8d8bef9SDimitry Andric raw_string_ostream OS(Ret); 1640e8d8bef9SDimitry Andric OS << '{'; 1641e8d8bef9SDimitry Andric if (isLiteralMatch()) 1642e8d8bef9SDimitry Andric OS << "LITERAL"; 1643e8d8bef9SDimitry Andric OS << '}'; 1644e8d8bef9SDimitry Andric return OS.str(); 1645e8d8bef9SDimitry Andric } 1646e8d8bef9SDimitry Andric 1647e8d8bef9SDimitry Andric std::string Check::FileCheckType::getDescription(StringRef Prefix) const { 1648e8d8bef9SDimitry Andric // Append directive modifiers. 1649e8d8bef9SDimitry Andric auto WithModifiers = [this, Prefix](StringRef Str) -> std::string { 1650e8d8bef9SDimitry Andric return (Prefix + Str + getModifiersDescription()).str(); 1651e8d8bef9SDimitry Andric }; 1652e8d8bef9SDimitry Andric 1653e8d8bef9SDimitry Andric switch (Kind) { 1654e8d8bef9SDimitry Andric case Check::CheckNone: 1655e8d8bef9SDimitry Andric return "invalid"; 165681ad6265SDimitry Andric case Check::CheckMisspelled: 165781ad6265SDimitry Andric return "misspelled"; 1658e8d8bef9SDimitry Andric case Check::CheckPlain: 1659e8d8bef9SDimitry Andric if (Count > 1) 1660e8d8bef9SDimitry Andric return WithModifiers("-COUNT"); 1661e8d8bef9SDimitry Andric return WithModifiers(""); 1662e8d8bef9SDimitry Andric case Check::CheckNext: 1663e8d8bef9SDimitry Andric return WithModifiers("-NEXT"); 1664e8d8bef9SDimitry Andric case Check::CheckSame: 1665e8d8bef9SDimitry Andric return WithModifiers("-SAME"); 1666e8d8bef9SDimitry Andric case Check::CheckNot: 1667e8d8bef9SDimitry Andric return WithModifiers("-NOT"); 1668e8d8bef9SDimitry Andric case Check::CheckDAG: 1669e8d8bef9SDimitry Andric return WithModifiers("-DAG"); 1670e8d8bef9SDimitry Andric case Check::CheckLabel: 1671e8d8bef9SDimitry Andric return WithModifiers("-LABEL"); 1672e8d8bef9SDimitry Andric case Check::CheckEmpty: 1673e8d8bef9SDimitry Andric return WithModifiers("-EMPTY"); 1674e8d8bef9SDimitry Andric case Check::CheckComment: 1675e8d8bef9SDimitry Andric return std::string(Prefix); 1676e8d8bef9SDimitry Andric case Check::CheckEOF: 1677e8d8bef9SDimitry Andric return "implicit EOF"; 1678e8d8bef9SDimitry Andric case Check::CheckBadNot: 1679e8d8bef9SDimitry Andric return "bad NOT"; 1680e8d8bef9SDimitry Andric case Check::CheckBadCount: 1681e8d8bef9SDimitry Andric return "bad COUNT"; 1682e8d8bef9SDimitry Andric } 1683e8d8bef9SDimitry Andric llvm_unreachable("unknown FileCheckType"); 1684e8d8bef9SDimitry Andric } 1685e8d8bef9SDimitry Andric 1686e8d8bef9SDimitry Andric static std::pair<Check::FileCheckType, StringRef> 168781ad6265SDimitry Andric FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix, 168881ad6265SDimitry Andric bool &Misspelled) { 1689e8d8bef9SDimitry Andric if (Buffer.size() <= Prefix.size()) 1690e8d8bef9SDimitry Andric return {Check::CheckNone, StringRef()}; 1691e8d8bef9SDimitry Andric 1692e8d8bef9SDimitry Andric StringRef Rest = Buffer.drop_front(Prefix.size()); 1693e8d8bef9SDimitry Andric // Check for comment. 1694e8d8bef9SDimitry Andric if (llvm::is_contained(Req.CommentPrefixes, Prefix)) { 1695e8d8bef9SDimitry Andric if (Rest.consume_front(":")) 1696e8d8bef9SDimitry Andric return {Check::CheckComment, Rest}; 1697e8d8bef9SDimitry Andric // Ignore a comment prefix if it has a suffix like "-NOT". 1698e8d8bef9SDimitry Andric return {Check::CheckNone, StringRef()}; 1699e8d8bef9SDimitry Andric } 1700e8d8bef9SDimitry Andric 1701e8d8bef9SDimitry Andric auto ConsumeModifiers = [&](Check::FileCheckType Ret) 1702e8d8bef9SDimitry Andric -> std::pair<Check::FileCheckType, StringRef> { 1703e8d8bef9SDimitry Andric if (Rest.consume_front(":")) 1704e8d8bef9SDimitry Andric return {Ret, Rest}; 1705e8d8bef9SDimitry Andric if (!Rest.consume_front("{")) 1706e8d8bef9SDimitry Andric return {Check::CheckNone, StringRef()}; 1707e8d8bef9SDimitry Andric 1708e8d8bef9SDimitry Andric // Parse the modifiers, speparated by commas. 1709e8d8bef9SDimitry Andric do { 1710e8d8bef9SDimitry Andric // Allow whitespace in modifiers list. 1711e8d8bef9SDimitry Andric Rest = Rest.ltrim(); 1712e8d8bef9SDimitry Andric if (Rest.consume_front("LITERAL")) 1713e8d8bef9SDimitry Andric Ret.setLiteralMatch(); 1714e8d8bef9SDimitry Andric else 1715e8d8bef9SDimitry Andric return {Check::CheckNone, Rest}; 1716e8d8bef9SDimitry Andric // Allow whitespace in modifiers list. 1717e8d8bef9SDimitry Andric Rest = Rest.ltrim(); 1718e8d8bef9SDimitry Andric } while (Rest.consume_front(",")); 1719e8d8bef9SDimitry Andric if (!Rest.consume_front("}:")) 1720e8d8bef9SDimitry Andric return {Check::CheckNone, Rest}; 1721e8d8bef9SDimitry Andric return {Ret, Rest}; 1722e8d8bef9SDimitry Andric }; 1723e8d8bef9SDimitry Andric 1724e8d8bef9SDimitry Andric // Verify that the prefix is followed by directive modifiers or a colon. 1725e8d8bef9SDimitry Andric if (Rest.consume_front(":")) 1726e8d8bef9SDimitry Andric return {Check::CheckPlain, Rest}; 1727e8d8bef9SDimitry Andric if (Rest.front() == '{') 1728e8d8bef9SDimitry Andric return ConsumeModifiers(Check::CheckPlain); 1729e8d8bef9SDimitry Andric 173081ad6265SDimitry Andric if (Rest.consume_front("_")) 173181ad6265SDimitry Andric Misspelled = true; 173281ad6265SDimitry Andric else if (!Rest.consume_front("-")) 1733e8d8bef9SDimitry Andric return {Check::CheckNone, StringRef()}; 1734e8d8bef9SDimitry Andric 1735e8d8bef9SDimitry Andric if (Rest.consume_front("COUNT-")) { 1736e8d8bef9SDimitry Andric int64_t Count; 1737e8d8bef9SDimitry Andric if (Rest.consumeInteger(10, Count)) 1738e8d8bef9SDimitry Andric // Error happened in parsing integer. 1739e8d8bef9SDimitry Andric return {Check::CheckBadCount, Rest}; 1740e8d8bef9SDimitry Andric if (Count <= 0 || Count > INT32_MAX) 1741e8d8bef9SDimitry Andric return {Check::CheckBadCount, Rest}; 1742e8d8bef9SDimitry Andric if (Rest.front() != ':' && Rest.front() != '{') 1743e8d8bef9SDimitry Andric return {Check::CheckBadCount, Rest}; 1744e8d8bef9SDimitry Andric return ConsumeModifiers( 1745e8d8bef9SDimitry Andric Check::FileCheckType(Check::CheckPlain).setCount(Count)); 1746e8d8bef9SDimitry Andric } 1747e8d8bef9SDimitry Andric 1748e8d8bef9SDimitry Andric // You can't combine -NOT with another suffix. 1749e8d8bef9SDimitry Andric if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || 1750e8d8bef9SDimitry Andric Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") || 1751e8d8bef9SDimitry Andric Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") || 1752e8d8bef9SDimitry Andric Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:")) 1753e8d8bef9SDimitry Andric return {Check::CheckBadNot, Rest}; 1754e8d8bef9SDimitry Andric 1755e8d8bef9SDimitry Andric if (Rest.consume_front("NEXT")) 1756e8d8bef9SDimitry Andric return ConsumeModifiers(Check::CheckNext); 1757e8d8bef9SDimitry Andric 1758e8d8bef9SDimitry Andric if (Rest.consume_front("SAME")) 1759e8d8bef9SDimitry Andric return ConsumeModifiers(Check::CheckSame); 1760e8d8bef9SDimitry Andric 1761e8d8bef9SDimitry Andric if (Rest.consume_front("NOT")) 1762e8d8bef9SDimitry Andric return ConsumeModifiers(Check::CheckNot); 1763e8d8bef9SDimitry Andric 1764e8d8bef9SDimitry Andric if (Rest.consume_front("DAG")) 1765e8d8bef9SDimitry Andric return ConsumeModifiers(Check::CheckDAG); 1766e8d8bef9SDimitry Andric 1767e8d8bef9SDimitry Andric if (Rest.consume_front("LABEL")) 1768e8d8bef9SDimitry Andric return ConsumeModifiers(Check::CheckLabel); 1769e8d8bef9SDimitry Andric 1770e8d8bef9SDimitry Andric if (Rest.consume_front("EMPTY")) 1771e8d8bef9SDimitry Andric return ConsumeModifiers(Check::CheckEmpty); 1772e8d8bef9SDimitry Andric 1773e8d8bef9SDimitry Andric return {Check::CheckNone, Rest}; 1774e8d8bef9SDimitry Andric } 1775e8d8bef9SDimitry Andric 177681ad6265SDimitry Andric static std::pair<Check::FileCheckType, StringRef> 177781ad6265SDimitry Andric FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix) { 177881ad6265SDimitry Andric bool Misspelled = false; 177981ad6265SDimitry Andric auto Res = FindCheckType(Req, Buffer, Prefix, Misspelled); 178081ad6265SDimitry Andric if (Res.first != Check::CheckNone && Misspelled) 178181ad6265SDimitry Andric return {Check::CheckMisspelled, Res.second}; 178281ad6265SDimitry Andric return Res; 178381ad6265SDimitry Andric } 178481ad6265SDimitry Andric 1785e8d8bef9SDimitry Andric // From the given position, find the next character after the word. 1786e8d8bef9SDimitry Andric static size_t SkipWord(StringRef Str, size_t Loc) { 1787e8d8bef9SDimitry Andric while (Loc < Str.size() && IsPartOfWord(Str[Loc])) 1788e8d8bef9SDimitry Andric ++Loc; 1789e8d8bef9SDimitry Andric return Loc; 1790e8d8bef9SDimitry Andric } 1791e8d8bef9SDimitry Andric 1792e8d8bef9SDimitry Andric /// Searches the buffer for the first prefix in the prefix regular expression. 1793e8d8bef9SDimitry Andric /// 1794e8d8bef9SDimitry Andric /// This searches the buffer using the provided regular expression, however it 1795e8d8bef9SDimitry Andric /// enforces constraints beyond that: 1796e8d8bef9SDimitry Andric /// 1) The found prefix must not be a suffix of something that looks like 1797e8d8bef9SDimitry Andric /// a valid prefix. 1798e8d8bef9SDimitry Andric /// 2) The found prefix must be followed by a valid check type suffix using \c 1799e8d8bef9SDimitry Andric /// FindCheckType above. 1800e8d8bef9SDimitry Andric /// 1801e8d8bef9SDimitry Andric /// \returns a pair of StringRefs into the Buffer, which combines: 1802e8d8bef9SDimitry Andric /// - the first match of the regular expression to satisfy these two is 1803e8d8bef9SDimitry Andric /// returned, 1804e8d8bef9SDimitry Andric /// otherwise an empty StringRef is returned to indicate failure. 1805e8d8bef9SDimitry Andric /// - buffer rewound to the location right after parsed suffix, for parsing 1806e8d8bef9SDimitry Andric /// to continue from 1807e8d8bef9SDimitry Andric /// 1808e8d8bef9SDimitry Andric /// If this routine returns a valid prefix, it will also shrink \p Buffer to 1809e8d8bef9SDimitry Andric /// start at the beginning of the returned prefix, increment \p LineNumber for 1810e8d8bef9SDimitry Andric /// each new line consumed from \p Buffer, and set \p CheckTy to the type of 1811e8d8bef9SDimitry Andric /// check found by examining the suffix. 1812e8d8bef9SDimitry Andric /// 1813e8d8bef9SDimitry Andric /// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy 1814e8d8bef9SDimitry Andric /// is unspecified. 1815e8d8bef9SDimitry Andric static std::pair<StringRef, StringRef> 1816e8d8bef9SDimitry Andric FindFirstMatchingPrefix(const FileCheckRequest &Req, Regex &PrefixRE, 1817e8d8bef9SDimitry Andric StringRef &Buffer, unsigned &LineNumber, 1818e8d8bef9SDimitry Andric Check::FileCheckType &CheckTy) { 1819e8d8bef9SDimitry Andric SmallVector<StringRef, 2> Matches; 1820e8d8bef9SDimitry Andric 1821e8d8bef9SDimitry Andric while (!Buffer.empty()) { 1822e8d8bef9SDimitry Andric // Find the first (longest) match using the RE. 1823e8d8bef9SDimitry Andric if (!PrefixRE.match(Buffer, &Matches)) 1824e8d8bef9SDimitry Andric // No match at all, bail. 1825e8d8bef9SDimitry Andric return {StringRef(), StringRef()}; 1826e8d8bef9SDimitry Andric 1827e8d8bef9SDimitry Andric StringRef Prefix = Matches[0]; 1828e8d8bef9SDimitry Andric Matches.clear(); 1829e8d8bef9SDimitry Andric 1830e8d8bef9SDimitry Andric assert(Prefix.data() >= Buffer.data() && 1831e8d8bef9SDimitry Andric Prefix.data() < Buffer.data() + Buffer.size() && 1832e8d8bef9SDimitry Andric "Prefix doesn't start inside of buffer!"); 1833e8d8bef9SDimitry Andric size_t Loc = Prefix.data() - Buffer.data(); 1834e8d8bef9SDimitry Andric StringRef Skipped = Buffer.substr(0, Loc); 1835e8d8bef9SDimitry Andric Buffer = Buffer.drop_front(Loc); 1836e8d8bef9SDimitry Andric LineNumber += Skipped.count('\n'); 1837e8d8bef9SDimitry Andric 1838e8d8bef9SDimitry Andric // Check that the matched prefix isn't a suffix of some other check-like 1839e8d8bef9SDimitry Andric // word. 1840e8d8bef9SDimitry Andric // FIXME: This is a very ad-hoc check. it would be better handled in some 1841e8d8bef9SDimitry Andric // other way. Among other things it seems hard to distinguish between 1842e8d8bef9SDimitry Andric // intentional and unintentional uses of this feature. 1843e8d8bef9SDimitry Andric if (Skipped.empty() || !IsPartOfWord(Skipped.back())) { 1844e8d8bef9SDimitry Andric // Now extract the type. 1845e8d8bef9SDimitry Andric StringRef AfterSuffix; 1846e8d8bef9SDimitry Andric std::tie(CheckTy, AfterSuffix) = FindCheckType(Req, Buffer, Prefix); 1847e8d8bef9SDimitry Andric 1848e8d8bef9SDimitry Andric // If we've found a valid check type for this prefix, we're done. 1849e8d8bef9SDimitry Andric if (CheckTy != Check::CheckNone) 1850e8d8bef9SDimitry Andric return {Prefix, AfterSuffix}; 1851e8d8bef9SDimitry Andric } 1852e8d8bef9SDimitry Andric 1853e8d8bef9SDimitry Andric // If we didn't successfully find a prefix, we need to skip this invalid 1854e8d8bef9SDimitry Andric // prefix and continue scanning. We directly skip the prefix that was 1855e8d8bef9SDimitry Andric // matched and any additional parts of that check-like word. 1856e8d8bef9SDimitry Andric Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size())); 1857e8d8bef9SDimitry Andric } 1858e8d8bef9SDimitry Andric 1859e8d8bef9SDimitry Andric // We ran out of buffer while skipping partial matches so give up. 1860e8d8bef9SDimitry Andric return {StringRef(), StringRef()}; 1861e8d8bef9SDimitry Andric } 1862e8d8bef9SDimitry Andric 1863e8d8bef9SDimitry Andric void FileCheckPatternContext::createLineVariable() { 1864e8d8bef9SDimitry Andric assert(!LineVariable && "@LINE pseudo numeric variable already created"); 1865e8d8bef9SDimitry Andric StringRef LineName = "@LINE"; 1866e8d8bef9SDimitry Andric LineVariable = makeNumericVariable( 1867e8d8bef9SDimitry Andric LineName, ExpressionFormat(ExpressionFormat::Kind::Unsigned)); 1868e8d8bef9SDimitry Andric GlobalNumericVariableTable[LineName] = LineVariable; 1869e8d8bef9SDimitry Andric } 1870e8d8bef9SDimitry Andric 1871e8d8bef9SDimitry Andric FileCheck::FileCheck(FileCheckRequest Req) 1872e8d8bef9SDimitry Andric : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()), 1873e8d8bef9SDimitry Andric CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {} 1874e8d8bef9SDimitry Andric 1875e8d8bef9SDimitry Andric FileCheck::~FileCheck() = default; 1876e8d8bef9SDimitry Andric 1877e8d8bef9SDimitry Andric bool FileCheck::readCheckFile( 1878e8d8bef9SDimitry Andric SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, 1879e8d8bef9SDimitry Andric std::pair<unsigned, unsigned> *ImpPatBufferIDRange) { 1880e8d8bef9SDimitry Andric if (ImpPatBufferIDRange) 1881e8d8bef9SDimitry Andric ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0; 1882e8d8bef9SDimitry Andric 1883e8d8bef9SDimitry Andric Error DefineError = 1884e8d8bef9SDimitry Andric PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM); 1885e8d8bef9SDimitry Andric if (DefineError) { 1886e8d8bef9SDimitry Andric logAllUnhandledErrors(std::move(DefineError), errs()); 1887e8d8bef9SDimitry Andric return true; 1888e8d8bef9SDimitry Andric } 1889e8d8bef9SDimitry Andric 1890e8d8bef9SDimitry Andric PatternContext->createLineVariable(); 1891e8d8bef9SDimitry Andric 1892e8d8bef9SDimitry Andric std::vector<Pattern> ImplicitNegativeChecks; 1893e8d8bef9SDimitry Andric for (StringRef PatternString : Req.ImplicitCheckNot) { 1894e8d8bef9SDimitry Andric // Create a buffer with fake command line content in order to display the 1895e8d8bef9SDimitry Andric // command line option responsible for the specific implicit CHECK-NOT. 1896e8d8bef9SDimitry Andric std::string Prefix = "-implicit-check-not='"; 1897e8d8bef9SDimitry Andric std::string Suffix = "'"; 1898e8d8bef9SDimitry Andric std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy( 1899e8d8bef9SDimitry Andric (Prefix + PatternString + Suffix).str(), "command line"); 1900e8d8bef9SDimitry Andric 1901e8d8bef9SDimitry Andric StringRef PatternInBuffer = 1902e8d8bef9SDimitry Andric CmdLine->getBuffer().substr(Prefix.size(), PatternString.size()); 1903e8d8bef9SDimitry Andric unsigned BufferID = SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc()); 1904e8d8bef9SDimitry Andric if (ImpPatBufferIDRange) { 1905e8d8bef9SDimitry Andric if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) { 1906e8d8bef9SDimitry Andric ImpPatBufferIDRange->first = BufferID; 1907e8d8bef9SDimitry Andric ImpPatBufferIDRange->second = BufferID + 1; 1908e8d8bef9SDimitry Andric } else { 1909e8d8bef9SDimitry Andric assert(BufferID == ImpPatBufferIDRange->second && 1910e8d8bef9SDimitry Andric "expected consecutive source buffer IDs"); 1911e8d8bef9SDimitry Andric ++ImpPatBufferIDRange->second; 1912e8d8bef9SDimitry Andric } 1913e8d8bef9SDimitry Andric } 1914e8d8bef9SDimitry Andric 1915e8d8bef9SDimitry Andric ImplicitNegativeChecks.push_back( 1916e8d8bef9SDimitry Andric Pattern(Check::CheckNot, PatternContext.get())); 1917e8d8bef9SDimitry Andric ImplicitNegativeChecks.back().parsePattern(PatternInBuffer, 1918e8d8bef9SDimitry Andric "IMPLICIT-CHECK", SM, Req); 1919e8d8bef9SDimitry Andric } 1920e8d8bef9SDimitry Andric 1921e8d8bef9SDimitry Andric std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks; 1922e8d8bef9SDimitry Andric 1923e8d8bef9SDimitry Andric // LineNumber keeps track of the line on which CheckPrefix instances are 1924e8d8bef9SDimitry Andric // found. 1925e8d8bef9SDimitry Andric unsigned LineNumber = 1; 1926e8d8bef9SDimitry Andric 1927e8d8bef9SDimitry Andric std::set<StringRef> PrefixesNotFound(Req.CheckPrefixes.begin(), 1928e8d8bef9SDimitry Andric Req.CheckPrefixes.end()); 1929e8d8bef9SDimitry Andric const size_t DistinctPrefixes = PrefixesNotFound.size(); 1930e8d8bef9SDimitry Andric while (true) { 1931e8d8bef9SDimitry Andric Check::FileCheckType CheckTy; 1932e8d8bef9SDimitry Andric 1933e8d8bef9SDimitry Andric // See if a prefix occurs in the memory buffer. 1934e8d8bef9SDimitry Andric StringRef UsedPrefix; 1935e8d8bef9SDimitry Andric StringRef AfterSuffix; 1936e8d8bef9SDimitry Andric std::tie(UsedPrefix, AfterSuffix) = 1937e8d8bef9SDimitry Andric FindFirstMatchingPrefix(Req, PrefixRE, Buffer, LineNumber, CheckTy); 1938e8d8bef9SDimitry Andric if (UsedPrefix.empty()) 1939e8d8bef9SDimitry Andric break; 1940e8d8bef9SDimitry Andric if (CheckTy != Check::CheckComment) 1941e8d8bef9SDimitry Andric PrefixesNotFound.erase(UsedPrefix); 1942e8d8bef9SDimitry Andric 1943e8d8bef9SDimitry Andric assert(UsedPrefix.data() == Buffer.data() && 1944e8d8bef9SDimitry Andric "Failed to move Buffer's start forward, or pointed prefix outside " 1945e8d8bef9SDimitry Andric "of the buffer!"); 1946e8d8bef9SDimitry Andric assert(AfterSuffix.data() >= Buffer.data() && 1947e8d8bef9SDimitry Andric AfterSuffix.data() < Buffer.data() + Buffer.size() && 1948e8d8bef9SDimitry Andric "Parsing after suffix doesn't start inside of buffer!"); 1949e8d8bef9SDimitry Andric 1950e8d8bef9SDimitry Andric // Location to use for error messages. 1951e8d8bef9SDimitry Andric const char *UsedPrefixStart = UsedPrefix.data(); 1952e8d8bef9SDimitry Andric 1953e8d8bef9SDimitry Andric // Skip the buffer to the end of parsed suffix (or just prefix, if no good 1954e8d8bef9SDimitry Andric // suffix was processed). 1955e8d8bef9SDimitry Andric Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size()) 1956e8d8bef9SDimitry Andric : AfterSuffix; 1957e8d8bef9SDimitry Andric 195881ad6265SDimitry Andric // Complain about misspelled directives. 195981ad6265SDimitry Andric if (CheckTy == Check::CheckMisspelled) { 196081ad6265SDimitry Andric StringRef UsedDirective(UsedPrefix.data(), 196181ad6265SDimitry Andric AfterSuffix.data() - UsedPrefix.data()); 196281ad6265SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(UsedDirective.data()), 196381ad6265SDimitry Andric SourceMgr::DK_Error, 196481ad6265SDimitry Andric "misspelled directive '" + UsedDirective + "'"); 196581ad6265SDimitry Andric return true; 196681ad6265SDimitry Andric } 196781ad6265SDimitry Andric 1968e8d8bef9SDimitry Andric // Complain about useful-looking but unsupported suffixes. 1969e8d8bef9SDimitry Andric if (CheckTy == Check::CheckBadNot) { 1970e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, 1971e8d8bef9SDimitry Andric "unsupported -NOT combo on prefix '" + UsedPrefix + "'"); 1972e8d8bef9SDimitry Andric return true; 1973e8d8bef9SDimitry Andric } 1974e8d8bef9SDimitry Andric 1975e8d8bef9SDimitry Andric // Complain about invalid count specification. 1976e8d8bef9SDimitry Andric if (CheckTy == Check::CheckBadCount) { 1977e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, 1978e8d8bef9SDimitry Andric "invalid count in -COUNT specification on prefix '" + 1979e8d8bef9SDimitry Andric UsedPrefix + "'"); 1980e8d8bef9SDimitry Andric return true; 1981e8d8bef9SDimitry Andric } 1982e8d8bef9SDimitry Andric 1983e8d8bef9SDimitry Andric // Okay, we found the prefix, yay. Remember the rest of the line, but ignore 1984e8d8bef9SDimitry Andric // leading whitespace. 1985e8d8bef9SDimitry Andric if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) 1986e8d8bef9SDimitry Andric Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); 1987e8d8bef9SDimitry Andric 1988e8d8bef9SDimitry Andric // Scan ahead to the end of line. 1989e8d8bef9SDimitry Andric size_t EOL = Buffer.find_first_of("\n\r"); 1990e8d8bef9SDimitry Andric 1991e8d8bef9SDimitry Andric // Remember the location of the start of the pattern, for diagnostics. 1992e8d8bef9SDimitry Andric SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); 1993e8d8bef9SDimitry Andric 1994e8d8bef9SDimitry Andric // Extract the pattern from the buffer. 1995e8d8bef9SDimitry Andric StringRef PatternBuffer = Buffer.substr(0, EOL); 1996e8d8bef9SDimitry Andric Buffer = Buffer.substr(EOL); 1997e8d8bef9SDimitry Andric 1998e8d8bef9SDimitry Andric // If this is a comment, we're done. 1999e8d8bef9SDimitry Andric if (CheckTy == Check::CheckComment) 2000e8d8bef9SDimitry Andric continue; 2001e8d8bef9SDimitry Andric 2002e8d8bef9SDimitry Andric // Parse the pattern. 2003e8d8bef9SDimitry Andric Pattern P(CheckTy, PatternContext.get(), LineNumber); 2004e8d8bef9SDimitry Andric if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req)) 2005e8d8bef9SDimitry Andric return true; 2006e8d8bef9SDimitry Andric 2007e8d8bef9SDimitry Andric // Verify that CHECK-LABEL lines do not define or use variables 2008e8d8bef9SDimitry Andric if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { 2009e8d8bef9SDimitry Andric SM.PrintMessage( 2010e8d8bef9SDimitry Andric SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, 2011e8d8bef9SDimitry Andric "found '" + UsedPrefix + "-LABEL:'" 2012e8d8bef9SDimitry Andric " with variable definition or use"); 2013e8d8bef9SDimitry Andric return true; 2014e8d8bef9SDimitry Andric } 2015e8d8bef9SDimitry Andric 2016e8d8bef9SDimitry Andric // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them. 2017e8d8bef9SDimitry Andric if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame || 2018e8d8bef9SDimitry Andric CheckTy == Check::CheckEmpty) && 2019e8d8bef9SDimitry Andric CheckStrings->empty()) { 2020e8d8bef9SDimitry Andric StringRef Type = CheckTy == Check::CheckNext 2021e8d8bef9SDimitry Andric ? "NEXT" 2022e8d8bef9SDimitry Andric : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME"; 2023e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), 2024e8d8bef9SDimitry Andric SourceMgr::DK_Error, 2025e8d8bef9SDimitry Andric "found '" + UsedPrefix + "-" + Type + 2026e8d8bef9SDimitry Andric "' without previous '" + UsedPrefix + ": line"); 2027e8d8bef9SDimitry Andric return true; 2028e8d8bef9SDimitry Andric } 2029e8d8bef9SDimitry Andric 2030e8d8bef9SDimitry Andric // Handle CHECK-DAG/-NOT. 2031e8d8bef9SDimitry Andric if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { 2032e8d8bef9SDimitry Andric DagNotMatches.push_back(P); 2033e8d8bef9SDimitry Andric continue; 2034e8d8bef9SDimitry Andric } 2035e8d8bef9SDimitry Andric 2036e8d8bef9SDimitry Andric // Okay, add the string we captured to the output vector and move on. 2037e8d8bef9SDimitry Andric CheckStrings->emplace_back(P, UsedPrefix, PatternLoc); 2038e8d8bef9SDimitry Andric std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); 2039e8d8bef9SDimitry Andric DagNotMatches = ImplicitNegativeChecks; 2040e8d8bef9SDimitry Andric } 2041e8d8bef9SDimitry Andric 2042e8d8bef9SDimitry Andric // When there are no used prefixes we report an error except in the case that 2043e8d8bef9SDimitry Andric // no prefix is specified explicitly but -implicit-check-not is specified. 2044e8d8bef9SDimitry Andric const bool NoPrefixesFound = PrefixesNotFound.size() == DistinctPrefixes; 2045e8d8bef9SDimitry Andric const bool SomePrefixesUnexpectedlyNotUsed = 2046e8d8bef9SDimitry Andric !Req.AllowUnusedPrefixes && !PrefixesNotFound.empty(); 2047e8d8bef9SDimitry Andric if ((NoPrefixesFound || SomePrefixesUnexpectedlyNotUsed) && 2048e8d8bef9SDimitry Andric (ImplicitNegativeChecks.empty() || !Req.IsDefaultCheckPrefix)) { 2049e8d8bef9SDimitry Andric errs() << "error: no check strings found with prefix" 2050e8d8bef9SDimitry Andric << (PrefixesNotFound.size() > 1 ? "es " : " "); 2051e8d8bef9SDimitry Andric bool First = true; 2052e8d8bef9SDimitry Andric for (StringRef MissingPrefix : PrefixesNotFound) { 2053e8d8bef9SDimitry Andric if (!First) 2054e8d8bef9SDimitry Andric errs() << ", "; 2055e8d8bef9SDimitry Andric errs() << "\'" << MissingPrefix << ":'"; 2056e8d8bef9SDimitry Andric First = false; 2057e8d8bef9SDimitry Andric } 2058e8d8bef9SDimitry Andric errs() << '\n'; 2059e8d8bef9SDimitry Andric return true; 2060e8d8bef9SDimitry Andric } 2061e8d8bef9SDimitry Andric 2062e8d8bef9SDimitry Andric // Add an EOF pattern for any trailing --implicit-check-not/CHECK-DAG/-NOTs, 2063e8d8bef9SDimitry Andric // and use the first prefix as a filler for the error message. 2064e8d8bef9SDimitry Andric if (!DagNotMatches.empty()) { 2065e8d8bef9SDimitry Andric CheckStrings->emplace_back( 2066e8d8bef9SDimitry Andric Pattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1), 2067e8d8bef9SDimitry Andric *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data())); 2068e8d8bef9SDimitry Andric std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); 2069e8d8bef9SDimitry Andric } 2070e8d8bef9SDimitry Andric 2071e8d8bef9SDimitry Andric return false; 2072e8d8bef9SDimitry Andric } 2073e8d8bef9SDimitry Andric 2074fe6060f1SDimitry Andric /// Returns either (1) \c ErrorSuccess if there was no error or (2) 2075fe6060f1SDimitry Andric /// \c ErrorReported if an error was reported, such as an unexpected match. 2076fe6060f1SDimitry Andric static Error printMatch(bool ExpectedMatch, const SourceMgr &SM, 2077e8d8bef9SDimitry Andric StringRef Prefix, SMLoc Loc, const Pattern &Pat, 2078fe6060f1SDimitry Andric int MatchedCount, StringRef Buffer, 2079fe6060f1SDimitry Andric Pattern::MatchResult MatchResult, 2080fe6060f1SDimitry Andric const FileCheckRequest &Req, 2081e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags) { 2082fe6060f1SDimitry Andric // Suppress some verbosity if there's no error. 2083fe6060f1SDimitry Andric bool HasError = !ExpectedMatch || MatchResult.TheError; 2084e8d8bef9SDimitry Andric bool PrintDiag = true; 2085fe6060f1SDimitry Andric if (!HasError) { 2086e8d8bef9SDimitry Andric if (!Req.Verbose) 2087fe6060f1SDimitry Andric return ErrorReported::reportedOrSuccess(HasError); 2088e8d8bef9SDimitry Andric if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF) 2089fe6060f1SDimitry Andric return ErrorReported::reportedOrSuccess(HasError); 2090e8d8bef9SDimitry Andric // Due to their verbosity, we don't print verbose diagnostics here if we're 2091fe6060f1SDimitry Andric // gathering them for Diags to be rendered elsewhere, but we always print 2092fe6060f1SDimitry Andric // other diagnostics. 2093e8d8bef9SDimitry Andric PrintDiag = !Diags; 2094e8d8bef9SDimitry Andric } 2095fe6060f1SDimitry Andric 2096fe6060f1SDimitry Andric // Add "found" diagnostic, substitutions, and variable definitions to Diags. 2097e8d8bef9SDimitry Andric FileCheckDiag::MatchType MatchTy = ExpectedMatch 2098e8d8bef9SDimitry Andric ? FileCheckDiag::MatchFoundAndExpected 2099e8d8bef9SDimitry Andric : FileCheckDiag::MatchFoundButExcluded; 2100e8d8bef9SDimitry Andric SMRange MatchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(), 2101fe6060f1SDimitry Andric Buffer, MatchResult.TheMatch->Pos, 2102fe6060f1SDimitry Andric MatchResult.TheMatch->Len, Diags); 2103e8d8bef9SDimitry Andric if (Diags) { 2104e8d8bef9SDimitry Andric Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, Diags); 2105e8d8bef9SDimitry Andric Pat.printVariableDefs(SM, MatchTy, Diags); 2106e8d8bef9SDimitry Andric } 2107fe6060f1SDimitry Andric if (!PrintDiag) { 2108fe6060f1SDimitry Andric assert(!HasError && "expected to report more diagnostics for error"); 2109fe6060f1SDimitry Andric return ErrorReported::reportedOrSuccess(HasError); 2110fe6060f1SDimitry Andric } 2111e8d8bef9SDimitry Andric 2112fe6060f1SDimitry Andric // Print the match. 2113e8d8bef9SDimitry Andric std::string Message = formatv("{0}: {1} string found in input", 2114e8d8bef9SDimitry Andric Pat.getCheckTy().getDescription(Prefix), 2115e8d8bef9SDimitry Andric (ExpectedMatch ? "expected" : "excluded")) 2116e8d8bef9SDimitry Andric .str(); 2117e8d8bef9SDimitry Andric if (Pat.getCount() > 1) 2118e8d8bef9SDimitry Andric Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); 2119e8d8bef9SDimitry Andric SM.PrintMessage( 2120e8d8bef9SDimitry Andric Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message); 2121e8d8bef9SDimitry Andric SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here", 2122e8d8bef9SDimitry Andric {MatchRange}); 2123fe6060f1SDimitry Andric 2124fe6060f1SDimitry Andric // Print additional information, which can be useful even if there are errors. 2125e8d8bef9SDimitry Andric Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, nullptr); 2126e8d8bef9SDimitry Andric Pat.printVariableDefs(SM, MatchTy, nullptr); 2127fe6060f1SDimitry Andric 2128fe6060f1SDimitry Andric // Print errors and add them to Diags. We report these errors after the match 2129fe6060f1SDimitry Andric // itself because we found them after the match. If we had found them before 2130fe6060f1SDimitry Andric // the match, we'd be in printNoMatch. 2131fe6060f1SDimitry Andric handleAllErrors(std::move(MatchResult.TheError), 2132fe6060f1SDimitry Andric [&](const ErrorDiagnostic &E) { 2133fe6060f1SDimitry Andric E.log(errs()); 2134fe6060f1SDimitry Andric if (Diags) { 2135fe6060f1SDimitry Andric Diags->emplace_back(SM, Pat.getCheckTy(), Loc, 2136fe6060f1SDimitry Andric FileCheckDiag::MatchFoundErrorNote, 2137fe6060f1SDimitry Andric E.getRange(), E.getMessage().str()); 2138fe6060f1SDimitry Andric } 2139fe6060f1SDimitry Andric }); 2140fe6060f1SDimitry Andric return ErrorReported::reportedOrSuccess(HasError); 2141e8d8bef9SDimitry Andric } 2142e8d8bef9SDimitry Andric 2143fe6060f1SDimitry Andric /// Returns either (1) \c ErrorSuccess if there was no error, or (2) 2144fe6060f1SDimitry Andric /// \c ErrorReported if an error was reported, such as an expected match not 2145fe6060f1SDimitry Andric /// found. 2146fe6060f1SDimitry Andric static Error printNoMatch(bool ExpectedMatch, const SourceMgr &SM, 2147e8d8bef9SDimitry Andric StringRef Prefix, SMLoc Loc, const Pattern &Pat, 2148fe6060f1SDimitry Andric int MatchedCount, StringRef Buffer, Error MatchError, 2149fe6060f1SDimitry Andric bool VerboseVerbose, 2150fe6060f1SDimitry Andric std::vector<FileCheckDiag> *Diags) { 2151fe6060f1SDimitry Andric // Print any pattern errors, and record them to be added to Diags later. 2152fe6060f1SDimitry Andric bool HasError = ExpectedMatch; 2153fe6060f1SDimitry Andric bool HasPatternError = false; 2154e8d8bef9SDimitry Andric FileCheckDiag::MatchType MatchTy = ExpectedMatch 2155e8d8bef9SDimitry Andric ? FileCheckDiag::MatchNoneButExpected 2156e8d8bef9SDimitry Andric : FileCheckDiag::MatchNoneAndExcluded; 2157fe6060f1SDimitry Andric SmallVector<std::string, 4> ErrorMsgs; 2158fe6060f1SDimitry Andric handleAllErrors( 2159fe6060f1SDimitry Andric std::move(MatchError), 2160fe6060f1SDimitry Andric [&](const ErrorDiagnostic &E) { 2161fe6060f1SDimitry Andric HasError = HasPatternError = true; 2162fe6060f1SDimitry Andric MatchTy = FileCheckDiag::MatchNoneForInvalidPattern; 2163fe6060f1SDimitry Andric E.log(errs()); 2164e8d8bef9SDimitry Andric if (Diags) 2165fe6060f1SDimitry Andric ErrorMsgs.push_back(E.getMessage().str()); 2166fe6060f1SDimitry Andric }, 2167fe6060f1SDimitry Andric // NotFoundError is why printNoMatch was invoked. 2168fe6060f1SDimitry Andric [](const NotFoundError &E) {}); 2169fe6060f1SDimitry Andric 2170fe6060f1SDimitry Andric // Suppress some verbosity if there's no error. 2171fe6060f1SDimitry Andric bool PrintDiag = true; 2172fe6060f1SDimitry Andric if (!HasError) { 2173fe6060f1SDimitry Andric if (!VerboseVerbose) 2174fe6060f1SDimitry Andric return ErrorReported::reportedOrSuccess(HasError); 2175fe6060f1SDimitry Andric // Due to their verbosity, we don't print verbose diagnostics here if we're 2176fe6060f1SDimitry Andric // gathering them for Diags to be rendered elsewhere, but we always print 2177fe6060f1SDimitry Andric // other diagnostics. 2178fe6060f1SDimitry Andric PrintDiag = !Diags; 2179e8d8bef9SDimitry Andric } 2180e8d8bef9SDimitry Andric 2181fe6060f1SDimitry Andric // Add "not found" diagnostic, substitutions, and pattern errors to Diags. 2182fe6060f1SDimitry Andric // 2183fe6060f1SDimitry Andric // We handle Diags a little differently than the errors we print directly: 2184fe6060f1SDimitry Andric // we add the "not found" diagnostic to Diags even if there are pattern 2185fe6060f1SDimitry Andric // errors. The reason is that we need to attach pattern errors as notes 2186fe6060f1SDimitry Andric // somewhere in the input, and the input search range from the "not found" 2187fe6060f1SDimitry Andric // diagnostic is all we have to anchor them. 2188fe6060f1SDimitry Andric SMRange SearchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(), 2189fe6060f1SDimitry Andric Buffer, 0, Buffer.size(), Diags); 2190fe6060f1SDimitry Andric if (Diags) { 2191fe6060f1SDimitry Andric SMRange NoteRange = SMRange(SearchRange.Start, SearchRange.Start); 2192fe6060f1SDimitry Andric for (StringRef ErrorMsg : ErrorMsgs) 2193fe6060f1SDimitry Andric Diags->emplace_back(SM, Pat.getCheckTy(), Loc, MatchTy, NoteRange, 2194fe6060f1SDimitry Andric ErrorMsg); 2195fe6060f1SDimitry Andric Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, Diags); 2196fe6060f1SDimitry Andric } 2197fe6060f1SDimitry Andric if (!PrintDiag) { 2198fe6060f1SDimitry Andric assert(!HasError && "expected to report more diagnostics for error"); 2199fe6060f1SDimitry Andric return ErrorReported::reportedOrSuccess(HasError); 2200fe6060f1SDimitry Andric } 2201e8d8bef9SDimitry Andric 2202fe6060f1SDimitry Andric // Print "not found" diagnostic, except that's implied if we already printed a 2203fe6060f1SDimitry Andric // pattern error. 2204fe6060f1SDimitry Andric if (!HasPatternError) { 2205e8d8bef9SDimitry Andric std::string Message = formatv("{0}: {1} string not found in input", 2206e8d8bef9SDimitry Andric Pat.getCheckTy().getDescription(Prefix), 2207e8d8bef9SDimitry Andric (ExpectedMatch ? "expected" : "excluded")) 2208e8d8bef9SDimitry Andric .str(); 2209e8d8bef9SDimitry Andric if (Pat.getCount() > 1) 2210fe6060f1SDimitry Andric Message += 2211fe6060f1SDimitry Andric formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); 2212fe6060f1SDimitry Andric SM.PrintMessage(Loc, 2213fe6060f1SDimitry Andric ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, 2214fe6060f1SDimitry Andric Message); 2215fe6060f1SDimitry Andric SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, 2216fe6060f1SDimitry Andric "scanning from here"); 2217e8d8bef9SDimitry Andric } 2218e8d8bef9SDimitry Andric 2219fe6060f1SDimitry Andric // Print additional information, which can be useful even after a pattern 2220fe6060f1SDimitry Andric // error. 2221fe6060f1SDimitry Andric Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, nullptr); 2222fe6060f1SDimitry Andric if (ExpectedMatch) 2223fe6060f1SDimitry Andric Pat.printFuzzyMatch(SM, Buffer, Diags); 2224fe6060f1SDimitry Andric return ErrorReported::reportedOrSuccess(HasError); 2225fe6060f1SDimitry Andric } 2226fe6060f1SDimitry Andric 2227fe6060f1SDimitry Andric /// Returns either (1) \c ErrorSuccess if there was no error, or (2) 2228fe6060f1SDimitry Andric /// \c ErrorReported if an error was reported. 2229fe6060f1SDimitry Andric static Error reportMatchResult(bool ExpectedMatch, const SourceMgr &SM, 2230fe6060f1SDimitry Andric StringRef Prefix, SMLoc Loc, const Pattern &Pat, 2231fe6060f1SDimitry Andric int MatchedCount, StringRef Buffer, 2232fe6060f1SDimitry Andric Pattern::MatchResult MatchResult, 2233fe6060f1SDimitry Andric const FileCheckRequest &Req, 2234fe6060f1SDimitry Andric std::vector<FileCheckDiag> *Diags) { 2235fe6060f1SDimitry Andric if (MatchResult.TheMatch) 2236fe6060f1SDimitry Andric return printMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer, 2237fe6060f1SDimitry Andric std::move(MatchResult), Req, Diags); 2238fe6060f1SDimitry Andric return printNoMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer, 2239fe6060f1SDimitry Andric std::move(MatchResult.TheError), Req.VerboseVerbose, 2240fe6060f1SDimitry Andric Diags); 2241e8d8bef9SDimitry Andric } 2242e8d8bef9SDimitry Andric 2243e8d8bef9SDimitry Andric /// Counts the number of newlines in the specified range. 2244e8d8bef9SDimitry Andric static unsigned CountNumNewlinesBetween(StringRef Range, 2245e8d8bef9SDimitry Andric const char *&FirstNewLine) { 2246e8d8bef9SDimitry Andric unsigned NumNewLines = 0; 224704eeddc0SDimitry Andric while (true) { 2248e8d8bef9SDimitry Andric // Scan for newline. 2249e8d8bef9SDimitry Andric Range = Range.substr(Range.find_first_of("\n\r")); 2250e8d8bef9SDimitry Andric if (Range.empty()) 2251e8d8bef9SDimitry Andric return NumNewLines; 2252e8d8bef9SDimitry Andric 2253e8d8bef9SDimitry Andric ++NumNewLines; 2254e8d8bef9SDimitry Andric 2255e8d8bef9SDimitry Andric // Handle \n\r and \r\n as a single newline. 2256e8d8bef9SDimitry Andric if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') && 2257e8d8bef9SDimitry Andric (Range[0] != Range[1])) 2258e8d8bef9SDimitry Andric Range = Range.substr(1); 2259e8d8bef9SDimitry Andric Range = Range.substr(1); 2260e8d8bef9SDimitry Andric 2261e8d8bef9SDimitry Andric if (NumNewLines == 1) 2262e8d8bef9SDimitry Andric FirstNewLine = Range.begin(); 2263e8d8bef9SDimitry Andric } 2264e8d8bef9SDimitry Andric } 2265e8d8bef9SDimitry Andric 2266e8d8bef9SDimitry Andric size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, 2267e8d8bef9SDimitry Andric bool IsLabelScanMode, size_t &MatchLen, 2268e8d8bef9SDimitry Andric FileCheckRequest &Req, 2269e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags) const { 2270e8d8bef9SDimitry Andric size_t LastPos = 0; 2271e8d8bef9SDimitry Andric std::vector<const Pattern *> NotStrings; 2272e8d8bef9SDimitry Andric 2273e8d8bef9SDimitry Andric // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL 2274e8d8bef9SDimitry Andric // bounds; we have not processed variable definitions within the bounded block 2275e8d8bef9SDimitry Andric // yet so cannot handle any final CHECK-DAG yet; this is handled when going 2276e8d8bef9SDimitry Andric // over the block again (including the last CHECK-LABEL) in normal mode. 2277e8d8bef9SDimitry Andric if (!IsLabelScanMode) { 2278e8d8bef9SDimitry Andric // Match "dag strings" (with mixed "not strings" if any). 2279e8d8bef9SDimitry Andric LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags); 2280e8d8bef9SDimitry Andric if (LastPos == StringRef::npos) 2281e8d8bef9SDimitry Andric return StringRef::npos; 2282e8d8bef9SDimitry Andric } 2283e8d8bef9SDimitry Andric 2284e8d8bef9SDimitry Andric // Match itself from the last position after matching CHECK-DAG. 2285e8d8bef9SDimitry Andric size_t LastMatchEnd = LastPos; 2286e8d8bef9SDimitry Andric size_t FirstMatchPos = 0; 2287e8d8bef9SDimitry Andric // Go match the pattern Count times. Majority of patterns only match with 2288e8d8bef9SDimitry Andric // count 1 though. 2289e8d8bef9SDimitry Andric assert(Pat.getCount() != 0 && "pattern count can not be zero"); 2290e8d8bef9SDimitry Andric for (int i = 1; i <= Pat.getCount(); i++) { 2291e8d8bef9SDimitry Andric StringRef MatchBuffer = Buffer.substr(LastMatchEnd); 2292e8d8bef9SDimitry Andric // get a match at current start point 2293fe6060f1SDimitry Andric Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM); 2294e8d8bef9SDimitry Andric 2295e8d8bef9SDimitry Andric // report 2296fe6060f1SDimitry Andric if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix, Loc, 2297fe6060f1SDimitry Andric Pat, i, MatchBuffer, 2298fe6060f1SDimitry Andric std::move(MatchResult), Req, Diags)) { 2299fe6060f1SDimitry Andric cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {})); 2300e8d8bef9SDimitry Andric return StringRef::npos; 2301e8d8bef9SDimitry Andric } 2302fe6060f1SDimitry Andric 2303fe6060f1SDimitry Andric size_t MatchPos = MatchResult.TheMatch->Pos; 2304e8d8bef9SDimitry Andric if (i == 1) 2305e8d8bef9SDimitry Andric FirstMatchPos = LastPos + MatchPos; 2306e8d8bef9SDimitry Andric 2307e8d8bef9SDimitry Andric // move start point after the match 2308fe6060f1SDimitry Andric LastMatchEnd += MatchPos + MatchResult.TheMatch->Len; 2309e8d8bef9SDimitry Andric } 2310e8d8bef9SDimitry Andric // Full match len counts from first match pos. 2311e8d8bef9SDimitry Andric MatchLen = LastMatchEnd - FirstMatchPos; 2312e8d8bef9SDimitry Andric 2313e8d8bef9SDimitry Andric // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT 2314e8d8bef9SDimitry Andric // or CHECK-NOT 2315e8d8bef9SDimitry Andric if (!IsLabelScanMode) { 2316e8d8bef9SDimitry Andric size_t MatchPos = FirstMatchPos - LastPos; 2317e8d8bef9SDimitry Andric StringRef MatchBuffer = Buffer.substr(LastPos); 2318e8d8bef9SDimitry Andric StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); 2319e8d8bef9SDimitry Andric 2320e8d8bef9SDimitry Andric // If this check is a "CHECK-NEXT", verify that the previous match was on 2321e8d8bef9SDimitry Andric // the previous line (i.e. that there is one newline between them). 2322e8d8bef9SDimitry Andric if (CheckNext(SM, SkippedRegion)) { 2323e8d8bef9SDimitry Andric ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc, 2324e8d8bef9SDimitry Andric Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, 2325e8d8bef9SDimitry Andric Diags, Req.Verbose); 2326e8d8bef9SDimitry Andric return StringRef::npos; 2327e8d8bef9SDimitry Andric } 2328e8d8bef9SDimitry Andric 2329e8d8bef9SDimitry Andric // If this check is a "CHECK-SAME", verify that the previous match was on 2330e8d8bef9SDimitry Andric // the same line (i.e. that there is no newline between them). 2331e8d8bef9SDimitry Andric if (CheckSame(SM, SkippedRegion)) { 2332e8d8bef9SDimitry Andric ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc, 2333e8d8bef9SDimitry Andric Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, 2334e8d8bef9SDimitry Andric Diags, Req.Verbose); 2335e8d8bef9SDimitry Andric return StringRef::npos; 2336e8d8bef9SDimitry Andric } 2337e8d8bef9SDimitry Andric 2338e8d8bef9SDimitry Andric // If this match had "not strings", verify that they don't exist in the 2339e8d8bef9SDimitry Andric // skipped region. 2340e8d8bef9SDimitry Andric if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) 2341e8d8bef9SDimitry Andric return StringRef::npos; 2342e8d8bef9SDimitry Andric } 2343e8d8bef9SDimitry Andric 2344e8d8bef9SDimitry Andric return FirstMatchPos; 2345e8d8bef9SDimitry Andric } 2346e8d8bef9SDimitry Andric 2347e8d8bef9SDimitry Andric bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { 2348e8d8bef9SDimitry Andric if (Pat.getCheckTy() != Check::CheckNext && 2349e8d8bef9SDimitry Andric Pat.getCheckTy() != Check::CheckEmpty) 2350e8d8bef9SDimitry Andric return false; 2351e8d8bef9SDimitry Andric 2352e8d8bef9SDimitry Andric Twine CheckName = 2353e8d8bef9SDimitry Andric Prefix + 2354e8d8bef9SDimitry Andric Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT"); 2355e8d8bef9SDimitry Andric 2356e8d8bef9SDimitry Andric // Count the number of newlines between the previous match and this one. 2357e8d8bef9SDimitry Andric const char *FirstNewLine = nullptr; 2358e8d8bef9SDimitry Andric unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); 2359e8d8bef9SDimitry Andric 2360e8d8bef9SDimitry Andric if (NumNewLines == 0) { 2361e8d8bef9SDimitry Andric SM.PrintMessage(Loc, SourceMgr::DK_Error, 2362e8d8bef9SDimitry Andric CheckName + ": is on the same line as previous match"); 2363e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 2364e8d8bef9SDimitry Andric "'next' match was here"); 2365e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 2366e8d8bef9SDimitry Andric "previous match ended here"); 2367e8d8bef9SDimitry Andric return true; 2368e8d8bef9SDimitry Andric } 2369e8d8bef9SDimitry Andric 2370e8d8bef9SDimitry Andric if (NumNewLines != 1) { 2371e8d8bef9SDimitry Andric SM.PrintMessage(Loc, SourceMgr::DK_Error, 2372e8d8bef9SDimitry Andric CheckName + 2373e8d8bef9SDimitry Andric ": is not on the line after the previous match"); 2374e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 2375e8d8bef9SDimitry Andric "'next' match was here"); 2376e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 2377e8d8bef9SDimitry Andric "previous match ended here"); 2378e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note, 2379e8d8bef9SDimitry Andric "non-matching line after previous match is here"); 2380e8d8bef9SDimitry Andric return true; 2381e8d8bef9SDimitry Andric } 2382e8d8bef9SDimitry Andric 2383e8d8bef9SDimitry Andric return false; 2384e8d8bef9SDimitry Andric } 2385e8d8bef9SDimitry Andric 2386e8d8bef9SDimitry Andric bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { 2387e8d8bef9SDimitry Andric if (Pat.getCheckTy() != Check::CheckSame) 2388e8d8bef9SDimitry Andric return false; 2389e8d8bef9SDimitry Andric 2390e8d8bef9SDimitry Andric // Count the number of newlines between the previous match and this one. 2391e8d8bef9SDimitry Andric const char *FirstNewLine = nullptr; 2392e8d8bef9SDimitry Andric unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); 2393e8d8bef9SDimitry Andric 2394e8d8bef9SDimitry Andric if (NumNewLines != 0) { 2395e8d8bef9SDimitry Andric SM.PrintMessage(Loc, SourceMgr::DK_Error, 2396e8d8bef9SDimitry Andric Prefix + 2397e8d8bef9SDimitry Andric "-SAME: is not on the same line as the previous match"); 2398e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 2399e8d8bef9SDimitry Andric "'next' match was here"); 2400e8d8bef9SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 2401e8d8bef9SDimitry Andric "previous match ended here"); 2402e8d8bef9SDimitry Andric return true; 2403e8d8bef9SDimitry Andric } 2404e8d8bef9SDimitry Andric 2405e8d8bef9SDimitry Andric return false; 2406e8d8bef9SDimitry Andric } 2407e8d8bef9SDimitry Andric 2408e8d8bef9SDimitry Andric bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, 2409e8d8bef9SDimitry Andric const std::vector<const Pattern *> &NotStrings, 2410e8d8bef9SDimitry Andric const FileCheckRequest &Req, 2411e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags) const { 2412e8d8bef9SDimitry Andric bool DirectiveFail = false; 2413e8d8bef9SDimitry Andric for (const Pattern *Pat : NotStrings) { 2414e8d8bef9SDimitry Andric assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); 2415fe6060f1SDimitry Andric Pattern::MatchResult MatchResult = Pat->match(Buffer, SM); 2416fe6060f1SDimitry Andric if (Error Err = reportMatchResult(/*ExpectedMatch=*/false, SM, Prefix, 2417fe6060f1SDimitry Andric Pat->getLoc(), *Pat, 1, Buffer, 2418fe6060f1SDimitry Andric std::move(MatchResult), Req, Diags)) { 2419fe6060f1SDimitry Andric cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {})); 2420fe6060f1SDimitry Andric DirectiveFail = true; 2421e8d8bef9SDimitry Andric continue; 2422e8d8bef9SDimitry Andric } 2423e8d8bef9SDimitry Andric } 2424e8d8bef9SDimitry Andric return DirectiveFail; 2425e8d8bef9SDimitry Andric } 2426e8d8bef9SDimitry Andric 2427e8d8bef9SDimitry Andric size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, 2428e8d8bef9SDimitry Andric std::vector<const Pattern *> &NotStrings, 2429e8d8bef9SDimitry Andric const FileCheckRequest &Req, 2430e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags) const { 2431e8d8bef9SDimitry Andric if (DagNotStrings.empty()) 2432e8d8bef9SDimitry Andric return 0; 2433e8d8bef9SDimitry Andric 2434e8d8bef9SDimitry Andric // The start of the search range. 2435e8d8bef9SDimitry Andric size_t StartPos = 0; 2436e8d8bef9SDimitry Andric 2437e8d8bef9SDimitry Andric struct MatchRange { 2438e8d8bef9SDimitry Andric size_t Pos; 2439e8d8bef9SDimitry Andric size_t End; 2440e8d8bef9SDimitry Andric }; 2441e8d8bef9SDimitry Andric // A sorted list of ranges for non-overlapping CHECK-DAG matches. Match 2442e8d8bef9SDimitry Andric // ranges are erased from this list once they are no longer in the search 2443e8d8bef9SDimitry Andric // range. 2444e8d8bef9SDimitry Andric std::list<MatchRange> MatchRanges; 2445e8d8bef9SDimitry Andric 2446e8d8bef9SDimitry Andric // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG 2447e8d8bef9SDimitry Andric // group, so we don't use a range-based for loop here. 2448e8d8bef9SDimitry Andric for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end(); 2449e8d8bef9SDimitry Andric PatItr != PatEnd; ++PatItr) { 2450e8d8bef9SDimitry Andric const Pattern &Pat = *PatItr; 2451e8d8bef9SDimitry Andric assert((Pat.getCheckTy() == Check::CheckDAG || 2452e8d8bef9SDimitry Andric Pat.getCheckTy() == Check::CheckNot) && 2453e8d8bef9SDimitry Andric "Invalid CHECK-DAG or CHECK-NOT!"); 2454e8d8bef9SDimitry Andric 2455e8d8bef9SDimitry Andric if (Pat.getCheckTy() == Check::CheckNot) { 2456e8d8bef9SDimitry Andric NotStrings.push_back(&Pat); 2457e8d8bef9SDimitry Andric continue; 2458e8d8bef9SDimitry Andric } 2459e8d8bef9SDimitry Andric 2460e8d8bef9SDimitry Andric assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!"); 2461e8d8bef9SDimitry Andric 2462e8d8bef9SDimitry Andric // CHECK-DAG always matches from the start. 2463e8d8bef9SDimitry Andric size_t MatchLen = 0, MatchPos = StartPos; 2464e8d8bef9SDimitry Andric 2465e8d8bef9SDimitry Andric // Search for a match that doesn't overlap a previous match in this 2466e8d8bef9SDimitry Andric // CHECK-DAG group. 2467e8d8bef9SDimitry Andric for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) { 2468e8d8bef9SDimitry Andric StringRef MatchBuffer = Buffer.substr(MatchPos); 2469fe6060f1SDimitry Andric Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM); 2470e8d8bef9SDimitry Andric // With a group of CHECK-DAGs, a single mismatching means the match on 2471e8d8bef9SDimitry Andric // that group of CHECK-DAGs fails immediately. 2472fe6060f1SDimitry Andric if (MatchResult.TheError || Req.VerboseVerbose) { 2473fe6060f1SDimitry Andric if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix, 2474fe6060f1SDimitry Andric Pat.getLoc(), Pat, 1, MatchBuffer, 2475fe6060f1SDimitry Andric std::move(MatchResult), Req, Diags)) { 2476fe6060f1SDimitry Andric cantFail( 2477fe6060f1SDimitry Andric handleErrors(std::move(Err), [&](const ErrorReported &E) {})); 2478e8d8bef9SDimitry Andric return StringRef::npos; 2479e8d8bef9SDimitry Andric } 2480fe6060f1SDimitry Andric } 2481fe6060f1SDimitry Andric MatchLen = MatchResult.TheMatch->Len; 2482fe6060f1SDimitry Andric // Re-calc it as the offset relative to the start of the original 2483fe6060f1SDimitry Andric // string. 2484fe6060f1SDimitry Andric MatchPos += MatchResult.TheMatch->Pos; 2485e8d8bef9SDimitry Andric MatchRange M{MatchPos, MatchPos + MatchLen}; 2486e8d8bef9SDimitry Andric if (Req.AllowDeprecatedDagOverlap) { 2487e8d8bef9SDimitry Andric // We don't need to track all matches in this mode, so we just maintain 2488e8d8bef9SDimitry Andric // one match range that encompasses the current CHECK-DAG group's 2489e8d8bef9SDimitry Andric // matches. 2490e8d8bef9SDimitry Andric if (MatchRanges.empty()) 2491e8d8bef9SDimitry Andric MatchRanges.insert(MatchRanges.end(), M); 2492e8d8bef9SDimitry Andric else { 2493e8d8bef9SDimitry Andric auto Block = MatchRanges.begin(); 2494e8d8bef9SDimitry Andric Block->Pos = std::min(Block->Pos, M.Pos); 2495e8d8bef9SDimitry Andric Block->End = std::max(Block->End, M.End); 2496e8d8bef9SDimitry Andric } 2497e8d8bef9SDimitry Andric break; 2498e8d8bef9SDimitry Andric } 2499e8d8bef9SDimitry Andric // Iterate previous matches until overlapping match or insertion point. 2500e8d8bef9SDimitry Andric bool Overlap = false; 2501e8d8bef9SDimitry Andric for (; MI != ME; ++MI) { 2502e8d8bef9SDimitry Andric if (M.Pos < MI->End) { 2503e8d8bef9SDimitry Andric // !Overlap => New match has no overlap and is before this old match. 2504e8d8bef9SDimitry Andric // Overlap => New match overlaps this old match. 2505e8d8bef9SDimitry Andric Overlap = MI->Pos < M.End; 2506e8d8bef9SDimitry Andric break; 2507e8d8bef9SDimitry Andric } 2508e8d8bef9SDimitry Andric } 2509e8d8bef9SDimitry Andric if (!Overlap) { 2510e8d8bef9SDimitry Andric // Insert non-overlapping match into list. 2511e8d8bef9SDimitry Andric MatchRanges.insert(MI, M); 2512e8d8bef9SDimitry Andric break; 2513e8d8bef9SDimitry Andric } 2514e8d8bef9SDimitry Andric if (Req.VerboseVerbose) { 2515e8d8bef9SDimitry Andric // Due to their verbosity, we don't print verbose diagnostics here if 2516e8d8bef9SDimitry Andric // we're gathering them for a different rendering, but we always print 2517e8d8bef9SDimitry Andric // other diagnostics. 2518e8d8bef9SDimitry Andric if (!Diags) { 2519e8d8bef9SDimitry Andric SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos); 2520e8d8bef9SDimitry Andric SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End); 2521e8d8bef9SDimitry Andric SMRange OldRange(OldStart, OldEnd); 2522e8d8bef9SDimitry Andric SM.PrintMessage(OldStart, SourceMgr::DK_Note, 2523e8d8bef9SDimitry Andric "match discarded, overlaps earlier DAG match here", 2524e8d8bef9SDimitry Andric {OldRange}); 2525e8d8bef9SDimitry Andric } else { 2526e8d8bef9SDimitry Andric SMLoc CheckLoc = Diags->rbegin()->CheckLoc; 2527e8d8bef9SDimitry Andric for (auto I = Diags->rbegin(), E = Diags->rend(); 2528e8d8bef9SDimitry Andric I != E && I->CheckLoc == CheckLoc; ++I) 2529e8d8bef9SDimitry Andric I->MatchTy = FileCheckDiag::MatchFoundButDiscarded; 2530e8d8bef9SDimitry Andric } 2531e8d8bef9SDimitry Andric } 2532e8d8bef9SDimitry Andric MatchPos = MI->End; 2533e8d8bef9SDimitry Andric } 2534e8d8bef9SDimitry Andric if (!Req.VerboseVerbose) 2535fe6060f1SDimitry Andric cantFail(printMatch( 2536fe6060f1SDimitry Andric /*ExpectedMatch=*/true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, 2537fe6060f1SDimitry Andric Pattern::MatchResult(MatchPos, MatchLen, Error::success()), Req, 2538fe6060f1SDimitry Andric Diags)); 2539e8d8bef9SDimitry Andric 2540e8d8bef9SDimitry Andric // Handle the end of a CHECK-DAG group. 2541e8d8bef9SDimitry Andric if (std::next(PatItr) == PatEnd || 2542e8d8bef9SDimitry Andric std::next(PatItr)->getCheckTy() == Check::CheckNot) { 2543e8d8bef9SDimitry Andric if (!NotStrings.empty()) { 2544e8d8bef9SDimitry Andric // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to 2545e8d8bef9SDimitry Andric // CHECK-DAG, verify that there are no 'not' strings occurred in that 2546e8d8bef9SDimitry Andric // region. 2547e8d8bef9SDimitry Andric StringRef SkippedRegion = 2548e8d8bef9SDimitry Andric Buffer.slice(StartPos, MatchRanges.begin()->Pos); 2549e8d8bef9SDimitry Andric if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) 2550e8d8bef9SDimitry Andric return StringRef::npos; 2551e8d8bef9SDimitry Andric // Clear "not strings". 2552e8d8bef9SDimitry Andric NotStrings.clear(); 2553e8d8bef9SDimitry Andric } 2554e8d8bef9SDimitry Andric // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the 2555e8d8bef9SDimitry Andric // end of this CHECK-DAG group's match range. 2556e8d8bef9SDimitry Andric StartPos = MatchRanges.rbegin()->End; 2557e8d8bef9SDimitry Andric // Don't waste time checking for (impossible) overlaps before that. 2558e8d8bef9SDimitry Andric MatchRanges.clear(); 2559e8d8bef9SDimitry Andric } 2560e8d8bef9SDimitry Andric } 2561e8d8bef9SDimitry Andric 2562e8d8bef9SDimitry Andric return StartPos; 2563e8d8bef9SDimitry Andric } 2564e8d8bef9SDimitry Andric 2565e8d8bef9SDimitry Andric static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes, 2566e8d8bef9SDimitry Andric ArrayRef<StringRef> SuppliedPrefixes) { 2567e8d8bef9SDimitry Andric for (StringRef Prefix : SuppliedPrefixes) { 2568e8d8bef9SDimitry Andric if (Prefix.empty()) { 2569e8d8bef9SDimitry Andric errs() << "error: supplied " << Kind << " prefix must not be the empty " 2570e8d8bef9SDimitry Andric << "string\n"; 2571e8d8bef9SDimitry Andric return false; 2572e8d8bef9SDimitry Andric } 2573e8d8bef9SDimitry Andric static const Regex Validator("^[a-zA-Z0-9_-]*$"); 2574e8d8bef9SDimitry Andric if (!Validator.match(Prefix)) { 2575e8d8bef9SDimitry Andric errs() << "error: supplied " << Kind << " prefix must start with a " 2576e8d8bef9SDimitry Andric << "letter and contain only alphanumeric characters, hyphens, and " 2577e8d8bef9SDimitry Andric << "underscores: '" << Prefix << "'\n"; 2578e8d8bef9SDimitry Andric return false; 2579e8d8bef9SDimitry Andric } 2580e8d8bef9SDimitry Andric if (!UniquePrefixes.insert(Prefix).second) { 2581e8d8bef9SDimitry Andric errs() << "error: supplied " << Kind << " prefix must be unique among " 2582e8d8bef9SDimitry Andric << "check and comment prefixes: '" << Prefix << "'\n"; 2583e8d8bef9SDimitry Andric return false; 2584e8d8bef9SDimitry Andric } 2585e8d8bef9SDimitry Andric } 2586e8d8bef9SDimitry Andric return true; 2587e8d8bef9SDimitry Andric } 2588e8d8bef9SDimitry Andric 2589e8d8bef9SDimitry Andric static const char *DefaultCheckPrefixes[] = {"CHECK"}; 2590e8d8bef9SDimitry Andric static const char *DefaultCommentPrefixes[] = {"COM", "RUN"}; 2591e8d8bef9SDimitry Andric 2592e8d8bef9SDimitry Andric bool FileCheck::ValidateCheckPrefixes() { 2593e8d8bef9SDimitry Andric StringSet<> UniquePrefixes; 2594e8d8bef9SDimitry Andric // Add default prefixes to catch user-supplied duplicates of them below. 2595e8d8bef9SDimitry Andric if (Req.CheckPrefixes.empty()) { 2596e8d8bef9SDimitry Andric for (const char *Prefix : DefaultCheckPrefixes) 2597e8d8bef9SDimitry Andric UniquePrefixes.insert(Prefix); 2598e8d8bef9SDimitry Andric } 2599e8d8bef9SDimitry Andric if (Req.CommentPrefixes.empty()) { 2600e8d8bef9SDimitry Andric for (const char *Prefix : DefaultCommentPrefixes) 2601e8d8bef9SDimitry Andric UniquePrefixes.insert(Prefix); 2602e8d8bef9SDimitry Andric } 2603e8d8bef9SDimitry Andric // Do not validate the default prefixes, or diagnostics about duplicates might 2604e8d8bef9SDimitry Andric // incorrectly indicate that they were supplied by the user. 2605e8d8bef9SDimitry Andric if (!ValidatePrefixes("check", UniquePrefixes, Req.CheckPrefixes)) 2606e8d8bef9SDimitry Andric return false; 2607e8d8bef9SDimitry Andric if (!ValidatePrefixes("comment", UniquePrefixes, Req.CommentPrefixes)) 2608e8d8bef9SDimitry Andric return false; 2609e8d8bef9SDimitry Andric return true; 2610e8d8bef9SDimitry Andric } 2611e8d8bef9SDimitry Andric 2612e8d8bef9SDimitry Andric Regex FileCheck::buildCheckPrefixRegex() { 2613e8d8bef9SDimitry Andric if (Req.CheckPrefixes.empty()) { 2614e8d8bef9SDimitry Andric for (const char *Prefix : DefaultCheckPrefixes) 2615e8d8bef9SDimitry Andric Req.CheckPrefixes.push_back(Prefix); 2616e8d8bef9SDimitry Andric Req.IsDefaultCheckPrefix = true; 2617e8d8bef9SDimitry Andric } 2618e8d8bef9SDimitry Andric if (Req.CommentPrefixes.empty()) { 2619e8d8bef9SDimitry Andric for (const char *Prefix : DefaultCommentPrefixes) 2620e8d8bef9SDimitry Andric Req.CommentPrefixes.push_back(Prefix); 2621e8d8bef9SDimitry Andric } 2622e8d8bef9SDimitry Andric 2623e8d8bef9SDimitry Andric // We already validated the contents of CheckPrefixes and CommentPrefixes so 2624e8d8bef9SDimitry Andric // just concatenate them as alternatives. 2625e8d8bef9SDimitry Andric SmallString<32> PrefixRegexStr; 2626e8d8bef9SDimitry Andric for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) { 2627e8d8bef9SDimitry Andric if (I != 0) 2628e8d8bef9SDimitry Andric PrefixRegexStr.push_back('|'); 2629e8d8bef9SDimitry Andric PrefixRegexStr.append(Req.CheckPrefixes[I]); 2630e8d8bef9SDimitry Andric } 2631e8d8bef9SDimitry Andric for (StringRef Prefix : Req.CommentPrefixes) { 2632e8d8bef9SDimitry Andric PrefixRegexStr.push_back('|'); 2633e8d8bef9SDimitry Andric PrefixRegexStr.append(Prefix); 2634e8d8bef9SDimitry Andric } 2635e8d8bef9SDimitry Andric 2636e8d8bef9SDimitry Andric return Regex(PrefixRegexStr); 2637e8d8bef9SDimitry Andric } 2638e8d8bef9SDimitry Andric 2639e8d8bef9SDimitry Andric Error FileCheckPatternContext::defineCmdlineVariables( 2640e8d8bef9SDimitry Andric ArrayRef<StringRef> CmdlineDefines, SourceMgr &SM) { 2641e8d8bef9SDimitry Andric assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() && 2642e8d8bef9SDimitry Andric "Overriding defined variable with command-line variable definitions"); 2643e8d8bef9SDimitry Andric 2644e8d8bef9SDimitry Andric if (CmdlineDefines.empty()) 2645e8d8bef9SDimitry Andric return Error::success(); 2646e8d8bef9SDimitry Andric 2647e8d8bef9SDimitry Andric // Create a string representing the vector of command-line definitions. Each 2648e8d8bef9SDimitry Andric // definition is on its own line and prefixed with a definition number to 2649e8d8bef9SDimitry Andric // clarify which definition a given diagnostic corresponds to. 2650e8d8bef9SDimitry Andric unsigned I = 0; 2651e8d8bef9SDimitry Andric Error Errs = Error::success(); 2652e8d8bef9SDimitry Andric std::string CmdlineDefsDiag; 2653e8d8bef9SDimitry Andric SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices; 2654e8d8bef9SDimitry Andric for (StringRef CmdlineDef : CmdlineDefines) { 2655e8d8bef9SDimitry Andric std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str(); 2656e8d8bef9SDimitry Andric size_t EqIdx = CmdlineDef.find('='); 2657e8d8bef9SDimitry Andric if (EqIdx == StringRef::npos) { 2658e8d8bef9SDimitry Andric CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0)); 2659e8d8bef9SDimitry Andric continue; 2660e8d8bef9SDimitry Andric } 2661e8d8bef9SDimitry Andric // Numeric variable definition. 2662e8d8bef9SDimitry Andric if (CmdlineDef[0] == '#') { 2663e8d8bef9SDimitry Andric // Append a copy of the command-line definition adapted to use the same 2664e8d8bef9SDimitry Andric // format as in the input file to be able to reuse 2665e8d8bef9SDimitry Andric // parseNumericSubstitutionBlock. 2666e8d8bef9SDimitry Andric CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str(); 2667e8d8bef9SDimitry Andric std::string SubstitutionStr = std::string(CmdlineDef); 2668e8d8bef9SDimitry Andric SubstitutionStr[EqIdx] = ':'; 2669e8d8bef9SDimitry Andric CmdlineDefsIndices.push_back( 2670e8d8bef9SDimitry Andric std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size())); 2671e8d8bef9SDimitry Andric CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str(); 2672e8d8bef9SDimitry Andric } else { 2673e8d8bef9SDimitry Andric CmdlineDefsDiag += DefPrefix; 2674e8d8bef9SDimitry Andric CmdlineDefsIndices.push_back( 2675e8d8bef9SDimitry Andric std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size())); 2676e8d8bef9SDimitry Andric CmdlineDefsDiag += (CmdlineDef + "\n").str(); 2677e8d8bef9SDimitry Andric } 2678e8d8bef9SDimitry Andric } 2679e8d8bef9SDimitry Andric 2680e8d8bef9SDimitry Andric // Create a buffer with fake command line content in order to display 2681e8d8bef9SDimitry Andric // parsing diagnostic with location information and point to the 2682e8d8bef9SDimitry Andric // global definition with invalid syntax. 2683e8d8bef9SDimitry Andric std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer = 2684e8d8bef9SDimitry Andric MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines"); 2685e8d8bef9SDimitry Andric StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer(); 2686e8d8bef9SDimitry Andric SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc()); 2687e8d8bef9SDimitry Andric 2688e8d8bef9SDimitry Andric for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) { 2689e8d8bef9SDimitry Andric StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first, 2690e8d8bef9SDimitry Andric CmdlineDefIndices.second); 2691e8d8bef9SDimitry Andric if (CmdlineDef.empty()) { 2692e8d8bef9SDimitry Andric Errs = joinErrors( 2693e8d8bef9SDimitry Andric std::move(Errs), 2694e8d8bef9SDimitry Andric ErrorDiagnostic::get(SM, CmdlineDef, 2695e8d8bef9SDimitry Andric "missing equal sign in global definition")); 2696e8d8bef9SDimitry Andric continue; 2697e8d8bef9SDimitry Andric } 2698e8d8bef9SDimitry Andric 2699e8d8bef9SDimitry Andric // Numeric variable definition. 2700e8d8bef9SDimitry Andric if (CmdlineDef[0] == '#') { 2701e8d8bef9SDimitry Andric // Now parse the definition both to check that the syntax is correct and 2702e8d8bef9SDimitry Andric // to create the necessary class instance. 2703e8d8bef9SDimitry Andric StringRef CmdlineDefExpr = CmdlineDef.substr(1); 2704e8d8bef9SDimitry Andric Optional<NumericVariable *> DefinedNumericVariable; 2705e8d8bef9SDimitry Andric Expected<std::unique_ptr<Expression>> ExpressionResult = 2706e8d8bef9SDimitry Andric Pattern::parseNumericSubstitutionBlock( 2707e8d8bef9SDimitry Andric CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM); 2708e8d8bef9SDimitry Andric if (!ExpressionResult) { 2709e8d8bef9SDimitry Andric Errs = joinErrors(std::move(Errs), ExpressionResult.takeError()); 2710e8d8bef9SDimitry Andric continue; 2711e8d8bef9SDimitry Andric } 2712e8d8bef9SDimitry Andric std::unique_ptr<Expression> Expression = std::move(*ExpressionResult); 2713e8d8bef9SDimitry Andric // Now evaluate the expression whose value this variable should be set 2714e8d8bef9SDimitry Andric // to, since the expression of a command-line variable definition should 2715e8d8bef9SDimitry Andric // only use variables defined earlier on the command-line. If not, this 2716e8d8bef9SDimitry Andric // is an error and we report it. 2717e8d8bef9SDimitry Andric Expected<ExpressionValue> Value = Expression->getAST()->eval(); 2718e8d8bef9SDimitry Andric if (!Value) { 2719e8d8bef9SDimitry Andric Errs = joinErrors(std::move(Errs), Value.takeError()); 2720e8d8bef9SDimitry Andric continue; 2721e8d8bef9SDimitry Andric } 2722e8d8bef9SDimitry Andric 2723e8d8bef9SDimitry Andric assert(DefinedNumericVariable && "No variable defined"); 2724e8d8bef9SDimitry Andric (*DefinedNumericVariable)->setValue(*Value); 2725e8d8bef9SDimitry Andric 2726e8d8bef9SDimitry Andric // Record this variable definition. 2727e8d8bef9SDimitry Andric GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] = 2728e8d8bef9SDimitry Andric *DefinedNumericVariable; 2729e8d8bef9SDimitry Andric } else { 2730e8d8bef9SDimitry Andric // String variable definition. 2731e8d8bef9SDimitry Andric std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('='); 2732e8d8bef9SDimitry Andric StringRef CmdlineName = CmdlineNameVal.first; 2733e8d8bef9SDimitry Andric StringRef OrigCmdlineName = CmdlineName; 2734e8d8bef9SDimitry Andric Expected<Pattern::VariableProperties> ParseVarResult = 2735e8d8bef9SDimitry Andric Pattern::parseVariable(CmdlineName, SM); 2736e8d8bef9SDimitry Andric if (!ParseVarResult) { 2737e8d8bef9SDimitry Andric Errs = joinErrors(std::move(Errs), ParseVarResult.takeError()); 2738e8d8bef9SDimitry Andric continue; 2739e8d8bef9SDimitry Andric } 2740e8d8bef9SDimitry Andric // Check that CmdlineName does not denote a pseudo variable is only 2741e8d8bef9SDimitry Andric // composed of the parsed numeric variable. This catches cases like 2742e8d8bef9SDimitry Andric // "FOO+2" in a "FOO+2=10" definition. 2743e8d8bef9SDimitry Andric if (ParseVarResult->IsPseudo || !CmdlineName.empty()) { 2744e8d8bef9SDimitry Andric Errs = joinErrors(std::move(Errs), 2745e8d8bef9SDimitry Andric ErrorDiagnostic::get( 2746e8d8bef9SDimitry Andric SM, OrigCmdlineName, 2747e8d8bef9SDimitry Andric "invalid name in string variable definition '" + 2748e8d8bef9SDimitry Andric OrigCmdlineName + "'")); 2749e8d8bef9SDimitry Andric continue; 2750e8d8bef9SDimitry Andric } 2751e8d8bef9SDimitry Andric StringRef Name = ParseVarResult->Name; 2752e8d8bef9SDimitry Andric 2753e8d8bef9SDimitry Andric // Detect collisions between string and numeric variables when the former 2754e8d8bef9SDimitry Andric // is created later than the latter. 2755e8d8bef9SDimitry Andric if (GlobalNumericVariableTable.find(Name) != 2756e8d8bef9SDimitry Andric GlobalNumericVariableTable.end()) { 2757e8d8bef9SDimitry Andric Errs = joinErrors(std::move(Errs), 2758e8d8bef9SDimitry Andric ErrorDiagnostic::get(SM, Name, 2759e8d8bef9SDimitry Andric "numeric variable with name '" + 2760e8d8bef9SDimitry Andric Name + "' already exists")); 2761e8d8bef9SDimitry Andric continue; 2762e8d8bef9SDimitry Andric } 2763e8d8bef9SDimitry Andric GlobalVariableTable.insert(CmdlineNameVal); 2764e8d8bef9SDimitry Andric // Mark the string variable as defined to detect collisions between 2765e8d8bef9SDimitry Andric // string and numeric variables in defineCmdlineVariables when the latter 2766e8d8bef9SDimitry Andric // is created later than the former. We cannot reuse GlobalVariableTable 2767e8d8bef9SDimitry Andric // for this by populating it with an empty string since we would then 2768e8d8bef9SDimitry Andric // lose the ability to detect the use of an undefined variable in 2769e8d8bef9SDimitry Andric // match(). 2770e8d8bef9SDimitry Andric DefinedVariableTable[Name] = true; 2771e8d8bef9SDimitry Andric } 2772e8d8bef9SDimitry Andric } 2773e8d8bef9SDimitry Andric 2774e8d8bef9SDimitry Andric return Errs; 2775e8d8bef9SDimitry Andric } 2776e8d8bef9SDimitry Andric 2777e8d8bef9SDimitry Andric void FileCheckPatternContext::clearLocalVars() { 2778e8d8bef9SDimitry Andric SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars; 2779e8d8bef9SDimitry Andric for (const StringMapEntry<StringRef> &Var : GlobalVariableTable) 2780e8d8bef9SDimitry Andric if (Var.first()[0] != '$') 2781e8d8bef9SDimitry Andric LocalPatternVars.push_back(Var.first()); 2782e8d8bef9SDimitry Andric 2783e8d8bef9SDimitry Andric // Numeric substitution reads the value of a variable directly, not via 2784e8d8bef9SDimitry Andric // GlobalNumericVariableTable. Therefore, we clear local variables by 2785e8d8bef9SDimitry Andric // clearing their value which will lead to a numeric substitution failure. We 2786e8d8bef9SDimitry Andric // also mark the variable for removal from GlobalNumericVariableTable since 2787e8d8bef9SDimitry Andric // this is what defineCmdlineVariables checks to decide that no global 2788e8d8bef9SDimitry Andric // variable has been defined. 2789e8d8bef9SDimitry Andric for (const auto &Var : GlobalNumericVariableTable) 2790e8d8bef9SDimitry Andric if (Var.first()[0] != '$') { 2791e8d8bef9SDimitry Andric Var.getValue()->clearValue(); 2792e8d8bef9SDimitry Andric LocalNumericVars.push_back(Var.first()); 2793e8d8bef9SDimitry Andric } 2794e8d8bef9SDimitry Andric 2795e8d8bef9SDimitry Andric for (const auto &Var : LocalPatternVars) 2796e8d8bef9SDimitry Andric GlobalVariableTable.erase(Var); 2797e8d8bef9SDimitry Andric for (const auto &Var : LocalNumericVars) 2798e8d8bef9SDimitry Andric GlobalNumericVariableTable.erase(Var); 2799e8d8bef9SDimitry Andric } 2800e8d8bef9SDimitry Andric 2801e8d8bef9SDimitry Andric bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer, 2802e8d8bef9SDimitry Andric std::vector<FileCheckDiag> *Diags) { 2803e8d8bef9SDimitry Andric bool ChecksFailed = false; 2804e8d8bef9SDimitry Andric 2805e8d8bef9SDimitry Andric unsigned i = 0, j = 0, e = CheckStrings->size(); 2806e8d8bef9SDimitry Andric while (true) { 2807e8d8bef9SDimitry Andric StringRef CheckRegion; 2808e8d8bef9SDimitry Andric if (j == e) { 2809e8d8bef9SDimitry Andric CheckRegion = Buffer; 2810e8d8bef9SDimitry Andric } else { 2811e8d8bef9SDimitry Andric const FileCheckString &CheckLabelStr = (*CheckStrings)[j]; 2812e8d8bef9SDimitry Andric if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) { 2813e8d8bef9SDimitry Andric ++j; 2814e8d8bef9SDimitry Andric continue; 2815e8d8bef9SDimitry Andric } 2816e8d8bef9SDimitry Andric 2817e8d8bef9SDimitry Andric // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG 2818e8d8bef9SDimitry Andric size_t MatchLabelLen = 0; 2819e8d8bef9SDimitry Andric size_t MatchLabelPos = 2820e8d8bef9SDimitry Andric CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags); 2821e8d8bef9SDimitry Andric if (MatchLabelPos == StringRef::npos) 2822e8d8bef9SDimitry Andric // Immediately bail if CHECK-LABEL fails, nothing else we can do. 2823e8d8bef9SDimitry Andric return false; 2824e8d8bef9SDimitry Andric 2825e8d8bef9SDimitry Andric CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen); 2826e8d8bef9SDimitry Andric Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen); 2827e8d8bef9SDimitry Andric ++j; 2828e8d8bef9SDimitry Andric } 2829e8d8bef9SDimitry Andric 2830e8d8bef9SDimitry Andric // Do not clear the first region as it's the one before the first 2831e8d8bef9SDimitry Andric // CHECK-LABEL and it would clear variables defined on the command-line 2832e8d8bef9SDimitry Andric // before they get used. 2833e8d8bef9SDimitry Andric if (i != 0 && Req.EnableVarScope) 2834e8d8bef9SDimitry Andric PatternContext->clearLocalVars(); 2835e8d8bef9SDimitry Andric 2836e8d8bef9SDimitry Andric for (; i != j; ++i) { 2837e8d8bef9SDimitry Andric const FileCheckString &CheckStr = (*CheckStrings)[i]; 2838e8d8bef9SDimitry Andric 2839e8d8bef9SDimitry Andric // Check each string within the scanned region, including a second check 2840e8d8bef9SDimitry Andric // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) 2841e8d8bef9SDimitry Andric size_t MatchLen = 0; 2842e8d8bef9SDimitry Andric size_t MatchPos = 2843e8d8bef9SDimitry Andric CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags); 2844e8d8bef9SDimitry Andric 2845e8d8bef9SDimitry Andric if (MatchPos == StringRef::npos) { 2846e8d8bef9SDimitry Andric ChecksFailed = true; 2847e8d8bef9SDimitry Andric i = j; 2848e8d8bef9SDimitry Andric break; 2849e8d8bef9SDimitry Andric } 2850e8d8bef9SDimitry Andric 2851e8d8bef9SDimitry Andric CheckRegion = CheckRegion.substr(MatchPos + MatchLen); 2852e8d8bef9SDimitry Andric } 2853e8d8bef9SDimitry Andric 2854e8d8bef9SDimitry Andric if (j == e) 2855e8d8bef9SDimitry Andric break; 2856e8d8bef9SDimitry Andric } 2857e8d8bef9SDimitry Andric 2858e8d8bef9SDimitry Andric // Success if no checks failed. 2859e8d8bef9SDimitry Andric return !ChecksFailed; 2860e8d8bef9SDimitry Andric } 2861