This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ 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: C++17 std::launder and aliasing


On Mon, 24 Oct 2016, Jonathan Wakely wrote:

> On 24/10/16 11:44 +0200, Richard Biener wrote:
> > On Mon, 24 Oct 2016, Jonathan Wakely wrote:
> > 
> > > On 24/10/16 10:18 +0200, Richard Biener wrote:
> > > > On Mon, 24 Oct 2016, Ville Voutilainen wrote:
> > > >
> > > > > On 24 October 2016 at 10:41, Richard Biener <rguenther@suse.de> wrote:
> > > > > >> Seems that testcase is devirtualization related.
> > > > > >> With -O3 -fno-devirtualize we return 3 (but still no calls).
> > > > > >> With asm ("" : "+g" (p)); before return p; in launder we don't
> > > > > devirtualize
> > > > > >> it any more and return 3 in the end.  Is the testcase only valid
> > > > > >> with std::launder and not valid otherwise (I hope so, otherwise we
> > > are
> > > > > in
> > > > > >> big trouble with devirtualization)?
> > > > > >
> > > > > > I believe the testcase shows a bug in devirtualization.  (stpuid
> > > > > > godbolt.org having no way to textually extract the source easily)
> > > > > >
> > > > > > Please file a GCC bugreport.  GCC shouldn't miscompile this even
> > > > > > without std::launder.
> > > > >
> > > > >
> > > > > Note that A::f() can be in a different translation unit, so we still
> > > > > need the optimization
> > > > > barrier in some cases, even if in this particular case as written we
> > > > > wouldn't.
> > > >
> > > > Well, if it is valid to construct a new object in place of *this in
> > > > a virtual function call on this then GCC has an issue regardless of
> > > > std::launder.  So, for
> > > >
> > > > {
> > > >   A a;
> > > >   A::f ();
> > > > }
> > > >
> > > > where does the _FE_ get the knowledge what destructor to call?  IIRC
> > > > we "devirtualize" destructor calls in this case as well.
> > > >
> > > > struct B {
> > > >    virtual ~B();
> > > > };
> > > > struct A : B {
> > > >    virtual ~A();
> > > >    void foo ();
> > > > };
> > > >
> > > > int foo ()
> > > > {
> > > >  A a;
> > > >  a.foo();
> > > > }
> > > >
> > > >
> > > > foo ends up calling A::~A() with GCC 6.
> > > >
> > > > How do I launder a here?
> > > 
> > > This example has undefined behaviour even if you add std::launder. The
> > > original example doesn't.
> > > 
> > > The difference is 3.8 [basic.life] paragraph 9, which says that if the
> > > program ends the lifetime of the automatic object 'a' then it must
> > > ensure that another object of the same type occupies the same storage
> > > when the implicit destructor runs. So the original example is OK
> > > because it ends the lifetime of the original object by creating a B at
> > > the same location, but then creates another A there, so the implicit
> > > destructor call to A::~A() is valid, because there is an A at that
> > > location.
> > 
> > Ok, but in the original example if either f () would throw
> > before switching back to A then the testcase would invoke
> > undefined behavior again?
> 
> Yes. If there isn't an object of type A (and not a sub-object of some
> more derived type) at that location it's UB.
> 
> > > I don't think we have a bug, or a defect, in the absence of
> > > std::launder. Without std::launder our devirtualization is OK.
> > > 
> > > Again, std::launder(&a) is not the same as &a, so if we simply fold
> > > std::launder(&a) to &a we allow devirtualization through the pointer
> > > as though it was still a pointer to the original object &a, and that's
> > > what std::launder is supposed to prevent.
> > 
> > Note that std::launder () then has to be implemented as clobbering
> > memory (the vtable pointer) as otherwise the devirt machiner won't see it.
> > This means that std::launder () will pessimize optimizations (well,
> > we can try to special-case it in the alias machinery to only consider
> > clobbering its argument directly pointed to memory and not keeping
> > its argument pointed to memory live).
> 
> It's OK for std::launder to pessimize optimizations. That's what it's
> for, after all :-)

Then hopefully there's no need to use it in libstdc++ itself ;)

Richard.


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