public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "redi at gcc dot gnu.org" <gcc-bugzilla@gcc.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	[thread overview]
Message-ID: <bug-106784-4-VuUJ76xqOY@http.gcc.gnu.org/bugzilla/> (raw)
In-Reply-To: <bug-106784-4@http.gcc.gnu.org/bugzilla/>

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106784

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jason at gcc dot gnu.org

--- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> ---
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<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 is_void : false_type { };
template<> struct is_void<void> : true_type { };

template<typename T> T&& declval();

template<bool> struct enable_if { };
template<> struct enable_if<true> { using type = void; };
template<bool B> using enable_if_t = typename enable_if<B>::type;

#ifdef USE_BUILTIN
  template<typename _From, typename _To>
    struct is_convertible
    : public bool_constant<__is_convertible(_From, _To)>
    { };

#else

  template<typename _From, typename _To,
           bool = is_void<_From>::value>
    struct __is_convertible_helper
    {
      typedef typename is_void<_To>::type type;
    };

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
  template<typename _From, typename _To>
    class __is_convertible_helper<_From, _To, false>
    {
      template<typename _To1>
        static void __test_aux(_To1) noexcept;

      template<typename _From1, typename _To1,
               typename = decltype(__test_aux<_To1>(declval<_From1>()))>
        static true_type
        __test(int);

      template<typename, typename>
        static false_type
        __test(...);

    public:
      typedef decltype(__test<_From, _To>(0)) type;
    };
#pragma GCC diagnostic pop

  /// is_convertible
  template<typename _From, typename _To>
    struct is_convertible
    : public __is_convertible_helper<_From, _To>::type
    { };
#endif

template<class CharT>
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<class CharT>
struct basic_string_view
{
  using traits_type = char_traits<CharT>;

  constexpr basic_string_view() = default;
  constexpr basic_string_view(const basic_string_view&) = default;

  constexpr
  basic_string_view(const CharT* __str) noexcept
  : _M_len{traits_type::length(__str)}
  { }

  unsigned long _M_len = 0;
};

template<class CharT>
struct basic_string
{
  template<class T>
    enable_if_t<is_convertible<const T&, basic_string_view<CharT>>::value
                && !is_convertible<const T&, const char*>::value>
    replace(int, T) { }

  void replace(unsigned long, const char*) { }

  void replace(const char* s) { replace(1, s); }
};

int main()
{
  basic_string<char> s;
  s.replace("");
}

This is fine using the library trait, but compiled with -DUSE_BUILTIN it fails:

conv.cc: In instantiation of 'static void char_traits<CharT>::eq(CharT, CharT)
[with CharT = char]':
conv.cc:62:50:   required from 'static long unsigned int
char_traits<CharT>::length(const char*) [with CharT = char]'
conv.cc:77:31:   required from 'constexpr
basic_string_view<CharT>::basic_string_view(const CharT*) [with CharT = char]'
conv.cc:18:28:   required from 'struct is_convertible<const char* const&,
basic_string_view<char> >'
conv.cc:87:69:   required by substitution of 'template<class T>
enable_if_t<(is_convertible<const T&, basic_string_view<char> >::value && (!
is_convertible<const T&, const char*>::value))>
basic_string<char>::replace(int, T) [with T = const char*]'
conv.cc:93:40:   required from 'void basic_string<CharT>::replace(const char*)
[with CharT = 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<char>::eq is ill-formed. Strictly speaking,
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 need
to examine the signature, and not instantiate the body of the function. I think
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 checking
first whether something in __is_convertible needs a fix.

  parent reply	other threads:[~2022-09-24 14:10 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-31 10:41 [Bug c++/106784] New: " redi at gcc dot gnu.org
2022-08-31 13:38 ` [Bug c++/106784] " mpolacek at gcc dot gnu.org
2022-08-31 14:05 ` mpolacek at gcc dot gnu.org
2022-09-01 16:26 ` redi at gcc dot gnu.org
2022-09-20 21:24 ` mpolacek at gcc dot gnu.org
2022-09-21  0:02 ` redi at gcc dot gnu.org
2022-09-23 16:17 ` cvs-commit at gcc dot gnu.org
2022-09-23 16:18 ` mpolacek at gcc dot gnu.org
2022-09-24 14:10 ` redi at gcc dot gnu.org [this message]
2022-09-26 16:42 ` cvs-commit at gcc dot gnu.org
2023-04-29 17:44 ` pinskia at gcc dot gnu.org

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bug-106784-4-VuUJ76xqOY@http.gcc.gnu.org/bugzilla/ \
    --to=gcc-bugzilla@gcc.gnu.org \
    --cc=gcc-bugs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).