6.5 Return Statements
1/2
Syntax
2/2
2.1/3
2.2/2
Name Resolution Rules
3/2
3.a
To be honest: The same applies to generic
functions.
Legality Rules
4/2
5/3
5.a/2
Reason: {
AI95-00318-02}
The requirement that a function body has to have at least one
return
statement return_statement
is a “helpful” restriction. There
has was
been some interest in lifting this restriction, or allowing a raise statement
to substitute for the
return statement return_statement.
However, there was enough interest in leaving it as is that we decided
not to change it.
5.b/2
5.1/2
5.2/3
5.3/2
5.4/3
{
AI05-0032-1}
If the result subtype of the function is class-wide,
the accessibility level of the type of the subtype defined by the return_subtype_indication
shall not be statically deeper than that of the master that elaborated
the function body.
5.b.1/3
5.5/3
5.6/3
{
AI95-00318-02}
{
AI05-0188-1}
[If the result subtype of the function is limited,
then the expression
of the return statement (if any) shall meet
the restrictions described in 7.5 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.]
5.c/3
This paragraph
was deleted.Discussion: {
AI05-0188-1}
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).
5.7/3
{
AI95-00416-01}
{
AI05-0032-1}
{
AI05-0051-1}
If the result subtype of the function is class-wide,
the accessibility level of the type of the expression
(if any) 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.
5.d/3
5.8/3
5.d.1/3
Discussion: We
use the type used by the return statement rather than from the function
return type since we want to check whenever the return object has access
discriminants, even if the function return type doesn't have any (mostly
for a class-wide type).
Static Semantics
5.9/3
Dynamic Semantics
5.10/3
{
AI95-00318-02}
{
AI95-00416-01}
{
AI05-0032-1}
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);
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. A check is made that the value of the return object belongs to the function
result subtype. Constraint_Error is raised if this check fails.
5.e/2
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).
5.f/3
{
AI05-0005-1}
If the return statement is left without resulting
in a return (for example, due to an exception propagated from the expression
or the handled_sequence_of_statements,
or a goto out of the handled_sequence_of_statements),
if the return
object has been created, it is
finalized prior to leaving the return statement. If it has not been created when the return statement is left, it is not
created or finalized.
5.g/3
{
AI05-0032-1}
Other rules ensure that the check required by this
rule cannot fail unless the function has a class-wide result subtype
where the associated specific subtype is constrained. In other cases,
either the subtypes have to match or the function's subtype is unconstrained
and needs no checking.
6/2
6.a
Ramification: The conversion might raise
Constraint_Error — (see
4.6).
7/2
{
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).] If
the result type is class-wide, then the tag of the result is the tag
of the value of the expression.
7.a/2
Proof: This is
specified by the rules in 9.2.
7.b/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.
8/3
{
AI95-00318-02}
{
AI95-00344-01}
{
AI05-0024-1}
{
AI05-0032-1}
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
type of the subtype_indication
if it is specific, or otherwise that of the
value of the expression expression.
A check is made that the master accessibility
level of the type identified by the
tag of the result includes the elaboration is
not deeper than that of the master
that elaborated the function body. If this check fails, Program_Error
is raised. :
8.a/2
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.
8.b/2
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).
8.c/3
The master
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.
8.d/3
We can't use the normal
accessibility level “deeper than” check here because we may
have “incomparable” levels if the masters belong to two different
tasks. This can happen when an accept statement calls a function declared
in the enclosing task body, and the function returns an object passed
to it from the accept statement, and this object was itself a parameter
to the accept statement.
8.1/3
{
AI05-0073-1}
If the
result subtype of the function is defined by an access_definition
designating a specific tagged type T, a check is made that the
result value is null or the tag of the object designated by the result
value identifies T. Constraint_Error is raised
if this check fails.
8.e/3
Reason: This check
is needed so that dispatching on controlling access results works for
tag-indeterminate functions. If it was not made, it would be possible
for such functions to return an access to a descendant type, meaning
the function could return an object with a tag different than the one
assumed by the dispatching rules.
Paragraphs
9 through 20 were deleted.
9/2
{
AI95-00318-02}
If it is
limited, then a check is made that the tag of the value of the return
expression identifies the result type. Constraint_Error
is raised if this check fails.
10/2
{
AI95-00318-02}
If it is nonlimited, then the tag of the result
is that of the result type.
10.a/2
Ramification: {
AI95-00318-02}
This is true even if the tag of the return expression
is different.
10.b/2
Reason: {
AI95-00318-02}
These rules ensure 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, if nonlimited, allows the caller to allocate the appropriate
amount of space to hold the value being returned (assuming there are
no discriminants).
11/2
{
AI95-00318-02}
A type is a return-by-reference
type if it is a descendant of one of the following:
12/2
13/2
14/2
{
AI95-00318-02}
a nonprivate type with the reserved word limited
in its declaration;
15/2
{
AI95-00318-02}
a composite type with a subcomponent of a return-by-reference
type;
16/2
{
AI95-00318-02}
a private type whose full type is a return-by-reference
type.
16.a/2
Ramification: The
above rules are such that there are no "Ada 83" types other
than those containing tasks that are return-by-reference. This helps
to minimize upward incompatibilities relating to return-by-reference.
17/2
{
AI95-00318-02}
If the
result type is a return-by-reference type, then a check is made that
the return expression is one of the following:
18/2
{
AI95-00318-02}
a name
that denotes an object view whose accessibility level is not deeper than
that of the master that elaborated the function body; or
18.a/2
Discussion: {
AI95-00316-01}
This rule was unnecessarily confusing, and the
parenthetical remark "(or a value with an associated object, see
6.2)" was added — and then the entire concept was deleted.
19/2
20/2
{
AI95-00318-02}
The exception Program_Error
is raised if this check fails.
20.a/2
Discussion: Compare
the definition of return-by-reference with that of by-reference.
20.b/2
The return-by-reference
types are all limited types except those that are limited only because
of a limited private type with a nonlimited untagged full type.
20.c/2
Reason: This
check can often be performed at compile time. It is defined to be a run-time
check to avoid generic contract model problems. In a future version of
the standard, we anticipate that function return of a local variable
will be illegal for all limited types, eliminating the need for the run-time
check except for dereferences of an access parameter.
21/3
{
AI95-00318-02}
{
AI95-00402-01}
{
AI95-00416-01}
{
AI05-0051-1}
If any part of the
specific type of the return object the
result subtype of a function (or
coextension thereof) has one or more unconstrained
access discriminants whose value is not constrained by the result subtype of the function,
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 return statement function,
is not deeper than the level of the master
of the call (see 3.10.2) that
of the master that elaborated the function body.
If this check fails, Program_Error is raised. For
a function with a return-by-reference result type the result is returned
by reference; that is, the function call denotes a constant view of the
object associated with the value of the return expression. For
any other function, the result is returned by copy; that is, the converted
value is assigned into an anonymous constant created at the point of
the return_statement,
and the function call denotes that object.
21.a/2
This paragraph
was deleted.Ramification: The
assignment operation does the necessary value adjustment, as described
in 7.6, “Assignment
and Finalization”. 7.6.1 describes
when the anonymous constant is finalized.
21.b/2
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.
21.c/3
Implementation Note:
{
AI05-0234-1}
The reason for saying “any part of the specific
type” is to simplify implementation. In the case of class-wide
result objects this allows the testing of a simple flag in the tagged
type descriptor that indicates whether specific type has any parts with
access discriminants. By basing the test on the type of the object rather
than the object itself, we avoid concerns about whether subcomponents
in variant parts and of arrays (which might be empty) are present.
21.d/3
Discussion: {
AI05-0234-1}
For a function with a class-wide result type, the
access values that need to be checked are determined by the tag of the
return object. In order to implement this accessibility check in the
case where the tag of the result is not known statically at the point
of the return statement, an implementation may need to somehow associate
with the tag of a specific tagged type an indication of whether the type
has unconstrained access discriminants (explicit or inherited) or has
any subcomponents with such discriminants. If an implementation is already
maintaining a statically initialized descriptor of some kind for each
specific tagged type, then an additional Boolean could be added to this
descriptor.
21.e/3
Note that the flag should
only be queried in the case where any access discriminants which the
result object might have subtypes with "bad" accessibility
levels (as determined by the rules of 3.10.2
for determining the accessibility level of the type of an access discriminant
in the expression
or return_subtype_indication
of a return statement).
21.f/3
Thus,
in a case like
21.g/3
type Global is access T'Class;
function F (Ptr : Global) return T'Class is
begin
return Ptr.all;
end F;
21.h/3
there
is no need for a run-time accessibility check. The setting of the bit
doesn't matter and there is no need to query it.
21.i/3
On
the other hand, given
21.j/3
function F return T'Class is
Local : T'Class := ... ;
begin
return Local;
end F;
21.k/3
In
this case, a check would typically be required.
21.l/3
The
need for including subcomponents in this check is illustrated by the
following example:
21.m/3
X : aliased Integer;
21.n/3
type Component_Type (Discrim : access Integer := X'Access)
is limited null record;
21.o/3
type Undiscriminated is record
Fld : Component_Type;
end record;
21.p/3
function F return Undiscriminated is
Local : aliased Integer;
begin
return X : Undiscriminated := (Fld => (Discrim => Local'Access)) do
Foo;
end return;
-- raises Program_Error after calling Foo.
end} F;
21.q/3
Ramification: {
AI05-0234-1}
In the case where the tag of the result is not
known statically at the point of the return statement and the run-time
accessibility check is needed, discriminant values and array bounds play
no role in performing this check. That is, array components are assumed
to have nonzero length and components declared within variant parts are
assumed to be present. Thus, the check may be implemented simply by testing
the aforementioned descriptor bit and conditionally raising Program_Error.
22/3
22.a/3
23/2
Implementation Permissions
24/3
{
AI95-00416-01}
{
AI05-0050-1}
For
a function call used to initialize a composite 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 or used to initialize a return object that is built in place into such
an object:,
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.
24.1/3
{
AI05-0050-1}
If the result subtype of the function is constrained,
and conversion of an object of this subtype to the subtype of the object
being initialized would raise Constraint_Error, then Constraint_Error
may be raised before calling the function.
24.2/3
{
AI05-0050-1}
If the result subtype of the function is unconstrained,
and a return statement is executed such that the return object is known
to be constrained, and conversion of the return object to the subtype
of the object being initialized would raise Constraint_Error, then Constraint_Error
may be raised at the point of the call (after abandoning the execution
of the function body).
24.a/3
Reason: {
AI95-00416-01}
{
AI05-0050-1}
Without such a permission, it would be very difficult
to implement “ built-in-place build-in-place ”
semantics. The intention is that the exception
is raised at the same point that it would have been raised without the
permission; it should not change handlers if the implementation switches
between return-by-copy and built-in-place. This means that the 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.
24.b/3
Ramification: {
AI95-00416-01}
{
AI05-0050-1}
These permissions do not apply in the case of an
extended return object with mutable discriminants. That's necessary because
in that case a return object can be created with the “wrong”
discriminants and then changed to the “right” discriminants
later (but before returning). We don't want this case raising an exception
when the canonical semantics will not do so. This
permission is allowed during the evaluation of the expression
of an extended_return_statement,
because the return_subtype_indication
may be unconstrained and the expression
then would provide the constraints.
24.c/3
{
AI05-0050-1}
It's still possible to write a program that will
raise an exception using this permission that would not in the canonical
semantics. That could happen if a return statement with the “wrong”
discriminants or bounds is abandoned (via an exception, or for an extended_return_statement,
via an exit or goto statement), and then a return statement with the
“right” discriminants or bounds is executed. The only solution
for this problem is to not have the permission at all, but this is too
unusual of a case to worry about the effects of the permission, especially
given the implementation difficulties for built-in-place objects that
this permission is intended to ease.
24.d/3
{
AI05-0050-1}
Note that the mutable-discriminant case only happens
when built-in-place initialization is optional. This means that any difficulties
associated with implementing built-in-place initialization without these
permissions can be sidestepped by not building in place.
Examples
25
Examples of return
statements:
26/2
27
return Key_Value(Last_Index); -- in a function body
28/2
{
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
28.a/2
{
AI95-00318-02}
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.
28.b
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
28.c
This clause has been moved here from chapter
5, since it has mainly to do with subprograms.
28.d
A function now creates an anonymous object.
This is necessary so that controlled types will work.
28.e/2
28.f/2
{
AI95-00318-02}
There is no need to mention generics in the rules about where a
return
statement 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”.
Inconsistencies With Ada 95
28.f.1/3
{
AI95-0416-1}
{
AI05-0005-1}
{
AI05-0050-1}
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). However, it allows raising an
Constraint_Error in some cases where
it would not be raised if the permission was not used. See
Inconsistencies With Ada 2005 for additional changes. This
case is potentially inconsistent with Ada 95, but a compiler does not
have to take advantage of these permissions for any Ada 95 code, so there
should be little practical impact.
Incompatibilities With Ada 95
28.g/2
{
AI95-00318-02}
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.
28.h/2
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
28.i/2
{
AI95-00318-02}
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
28.j/2
{
AI95-00318-02}
The wording was updated to support anonymous access
return subtypes.
28.k/2
28.l/2
{
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).
28.m/2
{
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.
Inconsistencies With Ada 2005
28.n/3
{
AI05-0050-1}
Correction: The Implementation
Permission allowing early raising of Constraint_Error was modified to
remove the most common of these cases from the permission (returning
an object with mutable discriminants, where the return object is created
with one set of discriminants and then changed to another). (The permission
was also widened to allow the early check for constrained functions when
that constraint is wrong.) However, there still is an unlikely case where
the permission would allow an exception to be raised when none would
be raised by the canonical semantics (when a return statement is abandoned).
These changes can only remove the raising of an exception (or change
the place where it is raised) compared to Ada 2005, so programs that
depend on the previous behavior should be very rare.
28.o/3
{
AI05-0051-1}
{
AI05-0234-1}
Correction: Accessibility checks for access
discriminants now depend on the master of the call rather than the point
of declaration of the function. This will result in cases that used to
raise Program_Error now running without raising any exception. This is
technically inconsistent with Ada 2005 (as defined by Amendment 1), but
it is unlikely that any real code depends on the raising of this exception.
28.p/3
{
AI05-0073-1}
Correction: Added a tag check for functions
returning anonymous access-to-tagged types, so that dispatching of tag-indeterminate
function works as expected. This is technically inconsistent with Ada
2005 (as defined by Amendment 1), but as the feature in question was
newly added to Ada 2005, there should be little code that depends on
the behavior that now raises an exception.
Incompatibilities With Ada 2005
28.q/3
{
AI05-0053-1}
Correction: Eliminated
the aliased keyword from the syntax of extended_return_statements,
as this would provide a way to get an aliased view of an object that
is not necessarily aliased. This is technically incompatible, but since
the feature was added in Ada 2005 and not widely implemented, it is very
unlikely that it appears in existing programs.
28.r/3
{
AI05-0103-1}
Correction: Added wording to require static
matching for unconstrained access types in extended return statements.
This disallows adding or omitting null exclusions, and adding access
constraints, in the declaration of the return object. While this is incompatible,
the incompatible cases in question are either useless (access constraints
– the constraint can be given on an allocator
if necessary, and still must be given there even if given on the return
object) or wrong (null exclusions – null could be returned from
a function declared to be null excluding), so we expect them to be extremely
rare in practice.
Extensions to Ada 2005
28.s/3
28.t/3
{
AI05-0032-1}
Added wording to allow the return_subtype_indication
to have a specific type if the return subtype of the function is class-wide.
Specifying the (specific) type of the return object is awkward without
this change, and this is consistent with the way allocators
work.
Wording Changes from Ada 2005
28.u/3
{
AI05-0024-1}
Correction: Corrected the master check for
tags since the masters may be for different tasks and thus incomparable.
28.v/3
{
AI05-0058-1}
Correction: Corrected the wording defining
returns for extended_return_statements,
since leaving by an exit or goto is considered “normal” completion
of the statement.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe