Skip to content

[libc++] Fix ambiguity when using std::scoped_allocator constructor #80020

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions libcxx/include/scoped_allocator
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ struct __get_is_always_equal<_A0, _Allocs...> {
static const bool value = allocator_traits<_A0>::is_always_equal::value && __get_is_always_equal<_Allocs...>::value;
};

struct __chained_ctor_tag {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some comment to this tag, preferably referring to the bug it fixes.


template <class... _Allocs>
class __scoped_allocator_storage;

Expand Down Expand Up @@ -249,6 +251,7 @@ protected:
scoped_allocator_adaptor<outer_allocator_type, _InnerAllocs...> _LIBCPP_HIDE_FROM_ABI
select_on_container_copy_construction() const _NOEXCEPT {
return scoped_allocator_adaptor<outer_allocator_type, _InnerAllocs...>(
__chained_ctor_tag(),
allocator_traits<outer_allocator_type>::select_on_container_copy_construction(outer_allocator()),
allocator_traits<inner_allocator_type>::select_on_container_copy_construction(inner_allocator()));
}
Expand Down Expand Up @@ -334,12 +337,12 @@ struct __outermost<_Alloc, true> {
template <class _OuterAlloc, class... _InnerAllocs>
class _LIBCPP_TEMPLATE_VIS scoped_allocator_adaptor<_OuterAlloc, _InnerAllocs...>
: public __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...> {
typedef __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...> base;
typedef __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...> _Base;
typedef allocator_traits<_OuterAlloc> _OuterTraits;

public:
typedef _OuterAlloc outer_allocator_type;
typedef typename base::inner_allocator_type inner_allocator_type;
typedef typename _Base::inner_allocator_type inner_allocator_type;
typedef typename _OuterTraits::size_type size_type;
typedef typename _OuterTraits::difference_type difference_type;
typedef typename _OuterTraits::pointer pointer;
Expand All @@ -365,29 +368,29 @@ public:
template <class _OuterA2, __enable_if_t<is_constructible<outer_allocator_type, _OuterA2>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI
scoped_allocator_adaptor(_OuterA2&& __outer_alloc, const _InnerAllocs&... __inner_allocs) _NOEXCEPT
: base(std::forward<_OuterA2>(__outer_alloc), __inner_allocs...) {}
: _Base(std::forward<_OuterA2>(__outer_alloc), __inner_allocs...) {}
// scoped_allocator_adaptor(const scoped_allocator_adaptor& __other) = default;
template <class _OuterA2, __enable_if_t<is_constructible<outer_allocator_type, const _OuterA2&>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI
scoped_allocator_adaptor(const scoped_allocator_adaptor<_OuterA2, _InnerAllocs...>& __other) _NOEXCEPT
: base(__other) {}
: _Base(__other) {}
template <class _OuterA2, __enable_if_t<is_constructible<outer_allocator_type, _OuterA2>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI
scoped_allocator_adaptor(scoped_allocator_adaptor<_OuterA2, _InnerAllocs...>&& __other) _NOEXCEPT
: base(std::move(__other)) {}
: _Base(std::move(__other)) {}

// scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default;
// scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default;
// ~scoped_allocator_adaptor() = default;

_LIBCPP_HIDE_FROM_ABI inner_allocator_type& inner_allocator() _NOEXCEPT { return base::inner_allocator(); }
_LIBCPP_HIDE_FROM_ABI inner_allocator_type& inner_allocator() _NOEXCEPT { return _Base::inner_allocator(); }
_LIBCPP_HIDE_FROM_ABI const inner_allocator_type& inner_allocator() const _NOEXCEPT {
return base::inner_allocator();
return _Base::inner_allocator();
}

_LIBCPP_HIDE_FROM_ABI outer_allocator_type& outer_allocator() _NOEXCEPT { return base::outer_allocator(); }
_LIBCPP_HIDE_FROM_ABI outer_allocator_type& outer_allocator() _NOEXCEPT { return _Base::outer_allocator(); }
_LIBCPP_HIDE_FROM_ABI const outer_allocator_type& outer_allocator() const _NOEXCEPT {
return base::outer_allocator();
return _Base::outer_allocator();
}

_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI pointer allocate(size_type __n) {
Expand Down Expand Up @@ -472,13 +475,14 @@ public:
}

_LIBCPP_HIDE_FROM_ABI scoped_allocator_adaptor select_on_container_copy_construction() const _NOEXCEPT {
return base::select_on_container_copy_construction();
return _Base::select_on_container_copy_construction();
}

private:
template <class _OuterA2, __enable_if_t<is_constructible<outer_allocator_type, _OuterA2>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI scoped_allocator_adaptor(_OuterA2&& __o, const inner_allocator_type& __i) _NOEXCEPT
: base(std::forward<_OuterA2>(__o), __i) {}
_LIBCPP_HIDE_FROM_ABI
scoped_allocator_adaptor(__chained_ctor_tag, _OuterA2&& __o, const inner_allocator_type& __i) _NOEXCEPT
: _Base(std::forward<_OuterA2>(__o), __i) {}

template <class _Tp, class... _Args>
_LIBCPP_HIDE_FROM_ABI void __construct(integral_constant<int, 0>, _Tp* __p, _Args&&... __args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
// scoped_allocator_adaptor(OuterA2&& outerAlloc,
// const InnerAllocs& ...innerAllocs);

#include <scoped_allocator>
#include <cassert>
#include <memory_resource>
#include <scoped_allocator>

#include "test_macros.h"
#include "allocators.h"
Expand Down Expand Up @@ -111,6 +112,17 @@ int main(int, char**) {
!std::is_convertible< std::scoped_allocator_adaptor<A1<int>>, std::scoped_allocator_adaptor<A2<int>>>::value,
"");
}
{
// https://github.com/llvm/llvm-project/issues/78754
using PA = std::pmr::polymorphic_allocator<int>;
std::pmr::monotonic_buffer_resource mr1;
std::pmr::monotonic_buffer_resource mr2;

using A = std::scoped_allocator_adaptor<PA, PA>;
A a(&mr1, &mr2);
assert(a.outer_allocator().resource() == &mr1);
assert(a.inner_allocator().resource() == &mr2);
}

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03

// <memory>

// This test ensures that we don't use a non-uglified name 'base' in the
// implementation of scoped_allcoator_adaptor.
//
// See https://github.com/llvm/llvm-project/issues/78754.

#include <memory>
#include <scoped_allocator>

using ScopedAlloc = std::scoped_allocator_adaptor<std::allocator<int>, std::allocator<int>>;
struct MyBase {
using base = MyBase;
};
struct MyDerived : ScopedAlloc, MyBase {};

using T = MyDerived::base; // Should be well-formed