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.