blob: 0bb2a68b8cfd1f5b4c161f44b2a6d7edab356fd2 [file] [log] [blame]
// RUN: %clang_cc1 -std=c++2c -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -std=c++2c -verify=ref,both %s
/// This used to cause an assertion failure because we were deallocating a
/// dynamic block that was already dead.
namespace std {
inline namespace __1 {
template <class _Tp, _Tp __v> struct integral_constant {
static inline constexpr const _Tp value = __v;
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
template <bool _Val> using _BoolConstant = integral_constant<bool, _Val>;
template <class _Tp> using __remove_cv_t = __remove_cv(_Tp);
template <class _Tp> using remove_cv_t = __remove_cv_t<_Tp>;
template <class _Tp>
inline constexpr bool is_lvalue_reference_v = __is_lvalue_reference(_Tp);
template <class _Tp>
using __libcpp_remove_reference_t = __remove_reference_t(_Tp);
template <class _Tp>
constexpr _Tp &&forward(__libcpp_remove_reference_t<_Tp> &__t) noexcept;
template <bool _Bp, class _If, class _Then> struct conditional {
using type = _If;
};
template <bool _Bp, class _IfRes, class _ElseRes>
using conditional_t = typename conditional<_Bp, _IfRes, _ElseRes>::type;
template <class _Tp, class _Up>
using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>;
using size_t = decltype(sizeof(int));
template <class _Tp> using __decay_t = __decay(_Tp);
template <class _Tp> using decay_t = __decay_t<_Tp>;
template <bool, class _Tp = void> struct enable_if;
template <class _Tp> struct enable_if<true, _Tp> {
typedef _Tp type;
};
template <bool _Bp, class _Tp = void>
using __enable_if_t = typename enable_if<_Bp, _Tp>::type;
template <class _Bp, class _Dp>
inline constexpr bool is_base_of_v = __is_base_of(_Bp, _Dp);
template <class _Tp> _Tp &&__declval(int);
template <class _Tp> decltype(std::__declval<_Tp>(0)) declval() noexcept;
template <class _Ret, class _Fp, class... _Args> struct __invokable_r {};
template <class _Fp, class... _Args>
using __is_invocable = __invokable_r<void, _Fp, _Args...>;
template <class _Func, class... _Args>
inline const bool __is_invocable_v = __is_invocable<_Func, _Args...>::value;
template <class _Func, class... _Args>
struct __invoke_result
: enable_if<__is_invocable_v<_Func, _Args...>,
typename __invokable_r<void, _Func, _Args...>::_Result> {};
template <class _Fn, class... _Args>
struct invoke_result : __invoke_result<_Fn, _Args...> {};
template <class _Tp, class... _Args>
inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
template <class _Tp>
constexpr __libcpp_remove_reference_t<_Tp> &&move(_Tp &&__t) noexcept;
template <class _Tp> inline constexpr bool is_enum_v = __is_enum(_Tp);
template <class _From, class _To>
inline constexpr bool is_convertible_v = __is_convertible(_From, _To);
template <class _From, class _To>
concept convertible_to = is_convertible_v<_From, _To> &&
requires { static_cast<_To>(std::declval<_From>()); };
template <class _Tp, class _Up>
concept __same_as_impl = _IsSame<_Tp, _Up>::value;
template <class _Tp, class _Up>
concept same_as = __same_as_impl<_Tp, _Up> && __same_as_impl<_Up, _Tp>;
template <class _Tp> using __remove_cvref_t = __remove_cvref(_Tp);
template <class _Tp> using remove_cvref_t = __remove_cvref_t<_Tp>;
template <class _Tp>
using __make_const_lvalue_ref = const __libcpp_remove_reference_t<_Tp> &;
template <class _Lhs, class _Rhs>
concept assignable_from =
is_lvalue_reference_v<_Lhs> &&
requires(_Lhs __lhs, _Rhs &&__rhs) {
{ __lhs = std::forward<_Rhs>(__rhs) } -> same_as<_Lhs>;
};
template <class _Tp>
struct is_nothrow_destructible
: integral_constant<bool, __is_nothrow_destructible(_Tp)> {};
template <class _Tp>
inline constexpr bool is_nothrow_destructible_v =
is_nothrow_destructible<_Tp>::value;
template <class _Tp>
concept destructible = is_nothrow_destructible_v<_Tp>;
template <class _Tp, class... _Args>
concept constructible_from =
destructible<_Tp> && is_constructible_v<_Tp, _Args...>;
template <class _Tp>
concept __default_initializable = requires { ::new _Tp; };
template <class _Tp>
concept default_initializable = constructible_from<_Tp> && requires {
_Tp{};
} && __default_initializable<_Tp>;
template <class _Tp>
concept move_constructible =
constructible_from<_Tp, _Tp> && convertible_to<_Tp, _Tp>;
template <class _Tp> inline constexpr bool is_class_v = __is_class(_Tp);
template <class _Tp> inline constexpr bool is_union_v = __is_union(_Tp);
template <class _Tp>
concept __class_or_enum = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
namespace ranges {
namespace __swap {
template <class _Tp, class _Up>
concept __unqualified_swappable_with =
(__class_or_enum<remove_cvref_t<_Tp>> ||
__class_or_enum<remove_cvref_t<_Up>>) &&
requires(_Tp &&__t, _Up &&__u) {
swap(std::forward<_Tp>(__t), std::forward<_Up>(__u));
};
template <class _Tp>
concept __exchangeable = !__unqualified_swappable_with<_Tp &, _Tp &> &&
move_constructible<_Tp> && assignable_from<_Tp &, _Tp>;
struct __fn {
template <__exchangeable _Tp>
constexpr void operator()(_Tp &__x, _Tp &__y) const;
};
} // namespace __swap
inline namespace __cpo {
inline constexpr auto swap = __swap::__fn{};
}
} // namespace ranges
template <class _Tp> inline constexpr bool is_object_v = __is_object(_Tp);
template <class _Tp>
concept movable = is_object_v<_Tp> && move_constructible<_Tp> &&
assignable_from<_Tp &, _Tp>;
template <class _Tp>
concept copyable =
assignable_from<_Tp &, const _Tp &> && assignable_from<_Tp &, const _Tp>;
template <class _Dp, class _Bp>
concept derived_from =
is_base_of_v<_Bp, _Dp> &&
is_convertible_v<const volatile _Dp *, const volatile _Bp *>;
template <class _Tp>
concept __boolean_testable_impl = convertible_to<_Tp, bool>;
template <class _Tp>
concept __boolean_testable =
__boolean_testable_impl<_Tp> && requires(_Tp &&__t) {
{ !std::forward<_Tp>(__t) } -> __boolean_testable_impl;
};
template <class _Tp, class _Up>
concept __weakly_equality_comparable_with = requires(
__make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) {
{ __u != __t } -> __boolean_testable;
};
template <class _Tp>
concept semiregular = copyable<_Tp> && default_initializable<_Tp>;
template <template <class...> class _Templ, class... _Args,
class = _Templ<_Args...>>
true_type __sfinae_test_impl(int);
template <template <class...> class, class...>
false_type __sfinae_test_impl(...);
template <template <class...> class _Templ, class... _Args>
using _IsValidExpansion =
decltype(std::__sfinae_test_impl<_Templ, _Args...>(0));
template <class _Tp>
using __test_for_primary_template =
__enable_if_t<_IsSame<_Tp, typename _Tp::__primary_template>::value>;
template <class _Tp>
using __is_primary_template =
_IsValidExpansion<__test_for_primary_template, _Tp>;
template <class> struct iterator_traits;
template <class> struct __cond_value_type;
template <class _Tp>
requires is_object_v<_Tp>
struct __cond_value_type<_Tp> {
using value_type = remove_cv_t<_Tp>;
};
template <class _Tp>
concept __has_member_value_type = requires { typename _Tp::value_type; };
template <class> struct indirectly_readable_traits;
template <class _Tp>
struct indirectly_readable_traits<_Tp *> : __cond_value_type<_Tp> {};
template <__has_member_value_type _Tp>
struct indirectly_readable_traits<_Tp>
: __cond_value_type<typename _Tp::value_type> {};
template <bool> struct _OrImpl;
template <> struct _OrImpl<true> {
template <class _Res, class _First, class... _Rest>
using _Result =
typename _OrImpl<!bool(_First::value) && sizeof...(_Rest) != 0>::
template _Result<_First, _Rest...>;
};
template <> struct _OrImpl<false> {
template <class _Res, class...> using _Result = _Res;
};
template <class... _Args>
using _Or = typename _OrImpl<sizeof...(_Args) !=
0>::template _Result<false_type, _Args...>;
template <class _Tp> using __with_reference = _Tp &;
template <class _Tp>
concept __can_reference = requires { typename __with_reference<_Tp>; };
template <class _Tp>
concept __dereferenceable = requires(_Tp &__t) {
{ *__t } -> __can_reference;
};
template <__dereferenceable _Tp>
using iter_reference_t = decltype(*std::declval<_Tp &>());
struct input_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
template <class _Iter> struct __iter_traits_cache;
template <class _Iter>
using _ITER_TRAITS = typename __iter_traits_cache<_Iter>::type;
struct __iter_concept_concept_test {
template <class _Iter>
using _Apply = typename _ITER_TRAITS<_Iter>::iterator_concept;
};
struct __iter_concept_category_test {
template <class _Iter>
using _Apply = typename _ITER_TRAITS<_Iter>::iterator_category;
};
struct __iter_concept_random_fallback {
template <class _Iter>
using _Apply =
__enable_if_t<__is_primary_template<iterator_traits<_Iter>>::value,
random_access_iterator_tag>;
};
template <class _Iter, class _Tester>
struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>,
_Tester {};
template <class _Iter> struct __iter_concept_cache {
using type = _Or<__test_iter_concept<_Iter, __iter_concept_concept_test>,
__test_iter_concept<_Iter, __iter_concept_category_test>,
__test_iter_concept<_Iter, __iter_concept_random_fallback>>;
};
template <class _Iter>
using _ITER_CONCEPT =
typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>;
template <class _Ip> struct iterator_traits {
using __primary_template = iterator_traits;
};
template <class _Ip>
using iter_value_t = typename conditional_t<
__is_primary_template<iterator_traits<remove_cvref_t<_Ip>>>::value,
indirectly_readable_traits<remove_cvref_t<_Ip>>,
iterator_traits<remove_cvref_t<_Ip>>>::value_type;
namespace ranges {
namespace __iter_move {
template <class _Tp>
concept __move_deref = requires(_Tp &&__t) {
requires is_lvalue_reference_v<decltype(*__t)>;
};
struct __fn {
template <class _Ip>
requires __move_deref<_Ip>
constexpr auto operator()(_Ip &&__i) const
-> decltype(std::move(*std::forward<_Ip>(__i))) {
return std::move(*std::forward<_Ip>(__i));
}
template <class _Ip>
constexpr auto operator()(_Ip &&__i) const
-> decltype(*std::forward<_Ip>(__i));
};
} // namespace __iter_move
inline namespace __cpo {
inline constexpr auto iter_move = __iter_move::__fn{};
}
} // namespace ranges
template <__dereferenceable _Tp>
requires requires(_Tp &__t) {
{ ranges::iter_move(__t) } -> __can_reference;
}
using iter_rvalue_reference_t =
decltype(ranges::iter_move(std::declval<_Tp &>()));
template <class _Ptr, class = void> struct __pointer_traits_impl {};
template <class _Tp> inline constexpr bool is_pointer_v = __is_pointer(_Tp);
template <class _Ip>
concept input_or_output_iterator = requires(_Ip __i) {
{ *__i } -> __can_reference;
};
template <class _Sp, class _Ip>
concept sentinel_for = semiregular<_Sp> && input_or_output_iterator<_Ip> &&
__weakly_equality_comparable_with<_Sp, _Ip>;
template <class _Ip>
concept input_iterator =
input_or_output_iterator<_Ip> && requires {
typename _ITER_CONCEPT<_Ip>;
} && derived_from<_ITER_CONCEPT<_Ip>, input_iterator_tag>;
namespace ranges {
namespace __begin {
struct __fn {
template <class _Tp> constexpr auto operator()(_Tp &&__t) const {
return static_cast<::std::__decay_t<decltype((__t.begin()))>>(__t.begin());
}
};
} // namespace __begin
inline namespace __cpo {
inline constexpr auto begin = __begin::__fn{};
}
template <class _Tp>
using iterator_t = decltype(ranges::begin(std::declval<_Tp &>()));
namespace __end {
struct __fn {
template <class _Tp> constexpr auto operator()(_Tp &&__t) const {}
};
} // namespace __end
inline namespace __cpo {
inline constexpr auto end = __end::__fn{};
}
} // namespace ranges
namespace ranges {
template <class _Tp>
concept range = requires(_Tp &__t) { ranges::end(__t); };
template <class _Tp>
concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>;
template <range _Rp> using range_value_t = iter_value_t<iterator_t<_Rp>>;
} // namespace ranges
} // namespace __1
} // namespace std
constexpr void *operator new(std::size_t, void *__p) noexcept; // both-warning {{not defined}}
namespace std {
inline namespace __1 {
template <class _Tp, class... _Args,
class = decltype(::new (std::declval<void *>())
_Tp(std::declval<_Args>()...))>
constexpr _Tp *construct_at(_Tp *__location, _Args &&...__args) {
return ::new (static_cast<void *>(__location)) _Tp(std::forward<_Args>(__args)...); // both-note {{here}}
}
enum class __element_count : size_t;
template <class _Tp, class _Up>
constexpr _Tp *__constexpr_memmove(_Tp *__dest, _Up *__src,
__element_count __n) {
size_t __count = static_cast<size_t>(__n);
::__builtin_memcpy(__dest, __src, __count * sizeof(_Tp));
return __dest;
};
namespace ranges {
template <class _From, class _To>
concept __convertible_to_non_slicing =
convertible_to<_From, _To>;
template <input_or_output_iterator _Iter, sentinel_for<_Iter> _Sent = _Iter>
class subrange {
private:
_Iter __begin_ = _Iter();
_Sent __end_ = _Sent();
public:
constexpr subrange(__convertible_to_non_slicing<_Iter> auto __iter,
_Sent __sent)
: __begin_(std::move(__iter)), __end_(std::move(__sent)) {}
constexpr _Iter begin() { return std::move(__begin_); }
constexpr _Sent end() const;
};
template <input_or_output_iterator _Iter, sentinel_for<_Iter> _Sent>
subrange(_Iter, _Sent) -> subrange<_Iter, _Sent>;
} // namespace ranges
template <class _Tp> class allocator {
public:
constexpr _Tp *allocate(size_t __n) {
return static_cast<_Tp *>(::operator new(__n * sizeof(_Tp)));
}
constexpr void deallocate(_Tp *__p, size_t __n) noexcept {
::operator delete(__p);
}
};
template <class _CharT> struct char_traits;
template <class _CharT, class _Traits = char_traits<_CharT>,
class _Allocator = allocator<_CharT>>
class basic_string;
using string = basic_string<char>;
template <class _Iter>
class move_iterator {
private:
public:
using iterator_type = _Iter;
using value_type = iter_value_t<_Iter>;
using reference = iter_rvalue_reference_t<_Iter>;
constexpr explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {}
constexpr move_iterator();
constexpr reference operator*() const {
return ranges::iter_move(__current_);
}
_Iter __current_;
};
namespace ranges {
template <class _T1> struct min_max_result {
_T1 min;
};
template <class _T1> using minmax_result = min_max_result<_T1>;
struct __minmax {
template <input_range _Range>
constexpr ranges::minmax_result<range_value_t<_Range>>
operator()(_Range &&__r) const {
auto __first = ranges::begin(__r);
using _ValueT = range_value_t<_Range>;
ranges::minmax_result<_ValueT> __result = {*__first};
return __result;
}
};
inline namespace __cpo {
inline constexpr auto minmax = __minmax{};
}
} // namespace ranges
template <> struct char_traits<char> {
using char_type = char;
static constexpr int compare(const char_type *__lhs, const char_type *__rhs,
size_t __count) noexcept {
return __builtin_memcmp(__lhs, __rhs, __count);
}
static inline size_t constexpr length(const char_type *__s) noexcept {
return __builtin_strlen(__s);
}
static inline constexpr char_type *
copy(char_type *__s1, const char_type *__s2, size_t __n) noexcept {
std::__constexpr_memmove(__s1, __s2, __element_count(__n));
return __s1;
}
};
template <class _CharT, class _Traits, class _Allocator> class basic_string {
using traits_type = _Traits;
using value_type = _CharT;
using allocator_type = _Allocator;
private:
struct __long {
struct {
unsigned __is_long_ : 1;
unsigned __cap_ : sizeof(unsigned) * 8 - 1;
};
unsigned __size_;
char *__data_;
};
struct __short {
struct {
unsigned char __is_long_ : 1;
};
};
union __rep {
__short __s;
__long __l;
};
__rep __rep_;
allocator_type __alloc_;
public:
constexpr basic_string(const basic_string &__str) : __alloc_(__str.__alloc_) {
__init_copy_ctor_external(__str.__rep_.__l.__data_,
__str.__rep_.__l.__size_);
}
constexpr basic_string(basic_string &&__str)
: __rep_(__str.__rep_), __alloc_(std::move(__str.__alloc_)) {
__str.__rep_ = __rep();
}
constexpr basic_string(const _CharT *__s) {
__init_copy_ctor_external(__s, traits_type::length(__s));
}
inline constexpr ~basic_string() {
if (__is_long())
__alloc_.deallocate(__rep_.__l.__data_, __rep_.__l.__cap_*2);
}
constexpr unsigned size() const noexcept { return __rep_.__l.__size_; }
constexpr const value_type *data() const noexcept { return __rep_.__l.__data_; }
private:
constexpr bool __is_long() const {
if (__builtin_constant_p(__rep_.__l.__is_long_)) {
return __rep_.__l.__is_long_;
}
return __rep_.__s.__is_long_;
}
static constexpr void __begin_lifetime(char *__begin, unsigned __n) {
for (unsigned __i = 0; __i != __n; ++__i)
std::construct_at(&__begin[__i]);
}
constexpr void __init_copy_ctor_external(const value_type *__s,
unsigned __sz);
};
template <class _CharT, class _Traits, class _Allocator>
constexpr void
basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(
const value_type *__s, unsigned __sz) {
char *__p;
auto __allocation = __alloc_.allocate(__sz + 1);
__p = __allocation;
__begin_lifetime(__p, __sz + 1);
__rep_.__l.__data_ = __p;
__rep_.__l.__cap_ = (__sz + 1) / 2;
__rep_.__l.__is_long_ = true;
__rep_.__l.__size_ = __sz;
traits_type::copy(__p, __s, __sz + 1);
}
template <class _CharT, class _Traits, class _Allocator>
inline constexpr bool
operator==(const basic_string<_CharT, _Traits, _Allocator> &__lhs,
const basic_string<_CharT, _Traits, _Allocator> &__rhs) noexcept {
return _Traits::compare(__lhs.data(), __rhs.data(), __lhs.size()) == 0;
}
} // namespace __1
} // namespace std
template <class It> class cpp20_input_iterator {
It it_;
public:
using value_type = std::iter_value_t<It>;
constexpr explicit cpp20_input_iterator(It it) : it_(it) {}
constexpr decltype(auto) operator*() const { return *it_; }
constexpr void operator++(int);
friend constexpr It base(const cpp20_input_iterator &i) { return i.it_; }
};
template <class It> class sentinel_wrapper {
public:
explicit sentinel_wrapper() = default;
constexpr explicit sentinel_wrapper(const It &it) : base_(base(it)) {}
constexpr bool operator==(const It &other) const;
private:
decltype(base(std::declval<It>())) base_;
};
constexpr bool test_range() {
const std::string str{
"this long string will be dynamically "
"allocatedasfajkshdfasdhjkfahjksdgfjkasdhkfgaksdgfhkasghjkdfgjhasdghjfgah"
"jksdgjfhkasghjkdfghjasgjdfghasdghjkfgajksdgfgajsdfghjkgashjkdfghjasjdhkf"
"gahjsdfghjkgashjdghjfkasghjkdfasgjkdhfgajkshdfgkjashdgfkjasghdfkjghasdkf"
"hgaskdjghfasdfasdfasdfasdfasdf"};
std::string a[] = {str};
auto range = std::ranges::subrange(
cpp20_input_iterator(std::move_iterator(a)),
sentinel_wrapper(cpp20_input_iterator(std::move_iterator(a + 1))));
auto ret = std::ranges::minmax(range);
if (ret.min != str)
__builtin_abort();
return true;
}
static_assert(test_range());