<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8">
</head>
<body>
<div style="font-family:sans-serif"><div style="white-space:normal">
<p dir="auto">On 31 Jul 2020, at 19:50, Hal Finkel wrote:</p>
</div>
<div style="white-space:normal"><blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px"><p dir="auto">On 7/31/20 5:59 PM, James Y Knight wrote:</p>
<blockquote style="border-left:2px solid #777; color:#999; margin:0 0 5px; padding-left:5px; border-left-color:#999"><p dir="auto">This discussion reminds me of an example I ran into a couple weeks ago, where the execution of the program is dependent precisely upon whether the ABI calls for the object to be passed indirectly, or in a register<br>
<br>
In the case where NVRO is triggered, the class member foo_ is fully-constructed on the first line of CreateFoo (despite appearing as if that's only constructing a local variable). In the case where the struct is small enough to fit in a register, NVRO does not apply, and in that case, foo_ isn't constructed until after CreateFoo returns.<br>
<br>
Therefore, I believe it's implementation-defined whether the following program has undefined behavior.<br>
<br>
<a href="https://godbolt.org/z/YT9zsz" style="color:#999">https://godbolt.org/z/YT9zsz</a> <<a href="https://godbolt.org/z/YT9zsz" style="color:#999">https://godbolt.org/z/YT9zsz</a>><br>
<br>
#include <assert.h><br>
<br>
struct Foo {<br>
int x;<br>
* // assert fails if you comment out these unused fields!<br>
* int dummy[4];<br>
};<br>
<br>
struct Bar {<br>
Bar() : foo_(CreateFoo()) {}<br>
<br>
Foo CreateFoo() {<br>
Foo f;<br>
f.x = 55;<br>
assert(foo_.x == 55);<br>
return f;<br>
}<br>
Foo foo_;<br>
};<br>
<br>
int main() {<br>
Bar b;<br>
}</p>
</blockquote><p dir="auto">Looks that way to me too. The example in 11.10.5p2 sort of makes this point as well (by pointing out that you can directly initialize a global this way).</p>
</blockquote></div>
<div style="white-space:normal">
<p dir="auto">It does seem hard to argue that this is invalid under the specification. To me it seems like it clearly <em>ought</em> to be invalid, though. Note that Clang has always emitted return address arguments as <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">noalias</code>, so this has immediate significance.</p>
<p dir="auto">If I were writing the specification, I would rewrite the restriction in <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">[class.cdtor]p2</code> to say that pointers derived by naming a returned/constructed object do not formally point to the object until the function actually returns, even if the copy is elided. That would make James’s example undefined behavior.</p>
<p dir="auto">John.</p>
</div>
<div style="white-space:normal"><blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px"><p dir="auto"> -Hal<br>
<br>
</p>
<blockquote style="border-left:2px solid #777; color:#999; margin:0 0 5px; padding-left:5px; border-left-color:#999"><p dir="auto">On Fri, Jul 31, 2020 at 2:27 PM Hal Finkel via cfe-dev <cfe-dev@lists.llvm.org <<a href="mailto:cfe-dev@lists.llvm.org" style="color:#999">mailto:cfe-dev@lists.llvm.org</a>>> wrote:<br>
<br>
<br>
On 7/31/20 1:24 PM, Hal Finkel wrote:</p>
<blockquote style="border-left:2px solid #777; color:#BBB; margin:0 0 5px; padding-left:5px; border-left-color:#BBB"><p dir="auto"> On 7/31/20 12:43 PM, John McCall wrote:</p>
<blockquote style="border-left:2px solid #777; color:#BBB; margin:0 0 5px; padding-left:5px; border-left-color:#BBB"><p dir="auto"> n 31 Jul 2020, at 7:35, Hal Finkel wrote:<br>
<br>
On 7/29/20 9:00 PM, John McCall via cfe-dev wrote:<br>
<br>
On 29 Jul 2020, at 17:42, Richard Smith wrote:<br>
<br>
On Wed, 29 Jul 2020 at 12:52, John McCall<br>
<rjmccall@apple.com> <<a href="mailto:rjmccall@apple.com" style="color:#BBB">mailto:rjmccall@apple.com</a>> wrote:<br>
<br>
...<br>
<br>
I think concretely, the escape hatch doesn't stop things<br>
from<br>
going wrong,<br>
because -- as you note -- even though we *could* have<br>
made a copy,<br>
it's<br>
observable whether or not we *did* make a copy. For example:<br>
<br>
I would say that it’s observable whether the parameter<br>
variable has<br>
the same address as the argument. That doesn’t /have/ to<br>
be the same<br>
question as whether a copy was performed: we could<br>
consider there to be<br>
a formal copy (or series of copies) that ultimately<br>
creates /an/ object<br>
at the same address, but it’s not the /same/ object and<br>
so pointers<br>
to the old object no longer validly pointer to it. But I<br>
guess that<br>
would probably violate the lifetime rules, because it<br>
would make accesses<br>
through old pointers UB when in fact they should at<br>
worst access a valid<br>
object that’s just unrelated to the parameter object.<br>
<br>
I think that it would be great to be able to do this, but<br>
unfortunately, I think that the point that you raise here is<br>
a key issue. Whether or not the copy is performed is visible<br>
in the model, and so we can't simply act as though there was<br>
a copy when optimizing. Someone could easily have code that<br>
looks like:<br>
<br>
Foo DefaultX;<br>
<br>
...<br>
<br>
void something(Foo &A, Foo &B) {<br>
<br>
if (&A == &B) { ... }<br>
<br>
}<br>
<br>
void bar(Foo X) { something(X, DefaultX); }<br>
<br>
This example isn’t really on point; a call like |bar(DefaultX)|<br>
obviously cannot just pass the address of |DefaultX| as a<br>
by-value argument without first proving a lot of stuff about how<br>
|foo| uses both its parameter and |DefaultX|. I think |noalias|<br>
is actually a subset of what would have to be proven there.<br>
</p>
</blockquote><p dir="auto"> Yes, I apologize. You're right: my pseudo-code missed the point.<br>
So the record is clear, let me rephrase:<br>
<br>
Foo *DefaultX = nullptr;<br>
...<br>
Foo::Foo() { if (!DefaultX) DefaultX = this; }<br>
...<br>
void bar(Foo X) { something(X, *DefaultX); }<br>
...<br>
bar(Foo{});<br>
<br>
I think that's closer to what we're talking about.<br>
<br>
</p>
<blockquote style="border-left:2px solid #777; color:#BBB; margin:0 0 5px; padding-left:5px; border-left-color:#BBB"><p dir="auto"> In general, the standard is clear that you cannot rely on<br>
escaping a pointer to/into a trivially-copyable pr-value<br>
argument prior to the call and then rely on that pointer<br>
pointing into the corresponding parameter object.<br>
Implementations are /allowed/ to introduce copies. But it does<br>
seem like the current wording would allow you to rely on that<br>
pointer pointing into /some/ valid object, at least until the<br>
end of the caller’s full-expression. That means that, if we<br>
don’t guarantee to do an actual copy of the argument, we cannot<br>
make it UB to access the parameter variable through pointers to<br>
the argument temporary, which is what marking the parameter as<br>
|noalias| would do.<br>
<br>
So I guess the remaining questions are:<br>
<br>
* Is this something we can reasonably change in the standard?<br>
</p>
</blockquote><p dir="auto"> This is the part that I'm unclear about. What change would we make?<br>
<br>
</p>
</blockquote><p dir="auto"> Also, maybe some extended use of the no_unique_address attribute<br>
would help?<br>
<br>
-Hal<br>
<br>
</p>
<blockquote style="border-left:2px solid #777; color:#BBB; margin:0 0 5px; padding-left:5px; border-left-color:#BBB"><blockquote style="border-left:2px solid #777; color:#BBB; margin:0 0 5px; padding-left:5px; border-left-color:#BBB"><p dir="auto"> * Are we comfortable setting |noalias| in C if the only place<br>
that would break is with a C++ caller?<br>
</p>
</blockquote><p dir="auto"> Out of curiosity, if you take C in combination with our<br>
statement-expression extension implementation<br>
(<a href="https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html" style="color:#BBB">https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html</a><br>
<<a href="https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html" style="color:#BBB">https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html</a>>), and<br>
notwithstanding the statement in the GCC manual about returns by<br>
value (i.e., the part just before where it says, "Therefore the<br>
this pointer observed by Foo is not the address of a."), is there<br>
any relationship to this topic?<br>
<br>
Thanks again,<br>
<br>
Hal<br>
<br>
</p>
<blockquote style="border-left:2px solid #777; color:#BBB; margin:0 0 5px; padding-left:5px; border-left-color:#BBB"><p dir="auto"> John.<br>
<br>
As Richard's example shows, the code doesn't need to<br>
explicitly compare the addresses to detect the copy either.<br>
Any code that reads/writes to the objects can do it. A<br>
perhaps-more-realistic example might be:<br>
<br>
int Cnt = A.RefCnt; ++A.RefCnt; ++B.RefCnt; if (Cnt + 1 !=<br>
A.RefCnt) { /* same object case */ }<br>
<br>
The best suggestion that I have so far is that we could add<br>
an attribute like 'can_copy' indicating that the optimizer<br>
can make a formal copy of the argument in the callee and use<br>
that instead of the original pointer if that seems useful. I<br>
can certainly imagine a transformation such as LICM making<br>
use of such a thing (although the cost modeling would<br>
probably need to be fairly conservative).<br>
<br>
-Hal<br>
<br>
...<br>
<br>
John.<br>
<br>
<br>
_______________________________________________<br>
cfe-dev mailing list<br>
cfe-dev@lists.llvm.org <<a href="mailto:cfe-dev@lists.llvm.org" style="color:#BBB">mailto:cfe-dev@lists.llvm.org</a>><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" style="color:#BBB">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
<<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" style="color:#BBB">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a>><br>
<br>
-- <br>
Hal Finkel<br>
Lead, Compiler Technology and Programming Languages<br>
Leadership Computing Facility<br>
Argonne National Laboratory<br>
</p>
</blockquote><p dir="auto"> -- <br>
Hal Finkel<br>
Lead, Compiler Technology and Programming Languages<br>
Leadership Computing Facility<br>
Argonne National Laboratory</p>
</blockquote><p dir="auto"> -- <br>
Hal Finkel<br>
Lead, Compiler Technology and Programming Languages<br>
Leadership Computing Facility<br>
Argonne National Laboratory<br>
<br>
_______________________________________________<br>
cfe-dev mailing list<br>
cfe-dev@lists.llvm.org <<a href="mailto:cfe-dev@lists.llvm.org" style="color:#999">mailto:cfe-dev@lists.llvm.org</a>><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" style="color:#999">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
<<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" style="color:#999">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a>><br>
</p>
</blockquote><p dir="auto">-- <br>
Hal Finkel<br>
Lead, Compiler Technology and Programming Languages<br>
Leadership Computing Facility<br>
Argonne National Laboratory</p>
</blockquote></div>
<div style="white-space:normal">
</div>
</div>
</body>
</html>