6.5 Return Statements

15
Jan

6.5 Return Statements

1/2 A simple_return_statement or extended_return_statement (collectively called a return statement) {return statement} is used to complete the execution of the innermost enclosing subprogram_body, entry_body, or accept_statement.

Syntax

2/2 simple_return_statement ::= return [expression];

2.1/2 extended_return_statement ::= 
    return defining_identifier : [aliased] return_subtype_indication [:= expression] [do
        handled_sequence_of_statements
    end return];

2.2/2 return_subtype_indication ::= subtype_indication | access_definition

Name Resolution Rules

3/2 {result subtype (of a function)} The result subtype of a function is the subtype denoted by the subtype_mark, or defined by the access_definition, after the reserved word return in the profile of the function.{expected type (expression of simple_return_statement) [partial]} The expected type for the expression, if any, of a simple_return_statement is the result type of the corresponding function. {expected type (expression of extended_return_statement) [partial]} The expected type for the expression of an extended_return_statement is that of the return_subtype_indication.

3.a To be honest: The same applies to generic functions. 

Legality Rules

4/2 {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.

5/2 A function body shall contain at least one return statement that applies to the function body, unless the function contains code_statements. A simple_return_statement shall include an expression if and only if it applies to a function body. An extended_return_statement shall apply to a function body.

5.a/2 Reason: 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.

5.b/2 Ramification: A return statement can apply to an extended_return_statement, so a simple_return_statement without an expression can be given in one. However, neither simple_return_statement with an expression nor an extended_return_statement can be given inside an extended_return_statement, as they must apply (directly) to a function body. 

5.1/2 For an extended_return_statement that applies to a function body:

  • 5.2/2 If the result subtype of the function is defined by a subtype_mark, the return_subtype_indication shall be a subtype_indication. The type of the subtype_indication shall be the result type of the function. If the result subtype of the function is constrained, then the subtype defined by the subtype_indication shall also be constrained and shall statically match this result subtype. {statically matching (required) [partial]} If the result subtype of the function is unconstrained, then the subtype defined by the subtype_indication shall be a definite subtype, or there shall be an expression.
  • 5.3/2 If the result subtype of the function is defined by an access_definition, the return_subtype_indication shall be an access_definition. The subtype defined by the access_definition shall statically match the result subtype of the function. The accessibility level of this anonymous access subtype is that of the result subtype.
5.4/2 For any return statement that applies to a function body:
  • 5.5/2 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. 
5.c/2 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). 
  • 5.6/2 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.

5.d/2 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

5.7/2 {return object (extended_return_statement) [partial]} Within an extended_return_statement, the return object is declared with the given defining_identifier, with the nominal subtype defined by the return_subtype_indication.

Dynamic Semantics

5.8/2 {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]} 

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/2 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), the return object is finalized prior to leaving the return statement.

6/2 {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]}

6.a Ramification: The conversion might raise Constraint_Error — (see §4.6). 

7/2 [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).]

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/2 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)}

8.a/2 Ramification:  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: 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/2 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.

21/2 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)}

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. 

22/2 For the execution of an extended_return_statement, the handled_sequence_of_statements is executed. Within this handled_sequence_of_statements, the execution of a simple_return_statement that applies to the extended_return_statement causes a transfer of control that completes the extended_return_statement. Upon completion of a return statement that applies to a callable construct, a transfer of control is performed which completes the execution of the callable construct, and returns to the caller.

23/2 In the case of a function, the function_call denotes a constant view of the return object. 

Implementation Permissions

24/2 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.

24.a/2 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. 

24.b/2 Ramification: 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. 

Examples

25 Examples of return statements: 

26/2

return;                         -- in a procedure body, entry_body,
                                -- accept_statement, or extended_return_statement

27

return Key_Value(Last_Index);   -- in a function body

28/2

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 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 We have clarified that a return statement applies to a callable construct, not to a callable entity.

28.f/2 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

28.g/2 {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.

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 {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

28.j/2 The wording was updated to support anonymous access return subtypes.

28.k/2 The term “return expression” was dropped because reviewers found it confusing when applied to the default expression of an extended_return_statement.

28.l/2 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 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.

28.n/2 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).