[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-21 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

--- Comment #9 from Jonathan Wakely  ---
(In reply to Kostya Frumkin from comment #8)
> At the same time this design pattern (strategy) with placement-new is more
> efficient than with common new.

That's fine, but you can't use  to access the AStrategy object you
created at that position. You have several choices:

- use an untyped buffer and create objects in there:

  alignas(AStrategy) unsigned char buf[sizeof(AStrategy)];

- use std::launder

- use the pointer returned by the placement new-expression, which has the right
type


There are ways to do this safely in C++ today, but your original code is not
one of those ways. You should fix your code.


> So it has no rationale if the base methods
> are used when using placement-new. At the same time other compilers
> generates code where the derived method is callsed after placement-new. 

It's undefined behaviour, so anything can happen.

[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-21 Thread fro0m.spam at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

--- Comment #8 from Kostya Frumkin  ---
> Either way you need to placement new the original type back again, otherwise
> the wrong destructor gets called on scope exit, which adds more undefined
> behaviour.

There should not be undefined behavior because the size of both classes is same
and destructors executes same code (in the case it is noop).
So the memory to be freed up is same.

The behavior must be defined by ISO committee because it is counterintuitive
when the base methods are being called. (where to ask?)

At the same time this design pattern (strategy) with placement-new is more
efficient than with common new. So it has no rationale if the base methods are
used when using placement-new. At the same time other compilers generates code
where the derived method is callsed after placement-new. 

So I see two ways:
- Ask the community to define behavior.
or
- Define behavior in gcc itself.

[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-21 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

--- Comment #7 from Jonathan Wakely  ---
(In reply to Richard Biener from comment #6)
> (In reply to Jonathan Wakely from comment #1)
> > No, your program has undefined behaviour. To make it valid you either need
> > to use std::launder, or use the pointer that is returned by the placement
> > new.
> > 
> > The compiler is allowed to assume that the dynamic type of  does
> > not change (that's why you need to use std::launder).
> 
> You need to use std::launder at every use of the object, right?

Or just launder the pointer once and then use that:

  auto laundered = std::launder();
  laundered->doIt();  // 

> I wonder
> why static_cast() isn't a good enough "hint" here that
> the type of strategy changed (from QOI perspective, std::launder is new).

Casting from type X* to Y* where X and Y happen to be the same type can happen
in generic code that was already written years ago, and doesn't play these sort
of dirty tricks. It would be a shame to prevent useful optimisations because of
a no-op cast.

We don't need to make it easier to play nasty games with the type system. There
are ways to do this sanely, without undefined behaviour, even without
std::launder (just using the pointer returned by the placement new-expression
should be good enough, instead of accessing through  every time).

> I guess a better testcase would be to declare strategy as AStrategy
> and placement-new BaseStrategy over it or does the standard guaranteee
> that AStrategy fits in the storage of BaseStrategy?

For these types, with the Itanium ABI, it fits, and you could add a
static_assert to verify it.

Either way you need to placement new the original type back again, otherwise
the wrong destructor gets called on scope exit, which adds more undefined
behaviour.

[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-21 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

Richard Biener  changed:

   What|Removed |Added

 CC||rguenth at gcc dot gnu.org

--- Comment #6 from Richard Biener  ---
(In reply to Jonathan Wakely from comment #1)
> No, your program has undefined behaviour. To make it valid you either need
> to use std::launder, or use the pointer that is returned by the placement
> new.
> 
> The compiler is allowed to assume that the dynamic type of  does
> not change (that's why you need to use std::launder).

You need to use std::launder at every use of the object, right?  I wonder
why static_cast() isn't a good enough "hint" here that
the type of strategy changed (from QOI perspective, std::launder is new).

I guess a better testcase would be to declare strategy as AStrategy
and placement-new BaseStrategy over it or does the standard guaranteee
that AStrategy fits in the storage of BaseStrategy?

[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-10 Thread fro0m.spam at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

--- Comment #5 from Kostya Frumkin  ---
(In reply to Jonathan Wakely from comment #4)
> (In reply to Kostya Frumkin from comment #3)
> > Hi, for example msvc2013 calls base class's virtual method when msvc2015
> > calls derived class's virtual method.
> 
> It's undefined behaviour. Anything can happen.
> 
> > This is developer's mistake which can be predicted by compiler. Few
> > developers know about this behavior.
> 
> Using placement new to replace a polymorphic type is not a common idiom, I
> don't think it's worth adding a warning about it. Just don't do it.
> 
> > It'd be awesome to see the correct behavior or at least warning that base
> > method is being used after placement new.
> 
> GCC's behaviour is already correct.

It is best way to get away with heap allocation in many cases. Let's make a
warning about undefined behavior.

[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-10 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

--- Comment #4 from Jonathan Wakely  ---
(In reply to Kostya Frumkin from comment #3)
> Hi, for example msvc2013 calls base class's virtual method when msvc2015
> calls derived class's virtual method.

It's undefined behaviour. Anything can happen.

> This is developer's mistake which can be predicted by compiler. Few
> developers know about this behavior.

Using placement new to replace a polymorphic type is not a common idiom, I
don't think it's worth adding a warning about it. Just don't do it.

> It'd be awesome to see the correct behavior or at least warning that base
> method is being used after placement new.

GCC's behaviour is already correct.

[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-10 Thread fro0m.spam at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

Kostya Frumkin  changed:

   What|Removed |Added

 Status|RESOLVED|UNCONFIRMED
Version|unknown |9.0
 Resolution|INVALID |---

--- Comment #3 from Kostya Frumkin  ---
(In reply to Jonathan Wakely from comment #1)
> No, your program has undefined behaviour. To make it valid you either need
> to use std::launder, or use the pointer that is returned by the placement
> new.
> 
> The compiler is allowed to assume that the dynamic type of  does
> not change (that's why you need to use std::launder).

Hi, for example msvc2013 calls base class's virtual method when msvc2015 calls
derived class's virtual method.
This is developer's mistake which can be predicted by compiler. Few developers
know about this behavior.
It'd be awesome to see the correct behavior or at least warning that base
method is being used after placement new.

[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-10 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

--- Comment #2 from Jonathan Wakely  ---
This makes the program correct:

strategyPtr = new() AStrategy;
static_cast(std::launder())->doIt();
strategyPtr->doIt();

[Bug c++/86908] static_cast()->virtualMehod() calls base version of virtualMethod()

2018-08-10 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908

Jonathan Wakely  changed:

   What|Removed |Added

 Status|UNCONFIRMED |RESOLVED
 Resolution|--- |INVALID

--- Comment #1 from Jonathan Wakely  ---
No, your program has undefined behaviour. To make it valid you either need to
use std::launder, or use the pointer that is returned by the placement new.

The compiler is allowed to assume that the dynamic type of  does not
change (that's why you need to use std::launder).