Skip to content

Commit

Permalink
[libc++] Fix allocate_shared when used with an explicitly convertible…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
ldionne committed Dec 15, 2020
1 parent 380e1d9 commit a00290e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
3 changes: 2 additions & 1 deletion libcxx/include/__memory/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ struct __allocation_guard {
using _Pointer = typename allocator_traits<_Alloc>::pointer;
using _Size = typename allocator_traits<_Alloc>::size_type;

template<class _AllocT> // 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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <cassert>
#include <cstddef>
#include <memory>

template <class T>
struct ExplicitAllocator {
ExplicitAllocator() = default;
template <class U>
explicit ExplicitAllocator(ExplicitAllocator<U>) { }

using value_type = T;
T* allocate(std::size_t n) { return std::allocator<T>().allocate(n); }
void deallocate(T* ptr, std::size_t n) { return std::allocator<T>().deallocate(ptr, n); }
};

int main(int, char**) {
std::shared_ptr<int> ptr = std::allocate_shared<int>(ExplicitAllocator<int>(), 0);
(void)ptr;

return 0;
}

0 comments on commit a00290e

Please sign in to comment.