https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87603
--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> ---
I suspect this is the reason that our is_nothrow_convertible trait fails in
some cases:
template<typename T> T&& declval();
template<bool B> struct bool_constant { static constexpr bool value = B; };
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;
template<typename T>
struct char_traits
{
static int length(T* p) { int n = 0; while (*p++ != T()) ++n; return n; }
};
template<typename T, typename U = char_traits<T>>
struct basic_string_view
{
constexpr basic_string_view(T* p) noexcept : len(U::length(p)) { }
int len;
};
template<typename From, typename To>
class is_nothrow_convertible_helper
{
template<typename To1>
static void test_aux(To1) noexcept;
template<typename From1, typename To1,
bool NoEx = noexcept(test_aux<To1>(declval<From1>()))>
static bool_constant<NoEx>
test_nothrow(int);
template<typename, typename>
static false_type
test_nothrow(...);
public:
typedef decltype(test_nothrow<From, To>(0)) type;
};
template<typename From, typename To>
struct is_nothrow_convertible
: is_nothrow_convertible_helper<From, To>::type
{ };
struct X { };
bool b = is_nothrow_convertible<X*, basic_string_view<X>>::value;
ntconv.cc: In instantiation of 'static int char_traits<T>::length(T*) [with T =
X]':
ntconv.cc:15:61: required from 'constexpr basic_string_view<T,
U>::basic_string_view(T*) [with T = X; U = char_traits<X>]'
ntconv.cc:26:66: required by substitution of 'template<class From1, class
To1, bool NoEx> static bool_constant<NoEx> is_nothrow_convertible_helper<X*,
basic_string_view<X> >::test_nothrow<From1, To1, NoEx>(int) [with From1 = X*;
To1 = basic_string_view<X>; bool NoEx = false]'
ntconv.cc:35:44: required from 'class is_nothrow_convertible_helper<X*,
basic_string_view<X> >'
ntconv.cc:39:10: required from 'struct is_nothrow_convertible<X*,
basic_string_view<X> >'
ntconv.cc:45:58: required from here
ntconv.cc:9:52: error: no match for 'operator!=' (operand types are 'X' and
'X')
9 | static int length(T* p) { int n = 0; while (*p++ != T()) ++n; return
n; }
| ~~~~~^~~~~~
The basic_string_view<X>::basic_string_view(X*) ctor is ill-formed, but I don't
think it should actually need to be instantiated here in order to tell whether
it can throw. I suspect it gets instantiated because of this bug, by the
compiler trying to determine if it can throw.
I don't have a rejects-valid testcase though, so it might not matter.