[multiple changes]
authorArnaud Charlet <charlet@gcc.gnu.org>
Tue, 20 Jul 2004 10:26:51 +0000 (12:26 +0200)
committerArnaud Charlet <charlet@gcc.gnu.org>
Tue, 20 Jul 2004 10:26:51 +0000 (12:26 +0200)
2004-07-20  Olivier Hainque  <hainque@act-europe.fr>

* a-elchha.adb (Last_Chance_Handler): Remove the bogus buffer dynamic
allocation and potentially overflowing update with
Tailored_Exception_Information. Use the sec-stack free procedural
interface to output Exception_Information instead.

* a-except.adb (To_Stderr): New subprogram for character, and string
version moved from a-exextr to be visible from other separate units.
(Tailored_Exception_Information): Remove the procedural version,
previously used by the default Last_Chance_Handler and not any more.
Adjust various comments.

* a-exexda.adb: Generalize the exception information procedural
interface, to minimize the use of secondary stack and the need for
local buffers when the info is to be output to stderr:
(Address_Image): Removed.
(Append_Info_Character): New subprogram, checking for overflows and
outputing to stderr if buffer to fill is of length 0.
(Append_Info_String): Output to stderr if buffer to fill is of length 0.
(Append_Info_Address, Append_Info_Exception_Name,
Append_Info_Exception_Message, Append_Info_Basic_Exception_Information,
Append_Info_Basic_Exception_Traceback,
Append_Info_Exception_Information): New subprograms.
(Append_Info_Nat, Append_Info_NL): Use Append_Info_Character.
(Basic_Exception_Info_Maxlength, Basic_Exception_Tback_Maxlength,
Exception_Info_Maxlength, Exception_Name_Length,
Exception_Message_Length): New subprograms.
(Exception_Information): Use Append_Info_Exception_Information.
(Tailored_Exception_Information): Use
Append_Info_Basic_Exception_Information.
Export services for the default Last_Chance_Handler.

* a-exextr.adb (To_Stderr): Remove. Now in a-except to be usable by
other separate units.

2004-07-20  Vincent Celier  <celier@gnat.com>

* clean.adb, mlib-utl.adb, osint.adb, makegpr.adb: Minor reformatting.

2004-07-20  Ed Schonberg  <schonberg@gnat.com>

* freeze.adb (Freeze_Entity): If entity is a discriminated record type,
emit itype references for the designated types of component types that
are declared outside of the full record declaration, and that may
denote a partial view of that record type.

2004-07-20  Ed Schonberg  <schonberg@gnat.com>

PR ada/15607
* sem_ch3.adb (Build_Discriminated_Subtype): Do not attach a subtype
which is the designated type in an access component declaration, to the
list of incomplete dependents of the parent type, to avoid elaboration
issues with out-of-scope subtypes.
(Complete_Private_Subtype): Recompute Has_Unknown_Discriminants from the
full view of the parent.

2004-07-20  Ed Schonberg  <schonberg@gnat.com>

PR ada/15610
* sem_ch8.adb (Find_Expanded_Name): If name is overloaded, reject
entities that are hidden, such as references to generic actuals
outside an instance.

2004-07-20  Javier Miranda  <miranda@gnat.com>

* sem_ch4.adb (Try_Object_Operation): New subprogram that gives
support to the new notation.
(Analyze_Selected_Component): Add call to Try_Object_Operation.

2004-07-20  Jose Ruiz  <ruiz@act-europe.fr>

* s-taprob.adb: Adding the elaboration code required for initializing
the tasking soft links that are common to the full and the restricted
run times.

* s-tarest.adb (Init_RTS): Tasking soft links that are shared with the
restricted run time has been moved to the package
System.Soft_Links.Tasking.

* s-tasini.adb (Init_RTS): Tasking soft links that are shared with the
restricted run time has been moved to the package
System.Soft_Links.Tasking.

* Makefile.rtl: Add entry for s-solita.o in run-time library list.

* s-solita.ads, s-solita.adb: New files.

2004-07-20  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>

* trans.c (Identifier_to_gnu, Pragma_to_gnu, Attribute_to_gnu,
Case_Statement_to_gnu): Split off from gnat_to_gnu.
(Loop_Statement_to_gnu, Subprogram_Body_to_gnu, call_to_gnu,
Handled_Sequence_Of_Statements_to_gnu, Exception_Handler_to_gnu_sjlj,
Exception_Handler_to_gnu_zcx): Likewise.

From-SVN: r84948

20 files changed:
gcc/ada/ChangeLog
gcc/ada/Makefile.rtl
gcc/ada/a-elchha.adb
gcc/ada/a-except.adb
gcc/ada/a-exexda.adb
gcc/ada/a-exextr.adb
gcc/ada/clean.adb
gcc/ada/freeze.adb
gcc/ada/makegpr.adb
gcc/ada/mlib-utl.adb
gcc/ada/osint.adb
gcc/ada/s-solita.adb [new file with mode: 0644]
gcc/ada/s-solita.ads [new file with mode: 0644]
gcc/ada/s-taprob.adb
gcc/ada/s-tarest.adb
gcc/ada/s-tasini.adb
gcc/ada/sem_ch3.adb
gcc/ada/sem_ch4.adb
gcc/ada/sem_ch8.adb
gcc/ada/trans.c

index 5af5ee3..28445a8 100644 (file)
@@ -1,3 +1,99 @@
+2004-07-20  Olivier Hainque  <hainque@act-europe.fr>
+
+       * a-elchha.adb (Last_Chance_Handler): Remove the bogus buffer dynamic
+       allocation and potentially overflowing update with
+       Tailored_Exception_Information. Use the sec-stack free procedural
+       interface to output Exception_Information instead.
+
+       * a-except.adb (To_Stderr): New subprogram for character, and string
+       version moved from a-exextr to be visible from other separate units.
+       (Tailored_Exception_Information): Remove the procedural version,
+       previously used by the default Last_Chance_Handler and not any more.
+       Adjust various comments.
+
+       * a-exexda.adb: Generalize the exception information procedural
+       interface, to minimize the use of secondary stack and the need for
+       local buffers when the info is to be output to stderr:
+       (Address_Image): Removed.
+       (Append_Info_Character): New subprogram, checking for overflows and
+       outputing to stderr if buffer to fill is of length 0.
+       (Append_Info_String): Output to stderr if buffer to fill is of length 0.
+       (Append_Info_Address, Append_Info_Exception_Name,
+       Append_Info_Exception_Message, Append_Info_Basic_Exception_Information,
+       Append_Info_Basic_Exception_Traceback,
+       Append_Info_Exception_Information): New subprograms.
+       (Append_Info_Nat, Append_Info_NL): Use Append_Info_Character.
+       (Basic_Exception_Info_Maxlength, Basic_Exception_Tback_Maxlength,
+       Exception_Info_Maxlength, Exception_Name_Length,
+       Exception_Message_Length): New subprograms.
+       (Exception_Information): Use Append_Info_Exception_Information.
+       (Tailored_Exception_Information): Use
+       Append_Info_Basic_Exception_Information.
+       Export services for the default Last_Chance_Handler.
+
+       * a-exextr.adb (To_Stderr): Remove. Now in a-except to be usable by
+       other separate units.
+
+2004-07-20  Vincent Celier  <celier@gnat.com>
+
+       * clean.adb, mlib-utl.adb, osint.adb, makegpr.adb: Minor reformatting.
+
+2004-07-20  Ed Schonberg  <schonberg@gnat.com>
+
+       * freeze.adb (Freeze_Entity): If entity is a discriminated record type,
+       emit itype references for the designated types of component types that
+       are declared outside of the full record declaration, and that may
+       denote a partial view of that record type.
+
+2004-07-20  Ed Schonberg  <schonberg@gnat.com>
+
+       PR ada/15607
+       * sem_ch3.adb (Build_Discriminated_Subtype): Do not attach a subtype
+       which is the designated type in an access component declaration, to the
+       list of incomplete dependents of the parent type, to avoid elaboration
+       issues with out-of-scope subtypes.
+       (Complete_Private_Subtype): Recompute Has_Unknown_Discriminants from the
+       full view of the parent.
+
+2004-07-20  Ed Schonberg  <schonberg@gnat.com>
+
+       PR ada/15610
+       * sem_ch8.adb (Find_Expanded_Name): If name is overloaded, reject
+       entities that are hidden, such as references to generic actuals
+       outside an instance.
+
+2004-07-20  Javier Miranda  <miranda@gnat.com>
+
+       * sem_ch4.adb (Try_Object_Operation): New subprogram that gives
+       support to the new notation.
+       (Analyze_Selected_Component): Add call to Try_Object_Operation.
+
+2004-07-20  Jose Ruiz  <ruiz@act-europe.fr>
+
+       * s-taprob.adb: Adding the elaboration code required for initializing
+       the tasking soft links that are common to the full and the restricted
+       run times.
+
+       * s-tarest.adb (Init_RTS): Tasking soft links that are shared with the
+       restricted run time has been moved to the package
+       System.Soft_Links.Tasking.
+
+       * s-tasini.adb (Init_RTS): Tasking soft links that are shared with the
+       restricted run time has been moved to the package
+       System.Soft_Links.Tasking.
+
+       * Makefile.rtl: Add entry for s-solita.o in run-time library list.
+
+       * s-solita.ads, s-solita.adb: New files.
+
+2004-07-20  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
+
+       * trans.c (Identifier_to_gnu, Pragma_to_gnu, Attribute_to_gnu,
+       Case_Statement_to_gnu): Split off from gnat_to_gnu.
+       (Loop_Statement_to_gnu, Subprogram_Body_to_gnu, call_to_gnu,
+       Handled_Sequence_Of_Statements_to_gnu, Exception_Handler_to_gnu_sjlj,
+       Exception_Handler_to_gnu_zcx): Likewise.
+
 2004-07-17  Joseph S. Myers  <jsm@polyomino.org.uk>
 
        * gigi.h (builtin_function): Declare.
index 9e45d01..10031f8 100644 (file)
@@ -46,6 +46,7 @@ GNATRTL_TASKING_OBJS= \
   s-intman$(objext) \
   s-osinte$(objext) \
   s-proinf$(objext) \
+  s-solita$(objext) \
   s-taenca$(objext) \
   s-taprob$(objext) \
   s-taprop$(objext) \
index 6e2da23..e7eb65c 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---             Copyright (C) 2003 Free Software Foundation, Inc.            --
+--           Copyright (C) 2003-2004 Free Software Foundation, Inc.         --
 --                                                                          --
 -- This specification is derived from the Ada Reference Manual for use with --
 -- GNAT. The copyright notice above, and the license provisions that follow --
@@ -45,83 +45,43 @@ is
    pragma Import (C, Unhandled_Terminate, "__gnat_unhandled_terminate");
    --  Perform system dependent shutdown code
 
-   function Tailored_Exception_Information
-     (X : Exception_Occurrence) return String;
-   --  Exception information to be output in the case of automatic tracing
-   --  requested through GNAT.Exception_Traces.
-   --
-   --  This is the same as Exception_Information if no backtrace decorator
-   --  is currently in place. Otherwise, this is Exception_Information with
-   --  the call chain raw addresses replaced by the result of a call to the
-   --  current decorator provided with the call chain addresses.
+   function Exception_Message_Length
+     (X : Exception_Occurrence) return Natural;
+   pragma Import (Ada, Exception_Message_Length, "__gnat_exception_msg_len");
 
+   procedure Append_Info_Exception_Message
+     (X : Exception_Occurrence; Info : in out String; Ptr : in out Natural);
    pragma Import
-     (Ada, Tailored_Exception_Information,
-        "__gnat_tailored_exception_information");
+     (Ada, Append_Info_Exception_Message, "__gnat_append_info_e_msg");
 
-   procedure Tailored_Exception_Information
-     (X    : Exception_Occurrence;
-      Buff : in out String;
-      Last : in out Integer);
-   --  Procedural version of the above function. Instead of returning the
-   --  result, this one is put in Buff (Buff'first .. Buff'first + Last)
+   procedure Append_Info_Exception_Information
+     (X : Exception_Occurrence; Info : in out String; Ptr : in out Natural);
+   pragma Import
+     (Ada, Append_Info_Exception_Information, "__gnat_append_info_e_info");
 
    procedure To_Stderr (S : String);
    pragma Import (Ada, To_Stderr, "__gnat_to_stderr");
    --  Little routine to output string to stderr
 
+   Ptr   : Natural := 0;
+   Nobuf : String (1 .. 0);
+
    Nline : constant String := String'(1 => ASCII.LF);
    --  Convenient shortcut
 
-   Msg : constant String := Except.Msg (1 .. Except.Msg_Length);
-
-   Max_Static_Exc_Info : constant := 1024;
-   --  This should be enough for most exception information cases
-   --  even though tailoring introduces some uncertainty.  The
-   --  name+message should not exceed 320 chars, so that leaves at
-   --  least 35 backtrace slots (each slot needs 19 chars for
-   --  representing a 64 bit address).
-
-   subtype Exc_Info_Type is String (1 .. Max_Static_Exc_Info);
-   type Str_Ptr is access Exc_Info_Type;
-   Exc_Info : Str_Ptr;
-   Exc_Info_Last : Natural := 0;
-   --  Buffer that is allocated to store the tailored exception
-   --  information while Adafinal is run. This buffer is allocated
-   --  on the heap only when it is needed. It is better to allocate
-   --  on the heap than on the stack since stack overflows are more
-   --  common than heap overflows.
-
-   procedure Tailored_Exception_Information
-     (X    : Exception_Occurrence;
-      Buff : in out String;
-      Last : in out Integer)
-   is
-      Info : constant String := Tailored_Exception_Information (X);
-   begin
-      Last := Info'Last;
-      Buff (1 .. Last) := Info;
-   end Tailored_Exception_Information;
-
 begin
-   --  First allocate & store the exception info in a buffer when
-   --  we know it will be needed. This needs to be done before
-   --  Adafinal because it implicitly uses the secondary stack.
-
-   if Except.Id.Full_Name.all (1) /= '_'
-     and then Except.Num_Tracebacks /= 0
-   then
-      Exc_Info := new Exc_Info_Type;
-      if Exc_Info /= null then
-         Tailored_Exception_Information
-           (Except, Exc_Info.all, Exc_Info_Last);
-      end if;
-   end if;
+   --  Let's shutdown the runtime now. The rest of the procedure needs to be
+   --  careful not to use anything that would require runtime support. In
+   --  particular, functions returning strings are banned since the sec stack
+   --  is no longer functional. This is particularly important to note for the
+   --  Exception_Information output. We used to allow the tailored version to
+   --  show up here, which turned out to be a bad idea as it might involve a
+   --  traceback decorator the length of which we don't control. Potentially
+   --  heavy primary/secondary stack use or dynamic allocations right before
+   --  this point are not welcome, moving the output before the finalization
+   --  raises order of outputs concerns, and decorators are intended to only
+   --  be used with exception traces, which should have been issued already.
 
-   --  Let's shutdown the runtime now. The rest of the procedure
-   --  needs to be careful not to use anything that would require
-   --  runtime support. In particular, functions returning strings
-   --  are banned since the sec stack is no longer functional.
    System.Standard_Library.Adafinal;
 
    --  Check for special case of raising _ABORT_SIGNAL, which is not
@@ -142,9 +102,9 @@ begin
       To_Stderr ("raised ");
       To_Stderr (Except.Id.Full_Name.all (1 .. Except.Id.Name_Length - 1));
 
-      if Msg'Length /= 0 then
+      if Exception_Message_Length (Except) /= 0 then
          To_Stderr (" : ");
-         To_Stderr (Msg);
+         Append_Info_Exception_Message (Except, Nobuf, Ptr);
       end if;
 
       To_Stderr (Nline);
@@ -152,13 +112,11 @@ begin
    --  Traceback exists
 
    else
-      --  Note we can have this whole information output twice if
-      --  this occurrence gets reraised up to here.
-
       To_Stderr (Nline);
       To_Stderr ("Execution terminated by unhandled exception");
       To_Stderr (Nline);
-      To_Stderr (Exc_Info (1 .. Exc_Info_Last));
+
+      Append_Info_Exception_Information (Except, Nobuf, Ptr);
    end if;
 
    Unhandled_Terminate;
index 6a0885f..2da9de2 100644 (file)
@@ -120,6 +120,17 @@ package body Ada.Exceptions is
    --  Raise_From_Signal_Handler. The origin of the call is indicated by the
    --  From_Signal_Handler argument.
 
+   procedure To_Stderr (S : String);
+   pragma Export (Ada, To_Stderr, "__gnat_to_stderr");
+   --  Little routine to output string to stderr that is also used
+   --  in the tasking run time.
+
+   procedure To_Stderr (C : Character);
+   pragma Inline (To_Stderr);
+   pragma Export (Ada, To_Stderr, "__gnat_to_stderr_char");
+   --  Little routine to output a character to stderr, used by some of
+   --  the separate units below.
+
    package Exception_Data is
 
       ---------------------------------
@@ -154,34 +165,40 @@ package body Ada.Exceptions is
       function Exception_Information (X : Exception_Occurrence) return String;
       --  The format of the exception information is as follows:
       --
-      --    exception name (as in Exception_Name)
-      --    message (or a null line if no message)
-      --    PID=nnnn
-      --    0xyyyyyyyy 0xyyyyyyyy ...
+      --    Exception_Name: <exception name> (as in Exception_Name)
+      --    Message: <message> (only if Exception_Message is empty)
+      --    PID=nnnn (only if != 0)
+      --    Call stack traceback locations:  (only if at least one location)
+      --    <0xyyyyyyyy 0xyyyyyyyy ...>      (is recorded)
       --
-      --  The lines are separated by a ASCII.LF character
+      --  The lines are separated by a ASCII.LF character.
       --  The nnnn is the partition Id given as decimal digits.
-      --  The 0x... line represents traceback program counter locations,
-      --  in order with the first one being the exception location.
+      --  The 0x... line represents traceback program counter locations, in
+      --  execution order with the first one being the exception location. It
+      --  is present only
+      --
+      --  The Exception_Name and Message lines are omitted in the abort
+      --  signal case, since this is not really an exception.
+
+      --  !! If the format of the generated string is changed, please note
+      --  !! that an equivalent modification to the routine String_To_EO must
+      --  !! be made to preserve proper functioning of the stream attributes.
 
       ---------------------------------------
       -- Exception backtracing subprograms --
       ---------------------------------------
 
-      --  What is automatically output when exception tracing is on basically
-      --  corresponds to the usual exception information, but with the call
-      --  chain backtrace possibly tailored by a backtrace decorator. Modifying
-      --  Exception_Information itself is not a good idea because the decorated
-      --  output is completely out of control and would break all our code
-      --  related to the streaming of exceptions.
-      --
-      --  We then provide an alternative function to Exception_Information to
-      --  compute the possibly tailored output, which is equivalent if no
-      --  decorator is currently set.
+      --  What is automatically output when exception tracing is on is the
+      --  usual exception information with the call chain backtrace possibly
+      --  tailored by a backtrace decorator. Modifying Exception_Information
+      --  itself is not a good idea because the decorated output is completely
+      --  out of control and would break all our code related to the streaming
+      --  of exceptions.  We then provide an alternative function to compute
+      --  the possibly tailored output, which is equivalent if no decorator is
+      --  currently set:
 
       function Tailored_Exception_Information
-        (X    : Exception_Occurrence)
-        return String;
+        (X : Exception_Occurrence) return String;
       --  Exception information to be output in the case of automatic tracing
       --  requested through GNAT.Exception_Traces.
       --
@@ -193,28 +210,7 @@ package body Ada.Exceptions is
       pragma Export
         (Ada, Tailored_Exception_Information,
            "__gnat_tailored_exception_information");
-      --  This function is used within this package but also from within
-      --  System.Tasking.Stages.
-      --
-      --  The output of Exception_Information and
-      --  Tailored_Exception_Information share a common part which was
-      --  formerly built using local procedures within
-      --  Exception_Information. These procedures have been extracted
-      --  from their original place to be available to
-      --  Tailored_Exception_Information also.
-      --
-      --  Each of these procedures appends some input to an
-      --  information string currently being built. The Ptr argument
-      --  represents the last position in this string at which a
-      --  character has been written.
-
-      procedure Tailored_Exception_Information
-        (X    : Exception_Occurrence;
-         Buff : in out String;
-         Last : in out Integer);
-      --  Procedural version of the above function. Instead of returning the
-      --  result, this one is put in Buff (Buff'first .. Buff'first + Last)
-      --  And what happens on overflow ???
+      --  This is currently used by System.Tasking.Stages.
 
    end Exception_Data;
 
@@ -234,14 +230,14 @@ package body Ada.Exceptions is
       --  routine when the GCC 3 mechanism is used.
 
       procedure Notify_Handled_Exception;
-      pragma Export (C, Notify_Handled_Exception,
-                       "__gnat_notify_handled_exception");
+      pragma Export
+        (C, Notify_Handled_Exception, "__gnat_notify_handled_exception");
       --  This routine is called for a handled occurrence is about to be
       --  propagated.
 
       procedure Notify_Unhandled_Exception;
-      pragma Export (C, Notify_Unhandled_Exception,
-                       "__gnat_notify_unhandled_exception");
+      pragma Export
+        (C, Notify_Unhandled_Exception, "__gnat_notify_unhandled_exception");
       --  This routine is called when an unhandled occurrence is about to be
       --  propagated.
 
@@ -1309,6 +1305,30 @@ package body Ada.Exceptions is
       Raise_Current_Excep (E);
    end Raise_Exception_No_Defer;
 
+   ---------------
+   -- To_Stderr --
+   ---------------
+
+   procedure To_Stderr (C : Character) is
+
+      type int is new Integer;
+
+      procedure put_char_stderr (C : int);
+      pragma Import (C, put_char_stderr, "put_char_stderr");
+
+   begin
+      put_char_stderr (Character'Pos (C));
+   end To_Stderr;
+
+   procedure To_Stderr (S : String) is
+   begin
+      for J in S'Range loop
+         if S (J) /= ASCII.CR then
+            To_Stderr (S (J));
+         end if;
+      end loop;
+   end To_Stderr;
+
    ---------
    -- ZZZ --
    ---------
index 214d534..63085f6 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2003 Free Software Foundation, Inc.          --
+--          Copyright (C) 1992-2004 Free Software Foundation, Inc.          --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -36,39 +36,153 @@ with System.Storage_Elements; use System.Storage_Elements;
 separate (Ada.Exceptions)
 package body Exception_Data is
 
-   -----------------------
-   -- Local Subprograms --
-   -----------------------
+   --  This unit implements the Exception_Information related services for
+   --  both the Ada standard requirements and the GNAT.Exception_Traces
+   --  facility.
+
+   --  There are common parts between the contents of Exception_Information
+   --  (the regular Ada interface) and Tailored_Exception_Information (what
+   --  the automatic backtracing output includes). The overall structure is
+   --  sketched below:
 
-   function Address_Image (A : System.Address) return String;
-   --  Returns at string of the form 0xhhhhhhhhh for an address, with
-   --  leading zeros suppressed. Hex characters a-f are in lower case.
+   --
+   --                      Exception_Information
+   --                               |
+   --                       +-------+--------+
+   --                       |                |
+   --                Basic_Exc_Info & Basic_Exc_Tback
+   --                    (B_E_I)          (B_E_TB)
+
+   --           o--
+   --  (B_E_I)  |  Exception_Name: <exception name> (as in Exception_Name)
+   --           |  Message: <message> (or a null line if no message)
+   --           |  PID=nnnn (if != 0)
+   --           o--
+   --  (B_E_TB) |  Call stack traceback locations:
+   --           |  <0xyyyyyyyy 0xyyyyyyyy ...>
+   --           o--
+
+   --                  Tailored_Exception_Information
+   --                               |
+   --                    +----------+----------+
+   --                    |                     |
+   --             Basic_Exc_Info    &  Tailored_Exc_Tback
+   --                                          |
+   --                              +-----------+------------+
+   --                              |                        |
+   --                       Basic_Exc_Tback    Or    Tback_Decorator
+   --                     if no decorator set           otherwise
+
+   --  Functions returning String imply secondary stack use, which is a heavy
+   --  mechanism requiring run-time support. Besides, some of the routines we
+   --  provide here are to be used by the default Last_Chance_Handler, at the
+   --  critical point where the runtime is about to be finalized. Since most
+   --  of the items we have at hand are of bounded length, we also provide a
+   --  procedural interface able to incrementally append the necessary bits to
+   --  a preallocated buffer or output them straight to stderr.
+
+   --  The procedural interface is composed of two major sections: a neutral
+   --  section for basic types like Address, Character, Natural or String, and
+   --  an exception oriented section for the e.g. Basic_Exception_Information.
+   --  This is the Append_Info family of procedures below.
+
+   --  Output to stderr is commanded by passing an empty buffer to update, and
+   --  care is taken not to overflow otherwise.
+
+   --------------------------------------------
+   -- Procedural Interface - Neutral section --
+   --------------------------------------------
+
+   procedure Append_Info_Address
+     (A    : Address;
+      Info : in out String;
+      Ptr  : in out Natural);
+
+   procedure Append_Info_Character
+     (C    : Character;
+      Info : in out String;
+      Ptr  : in out Natural);
 
    procedure Append_Info_Nat
      (N    : Natural;
       Info : in out String;
       Ptr  : in out Natural);
-   --  Append the image of N at the end of the provided information string
 
    procedure Append_Info_NL
      (Info : in out String;
       Ptr  : in out Natural);
-   --  Append a LF at the end of the provided information string
+   pragma Inline (Append_Info_NL);
 
    procedure Append_Info_String
      (S    : String;
       Info : in out String;
       Ptr  : in out Natural);
-   --  Append a string at the end of the provided information string
 
-   --  To build Exception_Information and Tailored_Exception_Information,
-   --  we then use three intermediate functions :
+   -------------------------------------------------------
+   -- Procedural Interface - Exception oriented section --
+   -------------------------------------------------------
 
-   function Basic_Exception_Information
-     (X : Exception_Occurrence) return String;
-   --  Returns the basic exception information string associated with a
-   --  given exception occurrence. This is the common part shared by both
-   --  Exception_Information and Tailored_Exception_Infomation.
+   procedure Append_Info_Exception_Name
+     (Id   : Exception_Id;
+      Info : in out String;
+      Ptr  : in out Natural);
+
+   procedure Append_Info_Exception_Name
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural);
+
+   procedure Append_Info_Exception_Message
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural);
+
+   procedure Append_Info_Basic_Exception_Information
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural);
+
+   procedure Append_Info_Basic_Exception_Traceback
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural);
+
+   procedure Append_Info_Exception_Information
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural);
+
+
+   --  The "functional" interface to the exception information not involving
+   --  a traceback decorator uses preallocated intermediate buffers to avoid
+   --  the use of secondary stack. Preallocation requires preliminary length
+   --  computation, for which a series of functions are introduced:
+
+   ---------------------------------
+   -- Length evaluation utilities --
+   ---------------------------------
+
+   function Basic_Exception_Info_Maxlength
+     (X : Exception_Occurrence) return Natural;
+
+   function Basic_Exception_Tback_Maxlength
+     (X : Exception_Occurrence) return Natural;
+
+   function Exception_Info_Maxlength
+     (X : Exception_Occurrence) return Natural;
+
+   function Exception_Name_Length
+     (Id : Exception_Id) return Natural;
+
+   function Exception_Name_Length
+     (X : Exception_Occurrence) return Natural;
+
+   function Exception_Message_Length
+     (X : Exception_Occurrence) return Natural;
+
+   --------------------------
+   -- Functional Interface --
+   --------------------------
 
    function Basic_Exception_Traceback
      (X : Exception_Occurrence) return String;
@@ -82,32 +196,28 @@ package body Exception_Data is
    --  exception occurrence, either in its basic form if no decorator is
    --  in place, or as formatted by the decorator otherwise.
 
-   --  The overall organization of the exception information related code
-   --  is summarized below :
-   --
-   --           Exception_Information
-   --                    |
-   --            +-------+--------+
-   --            |                |
-   --     Basic_Exc_Info & Basic_Exc_Tback
-   --
-   --
-   --       Tailored_Exception_Information
-   --                    |
-   --         +----------+----------+
-   --         |                     |
-   --  Basic_Exc_Info    &  Tailored_Exc_Tback
-   --                               |
-   --                   +-----------+------------+
-   --                   |                        |
-   --            Basic_Exc_Tback    Or    Tback_Decorator
-   --          if no decorator set           otherwise
+   -----------------------------------------------------------------------
+   -- Services for the default Last_Chance_Handler and the task wrapper --
+   -----------------------------------------------------------------------
 
-   -------------------
-   -- Address_Image --
-   -------------------
+   pragma Export
+     (Ada, Append_Info_Exception_Message, "__gnat_append_info_e_msg");
 
-   function Address_Image (A : Address) return String is
+   pragma Export
+     (Ada, Append_Info_Exception_Information, "__gnat_append_info_e_info");
+
+   pragma Export
+     (Ada, Exception_Message_Length, "__gnat_exception_msg_len");
+
+   -------------------------
+   -- Append_Info_Address --
+   -------------------------
+
+   procedure Append_Info_Address
+     (A    : Address;
+      Info : in out String;
+      Ptr  : in out Natural)
+   is
       S : String (1 .. 18);
       P : Natural;
       N : Integer_Address;
@@ -126,8 +236,27 @@ package body Exception_Data is
 
       S (P - 1) := '0';
       S (P) := 'x';
-      return S (P - 1 .. S'Last);
-   end Address_Image;
+
+      Append_Info_String (S (P - 1 .. S'Last), Info, Ptr);
+   end Append_Info_Address;
+
+   ---------------------------
+   -- Append_Info_Character --
+   ---------------------------
+
+   procedure Append_Info_Character
+     (C    : Character;
+      Info : in out String;
+      Ptr  : in out Natural)
+   is
+   begin
+      if Info'Length = 0 then
+         To_Stderr (C);
+      elsif Ptr < Info'Last then
+         Ptr := Ptr + 1;
+         Info (Ptr) := C;
+      end if;
+   end Append_Info_Character;
 
    ---------------------
    -- Append_Info_Nat --
@@ -143,8 +272,8 @@ package body Exception_Data is
          Append_Info_Nat (N / 10, Info, Ptr);
       end if;
 
-      Ptr := Ptr + 1;
-      Info (Ptr) := Character'Val (Character'Pos ('0') + N mod 10);
+      Append_Info_Character
+        (Character'Val (Character'Pos ('0') + N mod 10), Info, Ptr);
    end Append_Info_Nat;
 
    --------------------
@@ -156,8 +285,7 @@ package body Exception_Data is
       Ptr  : in out Natural)
    is
    begin
-      Ptr := Ptr + 1;
-      Info (Ptr) := ASCII.LF;
+      Append_Info_Character (ASCII.LF, Info, Ptr);
    end Append_Info_NL;
 
    ------------------------
@@ -169,64 +297,56 @@ package body Exception_Data is
       Info : in out String;
       Ptr  : in out Natural)
    is
-      Last : constant Natural := Integer'Min (Ptr + S'Length, Info'Last);
-
    begin
-      Info (Ptr + 1 .. Last) := S;
-      Ptr := Last;
+      if Info'Length = 0 then
+         To_Stderr (S);
+      else
+         declare
+            Last : constant Natural :=
+              Integer'Min (Ptr + S'Length, Info'Last);
+         begin
+            Info (Ptr + 1 .. Last) := S;
+            Ptr := Last;
+         end;
+      end if;
    end Append_Info_String;
 
-   ---------------------------------
-   -- Basic_Exception_Information --
-   ---------------------------------
+   ---------------------------------------------
+   -- Append_Info_Basic_Exception_Information --
+   ---------------------------------------------
 
-   function Basic_Exception_Information
-     (X : Exception_Occurrence) return String
+   --  To ease the maximum length computation, we define and pull out a couple
+   --  of string constants:
+
+   BEI_Name_Header : constant String := "Exception name: ";
+   BEI_Msg_Header  : constant String := "Message: ";
+   BEI_PID_Header  : constant String := "PID: ";
+
+   procedure Append_Info_Basic_Exception_Information
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural)
    is
-      Name : constant String := Exception_Name (X);
-      Msg  : constant String := Exception_Message (X);
-      --  Exception name and message that are going to be included in the
-      --  information to return, if not empty.
-
-      Name_Len : constant Natural := Name'Length;
-      Msg_Len  : constant Natural := Msg'Length;
-      --  Length of these strings, useful to compute the size of the string
-      --  we have to allocate for the complete result as well as in the body
-      --  of this procedure.
-
-      Info_Maxlen : constant Natural := 50 + Name_Len + Msg_Len;
-      --  Maximum length of the information string we will build, with :
-      --
-      --  50 =    16 + 2   for the text associated with the name
-      --        +  9 + 2   for the text associated with the message
-      --        +  5 + 2   for the text associated with the pid
-      --        + 14       for the text image of the pid itself and a margin.
-      --
-      --  This is indeed a maximum since some data may not appear at all if
-      --  not relevant. For example, nothing related to the exception message
-      --  will be there if this message is empty.
-      --
-      --  WARNING : Do not forget to update these numbers if anything
-      --  involved in the computation changes.
-
-      Info : String (1 .. Info_Maxlen);
-      --  Information string we are going to build, containing the common
-      --  part shared by Exc_Info and Tailored_Exc_Info.
-
-      Ptr  : Natural := 0;
+      Name : String (1 .. Exception_Name_Length (X));
+      --  Bufer in which to fetch the exception name, in order to check
+      --  whether this is an internal _ABORT_SIGNAL or a regular occurrence.
+
+      Name_Ptr : Natural := Name'First - 1;
 
    begin
       --  Output exception name and message except for _ABORT_SIGNAL, where
-      --  these two lines are omitted (see discussion above).
+      --  these two lines are omitted.
 
