Skip to content

Commit 38e35eb

Browse files
authored
Update libcxx and libcxxabi from LLVM 21.1.8 to 22.1.8 (#27428)
This updates libcxx and libcxxabi from 21.1.8 to LLVM 22.1.8: https://github.com/llvm/llvm-project/releases/tag/llvmorg-22.1.8 Additional changes: (More detailed descriptions are in the commit messages) - Don't copy llvm-libc files in `update_libcxx.py`: e7af49c, e81407b In `update_libcxx.py`, we don't copy llvm-libc files that libcxx depend on anymore, because we copy those files in `update_llvm_libc.py` too. We just assume llvm-libc has been updated to the same version before doing update, and I wrote that in the comments. - Define `_LIBCPP_ASSERTION_SEMANTIC_DEFAULT` in `__config_site`: b119c87 llvm/llvm-project#167636 forces us to define `_LIBCPP_ASSERTION_SEMANTIC_DEFAULT`. This defines it to follow the hardening mode. - Undefine `_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE`: e9f7296 After llvm/llvm-project#169405, `_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE` was defined, which caused Emscripten to use `copy_file_range`. This commit adds `!defined(__EMSCRIPTEN__)` clause at the end to make `_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE` undefined for Emscripten, as was before this update. - Make `__cxa_thread_atexit` available for Emscripten: 638d0e1 llvm/llvm-project#116261 wrapped `__cxa_thread_atexit` with `#if defined(__linux__) || defined(__Fuchsia__)`, which caused it to be undefined in Emscripten. This adds `defined(__EMSCRIPTEN__)` to make it available again. - Increase size expectations of `test_malloc_size*`: c818aa2 This increase seems to be mainly due to the changes of implementation of `std::num_get` in `libcxx/include/__locale_dir/num.h` in llvm/llvm-project#121795. Note that we had a similar size increase due to changes in `std::num_put` in llvm/llvm-project#133572 in LLVM 21 update (#26058). - Create `module.modulemap` from `module.modulemap.in`: be1f0a7 libcxx used to have `module.modulemap`, but since LLVM 21, it was changed to `module.modulemap.in` in llvm/llvm-project#134699. Rather than we copy this manually in each update, this makes `update_libcxx.py` create `module.modulemap` from `module.modulemap.in` automaticaly. - Copy `default_assertion_handler.in` to `__assertion_handler`: 547432f Since LLVM 18, llvm/llvm-project#77883 started to provide a default assertion handler and a way to override it. We have been using the default handler ever since. Rather than manually copying it in each release, this automates the copying of the file in `update_libcxx.py`.
1 parent 86ea17d commit 38e35eb

478 files changed

Lines changed: 16523 additions & 11163 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ See docs/process.md for more on how version tagging works.
2020

2121
6.0.6 (in development)
2222
----------------------
23+
- libcxx and libcxxabi were updated to LLVM 22.1.8. (#27428)
2324

2425
6.0.5 - 07/29/26
2526
----------------
2627
- Revert #27397, which changed the way config keys such as NODE_JS were parsed
2728
when reading the config file. This change broke emsdk installations that
2829
contained spaces. (#27421)
30+
- libcxx, libcxxabi and OpenMP were updated to LLVM 22.1.8. (#27428, #27437)
2931
- OpenMP was updated to LLVM 22.1.8 (#27437)
3032

3133
6.0.4 - 07/24/26

system/lib/libcxx/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
LLVM's libcxx
22
-------------
33

4-
These files are from the llvm-project based on release 21.1.8.
4+
These files are from the llvm-project based on release 22.1.8.
55

66
We maintain a local fork of llvm-project that contains any Emscripten
77
specific patches:
88

99
https://github.com/emscripten-core/llvm-project
1010

11-
The current patch is based on the emscripten-libs-21 branch.
11+
The current patch is based on the emscripten-libs-22 branch.
1212

1313
Update Instructions
1414
-------------------
@@ -20,4 +20,4 @@ Modifications
2020

2121
For a list of changes from upstream see the libcxx files that are part of:
2222

23-
https://github.com/llvm/llvm-project/compare/llvmorg-21.1.8...emscripten-core:emscripten-libs-21
23+
https://github.com/llvm/llvm-project/compare/llvmorg-22.1.8...emscripten-core:emscripten-libs-22

system/lib/libcxx/include/__algorithm/all_of.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,28 @@
1010
#ifndef _LIBCPP___ALGORITHM_ALL_OF_H
1111
#define _LIBCPP___ALGORITHM_ALL_OF_H
1212

13+
#include <__algorithm/any_of.h>
1314
#include <__config>
1415
#include <__functional/identity.h>
1516
#include <__type_traits/invoke.h>
17+
#include <__utility/forward.h>
18+
#include <__utility/move.h>
1619

1720
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1821
# pragma GCC system_header
1922
#endif
2023

24+
_LIBCPP_PUSH_MACROS
25+
#include <__undef_macros>
26+
2127
_LIBCPP_BEGIN_NAMESPACE_STD
2228

2329
template <class _Iter, class _Sent, class _Proj, class _Pred>
2430
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
2531
__all_of(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) {
26-
for (; __first != __last; ++__first) {
27-
if (!std::__invoke(__pred, std::__invoke(__proj, *__first)))
28-
return false;
29-
}
30-
return true;
32+
using _Ref = decltype(std::__invoke(__proj, *__first));
33+
auto __negated_pred = [&__pred](_Ref __arg) -> bool { return !std::__invoke(__pred, std::forward<_Ref>(__arg)); };
34+
return !std::__any_of(std::move(__first), std::move(__last), __negated_pred, __proj);
3135
}
3236

3337
template <class _InputIterator, class _Predicate>
@@ -39,4 +43,6 @@ all_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) {
3943

4044
_LIBCPP_END_NAMESPACE_STD
4145

46+
_LIBCPP_POP_MACROS
47+
4248
#endif // _LIBCPP___ALGORITHM_ALL_OF_H

system/lib/libcxx/include/__algorithm/comp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <__config>
1313
#include <__type_traits/desugars_to.h>
14+
#include <__type_traits/is_generic_transparent_comparator.h>
1415
#include <__type_traits/is_integral.h>
1516

1617
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -48,6 +49,9 @@ inline const bool __desugars_to_v<__less_tag, __less<>, _Tp, _Tp> = true;
4849
template <class _Tp>
4950
inline const bool __desugars_to_v<__totally_ordered_less_tag, __less<>, _Tp, _Tp> = is_integral<_Tp>::value;
5051

52+
template <>
53+
inline const bool __is_generic_transparent_comparator_v<__less<> > = true;
54+
5155
_LIBCPP_END_NAMESPACE_STD
5256

5357
#endif // _LIBCPP___ALGORITHM_COMP_H

system/lib/libcxx/include/__algorithm/copy.h

Lines changed: 28 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@
1212
#include <__algorithm/copy_move_common.h>
1313
#include <__algorithm/for_each_segment.h>
1414
#include <__algorithm/min.h>
15+
#include <__algorithm/specialized_algorithms.h>
1516
#include <__config>
16-
#include <__fwd/bit_reference.h>
1717
#include <__iterator/iterator_traits.h>
1818
#include <__iterator/segmented_iterator.h>
19-
#include <__memory/pointer_traits.h>
2019
#include <__type_traits/common_type.h>
2120
#include <__type_traits/enable_if.h>
2221
#include <__utility/move.h>
@@ -38,124 +37,14 @@ copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result);
3837
template <class _InIter, class _Sent, class _OutIter>
3938
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> __copy(_InIter, _Sent, _OutIter);
4039

41-
template <class _Cp, bool _IsConst>
42-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_aligned(
43-
__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) {
44-
using _In = __bit_iterator<_Cp, _IsConst>;
45-
using difference_type = typename _In::difference_type;
46-
using __storage_type = typename _In::__storage_type;
47-
48-
const int __bits_per_word = _In::__bits_per_word;
49-
difference_type __n = __last - __first;
50-
if (__n > 0) {
51-
// do first word
52-
if (__first.__ctz_ != 0) {
53-
unsigned __clz = __bits_per_word - __first.__ctz_;
54-
difference_type __dn = std::min(static_cast<difference_type>(__clz), __n);
55-
__n -= __dn;
56-
__storage_type __m = std::__middle_mask<__storage_type>(__clz - __dn, __first.__ctz_);
57-
__storage_type __b = *__first.__seg_ & __m;
58-
*__result.__seg_ &= ~__m;
59-
*__result.__seg_ |= __b;
60-
__result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
61-
__result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
62-
++__first.__seg_;
63-
// __first.__ctz_ = 0;
64-
}
65-
// __first.__ctz_ == 0;
66-
// do middle words
67-
__storage_type __nw = __n / __bits_per_word;
68-
std::copy(std::__to_address(__first.__seg_),
69-
std::__to_address(__first.__seg_ + __nw),
70-
std::__to_address(__result.__seg_));
71-
__n -= __nw * __bits_per_word;
72-
__result.__seg_ += __nw;
73-
// do last word
74-
if (__n > 0) {
75-
__first.__seg_ += __nw;
76-
__storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
77-
__storage_type __b = *__first.__seg_ & __m;
78-
*__result.__seg_ &= ~__m;
79-
*__result.__seg_ |= __b;
80-
__result.__ctz_ = static_cast<unsigned>(__n);
81-
}
82-
}
83-
return __result;
84-
}
85-
86-
template <class _Cp, bool _IsConst>
87-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_unaligned(
88-
__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) {
89-
using _In = __bit_iterator<_Cp, _IsConst>;
90-
using difference_type = typename _In::difference_type;
91-
using __storage_type = typename _In::__storage_type;
92-
93-
const int __bits_per_word = _In::__bits_per_word;
94-
difference_type __n = __last - __first;
95-
if (__n > 0) {
96-
// do first word
97-
if (__first.__ctz_ != 0) {
98-
unsigned __clz_f = __bits_per_word - __first.__ctz_;
99-
difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n);
100-
__n -= __dn;
101-
__storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_);
102-
__storage_type __b = *__first.__seg_ & __m;
103-
unsigned __clz_r = __bits_per_word - __result.__ctz_;
104-
__storage_type __ddn = std::min<__storage_type>(__dn, __clz_r);
105-
__m = std::__middle_mask<__storage_type>(__clz_r - __ddn, __result.__ctz_);
106-
*__result.__seg_ &= ~__m;
107-
if (__result.__ctz_ > __first.__ctz_)
108-
*__result.__seg_ |= __b << (__result.__ctz_ - __first.__ctz_);
109-
else
110-
*__result.__seg_ |= __b >> (__first.__ctz_ - __result.__ctz_);
111-
__result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word;
112-
__result.__ctz_ = static_cast<unsigned>((__ddn + __result.__ctz_) % __bits_per_word);
113-
__dn -= __ddn;
114-
if (__dn > 0) {
115-
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __dn);
116-
*__result.__seg_ &= ~__m;
117-
*__result.__seg_ |= __b >> (__first.__ctz_ + __ddn);
118-
__result.__ctz_ = static_cast<unsigned>(__dn);
119-
}
120-
++__first.__seg_;
121-
// __first.__ctz_ = 0;
122-
}
123-
// __first.__ctz_ == 0;
124-
// do middle words
125-
unsigned __clz_r = __bits_per_word - __result.__ctz_;
126-
__storage_type __m = std::__leading_mask<__storage_type>(__result.__ctz_);
127-
for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) {
128-
__storage_type __b = *__first.__seg_;
129-
*__result.__seg_ &= ~__m;
130-
*__result.__seg_ |= __b << __result.__ctz_;
131-
++__result.__seg_;
132-
*__result.__seg_ &= __m;
133-
*__result.__seg_ |= __b >> __clz_r;
134-
}
135-
// do last word
136-
if (__n > 0) {
137-
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
138-
__storage_type __b = *__first.__seg_ & __m;
139-
__storage_type __dn = std::min(__n, static_cast<difference_type>(__clz_r));
140-
__m = std::__middle_mask<__storage_type>(__clz_r - __dn, __result.__ctz_);
141-
*__result.__seg_ &= ~__m;
142-
*__result.__seg_ |= __b << __result.__ctz_;
143-
__result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
144-
__result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
145-
__n -= __dn;
146-
if (__n > 0) {
147-
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
148-
*__result.__seg_ &= ~__m;
149-
*__result.__seg_ |= __b >> __dn;
150-
__result.__ctz_ = static_cast<unsigned>(__n);
151-
}
152-
}
153-
}
154-
return __result;
155-
}
156-
15740
struct __copy_impl {
158-
template <class _InIter, class _Sent, class _OutIter>
41+
template <class _InIter,
42+
class _Sent,
43+
class _OutIter,
44+
__enable_if_t<!__specialized_algorithm<_Algorithm::__copy,
45+
__iterator_pair<_InIter, _Sent>,
46+
__single_iterator<_OutIter> >::__has_algorithm,
47+
int> = 0>
15948
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
16049
operator()(_InIter __first, _Sent __last, _OutIter __result) const {
16150
while (__first != __last) {
@@ -167,37 +56,39 @@ struct __copy_impl {
16756
return std::make_pair(std::move(__first), std::move(__result));
16857
}
16958

170-
template <class _InIter, class _OutIter>
171-
struct _CopySegment {
172-
using _Traits _LIBCPP_NODEBUG = __segmented_iterator_traits<_InIter>;
173-
174-
_OutIter& __result_;
175-
176-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit _CopySegment(_OutIter& __result)
177-
: __result_(__result) {}
178-
179-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
180-
operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) {
181-
__result_ = std::__copy(__lfirst, __llast, std::move(__result_)).second;
182-
}
183-
};
59+
template <class _InIter,
60+
class _Sent,
61+
class _OutIter,
62+
__enable_if_t<__specialized_algorithm<_Algorithm::__copy,
63+
__iterator_pair<_InIter, _Sent>,
64+
__single_iterator<_OutIter> >::__has_algorithm,
65+
int> = 0>
66+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static pair<_InIter, _OutIter>
67+
operator()(_InIter __first, _Sent __last, _OutIter __result) {
68+
return __specialized_algorithm<_Algorithm::__copy, __iterator_pair<_InIter, _Sent>, __single_iterator<_OutIter> >()(
69+
std::move(__first), std::move(__last), std::move(__result));
70+
}
18471

185-
template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0>
72+
template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0>
18673
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
18774
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
188-
std::__for_each_segment(__first, __last, _CopySegment<_InIter, _OutIter>(__result));
75+
using __local_iterator = typename __segmented_iterator_traits<_InIter>::__local_iterator;
76+
std::__for_each_segment(__first, __last, [&__result](__local_iterator __lfirst, __local_iterator __llast) {
77+
__result = std::__copy(std::move(__lfirst), std::move(__llast), std::move(__result)).second;
78+
});
18979
return std::make_pair(__last, std::move(__result));
19080
}
19181

19282
template <class _InIter,
19383
class _OutIter,
19484
__enable_if_t<__has_random_access_iterator_category<_InIter>::value &&
195-
!__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value,
85+
!__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>,
19686
int> = 0>
19787
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
19888
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
19989
using _Traits = __segmented_iterator_traits<_OutIter>;
200-
using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type;
90+
using _DiffT =
91+
typename common_type<__iterator_difference_type<_InIter>, __iterator_difference_type<_OutIter> >::type;
20192

20293
if (__first == __last)
20394
return std::make_pair(std::move(__first), std::move(__result));
@@ -217,16 +108,6 @@ struct __copy_impl {
217108
}
218109
}
219110

