

                           Section 11: Exceptions


1     This section defines the facilities for dealing with errors or other
exceptional situations that arise during program execution. An exception
represents a kind of exceptional situation; an occurrence of such a situation
(at run time) is called an exception occurrence. To raise an exception is to
abandon normal program execution so as to draw attention to the fact that the
corresponding situation has arisen. Performing some actions in response to the
arising of an exception is called handling the exception.

2     An exception_declaration declares a name for an exception. An exception
is raised initially either by a raise_statement or by the failure of a
language-defined check. When an exception arises, control can be transferred
to a user-provided exception_handler at the end of a handled_sequence_of_-
statements, or it can be propagated to a dynamically enclosing execution.


11.1 Exception Declarations


1     An exception_declaration declares a name for an exception.


                                   Syntax

2     exception_declaration ::= defining_identifier_list : exception;


                              Static Semantics

3     Each single exception_declaration declares a name for a different
exception. If a generic unit includes an exception_declaration, the
exception_declarations implicitly generated by different instantiations of the
generic unit refer to distinct exceptions (but all have the same
defining_identifier). The particular exception denoted by an exception name is
determined at compilation time and is the same regardless of how many times
the exception_declaration is elaborated.

4     The predefined exceptions are the ones declared in the declaration of
package Standard: Constraint_Error, Program_Error, Storage_Error, and
Tasking_Error; one of them is raised when a language-defined check fails.


                              Dynamic Semantics

5     The elaboration of an exception_declaration has no effect.

6     The execution of any construct raises Storage_Error if there is
insufficient storage for that execution. The amount of storage needed for the
execution of constructs is unspecified.


                                  Examples

7     Examples of user-defined exception declarations:

8     Singular : exception;
      Error    : exception;
      Overflow, Underflow : exception;


11.2 Exception Handlers


1     The response to one or more exceptions is specified by an
exception_handler.


                                   Syntax

2     handled_sequence_of_statements ::= 
           sequence_of_statements
        [exception
           exception_handler
          {exception_handler}]

3     exception_handler ::= 
        when [choice_parameter_specification:] exception_choice
       {| exception_choice} =>
           sequence_of_statements

4     choice_parameter_specification ::= defining_identifier

5     exception_choice ::= exception_name | others


                               Legality Rules

6     A choice with an exception_name covers the named exception. A choice
with others covers all exceptions not named by previous choices of the same
handled_sequence_of_statements. Two choices in different exception_handlers of
the same handled_sequence_of_statements shall not cover the same exception.

7     A choice with others is allowed only for the last handler of a
handled_sequence_of_statements and as the only choice of that handler.

8     An exception_name of a choice shall not denote an exception declared in
a generic formal package.


                              Static Semantics

9     A choice_parameter_specification declares a choice parameter, which is a
constant object of type Exception_Occurrence (see 11.4.1). During the handling
of an exception occurrence, the choice parameter, if any, of the handler
represents the exception occurrence that is being handled.


                              Dynamic Semantics

10    The execution of a handled_sequence_of_statements consists of the
execution of the sequence_of_statements. The optional handlers are used to
handle any exceptions that are propagated by the sequence_of_statements.


                                  Examples

11    Example of an exception handler:

12    begin
         Open(File, In_File, "input.txt");   -- see A.8.2
      exception
         when E : Name_Error =>
            Put("Cannot open input file : ");
            Put_Line(Exception_Message(E));  -- see 11.4.1
            raise;
      end;


11.3 Raise Statements


1     A raise_statement raises an exception.


                                   Syntax

2     raise_statement ::= raise [exception_name];


                               Legality Rules

3     The name, if any, in a raise_statement shall denote an exception. A
raise_statement with no exception_name (that is, a re-raise statement) shall
be within a handler, but not within a body enclosed by that handler.


                              Dynamic Semantics

4     To raise an exception is to raise a new occurrence of that exception, as
explained in 11.4. For the execution of a raise_statement with an
exception_name, the named exception is raised. For the execution of a re-raise
statement, the exception occurrence that caused transfer of control to the
innermost enclosing handler is raised again.


                                  Examples

5     Examples of raise statements:

6     raise Ada.IO_Exceptions.Name_Error;   -- see A.13

7     raise;                                -- re-raise the current exception


11.4 Exception Handling


1     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.


                              Dynamic Semantics

2     Within a given task, if the execution of construct a is defined by this
International Standard 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.

3     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:

4     If the construct is a task_body, the exception does not propagate
      further;

5     If the construct is the sequence_of_statements of a
      handled_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.

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

      NOTES

8     1  Note that exceptions raised in a 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

1     The following language-defined library package exists:

2     
      package Ada.Exceptions is
          type Exception_Id is private;
          Null_Id : constant Exception_Id;
          function Exception_Name(Id : Exception_Id) return String;

3         type Exception_Occurrence is limited private;
          type Exception_Occurrence_Access is access all Exception_Occurrence;
          Null_Occurrence : constant Exception_Occurrence;

4         procedure Raise_Exception(E : in Exception_Id;
                                    Message : in String := "");
          function Exception_Message(X : Exception_Occurrence) return String;
          procedure Reraise_Occurrence(X : in Exception_Occurrence);

5         function Exception_Identity(X : Exception_Occurrence)
                                      return Exception_Id;
          function Exception_Name(X : Exception_Occurrence) return String;
              -- Same as Exception_Name(Exception_Identity(X)).
          function Exception_Information
      (X : Exception_Occurrence) return String;

6         procedure Save_Occurrence(Target : out Exception_Occurrence;
                                    Source : in Exception_Occurrence);
          function Save_Occurrence(Source : Exception_Occurrence)
                                   return Exception_Occurrence_Access;
      private
         ... -- not specified by the language
      end Ada.Exceptions;

7     Each 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.

8/1   For a prefix E that denotes an exception, the following attribute is
defined:

9     E'Identity
              E'Identity returns the unique identity of the exception. The
              type of this attribute is Exception_Id.

10    Raise_Exception raises a new occurrence of the identified exception. In
this case, Exception_Message returns the Message parameter of Raise_Exception.
For a raise_statement with an exception_name, Exception_Message returns
implementation-defined information about the exception occurrence.
Reraise_Occurrence reraises the specified exception occurrence.

11    Exception_Identity returns the identity of the exception of the
occurrence.

12    The 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.

13    Exception_Information returns implementation-defined information about
the exception occurrence.

14    Raise_Exception and Reraise_Occurrence have no effect in the case of
Null_Id or Null_Occurrence. Exception_Message, Exception_Identity,
Exception_Name, and Exception_Information raise Constraint_Error for a Null_Id
or Null_Occurrence.

15    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.


                         Implementation Requirements

16    The implementation of the Write attribute (see 13.13.2) of
Exception_Occurrence shall support writing a representation of an exception
occurrence to a stream; the implementation of the Read attribute of
Exception_Occurrence shall support reconstructing an exception occurrence from
a stream (including one written in a different partition).


                         Implementation Permissions

17    An implementation of Exception_Name in a space-constrained environment
may return the defining_identifier instead of the full expanded name.

18    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

19    Exception_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.


11.4.2 Example of Exception Handling



                                  Examples

1     Exception handling may be used to separate the detection of an error
from the response to that error:

2     with Ada.Exceptions;
      use Ada;
      package File_System is
          type File_Handle is limited private;

3         File_Not_Found : exception;
          procedure Open(F : in out File_Handle; Name : String);
              -- raises File_Not_Found if named file does not exist

4         End_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         ...
      end File_System;

6     package body File_System is
          procedure Open(F : in out File_Handle; Name : String) is
          begin
              if File_Exists(Name) then
                  ...
              else
                  Exceptions.Raise_Exception(File_Not_Found'Identity,
                                            "File not found: " & Name & ".");
              end if;
          end Open;

7         procedure 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         ...

9     end File_System;

10    with Ada.Text_IO;
      with Ada.Exceptions;
      with File_System; use File_System;
      use Ada;
      procedure Main is
      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    In 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 might have different handlers, even though the
exceptional situations arise from the same basic causes.


11.5 Suppressing Checks


1     A pragma Suppress gives permission to an implementation to omit certain
language-defined checks.

2     A language-defined check (or simply, a ``check'') is one of the
situations defined by this International Standard that requires a check to be
made at run time to determine whether some condition is true. A check fails
when the condition being checked is false, causing an exception to be raised.


                                   Syntax

3     The form of a pragma Suppress is as follows:

4       pragma Suppress(identifier [, [On =>] name]);

5     A pragma Suppress is allowed only immediately within a declarative_part,
      immediately within a package_specification, or as a configuration
      pragma.


                               Legality Rules

6     The identifier shall be the name of a check. The name (if present) shall
statically denote some entity.

7     For a pragma Suppress that is immediately within a package_specification
and includes a name, the name shall denote an entity (or several overloaded
subprograms) declared immediately within the package_specification.


                              Static Semantics

8     A pragma Suppress gives permission to an implementation to omit the
named check from the place of the pragma to the end of the innermost enclosing
declarative region, or, if the pragma is given in a package_specification and
includes a name, to the end of the scope of the named entity. If the pragma
includes a name, the permission applies only to checks performed on the named
entity, or, for a subtype, on objects and values of its type. Otherwise, the
permission applies to all entities. If permission has been given to suppress a
given check, the check is said to be suppressed.

9     The following are the language-defined checks:

10    The following checks correspond to situations in which the exception
      Constraint_Error is raised upon failure.

11/1  Access_Check
              When evaluating a dereference (explicit or implicit), check that
              the value of the name is not null. When passing an actual
              parameter to a formal access parameter, check that the value of
              the actual parameter is not null. When evaluating a
              discriminant_association for an access discriminant, check that
              the value of the discriminant is not null.

12    Discriminant_Check
              Check that the discriminants of a composite value have the
              values imposed by a discriminant constraint. Also, when
              accessing a record component, check that it exists for the
              current discriminant values.

13    Division_Check
              Check that the second operand is not zero for the operations /,
              rem and mod.

