11.4 Exception Handling
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
[When an exception occurrence is raised, normal program execution is abandoned and control is transferred to an applicable exception_handler
, if any. To handle an exception occurrence is to respond to the exceptional event. To propagate an exception occurrence is to raise it again in another context; that is, to fail to respond to the exceptional event in the present context.]
task_body
).Dynamic Semantics
2Within a given task, if the execution of construct a is defined by this document to consist (in part) of the execution of construct b, then while b is executing, the execution of a is said to dynamically enclose the execution of b. The innermost dynamically enclosing execution of a given execution is the dynamically enclosing execution that started most recently.
if_statement
dynamically encloses the evaluation of the condition
after the if (during that evaluation). (Recall that “execution” includes both “elaboration” and “evaluation”, as well as other executions.) The evaluation of a function call dynamically encloses the execution of the sequence_of_statements
of the function body
(during that execution). Note that, due to recursion, several simultaneous executions of the same construct can be occurring at once during the execution of a particular task.if_statement
is currently executing the sequence_of_statements
after then, then the evaluation of the condition
is no longer dynamically enclosed by the execution of the if_statement
(or anything else). When an exception occurrence is raised by the execution of a given construct, the rest of the execution of that construct is abandoned; that is, any portions of the execution that have not yet taken place are not performed. The construct is first completed, and then left, as explained in 7.6.1. Then:
- If the construct is a
task_body
, the exception does not propagate further;
task_body
, there is no dynamically enclosing execution, so the exception does not propagate any further. If the exception occurred during the activation of the task, then the activator raises Tasking_Error, as explained in 9.2, “Task Execution - Task Activation”, but we don't define that as propagation; it's a special rule. Otherwise (the exception occurred during the execution of the handled_sequence_of_statements
of the task), the task silently disappears. Thus, abnormal termination of tasks is not always considered to be an error. - If the construct is the
sequence_of_statements
of ahandled_sequence_of_statements
that has a handler with a choice covering the exception, the occurrence is handled by that handler; 6 - Otherwise, the occurrence is propagated to the innermost dynamically enclosing execution, which means that the occurrence is raised again in that context.
When an occurrence is handled by a given handler, the choice_parameter_specification
, if any, is first elaborated, which creates the choice parameter and initializes it to the occurrence. Then, the sequence_of_statements
of the handler is executed; this execution replaces the abandoned portion of the execution of the sequence_of_statements
.
declarative_part
of a body are not handled by the handlers of the handled_sequence_of_statements
of that body. 11.4.1 The Package Exceptions
Static Semantics
1The following language-defined library package exists:
with Ada.Streams;
package Ada.Exceptions
with Preelaborate, Nonblocking, Global => in out synchronized is
type Exception_Id is private
with Preelaborable_Initialization ;
Null_Id : constant Exception_Id;
function Exception_Name(Id : Exception_Id) return String;
function Wide_Exception_Name(Id : Exception_Id) return Wide_String;
function Wide_Wide_Exception_Name(Id : Exception_Id)
return Wide_Wide_String;
3/5type Exception_Occurrence is limited private
with Preelaborable_Initialization ;
type Exception_Occurrence_Access is access all Exception_Occurrence;
Null_Occurrence : constant Exception_Occurrence;
4/3procedure Raise_Exception(E : in Exception_Id;
Message : in String := "")
with No_Return;
function Exception_Message(X : Exception_Occurrence) return String;
procedure Reraise_Occurrence(X : in Exception_Occurrence);
5/2function Exception_Identity(X : Exception_Occurrence)
return Exception_Id;
function Exception_Name(X : Exception_Occurrence) return String;
-- Same as Exception_Name(Exception_Identity(X)).
function Wide_Exception_Name(X : Exception_Occurrence)
return Wide_String;
-- Same as Wide_Exception_Name(Exception_Identity(X)).
function Wide_Wide_Exception_Name(X : Exception_Occurrence)
return Wide_Wide_String;
-- Same as Wide_Wide_Exception_Name(Exception_Identity(X)).
function Exception_Information(X : Exception_Occurrence) return String;
6/2procedure Save_Occurrence(Target : out Exception_Occurrence;
Source : in Exception_Occurrence);
function Save_Occurrence(Source : Exception_Occurrence)
return Exception_Occurrence_Access;
6.1/2procedure Read_Exception_Occurrence
(Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out Exception_Occurrence);
procedure Write_Exception_Occurrence
(Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in Exception_Occurrence);
6.2/2for Exception_Occurrence'Read use Read_Exception_Occurrence;
for Exception_Occurrence'Write use Write_Exception_Occurrence;
6.3/2private
... -- not specified by the language
end Ada.Exceptions;
7Each distinct exception is represented by a distinct value of type Exception_Id. Null_Id does not represent any exception, and is the default initial value of type Exception_Id. Each occurrence of an exception is represented by a value of type Exception_Occurrence. Null_Occurrence does not represent any exception occurrence, and is the default initial value of type Exception_Occurrence.
For a prefix
E that denotes an exception, the following attribute is defined:
E'Identity
- E'Identity returns the unique identity of the exception. The type of this attribute is Exception_Id.
Raise_Exception raises a new occurrence of the identified exception.
Exception_Message returns the message associated with the given Exception_Occurrence. For an occurrence raised by a call to Raise_Exception, the message is the Message parameter passed to Raise_Exception. For the occurrence raised by a raise_statement
or raise_expression
with an exception_name
and a string_expression
or string_simple_expression
, the message is the string_expression
or string_simple_expression
. For the occurrence raised by a raise_statement
or raise_expression
with an exception_name
but without a string_expression
or string_simple_expression
, the message is a string giving implementation-defined information about the exception occurrence. For an occurrence originally raised in some other manner (including by the failure of a language-defined check), the message is an unspecified string. In all cases, Exception_Message returns a string with lower bound 1.
raise_statement
: raise E;
Raise_Exception(E'Identity, Message => implementation-defined-string);
raise E with "some information";
Raise_Exception(E'Identity, Message => "some information");
Reraise_Occurrence reraises the specified exception occurrence.
when others =>
Cleanup;
raise;
when X : others =>
Cleanup;
Reraise_Occurrence(X);
Exception_Identity returns the identity of the exception of the occurrence.
The Wide_Wide_Exception_Name functions return the full expanded name of the exception, in upper case, starting with a root library unit. For an exception declared immediately within package Standard, the defining_identifier
is returned. The result is implementation defined if the exception is declared within an unnamed block_statement
.
block_statement
.The Exception_Name functions (respectively, Wide_Exception_Name) return the same sequence of graphic characters as that defined for Wide_Wide_Exception_Name, if all the graphic characters are defined in Character (respectively, Wide_Character); otherwise, the sequence of characters is implementation defined, but no shorter than that returned by Wide_Wide_Exception_Name for the same value of the argument.
The string returned by the Exception_Name, Wide_Exception_Name, and Wide_Wide_Exception_Name functions has lower bound 1.
Exception_Information returns implementation-defined information about the exception occurrence. The returned string has lower bound 1.
Reraise_Occurrence has no effect in the case of Null_Occurrence. Raise_Exception and Exception_Name raise Constraint_Error for a Null_Id. Exception_Message, Exception_Name, and Exception_Information raise Constraint_Error for a Null_Occurrence. Exception_Identity applied to Null_Occurrence returns Null_Id.
The Save_Occurrence procedure copies the Source to the Target. The Save_Occurrence function uses an allocator
of type Exception_Occurrence_Access to create a new object, copies the Source to this new object, and returns an access value designating this new object; [the result may be deallocated using an instance of Unchecked_Deallocation.]
Write_Exception_Occurrence writes a representation of an exception occurrence to a stream; Read_Exception_Occurrence reconstructs an exception occurrence from a stream (including one written in a different partition).
Paragraph 16 was deleted.
Implementation Permissions
17An implementation of Exception_Name in a space-constrained environment may return the defining_identifier
instead of the full expanded name.
The string returned by Exception_Message may be truncated (to no less than 200 characters) by the Save_Occurrence procedure [(not the function)], the Reraise_Occurrence procedure, and the re-raise statement.
Implementation Advice
19Exception_Message (by default) and Exception_Information should produce information useful for debugging. Exception_Message should be short (about one line), whereas Exception_Information can be long. Exception_Message should not include the Exception_Name. Exception_Information should include both the Exception_Name and the Exception_Message.
type Exception_Occurrence(Message_Length : Natural := 200) is
limited record
Id : Exception_Id;
Message : String(1..Message_Length);
end record;
Temp : Exception_Occurrence(10); -- for a 10-character message
type Exception_Occurrence_Kind is (Normal, As_Choice_Param);
19.ptype Exception_Occurrence(Kind : Exception_Occurrence_Kind := Normal) is
limited record
case Kind is
when Normal =>
... -- space for 200 characters
when As_Choice_Param =>
... -- pointer to heap string
end case;
end record;
procedure Reraise_Occurrence(X : in Exception_Occurrence) is
begin
Raise_Exception(Identity(X), Exception_Message(X));
end Reraise_Occurrence;
Extensions to Ada 83
Inconsistencies With Ada 95
Incompatibilities With Ada 95
use_clause
, and an entity E with the same defining_identifier
as a new entity in Exceptions is defined in a package that is also referenced in a use_clause
, the entity E may no longer be use-visible, resulting in errors. This should be rare and is easily fixed if it does occur. Extensions to Ada 95
Wording Changes from Ada 95
raise_statement
as well as a call of Raise_Exception.Wording Changes from Ada 2005
11.4.2 Pragmas Assert and Assertion_Policy
1/3Pragma Assert is used to assert the truth of a boolean expression at a point within a sequence of declarations or statements.
Assert pragmas, subtype predicates (see 3.2.4), preconditions and postconditions (see 6.1.1), type invariants (see 7.3.2), and default initial conditions (see 7.3.3) are collectively referred to as assertions; their boolean expressions are referred to as assertion expressions.
Pragma Assertion_Policy is used to control whether assertions are to be ignored by the implementation, checked at run time, or handled in some implementation-defined manner.
Syntax
2/2The form of a pragma
Assert is as follows:
pragma Assert([Check =>] boolean_expression
[, [Message =>] string_expression
]);
A pragma
Assert is allowed at the place where a declarative_item
or a statement
is allowed.
The form of a pragma
Assertion_Policy is as follows:
pragma Assertion_Policy(policy_identifier
);
pragma Assertion_Policy(
assertion_aspect_mark
=> policy_identifier
{, assertion_aspect_mark
=> policy_identifier
});
A pragma
Assertion_Policy is allowed only immediately within a declarative_part
, immediately within a package_specification
, or as a configuration pragma.
Name Resolution Rules
8/2The expected type for the boolean_expression
of a pragma
Assert is any boolean type. The expected type for the string_expression
of a pragma
Assert is type String.
if_statement
s and other conditionals; we only allow String for the message in order to match raise_statement
s. Legality Rules
9/5The assertion_aspect_mark
of a pragma
Assertion_Policy shall identify an assertion aspect, namely one of Assert, Static_Predicate, Dynamic_Predicate, Pre, Pre'Class, Post, Post'Class, Type_Invariant, Type_Invariant'Class, Default_Initial_Condition, or some implementation-defined (assertion) aspect_mark
. The policy_identifier
shall be either Check, Ignore, or some implementation-defined identifier
.
identifier
s and assertion_aspect_mark
s allowed in a pragma
Assertion_Policy.Static Semantics
10/3A pragma
Assertion_Policy determines for each assertion aspect named in the pragma_argument_association
s whether assertions of the given aspect are to be enforced by a runtime check. The policy_identifier
Check requires that assertion expressions of the given aspect be checked that they evaluate to True at the points specified for the given aspect; the policy_identifier
Ignore requires that the assertion expression not be evaluated at these points, and the runtime checks not be performed. [Note that for subtype predicate aspects (see 3.2.4), even when the applicable Assertion_Policy is Ignore, the predicate will still be evaluated as part of membership tests and Valid attribute_reference
s, and if static, will still have an effect on loop iteration over the subtype, and the selection of case_statement_alternative
s and variant
s.]
If no assertion_aspect_mark
s are specified in the pragma, the specified policy applies to all assertion aspects.
A pragma
Assertion_Policy applies to the named assertion aspects in a specific region, and applies to all assertion expressions associated with those aspects specified in that region. A pragma
Assertion_Policy given in a declarative_part
or immediately within a package_specification
applies from the place of the pragma to the end of the innermost enclosing declarative region. The region for a pragma
Assertion_Policy given as a configuration pragma is the declarative region for the entire compilation unit (or units) to which it applies.
If a pragma
Assertion_Policy applies to a generic_instantiation
, then the pragma
Assertion_Policy applies to the entire instance.
If multiple Assertion_Policy pragmas apply to a given construct for a given assertion aspect, the assertion policy is determined by the one in the innermost enclosing region of a pragma
Assertion_Policy specifying a policy for the assertion aspect. If no such Assertion_Policy pragma exists, the policy is implementation defined.
The following language-defined library package exists:
package Ada.Assertions
with Pure is
13/2Assertion_Error : exception;
14/2procedure Assert(Check : in Boolean);
procedure Assert(Check : in Boolean; Message : in String);
15/2end Ada.Assertions;
16/3A compilation unit containing a check for an assertion (including a pragma
Assert) has a semantic dependence on the Assertions library unit.
This paragraph was deleted.
Dynamic Semantics
18/3If performing checks is required by the Assert assertion policy in effect at the place of a pragma
Assert, the elaboration of the pragma consists of evaluating the boolean expression, and if the result is False, evaluating the Message argument, if any, and raising the exception Assertions.Assertion_Error, with a message if the Message argument is provided.
Calling the procedure Assertions.Assert without a Message parameter is equivalent to:
if Check = False then
raise Ada.Assertions.Assertion_Error;
end if;
Calling the procedure Assertions.Assert with a Message parameter is equivalent to:
if Check = False then
raise Ada.Assertions.Assertion_Error with Message;
end if;
The procedures Assertions.Assert have these effects independently of the assertion policy in effect.
Bounded (Run-Time) Errors
23.1/5It is a bounded error to invoke a potentially blocking operation (see 9.5.1) during the evaluation of an assertion expression associated with a call on, or return from, a protected operation. If the bounded error is detected, Program_Error is raised. If not detected, execution proceeds normally, but if it is invoked within a protected action, it can result in deadlock or a (nested) protected action.
Implementation Requirements
23.2/5Any postcondition expression, type invariant expression, or default initial condition expression occurring in the specification of a language-defined unit is enabled (see 6.1.1, 7.3.2, and 7.3.3).
The evaluation of any such postcondition, type invariant, or default initial condition expression shall either yield True or propagate an exception from a raise_expression
that appears within the assertion expression.
raise_expression
which is syntactically all or part of the assertion expression. Any precondition expression occurring in the specification of a language-defined unit is enabled (see 6.1.1) unless suppressed (see 11.5). Similarly, any predicate checks for a subtype occurring in the specification of a language-defined unit are enabled (see 3.2.4) unless suppressed.
Implementation Permissions
24/2Assertion_Error may be declared by renaming an implementation-defined exception from another package.
Implementations may define their own assertion policies.
If the result of a function call in an assertion is not used to determine the value of the assertion expression, an implementation is permitted to omit the function call. [This permission applies even if the function has side effects.]
An implementation may disallow the specification of an assertion expression if the evaluation of the expression has a side effect such that an immediate reevaluation of the expression can produce a different value. Similarly, an implementation may disallow the specification of an assertion expression that is checked as part of a call on or return from a callable entity C, if the evaluation of the expression has a side effect such that the evaluation of some other assertion expression associated with the same call of (or return from) C can produce a different value than in the case when the first expression had not been evaluated.
Language Design Principles
pragma
Assert should not call functions that have significant side effects when the result of the expression is True, so that the particular assertion policy in effect will not affect normal operation of the program. Extensions to Ada 95
Incompatibilities With Ada 2005
pragma
Assert that works in Ada 2005 might be illegal in Ada 2012 in the unlikely event that the compiler detected such an error. This should be unlikely to occur in practice and it is considered a good thing, as the original expression was tricky and probably was not portable (as order of evaluation is unspecified within an expression). Moreover, no compiler is required to reject such expressions, so there is no need for any compiler to change behavior. Extensions to Ada 2005
Wording Changes from Ada 2012
11.4.3 Example of Exception Handling
Examples
1/5Exception handling can be used to separate the detection of an error from the response to that error:
package File_System is
type Data_Type is ...;
type File_Handle is limited private;
3File_Not_Found : exception;
procedure Open(F : in out File_Handle; Name : String);
-- raises File_Not_Found if named file does not exist
4End_Of_File : exception;
procedure Read(F : in out File_Handle; Data : out Data_Type);
-- raises End_Of_File if the file is not open
5/5...
private
...
end File_System;
package body File_System is
...
procedure Open(F : in out File_Handle; Name : String) is
begin
if File_Exists(Name) then
...
else
raise File_Not_Found with "File not found: " & Name & ".";
end if;
end Open;
7procedure Read(F : in out File_Handle; Data : out Data_Type) is
begin
if F.Current_Position <= F.Last_Position then
...
else
raise End_Of_File;
end if;
end Read;
8...
9end File_System;
10/5with Ada.Text_IO;
with Ada.Exceptions;
with File_System; use File_System;
use Ada;
procedure Main is
Verbosity_Desired : Boolean := ...;
begin
... -- call operations in File_System
exception
when End_Of_File =>
Close(Some_File);
when Not_Found_Error : File_Not_Found =>
Text_IO.Put_Line(Exceptions.Exception_Message(Not_Found_Error));
when The_Error : others =>
Text_IO.Put_Line("Unknown error:");
if Verbosity_Desired then
Text_IO.Put_Line(Exceptions.Exception_Information(The_Error));
else
Text_IO.Put_Line(Exceptions.Exception_Name(The_Error));
Text_IO.Put_Line(Exceptions.Exception_Message(The_Error));
end if;
raise;
end Main;
11/5In the above example, the File_System package contains information about detecting certain exceptional situations, but it does not specify how to handle those situations. Procedure Main specifies how to handle them; other clients of File_System can have different handlers, even though the exceptional situations arise from the same basic causes.