This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Missed optimization with const member


On 5 July 2017 at 10:13, Oleg Endo wrote:
> Hi,
>
> On Wed, 2017-07-05 at 02:02 +0200, Geza Herman wrote:
>>
>> Here's what happens: in callInitA(), an Object put onto the stack (which
>> has a const member variable, initialized to 0). Then somefunction called
>> (which is intentionally not defined). Then ~Object() is called, which
>> has an "if", which has a not-immediately-obvious, but always false
>> condition. Compiling with -03, everything gets inlined.
>>
>> My question is about the inlined ~Object(). As m_initType is always 0,
>> why does not optimize the destructor GCC away? GCC inserts code that
>> checks the value of m_initType.
>>
>> Is it because such construct is rare in practice? Or is it hard to do an
>> optimization like that?
>
> It's not safe to optimize it away because the compiler does not know
> what "somefunction" does.  Theoretically, it could cast the "Object&"
> to some subclass and overwrite the const variable.  "const" does not
> mean that the memory location is read-only in some way.

No, that would be undefined behaviour. The data member is defined as
const, so it's not possible to write to that member without undefined
behaviour. A variable defined with a const type is not the same as a
variable accessed through a pointer/reference to a const type.

Furthermore, casting the Object to a derived class would also be
undefined, because the dynamic type is Object, not some derived type.

I think the reason it's not optimized away is for this case:

void somefunction(const Object& object);
{
  void* p = &object;
  object.~Object();
  new(p) Object();
}

This means that after calling someFunction there could be a different
object at the same location (with a possibly different value for that
member).

However, for this specific case that's also not possible, because
there are no constructors that could initialize the member to anything
except zero. But that requires more than just control-flow analysis,
it also requires analysing all the available constructors to check
there isn't one that does:

Object::Object(int) : m_initType(1) { }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]