https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92727
--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to David Brown from comment #3) > Perhaps this could be better handled using concepts? Yes, ideally. That stops compilation as soon as you try to call something that fails to satisfy the constraints (in this case, that the vector's value type is constructible from the argument to push_back). > Maybe "push_back" > could be declared to take a parameter with a concept requiring either a type > that could be copied into the vector or a type that is a compatible rvalue > reference? We can't change the parameter type of push_back, that would not be conforming. > Or perhaps concepts and "if constexpr" in C++17 would make it > practical to make the "push_back(const T&)" overload unavailable if T is not > copyable? That would get you straight to a "no matching function call for > std::vector<X>::push_back(X&)" message on the offending line. if-constexpr can't help, that can only be used inside the function, by which point it's too late. I don't think concepts are really practical either, because we're limited where we can reasonably use them. std::vector has to be usable in C++98 still, and implementing the whole thing twice (with and without concepts in the API) would be a maintenance nightmare. Also, altering the overload set as you suggest needs to be done *very* carefuly, or what happens is you end up removing one bad function and so a different function gets called instead. You need to consider the entire overload set at once. I think a much more maintainable approach is something like: --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -1183,6 +1183,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER void push_back(const value_type& __x) { +#if __cplusplus >= 201703L + if constexpr (is_same_v<allocator_type, allocator<value_type>>) + static_assert(is_copy_constructible_v<value_type>); +#endif if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) { _GLIBCXX_ASAN_ANNOTATE_GROW(1); With that change your example prints: In file included from /home/jwakely/gcc/10/include/c++/10.0.0/vector:67, from up.cc:1: /home/jwakely/gcc/10/include/c++/10.0.0/bits/stl_vector.h: In instantiation of 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = X; _Alloc = std::allocator<X>; std::vector<_Tp, _Alloc>::value_type = X]': up.cc:14:18: required from here /home/jwakely/gcc/10/include/c++/10.0.0/bits/stl_vector.h:1188:18: error: static assertion failed 1188 | static_assert(is_copy_constructible_v<value_type>); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I think trying to do this via "smart" diagnostics would be doomed to failure. Enforcing preconditions via static_assert is much more reliable, and easier to tweak to improve it. Somebody just needs to add those assertions.