diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index a55b93ea461..94d05e00561 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -76,6 +76,11 @@ jobs: strategy: matrix: os: [ubuntu-22.04, macos-15] + int128: [Off, On] + # TODO: remove when GCC build works + exclude: + - os: ubuntu-22.04 + int128: On fail-fast: false # Prefer quick result runs-on: ${{ matrix.os }} @@ -92,7 +97,7 @@ jobs: - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: - key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }} + key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}-${{ matrix.int128 }} # TODO: move latest compiler to separate step # TODO: bail out on warnings with latest GCC @@ -127,37 +132,62 @@ jobs: - name: Run CMake on ubuntu (with GUI) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install + cmake -S . -B cmake.output -G "Unix Makefiles" -DUSE_INT128=${{ matrix.int128 }} -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install - name: Run CMake on macos (with GUI) if: contains(matrix.os, 'macos') run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 + cmake -S . -B cmake.output -G "Unix Makefiles" -DUSE_INT128=${{ matrix.int128 }} -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 - name: Run CMake build run: | cmake --build cmake.output -- -j$(nproc) - name: Run CMake test + if: matrix.int128 == 'Off' # TODO: enable when tests work run: | cmake --build cmake.output --target check -- -j$(nproc) - name: Run CTest + if: matrix.int128 == 'Off' # TODO: enable when tests work run: | pushd cmake.output ctest --output-on-failure -j$(nproc) - name: Run CMake install + if: matrix.int128 == 'Off' run: | cmake --build cmake.output --target install - - name: Run CMake on ubuntu (no CLI) - if: matrix.os == 'ubuntu-22.04' + build_cmake_no_with: + + strategy: + matrix: + # TODO: also run on macOS? + os: [ubuntu-22.04] + fail-fast: false # Prefer quick result + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install missing software on ubuntu + if: contains(matrix.os, 'ubuntu') + run: | + sudo apt-get update + sudo apt-get install libxml2-utils + # qt6-tools-dev-tools for lprodump + # qt6-l10n-tools for lupdate + sudo apt-get install qt6-base-dev libqt6charts6-dev qt6-tools-dev qt6-tools-dev-tools qt6-l10n-tools libglx-dev libgl1-mesa-dev + + - name: Run CMake (no CLI) run: | cmake -S . -B cmake.output_nocli -G "Unix Makefiles" -DBUILD_CLI=Off - - name: Run CMake on ubuntu (no CLI / with tests) - if: matrix.os == 'ubuntu-22.04' + - name: Run CMake (no CLI / with tests) run: | # the test and CLI code are too intertwined so for now we need to reject that if cmake -S . -B cmake.output_nocli_tests -G "Unix Makefiles" -DBUILD_TESTS=On -DBUILD_CLI=Off; then @@ -166,18 +196,15 @@ jobs: exit 0 fi - - name: Run CMake on ubuntu (no CLI / with GUI) - if: matrix.os == 'ubuntu-22.04' + - name: Run CMake (no CLI / with GUI) run: | cmake -S . -B cmake.output_nocli_gui -G "Unix Makefiles" -DBUILD_CLI=Off -DBUILD_GUI=On - - name: Run CMake on ubuntu (no GUI) - if: matrix.os == 'ubuntu-22.04' + - name: Run CMake (no GUI) run: | cmake -S . -B cmake.output_nogui -G "Unix Makefiles" -DBUILD_GUI=Off - - name: Run CMake on ubuntu (no GUI / with triage) - if: matrix.os == 'ubuntu-22.04' + - name: Run CMake (no GUI / with triage) run: | # cannot build triage without GUI if cmake -S . -B cmake.output_nogui_triage -G "Unix Makefiles" -DBUILD_GUI=Off -DBUILD_TRIAGE=On; then @@ -186,8 +213,7 @@ jobs: exit 0 fi - - name: Run CMake on ubuntu (no CLI / no GUI) - if: matrix.os == 'ubuntu-22.04' + - name: Run CMake (no CLI / no GUI) run: | cmake -S . -B cmake.output_nocli_nogui -G "Unix Makefiles" -DBUILD_GUI=Off diff --git a/cmake/compilerDefinitions.cmake b/cmake/compilerDefinitions.cmake index 6ad938fa009..564ba35a70d 100644 --- a/cmake/compilerDefinitions.cmake +++ b/cmake/compilerDefinitions.cmake @@ -37,9 +37,13 @@ if(HAVE_RULES) add_definitions(-DHAVE_RULES) endif() +if(USE_INT128) + add_definitions(-DHAVE_INT128) +endif() + if(Boost_FOUND) add_definitions(-DHAVE_BOOST) - if(USE_BOOST_INT128) + if(USE_INT128 AND USE_BOOST_INT128) add_definitions(-DHAVE_BOOST_INT128) endif() endif() diff --git a/cmake/options.cmake b/cmake/options.cmake index 5765f9a9595..c11cfd44f61 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -92,11 +92,16 @@ option(DISALLOW_THREAD_EXECUTOR "Disallow usage of ThreadExecutor for -j" if(DISALLOW_THREAD_EXECUTOR AND WIN32) message(FATAL_ERROR "Cannot disable usage of ThreadExecutor on Windows as no other executor implementation is currently available") endif() +set(USE_INT128 "Off" CACHE STRING "Usage of 128-bit integer type") # TODO: default to Auto when working +set_property(CACHE USE_INT128 PROPERTY STRINGS Auto Off On) set(USE_BOOST "Auto" CACHE STRING "Usage of Boost") set_property(CACHE USE_BOOST PROPERTY STRINGS Auto Off On) -option(USE_BOOST_INT128 "Usage of Boost.Multiprecision 128-bit integer for Mathlib" OFF) -if (NOT USE_BOOST AND USE_BOOST_INT128) - message(FATAL_ERROR "USE_BOOST_INT128 requires USE_BOOST to be enabled") +set(USE_BOOST_INT128 "Off" CACHE STRING "Usage of Boost.Multiprecision 128-bit integer for Mathlib") # TODO: default to Auto when working +set_property(CACHE USE_BOOST_INT128 PROPERTY STRINGS Auto Off On) +if (USE_INT128) + if (NOT USE_BOOST AND USE_BOOST_INT128) + message(FATAL_ERROR "USE_BOOST_INT128 requires USE_BOOST to be enabled") + endif() endif() option(USE_LIBCXX "Use libc++ instead of libstdc++" OFF) diff --git a/cmake/printInfo.cmake b/cmake/printInfo.cmake index 76c8112ce8a..c096bb0bdcf 100644 --- a/cmake/printInfo.cmake +++ b/cmake/printInfo.cmake @@ -86,6 +86,8 @@ if(NOT USE_BUNDLED_TINYXML2) message(STATUS "tinyxml2_INCLUDE_DIRS = ${tinyxml2_INCLUDE_DIRS}") endif() message(STATUS) +message(STATUS "USE_INT128 = ${USE_INT128}") +message(STATUS) message(STATUS "USE_BOOST = ${USE_BOOST}") if(USE_BOOST) message(STATUS "Boost_FOUND = ${Boost_FOUND}") diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 54240fa4f2f..f288617dcd6 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -163,7 +163,7 @@ MathLib::value MathLib::value::calc(char op, const MathLib::value &v1, const Mat case '/': if (v2.mIntValue == 0) throw InternalError(nullptr, "Internal Error: Division by zero"); - if (v1.mIntValue == std::numeric_limits::min() && std::abs(v2.mIntValue)<=1) + if (v1.mIntValue == std::numeric_limits::min() && MathLib::abs(v2.mIntValue)<=1) throw InternalError(nullptr, "Internal Error: Division overflow"); temp.mIntValue /= static_cast(v2.mIntValue); break; @@ -198,7 +198,7 @@ MathLib::value MathLib::value::calc(char op, const MathLib::value &v1, const Mat case '/': if (v2.mIntValue == 0) throw InternalError(nullptr, "Internal Error: Division by zero"); - if (v1.mIntValue == std::numeric_limits::min() && std::abs(v2.mIntValue)<=1) + if (v1.mIntValue == std::numeric_limits::min() && MathLib::abs(v2.mIntValue)<=1) throw InternalError(nullptr, "Internal Error: Division overflow"); temp.mIntValue /= v2.mIntValue; break; @@ -537,10 +537,16 @@ double MathLib::toDoubleNumber(const std::string &str, const Token * const tok) template<> std::string MathLib::toString(MathLib::bigint value) { -#if defined(HAVE_BOOST) && defined(HAVE_BOOST_INT128) +#if defined(HAVE_INT128) +# if defined(HAVE_BOOST) && defined(HAVE_BOOST_INT128) std::ostringstream result; result << value; return result.str(); +# else + // TODO: handle actual 128-bit values + assert(value >= std::numeric_limits::min() && value <= std::numeric_limits::max()); + return std::to_string(static_cast(value)); +# endif #else return std::to_string(value); #endif @@ -548,10 +554,16 @@ template<> std::string MathLib::toString(MathLib::bigint value) template<> std::string MathLib::toString(MathLib::biguint value) { -#if defined(HAVE_BOOST) && defined(HAVE_BOOST_INT128) +#if defined(HAVE_INT128) +# if defined(HAVE_BOOST) && defined(HAVE_BOOST_INT128) std::ostringstream result; result << value; return result.str(); +# else + // TODO: handle actual 128-bit values + assert(value <= std::numeric_limits::max()); + return std::to_string(static_cast(value)); +# endif #else return std::to_string(value); #endif @@ -1148,7 +1160,7 @@ std::string MathLib::divide(const std::string &first, const std::string &second) const bigint b = toBigNumber(second); if (b == 0) throw InternalError(nullptr, "Internal Error: Division by zero"); - if (a == std::numeric_limits::min() && std::abs(b)<=1) + if (a == std::numeric_limits::min() && MathLib::abs(b)<=1) throw InternalError(nullptr, "Internal Error: Division overflow"); return MathLib::toString(toBigNumber(first) / b) + intsuffix(first, second); } diff --git a/lib/mathlib.h b/lib/mathlib.h index 6b415d3bb55..9ec9881b78e 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -26,8 +26,10 @@ #include #include -#if defined(HAVE_BOOST) && defined(HAVE_BOOST_INT128) -#include +#if defined(HAVE_INT128) +# if defined(HAVE_BOOST) && defined(HAVE_BOOST_INT128) +# include +# endif #endif class Token; @@ -41,9 +43,18 @@ class CPPCHECKLIB MathLib { friend class TestMathLib; public: -#if defined(HAVE_BOOST) && defined(HAVE_BOOST_INT128) +#if defined(HAVE_INT128) +# if defined(HAVE_BOOST) && defined(HAVE_BOOST_INT128) using bigint = boost::multiprecision::int128_t; using biguint = boost::multiprecision::uint128_t; +# elif defined(__GNUC__) + SUPPRESS_WARNING_GCC_PUSH("-Wpedantic") + using bigint = __int128; + using biguint = unsigned __int128; + SUPPRESS_WARNING_GCC_POP +# else + #error "no 128-bit type" +# endif #else using bigint = long long; using biguint = unsigned long long; @@ -144,6 +155,12 @@ class CPPCHECKLIB MathLib { static bool isOctalDigit(char c); static unsigned int encodeMultiChar(const std::string& str); + + static bigint abs(bigint i) { + if (i < 0) + return -i; + return i; + } }; MathLib::value operator+(const MathLib::value &v1, const MathLib::value &v2); @@ -161,6 +178,20 @@ template<> CPPCHECKLIB std::string MathLib::toString(MathLib::b template<> CPPCHECKLIB std::string MathLib::toString(MathLib::biguint value); template<> CPPCHECKLIB std::string MathLib::toString(double value); +// Boost provides stream insertion operators +#if defined(HAVE_INT128) && !defined(HAVE_BOOST_INT128) +inline std::ostream& operator<<(std::ostream& os, MathLib::bigint i) +{ + os << MathLib::toString(i); + return os; +} +inline std::ostream& operator<<(std::ostream& os, MathLib::biguint u) +{ + os << MathLib::toString(u); + return os; +} +#endif + /// @} //--------------------------------------------------------------------------- #endif // mathlibH diff --git a/lib/token.cpp b/lib/token.cpp index 8313305c2c8..6662b4a8acd 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2027,7 +2027,7 @@ static bool isAdjacent(const ValueFlow::Value& x, const ValueFlow::Value& y) return true; if (x.valueType == ValueFlow::Value::ValueType::FLOAT) return false; - return std::abs(x.intvalue - y.intvalue) == 1; + return MathLib::abs(x.intvalue - y.intvalue) == 1; } static bool removePointValue(std::list& values, std::list::iterator& x) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 7837932f672..32dacc7f6a8 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4515,7 +4515,7 @@ struct ConditionHandler { MathLib::bigint getPath() const { - assert(std::abs(findPath(true_values) - findPath(false_values)) == 0); + assert(MathLib::abs(findPath(true_values) - findPath(false_values)) == 0); return findPath(true_values) | findPath(false_values); } diff --git a/lib/vfvalue.h b/lib/vfvalue.h index 8a473143b68..a530f1af6a7 100644 --- a/lib/vfvalue.h +++ b/lib/vfvalue.h @@ -168,6 +168,7 @@ namespace ValueFlow return !(*this == rhs); } + // TODO: requires check fails with GCC using __int128 template )> bool equalTo(const T& x) const { bool result = false; @@ -316,6 +317,9 @@ namespace ValueFlow std::int8_t indirect{}; // TODO: can we reduce the size? +#if defined(HAVE_INT128) + long long : 64; +#endif /** int value (or sometimes bool value?) */ MathLib::bigint intvalue{}; diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 6a0ba4c0871..ce598fe283b 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -358,12 +358,12 @@ class TestMathLib : public TestFixture { // min/max and out-of-bounds - hex { constexpr MathLib::bigint i = 0xFFFFFFFFFFFFFFFF; - ASSERT_EQUALS(i, MathLib::toBigNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toBigNumber(MathLib::toString(i))); ASSERT_EQUALS(i, MathLib::toBigNumber("0xFFFFFFFFFFFFFFFF")); } { constexpr MathLib::bigint i = -0xFFFFFFFFFFFFFFFF; - ASSERT_EQUALS(i, MathLib::toBigNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toBigNumber(MathLib::toString(i))); ASSERT_EQUALS(i, MathLib::toBigNumber("-0xFFFFFFFFFFFFFFFF")); } @@ -373,12 +373,12 @@ class TestMathLib : public TestFixture { // min/max and out-of-bounds - octal { constexpr MathLib::bigint i = 01777777777777777777777; - ASSERT_EQUALS(i, MathLib::toBigNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toBigNumber(MathLib::toString(i))); ASSERT_EQUALS(i, MathLib::toBigNumber("01777777777777777777777")); } { constexpr MathLib::bigint i = -01777777777777777777777; - ASSERT_EQUALS(i, MathLib::toBigNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toBigNumber(MathLib::toString(i))); ASSERT_EQUALS(i, MathLib::toBigNumber("-01777777777777777777777")); } @@ -388,12 +388,12 @@ class TestMathLib : public TestFixture { // min/max and out-of-range - decimal { constexpr MathLib::bigint i = 18446744073709551615ULL; - ASSERT_EQUALS(i, MathLib::toBigNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toBigNumber(MathLib::toString(i))); ASSERT_EQUALS(i, MathLib::toBigNumber("18446744073709551615")); } { constexpr MathLib::bigint i = -18446744073709551615ULL; - ASSERT_EQUALS(i, MathLib::toBigNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toBigNumber(MathLib::toString(i))); ASSERT_EQUALS(i, MathLib::toBigNumber("-18446744073709551615")); } @@ -530,12 +530,12 @@ class TestMathLib : public TestFixture { // min/max and out-of-bounds - hex { constexpr MathLib::biguint u = 0xFFFFFFFFFFFFFFFF; - ASSERT_EQUALS(u, MathLib::toBigUNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toBigUNumber(MathLib::toString(u))); ASSERT_EQUALS(u, MathLib::toBigUNumber("0xFFFFFFFFFFFFFFFF")); } { constexpr MathLib::biguint u = -0xFFFFFFFFFFFFFFFF; - ASSERT_EQUALS(u, MathLib::toBigUNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toBigUNumber(MathLib::toString(u))); ASSERT_EQUALS(u, MathLib::toBigUNumber("-0xFFFFFFFFFFFFFFFF")); } @@ -545,12 +545,12 @@ class TestMathLib : public TestFixture { // min/max and out-of-bounds - octal { constexpr MathLib::biguint u = 01777777777777777777777; - ASSERT_EQUALS(u, MathLib::toBigUNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toBigUNumber(MathLib::toString(u))); ASSERT_EQUALS(u, MathLib::toBigUNumber("01777777777777777777777")); } { constexpr MathLib::biguint u = -01777777777777777777777; - ASSERT_EQUALS(u, MathLib::toBigUNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toBigUNumber(MathLib::toString(u))); ASSERT_EQUALS(u, MathLib::toBigUNumber("-01777777777777777777777")); } @@ -560,12 +560,12 @@ class TestMathLib : public TestFixture { // min/max and out-of-range - decimal { constexpr MathLib::biguint u = 18446744073709551615ULL; - ASSERT_EQUALS(u, MathLib::toBigUNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toBigUNumber(MathLib::toString(u))); ASSERT_EQUALS(u, MathLib::toBigUNumber("18446744073709551615")); } { constexpr MathLib::biguint u = -18446744073709551615ULL; - ASSERT_EQUALS(u, MathLib::toBigUNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toBigUNumber(MathLib::toString(u))); ASSERT_EQUALS(u, MathLib::toBigUNumber("-18446744073709551615")); } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index fe0ea225b5b..18685cb2e07 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6452,7 +6452,7 @@ class TestValueFlow : public TestFixture { if (!values.front().isPossible()) return "Possible"; if (values.front().intvalue != i) - return "intvalue:" + std::to_string(values.front().intvalue); + return "intvalue:" + MathLib::toString(values.front().intvalue); return ""; } @@ -6470,7 +6470,7 @@ class TestValueFlow : public TestFixture { if (!values.front().isImpossible()) return "Impossible"; if (values.front().intvalue != i) - return "intvalue:" + std::to_string(values.front().intvalue); + return "intvalue:" + MathLib::toString(values.front().intvalue); return ""; } @@ -6488,7 +6488,7 @@ class TestValueFlow : public TestFixture { if (!values.front().isInconclusive()) return "Inconclusive"; if (values.front().intvalue != i) - return "intvalue:" + std::to_string(values.front().intvalue); + return "intvalue:" + MathLib::toString(values.front().intvalue); return ""; } @@ -6504,7 +6504,7 @@ class TestValueFlow : public TestFixture { if (!values.front().isKnown()) return "Known"; if (values.front().intvalue != i) - return "intvalue:" + std::to_string(values.front().intvalue); + return "intvalue:" + MathLib::toString(values.front().intvalue); return ""; }