Fix nvcc CUDA 12.0/12.1 C++20 ranges parse error (#3907)

The diagnostic matrix in this PR confirmed the affected range exactly:
nvcc 12.0.1 and 12.1.1 both fail with "expected initializer before
'<' token" on iteration_proxy.hpp's enable_borrowed_range variable
template specialization at -std=c++20; 12.2.2 and newer already build
cleanly. Guard JSON_HAS_RANGES off for that narrow nvcc version range,
matching the existing GCC-11/libstdc++ carve-outs in the same ifdef
chain, and regenerate single_include accordingly.

Broaden the CUDA smoke test to also exercise comparisons
(operator==/operator<=>, gated independently by
JSON_HAS_THREE_WAY_COMPARISON) and range-based iteration, not just
dump()/erase(), so the fix's actual scope is evidenced by CI rather
than assumed from the single reported symptom.

Have tests/cuda_example/CMakeLists.txt pick the newest C++ standard
the detected nvcc version actually supports (20/17/11) instead of
hard-requiring C++20, so older toolkits build at a lower standard
instead of failing CMake configure outright. This is test-project-local
only; the JSON_HAS_RANGES guard is what protects real client code,
since a header can't control what -std= flag it's compiled with.

Right-size the CI matrix from the 8-version diagnostic sweep down to
11.8.0 (C++17 fallback path) / 12.1.1 (permanent #3907 regression
guard) / 12.6.3 (recent coverage), and update the compiler-version
table in the quality assurance docs to match.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-07-09 07:12:01 +02:00
parent f3d48e4f2f
commit 8917c42bbc
6 changed files with 45 additions and 6 deletions
+6 -4
View File
@@ -237,10 +237,12 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
# matrix to empirically pin down which nvcc/CUDA versions reproduce #3907 # 11.8.0: newest pre-C++20 CUDA release, exercises the C++17 fallback
# (a c++20 parse error in iteration_proxy.hpp's enable_borrowed_range) before # path (tests/cuda_example/CMakeLists.txt picks the standard per nvcc
# attempting a source-level fix; 11.8 predates CUDA's C++20 support entirely. # version); 12.1.1: permanent regression guard for #3907 (nvcc 12.0/12.1
cuda: ['11.8.0', '12.0.1', '12.1.1', '12.2.2', '12.3.2', '12.4.1', '12.5.1', '12.6.3'] # choke on enable_borrowed_range at C++20, fixed in 12.2); 12.6.3: recent
# CUDA/C++20 coverage.
cuda: ['11.8.0', '12.1.1', '12.6.3']
container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu22.04 container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu22.04
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -62,7 +62,9 @@ violations will result in a failed build.
| Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub | | Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub |
| Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| CUDA 11.0.221 (nvcc) | x86_64 | Ubuntu 20.04 LTS | GitHub | | CUDA 11.8.0 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| CUDA 12.1.1 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| CUDA 12.6.3 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| Emscripten 4.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Emscripten 4.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.8.5 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 4.8.5 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.9.3 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 4.9.3 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
+5
View File
@@ -146,6 +146,11 @@
#define JSON_HAS_RANGES 0 #define JSON_HAS_RANGES 0
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000 #elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
#define JSON_HAS_RANGES 0 #define JSON_HAS_RANGES 0
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
// syntax when compiling as CUDA source; fixed in CUDA 12.2 (issue #3907)
#elif defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) && __CUDACC_VER_MAJOR__ == 12 \
&& defined(__CUDACC_VER_MINOR__) && (__CUDACC_VER_MINOR__ == 0 || __CUDACC_VER_MINOR__ == 1)
#define JSON_HAS_RANGES 0
#elif defined(__cpp_lib_ranges) #elif defined(__cpp_lib_ranges)
#define JSON_HAS_RANGES 1 #define JSON_HAS_RANGES 1
#else #else
+5
View File
@@ -2520,6 +2520,11 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define JSON_HAS_RANGES 0 #define JSON_HAS_RANGES 0
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000 #elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
#define JSON_HAS_RANGES 0 #define JSON_HAS_RANGES 0
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
// syntax when compiling as CUDA source; fixed in CUDA 12.2 (issue #3907)
#elif defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) && __CUDACC_VER_MAJOR__ == 12 \
&& defined(__CUDACC_VER_MINOR__) && (__CUDACC_VER_MINOR__ == 0 || __CUDACC_VER_MINOR__ == 1)
#define JSON_HAS_RANGES 0
#elif defined(__cpp_lib_ranges) #elif defined(__cpp_lib_ranges)
#define JSON_HAS_RANGES 1 #define JSON_HAS_RANGES 1
#else #else
+12 -1
View File
@@ -3,7 +3,18 @@ project(json_cuda LANGUAGES CUDA)
add_executable(json_cuda json_cuda.cu) add_executable(json_cuda json_cuda.cu)
target_include_directories(json_cuda PRIVATE ../../include) target_include_directories(json_cuda PRIVATE ../../include)
target_compile_features(json_cuda PUBLIC cuda_std_20)
# nvcc added C++20 support in CUDA 12.0 and C++17 in CUDA 11.0; pick the
# newest standard the detected compiler actually supports (see #3907)
# instead of hard-requiring one standard for every CUDA version.
if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0)
set(json_cuda_std 20)
elseif(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0)
set(json_cuda_std 17)
else()
set(json_cuda_std 11)
endif()
target_compile_features(json_cuda PUBLIC cuda_std_${json_cuda_std})
set_target_properties(json_cuda PROPERTIES set_target_properties(json_cuda PROPERTIES
CUDA_EXTENSIONS OFF CUDA_EXTENSIONS OFF
CUDA_STANDARD_REQUIRED ON CUDA_STANDARD_REQUIRED ON
+14
View File
@@ -16,4 +16,18 @@ int main()
// regression for #3013 (ordered_json::reset() compile error with nvcc) // regression for #3013 (ordered_json::reset() compile error with nvcc)
nlohmann::ordered_json metadata; nlohmann::ordered_json metadata;
metadata.erase("key"); metadata.erase("key");
// exercise comparisons (operator==/operator<=>, gated by
// JSON_HAS_THREE_WAY_COMPARISON, independent of JSON_HAS_RANGES) and
// range-based iteration (exercises iteration_proxy/ranges machinery
// beyond just the enable_borrowed_range specialization) — see #3907
nlohmann::json a = {1, 2, 3};
nlohmann::json b = {1, 2, 3};
static_cast<void>(a == b);
static_cast<void>(a <=> b); // *NOPAD*
static_cast<void>(a <=> 1); // *NOPAD*
for (const auto& element : a)
{
static_cast<void>(element);
}
} }