Fix CI: skip std::pair noexcept assumptions on EDG-based compilers

ci_icpc and ci_nvhpc failed to compile unit-ordered_map.cpp: the static
assertion that std::pair<const std::string, ordered_json> is not nothrow
move-constructible fails there. The EDG front end (Intel icpc 2021.10,
NVIDIA nvc++ 25.5) considers the defaulted move constructor of
std::pair<const Key, T> noexcept even if copying Key can throw. With these
compilers, std::vector already moves such elements itself when it grows,
and ordered_map correctly leaves growing to it.

The same misjudgement makes std::vector call std::terminate when a key copy
throws during growth, so the exception-safety test with throwing_key would
abort on these compilers as well.

Skip the static assertion and the exception-safety section when __EDG__ is
defined. Verified with icpc 2021.10 (-std=gnu++11) and nvc++ 25.5 (C++11 and
C++17) on Compiler Explorer: unit-ordered_map and unit-disabled_exceptions
build and pass.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-29 16:44:24 +02:00
parent 998456a218
commit c5d40f05fe
+13 -3
View File
@@ -17,6 +17,14 @@ using nlohmann::ordered_map;
#include <utility> #include <utility>
#include <vector> #include <vector>
// The EDG front end (Intel icpc, NVIDIA nvc++) considers the defaulted move
// constructor of std::pair<const Key, T> noexcept even if copying Key can
// throw. std::vector then moves such elements itself when it grows (and calls
// std::terminate if a key copy throws), so ordered_map leaves growing to it.
#if defined(__EDG__)
#define JSON_TEST_PAIR_MOVE_IS_NOEXCEPT
#endif
namespace namespace
{ {
// number of copies made of counted values // number of copies made of counted values
@@ -46,7 +54,7 @@ struct counted // NOLINT(cppcoreguidelines-special-member-functions,hicpp-specia
} }
}; };
#if !defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION) && !defined(JSON_TEST_PAIR_MOVE_IS_NOEXCEPT)
// number of throwing_key copies that still succeed; the next one throws // number of throwing_key copies that still succeed; the next one throws
// (a negative value means that copies never throw) // (a negative value means that copies never throw)
int key_copies_until_throw = -1; int key_copies_until_throw = -1;
@@ -86,7 +94,9 @@ struct no_default
// ordered_json must keep moving its values when an object grows // ordered_json must keep moving its values when an object grows
using ordered_object_t = nlohmann::ordered_json::object_t; using ordered_object_t = nlohmann::ordered_json::object_t;
static_assert(!std::is_nothrow_move_constructible<ordered_object_t::value_type>::value, "std::vector would move the elements itself"); #if !defined(JSON_TEST_PAIR_MOVE_IS_NOEXCEPT)
static_assert(!std::is_nothrow_move_constructible<ordered_object_t::value_type>::value, "std::vector would move the elements itself");
#endif
static_assert(std::is_copy_constructible<ordered_object_t::key_type>::value, "keys must be copyable"); static_assert(std::is_copy_constructible<ordered_object_t::key_type>::value, "keys must be copyable");
static_assert(std::is_default_constructible<ordered_object_t::mapped_type>::value, "values must be default-constructible"); static_assert(std::is_default_constructible<ordered_object_t::mapped_type>::value, "values must be default-constructible");
static_assert(std::is_nothrow_move_assignable<ordered_object_t::mapped_type>::value, "values must be nothrow move-assignable"); static_assert(std::is_nothrow_move_assignable<ordered_object_t::mapped_type>::value, "values must be nothrow move-assignable");
@@ -566,7 +576,7 @@ TEST_CASE("ordered_map growth")
} }
} }
#if !defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION) && !defined(JSON_TEST_PAIR_MOVE_IS_NOEXCEPT)
SECTION("the container is unchanged if growing it throws") SECTION("the container is unchanged if growing it throws")
{ {
ordered_map<throwing_key, counted> om; ordered_map<throwing_key, counted> om;