14    Index_Check
              Check that the bounds of an array value are equal to the
              corresponding bounds of an index constraint. Also, when
              accessing a component of an array object, check for each
              dimension that the given index value belongs to the range
              defined by the bounds of the array object. Also, when accessing
              a slice of an array object, check that the given discrete range
              is compatible with the range defined by the bounds of the array
              object.

15    Length_Check
              Check that two arrays have matching components, in the case of
              array subtype conversions, and logical operators for arrays of
              boolean components.

16    Overflow_Check
              Check that a scalar value is within the base range of its type,
              in cases where the implementation chooses to raise an exception
              instead of returning the correct mathematical result.

17    Range_Check
              Check that a scalar value satisfies a range constraint. Also,
              for the elaboration of a subtype_indication, check that the
              constraint (if present) is compatible with the subtype denoted
              by the subtype_mark. Also, for an aggregate, check that an index
              or discriminant value belongs to the corresponding subtype.
              Also, check that when the result of an operation yields an
              array, the value of each component belongs to the component
              subtype.

18    Tag_Check
              Check that operand tags in a dispatching call are all equal.
              Check for the correct tag on tagged type conversions, for an
              assignment_statement, and when returning a tagged limited object
              from a function.

19    The following checks correspond to situations in which the exception
      Program_Error is raised upon failure.

20    Elaboration_Check
              When a subprogram or protected entry is called, a task
              activation is accomplished, or a generic instantiation is
              elaborated, check that the body of the corresponding unit has
              already been elaborated.

21    Accessibility_Check
              Check the accessibility level of an entity or view.

22    The following check corresponds to situations in which the exception
      Storage_Error is raised upon failure.

23    Storage_Check
              Check that evaluation of an allocator does not require more
              space than is available for a storage pool. Check that the space
              available for a task or subprogram has not been exceeded.

24    The following check corresponds to all situations in which any
      predefined exception is raised.

25    All_Checks
              Represents the union of all checks; suppressing All_Checks
              suppresses all checks.


                             Erroneous Execution

26    If a given check has been suppressed, and the corresponding error
situation occurs, the execution of the program is erroneous.


                         Implementation Permissions

27    An implementation is allowed to place restrictions on Suppress pragmas.
An implementation is allowed to add additional check names, with
implementation-defined semantics. When Overflow_Check has been suppressed, an
implementation may also suppress an unspecified subset of the Range_Checks.


                            Implementation Advice

28    The implementation should minimize the code executed for checks that
have been suppressed.

      NOTES

29    2  There is no guarantee that a suppressed check is actually removed;
      hence a pragma Suppress should be used only for efficiency reasons.


                                  Examples

30    Examples of suppressing checks:

31    pragma Suppress(Range_Check);
      pragma Suppress(Index_Check, On => Table);


11.6 Exceptions and Optimization


1     This clause gives permission to the implementation to perform certain
``optimizations'' that do not necessarily preserve the canonical semantics.


                              Dynamic Semantics

2     The rest of this International Standard (outside this clause) defines
the canonical semantics of the language. The canonical semantics of a given
(legal) program determines a set of possible external effects that can result
from the execution of the program with given inputs.

3     As explained in 1.1.3, ``
Conformity of an Implementation with the Standard'', the external effect of a
program is defined in terms of its interactions with its external environment.
Hence, the implementation can perform any internal actions whatsoever, in any
order or in parallel, so long as the external effect of the execution of the
program is one that is allowed by the canonical semantics, or by the rules of
this clause.


                         Implementation Permissions

4     The following additional permissions are granted to the implementation:

5     An implementation need not always raise an exception when a
      language-defined check fails. Instead, the operation that failed the
      check can simply yield an undefined result. The exception need be raised
      by the implementation only if, in the absence of raising it, the value
      of this undefined result would have some effect on the external
      interactions of the program. In determining this, the implementation
      shall not presume that an undefined result has a value that belongs to
      its subtype, nor even to the base range of its type, if scalar. Having
      removed the raise of the exception, the canonical semantics will in
      general allow the implementation to omit the code for the check, and
      some or all of the operation itself.

6     If an exception is raised due to the failure of a language-defined
      check, then upon reaching the corresponding exception_handler (or the
      termination of the task, if none), the external interactions that have
      occurred need reflect only that the exception was raised somewhere
      within the execution of the sequence_of_statements with the handler (or
      the task_body), possibly earlier (or later if the interactions are
      independent of the result of the checked operation) than that defined by
      the canonical semantics, but not within the execution of some
      abort-deferred operation or independent subprogram that does not
      dynamically enclose the execution of the construct whose check failed.
      An independent subprogram is one that is defined outside the library
      unit containing the construct whose check failed, and has no Inline
      pragma applied to it. Any assignment that occurred outside of such
      abort-deferred operations or independent subprograms can be disrupted by
      the raising of the exception, causing the object or its parts to become
      abnormal, and certain subsequent uses of the object to be erroneous, as
      explained in 13.9.1.

      NOTES

7     3  The permissions granted by this clause can have an effect on the
      semantics of a program only if the program fails a language-defined
      check.

