# Changeset View

Changeset View

# Standalone View

Standalone View

# llvm/lib/Support/FileCheck.cpp

Show All 20 Lines | |||||

21 | #include <map> | 21 | #include <map> | ||

22 | #include <tuple> | 22 | #include <tuple> | ||

23 | #include <utility> | 23 | #include <utility> | ||

24 | 24 | | |||

25 | using namespace llvm; | 25 | using namespace llvm; | ||

26 | 26 | | |||

27 | bool FileCheckExpressionFormat:: | 27 | bool FileCheckExpressionFormat:: | ||

28 | operator==(const FileCheckExpressionFormat &other) { | 28 | operator==(const FileCheckExpressionFormat &other) { | ||

29 | return Valid == other.Valid && Hex == other.Hex && Cap == other.Cap; | 29 | return Valid == other.Valid && Conflict == other.Conflict && | ||

30 | Signed == other.Signed && Hex == other.Hex && Cap == other.Cap; | ||||

30 | } | 31 | } | ||

31 | 32 | | |||

32 | StringRef FileCheckExpressionFormat::getWildcardRegex() const { | 33 | StringRef FileCheckExpressionFormat::getWildcardRegex() const { | ||

33 | assert(Valid && !Conflict && "Trying to match value with invalid format"); | 34 | assert(Valid && !Conflict && "Trying to match value with invalid format"); | ||

34 | if (!Hex) | 35 | if (Hex) { | ||

35 | return StringRef("[[:digit:]]+"); | | |||

36 | if (Cap) | 36 | if (Cap) | ||

37 | return StringRef("[[:digit:]A-F]+"); | 37 | return StringRef("[[:digit:]A-F]+"); | ||

38 | return StringRef("[[:digit:]a-f]+"); | 38 | return StringRef("[[:digit:]a-f]+"); | ||

39 | } | 39 | } | ||

40 | if (Signed) | ||||

41 | return StringRef("-?[[:digit:]]+"); | ||||

42 | return StringRef("[[:digit:]]+"); | ||||

43 | } | ||||

40 | 44 | | |||

41 | std::string FileCheckExpressionFormat::getMatchingString(uint64_t Value) const { | 45 | Expected<std::string> FileCheckExpressionFormat::getMatchingString( | ||

46 | FileCheckExpressionValue Value) const { | ||||

42 | assert(Valid && !Conflict && "Trying to match value with invalid format"); | 47 | assert(Valid && !Conflict && "Trying to match value with invalid format"); | ||

48 | | ||||

49 | Error ConvError = Signed ? Value.convertSigned() : Value.convertUnsigned(); | ||||

50 | | ||||

51 | // Conversion error (e.g. negative value converted to unsigned). | ||||

52 | if (ConvError) | ||||

53 | return std::move(ConvError); | ||||

54 | | ||||

43 | if (Hex) | 55 | if (Hex) | ||

44 | return utohexstr(Value, !Cap); | 56 | return utohexstr(Value.getUnsignedValue(), !Cap); | ||

45 | return utostr(Value); | 57 | if (Signed) | ||

58 | return itostr(Value.getSignedValue()); | ||||

59 | return utostr(Value.getUnsignedValue()); | ||||

46 | } | 60 | } | ||

47 | 61 | | |||

48 | Expected<uint64_t> | 62 | Expected<FileCheckExpressionValue> | ||

49 | FileCheckExpressionFormat::valueFromStringRepr(StringRef StrVal, | 63 | FileCheckExpressionFormat::valueFromStringRepr(StringRef StrVal, | ||

50 | const SourceMgr &SM) const { | 64 | const SourceMgr &SM) const { | ||

51 | unsigned Radix = Hex ? 16 : 10; | 65 | unsigned Radix = Hex ? 16 : 10; | ||

52 | uint64_t Value; | 66 | if (Signed) { | ||

67 | int64_t SignedValue; | ||||

68 | | ||||

69 | if (StrVal.getAsInteger(Radix, SignedValue)) | ||||

70 | return FileCheckErrorDiagnostic::get(SM, StrVal, | ||||

71 | "Unable to represent numeric value"); | ||||

72 | | ||||

73 | return FileCheckExpressionValue(SignedValue); | ||||

74 | } else { | ||||

75 | uint64_t UnsignedValue; | ||||

53 | 76 | | |||

54 | if (StrVal.getAsInteger(Radix, Value)) | 77 | if (StrVal.getAsInteger(Radix, UnsignedValue)) | ||

55 | return FileCheckErrorDiagnostic::get(SM, StrVal, | 78 | return FileCheckErrorDiagnostic::get(SM, StrVal, | ||

56 | "Unable to represent numeric value"); | 79 | "Unable to represent numeric value"); | ||

57 | 80 | | |||

58 | return Value; | 81 | return FileCheckExpressionValue(UnsignedValue); | ||

82 | } | ||||

83 | } | ||||

84 | | ||||

85 | bool FileCheckExpressionValue:: | ||||

86 | operator==(const FileCheckExpressionValue &other) { | ||||

87 | if (Signed) | ||||

88 | return SignedValue == other.SignedValue; | ||||

89 | else | ||||

90 | return UnsignedValue == other.UnsignedValue; | ||||

91 | } | ||||

92 | | ||||

93 | Error | ||||

94 | FileCheckExpressionValue::convertSigned() { | ||||

95 | if (Signed) | ||||

96 | return Error::success(); | ||||

97 | | ||||

98 | if (UnsignedValue > std::numeric_limits<int64_t>::max()) | ||||

99 | return make_error<FileCheckValueError>(ValOverflow); | ||||

100 | | ||||

101 | SignedValue = UnsignedValue; | ||||

102 | Signed = true; | ||||

103 | return Error::success(); | ||||

104 | } | ||||

105 | | ||||

106 | Error | ||||

107 | FileCheckExpressionValue::convertUnsigned() { | ||||

108 | if (!Signed) | ||||

109 | return Error::success(); | ||||

110 | | ||||

111 | if (SignedValue < 0) | ||||

112 | return make_error<FileCheckValueError>(ValOverflow); | ||||

113 | | ||||

114 | UnsignedValue = SignedValue; | ||||

115 | Signed = false; | ||||

116 | return Error::success(); | ||||

117 | } | ||||

118 | | ||||

119 | Expected<FileCheckExpressionValue> llvm:: | ||||

120 | operator+(const FileCheckExpressionValue &Op1, | ||||

121 | const FileCheckExpressionValue &Op2) { | ||||

122 | // Operands must have same sign. | ||||

123 | if (Op1.Signed != Op2.Signed) | ||||

124 | return make_error<FileCheckValueError>(ValPromotion); | ||||

125 | | ||||

126 | if (Op1.Signed) { | ||||

127 | int64_t Val1 = Op1.SignedValue; | ||||

128 | int64_t Val2 = Op2.SignedValue; | ||||

129 | | ||||

130 | // Op1 + Op2 > max int64_t. | ||||

131 | if (Val1 > 0 && Val2 > 0 && | ||||

arichardson: `llvm/include/llvm/Support/CheckedArithmetic.h` contains `llvm::checkedAdd`, `llvm::checkedSub`… | |||||

132 | Val1 > (std::numeric_limits<int64_t>::max() - Val2)) | ||||

133 | return make_error<FileCheckValueError>(ValOverflow); | ||||

134 | | ||||

135 | // Op1 + Op2 < min int64_t. | ||||

136 | if (Val1 < 0 && Val2 < 0 && | ||||

137 | Val1 < (std::numeric_limits<int64_t>::min() - Val2)) | ||||

138 | return make_error<FileCheckValueError>(ValOverflow); | ||||

139 | | ||||

140 | return FileCheckExpressionValue(Val1 + Val2); | ||||

141 | } else { | ||||

142 | uint64_t Val1 = Op1.UnsignedValue; | ||||

143 | uint64_t Val2 = Op2.UnsignedValue; | ||||

144 | | ||||

145 | // Op1 + Op2 > max uint64_t. | ||||

146 | if (Val1 > std::numeric_limits<uint64_t>::max() - Val2) | ||||

147 | return make_error<FileCheckValueError>(ValOverflow); | ||||

148 | | ||||

149 | return FileCheckExpressionValue(Val1 + Val2); | ||||

150 | } | ||||

151 | } | ||||

152 | | ||||

153 | Expected<FileCheckExpressionValue> llvm:: | ||||

154 | operator-(const FileCheckExpressionValue &Op1, | ||||

155 | const FileCheckExpressionValue &Op2) { | ||||

156 | // Operands must have same sign. | ||||

157 | if (Op1.Signed != Op2.Signed) | ||||

158 | return make_error<FileCheckValueError>(ValPromotion); | ||||

159 | | ||||

160 | if (Op1.Signed) { | ||||

161 | int64_t Val1 = Op1.SignedValue; | ||||

162 | int64_t Val2 = Op2.SignedValue; | ||||

163 | | ||||

164 | // Op1 - Op2 > max int64_t. | ||||

165 | if (Val1 > 0 && Val2 < 0 && | ||||

166 | Val1 > (std::numeric_limits<int64_t>::max() + Val2)) | ||||

167 | return make_error<FileCheckValueError>(ValOverflow); | ||||

168 | | ||||

169 | // Op1 - Op2 < min int64_t. | ||||

170 | if (Val1 < 0 && Val2 > 0 && | ||||

171 | Val1 < (std::numeric_limits<int64_t>::min() + Val2)) | ||||

172 | return make_error<FileCheckValueError>(ValOverflow); | ||||

173 | | ||||

174 | return FileCheckExpressionValue(Val1 - Val2); | ||||

175 | } else { | ||||

176 | uint64_t Val1 = Op1.UnsignedValue; | ||||

177 | uint64_t Val2 = Op2.UnsignedValue; | ||||

178 | | ||||

179 | // Op1 < Op2. | ||||

180 | if (Val1 < Val2) | ||||

181 | return make_error<FileCheckValueError>(ValOverflow); | ||||

182 | return FileCheckExpressionValue(Val1 - Val2); | ||||

183 | } | ||||

59 | } | 184 | } | ||

