From a00290ed10a6b4e9f6e9be44ceec367562f270c6 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 15 Dec 2020 11:45:53 -0500 Subject: [PATCH] [libc++] Fix allocate_shared when used with an explicitly convertible allocator When the allocator is only explicitly convertible from other specializations of itself, the new version of std::allocate_shared would not work because it would try to do an implicit conversion. This patch fixes the problem and adds a test so that we don't fall into the same trap in the future. --- libcxx/include/__memory/utilities.h | 3 +- .../allocate_shared.explicit_conversion.pass.cpp | 32 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.explicit_conversion.pass.cpp diff --git a/libcxx/include/__memory/utilities.h b/libcxx/include/__memory/utilities.h index ccbfbe7..aac3d11 100644 --- a/libcxx/include/__memory/utilities.h +++ b/libcxx/include/__memory/utilities.h @@ -48,8 +48,9 @@ struct __allocation_guard { using _Pointer = typename allocator_traits<_Alloc>::pointer; using _Size = typename allocator_traits<_Alloc>::size_type; + template // we perform the allocator conversion inside the constructor _LIBCPP_HIDE_FROM_ABI - explicit __allocation_guard(_Alloc __alloc, _Size __n) + explicit __allocation_guard(_AllocT __alloc, _Size __n) : __alloc_(_VSTD::move(__alloc)) , __n_(__n) , __ptr_(allocator_traits<_Alloc>::allocate(__alloc_, __n_)) // initialization order is important diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.explicit_conversion.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.explicit_conversion.pass.cpp new file mode 100644 index 0000000..446daa1 --- /dev/null +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.explicit_conversion.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Make sure that std::allocate_shared works with an allocator type that is +// only explicitly convertible from another specialization of itself. + +#include +#include +#include + +template +struct ExplicitAllocator { + ExplicitAllocator() = default; + template + explicit ExplicitAllocator(ExplicitAllocator) { } + + using value_type = T; + T* allocate(std::size_t n) { return std::allocator().allocate(n); } + void deallocate(T* ptr, std::size_t n) { return std::allocator().deallocate(ptr, n); } +}; + +int main(int, char**) { + std::shared_ptr ptr = std::allocate_shared(ExplicitAllocator(), 0); + (void)ptr; + + return 0; +} -- 2.7.4