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.

Reply via email to