blob: 2a9ca2b39b4b330cc6e407a54469c6f55dc6931d [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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_resource>
// template <class T> class polymorphic_allocator
// template <class U1, class U2, class ...Args1, class ...Args2>
// void polymorphic_allocator<T>::construct(pair<U1, U2>*, piecewise_construct_t
// tuple<Args1...>, tuple<Args2...>)
#include <experimental/memory_resource>
#include <tuple>
#include <type_traits>
#include <utility>
#include <cassert>
#include <cstdlib>
#include "test_macros.h"
namespace ex = std::experimental::pmr;
template <class T>
struct EvilAlloc {
explicit EvilAlloc() : inner_(ex::null_memory_resource()) {}
EvilAlloc(ex::polymorphic_allocator<T> & a) : inner_(a) {}
EvilAlloc(ex::polymorphic_allocator<T> && a) : inner_(a) {}
EvilAlloc(ex::polymorphic_allocator<T> const & a) = delete;
EvilAlloc(ex::polymorphic_allocator<T> const && a) = delete;
using value_type = T;
template <class U> EvilAlloc(EvilAlloc<U> const & rhs) : inner_(rhs.inner_) {}
ex::polymorphic_allocator<T> inner_;
};
struct WidgetV0 {
WidgetV0(int v) : value_(v) {}
bool holds(int v, const ex::polymorphic_allocator<char>&) const {
return value_ == v;
}
private:
int value_;
};
struct WidgetV1 {
using allocator_type = EvilAlloc<char>;
WidgetV1(int v) : value_(v), alloc_() {}
WidgetV1(std::allocator_arg_t, EvilAlloc<char> a, int v) : value_(v), alloc_(a) {}
bool holds(int v, const ex::polymorphic_allocator<char>& a) const {
return value_ == v && alloc_.inner_ == a;
}
private:
int value_;
EvilAlloc<char> alloc_;
};
struct WidgetV2 {
using allocator_type = EvilAlloc<char>;
WidgetV2(int v) : value_(v), alloc_() {}
WidgetV2(int v, EvilAlloc<char> a) : value_(v), alloc_(a) {}
bool holds(int v, ex::polymorphic_allocator<char> a) const {
return value_ == v && alloc_.inner_ == a;
}
private:
int value_;
EvilAlloc<char> alloc_;
};
struct WidgetV3 {
using allocator_type = EvilAlloc<char>;
WidgetV3(int v) : value_(v), alloc_() {}
WidgetV3(std::allocator_arg_t, EvilAlloc<char> a, int v) : value_(v), alloc_(a) {}
WidgetV3(int v, EvilAlloc<char> a) : value_(v), alloc_(a) {}
bool holds(int v, ex::polymorphic_allocator<char> a) const {
return value_ == v && alloc_.inner_ == a;
}
private:
int value_;
EvilAlloc<char> alloc_;
};
static_assert(std::uses_allocator<WidgetV1, EvilAlloc<char>>::value, "");
static_assert(std::uses_allocator<WidgetV2, EvilAlloc<char>>::value, "");
static_assert(std::uses_allocator<WidgetV3, EvilAlloc<char>>::value, "");
static_assert(std::uses_allocator<WidgetV1, ex::polymorphic_allocator<char>>::value, "");
static_assert(std::uses_allocator<WidgetV2, ex::polymorphic_allocator<char>>::value, "");
static_assert(std::uses_allocator<WidgetV3, ex::polymorphic_allocator<char>>::value, "");
template<class W1, class W2>
void test_evil()
{
using PMA = ex::polymorphic_allocator<char>;
PMA pma(ex::new_delete_resource());
{
using Pair = std::pair<W1, W2>;
void *where = std::malloc(sizeof (Pair));
Pair *p = (Pair *)where;
pma.construct(p, std::piecewise_construct, std::make_tuple(42), std::make_tuple(42));
assert(p->first.holds(42, pma));
assert(p->second.holds(42, pma));
pma.destroy(p);
std::free(where);
}
}
int main(int, char**)
{
test_evil<WidgetV0, WidgetV0>();
test_evil<WidgetV0, WidgetV1>();
test_evil<WidgetV0, WidgetV2>();
test_evil<WidgetV0, WidgetV3>();
test_evil<WidgetV1, WidgetV0>();
test_evil<WidgetV1, WidgetV1>();
test_evil<WidgetV1, WidgetV2>();
test_evil<WidgetV1, WidgetV3>();
test_evil<WidgetV2, WidgetV0>();
test_evil<WidgetV2, WidgetV1>();
test_evil<WidgetV2, WidgetV2>();
test_evil<WidgetV2, WidgetV3>();
test_evil<WidgetV3, WidgetV0>();
test_evil<WidgetV3, WidgetV1>();
test_evil<WidgetV3, WidgetV2>();
test_evil<WidgetV3, WidgetV3>();
return 0;
}