rjmccall added a comment.

Under [expr.call]p6 (https://eel.is/c++draft/expr.call#6), it is 
implementation-defined whether the lifetime of a parameter ends at the end of 
the containing full expression or at the end of the function.  If the 
implementation chooses the latter, a reference to the parameter will dangle 
after the return.  In your example, on your chosen target (probably x64-64?), 
we are actually forced by the psABI to end those lifetimes at the end of the 
function, because the contents of the parameters are passed in registers 
(rather than by implicit reference) and reconstituted in the stack frame of the 
callee.  Therefore your `min` function has undefined behavior, and not just in 
a formal sense but actually in a very directly dangerous sense.  That should 
not be surprising; intuitively, you should think of this as returning a 
reference to a local variable, which is highly suspect even if it is sometimes 
— only on certain targets and for certain types — formally allowed.

> That makes me think we should probably do this lifetime annotation in the 
> caller of CodeGenFunction::EmitCallArg since it will have information about 
> the return type of the caller. If a function returns a reference to a type, 
> we probably don't want to emit the lifetime markers for any parameter of that 
> type. I wonder if strict aliasing needs to be considered, too?

This is definitely barking up the wrong tree.  The language specifies the 
lifetime of an object, and any access to the object during its lifetime is 
valid.  If the parameter's lifetime *was* guaranteed to be the full expression 
here, we would be obliged to keep it alive for that full duration.

In particular, we cannot do anything with reasoning like "the return value 
cannot be a reference to the parameter". The right way to understand that is as 
an effort to invoke the as-if rule, arguing that it is impossible to reference 
the parameter after the call if it is not part of the return value, and 
therefore we can be more aggressive than the language would formally allow. But 
it is not true that the only way to reference a parameter after a call is if it 
is part of the return value.  For example, the function could store a pointer 
to the parameter into a global variable, and as long as all accesses through 
that global happen before the parameter's lifetime ends, that's totally fine — 
it's obviously a very confusing and error-prone way to write code, but it's 
legal.  (Also, even if the address of the parameter *could* only escape into 
the return value, the type analysis would have to be much more complicated than 
just whether it's a reference to the type of a parameter.)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74094/new/

https://reviews.llvm.org/D74094

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to