60 | 185 | | |||

61 | FileCheckExpression::FileCheckExpression( | 186 | FileCheckExpression::FileCheckExpression( | ||

62 | std::shared_ptr<FileCheckExpressionAST> AST, | 187 | std::shared_ptr<FileCheckExpressionAST> AST, | ||

63 | FileCheckExpressionFormat Format) | 188 | FileCheckExpressionFormat Format) | ||

64 | : AST(AST) { | 189 | : AST(AST) { | ||

65 | this->Format = Format.Valid ? Format : FormatUnsigned; | 190 | this->Format = Format.Valid ? Format : FormatUnsigned; | ||

66 | } | 191 | } | ||

67 | 192 | | |||

68 | Expected<uint64_t> FileCheckNumericVariable::eval() const { | 193 | Expected<FileCheckExpressionValue> FileCheckNumericVariable::eval() const { | ||

69 | if (Value) | 194 | if (Value) | ||

70 | return *Value; | 195 | return *Value; | ||

71 | 196 | | |||

72 | if (Expression == nullptr || Expression->getAST() == nullptr) | 197 | if (Expression == nullptr || Expression->getAST() == nullptr) | ||

73 | return make_error<FileCheckUndefVarError>(Name); | 198 | return make_error<FileCheckUndefVarError>(Name); | ||

74 | 199 | | |||

75 | return Expression->getAST()->eval(); | 200 | return Expression->getAST()->eval(); | ||

76 | } | 201 | } | ||

77 | 202 | | |||

78 | bool FileCheckNumericVariable::isMatchTimeKnown() const { | 203 | bool FileCheckNumericVariable::isMatchTimeKnown() const { | ||

79 | if (Value) | 204 | if (Value) | ||

80 | return true; | 205 | return true; | ||

81 | 206 | | |||

82 | return Expression != nullptr && Expression->getAST() != nullptr; | 207 | return Expression != nullptr && Expression->getAST() != nullptr; | ||

83 | } | 208 | } | ||

Not Done ReplyThis is fine for the initial version of the patch, but I think in the future it will be useful to permit adding an unsigned variable to a signed one, etc. as long as the result is still within the representable range. arichardson: This is fine for the initial version of the patch, but I think in the future it will be useful… | |||||

84 | 209 | | |||

85 | FileCheckExpressionFormat FileCheckNumericVariable::getImplicitFormat() const { | 210 | FileCheckExpressionFormat FileCheckNumericVariable::getImplicitFormat() const { | ||

86 | return Expression ? Expression->getEffectiveFormat() : FormatNone; | 211 | return Expression ? Expression->getEffectiveFormat() : FormatNone; | ||

87 | } | 212 | } | ||

88 | 213 | | |||

89 | bool FileCheckNumericVariable::setValue(uint64_t NewValue) { | 214 | bool FileCheckNumericVariable::setValue(FileCheckExpressionValue NewValue) { | ||

90 | if (Value) | 215 | if (Value) | ||

91 | return true; | 216 | return true; | ||

92 | if (Expression != nullptr && Expression->getAST() != nullptr) { | 217 | if (Expression != nullptr && Expression->getAST() != nullptr) { | ||

93 | Expected<uint64_t> EvaluatedValue = Expression->getAST()->eval(); | 218 | Expected<FileCheckExpressionValue> EvaluatedValue = | ||

219 | Expression->getAST()->eval(); | ||||

94 | if (!EvaluatedValue || *EvaluatedValue != NewValue) | 220 | if (!EvaluatedValue || *EvaluatedValue != NewValue) | ||

95 | return true; | 221 | return true; | ||

96 | } | 222 | } | ||

97 | Value = NewValue; | 223 | Value = NewValue; | ||

98 | return false; | 224 | return false; | ||

99 | } | 225 | } | ||

100 | 226 | | |||

101 | bool FileCheckNumericVariable::clearValue() { | 227 | bool FileCheckNumericVariable::clearValue() { | ||

102 | if (!Value) | 228 | if (!Value) | ||

103 | return true; | 229 | return true; | ||

104 | Value = None; | 230 | Value = None; | ||

105 | Expression = nullptr; | 231 | Expression = nullptr; | ||

106 | return false; | 232 | return false; | ||

107 | } | 233 | } | ||

108 | 234 | | |||

