diff --git a/benchmarks/src/regex_match.cpp b/benchmarks/src/regex_match.cpp
index 4522be62883..e705bde94b4 100644
--- a/benchmarks/src/regex_match.cpp
+++ b/benchmarks/src/regex_match.cpp
@@ -22,6 +22,23 @@ void bm_match_sequence_of_as(benchmark::State& state, const char* pattern, synta
}
}
+void bm_match_sequence_of_9a1b(benchmark::State& state, const char* pattern, syntax_option_type syntax = ECMAScript) {
+ string input;
+ for (int i = 0; i < state.range(); ++i) {
+ input += "aaaaaaaaab";
+ }
+
+ regex re{pattern, syntax};
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(input);
+ const char* pos = input.data();
+ const char* end = input.data() + input.size();
+ cmatch match;
+ regex_match(pos, end, match, re);
+ }
+}
+
void common_args(auto bm) {
bm->Arg(100)->Arg(200)->Arg(400);
}
@@ -36,5 +53,6 @@ BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(b|a)*", "(b|a)*")->Apply(common_arg
BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(?:b|a)*", "(a)(?:b|a)*")->Apply(common_args);
BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(b|a)*", "(a)(b|a)*")->Apply(common_args);
BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(?:b|a)*c", "(a)(?:b|a)*c")->Apply(common_args);
+BENCHMARK_CAPTURE(bm_match_sequence_of_9a1b, "(?:a*b)*", "(?:a*b)*")->Apply(common_args);
BENCHMARK_MAIN();
diff --git a/stl/debugger/STL.natvis b/stl/debugger/STL.natvis
index aad4b34577e..c61e29cf5e3 100644
--- a/stl/debugger/STL.natvis
+++ b/stl/debugger/STL.natvis
@@ -586,7 +586,16 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
+
+ ranges::equal_to
+ ranges::not_equal_to
+ ranges::greater
+ ranges::less
+ ranges::greater_equal
+ ranges::less_equal
+ compare_three_way
+
+
plus<>
minus<>
multiplies<>
@@ -607,101 +616,26 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
bit_xor<>
bit_not<>
-
-
- plus
-
-
-
-
- minus
-
-
-
-
- multiplies
-
-
-
-
- divides
-
-
-
-
- modulus
-
-
-
-
- negate
-
-
-
-
- equal_to
-
-
-
-
- not_equal_to
-
-
-
-
- greater
-
-
-
-
- less
-
-
-
-
- greater_equal
-
-
-
-
- less_equal
-
-
-
-
- logical_and
-
-
-
-
- logical_or
-
-
-
-
- logical_not
-
-
-
-
- bit_and
-
-
-
-
- bit_or
-
-
-
-
- bit_xor
-
-
-
-
- bit_not
-
-
+
+ plus
+ minus
+ multiplies
+ divides
+ modulus
+ negate
+ equal_to
+ not_equal_to
+ greater
+ less
+ greater_equal
+ less_equal
+ logical_and
+ logical_or
+ logical_not
+ bit_and
+ bit_or
+ bit_xor
+ bit_not
@@ -1084,6 +1018,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
_Ptr,na
+ {*_Ptr}
- _Ptr
@@ -1228,14 +1163,27 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
+
+
_Ptr,na
+ {*_Ptr}
- _Ptr
+
+
+
+
+ _Ptr,na
+ end
+ {*_Ptr}
+
+ - _Ptr
+
+
@@ -1838,13 +1786,25 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
+
+
_Myptr,na
+ {*_Myptr}
- _Myptr
+
+
+ _Myptr,na
+ end
+ {*_Myptr}
+
+ - _Myptr
+
+
+
default sentinel
diff --git a/stl/inc/cmath b/stl/inc/cmath
index 78e0d7cb959..6c45e1c61a3 100644
--- a/stl/inc/cmath
+++ b/stl/inc/cmath
@@ -1686,14 +1686,15 @@ _EXPORT_STD _NODISCARD constexpr inline double lerp(
_EXPORT_STD _NODISCARD constexpr inline long double lerp(
const long double _ArgA, const long double _ArgB, const long double _ArgT) noexcept {
- return _Common_lerp(_ArgA, _ArgB, _ArgT);
+ return _Common_lerp(static_cast(_ArgA), static_cast(_ArgB), static_cast(_ArgT));
}
_EXPORT_STD template
requires is_arithmetic_v<_Ty1> && is_arithmetic_v<_Ty2> && is_arithmetic_v<_Ty3>
_NODISCARD constexpr auto lerp(const _Ty1 _ArgA, const _Ty2 _ArgB, const _Ty3 _ArgT) noexcept {
- using _Tgt = conditional_t<_Is_any_of_v, long double, double>;
- return _Common_lerp(static_cast<_Tgt>(_ArgA), static_cast<_Tgt>(_ArgB), static_cast<_Tgt>(_ArgT));
+ using _Common = _Common_float_type_t<_Ty1, _Common_float_type_t<_Ty2, _Ty3>>;
+ return static_cast<_Common>(
+ _Common_lerp(static_cast(_ArgA), static_cast(_ArgB), static_cast(_ArgT)));
}
#endif // _HAS_CXX20
_STD_END
diff --git a/stl/inc/functional b/stl/inc/functional
index 1e8877df2d6..21654698b9b 100644
--- a/stl/inc/functional
+++ b/stl/inc/functional
@@ -974,7 +974,7 @@ private:
};
#if _HAS_CXX23
-template
+template
class _Function_base;
#endif // _HAS_CXX23
@@ -1105,7 +1105,7 @@ protected:
private:
#if _HAS_CXX23
- friend _Function_base<_Ret, false, _Types...>;
+ friend _Function_base<_Ret, _Types...>;
#endif // _HAS_CXX23
bool _Local() const noexcept { // test for locally stored copy of object
@@ -1574,10 +1574,11 @@ _NODISCARD void* _Function_new_large(_CTypes&&... _Args) {
return _Ptr;
}
-template
+template
class _Function_base {
public:
- using result_type = _Rx;
+ using result_type = _Rx;
+ using _Signature_without_cv_ref_noex = _Rx(_Types...);
struct _Impl_t { // A per-callable-type structure acting as a virtual function table.
// Using vtable emulations gives more flexibility for optimizations and reduces the amount of RTTI data.
@@ -1588,7 +1589,7 @@ public:
// empty function from a DLL that is unloaded later, and then safely moving/destroying that empty function.
// Calls target
- _Rx(__stdcall* _Invoke)(void*, _Types&&...) _NOEXCEPT_FNPTR_COND(_Noexcept);
+ _Rx(__stdcall* _Invoke)(void*, _Types&&...);
// Moves the data, including pointer to "vtable", AND destroys old data (not resetting its "vtable").
// nullptr if we can trivially move two pointers.
void(__stdcall* _Move)(_Function_data&, _Function_data&) _NOEXCEPT_FNPTR;
@@ -1625,12 +1626,12 @@ public:
void _Construct_with_old_fn(_Fn&& _Func) {
const auto _Old_fn_impl = _Func._Getimpl();
if (_Old_fn_impl == nullptr) {
- _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, void>();
+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, false, void>();
} else if (_Func._Local()) {
#ifdef _WIN64
_STL_INTERNAL_STATIC_ASSERT(alignof(max_align_t) == alignof(void*));
// 64-bit target, can put small function into small move_only_function directly
- _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, void>();
+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, false, void>();
if constexpr (is_lvalue_reference_v<_Fn>) {
_Old_fn_impl->_Copy(_Data._Buf_ptr());
} else {
@@ -1663,12 +1664,12 @@ public:
_Func._Tidy();
}
- _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, void>();
+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, false, void>();
_Data._Set_large_fn_ptr(_Where);
#endif // ^^^ 32-bit ^^^
} else {
// Just take ownership of the inner impl pointer
- _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, void>();
+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, false, void>();
if constexpr (is_lvalue_reference_v<_Fn>) {
_Data._Set_large_fn_ptr(_Old_fn_impl->_Copy(nullptr));
} else {
@@ -1678,9 +1679,9 @@ public:
}
}
- template
+ template
void _Construct_with_fn(_CTypes&&... _Args) {
- _Data._Impl = _Create_impl_ptr<_Impl_kind::_Usual, _Vt, _VtInvQuals>();
+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Usual, _Vt, _Noexcept, _VtInvQuals>();
if constexpr (_Large_function_engaged<_Vt>) {
_Data._Set_large_fn_ptr(_STD _Function_new_large<_Vt>(_STD forward<_CTypes>(_Args)...));
} else {
@@ -1756,8 +1757,17 @@ public:
|| sizeof(_Vt) > _Function_data::_Buf_size<_Vt>
|| !is_nothrow_move_constructible_v<_Vt>;
+ template
_NODISCARD auto _Get_invoke() const noexcept {
- return _Get_impl(_Data)->_Invoke;
+ if constexpr (_Noexcept) {
+#ifdef __cpp_noexcept_function_type
+ return reinterpret_cast<_Rx(__stdcall*)(void*, _Types&&...) noexcept>(_Get_impl(_Data)->_Invoke);
+#else
+ static_assert(false); // when noexcept isn't in the type system, this should never be selected
+#endif
+ } else {
+ return _Get_impl(_Data)->_Invoke;
+ }
}
_NODISCARD static const _Impl_t* _Get_impl(const _Function_data& _Data) noexcept {
@@ -1771,7 +1781,7 @@ public:
return _Ret ? _Ret : &_Null_move_only_function;
}
- template <_Impl_kind _Kind, class _Vt, class _VtInvQuals>
+ template <_Impl_kind _Kind, class _Vt, bool _Noexcept, class _VtInvQuals>
_NODISCARD static constexpr _Impl_t _Create_impl() noexcept {
_Impl_t _Impl{};
if constexpr (_Kind != _Impl_kind::_Usual) {
@@ -1834,9 +1844,9 @@ public:
return _Impl;
}
- template <_Impl_kind _Kind, class _Vt, class _VtInvQuals>
+ template <_Impl_kind _Kind, class _Vt, bool _Noexcept, class _VtInvQuals>
_NODISCARD static const _Impl_t* _Create_impl_ptr() noexcept {
- static constexpr _Impl_t _Impl = _Create_impl<_Kind, _Vt, _VtInvQuals>();
+ static constexpr _Impl_t _Impl = _Create_impl<_Kind, _Vt, _Noexcept, _VtInvQuals>();
return &_Impl;
}
};
@@ -1856,7 +1866,7 @@ class _Function_call {
// Beginning of generated code - DO NOT EDIT manually!
template
class _Function_call<_Rx(_Types...)> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, false, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = _Vt&;
@@ -1865,14 +1875,16 @@ public:
static constexpr bool _Is_callable_from =
is_invocable_r_v<_Rx, _Vt, _Types...> && is_invocable_r_v<_Rx, _Vt&, _Types...>;
+ static constexpr bool _Noexcept = false;
+
_Rx operator()(_Types... _Args) {
- return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) &> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, false, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = _Vt&;
@@ -1880,14 +1892,16 @@ public:
template
static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, _Vt&, _Types...>;
+ static constexpr bool _Noexcept = false;
+
_Rx operator()(_Types... _Args) & {
- return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) &&> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, false, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = _Vt&&;
@@ -1895,14 +1909,16 @@ public:
template
static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, _Vt, _Types...>;
+ static constexpr bool _Noexcept = false;
+
_Rx operator()(_Types... _Args) && {
- return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) const> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, false, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = const _Vt&;
@@ -1911,14 +1927,17 @@ public:
static constexpr bool _Is_callable_from =
is_invocable_r_v<_Rx, const _Vt, _Types...> && is_invocable_r_v<_Rx, const _Vt&, _Types...>;
+ static constexpr bool _Noexcept = false;
+
_Rx operator()(_Types... _Args) const {
- return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(
+ const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) const&> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, false, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = const _Vt&;
@@ -1926,14 +1945,17 @@ public:
template
static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, const _Vt&, _Types...>;
+ static constexpr bool _Noexcept = false;
+
_Rx operator()(_Types... _Args) const& {
- return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(
+ const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) const&&> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, false, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = const _Vt&&;
@@ -1941,15 +1963,18 @@ public:
template
static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, const _Vt, _Types...>;
+ static constexpr bool _Noexcept = false;
+
_Rx operator()(_Types... _Args) const&& {
- return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(
+ const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
}
};
#ifdef __cpp_noexcept_function_type
template
class _Function_call<_Rx(_Types...) noexcept> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, true, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = _Vt&;
@@ -1958,14 +1983,16 @@ public:
static constexpr bool _Is_callable_from =
is_nothrow_invocable_r_v<_Rx, _Vt, _Types...> && is_nothrow_invocable_r_v<_Rx, _Vt&, _Types...>;
+ static constexpr bool _Noexcept = true;
+
_Rx operator()(_Types... _Args) noexcept {
- return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) & noexcept> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, true, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = _Vt&;
@@ -1973,14 +2000,16 @@ public:
template
static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, _Vt&, _Types...>;
+ static constexpr bool _Noexcept = true;
+
_Rx operator()(_Types... _Args) & noexcept {
- return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) && noexcept> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, true, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = _Vt&&;
@@ -1988,14 +2017,16 @@ public:
template
static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, _Vt, _Types...>;
+ static constexpr bool _Noexcept = true;
+
_Rx operator()(_Types... _Args) && noexcept {
- return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) const noexcept> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, true, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = const _Vt&;
@@ -2004,14 +2035,17 @@ public:
static constexpr bool _Is_callable_from =
is_nothrow_invocable_r_v<_Rx, const _Vt, _Types...> && is_nothrow_invocable_r_v<_Rx, const _Vt&, _Types...>;
+ static constexpr bool _Noexcept = true;
+
_Rx operator()(_Types... _Args) const noexcept {
- return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(
+ const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) const & noexcept> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, true, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = const _Vt&;
@@ -2019,14 +2053,17 @@ public:
template
static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, const _Vt&, _Types...>;
+ static constexpr bool _Noexcept = true;
+
_Rx operator()(_Types... _Args) const& noexcept {
- return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(
+ const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
}
};
template
class _Function_call<_Rx(_Types...) const && noexcept> // Generated code - DO NOT EDIT manually!
- : public _Function_base<_Rx, true, _Types...> {
+ : public _Function_base<_Rx, _Types...> {
public:
template
using _VtInvQuals = const _Vt&&;
@@ -2034,8 +2071,11 @@ public:
template
static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, const _Vt, _Types...>;
+ static constexpr bool _Noexcept = true;
+
_Rx operator()(_Types... _Args) const&& noexcept {
- return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
+ return this->template _Get_invoke<_Noexcept>()(
+ const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...);
}
};
#endif // defined(__cpp_noexcept_function_type)
@@ -2060,6 +2100,19 @@ private:
is_constructible_v, initializer_list<_Ux>&, _CTypes...>
&& _Call::template _Is_callable_from>;
+ template
+ friend class move_only_function;
+
+ template
+ static constexpr bool _Is_move_only_function_varying_cv_ref_noex() {
+ if constexpr (_Is_specialization_v<_Vt, move_only_function>) {
+ return is_same_v;
+ } else {
+ return false;
+ }
+ }
+
public:
using typename _Call::result_type;
@@ -2079,7 +2132,7 @@ public:
using _Vt = decay_t<_Fn>;
static_assert(is_constructible_v<_Vt, _Fn>, "_Vt should be constructible from _Fn. "
"(N4950 [func.wrap.move.ctor]/6)");
- if constexpr (is_same_v<_Vt, function<_Signature...>>) {
+ if constexpr (is_same_v<_Vt, function>) {
this->template _Construct_with_old_fn<_Vt>(_STD forward<_Fn>(_Callable));
} else {
if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt>
@@ -2090,8 +2143,13 @@ public:
}
}
- using _VtInvQuals = _Call::template _VtInvQuals<_Vt>;
- this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable));
+ if constexpr (_Is_move_only_function_varying_cv_ref_noex<_Vt>()) {
+ _Call::_Checked_move(this->_Data, _Callable._Data);
+ _Callable._Reset_to_null();
+ } else {
+ using _VtInvQuals = _Call::template _VtInvQuals<_Vt>;
+ this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_STD forward<_Fn>(_Callable));
+ }
}
}
@@ -2102,7 +2160,7 @@ public:
static_assert(is_same_v<_Vt, _Fn>, "_Vt should be the same type as _Fn. (N4950 [func.wrap.move.ctor]/12)");
using _VtInvQuals = _Call::template _VtInvQuals<_Vt>;
- this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_CTypes>(_Args)...);
+ this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_STD forward<_CTypes>(_Args)...);
}
template
@@ -2112,7 +2170,7 @@ public:
static_assert(is_same_v<_Vt, _Fn>, "_Vt should be the same type as _Fn. (N4950 [func.wrap.move.ctor]/18)");
using _VtInvQuals = _Call::template _VtInvQuals<_Vt>;
- this->template _Construct_with_fn<_Vt, _VtInvQuals>(_Li, _STD forward<_CTypes>(_Args)...);
+ this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_Li, _STD forward<_CTypes>(_Args)...);
}
~move_only_function() {
diff --git a/stl/inc/regex b/stl/inc/regex
index 932cddeefe4..35ba5ef909b 100644
--- a/stl/inc/regex
+++ b/stl/inc/regex
@@ -1279,7 +1279,8 @@ enum _Node_flags : int { // flags for nfa nodes with special properties
_Fl_class_cl_all_bits = 0x800, // TRANSITION, ABI: GH-5242
_Fl_begin_needs_w = 0x100,
_Fl_begin_needs_s = 0x200,
- _Fl_begin_needs_d = 0x400
+ _Fl_begin_needs_d = 0x400,
+ _Fl_rep_branchless = 0x800,
};
_BITMASK_OPS(_EMPTY_ARGUMENT, _Node_flags)
@@ -1700,7 +1701,7 @@ class _Matcher3 { // provides ways to match a regular expression to a text seque
public:
_Matcher3(_It _Pfirst, _It _Plast, const _RxTraits& _Tr, _Root_node* _Re, unsigned int _Nx,
regex_constants::syntax_option_type _Sf, regex_constants::match_flag_type _Mf)
- : _Begin(_Pfirst), _End(_Plast), _Rep(_Re), _Sflags(_Sf), _Mflags(_Mf), _Ncap(_Nx),
+ : _Begin(_Pfirst), _End(_Plast), _Sflags(_Sf), _Mflags(_Mf), _Ncap(_Nx),
_Longest((_Re->_Flags & _Fl_longest) && !(_Mf & regex_constants::match_any)), _Traits(_Tr) {
_Loop_vals.resize(_Re->_Loops);
_Adl_verify_range(_Pfirst, _Plast);
@@ -1720,6 +1721,12 @@ public:
_Frames_limit = _Calculate_frames_limit(_Input_length);
_Complexity_limit = _Calculate_complexity_limit(_Input_length);
+ // TRANSITION, ABI, GH-6025:
+ // The first two nodes are of types _N_begin and _N_capture with capturing group 0.
+ // These nodes do not affect the state of the matcher and thus can be skipped immediately
+ // before engaging the expensive NFA interpreter loop.
+ _Start = _Re->_Next->_Next;
+
// sanitize multiline mode setting
#if _REGEX_LEGACY_MULTILINE_MODE
_Sflags |= regex_constants::multiline; // old matcher applied multiline mode for all grammars
@@ -1763,7 +1770,7 @@ public:
_Matched = false;
- bool _Succeeded = _Match_pat(_Rep) || _Matched;
+ bool _Succeeded = _Match_pat(_Start) || _Matched;
if (!_Succeeded) {
return false;
@@ -1832,7 +1839,7 @@ private:
_It _Begin;
_It _End;
- _Node_base* _Rep;
+ _Node_base* _Start;
regex_constants::syntax_option_type _Sflags;
regex_constants::match_flag_type _Mflags;
bool _Matched = false;
@@ -1900,7 +1907,7 @@ private:
void _Quantifier();
bool _Alternative();
void _Disjunction();
- void _Calculate_loop_simplicity(_Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep);
+ void _Calculate_loop_simplicity(_Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep, bool _Nonreentrant);
_FwdIt _Pat;
_FwdIt _End;
@@ -3997,14 +4004,13 @@ bool _Matcher3<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Match_pat(_Node_base* _N
{ // record current position
auto _Node = static_cast<_Node_capture*>(_Nx);
auto _Idx = _Node->_Idx;
- if (_Idx != 0U) {
- auto& _Group = _Tgt_state._Grps[_Idx];
- auto _Frame_idx = _Push_frame(_Rx_unwind_ops::_Capture_restore_begin, _Node);
- auto& _Frame = _Frames[_Frame_idx];
- _Frame._Pos = _Group._Begin;
- _Frame._Capture_idx = _Idx;
- _Group._Begin = _Tgt_state._Cur;
- }
+ _STL_INTERNAL_CHECK(_Idx != 0U);
+ auto& _Group = _Tgt_state._Grps[_Idx];
+ auto _Frame_idx = _Push_frame(_Rx_unwind_ops::_Capture_restore_begin, _Node);
+ auto& _Frame = _Frames[_Frame_idx];
+ _Frame._Pos = _Group._Begin;
+ _Frame._Capture_idx = _Idx;
+ _Group._Begin = _Tgt_state._Cur;
break;
}
@@ -4129,7 +4135,7 @@ bool _Matcher3<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Match_pat(_Node_base* _N
_Node_rep* _Nr = static_cast<_Node_end_rep*>(_Nx)->_Begin_rep;
auto& _Sav = _Loop_vals[_Nr->_Loop_number];
bool _Greedy = (_Nr->_Flags & _Fl_greedy) != 0;
- if (_Nr->_Simple_loop != 0) {
+ if (_Nr->_Simple_loop != 0 || (_Nr->_Flags & _Fl_rep_branchless) != 0) {
if (_Sav._Loop_idx == 1) {
auto& _Base_frame = _Frames[_Sav._Loop_frame_idx];
_Sav._Loop_length = _STD distance(_Base_frame._Pos, _Tgt_state._Cur);
@@ -4146,6 +4152,7 @@ bool _Matcher3<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Match_pat(_Node_base* _N
// allocate stack frame holding loop-specific unwinding opcode for second rep and beyond
auto _New_frame_code = _Base_frame._Code == _Rx_unwind_ops::_Loop_simple_greedy_firstrep
+ || _Base_frame._Code == _Rx_unwind_ops::_Loop_greedy
? _Rx_unwind_ops::_Loop_simple_greedy_lastrep
: _Rx_unwind_ops::_Do_nothing;
auto _New_frame_idx = _Push_frame(_New_frame_code, _Nr);
@@ -4469,7 +4476,7 @@ _BidIt _Matcher3<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Skip(
static constexpr wchar_t _Line_terminators_wchar_t[] = {static_cast(_Meta_cr),
static_cast(_Meta_nl), static_cast(_Meta_ls), static_cast(_Meta_ps)};
constexpr unsigned int _Max_recursion_depth = 50U;
- _Node_base* _Nx = _Node_arg ? _Node_arg : _Rep;
+ _Node_base* _Nx = _Node_arg ? _Node_arg : _Start;
while (_First_arg != _Last && _Nx) { // check current node
switch (_Nx->_Kind) { // handle current node's type
@@ -5424,7 +5431,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Disjunction() { // check for valid dis
template
void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity(
- _Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep) {
+ _Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep, const bool _Nonreentrant) {
// walks regex NFA, calculates values of _Node_rep::_Simple_loop
for (; _Nx != _Ne && _Nx; _Nx = _Nx->_Next) {
switch (_Nx->_Kind) {
@@ -5432,11 +5439,12 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity(
// _Node_if inside a _Node_rep makes the rep not simple
if (_Outer_rep) {
_Outer_rep->_Simple_loop = 0;
+ _Outer_rep->_Flags &= ~_Fl_rep_branchless;
}
// visit each branch of the if
for (_Node_if* _Branch = static_cast<_Node_if*>(_Nx)->_Child; _Branch; _Branch = _Branch->_Child) {
- _Calculate_loop_simplicity(_Branch->_Next, _Branch->_Endif, _Outer_rep);
+ _Calculate_loop_simplicity(_Branch->_Next, _Branch->_Endif, _Outer_rep, _Nonreentrant);
}
break;
@@ -5444,13 +5452,14 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity(
// A positive lookahead assertion inside a _Node_rep makes the rep not simple
if (_Outer_rep) {
_Outer_rep->_Simple_loop = 0;
+ _Outer_rep->_Flags &= ~_Fl_rep_branchless;
}
_FALLTHROUGH;
case _N_neg_assert:
// visit the assertion body
// note _Outer_rep being reset: the assertion regex is completely independent
- _Calculate_loop_simplicity(static_cast<_Node_assert*>(_Nx)->_Child, nullptr, nullptr);
+ _Calculate_loop_simplicity(static_cast<_Node_assert*>(_Nx)->_Child, nullptr, nullptr, true);
break;
case _N_rep:
@@ -5459,15 +5468,20 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity(
// If _Outer_rep can repeat at most once, we have to analyze the structure of the inner loop.
if (_Outer_rep) {
_Outer_rep->_Simple_loop = 0;
- auto _Inner_rep = static_cast<_Node_rep*>(_Nx);
- if (_Outer_rep->_Max >= 0 && _Outer_rep->_Max <= 1) {
- _Calculate_loop_simplicity(_Inner_rep->_Next, _Inner_rep->_End_rep->_Next, _Inner_rep);
- _Nx = _Inner_rep->_End_rep;
- } else {
+ _Outer_rep->_Flags &= ~_Fl_rep_branchless;
+ auto _Inner_rep = static_cast<_Node_rep*>(_Nx);
+ _Inner_rep->_Flags |= _Fl_rep_branchless;
+ const bool _Inner_nonreentrant = _Outer_rep->_Max >= 0 && _Outer_rep->_Max <= 1 && _Nonreentrant;
+ if (!_Inner_nonreentrant) {
_Inner_rep->_Simple_loop = 0;
}
+
+ _Calculate_loop_simplicity(
+ _Inner_rep->_Next, _Inner_rep->_End_rep->_Next, _Inner_rep, _Inner_nonreentrant);
+ _Nx = _Inner_rep->_End_rep;
} else {
_Outer_rep = static_cast<_Node_rep*>(_Nx);
+ _Outer_rep->_Flags |= _Fl_rep_branchless;
}
break;
@@ -5492,6 +5506,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity(
if (_Coll_diff_size || _Node->_Equiv
|| ((_Flags & regex_constants::collate) && (_Node->_Ranges || (_Node->_Flags & _Fl_negate)))) {
_Outer_rep->_Simple_loop = 0;
+ _Outer_rep->_Flags &= ~_Fl_rep_branchless;
}
}
break;
@@ -5530,7 +5545,7 @@ _Root_node* _Parser2<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular
_Res = _Nfa._End_pattern();
_Res->_Fl = _Flags;
_Res->_Marks = _Mark_count();
- _Calculate_loop_simplicity(_Res, nullptr, nullptr);
+ _Calculate_loop_simplicity(_Res, nullptr, nullptr, true);
_Guard._Target = nullptr;
return _Res;
}
diff --git a/stl/inc/vector b/stl/inc/vector
index 2994548bd8c..5ada42b06b7 100644
--- a/stl/inc/vector
+++ b/stl/inc/vector
@@ -39,7 +39,8 @@ public:
using pointer = typename _Myvec::const_pointer;
using reference = const value_type&;
- using _Tptr = typename _Myvec::pointer;
+ using _Tptr = typename _Myvec::pointer;
+ using _Myvec_t = _Myvec; // helper for expression evaluator
_CONSTEXPR20 _Vector_const_iterator() noexcept : _Ptr() {}
@@ -3705,8 +3706,8 @@ _CONSTEXPR20 void _Fill_vbool(_VbIt _First, const _VbIt _Last, const bool _Val)
} else
#endif // _HAS_CXX20
{
- const auto _VbFirst_ch = reinterpret_cast(_VbFirst);
- const auto _VbLast_ch = reinterpret_cast(_VbLast);
+ const auto _VbFirst_ch = reinterpret_cast(_VbFirst);
+ const auto _VbLast_ch = reinterpret_cast(_VbLast);
const auto _Count_ch = static_cast(_VbLast_ch - _VbFirst_ch);
const auto _ValChar = static_cast(_Val ? -1 : 0);
_CSTD memset(_VbFirst, _ValChar, _Count_ch);
@@ -3895,21 +3896,24 @@ _CONSTEXPR20 _OutIt _Copy_vbool(_VbIt _First, _VbIt _Last, _OutIt _Dest) {
} else
#endif // _HAS_CXX20
{
- // If _First and _Dest have matching char alignment, use memmove
+ // If _First and _Dest have matching unsigned char alignment, use memmove
const auto _UnalignedFirstBits = _First._Myoff & _Vbase{7};
const auto _UnalignedDestBits = _Dest._Myoff & _Vbase{7};
if (_UnalignedFirstBits == _UnalignedDestBits) {
const auto _UnalignedLastBits = _Last._Myoff & _Vbase{7};
- auto _VbFirst_ch = reinterpret_cast(_VbFirst) + (_First._Myoff - _UnalignedFirstBits) / 8;
- const auto _VbLast_ch = reinterpret_cast(_VbLast) + (_Last._Myoff - _UnalignedLastBits) / 8;
- auto _VbDest_ch = reinterpret_cast(_VbDest) + (_Dest._Myoff - _UnalignedDestBits) / 8;
+ auto _VbFirst_ch =
+ reinterpret_cast(_VbFirst) + (_First._Myoff - _UnalignedFirstBits) / 8;
+ const auto _VbLast_ch =
+ reinterpret_cast(_VbLast) + (_Last._Myoff - _UnalignedLastBits) / 8;
+ auto _VbDest_ch = reinterpret_cast(_VbDest) + (_Dest._Myoff - _UnalignedDestBits) / 8;
- // Copy bits until the next char alignment
+ // Copy bits until the next unsigned char alignment
if (_UnalignedFirstBits != 0) {
- const auto _SourceBitMask = static_cast(UCHAR_MAX << _UnalignedFirstBits);
- const auto _DestBitMask = static_cast(UCHAR_MAX >> (8 - _UnalignedFirstBits));
- *_VbDest_ch = (*_VbDest_ch & _DestBitMask) | (*_VbFirst_ch & _SourceBitMask);
+ const auto _SourceBitMask = static_cast(UCHAR_MAX << _UnalignedFirstBits);
+ const auto _DestBitMask = static_cast(UCHAR_MAX >> (8 - _UnalignedFirstBits));
+ *_VbDest_ch =
+ static_cast((*_VbDest_ch & _DestBitMask) | (*_VbFirst_ch & _SourceBitMask));
++_VbFirst_ch;
++_VbDest_ch;
}
@@ -3918,9 +3922,9 @@ _CONSTEXPR20 _OutIt _Copy_vbool(_VbIt _First, _VbIt _Last, _OutIt _Dest) {
// Copy remaining last bits
if (_UnalignedLastBits != 0) {
- const auto _SourceBitMask = static_cast(UCHAR_MAX >> (8 - _UnalignedLastBits));
- const auto _DestBitMask = static_cast(UCHAR_MAX << _UnalignedLastBits);
- *_VbDest_ch = (*_VbDest_ch & _DestBitMask) | (*_VbLast_ch & _SourceBitMask);
+ const auto _SourceBitMask = static_cast(UCHAR_MAX >> (8 - _UnalignedLastBits));
+ const auto _DestBitMask = static_cast(UCHAR_MAX << _UnalignedLastBits);
+ *_VbDest_ch = static_cast((*_VbDest_ch & _DestBitMask) | (*_VbLast_ch & _SourceBitMask));
}
return _DestEnd;
diff --git a/stl/inc/xutility b/stl/inc/xutility
index 39e202b8c27..0ce4be4193f 100644
--- a/stl/inc/xutility
+++ b/stl/inc/xutility
@@ -88,7 +88,7 @@ _STL_DISABLE_CLANG_WARNINGS
#define _VECTORIZED_FIND_LAST _VECTORIZED_FOR_X64_X86
#define _VECTORIZED_FIND_LAST_OF _VECTORIZED_FOR_X64_X86
#define _VECTORIZED_INCLUDES _VECTORIZED_FOR_X64_X86
-#define _VECTORIZED_IS_SORTED_UNTIL _VECTORIZED_FOR_X64_X86
+#define _VECTORIZED_IS_SORTED_UNTIL _VECTORIZED_FOR_X64_X86_ARM64
#define _VECTORIZED_MINMAX _VECTORIZED_FOR_X64_X86_ARM64
#define _VECTORIZED_MINMAX_ELEMENT _VECTORIZED_FOR_X64_X86_ARM64
#define _VECTORIZED_MISMATCH _VECTORIZED_FOR_X64_X86
diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h
index baaf9c6539a..7550a613043 100644
--- a/stl/inc/yvals_core.h
+++ b/stl/inc/yvals_core.h
@@ -1935,11 +1935,9 @@ _EMIT_STL_ERROR(STL1013, "The STL doesn't support /RTCc because it rejects confo
// The earliest Windows supported by this implementation is Windows 10.
#ifdef __cpp_noexcept_function_type
-#define _NOEXCEPT_FNPTR noexcept
-#define _NOEXCEPT_FNPTR_COND(...) noexcept(__VA_ARGS__)
+#define _NOEXCEPT_FNPTR noexcept
#else // ^^^ defined(__cpp_noexcept_function_type) / !defined(__cpp_noexcept_function_type) vvv
#define _NOEXCEPT_FNPTR
-#define _NOEXCEPT_FNPTR_COND(...)
#endif // ^^^ !defined(__cpp_noexcept_function_type) ^^^
#ifdef __clang__
diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp
index a9d49bd754a..57f33bfc920 100644
--- a/stl/src/vector_algorithms.cpp
+++ b/stl/src/vector_algorithms.cpp
@@ -1085,6 +1085,11 @@ namespace {
return vget_lane_u64(vreinterpret_u64_u8(_Res), 0);
}
+ static uint64_t _Match_mask(const _Vec_t _Val_lo, const _Vec_t _Val_hi) noexcept {
+ const uint64x2_t _Val = vreinterpretq_u64_s8(vorrq_s8(_Val_lo, _Val_hi));
+ return vgetq_lane_u64(vpaddq_u64(_Val, _Val), 0);
+ }
+
static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept {
return _CountTrailingZeros64(_Mask) >> 2;
}
@@ -1396,6 +1401,11 @@ namespace {
return vget_lane_u64(vreinterpret_u64_u16(_Res), 0);
}
+ static uint64_t _Match_mask(const _Vec_t _Val_lo, const _Vec_t _Val_hi) noexcept {
+ const int8x8_t _Val = vaddhn_s16(_Val_lo, _Val_hi);
+ return vget_lane_u64(vreinterpret_u64_s8(_Val), 0);
+ }
+
static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept {
return _CountTrailingZeros64(_Mask) >> 2;
}
@@ -1704,6 +1714,11 @@ namespace {
return vget_lane_u64(vreinterpret_u64_u32(_Res), 0);
}
+ static uint64_t _Match_mask(const _Vec_t _Val_lo, const _Vec_t _Val_hi) noexcept {
+ const int8x8_t _Val = vaddhn_s16(vreinterpretq_s16_s32(_Val_lo), vreinterpretq_s16_s32(_Val_hi));
+ return vget_lane_u64(vreinterpret_u64_s8(_Val), 0);
+ }
+
static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept {
return _CountTrailingZeros64(_Mask) >> 2;
}
@@ -1983,6 +1998,21 @@ namespace {
return _Val;
}
+ // Compresses a 128-bit Mask of 2 64-bit values into a 64-bit Mask of 2 32-bit values.
+ static uint64_t _Mask(const _Vec_t _Val) noexcept {
+ const uint32x2_t _Res = vreinterpret_u32_s32(vmovn_s64(_Val));
+ return vget_lane_u64(vreinterpret_u64_u32(_Res), 0);
+ }
+
+ static uint64_t _Match_mask(const _Vec_t _Val_lo, const _Vec_t _Val_hi) noexcept {
+ const int8x8_t _Val = vaddhn_s16(vreinterpretq_s16_s64(_Val_lo), vreinterpretq_s16_s64(_Val_hi));
+ return vget_lane_u64(vreinterpret_u64_s8(_Val), 0);
+ }
+
+ static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept {
+ return _CountTrailingZeros64(_Mask) >> 2;
+ }
+
static _Vec_t _Load(const void* const _Src) noexcept {
return vld1q_s64(reinterpret_cast(_Src));
}
@@ -2048,6 +2078,10 @@ namespace {
static _Vec_t _Max_u(const _Vec_t _First, const _Vec_t _Second) noexcept {
return _Max(_First, _Second, _Cmp_gt_u(_Second, _First));
}
+
+ static _Vec_t _Mask_cast(const _Vec_t _Mask) noexcept {
+ return _Mask;
+ }
};
#elif !defined(_M_ARM64EC)
struct _Traits_8_sse : _Traits_8_base, _Traits_sse_base {
@@ -2284,6 +2318,10 @@ namespace {
return _Traits_4_neon::_Mask(_Val);
}
+ static uint64_t _Match_mask(const _Idx_t _Val_lo, const _Idx_t _Val_hi) noexcept {
+ return _Traits_4_neon::_Match_mask(_Val_lo, _Val_hi);
+ }
+
static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept {
return _Traits_4_neon::_Get_first_h_pos(_Mask);
}
@@ -2549,12 +2587,15 @@ namespace {
// Compresses a 128-bit Mask of 2 64-bit values into a 64-bit Mask of 2 32-bit values.
static uint64_t _Mask(const int64x2_t _Val) noexcept {
- const uint32x2_t _Res = vreinterpret_u32_s32(vmovn_s64(_Val));
- return vget_lane_u64(vreinterpret_u64_u32(_Res), 0);
+ return _Traits_8_neon::_Mask(_Val);
+ }
+
+ static uint64_t _Match_mask(const _Idx_t _Val_lo, const _Idx_t _Val_hi) noexcept {
+ return _Traits_8_neon::_Match_mask(_Val_lo, _Val_hi);
}
static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept {
- return _CountTrailingZeros64(_Mask) >> 2;
+ return _Traits_8_neon::_Get_first_h_pos(_Mask);
}
static unsigned long _Get_last_h_pos(const uint64_t _Mask) noexcept {
@@ -3490,7 +3531,88 @@ namespace {
return _Minmax_impl<_Mode, typename _Traits::_Scalar, _Sign>(_First, _Last);
}
-#ifndef _M_ARM64
+#ifdef _M_ARM64
+ template
+ const void* _Is_sorted_until_impl(const void* _First, const void* const _Last, const bool _Greater) noexcept {
+ const ptrdiff_t _Left_off = 0 - static_cast(_Greater);
+ const ptrdiff_t _Right_off = static_cast(_Greater) - 1;
+
+ if constexpr (_Traits::_Vectorized) {
+ const size_t _Total_size_bytes = _Byte_length(_First, _Last);
+
+ const auto _Cmp_gt_wrap = [](const auto _Right, const auto _Left) noexcept {
+ constexpr bool _Unsigned = static_cast<_Ty>(-1) > _Ty{0};
+
+ if constexpr (_Unsigned && _Traits::_Has_unsigned_cmp) {
+ return _Traits::_Cmp_gt_u(_Right, _Left);
+ } else {
+ return _Traits::_Cmp_gt(_Right, _Left);
+ }
+ };
+
+ if (_Total_size_bytes >= 32) {
+ constexpr size_t _Bytes_per_iter = 2 * _Traits::_Vec_size;
+ const size_t _Vec_byte_size = _Total_size_bytes & ~(_Bytes_per_iter - 1);
+ const void* _Stop_at = _First;
+ _Advance_bytes(_Stop_at, _Vec_byte_size);
+
+ do {
+ const void* const _Next = static_cast(_First) + _Traits::_Vec_size;
+
+ const auto _Left_lo = _Traits::_Load(static_cast(_First) + _Left_off);
+ const auto _Right_lo = _Traits::_Load(static_cast(_First) + _Right_off);
+ const auto _Left_hi = _Traits::_Load(static_cast(_Next) + _Left_off);
+ const auto _Right_hi = _Traits::_Load(static_cast(_Next) + _Right_off);
+
+ const auto _Is_less_lo = _Cmp_gt_wrap(_Right_lo, _Left_lo);
+ const auto _Is_less_hi = _Cmp_gt_wrap(_Right_hi, _Left_hi);
+ const auto _Any_match = _Traits::_Match_mask(_Is_less_lo, _Is_less_hi);
+
+ if (_Any_match != 0) {
+ const auto _Mask_lo = _Traits::_Mask(_Is_less_lo);
+ if (_Mask_lo != 0) {
+ const unsigned long _H_pos = _Traits::_Get_first_h_pos(_Mask_lo);
+ _Advance_bytes(_First, _H_pos);
+ return _First;
+ }
+
+ const auto _Mask_hi = _Traits::_Mask(_Is_less_hi);
+ const unsigned long _H_pos = _Traits::_Get_first_h_pos(_Mask_hi) + _Traits::_Vec_size;
+ _Advance_bytes(_First, _H_pos);
+ return _First;
+ }
+
+ _Advance_bytes(_First, 2 * _Traits::_Vec_size);
+ } while (_First != _Stop_at);
+ }
+
+ const size_t _Has_vec_tail = (_Byte_length(_First, _Last) & ~_Traits::_Vec_mask) != 0;
+ if (_Has_vec_tail) {
+ const auto _Left = _Traits::_Load(static_cast(_First) + _Left_off);
+ const auto _Right = _Traits::_Load(static_cast(_First) + _Right_off);
+
+ const auto _Is_less = _Cmp_gt_wrap(_Right, _Left);
+ const auto _Mask = _Traits::_Mask(_Traits::_Mask_cast(_Is_less));
+
+ if (_Mask != 0) {
+ const unsigned long _H_pos = _Traits::_Get_first_h_pos(_Mask);
+ _Advance_bytes(_First, _H_pos);
+ return _First;
+ }
+
+ _Advance_bytes(_First, _Traits::_Vec_size);
+ }
+ }
+
+ for (const _Ty* _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) {
+ if (_Ptr[_Left_off] < _Ptr[_Right_off]) {
+ return _Ptr;
+ }
+ }
+
+ return _Last;
+ }
+#else // ^^^ defined(_M_ARM64) / !defined(_M_ARM64) vvv
template
const void* _Is_sorted_until_impl(const void* _First, const void* const _Last, const bool _Greater) noexcept {
const ptrdiff_t _Left_off = 0 - static_cast(_Greater);
@@ -3569,6 +3691,7 @@ namespace {
return _Last;
}
+#endif // ^^^ !defined(_M_ARM64) ^^^
template
const void* __stdcall _Is_sorted_until_disp(
@@ -3579,7 +3702,11 @@ namespace {
_Advance_bytes(_First, sizeof(_Ty));
-#ifndef _M_ARM64EC
+#ifdef _M_ARM64
+ if (_Byte_length(_First, _Last) >= 16) {
+ return _Is_sorted_until_impl(_First, _Last, _Greater);
+ }
+#elif !defined(_M_ARM64EC)
if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) {
return _Is_sorted_until_impl(_First, _Last, _Greater);
}
@@ -3590,7 +3717,6 @@ namespace {
#endif // ^^^ !defined(_M_ARM64EC) ^^^
return _Is_sorted_until_impl(_First, _Last, _Greater);
}
-#endif // ^^^ !defined(_M_ARM64) ^^^
} // namespace _Sorting
} // unnamed namespace
@@ -3812,7 +3938,6 @@ __declspec(noalias) _Min_max_d __stdcall __std_minmax_d(const void* const _First
return _Sorting::_Minmax_disp<_Sorting::_Mode_both, _Sorting::_Traits_d, true>(_First, _Last);
}
-#ifndef _M_ARM64
const void* __stdcall __std_is_sorted_until_1i(
const void* const _First, const void* const _Last, const bool _Greater) noexcept {
return _Sorting::_Is_sorted_until_disp<_Sorting::_Traits_1, int8_t>(_First, _Last, _Greater);
@@ -3862,7 +3987,6 @@ const void* __stdcall __std_is_sorted_until_d(
const void* const _First, const void* const _Last, const bool _Greater) noexcept {
return _Sorting::_Is_sorted_until_disp<_Sorting::_Traits_d, double>(_First, _Last, _Greater);
}
-#endif // ^^^ !defined(_M_ARM64) ^^^
} // extern "C"
diff --git a/tests/std/test.lst b/tests/std/test.lst
index 7e348a49808..b6d7f41de16 100644
--- a/tests/std/test.lst
+++ b/tests/std/test.lst
@@ -277,6 +277,7 @@ tests\GH_005546_containers_size_type_cast
tests\GH_005553_regex_character_translation
tests\GH_005768_pow_accuracy
tests\GH_005800_stable_sort_large_alignment
+tests\GH_005968_headers_provide_begin_end
tests\LWG2381_num_get_floating_point
tests\LWG2510_tag_classes
tests\LWG2597_complex_branch_cut
diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/env.lst b/tests/std/tests/GH_000625_vector_bool_optimization/env.lst
index 19f025bd0e6..52bbd11aa13 100644
--- a/tests/std/tests/GH_000625_vector_bool_optimization/env.lst
+++ b/tests/std/tests/GH_000625_vector_bool_optimization/env.lst
@@ -1,4 +1,7 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-RUNALL_INCLUDE ..\usual_matrix.lst
+RUNALL_INCLUDE ..\impure_matrix.lst
+RUNALL_CROSSLIST
+* PM_CL=""
+* PM_CL="/J"
diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp
index 41e73cff35a..6a7ab81aea1 100644
--- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp
+++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp
@@ -18,8 +18,6 @@
#define CONSTEXPR20 inline
#endif
-#pragma warning(disable : 4365) // conversion from 'unsigned __int64' to 'const __int64', signed/unsigned mismatch
-
using namespace std;
constexpr int blockSize = 32;
@@ -84,14 +82,14 @@ CONSTEXPR20 void test_transform_helper(const size_t length) {
transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xnor_expected_raw), equal_to<>{});
transform(begin(source_raw), end(source_raw), begin(not_expected_raw), logical_not<>{});
- const vector source1(source_raw, source_raw + length);
- const vector source2(source2_raw, source2_raw + length);
+ const vector source1(source_raw, source_raw + static_cast(length));
+ const vector source2(source2_raw, source2_raw + static_cast(length));
- vector and_expected(and_expected_raw, and_expected_raw + length);
- vector or_expected(or_expected_raw, or_expected_raw + length);
- vector xor_expected(xor_expected_raw, xor_expected_raw + length);
- vector xnor_expected(xnor_expected_raw, xnor_expected_raw + length);
- vector not_expected(not_expected_raw, not_expected_raw + length);
+ vector and_expected(and_expected_raw, and_expected_raw + static_cast(length));
+ vector or_expected(or_expected_raw, or_expected_raw + static_cast(length));
+ vector xor_expected(xor_expected_raw, xor_expected_raw + static_cast(length));
+ vector xnor_expected(xnor_expected_raw, xnor_expected_raw + static_cast(length));
+ vector not_expected(not_expected_raw, not_expected_raw + static_cast(length));
and_expected.resize(length + 3, false);
or_expected.resize(length + 3, false);
@@ -110,49 +108,49 @@ CONSTEXPR20 void test_transform_helper(const size_t length) {
const auto cfirst1 = source1.cbegin();
const auto first2 = source2.begin();
const auto cfirst2 = source2.cbegin();
- const auto last1 = first1 + length;
- const auto clast1 = cfirst1 + length;
+ const auto last1 = first1 + static_cast(length);
+ const auto clast1 = cfirst1 + static_cast(length);
{
auto and_ret = transform(first1, last1, first2, and_actual.begin(), logical_and<>{});
assert(and_actual == and_expected);
- assert(and_ret == and_actual.begin() + length);
+ assert(and_ret == and_actual.begin() + static_cast(length));
and_actual.assign(and_actual.size(), false);
and_ret = transform(first1, last1, first2, and_actual.begin(), bit_and<>{});
assert(and_actual == and_expected);
- assert(and_ret == and_actual.begin() + length);
+ assert(and_ret == and_actual.begin() + static_cast(length));
}
{
auto or_ret = transform(first1, last1, cfirst2, or_actual.begin(), logical_or<>{});
assert(or_actual == or_expected);
- assert(or_ret == or_actual.begin() + length);
+ assert(or_ret == or_actual.begin() + static_cast(length));
or_actual.assign(or_actual.size(), false);
or_ret = transform(first1, last1, cfirst2, or_actual.begin(), bit_or<>{});
assert(or_actual == or_expected);
- assert(or_ret == or_actual.begin() + length);
+ assert(or_ret == or_actual.begin() + static_cast(length));
}
{
auto xor_ret = transform(cfirst1, clast1, first2, xor_actual.begin(), not_equal_to<>{});
assert(xor_actual == xor_expected);
- assert(xor_ret == xor_actual.begin() + length);
+ assert(xor_ret == xor_actual.begin() + static_cast(length));
xor_actual.assign(xor_actual.size(), false);
xor_ret = transform(cfirst1, clast1, first2, xor_actual.begin(), bit_xor<>{});
assert(xor_actual == xor_expected);
- assert(xor_ret == xor_actual.begin() + length);
+ assert(xor_ret == xor_actual.begin() + static_cast(length));
}
{
const auto xnor_ret = transform(cfirst1, clast1, cfirst2, xnor_actual.begin(), equal_to<>{});
assert(xnor_actual == xnor_expected);
- assert(xnor_ret == xnor_actual.begin() + length);
+ assert(xnor_ret == xnor_actual.begin() + static_cast(length));
// bit_xnor doesn't exist in the Standard
}
@@ -160,7 +158,7 @@ CONSTEXPR20 void test_transform_helper(const size_t length) {
{
auto not_ret = transform(first1, last1, not_actual.begin(), logical_not<>{});
assert(not_actual == not_expected);
- assert(not_ret == not_actual.begin() + length);
+ assert(not_ret == not_actual.begin() + static_cast(length));
not_actual.assign(not_actual.size(), false);
@@ -168,7 +166,7 @@ CONSTEXPR20 void test_transform_helper(const size_t length) {
// Continue using logical_not to test vector::const_iterator:
not_ret = transform(cfirst1, clast1, not_actual.begin(), logical_not<>{});
assert(not_actual == not_expected);
- assert(not_ret == not_actual.begin() + length);
+ assert(not_ret == not_actual.begin() + static_cast(length));
}
}
@@ -459,28 +457,29 @@ CONSTEXPR20 void test_copy_no_offset(const size_t length) {
{
vector dest(length, false);
- const auto res_copy = copy(source.begin(), next(source.begin(), length), dest.begin());
+ const auto res_copy = copy(source.begin(), source.begin() + static_cast(length), dest.begin());
assert(dest == result);
assert(res_copy == dest.end());
}
{
vector dest_n(length, false);
- const auto res_copy_n = copy_n(source.begin(), length, dest_n.begin());
+ const auto res_copy_n = copy_n(source.begin(), static_cast(length), dest_n.begin());
assert(dest_n == result);
assert(res_copy_n == dest_n.end());
}
{
vector dest_backward(length, false);
- const auto res_copy_backward = copy_backward(source.begin(), next(source.begin(), length), dest_backward.end());
+ const auto res_copy_backward =
+ copy_backward(source.begin(), source.begin() + static_cast(length), dest_backward.end());
assert(dest_backward == result);
assert(res_copy_backward == dest_backward.begin());
}
{
vector dest_move(length, false);
- const auto res_move = move(source.begin(), next(source.begin(), length), dest_move.begin());
+ const auto res_move = move(source.begin(), source.begin() + static_cast(length), dest_move.begin());
assert(dest_move == result);
assert(res_move == dest_move.end());
}
@@ -488,7 +487,7 @@ CONSTEXPR20 void test_copy_no_offset(const size_t length) {
{
vector dest_move_backward(length, false);
const auto res_move_backward =
- move_backward(source.begin(), next(source.begin(), length), dest_move_backward.end());
+ move_backward(source.begin(), source.begin() + static_cast(length), dest_move_backward.end());
assert(dest_move_backward == result);
assert(res_move_backward == dest_move_backward.begin());
}
@@ -546,37 +545,39 @@ CONSTEXPR20 void test_copy_offset_source(const size_t length) {
{
vector dest(length, false);
- const auto res_copy = copy(next(source.begin()), next(source.begin(), length + 1), dest.begin());
+ const auto res_copy =
+ copy(next(source.begin()), source.begin() + static_cast(length) + 1, dest.begin());
assert(dest == result);
assert(res_copy == dest.end());
}
{
vector dest_n(length, false);
- const auto res_copy_n = copy_n(next(source.begin()), length, dest_n.begin());
+ const auto res_copy_n = copy_n(next(source.begin()), static_cast(length), dest_n.begin());
assert(dest_n == result);
assert(res_copy_n == dest_n.end());
}
{
vector dest_backward(length, false);
- const auto res_copy_backward =
- copy_backward(next(source.begin()), next(source.begin(), length + 1), dest_backward.end());
+ const auto res_copy_backward = copy_backward(
+ next(source.begin()), source.begin() + static_cast(length) + 1, dest_backward.end());
assert(dest_backward == result);
assert(res_copy_backward == dest_backward.begin());
}
{
vector dest_move(length, false);
- const auto res_move = move(next(source.begin()), next(source.begin(), length + 1), dest_move.begin());
+ const auto res_move =
+ move(next(source.begin()), source.begin() + static_cast(length) + 1, dest_move.begin());
assert(dest_move == result);
assert(res_move == dest_move.end());
}
{
vector dest_move_backward(length, false);
- const auto res_move_backward =
- move_backward(next(source.begin()), next(source.begin(), length + 1), dest_move_backward.end());
+ const auto res_move_backward = move_backward(
+ next(source.begin()), source.begin() + static_cast(length) + 1, dest_move_backward.end());
assert(dest_move_backward == result);
assert(res_move_backward == dest_move_backward.begin());
}
@@ -639,28 +640,30 @@ CONSTEXPR20 void test_copy_offset_dest(const size_t length) {
{
vector dest(length + 1, false);
- const auto res_copy = copy(source.begin(), next(source.begin(), length), next(dest.begin()));
+ const auto res_copy = copy(source.begin(), source.begin() + static_cast(length), next(dest.begin()));
assert(dest == result);
assert(res_copy == dest.end());
}
{
vector dest_n(length + 1, false);
- const auto res_copy_n = copy_n(source.begin(), length, next(dest_n.begin()));
+ const auto res_copy_n = copy_n(source.begin(), static_cast(length), next(dest_n.begin()));
assert(dest_n == result);
assert(res_copy_n == dest_n.end());
}
{
vector dest_backward(length + 1, false);
- const auto res_copy_backward = copy_backward(source.begin(), next(source.begin(), length), dest_backward.end());
+ const auto res_copy_backward =
+ copy_backward(source.begin(), source.begin() + static_cast(length), dest_backward.end());
assert(dest_backward == result);
assert(res_copy_backward == next(dest_backward.begin()));
}
{
vector dest_move(length + 1, false);
- const auto res_move = move(source.begin(), next(source.begin(), length), next(dest_move.begin()));
+ const auto res_move =
+ move(source.begin(), source.begin() + static_cast(length), next(dest_move.begin()));
assert(dest_move == result);
assert(res_move == dest_move.end());
}
@@ -668,7 +671,7 @@ CONSTEXPR20 void test_copy_offset_dest(const size_t length) {
{
vector dest_move_backward(length + 1, false);
const auto res_move_backward =
- move_backward(source.begin(), next(source.begin(), length), dest_move_backward.end());
+ move_backward(source.begin(), source.begin() + static_cast(length), dest_move_backward.end());
assert(dest_move_backward == result);
assert(res_move_backward == next(dest_move_backward.begin()));
}
@@ -731,14 +734,15 @@ CONSTEXPR20 void test_copy_offset_match(const size_t length) {
{
vector dest(length, false);
- const auto res_copy = copy(next(source.begin()), next(source.begin(), length), next(dest.begin()));
+ const auto res_copy =
+ copy(next(source.begin()), source.begin() + static_cast(length), next(dest.begin()));
assert(dest == result);
assert(res_copy == dest.end());
}
{
vector dest_n(length, false);
- const auto res_copy_n = copy_n(next(source.begin()), length - 1, next(dest_n.begin()));
+ const auto res_copy_n = copy_n(next(source.begin()), static_cast(length) - 1, next(dest_n.begin()));
assert(dest_n == result);
assert(res_copy_n == dest_n.end());
}
@@ -746,22 +750,23 @@ CONSTEXPR20 void test_copy_offset_match(const size_t length) {
{
vector dest_backward(length, false);
const auto res_copy_backward =
- copy_backward(next(source.begin()), next(source.begin(), length), dest_backward.end());
+ copy_backward(next(source.begin()), source.begin() + static_cast(length), dest_backward.end());
assert(dest_backward == result);
assert(res_copy_backward == next(dest_backward.begin()));
}
{
vector dest_move(length, false);
- const auto res_move = move(next(source.begin()), next(source.begin(), length), next(dest_move.begin()));
+ const auto res_move =
+ move(next(source.begin()), source.begin() + static_cast(length), next(dest_move.begin()));
assert(dest_move == result);
assert(res_move == dest_move.end());
}
{
vector dest_move_backward(length, false);
- const auto res_move_backward =
- move_backward(next(source.begin()), next(source.begin(), length), dest_move_backward.end());
+ const auto res_move_backward = move_backward(
+ next(source.begin()), source.begin() + static_cast(length), dest_move_backward.end());
assert(dest_move_backward == result);
assert(res_move_backward == next(dest_move_backward.begin()));
}
@@ -824,14 +829,16 @@ CONSTEXPR20 void test_copy_offset_mismatch_leftshift(const size_t length) {
{
vector dest(length + 1, false);
- const auto res_copy = copy(next(source.begin()), next(source.begin(), length), next(dest.begin(), 2));
+ const auto res_copy =
+ copy(next(source.begin()), source.begin() + static_cast(length), next(dest.begin(), 2));
assert(dest == result);
assert(res_copy == dest.end());
}
{
vector dest_n(length + 1, false);
- const auto res_copy_n = copy_n(next(source.begin()), length - 1, next(dest_n.begin(), 2));
+ const auto res_copy_n =
+ copy_n(next(source.begin()), static_cast(length) - 1, next(dest_n.begin(), 2));
assert(dest_n == result);
assert(res_copy_n == dest_n.end());
}
@@ -839,22 +846,23 @@ CONSTEXPR20 void test_copy_offset_mismatch_leftshift(const size_t length) {
{
vector dest_backward(length + 1, false);
const auto res_copy_backward =
- copy_backward(next(source.begin()), next(source.begin(), length), dest_backward.end());
+ copy_backward(next(source.begin()), source.begin() + static_cast(length), dest_backward.end());
assert(dest_backward == result);
assert(res_copy_backward == next(dest_backward.begin(), 2));
}
{
vector dest_move(length + 1, false);
- const auto res_move = move(next(source.begin()), next(source.begin(), length), next(dest_move.begin(), 2));
+ const auto res_move =
+ move(next(source.begin()), source.begin() + static_cast(length), next(dest_move.begin(), 2));
assert(dest_move == result);
assert(res_move == dest_move.end());
}
{
vector dest_move_backward(length + 1, false);
- const auto res_move_backward =
- move_backward(next(source.begin()), next(source.begin(), length), dest_move_backward.end());
+ const auto res_move_backward = move_backward(
+ next(source.begin()), source.begin() + static_cast(length), dest_move_backward.end());
assert(dest_move_backward == result);
assert(res_move_backward == next(dest_move_backward.begin(), 2));
}
@@ -919,37 +927,40 @@ CONSTEXPR20 void test_copy_offset_mismatch_rightshift(const size_t length) {
{
vector dest(length, false);
- const auto res_copy = copy(next(source.begin(), 2), next(source.begin(), length + 1), next(dest.begin()));
+ const auto res_copy =
+ copy(next(source.begin(), 2), source.begin() + static_cast(length) + 1, next(dest.begin()));
assert(dest == result);
assert(res_copy == dest.end());
}
{
vector dest_n(length, false);
- const auto res_copy_n = copy_n(next(source.begin(), 2), length - 1, next(dest_n.begin()));
+ const auto res_copy_n =
+ copy_n(next(source.begin(), 2), static_cast(length) - 1, next(dest_n.begin()));
assert(dest_n == result);
assert(res_copy_n == dest_n.end());
}
{
vector dest_backward(length, false);
- const auto res_copy_backward =
- copy_backward(next(source.begin(), 2), next(source.begin(), length + 1), dest_backward.end());
+ const auto res_copy_backward = copy_backward(
+ next(source.begin(), 2), source.begin() + static_cast(length) + 1, dest_backward.end());
assert(dest_backward == result);
assert(res_copy_backward == next(dest_backward.begin()));
}
{
vector dest_move(length, false);
- const auto res_move = move(next(source.begin(), 2), next(source.begin(), length + 1), next(dest_move.begin()));
+ const auto res_move =
+ move(next(source.begin(), 2), source.begin() + static_cast(length) + 1, next(dest_move.begin()));
assert(dest_move == result);
assert(res_move == dest_move.end());
}
{
vector dest_move_backward(length, false);
- const auto res_move_backward =
- move_backward(next(source.begin(), 2), next(source.begin(), length + 1), dest_move_backward.end());
+ const auto res_move_backward = move_backward(
+ next(source.begin(), 2), source.begin() + static_cast(length) + 1, dest_move_backward.end());
assert(dest_move_backward == result);
assert(res_move_backward == next(dest_move_backward.begin()));
}
@@ -1012,37 +1023,40 @@ CONSTEXPR20 void test_copy_offset_aligned(const size_t length) {
{
vector dest(length, false);
- const auto res_copy = copy(next(source.begin(), 9), next(source.begin(), length + 8), next(dest.begin()));
+ const auto res_copy =
+ copy(next(source.begin(), 9), source.begin() + static_cast(length) + 8, next(dest.begin()));
assert(dest == result);
assert(res_copy == dest.end());
}
{
vector dest_n(length, false);
- const auto res_copy_n = copy_n(next(source.begin(), 9), length - 1, next(dest_n.begin()));
+ const auto res_copy_n =
+ copy_n(next(source.begin(), 9), static_cast(length) - 1, next(dest_n.begin()));
assert(dest_n == result);
assert(res_copy_n == dest_n.end());
}
{
vector dest_backward(length, false);
- const auto res_copy_backward =
- copy_backward(next(source.begin(), 9), next(source.begin(), length + 8), dest_backward.end());
+ const auto res_copy_backward = copy_backward(
+ next(source.begin(), 9), source.begin() + static_cast(length) + 8, dest_backward.end());
assert(dest_backward == result);
assert(res_copy_backward == next(dest_backward.begin()));
}
{
vector dest_move(length, false);
- const auto res_move = move(next(source.begin(), 9), next(source.begin(), length + 8), next(dest_move.begin()));
+ const auto res_move =
+ move(next(source.begin(), 9), source.begin() + static_cast(length) + 8, next(dest_move.begin()));
assert(dest_move == result);
assert(res_move == dest_move.end());
}
{
vector dest_move_backward(length, false);
- const auto res_move_backward =
- move_backward(next(source.begin(), 9), next(source.begin(), length + 8), dest_move_backward.end());
+ const auto res_move_backward = move_backward(
+ next(source.begin(), 9), source.begin() + static_cast(length) + 8, dest_move_backward.end());
assert(dest_move_backward == result);
assert(res_move_backward == next(dest_move_backward.begin()));
}
@@ -1389,8 +1403,8 @@ void randomized_test_copy(mt19937_64& gen) {
// src vector:
// dst vector:
- vector vb_src(src_prefix + copy_len + src_suffix);
- vector vb_dst(dst_prefix + copy_len + dst_suffix);
+ vector vb_src(static_cast(src_prefix + copy_len + src_suffix));
+ vector vb_dst(static_cast(dst_prefix + copy_len + dst_suffix));
generate(vb_src.begin(), vb_src.end(), bool_dist);
generate(vb_dst.begin(), vb_dst.end(), bool_dist);
@@ -1435,7 +1449,7 @@ void randomized_test_copy(mt19937_64& gen) {
// ^
//
- vector vb(prefix + overhang + copy_len + suffix);
+ vector vb(static_cast(prefix + overhang + copy_len + suffix));
generate(vb.begin(), vb.end(), bool_dist);
@@ -1473,7 +1487,7 @@ void randomized_test_copy(mt19937_64& gen) {
// Vector diagram:
//
- vector vb(prefix + copy_len + gap + copy_len + suffix);
+ vector vb(static_cast(prefix + copy_len + gap + copy_len + suffix));
generate(vb.begin(), vb.end(), bool_dist);
diff --git a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp
index 1102e74009b..62e1a6ed6db 100644
--- a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp
+++ b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp
@@ -69,12 +69,18 @@ struct copy_counter {
int count = 0;
};
-using fn_type = int(copy_counter);
+using fn_type = int(copy_counter);
+using fn_type_r = int(copy_counter) &;
+using fn_type_c = int(copy_counter) const;
+
+#ifdef __cpp_noexcept_function_type
+using fn_type_nx = int(copy_counter) noexcept;
+#endif // defined(__cpp_noexcept_function_type)
struct small_callable {
const int context = 42;
- int operator()(const copy_counter& counter) {
+ int operator()(const copy_counter& counter) const noexcept {
assert(context == 42);
return counter.count;
}
@@ -83,7 +89,7 @@ struct small_callable {
struct alignas(128) large_callable {
const int context = 1729;
- int operator()(const copy_counter& counter) {
+ int operator()(const copy_counter& counter) const noexcept {
assert((reinterpret_cast(this) & 0x7f) == 0);
assert(context == 1729);
return counter.count;
@@ -156,6 +162,22 @@ int main() {
alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0);
alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0);
+ // Abominables and noexcept specifier
+ alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0);
+ alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0);
+ alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0);
+ alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0);
+
+ static_assert(!is_constructible_v, move_only_function>);
+ static_assert(!is_constructible_v, move_only_function>);
+
+#ifdef __cpp_noexcept_function_type
+ alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0);
+ alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0);
+
+ static_assert(!is_constructible_v, move_only_function>);
+#endif // defined(__cpp_noexcept_function_type)
+
constexpr bool is_64_bit = sizeof(void*) > 4;
// Moves from function to move_only_function
@@ -163,6 +185,18 @@ int main() {
test_wrapped_call, function