https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104855
Bug ID: 104855
Summary: -Wclass-memaccess is too broad with valid code
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: soap at gentoo dot org
Target Milestone: ---
Given the following snippet:
#include <cassert>
#include <cstring>
#include <type_traits>
struct A
{
A() = default;
A(unsigned a, unsigned b) : data_(a + b) {}
private:
unsigned data_;
};
static_assert(std::is_trivial_v<A>, "");
static_assert(std::is_trivially_copyable_v<A>, "");
A foo(unsigned x)
{
A result;
std::memcpy(&result, &x, sizeof(x));
return result;
}
with GCC 11 and -Wall, I get the following warning
example.cpp: In function ‘A foo(unsigned int)’:
example.cpp:20:16: warning: ‘void* memcpy(void*, const void*, size_t)’ copying
an object of type ‘struct A’ with ‘private’ member ‘A::data_’ from an array of
‘unsigned int’; use assignment or copy-initialization instead
[-Wclass-memaccess]
20 | std::memcpy(&result, &x, sizeof(x));
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
example.cpp:5:8: note: ‘struct A’ declared here
5 | struct A
| ^
which seems overbroad given that the code is 100% valid. I have asked Martin
Sebor, and his reason for this warning is
> about it breaking encapsulation by modifying a private data member.
> In the test case the modification might violate the invariant that
> the class represent the sum of the arguments it's constructed with.
which I understand, but I still consider this warning too broad for valid code,
especially because the suggested workaround is to cast the &result to a void*,
which involves reinterpret_cast and will raise eyebrows. Clang doesn't do this,
and I think it's right on this one.