-      if Name (1) /= '_' then
-         Append_Info_String ("Exception name: ", Info, Ptr);
+      Append_Info_Exception_Name (X, Name, Name_Ptr);
+
+      if Name (Name'First) /= '_' then
+         Append_Info_String (BEI_Name_Header, Info, Ptr);
          Append_Info_String (Name, Info, Ptr);
          Append_Info_NL (Info, Ptr);
 
-         if Msg_Len /= 0 then
-            Append_Info_String ("Message: ", Info, Ptr);
-            Append_Info_String (Msg, Info, Ptr);
+         if Exception_Message_Length (X) /= 0 then
+            Append_Info_String (BEI_Msg_Header, Info, Ptr);
+            Append_Info_Exception_Message  (X, Info, Ptr);
             Append_Info_NL (Info, Ptr);
          end if;
       end if;
@@ -234,116 +354,202 @@ package body Exception_Data is
       --  Output PID line if non-zero
 
       if X.Pid /= 0 then
-         Append_Info_String ("PID: ", Info, Ptr);
+         Append_Info_String (BEI_PID_Header, Info, Ptr);
          Append_Info_Nat (X.Pid, Info, Ptr);
          Append_Info_NL (Info, Ptr);
       end if;
+   end Append_Info_Basic_Exception_Information;
 
-      return Info (1 .. Ptr);
-   end Basic_Exception_Information;
+   -------------------------------------------
+   -- Basic_Exception_Information_Maxlength --
+   -------------------------------------------
 
-   -------------------------------
-   -- Basic_Exception_Traceback --
-   -------------------------------
+   function Basic_Exception_Info_Maxlength
+     (X : Exception_Occurrence) return Natural is
+   begin
+      return
+        BEI_Name_Header'Length + Exception_Name_Length (X) + 1
+        + BEI_Msg_Header'Length + Exception_Message_Length (X) + 1
+        + BEI_PID_Header'Length + 15;
+   end Basic_Exception_Info_Maxlength;
 
-   function Basic_Exception_Traceback
-     (X : Exception_Occurrence) return String
+   -------------------------------------------
+   -- Append_Info_Basic_Exception_Traceback --
+   -------------------------------------------
+
+   --  As for Basic_Exception_Information:
+
+   BETB_Header : constant String := "Call stack traceback locations:";
+
+   procedure Append_Info_Basic_Exception_Traceback
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural)
    is
-      Info_Maxlen : constant Natural := 35 + X.Num_Tracebacks * 19;
-      --  Maximum length of the information string we are building, with :
-      --  33 = 31 + 4      for the text before and after the traceback, and
-      --  19 =  2 + 16 + 1 for each address ("0x" + HHHH + " ")
-      --
-      --  WARNING : Do not forget to update these numbers if anything
-      --  involved in the computation changes.
+   begin
+      if X.Num_Tracebacks <= 0 then
+         return;
+      end if;
+
+      Append_Info_String (BETB_Header, Info, Ptr);
+      Append_Info_NL (Info, Ptr);
 
-      Info : String (1 .. Info_Maxlen);
-      --  Information string we are going to build, containing an image
-      --  of the call chain associated with the exception occurrence in its
-      --  most basic form, that is as a sequence of binary addresses.
+      for J in 1 .. X.Num_Tracebacks loop
+         Append_Info_Address (TBE.PC_For (X.Tracebacks (J)), Info, Ptr);
+         exit when J = X.Num_Tracebacks;
+         Append_Info_Character (' ', Info, Ptr);
+      end loop;
 
-      Ptr  : Natural := 0;
+      Append_Info_NL (Info, Ptr);
+   end Append_Info_Basic_Exception_Traceback;
 
+   -----------------------------------------
+   -- Basic_Exception_Traceback_Maxlength --
+   -----------------------------------------
+
+   function Basic_Exception_Tback_Maxlength
+     (X : Exception_Occurrence) return Natural is
    begin
-      if X.Num_Tracebacks > 0 then
-         Append_Info_String ("Call stack traceback locations:", Info, Ptr);
-         Append_Info_NL (Info, Ptr);
+      return BETB_Header'Length + 1 + X.Num_Tracebacks * 19 + 1;
+      --  19 =  2 + 16 + 1 for each address ("0x" + HHHH + " ")
+   end Basic_Exception_Tback_Maxlength;
 
-         for J in 1 .. X.Num_Tracebacks loop
-            Append_Info_String
-              (Address_Image (TBE.PC_For (X.Tracebacks (J))), Info, Ptr);
-            exit when J = X.Num_Tracebacks;
-            Append_Info_String (" ", Info, Ptr);
-         end loop;
+   ---------------------------------------
+   -- Append_Info_Exception_Information --
+   ---------------------------------------
 
-         Append_Info_NL (Info, Ptr);
-      end if;
+   procedure Append_Info_Exception_Information
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural)
+   is
+   begin
+      Append_Info_Basic_Exception_Information (X, Info, Ptr);
+      Append_Info_Basic_Exception_Traceback   (X, Info, Ptr);
+   end Append_Info_Exception_Information;
 
-      return Info (1 .. Ptr);
-   end Basic_Exception_Traceback;
+   ------------------------------
+   -- Exception_Info_Maxlength --
+   ------------------------------
 
-   ---------------------------
-   -- Exception_Information --
-   ---------------------------
+   function Exception_Info_Maxlength
+     (X : Exception_Occurrence) return Natural is
+   begin
+      return
+        Basic_Exception_Info_Maxlength (X)
+        + Basic_Exception_Tback_Maxlength (X);
+   end Exception_Info_Maxlength;
 
-   --  The format of the string is:
+   -----------------------------------
+   -- Append_Info_Exception_Message --
+   -----------------------------------
 
-   --    Exception_Name: nnnnn
-   --    Message: mmmmm
-   --    PID: ppp
-   --    Call stack traceback locations:
-   --    0xhhhh 0xhhhh 0xhhhh ... 0xhhh
+   procedure Append_Info_Exception_Message
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural) is
+   begin
+      if X.Id = Null_Id then
+         raise Constraint_Error;
+      end if;
 
-   --  where
+      declare
+         Len : constant Natural := Exception_Message_Length (X);
+         Msg : constant String (1 .. Len) := X.Msg (1 .. Len);
+      begin
+         Append_Info_String (Msg, Info, Ptr);
+      end;
+   end Append_Info_Exception_Message;
 
-   --    nnnn is the fully qualified name of the exception in all upper
-   --    case letters. This line is always present.
+   --------------------------------
+   -- Append_Info_Exception_Name --
+   --------------------------------
 
-   --    mmmm is the message (this line present only if message is non-null)
+   procedure Append_Info_Exception_Name
+     (Id   : Exception_Id;
+      Info : in out String;
+      Ptr  : in out Natural)
+   is
+   begin
+      if Id = Null_Id then
+         raise Constraint_Error;
+      end if;
 
-   --    ppp is the Process Id value as a decimal integer (this line is
-   --    present only if the Process Id is non-zero). Currently we are
-   --    not making use of this field.
+      declare
+         Len  : constant Natural := Exception_Name_Length (Id);
+         Name : constant String (1 .. Len) := Id.Full_Name (1 .. Len);
+      begin
+         Append_Info_String (Name, Info, Ptr);
+      end;
+   end Append_Info_Exception_Name;
 
-   --    The Call stack traceback locations line and the following values
-   --    are present only if at least one traceback location was recorded.
-   --    the values are given in C style format, with lower case letters
-   --    for a-f, and only as many digits present as are necessary.
+   procedure Append_Info_Exception_Name
+     (X    : Exception_Occurrence;
+      Info : in out String;
+      Ptr  : in out Natural)
+   is
+   begin
+      Append_Info_Exception_Name (X.Id, Info, Ptr);
+   end Append_Info_Exception_Name;
 
