!standard 4.5.9(10/5)                                    23-03-17  AI22-0017-1/01

!class ramification 23-03-17

!status work item 21-11-12

!status received 21-04-08

!priority Low

!difficulty Easy

!subject Objects declared in declare expressions may be surprisingly long-lived


Clarify that an object declared within a declare_expression may outlive the evaluation of the expression. This may be surprising for folks who incorrectly think that a declare expression is equivalent to declaring a function and then calling it.


In some (most?) cases, the evaluation of a declare expression is not a master. In such cases, the lifetimes of objects declared within the declare expression may extend well beyond the completion of the evaluation of the declare expression. This seems to be inconsistent with what many users expect, so an AARM note clarifying this point is added.


This is just a clarification. No changes are being made.


Add after 4.5.9(10/5) [at the end of the Dynamic semantics section]

AARM Ramification:

If the evaluation of a declare_expression is not a master (see 7.6.1) then objects declared therein may still exist (and have pending finalization) after the evaluation of the declare_expression has completed. This can also be the case for other objects, such as those created by the evaluation of aggregates or function calls.


The original motivation for this AI was the requirement that objects created in an iteration last until the end of that iteration. Eventually, it was recognized that that was a problem that existed in many existing cases and was not specific to declare_expressions. It was spun out into AI22-0040-1 and addressed for all expressions.

After some false starts, we realized that the model for Ada has always been that there is a single master for an (entire) expression. This means that temporaries created for inner function calls have to persist until the expression as a whole has been evaluated. The declare expression case is no different, and should be handled consistently.

We note that AI22-0040-1 makes some exceptions to this general rule, but the general rule remains. This rule was adopted in part because creating/destroying a master probably has a runtime cost in any case where it is possible that finalization (or tasks waiting!) is needed. And there are many cases where it is not possible to determine that finalization is not needed. If every expression construct was a potential master, a lot of additional and unnecessary overhead could be created. Moreover, changing the general rule could have a significant effect on existing implementations (which do not have to create masters in the middle of expressions).


In the following example, the finalization of X takes place after, not before, the call to the procedure Proc:

  Proc (Boolean'(declare X : constant Some_Controlled_Type := ...;
          begin True));

!ACATS test

No ACATS test is needed for a ramification, although it would be possible to write one based on the example given above.