diff --git a/stl/inc/list b/stl/inc/list index 033a43c60c7..819e3d7eb96 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -751,6 +751,10 @@ private: template class _Hash; +struct _Move_allocator_tag { + explicit _Move_allocator_tag() = default; +}; + _EXPORT_STD template > class list { // bidirectional linked list private: @@ -804,8 +808,8 @@ public: } private: - template - explicit list(_Move_allocator_tag, _Any_alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _STD move(_Al)) { + template , int> = 0> + explicit list(_Tag, _Any_alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _STD move(_Al)) { _Alloc_sentinel_and_proxy(); } diff --git a/stl/inc/sstream b/stl/inc/sstream index 83e7ad49aa8..b148784abbf 100644 --- a/stl/inc/sstream +++ b/stl/inc/sstream @@ -239,7 +239,7 @@ public: // the buffer may already be full, and the terminating char is not '\0'. // In that case, copy the string as usual. _NODISCARD _Mystr str() && { - _Mystr _Result{_String_constructor_rvalue_allocator_tag{}, _STD move(_Al)}; + _Mystr _Result{_Al}; const auto _View = _Get_buffer_view(); // _Size cannot be larger than _Res, but it could be equal, // because basic_stringbuf doesn't allocate for the terminating '\0'. diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 3aa11f488c8..0af1a94bdc8 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1535,10 +1535,6 @@ public: } }; -struct _Move_allocator_tag { - explicit _Move_allocator_tag() = default; -}; - template pair<_Ty*, ptrdiff_t> _Get_temporary_buffer(ptrdiff_t _Count) noexcept { if (static_cast(_Count) <= static_cast(-1) / sizeof(_Ty)) { diff --git a/stl/inc/xstring b/stl/inc/xstring index 212d55880a5..e39cb1871a3 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -508,11 +508,6 @@ struct _String_constructor_concat_tag { explicit _String_constructor_concat_tag() = default; }; -struct _String_constructor_rvalue_allocator_tag { - // tag to select constructors used by basic_stringbuf's rvalue str() - explicit _String_constructor_rvalue_allocator_tag() = default; -}; - [[noreturn]] inline void _Xlen_string() { _Xlength_error("string too long"); } @@ -1145,12 +1140,6 @@ public: #endif // _HAS_CXX17 #if _HAS_CXX20 - basic_string(_String_constructor_rvalue_allocator_tag, _Alloc&& _Al) - : _Mypair(_One_then_variadic_args_t{}, _STD move(_Al)) { - // Used exclusively by basic_stringbuf - _Construct_empty(); - } - _NODISCARD bool _Move_assign_from_buffer( _Elem* const _Right, const size_type _Size, const size_type _Actual_allocation_size) { // Move assign from a buffer, used exclusively by basic_stringbuf; returns _Large_mode_engaged() diff --git a/tests/std/test.lst b/tests/std/test.lst index 6965091e415..3daaf646130 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -250,6 +250,7 @@ tests\GH_004618_mixed_operator_usage_keeps_statistical_properties tests\GH_004618_normal_distribution_avoids_resets tests\GH_004657_expected_constraints_permissive tests\GH_004845_logical_operator_traits_with_non_bool_constant +tests\GH_004929_internal_tag_constructors tests\GH_004930_char_traits_user_specialization tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut diff --git a/tests/std/tests/GH_004929_internal_tag_constructors/env.lst b/tests/std/tests/GH_004929_internal_tag_constructors/env.lst new file mode 100644 index 00000000000..f141421b292 --- /dev/null +++ b/tests/std/tests/GH_004929_internal_tag_constructors/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\impure_matrix.lst diff --git a/tests/std/tests/GH_004929_internal_tag_constructors/test.cpp b/tests/std/tests/GH_004929_internal_tag_constructors/test.cpp new file mode 100644 index 00000000000..9509fe13142 --- /dev/null +++ b/tests/std/tests/GH_004929_internal_tag_constructors/test.cpp @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#if _HAS_CXX17 +#include +#endif // _HAS_CXX17 + +#if _HAS_CXX20 +#define CONSTEXPR20 constexpr +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#define CONSTEXPR20 inline +#endif // ^^^ !_HAS_CXX20 ^^^ + +using namespace std; + +template +constexpr bool is_initializer_list = false; +template +constexpr bool is_initializer_list> = true; + +template +constexpr initializer_list ilist42 = {T{'4'}, T{'2'}}; + +template +constexpr bool is_basic_string_or_cstr_or_view = false; +template +constexpr bool is_basic_string_or_cstr_or_view> = true; +template +constexpr bool is_basic_string_or_cstr_or_view = true; +#if _HAS_CXX17 +template +constexpr bool is_basic_string_or_cstr_or_view> = true; +#endif // _HAS_CXX17 + +struct nasty_string_source { + template , int> = 0> + constexpr operator IList() const { + return ilist42; + } + + template && !is_basic_string_or_cstr_or_view, int> = 0> + constexpr operator T() const { + return T{}; + } +}; + +CONSTEXPR20 bool test_nasty_conversion_to_basic_string() { + assert(string(nasty_string_source{}, allocator{}) == "42"s); +#ifdef __cpp_char8_t + assert(u8string(nasty_string_source{}, allocator{}) == u8"42"s); +#endif // defined(__cpp_char8_t) + assert(u16string(nasty_string_source{}, allocator{}) == u"42"s); + assert(u32string(nasty_string_source{}, allocator{}) == U"42"s); + assert(wstring(nasty_string_source{}, allocator{}) == L"42"s); + + return true; +} + +template +constexpr bool is_list = false; +template +constexpr bool is_list> = true; + +struct nasty_list_source { + template , int> = 0> + constexpr operator IList() const { + return ilist42; + } + + template && !is_list && !is_integral_v, int> = 0> + constexpr operator T() const { + return T{}; + } +}; + +void test_nasty_conversion_to_list() { + allocator ator{}; + assert((list{nasty_list_source{}, ator} == list{int{'4'}, int{'2'}})); +} + +#if _HAS_CXX20 +static_assert(test_nasty_conversion_to_basic_string()); +#endif // _HAS_CXX20 + +int main() { + test_nasty_conversion_to_basic_string(); + test_nasty_conversion_to_list(); +}