-   --  The line terminator sequence at the end of each line, including the
-   --  last line is a CR-LF sequence (16#0D# followed by 16#0A#).
+   ---------------------------
+   -- Exception_Name_Length --
+   ---------------------------
 
-   --  The Exception_Name and Message lines are omitted in the abort
-   --  signal case, since this is not really an exception, and the only
-   --  use of this routine is internal for printing termination output.
+   function Exception_Name_Length
+     (Id : Exception_Id) return Natural is
+   begin
+      --  What is stored in the internal Name buffer includes a terminating
+      --  null character that we never care about.
 
-   --  WARNING: if the format of the generated string is changed, please note
-   --  that an equivalent modification to the routine String_To_EO must be
-   --  made to preserve proper functioning of the stream attributes.
+      return Id.Name_Length - 1;
+   end Exception_Name_Length;
 
-   function Exception_Information (X : Exception_Occurrence) return String is
+   function Exception_Name_Length
+     (X : Exception_Occurrence) return Natural is
+   begin
+      return Exception_Name_Length (X.Id);
+   end Exception_Name_Length;
 
-      --  This information is now built using the circuitry introduced in
-      --  association with the support of traceback decorators, as the
-      --  catenation of the exception basic information and the call chain
-      --  backtrace in its basic form.
+   ------------------------------
+   -- Exception_Message_Length --
+   ------------------------------
 
-      Basic_Info : constant String  := Basic_Exception_Information (X);
-      Tback_Info : constant String  := Basic_Exception_Traceback (X);
+   function Exception_Message_Length
+     (X : Exception_Occurrence) return Natural is
+   begin
+      return X.Msg_Length;
+   end Exception_Message_Length;
 
-      Basic_Len  : constant Natural := Basic_Info'Length;
-      Tback_Len  : constant Natural := Tback_Info'Length;
+   -------------------------------
+   -- Basic_Exception_Traceback --
+   -------------------------------
 
-      Info : String (1 .. Basic_Len + Tback_Len);
-      Ptr  : Natural := 0;
+   function Basic_Exception_Traceback
+     (X : Exception_Occurrence) return String
+   is
+      Info : aliased String (1 .. Basic_Exception_Tback_Maxlength (X));
+      Ptr  : Natural := Info'First - 1;
 
    begin
-      Append_Info_String (Basic_Info, Info, Ptr);
-      Append_Info_String (Tback_Info, Info, Ptr);
+      Append_Info_Basic_Exception_Traceback (X, Info, Ptr);
+      return Info (Info'First .. Ptr);
+   end Basic_Exception_Traceback;
 
-      return Info;
-   end Exception_Information;
+   ---------------------------
+   -- Exception_Information --
+   ---------------------------
+
+   function Exception_Information
+     (X : Exception_Occurrence) return String
+   is
+      Info : String (1 .. Exception_Info_Maxlength (X));
+      Ptr  : Natural := Info'First - 1;
 
+   begin
+      Append_Info_Exception_Information (X, Info, Ptr);
+      return Info (Info'First .. Ptr);
+   end Exception_Information;
 
    -------------------------
    -- Set_Exception_C_Msg --
@@ -457,11 +663,10 @@ package body Exception_Data is
    function Tailored_Exception_Traceback
      (X : Exception_Occurrence) return String
    is
-      --  We indeed reference the decorator *wrapper* from here and not the
-      --  decorator itself. The purpose of the local variable Wrapper is to
-      --  prevent a potential crash by race condition in the code below. The
-      --  atomicity of this assignment is enforced by pragma Atomic in
-      --  System.Soft_Links.
+      --  We reference the decorator *wrapper* here and not the decorator
+      --  itself. The purpose of the local variable Wrapper is to prevent a
+      --  potential race condition in the code below. The atomicity of this
+      --  assignment is enforced by pragma Atomic in System.Soft_Links.
 
       --  The potential race condition here, if no local variable was used,
       --  relates to the test upon the wrapper's value and the call, which
@@ -487,33 +692,19 @@ package body Exception_Data is
    function Tailored_Exception_Information
      (X : Exception_Occurrence) return String
    is
-      --  The tailored exception information is simply the basic information
+      --  The tailored exception information is the basic information
       --  associated with the tailored call chain backtrace.
 
-      Basic_Info : constant String  := Basic_Exception_Information (X);
       Tback_Info : constant String  := Tailored_Exception_Traceback (X);
-
-      Basic_Len  : constant Natural := Basic_Info'Length;
       Tback_Len  : constant Natural := Tback_Info'Length;
 
-      Info : String (1 .. Basic_Len + Tback_Len);
-      Ptr  : Natural := 0;
+      Info : String (1 .. Basic_Exception_Info_Maxlength (X) + Tback_Len);
+      Ptr  : Natural := Info'First - 1;
 
    begin
-      Append_Info_String (Basic_Info, Info, Ptr);
+      Append_Info_Basic_Exception_Information (X, Info, Ptr);
       Append_Info_String (Tback_Info, Info, Ptr);
-
-      return Info;
-   end Tailored_Exception_Information;
-
-   procedure Tailored_Exception_Information
-     (X    : Exception_Occurrence;
-      Buff : in out String;
-      Last : in out Integer)
-   is
-   begin
-      Append_Info_String (Basic_Exception_Information (X), Buff, Last);
-      Append_Info_String (Tailored_Exception_Traceback (X), Buff, Last);
+      return Info (Info'First .. Ptr);
    end Tailored_Exception_Information;
 
 end Exception_Data;
index 938f04b..835c2cb 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2003 Free Software Foundation, Inc.          --
+--          Copyright (C) 1992-2004 Free Software Foundation, Inc.          --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -57,8 +57,7 @@ package body Exception_Traces is
 
    procedure Last_Chance_Handler
      (Except :  Exception_Occurrence);
-   pragma Import
-     (C, Last_Chance_Handler, "__gnat_last_chance_handler");
+   pragma Import (C, Last_Chance_Handler, "__gnat_last_chance_handler");
    pragma No_Return (Last_Chance_Handler);
    --  Users can replace the default version of this routine,
    --  Ada.Exceptions.Last_Chance_Handler.
@@ -76,11 +75,6 @@ package body Exception_Traces is
    --  latter case because Notify_Handled_Exception may be called for an
    --  actually unhandled occurrence in the Front-End-SJLJ case.
 
-   procedure To_Stderr (S : String);
-   pragma Export (Ada, To_Stderr, "__gnat_to_stderr");
-   --  Little routine to output string to stderr that is also used
-   --  in the tasking run time.
-
    ---------------------------------
    -- Debugger Interface Routines --
    ---------------------------------
@@ -185,8 +179,6 @@ package body Exception_Traces is
    -- Unhandled_Exception_Terminate --
    -----------------------------------
 
-   type int is new Integer;
-
    procedure Unhandled_Exception_Terminate is
       Excep : constant EOA := Save_Occurrence (Get_Current_Excep.all.all);
       --  This occurrence will be used to display a message after finalization.
@@ -198,22 +190,6 @@ package body Exception_Traces is
       Last_Chance_Handler (Excep.all);
    end Unhandled_Exception_Terminate;
 
-   ---------------
-   -- To_Stderr --
-   ---------------
-
-   procedure To_Stderr (S : String) is
-      procedure put_char_stderr (C : int);
-      pragma Import (C, put_char_stderr, "put_char_stderr");
-
-   begin
-      for J in 1 .. S'Length loop
-         if S (J) /= ASCII.CR then
-            put_char_stderr (Character'Pos (S (J)));
-         end if;
-      end loop;
-   end To_Stderr;
-
 
    ------------------------------------
    -- Handling GNAT.Exception_Traces --
index 0f06fd3..3f82937 100644 (file)
@@ -1065,7 +1065,7 @@ package body Clean is
    begin
       --  Do the necessary initializations
 
-      Initialize;
+      Clean.Initialize;
 
       --  Parse the command line, getting the switches and the executable names
 
index 2438d3f..c017d6d 100644 (file)
@@ -3088,6 +3088,44 @@ package body Freeze is
          else
             Append (F_Node, Result);
          end if;
+
+         --  A final pass over record types with discriminants. If the type
+         --  has an incomplete declaration, there may be constrained access
+         --  subtypes declared elsewhere, which do not depend on the discrimi-
+         --  nants of the type, and which are used as component types (i.e.
+         --  the full view is a recursive type). The designated types of these
+         --  subtypes can only be elaborated after the type itself, and they
+         --  need an itype reference.
+
+         if Ekind (E) = E_Record_Type
+           and then Has_Discriminants (E)
+         then
+            declare
+               Comp : Entity_Id;
+               IR   : Node_Id;
+               Typ  : Entity_Id;
+
+            begin
+               Comp := First_Component (E);
+
+               while Present (Comp) loop
+                  Typ  := Etype (Comp);
+
+                  if Ekind (Comp) = E_Component
+                    and then Is_Access_Type (Typ)
+                    and then Scope (Typ) /= E
+                    and then Base_Type (Designated_Type (Typ)) = E
+                    and then Is_Itype (Designated_Type (Typ))
+                  then
+                     IR := Make_Itype_Reference (Sloc (Comp));
+                     Set_Itype (IR, Designated_Type (Typ));
+                     Append (IR, Result);
+                  end if;
+
+                  Next_Component (Comp);
+               end loop;
+            end;
+         end if;
       end if;
 
       --  When a type is frozen, the first subtype of the type is frozen as
index 5594bba..7f39b00 100644 (file)
@@ -2938,7 +2938,7 @@ package body Makegpr is
 
    procedure Gprmake is
    begin
-      Initialize;
+      Makegpr.Initialize;
 
       if Verbose_Mode then
          Write_Eol;
index 152d272..328d5a5 100644 (file)
@@ -66,7 +66,7 @@ package body MLib.Utl is
       Line_Length : Natural := 0;
 
    begin
-      Initialize;
+      Utl.Initialize;
 
       Arguments :=
         new String_List (1 .. 1 + Ar_Options'Length + Objects'Length);
@@ -177,7 +177,7 @@ package body MLib.Utl is
 
       Driver  : String_Access;
    begin
-      Initialize;
+      Utl.Initialize;
 
       if Driver_Name = No_Name then
          Driver := Gcc_Exec;
index 48da307..0b6a238 100644 (file)
@@ -2820,7 +2820,7 @@ begin
       Lib_Search_Directories.Set_Last (Primary_Directory);
       Lib_Search_Directories.Table (Primary_Directory) := new String'("");
 
-      Initialize;
+      Osint.Initialize;
    end Initialization;
 
 end Osint;
diff --git a/gcc/ada/s-solita.adb b/gcc/ada/s-solita.adb
new file mode 100644 (file)
index 0000000..4144acc
--- /dev/null
@@ -0,0 +1,164 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT COMPILER COMPONENTS                         --
+--                                                                          --
+--             S Y S T E M . S O F T _ L I N K S . T A S K I N G            --
+--                                                                          --
+--                                 B o d y                                  --
+--                                                                          --
+--             Copyright (C) 2004, Free Software Foundation, Inc.           --
+--                                                                          --
+-- GNAT is free software;  you can  redistribute it  and/or modify it under --
+-- terms of the  GNU General Public License as published  by the Free Soft- --
+-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
+-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
+-- for  more details.  You should have  received  a copy of the GNU General --
+-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
+-- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
+-- MA 02111-1307, USA.                                                      --
+--                                                                          --
+-- As a special exception,  if other files  instantiate  generics from this --
+-- unit, or you link  this unit with other files  to produce an executable, --
+-- this  unit  does not  by itself cause  the resulting  executable  to  be --
+-- covered  by the  GNU  General  Public  License.  This exception does not --
+-- however invalidate  any other reasons why  the executable file  might be --
+-- covered by the  GNU Public License.                                      --
+--                                                                          --
+-- GNAT was originally developed  by the GNAT team at  New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc.      --
+--                                                                          --
+------------------------------------------------------------------------------
+
+--  This package contains the tasking versions soft links.
+
+pragma Style_Checks (All_Checks);
+--  Turn off subprogram alpha ordering check, since we group soft link
+--  bodies and dummy soft link bodies together separately in this unit.
+
+pragma Polling (Off);
+--  Turn polling off for this package. We don't need polling during any
+--  of the routines in this package, and more to the point, if we try
+--  to poll it can cause infinite loops.
+
+with System.Task_Primitives.Operations;
+--  Used for Self
+--           Timed_Delay
+
+package body System.Soft_Links.Tasking is
+
+   package STPO renames System.Task_Primitives.Operations;
+   package SSL  renames System.Soft_Links;
+
+   ----------------
+   -- Local Data --
+   ----------------
+
+   Initialized : Boolean := False;
+   --  Boolean flag that indicates whether the tasking soft links have
+   --  already been set.
+
+   ----------------------------------------------------------------------
+   -- Tasking versions of some services needed by non-tasking programs --
+   ----------------------------------------------------------------------
+
+   function  Get_Jmpbuf_Address return  Address;
+   procedure Set_Jmpbuf_Address (Addr : Address);
+   --  Get/Set Jmpbuf_Address for current task
+
+   function  Get_Sec_Stack_Addr return  Address;
+   procedure Set_Sec_Stack_Addr (Addr : Address);
+   --  Get/Set location of current task's secondary stack
+
+   function  Get_Machine_State_Addr return Address;
+   procedure Set_Machine_State_Addr (Addr : Address);
+   --  Get/Set the address for storing the current task's machine state
+
+   function Get_Current_Excep return SSL.EOA;
+   --  Task-safe version of SSL.Get_Current_Excep
+
+   procedure Timed_Delay_T (Time : Duration; Mode : Integer);
+   --  Task-safe version of SSL.Timed_Delay
+
+   ----------------------
+   -- Soft-Link Bodies --
+   ----------------------
+
+   function Get_Current_Excep return SSL.EOA is
+   begin
+      return STPO.Self.Common.Compiler_Data.Current_Excep'Access;
+   end Get_Current_Excep;
+
+   function Get_Jmpbuf_Address return  Address is
+   begin
+      return STPO.Self.Common.Compiler_Data.Jmpbuf_Address;
+   end Get_Jmpbuf_Address;
+
+   function Get_Machine_State_Addr return Address is
+   begin
+      return STPO.Self.Common.Compiler_Data.Machine_State_Addr;
+   end Get_Machine_State_Addr;
+
+   function Get_Sec_Stack_Addr return  Address is
+   begin
+      return STPO.Self.Common.Compiler_Data.Sec_Stack_Addr;
+   end Get_Sec_Stack_Addr;
+
+   procedure Set_Jmpbuf_Address (Addr : Address) is
+   begin
+      STPO.Self.Common.Compiler_Data.Jmpbuf_Address := Addr;
+   end Set_Jmpbuf_Address;
+
+   procedure Set_Machine_State_Addr (Addr : Address) is
+   begin
+      STPO.Self.Common.Compiler_Data.Machine_State_Addr := Addr;
+   end Set_Machine_State_Addr;
+
+   procedure Set_Sec_Stack_Addr (Addr : Address) is
+   begin
+      STPO.Self.Common.Compiler_Data.Sec_Stack_Addr := Addr;
+   end Set_Sec_Stack_Addr;
+
+   procedure Timed_Delay_T (Time : Duration; Mode : Integer) is
+   begin
+      STPO.Timed_Delay (STPO.Self, Time, Mode);
+   end Timed_Delay_T;
+
+   -----------------------------
+   -- Init_Tasking_Soft_Links --
+   -----------------------------
+
+   procedure Init_Tasking_Soft_Links is
+   begin
+      --  If the tasking soft links have already been initialized do not
+      --  repeat it.
+
+      if not Initialized then
+         --  Mark tasking soft links as initialized
+
+         Initialized := True;
+
+         --  The application being executed uses tasking so that the tasking
+         --  version of the following soft links need to be used.
+
+         SSL.Get_Jmpbuf_Address     := Get_Jmpbuf_Address'Access;
+         SSL.Set_Jmpbuf_Address     := Set_Jmpbuf_Address'Access;
+         SSL.Get_Sec_Stack_Addr     := Get_Sec_Stack_Addr'Access;
+         SSL.Set_Sec_Stack_Addr     := Set_Sec_Stack_Addr'Access;
+         SSL.Get_Machine_State_Addr := Get_Machine_State_Addr'Access;
+         SSL.Set_Machine_State_Addr := Set_Machine_State_Addr'Access;
+         SSL.Get_Current_Excep      := Get_Current_Excep'Access;
+         SSL.Timed_Delay            := Timed_Delay_T'Access;
+
+         --  No need to create a new Secondary Stack, since we will use the
+         --  default one created in s-secsta.adb
+
+         SSL.Set_Sec_Stack_Addr     (SSL.Get_Sec_Stack_Addr_NT);
+         SSL.Set_Jmpbuf_Address     (SSL.Get_Jmpbuf_Address_NT);
+         SSL.Set_Machine_State_Addr (SSL.Get_Machine_State_Addr_NT);
+      end if;
+
+   end Init_Tasking_Soft_Links;
+
+end System.Soft_Links.Tasking;
diff --git a/gcc/ada/s-solita.ads b/gcc/ada/s-solita.ads
new file mode 100644 (file)
index 0000000..1b9dae4
--- /dev/null
@@ -0,0 +1,46 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT COMPILER COMPONENTS                         --
+--                                                                          --
+--             S Y S T E M . S O F T _ L I N K S . T A S K I N G            --
+--                                                                          --
+--                                 S p e c                                  --
+--                                                                          --
+--             Copyright (C) 2004, Free Software Foundation, Inc.           --
+--                                                                          --
+-- GNAT is free software;  you can  redistribute it  and/or modify it under --
+-- terms of the  GNU General Public License as published  by the Free Soft- --
+-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
+-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
+-- for  more details.  You should have  received  a copy of the GNU General --
+-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
+-- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
+-- MA 02111-1307, USA.                                                      --
+--                                                                          --
+-- As a special exception,  if other files  instantiate  generics from this --
+-- unit, or you link  this unit with other files  to produce an executable, --
+-- this  unit  does not  by itself cause  the resulting  executable  to  be --
+-- covered  by the  GNU  General  Public  License.  This exception does not --
+-- however invalidate  any other reasons why  the executable file  might be --
+-- covered by the  GNU Public License.                                      --
+--                                                                          --
+-- GNAT was originally developed  by the GNAT team at  New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc.      --
+--                                                                          --
+------------------------------------------------------------------------------
+
+--  This package contains the tasking versions soft links that are common
+--  to the full and the restricted run times. The rest of the required soft
+--  links are set by System.Tasking.Initialization and System.Tasking.Stages
+--  (full run time) or System.Tasking.Restricted.Stages (restricted run
+--  time).
+
+package System.Soft_Links.Tasking is
+
+   procedure Init_Tasking_Soft_Links;
+   --  Set the tasking soft links that are common to the full and the
+   --  restricted run times.
+
+end System.Soft_Links.Tasking;
index a5f6278..4a5b6af 100644 (file)
@@ -7,7 +7,7 @@
 --                                  B o d y                                 --
 --                                                                          --
 --             Copyright (C) 1991-1994, Florida State University            --
---             Copyright (C) 1995-2003, Ada Core Technologies               --
+--             Copyright (C) 1995-2004, Ada Core Technologies               --
 --                                                                          --
 -- GNARL is free software; you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -46,6 +46,9 @@ with System.Parameters;
 with System.Traces;
 --  used for Send_Trace_Info
 
+with System.Soft_Links.Tasking;
+--  Used for Init_Tasking_Soft_Links
+
 package body System.Tasking.Protected_Objects is
 
    use System.Task_Primitives.Operations;
@@ -137,4 +140,8 @@ package body System.Tasking.Protected_Objects is
       end if;
    end Unlock;
 
+begin
+   --  Ensure that tasking soft links are set when using protected objects
+
+   System.Soft_Links.Tasking.Init_Tasking_Soft_Links;
 end System.Tasking.Protected_Objects;
index be0c661..17c3ba6 100644 (file)
@@ -67,6 +67,9 @@ with System.Soft_Links;
 --  The GNARL must call these to be sure that all non-tasking
 --  Ada constructs will work.
 
+with System.Soft_Links.Tasking;
+--  Used for Init_Tasking_Soft_Links
+
 with System.Secondary_Stack;
 --  used for SS_Init;
 
@@ -105,21 +108,6 @@ package body System.Tasking.Restricted.Stages is
    --  all nested locks must be released before other tasks competing for the
    --  tasking lock are released.
 
-   --  See s-tasini.adb for more information on the following functions.
-
-   function Get_Jmpbuf_Address return Address;
-   procedure Set_Jmpbuf_Address (Addr : Address);
-
-   function Get_Sec_Stack_Addr return Address;
-   procedure Set_Sec_Stack_Addr (Addr : Address);
-
-   function  Get_Machine_State_Addr return Address;
-   procedure Set_Machine_State_Addr (Addr : Address);
-
-   function Get_Current_Excep return SSL.EOA;
-
-   procedure Timed_Delay_T (Time : Duration; Mode : Integer);
-
    -----------------------
    -- Local Subprograms --
    -----------------------
@@ -158,45 +146,6 @@ package body System.Tasking.Restricted.Stages is
       STPO.Unlock (Global_Task_Lock'Access, Global_Lock => True);
    end Task_Unlock;
 
-   ----------------------
-   -- Soft-Link Bodies --
-   ----------------------
-
-   function Get_Current_Excep return SSL.EOA is
-   begin
-      return STPO.Self.Common.Compiler_Data.Current_Excep'Access;
-   end Get_Current_Excep;
-
-   function Get_Jmpbuf_Address return  Address is
-   begin
-      return STPO.Self.Common.Compiler_Data.Jmpbuf_Address;
-   end Get_Jmpbuf_Address;
-
-   function Get_Machine_State_Addr return Address is
-   begin
-      return STPO.Self.Common.Compiler_Data.Machine_State_Addr;
-   end Get_Machine_State_Addr;
-
-   function Get_Sec_Stack_Addr return  Address is
-   begin
-      return STPO.Self.Common.Compiler_Data.Sec_Stack_Addr;
-   end Get_Sec_Stack_Addr;
-
-   procedure Set_Jmpbuf_Address (Addr : Address) is
-   begin
-      STPO.Self.Common.Compiler_Data.Jmpbuf_Address := Addr;
-   end Set_Jmpbuf_Address;
-
-   procedure Set_Machine_State_Addr (Addr : Address) is
-   begin
-      STPO.Self.Common.Compiler_Data.Machine_State_Addr := Addr;
-   end Set_Machine_State_Addr;
-
-   procedure Set_Sec_Stack_Addr (Addr : Address) is
-   begin
-      STPO.Self.Common.Compiler_Data.Sec_Stack_Addr := Addr;
-   end Set_Sec_Stack_Addr;
-
    ------------------
    -- Task_Wrapper --
    ------------------
@@ -262,15 +211,6 @@ package body System.Tasking.Restricted.Stages is
       end;
    end Task_Wrapper;
 
-   -------------------
-   -- Timed_Delay_T --
-   -------------------
-
-   procedure Timed_Delay_T (Time : Duration; Mode : Integer) is
-   begin
-      STPO.Timed_Delay (STPO.Self, Time, Mode);
-   end Timed_Delay_T;
-
    -----------------------
    -- Restricted GNARLI --
    -----------------------
@@ -566,27 +506,14 @@ package body System.Tasking.Restricted.Stages is
       --  Notify that the tasking run time has been elaborated so that
       --  the tasking version of the soft links can be used.
 
-      SSL.Lock_Task              := Task_Lock'Access;
-      SSL.Unlock_Task            := Task_Unlock'Access;
-
-      SSL.Get_Jmpbuf_Address     := Get_Jmpbuf_Address'Access;
-      SSL.Set_Jmpbuf_Address     := Set_Jmpbuf_Address'Access;
-      SSL.Get_Machine_State_Addr := Get_Machine_State_Addr'Access;
-      SSL.Set_Machine_State_Addr := Set_Machine_State_Addr'Access;
-      SSL.Get_Current_Excep      := Get_Current_Excep'Access;
-      SSL.Set_Jmpbuf_Address     (SSL.Get_Jmpbuf_Address_NT);
-      SSL.Set_Machine_State_Addr (SSL.Get_Machine_State_Addr_NT);
-
-      SSL.Get_Sec_Stack_Addr     := Get_Sec_Stack_Addr'Access;
-      SSL.Set_Sec_Stack_Addr     := Set_Sec_Stack_Addr'Access;
-
-      --  No need to create a new Secondary Stack, since we will use the
-      --  default one created in s-secsta.adb
+      SSL.Lock_Task   := Task_Lock'Access;
+      SSL.Unlock_Task := Task_Unlock'Access;
+      SSL.Adafinal    := Finalize_Global_Tasks'Access;
 
-      Set_Sec_Stack_Addr (SSL.Get_Sec_Stack_Addr_NT);
+      --  Initialize the tasking soft links (if not done yet) that are common
+      --  to the full and the restricted run times.
 
-      SSL.Timed_Delay            := Timed_Delay_T'Access;
-      SSL.Adafinal               := Finalize_Global_Tasks'Access;
+      SSL.Tasking.Init_Tasking_Soft_Links;
    end Init_RTS;
 
 begin
index d05654a..871b2d0 100644 (file)
@@ -60,6 +60,9 @@ with System.Soft_Links;
 --  used for the non-tasking routines (*_NT) that refer to global data.
 --  They are needed here before the tasking run time has been elaborated.
 
+with System.Soft_Links.Tasking;
+--  Used for Init_Tasking_Soft_Links
+
 with System.Tasking.Debug;
 --  used for Trace
 
@@ -87,9 +90,9 @@ package body System.Tasking.Initialization is
      (Ada, Current_Target_Exception, "__gnat_current_target_exception");
    --  Import this subprogram from the private part of Ada.Exceptions.
 
-   -----------------------------------------------------------------
-   -- Tasking versions of services needed by non-tasking programs --
-   -----------------------------------------------------------------
+   ----------------------------------------------------------------------
+   -- Tasking versions of some services needed by non-tasking programs --
+   ----------------------------------------------------------------------
 
    procedure Task_Lock;
    --  Locks out other tasks. Preceding a section of code by Task_Lock and
@@ -104,14 +107,6 @@ package body System.Tasking.Initialization is
    --  all nested locks must be released before other tasks competing for the
    --  tasking lock are released.
 
-   function  Get_Jmpbuf_Address return  Address;
-   procedure Set_Jmpbuf_Address (Addr : Address);
-   --  Get/Set Jmpbuf_Address for current task
-
-   function  Get_Sec_Stack_Addr return  Address;
-   procedure Set_Sec_Stack_Addr (Addr : Address);
-   --  Get/Set location of current task's secondary stack
-
    function  Get_Exc_Stack_Addr return Address;
    --  Get the exception stack for the current task
 
@@ -119,16 +114,6 @@ package body System.Tasking.Initialization is
    --  Self_ID is the Task_Id of the task that gets the exception stack.
    --  For Self_ID = Null_Address, the current task gets the exception stack.
 
-   function  Get_Machine_State_Addr return Address;
-   procedure Set_Machine_State_Addr (Addr : Address);
-   --  Get/Set the address for storing the current task's machine state
-
-   function Get_Current_Excep return SSL.EOA;
-   --  Task-safe version of SSL.Get_Current_Excep
-
-   procedure Timed_Delay_T (Time : Duration; Mode : Integer);
-   --  Task-safe version of SSL.Timed_Delay
-
    function Get_Stack_Info return Stack_Checking.Stack_Access;
    --  Get access to the current task's Stack_Info
 
@@ -404,30 +389,21 @@ package body System.Tasking.Initialization is
          SSL.Abort_Undefer := Undefer_Abortion'Access;
       end if;
 
-      SSL.Update_Exception       := Update_Exception'Access;
-      SSL.Lock_Task              := Task_Lock'Access;
-      SSL.Unlock_Task            := Task_Unlock'Access;
-      SSL.Get_Jmpbuf_Address     := Get_Jmpbuf_Address'Access;
-      SSL.Set_Jmpbuf_Address     := Set_Jmpbuf_Address'Access;
-      SSL.Get_Sec_Stack_Addr     := Get_Sec_Stack_Addr'Access;
-      SSL.Set_Sec_Stack_Addr     := Set_Sec_Stack_Addr'Access;
-      SSL.Get_Exc_Stack_Addr     := Get_Exc_Stack_Addr'Access;
-      SSL.Set_Exc_Stack_Addr     := Set_Exc_Stack_Addr'Access;
-      SSL.Get_Machine_State_Addr := Get_Machine_State_Addr'Access;
-      SSL.Set_Machine_State_Addr := Set_Machine_State_Addr'Access;
-      SSL.Get_Current_Excep      := Get_Current_Excep'Access;
-      SSL.Timed_Delay            := Timed_Delay_T'Access;
-      SSL.Check_Abort_Status     := Check_Abort_Status'Access;
-      SSL.Get_Stack_Info         := Get_Stack_Info'Access;
-      SSL.Task_Name              := Task_Name'Access;
-
-      --  No need to create a new Secondary Stack, since we will use the
-      --  default one created in s-secsta.adb
-
-      SSL.Set_Sec_Stack_Addr     (SSL.Get_Sec_Stack_Addr_NT);
-      SSL.Set_Exc_Stack_Addr     (Null_Address, SSL.Get_Exc_Stack_Addr_NT);
-      SSL.Set_Jmpbuf_Address     (SSL.Get_Jmpbuf_Address_NT);
-      SSL.Set_Machine_State_Addr (SSL.Get_Machine_State_Addr_NT);
+      SSL.Update_Exception   := Update_Exception'Access;
+      SSL.Lock_Task          := Task_Lock'Access;
+      SSL.Unlock_Task        := Task_Unlock'Access;
+      SSL.Get_Exc_Stack_Addr := Get_Exc_Stack_Addr'Access;
+      SSL.Set_Exc_Stack_Addr := Set_Exc_Stack_Addr'Access;
+      SSL.Check_Abort_Status := Check_Abort_Status'Access;
+      SSL.Get_Stack_Info     := Get_Stack_Info'Access;
+      SSL.Task_Name          := Task_Name'Access;
+
+      SSL.Set_Exc_Stack_Addr (Null_Address, SSL.Get_Exc_Stack_Addr_NT);
+
+      --  Initialize the tasking soft links (if not done yet) that are common
+      --  to the full and the restricted run times.
+
+      SSL.Tasking.Init_Tasking_Soft_Links;
 
       --  Install tasking locks in the GCC runtime.
 
@@ -920,31 +896,11 @@ package body System.Tasking.Initialization is
    -- Soft-Link Bodies --
    ----------------------
 
-   function Get_Current_Excep return SSL.EOA is
-   begin
-      return STPO.Self.Common.Compiler_Data.Current_Excep'Access;
-   end Get_Current_Excep;
-
    function Get_Exc_Stack_Addr return Address is
    begin
       return STPO.Self.Common.Compiler_Data.Exc_Stack_Addr;
    end Get_Exc_Stack_Addr;
 
-   function Get_Jmpbuf_Address return  Address is
-   begin
-      return STPO.Self.Common.Compiler_Data.Jmpbuf_Address;
-   end Get_Jmpbuf_Address;
-
-   function Get_Machine_State_Addr return Address is
-   begin
-      return STPO.Self.Common.Compiler_Data.Machine_State_Addr;
-   end Get_Machine_State_Addr;
-
-   function Get_Sec_Stack_Addr return  Address is
-   begin
-      return STPO.Self.Common.Compiler_Data.Sec_Stack_Addr;
-   end Get_Sec_Stack_Addr;
-
    function Get_Stack_Info return Stack_Checking.Stack_Access is
    begin
       return STPO.Self.Common.Compiler_Data.Pri_Stack_Info'Access;
@@ -960,26 +916,6 @@ package body System.Tasking.Initialization is
       Me.Common.Compiler_Data.Exc_Stack_Addr := Addr;
    end Set_Exc_Stack_Addr;
 
-   procedure Set_Jmpbuf_Address (Addr : Address) is
-   begin
-      STPO.Self.Common.Compiler_Data.Jmpbuf_Address := Addr;
-   end Set_Jmpbuf_Address;
-
-   procedure Set_Machine_State_Addr (Addr : Address) is
-   begin
-      STPO.Self.Common.Compiler_Data.Machine_State_Addr := Addr;
-   end Set_Machine_State_Addr;
-
-   procedure Set_Sec_Stack_Addr (Addr : Address) is
-   begin
-      STPO.Self.Common.Compiler_Data.Sec_Stack_Addr := Addr;
-   end Set_Sec_Stack_Addr;
-
-   procedure Timed_Delay_T (Time : Duration; Mode : Integer) is
-   begin
-      STPO.Timed_Delay (STPO.Self, Time, Mode);
-   end Timed_Delay_T;
-
    -----------------------
    -- Soft-Link Dummies --
    -----------------------
index 11d4c01..73c6b33 100644 (file)
@@ -6075,11 +6075,22 @@ package body Sem_Ch3 is
          Set_Ekind (Def_Id, E_Class_Wide_Subtype);
 
       else
-         --  Incomplete type. Attach subtype to list of dependents, to be
-         --  completed with full view of parent type.
+         --  Incomplete type.  attach subtype to list of dependents, to be
+         --  completed with full view of parent type,  unless is it the
+         --  designated subtype of a record component within an init_proc.
+         --  This last case arises for a component of an access type whose
+         --  designated type is incomplete (e.g. a Taft Amendment type).
+         --  The designated subtype is within an inner scope, and needs no
+         --  elaboration, because only the access type is needed in the
+         --  initialization procedure.
 
          Set_Ekind (Def_Id, Ekind (T));
-         Append_Elmt (Def_Id, Private_Dependents (T));
+
+         if For_Access and then Within_Init_Proc then
+            null;
+         else
+            Append_Elmt (Def_Id, Private_Dependents (T));
+         end if;
       end if;
 
       Set_Etype             (Def_Id, T);
@@ -6831,6 +6842,12 @@ package body Sem_Ch3 is
          if Has_Discriminants (Full_Base) then
             Set_Discriminant_Constraint
               (Full, Discriminant_Constraint (Full_Base));
+
+            --  The partial view may have been indefinite, the full view
+            --  might not be.
+
+            Set_Has_Unknown_Discriminants
+              (Full, Has_Unknown_Discriminants (Full_Base));
          end if;
       end if;
 
index f674ba6..3831b67 100644 (file)
@@ -28,6 +28,7 @@ with Atree;    use Atree;
 with Checks;   use Checks;
 with Debug;    use Debug;
 with Einfo;    use Einfo;
+with Elists;   use Elists;
 with Errout;   use Errout;
 with Exp_Util; use Exp_Util;
 with Fname;    use Fname;
@@ -233,6 +234,9 @@ package body Sem_Ch4 is
    --  to a subprogram, and the call F (X)  interpreted as F.all (X). In
    --  this case the call may be overloaded with both interpretations.
 
+   function Try_Object_Operation (N : Node_Id) return Boolean;
+   --  Ada 2005 (AI-252): Give support to the object operation notation
+
    ------------------------
    -- Ambiguous_Operands --
    ------------------------
@@ -2677,6 +2681,15 @@ package body Sem_Ch4 is
             Next_Entity (Comp);
          end loop;
 
+         --  Ada 2005 (AI-252)
+
+         if Ada_Version >= Ada_05
+           and then Is_Tagged_Type (Prefix_Type)
+           and then Try_Object_Operation (N)
+         then
+            return;
+         end if;
+
       elsif Is_Private_Type (Prefix_Type) then
 
          --  Allow access only to discriminants of the type. If the
@@ -4635,4 +4648,309 @@ package body Sem_Ch4 is
 
    end Try_Indexed_Call;
 
+   --------------------------
+   -- Try_Object_Operation --
+   --------------------------
+
+   function Try_Object_Operation (N : Node_Id) return Boolean is
+      Obj        : constant Node_Id := Prefix (N);
+      Obj_Type   : Entity_Id;
+      Actual     : Node_Id;
+      Last_Node  : Node_Id;
+      --  Last_Node is used to free all the nodes generated while trying the
+      --  alternatives. NOTE: This must be removed because it is considered
+      --  too low level
+      use Atree_Private_Part;
+
+      function Try_Replacement
+        (New_Prefix : Entity_Id;
+         New_Subprg : Node_Id;
+         New_Formal : Node_Id;
+         Nam_Ent    : Entity_Id) return Boolean;
+      --  Replace the node with the Object.Operation notation by the
+      --  equivalent node with the Package.Operation (Object, ...) notation
+      --
+      --  Nam_Ent is the entity that provides the formals against which
+      --  the actuals are checked. If the actuals are compatible with
+      --  Ent_Nam, this function returns true.
+
+      function Try_Primitive_Operations
+        (New_Prefix : Entity_Id;
+         New_Subprg : Node_Id;
+         Obj        : Node_Id;
+         Obj_Type   : Entity_Id) return Boolean;
+      --  Traverse the list of primitive subprograms to look for the
+      --  subprogram.
+
+      function Try_Class_Wide_Operation
+        (New_Subprg : Node_Id;
+         Obj        : Node_Id;
+         Obj_Type   : Entity_Id) return Boolean;
+      --  Traverse all the ancestor types to look for a class-wide
+      --  subprogram
+
+      ------------------------------
+      -- Try_Primitive_Operations --
+      ------------------------------
+
+      function Try_Primitive_Operations
+        (New_Prefix : Entity_Id;
+         New_Subprg : Node_Id;
+         Obj        : Node_Id;
+         Obj_Type   : Entity_Id) return Boolean
+      is
+         Deref      : Node_Id;
+         Elmt       : Elmt_Id;
+         Prim_Op    : Entity_Id;
+
+      begin
+         --  Look for the subprogram in the list of primitive operations.
+         --  This case is simple because all the primitive operations are
+         --  implicitly inherited and thus we have a candidate as soon as
+         --  we find a primitive subprogram with the same name. The latter
+         --  analysis after the node replacement will resolve it.
+
+         Elmt := First_Elmt (Primitive_Operations (Obj_Type));
+
+         while Present (Elmt) loop
+            Prim_Op := Node (Elmt);
+
+            if Chars (Prim_Op) = Chars (New_Subprg) then
+               if Try_Replacement (New_Prefix => New_Prefix,
+                                   New_Subprg => New_Subprg,
+                                   New_Formal => Obj,
+                                   Nam_Ent    => Prim_Op)
+               then
+                  return True;
+
+               --  Try the implicit dereference in case of access type
+
+               elsif Is_Access_Type (Etype (Obj)) then
+                  Deref := Make_Explicit_Dereference (Sloc (Obj), Obj);
+                  Set_Etype (Deref, Obj_Type);
+
+                  if Try_Replacement (New_Prefix => New_Prefix,
+                                      New_Subprg => New_Subprg,
+                                      New_Formal => Deref,
+                                      Nam_Ent    => Prim_Op)
+                  then
+                     return True;
+                  end if;
+               end if;
+            end if;
+
+            Next_Elmt (Elmt);
+         end loop;
+
+         return False;
+      end Try_Primitive_Operations;
+
+      ------------------------------
+      -- Try_Class_Wide_Operation --
+      ------------------------------
+
+      function Try_Class_Wide_Operation
+        (New_Subprg : Node_Id;
+         Obj        : Node_Id;
+         Obj_Type   : Entity_Id) return Boolean
+      is
+         Deref      : Node_Id;
+         Hom        : Entity_Id;
+         Typ        : Entity_Id;
+
+      begin
+         Typ := Obj_Type;
+
+         loop
+            --  For each parent subtype we traverse all the homonym chain
+            --  looking for a candidate class-wide subprogram
+
+            Hom := Current_Entity (New_Subprg);
+
+            while Present (Hom) loop
+               if (Ekind (Hom) = E_Procedure
+                     or else Ekind (Hom) = E_Function)
+                   and then Present (First_Entity (Hom))
+                   and then Etype (First_Entity (Hom)) = Class_Wide_Type (Typ)
+               then
+                  if Try_Replacement
+                    (New_Prefix => Scope (Hom),
+                     New_Subprg => Make_Identifier (Sloc (N), Chars (Hom)),
+                     New_Formal => Obj,
+                     Nam_Ent    => Hom)
+                  then
+                     return True;
+
+                  --  Try the implicit dereference in case of access type
+
+                  elsif Is_Access_Type (Etype (Obj)) then
+                     Deref := Make_Explicit_Dereference (Sloc (Obj), Obj);
+                     Set_Etype (Deref, Obj_Type);
+
+                     if Try_Replacement
+                       (New_Prefix => Scope (Hom),
+                        New_Subprg => Make_Identifier (Sloc (N), Chars (Hom)),
+                        New_Formal => Deref,
+                        Nam_Ent    => Hom)
+                     then
+                        return True;
+                     end if;
+                  end if;
+               end if;
+
+               Hom := Homonym (Hom);
+            end loop;
+
+            exit when Etype (Typ) = Typ;
+
+            Typ := Etype (Typ); --  Climb to the ancestor type
+         end loop;
+
+         return False;
+      end Try_Class_Wide_Operation;
+
+      ---------------------
+      -- Try_Replacement --
+      ---------------------
+
+      function Try_Replacement
+        (New_Prefix : Entity_Id;
+         New_Subprg : Node_Id;
+         New_Formal : Node_Id;
+         Nam_Ent    : Entity_Id) return Boolean
+      is
+         Loc             : constant Source_Ptr := Sloc (N);
+         Call_Node       : Node_Id;
+         New_Name        : Node_Id;
+         New_Actuals     : List_Id;
+         Node_To_Replace : Node_Id;
+         Success         : Boolean;
+
+      begin
+         --  Step 1. Build the replacement node: a subprogram call node
+         --  with the object as its first actual parameter
+
+         New_Name := Make_Selected_Component (Loc,
+                       Prefix        => New_Reference_To (New_Prefix, Loc),
+                       Selector_Name => New_Copy_Tree (New_Subprg));
+
+         New_Actuals := New_List (New_Copy_Tree (New_Formal));
+
+         if (Nkind (Parent (N)) = N_Procedure_Call_Statement
+               or else Nkind (Parent (N)) = N_Function_Call)
+             and then N /= First (Parameter_Associations (Parent (N)))
+               --  Protect against recursive call; It occurs in "..:= F (O.P)"
+         then
+            Node_To_Replace := Parent (N);
+
+            Append_List_To
+              (New_Actuals,
+               New_Copy_List (Parameter_Associations (Node_To_Replace)));
+
+            if Nkind (Node_To_Replace) = N_Procedure_Call_Statement then
+               Call_Node :=
+                 Make_Procedure_Call_Statement (Loc, New_Name, New_Actuals);
+
+            else pragma Assert (Nkind (Node_To_Replace) = N_Function_Call);
+               Call_Node :=
+                 Make_Function_Call (Loc, New_Name, New_Actuals);
+            end if;
+
+         --  Case of a function without parameters
+
+         else
+            Node_To_Replace := N;
+
+            Call_Node :=
+              Make_Function_Call (Loc, New_Name, New_Actuals);
+         end if;
+
+         --  Step 2. Analyze the candidate replacement node. If it was
+         --  successfully analyzed then replace the original node and
+         --  carry out the full analysis to verify that there is no
+         --  conflict with overloaded subprograms.
+
+         --  To properly analyze the candidate we must initialize the type
+         --  of the result node of the call to the error type; it will be
+         --  reset if the type is successfully resolved.
+
+         Set_Etype (Call_Node, Any_Type);
+
+         Analyze_One_Call
+           (N       => Call_Node,
+            Nam     => Nam_Ent,
+            Report  => False,  -- do not post errors
+            Success => Success);
+
+         if Success then
+            --  Previous analysis transformed the node with the name
+            --  and we have to reset it to properly re-analyze it.
+
+            New_Name := Make_Selected_Component (Loc,
+                          Prefix        => New_Reference_To (New_Prefix, Loc),
+                          Selector_Name => New_Copy_Tree (New_Subprg));
+            Set_Name (Call_Node, New_Name);
+
+            Set_Analyzed (Call_Node, False);
+            Set_Parent (Call_Node, Parent (Node_To_Replace));
+            Replace (Node_To_Replace, Call_Node);
+            Analyze (Node_To_Replace);
+            return True;
+
+         --  Free all the nodes used for this test and return
+         else
+            Nodes.Set_Last (Last_Node);
+            return False;
+         end if;
+      end Try_Replacement;
+
+   --  Start of processing for Try_Object_Operation
+
+   begin
+      --  Find the type of the object
+
+      Obj_Type := Etype (Obj);
+
+      if Is_Access_Type (Obj_Type) then
+         Obj_Type := Designated_Type (Obj_Type);
+      end if;
+
+      if Ekind (Obj_Type) = E_Private_Subtype then
+         Obj_Type := Base_Type (Obj_Type);
+      end if;
+
+      if Is_Class_Wide_Type (Obj_Type) then
+         Obj_Type := Etype (Class_Wide_Type (Obj_Type));
+      end if;
+
+      --  Analyze the actuals
+
+      if (Nkind (Parent (N)) = N_Procedure_Call_Statement
+            or else Nkind (Parent (N)) = N_Function_Call)
+          and then N /= First (Parameter_Associations (Parent (N)))
+            --  Protects against recursive call in case of "..:= F (O.Proc)"
+      then
+         Actual := First (Parameter_Associations (Parent (N)));
+
+         while Present (Actual) loop
+            Analyze (Actual);
+            Check_Parameterless_Call (Actual);
+            Next_Actual (Actual);
+         end loop;
+      end if;
+
+      Last_Node := Last_Node_Id;
+
+      return Try_Primitive_Operations
+               (New_Prefix => Scope (Obj_Type),
+                New_Subprg => Selector_Name (N),
+                Obj        => Obj,
+                Obj_Type   => Obj_Type)
+           or else
+             Try_Class_Wide_Operation
+               (New_Subprg => Selector_Name (N),
+                Obj        => Obj,
+                Obj_Type   => Obj_Type);
+   end Try_Object_Operation;
+
 end Sem_Ch4;
index 55806aa..eeff994 100644 (file)
@@ -3592,7 +3592,11 @@ package body Sem_Ch8 is
 
          begin
             while Present (H) loop
-               if Scope (H) = Scope (Id) then
+               if Scope (H) = Scope (Id)
+                 and then
+                   (not Is_Hidden (H)
+                      or else Is_Immediately_Visible (H))
+               then
                   Collect_Interps (N);
                   exit;
                end if;
index 903b314..6b7a174 100644 (file)
@@ -297,6 +297,2036 @@ gnat_init_stmt_group ()
   REAL_ARITHMETIC (dconstmp5, RDIV_EXPR, dconstm1, dconst2);
 }
 \f
+/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Identifier,
+   to a GCC tree, which is returned.  GNU_RESULT_TYPE_P is a pointer to
+   where we should place the result type.  */
+
+static tree
+Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
+{
+  tree gnu_result_type;
+  tree gnu_result;
+  Node_Id gnat_temp, gnat_temp_type;
+
+  /* If the Etype of this node does not equal the Etype of the Entity,
+     something is wrong with the entity map, probably in generic
+     instantiation. However, this does not apply to types. Since we sometime
+     have strange Ekind's, just do this test for objects. Also, if the Etype of
+     the Entity is private, the Etype of the N_Identifier is allowed to be the
+     full type and also we consider a packed array type to be the same as the
+     original type. Similarly, a class-wide type is equivalent to a subtype of
+     itself. Finally, if the types are Itypes, one may be a copy of the other,
+     which is also legal.  */
+  gnat_temp = (Nkind (gnat_node) == N_Defining_Identifier
+              ? gnat_node : Entity (gnat_node));
+  gnat_temp_type = Etype (gnat_temp);
+
+  if (Etype (gnat_node) != gnat_temp_type
+      && ! (Is_Packed (gnat_temp_type)
+           && Etype (gnat_node) == Packed_Array_Type (gnat_temp_type))
+      && ! (Is_Class_Wide_Type (Etype (gnat_node)))
+      && ! (IN (Ekind (gnat_temp_type), Private_Kind)
+           && Present (Full_View (gnat_temp_type))
+           && ((Etype (gnat_node) == Full_View (gnat_temp_type))
+               || (Is_Packed (Full_View (gnat_temp_type))
+                   && (Etype (gnat_node)
+                       == Packed_Array_Type (Full_View (gnat_temp_type))))))
+      && (!Is_Itype (Etype (gnat_node)) || !Is_Itype (gnat_temp_type))
+      && (Ekind (gnat_temp) == E_Variable
+         || Ekind (gnat_temp) == E_Component
+         || Ekind (gnat_temp) == E_Constant
+         || Ekind (gnat_temp) == E_Loop_Parameter
+         || IN (Ekind (gnat_temp), Formal_Kind)))
+    gigi_abort (304);
+
+  /* If this is a reference to a deferred constant whose partial view is an
+     unconstrained private type, the proper type is on the full view of the
+     constant, not on the full view of the type, which may be unconstrained.
+
+     This may be a reference to a type, for example in the prefix of the
+     attribute Position, generated for dispatching code (see Make_DT in
+     exp_disp,adb). In that case we need the type itself, not is parent,
+     in particular if it is a derived type  */
+  if (Is_Private_Type (gnat_temp_type)
+      && Has_Unknown_Discriminants (gnat_temp_type)
+      && Present (Full_View (gnat_temp))
+      && ! Is_Type (gnat_temp))
+    {
+      gnat_temp = Full_View (gnat_temp);
+      gnat_temp_type = Etype (gnat_temp);
+      gnu_result_type = get_unpadded_type (gnat_temp_type);
+    }
+  else
+    {
+      /* Expand the type of this identitier first, in case it is an enumeral
+        literal, which only get made when the type is expanded.  There is no
+        order-of-elaboration issue here.  We want to use the Actual_Subtype if
+        it has already been elaborated, otherwise the Etype.  Avoid using
+        Actual_Subtype for packed arrays to simplify things.  */
+      if ((Ekind (gnat_temp) == E_Constant
+          || Ekind (gnat_temp) == E_Variable || Is_Formal (gnat_temp))
+         && ! (Is_Array_Type (Etype (gnat_temp))
+               && Present (Packed_Array_Type (Etype (gnat_temp))))
+         && Present (Actual_Subtype (gnat_temp))
+         && present_gnu_tree (Actual_Subtype (gnat_temp)))
+       gnat_temp_type = Actual_Subtype (gnat_temp);
+      else
+       gnat_temp_type = Etype (gnat_node);
+
+      gnu_result_type = get_unpadded_type (gnat_temp_type);
+    }
+
+  gnu_result = gnat_to_gnu_entity (gnat_temp, NULL_TREE, 0);
+
+  /* If we are in an exception handler, force this variable into memory to
+     ensure optimization does not remove stores that appear redundant but are
+     actually needed in case an exception occurs.
+
+     ??? Note that we need not do this if the variable is declared within the
+     handler, only if it is referenced in the handler and declared in an
+     enclosing block, but we have no way of testing that right now.
+
+     ??? Also, for now all we can do is make it volatile.  But we only
+     do this for SJLJ.  */
+  if (TREE_VALUE (gnu_except_ptr_stack) != 0
+      && TREE_CODE (gnu_result) == VAR_DECL)
+    TREE_THIS_VOLATILE (gnu_result) = TREE_SIDE_EFFECTS (gnu_result) = 1;
+
+  /* Some objects (such as parameters passed by reference, globals of
+     variable size, and renamed objects) actually represent the address
+     of the object.  In that case, we must do the dereference.  Likewise,
+     deal with parameters to foreign convention subprograms.  Call fold
+     here since GNU_RESULT may be a CONST_DECL.  */
+  if (DECL_P (gnu_result)
+      && (DECL_BY_REF_P (gnu_result)
+         || (TREE_CODE (gnu_result) == PARM_DECL
+             && DECL_BY_COMPONENT_PTR_P (gnu_result))))
+    {
+      int ro = DECL_POINTS_TO_READONLY_P (gnu_result);
+      tree initial;
+
+      if (TREE_CODE (gnu_result) == PARM_DECL
+         && DECL_BY_COMPONENT_PTR_P (gnu_result))
+       gnu_result
+         = build_unary_op (INDIRECT_REF, NULL_TREE,
+                           convert (build_pointer_type (gnu_result_type),
+                                    gnu_result));
+
+      /* If the object is constant, we try to do the dereference directly
+        through the DECL_INITIAL.  This is actually required in order to get
+        correct aliasing information for renamed objects that are components
+        of non-aliased aggregates, because the type of the renamed object and
+        that of the aggregate don't alias.
+
+        Note that we expect the initial value to have been stabilized.
+        If it contains e.g. a variable reference, we certainly don't want
+        to re-evaluate the variable each time the renaming is used.
+
+        Stabilization is currently not performed at the global level but
+        create_var_decl avoids setting DECL_INITIAL if the value is not
+        constant then, and we get to the pointer dereference below.
+
+        ??? Couldn't the aliasing issue show up again in this case ?
+        There is no obvious reason why not.  */
+      else if (TREE_READONLY (gnu_result)
+              && DECL_INITIAL (gnu_result)
+              /* Strip possible conversion to reference type.  */
+              && ((initial = TREE_CODE (DECL_INITIAL (gnu_result))
+                   == NOP_EXPR
+                   ? TREE_OPERAND (DECL_INITIAL (gnu_result), 0)
+                   : DECL_INITIAL (gnu_result), 1))
+              && TREE_CODE (initial) == ADDR_EXPR
+              && (TREE_CODE (TREE_OPERAND (initial, 0)) == ARRAY_REF
+                  || (TREE_CODE (TREE_OPERAND (initial, 0))
+                      == COMPONENT_REF)))
+       gnu_result = TREE_OPERAND (initial, 0);
+      else
+       gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE,
+                                    fold (gnu_result));
+
+      TREE_READONLY (gnu_result) = TREE_STATIC (gnu_result) = ro;
+    }
+
+  /* The GNAT tree has the type of a function as the type of its result.  Also
+     use the type of the result if the Etype is a subtype which is nominally
+     unconstrained.  But remove any padding from the resulting type.  */
+  if (TREE_CODE (TREE_TYPE (gnu_result)) == FUNCTION_TYPE
+      || Is_Constr_Subt_For_UN_Aliased (gnat_temp_type))
+    {
+      gnu_result_type = TREE_TYPE (gnu_result);
+      if (TREE_CODE (gnu_result_type) == RECORD_TYPE
+         && TYPE_IS_PADDING_P (gnu_result_type))
+       gnu_result_type = TREE_TYPE (TYPE_FIELDS (gnu_result_type));
+    }
+
+  /* We always want to return the underlying INTEGER_CST for an enumeration
+     literal to avoid the need to call fold in lots of places.  But don't do
+     this is the parent will be taking the address of this object.  */
+  if (TREE_CODE (gnu_result) == CONST_DECL)
+    {
+      gnat_temp = Parent (gnat_node);
+      if (DECL_CONST_CORRESPONDING_VAR (gnu_result) == 0
+         || (Nkind (gnat_temp) != N_Reference
+             && ! (Nkind (gnat_temp) == N_Attribute_Reference
+                   && ((Get_Attribute_Id (Attribute_Name (gnat_temp))
+                        == Attr_Address)
+                       || (Get_Attribute_Id (Attribute_Name (gnat_temp))
+                           == Attr_Access)
+                       || (Get_Attribute_Id (Attribute_Name (gnat_temp))
+                           == Attr_Unchecked_Access)
+                       || (Get_Attribute_Id (Attribute_Name (gnat_temp))
+                           == Attr_Unrestricted_Access)))))
+       gnu_result = DECL_INITIAL (gnu_result);
+    }
+
+  *gnu_result_type_p = gnu_result_type;
+  return gnu_result;
+}
+
+/* Subroutine of gnat_to_gnu to process gnat_node, an N_Pragma.  We don't
+   return anything.  */
+
+static void
+Pragma_to_gnu (Node_Id gnat_node)
+{
+  Node_Id gnat_temp;
+
+  /* Check for (and ignore) unrecognized pragma and do nothing if we are just
+     annotating types.  */
+  if (type_annotate_only
+      || ! Is_Pragma_Name (Chars (gnat_node)))
+    return;
+
+  switch (Get_Pragma_Id (Chars (gnat_node)))
+    {
+    case Pragma_Inspection_Point:
+      /* Do nothing at top level: all such variables are already viewable.  */
+      if (global_bindings_p ())
+       break;
+
+      for (gnat_temp = First (Pragma_Argument_Associations (gnat_node));
+          Present (gnat_temp);
+          gnat_temp = Next (gnat_temp))
+       {
+         tree gnu_expr = gnat_to_gnu (Expression (gnat_temp));
+
+         if (TREE_CODE (gnu_expr) == UNCONSTRAINED_ARRAY_REF)
+           gnu_expr = TREE_OPERAND (gnu_expr, 0);
+
+         gnu_expr = build1 (USE_STMT, void_type_node, gnu_expr);
+         add_stmt (gnu_expr);
+       }
+      break;
+
+    case Pragma_Optimize:
+      switch (Chars (Expression
+                    (First (Pragma_Argument_Associations (gnat_node)))))
+       {
+       case Name_Time:  case Name_Space:
+         if (optimize == 0)
+           post_error ("insufficient -O value?", gnat_node);
+         break;
+
+       case Name_Off:
+         if (optimize != 0)
+           post_error ("must specify -O0?", gnat_node);
+         break;
+
+       default:
+         gigi_abort (331);
+         break;
+       }
+      break;
+
+    case Pragma_Reviewable:
+      if (write_symbols == NO_DEBUG)
+       post_error ("must specify -g?", gnat_node);
+      break;
+    }
+}
+/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Attribute,
+   to a GCC tree, which is returned.  GNU_RESULT_TYPE_P is a pointer to
+   where we should place the result type.  ATTRIBUTE is the attribute ID.  */
+
+static tree
+Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute)
+{
+  tree gnu_result = error_mark_node;
+  tree gnu_result_type;
+  tree gnu_expr;
+  bool prefix_unused = false;
+  tree gnu_prefix = gnat_to_gnu (Prefix (gnat_node));
+  tree gnu_type = TREE_TYPE (gnu_prefix);
+
+  /* If the input is a NULL_EXPR, make a new one.  */
+  if (TREE_CODE (gnu_prefix) == NULL_EXPR)
+    {
+      *gnu_result_type_p = get_unpadded_type (Etype (gnat_node));
+      return build1 (NULL_EXPR, *gnu_result_type_p,
+                    TREE_OPERAND (gnu_prefix, 0));
+    }
+
+  switch (attribute)
+    {
+    case Attr_Pos:
+    case Attr_Val:
+      /* These are just conversions until since representation clauses for
+        enumerations are handled in the front end.  */
+      {
+       int check_p = Do_Range_Check (First (Expressions (gnat_node)));
+
+       gnu_result = gnat_to_gnu (First (Expressions (gnat_node)));
+       gnu_result_type = get_unpadded_type (Etype (gnat_node));
+       gnu_result = convert_with_check (Etype (gnat_node), gnu_result,
+                                        check_p, check_p, 1);
+      }
+      break;
+
+    case Attr_Pred:
+    case Attr_Succ:
+      /* These just add or subject the constant 1.  Representation clauses for
+        enumerations are handled in the front-end.  */
+      gnu_expr = gnat_to_gnu (First (Expressions (gnat_node)));
+      gnu_result_type = get_unpadded_type (Etype (gnat_node));
+
+      if (Do_Range_Check (First (Expressions (gnat_node))))
+       {
+         gnu_expr = protect_multiple_eval (gnu_expr);
+         gnu_expr
+           = emit_check
+             (build_binary_op (EQ_EXPR, integer_type_node,
+                               gnu_expr,
+                               attribute == Attr_Pred
+                               ? TYPE_MIN_VALUE (gnu_result_type)
+                               : TYPE_MAX_VALUE (gnu_result_type)),
+              gnu_expr, CE_Range_Check_Failed);
+       }
+
+      gnu_result
+       = build_binary_op (attribute == Attr_Pred
+                          ? MINUS_EXPR : PLUS_EXPR,
+                          gnu_result_type, gnu_expr,
+                          convert (gnu_result_type, integer_one_node));
+      break;
+
+    case Attr_Address:
+    case Attr_Unrestricted_Access:
+      /* Conversions don't change something's address but can cause us to miss
+        the COMPONENT_REF case below, so strip them off.  */
+      gnu_prefix = remove_conversions (gnu_prefix,
+                                      ! Must_Be_Byte_Aligned (gnat_node));
+
+      /* If we are taking 'Address of an unconstrained object, this is the
+        pointer to the underlying array.  */
+      gnu_prefix = maybe_unconstrained_array (gnu_prefix);
+
+      /* ... fall through ... */
+
+    case Attr_Access:
+    case Attr_Unchecked_Access:
+    case Attr_Code_Address:
+      gnu_result_type = get_unpadded_type (Etype (gnat_node));
+      gnu_result
+       = build_unary_op (((attribute == Attr_Address
+                           || attribute == Attr_Unrestricted_Access)
+                          && ! Must_Be_Byte_Aligned (gnat_node))
+                         ? ATTR_ADDR_EXPR : ADDR_EXPR,
+                         gnu_result_type, gnu_prefix);
+
+      /* For 'Code_Address, find an inner ADDR_EXPR and mark it so that we
+        don't try to build a trampoline.  */
+      if (attribute == Attr_Code_Address)
+       {
+         for (gnu_expr = gnu_result;
+              TREE_CODE (gnu_expr) == NOP_EXPR
+              || TREE_CODE (gnu_expr) == CONVERT_EXPR;
+              gnu_expr = TREE_OPERAND (gnu_expr, 0))
+           TREE_CONSTANT (gnu_expr) = 1;
+
+         if (TREE_CODE (gnu_expr) == ADDR_EXPR)
+           TREE_STATIC (gnu_expr) = TREE_CONSTANT (gnu_expr) = 1;
+       }
+      break;
+
+    case Attr_Pool_Address:
+      {
+       tree gnu_obj_type;
+       tree gnu_ptr = gnu_prefix;
+
+       gnu_result_type = get_unpadded_type (Etype (gnat_node));
+
+       /* If this is an unconstrained array, we know the object must have been
+          allocated with the template in front of the object.  So compute the
+          template address.*/
+       if (TYPE_FAT_POINTER_P (TREE_TYPE (gnu_ptr)))
+         gnu_ptr
+           = convert (build_pointer_type
+                      (TYPE_OBJECT_RECORD_TYPE
+                       (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (gnu_ptr)))),
+                      gnu_ptr);
+
+       gnu_obj_type = TREE_TYPE (TREE_TYPE (gnu_ptr));
+       if (TREE_CODE (gnu_obj_type) == RECORD_TYPE
+           && TYPE_CONTAINS_TEMPLATE_P (gnu_obj_type))
+         {
+           tree gnu_char_ptr_type = build_pointer_type (char_type_node);
+           tree gnu_pos = byte_position (TYPE_FIELDS (gnu_obj_type));
+           tree gnu_byte_offset
+             = convert (gnu_char_ptr_type,
+                        size_diffop (size_zero_node, gnu_pos));
+
+           gnu_ptr = convert (gnu_char_ptr_type, gnu_ptr);
+           gnu_ptr = build_binary_op (MINUS_EXPR, gnu_char_ptr_type,
+                                      gnu_ptr, gnu_byte_offset);
+         }
+
+       gnu_result = convert (gnu_result_type, gnu_ptr);
+      }
+      break;
+
+    case Attr_Size:
+    case Attr_Object_Size:
+    case Attr_Value_Size:
+    case Attr_Max_Size_In_Storage_Elements:
+      gnu_expr = gnu_prefix;
+
+      /* Remove NOPS from gnu_expr and conversions from gnu_prefix.
+        We only use GNU_EXPR to see if a COMPONENT_REF was involved. */
+      while (TREE_CODE (gnu_expr) == NOP_EXPR)
+       gnu_expr = TREE_OPERAND (gnu_expr, 0)
+         ;
+
+      gnu_prefix = remove_conversions (gnu_prefix, 1);
+      prefix_unused = true;
+      gnu_type = TREE_TYPE (gnu_prefix);
+
+      /* Replace an unconstrained array type with the type of the underlying
+        array.  We can't do this with a call to maybe_unconstrained_array
+        since we may have a TYPE_DECL.  For 'Max_Size_In_Storage_Elements,
+        use the record type that will be used to allocate the object and its
+        template.  */
+      if (TREE_CODE (gnu_type) == UNCONSTRAINED_ARRAY_TYPE)
+       {
+         gnu_type = TYPE_OBJECT_RECORD_TYPE (gnu_type);
+         if (attribute != Attr_Max_Size_In_Storage_Elements)
+           gnu_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (gnu_type)));
+       }
+
+      /* If we're looking for the size of a field, return the field size.
+        Otherwise, if the prefix is an object, or if 'Object_Size or
+        'Max_Size_In_Storage_Elements has been specified, the result is the
+        GCC size of the type. Otherwise, the result is the RM_Size of the
+        type.  */
+      if (TREE_CODE (gnu_prefix) == COMPONENT_REF)
+       gnu_result = DECL_SIZE (TREE_OPERAND (gnu_prefix, 1));
+      else if (TREE_CODE (gnu_prefix) != TYPE_DECL
+              || attribute == Attr_Object_Size
+              || attribute == Attr_Max_Size_In_Storage_Elements)
+       {
+         /* If this is a padded type, the GCC size isn't relevant to the
+            programmer.  Normally, what we want is the RM_Size, which was set
+            from the specified size, but if it was not set, we want the size
+            of the relevant field.  Using the MAX of those two produces the
+            right result in all case.  Don't use the size of the field if it's
+            a self-referential type, since that's never what's wanted.  */
+         if (TREE_CODE (gnu_type) == RECORD_TYPE
+             && TYPE_IS_PADDING_P (gnu_type)
+             && TREE_CODE (gnu_expr) == COMPONENT_REF)
+           {
+             gnu_result = rm_size (gnu_type);
+             if (! (CONTAINS_PLACEHOLDER_P
+                    (DECL_SIZE (TREE_OPERAND (gnu_expr, 1)))))
+               gnu_result
+                 = size_binop (MAX_EXPR, gnu_result,
+                               DECL_SIZE (TREE_OPERAND (gnu_expr, 1)));
+           }
+         else
+           gnu_result = TYPE_SIZE (gnu_type);
+       }
+      else
+       gnu_result = rm_size (gnu_type);
+
+      if (gnu_result == 0)
+       gigi_abort (325);
+
+      /* Deal with a self-referential size by returning the maximum size for a
+        type and by qualifying the size with the object for 'Size of an
+        object.  */
+      if (CONTAINS_PLACEHOLDER_P (gnu_result))
+       {
+         if (TREE_CODE (gnu_prefix) != TYPE_DECL)
+           gnu_result = substitute_placeholder_in_expr (gnu_result,
+                                                        gnu_expr);
+         else
+           gnu_result = max_size (gnu_result, 1);
+       }
+
+      /* If the type contains a template, subtract its size.  */
+      if (TREE_CODE (gnu_type) == RECORD_TYPE
+         && TYPE_CONTAINS_TEMPLATE_P (gnu_type))
+       gnu_result = size_binop (MINUS_EXPR, gnu_result,
+                                DECL_SIZE (TYPE_FIELDS (gnu_type)));
+
+      gnu_result_type = get_unpadded_type (Etype (gnat_node));
+
+      /* Always perform division using unsigned arithmetic as the size cannot
+        be negative, but may be an overflowed positive value. This provides
+        correct results for sizes up to 512 MB.
+
+        ??? Size should be calculated in storage elements directly.  */
+
+      if (attribute == Attr_Max_Size_In_Storage_Elements)
+       gnu_result = convert (sizetype,
+                             fold (build (CEIL_DIV_EXPR, bitsizetype,
+                                          gnu_result, bitsize_unit_node)));
+      break;
+
+    case Attr_Alignment:
+      if (TREE_CODE (gnu_prefix) == COMPONENT_REF
+         && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))
+             == RECORD_TYPE)
+         && (TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))))
+       gnu_prefix = TREE_OPERAND (gnu_prefix, 0);
+
+      gnu_type = TREE_TYPE (gnu_prefix);
+      gnu_result_type = get_unpadded_type (Etype (gnat_node));
+      prefix_unused = true;
+
+      if (TREE_CODE (gnu_prefix) == COMPONENT_REF)
+       gnu_result = size_int (DECL_ALIGN (TREE_OPERAND (gnu_prefix, 1)));
+      else
+       gnu_result = size_int (TYPE_ALIGN (gnu_type) / BITS_PER_UNIT);
+      break;
+
+    case Attr_First:
+    case Attr_Last:
+    case Attr_Range_Length:
+      prefix_unused = true;
+
+      if (INTEGRAL_TYPE_P (gnu_type) || TREE_CODE (gnu_type) == REAL_TYPE)
+       {
+         gnu_result_type = get_unpadded_type (Etype (gnat_node));
+
+         if (attribute == Attr_First)
+           gnu_result = TYPE_MIN_VALUE (gnu_type);
+         else if (attribute == Attr_Last)
+           gnu_result = TYPE_MAX_VALUE (gnu_type);
+         else
+           gnu_result
+             = build_binary_op
+               (MAX_EXPR, get_base_type (gnu_result_type),
+                build_binary_op
+                (PLUS_EXPR, get_base_type (gnu_result_type),
+                 build_binary_op (MINUS_EXPR,
+                                  get_base_type (gnu_result_type),
+                                  convert (gnu_result_type,
+                                           TYPE_MAX_VALUE (gnu_type)),
+                                  convert (gnu_result_type,
+                                           TYPE_MIN_VALUE (gnu_type))),
+                 convert (gnu_result_type, integer_one_node)),
+                convert (gnu_result_type, integer_zero_node));
+
+         break;
+       }
+
+      /* ... fall through ... */
+
+    case Attr_Length:
+      {
+       int Dimension = (Present (Expressions (gnat_node))
+                        ? UI_To_Int (Intval (First (Expressions (gnat_node))))
+                        : 1);
+
+       /* Make sure any implicit dereference gets done.  */
+       gnu_prefix = maybe_implicit_deref (gnu_prefix);
+       gnu_prefix = maybe_unconstrained_array (gnu_prefix);
+       gnu_type = TREE_TYPE (gnu_prefix);
+       prefix_unused = true;
+       gnu_result_type = get_unpadded_type (Etype (gnat_node));
+
+       if (TYPE_CONVENTION_FORTRAN_P (gnu_type))
+         {
+           int ndim;
+           tree gnu_type_temp;
+
+           for (ndim = 1, gnu_type_temp = gnu_type;
+                TREE_CODE (TREE_TYPE (gnu_type_temp)) == ARRAY_TYPE
+                && TYPE_MULTI_ARRAY_P (TREE_TYPE (gnu_type_temp));
+                ndim++, gnu_type_temp = TREE_TYPE (gnu_type_temp))
+             ;
+
+           Dimension = ndim + 1 - Dimension;
+         }
+
+       for (; Dimension > 1; Dimension--)
+         gnu_type = TREE_TYPE (gnu_type);
+
+       if (TREE_CODE (gnu_type) != ARRAY_TYPE)
+         gigi_abort (309);
+
+       if (attribute == Attr_First)
+         gnu_result
+           = TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)));
+       else if (attribute == Attr_Last)
+         gnu_result
+           = TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)));
+       else
+         /* 'Length or 'Range_Length.  */
+         {
+           tree gnu_compute_type
+             = gnat_signed_or_unsigned_type (0,
+                                             get_base_type (gnu_result_type));
+
+           gnu_result
+             = build_binary_op
+               (MAX_EXPR, gnu_compute_type,
+                build_binary_op
+                (PLUS_EXPR, gnu_compute_type,
+                 build_binary_op
+                 (MINUS_EXPR, gnu_compute_type,
+                  convert (gnu_compute_type,
+                           TYPE_MAX_VALUE
+                           (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)))),
+                  convert (gnu_compute_type,
+                           TYPE_MIN_VALUE
+                           (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type))))),
+                 convert (gnu_compute_type, integer_one_node)),
+                convert (gnu_compute_type, integer_zero_node));
+         }
+
+       /* If this has a PLACEHOLDER_EXPR, qualify it by the object we are
+          handling.  Note that these attributes could not have been used on
+          an unconstrained array type.  */
+       gnu_result = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_result,
+                                                    gnu_prefix);
+       break;
+      }
+
+    case Attr_Bit_Position:
+    case Attr_Position:
+    case Attr_First_Bit:
+    case Attr_Last_Bit:
+    case Attr_Bit:
+      {
+       HOST_WIDE_INT bitsize;
+       HOST_WIDE_INT bitpos;
+       tree gnu_offset;
+       tree gnu_field_bitpos;
+       tree gnu_field_offset;
+       tree gnu_inner;
+       enum machine_mode mode;
+       int unsignedp, volatilep;
+
+       gnu_result_type = get_unpadded_type (Etype (gnat_node));
+       gnu_prefix = remove_conversions (gnu_prefix, 1);
+       prefix_unused = true;
+
+       /* We can have 'Bit on any object, but if it isn't a COMPONENT_REF,
+          the result is 0.  Don't allow 'Bit on a bare component, though. */
+       if (attribute == Attr_Bit
+           && TREE_CODE (gnu_prefix) != COMPONENT_REF
+           && TREE_CODE (gnu_prefix) != FIELD_DECL)
+         {
+           gnu_result = integer_zero_node;
+           break;
+         }
+
+       else if (TREE_CODE (gnu_prefix) != COMPONENT_REF
+                && ! (attribute == Attr_Bit_Position
+                      && TREE_CODE (gnu_prefix) == FIELD_DECL))
+         gigi_abort (310);
+
+       get_inner_reference (gnu_prefix, &bitsize, &bitpos, &gnu_offset,
+                            &mode, &unsignedp, &volatilep);
+
+       if (TREE_CODE (gnu_prefix) == COMPONENT_REF)
+         {
+           gnu_field_bitpos = bit_position (TREE_OPERAND (gnu_prefix, 1));
+           gnu_field_offset = byte_position (TREE_OPERAND (gnu_prefix, 1));
+
+           for (gnu_inner = TREE_OPERAND (gnu_prefix, 0);
+                TREE_CODE (gnu_inner) == COMPONENT_REF
+                && DECL_INTERNAL_P (TREE_OPERAND (gnu_inner, 1));
+                gnu_inner = TREE_OPERAND (gnu_inner, 0))
+             {
+               gnu_field_bitpos
+                 = size_binop (PLUS_EXPR, gnu_field_bitpos,
+                               bit_position (TREE_OPERAND (gnu_inner, 1)));
+               gnu_field_offset
+                 = size_binop (PLUS_EXPR, gnu_field_offset,
+                               byte_position (TREE_OPERAND (gnu_inner, 1)));
+             }
+         }
+       else if (TREE_CODE (gnu_prefix) == FIELD_DECL)
+         {
+           gnu_field_bitpos = bit_position (gnu_prefix);
+           gnu_field_offset = byte_position (gnu_prefix);
+         }
+       else
+         {
+           gnu_field_bitpos = bitsize_zero_node;
+           gnu_field_offset = size_zero_node;
+         }
+
+       switch (attribute)
+         {
+         case Attr_Position:
+           gnu_result = gnu_field_offset;
+           break;
+
+         case Attr_First_Bit:
+         case Attr_Bit:
+           gnu_result = size_int (bitpos % BITS_PER_UNIT);
+           break;
+
+         case Attr_Last_Bit:
+           gnu_result = bitsize_int (bitpos % BITS_PER_UNIT);
+           gnu_result = size_binop (PLUS_EXPR, gnu_result,
+                                    TYPE_SIZE (TREE_TYPE (gnu_prefix)));
+           gnu_result = size_binop (MINUS_EXPR, gnu_result,
+                                    bitsize_one_node);
+           break;
+
+         case Attr_Bit_Position:
+           gnu_result = gnu_field_bitpos;
+           break;
+               }
+
+       /* If this has a PLACEHOLDER_EXPR, qualify it by the object
+          we are handling. */
+       gnu_result = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_result, gnu_prefix);
+       break;
+      }
+
+    case Attr_Min:
+    case Attr_Max:
+      {
+       tree gnu_lhs = gnat_to_gnu (First (Expressions (gnat_node)));
+       tree gnu_rhs = gnat_to_gnu (Next (First (Expressions (gnat_node))));
+
+       gnu_result_type = get_unpadded_type (Etype (gnat_node));
+       gnu_result = build_binary_op (attribute == Attr_Min
+                                     ? MIN_EXPR : MAX_EXPR,
+                                     gnu_result_type, gnu_lhs, gnu_rhs);
+      }
+      break;
+
+    case Attr_Passed_By_Reference:
+      gnu_result = size_int (default_pass_by_ref (gnu_type)
+                            || must_pass_by_ref (gnu_type));
+      gnu_result_type = get_unpadded_type (Etype (gnat_node));
+      break;
+
+    case Attr_Component_Size:
+      if (TREE_CODE (gnu_prefix) == COMPONENT_REF
+         && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))
+             == RECORD_TYPE)
+         && (TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))))
+       gnu_prefix = TREE_OPERAND (gnu_prefix, 0);
+
+      gnu_prefix = maybe_implicit_deref (gnu_prefix);
+      gnu_type = TREE_TYPE (gnu_prefix);
+
+      if (TREE_CODE (gnu_type) == UNCONSTRAINED_ARRAY_TYPE)
+       gnu_type = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_type))));
+
+      while (TREE_CODE (TREE_TYPE (gnu_type)) == ARRAY_TYPE
+            && TYPE_MULTI_ARRAY_P (TREE_TYPE (gnu_type)))
+       gnu_type = TREE_TYPE (gnu_type);
+
+      if (TREE_CODE (gnu_type) != ARRAY_TYPE)
+       gigi_abort (330);
+
+      /* Note this size cannot be self-referential.  */
+      gnu_result = TYPE_SIZE (TREE_TYPE (gnu_type));
+      gnu_result_type = get_unpadded_type (Etype (gnat_node));
+      prefix_unused = true;
+      break;
+
+    case Attr_Null_Parameter:
+      /* This is just a zero cast to the pointer type for
+        our prefix and dereferenced.  */
+      gnu_result_type = get_unpadded_type (Etype (gnat_node));
+      gnu_result
+       = build_unary_op (INDIRECT_REF, NULL_TREE,
+                         convert (build_pointer_type (gnu_result_type),
+                                  integer_zero_node));
+      TREE_PRIVATE (gnu_result) = 1;
+      break;
+
+    case Attr_Mechanism_Code:
+      {
+       int code;
+       Entity_Id gnat_obj = Entity (Prefix (gnat_node));
+
+       prefix_unused = true;
+       gnu_result_type = get_unpadded_type (Etype (gnat_node));
+       if (Present (Expressions (gnat_node)))
+         {
+           int i = UI_To_Int (Intval (First (Expressions (gnat_node))));
+
+           for (gnat_obj = First_Formal (gnat_obj); i > 1;
+                i--, gnat_obj = Next_Formal (gnat_obj))
+             ;
+         }
+
+       code = Mechanism (gnat_obj);
+       if (code == Default)
+         code = ((present_gnu_tree (gnat_obj)
+                  && (DECL_BY_REF_P (get_gnu_tree (gnat_obj))
+                      || ((TREE_CODE (get_gnu_tree (gnat_obj))
+                           == PARM_DECL)
+                          && (DECL_BY_COMPONENT_PTR_P
+                              (get_gnu_tree (gnat_obj))))))
+                 ? By_Reference : By_Copy);
+       gnu_result = convert (gnu_result_type, size_int (- code));
+      }
+      break;
+
+    default:
+      /* Say we have an unimplemented attribute.  Then set the value to be
+        returned to be a zero and hope that's something we can convert to the
+        type of this attribute.  */
+      post_error ("unimplemented attribute", gnat_node);
+      gnu_result_type = get_unpadded_type (Etype (gnat_node));
+      gnu_result = integer_zero_node;
+      break;
+    }
+
+  /* If this is an attribute where the prefix was unused, force a use of it if
+     it has a side-effect.  But don't do it if the prefix is just an entity
+     name.  However, if an access check is needed, we must do it.  See second
+     example in AARM 11.6(5.e). */
+  if (prefix_unused && TREE_SIDE_EFFECTS (gnu_prefix)
+      && ! Is_Entity_Name (Prefix (gnat_node)))
+    gnu_result = fold (build (COMPOUND_EXPR, TREE_TYPE (gnu_result),
+                             gnu_prefix, gnu_result));
+
+  *gnu_result_type_p = gnu_result_type;
+  return gnu_result;
+}
+\f
+/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Case_Statement,
+   to a GCC tree, which is returned.  */
+
+static tree
+Case_Statement_to_gnu (Node_Id gnat_node)
+{
+  tree gnu_result;
+  tree gnu_expr;
+  Node_Id gnat_when;
+
+  gnu_expr = gnat_to_gnu (Expression (gnat_node));
+  gnu_expr = convert (get_base_type (TREE_TYPE (gnu_expr)), gnu_expr);
+
+  /*  The range of values in a case statement is determined by the rules in
+      RM 5.4(7-9). In almost all cases, this range is represented by the Etype
+      of the expression. One exception arises in the case of a simple name that
+      is parenthesized. This still has the Etype of the name, but since it is
+      not a name, para 7 does not apply, and we need to go to the base type.
+      This is the only case where parenthesization affects the dynamic
+      semantics (i.e. the range of possible values at runtime that is covered
+      by the others alternative.
+
+      Another exception is if the subtype of the expression is non-static.  In
+      that case, we also have to use the base type.  */
+  if (Paren_Count (Expression (gnat_node)) != 0
+      || !Is_OK_Static_Subtype (Underlying_Type
+                               (Etype (Expression (gnat_node)))))
+    gnu_expr = convert (get_base_type (TREE_TYPE (gnu_expr)), gnu_expr);
+
+  /* We build a SWITCH_EXPR that contains the code with interspersed
+     CASE_LABEL_EXPRs for each label.  */
+
+  push_stack (&gnu_switch_label_stack, NULL_TREE, create_artificial_label ());
+  start_stmt_group ();
+  for (gnat_when = First_Non_Pragma (Alternatives (gnat_node));
+       Present (gnat_when);
+       gnat_when = Next_Non_Pragma (gnat_when))
+    {
+      Node_Id gnat_choice;
+
+      /* First compile all the different case choices for the current WHEN
+        alternative.  */
+      for (gnat_choice = First (Discrete_Choices (gnat_when));
+          Present (gnat_choice); gnat_choice = Next (gnat_choice))
+       {
+         tree gnu_low = NULL_TREE, gnu_high = NULL_TREE;
+
+         switch (Nkind (gnat_choice))
+           {
+           case N_Range:
+             gnu_low = gnat_to_gnu (Low_Bound (gnat_choice));
+             gnu_high = gnat_to_gnu (High_Bound (gnat_choice));
+             break;
+
+           case N_Subtype_Indication:
+             gnu_low = gnat_to_gnu (Low_Bound (Range_Expression
+                                               (Constraint (gnat_choice))));
+             gnu_high = gnat_to_gnu (High_Bound (Range_Expression
+                                                 (Constraint (gnat_choice))));
+             break;
+
+           case N_Identifier:
+           case N_Expanded_Name:
+             /* This represents either a subtype range or a static value of
+                some kind; Ekind says which.  If a static value, fall through
+                to the next case.  */
+             if (IN (Ekind (Entity (gnat_choice)), Type_Kind))
+               {
+                 tree gnu_type = get_unpadded_type (Entity (gnat_choice));
+
+                 gnu_low = fold (TYPE_MIN_VALUE (gnu_type));
+                 gnu_high = fold (TYPE_MAX_VALUE (gnu_type));
+                 break;
+               }
+
+             /* ... fall through ... */
+
+           case N_Character_Literal:
+           case N_Integer_Literal:
+             gnu_low = gnat_to_gnu (gnat_choice);
+             break;
+
+           case N_Others_Choice:
+             break;
+
+           default:
+             gigi_abort (316);
+           }
+
+         add_stmt_with_node (build (CASE_LABEL_EXPR, void_type_node,
+                                    gnu_low, gnu_high,
+                                    create_artificial_label ()),
+                             gnat_choice);
+       }
+
+      /* Push a binding level here in case variables are declared since we want
+        them to be local to this set of statements instead of the block
+        containing the Case statement.  */
+      add_stmt (build_stmt_group (Statements (gnat_when), true));
+      add_stmt (build1 (GOTO_EXPR, void_type_node,
+                       TREE_VALUE (gnu_switch_label_stack)));
+    }
+
+  /* Now emit a definition of the label all the cases branched to. */
+  add_stmt (build1 (LABEL_EXPR, void_type_node,
+                   TREE_VALUE (gnu_switch_label_stack)));
+  gnu_result = build (SWITCH_EXPR, TREE_TYPE (gnu_expr), gnu_expr,
+                     end_stmt_group (), NULL_TREE);
+  pop_stack (&gnu_switch_label_stack);
+
+  return gnu_result;
+}
+\f
+/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Loop_Statement,
+   to a GCC tree, which is returned.  */
+
+static tree
+Loop_Statement_to_gnu (Node_Id gnat_node)
+{
+  /* ??? It would be nice to use "build" here, but there's no build5.  */
+  tree gnu_loop_stmt = build_nt (LOOP_STMT, NULL_TREE, NULL_TREE,
+                                NULL_TREE, NULL_TREE, NULL_TREE);
+  tree gnu_loop_var = NULL_TREE;
+  Node_Id gnat_iter_scheme = Iteration_Scheme (gnat_node);
+  tree gnu_cond_expr = NULL_TREE;
+  tree gnu_result;
+
+  TREE_TYPE (gnu_loop_stmt) = void_type_node;
+  TREE_SIDE_EFFECTS (gnu_loop_stmt) = 1;
+  LOOP_STMT_LABEL (gnu_loop_stmt) = create_artificial_label ();
+  annotate_with_node (gnu_loop_stmt, gnat_node);
+
+  /* Save the end label of this LOOP_STMT in a stack so that the corresponding
+     N_Exit_Statement can find it.  */
+  push_stack (&gnu_loop_label_stack, NULL_TREE,
+             LOOP_STMT_LABEL (gnu_loop_stmt));
+
+  /* Set the condition that under which the loop should continue.
+     For "LOOP .... END LOOP;" the condition is always true.  */
+  if (No (gnat_iter_scheme))
+    ;
+  /* The case "WHILE condition LOOP ..... END LOOP;" */
+  else if (Present (Condition (gnat_iter_scheme)))
+    LOOP_STMT_TOP_COND (gnu_loop_stmt)
+      = gnat_to_gnu (Condition (gnat_iter_scheme));
+  else
+    {
+      /* We have an iteration scheme.  */
+      Node_Id gnat_loop_spec = Loop_Parameter_Specification (gnat_iter_scheme);
+      Entity_Id gnat_loop_var = Defining_Entity (gnat_loop_spec);
+      Entity_Id gnat_type = Etype (gnat_loop_var);
+      tree gnu_type = get_unpadded_type (gnat_type);
+      tree gnu_low = TYPE_MIN_VALUE (gnu_type);
+      tree gnu_high = TYPE_MAX_VALUE (gnu_type);
+      bool reversep = Reverse_Present (gnat_loop_spec);
+      tree gnu_first = reversep ? gnu_high : gnu_low;
+      tree gnu_last = reversep ? gnu_low : gnu_high;
+      enum tree_code end_code = reversep ? GE_EXPR : LE_EXPR;
+      tree gnu_base_type = get_base_type (gnu_type);
+      tree gnu_limit = (reversep ? TYPE_MIN_VALUE (gnu_base_type)
+                       : TYPE_MAX_VALUE (gnu_base_type));
+
+      /* We know the loop variable will not overflow if GNU_LAST is a constant
+        and is not equal to GNU_LIMIT.  If it might overflow, we have to move
+        the limit test to the end of the loop.  In that case, we have to test
+        for an empty loop outside the loop.  */
+      if (TREE_CODE (gnu_last) != INTEGER_CST
+         || TREE_CODE (gnu_limit) != INTEGER_CST
+         || tree_int_cst_equal (gnu_last, gnu_limit))
+       {
+         gnu_cond_expr
+           = build (COND_EXPR, void_type_node,
+                    build_binary_op (LE_EXPR, integer_type_node,
+                                     gnu_low, gnu_high),
+                    NULL_TREE, alloc_stmt_list ());
+         annotate_with_node (gnu_cond_expr, gnat_loop_spec);
+       }
+
+      /* Open a new nesting level that will surround the loop to declare the
+        loop index variable.  */
+      start_stmt_group ();
+      gnat_pushlevel ();
+
+      /* Declare the loop index and set it to its initial value.  */
+      gnu_loop_var = gnat_to_gnu_entity (gnat_loop_var, gnu_first, 1);
+      if (DECL_BY_REF_P (gnu_loop_var))
+       gnu_loop_var = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_loop_var);
+
+      /* The loop variable might be a padded type, so use `convert' to get a
+        reference to the inner variable if so.  */
+      gnu_loop_var = convert (get_base_type (gnu_type), gnu_loop_var);
+
+      /* Set either the top or bottom exit condition as appropriate depending
+        on whether or not we know an overflow cannot occur. */
+      if (gnu_cond_expr)
+       LOOP_STMT_BOT_COND (gnu_loop_stmt)
+         = build_binary_op (NE_EXPR, integer_type_node,
+                            gnu_loop_var, gnu_last);
+      else
+       LOOP_STMT_TOP_COND (gnu_loop_stmt)
+         = build_binary_op (end_code, integer_type_node,
+                            gnu_loop_var, gnu_last);
+
+      LOOP_STMT_UPDATE (gnu_loop_stmt)
+       = build_binary_op (reversep ? PREDECREMENT_EXPR
+                          : PREINCREMENT_EXPR,
+                          TREE_TYPE (gnu_loop_var),
+                          gnu_loop_var,
+                          convert (TREE_TYPE (gnu_loop_var),
+                                   integer_one_node));
+      annotate_with_node (LOOP_STMT_UPDATE (gnu_loop_stmt),
+                         gnat_iter_scheme);
+    }
+
+  /* If the loop was named, have the name point to this loop.  In this case,
+     the association is not a ..._DECL node, but the end label from this
+     LOOP_STMT. */
+  if (Present (Identifier (gnat_node)))
+    save_gnu_tree (Entity (Identifier (gnat_node)),
+                  LOOP_STMT_LABEL (gnu_loop_stmt), 1);
+
+  /* Make the loop body into its own block, so any allocated storage will be
+     released every iteration.  This is needed for stack allocation.  */
+  LOOP_STMT_BODY (gnu_loop_stmt)
+    = build_stmt_group (Statements (gnat_node), true);
+
+  /* If we declared a variable, then we are in a statement group for that
+     declaration.  Add the LOOP_STMT to it and make that the "loop".  */
+  if (gnu_loop_var)
+    {
+      add_stmt (gnu_loop_stmt);
+      gnat_poplevel ();
+      gnu_loop_stmt = end_stmt_group ();
+    }
+
+  /* If we have an outer COND_EXPR, that's our result and this loop is its
+     "true" statement.  Otherwise, the result is the LOOP_STMT. */
+  if (gnu_cond_expr)
+    {
+      COND_EXPR_THEN (gnu_cond_expr) = gnu_loop_stmt;
+      gnu_result = gnu_cond_expr;
+      recalculate_side_effects (gnu_cond_expr);
+    }
+  else
+    gnu_result = gnu_loop_stmt;
+
+  pop_stack (&gnu_loop_label_stack);
+
+  return gnu_result;
+}
+\f
+/* Subroutine of gnat_to_gnu to process gnat_node, an N_Subprogram_Body.  We
+   don't return anything.  */
+
+static void
+Subprogram_Body_to_gnu (Node_Id gnat_node)
+{
+  /* Save debug output mode in case it is reset.  */
+  enum debug_info_type save_write_symbols = write_symbols;
+  const struct gcc_debug_hooks *const save_debug_hooks = debug_hooks;
+  /* Definining identifier of a parameter to the subprogram.  */
+  Entity_Id gnat_param;
+  /* The defining identifier for the subprogram body. Note that if a
+     specification has appeared before for this body, then the identifier
+     occurring in that specification will also be a defining identifier and all
+     the calls to this subprogram will point to that specification.  */
+  Entity_Id gnat_subprog_id
+    = (Present (Corresponding_Spec (gnat_node))
+       ? Corresponding_Spec (gnat_node) : Defining_Entity (gnat_node));
+  /* The FUNCTION_DECL node corresponding to the subprogram spec.   */
+  tree gnu_subprog_decl;
+  /* The FUNCTION_TYPE node corresponding to the subprogram spec.  */
+  tree gnu_subprog_type;
+  tree gnu_cico_list;
+  tree gnu_result;
+
+  /* If this is a generic object or if it has been eliminated,
+     ignore it.  */
+  if (Ekind (gnat_subprog_id) == E_Generic_Procedure
+      || Ekind (gnat_subprog_id) == E_Generic_Function
+      || Is_Eliminated (gnat_subprog_id))
+    return;
+
+  /* If debug information is suppressed for the subprogram, turn debug
+     mode off for the duration of processing.  */
+  if (!Needs_Debug_Info (gnat_subprog_id))
+    {
+      write_symbols = NO_DEBUG;
+      debug_hooks = &do_nothing_debug_hooks;
+    }
+
+  /* If this subprogram acts as its own spec, define it.  Otherwise, just get
+     the already-elaborated tree node.  However, if this subprogram had its
+     elaboration deferred, we will already have made a tree node for it.  So
+     treat it as not being defined in that case.  Such a subprogram cannot
+     have an address clause or a freeze node, so this test is safe, though it
+     does disable some otherwise-useful error checking.  */
+  gnu_subprog_decl
+    = gnat_to_gnu_entity (gnat_subprog_id, NULL_TREE,
+                         Acts_As_Spec (gnat_node)
+                         && ! present_gnu_tree (gnat_subprog_id));
+
+  gnu_subprog_type = TREE_TYPE (gnu_subprog_decl);
+
+  /* Set the line number in the decl to correspond to that of the body so that
+     the line number notes are written
+     correctly.  */
+  Sloc_to_locus (Sloc (gnat_node), &DECL_SOURCE_LOCATION (gnu_subprog_decl));
+
+  begin_subprog_body (gnu_subprog_decl);
+  gnu_cico_list = TYPE_CI_CO_LIST (gnu_subprog_type);
+
+  /* If there are OUT parameters, we need to ensure that the return statement
+     properly copies them out.  We do this by making a new block and converting
+     any inner return into a goto to a label at the end of the block.  */
+  push_stack (&gnu_return_label_stack, NULL_TREE,
+             gnu_cico_list ? create_artificial_label () : NULL_TREE);
+
+  /* Get a tree corresponding to the code for the subprogram.  */
+  start_stmt_group ();
+  gnat_pushlevel ();
+
+  /* See if there are any parameters for which we don't yet have GCC entities.
+     These must be for OUT parameters for which we will be making VAR_DECL
+     nodes here.  Fill them in to TYPE_CI_CO_LIST, which must contain the empty
+     entry as well.  We can match up the entries because TYPE_CI_CO_LIST is in
+     the order of the parameters.  */
+  for (gnat_param = First_Formal (gnat_subprog_id);
+       Present (gnat_param);
+       gnat_param = Next_Formal_With_Extras (gnat_param))
+    if (!present_gnu_tree (gnat_param))
+      {
+       /* Skip any entries that have been already filled in; they must
+          correspond to IN OUT parameters.  */
+       for (; gnu_cico_list != 0 && TREE_VALUE (gnu_cico_list) != 0;
+            gnu_cico_list = TREE_CHAIN (gnu_cico_list))
+         ;
+
+       /* Do any needed references for padded types.  */
+       TREE_VALUE (gnu_cico_list)
+         = convert (TREE_TYPE (TREE_PURPOSE (gnu_cico_list)),
+                    gnat_to_gnu_entity (gnat_param, NULL_TREE, 1));
+      }
+
+  process_decls (Declarations (gnat_node), Empty, Empty, 1, 1);
+
+  /* Generate the code of the subprogram itself.  A return statement will be
+     present and any OUT parameters will be handled there.  */
+  add_stmt (gnat_to_gnu (Handled_Statement_Sequence (gnat_node)));
+  gnat_poplevel ();
+  gnu_result = end_stmt_group ();
+
+  /* If we made a special return label, we need to make a block that contains
+     the definition of that label and the copying to the return value.  That
+     block first contains the function, then the label and copy statement.  */
+  if (TREE_VALUE (gnu_return_label_stack) != 0)
+    {
+      tree gnu_retval;
+
+      start_stmt_group ();
+      gnat_pushlevel ();
+      add_stmt (gnu_result);
+      add_stmt (build1 (LABEL_EXPR, void_type_node,
+                       TREE_VALUE (gnu_return_label_stack)));
+
+      gnu_cico_list = TYPE_CI_CO_LIST (gnu_subprog_type);
+      if (list_length (gnu_cico_list) == 1)
+       gnu_retval = TREE_VALUE (gnu_cico_list);
+      else
+       gnu_retval = gnat_build_constructor (TREE_TYPE (gnu_subprog_type),
+                                            gnu_cico_list);
+
+      if (DECL_P (gnu_retval) && DECL_BY_REF_P (gnu_retval))
+       gnu_retval = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_retval);
+
+      add_stmt_with_node
+       (build1 (RETURN_EXPR, void_type_node,
+                build (MODIFY_EXPR, TREE_TYPE (gnu_retval),
+                       DECL_RESULT (current_function_decl), gnu_retval)),
+        gnat_node);
+      gnat_poplevel ();
+      gnu_result = end_stmt_group ();
+    }
+
+  pop_stack (&gnu_return_label_stack);
+
+  /* Initialize the information node for the function and set the
+     end location.  */
+  allocate_struct_function (current_function_decl);
+  Sloc_to_locus
+    ((Present (End_Label (Handled_Statement_Sequence (gnat_node)))
+      ? Sloc (End_Label (Handled_Statement_Sequence (gnat_node)))
+      : Sloc (gnat_node)),
+     &cfun->function_end_locus);
+
+  end_subprog_body (gnu_result);
+
+  /* Disconnect the trees for parameters that we made variables for from the
+     GNAT entities since these are unusable after we end the function.  */
+  for (gnat_param = First_Formal (gnat_subprog_id);
+       Present (gnat_param);
+       gnat_param = Next_Formal_With_Extras (gnat_param))
+    if (TREE_CODE (get_gnu_tree (gnat_param)) == VAR_DECL)
+      save_gnu_tree (gnat_param, NULL_TREE, 0);
+
+  mark_out_of_scope (Defining_Unit_Name (Specification (gnat_node)));
+  write_symbols = save_write_symbols;
+  debug_hooks = save_debug_hooks;
+}
+\f
+/* Subroutine of gnat_to_gnu to translate gnat_node, either an N_Function_Call
+   or an N_Procedure_Call_Statement, to a GCC tree, which is returned.
+   GNU_RESULT_TYPE_P is a pointer to where we should place the result type.  */
+
+static tree
+call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
+{
+  tree gnu_result;
+  /* The GCC node corresponding to the GNAT subprogram name.  This can either
+     be a FUNCTION_DECL node if we are dealing with a standard subprogram call,
+     or an indirect reference expression (an INDIRECT_REF node) pointing to a
+     subprogram.  */
+  tree gnu_subprog_node = gnat_to_gnu (Name (gnat_node));
+  /* The FUNCTION_TYPE node giving the GCC type of the subprogram.  */
+  tree gnu_subprog_type = TREE_TYPE (gnu_subprog_node);
+  tree gnu_subprog_addr = build_unary_op (ADDR_EXPR, NULL_TREE,
+                                         gnu_subprog_node);
+  Entity_Id gnat_formal;
+  Node_Id gnat_actual;
+  tree gnu_actual_list = NULL_TREE;
+  tree gnu_name_list = NULL_TREE;
+  tree gnu_before_list = NULL_TREE;
+  tree gnu_after_list = NULL_TREE;
+  tree gnu_subprog_call;
+
+  switch (Nkind (Name (gnat_node)))
+    {
+    case N_Identifier:
+    case N_Operator_Symbol:
+    case N_Expanded_Name:
+    case N_Attribute_Reference:
+      if (Is_Eliminated (Entity (Name (gnat_node))))
+       Eliminate_Error_Msg (gnat_node, Entity (Name (gnat_node)));
+    }
+
+  if (TREE_CODE (gnu_subprog_type) != FUNCTION_TYPE)
+    gigi_abort (317);
+
+  /* If we are calling a stubbed function, make this into a raise of
+     Program_Error.  Elaborate all our args first.  */
+  if (TREE_CODE (gnu_subprog_node) == FUNCTION_DECL
+      && DECL_STUBBED_P (gnu_subprog_node))
+    {
+      for (gnat_actual = First_Actual (gnat_node);
+          Present (gnat_actual);
+          gnat_actual = Next_Actual (gnat_actual))
+       add_stmt (gnat_to_gnu (gnat_actual));
+
+      if (Nkind (gnat_node) == N_Function_Call)
+       {
+         *gnu_result_type_p = TREE_TYPE (gnu_subprog_type);
+         return build1 (NULL_EXPR, *gnu_result_type_p,
+                        build_call_raise (PE_Stubbed_Subprogram_Called));
+       }
+      else
+       return build_call_raise (PE_Stubbed_Subprogram_Called);
+    }
+
+  /* The only way we can be making a call via an access type is if Name is an
+     explicit dereference.  In that case, get the list of formal args from the
+     type the access type is pointing to.  Otherwise, get the formals from
+     entity being called.  */
+  if (Nkind (Name (gnat_node)) == N_Explicit_Dereference)
+    gnat_formal = First_Formal (Etype (Name (gnat_node)));
+  else if (Nkind (Name (gnat_node)) == N_Attribute_Reference)
+    /* Assume here that this must be 'Elab_Body or 'Elab_Spec.  */
+    gnat_formal = 0;
+  else
+    gnat_formal = First_Formal (Entity (Name (gnat_node)));
+
+  /* Create the list of the actual parameters as GCC expects it, namely a chain
+     of TREE_LIST nodes in which the TREE_VALUE field of each node is a
+     parameter-expression and the TREE_PURPOSE field is null.  Skip OUT
+     parameters not passed by reference and don't need to be copied in.  */
+  for (gnat_actual = First_Actual (gnat_node);
+       Present (gnat_actual);
+       gnat_formal = Next_Formal_With_Extras (gnat_formal),
+       gnat_actual = Next_Actual (gnat_actual))
+    {
+      tree gnu_formal_type = gnat_to_gnu_type (Etype (gnat_formal));
+      /* We treat a conversion between aggregate types as if it is an
+        unchecked conversion.  */
+      bool unchecked_convert_p
+       = (Nkind (gnat_actual) == N_Unchecked_Type_Conversion
+          || (Nkind (gnat_actual) == N_Type_Conversion
+              && Is_Composite_Type (Underlying_Type (Etype (gnat_formal)))));
+      Node_Id gnat_name = (unchecked_convert_p
+                          ? Expression (gnat_actual) : gnat_actual);
+      tree gnu_name = gnat_to_gnu (gnat_name);
+      tree gnu_name_type = gnat_to_gnu_type (Etype (gnat_name));
+      tree gnu_actual;
+
+      /* If it's possible we may need to use this expression twice, make sure
+        than any side-effects are handled via SAVE_EXPRs. Likewise if we need
+        to force side-effects before the call.
+
+        ??? This is more conservative than we need since we don't need to do
+        this for pass-by-ref with no conversion. If we are passing a
+        non-addressable Out or In Out parameter by reference, pass the address
+        of a copy and set up to copy back out after the call.  */
+      if (Ekind (gnat_formal) != E_In_Parameter)
+       {
+         gnu_name = gnat_stabilize_reference (gnu_name, 1);
+         if (! addressable_p (gnu_name)
+             && present_gnu_tree (gnat_formal)
+             && (DECL_BY_REF_P (get_gnu_tree (gnat_formal))
+                 || (TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
+                     && (DECL_BY_COMPONENT_PTR_P (get_gnu_tree (gnat_formal))
+                         || (DECL_BY_DESCRIPTOR_P
+                             (get_gnu_tree (gnat_formal)))))))
+           {
+             tree gnu_copy = gnu_name;
+             tree gnu_temp;
+
+             /* Remove any unpadding on the actual and make a copy.  But if
+                the actual is a left-justified modular type, first convert
+                to it.  */
+             if (TREE_CODE (gnu_name) == COMPONENT_REF
+                 && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_name, 0)))
+                      == RECORD_TYPE)
+                     && (TYPE_IS_PADDING_P
+                         (TREE_TYPE (TREE_OPERAND (gnu_name, 0))))))
+               gnu_name = gnu_copy = TREE_OPERAND (gnu_name, 0);
+             else if (TREE_CODE (gnu_name_type) == RECORD_TYPE
+                      && (TYPE_LEFT_JUSTIFIED_MODULAR_P (gnu_name_type)))
+               gnu_name = convert (gnu_name_type, gnu_name);
+
+             gnu_actual = save_expr (gnu_name);
+
+             /* Since we're going to take the address of the SAVE_EXPR, we
+                don't want it to be marked as unchanging. So set
+                TREE_ADDRESSABLE.  */
+             gnu_temp = skip_simple_arithmetic (gnu_actual);
+             if (TREE_CODE (gnu_temp) == SAVE_EXPR)
+               {
+                 TREE_ADDRESSABLE (gnu_temp) = 1;
+                 TREE_READONLY (gnu_temp) = 0;
+               }
+
+             /* Set up to move the copy back to the original.  */
+             gnu_temp = build (MODIFY_EXPR, TREE_TYPE (gnu_copy),
+                               gnu_copy, gnu_actual);
+             annotate_with_node (gnu_temp, gnat_actual);
+             append_to_statement_list (gnu_temp, &gnu_after_list);
+           }
+       }
+
+      /* If this was a procedure call, we may not have removed any padding.
+        So do it here for the part we will use as an input, if any.  */
+      gnu_actual = gnu_name;
+      if (Ekind (gnat_formal) != E_Out_Parameter
+         && TREE_CODE (TREE_TYPE (gnu_actual)) == RECORD_TYPE
+         && TYPE_IS_PADDING_P (TREE_TYPE (gnu_actual)))
+       gnu_actual = convert (get_unpadded_type (Etype (gnat_actual)),
+                             gnu_actual);
+
+      /* Unless this is an In parameter, we must remove any LJM building
+        from GNU_NAME.  */
+      if (Ekind (gnat_formal) != E_In_Parameter
+         && TREE_CODE (gnu_name) == CONSTRUCTOR
+         && TREE_CODE (TREE_TYPE (gnu_name)) == RECORD_TYPE
+         && TYPE_LEFT_JUSTIFIED_MODULAR_P (TREE_TYPE (gnu_name)))
+       gnu_name = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_name))),
+                           gnu_name);
+
+      if (Ekind (gnat_formal) != E_Out_Parameter
+         && ! unchecked_convert_p
+         && Do_Range_Check (gnat_actual))
+       gnu_actual = emit_range_check (gnu_actual, Etype (gnat_formal));
+
+      /* Do any needed conversions.  We need only check for unchecked
+        conversion since normal conversions will be handled by just
+        converting to the formal type.  */
+      if (unchecked_convert_p)
+       {
+         gnu_actual
+           = unchecked_convert (gnat_to_gnu_type (Etype (gnat_actual)),
+                                gnu_actual,
+                                (Nkind (gnat_actual)
+                                 == N_Unchecked_Type_Conversion)
+                                && No_Truncation (gnat_actual));
+
+         /* One we've done the unchecked conversion, we still must ensure that
+            the object is in range of the formal's type.  */
+         if (Ekind (gnat_formal) != E_Out_Parameter
+             && Do_Range_Check (gnat_actual))
+           gnu_actual = emit_range_check (gnu_actual,
+                                          Etype (gnat_formal));
+       }
+      else if (TREE_CODE (gnu_actual) != SAVE_EXPR)
+       /* We may have suppressed a conversion to the Etype of the actual since
+          the parent is a procedure call.  So add the conversion here.  */
+       gnu_actual = convert (gnat_to_gnu_type (Etype (gnat_actual)),
+                             gnu_actual);
+
+      if (TREE_CODE (gnu_actual) != SAVE_EXPR)
+       gnu_actual = convert (gnu_formal_type, gnu_actual);
+
+      /* If we have not saved a GCC object for the formal, it means it is an
+        OUT parameter not passed by reference and that does not need to be
+        copied in. Otherwise, look at the PARM_DECL to see if it is passed by
+        reference. */
+      if (present_gnu_tree (gnat_formal)
+         && TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
+         && DECL_BY_REF_P (get_gnu_tree (gnat_formal)))
+       {
+         if (Ekind (gnat_formal) != E_In_Parameter)
+           {
+             gnu_actual = gnu_name;
+
+             /* If we have a padded type, be sure we've removed padding.  */
+             if (TREE_CODE (TREE_TYPE (gnu_actual)) == RECORD_TYPE
+                 && TYPE_IS_PADDING_P (TREE_TYPE (gnu_actual))
+                 && TREE_CODE (gnu_actual) != SAVE_EXPR)
+               gnu_actual = convert (get_unpadded_type (Etype (gnat_actual)),
+                                     gnu_actual);
+           }
+
+         /* Otherwise, if we have a non-addressable COMPONENT_REF of a
+            variable-size type see if it's doing a unpadding operation.  If
+            so, remove that operation since we have no way of allocating the
+            required temporary.  */
+         if (TREE_CODE (gnu_actual) == COMPONENT_REF
+             && ! TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (gnu_actual)))
+             && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_actual, 0)))
+                 == RECORD_TYPE)
+             && TYPE_IS_PADDING_P (TREE_TYPE
+                                   (TREE_OPERAND (gnu_actual, 0)))
+             && !addressable_p (gnu_actual))
+           gnu_actual = TREE_OPERAND (gnu_actual, 0);
+
+         /* The symmetry of the paths to the type of an entity is broken here
+            since arguments don't know that they will be passed by ref. */
+         gnu_formal_type = TREE_TYPE (get_gnu_tree (gnat_formal));
+         gnu_actual = build_unary_op (ADDR_EXPR, gnu_formal_type, gnu_actual);
+       }
+      else if (present_gnu_tree (gnat_formal)
+              && TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
+              && DECL_BY_COMPONENT_PTR_P (get_gnu_tree (gnat_formal)))
+       {
+         gnu_formal_type = TREE_TYPE (get_gnu_tree (gnat_formal));
+         gnu_actual = maybe_implicit_deref (gnu_actual);
+         gnu_actual = maybe_unconstrained_array (gnu_actual);
+
+         if (TREE_CODE (gnu_formal_type) == RECORD_TYPE
+             && TYPE_IS_PADDING_P (gnu_formal_type))
+           {
+             gnu_formal_type = TREE_TYPE (TYPE_FIELDS (gnu_formal_type));
+             gnu_actual = convert (gnu_formal_type, gnu_actual);
+           }
+
+         /* Take the address of the object and convert to the proper pointer
+            type.  We'd like to actually compute the address of the beginning
+            of the array using an ADDR_EXPR of an ARRAY_REF, but there's a
+            possibility that the ARRAY_REF might return a constant and we'd be
+            getting the wrong address.  Neither approach is exactly correct,
+            but this is the most likely to work in all cases.  */
+         gnu_actual = convert (gnu_formal_type,
+                               build_unary_op (ADDR_EXPR, NULL_TREE,
+                                               gnu_actual));
+       }
+      else if (present_gnu_tree (gnat_formal)
+              && TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
+              && DECL_BY_DESCRIPTOR_P (get_gnu_tree (gnat_formal)))
+       {
+         /* If arg is 'Null_Parameter, pass zero descriptor.  */
+         if ((TREE_CODE (gnu_actual) == INDIRECT_REF
+              || TREE_CODE (gnu_actual) == UNCONSTRAINED_ARRAY_REF)
+             && TREE_PRIVATE (gnu_actual))
+           gnu_actual = convert (DECL_ARG_TYPE (get_gnu_tree (gnat_formal)),
+                                 integer_zero_node);
+         else
+           gnu_actual = build_unary_op (ADDR_EXPR, NULL_TREE,
+                                        fill_vms_descriptor (gnu_actual,
+                                                             gnat_formal));
+       }
+      else
+       {
+         tree gnu_actual_size = TYPE_SIZE (TREE_TYPE (gnu_actual));
+         
+         if (Ekind (gnat_formal) != E_In_Parameter)
+           gnu_name_list = chainon (gnu_name_list,
+                                    build_tree_list (NULL_TREE, gnu_name));
+
+         if (! present_gnu_tree (gnat_formal)
+             || TREE_CODE (get_gnu_tree (gnat_formal)) != PARM_DECL)
+           continue;
+
+         /* If this is 'Null_Parameter, pass a zero even though we are
+            dereferencing it.  */
+         else if (TREE_CODE (gnu_actual) == INDIRECT_REF
+                  && TREE_PRIVATE (gnu_actual)
+                  && host_integerp (gnu_actual_size, 1)
+                  && 0 >= compare_tree_int (gnu_actual_size,
+                                                  BITS_PER_WORD))
+           gnu_actual
+             = unchecked_convert
+               (DECL_ARG_TYPE (get_gnu_tree (gnat_formal)),
+                convert (gnat_type_for_size
+                         (tree_low_cst (gnu_actual_size, 1), 1),
+                         integer_zero_node), 0);
+         else
+           gnu_actual = convert (TYPE_MAIN_VARIANT
+                                 (DECL_ARG_TYPE (get_gnu_tree (gnat_formal))),
+                                 gnu_actual);
+       }
+
+      gnu_actual_list = chainon (gnu_actual_list,
+                                build_tree_list (NULL_TREE, gnu_actual));
+    }
+
+  gnu_subprog_call = build (CALL_EXPR, TREE_TYPE (gnu_subprog_type),
+                           gnu_subprog_addr, gnu_actual_list, NULL_TREE);
+  TREE_SIDE_EFFECTS (gnu_subprog_call) = 1;
+
+  /* If it is a function call, the result is the call expression.  */
+  if (Nkind (gnat_node) == N_Function_Call)
+    {
+      gnu_result = gnu_subprog_call;
+
+      /* If the function returns an unconstrained array or by reference,
+        we have to de-dereference the pointer.  */
+      if (TYPE_RETURNS_UNCONSTRAINED_P (gnu_subprog_type)
+         || TYPE_RETURNS_BY_REF_P (gnu_subprog_type))
+       gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result);
+
+      *gnu_result_type_p = get_unpadded_type (Etype (gnat_node));
+      return gnu_result;
+    }
+
+  /* If this is the case where the GNAT tree contains a procedure call
+     but the Ada procedure has copy in copy out parameters, the special
+     parameter passing mechanism must be used.  */
+  else if (TYPE_CI_CO_LIST (gnu_subprog_type) != NULL_TREE)
+    {
+      /* List of FIELD_DECLs associated with the PARM_DECLs of the copy
+        in copy out parameters.  */
+      tree scalar_return_list = TYPE_CI_CO_LIST (gnu_subprog_type);
+      int length = list_length (scalar_return_list);
+
+      if (length > 1)
+       {
+         tree gnu_name;
+
+         gnu_subprog_call = protect_multiple_eval (gnu_subprog_call);
+
+         /* If any of the names had side-effects, ensure they are all
+            evaluated before the call.  */
+         for (gnu_name = gnu_name_list; gnu_name;
+              gnu_name = TREE_CHAIN (gnu_name))
+           if (TREE_SIDE_EFFECTS (TREE_VALUE (gnu_name)))
+             add_stmt (TREE_VALUE (gnu_name));
+       }
+
+      if (Nkind (Name (gnat_node)) == N_Explicit_Dereference)
+       gnat_formal = First_Formal (Etype (Name (gnat_node)));
+      else
+       gnat_formal = First_Formal (Entity (Name (gnat_node)));
+
+      for (gnat_actual = First_Actual (gnat_node);
+          Present (gnat_actual);
+          gnat_formal = Next_Formal_With_Extras (gnat_formal),
+          gnat_actual = Next_Actual (gnat_actual))
+       /* If we are dealing with a copy in copy out parameter, we must
+          retrieve its value from the record returned in the call.  */
+       if (! (present_gnu_tree (gnat_formal)
+              && TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
+              && (DECL_BY_REF_P (get_gnu_tree (gnat_formal))
+                  || (TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
+                      && ((DECL_BY_COMPONENT_PTR_P
+                           (get_gnu_tree (gnat_formal))
+                           || (DECL_BY_DESCRIPTOR_P
+                               (get_gnu_tree (gnat_formal))))))))
+           && Ekind (gnat_formal) != E_In_Parameter)
+         {
+           /* Get the value to assign to this OUT or IN OUT parameter.  It is
+              either the result of the function if there is only a single such
+              parameter or the appropriate field from the record returned.  */
+           tree gnu_result
+             = length == 1 ? gnu_subprog_call
+               : build_component_ref (gnu_subprog_call, NULL_TREE,
+                                      TREE_PURPOSE (scalar_return_list), 0);
+           bool unchecked_conversion = (Nkind (gnat_actual)
+                                        == N_Unchecked_Type_Conversion);
+           /* If the actual is a conversion, get the inner expression, which
+              will be the real destination, and convert the result to the
+              type of the actual parameter.  */
+           tree gnu_actual
+             = maybe_unconstrained_array (TREE_VALUE (gnu_name_list));
+
+           /* If the result is a padded type, remove the padding.  */
+           if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE
+               && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)))
+             gnu_result = convert (TREE_TYPE (TYPE_FIELDS
+                                              (TREE_TYPE (gnu_result))),
+                                   gnu_result);
+
+           /* If the result is a type conversion, do it.  */
+           if (Nkind (gnat_actual) == N_Type_Conversion)
+             gnu_result
+               = convert_with_check
+                 (Etype (Expression (gnat_actual)), gnu_result,
+                  Do_Overflow_Check (gnat_actual),
+                  Do_Range_Check (Expression (gnat_actual)),
+                  Float_Truncate (gnat_actual));
+
+           else if (unchecked_conversion)
+             gnu_result = unchecked_convert (TREE_TYPE (gnu_actual),
+                                             gnu_result,
+                                             No_Truncation (gnat_actual));
+           else
+             {
+               if (Do_Range_Check (gnat_actual))
+                 gnu_result = emit_range_check (gnu_result,
+                                                Etype (gnat_actual));
+
+               if (! (! TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (gnu_actual)))
+                      && TREE_CONSTANT (TYPE_SIZE
+                                        (TREE_TYPE (gnu_result)))))
+                 gnu_result = convert (TREE_TYPE (gnu_actual), gnu_result);
+             }
+               
+           gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
+                                         gnu_actual, gnu_result);
+           annotate_with_node (gnu_result, gnat_actual);
+           append_to_statement_list (gnu_result, &gnu_before_list);
+           scalar_return_list = TREE_CHAIN (scalar_return_list);
+           gnu_name_list = TREE_CHAIN (gnu_name_list);
+         }
+       }
+  else
+    {
+      annotate_with_node (gnu_subprog_call, gnat_node);
+      append_to_statement_list (gnu_subprog_call, &gnu_before_list);
+    }
+
+  append_to_statement_list (gnu_after_list, &gnu_before_list);
+  return gnu_before_list;
+}
+\f
+/* Subroutine of gnat_to_gnu to translate gnat_node, an
+   N_Handled_Sequence_Of_Statements, to a GCC tree, which is returned.  */
+
+static tree
+Handled_Sequence_Of_Statements_to_gnu (Node_Id gnat_node)
+{
+  tree gnu_jmpsave_decl = NULL_TREE;
+  tree gnu_jmpbuf_decl = NULL_TREE;
+  /* If just annotating, ignore all EH and cleanups.  */
+  bool gcc_zcx = (!type_annotate_only
+                 && Present (Exception_Handlers (gnat_node))
+                 && Exception_Mechanism == GCC_ZCX);
+  bool setjmp_longjmp
+    = (!type_annotate_only && Present (Exception_Handlers (gnat_node))
+       && Exception_Mechanism == Setjmp_Longjmp);
+  bool at_end = !type_annotate_only && Present (At_End_Proc (gnat_node));
+  bool binding_for_block = (at_end || gcc_zcx || setjmp_longjmp);
+  tree gnu_inner_block; /* The statement(s) for the block itself.  */
+  tree gnu_result;
+  tree gnu_expr;
+  Node_Id gnat_temp;
+
+  /* The GCC exception handling mechanism can handle both ZCX and SJLJ schemes
+     and we have our own SJLJ mechanism.  To call the GCC mechanism, we call
+     add_cleanup, and when we leave the binding, end_stmt_group will create
+     the TRY_FINALLY_EXPR.
+
+     ??? The region level calls down there have been specifically put in place
+     for a ZCX context and currently the order in which things are emitted
+     (region/handlers) is different from the SJLJ case. Instead of putting
+     other calls with different conditions at other places for the SJLJ case,
+     it seems cleaner to reorder things for the SJLJ case and generalize the
+     condition to make it not ZCX specific.
+
+     If there are any exceptions or cleanup processing involved, we need an
+     outer statement group (for Setjmp_Longjmp) and binding level.  */
+  if (binding_for_block)
+    {
+      start_stmt_group ();
+      gnat_pushlevel ();
+    }
+
+  /* If we are to call a function when exiting this block add a cleanup
+     to the binding level we made above.  */
+  if (at_end)
+    add_cleanup (build_call_0_expr (gnat_to_gnu (At_End_Proc (gnat_node))));
+
+  /* If using setjmp_longjmp, make the variables for the setjmp buffer and save
+     area for address of previous buffer.  Do this first since we need to have
+     the setjmp buf known for any decls in this block.  */
+  if (setjmp_longjmp)
+    {
+      gnu_jmpsave_decl = create_var_decl (get_identifier ("JMPBUF_SAVE"),
+                                         NULL_TREE, jmpbuf_ptr_type,
+                                         build_call_0_expr (get_jmpbuf_decl),
+                                         0, 0, 0, 0, 0, gnat_node);
+      gnu_jmpbuf_decl = create_var_decl (get_identifier ("JMP_BUF"),
+                                        NULL_TREE, jmpbuf_type,
+                                        NULL_TREE, 0, 0, 0, 0, 0, gnat_node);
+
+      set_block_jmpbuf_decl (gnu_jmpbuf_decl);
+
+      /* When we exit this block, restore the saved value.  */
+      add_cleanup (build_call_1_expr (set_jmpbuf_decl, gnu_jmpsave_decl));
+    }
+
+  /* Now build the tree for the declarations and statements inside this block.
+     If this is SJLJ, set our jmp_buf as the current buffer.  */
+  start_stmt_group ();
+
+  if (setjmp_longjmp)
+    add_stmt (build_call_1_expr (set_jmpbuf_decl,
+                                build_unary_op (ADDR_EXPR, NULL_TREE,
+                                                gnu_jmpbuf_decl)));
+
+
+  if (Present (First_Real_Statement (gnat_node)))
+    process_decls (Statements (gnat_node), Empty,
+                  First_Real_Statement (gnat_node), 1, 1);
+
+  /* Generate code for each statement in the block.  */
+  for (gnat_temp = (Present (First_Real_Statement (gnat_node))
+                   ? First_Real_Statement (gnat_node)
+                   : First (Statements (gnat_node)));
+       Present (gnat_temp); gnat_temp = Next (gnat_temp))
+    add_stmt (gnat_to_gnu (gnat_temp));
+  gnu_inner_block = end_stmt_group ();
+
+  /* Now generate code for the two exception models, if either is relevant for
+     this block.  */
+  if (setjmp_longjmp)
+    {
+      tree *gnu_else_ptr = 0;
+      tree gnu_handler;
+
+      /* Make a binding level for the exception handling declarations and code
+        and set up gnu_except_ptr_stack for the handlers to use.  */
+      start_stmt_group ();
+      gnat_pushlevel ();
+
+      push_stack (&gnu_except_ptr_stack, NULL_TREE,
+                 create_var_decl (get_identifier ("EXCEPT_PTR"),
+                                  NULL_TREE,
+                                  build_pointer_type (except_type_node),
+                                  build_call_0_expr (get_excptr_decl),
+                                  0, 0, 0, 0, 0, gnat_node));
+
+      /* Generate code for each handler. The N_Exception_Handler case does the
+        real work and returns a COND_EXPR for each handler, which we chain
+        together here.  */
+      for (gnat_temp = First_Non_Pragma (Exception_Handlers (gnat_node));
+          Present (gnat_temp); gnat_temp = Next_Non_Pragma (gnat_temp))
+       {
+         gnu_expr = gnat_to_gnu (gnat_temp);
+
+         /* If this is the first one, set it as the outer one. Otherwise,
+            point the "else" part of the previous handler to us. Then point
+            to our "else" part.  */
+         if (!gnu_else_ptr)
+           add_stmt (gnu_expr);
+         else
+           *gnu_else_ptr = gnu_expr;
+
+         gnu_else_ptr = &COND_EXPR_ELSE (gnu_expr);
+       }
+
+      /* If none of the exception handlers did anything, re-raise but do not
+        defer abortion.  */
+      gnu_expr = build_call_1_expr (raise_nodefer_decl,
+                                   TREE_VALUE (gnu_except_ptr_stack));
+      annotate_with_node (gnu_expr, gnat_node);
+
+      if (gnu_else_ptr)
+       *gnu_else_ptr = gnu_expr;
+      else
+       add_stmt (gnu_expr);
+
+      /* End the binding level dedicated to the exception handlers and get the
+        whole statement group.  */
+      pop_stack (&gnu_except_ptr_stack);
+      gnat_poplevel ();
+      gnu_handler = end_stmt_group ();
+
+      /* If the setjmp returns 1, we restore our incoming longjmp value and
+        then check the handlers.  */
+      start_stmt_group ();
+      add_stmt_with_node (build_call_1_expr (set_jmpbuf_decl,
+                                            gnu_jmpsave_decl),
+                         gnat_node);
+      add_stmt (gnu_handler);
+      gnu_handler = end_stmt_group ();
+
+      /* This block is now "if (setjmp) ... <handlers> else <block>".  */
+      gnu_result = build (COND_EXPR, void_type_node,
+                         (build_call_1_expr
+                          (setjmp_decl,
+                           build_unary_op (ADDR_EXPR, NULL_TREE,
+                                           gnu_jmpbuf_decl))),
+                         gnu_handler, gnu_inner_block);
+    }
+  else if (gcc_zcx)
+    {
+      tree gnu_handlers;
+
+      /* First make a block containing the handlers.  */
+      start_stmt_group ();
+      for (gnat_temp = First_Non_Pragma (Exception_Handlers (gnat_node));
+          Present (gnat_temp);
+          gnat_temp = Next_Non_Pragma (gnat_temp))
+       add_stmt (gnat_to_gnu (gnat_temp));
+      gnu_handlers = end_stmt_group ();
+
+      /* Now make the TRY_CATCH_EXPR for the block.  */
+      gnu_result = build (TRY_CATCH_EXPR, void_type_node,
+                         gnu_inner_block, gnu_handlers);
+    }
+  else
+    gnu_result = gnu_inner_block;
+
+  /* Now close our outer block, if we had to make one.  */
+  if (binding_for_block)
+    {
+      add_stmt (gnu_result);
+      gnat_poplevel ();
+      gnu_result = end_stmt_group ();
+    }
+
+  return gnu_result;
+}
+\f
+/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Exception_Handler,
+   to a GCC tree, which is returned.  This is the variant for Setjmp_Longjmp
+   exception handling.  */
+
+static tree
+Exception_Handler_to_gnu_sjlj (Node_Id gnat_node)
+{
+  /* Unless this is "Others" or the special "Non-Ada" exception for Ada, make
+     an "if" statement to select the proper exceptions.  For "Others", exclude
+     exceptions where Handled_By_Others is nonzero unless the All_Others flag
+     is set. For "Non-ada", accept an exception if "Lang" is 'V'.  */
+  tree gnu_choice = integer_zero_node;
+  tree gnu_body = build_stmt_group (Statements (gnat_node), false);
+  Node_Id gnat_temp;
+
+  for (gnat_temp = First (Exception_Choices (gnat_node));
+       gnat_temp; gnat_temp = Next (gnat_temp))
+    {
+      tree this_choice;
+
+      if (Nkind (gnat_temp) == N_Others_Choice)
+       {
+         if (All_Others (gnat_temp))
+           this_choice = integer_one_node;
+         else
+           this_choice
+             = build_binary_op
+               (EQ_EXPR, integer_type_node,
+                convert
+                (integer_type_node,
+                 build_component_ref
+                 (build_unary_op
+                  (INDIRECT_REF, NULL_TREE,
+                   TREE_VALUE (gnu_except_ptr_stack)),
+                  get_identifier ("not_handled_by_others"), NULL_TREE,
+                  0)),
+                integer_zero_node);
+       }
+
+      else if (Nkind (gnat_temp) == N_Identifier
+              || Nkind (gnat_temp) == N_Expanded_Name)
+       {
+         tree gnu_expr
+           = gnat_to_gnu_entity (Entity (gnat_temp), NULL_TREE, 0);
+
+         this_choice
+           = build_binary_op
+             (EQ_EXPR, integer_type_node, TREE_VALUE (gnu_except_ptr_stack),
+              convert (TREE_TYPE (TREE_VALUE (gnu_except_ptr_stack)),
+                       build_unary_op (ADDR_EXPR, NULL_TREE, gnu_expr)));
+
+         /* If this is the distinguished exception "Non_Ada_Error" (and we are
+            in VMS mode), also allow a non-Ada exception (a VMS condition) t
+            match.  */
+         if (Is_Non_Ada_Error (Entity (gnat_temp)))
+           {
+             tree gnu_comp
+               = build_component_ref
+                 (build_unary_op (INDIRECT_REF, NULL_TREE,
+                                  TREE_VALUE (gnu_except_ptr_stack)),
+                  get_identifier ("lang"), NULL_TREE, 0);
+
+             this_choice
+               = build_binary_op
+                 (TRUTH_ORIF_EXPR, integer_type_node,
+                  build_binary_op (EQ_EXPR, integer_type_node, gnu_comp,
+                                   convert (TREE_TYPE (gnu_comp),
+                                            build_int_2 ('V', 0))),
+                  this_choice);
+           }
+       }
+      else
+       gigi_abort (318);
+
+      gnu_choice = build_binary_op (TRUTH_ORIF_EXPR, integer_type_node,
+                                   gnu_choice, this_choice);
+    }
+
+  return build (COND_EXPR, void_type_node, gnu_choice, gnu_body, NULL_TREE);
+}
+\f
+/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Exception_Handler,
+   to a GCC tree, which is returned.  This is the variant for ZCX.  */
+
+static tree
+Exception_Handler_to_gnu_zcx (Node_Id gnat_node)
+{
+  tree gnu_etypes_list = NULL_TREE;
+  tree gnu_expr;
+  tree gnu_etype;
+  tree gnu_current_exc_ptr;
+  tree gnu_incoming_exc_ptr;
+  Node_Id gnat_temp;
+
+  /* We build a TREE_LIST of nodes representing what exception types this
+     handler can catch, with special cases for others and all others cases.
+
+     Each exception type is actually identified by a pointer to the exception
+     id, with special value zero for "others" and one for "all others". Beware
+     that these special values are known and used by the personality routine to
+     identify the corresponding specific kinds of handlers.
+
+     ??? For initial time frame reasons, the others and all_others cases have
+     been handled using specific type trees, but this somehow hides information
+     from the back-end, which expects NULL to be passed for catch all and
+     end_cleanup to be used for cleanups.
+
+     Care should be taken to ensure that the control flow impact of such
+     clauses is rendered in some way. lang_eh_type_covers is doing the trick
+     currently.  */
+  for (gnat_temp = First (Exception_Choices (gnat_node));
+       gnat_temp; gnat_temp = Next (gnat_temp))
+    {
+      if (Nkind (gnat_temp) == N_Others_Choice)
+       gnu_etype = (All_Others (gnat_temp) ? integer_one_node
+                    : integer_zero_node);
+      else if (Nkind (gnat_temp) == N_Identifier
+              || Nkind (gnat_temp) == N_Expanded_Name)
+       {
+         Entity_Id gnat_ex_id = Entity (gnat_temp);
+
+         /* Exception may be a renaming. Recover original exception which is
+            the one elaborated and registered.  */
+         if (Present (Renamed_Object (gnat_ex_id)))
+           gnat_ex_id = Renamed_Object (gnat_ex_id);
+
+         gnu_expr = gnat_to_gnu_entity (gnat_ex_id, NULL_TREE, 0);
+         gnu_etype = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_expr);
+
+         /* The Non_Ada_Error case for VMS exceptions is handled
+            by the personality routine.  */
+       }
+      else
+       gigi_abort (337);
+
+      /* The GCC interface expects NULL to be passed for catch all handlers, so
+        it would be quite tempting to set gnu_etypes_list to NULL if gnu_etype
+        is integer_zero_node.  It would not work, however, because GCC's
+        notion of "catch all" is stronger than our notion of "others".  Until
+        we correctly use the cleanup interface as well, doing that would
+        prevent the "all others" handlers from beeing seen, because nothing
+        can be caught beyond a catch all from GCC's point of view.  */
+      gnu_etypes_list = tree_cons (NULL_TREE, gnu_etype, gnu_etypes_list);
+    }
+
+  start_stmt_group ();
+  gnat_pushlevel ();
+
+  /* Expand a call to the begin_handler hook at the beginning of the handler,
+     and arrange for a call to the end_handler hook to occur on every possible
+     exit path.
+
+     The hooks expect a pointer to the low level occurrence. This is required
+     for our stack management scheme because a raise inside the handler pushes
+     a new occurrence on top of the stack, which means that this top does not
+     necessarily match the occurrence this handler was dealing with.
+
+     The EXC_PTR_EXPR object references the exception occurrence being
+     propagated. Upon handler entry, this is the exception for which the
+     handler is triggered. This might not be the case upon handler exit,
+     however, as we might have a new occurrence propagated by the handler's
+     body, and the end_handler hook called as a cleanup in this context.
+
+     We use a local variable to retrieve the incoming value at handler entry
+     time, and reuse it to feed the end_handler hook's argument at exit.  */
+  gnu_current_exc_ptr = build (EXC_PTR_EXPR, ptr_type_node);
+  gnu_incoming_exc_ptr = create_var_decl (get_identifier ("EXPTR"), NULL_TREE,
+                                         ptr_type_node, gnu_current_exc_ptr,
+                                         0, 0, 0, 0, 0, gnat_node);
+
+  add_stmt_with_node (build_call_1_expr (begin_handler_decl,
+                                        gnu_incoming_exc_ptr),
+                     gnat_node);
+  add_cleanup (build_call_1_expr (end_handler_decl, gnu_incoming_exc_ptr));
+  add_stmt_list (Statements (gnat_node));
+  gnat_poplevel ();
+
+  return build (CATCH_EXPR, void_type_node, gnu_etypes_list,
+               end_stmt_group ());
+}
+\f
 /* This function is the driver of the GNAT to GCC tree transformation
    process.  It is the entry point of the tree transformer.  GNAT_NODE is the
    root of some GNAT tree.  Return the root of the corresponding GCC tree.
@@ -315,7 +2345,6 @@ gnat_to_gnu (Node_Id gnat_node)
   tree gnu_expr;
   tree gnu_lhs, gnu_rhs;
   Node_Id gnat_temp;
-  Entity_Id gnat_temp_type;
 
   /* Save node number for error message and set location information.  */
   error_gnat_node = gnat_node;
