diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 403662f4df2..c7c055899fd 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -266,7 +266,7 @@ MathLib::value MathLib::value::shiftLeft(const MathLib::value &v) const if (!isInt() || !v.isInt()) throw InternalError(nullptr, "Shift operand is not integer"); MathLib::value ret(*this); - if (v.mIntValue >= MathLib::bigint_bits) { + if (v.mIntValue < 0 || v.mIntValue >= MathLib::bigint_bits || ret.mIntValue < 0) { return ret; } ret.mIntValue <<= v.mIntValue; @@ -278,7 +278,7 @@ MathLib::value MathLib::value::shiftRight(const MathLib::value &v) const if (!isInt() || !v.isInt()) throw InternalError(nullptr, "Shift operand is not integer"); MathLib::value ret(*this); - if (v.mIntValue >= MathLib::bigint_bits) { + if (v.mIntValue < 0 || v.mIntValue >= MathLib::bigint_bits) { return ret; } ret.mIntValue >>= v.mIntValue; diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index b28bc503869..6960b791426 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -320,6 +320,8 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(templateArgPreserveType); // #13882 - type of template argument + TEST_CASE(template_shift_negative); // shift folding with a negative operand + TEST_CASE(dumpTemplateArgFrom); } @@ -6715,6 +6717,21 @@ class TestSimplifyTemplate : public TestFixture { tok(code)); } + void template_shift_negative() { + // a large hex literal is not negative as a string but parses to a negative + // bigint, so folding the shift in simplifyNumericCalculations would left-shift + // a negative value / shift by a negative count, both UB. the operand must be + // returned unchanged. parentheses are needed so the numeric folding is reached. + const char code[] = "template struct S { };\n" + "S<(0x8000000000000000 << 1)> s1;\n" + "S<(1 << 0x8000000000000000)> s2;\n" + "S<(1 >> 0x8000000000000000)> s3;"; + const char expected[] = "struct S<9223372036854775808U> ; struct S<1> ; " + "S<9223372036854775808U> s1 ; S<1> s2 ; S<1> s3 ; " + "struct S<9223372036854775808U> { } ; struct S<1> { } ;"; + ASSERT_EQUALS(expected, tok(code)); + } + void dumpTemplateArgFrom() { const char code[] = "template void foo(T t) {}\n" "foo(23);";