libstdc++: Fix constraints for rvalue stream insertion/extraction
The __rval_streamable() function was an attempt to test for convertibility cheaply and without confusing diagnostics. It doesn't work with Clang though, and is probably ill-formed. Replace that helper function with a check for derivation from ios_base, and use that in the alias templates __rvalue_stream_insertion_t and __rvalue_stream_extraction_t. Use concepts for the constraints when available. libstdc++-v3/ChangeLog: * include/std/istream (__rvalue_stream_extraction_t): Replace use of __rval_streamable. * include/std/ostream (__rvalue_stream_insertion_t): Likewise. (__rval_streamable): Remove. (_Require_derived_from_ios_base, __derived_from_ios_base): New helper for checking constraints. * testsuite/27_io/basic_istream/extractors_other/char/4.cc: Fix reference to the wrong subclause of the standard. * testsuite/27_io/basic_istream/extractors_other/wchar_t/4.cc: Likewise. * testsuite/27_io/basic_ostream/inserters_other/char/6.cc: Likewise. * testsuite/27_io/basic_ostream/inserters_other/wchar_t/6.cc: Likewise. * testsuite/27_io/basic_ostream/inserters_other/char/99692.cc: New test. * testsuite/27_io/filesystem/path/io/dr2989.cc: Adjust pruned errors.
This commit is contained in:
parent
7c4c9fcc0d
commit
a87ceadf17
8 changed files with 67 additions and 31 deletions
|
@ -958,12 +958,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
// 2328. Rvalue stream extraction should use perfect forwarding
|
||||
// 1203. More useful rvalue stream insertion
|
||||
|
||||
// SFINAE helper to check constraints for operator>>(Istream&&, T&&).
|
||||
// If the constraints are satisfied, it is an alias for Istream&&.
|
||||
template<typename _Is, typename _Tp,
|
||||
typename = decltype(std::__rval_streamable<_Is>()
|
||||
>> std::declval<_Tp>())>
|
||||
#if __cpp_lib_concepts
|
||||
template<typename _Is, typename _Tp>
|
||||
requires __derived_from_ios_base<_Is>
|
||||
&& requires (_Is& __is, _Tp&& __t) { __is >> std::forward<_Tp>(__t); }
|
||||
using __rvalue_stream_extraction_t = _Is&&;
|
||||
#else
|
||||
template<typename _Is, typename _Tp,
|
||||
typename = _Require_derived_from_ios_base<_Is>,
|
||||
typename = decltype(std::declval<_Is&>() >> std::declval<_Tp>())>
|
||||
using __rvalue_stream_extraction_t = _Is&&;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic extractor for rvalue stream
|
||||
|
|
|
@ -708,31 +708,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 1203. More useful rvalue stream insertion
|
||||
|
||||
// SFINAE helper to check constraints for operator<<(Ostream&&, const T&).
|
||||
// If Ostream is publicly and unambiguously derived from ios_base, then
|
||||
// __rval_streamable<Ostream>() is equivalent to declval<Ostream&>().
|
||||
// Otherwise, it results in a substitution failure. Specifically, it will
|
||||
// fail if Ostream is an lvalue reference or the same type as ios_base.
|
||||
// Use concepts if possible because they're cheaper to evaluate.
|
||||
#if __cpp_lib_concepts
|
||||
// Use concepts if possible because they're cheaper to evaluate.
|
||||
template<typename _Tp>
|
||||
requires (!is_same_v<_Tp, ios_base>)
|
||||
&& requires (_Tp* __t, ios_base* __b) { __b = __t; }
|
||||
_Tp&
|
||||
__rval_streamable();
|
||||
#else
|
||||
template<typename _Tp,
|
||||
typename = _Require<__not_<__is_one_of<_Tp, _Tp&, ios_base>>>>
|
||||
_Tp&
|
||||
__rval_streamable(ios_base* = (_Tp*)nullptr);
|
||||
#endif
|
||||
concept __derived_from_ios_base = is_class_v<_Tp>
|
||||
&& (!is_same_v<_Tp, ios_base>)
|
||||
&& requires (_Tp* __t, ios_base* __b) { __b = __t; };
|
||||
|
||||
// SFINAE helper to check constraints for operator<<(Ostream&&, const T&).
|
||||
// If the constraints are satisfied, it is an alias for Ostream&&.
|
||||
template<typename _Os, typename _Tp,
|
||||
typename = decltype(std::__rval_streamable<_Os>()
|
||||
<< std::declval<const _Tp&>())>
|
||||
template<typename _Os, typename _Tp>
|
||||
requires __derived_from_ios_base<_Os>
|
||||
&& requires (_Os& __os, const _Tp& __t) { __os << __t; }
|
||||
using __rvalue_stream_insertion_t = _Os&&;
|
||||
#else
|
||||
template<typename _Tp>
|
||||
using _Require_derived_from_ios_base
|
||||
= _Require<is_class<_Tp>, __not_<is_same<_Tp, ios_base>>,
|
||||
is_convertible<typename add_pointer<_Tp>::type, ios_base*>>;
|
||||
|
||||
template<typename _Os, typename _Tp,
|
||||
typename = _Require_derived_from_ios_base<_Os>,
|
||||
typename
|
||||
= decltype(std::declval<_Os&>() << std::declval<const _Tp&>())>
|
||||
using __rvalue_stream_insertion_t = _Os&&;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic inserter for rvalue stream
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 27.6.2.5.3 basic_ostream manipulator inserters
|
||||
// C++11 27.7.2.6 Rvalue stream extraction [istream.rvalue]
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 27.6.2.5.3 basic_ostream manipulator inserters
|
||||
// C++11 27.7.2.6 Rvalue stream extraction [istream.rvalue]
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 27.6.2.5.3 basic_ostream manipulator inserters
|
||||
// C++11 27.7.3.9 Rvalue stream insertion [ostream.rvalue]
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// { dg-do compile { target c++11 } }
|
||||
|
||||
#include <ostream>
|
||||
|
||||
struct CustomStream : std::ostream {};
|
||||
|
||||
namespace N {
|
||||
class A{};
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const N::A&)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
CustomStream&& operator<<(CustomStream&& s, const N::A& v)
|
||||
{
|
||||
static_cast<std::ostream&>(s) << v;
|
||||
return std::move(s);
|
||||
}
|
||||
|
||||
void test_pr99692()
|
||||
{
|
||||
// PR libstdc++/99692
|
||||
CustomStream() << N::A{};
|
||||
}
|
||||
|
||||
int test_shift_ios_enum()
|
||||
{
|
||||
// https://gcc.gnu.org/pipermail/libstdc++/2021-May/052507.html
|
||||
int i = 1 << std::ios::erase_event;
|
||||
|
||||
return i;
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 27.6.2.5.3 basic_ostream manipulator inserters
|
||||
// C++11 27.7.3.9 Rvalue stream insertion [ostream.rvalue]
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
|
|
@ -33,4 +33,3 @@ void foo(std::iostream& s) {
|
|||
s >> p; // { dg-error "no match" }
|
||||
}
|
||||
// { dg-prune-output "no type .*enable_if" }
|
||||
// { dg-prune-output "no matching function for call to '__rval_streamable" }
|
||||
|
|
Loading…
Add table
Reference in a new issue