109 | Expected<uint64_t> FileCheckASTBinop::eval() const { | 235 | Expected<FileCheckExpressionValue> FileCheckASTBinop::eval() const { | ||

110 | Expected<uint64_t> LeftOp = this->LeftOp->eval(); | 236 | Expected<FileCheckExpressionValue> LeftOp = this->LeftOp->eval(); | ||

111 | Expected<uint64_t> RightOp = this->RightOp->eval(); | 237 | Expected<FileCheckExpressionValue> RightOp = this->RightOp->eval(); | ||

112 | 238 | | |||

113 | // Uses undefined variable(s). | 239 | // Uses undefined variable(s). | ||

114 | if (!LeftOp || !RightOp) { | 240 | if (!LeftOp || !RightOp) { | ||

115 | Error Err = Error::success(); | 241 | Error Err = Error::success(); | ||

116 | if (!LeftOp) | 242 | if (!LeftOp) | ||

117 | Err = joinErrors(std::move(Err), LeftOp.takeError()); | 243 | Err = joinErrors(std::move(Err), LeftOp.takeError()); | ||

118 | if (!RightOp) | 244 | if (!RightOp) | ||

119 | Err = joinErrors(std::move(Err), RightOp.takeError()); | 245 | Err = joinErrors(std::move(Err), RightOp.takeError()); | ||

120 | return std::move(Err); | 246 | return std::move(Err); | ||

121 | } | 247 | } | ||

122 | 248 | | |||

123 | return EvalBinop(*LeftOp, *RightOp); | 249 | // Integer promotion. | ||

250 | FileCheckExpressionValue LeftValue = *LeftOp; | ||||

251 | FileCheckExpressionValue RightValue = *RightOp; | ||||

252 | if (!LeftValue.isSigned() || !RightValue.isSigned()) { | ||||

Not Done ReplyI'm not sure if this is necessary but I feel like it may be useful to permit adding a signed (negative value) to an unsigned value as long as the result is >= 0. Maybe these checks should move into operator+/-? arichardson: I'm not sure if this is necessary but I feel like it may be useful to permit adding a signed… | |||||

253 | Error ConvError = LeftValue.convertUnsigned(); | ||||

254 | if (ConvError) | ||||

255 | return std::move(ConvError); | ||||

256 | ConvError = RightValue.convertUnsigned(); | ||||

257 | if (ConvError) | ||||

258 | return std::move(ConvError); | ||||

259 | } | ||||

260 | | ||||

261 | return EvalBinop(LeftValue, RightValue); | ||||

124 | } | 262 | } | ||

125 | 263 | | |||

126 | FileCheckExpressionFormat FileCheckASTBinop::getImplicitFormat() const { | 264 | FileCheckExpressionFormat FileCheckASTBinop::getImplicitFormat() const { | ||

127 | FileCheckExpressionFormat LeftFormat = LeftOp->getImplicitFormat(); | 265 | FileCheckExpressionFormat LeftFormat = LeftOp->getImplicitFormat(); | ||

128 | FileCheckExpressionFormat RightFormat = RightOp->getImplicitFormat(); | 266 | FileCheckExpressionFormat RightFormat = RightOp->getImplicitFormat(); | ||

129 | 267 | | |||

130 | FileCheckExpressionFormat Format = | 268 | FileCheckExpressionFormat Format = | ||

131 | (LeftFormat.Valid) ? LeftFormat : RightFormat; | 269 | (LeftFormat.Valid) ? LeftFormat : RightFormat; | ||

132 | if (LeftFormat.Valid && RightFormat.Valid && LeftFormat != RightFormat) | 270 | if (LeftFormat.Valid && RightFormat.Valid && LeftFormat != RightFormat) | ||

133 | Format.Conflict = 1; | 271 | Format.Conflict = 1; | ||

134 | 272 | | |||

135 | return Format; | 273 | return Format; | ||

136 | } | 274 | } | ||

137 | 275 | | |||

138 | Expected<std::string> FileCheckNumericSubstitution::getResult() const { | 276 | Expected<std::string> FileCheckNumericSubstitution::getResult() const { | ||

139 | assert(Expression->getAST() != nullptr && "Substituting empty expression"); | 277 | assert(Expression->getAST() != nullptr && "Substituting empty expression"); | ||

140 | Expected<uint64_t> EvaluatedValue = Expression->getAST()->eval(); | 278 | Expected<FileCheckExpressionValue> EvaluatedValue = | ||

279 | Expression->getAST()->eval(); | ||||

141 | if (!EvaluatedValue) | 280 | if (!EvaluatedValue) | ||

142 | return EvaluatedValue.takeError(); | 281 | return EvaluatedValue.takeError(); | ||

143 | FileCheckExpressionFormat Format = Expression->getEffectiveFormat(); | 282 | FileCheckExpressionFormat Format = Expression->getEffectiveFormat(); | ||

144 | return Format.getMatchingString(*EvaluatedValue); | 283 | return Format.getMatchingString(*EvaluatedValue); | ||

145 | } | 284 | } | ||

