From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 8682C3858C53; Sat, 24 Sep 2022 14:10:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8682C3858C53 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1664028637; bh=jYOnzTYwnRYuXwgfcl0Z1hldB6wBInTtGUX5amNh9AA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=ry4bqSmqkYwQ9rEVw8TWhCWEUFqIHgj1+dA0nkN6gFQ3h55GEP492fzjfU1++1LdE 7m1zaMvCT85DauR66dPEs7LAdwT2nwAM6FTfGnm307yn6aIF/R3up290VzXLJNSx3I nhEFr7DKr4tWnQJWACCR1q93XQcYMSx9ffWtds6I= From: "redi at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug c++/106784] Add __is_convertible built-in Date: Sat, 24 Sep 2022 14:10:35 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: 13.0 X-Bugzilla-Keywords: X-Bugzilla-Severity: enhancement X-Bugzilla-Who: redi at gcc dot gnu.org X-Bugzilla-Status: RESOLVED X-Bugzilla-Resolution: FIXED X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: mpolacek at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: cc Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 List-Id: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D106784 Jonathan Wakely changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jason at gcc dot gnu.org --- Comment #6 from Jonathan Wakely --- I'm seeing a regression in 21_strings/basic_string/types/1.cc when I start using __is_convertible in the library. Reduced to: template struct bool_constant { static constexpr bool value =3D B; }; using true_type =3D bool_constant; using false_type =3D bool_constant; template struct is_void : false_type { }; template<> struct is_void : true_type { }; template T&& declval(); template struct enable_if { }; template<> struct enable_if { using type =3D void; }; template using enable_if_t =3D typename enable_if::type; #ifdef USE_BUILTIN template struct is_convertible : public bool_constant<__is_convertible(_From, _To)> { }; #else template::value> struct __is_convertible_helper { typedef typename is_void<_To>::type type; }; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wctor-dtor-privacy" template class __is_convertible_helper<_From, _To, false> { template static void __test_aux(_To1) noexcept; template(declval<_From1>()))> static true_type __test(int); template static false_type __test(...); public: typedef decltype(__test<_From, _To>(0)) type; }; #pragma GCC diagnostic pop /// is_convertible template struct is_convertible : public __is_convertible_helper<_From, _To>::type { }; #endif template struct char_traits { static unsigned long length(const char* s) { eq(*s, *s); return 0; } static void eq(CharT l, CharT r) noexcept { l.f(r); } }; template struct basic_string_view { using traits_type =3D char_traits; constexpr basic_string_view() =3D default; constexpr basic_string_view(const basic_string_view&) =3D default; constexpr basic_string_view(const CharT* __str) noexcept : _M_len{traits_type::length(__str)} { } unsigned long _M_len =3D 0; }; template struct basic_string { template enable_if_t>::value && !is_convertible::value> replace(int, T) { } void replace(unsigned long, const char*) { } void replace(const char* s) { replace(1, s); } }; int main() { basic_string s; s.replace(""); } This is fine using the library trait, but compiled with -DUSE_BUILTIN it fa= ils: conv.cc: In instantiation of 'static void char_traits::eq(CharT, Cha= rT) [with CharT =3D char]': conv.cc:62:50: required from 'static long unsigned int char_traits::length(const char*) [with CharT =3D char]' conv.cc:77:31: required from 'constexpr basic_string_view::basic_string_view(const CharT*) [with CharT =3D c= har]' conv.cc:18:28: required from 'struct is_convertible >' conv.cc:87:69: required by substitution of 'template enable_if_t<(is_convertible >::value && (! is_convertible::value))> basic_string::replace(int, T) [with T =3D const char*]' conv.cc:93:40: required from 'void basic_string::replace(const cha= r*) [with CharT =3D char]' conv.cc:99:12: required from here conv.cc:64:49: error: request for member 'f' in 'l', which is of non-class = type 'char' 64 | static void eq(CharT l, CharT r) noexcept { l.f(r); } | ~~^ The error is correct, char_traits::eq is ill-formed. Strictly speakin= g, the library testcase is invalid for basic_string, the N::X type needs to be equality comparable. But I don't think __is_convertible should be detecting that. To determine if const char* is convertible to basic_string_view(const char*) should just ne= ed to examine the signature, and not instantiate the body of the function. I t= hink it probably instantiates it eagerly because it's constexpr. IIRC Jason made some changes to template substitution to prevent such eager instantiations = of constexpr functions. Maybe something like that is currently missing from __is_convertible? Or maybe the trait is fine, and the code above is just invalid. I can easily fix the library test that fails, but I think it's worth checki= ng first whether something in __is_convertible needs a fix.=