From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id CD0803858D3C; Wed, 12 Apr 2023 07:40:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CD0803858D3C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1681285237; bh=ncJ9vDgtQHZvYVbf0RzQ3XkJTS3L1UAQiWcgntlct3c=; h=From:To:Subject:Date:In-Reply-To:References:From; b=txdR1H06eMv+UG0BEopVe9rY3JhYC4wf0YajuVkgVp2gL1xapDYxGYyhbKGGDNdII UYqGE7m1P0/dyEBRdD9GyhFHHi5plkXIA0HoccdiqGuMxmAHL35NcH8foTWFEw24ge w0a+RdqjAb+mJALeHw5SCBkNibaldJKmApbQY2qM= From: "rguenth at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug libstdc++/109442] Dead local copy of std::vector not removed from function Date: Wed, 12 Apr 2023 07:40:37 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: libstdc++ X-Bugzilla-Version: 13.0 X-Bugzilla-Keywords: missed-optimization X-Bugzilla-Severity: normal X-Bugzilla-Who: rguenth at gcc dot gnu.org 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: component 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=3D109442 Richard Biener changed: What |Removed |Added ---------------------------------------------------------------------------- Component|tree-optimization |libstdc++ --- Comment #4 from Richard Biener --- (In reply to Jonathan Wakely from comment #3) > Ah, maybe the problem is that the library code manually elides destroying > the elements, precisely because it's a no-op. So we don't actually destroy > the elements, which means the compiler might think they're still initiali= zed > and so could be inspected. >=20 > If the library explicitly does vec[i].~T() for every i then would that he= lp? > The compiler would know there are no valid elements in the storage, and so > nothing operator delete could inspect. >=20 > We could continue to elide destroying the elements when !defined > __OPTIMIZE__ so that we don't run a loop that does nothing, but with > optimization enabled rely on the compiler to remove that loop. I don't think that would help. The issue is the compiler thinks that operator delete (_37, _49); uses the memory at _37 and thus the stores *_37 =3D _24; and __builtin_memmove (_37, pretmp_63, _23); are not dead. IIRC 'operator delete' (_ZdlPvm in this case), can be overridden by the user and can inspect the memory state before "releasing" the storage? This also seems to be a form not handled by fndecl_dealloc_argno even though it's marked as DECL_IS_OPERATOR_DELETE_P and DECL_IS_REPLACEABLE_OPERATOR - but the actual call stmt is not marked as such. That's to catch a new/delete _expression_ and not a direct call to the operator - ISTR we need the semantics guaranteed by the standard for new/delete expressions here. I see ~_Vector_base uses typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr; if (__p) _Tr::deallocate(_M_impl, __p, __n); but I fail to trace that further (in the preprocessed source), the line info on the delete stmt above points to new_allocator.h:168 which is _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n)); which looks like a direct invocation of operator delete rather than a delete expression. So the compiler rightfully(?) refuses to apply strict semantics ('delete' is _just_ like free with no other side-effects, a 'new' / 'delete' pair may be elided). Indeed in preprocessed source the above expands to ::operator delete((__p), (__n) * sizeof(_Tp)); rather than delete[] __p; (or what the correct syntax with explicit size would be). In theory we could implement an attribute specifying a operator new or delete invocation acts like a new or delete expression and use that in the library and make sure that CALL_FROM_NEW_OR_DELETE_P is set on the generated CALL_EXPRs. When I replace the above operator invocation in the library with delete[] (char *)__p; then the dead stores are elided but since I didn't track down the call to 'operator new' which suffers from a similar problem the new/delete pair isn't elided yet. So in the end it seems this is a library/C++ frontend issue.=