https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79162
--- Comment #14 from Daniel Krügler <daniel.kruegler at googlemail dot com> --- (In reply to Jonathan Wakely from comment #10) > (In reply to Jonathan Wakely from comment #8) > > Richard also says the overload shouldn't exist and is a bug, but the > > overload has to exist, because the C++17 draft is defective. > > That's https://wg21.link/lwg2946 The problem here is that the current gcc implementation differs from the LWG 2949 wording. The wording suggests to use template<class T> basic_string& operator=(const T& t); but the existing gcc approach uses effectively a by-value signature: template<class T> basic_string& operator=(T t); In the example code, the model type llvm::cl::opt is not copy-constructible, but the constraints accept it, because it is (a) convertible to std::string_view (Because it inherits from std::string) and (b) it is not convertible to char*. Now after acceptance of the constraints, the template signature is instantiated, because it is a (slightly) better match than the copy_assignment operator of std::string. When this has happened, the compile error arises, because it is attempted to call the deleted (and private) copy constructor of llvm::cl::opt. It seems to me that it would suffice to change the signature of the constrained assignment operator to use const T& instead of T, as suggested by the issue resolution proposal. Here is a reproducer for the situation: #include <string> template <class DataType> class opt : public DataType { opt(const opt &) = delete; opt &operator=(const opt &) = delete; public: opt() {} }; int main() { opt<std::string> PGOTestProfileFile; std::string ProfileFileName; ProfileFileName = PGOTestProfileFile; } Here is a minimized emulation of basic_string that shows that the suggested fix should work (Please uncomment '#define USE_FIX' below): #include <type_traits> #include <string> #include <memory> #include <cstddef> namespace xstd { template<class CharT, class Traits = std::char_traits<CharT>> struct basic_string_view { using traits_type = Traits; using size_type = std::size_t; constexpr basic_string_view() noexcept : len{0}, str{nullptr} {} constexpr basic_string_view(const CharT* str) : len{str == nullptr ? 0 : traits_type::length(str)}, str{str} {} constexpr size_type size() const noexcept { return this->len; } constexpr const CharT* data() const noexcept { return this->str; } private: size_type len; const CharT* str; }; template<class CharT, class Traits = std::char_traits<CharT>> struct basic_string { private: using sv_type = basic_string_view<CharT, Traits>; template<typename T, typename Res> using If_sv = std::enable_if_t< std::__and_< std::is_convertible<const T&, sv_type>, std::__not_<std::is_convertible<const T&, const CharT*>> >::value, Res>; public: using size_type = std::size_t; static const size_type npos = static_cast<size_type>(-1); basic_string& operator=(const basic_string& str); basic_string& operator=(const CharT* s); basic_string& operator=(CharT c); basic_string& operator=(std::initializer_list<CharT>); basic_string& operator=(basic_string&& str); //#define USE_FIX #ifndef USE_FIX template<typename T> If_sv<T, basic_string&> operator=(T sv); #else template<typename T> If_sv<T, basic_string&> operator=(const T& sv); #endif operator sv_type() const noexcept; }; using string = basic_string<char>; } namespace llvm { namespace cl { template <class DataType> class opt_storage : public DataType { }; template <class DataType> class opt : public opt_storage<DataType> { opt(const opt &) = delete; opt &operator=(const opt &) = delete; public: opt(); }; } } using namespace llvm; cl::opt<xstd::string> PGOTestProfileFile; namespace { class PGOInstrumentationUseLegacyPass { PGOInstrumentationUseLegacyPass(xstd::string) { ProfileFileName = PGOTestProfileFile; } xstd::string ProfileFileName; }; } int main() { }