@@ -354,7 +2383,6 @@ gnat_to_gnu (Node_Id gnat_node)
       went_into_elab_proc = true;
     }
 
-
   switch (Nkind (gnat_node))
     {
       /********************************/
@@ -365,182 +2393,7 @@ gnat_to_gnu (Node_Id gnat_node)
     case N_Expanded_Name:
     case N_Operator_Symbol:
     case N_Defining_Identifier:
-
-      /* If the Etype of this node does not equal the Etype of the Entity,
-         something is wrong with the entity map, probably in generic
-         instantiation. However, this does not apply to types. Since we
-         sometime have strange Ekind's, just do this test for objects. Also,
-         if the Etype of the Entity is private, the Etype of the N_Identifier
-         is allowed to be the full type and also we consider a packed array
-         type to be the same as the original type. Similarly, a class-wide
-         type is equivalent to a subtype of itself. Finally, if the types are
-         Itypes, one may be a copy of the other, which is also legal.  */
-      gnat_temp = (Nkind (gnat_node) == N_Defining_Identifier
-                  ? gnat_node : Entity (gnat_node));
-      gnat_temp_type = Etype (gnat_temp);
-
-      if (Etype (gnat_node) != gnat_temp_type
-          && ! (Is_Packed (gnat_temp_type)
-                && Etype (gnat_node) == Packed_Array_Type (gnat_temp_type))
-          && ! (Is_Class_Wide_Type (Etype (gnat_node)))
-          && ! (IN (Ekind (gnat_temp_type), Private_Kind)
-                && Present (Full_View (gnat_temp_type))
-                && ((Etype (gnat_node) == Full_View (gnat_temp_type))
-                    || (Is_Packed (Full_View (gnat_temp_type))
-                        && Etype (gnat_node) ==
-                             Packed_Array_Type (Full_View (gnat_temp_type)))))
-          && (!Is_Itype (Etype (gnat_node)) || !Is_Itype (gnat_temp_type))
-          && (Ekind (gnat_temp) == E_Variable
-             || Ekind (gnat_temp) == E_Component
-             || Ekind (gnat_temp) == E_Constant
-             || Ekind (gnat_temp) == E_Loop_Parameter
-             || IN (Ekind (gnat_temp), Formal_Kind)))
-       gigi_abort (304);
-
-      /* If this is a reference to a deferred constant whose partial view
-         is an unconstrained private type, the proper type is on the full
-         view of the constant, not on the full view of the type, which may
-         be unconstrained.
-
-         This may be a reference to a type, for example in the prefix of the
-         attribute Position, generated for dispatching code (see Make_DT in
-         exp_disp,adb). In that case we need the type itself, not is parent,
-         in particular if it is a derived type  */
-      if (Is_Private_Type (gnat_temp_type)
-         && Has_Unknown_Discriminants (gnat_temp_type)
-         && Present (Full_View (gnat_temp))
-          && ! Is_Type (gnat_temp))
-       {
-         gnat_temp = Full_View (gnat_temp);
-         gnat_temp_type = Etype (gnat_temp);
-         gnu_result_type = get_unpadded_type (gnat_temp_type);
-       }
-      else
-       {
-         /* Expand the type of this identitier first, in case it is
-            an enumeral literal, which only get made when the type
-            is expanded.  There is no order-of-elaboration issue here.
-            We want to use the Actual_Subtype if it has already been
-            elaborated, otherwise the Etype.  Avoid using Actual_Subtype
-            for packed arrays to simplify things.  */
-         if ((Ekind (gnat_temp) == E_Constant
-              || Ekind (gnat_temp) == E_Variable || Is_Formal (gnat_temp))
-             && ! (Is_Array_Type (Etype (gnat_temp))
-                   && Present (Packed_Array_Type (Etype (gnat_temp))))
-             && Present (Actual_Subtype (gnat_temp))
-             && present_gnu_tree (Actual_Subtype (gnat_temp)))
-           gnat_temp_type = Actual_Subtype (gnat_temp);
-         else
-           gnat_temp_type = Etype (gnat_node);
-
-         gnu_result_type = get_unpadded_type (gnat_temp_type);
-       }
-
-      gnu_result = gnat_to_gnu_entity (gnat_temp, NULL_TREE, 0);
-
-      /* If we are in an exception handler, force this variable into memory
-        to ensure optimization does not remove stores that appear
-        redundant but are actually needed in case an exception occurs.
-
-        ??? Note that we need not do this if the variable is declared within
-        the handler, only if it is referenced in the handler and declared
-        in an enclosing block, but we have no way of testing that
-        right now.
-
-        ??? Also, for now all we can do is make it volatile.  But we only
-        do this for SJLJ.  */
-      if (TREE_VALUE (gnu_except_ptr_stack) != 0
-         && TREE_CODE (gnu_result) == VAR_DECL)
-       TREE_THIS_VOLATILE (gnu_result) = TREE_SIDE_EFFECTS (gnu_result) = 1;
-
-      /* Some objects (such as parameters passed by reference, globals of
-        variable size, and renamed objects) actually represent the address
-        of the object.  In that case, we must do the dereference.  Likewise,
-        deal with parameters to foreign convention subprograms.  Call fold
-        here since GNU_RESULT may be a CONST_DECL.  */
-      if (DECL_P (gnu_result)
-         && (DECL_BY_REF_P (gnu_result)
-             || (TREE_CODE (gnu_result) == PARM_DECL
-                 && DECL_BY_COMPONENT_PTR_P (gnu_result))))
-       {
-         int ro = DECL_POINTS_TO_READONLY_P (gnu_result);
-         tree initial;
-
-         if (TREE_CODE (gnu_result) == PARM_DECL
-             && DECL_BY_COMPONENT_PTR_P (gnu_result))
-           gnu_result
-             = build_unary_op (INDIRECT_REF, NULL_TREE,
-                               convert (build_pointer_type (gnu_result_type),
-                                        gnu_result));
-
-         /* If the object is constant, we try to do the dereference directly
-            through the DECL_INITIAL.  This is actually required in order to
-            get correct aliasing information for renamed objects that are
-            components of non-aliased aggregates, because the type of the
-            renamed object and that of the aggregate don't alias.
-
-            Note that we expect the initial value to have been stabilized.
-            If it contains e.g. a variable reference, we certainly don't want
-            to re-evaluate the variable each time the renaming is used.
-
-            Stabilization is currently not performed at the global level but
-            create_var_decl avoids setting DECL_INITIAL if the value is not
-            constant then, and we get to the pointer dereference below.
-
-            ??? Couldn't the aliasing issue show up again in this case ?
-            There is no obvious reason why not.  */
-         else if (TREE_READONLY (gnu_result)
-                  && DECL_INITIAL (gnu_result)
-                  /* Strip possible conversion to reference type.  */
-                  && ((initial = TREE_CODE (DECL_INITIAL (gnu_result))
-                       == NOP_EXPR
-                       ? TREE_OPERAND (DECL_INITIAL (gnu_result), 0)
-                       : DECL_INITIAL (gnu_result), 1))
-                  && TREE_CODE (initial) == ADDR_EXPR
-                  && (TREE_CODE (TREE_OPERAND (initial, 0)) == ARRAY_REF
-                      || (TREE_CODE (TREE_OPERAND (initial, 0))
-                          == COMPONENT_REF)))
-           gnu_result = TREE_OPERAND (initial, 0);
-         else
-           gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE,
-                                        fold (gnu_result));
-
-         TREE_READONLY (gnu_result) = TREE_STATIC (gnu_result) = ro;
-       }
-
-      /* The GNAT tree has the type of a function as the type of its result.
-        Also use the type of the result if the Etype is a subtype which
-        is nominally unconstrained.  But remove any padding from the
-        resulting type.  */
-      if (TREE_CODE (TREE_TYPE (gnu_result)) == FUNCTION_TYPE
-         || Is_Constr_Subt_For_UN_Aliased (gnat_temp_type))
-       {
-         gnu_result_type = TREE_TYPE (gnu_result);
-         if (TREE_CODE (gnu_result_type) == RECORD_TYPE
-             && TYPE_IS_PADDING_P (gnu_result_type))
-           gnu_result_type = TREE_TYPE (TYPE_FIELDS (gnu_result_type));
-       }
-
-      /* We always want to return the underlying INTEGER_CST for an
-        enumeration literal to avoid the need to call fold in lots
-        of places.  But don't do this is the parent will be taking
-        the address of this object.  */
-      if (TREE_CODE (gnu_result) == CONST_DECL)
-       {
-         gnat_temp = Parent (gnat_node);
-         if (DECL_CONST_CORRESPONDING_VAR (gnu_result) == 0
-             || (Nkind (gnat_temp) != N_Reference
-                 && ! (Nkind (gnat_temp) == N_Attribute_Reference
-                       && ((Get_Attribute_Id (Attribute_Name (gnat_temp))
-                            == Attr_Address)
-                           || (Get_Attribute_Id (Attribute_Name (gnat_temp))
-                               == Attr_Access)
-                           || (Get_Attribute_Id (Attribute_Name (gnat_temp))
-                               == Attr_Unchecked_Access)
-                           || (Get_Attribute_Id (Attribute_Name (gnat_temp))
-                               == Attr_Unrestricted_Access)))))
-           gnu_result = DECL_INITIAL (gnu_result);
-       }
+      gnu_result = Identifier_to_gnu (gnat_node, &gnu_result_type);
       break;
 
     case N_Integer_Literal:
@@ -657,9 +2510,6 @@ gnat_to_gnu (Node_Id gnat_node)
       gnu_result_type = get_unpadded_type (Etype (gnat_node));
       if (TYPE_PRECISION (TREE_TYPE (gnu_result_type)) == HOST_BITS_PER_CHAR)
        {
-         /* We assume here that all strings are of type standard.string.
-            "Weird" types of string have been converted to an aggregate
-            by the expander. */
          String_Id gnat_string = Strval (gnat_node);
          int length = String_Length (gnat_string);
          char *string = (char *) alloca (length + 1);
@@ -711,58 +2561,7 @@ gnat_to_gnu (Node_Id gnat_node)
 
     case N_Pragma:
       gnu_result = alloc_stmt_list ();
-      /* Check for (and ignore) unrecognized pragma and do nothing if
-        we are just annotating types.  */
-      if (type_annotate_only
-         || ! Is_Pragma_Name (Chars (gnat_node)))
-        break;
-
-      switch (Get_Pragma_Id (Chars (gnat_node)))
-       {
-       case Pragma_Inspection_Point:
-         /* Do nothing at top level: all such variables are already
-            viewable.  */
-         if (global_bindings_p ())
-           break;
-
-         for (gnat_temp = First (Pragma_Argument_Associations (gnat_node));
-              Present (gnat_temp);
-              gnat_temp = Next (gnat_temp))
-           {
-             gnu_expr = gnat_to_gnu (Expression (gnat_temp));
-             if (TREE_CODE (gnu_expr) == UNCONSTRAINED_ARRAY_REF)
-               gnu_expr = TREE_OPERAND (gnu_expr, 0);
-
-             gnu_expr = build1 (USE_STMT, void_type_node, gnu_expr);
-             add_stmt (gnu_expr);
-           }
-         break;
-
-       case Pragma_Optimize:
-         switch (Chars (Expression
-                        (First (Pragma_Argument_Associations (gnat_node)))))
-           {
-           case Name_Time:  case Name_Space:
-             if (optimize == 0)
-               post_error ("insufficient -O value?", gnat_node);
-             break;
-
-           case Name_Off:
-             if (optimize != 0)
-               post_error ("must specify -O0?", gnat_node);
-             break;
-
-           default:
-             gigi_abort (331);
-             break;
-           }
-         break;
-
-       case Pragma_Reviewable:
-         if (write_symbols == NO_DEBUG)
-           post_error ("must specify -g?", gnat_node);
-         break;
-       }
+      Pragma_to_gnu (gnat_node);
       break;
 
     /**************************************/
@@ -1003,659 +2802,88 @@ gnat_to_gnu (Node_Id gnat_node)
         gnu_result = build_binary_op (ARRAY_RANGE_REF, gnu_result_type,
                                      gnu_result, gnu_expr);
       }
