Code which compiles with g++ but not with clang++

Hello,

I would like to ask what is wrong with the following code:


#include <optional>

struct S
{
    S& operator=(S&) { return *this; };
};

void thisWillNotCompileInClang()
{
   std::optional<S> a;
}

Compilation command is `g++ or clang++ -std=c++17 -c source.cpp`. It compiles without problems with g++ 9.3.0, but not with clang++ 10.0.0 (both from current stable Ubuntu 20). This code is simplification of code using widely adopted rapidjson library which uses assignment operator with non-const parameter a lot. Earlier versions of clang did not complain (tried with 7.0.1 on currently stable Debian Buster).

Thank you very much for your time and explanation. Kind regards,

Pavel Cernohorsky

I tried this code on compiler explorer.
It compiles w/o error with clang + libc++
It fails to compile with clang and libstdc++

The error message given is:

In file included from :1:
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/…/…/…/…/include/c++/10.2.0/optional:158:7: error: the parameter for this explicitly-defaulted copy assignment operator is const, but a member or base requires it to be non-const
operator=(const _Optional_payload_base&) = default;
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/…/…/…/…/include/c++/10.2.0/optional:357:7: note: in instantiation of template class ‘std::_Optional_payload_base’ requested here
: _Optional_payload_base<_Tp>
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/…/…/…/…/include/c++/10.2.0/optional:631:30: note: in instantiation of template class ‘std::_Optional_payload<S, true, false, false>’ requested here
_Optional_payload<_Tp> _M_payload;
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/…/…/…/…/include/c++/10.2.0/optional:660:15: note: in instantiation of template class ‘std::_Optional_base<S, true, true>’ requested here
: private _Optional_base<_Tp>,
^

:10:20: note: in instantiation of template class 'std::optional' requested here std::optional a; ^ 1 error generated.

— Marshall

I got exactly the same error, but the question is why. Shouldn't both g++ and clang++ behave the same way even on the libstdc++ (which is the default library clang uses on a lot of distros)? Is this gcc being too permissive to some bug in libstdc++ or is it a clang bug? Should I file a bug report to clang?

I’ve actually reduced the problem to the defaulted copy assignment operator itself:
gcc: https://godbolt.org/z/83Gjdb
clang: https://godbolt.org/z/z35x4K

The controlling clause would seem to be https://eel.is/c++draft/class.copy.assign#7.4. In particular, because overload resolution cannot find this->_m.operator=(rhs._m), the operator should be defined as deleted (which seems to be the behaviour of gcc, https://godbolt.org/z/bs5aPY).

Hello,

I would like to ask what is wrong with the following code:


#include <optional>

struct S
{
   S& operator=(S&) { return *this; };
};

void thisWillNotCompileInClang()
{
  std::optional<S> a;
}

Compilation command is `g++ or clang++ -std=c++17 -c source.cpp`. It compiles without problems with g++ 9.3.0, but not with clang++ 10.0.0 (both from current stable Ubuntu 20). This code is simplification of code using widely adopted rapidjson library which uses assignment operator with non-const parameter a lot. Earlier versions of clang did not complain (tried with 7.0.1 on currently stable Debian Buster).

A note from the libstdc++ maintainer:

I think there was a core change in C++20 to make the =default do the right thing (which is delete it, I think).
Clang does compile it with -std=c++20 just not -std=c++17.

— Marshall

Hello,

I would like to ask what is wrong with the following code:


#include <optional>

struct S
{
S& operator=(S&) { return *this; };
};

void thisWillNotCompileInClang()
{
std::optional<S> a;
}

Compilation command is g++ or clang++ -std=c++17 -c source.cpp. It compiles without problems with g++ 9.3.0, but not with clang++ 10.0.0 (both from current stable Ubuntu 20). This code is simplification of code using widely adopted rapidjson library which uses assignment operator with non-const parameter a lot. Earlier versions of clang did not complain (tried with 7.0.1 on currently stable Debian Buster).

A note from the libstdc++ maintainer:

I think there was a core change in C++20 to make the =default do the right thing (which is delete it, I think).
Clang does compile it with -std=c++20 just not -std=c++17.

Right, this was made valid by P0641R2, which was voted into C++20 but was not moved as a defect report resolution against prior standards. So I think g++ is being more permissive than the standard requires (though as far as I can see, it would be a conforming extension to accept these cases retroactively), and libstdc++ seems to be relying on that lenience (probably unintentionally).

Thank you all for your help, the problem reduction and the reference to P0641R2 made things really clear for me. Now I see what is happening.

Kind regards,

Pavel