From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 24ABD3858C2A; Tue, 20 Feb 2024 15:47:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 24ABD3858C2A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1708444070; bh=K9YMpLR/zTtP6sH4XbkjCGBZmHrvUwzZqbeZFoP0Ib8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Ck8rme4ZfmE+A8bZ7bIwzvO7uZ523cHVrl/5CZ21A0x1aRTOkGlhLKe58ZSy5Flkv NjjiKzYfB3QRKY0qkL4KLGjEUCbZ4NXpjIk3E1Xy4RPI2yymYXervW5icuWgRTk7Pj Q9KGUjZEolFs1TJBVA+bTvMK0mQE+n2A9nZzdzsQ= From: "arthur.j.odwyer at gmail dot com" To: gcc-bugs@gcc.gnu.org Subject: [Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2 Date: Tue, 20 Feb 2024 15:47:49 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: tree-optimization X-Bugzilla-Version: 14.0 X-Bugzilla-Keywords: wrong-code X-Bugzilla-Severity: normal X-Bugzilla-Who: arthur.j.odwyer at gmail dot com X-Bugzilla-Status: NEW X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 List-Id: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D109945 --- Comment #30 from Arthur O'Dwyer --- I think I understand jwakely's argument at this point, and it's consistent = and teachable. https://eel.is/c++draft/class.temporary#3.sentence-1 says: > When an object of class type X is passed to or returned from a function, = if X has at least one eligible copy or move constructor, each such construc= tor is trivial, and the destructor of X is either trivial or deleted, imple= mentations are permitted to create a temporary object to hold the function = parameter or result object. It says "implementations are permitted"; this means that an implementation (GCC) can create such a temporary *whenever* permitted, and then re-optimize the codegen under the As-If Rule to eliminate the trivial move. That still = ends the lifetime of the original object. `global` points to that original objec= t, which is out-of-lifetime, so dereferencing `global` is UB. (Yes, even if its value happens to _compare_ equal to some other pointer that's still in-lifetime: this is "pointer provenance" as I see and understand it.) So, in order for me to call this `Widget` example a "bug," I'd have to find= a `Widget` that doesn't meet [class.temporary]/3's conditions. That is, it wo= uld have to be a type that does NOT have eligible copy or move constructors; or= has at least one NON-trivial eligible copy or move constructor; or has a NON-deleted NON-trivial destructor. Then the implementation (GCC) would NOT= be permitted to create a temporary and the argument wouldn't hold anymore. And indeed, I cannot find such a `Widget`! Every example I've tried so far matches jwakely's explanation. For example: https://godbolt.org/z/rT6Mv537e struct X { X(); X(X&, int=3D0); X(const X&) =3D default; int i =3D 1; int a[4]; }; This `X` has a non-trivial eligible copy constructor, so it doesn't meet [class.temporary]/3's conditions, and GCC treats it the same at -O1 and -O2. If you delete the characters `=3D0`, then that constructor is no longer a c= opy constructor, so `X` DOES meet [class.temporary]/3 and GCC treats it differe= ntly at -O1 and -O2 (which is fine because now the program has UB, as jwakely sa= ys). GCC is not misbehaving in this example. Here's another example (still matching jwakely's argument perfectly: GCC is= not misbehaving) -- this one exploits [special]/6 to play with whether the non-trivial copy ctor is "eligible" -- https://godbolt.org/z/PWT85n5xb I'm satisfied with the explanation -- and GCC seems to be implementing it correctly AFAICT -- so I think it would be reasonable to close this bug as INVALID. On the other hand, if anyone wants to argue that the current behav= ior is technically correct but super confusing to working programmers, I wouldn= 't argue against them, either. ;)=