-      break;
-
-    case N_Selected_Component:
-      {
-       tree gnu_prefix = gnat_to_gnu (Prefix (gnat_node));
-       Entity_Id gnat_field = Entity (Selector_Name (gnat_node));
-       Entity_Id gnat_pref_type = Etype (Prefix (gnat_node));
-       tree gnu_field;
-
-       while (IN (Ekind (gnat_pref_type), Incomplete_Or_Private_Kind)
-              || IN (Ekind (gnat_pref_type), Access_Kind))
-         {
-           if (IN (Ekind (gnat_pref_type), Incomplete_Or_Private_Kind))
-             gnat_pref_type = Underlying_Type (gnat_pref_type);
-           else if (IN (Ekind (gnat_pref_type), Access_Kind))
-             gnat_pref_type = Designated_Type (gnat_pref_type);
-         }
-
-       gnu_prefix = maybe_implicit_deref (gnu_prefix);
-
-       /* For discriminant references in tagged types always substitute the
-          corresponding discriminant as the actual selected component. */
-
-       if (Is_Tagged_Type (gnat_pref_type))
-         while (Present (Corresponding_Discriminant (gnat_field)))
-           gnat_field = Corresponding_Discriminant (gnat_field);
-
-       /* For discriminant references of untagged types always substitute the
-          corresponding stored discriminant. */
-
-       else if (Present (Corresponding_Discriminant (gnat_field)))
-         gnat_field = Original_Record_Component (gnat_field);
-
-       /* Handle extracting the real or imaginary part of a complex.
-          The real part is the first field and the imaginary the last.  */
-
-       if (TREE_CODE (TREE_TYPE (gnu_prefix)) == COMPLEX_TYPE)
-         gnu_result = build_unary_op (Present (Next_Entity (gnat_field))
-                                      ? REALPART_EXPR : IMAGPART_EXPR,
-                                      NULL_TREE, gnu_prefix);
-       else
-         {
-           gnu_field = gnat_to_gnu_entity (gnat_field, NULL_TREE, 0);
-
-           /* If there are discriminants, the prefix might be
-               evaluated more than once, which is a problem if it has
-               side-effects. */
-           if (Has_Discriminants (Is_Access_Type (Etype (Prefix (gnat_node)))
-                                  ? Designated_Type (Etype
-                                                     (Prefix (gnat_node)))
-                                  : Etype (Prefix (gnat_node))))
-             gnu_prefix = gnat_stabilize_reference (gnu_prefix, 0);
-
-           gnu_result
-             = build_component_ref (gnu_prefix, NULL_TREE, gnu_field,
-                                    (Nkind (Parent (gnat_node))
-                                     == N_Attribute_Reference));
-         }
-
-       if (gnu_result == 0)
-         gigi_abort (308);
-
-       gnu_result_type = get_unpadded_type (Etype (gnat_node));
-      }
-      break;
-
-    case N_Attribute_Reference:
-      {
-        /* The attribute designator (like an enumeration value). */
-        int attribute = Get_Attribute_Id (Attribute_Name (gnat_node));
-       int prefix_unused = 0;
-       tree gnu_prefix;
-       tree gnu_type;
-
-       /* The Elab_Spec and Elab_Body attributes are special in that
-          Prefix is a unit, not an object with a GCC equivalent.  Similarly
-          for Elaborated, since that variable isn't otherwise known.  */
-       if (attribute == Attr_Elab_Body || attribute == Attr_Elab_Spec)
-         return (create_subprog_decl
-                 (create_concat_name (Entity (Prefix (gnat_node)),
-                                      attribute == Attr_Elab_Body
-                                      ? "elabb" : "elabs"),
-                  NULL_TREE, void_ftype, NULL_TREE, 0, 1, 1, 0, gnat_node));
-
-       gnu_prefix = gnat_to_gnu (Prefix (gnat_node));
-       gnu_type = TREE_TYPE (gnu_prefix);
-
-       /* If the input is a NULL_EXPR, make a new one.  */
-       if (TREE_CODE (gnu_prefix) == NULL_EXPR)
-         {
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           gnu_result = build1 (NULL_EXPR, gnu_result_type,
-                                TREE_OPERAND (gnu_prefix, 0));
-           break;
-         }
-
-        switch (attribute)
-          {
-         case Attr_Pos:
-         case Attr_Val:
-           /* These are just conversions until since representation
-              clauses for enumerations are handled in the front end.  */
-           {
-             int check_p = Do_Range_Check (First (Expressions (gnat_node)));
-
-             gnu_result = gnat_to_gnu (First (Expressions (gnat_node)));
-             gnu_result_type = get_unpadded_type (Etype (gnat_node));
-             gnu_result = convert_with_check (Etype (gnat_node), gnu_result,
-                                              check_p, check_p, 1);
-           }
-           break;
-
-         case Attr_Pred:
-         case Attr_Succ:
-           /* These just add or subject the constant 1.  Representation
-              clauses for enumerations are handled in the front-end.  */
-           gnu_expr = gnat_to_gnu (First (Expressions (gnat_node)));
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-
-           if (Do_Range_Check (First (Expressions (gnat_node))))
-             {
-               gnu_expr = protect_multiple_eval (gnu_expr);
-               gnu_expr
-                 = emit_check
-                   (build_binary_op (EQ_EXPR, integer_type_node,
-                                     gnu_expr,
-                                     attribute == Attr_Pred
-                                     ? TYPE_MIN_VALUE (gnu_result_type)
-                                     : TYPE_MAX_VALUE (gnu_result_type)),
-                    gnu_expr, CE_Range_Check_Failed);
-             }
-
-           gnu_result
-             = build_binary_op (attribute == Attr_Pred
-                                ? MINUS_EXPR : PLUS_EXPR,
-                                gnu_result_type, gnu_expr,
-                                convert (gnu_result_type, integer_one_node));
-           break;
-
-         case Attr_Address:
-         case Attr_Unrestricted_Access:
-
-           /* Conversions don't change something's address but can cause
-              us to miss the COMPONENT_REF case below, so strip them off.  */
-           gnu_prefix
-             = remove_conversions (gnu_prefix,
-                                   ! Must_Be_Byte_Aligned (gnat_node));
-
-           /* If we are taking 'Address of an unconstrained object,
-              this is the pointer to the underlying array.  */
-           gnu_prefix = maybe_unconstrained_array (gnu_prefix);
-
-           /* ... fall through ... */
-
-         case Attr_Access:
-         case Attr_Unchecked_Access:
-         case Attr_Code_Address:
-
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           gnu_result
-             = build_unary_op (((attribute == Attr_Address
-                                 || attribute == Attr_Unrestricted_Access)
-                                && ! Must_Be_Byte_Aligned (gnat_node))
-                               ? ATTR_ADDR_EXPR : ADDR_EXPR,
-                               gnu_result_type, gnu_prefix);
-
-           /* For 'Code_Address, find an inner ADDR_EXPR and mark it
-              so that we don't try to build a trampoline.  */
-           if (attribute == Attr_Code_Address)
-             {
-               for (gnu_expr = gnu_result;
-                    TREE_CODE (gnu_expr) == NOP_EXPR
-                    || TREE_CODE (gnu_expr) == CONVERT_EXPR;
-                    gnu_expr = TREE_OPERAND (gnu_expr, 0))
-                 TREE_CONSTANT (gnu_expr) = 1;
-                 ;
-
-               if (TREE_CODE (gnu_expr) == ADDR_EXPR)
-                 TREE_STATIC (gnu_expr) = TREE_CONSTANT (gnu_expr) = 1;
-             }
-
-           break;
-
-          case Attr_Pool_Address:
-            {
-            tree gnu_obj_type;
-             tree gnu_ptr = gnu_prefix;
-
-            gnu_result_type = get_unpadded_type (Etype (gnat_node));
-
-            /* If this is an unconstrained array, we know the object must
-               have been allocated with the template in front of the object.
-               So compute the template address.*/
-
-            if (TYPE_FAT_POINTER_P (TREE_TYPE (gnu_ptr)))
-              gnu_ptr
-                = convert (build_pointer_type
-                   (TYPE_OBJECT_RECORD_TYPE
-                     (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (gnu_ptr)))),
-                       gnu_ptr);
-
-            gnu_obj_type = TREE_TYPE (TREE_TYPE (gnu_ptr));
-            if (TREE_CODE (gnu_obj_type) == RECORD_TYPE
-                && TYPE_CONTAINS_TEMPLATE_P (gnu_obj_type))
-              {
-                tree gnu_char_ptr_type = build_pointer_type (char_type_node);
-                tree gnu_pos = byte_position (TYPE_FIELDS (gnu_obj_type));
-                tree gnu_byte_offset
-                  = convert (gnu_char_ptr_type,
-                             size_diffop (size_zero_node, gnu_pos));
-
-                gnu_ptr = convert (gnu_char_ptr_type, gnu_ptr);
-                gnu_ptr = build_binary_op (MINUS_EXPR, gnu_char_ptr_type,
-                                           gnu_ptr, gnu_byte_offset);
-               }
-
-             gnu_result = convert (gnu_result_type, gnu_ptr);
-            }
-            break;
-
-         case Attr_Size:
-         case Attr_Object_Size:
-         case Attr_Value_Size:
-         case Attr_Max_Size_In_Storage_Elements:
-
-           gnu_expr = gnu_prefix;
-
-           /* Remove NOPS from gnu_expr and conversions from gnu_prefix.
-              We only use GNU_EXPR to see if a COMPONENT_REF was involved. */
-           while (TREE_CODE (gnu_expr) == NOP_EXPR)
-             gnu_expr = TREE_OPERAND (gnu_expr, 0);
-
-           gnu_prefix = remove_conversions (gnu_prefix, 1);
-           prefix_unused = 1;
-           gnu_type = TREE_TYPE (gnu_prefix);
-
-           /* Replace an unconstrained array type with the type of the
-              underlying array.  We can't do this with a call to
-              maybe_unconstrained_array since we may have a TYPE_DECL.
-              For 'Max_Size_In_Storage_Elements, use the record type
-              that will be used to allocate the object and its template.  */
-
-           if (TREE_CODE (gnu_type) == UNCONSTRAINED_ARRAY_TYPE)
-             {
-               gnu_type = TYPE_OBJECT_RECORD_TYPE (gnu_type);
-               if (attribute != Attr_Max_Size_In_Storage_Elements)
-                 gnu_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (gnu_type)));
-             }
-
-           /* If we are looking for the size of a field, return the
-              field size.  Otherwise, if the prefix is an object,
-              or if 'Object_Size or 'Max_Size_In_Storage_Elements has
-              been specified, the result is the GCC size of the type.
-              Otherwise, the result is the RM_Size of the type.  */
-           if (TREE_CODE (gnu_prefix) == COMPONENT_REF)
-             gnu_result = DECL_SIZE (TREE_OPERAND (gnu_prefix, 1));
-           else if (TREE_CODE (gnu_prefix) != TYPE_DECL
-                    || attribute == Attr_Object_Size
-                    || attribute == Attr_Max_Size_In_Storage_Elements)
-             {
-               /* If this is a padded type, the GCC size isn't relevant
-                  to the programmer.  Normally, what we want is the RM_Size,
-                  which was set from the specified size, but if it was not
-                  set, we want the size of the relevant field.  Using the MAX
-                  of those two produces the right result in all case.  Don't
-                  use the size of the field if it's a self-referential type,
-                  since that's never what's wanted.  */
-               if (TREE_CODE (gnu_type) == RECORD_TYPE
-                   && TYPE_IS_PADDING_P (gnu_type)
-                   && TREE_CODE (gnu_expr) == COMPONENT_REF)
-                 {
-                   gnu_result = rm_size (gnu_type);
-                   if (! (CONTAINS_PLACEHOLDER_P
-                          (DECL_SIZE (TREE_OPERAND (gnu_expr, 1)))))
-                     gnu_result
-                       = size_binop (MAX_EXPR, gnu_result,
-                                     DECL_SIZE (TREE_OPERAND (gnu_expr, 1)));
-                 }
-               else
-                 gnu_result = TYPE_SIZE (gnu_type);
-             }
-           else
-             gnu_result = rm_size (gnu_type);
-
-           if (gnu_result == 0)
-             gigi_abort (325);
-
-           /* Deal with a self-referential size by returning the maximum
-              size for a type and by qualifying the size with
-              the object for 'Size of an object.  */
-
-           if (CONTAINS_PLACEHOLDER_P (gnu_result))
-             {
-               if (TREE_CODE (gnu_prefix) != TYPE_DECL)
-                 gnu_result = substitute_placeholder_in_expr (gnu_result,
-                                                              gnu_expr);
-               else
-                 gnu_result = max_size (gnu_result, 1);
-             }
-
-           /* If the type contains a template, subtract the size of the
-              template.  */
-           if (TREE_CODE (gnu_type) == RECORD_TYPE
-               && TYPE_CONTAINS_TEMPLATE_P (gnu_type))
-             gnu_result = size_binop (MINUS_EXPR, gnu_result,
-                                      DECL_SIZE (TYPE_FIELDS (gnu_type)));
-
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-
-            /* Always perform division using unsigned arithmetic as the
-              size cannot be negative, but may be an overflowed positive
-              value. This provides correct results for sizes up to 512 MB.
-              ??? Size should be calculated in storage elements directly.  */
-
-           if (attribute == Attr_Max_Size_In_Storage_Elements)
-             gnu_result = convert (sizetype,
-                                   fold (build (CEIL_DIV_EXPR, bitsizetype,
-                                                gnu_result,
-                                                bitsize_unit_node)));
-           break;
-
-         case Attr_Alignment:
-           if (TREE_CODE (gnu_prefix) == COMPONENT_REF
-               && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))
-                   == RECORD_TYPE)
-               && (TYPE_IS_PADDING_P
-                   (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))))
-             gnu_prefix = TREE_OPERAND (gnu_prefix, 0);
-
-           gnu_type = TREE_TYPE (gnu_prefix);
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           prefix_unused = 1;
-
-           if (TREE_CODE (gnu_prefix) == COMPONENT_REF)
-             gnu_result
-               = size_int (DECL_ALIGN (TREE_OPERAND (gnu_prefix, 1)));
-           else
-             gnu_result = size_int (TYPE_ALIGN (gnu_type) / BITS_PER_UNIT);
-           break;
-
-         case Attr_First:
-         case Attr_Last:
-         case Attr_Range_Length:
-           prefix_unused = 1;
-
-           if (INTEGRAL_TYPE_P (gnu_type)
-               || TREE_CODE (gnu_type) == REAL_TYPE)
-             {
-               gnu_result_type = get_unpadded_type (Etype (gnat_node));
-
-               if (attribute == Attr_First)
-                 gnu_result = TYPE_MIN_VALUE (gnu_type);
-               else if (attribute == Attr_Last)
-                 gnu_result = TYPE_MAX_VALUE (gnu_type);
-               else
-                 gnu_result
-                   = build_binary_op
-                     (MAX_EXPR, get_base_type (gnu_result_type),
-                      build_binary_op
-                      (PLUS_EXPR, get_base_type (gnu_result_type),
-                       build_binary_op (MINUS_EXPR,
-                                        get_base_type (gnu_result_type),
-                                        convert (gnu_result_type,
-                                                 TYPE_MAX_VALUE (gnu_type)),
-                                        convert (gnu_result_type,
-                                                 TYPE_MIN_VALUE (gnu_type))),
-                       convert (gnu_result_type, integer_one_node)),
-                      convert (gnu_result_type, integer_zero_node));
-
-               break;
-             }
-           /* ... fall through ... */
-         case Attr_Length:
-           {
-             int Dimension
-               = (Present (Expressions (gnat_node))
-                  ? UI_To_Int (Intval (First (Expressions (gnat_node))))
-                  : 1);
-
-             /* Make sure any implicit dereference gets done.  */
-             gnu_prefix = maybe_implicit_deref (gnu_prefix);
-             gnu_prefix = maybe_unconstrained_array (gnu_prefix);
-             gnu_type = TREE_TYPE (gnu_prefix);
-             prefix_unused = 1;
-             gnu_result_type = get_unpadded_type (Etype (gnat_node));
-
-             if (TYPE_CONVENTION_FORTRAN_P (gnu_type))
-               {
-                 int ndim;
-                 tree gnu_type_temp;
-
-                 for (ndim = 1, gnu_type_temp = gnu_type;
-                      TREE_CODE (TREE_TYPE (gnu_type_temp)) == ARRAY_TYPE
-                      && TYPE_MULTI_ARRAY_P (TREE_TYPE (gnu_type_temp));
-                      ndim++, gnu_type_temp = TREE_TYPE (gnu_type_temp))
-                   ;
-
-                 Dimension = ndim + 1 - Dimension;
-               }
-
-             for (; Dimension > 1; Dimension--)
-               gnu_type = TREE_TYPE (gnu_type);
-
-             if (TREE_CODE (gnu_type) != ARRAY_TYPE)
-               gigi_abort (309);
-
-             if (attribute == Attr_First)
-               gnu_result
-                 = TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)));
-             else if (attribute == Attr_Last)
-               gnu_result
-                 = TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)));
-             else
-               /* 'Length or 'Range_Length.  */
-               {
-                 tree gnu_compute_type
-                   = gnat_signed_or_unsigned_type
-                     (0, get_base_type (gnu_result_type));
-
-                 gnu_result
-                 = build_binary_op
-                   (MAX_EXPR, gnu_compute_type,
-                    build_binary_op
-                    (PLUS_EXPR, gnu_compute_type,
-                     build_binary_op
-                      (MINUS_EXPR, gnu_compute_type,
-                      convert (gnu_compute_type,
-                               TYPE_MAX_VALUE
-                               (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)))),
-                      convert (gnu_compute_type,
-                               TYPE_MIN_VALUE
-                               (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type))))),
-                     convert (gnu_compute_type, integer_one_node)),
-                    convert (gnu_compute_type, integer_zero_node));
-               }
-
-             /* If this has a PLACEHOLDER_EXPR, qualify it by the object
-                we are handling.  Note that these attributes could not
-                have been used on an unconstrained array type.  */
-             gnu_result = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_result,
-                                                          gnu_prefix);
-
-             break;
-           }
-
-          case Attr_Bit_Position:
-         case Attr_Position:
-         case Attr_First_Bit:
-         case Attr_Last_Bit:
-         case Attr_Bit:
-           {
-             HOST_WIDE_INT bitsize;
-             HOST_WIDE_INT bitpos;
-             tree gnu_offset;
-             tree gnu_field_bitpos;
-             tree gnu_field_offset;
-             tree gnu_inner;
-             enum machine_mode mode;
-             int unsignedp, volatilep;
-
-             gnu_result_type = get_unpadded_type (Etype (gnat_node));
-             gnu_prefix = remove_conversions (gnu_prefix, 1);
-             prefix_unused = 1;
-
-             /* We can have 'Bit on any object, but if it isn't a
-                COMPONENT_REF, the result is zero.  Do not allow
-                'Bit on a bare component, though.  */
-             if (attribute == Attr_Bit
-                 && TREE_CODE (gnu_prefix) != COMPONENT_REF
-                 && TREE_CODE (gnu_prefix) != FIELD_DECL)
-               {
-                 gnu_result = integer_zero_node;
-                 break;
-               }
-
-             else if (TREE_CODE (gnu_prefix) != COMPONENT_REF
-                      && ! (attribute == Attr_Bit_Position
-                            && TREE_CODE (gnu_prefix) == FIELD_DECL))
-               gigi_abort (310);
-
-             get_inner_reference (gnu_prefix, &bitsize, &bitpos, &gnu_offset,
-                                  &mode, &unsignedp, &volatilep);
-
-             if (TREE_CODE (gnu_prefix) == COMPONENT_REF)
-               {
-                 gnu_field_bitpos
-                   = bit_position (TREE_OPERAND (gnu_prefix, 1));
-                 gnu_field_offset
-                   = byte_position (TREE_OPERAND (gnu_prefix, 1));
-
-                 for (gnu_inner = TREE_OPERAND (gnu_prefix, 0);
-                      TREE_CODE (gnu_inner) == COMPONENT_REF
-                      && DECL_INTERNAL_P (TREE_OPERAND (gnu_inner, 1));
-                      gnu_inner = TREE_OPERAND (gnu_inner, 0))
-                   {
-                     gnu_field_bitpos
-                       = size_binop (PLUS_EXPR, gnu_field_bitpos,
-                                     bit_position (TREE_OPERAND (gnu_inner,
-                                                                 1)));
-                     gnu_field_offset
-                       = size_binop (PLUS_EXPR, gnu_field_offset,
-                                     byte_position (TREE_OPERAND (gnu_inner,
-                                                                  1)));
-                   }
-               }
-             else if (TREE_CODE (gnu_prefix) == FIELD_DECL)
-               {
-                 gnu_field_bitpos = bit_position (gnu_prefix);
-                 gnu_field_offset = byte_position (gnu_prefix);
-               }
-             else
-               {
-                 gnu_field_bitpos = bitsize_zero_node;
-                 gnu_field_offset = size_zero_node;
-               }
-
-             switch (attribute)
-               {
-               case Attr_Position:
-                 gnu_result = gnu_field_offset;
-                 break;
-
-               case Attr_First_Bit:
-               case Attr_Bit:
-                 gnu_result = size_int (bitpos % BITS_PER_UNIT);
-                 break;
-
-               case Attr_Last_Bit:
-                 gnu_result = bitsize_int (bitpos % BITS_PER_UNIT);
-                 gnu_result
-                   = size_binop (PLUS_EXPR, gnu_result,
-                                 TYPE_SIZE (TREE_TYPE (gnu_prefix)));
-                 gnu_result = size_binop (MINUS_EXPR, gnu_result,
-                                          bitsize_one_node);
-                 break;
-
-               case Attr_Bit_Position:
-                 gnu_result = gnu_field_bitpos;
-                 break;
-               }
-
-             /* If this has a PLACEHOLDER_EXPR, qualify it by the object
-                we are handling. */
-             gnu_result = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_result,
-                                                          gnu_prefix);
-
-             break;
-           }
-
-         case Attr_Min:
-         case Attr_Max:
-           gnu_lhs = gnat_to_gnu (First (Expressions (gnat_node)));
-           gnu_rhs = gnat_to_gnu (Next (First (Expressions (gnat_node))));
+      break;
 
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           gnu_result = build_binary_op (attribute == Attr_Min
-                                         ? MIN_EXPR : MAX_EXPR,
-                                         gnu_result_type, gnu_lhs, gnu_rhs);
-           break;
+    case N_Selected_Component:
+      {
+       tree gnu_prefix = gnat_to_gnu (Prefix (gnat_node));
+       Entity_Id gnat_field = Entity (Selector_Name (gnat_node));
+       Entity_Id gnat_pref_type = Etype (Prefix (gnat_node));
+       tree gnu_field;
 
-         case Attr_Passed_By_Reference:
-           gnu_result = size_int (default_pass_by_ref (gnu_type)
-                                  || must_pass_by_ref (gnu_type));
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           break;
+       while (IN (Ekind (gnat_pref_type), Incomplete_Or_Private_Kind)
+              || IN (Ekind (gnat_pref_type), Access_Kind))
+         {
+           if (IN (Ekind (gnat_pref_type), Incomplete_Or_Private_Kind))
+             gnat_pref_type = Underlying_Type (gnat_pref_type);
+           else if (IN (Ekind (gnat_pref_type), Access_Kind))
+             gnat_pref_type = Designated_Type (gnat_pref_type);
+         }
 
-         case Attr_Component_Size:
-           if (TREE_CODE (gnu_prefix) == COMPONENT_REF
-               && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))
-                   == RECORD_TYPE)
-               && (TYPE_IS_PADDING_P
-                   (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))))
-             gnu_prefix = TREE_OPERAND (gnu_prefix, 0);
+       gnu_prefix = maybe_implicit_deref (gnu_prefix);
 
