diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 152a4514b..4ba491a83 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -35,28 +35,29 @@ jobs: # - name: Test # run: cd build ; ctest -j 10 --output-on-failure - macos-12: - runs-on: macos-12 # https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md - strategy: - matrix: - xcode: ['13.1', '13.2.1', '13.3.1', '13.4.1', '14.0', '14.0.1', '14.1'] - env: - DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer - - steps: - - uses: actions/checkout@v4 - - name: Run CMake - run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON - - name: Build - run: cmake --build build --parallel 10 - - name: Test - run: cd build ; ctest -j 10 --output-on-failure +# macos-12 is deprecated (https://github.com/actions/runner-images/issues/10721) +# macos-12: +# runs-on: macos-12 # https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md +# strategy: +# matrix: +# xcode: ['13.1', '13.2.1', '13.3.1', '13.4.1', '14.0', '14.0.1', '14.1'] +# env: +# DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer +# +# steps: +# - uses: actions/checkout@v4 +# - name: Run CMake +# run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_FastTests=ON +# - name: Build +# run: cmake --build build --parallel 10 +# - name: Test +# run: cd build ; ctest -j 10 --output-on-failure macos-13: runs-on: macos-13 # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md strategy: matrix: - xcode: [ '14.2', '14.3', '14.3.1', '15.0.1', '15.1', '15.2'] + xcode: ['14.1', '14.2', '14.3', '14.3.1', '15.0.1', '15.1', '15.2'] env: DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer diff --git a/README.md b/README.md index 34a79f400..a49309282 100644 --- a/README.md +++ b/README.md @@ -1115,7 +1115,7 @@ Though it's 2024 already, the support for C++11 is still a bit sparse. Currently - GCC 4.8 - 14.2 (and possibly later) - Clang 3.4 - 20.0 (and possibly later) -- Apple Clang 9.1 - 16.0 (and possibly later) +- Apple Clang 9.1 - 16.1 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later) - Nvidia CUDA Compiler 11.0.221 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) @@ -1146,13 +1146,7 @@ The following compilers are currently used in continuous integration at [AppVeyo | Compiler | Operating System | CI Provider | |--------------------------------------------------------------------------------------------------------|--------------------|----------------| -| Apple Clang 13.0.0 (clang-1300.0.29.3); Xcode 13.1 | macOS 12.7.6 | GitHub Actions | -| Apple Clang 13.0.0 (clang-1300.0.29.30); Xcode 13.2.1 | macOS 12.7.6 | GitHub Actions | -| Apple Clang 13.1.6 (clang-1316.0.21.2.3); Xcode 13.3.1 | macOS 12.7.6 | GitHub Actions | -| Apple Clang 13.1.6 (clang-1316.0.21.2.5); Xcode 13.4.1 | macOS 12.7.6 | GitHub Actions | -| Apple Clang 14.0.0 (clang-1400.0.29.102); Xcode 14.0 | macOS 12.7.6 | GitHub Actions | -| Apple Clang 14.0.0 (clang-1400.0.29.102); Xcode 14.0.1 | macOS 12.7.6 | GitHub Actions | -| Apple Clang 14.0.0 (clang-1400.0.29.202); Xcode 14.1 | macOS 12.7.6 | GitHub Actions | +| Apple Clang 14.0.0 (clang-1400.0.29.202); Xcode 14.1 | macOS 13.7 | GitHub Actions | | Apple Clang 14.0.0 (clang-1400.0.29.202); Xcode 14.2 | macOS 13.7 | GitHub Actions | | Apple Clang 14.0.3 (clang-1403.0.22.14.1); Xcode 14.3 | macOS 13.7 | GitHub Actions | | Apple Clang 14.0.3 (clang-1403.0.22.14.1); Xcode 14.3.1 | macOS 13.7.1 | GitHub Actions | diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index 444709134..106c23fb2 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -463,7 +463,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator==(const IterImpl& other) const @@ -474,7 +474,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); } - JSON_ASSERT(m_object != nullptr); + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + return true; + } switch (m_object->m_data.m_type) { @@ -499,7 +503,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator!=(const IterImpl& other) const @@ -509,7 +513,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator<(const iter_impl& other) const { @@ -519,7 +523,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); } - JSON_ASSERT(m_object != nullptr); + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false + return false; + } switch (m_object->m_data.m_type) { @@ -544,7 +553,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator<=(const iter_impl& other) const { @@ -553,7 +562,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator>(const iter_impl& other) const { @@ -562,7 +571,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) The iterator is initialized; i.e. `m_object != nullptr`, or (2) both iterators are value-initialized. */ bool operator>=(const iter_impl& other) const { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index a6b4c3a71..09fffb3bd 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -13439,7 +13439,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator==(const IterImpl& other) const @@ -13450,7 +13450,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); } - JSON_ASSERT(m_object != nullptr); + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + return true; + } switch (m_object->m_data.m_type) { @@ -13475,7 +13479,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator!=(const IterImpl& other) const @@ -13485,7 +13489,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator<(const iter_impl& other) const { @@ -13495,7 +13499,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); } - JSON_ASSERT(m_object != nullptr); + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false + return false; + } switch (m_object->m_data.m_type) { @@ -13520,7 +13529,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator<=(const iter_impl& other) const { @@ -13529,7 +13538,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. */ bool operator>(const iter_impl& other) const { @@ -13538,7 +13547,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /*! @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. + @pre (1) The iterator is initialized; i.e. `m_object != nullptr`, or (2) both iterators are value-initialized. */ bool operator>=(const iter_impl& other) const { diff --git a/tests/src/unit-iterators3.cpp b/tests/src/unit-iterators3.cpp new file mode 100644 index 000000000..4b5cff7e2 --- /dev/null +++ b/tests/src/unit-iterators3.cpp @@ -0,0 +1,35 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#include +#include +#include + +#include +using nlohmann::json; + +#if (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +#ifdef JSON_HAS_CPP_14 +TEST_CASE_TEMPLATE("checking forward-iterators", T, // NOLINT(readability-math-missing-parentheses) + std::vector, std::string, nlohmann::json) +{ + auto it1 = typename T::iterator{}; + auto it2 = typename T::iterator{}; + CHECK(it1 == it2); + CHECK(it1 <= it2); + CHECK(it1 >= it2); + CHECK_FALSE(it1 != it2); + CHECK_FALSE(it1 < it2); + CHECK_FALSE(it1 > it2); +} +#endif