146 | 285 | | |||

147 | Expected<std::string> FileCheckStringSubstitution::getResult() const { | 286 | Expected<std::string> FileCheckStringSubstitution::getResult() const { | ||

148 | // Look up the value and escape it so that we can put it into the regex. | 287 | // Look up the value and escape it so that we can put it into the regex. | ||

▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Line(s) | |||||

197 | 336 | | |||

198 | // Parsing helper function that strips the first character in S and returns it. | 337 | // Parsing helper function that strips the first character in S and returns it. | ||

199 | static char popFront(StringRef &S) { | 338 | static char popFront(StringRef &S) { | ||

200 | char C = S.front(); | 339 | char C = S.front(); | ||

201 | S = S.drop_front(); | 340 | S = S.drop_front(); | ||

202 | return C; | 341 | return C; | ||

203 | } | 342 | } | ||

204 | 343 | | |||

344 | char FileCheckValueError::ID = 0; | ||||

205 | char FileCheckUndefVarError::ID = 0; | 345 | char FileCheckUndefVarError::ID = 0; | ||

206 | char FileCheckErrorDiagnostic::ID = 0; | 346 | char FileCheckErrorDiagnostic::ID = 0; | ||

207 | char FileCheckNotFoundError::ID = 0; | 347 | char FileCheckNotFoundError::ID = 0; | ||

208 | 348 | | |||

209 | Error FileCheckPattern::parseNumericVariableDefinition( | 349 | Error FileCheckPattern::parseNumericVariableDefinition( | ||

210 | StringRef &Expr, StringRef &Name, FileCheckPatternContext *Context, | 350 | StringRef &Expr, StringRef &Name, FileCheckPatternContext *Context, | ||

211 | const SourceMgr &SM) { | 351 | const SourceMgr &SM) { | ||

212 | bool IsPseudo; | 352 | bool IsPseudo; | ||

▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Line(s) | 410 | if (AO == LineVar || AO == Any) { | |||

278 | if (AO == LineVar) | 418 | if (AO == LineVar) | ||

279 | return ParseVarResult.takeError(); | 419 | return ParseVarResult.takeError(); | ||

280 | // Ignore the error and retry parsing as a literal. | 420 | // Ignore the error and retry parsing as a literal. | ||

281 | consumeError(ParseVarResult.takeError()); | 421 | consumeError(ParseVarResult.takeError()); | ||

282 | } | 422 | } | ||

283 | 423 | | |||

284 | // Otherwise, parse it as a literal. | 424 | // Otherwise, parse it as a literal. | ||

285 | unsigned Radix = (AO == Literal) ? 10 : 0; | 425 | unsigned Radix = (AO == Literal) ? 10 : 0; | ||

286 | uint64_t LiteralValue; | 426 | int64_t SignedLiteralValue; | ||

287 | if (!Expr.consumeInteger(Radix, LiteralValue)) | 427 | uint64_t UnsignedLiteralValue; | ||

288 | return std::make_shared<FileCheckExpressionLiteral>(LiteralValue); | 428 | StringRef SaveExpr = Expr; | ||

429 | // Accept both signed and unsigned literal. | ||||

430 | if (AO == Any && !Expr.consumeInteger(Radix, SignedLiteralValue)) | ||||

431 | return std::make_shared<FileCheckExpressionLiteral>(SignedLiteralValue); | ||||

432 | Expr = SaveExpr; | ||||

433 | if (!Expr.consumeInteger(Radix, UnsignedLiteralValue)) | ||||

434 | return std::make_shared<FileCheckExpressionLiteral>(UnsignedLiteralValue); | ||||

289 | 435 | | |||

290 | return FileCheckErrorDiagnostic::get(SM, Expr, | 436 | return FileCheckErrorDiagnostic::get(SM, Expr, | ||

291 | "invalid operand format '" + Expr + "'"); | 437 | "invalid operand format '" + Expr + "'"); | ||

292 | } | 438 | } | ||

293 | 439 | | |||

294 | static uint64_t add(uint64_t LeftOp, uint64_t RightOp) { | | |||

295 | return LeftOp + RightOp; | | |||

296 | } | | |||

297 | | ||||

298 | static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) { | | |||

299 | return LeftOp - RightOp; | | |||

300 | } | | |||

301 | | ||||