-           gnu_prefix = maybe_implicit_deref (gnu_prefix);
-           gnu_type = TREE_TYPE (gnu_prefix);
+       /* For discriminant references in tagged types always substitute the
+          corresponding discriminant as the actual selected component. */
 
-           if (TREE_CODE (gnu_type) == UNCONSTRAINED_ARRAY_TYPE)
-             gnu_type
-               = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_type))));
+       if (Is_Tagged_Type (gnat_pref_type))
+         while (Present (Corresponding_Discriminant (gnat_field)))
+           gnat_field = Corresponding_Discriminant (gnat_field);
 
-           while (TREE_CODE (TREE_TYPE (gnu_type)) == ARRAY_TYPE
-                  && TYPE_MULTI_ARRAY_P (TREE_TYPE (gnu_type)))
-             gnu_type = TREE_TYPE (gnu_type);
+       /* For discriminant references of untagged types always substitute the
+          corresponding stored discriminant. */
 
-           if (TREE_CODE (gnu_type) != ARRAY_TYPE)
-             gigi_abort (330);
+       else if (Present (Corresponding_Discriminant (gnat_field)))
+         gnat_field = Original_Record_Component (gnat_field);
 
-           /* Note this size cannot be self-referential.  */
-           gnu_result = TYPE_SIZE (TREE_TYPE (gnu_type));
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           prefix_unused = 1;
-           break;
+       /* Handle extracting the real or imaginary part of a complex.
+          The real part is the first field and the imaginary the last.  */
 
-         case Attr_Null_Parameter:
-           /* This is just a zero cast to the pointer type for
-              our prefix and dereferenced.  */
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           gnu_result
-             = build_unary_op (INDIRECT_REF, NULL_TREE,
-                               convert (build_pointer_type (gnu_result_type),
-                                        integer_zero_node));
-           TREE_PRIVATE (gnu_result) = 1;
-           break;
+       if (TREE_CODE (TREE_TYPE (gnu_prefix)) == COMPLEX_TYPE)
+         gnu_result = build_unary_op (Present (Next_Entity (gnat_field))
+                                      ? REALPART_EXPR : IMAGPART_EXPR,
+                                      NULL_TREE, gnu_prefix);
+       else
+         {
+           gnu_field = gnat_to_gnu_entity (gnat_field, NULL_TREE, 0);
 
-         case Attr_Mechanism_Code:
-           {
-             int code;
-             Entity_Id gnat_obj = Entity (Prefix (gnat_node));
+           /* If there are discriminants, the prefix might be
+               evaluated more than once, which is a problem if it has
+               side-effects. */
+           if (Has_Discriminants (Is_Access_Type (Etype (Prefix (gnat_node)))
+                                  ? Designated_Type (Etype
+                                                     (Prefix (gnat_node)))
+                                  : Etype (Prefix (gnat_node))))
+             gnu_prefix = gnat_stabilize_reference (gnu_prefix, 0);
 
-             prefix_unused = 1;
-             gnu_result_type = get_unpadded_type (Etype (gnat_node));
-             if (Present (Expressions (gnat_node)))
-               {
-                 int i = UI_To_Int (Intval (First (Expressions (gnat_node))));
+           gnu_result
+             = build_component_ref (gnu_prefix, NULL_TREE, gnu_field,
+                                    (Nkind (Parent (gnat_node))
+                                     == N_Attribute_Reference));
+         }
 
-                 for (gnat_obj = First_Formal (gnat_obj); i > 1;
-                      i--, gnat_obj = Next_Formal (gnat_obj))
-                   ;
-               }
+       if (gnu_result == 0)
+         gigi_abort (308);
 
-             code = Mechanism (gnat_obj);
-             if (code == Default)
-               code = ((present_gnu_tree (gnat_obj)
-                        && (DECL_BY_REF_P (get_gnu_tree (gnat_obj))
-                            || ((TREE_CODE (get_gnu_tree (gnat_obj))
-                                 == PARM_DECL)
-                                && (DECL_BY_COMPONENT_PTR_P
-                                    (get_gnu_tree (gnat_obj))))))
-                       ? By_Reference : By_Copy);
-             gnu_result = convert (gnu_result_type, size_int (- code));
-           }
-         break;
+       gnu_result_type = get_unpadded_type (Etype (gnat_node));
+      }
+      break;
 
-          default:
-           /* Say we have an unimplemented attribute.  Then set the
-              value to be returned to be a zero and hope that's something
-              we can convert to the type of this attribute.  */
+    case N_Attribute_Reference:
+      {
+        /* The attribute designator (like an enumeration value). */
+        int attribute = Get_Attribute_Id (Attribute_Name (gnat_node));
 
-           post_error ("unimplemented attribute", gnat_node);
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           gnu_result = integer_zero_node;
-           break;
-          }
+       /* The Elab_Spec and Elab_Body attributes are special in that
+          Prefix is a unit, not an object with a GCC equivalent.  Similarly
+          for Elaborated, since that variable isn't otherwise known.  */
+       if (attribute == Attr_Elab_Body || attribute == Attr_Elab_Spec)
+         return (create_subprog_decl
+                 (create_concat_name (Entity (Prefix (gnat_node)),
+                                      attribute == Attr_Elab_Body
+                                      ? "elabb" : "elabs"),
+                  NULL_TREE, void_ftype, NULL_TREE, 0, 1, 1, 0, gnat_node));
 
-       /* If this is an attribute where the prefix was unused,
-          force a use of it if it has a side-effect.  But don't do it if
-          the prefix is just an entity name.  However, if an access check
-          is needed, we must do it.  See second example in AARM 11.6(5.e). */
-       if (prefix_unused && TREE_SIDE_EFFECTS (gnu_prefix)
-           && ! Is_Entity_Name (Prefix (gnat_node)))
-         gnu_result = fold (build (COMPOUND_EXPR, TREE_TYPE (gnu_result),
-                                   gnu_prefix, gnu_result));
+       gnu_result = Attribute_to_gnu (gnat_node, &gnu_result_type, attribute);
       }
       break;
 
@@ -2114,253 +3342,11 @@ gnat_to_gnu (Node_Id gnat_node)
       break;
 
     case N_Case_Statement:
-      {
-       Node_Id gnat_when;
-
-       gnu_expr = gnat_to_gnu (Expression (gnat_node));
-       gnu_expr = convert (get_base_type (TREE_TYPE (gnu_expr)), gnu_expr);
-
-       /*  The range of values in a case statement is determined by the
-           rules in RM 5.4(7-9). In almost all cases, this range is
-           represented by the Etype of the expression. One exception arises
-           in the case of a simple name that is parenthesized. This still
-           has the Etype of the name, but since it is not a name, para 7
-           does not apply, and we need to go to the base type. This is the
-           only case where parenthesization affects the dynamic semantics
-           (i.e. the range of possible values at runtime that is covered by
-           the others alternative.
-
-           Another exception is if the subtype of the expression is
-           non-static.  In that case, we also have to use the base type.  */
-       if (Paren_Count (Expression (gnat_node)) != 0
-           || !Is_OK_Static_Subtype (Underlying_Type
-                                     (Etype (Expression (gnat_node)))))
-         gnu_expr = convert (get_base_type (TREE_TYPE (gnu_expr)), gnu_expr);
-
-       /* We build a SWITCH_EXPR that contains the code with interspersed
-          CASE_LABEL_EXPRs for each label.  */
-
-       push_stack (&gnu_switch_label_stack, NULL_TREE,
-                   create_artificial_label ());
-       start_stmt_group ();
-       for (gnat_when = First_Non_Pragma (Alternatives (gnat_node));
-            Present (gnat_when);
-            gnat_when = Next_Non_Pragma (gnat_when))
-         {
-           Node_Id gnat_choice;
-
-           /* First compile all the different case choices for the current
-              WHEN alternative.  */
-           for (gnat_choice = First (Discrete_Choices (gnat_when));
-                Present (gnat_choice); gnat_choice = Next (gnat_choice))
-             {
-               tree gnu_low = NULL_TREE, gnu_high = NULL_TREE;
-
-               switch (Nkind (gnat_choice))
-                 {
-                 case N_Range:
-                   gnu_low = gnat_to_gnu (Low_Bound (gnat_choice));
-                   gnu_high = gnat_to_gnu (High_Bound (gnat_choice));
-                   break;
-
-                 case N_Subtype_Indication:
-                   gnu_low = gnat_to_gnu (Low_Bound
-                                          (Range_Expression
-                                           (Constraint (gnat_choice))));
-                   gnu_high = gnat_to_gnu (High_Bound
-                                           (Range_Expression
-                                            (Constraint (gnat_choice))));
-                   break;
-
-                 case N_Identifier:
-                 case N_Expanded_Name:
-                   /* This represents either a subtype range or a static value
-                      of some kind; Ekind says which.  If a static value,
-                      fall through to the next case.  */
-                   if (IN (Ekind (Entity (gnat_choice)), Type_Kind))
-                     {
-                       tree gnu_type
-                         = get_unpadded_type (Entity (gnat_choice));
-
-                       gnu_low = fold (TYPE_MIN_VALUE (gnu_type));
-                       gnu_high = fold (TYPE_MAX_VALUE (gnu_type));
-                       break;
-                     }
-
-                   /* ... fall through ... */
-                 case N_Character_Literal:
-                 case N_Integer_Literal:
-                   gnu_low = gnat_to_gnu (gnat_choice);
-                   break;
-
-                 case N_Others_Choice:
-                   break;
-
-                 default:
-                   gigi_abort (316);
-                 }
-
-               add_stmt_with_node (build (CASE_LABEL_EXPR, void_type_node,
-                                          gnu_low, gnu_high,
-                                          create_artificial_label ()),
-                                   gnat_choice);
-             }
-
-           /* Push a binding level here in case variables are declared since
-              we want them to be local to this set of statements instead of
-              the block containing the Case statement.  */
-           add_stmt (build_stmt_group (Statements (gnat_when), true));
-           add_stmt (build1 (GOTO_EXPR, void_type_node,
-                             TREE_VALUE (gnu_switch_label_stack)));
-
-         }
-
-       /* Now emit a definition of the label all the cases branched to. */
-       add_stmt (build1 (LABEL_EXPR, void_type_node,
-                         TREE_VALUE (gnu_switch_label_stack)));
-       gnu_result = build (SWITCH_EXPR, TREE_TYPE (gnu_expr), gnu_expr,
-                           end_stmt_group (), NULL_TREE);
-       pop_stack (&gnu_switch_label_stack);
-       break;
-      }
+      gnu_result = Case_Statement_to_gnu (gnat_node);
+      break;
 
     case N_Loop_Statement:
-      {
-       /* ??? It would be nice to use "build" here, but there's no build5.  */
-       tree gnu_loop_stmt = build_nt (LOOP_STMT, NULL_TREE, NULL_TREE,
-                                      NULL_TREE, NULL_TREE, NULL_TREE);
-       tree gnu_loop_var = NULL_TREE;
-       Node_Id gnat_iter_scheme = Iteration_Scheme (gnat_node);
-       tree gnu_cond_expr = NULL_TREE;
-
-       TREE_TYPE (gnu_loop_stmt) = void_type_node;
-       TREE_SIDE_EFFECTS (gnu_loop_stmt) = 1;
-       LOOP_STMT_LABEL (gnu_loop_stmt) = create_artificial_label ();
-       annotate_with_node (gnu_loop_stmt, gnat_node);
-
-       /* Save the end label of this LOOP_STMT in a stack so that the
-          corresponding N_Exit_Statement can find it.  */
-       push_stack (&gnu_loop_label_stack, NULL_TREE,
-                   LOOP_STMT_LABEL (gnu_loop_stmt));
-
-       /* Set the condition that under which the loop should continue.
-          For "LOOP .... END LOOP;" the condition is always true.  */
-       if (No (gnat_iter_scheme))
-         ;
-       /* The case "WHILE condition LOOP ..... END LOOP;" */
-       else if (Present (Condition (gnat_iter_scheme)))
-         LOOP_STMT_TOP_COND (gnu_loop_stmt)
-           = gnat_to_gnu (Condition (gnat_iter_scheme));
-        else
-         {
-           /* We have an iteration scheme.  */
-           Node_Id gnat_loop_spec
-             = Loop_Parameter_Specification (gnat_iter_scheme);
-           Entity_Id gnat_loop_var = Defining_Entity (gnat_loop_spec);
-           Entity_Id gnat_type = Etype (gnat_loop_var);
-           tree gnu_type = get_unpadded_type (gnat_type);
-           tree gnu_low = TYPE_MIN_VALUE (gnu_type);
-           tree gnu_high = TYPE_MAX_VALUE (gnu_type);
-           int reversep = Reverse_Present (gnat_loop_spec);
-           tree gnu_first = reversep ? gnu_high : gnu_low;
-           tree gnu_last = reversep ? gnu_low : gnu_high;
-           enum tree_code end_code = reversep ? GE_EXPR : LE_EXPR;
-           tree gnu_base_type = get_base_type (gnu_type);
-           tree gnu_limit
-             = (reversep ? TYPE_MIN_VALUE (gnu_base_type)
-                : TYPE_MAX_VALUE (gnu_base_type));
-
-           /* We know the loop variable will not overflow if GNU_LAST is
-              a constant and is not equal to GNU_LIMIT.  If it might
-              overflow, we have to move the limit test to the end of
-              the loop.  In that case, we have to test for an
-              empty loop outside the loop.  */
-           if (TREE_CODE (gnu_last) != INTEGER_CST
-               || TREE_CODE (gnu_limit) != INTEGER_CST
-               || tree_int_cst_equal (gnu_last, gnu_limit))
-             {
-               gnu_cond_expr
-                 = build (COND_EXPR, void_type_node,
-                          build_binary_op (LE_EXPR, integer_type_node,
-                                           gnu_low, gnu_high),
-                          NULL_TREE, alloc_stmt_list ());
-               annotate_with_node (gnu_cond_expr, gnat_loop_spec);
-             }
-
-           /* Open a new nesting level that will surround the loop to declare
-              the loop index variable.  */
-           start_stmt_group ();
-           gnat_pushlevel ();
-
-           /* Declare the loop index and set it to its initial value.  */
-           gnu_loop_var = gnat_to_gnu_entity (gnat_loop_var, gnu_first, 1);
-           if (DECL_BY_REF_P (gnu_loop_var))
-             gnu_loop_var = build_unary_op (INDIRECT_REF, NULL_TREE,
-                                            gnu_loop_var);
-
-           /* The loop variable might be a padded type, so use `convert' to
-              get a reference to the inner variable if so.  */
-           gnu_loop_var = convert (get_base_type (gnu_type), gnu_loop_var);
-
-           /* Set either the top or bottom exit condition as
-              appropriate depending on whether we know an overflow
-              cannot occur or not. */
-           if (gnu_cond_expr)
-             LOOP_STMT_BOT_COND (gnu_loop_stmt)
-               = build_binary_op (NE_EXPR, integer_type_node,
-                                  gnu_loop_var, gnu_last);
-           else
-             LOOP_STMT_TOP_COND (gnu_loop_stmt)
-               = build_binary_op (end_code, integer_type_node,
-                                  gnu_loop_var, gnu_last);
-
-           LOOP_STMT_UPDATE (gnu_loop_stmt)
-             = build_binary_op (reversep ? PREDECREMENT_EXPR
-                                : PREINCREMENT_EXPR,
-                                TREE_TYPE (gnu_loop_var),
-                                gnu_loop_var,
-                                convert (TREE_TYPE (gnu_loop_var),
-                                         integer_one_node));
-           annotate_with_node (LOOP_STMT_UPDATE (gnu_loop_stmt),
-                               gnat_iter_scheme);
-         }
-
-       /* If the loop was named, have the name point to this loop.  In this case,
-          the association is not a ..._DECL node, but the end label from this
-          LOOP_STMT. */
-        if (Present (Identifier (gnat_node)))
-         save_gnu_tree (Entity (Identifier (gnat_node)),
-                        LOOP_STMT_LABEL (gnu_loop_stmt), 1);
-
-        /* Make the loop body into its own block, so any allocated storage
-           will be released every iteration.  This is needed for stack
-           allocation.  */
-       LOOP_STMT_BODY (gnu_loop_stmt)
-         = build_stmt_group (Statements (gnat_node), true);
-
-       /* If we declared a variable, then we are in a statement group for
-          that declaration.  Add the LOOP_STMT to it and make that the
-          "loop".  */
-       if (gnu_loop_var)
-         {
-           add_stmt (gnu_loop_stmt);
-           gnat_poplevel ();
-           gnu_loop_stmt = end_stmt_group ();
-         }
-
-       /* If we have an outer COND_EXPR, that's our result and this loop
-          is its "true" statement.  Otherwise, the result is the LOOP_STMT. */
-       if (gnu_cond_expr)
-         {
-           COND_EXPR_THEN (gnu_cond_expr) = gnu_loop_stmt;
-           gnu_result = gnu_cond_expr;
-           recalculate_side_effects (gnu_cond_expr);
-         }
-       else
-         gnu_result = gnu_loop_stmt;
-
-       pop_stack (&gnu_loop_label_stack);
-      }
+      gnu_result = Loop_Statement_to_gnu (gnat_node);
       break;
 
     case N_Block_Statement:
@@ -2522,643 +3508,13 @@ gnat_to_gnu (Node_Id gnat_node)
       break;
 
     case N_Subprogram_Body:
-      {
-        /* Save debug output mode in case it is reset.  */
-        enum debug_info_type save_write_symbols = write_symbols;
-       const struct gcc_debug_hooks *const save_debug_hooks = debug_hooks;
-       /* Definining identifier of a parameter to the subprogram.  */
-        Entity_Id gnat_param;
-       /* The defining identifier for the subprogram body. Note that if a
-          specification has appeared before for this body, then the identifier
-          occurring in that specification will also be a defining identifier
-          and all the calls to this subprogram will point to that
-          specification.  */
-       Entity_Id gnat_subprog_id
-         = (Present (Corresponding_Spec (gnat_node))
-            ? Corresponding_Spec (gnat_node) : Defining_Entity (gnat_node));
-
-       /* The FUNCTION_DECL node corresponding to the subprogram spec.   */
-       tree gnu_subprog_decl;
-       /* The FUNCTION_TYPE node corresponding to the subprogram spec.  */
-       tree gnu_subprog_type;
-       tree gnu_cico_list;
-
-       /* If this is a generic object or if it has been eliminated,
-          ignore it.  */
-       if (Ekind (gnat_subprog_id) == E_Generic_Procedure
-           || Ekind (gnat_subprog_id) == E_Generic_Function
-           || Is_Eliminated (gnat_subprog_id))
-         return alloc_stmt_list ();
-
-        /* If debug information is suppressed for the subprogram, turn debug
-           mode off for the duration of processing.  */
-        if (!Needs_Debug_Info (gnat_subprog_id))
-         {
-           write_symbols = NO_DEBUG;
-           debug_hooks = &do_nothing_debug_hooks;
-         }
-
-       /* If this subprogram acts as its own spec, define it.  Otherwise,
-          just get the already-elaborated tree node.  However, if this
-          subprogram had its elaboration deferred, we will already have made
-          a tree node for it.  So treat it as not being defined in that
-          case.  Such a subprogram cannot have an address clause or a freeze
-          node, so this test is safe, though it does disable some
-          otherwise-useful error checking.  */
-       gnu_subprog_decl
-         = gnat_to_gnu_entity (gnat_subprog_id, NULL_TREE,
-                               Acts_As_Spec (gnat_node)
-                               && ! present_gnu_tree (gnat_subprog_id));
-
-       gnu_subprog_type = TREE_TYPE (gnu_subprog_decl);
-
-       /* Set the line number in the decl to correspond to that of
-          the body so that the line number notes are written
-          correctly.  */
-       Sloc_to_locus (Sloc (gnat_node),
-                      &DECL_SOURCE_LOCATION (gnu_subprog_decl));
-
-       begin_subprog_body (gnu_subprog_decl);
-
-       gnu_cico_list = TYPE_CI_CO_LIST (gnu_subprog_type);
-
-       /* If there are OUT parameters, we need to ensure that the return
-          statement properly copies them out.  We do this by making a new
-          block and converting any inner return into a goto to a label at
-          the end of the block.  */
-       push_stack (&gnu_return_label_stack, NULL_TREE,
-                   gnu_cico_list ? create_artificial_label () : NULL_TREE);
-
-       /* Get a tree corresponding to the code for the subprogram.  */
-       start_stmt_group ();
-       gnat_pushlevel ();
-
-       /* See if there are any parameters for which we don't yet have
-          GCC entities.  These must be for OUT parameters for which we
-          will be making VAR_DECL nodes here.  Fill them in to
-          TYPE_CI_CO_LIST, which must contain the empty entry as well.
-          We can match up the entries because TYPE_CI_CO_LIST is in the
-          order of the parameters.  */
-       for (gnat_param = First_Formal (gnat_subprog_id);
-            Present (gnat_param);
-            gnat_param = Next_Formal_With_Extras (gnat_param))
-         if (!present_gnu_tree (gnat_param))
-           {
-             /* Skip any entries that have been already filled in; they
-                must correspond to IN OUT parameters.  */
-             for (; gnu_cico_list != 0 && TREE_VALUE (gnu_cico_list) != 0;
-                  gnu_cico_list = TREE_CHAIN (gnu_cico_list))
-               ;
-
-             /* Do any needed references for padded types.  */
-             TREE_VALUE (gnu_cico_list)
-               = convert (TREE_TYPE (TREE_PURPOSE (gnu_cico_list)),
-                          gnat_to_gnu_entity (gnat_param, NULL_TREE, 1));
-           }
-
-       process_decls (Declarations (gnat_node), Empty, Empty, 1, 1);
-
-       /* Generate the code of the subprogram itself.  A return statement
-          will be present and any OUT parameters will be handled there.  */
-       add_stmt (gnat_to_gnu (Handled_Statement_Sequence (gnat_node)));
-       gnat_poplevel ();
-       gnu_result = end_stmt_group ();
-
-       /* If we made a special return label, we need to make a block that
-          contains the definition of that label and the copying to the
-          return value.  That block first contains the function, then
-          the label and copy statement.  */
-       if (TREE_VALUE (gnu_return_label_stack) != 0)
-         {
-           tree gnu_retval;
-
-           start_stmt_group ();
-           gnat_pushlevel ();
-           add_stmt (gnu_result);
-           add_stmt (build1 (LABEL_EXPR, void_type_node,
-                             TREE_VALUE (gnu_return_label_stack)));
-
-           gnu_cico_list = TYPE_CI_CO_LIST (gnu_subprog_type);
-           if (list_length (gnu_cico_list) == 1)
-             gnu_retval = TREE_VALUE (gnu_cico_list);
-           else
-             gnu_retval
-               = gnat_build_constructor (TREE_TYPE (gnu_subprog_type),
-                                         gnu_cico_list);
-
-           if (DECL_P (gnu_retval) && DECL_BY_REF_P (gnu_retval))
-             gnu_retval
-               = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_retval);
-
-           add_stmt_with_node
-             (build1 (RETURN_EXPR, void_type_node,
-                      build (MODIFY_EXPR, TREE_TYPE (gnu_retval),
-                             DECL_RESULT (current_function_decl),
-                             gnu_retval)),
-              gnat_node);
-           gnat_poplevel ();
-           gnu_result = end_stmt_group ();
-         }
-
-       pop_stack (&gnu_return_label_stack);
-
-       /* Initialize the information node for the function and set the
-          end location.  */
-       allocate_struct_function (current_function_decl);
-       Sloc_to_locus
-         ((Present (End_Label (Handled_Statement_Sequence (gnat_node)))
-           ? Sloc (End_Label (Handled_Statement_Sequence (gnat_node)))
-           : Sloc (gnat_node)),
-          &cfun->function_end_locus);
-
-       end_subprog_body (gnu_result);
-
-       /* Disconnect the trees for parameters that we made variables for
-          from the GNAT entities since these will become unusable after
-          we end the function.  */
-       for (gnat_param = First_Formal (gnat_subprog_id);
-            Present (gnat_param);
-            gnat_param = Next_Formal_With_Extras (gnat_param))
-         if (TREE_CODE (get_gnu_tree (gnat_param)) == VAR_DECL)
-           save_gnu_tree (gnat_param, NULL_TREE, 0);
-
-       mark_out_of_scope (Defining_Unit_Name (Specification (gnat_node)));
-       write_symbols = save_write_symbols;
-       debug_hooks = save_debug_hooks;
-       gnu_result = alloc_stmt_list ();
-      }
+      Subprogram_Body_to_gnu (gnat_node);
+      gnu_result = alloc_stmt_list ();
       break;
 
     case N_Function_Call:
     case N_Procedure_Call_Statement:
