Closed t3nsor closed 2 months ago
There also seems something wrong in [class.temporary] p3.
The current wording says:
[...] implementations are permitted to create a temporary object to hold the function parameter or result object. [...]
which is inconsistent with the next sentence:
[...] The temporary object is constructed from the function argument or return value, respectively, [...]
It seems to me that the part "to hold the function parameter or result object" is redundant and defective, perhaps we should strike it.
There also seems something wrong in [class.temporary] p3.
The current wording says:
[...] implementations are permitted to create a temporary object to hold the function parameter or result object. [...]
which is inconsistent with the next sentence:
[...] The temporary object is constructed from the function argument or return value, respectively, [...]
It seems to me that the part "to hold the function parameter or result object" is redundant and defective, perhaps we should strike it.
I think that could be fixed as part of CWG2434 (which probably needs a volunteer for drafting)
One says "function parameter or result object", the other "function argument or return value". Note parameter vs. argument.
If a parameter object is not a temporary object, what is the storage duration related to a function parameter object? (Function parameter objects may be destroyed when the function returns, or at the end of the full-expression. Does the storage outlive the point of destruction, at least in the former case?)
If a parameter object is not a temporary object, what is the storage duration related to a function parameter object? (Function parameter objects may be destroyed when the function returns, or at the end of the full-expression. Does the storage outlive the point of destruction, at least in the former case?)
In current wording, parameter objects unambiguously have automatic storage duration under [basic.stc.auto]/1 notwithstanding the special rules in [expr.call]/6 about when they're destroyed.
I don't think we ever explicitly say when storage lifetime ends, except in the case of dynamic storage duration, but that's a different issue.
I don't think we ever explicitly say when storage lifetime ends,
We do:
[basic.stc.auto] p1 says:
The storage for these entities lasts until the block in which they are created exits.
Since parameter objects are created in the caller, that means their storage stays around until the end of the block (and can't be reused by the compiler unless proven otherwise).
[basic.stc.auto] p1 says:
The storage for these entities lasts until the block in which they are created exits.
Since parameter objects are created in the caller, that means their storage stays around until the end of the block (and can't be reused by the compiler unless proven otherwise).
That seems unlikely to be what we actually want, right? If a block contains two separate statements that each contain a function call, it seems obvious that the second function call can reuse the space in which the first function call allocated parameter objects.
I think what we want is for the storage lifetime for parameter objects to parallel the (implementation-defined choice of) lifetime, and [stmt.dcl] probably needs to be amended too.
That seems unlikely to be what we actually want, right?
Right. That means we have three issue with "storage duration", at least in the sense of "how long does the storage exist":
CWG2849 for the original issue.
If we decide we also want to tackle the wider "storage duration of function parameters" issue then here's a first attempt at some drafting.
Edit [basic.stc.auto]/1, combining it with the note in paragraph 2. (The "end of duration of storage" wording is borrowed from [basic.stc.general].)
Variables that belong to a block or parameter scope and are not explicitly declared
static
,thread_local
, orextern
have automatic storage duration. The storage for ~these entities~ such block variables lasts until the block in which they are created exits.
[ Note 1: These block variables are initialized and destroyed as described in [stmt.dcl]. —end note ] It is implementation-defined whether the duration of storage for a parameter ends when the function in which it is defined returns or at the end of the full-expression containing the call.
[ Note 2: Parameters are initialized and destroyed as described in [expr.call]. — end note ]
Edit [class.temporary]/8:
~The destruction of a temporary whose lifetime is not extended beyond the full-expression in which it was created is sequenced before the destruction of every temporary which is constructed earlier in the same full-expression.~ Let
x
andy
each be either a temporary object whose lifetime is not extended, or a function parameter. If the lifetimes ofx
andy
end at the end of the same full-expression, and the initialization ofx
is sequenced before that ofy
, then the destruction ofy
is sequenced before that ofx
. If the lifetime of two or more temporaries with lifetimes extending beyond the full-expressions in which they were created ends at the same point, these temporaries are destroyed at that point in the reverse order of the completion of their construction. [...]
Edit [expr.call]/6:
[...] ~It is implementation-defined whether the lifetime of a parameter ends when the function in which it is defined returns or at the end of the enclosing full-expression.~ When the duration of storage for one or more parameters ends ([basic.stc.auto]), all such parameters are destroyed in the reverse order of their construction. The initialization and destruction of each parameter occurs within the context of the full-expression ([intro.execution]) where the function call appears.
Edit [stmt.dcl]/2 to clarify that it applies only to block variables, since that seems to be the original intent anyway (e.g., we don't guarantee that function parameters are initialized in declaration order). Since function parameters don't have a declaration-statement, it would make more sense to describe them elsewhere.
A block variable with automatic storage duration ([basic.stc.auto]) is active everywhere in the scope to which it belongs after its init-declarator. Upon each transfer of control (including sequential execution of statements) within a function from point P to point Q, all block variables with automatic storage duration that are active at P and not at Q are destroyed in the reverse order of their construction. Then, all block variables with automatic storage duration that are active at Q but not at P are initialized in declaration order; unless all such variables have vacuous initialization ([basic.life]), the transfer of control shall not be a jump. When a declaration-statement is executed, P and Q are the points immediately before and after it; when a function returns, Q is after its body.
I updated the drafting above based on feedback from today's telecon.
CWG2850 for the storage duration of function parameter objects
Full name of submitter: Brian Bi
Reference (section label): [class.temporary]
Issue description: From Stack Overflow.
The wording "temporary object other than a function parameter object" does not make sense since a function parameter object is never a temporary object ([class.temporary]/1). In the example that was added during CWG deliberation in Kona (2022) to illustrate this exception, the parameter of
f2
is not a temporary in the first place, so there is no exception. Note that in the special case where the implementation creates an extra temporary under [class.temporary]/3, that temporary is not the same as the function parameter object, and its lifetime is unobservable.Suggested resolution:
Strike "other than a function parameter object" from [class.temporary]/7.
Insert a new note before Example 2 in [stmt.ranged]: