public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/109738] New: C++20 implicit conversion is used during spaceship operator resolution instead of class's operator< for classes without spaceship operator
@ 2023-05-04 15:48 szhong at perforce dot com
  2023-05-04 18:15 ` [Bug c++/109738] " pinskia at gcc dot gnu.org
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: szhong at perforce dot com @ 2023-05-04 15:48 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 109738
           Summary: C++20 implicit conversion is used during spaceship
                    operator resolution instead of class's operator< for
                    classes without spaceship operator
           Product: gcc
           Version: 11.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: szhong at perforce dot com
  Target Milestone: ---

Using -std=c++20 -- implicit conversion is used during spaceship operator
resolution instead of class's operator< for classes without spaceship operator


testcase:
#include <string>
#include <list>
#include <map>
#include <iostream>

class StringWrapper {
public:
    StringWrapper(const char* s)
        : str_(s) {}
    std::string str_;
    operator const char* () const;
};

inline
StringWrapper::operator const char* () const
{
    return str_.data();
}

std::ostream&
operator<<(std::ostream& os, const StringWrapper& str)
{
    os << str.str_;
    return os;
}

bool
operator< (const StringWrapper& lhs, const StringWrapper& rhs)
{
    return lhs.str_ < rhs.str_;
}

#if defined(SPACE_SHIP)
auto operator<=>(const StringWrapper& lhs, const StringWrapper& rhs)
{
    return lhs.str_ <=> rhs.str_;
}
#endif

void print_map(std::string_view comment, const
std::map<std::list<StringWrapper>, std::list<StringWrapper> >& m)
{
    std::cout << comment;
    // iterate using C++17 facilities
    for (const auto& [key, value] : m) {
        std::cout << '[';
        for (const auto& i : key)
            std::cout << i << ", ";
        std::cout << "];";
    }
    std::cout << '\n';
}


int main()
{
    StringWrapper a("Diane");
    StringWrapper b("Harry");
    StringWrapper c("Sally");
    StringWrapper d("George");

    std::list<StringWrapper> l1;
    l1.push_back(a);
    l1.push_back(c);

    std::list<StringWrapper> l2;
    l2.push_back(b);
    l2.push_back(d);

    std::map<std::list<StringWrapper>, std::list<StringWrapper> > m1;

    m1.insert(m1.end(), std::map<std::list<StringWrapper>,
std::list<StringWrapper> >::value_type(l1, l2));
    m1.insert(m1.end(), std::map<std::list<StringWrapper>,
std::list<StringWrapper> >::value_type(l2, l1));

    print_map("m1: ", m1);

    std::map<std::list<StringWrapper>, std::list<StringWrapper> > m2;

    m2.insert(m2.end(), std::map<std::list<StringWrapper>,
std::list<StringWrapper> >::value_type(l2, l1));
    m2.insert(m2.end(), std::map<std::list<StringWrapper>,
std::list<StringWrapper> >::value_type(l1, l2));

    print_map("m2: ", m2);
}

$ g++ -std=c++20 -Wall -Wextra 20_list_compare_wrapper.cpp; ./a.out;
m1: [Harry, George, ];[Diane, Sally, ];
m2: [Diane, Sally, ];[Harry, George, ];

The problem is the std:map is no longer sorted according to StringWrapper but
sorted according const char* instead.

The debugger showed during resolution of spaceship operator, the implicit
conversion to const char* for StringWrapper is selected instead of
StringWrapper::operator<() during insertion into std::map with the key of
std::list<StringWrapper>.

This problem occurs with gcc 12.1.1 as well.


$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu
11.3.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs
--enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr
--with-gcc-major-version-only --program-suffix=-11
--program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id
--libexecdir=/usr/lib --without-included-gettext --enable-threads=posix
--libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu
--enable-libstdcxx-debug --enable-libstdcxx-time=yes
--with-default-libstdcxx-abi=new --enable-gnu-unique-object
--disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib
--enable-libphobos-checking=release --with-target-system-zlib=auto
--enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet
--with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32
--enable-multilib --with-tune=generic
--enable-offload-targets=nvptx-none=/build/gcc-11-xKiWfi/gcc-11-11.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-11-xKiWfi/gcc-11-11.3.0/debian/tmp-gcn/usr
--without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu
--with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)

system type: $ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c++/109738] C++20 implicit conversion is used during spaceship operator resolution instead of class's operator< for classes without spaceship operator
  2023-05-04 15:48 [Bug c++/109738] New: C++20 implicit conversion is used during spaceship operator resolution instead of class's operator< for classes without spaceship operator szhong at perforce dot com
@ 2023-05-04 18:15 ` pinskia at gcc dot gnu.org
  2023-05-10 20:52 ` redi at gcc dot gnu.org
  2023-05-11 19:32 ` szhong at perforce dot com
  2 siblings, 0 replies; 4+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-05-04 18:15 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
