Skip to content

Commit d81e017

Browse files
committed
Disallow T(&)[] and T&(Args...) from having iterator types as pre-caution
1 parent 5c60392 commit d81e017

File tree

2 files changed

+61
-11
lines changed

2 files changed

+61
-11
lines changed

libcxx/include/optional

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ namespace std {
225225
# include <__type_traits/is_convertible.h>
226226
# include <__type_traits/is_core_convertible.h>
227227
# include <__type_traits/is_destructible.h>
228+
# include <__type_traits/is_function.h>
228229
# include <__type_traits/is_nothrow_assignable.h>
229230
# include <__type_traits/is_nothrow_constructible.h>
230231
# include <__type_traits/is_object.h>
@@ -237,6 +238,7 @@ namespace std {
237238
# include <__type_traits/is_trivially_constructible.h>
238239
# include <__type_traits/is_trivially_destructible.h>
239240
# include <__type_traits/is_trivially_relocatable.h>
241+
# include <__type_traits/is_unbounded_array.h>
240242
# include <__type_traits/negation.h>
241243
# include <__type_traits/remove_const.h>
242244
# include <__type_traits/remove_cv.h>
@@ -605,28 +607,46 @@ struct __is_std_optional : false_type {};
605607
template <class _Tp>
606608
struct __is_std_optional<optional<_Tp>> : true_type {};
607609

608-
template <class _Tp>
609-
class _LIBCPP_DECLSPEC_EMPTY_BASES optional
610-
: private __optional_move_assign_base<_Tp>,
611-
private __optional_sfinae_ctor_base_t<_Tp>,
612-
private __optional_sfinae_assign_base_t<_Tp> {
613-
using __base _LIBCPP_NODEBUG = __optional_move_assign_base<_Tp>;
610+
template <class _Tp, class = void>
611+
struct __optional_iterator_aliases {};
614612

613+
// disallow T (&)() and T (&)[]
614+
template <class _Tp>
615+
struct __optional_iterator_aliases<
616+
_Tp,
617+
__enable_if_t<!(is_reference<_Tp>::value && (is_function<__libcpp_remove_reference_t<_Tp>>::value ||
618+
is_unbounded_array<__libcpp_remove_reference_t<_Tp>>::value))> > {
619+
private:
615620
using __pointer _LIBCPP_NODEBUG = std::add_pointer_t<_Tp>;
616621
using __const_pointer _LIBCPP_NODEBUG = std::add_pointer_t<const _Tp>;
617622

618623
public:
619-
using value_type = _Tp;
620624
# if _LIBCPP_STD_VER >= 26
621625
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
622-
using iterator = __bounded_iter<__wrap_iter<__pointer>>;
623-
using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>;
626+
using __iterator _LIBCPP_NODEBUG = __bounded_iter<__wrap_iter<__pointer>>;
627+
using __const_iterator _LIBCPP_NODEBUG = __bounded_iter<__wrap_iter<__const_pointer>>;
624628
# else
625-
using iterator = __wrap_iter<__pointer>;
626-
using const_iterator = __wrap_iter<__const_pointer>;
629+
using __iterator _LIBCPP_NODEBUG = __wrap_iter<__pointer>;
630+
using __const_iterator _LIBCPP_NODEBUG = __wrap_iter<__const_pointer>;
627631
# endif
628632
# endif
633+
};
634+
635+
template <class _Tp>
636+
class _LIBCPP_DECLSPEC_EMPTY_BASES optional
637+
: private __optional_move_assign_base<_Tp>,
638+
private __optional_sfinae_ctor_base_t<_Tp>,
639+
private __optional_sfinae_assign_base_t<_Tp>,
640+
public __optional_iterator_aliases<_Tp> {
641+
using __base _LIBCPP_NODEBUG = __optional_move_assign_base<_Tp>;
629642

643+
public:
644+
using value_type = _Tp;
645+
646+
# if _LIBCPP_STD_VER >= 26
647+
using iterator = __optional_iterator_aliases<_Tp>::__iterator;
648+
using const_iterator = __optional_iterator_aliases<_Tp>::__const_iterator;
649+
# endif
630650
using __trivially_relocatable _LIBCPP_NODEBUG =
631651
conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>;
632652
using __replaceable _LIBCPP_NODEBUG = conditional_t<__is_replaceable_v<_Tp>, optional, void>;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: std-at-least-c++26
10+
11+
// <optional>
12+
13+
// template <class T> class optional::iterator;
14+
// template <class T> class optional::const_iterator;
15+
16+
#include <optional>
17+
18+
template <typename T>
19+
concept has_iterator_aliases = requires {
20+
typename T::iterator;
21+
typename T::const_iterator;
22+
};
23+
24+
static_assert(has_iterator_aliases<std::optional<int>>);
25+
static_assert(has_iterator_aliases<std::optional<const int>>);
26+
27+
// TODO: Uncomment these once P2988R12 is implemented, as they would be testing optional<T&>
28+
29+
// static_assert(!has_iterator_aliases<std::optional<int (&)[]>>);
30+
// static_assert(!has_iterator_aliases<std::optional<void (&)(int, char)>>);

0 commit comments

Comments
 (0)