diff --git a/include/stdexec/__detail/__any_allocator.hpp b/include/stdexec/__detail/__any_allocator.hpp index a72bd483a..857fd1661 100644 --- a/include/stdexec/__detail/__any_allocator.hpp +++ b/include/stdexec/__detail/__any_allocator.hpp @@ -67,6 +67,12 @@ namespace STDEXEC __any_allocator() = default; + // The converting constructor below accesses the private member of another + // specialization of this template, which is rejected by MSVC, Clang and + // GCC. Declare the friendship explicitly. + template + friend struct __any_allocator; + template <__not_same_as<__any_allocator> _Alloc> requires __is_not_instance_of<_Alloc, __any_allocator> && __simple_allocator<_Alloc> __any_allocator(_Alloc __alloc) noexcept diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bf974fbc1..31c368410 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -75,6 +75,7 @@ set(stdexec_test_sources stdexec/algos/consumers/test_sync_wait.cpp stdexec/algos/consumers/test_spawn.cpp stdexec/detail/test_any.cpp + stdexec/detail/test_any_allocator.cpp stdexec/detail/test_common_domain.cpp stdexec/detail/test_completion_signatures.cpp stdexec/detail/test_demangle.cpp diff --git a/test/stdexec/detail/test_any_allocator.cpp b/test/stdexec/detail/test_any_allocator.cpp new file mode 100644 index 000000000..7aa2f4612 --- /dev/null +++ b/test/stdexec/detail/test_any_allocator.cpp @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + * Licensed under the Apache License, Version 2.0 with LLVM Exceptions (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://llvm.org/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +// The converting constructor __any_allocator(_Uy) reads the private member of +// another specialization of the same class template. That access is rejected by +// all major compilers (MSVC C2248, Clang and GCC report it as accessing a +// private member), so the constructor only compiles because it is never +// instantiated in the upstream test matrix. It *is* instantiated whenever +// task_scheduler's type-erased backend copies an allocator on the +// heap-allocation fallback path (e.g. with an asio-based scheduler), breaking +// the build on every compiler; the friend declaration makes the conversion +// legal. This test instantiates the constructor directly and guards the fix +// for NVIDIA/stdexec#2158. +TEST_CASE("__any_allocator cross-specialization converting constructor compiles", + "[detail][allocator]") +{ + STDEXEC::__any_allocator src; + STDEXEC::__any_allocator dst(std::move(src)); // instantiates the converting ctor + CHECK(dst.has_value() == false); +}