220-
template <class _Cp, bool _IsConst>
221-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> >
222-
operator()(__bit_iterator<_Cp, _IsConst> __first,
223-
__bit_iterator<_Cp, _IsConst> __last,
224-
__bit_iterator<_Cp, false> __result) const {
225-
if (__first.__ctz_ == __result.__ctz_)
226-
return std::make_pair(__last, std::__copy_aligned(__first, __last, __result));
227-
return std::make_pair(__last, std::__copy_unaligned(__first, __last, __result));
228-
}
229-
230111
// At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
231112
template <class _In, class _Out, __enable_if_t<__can_lower_copy_assignment_to_memmove<_In, _Out>::value, int> = 0>
232113
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>

system/lib/libcxx/include/__algorithm/copy_backward.h

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <__algorithm/copy_move_common.h>
1313
#include <__algorithm/copy_n.h>
14+
#include <__algorithm/for_each_segment.h>
1415
#include <__algorithm/iterator_operations.h>
1516
#include <__algorithm/min.h>
1617
#include <__config>
@@ -170,37 +171,20 @@ struct __copy_backward_impl {
170171
return std::make_pair(std::move(__original_last_iter), std::move(__result));
171172
}
172173

173-
template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0>
174+
template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0>
174175
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
175176
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
176-
using _Traits = __segmented_iterator_traits<_InIter>;
177-
auto __sfirst = _Traits::__segment(__first);
178-
auto __slast = _Traits::__segment(__last);
179-
if (__sfirst == __slast) {
180-
auto __iters =
181-
std::__copy_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result));
182-
return std::make_pair(__last, __iters.second);
183-
}
184-
185-
__result =
186-
std::__copy_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__local(__last), std::move(__result))
187-
.second;
188-
--__slast;
189-
while (__sfirst != __slast) {
190-
__result =
191-
std::__copy_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__end(__slast), std::move(__result))
192-
.second;
193-
--__slast;
194-
}
195-
__result = std::__copy_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__slast), std::move(__result))
196-
.second;
177+
using __local_iterator = typename __segmented_iterator_traits<_InIter>::__local_iterator;
178+
std::__for_each_segment_backward(__first, __last, [&__result](__local_iterator __lfirst, __local_iterator __llast) {
179+
__result = std::__copy_backward<_AlgPolicy>(std::move(__lfirst), std::move(__llast), std::move(__result)).second;
180+
});
197181
return std::make_pair(__last, std::move(__result));
198182
}
199183

200184
template <class _InIter,
201185
class _OutIter,
202186
__enable_if_t<__has_random_access_iterator_category<_InIter>::value &&
203-
!__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value,
187+
!__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>,
204188
int> = 0>
205189
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
206190
operator()(_InIter __first, _InIter __last, _OutIter __result) const {
@@ -214,7 +198,8 @@ struct __copy_backward_impl {
214198

215199
auto __local_last = _Traits::__local(__result);
216200
while (true) {
217-
using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type;
201+
using _DiffT =
202+
typename common_type<__iterator_difference_type<_InIter>, __iterator_difference_type<_OutIter> >::type;
218203

219204
auto __local_first = _Traits::__begin(__segment_iterator);
220205
auto __size = std::min<_DiffT>(__local_last - __local_first, __last - __first);

0 commit comments

Comments
 (0)