-      {
-       /* The GCC node corresponding to the GNAT subprogram name.  This can
-          either be a FUNCTION_DECL node if we are dealing with a standard
-          subprogram call, or an indirect reference expression (an
-          INDIRECT_REF node) pointing to a subprogram.  */
-       tree gnu_subprog_node = gnat_to_gnu (Name (gnat_node));
-       /* The FUNCTION_TYPE node giving the GCC type of the subprogram.  */
-       tree gnu_subprog_type = TREE_TYPE (gnu_subprog_node);
-       tree gnu_subprog_addr
-         = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_subprog_node);
-       Entity_Id gnat_formal;
-       Node_Id gnat_actual;
-       tree gnu_actual_list = NULL_TREE;
-       tree gnu_name_list = NULL_TREE;
-       tree gnu_before_list = NULL_TREE;
-       tree gnu_after_list = NULL_TREE;
-       tree gnu_subprog_call;
-
-       switch (Nkind (Name (gnat_node)))
-         {
-         case N_Identifier:
-         case N_Operator_Symbol:
-         case N_Expanded_Name:
-         case N_Attribute_Reference:
-           if (Is_Eliminated (Entity (Name (gnat_node))))
-             Eliminate_Error_Msg (gnat_node, Entity (Name (gnat_node)));
-          }
-
-       if (TREE_CODE (gnu_subprog_type) != FUNCTION_TYPE)
-         gigi_abort (317);
-
-       /* If we are calling a stubbed function, make this into a
-          raise of Program_Error.  Elaborate all our args first.  */
-
-       if (TREE_CODE (gnu_subprog_node) == FUNCTION_DECL
-           && DECL_STUBBED_P (gnu_subprog_node))
-         {
-           for (gnat_actual = First_Actual (gnat_node);
-                Present (gnat_actual);
-                gnat_actual = Next_Actual (gnat_actual))
-             add_stmt (gnat_to_gnu (gnat_actual));
-
-           if (Nkind (gnat_node) == N_Function_Call)
-             {
-               gnu_result_type = TREE_TYPE (gnu_subprog_type);
-               gnu_result
-                 = build1 (NULL_EXPR, gnu_result_type,
-                           build_call_raise (PE_Stubbed_Subprogram_Called));
-             }
-           else
-             gnu_result = build_call_raise (PE_Stubbed_Subprogram_Called);
-           break;
-         }
-
-       /* The only way we can be making a call via an access type is
-          if Name is an explicit dereference.  In that case, get the
-          list of formal args from the type the access type is pointing
-          to.  Otherwise, get the formals from entity being called.  */
-       if (Nkind (Name (gnat_node)) == N_Explicit_Dereference)
-         gnat_formal = First_Formal (Etype (Name (gnat_node)));
-       else if (Nkind (Name (gnat_node)) == N_Attribute_Reference)
-         /* Assume here that this must be 'Elab_Body or 'Elab_Spec.  */
-         gnat_formal = 0;
-       else
-         gnat_formal = First_Formal (Entity (Name (gnat_node)));
-
-       /* Create the list of the actual parameters as GCC expects it, namely
-          a chain of TREE_LIST nodes in which the TREE_VALUE field of each
-          node is a parameter-expression and the TREE_PURPOSE field is
-          null.  Skip OUT parameters that are not passed by reference and
-          don't need to be copied in.  */
-
-        for (gnat_actual = First_Actual (gnat_node);
-             Present (gnat_actual);
-             gnat_formal = Next_Formal_With_Extras (gnat_formal),
-             gnat_actual = Next_Actual (gnat_actual))
-         {
-           tree gnu_formal_type = gnat_to_gnu_type (Etype (gnat_formal));
-           /* We treat a conversion between aggregate types as if it
-              is an unchecked conversion.  */
-           int unchecked_convert_p
-             = (Nkind (gnat_actual) == N_Unchecked_Type_Conversion
-                || (Nkind (gnat_actual) == N_Type_Conversion
-                    && Is_Composite_Type (Underlying_Type
-                                          (Etype (gnat_formal)))));
-           Node_Id gnat_name
-             = unchecked_convert_p ? Expression (gnat_actual) : gnat_actual;
-           tree gnu_name = gnat_to_gnu (gnat_name);
-           tree gnu_name_type = gnat_to_gnu_type (Etype (gnat_name));
-           tree gnu_actual;
-
-           /* If it's possible we may need to use this expression twice,
-              make sure than any side-effects are handled via SAVE_EXPRs.
-              Likewise if we need to force side-effects before the call.
-              ??? This is more conservative than we need since we don't
-              need to do this for pass-by-ref with no conversion.
-              If we are passing a non-addressable Out or In Out parameter by
-              reference, pass the address of a copy and set up to copy back
-              out after the call.  */
-
-           if (Ekind (gnat_formal) != E_In_Parameter)
-             {
-               gnu_name = gnat_stabilize_reference (gnu_name, 1);
-               if (! addressable_p (gnu_name)
-                   && present_gnu_tree (gnat_formal)
-                   && (DECL_BY_REF_P (get_gnu_tree (gnat_formal))
-                       || (TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
-                           && (DECL_BY_COMPONENT_PTR_P
-                               (get_gnu_tree (gnat_formal))
-                               || DECL_BY_DESCRIPTOR_P
-                               (get_gnu_tree (gnat_formal))))))
-                 {
-                   tree gnu_copy = gnu_name;
-                   tree gnu_temp;
-
-                   /* Remove any unpadding on the actual and make a copy.
-                      But if the actual is a left-justified modular type,
-                      first convert to it.  */
-                   if (TREE_CODE (gnu_name) == COMPONENT_REF
-                       && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_name, 0)))
-                            == RECORD_TYPE)
-                           && (TYPE_IS_PADDING_P
-                               (TREE_TYPE (TREE_OPERAND (gnu_name, 0))))))
-                     gnu_name = gnu_copy = TREE_OPERAND (gnu_name, 0);
-                   else if (TREE_CODE (gnu_name_type) == RECORD_TYPE
-                            && (TYPE_LEFT_JUSTIFIED_MODULAR_P
-                                (gnu_name_type)))
-                     gnu_name = convert (gnu_name_type, gnu_name);
-
-                   gnu_actual = save_expr (gnu_name);
-
-                   /* Since we're going to take the address of the SAVE_EXPR,
-                      we don't want it to be marked as unchanging.
-                      So set TREE_ADDRESSABLE.  */
-                   gnu_temp = skip_simple_arithmetic (gnu_actual);
-                   if (TREE_CODE (gnu_temp) == SAVE_EXPR)
-                     {
-                       TREE_ADDRESSABLE (gnu_temp) = 1;
-                       TREE_READONLY (gnu_temp) = 0;
-                     }
-
-                   /* Set up to move the copy back to the original.  */
-                   gnu_temp = build (MODIFY_EXPR, TREE_TYPE (gnu_copy),
-                                     gnu_copy, gnu_actual);
-                   annotate_with_node (gnu_temp, gnat_actual);
-                   append_to_statement_list (gnu_temp, &gnu_after_list);
-                 }
-             }
-
-           /* If this was a procedure call, we may not have removed any
-              padding.  So do it here for the part we will use as an
-              input, if any.  */
-           gnu_actual = gnu_name;
-           if (Ekind (gnat_formal) != E_Out_Parameter
-               && TREE_CODE (TREE_TYPE (gnu_actual)) == RECORD_TYPE
-               && TYPE_IS_PADDING_P (TREE_TYPE (gnu_actual)))
-             gnu_actual = convert (get_unpadded_type (Etype (gnat_actual)),
-                                   gnu_actual);
-
-           /* Unless this is an In parameter, we must remove any LJM building
-              from GNU_NAME.  */
-           if (Ekind (gnat_formal) != E_In_Parameter
-               && TREE_CODE (gnu_name) == CONSTRUCTOR
-               && TREE_CODE (TREE_TYPE (gnu_name)) == RECORD_TYPE
-               && TYPE_LEFT_JUSTIFIED_MODULAR_P (TREE_TYPE (gnu_name)))
-             gnu_name
-               = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_name))),
-                          gnu_name);
-
-           if (Ekind (gnat_formal) != E_Out_Parameter
-               && ! unchecked_convert_p
-               && Do_Range_Check (gnat_actual))
-             gnu_actual = emit_range_check (gnu_actual, Etype (gnat_formal));
-
-           /* Do any needed conversions.  We need only check for
-              unchecked conversion since normal conversions will be handled
-              by just converting to the formal type.  */
-           if (unchecked_convert_p)
-             {
-               gnu_actual
-                 = unchecked_convert (gnat_to_gnu_type (Etype (gnat_actual)),
-                                      gnu_actual,
-                                      (Nkind (gnat_actual)
-                                       == N_Unchecked_Type_Conversion)
-                                      && No_Truncation (gnat_actual));
-
-               /* One we've done the unchecked conversion, we still
-                  must ensure that the object is in range of the formal's
-                  type.  */
-               if (Ekind (gnat_formal) != E_Out_Parameter
-                   && Do_Range_Check (gnat_actual))
-                 gnu_actual = emit_range_check (gnu_actual,
-                                                Etype (gnat_formal));
-             }
-           else if (TREE_CODE (gnu_actual) != SAVE_EXPR)
-             /* We may have suppressed a conversion to the Etype of the
-                actual since the parent is a procedure call.  So add the
-                conversion here.  */
-             gnu_actual = convert (gnat_to_gnu_type (Etype (gnat_actual)),
-                                   gnu_actual);
-
-           if (TREE_CODE (gnu_actual) != SAVE_EXPR)
-             gnu_actual = convert (gnu_formal_type, gnu_actual);
-
-           /* If we have not saved a GCC object for the formal, it means it
-              is an OUT parameter not passed by reference and that does not
-              need to be copied in. Otherwise, look at the PARM_DECL to see
-              if it is passed by reference. */
-           if (present_gnu_tree (gnat_formal)
-               && TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
-               && DECL_BY_REF_P (get_gnu_tree (gnat_formal)))
-             {
-               if (Ekind (gnat_formal) != E_In_Parameter)
-                 {
-                   gnu_actual = gnu_name;
-
-                   /* If we have a padded type, be sure we've removed the
-                      padding.  */
-                   if (TREE_CODE (TREE_TYPE (gnu_actual)) == RECORD_TYPE
-                       && TYPE_IS_PADDING_P (TREE_TYPE (gnu_actual))
-                       && TREE_CODE (gnu_actual) != SAVE_EXPR)
-                     gnu_actual
-                       = convert (get_unpadded_type (Etype (gnat_actual)),
-                                  gnu_actual);
-                 }
-
-               /* Otherwise, if we have a non-addressable COMPONENT_REF of a
-                  variable-size type see if it's doing a unpadding operation.
-                  If so, remove that operation since we have no way of
-                  allocating the required temporary.  */
-               if (TREE_CODE (gnu_actual) == COMPONENT_REF
-                   && ! TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (gnu_actual)))
-                   && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_actual, 0)))
-                       == RECORD_TYPE)
-                   && TYPE_IS_PADDING_P (TREE_TYPE
-                                         (TREE_OPERAND (gnu_actual, 0)))
-                   && !addressable_p (gnu_actual))
-                 gnu_actual = TREE_OPERAND (gnu_actual, 0);
-
-               /* The symmetry of the paths to the type of an entity is
-                  broken here since arguments don't know that they will
-                  be passed by ref. */
-               gnu_formal_type = TREE_TYPE (get_gnu_tree (gnat_formal));
-               gnu_actual = build_unary_op (ADDR_EXPR, gnu_formal_type,
-                                            gnu_actual);
-             }
-           else if (present_gnu_tree (gnat_formal)
-                    && TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
-                    && DECL_BY_COMPONENT_PTR_P (get_gnu_tree (gnat_formal)))
-             {
-               gnu_formal_type = TREE_TYPE (get_gnu_tree (gnat_formal));
-               gnu_actual = maybe_implicit_deref (gnu_actual);
-               gnu_actual = maybe_unconstrained_array (gnu_actual);
-
-               if (TREE_CODE (gnu_formal_type) == RECORD_TYPE
-                   && TYPE_IS_PADDING_P (gnu_formal_type))
-                 {
-                   gnu_formal_type
-                     = TREE_TYPE (TYPE_FIELDS (gnu_formal_type));
-                   gnu_actual = convert (gnu_formal_type, gnu_actual);
-                 }
-
-               /* Take the address of the object and convert to the
-                  proper pointer type.  We'd like to actually compute
-                  the address of the beginning of the array using
-                  an ADDR_EXPR of an ARRAY_REF, but there's a possibility
-                  that the ARRAY_REF might return a constant and we'd
-                  be getting the wrong address.  Neither approach is
-                  exactly correct, but this is the most likely to work
-                  in all cases.  */
-               gnu_actual = convert (gnu_formal_type,
-                                     build_unary_op (ADDR_EXPR, NULL_TREE,
-                                                     gnu_actual));
-             }
-           else if (present_gnu_tree (gnat_formal)
-                    && TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
-                    && DECL_BY_DESCRIPTOR_P (get_gnu_tree (gnat_formal)))
-             {
-               /* If arg is 'Null_Parameter, pass zero descriptor.  */
-               if ((TREE_CODE (gnu_actual) == INDIRECT_REF
-                    || TREE_CODE (gnu_actual) == UNCONSTRAINED_ARRAY_REF)
-                   && TREE_PRIVATE (gnu_actual))
-                 gnu_actual
-                   = convert (DECL_ARG_TYPE (get_gnu_tree (gnat_formal)),
-                              integer_zero_node);
-               else
-                 gnu_actual
-                   = build_unary_op (ADDR_EXPR, NULL_TREE,
-                                     fill_vms_descriptor (gnu_actual,
-                                                          gnat_formal));
-             }
-           else
-             {
-               tree gnu_actual_size = TYPE_SIZE (TREE_TYPE (gnu_actual));
-
-               if (Ekind (gnat_formal) != E_In_Parameter)
-                 gnu_name_list
-                   = chainon (gnu_name_list,
-                              build_tree_list (NULL_TREE, gnu_name));
-
-               if (! present_gnu_tree (gnat_formal)
-                   || TREE_CODE (get_gnu_tree (gnat_formal)) != PARM_DECL)
-                 continue;
-
-               /* If this is 'Null_Parameter, pass a zero even though we are
-                  dereferencing it.  */
-               else if (TREE_CODE (gnu_actual) == INDIRECT_REF
-                        && TREE_PRIVATE (gnu_actual)
-                        && host_integerp (gnu_actual_size, 1)
-                        && 0 >= compare_tree_int (gnu_actual_size,
-                                                  BITS_PER_WORD))
-                 gnu_actual
-                   = unchecked_convert
-                     (DECL_ARG_TYPE (get_gnu_tree (gnat_formal)),
-                      convert (gnat_type_for_size
-                               (tree_low_cst (gnu_actual_size, 1), 1),
-                               integer_zero_node), 0);
-               else
-                 gnu_actual
-                   = convert (TYPE_MAIN_VARIANT
-                              (DECL_ARG_TYPE (get_gnu_tree (gnat_formal))),
-                              gnu_actual);
-             }
-
-           gnu_actual_list
-             = chainon (gnu_actual_list,
-                        build_tree_list (NULL_TREE, gnu_actual));
-         }
-
-       gnu_subprog_call = build (CALL_EXPR, TREE_TYPE (gnu_subprog_type),
-                                 gnu_subprog_addr, gnu_actual_list,
-                                 NULL_TREE);
-       TREE_SIDE_EFFECTS (gnu_subprog_call) = 1;
-
-       /* If it is a function call, the result is the call expression.  */
-       if (Nkind (gnat_node) == N_Function_Call)
-         {
-           gnu_result = gnu_subprog_call;
-
-           /* If the function returns an unconstrained array or by reference,
-              we have to de-dereference the pointer.  */
-           if (TYPE_RETURNS_UNCONSTRAINED_P (gnu_subprog_type)
-               || TYPE_RETURNS_BY_REF_P (gnu_subprog_type))
-             gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE,
-                                          gnu_result);
-
-           gnu_result_type = get_unpadded_type (Etype (gnat_node));
-           break;
-         }
-
-       /* If this is the case where the GNAT tree contains a procedure call
-          but the Ada procedure has copy in copy out parameters, the special
-          parameter passing mechanism must be used.  */
-       else if (TYPE_CI_CO_LIST (gnu_subprog_type) != NULL_TREE)
-         {
-           /* List of FIELD_DECLs associated with the PARM_DECLs of the copy
-              in copy out parameters.  */
-           tree scalar_return_list = TYPE_CI_CO_LIST (gnu_subprog_type);
-           int length = list_length (scalar_return_list);
-
-           if (length > 1)
-             {
-               tree gnu_name;
-
-               gnu_subprog_call = protect_multiple_eval (gnu_subprog_call);
-
-               /* If any of the names had side-effects, ensure they are
-                  all evaluated before the call.  */
-               for (gnu_name = gnu_name_list; gnu_name;
-                    gnu_name = TREE_CHAIN (gnu_name))
-                 if (TREE_SIDE_EFFECTS (TREE_VALUE (gnu_name)))
-                   gnu_subprog_call
-                     = build (COMPOUND_EXPR, TREE_TYPE (gnu_subprog_call),
-                              TREE_VALUE (gnu_name), gnu_subprog_call);
-             }
-
-           if (Nkind (Name (gnat_node)) == N_Explicit_Dereference)
-             gnat_formal = First_Formal (Etype (Name (gnat_node)));
-           else
-             gnat_formal = First_Formal (Entity (Name (gnat_node)));
-
-           for (gnat_actual = First_Actual (gnat_node);
-                Present (gnat_actual);
-                gnat_formal = Next_Formal_With_Extras (gnat_formal),
-                gnat_actual = Next_Actual (gnat_actual))
-             /* If we are dealing with a copy in copy out parameter, we must
-                retrieve its value from the record returned in the function
-                call.  */
-             if (! (present_gnu_tree (gnat_formal)
-                    && TREE_CODE (get_gnu_tree (gnat_formal)) == PARM_DECL
-                    && (DECL_BY_REF_P (get_gnu_tree (gnat_formal))
-                        || ((TREE_CODE (get_gnu_tree (gnat_formal))
-                             == PARM_DECL)
-                            && ((DECL_BY_COMPONENT_PTR_P
-                                 (get_gnu_tree (gnat_formal))
-                                 || (DECL_BY_DESCRIPTOR_P
-                                     (get_gnu_tree (gnat_formal))))))))
-                 && Ekind (gnat_formal) != E_In_Parameter)
-               {
-                 /* Get the value to assign to this OUT or IN OUT
-                    parameter.  It is either the result of the function if
-                    there is only a single such parameter or the appropriate
-                    field from the record returned.  */
-                 tree gnu_result
-                   = length == 1 ? gnu_subprog_call
-                     : build_component_ref
-                       (gnu_subprog_call, NULL_TREE,
-                        TREE_PURPOSE (scalar_return_list), 0);
-                 int unchecked_conversion
-                   = Nkind (gnat_actual) == N_Unchecked_Type_Conversion;
-                 /* If the actual is a conversion, get the inner expression,
-                    which will be the real destination, and convert the
-                    result to the type of the actual parameter.  */
-                 tree gnu_actual
-                   = maybe_unconstrained_array (TREE_VALUE (gnu_name_list));
-
-                 /* If the result is a padded type, remove the padding.  */
-                 if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE
-                     && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)))
-                   gnu_result
-                     = convert (TREE_TYPE (TYPE_FIELDS
-                                           (TREE_TYPE (gnu_result))),
-                                gnu_result);
-
-                 /* If the result is a type conversion, do it.  */
-                 if (Nkind (gnat_actual) == N_Type_Conversion)
-                   gnu_result
-                     = convert_with_check
-                       (Etype (Expression (gnat_actual)), gnu_result,
-                        Do_Overflow_Check (gnat_actual),
-                        Do_Range_Check (Expression (gnat_actual)),
-                        Float_Truncate (gnat_actual));
-
-                 else if (unchecked_conversion)
-                   gnu_result
-                     = unchecked_convert (TREE_TYPE (gnu_actual), gnu_result,
-                                          No_Truncation (gnat_actual));
-                 else
-                   {
-                     if (Do_Range_Check (gnat_actual))
-                       gnu_result = emit_range_check (gnu_result,
-                                                      Etype (gnat_actual));
-
-                     if (! (! TREE_CONSTANT (TYPE_SIZE
-                                             (TREE_TYPE (gnu_actual)))
-                            && TREE_CONSTANT (TYPE_SIZE
-                                              (TREE_TYPE (gnu_result)))))
-                       gnu_result = convert (TREE_TYPE (gnu_actual),
-                                             gnu_result);
-                   }
-
-                 gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
-                                               gnu_actual, gnu_result);
-                 annotate_with_node (gnu_result, gnat_actual);
-                 append_to_statement_list (gnu_result, &gnu_before_list);
-                 scalar_return_list = TREE_CHAIN (scalar_return_list);
-                 gnu_name_list = TREE_CHAIN (gnu_name_list);
-               }
-         }
-       else
-         {
-           annotate_with_node (gnu_subprog_call, gnat_node);
-           append_to_statement_list (gnu_subprog_call, &gnu_before_list);
-         }
-
-       append_to_statement_list (gnu_after_list, &gnu_before_list);
-       gnu_result = gnu_before_list;
-      }
+      gnu_result = call_to_gnu (gnat_node, &gnu_result_type);
       break;
 
     /*************************/
@@ -3264,20 +3620,7 @@ gnat_to_gnu (Node_Id gnat_node)
     /***************************/
 
     case N_Handled_Sequence_Of_Statements:
-
-      /* The GCC exception handling mechanism can handle both ZCX and SJLJ
-        schemes and we have our own SJLJ mechanism.  To call the GCC
-        mechanism, we call add_cleanup, and when we leave the binding,
-        end_stmt_group will create the TRY_FINALLY_EXPR.
-
-        ??? The region level calls down there have been specifically put in
-        place for a ZCX context and currently the order in which things are
-        emitted (region/handlers) is different from the SJLJ case. Instead of
-        putting other calls with different conditions at other places for the
-        SJLJ case, it seems cleaner to reorder things for the SJLJ case and
-        generalize the condition to make it not ZCX specific. */
-
-      /* If there is an At_End procedure attached to this node, and the eh
+      /* If there is an At_End procedure attached to this node, and the EH
         mechanism is SJLJ, we must have at least a corresponding At_End
         handler, unless the No_Exception_Handlers restriction is set.  */
       if (! type_annotate_only
@@ -3287,370 +3630,14 @@ gnat_to_gnu (Node_Id gnat_node)
          && ! No_Exception_Handlers_Set())
        gigi_abort (335);
 
-      {
-       tree gnu_jmpsave_decl = NULL_TREE;
-       tree gnu_jmpbuf_decl = NULL_TREE;
-       /* If just annotating, ignore all EH and cleanups.  */
-       bool gcc_zcx
-         = (!type_annotate_only && Present (Exception_Handlers (gnat_node))
-            && Exception_Mechanism == GCC_ZCX);
-       bool setjmp_longjmp
-         = (!type_annotate_only && Present (Exception_Handlers (gnat_node))
-            && Exception_Mechanism == Setjmp_Longjmp);
-       bool at_end = !type_annotate_only && Present (At_End_Proc (gnat_node));
-       bool binding_for_block = (at_end || gcc_zcx || setjmp_longjmp);
-       tree gnu_inner_block; /* The statement(s) for the block itself.  */
-
-       /* If there are any exceptions or cleanup processing involved, we need
-          an outer statement group (for Setjmp_Longjmp) and binding level.  */
-       if (binding_for_block)
-         {
-           start_stmt_group ();
-           gnat_pushlevel ();
-         }
-
-       /* If we are to call a function when exiting this block add a cleanup
-          to the binding level we made above.  */
-       if (at_end)
-         add_cleanup (build_call_0_expr
-                      (gnat_to_gnu (At_End_Proc (gnat_node))));
-
-       /* If using setjmp_longjmp, make the variables for the setjmp
-          buffer and save area for address of previous buffer.  Do this
-          first since we need to have the setjmp buf known for any decls
-          in this block.  */
-       if (setjmp_longjmp)
-         {
-           gnu_jmpsave_decl
-             = create_var_decl (get_identifier ("JMPBUF_SAVE"), NULL_TREE,
-                                jmpbuf_ptr_type,
-                                build_call_0_expr (get_jmpbuf_decl),
-                                0, 0, 0, 0, 0, gnat_node);
-           gnu_jmpbuf_decl
-             = create_var_decl (get_identifier ("JMP_BUF"),
-                                NULL_TREE, jmpbuf_type,
-                                NULL_TREE, 0, 0, 0, 0, 0, gnat_node);
-
-           set_block_jmpbuf_decl (gnu_jmpbuf_decl);
-
-           /* When we exit this block, restore the saved value.  */
-           add_cleanup (build_call_1_expr (set_jmpbuf_decl,
-                                           gnu_jmpsave_decl));
-         }
-
-       /* Now build the tree for the declarations and statements inside this
-          block.  If this is SJLJ, set our jmp_buf as the current buffer.  */
-       start_stmt_group ();
-
-       if (setjmp_longjmp)
-         add_stmt (build_call_1_expr
-                   (set_jmpbuf_decl,
-                    build_unary_op (ADDR_EXPR, NULL_TREE, gnu_jmpbuf_decl)));
-
-
-       if (Present (First_Real_Statement (gnat_node)))
-         process_decls (Statements (gnat_node), Empty,
-                        First_Real_Statement (gnat_node), 1, 1);
-
-       /* Generate code for each statement in the block.  */
-       for (gnat_temp = (Present (First_Real_Statement (gnat_node))
-                         ? First_Real_Statement (gnat_node)
-                         : First (Statements (gnat_node)));
-            Present (gnat_temp); gnat_temp = Next (gnat_temp))
-         add_stmt (gnat_to_gnu (gnat_temp));
-       gnu_inner_block = end_stmt_group ();
-
-       /* Now generate code for the two exception models, if either is
-          relevant for this block.  */
-       if (setjmp_longjmp)
-         {
-           tree *gnu_else_ptr = 0;
-           tree gnu_handler;
-
-           /* Make a binding level for the exception handling declarations
-              and code and set up gnu_except_ptr_stack for the handlers
-              to use.  */
-           start_stmt_group ();
-           gnat_pushlevel ();
-
-           push_stack (&gnu_except_ptr_stack, NULL_TREE,
-                       create_var_decl (get_identifier ("EXCEPT_PTR"),
-                                        NULL_TREE,
-                                        build_pointer_type (except_type_node),
-                                        build_call_0_expr (get_excptr_decl),
-                                        0, 0, 0, 0, 0, gnat_node));
-
-           /* Generate code for each handler. The N_Exception_Handler case
-              below does the real work and returns a COND_EXPR for each
-              handler, which we chain together here.  */
-           for (gnat_temp = First_Non_Pragma (Exception_Handlers (gnat_node));
-                Present (gnat_temp);
-                gnat_temp = Next_Non_Pragma (gnat_temp))
-             {
-               gnu_expr = gnat_to_gnu (gnat_temp);
-
-               /* If this is the first one, set it as the outer one.
-                  Otherwise, point the "else" part of the previous handler
-                  to us. Then point to our "else" part.  */
-               if (!gnu_else_ptr)
-                 add_stmt (gnu_expr);
-               else
-                 *gnu_else_ptr = gnu_expr;
-
-               gnu_else_ptr = &COND_EXPR_ELSE (gnu_expr);
-             }
-
-           /* If none of the exception handlers did anything, re-raise but
-              do not defer abortion.  */
-           gnu_expr = build_call_1_expr (raise_nodefer_decl,
-                                         TREE_VALUE (gnu_except_ptr_stack));
-           annotate_with_node (gnu_expr, gnat_node);
-
-           if (gnu_else_ptr)
-             *gnu_else_ptr = gnu_expr;
-           else
-             add_stmt (gnu_expr);
-
-           /* End the binding level dedicated to the exception handlers
-              and get the whole statement group.  */
-           pop_stack (&gnu_except_ptr_stack);
-           gnat_poplevel ();
-           gnu_handler = end_stmt_group ();
-
-           /* If the setjmp returns 1, we restore our incoming longjmp value
-              and then check the handlers.  */
-           start_stmt_group ();
-           add_stmt_with_node (build_call_1_expr (set_jmpbuf_decl,
-                                                  gnu_jmpsave_decl),
-                               gnat_node);
-           add_stmt (gnu_handler);
-           gnu_handler = end_stmt_group ();
-
-           /* This block is now "if (setjmp) ... <handlers> else <block>".  */
-           gnu_result = build (COND_EXPR, void_type_node,
-                               (build_call_1_expr
-                                (setjmp_decl,
-                                 build_unary_op (ADDR_EXPR, NULL_TREE,
-                                                 gnu_jmpbuf_decl))),
-                               gnu_handler, gnu_inner_block);
-         }
-       else if (gcc_zcx)
-         {
-           tree gnu_handlers;
-
-           /* First make a block containing the handlers.  */
-           start_stmt_group ();
-           for (gnat_temp = First_Non_Pragma (Exception_Handlers (gnat_node));
-                Present (gnat_temp);
-                gnat_temp = Next_Non_Pragma (gnat_temp))
-             add_stmt (gnat_to_gnu (gnat_temp));
-           gnu_handlers = end_stmt_group ();
-
-           /* Now make the TRY_CATCH_EXPR for the block.  */
-           gnu_result = build (TRY_CATCH_EXPR, void_type_node,
-                               gnu_inner_block, gnu_handlers);
-         }
-       else
-         gnu_result = gnu_inner_block;
-
-       /* Now close our outer block, if we had to make one.  */
-       if (binding_for_block)
-         {
-           add_stmt (gnu_result);
-           gnat_poplevel ();
-           gnu_result = end_stmt_group ();
-         }
-      }
+      gnu_result = Handled_Sequence_Of_Statements_to_gnu (gnat_node);
       break;
 
     case N_Exception_Handler:
       if (Exception_Mechanism == Setjmp_Longjmp)
-       {
-         /* Unless this is "Others" or the special "Non-Ada" exception
-            for Ada, make an "if" statement to select the proper
-            exceptions.  For "Others", exclude exceptions where
-            Handled_By_Others is nonzero unless the All_Others flag is set.
-            For "Non-ada", accept an exception if "Lang" is 'V'.  */
-         tree gnu_choice = integer_zero_node;
-         tree gnu_body = build_stmt_group (Statements (gnat_node), false);
-
-         for (gnat_temp = First (Exception_Choices (gnat_node));
-              gnat_temp; gnat_temp = Next (gnat_temp))
-           {
-             tree this_choice;
-
-             if (Nkind (gnat_temp) == N_Others_Choice)
-               {
-                 if (All_Others (gnat_temp))
-                   this_choice = integer_one_node;
-                 else
-                   this_choice
-                     = build_binary_op
-                       (EQ_EXPR, integer_type_node,
-                      convert
-                      (integer_type_node,
-                       build_component_ref
-                       (build_unary_op
-                        (INDIRECT_REF, NULL_TREE,
-                         TREE_VALUE (gnu_except_ptr_stack)),
-                        get_identifier ("not_handled_by_others"), NULL_TREE,
-                        0)),
-                        integer_zero_node);
-               }
-
-             else if (Nkind (gnat_temp) == N_Identifier
-                      || Nkind (gnat_temp) == N_Expanded_Name)
-               {
-                 gnu_expr
-                   = gnat_to_gnu_entity (Entity (gnat_temp), NULL_TREE, 0);
-
-                 this_choice
-                   = build_binary_op
-                     (EQ_EXPR, integer_type_node,
-                      TREE_VALUE (gnu_except_ptr_stack),
-                      convert
-                        (TREE_TYPE (TREE_VALUE (gnu_except_ptr_stack)),
-                         build_unary_op (ADDR_EXPR, NULL_TREE, gnu_expr)));
-
-                 /* If this is the distinguished exception "Non_Ada_Error"
-                    (and we are in VMS mode), also allow a non-Ada
-                    exception (a VMS condition) to match.  */
-                 if (Is_Non_Ada_Error (Entity (gnat_temp)))
-                   {
-                     tree gnu_comp
-                       = build_component_ref
-                         (build_unary_op
-                          (INDIRECT_REF, NULL_TREE,
-                           TREE_VALUE (gnu_except_ptr_stack)),
-                          get_identifier ("lang"), NULL_TREE, 0);
-
-                     this_choice
-                       = build_binary_op
-                       (TRUTH_ORIF_EXPR, integer_type_node,
-                        build_binary_op
-                        (EQ_EXPR, integer_type_node, gnu_comp,
-                         convert (TREE_TYPE (gnu_comp),
-                                  build_int_2 ('V', 0))),
-                        this_choice);
-                   }
-               }
-             else
-               gigi_abort (318);
-
-             gnu_choice = build_binary_op (TRUTH_ORIF_EXPR, integer_type_node,
-                                           gnu_choice, this_choice);
-           }
-
-         gnu_result = build (COND_EXPR, void_type_node, gnu_choice, gnu_body,
-                             NULL_TREE);
-       }
-
-      /* Tell the back end that we start an exception handler if necessary.  */
+       gnu_result = Exception_Handler_to_gnu_sjlj (gnat_node);
       else if (Exception_Mechanism == GCC_ZCX)
-       {
-         /* We build a TREE_LIST of nodes representing what exception
-            types this handler is able to catch, with special cases
-            for others and all others cases.
-
-            Each exception type is actually identified by a pointer to the
-            exception id, with special value zero for "others" and one for
-            "all others". Beware that these special values are known and used
-            by the personality routine to identify the corresponding specific
-            kinds of handlers.
-
-            ??? For initial time frame reasons, the others and all_others
-            cases have been handled using specific type trees, but this
-            somehow hides information to the back-end, which expects NULL to
-            be passed for catch all and end_cleanup to be used for cleanups.
-
-            Care should be taken to ensure that the control flow impact of
-            such clauses is rendered in some way. lang_eh_type_covers is
-            doing the trick currently.  */
-
-         tree gnu_etypes_list = NULL_TREE;
-         tree gnu_etype;
-         tree gnu_current_exc_ptr;
-         tree gnu_incoming_exc_ptr;
-
-         for (gnat_temp = First (Exception_Choices (gnat_node));
-              gnat_temp; gnat_temp = Next (gnat_temp))
-           {
-             if (Nkind (gnat_temp) == N_Others_Choice)
-               gnu_etype
-                 = All_Others (gnat_temp) ? integer_one_node
-                   : integer_zero_node;
-             else if (Nkind (gnat_temp) == N_Identifier
-                      || Nkind (gnat_temp) == N_Expanded_Name)
-               {
-                  Entity_Id gnat_ex_id = Entity (gnat_temp);
-
-                 /* Exception may be a renaming. Recover original exception
-                    which is the one elaborated and registered.  */
-                 if (Present (Renamed_Object (gnat_ex_id)))
-                   gnat_ex_id = Renamed_Object (gnat_ex_id);
-
-                 gnu_expr = gnat_to_gnu_entity (gnat_ex_id, NULL_TREE, 0);
-
-                 gnu_etype
-                   = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_expr);
-
-                 /* The Non_Ada_Error case for VMS exceptions is handled
-                    by the personality routine.  */
-               }
-             else
-               gigi_abort (337);
-
-             /* The GCC interface expects NULL to be passed for catch all
-                handlers, so it would be quite tempting to set gnu_etypes_list
-                to NULL if gnu_etype is integer_zero_node.  It would not work,
-                however, because GCC's notion of "catch all" is stronger than
-                our notion of "others".  Until we correctly use the cleanup
-                interface as well, the doing tht would prevent the "all
-                others" handlers from beeing seen, because nothing can be
-                caught beyond a catch all from GCC's point of view.  */
-             gnu_etypes_list
-               = tree_cons (NULL_TREE, gnu_etype, gnu_etypes_list);
-           }
-
-         start_stmt_group ();
-         gnat_pushlevel ();
-
-         /* Expand a call to the begin_handler hook at the beginning of the
-            handler, and arrange for a call to the end_handler hook to occur
-            on every possible exit path.
-
-            The hooks expect a pointer to the low level occurrence. This is
-            required for our stack management scheme because a raise inside
-            the handler pushes a new occurrence on top of the stack, which
-            means that this top does not necessarily match the occurrence
-            this handler was dealing with.
-
-            The EXC_PTR_EXPR object references the exception occurrence
-            beeing propagated. Upon handler entry, this is the exception for
-            which the handler is triggered. This might not be the case upon
-            handler exit, however, as we might have a new occurrence
-            propagated by the handler's body, and the end_handler hook
-            called as a cleanup in this context.
-
-            We use a local variable to retrieve the incoming value at
-            handler entry time, and reuse it to feed the end_handler hook's
-            argument at exit time.  */
-         gnu_current_exc_ptr = build (EXC_PTR_EXPR, ptr_type_node);
-         gnu_incoming_exc_ptr
-           = create_var_decl (get_identifier ("EXPTR"), NULL_TREE,
-                              ptr_type_node, gnu_current_exc_ptr,
-                              0, 0, 0, 0, 0, gnat_node);
-
-         add_stmt_with_node (build_call_1_expr (begin_handler_decl,
-                                                gnu_incoming_exc_ptr),
-                             gnat_node);
-         add_cleanup (build_call_1_expr (end_handler_decl,
-                                         gnu_incoming_exc_ptr));
-         add_stmt_list (Statements (gnat_node));
-         gnat_poplevel ();
-         gnu_result = build (CATCH_EXPR, void_type_node,
-                             gnu_etypes_list, end_stmt_group ());
-       }
+       gnu_result = Exception_Handler_to_gnu_zcx (gnat_node);
       else
        abort ();