Search code examples
c++gcccompiler-warningsplacement-newstrict-aliasing

Is this hack to remove aliasing warning UB?


We just upgraded our compiler to gcc 4.6 and now we get some of these warnings. At the moment our codebase is not in a state to be compiled with c++0x and anyway, we don't want to run this in prod (at least not yet) - so I needed a fix to remove this warning.

The warnings occur typically because of something like this:

struct SomeDataPage
{
  // members
  char vData[SOME_SIZE];
};

later, this is used in the following way

SomeDataPage page;
new(page.vData) SomeType(); // non-trivial constructor

To read, update and return for example, the following cast used to happen

reinterpret_cast<SomeType*>(page.vData)->some_member();

This was okay with 4.4; in 4.6 the above generates:

warning: type punned pointer will break strict-aliasing rules

Now a clean way to remove this error is to use a union, however like I said, we can't use c++0x (and hence unrestricted unions), so I've employed the horrible hack below - now the warning has gone away, but am I likely to invoke nasal daemons?

static_cast<SomeType*>(reinterpret_cast<void*>(page.vData))->some_member();

This appears to work okay (see simple example here: http://www.ideone.com/9p3MS) and generates no warnings, is this okay(not in the stylistic sense) to use this till c++0x?

NOTE: I don't want to use -fno-strict-aliasing generally...

EDIT: It seems I was mistaken, the same warning is there on 4.4, I guess we only picked this up recently with the change (it was always unlikely to be a compiler issue), the question still stands though.

EDIT: further investigation yielded some interesting information, it seems that doing the cast and calling the member function in one line is what is causing the warning, if the code is split into two lines as follows

SomeType* ptr = reinterpret_cast<SomeType*>(page.vData);
ptr->some_method();

this actually does not generate a warning. As a result, my simple example on ideone is flawed and more importantly my hack above does not fix the warning, the only way to fix it is to split the function call from the cast - then the cast can be left as a reinterpret_cast.


Solution

  • SomeDataPage page;
    new(page.vData) SomeType(); // non-trivial constructor
    reinterpret_cast<SomeType*>(page.vData)->some_member();
    

    This was okay with 4.4; in 4.6 the above generates:

    warning: type punned pointer will break strict-aliasing rules
    

    You can try:

    SomeDataPage page;
    SomeType *data = new(page.vData) SomeType(); // non-trivial constructor
    data->some_member();