diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp --- a/llvm/lib/FileCheck/FileCheck.cpp +++ b/llvm/lib/FileCheck/FileCheck.cpp @@ -80,16 +80,8 @@ Expected ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const { APInt IntValue = IntegerValue.getAPIntValue(); - // Error out for values that cannot be represented by the appropriate 64-bit - // integer (e.g. int64_t for a signed format) to keep the getter of - // ExpressionValue as an APInt an NFC. - if (Value == Kind::Signed) { - if (!IntValue.isSignedIntN(64)) - return make_error(); - } else { - if (!IntValue.isIntN(64)) - return make_error(); - } + if (Value != Kind::Signed && IntValue.isNegative()) + return make_error(); unsigned Radix; bool UpperCase = false; @@ -129,6 +121,20 @@ .str(); } +static unsigned nextAPIntBitWidth(unsigned BitWidth) { + return (BitWidth < APInt::APINT_BITS_PER_WORD) ? APInt::APINT_BITS_PER_WORD + : BitWidth * 2; +} + +static APInt toSigned(APInt AbsVal, bool Negative) { + if (AbsVal.isSignBitSet()) + AbsVal = AbsVal.zext(nextAPIntBitWidth(AbsVal.getBitWidth())); + APInt Result = AbsVal; + if (Negative) + Result.negate(); + return Result; +} + Expected ExpressionFormat::valueFromStringRepr(StringRef StrVal, const SourceMgr &SM) const { @@ -138,101 +144,70 @@ // getWildcardRegex() above. Only underflow and overflow errors can thus // occur. However new uses of this method could be added in the future so // the error message does not make assumptions about StrVal. - StringRef IntegerParseErrorStr = "unable to represent numeric value"; - if (ValueIsSigned) { - int64_t SignedValue; - - if (StrVal.getAsInteger(10, SignedValue)) - return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr); - - return ExpressionValue(SignedValue); - } - + bool Negative = StrVal.consume_front("-"); bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower; - uint64_t UnsignedValue; - bool MissingFormPrefix = AlternateForm && !StrVal.consume_front("0x"); + bool MissingFormPrefix = + !ValueIsSigned && AlternateForm && !StrVal.consume_front("0x"); (void)MissingFormPrefix; assert(!MissingFormPrefix && "missing alternate form prefix"); - if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue)) - return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr); - - return ExpressionValue(UnsignedValue); + APInt ResultValue; + bool ParseFailure = StrVal.getAsInteger(Hex ? 16 : 10, ResultValue); + if (ParseFailure) + return ErrorDiagnostic::get(SM, StrVal, + "unable to represent numeric value"); + return ExpressionValue(toSigned(ResultValue, Negative)); } -Expected llvm::operator+(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - bool Overflow; +Expected llvm::exprAdd(const ExpressionValue &LeftOperand, + const ExpressionValue &RightOperand, + bool &Overflow) { APInt Result = LeftOperand.getAPIntValue().sadd_ov( RightOperand.getAPIntValue(), Overflow); - if (Overflow || - (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1))) - return make_error(); - - if (Result.isNegative()) - return ExpressionValue(Result.getSExtValue()); - else - return ExpressionValue(Result.getZExtValue()); + return ExpressionValue(Result); } -Expected llvm::operator-(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - bool Overflow; +Expected llvm::exprSub(const ExpressionValue &LeftOperand, + const ExpressionValue &RightOperand, + bool &Overflow) { APInt Result = LeftOperand.getAPIntValue().ssub_ov( RightOperand.getAPIntValue(), Overflow); - if (Overflow || - (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1))) - return make_error(); - - if (Result.isNegative()) - return ExpressionValue(Result.getSExtValue()); - else - return ExpressionValue(Result.getZExtValue()); + return ExpressionValue(Result); } -Expected llvm::operator*(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - bool Overflow; +Expected llvm::exprMul(const ExpressionValue &LeftOperand, + const ExpressionValue &RightOperand, + bool &Overflow) { APInt Result = LeftOperand.getAPIntValue().smul_ov( RightOperand.getAPIntValue(), Overflow); - if (Overflow || - (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1))) - return make_error(); - - if (Result.isNegative()) - return ExpressionValue(Result.getSExtValue()); - else - return ExpressionValue(Result.getZExtValue()); + return ExpressionValue(Result); } -Expected llvm::operator/(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { +Expected llvm::exprDiv(const ExpressionValue &LeftOperand, + const ExpressionValue &RightOperand, + bool &Overflow) { // Check for division by zero. if (RightOperand.getAPIntValue().isZero()) return make_error(); - bool Overflow; APInt Result = LeftOperand.getAPIntValue().sdiv_ov( RightOperand.getAPIntValue(), Overflow); - if (Overflow || - (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1))) - return make_error(); - - if (Result.isNegative()) - return ExpressionValue(Result.getSExtValue()); - else - return ExpressionValue(Result.getZExtValue()); + return ExpressionValue(Result); } -Expected llvm::max(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { +Expected llvm::exprMax(const ExpressionValue &LeftOperand, + const ExpressionValue &RightOperand, + bool &Overflow) { + Overflow = false; return LeftOperand.getAPIntValue().slt(RightOperand.getAPIntValue()) ? RightOperand : LeftOperand; } -Expected llvm::min(const ExpressionValue &LeftOperand, - const ExpressionValue &RightOperand) { - if (cantFail(max(LeftOperand, RightOperand)).getAPIntValue() == +Expected llvm::exprMin(const ExpressionValue &LeftOperand, + const ExpressionValue &RightOperand, + bool &Overflow) { + Overflow = false; + if (cantFail(exprMax(LeftOperand, RightOperand, Overflow)).getAPIntValue() == LeftOperand.getAPIntValue()) return RightOperand; @@ -248,21 +223,42 @@ } Expected BinaryOperation::eval() const { - Expected LeftOp = LeftOperand->eval(); - Expected RightOp = RightOperand->eval(); + Expected MaybeLeftOp = LeftOperand->eval(); + Expected MaybeRightOp = RightOperand->eval(); // Bubble up any error (e.g. undefined variables) in the recursive // evaluation. - if (!LeftOp || !RightOp) { + if (!MaybeLeftOp || !MaybeRightOp) { Error Err = Error::success(); - if (!LeftOp) - Err = joinErrors(std::move(Err), LeftOp.takeError()); - if (!RightOp) - Err = joinErrors(std::move(Err), RightOp.takeError()); + if (!MaybeLeftOp) + Err = joinErrors(std::move(Err), MaybeLeftOp.takeError()); + if (!MaybeRightOp) + Err = joinErrors(std::move(Err), MaybeRightOp.takeError()); return std::move(Err); } - return EvalBinop(*LeftOp, *RightOp); + APInt LeftOp = MaybeLeftOp->getAPIntValue(); + APInt RightOp = MaybeRightOp->getAPIntValue(); + bool Overflow; + // Ensure both operands have the same bitwidth. + unsigned LeftBitWidth = LeftOp.getBitWidth(); + unsigned RightBitWidth = RightOp.getBitWidth(); + unsigned NewBitWidth = std::max(LeftBitWidth, RightBitWidth); + LeftOp = LeftOp.sext(NewBitWidth); + RightOp = RightOp.sext(NewBitWidth); + do { + Expected MaybeResult = + EvalBinop(ExpressionValue(LeftOp), ExpressionValue(RightOp), Overflow); + if (!MaybeResult) + return MaybeResult.takeError(); + + if (!Overflow) + return MaybeResult; + + NewBitWidth = nextAPIntBitWidth(NewBitWidth); + LeftOp = LeftOp.sext(NewBitWidth); + RightOp = RightOp.sext(NewBitWidth); + } while (true); } Expected @@ -466,21 +462,17 @@ } // Otherwise, parse it as a literal. - int64_t SignedLiteralValue; - uint64_t UnsignedLiteralValue; + APInt LiteralValue; StringRef SaveExpr = Expr; - // Accept both signed and unsigned literal, default to signed literal. + bool Negative = Expr.consume_front("-"); if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0, - UnsignedLiteralValue)) + LiteralValue)) { + LiteralValue = toSigned(LiteralValue, Negative); return std::make_unique(SaveExpr.drop_back(Expr.size()), - UnsignedLiteralValue); - Expr = SaveExpr; - if (AO == AllowedOperand::Any && !Expr.consumeInteger(0, SignedLiteralValue)) - return std::make_unique(SaveExpr.drop_back(Expr.size()), - SignedLiteralValue); - + LiteralValue); + } return ErrorDiagnostic::get( - SM, Expr, + SM, SaveExpr, Twine("invalid ") + (MaybeInvalidConstraint ? "matching constraint or " : "") + "operand format"); @@ -535,10 +527,10 @@ binop_eval_t EvalBinop; switch (Operator) { case '+': - EvalBinop = operator+; + EvalBinop = exprAdd; break; case '-': - EvalBinop = operator-; + EvalBinop = exprSub; break; default: return ErrorDiagnostic::get( @@ -572,12 +564,12 @@ assert(Expr.startswith("(")); auto OptFunc = StringSwitch(FuncName) - .Case("add", operator+) - .Case("div", operator/) - .Case("max", max) - .Case("min", min) - .Case("mul", operator*) - .Case("sub", operator-) + .Case("add", exprAdd) + .Case("div", exprDiv) + .Case("max", exprMax) + .Case("min", exprMin) + .Case("mul", exprMul) + .Case("sub", exprSub) .Default(nullptr); if (!OptFunc) @@ -1124,7 +1116,8 @@ if (!Substitutions.empty()) { TmpStr = RegExStr; if (LineNumber) - Context->LineVariable->setValue(ExpressionValue(*LineNumber)); + Context->LineVariable->setValue( + ExpressionValue(APInt(sizeof(*LineNumber) * 8, *LineNumber))); size_t InsertOffset = 0; // Substitute all string variables and expressions whose values are only diff --git a/llvm/lib/FileCheck/FileCheckImpl.h b/llvm/lib/FileCheck/FileCheckImpl.h --- a/llvm/lib/FileCheck/FileCheckImpl.h +++ b/llvm/lib/FileCheck/FileCheckImpl.h @@ -124,27 +124,25 @@ APInt Value; public: - // Store signed and unsigned 64-bit integers in a signed 65-bit APInt. - template - explicit ExpressionValue(T Val) : Value(65, Val, /*isSigned=*/Val < 0) {} + ExpressionValue(APInt Val) : Value(Val) {} APInt getAPIntValue() const { return Value; } }; /// Performs operation and \returns its result or an error in case of failure, /// such as if an overflow occurs. -Expected operator+(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected operator-(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected operator*(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected operator/(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected max(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); -Expected min(const ExpressionValue &Lhs, - const ExpressionValue &Rhs); +Expected exprAdd(const ExpressionValue &Lhs, + const ExpressionValue &Rhs, bool &Overflow); +Expected exprSub(const ExpressionValue &Lhs, + const ExpressionValue &Rhs, bool &Overflow); +Expected exprMul(const ExpressionValue &Lhs, + const ExpressionValue &Rhs, bool &Overflow); +Expected exprDiv(const ExpressionValue &Lhs, + const ExpressionValue &Rhs, bool &Overflow); +Expected exprMax(const ExpressionValue &Lhs, + const ExpressionValue &Rhs, bool &Overflow); +Expected exprMin(const ExpressionValue &Lhs, + const ExpressionValue &Rhs, bool &Overflow); /// Base class representing the AST of a given expression. class ExpressionAST { @@ -179,8 +177,7 @@ ExpressionValue Value; public: - template - explicit ExpressionLiteral(StringRef ExpressionStr, T Val) + explicit ExpressionLiteral(StringRef ExpressionStr, APInt Val) : ExpressionAST(ExpressionStr), Value(Val) {} /// \returns the literal's value. @@ -322,7 +319,8 @@ /// Type of functions evaluating a given binary operation. using binop_eval_t = Expected (*)(const ExpressionValue &, - const ExpressionValue &); + const ExpressionValue &, + bool &); /// Class representing a single binary operation in the AST of an expression. class BinaryOperation : public ExpressionAST { diff --git a/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt deleted file mode 100644 --- a/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt +++ /dev/null @@ -1,67 +0,0 @@ -; Check handling of match-time diagnostics for invalid patterns (e.g., -; substitution overflow) in the case of excluded patterns (e.g., CHECK-NOT). -; -; At one time, FileCheck's exit status was zero for this case. Moreover, it -; printed the error diagnostic only if -vv was specified and input dumps were -; disabled. Test every combination as the logic is hard to get right. - -RUN: echo > %t.chk \ -RUN: 'CHECK-NOT: [[#0x8000000000000000+0x8000000000000000]] [[UNDEFVAR]]' -RUN: echo > %t.in '10000000000000000' - - ERR-NOT:{{.}} - ERR-VV:{{.*}}: remark: implicit EOF: expected string found in input - ERR-VV-NEXT:CHECK-NOT: {{.*}} - ERR-VV-NEXT:{{ *}}^ - ERR-VV-NEXT:{{.*}}: note: found here -ERR-VV-EMPTY: - ERR-VV-NEXT:^ - ERR-NOT:{{.}} - ERR:{{.*}}: error: unable to substitute variable or numeric expression: overflow error - ERR-NEXT:CHECK-NOT: {{.*}} - ERR-NEXT:{{ *}}^ - ERR-NEXT:{{.*}}: error: undefined variable: UNDEFVAR - ERR-NEXT:{{CHECK-NOT: \[\[#0x8000000000000000\+0x8000000000000000\]\] \[\[UNDEFVAR\]\]}} - ERR-NEXT:^ - ERR-NOT:{{error|note|remark}}: - - DUMP:<<<<<< - DUMP-NEXT: 1: 10000000000000000 - DUMP-NEXT:not:1'0 X~~~~~~~~~~~~~~~~~ error: match failed for invalid pattern - DUMP-NEXT:not:1'1 unable to substitute variable or numeric expression: overflow error - DUMP-NEXT:not:1'2 undefined variable: UNDEFVAR -DUMP-VV-NEXT: 2: -DUMP-VV-NEXT:eof:1 ^ - DUMP-NEXT:>>>>>> - -;-------------------------------------------------- -; Check -dump-input=never cases. -;-------------------------------------------------- - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never -v %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never -vv %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,ERR-VV - -;-------------------------------------------------- -; Check -dump-input=fail cases. -;-------------------------------------------------- - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP,DUMP-VV diff --git a/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt deleted file mode 100644 --- a/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt +++ /dev/null @@ -1,54 +0,0 @@ -; Check handling of match-time diagnostics for invalid patterns (e.g., -; substitution overflow) in the case of expected patterns (e.g., CHECK). - -RUN: echo > %t.chk \ -RUN: 'CHECK: [[#0x8000000000000000+0x8000000000000000]] [[UNDEFVAR]]' -RUN: echo > %t.in '10000000000000000' - - ERR-NOT:{{.}} - ERR:{{.*}}: error: unable to substitute variable or numeric expression: overflow error - ERR-NEXT:CHECK: {{.*}} - ERR-NEXT:{{ *}}^ - ERR-NEXT:{{.*}}: error: undefined variable: UNDEFVAR - ERR-NEXT:{{CHECK: \[\[#0x8000000000000000\+0x8000000000000000\]\] \[\[UNDEFVAR\]\]}} - ERR-NEXT:^ - ERR-NOT:{{error|note|remark}}: - - DUMP:<<<<<< -DUMP-NEXT: 1: 10000000000000000 -DUMP-NEXT:check:1'0 X~~~~~~~~~~~~~~~~~ error: match failed for invalid pattern -DUMP-NEXT:check:1'1 unable to substitute variable or numeric expression: overflow error -DUMP-NEXT:check:1'2 undefined variable: UNDEFVAR -DUMP-NEXT:>>>>>> - -;-------------------------------------------------- -; Check -dump-input=never cases. -;-------------------------------------------------- - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never -v %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never -vv %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -;-------------------------------------------------- -; Check -dump-input=fail cases. -;-------------------------------------------------- - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP diff --git a/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt deleted file mode 100644 --- a/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt +++ /dev/null @@ -1,88 +0,0 @@ -; Check handling of diagnostics for problematic matches (e.g., variable capture -; overflow) in the case of excluded patterns (e.g., CHECK-NOT). -; -; At one time, FileCheck's exit status for the following example was zero even -; though the excluded pattern does match (it's just capturing that fails). -; Moreover, it printed the error diagnostic only if -vv was specified and input -; dumps were disabled. Test every combination as the logic is hard to get -; right. -; -; TODO: Capturing from an excluded pattern probably shouldn't be permitted -; because it seems useless: it's captured only if the pattern matches, but then -; FileCheck fails. The helpfulness of reporting overflow from that capture is -; perhaps questionable then, but it doesn't seem harmful either. Anyway, the -; goal of this test is simply to exercise the error propagation mechanism for a -; matched excluded pattern. In the future, if we have a more interesting error -; to exercise in that case, we should instead use it in this test, and then we -; might want to think more about where that error should be presented in the -; list of diagnostics. - -RUN: echo > %t.chk 'CHECK-NOT: [[#122+1]] [[STR:abc]] [[#NUM:]]' -RUN: echo > %t.in '123 abc 1000000000000000000000000000000000000000000000000000' - - ERR-NOT:{{.}} - ERR-VV:{{.*}}: remark: implicit EOF: expected string found in input - ERR-VV-NEXT:CHECK-NOT: {{.*}} - ERR-VV-NEXT:{{ *}}^ - ERR-VV-NEXT:{{.*}}: note: found here -ERR-VV-EMPTY: - ERR-VV-NEXT:^ - ERR-NOT:{{.}} - ERR:{{.*}}: error: CHECK-NOT: excluded string found in input - ERR-NEXT:CHECK-NOT: {{.*}} - ERR-NEXT:{{ *}}^ - ERR-NEXT::1:1: note: found here - ERR-NEXT:123 abc 10{{0*}} - ERR-NEXT:^~~~~~~~~{{~*}} - ERR-NEXT::1:1: note: with "122+1" equal to "123" - ERR-NEXT:123 abc 10{{0*}} - ERR-NEXT:^ - ERR-NEXT::1:5: note: captured var "STR" - ERR-NEXT:123 abc 10{{0*}} - ERR-NEXT: ^~~ - ERR-NEXT::1:9: error: unable to represent numeric value - ERR-NEXT:123 abc 10{{0*}} - ERR-NEXT: ^ - ERR-NOT:{{error|note|remark}}: - - DUMP:<<<<<< - DUMP-NEXT: 1: 123 abc 10{{0*}} - DUMP-NEXT:not:1'0 !~~~~~~~~~{{~*}} error: no match expected - DUMP-NEXT:not:1'1 with "122+1" equal to "123" - DUMP-NEXT:not:1'2 !~~ captured var "STR" - DUMP-NEXT:not:1'3 !~{{~*}} error: unable to represent numeric value -DUMP-VV-NEXT: 2: -DUMP-VV-NEXT:eof:1 ^ - DUMP-NEXT:>>>>>> - -;-------------------------------------------------- -; Check -dump-input=never cases. -;-------------------------------------------------- - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never -v %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never -vv %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,ERR-VV - -;-------------------------------------------------- -; Check -dump-input=fail cases. -;-------------------------------------------------- - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP,DUMP-VV diff --git a/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt deleted file mode 100644 --- a/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt +++ /dev/null @@ -1,63 +0,0 @@ -; Check handling of diagnostics for problematic matches (e.g., variable capture -; overflow) in the case of expected patterns (e.g., CHECK). - -RUN: echo > %t.chk 'CHECK: [[#122+1]] [[STR:abc]] [[#NUM:]]' -RUN: echo > %t.in '123 abc 1000000000000000000000000000000000000000000000000000' - - ERR-NOT:{{.}} - ERR:{{.*}}: remark: CHECK: expected string found in input - ERR-NEXT:CHECK: {{.*}} - ERR-NEXT:{{ *}}^ - ERR-NEXT::1:1: note: found here - ERR-NEXT:123 abc 10{{0*}} - ERR-NEXT:^~~~~~~~~{{~*}} - ERR-NEXT::1:1: note: with "122+1" equal to "123" - ERR-NEXT:123 abc 10{{0*}} - ERR-NEXT:^ - ERR-NEXT::1:5: note: captured var "STR" - ERR-NEXT:123 abc 10{{0*}} - ERR-NEXT: ^~~ - ERR-NEXT::1:9: error: unable to represent numeric value - ERR-NEXT:123 abc 10{{0*}} - ERR-NEXT: ^ - ERR-NOT:{{error|note|remark}}: - - DUMP:<<<<<< -DUMP-NEXT: 1: 123 abc 10{{0*}} -DUMP-NEXT:check:1'0 ^~~~~~~~~~{{~*}} -DUMP-NEXT:check:1'1 with "122+1" equal to "123" -DUMP-NEXT:check:1'2 ^~~ captured var "STR" -DUMP-NEXT:check:1'3 !~{{~*}} error: unable to represent numeric value -DUMP-NEXT:>>>>>> - -;-------------------------------------------------- -; Check -dump-input=never cases. -;-------------------------------------------------- - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never -v %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=never -vv %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR - -;-------------------------------------------------- -; Check -dump-input=fail cases. -;-------------------------------------------------- - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP - -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \ -RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP diff --git a/llvm/test/FileCheck/numeric-expression.txt b/llvm/test/FileCheck/numeric-expression.txt --- a/llvm/test/FileCheck/numeric-expression.txt +++ b/llvm/test/FileCheck/numeric-expression.txt @@ -487,18 +487,13 @@ CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42 (parsed as: {{\[\[#STRVAR:42\]\]}}) CLI-NUM-CONFLICT-NEXT: {{^}} ^{{$}} -; Numeric variable definition with too big value. -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck --check-prefix BIGVAL --input-file %s %s 2>&1 \ -RUN: | FileCheck --strict-whitespace --check-prefix BIGVAL-MSG %s +; Numeric variable definition with big value. +RUN: FileCheck --check-prefix BIGVAL --input-file %s %s BIG VALUE NUMVAR: 10000000000000000000000 BIGVAL-LABEL: BIG VALUE BIGVAL-NEXT: NUMVAR: [[#NUMVAR:]] -BIGVAL-MSG: numeric-expression.txt:[[#@LINE-3]]:9: error: unable to represent numeric value - BIGVAL-MSG-NEXT: {{N}}UMVAR: 10000000000000000000000 -BIGVAL-MSG-NEXT: {{^}} ^{{$}} ; Verify that when a variable is set to an expression the expression is still ; checked. @@ -557,31 +552,21 @@ REDEF-NEW-FMT-MSG-NEXT: {{R}}EDEF-NEW-FMT-NEXT: {{\[\[#%X,UNSI:\]\]}} REDEF-NEW-FMT-MSG-NEXT: {{^}} ^{{$}} -; Numeric expression with overflow. -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck --check-prefix OVERFLOW --input-file %s %s 2>&1 \ -RUN: | FileCheck --check-prefix OVERFLOW-MSG --strict-whitespace %s - -OVERFLOW -BIGVAR=10000000000000000 -OVERFLOW-LABEL: OVERFLOW -OVERFLOW-NEXT: BIGVAR: [[#BIGVAR:0x8000000000000000+0x8000000000000000]] -OVERFLOW-MSG: numeric-expression.txt:[[#@LINE-1]]:27: error: unable to substitute variable or numeric expression -OVERFLOW-MSG-NEXT: {{O}}VERFLOW-NEXT: BIGVAR: {{\[\[#BIGVAR:0x8000000000000000\+0x8000000000000000\]\]}} -OVERFLOW-MSG-NEXT: {{^}} ^{{$}} - -; Numeric expression with underflow. -RUN: %ProtectFileCheckOutput \ -RUN: not FileCheck --check-prefix UNDERFLOW --input-file %s %s 2>&1 \ -RUN: | FileCheck --check-prefix UNDERFLOW-MSG --strict-whitespace %s - -UNDERFLOW -TINYVAR=-10000000000000000 -UNDERFLOW-LABEL: UNDERFLOW -UNDERFLOW-NEXT: TINYVAR: [[#%d,TINYVAR:-0x8000000000000000-0x8000000000000000]] -UNDERFLOW-MSG: numeric-expression.txt:[[#@LINE-1]]:29: error: unable to substitute variable or numeric expression -UNDERFLOW-MSG-NEXT: {{U}}NDERFLOW-NEXT: TINYVAR: {{\[\[#%d,TINYVAR:-0x8000000000000000-0x8000000000000000\]\]}} -UNDERFLOW-MSG-NEXT: {{^}} ^{{$}} +; Numeric expression with big resulting value. +RUN: FileCheck --check-prefix OVERFLOW --input-file %s %s + +OVERFLOW EXPRESSION +BIGVAL: 10000000000000000 +OVERFLOW-LABEL: OVERFLOW EXPRESSION +OVERFLOW-NEXT: BIGVAL: [[#%X,0x8000000000000000+0x8000000000000000]] + +; Numeric expression with big negative resulting value. +RUN: FileCheck --check-prefix UNDERFLOW --input-file %s %s + +UNDERFLOW EXPRESSION +TINYVAR: -18446744073709551616 # -0x10000000000000000 +UNDERFLOW-LABEL: UNDERFLOW EXPRESSION +UNDERFLOW-NEXT: TINYVAR: [[#%d,-0x8000000000000000-0x8000000000000000]] RUN: %ProtectFileCheckOutput \ RUN: not FileCheck -D#NUMVAR=10 --check-prefix CALL-MISSING-CLOSING-BRACKET --input-file %s %s 2>&1 \ diff --git a/llvm/unittests/FileCheck/FileCheckTest.cpp b/llvm/unittests/FileCheck/FileCheckTest.cpp --- a/llvm/unittests/FileCheck/FileCheckTest.cpp +++ b/llvm/unittests/FileCheck/FileCheckTest.cpp @@ -84,6 +84,9 @@ constexpr uint64_t AbsoluteMinInt64 = static_cast(-(MinInt64 + 1)) + 1; constexpr uint64_t AbsoluteMaxInt64 = static_cast(MaxInt64); +// Use 128 bitwidth for literals to keep one bit for sign for uint64_t +// literals. +constexpr unsigned LiteralsBitWidth = 128; struct ExpressionFormatParameterisedFixture : public ::testing::TestWithParam< @@ -184,16 +187,18 @@ } template void checkMatchingString(T Val, StringRef ExpectedStr) { + APInt Value(LiteralsBitWidth, Val, std::is_signed_v); Expected MatchingString = - Format.getMatchingString(ExpressionValue(Val)); + Format.getMatchingString(ExpressionValue(Value)); ASSERT_THAT_EXPECTED(MatchingString, Succeeded()) << "No matching string for " << Val; EXPECT_EQ(*MatchingString, ExpectedStr); } template void checkMatchingStringFailure(T Val) { + APInt Value(LiteralsBitWidth, Val, std::is_signed_v); Expected MatchingString = - Format.getMatchingString(ExpressionValue(Val)); + Format.getMatchingString(ExpressionValue(Value)); // Error message tested in ExpressionValue unit tests. EXPECT_THAT_EXPECTED(MatchingString, Failed()); } @@ -286,7 +291,7 @@ if (Signed) { checkMatchingString(-5, padWithLeadingZeros("-5")); - checkMatchingStringFailure(MaxUint64); + checkMatchingString(MaxUint64, padWithLeadingZeros(MaxUint64Str)); checkMatchingString(MaxInt64, padWithLeadingZeros(MaxInt64Str)); checkMatchingString(MinInt64, padWithLeadingZeros(MinInt64Str)); } else { @@ -308,7 +313,7 @@ if (Signed) { checkValueFromStringRepr("-5", -5); - checkValueFromStringReprFailure(MaxUint64Str); + checkValueFromStringRepr(MaxUint64Str, MaxUint64); } else { checkValueFromStringRepr(addBasePrefix(MaxUint64Str), MaxUint64); } @@ -358,7 +363,7 @@ NoFormat.getWildcardRegex().takeError()); expectError( "trying to match value with invalid format", - NoFormat.getMatchingString(ExpressionValue(18u)).takeError()); + NoFormat.getMatchingString(ExpressionValue(APInt(64, 18u))).takeError()); EXPECT_FALSE(bool(NoFormat)); } @@ -389,172 +394,177 @@ EXPECT_FALSE(NoFormat != ExpressionFormat::Kind::NoFormat); } -template -static Expected doValueOperation(binop_eval_t Operation, - T1 LeftValue, T2 RightValue) { - ExpressionValue LeftOperand(LeftValue); - ExpressionValue RightOperand(RightValue); - return Operation(LeftOperand, RightOperand); -} - -template -static void expectValueEqual(ExpressionValue ActualValue, T ExpectedValue) { - APInt Value = ActualValue.getAPIntValue(); - EXPECT_EQ(ExpectedValue < 0, Value.isNegative()); - if (ExpectedValue < 0) - EXPECT_EQ(Value.getSExtValue(), static_cast(ExpectedValue)); - else - EXPECT_EQ(Value.getZExtValue(), static_cast(ExpectedValue)); +static void expectOperationValueResult(binop_eval_t Operation, APInt LeftValue, + APInt RightValue, APInt ExpectedValue) { + bool Overflow; + ExpressionValue LeftVal(LeftValue); + ExpressionValue RightVal(RightValue); + Expected OperationResult = + Operation(LeftVal, RightVal, Overflow); + ASSERT_THAT_EXPECTED(OperationResult, Succeeded()); + EXPECT_EQ(OperationResult->getAPIntValue(), ExpectedValue); } template static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue, T2 RightValue, TR ResultValue) { - Expected OperationResult = - doValueOperation(Operation, LeftValue, RightValue); - ASSERT_THAT_EXPECTED(OperationResult, Succeeded()); - expectValueEqual(*OperationResult, ResultValue); + APInt LeftVal(LiteralsBitWidth, LeftValue, std::is_signed_v); + APInt RightVal(LiteralsBitWidth, RightValue, std::is_signed_v); + APInt ResultVal = + std::is_integral_v + ? APInt(LiteralsBitWidth, ResultValue, std::is_signed_v) + : APInt(LiteralsBitWidth, ResultValue, /*Radix=*/10); + expectOperationValueResult(Operation, LeftVal, RightVal, ResultVal); } template static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue, T2 RightValue) { + bool Overflow; + ExpressionValue LeftVal( + APInt(LiteralsBitWidth, LeftValue, std::is_signed_v)); + ExpressionValue RightVal( + APInt(LiteralsBitWidth, RightValue, std::is_signed_v)); expectError( - "overflow error", - doValueOperation(Operation, LeftValue, RightValue).takeError()); + "overflow error", Operation(LeftVal, RightVal, Overflow).takeError()); } TEST_F(FileCheckTest, ExpressionValueAddition) { // Test both negative values. - expectOperationValueResult(operator+, -10, -10, -20); + expectOperationValueResult(exprAdd, -10, -10, -20); // Test both negative values with underflow. - expectOperationValueResult(operator+, MinInt64, -1); - expectOperationValueResult(operator+, MinInt64, MinInt64); + expectOperationValueResult(exprAdd, MinInt64, -1, "-9223372036854775809"); + expectOperationValueResult(exprAdd, MinInt64, MinInt64, + "-18446744073709551616"); // Test negative and positive value. - expectOperationValueResult(operator+, -10, 10, 0); - expectOperationValueResult(operator+, -10, 11, 1); - expectOperationValueResult(operator+, -11, 10, -1); + expectOperationValueResult(exprAdd, -10, 10, 0); + expectOperationValueResult(exprAdd, -10, 11, 1); + expectOperationValueResult(exprAdd, -11, 10, -1); // Test positive and negative value. - expectOperationValueResult(operator+, 10, -10, 0); - expectOperationValueResult(operator+, 10, -11, -1); - expectOperationValueResult(operator+, 11, -10, 1); + expectOperationValueResult(exprAdd, 10, -10, 0); + expectOperationValueResult(exprAdd, 10, -11, -1); + expectOperationValueResult(exprAdd, 11, -10, 1); // Test both positive values. - expectOperationValueResult(operator+, 10, 10, 20); + expectOperationValueResult(exprAdd, 10, 10, 20); - // Test both positive values with overflow. - expectOperationValueResult(operator+, MaxUint64, 1); - expectOperationValueResult(operator+, MaxUint64, MaxUint64); + // Test both positive values with result not representable as uint64_t. + expectOperationValueResult(exprAdd, MaxUint64, 1, "18446744073709551616"); + expectOperationValueResult(exprAdd, MaxUint64, MaxUint64, + "36893488147419103230"); } TEST_F(FileCheckTest, ExpressionValueSubtraction) { // Test negative value and value bigger than int64_t max. - expectOperationValueResult(operator-, -10, MaxUint64); + expectOperationValueResult(exprSub, -10, MaxUint64, "-18446744073709551625"); - // Test negative and positive value with underflow. - expectOperationValueResult(operator-, MinInt64, 1); + // Test negative and positive value with result not representable as int64_t. + expectOperationValueResult(exprSub, MinInt64, 1, "-9223372036854775809"); // Test negative and positive value. - expectOperationValueResult(operator-, -10, 10, -20); + expectOperationValueResult(exprSub, -10, 10, -20); // Test both negative values. - expectOperationValueResult(operator-, -10, -10, 0); - expectOperationValueResult(operator-, -11, -10, -1); - expectOperationValueResult(operator-, -10, -11, 1); + expectOperationValueResult(exprSub, -10, -10, 0); + expectOperationValueResult(exprSub, -11, -10, -1); + expectOperationValueResult(exprSub, -10, -11, 1); // Test positive and negative values. - expectOperationValueResult(operator-, 10, -10, 20); + expectOperationValueResult(exprSub, 10, -10, 20); // Test both positive values with result positive. - expectOperationValueResult(operator-, 10, 5, 5); + expectOperationValueResult(exprSub, 10, 5, 5); - // Test both positive values with underflow. - expectOperationValueResult(operator-, 0, MaxUint64); - expectOperationValueResult(operator-, 0, - static_cast(-(MinInt64 + 10)) + 11); + // Test both positive values with result not representable as int64_t. + expectOperationValueResult(exprSub, 0, MaxUint64, "-18446744073709551615"); + expectOperationValueResult(exprSub, 0, + static_cast(-(MinInt64 + 10)) + 11, + "-9223372036854775809"); // Test both positive values with result < -(max int64_t) - expectOperationValueResult(operator-, 10, - static_cast(MaxInt64) + 11, + expectOperationValueResult(exprSub, 10, static_cast(MaxInt64) + 11, -MaxInt64 - 1); // Test both positive values with 0 > result > -(max int64_t) - expectOperationValueResult(operator-, 10, 11, -1); + expectOperationValueResult(exprSub, 10, 11, -1); } TEST_F(FileCheckTest, ExpressionValueMultiplication) { // Test mixed signed values. - expectOperationValueResult(operator*, -3, 10, -30); - expectOperationValueResult(operator*, 2, -17, -34); - expectOperationValueResult(operator*, 0, MinInt64, 0); - expectOperationValueResult(operator*, MinInt64, 1, MinInt64); - expectOperationValueResult(operator*, 1, MinInt64, MinInt64); - expectOperationValueResult(operator*, MaxInt64, -1, -MaxInt64); - expectOperationValueResult(operator*, -1, MaxInt64, -MaxInt64); + expectOperationValueResult(exprMul, -3, 10, -30); + expectOperationValueResult(exprMul, 2, -17, -34); + expectOperationValueResult(exprMul, 0, MinInt64, 0); + expectOperationValueResult(exprMul, MinInt64, 1, MinInt64); + expectOperationValueResult(exprMul, 1, MinInt64, MinInt64); + expectOperationValueResult(exprMul, MaxInt64, -1, -MaxInt64); + expectOperationValueResult(exprMul, -1, MaxInt64, -MaxInt64); // Test both negative values. - expectOperationValueResult(operator*, -3, -10, 30); - expectOperationValueResult(operator*, -2, -17, 34); - expectOperationValueResult(operator*, MinInt64, -1, AbsoluteMinInt64); + expectOperationValueResult(exprMul, -3, -10, 30); + expectOperationValueResult(exprMul, -2, -17, 34); + expectOperationValueResult(exprMul, MinInt64, -1, AbsoluteMinInt64); // Test both positive values. - expectOperationValueResult(operator*, 3, 10, 30); - expectOperationValueResult(operator*, 2, 17, 34); - expectOperationValueResult(operator*, 0, MaxUint64, 0); - - // Test negative results that underflow. - expectOperationValueResult(operator*, -10, MaxInt64); - expectOperationValueResult(operator*, MaxInt64, -10); - expectOperationValueResult(operator*, 10, MinInt64); - expectOperationValueResult(operator*, MinInt64, 10); - expectOperationValueResult(operator*, -1, MaxUint64); - expectOperationValueResult(operator*, MaxUint64, -1); - expectOperationValueResult(operator*, -1, AbsoluteMaxInt64 + 2); - expectOperationValueResult(operator*, AbsoluteMaxInt64 + 2, -1); - - // Test positive results that overflow. - expectOperationValueResult(operator*, 10, MaxUint64); - expectOperationValueResult(operator*, MaxUint64, 10); - expectOperationValueResult(operator*, MinInt64, -10); - expectOperationValueResult(operator*, -10, MinInt64); + expectOperationValueResult(exprMul, 3, 10, 30); + expectOperationValueResult(exprMul, 2, 17, 34); + expectOperationValueResult(exprMul, 0, MaxUint64, 0); + + // Test negative results not representable as int64_t. + expectOperationValueResult(exprMul, -10, MaxInt64, "-92233720368547758070"); + expectOperationValueResult(exprMul, MaxInt64, -10, "-92233720368547758070"); + expectOperationValueResult(exprMul, 10, MinInt64, "-92233720368547758080"); + expectOperationValueResult(exprMul, MinInt64, 10, "-92233720368547758080"); + expectOperationValueResult(exprMul, -1, MaxUint64, "-18446744073709551615"); + expectOperationValueResult(exprMul, MaxUint64, -1, "-18446744073709551615"); + expectOperationValueResult(exprMul, -1, AbsoluteMaxInt64 + 2, + "-9223372036854775809"); + expectOperationValueResult(exprMul, AbsoluteMaxInt64 + 2, -1, + "-9223372036854775809"); + + // Test positive results not representable as uint64_t. + expectOperationValueResult(exprMul, 10, MaxUint64, "184467440737095516150"); + expectOperationValueResult(exprMul, MaxUint64, 10, "184467440737095516150"); + expectOperationValueResult(exprMul, MinInt64, -10, "92233720368547758080"); + expectOperationValueResult(exprMul, -10, MinInt64, "92233720368547758080"); } TEST_F(FileCheckTest, ExpressionValueDivision) { // Test mixed signed values. - expectOperationValueResult(operator/, -30, 10, -3); - expectOperationValueResult(operator/, 34, -17, -2); - expectOperationValueResult(operator/, 0, -10, 0); - expectOperationValueResult(operator/, MinInt64, 1, MinInt64); - expectOperationValueResult(operator/, MaxInt64, -1, -MaxInt64); - expectOperationValueResult(operator/, -MaxInt64, 1, -MaxInt64); + expectOperationValueResult(exprDiv, -30, 10, -3); + expectOperationValueResult(exprDiv, 34, -17, -2); + expectOperationValueResult(exprDiv, 0, -10, 0); + expectOperationValueResult(exprDiv, MinInt64, 1, MinInt64); + expectOperationValueResult(exprDiv, MaxInt64, -1, -MaxInt64); + expectOperationValueResult(exprDiv, -MaxInt64, 1, -MaxInt64); // Test both negative values. - expectOperationValueResult(operator/, -30, -10, 3); - expectOperationValueResult(operator/, -34, -17, 2); + expectOperationValueResult(exprDiv, -30, -10, 3); + expectOperationValueResult(exprDiv, -34, -17, 2); // Test both positive values. - expectOperationValueResult(operator/, 30, 10, 3); - expectOperationValueResult(operator/, 34, 17, 2); - expectOperationValueResult(operator/, 0, 10, 0); + expectOperationValueResult(exprDiv, 30, 10, 3); + expectOperationValueResult(exprDiv, 34, 17, 2); + expectOperationValueResult(exprDiv, 0, 10, 0); // Test divide by zero. - expectOperationValueResult(operator/, -10, 0); - expectOperationValueResult(operator/, 10, 0); - expectOperationValueResult(operator/, 0, 0); - - // Test negative result that underflows. - expectOperationValueResult(operator/, MaxUint64, -1); - expectOperationValueResult(operator/, AbsoluteMaxInt64 + 2, -1); + expectOperationValueResult(exprDiv, -10, 0); + expectOperationValueResult(exprDiv, 10, 0); + expectOperationValueResult(exprDiv, 0, 0); + + // Test negative result not representable as int64_t. + expectOperationValueResult(exprDiv, MaxUint64, -1, "-18446744073709551615"); + expectOperationValueResult(exprDiv, AbsoluteMaxInt64 + 2, -1, + "-9223372036854775809"); } TEST_F(FileCheckTest, Literal) { SourceMgr SM; // Eval returns the literal's value. - ExpressionLiteral Ten(bufferize(SM, "10"), 10u); + ExpressionLiteral Ten(bufferize(SM, "10"), APInt(64, 10u)); Expected Value = Ten.eval(); ASSERT_THAT_EXPECTED(Value, Succeeded()); EXPECT_EQ(10, Value->getAPIntValue().getSExtValue()); @@ -563,13 +573,15 @@ EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::NoFormat); // Min value can be correctly represented. - ExpressionLiteral Min(bufferize(SM, std::to_string(MinInt64)), MinInt64); + ExpressionLiteral Min(bufferize(SM, std::to_string(MinInt64)), + APInt(64, MinInt64, /*IsSigned=*/true)); Value = Min.eval(); ASSERT_TRUE(bool(Value)); EXPECT_EQ(MinInt64, Value->getAPIntValue().getSExtValue()); // Max value can be correctly represented. - ExpressionLiteral Max(bufferize(SM, std::to_string(MaxUint64)), MaxUint64); + ExpressionLiteral Max(bufferize(SM, std::to_string(MaxUint64)), + APInt(64, MaxUint64)); Value = Max.eval(); ASSERT_THAT_EXPECTED(Value, Succeeded()); EXPECT_EQ(MaxUint64, Value->getAPIntValue().getZExtValue()); @@ -579,7 +591,7 @@ SourceMgr SM; std::unique_ptr Ten = - std::make_unique(bufferize(SM, "10"), 10u); + std::make_unique(bufferize(SM, "10"), APInt(64, 10u)); ExpressionLiteral *TenPtr = Ten.get(); Expression Expr(std::move(Ten), ExpressionFormat(ExpressionFormat::Kind::HexLower)); @@ -618,7 +630,7 @@ expectUndefErrors({"FOO"}, EvalResult.takeError()); // Defined variable without string: only getValue and eval return value set. - FooVar.setValue(ExpressionValue(42u)); + FooVar.setValue(ExpressionValue(APInt(64, 42u))); std::optional Value = FooVar.getValue(); ASSERT_TRUE(Value); EXPECT_EQ(42, Value->getAPIntValue().getSExtValue()); @@ -630,7 +642,7 @@ // Defined variable with string: getValue, eval, and getStringValue return // value set. StringRef StringValue = "925"; - FooVar.setValue(ExpressionValue(925u), StringValue); + FooVar.setValue(ExpressionValue(APInt(64, 925u)), StringValue); Value = FooVar.getValue(); ASSERT_TRUE(Value); EXPECT_EQ(925, Value->getAPIntValue().getSExtValue()); @@ -658,21 +670,20 @@ StringRef FooStr = ExprStr.take_front(3); NumericVariable FooVar(FooStr, ExpressionFormat(ExpressionFormat::Kind::Unsigned), 1); - FooVar.setValue(ExpressionValue(42u)); + FooVar.setValue(ExpressionValue(APInt(64, 42u))); std::unique_ptr FooVarUse = std::make_unique(FooStr, &FooVar); StringRef BarStr = ExprStr.take_back(3); NumericVariable BarVar(BarStr, ExpressionFormat(ExpressionFormat::Kind::Unsigned), 2); - BarVar.setValue(ExpressionValue(18u)); + BarVar.setValue(ExpressionValue(APInt(64, 18u))); std::unique_ptr BarVarUse = std::make_unique(BarStr, &BarVar); - binop_eval_t doAdd = operator+; - BinaryOperation Binop(ExprStr, doAdd, std::move(FooVarUse), + BinaryOperation Binop(ExprStr, exprAdd, std::move(FooVarUse), std::move(BarVarUse)); - // Defined variables: eval returns right value; implicit format is as - // expected. + // Defined variables with same bitwidth and no overflow: eval returns right + // value; implicit formas is as expected. Expected Value = Binop.eval(); ASSERT_THAT_EXPECTED(Value, Succeeded()); EXPECT_EQ(60, Value->getAPIntValue().getSExtValue()); @@ -680,6 +691,23 @@ ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded()); EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned); + // Defined variables with different bitwidth and no overflow: eval succeeds + // and return the right value. + BarVar.setValue(ExpressionValue(APInt(32, 18u))); + Value = Binop.eval(); + ASSERT_THAT_EXPECTED(Value, Succeeded()); + EXPECT_EQ(60, Value->getAPIntValue().getSExtValue()); + + // Defined variables with same bitwidth and wider result (i.e. overflow): + // eval succeeds and return the right value in a wider APInt. + BarVar.setValue(ExpressionValue(APInt(64, AbsoluteMaxInt64))); + Value = Binop.eval(); + ASSERT_THAT_EXPECTED(Value, Succeeded()); + EXPECT_EQ(128u, Value->getAPIntValue().getBitWidth()); + EXPECT_EQ(APInt(128, AbsoluteMaxInt64 + + FooVar.getValue()->getAPIntValue().getZExtValue()), + Value->getAPIntValue()); + // 1 undefined variable: eval fails, error contains name of undefined // variable. FooVar.clearValue(); @@ -698,8 +726,8 @@ StringRef EighteenStr = ExprStr.take_back(2); FooVarUse = std::make_unique(FooStr, &FooVar); std::unique_ptr Eighteen = - std::make_unique(EighteenStr, 18u); - Binop = BinaryOperation(ExprStr, doAdd, std::move(FooVarUse), + std::make_unique(EighteenStr, APInt(64, 18u)); + Binop = BinaryOperation(ExprStr, exprAdd, std::move(FooVarUse), std::move(Eighteen)); ImplicitFormat = Binop.getImplicitFormat(SM); ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded()); @@ -708,8 +736,8 @@ FooStr = ExprStr.take_back(3); EighteenStr = ExprStr.take_front(2); FooVarUse = std::make_unique(FooStr, &FooVar); - Eighteen = std::make_unique(EighteenStr, 18u); - Binop = BinaryOperation(ExprStr, doAdd, std::move(Eighteen), + Eighteen = std::make_unique(EighteenStr, APInt(64, 18u)); + Binop = BinaryOperation(ExprStr, exprAdd, std::move(Eighteen), std::move(FooVarUse)); ImplicitFormat = Binop.getImplicitFormat(SM); ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded()); @@ -724,7 +752,7 @@ FooVarUse = std::make_unique(FooStr, &FooVar); std::unique_ptr BazVarUse = std::make_unique(BazStr, &BazVar); - Binop = BinaryOperation(ExprStr, doAdd, std::move(FooVarUse), + Binop = BinaryOperation(ExprStr, exprAdd, std::move(FooVarUse), std::move(BazVarUse)); ImplicitFormat = Binop.getImplicitFormat(SM); expectDiagnosticError( @@ -749,12 +777,13 @@ std::unique_ptr QuuxVarUse = std::make_unique(QuuxStr, &QuuxVar); std::unique_ptr Binop1 = std::make_unique( - ExprStr.take_front(9), doAdd, std::move(FooVarUse), std::move(BazVarUse)); + ExprStr.take_front(9), exprAdd, std::move(FooVarUse), + std::move(BazVarUse)); std::unique_ptr Binop2 = std::make_unique( - ExprStr.take_back(10), doAdd, std::move(FooVarUse2), + ExprStr.take_back(10), exprAdd, std::move(FooVarUse2), std::move(QuuxVarUse)); std::unique_ptr OuterBinop = - std::make_unique(ExprStr, doAdd, std::move(Binop1), + std::make_unique(ExprStr, exprAdd, std::move(Binop1), std::move(Binop2)); ImplicitFormat = OuterBinop->getImplicitFormat(SM); expectSameErrors( @@ -1434,7 +1463,7 @@ // substituted for the variable's value. NumericVariable NVar("N", ExpressionFormat(ExpressionFormat::Kind::Unsigned), 1); - NVar.setValue(ExpressionValue(10u)); + NVar.setValue(ExpressionValue(APInt(64, 10u))); auto NVarUse = std::make_unique("N", &NVar); auto ExpressionN = std::make_unique( std::move(NVarUse), ExpressionFormat(ExpressionFormat::Kind::HexUpper));