From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id EF960384A033; Mon, 15 Jun 2020 09:29:25 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EF960384A033 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1592213365; bh=JtwFtstghdaXGxz1wRs8UKcuf+QDdIV0FQurYvcTHvo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=OkGxvz8bfukpunFQGLOEuvnFKVLIA0HUqVBTg3wTw7AHOgob77mjGoylH5RWLnnwS s8sYB1+BDuzWy5oOko3Rem5PjL4BhzdHiH5lTTYKCpPaoeEVm+9ih5K08eIDoFHfnR TvIL3DD+Iw5qTGxiPVj1eDJcQX1SQN+CyatMwOs8= From: "rguenth at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug c++/95349] Using std::launder(p) produces unexpected behavior where (p) produces expected behavior Date: Mon, 15 Jun 2020 09:29:25 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: 10.1.0 X-Bugzilla-Keywords: alias, wrong-code X-Bugzilla-Severity: normal X-Bugzilla-Who: rguenth at gcc dot gnu.org X-Bugzilla-Status: UNCONFIRMED 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 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Jun 2020 09:29:26 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D95349 --- Comment #36 from Richard Biener --- (In reply to Andrew Downing from comment #35) > I agree that the new implicit object creation rules sound very difficult = to > implement correctly especially because the behavior in C is different. I'm > curious to see how that will all play out. >=20 > In this situation though, if we use the C rules for what memcpy does C17 > 6.5/6 > https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc= 1/ > sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf#section.6.5, the effective > type shouldn't be changed. The declared type of both objects is known to = the > compiler. In the first memcpy the declared type of the object is unsigned > char[8], in the second memcpy the declared type of the object is double. The issue I have with this special handling of objects with a declared type is that the standard assumes universal knowledge and disregards that compilers are imperfect. It's also not clear what it means for int *p; int x; if () p =3D &x; else p =3D malloc (4); memcpy (p, q, 4); there is a single memcpy call and the standard says that both the dynamic type transfers (from q) and that it does not (to x). > Placement new changes the effective type to std::uint64_t, but that doesn= 't > change the behavior of memcpy. Footnote 88 says "Allocated objects have no > declared type.". I believe calling a function defined in another TU that > returns a pointer also has to be considered to return a pointer to an obj= ect > with no declared type, because the object's declaration isn't visible. In > this situation though, the declared types are visible, and so a modifying > access, or memcpy, or memmove shouldn't change the effective type. Note the C++ standard makes the placement new optional. Do you say that your example is incorrect with the placement new elided? Note you say the declared types are visible - but at least 'd' is in another function (compilers are imperfect) and is accessed via a pointer here. IIRC C++ does not have this "special-casing" of objects with declared types (it doesn't have this memcpy wording at all I think). [there's more "interesting" bits of all this dynamic type frobbing in PR79671 when partial objects are re-used] > If gcc is changing the effective type with every memcpy no matter what, t= hat > would be the wrong thing to do right? Especially since you're saying that > it's the reason that this example isn't being compiled correctly. As you say above the C rule that memcpy does not change the dynamic type of an object with a declared type can only be fulfilled by being conservati= ve. This is why GCC interprets memcpy as TBAA barrier but it uses the transfer of dynamic type as means to be able to elide a memcpy roundtrip as seen in your testcase. If the memcpy roundtrip has to be considered a side-effect then I see no easy way to preserve that without preserving the actual memcpy operation [without changing the intermediate representati= on of GCC, that is]. I'd be interested in a C testcase that we get wrong, even when relying on that special casing of objects with a declared type. It should then be possible to construct a C++ variant that expects exactly the opposite behavior. The main issue I see is that this differing expectations of C and C++ are impossible to get correct at the same time.=