6.5 Return Statements
Syntax
Name Resolution Rules
To be honest: The same applies to generic
functions.
Legality Rules
{
AI95-00318-02}
{apply (to a callable construct by a
return statement)} A return statement
shall be within a callable construct, and it
applies to the innermost
callable construct or
extended_return_statement
that contains it. A return statement shall not be within a body that
is within the construct to which the return statement applies.
Reason: {
AI95-00318-02}
The requirement that a function body has to have at least one return
statement is a “helpful” restriction. There has been some
interest in lifting this restriction, or allowing a raise statement to
substitute for the return statement. However, there was enough interest
in leaving it as is that we decided not to change it.
{
AI95-00318-02}
For any return statement that applies to a function body:
{
AI95-00318-02}
If the result subtype of the function is limited, then the
expression
of the return statement (if any) shall be an
aggregate,
a function call (or equivalent use of an operator), or a
qualified_expression
or parenthesized expression whose operand is one of these.
Discussion: In other words, if limited,
the
expression
must produce a “new” object, rather than being the name of
a preexisting object (which would imply copying).
{
AI95-00416-01}
If the result subtype of the function is class-wide, the accessibility
level of the type of the
expression
of the return statement shall not be statically deeper than that of the
master that elaborated the function body. If the result subtype has one
or more unconstrained access discriminants, the accessibility level of
the anonymous access type of each access discriminant, as determined
by the
expression
of the
simple_return_statement
or the
return_subtype_indication,
shall not be statically deeper than that of the master that elaborated
the function body.
Discussion: We know that if the result
type is class wide, then there must be an
expression
of the return statement. Similarly, if the result subtype is unconstrained,
then either the
return_subtype_indication
(if any) is constrained, or there must be an
expression.
Static Semantics
Dynamic Semantics
{
AI95-00318-02}
{
AI95-00416-01}
{execution (extended_return_statement)
[partial]} For the execution of an
extended_return_statement,
the
subtype_indication
or
access_definition
is elaborated. This creates the nominal subtype of the return object.
If there is an
expression,
it is evaluated and converted to the nominal subtype (which might raise
Constraint_Error — see
4.6{implicit
subtype conversion (function return) [partial]} );
the return object is created and the converted value is assigned to the
return object. Otherwise, the return object is created and initialized
by default as for a stand-alone object of its nominal subtype (see
3.3.1).
If the nominal subtype is indefinite, the return object is constrained
by its initial value.
{creation (of a
return object) [partial]}
Ramification: If the result type is controlled
or has a controlled part, appropriate calls on Initialize or Adjust are
performed prior to executing the
handled_sequence_of_statements,
except when the initial expression is an
aggregate
(which requires build-in-place with no call on Adjust).
{
AI95-00318-02}
{execution (simple_return_statement)
[partial]} For the execution of a
simple_return_statement,
the
expression
(if any) is first evaluated, converted to the result subtype, and then
is assigned to the anonymous
return object.
{return
object (simple_return_statement) [partial]} {implicit
subtype conversion (function return) [partial]}
Ramification: The conversion might raise
Constraint_Error — (see
4.6).
{
AI95-00318-02}
{
AI95-00416-01}
[If the return object has any parts that are tasks, the activation of
those tasks does not occur until after the function returns (see
9.2).]
Proof: This is specified by the rules
in
9.2.
Reason: Only the caller can know when
task activations should take place, as it depends on the context of the
call. If the function is being used to initialize the component of some
larger object, then that entire object must be initialized before any
task activations. Even after the outer object is fully initialized, task
activations are still postponed until the begin at the end of
the declarative part if the function is being used to initialize part
of a declared object.
{
AI95-00318-02}
{
AI95-00344-01}
If the result type of a function is a specific tagged type, the tag of
the return object is that of the result type. If the result type is class-wide,
the tag of the return object is that of the value of the expression.
A check is made that the accessibility level of the type identified by
the tag of the result is not deeper than that of the master that elaborated
the function body. If this check fails, Program_Error is raised.
{Program_Error
(raised by failure of run-time check)} {Accessibility_Check
[partial]} {check,
language-defined (Accessibility_Check)}
Ramification: {
AI95-00318-02}
The first sentence is true even if the tag of the
expression
is different, which could happen if the
expression
were a view conversion or a dereference of an access value. Note that
for a limited type, because of the restriction to
aggregates
and function calls (and no conversions), the tag will already match.
Reason: {
AI95-00318-02}
The first rule ensures that a function whose result type is a specific
tagged type always returns an object whose tag is that of the result
type. This is important for dispatching on controlling result, and allows
the caller to allocate the appropriate amount of space to hold the value
being returned (assuming there are no discriminants).
The check prevents the returned object from
outliving its type. Note that this check cannot fail for a specific tagged
type, as the tag represents the function's type, which necessarily must
be declared outside of the function.
Paragraphs 9 through
20 were deleted.
{
AI95-00318-02}
{
AI95-00402-01}
{
AI95-00416-01}
If the result subtype of a function has one or more unconstrained access
discriminants, a check is made that the accessibility level of the anonymous
access type of each access discriminant, as determined by the
expression
or the
return_subtype_indication
of the function, is not deeper than that of the master that elaborated
the function body. If this check fails, Program_Error is raised.
{Program_Error
(raised by failure of run-time check)} {Accessibility_Check
[partial]} {check,
language-defined (Accessibility_Check)}
This paragraph
was deleted.
Reason: The check prevents the returned
object (for a nonlimited type) from outliving the object designated by
one of its discriminants. The check is made on the values of the discriminants,
which may come from the
return_subtype_indication
(if constrained), or the
expression,
but it is never necessary to check both.
Implementation Permissions
{
AI95-00416-01}
If the result subtype of a function is unconstrained, and a call on the
function is used to provide the initial value of an object with a constrained
nominal subtype, Constraint_Error may be raised at the point of the call
(after abandoning the execution of the function body) if, while elaborating
the
return_subtype_indication
or evaluating the
expression
of a return statement that applies to the function body, it is determined
that the value of the result will violate the constraint of the subtype
of this object.
Reason: Without such a permission, it
would be very difficult to implement “build-in-place” semantics.
Such an exception is not handleable within the function, because in the
return-by-copy case, the constraint check to verify that the result satisfies
the constraints of the object being initialized happens after the function
returns, and we want the semantics to change as little as possible when
switching between return-by-copy and build-in-place. This implies further
that upon detecting such a situation, the implementation may need to
simulate a goto to a point outside any local exception handlers prior
to raising the exception.
Examples
Examples of return
statements:
return Key_Value(Last_Index); -- in a function body
{
AI95-00318-02}
return Node : Cell
do --
in a function body, see 3.10.1 for Cell
Node.Value := Result;
Node.Succ := Next_Node;
end return;
Incompatibilities With Ada 83
{
AI95-00318-02}
{
incompatibilities with Ada 83}
In Ada 95,
if the result type of a function has a part that is a task, then an attempt
to return a local variable will raise Program_Error. This is illegal
in Ada 2005, see below. In Ada 83, if a function returns a local variable
containing a task, execution is erroneous according to AI83-00867. However,
there are other situations where functions that return tasks (or that
return a variant record only one of whose variants includes a task) are
correct in Ada 83 but will raise Program_Error according to the new rules.
The rule change was made because there will
be more types (protected types, limited controlled types) in Ada 95 for
which it will be meaningless to return a local variable, and making all
of these erroneous is unacceptable. The current rule was felt to be the
simplest that kept upward incompatibilities to situations involving returning
tasks, which are quite rare.
Wording Changes from Ada 83
This clause has been moved here from chapter
5, since it has mainly to do with subprograms.
A function now creates an anonymous object.
This is necessary so that controlled types will work.
{
AI95-00318-02}
We have clarified that a return statement applies to a callable construct,
not to a callable entity.
{
AI95-00318-02}
There is no need to mention generics in the rules about where a return
statement can appear and what it applies to; the phrase “body of
a subprogram or generic subprogram” is syntactic, and refers exactly
to “
subprogram_body”.
Incompatibilities With Ada 95
{
AI95-00318-02}
{
incompatibilities with Ada 95}
The entire
business about return-by-reference types has been dropped. Instead, the
expression
of a return statement of a limited type can only be an
aggregate
or
function_call
(see
7.5). This means that returning a global
object or
type_conversion,
legal in Ada 95, is now illegal. Such functions can be converted to use
anonymous access return types by adding
access in the function
definition and return statement, adding .
all in uses, and adding
aliased in the object declarations. This has the advantage of
making the reference return semantics much clearer to the casual reader.
We changed these rules so that functions, combined
with the new rules for limited types (
7.5),
can be used as build-in-place constructors for limited types. This reduces
the differences between limited and nonlimited types, which will make
limited types useful in more circumstances.
Extensions to Ada 95
{
AI95-00318-02}
{
extensions to Ada 95}
The
extended_return_statement
is new. This provides a name for the object being returned, which reduces
the copying needed to return complex objects (including no copying at
all for limited objects). It also allows component-by-component construction
of the return object.
Wording Changes from Ada 95
{
AI95-00318-02}
The wording was updated to support anonymous access return subtypes.
{
AI95-00344-01}
{
AI95-00416-01}
Added accessibility checks to class-wide return statements. These checks
could not fail in Ada 95 (as all of the types had to be declared at the
same level, so the tagged type would necessarily have been at the same
level as the type of the object).
{
AI95-00402-01}
{
AI95-00416-01}
Added accessibility checks to return statements for types with access
discriminants. Since such types have to be limited in Ada 95, the
expression
of a return statement would have been illegal in order for this check
to fail.
{
AI95-00416-01}
Added an Implementation Permission allowing early raising of Constraint_Error
if the result cannot fit in the ultimate object. This gives implementations
more flexibility to do built-in-place returns, and is essential for limited
types (which cannot be built in a temporary).