1 // Copyright (C) 2016-2020 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library.  This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3.  If not see
16 // <http://www.gnu.org/licenses/>.
17 
18 // { dg-do compile { target c++11 } }
19 
20 #include <scoped_allocator>
21 
22 template<typename T>
23 struct alloc
24 {
25   using value_type = T;
26   alloc() = default;
27   template<typename U>
allocalloc28     alloc(alloc<U>) { }
29   T* allocate(std::size_t);
30   void deallocate(T*, std::size_t);
31 };
32 
33 template<typename T, typename U>
operator ==(alloc<T>,alloc<U>)34   bool operator==(alloc<T>, alloc<U>) { return true; }
35 
36 template<typename T, typename U>
operator !=(alloc<T>,alloc<U>)37   bool operator!=(alloc<T>, alloc<U>) { return false; }
38 
39 struct X
40 {
41   using allocator_type = alloc<int>;
42   X(const allocator_type&);
43 };
44 
45 template<typename A>
46 struct nested_alloc : A
47 {
48   nested_alloc() = default;
49   template<typename U>
nested_allocnested_alloc50     nested_alloc(nested_alloc<U>) { }
51 
outer_allocatornested_alloc52   A& outer_allocator() { return *this; }
53 
54   template<typename U, typename... Args>
constructnested_alloc55     void construct(U*, Args&&...)
56     {
57       static_assert(!std::is_same<U, X>::value,
58           "OUTERMOST should recurse and use alloc<int> to construct X");
59     }
60 };
61 
62 template<typename T, typename U>
operator ==(nested_alloc<T> l,nested_alloc<U> r)63   bool operator==(nested_alloc<T> l, nested_alloc<U> r)
64   { return l.outer_allocator() == r.outer_allocator(); }
65 
66 template<typename T, typename U>
operator !=(nested_alloc<T> l,nested_alloc<U> r)67   bool operator!=(nested_alloc<T> l, nested_alloc<U> r)
68   { return !(l == r); }
69 
70 template<typename A>
71   using scoped_alloc = std::scoped_allocator_adaptor<A>;
72 
73 void
test01()74 test01()
75 {
76   scoped_alloc<nested_alloc<alloc<int>>> a;
77   alignas(X) char buf[sizeof(X)];
78   X* p = (X*)buf;
79   // Test that OUTERMOST is recursive and doesn't just unwrap one level:
80   a.construct(p);
81 }
82 
83 void
test02()84 test02()
85 {
86   scoped_alloc<scoped_alloc<nested_alloc<alloc<int>>>> a;
87   alignas(X) char buf[sizeof(X)];
88   X* p = (X*)buf;
89   // Test that OUTERMOST is recursive and doesn't just unwrap one level:
90   a.construct(p);
91 }
92