Skip to content

Commit 68072a7

Browse files
committed
[libc++] P0433R2: test that deduction guides are properly SFINAEd away.
Deduction guides for containers should not participate in overload resolution when called with certain incorrect types (e.g. when called with a template argument in place of an `InputIterator` that doesn't qualify as an input iterator). Similarly, class template argument deduction should not select `unique_ptr` constructors that take a a pointer. The tests try out every possible incorrect parameter (but never more than one incorrect parameter in the same invocation). Also add deduction guides to the synopsis for associative and unordered containers (this was accidentally omitted from [D112510](https://reviews.llvm.org/D112510)). Differential Revision: https://reviews.llvm.org/D112904
1 parent 8619212 commit 68072a7

File tree

29 files changed

+883
-58
lines changed

29 files changed

+883
-58
lines changed

libcxx/docs/Status/Cxx17.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ Paper Status
4040

4141
.. note::
4242

43-
.. [#note-P0433] P0433: The only part not fully implemented is the requirement that certain deduction guides should not participate in overload resolution when given incorrect template arguments.
4443
.. [#note-P0607] P0607: The parts of P0607 that are not done are the ``<regex>`` bits.
4544
4645

libcxx/docs/Status/Cxx17Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
"`P0298R3 <https://wg21.link/P0298R3>`__","CWG","A byte type definition","Kona","|Complete|","5.0"
9595
"`P0317R1 <https://wg21.link/P0317R1>`__","LWG","Directory Entry Caching for Filesystem","Kona","|Complete|","7.0"
9696
"`P0430R2 <https://wg21.link/P0430R2>`__","LWG","File system library on non-POSIX-like operating systems","Kona","|Complete|","7.0"
97-
"`P0433R2 <https://wg21.link/P0433R2>`__","LWG","Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library","Kona","|In Progress| [#note-P0433]_","7.0"
97+
"`P0433R2 <https://wg21.link/P0433R2>`__","LWG","Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library","Kona","|Complete|","14.0"
9898
"`P0452R1 <https://wg21.link/P0452R1>`__","LWG","Unifying <numeric> Parallel Algorithms","Kona","",""
9999
"`P0467R2 <https://wg21.link/P0467R2>`__","LWG","Iterator Concerns for Parallel Algorithms","Kona","",""
100100
"`P0492R2 <https://wg21.link/P0492R2>`__","LWG","Proposed Resolution of C++17 National Body Comments for Filesystems","Kona","|Complete|","7.0"

libcxx/include/__memory/allocator_traits.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,14 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
349349
}
350350
};
351351

352+
// A version of `allocator_traits` for internal usage that SFINAEs away if the
353+
// given allocator doesn't have a nested `value_type`. This helps avoid hard
354+
// errors when forming implicit deduction guides for a container that has an
355+
// invalid Allocator type. See https://wg21.link/LWGXXXXX.
356+
// TODO(varconst): use the actual link once available.
357+
template <class _Alloc, class _ValueType = typename _Alloc::value_type>
358+
struct _LIBCPP_TEMPLATE_VIS __allocator_traits : allocator_traits<_Alloc> {};
359+
352360
template <class _Traits, class _Tp>
353361
struct __rebind_alloc_helper {
354362
#ifndef _LIBCPP_CXX03_LANG

libcxx/include/deque

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public:
129129
130130
template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
131131
deque(InputIterator, InputIterator, Allocator = Allocator())
132-
-> deque<typename iterator_traits<InputIterator>::value_type, Allocator>;
132+
-> deque<typename iterator_traits<InputIterator>::value_type, Allocator>; // C++17
133133
134134
template <class T, class Allocator>
135135
bool operator==(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
@@ -162,6 +162,7 @@ template <class T, class Allocator, class Predicate>
162162

163163
#include <__config>
164164
#include <__debug>
165+
#include <__iterator/iterator_traits.h>
165166
#include <__split_buffer>
166167
#include <__utility/forward.h>
167168
#include <algorithm>
@@ -1258,20 +1259,20 @@ public:
12581259
static_assert((is_same<typename allocator_type::value_type, value_type>::value),
12591260
"Allocator::value_type must be same type as value_type");
12601261

1261-
typedef __deque_base<value_type, allocator_type> __base;
1262+
typedef __deque_base<value_type, allocator_type> __base;
12621263

1263-
typedef typename __base::__alloc_traits __alloc_traits;
1264-
typedef typename __base::reference reference;
1265-
typedef typename __base::const_reference const_reference;
1266-
typedef typename __base::iterator iterator;
1267-
typedef typename __base::const_iterator const_iterator;
1268-
typedef typename __base::size_type size_type;
1269-
typedef typename __base::difference_type difference_type;
1264+
typedef typename __base::__alloc_traits __alloc_traits;
1265+
typedef typename __base::reference reference;
1266+
typedef typename __base::const_reference const_reference;
1267+
typedef typename __base::iterator iterator;
1268+
typedef typename __base::const_iterator const_iterator;
1269+
typedef typename __allocator_traits<allocator_type>::size_type size_type;
1270+
typedef typename __base::difference_type difference_type;
12701271

1271-
typedef typename __base::pointer pointer;
1272-
typedef typename __base::const_pointer const_pointer;
1273-
typedef _VSTD::reverse_iterator<iterator> reverse_iterator;
1274-
typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator;
1272+
typedef typename __base::pointer pointer;
1273+
typedef typename __base::const_pointer const_pointer;
1274+
typedef _VSTD::reverse_iterator<iterator> reverse_iterator;
1275+
typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator;
12751276

12761277
using typename __base::__deque_range;
12771278
using typename __base::__deque_block_range;
@@ -1568,20 +1569,21 @@ public:
15681569
#if _LIBCPP_STD_VER >= 17
15691570
template<class _InputIterator,
15701571
class _Alloc = allocator<__iter_value_type<_InputIterator>>,
1572+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
15711573
class = enable_if_t<__is_allocator<_Alloc>::value>
15721574
>
15731575
deque(_InputIterator, _InputIterator)
15741576
-> deque<__iter_value_type<_InputIterator>, _Alloc>;
15751577

15761578
template<class _InputIterator,
15771579
class _Alloc,
1580+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
15781581
class = enable_if_t<__is_allocator<_Alloc>::value>
15791582
>
15801583
deque(_InputIterator, _InputIterator, _Alloc)
15811584
-> deque<__iter_value_type<_InputIterator>, _Alloc>;
15821585
#endif
15831586

1584-
15851587
template <class _Tp, class _Allocator>
15861588
deque<_Tp, _Allocator>::deque(size_type __n)
15871589
{

libcxx/include/forward_list

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ public:
647647
typedef const value_type& const_reference;
648648
typedef typename allocator_traits<allocator_type>::pointer pointer;
649649
typedef typename allocator_traits<allocator_type>::const_pointer const_pointer;
650-
typedef typename allocator_traits<allocator_type>::size_type size_type;
650+
typedef typename __allocator_traits<allocator_type>::size_type size_type;
651651
typedef typename allocator_traits<allocator_type>::difference_type difference_type;
652652

653653
typedef typename base::iterator iterator;
@@ -873,13 +873,15 @@ private:
873873
#if _LIBCPP_STD_VER >= 17
874874
template<class _InputIterator,
875875
class _Alloc = allocator<__iter_value_type<_InputIterator>>,
876+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
876877
class = enable_if_t<__is_allocator<_Alloc>::value>
877878
>
878879
forward_list(_InputIterator, _InputIterator)
879880
-> forward_list<__iter_value_type<_InputIterator>, _Alloc>;
880881

881882
template<class _InputIterator,
882883
class _Alloc,
884+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
883885
class = enable_if_t<__is_allocator<_Alloc>::value>
884886
>
885887
forward_list(_InputIterator, _InputIterator, _Alloc)

libcxx/include/list

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -845,24 +845,24 @@ class _LIBCPP_TEMPLATE_VIS list
845845
typedef typename base::__link_pointer __link_pointer;
846846

847847
public:
848-
typedef _Tp value_type;
849-
typedef _Alloc allocator_type;
848+
typedef _Tp value_type;
849+
typedef _Alloc allocator_type;
850850
static_assert((is_same<value_type, typename allocator_type::value_type>::value),
851851
"Invalid allocator::value_type");
852-
typedef value_type& reference;
853-
typedef const value_type& const_reference;
854-
typedef typename base::pointer pointer;
855-
typedef typename base::const_pointer const_pointer;
856-
typedef typename base::size_type size_type;
857-
typedef typename base::difference_type difference_type;
858-
typedef typename base::iterator iterator;
859-
typedef typename base::const_iterator const_iterator;
860-
typedef _VSTD::reverse_iterator<iterator> reverse_iterator;
861-
typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator;
852+
typedef value_type& reference;
853+
typedef const value_type& const_reference;
854+
typedef typename base::pointer pointer;
855+
typedef typename base::const_pointer const_pointer;
856+
typedef typename __allocator_traits<allocator_type>::size_type size_type;
857+
typedef typename base::difference_type difference_type;
858+
typedef typename base::iterator iterator;
859+
typedef typename base::const_iterator const_iterator;
860+
typedef _VSTD::reverse_iterator<iterator> reverse_iterator;
861+
typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator;
862862
#if _LIBCPP_STD_VER > 17
863-
typedef size_type __remove_return_type;
863+
typedef size_type __remove_return_type;
864864
#else
865-
typedef void __remove_return_type;
865+
typedef void __remove_return_type;
866866
#endif
867867

868868
_LIBCPP_INLINE_VISIBILITY
@@ -1144,13 +1144,15 @@ private:
11441144
#if _LIBCPP_STD_VER >= 17
11451145
template<class _InputIterator,
11461146
class _Alloc = allocator<__iter_value_type<_InputIterator>>,
1147+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
11471148
class = enable_if_t<__is_allocator<_Alloc>::value>
11481149
>
11491150
list(_InputIterator, _InputIterator)
11501151
-> list<__iter_value_type<_InputIterator>, _Alloc>;
11511152

11521153
template<class _InputIterator,
11531154
class _Alloc,
1155+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
11541156
class = enable_if_t<__is_allocator<_Alloc>::value>
11551157
>
11561158
list(_InputIterator, _InputIterator, _Alloc)

libcxx/include/map

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,25 @@ public:
223223
pair<const_iterator,const_iterator> equal_range(const K& x) const; // C++14
224224
};
225225
226+
template <class InputIterator,
227+
class Compare = less<iter_key_t<InputIterator>>,
228+
class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
229+
map(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator())
230+
-> map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Compare, Allocator>; // C++17
231+
232+
template<class Key, class T, class Compare = less<Key>,
233+
class Allocator = allocator<pair<const Key, T>>>
234+
map(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
235+
-> map<Key, T, Compare, Allocator>; // C++17
236+
237+
template <class InputIterator, class Allocator>
238+
map(InputIterator, InputIterator, Allocator)
239+
-> map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, less<iter_key_t<InputIterator>>,
240+
Allocator>; // C++17
241+
242+
template<class Key, class T, class Allocator>
243+
map(initializer_list<pair<const Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>; // C++17
244+
226245
template <class Key, class T, class Compare, class Allocator>
227246
bool
228247
operator==(const map<Key, T, Compare, Allocator>& x,
@@ -444,6 +463,26 @@ public:
444463
pair<const_iterator,const_iterator> equal_range(const K& x) const; // C++14
445464
};
446465
466+
template <class InputIterator,
467+
class Compare = less<iter_key_t<InputIterator>>,
468+
class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
469+
multimap(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator())
470+
-> multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Compare, Allocator>; // C++17
471+
472+
template<class Key, class T, class Compare = less<Key>,
473+
class Allocator = allocator<pair<const Key, T>>>
474+
multimap(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
475+
-> multimap<Key, T, Compare, Allocator>; // C++17
476+
477+
template <class InputIterator, class Allocator>
478+
multimap(InputIterator, InputIterator, Allocator)
479+
-> multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
480+
less<iter_key_t<InputIterator>>, Allocator>; // C++17
481+
482+
template<class Key, class T, class Allocator>
483+
multimap(initializer_list<pair<const Key, T>>, Allocator)
484+
-> multimap<Key, T, less<Key>, Allocator>; // C++17
485+
447486
template <class Key, class T, class Compare, class Allocator>
448487
bool
449488
operator==(const multimap<Key, T, Compare, Allocator>& x,
@@ -492,6 +531,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
492531
#include <__config>
493532
#include <__debug>
494533
#include <__functional/is_transparent.h>
534+
#include <__iterator/iterator_traits.h>
495535
#include <__node_handle>
496536
#include <__tree>
497537
#include <__utility/forward.h>
@@ -1501,6 +1541,7 @@ private:
15011541
#if _LIBCPP_STD_VER >= 17
15021542
template<class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>,
15031543
class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
1544+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
15041545
class = enable_if_t<!__is_allocator<_Compare>::value, void>,
15051546
class = enable_if_t<__is_allocator<_Allocator>::value, void>>
15061547
map(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator())
@@ -1514,6 +1555,7 @@ map(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare(), _Allocator = _Allo
15141555
-> map<remove_const_t<_Key>, _Tp, _Compare, _Allocator>;
15151556

15161557
template<class _InputIterator, class _Allocator,
1558+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
15171559
class = enable_if_t<__is_allocator<_Allocator>::value, void>>
15181560
map(_InputIterator, _InputIterator, _Allocator)
15191561
-> map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
@@ -2174,6 +2216,7 @@ private:
21742216
#if _LIBCPP_STD_VER >= 17
21752217
template<class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>,
21762218
class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
2219+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
21772220
class = enable_if_t<!__is_allocator<_Compare>::value, void>,
21782221
class = enable_if_t<__is_allocator<_Allocator>::value, void>>
21792222
multimap(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator())
@@ -2187,6 +2230,7 @@ multimap(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare(), _Allocator =
21872230
-> multimap<remove_const_t<_Key>, _Tp, _Compare, _Allocator>;
21882231

21892232
template<class _InputIterator, class _Allocator,
2233+
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value, void>,
21902234
class = enable_if_t<__is_allocator<_Allocator>::value, void>>
21912235
multimap(_InputIterator, _InputIterator, _Allocator)
21922236
-> multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,

libcxx/include/queue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,16 @@ template<class InputIterator, class Allocator>
185185
priority_queue(InputIterator, InputIterator, Allocator)
186186
-> priority_queue<iter-value-type<InputIterator>,
187187
vector<iter-value-type<InputIterator>, Allocator>,
188-
less<iter-value-type<InputIterator>>>;
188+
less<iter-value-type<InputIterator>>>; // C++17
189189
190190
template<class InputIterator, class Compare, class Allocator>
191191
priority_queue(InputIterator, InputIterator, Compare, Allocator)
192192
-> priority_queue<iter-value-type<InputIterator>,
193-
vector<iter-value-type<InputIterator>, Allocator>, Compare>;
193+
vector<iter-value-type<InputIterator>, Allocator>, Compare>; // C++17
194194
195195
template<class InputIterator, class Compare, class Container, class Allocator>
196196
priority_queue(InputIterator, InputIterator, Compare, Container, Allocator)
197-
-> priority_queue<typename Container::value_type, Container, Compare>;
197+
-> priority_queue<typename Container::value_type, Container, Compare>; // C++17
198198
199199
template <class T, class Container, class Compare>
200200
void swap(priority_queue<T, Container, Compare>& x,

0 commit comments

Comments
 (0)