<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:purple;
text-decoration:underline;}
p.msonormal0, li.msonormal0, div.msonormal0
{mso-style-name:msonormal;
mso-margin-top-alt:auto;
margin-right:0in;
mso-margin-bottom-alt:auto;
margin-left:0in;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
span.EmailStyle18
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri",sans-serif;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal" style="margin-left:.5in">Once upon a time, C++ said that POD types could be memcpy'd, even if they were used as base classes. That rule got changed retroactively by core language defect reports, and you're no longer allowed to memcpy base
class subobjects (nor [[no_unique_address]] members), but too late for the ABI, so as a consequence of a rule that we're now pretending never existed, the Itanium ABI is careful not to reuse the tail padding of a base class for members of the derived class
if the base class is "POD for the purpose of layout" (which means POD according to some specific old C++ standard version).<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">As an aside, I believe PS4 got caught by something along these lines; some combination of (the rule changed) and (Clang had a bug) was in an unfortunate state right at the time we had to nail down our ABI. We’ve never gotten up the gumption
to post a patch upstream, though.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">IIUC (which is not super likely but I’ll give it a shot), pair is never trivially copyable, even with trivially copyable members. Which seems sad. Both pair and tuple have rules that say the destructor is trivial if the members are trivially
destructible; seems like an oversight not to make triviality just as transitive for construct/move/copy. Unless that ABI/tail-padding thing is what gets in the way.<o:p></o:p></p>
<p class="MsoNormal">--paulr<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div style="border:none;border-left:solid blue 1.5pt;padding:0in 0in 0in 4.0pt">
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> cfe-dev <cfe-dev-bounces@lists.llvm.org> <b>On Behalf Of
</b>Richard Smith via cfe-dev<br>
<b>Sent:</b> Wednesday, August 26, 2020 9:24 PM<br>
<b>To:</b> David Blaikie <dblaikie@gmail.com><br>
<b>Cc:</b> cfe-dev@lists.llvm.org<br>
<b>Subject:</b> Re: [cfe-dev] std::pair not trivially copyable?<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">On Wed, 26 Aug 2020 at 11:42, David Blaikie <<a href="mailto:dblaikie@gmail.com">dblaikie@gmail.com</a>> wrote:<o:p></o:p></p>
</div>
<div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<p class="MsoNormal">On Wed, Aug 26, 2020 at 11:34 AM Richard Smith via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<o:p></o:p></p>
</div>
<div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<p class="MsoNormal">On Wed, 26 Aug 2020 at 10:18, Nevin Liber via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<o:p></o:p></p>
</div>
<div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<p class="MsoNormal">On Tue, Aug 25, 2020 at 4:37 PM David Blaikie via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<o:p></o:p></p>
</div>
<div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<div>
<p class="MsoNormal">From what I can tell, reading this ( <a href="https://urldefense.com/v3/__https:/stackoverflow.com/questions/58283694/why-is-pair-of-const-trivially-copyable-but-pair-is-not__;!!JmoZiZGBv3RvKRSx!rMuXOBoosPAUEb_L7l9qA3KHSuisIvxQH9YC3nw5t0zEC7c5K6WEpAqMrB47qTd29A$" target="_blank">https://stackoverflow.com/questions/58283694/why-is-pair-of-const-trivially-copyable-but-pair-is-not</a> )
and the C++17 spec, it just doesn't specify the copy and move assignment operators as defaulted, or say anything about their triviality, so they aren't trivial even for trivial types. Perhaps an oversight when thinking about the other complexities of when
they shuold be deleted. <o:p></o:p></p>
</div>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">In general, move/copy assignment cannot be defaulted for pair, because assignment of reference types has meaning:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">int i = 2;</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">int j = 3;</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">std::pair<int&, int> p1(i, 5); </span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">std::pair<int&, int> p2(j, 7);</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">p2 = p1; // j now has the value 2</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New";color:black">struct A</span><span style="color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New";color:black">{</span><span style="color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New";color:black"> A(int& r_, int i_) : r(r_), i(i_) {}</span><span style="color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New";color:black"> int& r;</span><span style="color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New";color:black"> int i;</span><span style="color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New";color:black">};</span><span style="color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="color:black"><o:p> </o:p></span></p>
</div>
</div>
<div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New";color:black">int i = 2;</span><span style="color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New";color:black">int j = 3;</span><span style="color:black"><o:p></o:p></span></p>
</div>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">A a1(i, 5);</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">A a2(j, 7);</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:"Courier New"">a2 = a1; // Compile time error - deleted copy assignment operator</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Now, this doesn't that pair couldn't have trivial copy/move assignment operators when it holds trivially copy/move assignable types, but I don't know how much of an ABI break this would be.<o:p></o:p></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Making std::pair be trivially-copyable whenever possible would affect whether std::pair is POD for the purpose of layout, which could result in an ABI break for at least any code that derives from std::pair or that contains a [[no_unique_address]]
std::pair member: <a href="https://urldefense.com/v3/__https:/godbolt.org/z/GTvo4r__;!!JmoZiZGBv3RvKRSx!rMuXOBoosPAUEb_L7l9qA3KHSuisIvxQH9YC3nw5t0zEC7c5K6WEpAqMrB6_XykF_w$" target="_blank">
https://godbolt.org/z/GTvo4r</a><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">This is certainly not something we could do for the libc++ stable ABI. Maybe for the unstable ABI, but given the above change only makes layout worse, it's not clear that there would be a strong motivation. We already give std::pair trivial
copy/move construction and trivial destruction whenever possible, so we can pass and return it efficiently.<o:p></o:p></p>
</div>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal"><br>
Interesting - so POD for the purpose of layout is... not good? or more restrictive on the layout than if not. (probably an impractical idea, but would it be reasonable then to have an attribute that says "not POD for the purposes of layout" but I guess that'd
have to be cross-compiler/etc/etc... probably too much work)<o:p></o:p></p>
</div>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Once upon a time, C++ said that POD types could be memcpy'd, even if they were used as base classes. That rule got changed retroactively by core language defect reports, and you're no longer allowed to memcpy base class subobjects (nor
[[no_unique_address]] members), but too late for the ABI, so as a consequence of a rule that we're now pretending never existed, the Itanium ABI is careful not to reuse the tail padding of a base class for members of the derived class if the base class is
"POD for the purpose of layout" (which means POD according to some specific old C++ standard version).<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">An attribute to turn this off might make sense, for classes that really care. But so would an ABI-affecting flag to request that we always permit tail padding reuse. I do wonder if Clang should have a flag for "give me the best ABI you
can, I don't care if it's non-standard; I'm building the whole world this way with this version of this compiler", just like libc++ does.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<div>
<p class="MsoNormal">What's the cost of pair having non-trivial copy assignment? More expensive vector of pair resizing (though I guess the copy ctor calls would be readily optimized away & LLVM could get that back to a memcpy anyway?)?<o:p></o:p></p>
</div>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Yes, this is probably only significant for code that's detecting the triviality and taking different action based on it. Clang has code in IR generation that tries to emit the actual copy assignment operator as a single memcpy regardless.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<div>
<p class="MsoNormal">(the original issue with the warning could be fixed by narrowing the warning to only worry about trivial copy construction, not trivial copyability in general)<o:p></o:p></p>
</div>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">That sounds right to me. Is it worth also considering the triviality of the destructor?<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> <o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<div>
<p class="MsoNormal">- Dave <o:p></o:p></p>
</div>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</body>
</html>