302 | Expected<std::shared_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop( | 440 | Expected<std::shared_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop( | ||

303 | StringRef &Expr, std::shared_ptr<FileCheckExpressionAST> LeftOp, | 441 | StringRef &Expr, std::shared_ptr<FileCheckExpressionAST> LeftOp, | ||

304 | bool LegacyLineExpr, size_t LineNumber, FileCheckPatternContext *Context, | 442 | bool LegacyLineExpr, size_t LineNumber, FileCheckPatternContext *Context, | ||

305 | const SourceMgr &SM) { | 443 | const SourceMgr &SM) { | ||

306 | Expr = Expr.ltrim(SpaceChars); | 444 | Expr = Expr.ltrim(SpaceChars); | ||

307 | if (Expr.empty()) | 445 | if (Expr.empty()) | ||

308 | return LeftOp; | 446 | return LeftOp; | ||

309 | 447 | | |||

310 | // Check if this is a supported operation and select a function to perform | 448 | // Check if this is a supported operation and select a function to perform | ||

311 | // it. | 449 | // it. | ||

312 | SMLoc OpLoc = SMLoc::getFromPointer(Expr.data()); | 450 | SMLoc OpLoc = SMLoc::getFromPointer(Expr.data()); | ||

313 | char Operator = popFront(Expr); | 451 | char Operator = popFront(Expr); | ||

314 | binop_eval_t EvalBinop; | 452 | binop_eval_t EvalBinop; | ||

315 | switch (Operator) { | 453 | switch (Operator) { | ||

316 | case '+': | 454 | case '+': | ||

317 | EvalBinop = add; | 455 | EvalBinop = operator+; | ||

318 | break; | 456 | break; | ||

319 | case '-': | 457 | case '-': | ||

320 | EvalBinop = sub; | 458 | EvalBinop = operator-; | ||

321 | break; | 459 | break; | ||

322 | default: | 460 | default: | ||

323 | return FileCheckErrorDiagnostic::get( | 461 | return FileCheckErrorDiagnostic::get( | ||

324 | SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'"); | 462 | SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'"); | ||

325 | } | 463 | } | ||

326 | 464 | | |||

327 | // Parse right operand. | 465 | // Parse right operand. | ||

328 | Expr = Expr.ltrim(SpaceChars); | 466 | Expr = Expr.ltrim(SpaceChars); | ||

Show All 32 Lines | 494 | if (FormatSpecEnd != StringRef::npos) { | |||

361 | 499 | | |||

362 | // Check for unknown matching format specifier and set matching format in | 500 | // Check for unknown matching format specifier and set matching format in | ||

363 | // class instance representing this expression. | 501 | // class instance representing this expression. | ||

364 | SMLoc fmtloc = SMLoc::getFromPointer(Expr.data()); | 502 | SMLoc fmtloc = SMLoc::getFromPointer(Expr.data()); | ||

365 | switch (popFront(Expr)) { | 503 | switch (popFront(Expr)) { | ||

366 | case 'u': | 504 | case 'u': | ||

367 | ExplicitFormat = FormatUnsigned; | 505 | ExplicitFormat = FormatUnsigned; | ||

368 | break; | 506 | break; | ||

507 | case 'd': | ||||

508 | ExplicitFormat = FormatSigned; | ||||

509 | break; | ||||

369 | case 'x': | 510 | case 'x': | ||

370 | ExplicitFormat = FormatLowHex; | 511 | ExplicitFormat = FormatLowHex; | ||

371 | break; | 512 | break; | ||

372 | case 'X': | 513 | case 'X': | ||

373 | ExplicitFormat = FormatCapHex; | 514 | ExplicitFormat = FormatCapHex; | ||

374 | break; | 515 | break; | ||

375 | default: | 516 | default: | ||

376 | return FileCheckErrorDiagnostic::get( | 517 | return FileCheckErrorDiagnostic::get( | ||

▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Line(s) | 594 | bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix, | |||

455 | const FileCheckRequest &Req) { | 596 | const FileCheckRequest &Req) { | ||

456 | bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; | 597 | bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; | ||

457 | 598 | | |||

458 | PatternLoc = SMLoc::getFromPointer(PatternStr.data()); | 599 | PatternLoc = SMLoc::getFromPointer(PatternStr.data()); | ||

459 | 600 | | |||

460 | // Create fake @LINE pseudo variable definition. | 601 | // Create fake @LINE pseudo variable definition. | ||

461 | StringRef LinePseudo = "@LINE"; | 602 | StringRef LinePseudo = "@LINE"; | ||

462 | uint64_t LineNumber64 = LineNumber; | 603 | uint64_t LineNumber64 = LineNumber; | ||

604 | auto LineNumberVal = FileCheckExpressionValue(LineNumber64); | ||||

463 | std::shared_ptr<FileCheckNumericVariable> LinePseudoVar = | 605 | std::shared_ptr<FileCheckNumericVariable> LinePseudoVar = | ||

464 | std::make_shared<FileCheckNumericVariable>(LinePseudo, LineNumber64); | 606 | std::make_shared<FileCheckNumericVariable>(LinePseudo, LineNumberVal); | ||

465 | Context->GlobalNumericVariableTable[LinePseudo] = LinePseudoVar; | 607 | Context->GlobalNumericVariableTable[LinePseudo] = LinePseudoVar; | ||

466 | 608 | | |||

467 | if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) | 609 | if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) | ||

468 | // Ignore trailing whitespace. | 610 | // Ignore trailing whitespace. | ||

469 | while (!PatternStr.empty() && | 611 | while (!PatternStr.empty() && | ||

470 | (PatternStr.back() == ' ' || PatternStr.back() == '\t')) | 612 | (PatternStr.back() == ' ' || PatternStr.back() == '\t')) | ||

471 | PatternStr = PatternStr.substr(0, PatternStr.size() - 1); | 613 | PatternStr = PatternStr.substr(0, PatternStr.size() - 1); | ||

472 | 614 | | |||

▲ Show 20 Lines • Show All 304 Lines • ▼ Show 20 Line(s) | 917 | if (!Substitutions.empty()) { | |||

777 | 919 | | |||

778 | size_t InsertOffset = 0; | 920 | size_t InsertOffset = 0; | ||

779 | // Substitute all string variables and expressions whose values are only | 921 | // Substitute all string variables and expressions whose values are only | ||

780 | // now known. Use of string variables defined on the same line are handled | 922 | // now known. Use of string variables defined on the same line are handled | ||

781 | // by back-references. | 923 | // by back-references. | ||

782 | for (const auto &Substitution : Substitutions) { | 924 | for (const auto &Substitution : Substitutions) { | ||

783 | // Substitute and check for failure (e.g. use of undefined variable). | 925 | // Substitute and check for failure (e.g. use of undefined variable). | ||

784 | Expected<std::string> Value = Substitution->getResult(); | 926 | Expected<std::string> Value = Substitution->getResult(); | ||

785 | if (!Value) | 927 | if (!Value) { | ||

786 | return Value.takeError(); | 928 | Error Err = | ||

929 | handleErrors(Value.takeError(), [&](const FileCheckValueError &E) { | ||||

930 | switch (E.getType()) { | ||||

931 | case ValOverflow: | ||||

932 | case ValPromotion: | ||||

933 | return FileCheckErrorDiagnostic::get( | ||||

934 | SM, Substitution->getFromString(), | ||||

935 | Twine("Unable to substitute variable or numeric " | ||||

936 | "expression: ") + | ||||

937 | E.getMsg()); | ||||

938 | default: | ||||

939 | llvm_unreachable("Unexpected value error"); | ||||

940 | } | ||||

941 | }); | ||||

942 | return std::move(Err); | ||||

943 | } | ||||

787 | 944 | | |||

788 | // Plop it into the regex at the adjusted offset. | 945 | // Plop it into the regex at the adjusted offset. | ||

789 | TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset, | 946 | TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset, | ||

790 | Value->begin(), Value->end()); | 947 | Value->begin(), Value->end()); | ||

791 | InsertOffset += Value->size(); | 948 | InsertOffset += Value->size(); | ||

792 | } | 949 | } | ||

793 | 950 | | |||

794 | // Match the newly constructed regex. | 951 | // Match the newly constructed regex. | ||

Show All 23 Lines | 971 | for (const auto &NumericVariableDef : NumericVariableDefs) { | |||

818 | assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error"); | 975 | assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error"); | ||

819 | FileCheckNumericVariable *DefinedNumericVariable = | 976 | FileCheckNumericVariable *DefinedNumericVariable = | ||

820 | NumericVariableMatch.DefinedNumericVariable; | 977 | NumericVariableMatch.DefinedNumericVariable; | ||

821 | 978 | | |||

822 | StringRef MatchedValue = MatchInfo[CaptureParenGroup]; | 979 | StringRef MatchedValue = MatchInfo[CaptureParenGroup]; | ||

823 | assert(DefinedNumericVariable->getExpression() != nullptr); | 980 | assert(DefinedNumericVariable->getExpression() != nullptr); | ||

824 | FileCheckExpressionFormat Format = | 981 | FileCheckExpressionFormat Format = | ||

825 | DefinedNumericVariable->getExpression()->getEffectiveFormat(); | 982 | DefinedNumericVariable->getExpression()->getEffectiveFormat(); | ||

826 | Expected<uint64_t> Value = Format.valueFromStringRepr(MatchedValue, SM); | 983 | Expected<FileCheckExpressionValue> Value = | ||

984 | Format.valueFromStringRepr(MatchedValue, SM); | ||||

827 | if (!Value) | 985 | if (!Value) | ||

828 | return Value.takeError(); | 986 | return Value.takeError(); | ||

829 | if (DefinedNumericVariable->setValue(*Value)) | 987 | if (DefinedNumericVariable->setValue(*Value)) | ||

830 | llvm_unreachable("Numeric variable redefined"); | 988 | llvm_unreachable("Numeric variable redefined"); | ||

831 | } | 989 | } | ||

832 | 990 | | |||

833 | // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after | 991 | // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after | ||

834 | // the required preceding newline, which is consumed by the pattern in the | 992 | // the required preceding newline, which is consumed by the pattern in the | ||

Show All 32 Lines | 1020 | for (const auto &Substitution : Substitutions) { | |||

867 | // Substitution failed or is not known at match time, print the undefined | 1025 | // Substitution failed or is not known at match time, print the undefined | ||

868 | // variables it uses. | 1026 | // variables it uses. | ||

869 | if (!MatchedValue) { | 1027 | if (!MatchedValue) { | ||

870 | bool UndefSeen = false; | 1028 | bool UndefSeen = false; | ||

871 | handleAllErrors(MatchedValue.takeError(), | 1029 | handleAllErrors(MatchedValue.takeError(), | ||

872 | [](const FileCheckNotFoundError &E) {}, | 1030 | [](const FileCheckNotFoundError &E) {}, | ||

873 | // Handled in PrintNoMatch() | 1031 | // Handled in PrintNoMatch() | ||

874 | [](const FileCheckErrorDiagnostic &E) {}, | 1032 | [](const FileCheckErrorDiagnostic &E) {}, | ||

1033 | [](const FileCheckValueError &E) { | ||||

1034 | switch (E.getType()) { | ||||

1035 | case ValOverflow: | ||||

1036 | case ValPromotion: | ||||

1037 | case ValStringConversion: | ||||

1038 | // handled in match() | ||||

1039 | break; | ||||

1040 | } | ||||

1041 | }, | ||||

875 | [&](const FileCheckUndefVarError &E) { | 1042 | [&](const FileCheckUndefVarError &E) { | ||

876 | if (!UndefSeen) { | 1043 | if (!UndefSeen) { | ||

877 | OS << "uses undefined variable(s):"; | 1044 | OS << "uses undefined variable(s):"; | ||

878 | UndefSeen = true; | 1045 | UndefSeen = true; | ||

879 | } | 1046 | } | ||

880 | OS << " "; | 1047 | OS << " "; | ||

881 | E.log(OS); | 1048 | E.log(OS); | ||

882 | }, | | |||

883 | [](const ErrorInfoBase &E) { | | |||

884 | llvm_unreachable("Unexpected error"); | | |||

885 | }); | 1049 | }); | ||

886 | } else { | 1050 | } else { | ||

887 | // Substitution succeeded. Print substituted value. | 1051 | // Substitution succeeded. Print substituted value. | ||

888 | OS << "with \""; | 1052 | OS << "with \""; | ||

889 | OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; | 1053 | OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; | ||

890 | OS.write_escaped(*MatchedValue) << "\""; | 1054 | OS.write_escaped(*MatchedValue) << "\""; | ||

891 | } | 1055 | } | ||

892 | 1056 | | |||

▲ Show 20 Lines • Show All 1071 Lines • ▼ Show 20 Line(s) | 2123 | if (CmdlineDef[0] == '#') { | |||

1964 | Expected<FileCheckExpression *> ExpressionResult = | 2128 | Expected<FileCheckExpression *> ExpressionResult = | ||

1965 | FileCheckPattern::parseNumericSubstitutionBlock( | 2129 | FileCheckPattern::parseNumericSubstitutionBlock( | ||

1966 | CmdlineDefExpr, DefinedNumericVariable, false, 0, this, SM); | 2130 | CmdlineDefExpr, DefinedNumericVariable, false, 0, this, SM); | ||

1967 | if (!ExpressionResult) { | 2131 | if (!ExpressionResult) { | ||

1968 | Errs = joinErrors(std::move(Errs), ExpressionResult.takeError()); | 2132 | Errs = joinErrors(std::move(Errs), ExpressionResult.takeError()); | ||

1969 | continue; | 2133 | continue; | ||

1970 | } | 2134 | } | ||

1971 | FileCheckExpression *Expression = *ExpressionResult; | 2135 | FileCheckExpression *Expression = *ExpressionResult; | ||

1972 | Expected<uint64_t> Value = Expression->getAST()->eval(); | 2136 | Expected<FileCheckExpressionValue> Value = Expression->getAST()->eval(); | ||

1973 | if (!Value) { | 2137 | if (!Value) { | ||

1974 | Errs = joinErrors(std::move(Errs), Value.takeError()); | 2138 | Errs = joinErrors(std::move(Errs), Value.takeError()); | ||

1975 | continue; | 2139 | continue; | ||

1976 | } | 2140 | } | ||

1977 | (*DefinedNumericVariable)->setValue(*Value); | 2141 | (*DefinedNumericVariable)->setValue(*Value); | ||

1978 | 2142 | | |||

1979 | // Record this variable definition. | 2143 | // Record this variable definition. | ||

1980 | GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] = | 2144 | GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] = | ||

▲ Show 20 Lines • Show All 135 Lines • Show Last 20 Lines |

llvm/include/llvm/Support/CheckedArithmetic.hcontainsllvm::checkedAdd,llvm::checkedSub,llvm::checkedAddUnsignedandllvm::checkedSubUnsigned, which should make this code much simpler.