clang has the same behavior as GCC .

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c++/109738] C++20 implicit conversion is used during spaceship operator resolution instead of class's operator< for classes without spaceship operator
  2023-05-04 15:48 [Bug c++/109738] New: C++20 implicit conversion is used during spaceship operator resolution instead of class's operator< for classes without spaceship operator szhong at perforce dot com
  2023-05-04 18:15 ` [Bug c++/109738] " pinskia at gcc dot gnu.org
@ 2023-05-10 20:52 ` redi at gcc dot gnu.org
  2023-05-11 19:32 ` szhong at perforce dot com
  2 siblings, 0 replies; 4+ messages in thread
From: redi at gcc dot gnu.org @ 2023-05-10 20:52 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Scott Zhong from comment #0)
> The debugger showed during resolution of spaceship operator, the implicit
> conversion to const char* for StringWrapper is selected instead of
> StringWrapper::operator<() during insertion into std::map with the key of
> std::list<StringWrapper>.

I think this is the correct C++20 behaviour.

The library checks whether lhs <=> rhs is valid, and if so, it uses that.
Otherwise, it synthesizes a three-way comparison using operator<.

Because your type is implicitly convertible to something that is three-way
comparable, the lhs <=> rhs expression is valid, and so that's what gets used.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c++/109738] C++20 implicit conversion is used during spaceship operator resolution instead of class's operator< for classes without spaceship operator
  2023-05-04 15:48 [Bug c++/109738] New: C++20 implicit conversion is used during spaceship operator resolution instead of class's operator< for classes without spaceship operator szhong at perforce dot com
  2023-05-04 18:15 ` [Bug c++/109738] " pinskia at gcc dot gnu.org
  2023-05-10 20:52 ` redi at gcc dot gnu.org
@ 2023-05-11 19:32 ` szhong at perforce dot com
  2 siblings, 0 replies; 4+ messages in thread
From: szhong at perforce dot com @ 2023-05-11 19:32 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #3 from Scott Zhong <szhong at perforce dot com> ---
Is it very problematic if this is the correct behavior C++20 behaviour. For
example,

#include <compare>
#include <iostream>

struct IntWrapper {
  int value;
  constexpr IntWrapper(int value): value{value} { }
  auto operator<=>(const IntWrapper&) const = default;
  bool operator==(const IntWrapper&) const = default;
};

struct Derived : public IntWrapper
{
  int value2;
  Derived() :
    IntWrapper(0),
    value2(0) { }
  bool operator<(const Derived&) const {
    std::cout << "Derived::operator<()" << std::endl;
    return false;
  }
};

int main()
{
  Derived a,b;

  std::cout << (a <=> b < 0) << std::endl;

  return 0;
}

Derived::operator<() is not called, only IntWrapper::operator<=>() is called.
The scenario is IntWrapper has been updated to utilize spaceship operator but
the Derived class (downstream customers) hasn't been able to update their code
to provide the spaceship operator yet. It could potentially be hard to debug
that this scenario is happening.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-05-11 19:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-04 15:48 [Bug c++/109738] New: C++20 implicit conversion is used during spaceship operator resolution instead of class's operator< for classes without spaceship operator szhong at perforce dot com
2023-05-04 18:15 ` [Bug c++/109738] " pinskia at gcc dot gnu.org
2023-05-10 20:52 ` redi at gcc dot gnu.org
2023-05-11 19:32 ` szhong at perforce dot com

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).