https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93059
Bug ID: 93059 Summary: char and char8_t does not talk with each other with memcpy. std::copy std::copy_n, std::fill, std::fill_n, std::uninitialized_copy std::uninitialized_copy_n, std::fill, std::uninitialized_fill_n fails to convert to memxxx functions Product: gcc Version: 10.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: euloanty at live dot com Target Milestone: --- https://godbolt.org/z/SPktTz All these functions should generate exactly the same assembly but they do not. GCC does not treat char and char8_t the same because libstdc++ does not do this check. I did my native manually fix and it works. (does not do mul_overflow something) //g++ -S copy.cc -Ofast -std=c++2a #include<cstring> #include<algorithm> #include<array> #include<concepts> #include<iterator> auto copy_char8_t_array(char* out,std::array<char8_t,2> const& bits) { return std::copy_n(bits.data(),bits.size(),out); } auto memcpy_char8_t_array(char* out,std::array<char8_t,2> const& bits) { std::memcpy(out,bits.data(),bits.size()); return bits.size(); } auto copy_char_array(char* out,std::array<char,2> const& bits) { return std::copy_n(bits.data(),bits.size(),out); } auto memcpy_char_array(char* out,std::array<char,2> const& bits) { std::memcpy(out,bits.data(),bits.size()); return bits.size(); } auto copy_char_array_chars(char8_t* out,std::array<char8_t,2> const& bits) { return std::copy_n(bits.data(),bits.size(),out); } auto memcpy_char_array_array_chars(char8_t* out,std::array<char8_t,2> const& bits) { std::memcpy(out,bits.data(),bits.size()); return bits.size(); } auto copy_char_array(char8_t* out,std::array<char,2> const& bits) { return std::copy_n(bits.data(),bits.size(),out); } auto memcpy_char_array(char8_t* out,std::array<char,2> const& bits) { std::memcpy(out,bits.data(),bits.size()); return bits.size(); } template<std::input_iterator input_iter,std::input_iterator output_iter> inline constexpr output_iter my_copy_n(input_iter first,std::size_t count,output_iter result) { if constexpr(std::contiguous_iterator<input_iter>&& std::contiguous_iterator<output_iter>&& std::is_trivially_copyable_v<typename std::iterator_traits<input_iter>::value_type>&& std::is_trivially_copyable_v<typename std::iterator_traits<output_iter>::value_type>) { if constexpr(sizeof(std::is_trivially_copyable_v<typename std::iterator_traits<input_iter>::value_type>) ==sizeof(std::is_trivially_copyable_v<typename std::iterator_traits<output_iter>::value_type>)) { memcpy(std::to_address(result),std::to_address(first), sizeof(typename std::iterator_traits<input_iter>::value_type)*count); return result+count; } } return std::copy_n(first,count,result); } auto my_copy_char_array(char8_t* out,std::array<char,2> const& bits) { return my_copy_n(bits.data(),bits.size(),out); } auto my_copy_char_array(char* out,std::array<char8_t,2> const& bits) { return my_copy_n(bits.data(),bits.size(),out); } auto uninit_copy_char_array(char8_t* out,std::array<char,2> const& bits) { return std::uninitialized_copy_n(bits.data(),bits.size(),out); } _Z29memcpy_char_array_array_charsPDuRKSt5arrayIDuLm2EE: movzwl (%rsi), %eax movw %ax, (%rdi) movl $2, %eax ret std::copy_n generates more assembly than it should _Z15copy_char_arrayPDuRKSt5arrayIcLm2EE: movzbl (%rsi), %eax movb %al, (%rdi) movzbl 1(%rsi), %eax movb %al, 1(%rdi) leaq 2(%rdi), %rax ret