OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-cidlli.adb
index 6fb6d9e..cc93b4c 100644 (file)
@@ -2,58 +2,78 @@
 --                                                                          --
 --                         GNAT LIBRARY COMPONENTS                          --
 --                                                                          --
---                      A D A . C O N T A I N E R S .                       --
---        I N D E F I N I T E _ D O U B L Y _ L I N K E D _ L I S T S       --
+--               ADA.CONTAINERS.INDEFINITE_DOUBLY_LINKED_LISTS              --
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 2004-2005 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 --
--- apply solely to the  contents of the part following the private keyword. --
+--          Copyright (C) 2004-2012, 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- --
+-- ware  Foundation;  either version 3,  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.                                                      --
+-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
+--                                                                          --
+-- As a special exception under Section 7 of GPL version 3, you are granted --
+-- additional permissions described in the GCC Runtime Library Exception,   --
+-- version 3.1, as published by the Free Software Foundation.               --
 --                                                                          --
--- 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.                                      --
+-- You should have received a copy of the GNU General Public License and    --
+-- a copy of the GCC Runtime Library Exception along with this program;     --
+-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
+-- <http://www.gnu.org/licenses/>.                                          --
 --                                                                          --
 -- This unit was originally developed by Matthew J Heaney.                  --
 ------------------------------------------------------------------------------
 
-with System;  use type System.Address;
 with Ada.Unchecked_Deallocation;
 
-package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
+with System; use type System.Address;
 
-   procedure Free is
-     new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
+package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
    procedure Free is
      new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
 
+   type Iterator is new Limited_Controlled and
+     List_Iterator_Interfaces.Reversible_Iterator with
+   record
+      Container : List_Access;
+      Node      : Node_Access;
+   end record;
+
+   overriding procedure Finalize (Object : in out Iterator);
+
+   overriding function First (Object : Iterator) return Cursor;
+   overriding function Last  (Object : Iterator) return Cursor;
+
+   overriding function Next
+     (Object   : Iterator;
+      Position : Cursor) return Cursor;
+
+   overriding function Previous
+     (Object   : Iterator;
+      Position : Cursor) return Cursor;
+
    -----------------------
    -- Local Subprograms --
    -----------------------
 
+   procedure Free (X : in out Node_Access);
+
    procedure Insert_Internal
      (Container : in out List;
       Before    : Node_Access;
       New_Node  : Node_Access);
 
+   function Vet (Position : Cursor) return Boolean;
+   --  Checks invariants of the cursor and its designated container, as a
+   --  simple way of detecting dangling references (see operation Free for a
+   --  description of the detection mechanism), returning True if all checks
+   --  pass. Invocations of Vet are used here as the argument of pragma Assert,
+   --  so the checks are performed only when assertions are enabled.
+
    ---------
    -- "=" --
    ---------
@@ -146,6 +166,20 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       end loop;
    end Adjust;
 
+   procedure Adjust (Control : in out Reference_Control_Type) is
+   begin
+      if Control.Container /= null then
+         declare
+            C : List renames Control.Container.all;
+            B : Natural renames C.Busy;
+            L : Natural renames C.Lock;
+         begin
+            B := B + 1;
+            L := L + 1;
+         end;
+      end if;
+   end Adjust;
+
    ------------
    -- Append --
    ------------
@@ -159,12 +193,34 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       Insert (Container, No_Element, New_Item, Count);
    end Append;
 
+   ------------
+   -- Assign --
+   ------------
+
+   procedure Assign (Target : in out List; Source : List) is
+      Node : Node_Access;
+
+   begin
+      if Target'Address = Source'Address then
+         return;
+      end if;
+
+      Target.Clear;
+
+      Node := Source.First;
+      while Node /= null loop
+         Target.Append (Node.Element.all);
+         Node := Node.Next;
+      end loop;
+   end Assign;
+
    -----------
    -- Clear --
    -----------
 
    procedure Clear (Container : in out List) is
       X : Node_Access;
+      pragma Warnings (Off, X);
 
    begin
       if Container.Length = 0 then
@@ -179,7 +235,8 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       pragma Assert (Container.Last.Next = null);
 
       if Container.Busy > 0 then
-         raise Program_Error;
+         raise Program_Error with
+           "attempt to tamper with cursors (list is busy)";
       end if;
 
       while Container.Length > 1 loop
@@ -188,18 +245,8 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
          Container.First := X.Next;
          Container.First.Prev := null;
-         Container.Length := Container.Length - 1;
 
-         X.Next := null;  --  prevent mischief
-
-         begin
-            Free (X.Element);
-         exception
-            when others =>
-               X.Element := null;
-               Free (X);
-               raise;
-         end;
+         Container.Length := Container.Length - 1;
 
          Free (X);
       end loop;
@@ -211,29 +258,71 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       Container.Last := null;
       Container.Length := 0;
 
-      begin
-         Free (X.Element);
-      exception
-         when others =>
-            X.Element := null;
-            Free (X);
-            raise;
-      end;
-
       Free (X);
    end Clear;
 
+   ------------------------
+   -- Constant_Reference --
+   ------------------------
+
+   function Constant_Reference
+     (Container : aliased List;
+      Position  : Cursor) return Constant_Reference_Type
+   is
+   begin
+      if Position.Container = null then
+         raise Constraint_Error with "Position cursor has no element";
+      end if;
+
+      if Position.Container /= Container'Unrestricted_Access then
+         raise Program_Error with
+           "Position cursor designates wrong container";
+      end if;
+
+      if Position.Node.Element = null then
+         raise Program_Error with "Node has no element";
+      end if;
+
+      pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
+
+      declare
+         C : List renames Position.Container.all;
+         B : Natural renames C.Busy;
+         L : Natural renames C.Lock;
+      begin
+         return R : constant Constant_Reference_Type :=
+                      (Element => Position.Node.Element.all'Access,
+                       Control => (Controlled with Position.Container))
+         do
+            B := B + 1;
+            L := L + 1;
+         end return;
+      end;
+   end Constant_Reference;
+
    --------------
    -- Contains --
    --------------
 
    function Contains
      (Container : List;
-      Item      : Element_Type) return Boolean is
+      Item      : Element_Type) return Boolean
+   is
    begin
       return Find (Container, Item) /= No_Element;
    end Contains;
 
+   ----------
+   -- Copy --
+   ----------
+
+   function Copy (Source : List) return List is
+   begin
+      return Target : List do
+         Target.Assign (Source);
+      end return;
+   end Copy;
+
    ------------
    -- Delete --
    ------------
@@ -247,39 +336,36 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
    begin
       if Position.Node = null then
-         raise Constraint_Error;
+         raise Constraint_Error with
+           "Position cursor has no element";
       end if;
 
-      if Position.Container /= List_Access'(Container'Unchecked_Access) then
-         raise Program_Error;
+      if Position.Node.Element = null then
+         raise Program_Error with
+           "Position cursor has no element";
       end if;
 
-      pragma Assert (Container.Length > 0);
-      pragma Assert (Container.First.Prev = null);
-      pragma Assert (Container.Last.Next = null);
+      if Position.Container /= Container'Unrestricted_Access then
+         raise Program_Error with
+           "Position cursor designates wrong container";
+      end if;
 
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Container.Last);
+      pragma Assert (Vet (Position), "bad cursor in Delete");
 
       if Position.Node = Container.First then
          Delete_First (Container, Count);
-         Position := First (Container);
+         Position := No_Element;  --  Post-York behavior
          return;
       end if;
 
       if Count = 0 then
+         Position := No_Element;  --  Post-York behavior
          return;
       end if;
 
       if Container.Busy > 0 then
-         raise Program_Error;
+         raise Program_Error with
+           "attempt to tamper with cursors (list is busy)";
       end if;
 
       for Index in 1 .. Count loop
@@ -292,17 +378,6 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
             Container.Last := X.Prev;
             Container.Last.Next := null;
 
-            X.Prev := null;  --  prevent mischief
-
-            begin
-               Free (X.Element);
-            exception
-               when others =>
-                  X.Element := null;
-                  Free (X);
-                  raise;
-            end;
-
             Free (X);
             return;
          end if;
@@ -312,20 +387,10 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          X.Next.Prev := X.Prev;
          X.Prev.Next := X.Next;
 
-         X.Prev := null;
-         X.Next := null;
-
-         begin
-            Free (X.Element);
-         exception
-            when others =>
-               X.Element := null;
-               Free (X);
-               raise;
-         end;
-
          Free (X);
       end loop;
+
+      Position := No_Element;  --  Post-York behavior
    end Delete;
 
    ------------------
@@ -349,7 +414,8 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       end if;
 
       if Container.Busy > 0 then
-         raise Program_Error;
+         raise Program_Error with
+           "attempt to tamper with cursors (list is busy)";
       end if;
 
       for I in 1 .. Count loop
@@ -361,17 +427,6 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
          Container.Length := Container.Length - 1;
 
-         X.Next := null;  --  prevent mischief
-
-         begin
-            Free (X.Element);
-         exception
-            when others =>
-               X.Element := null;
-               Free (X);
-               raise;
-         end;
-
          Free (X);
       end loop;
    end Delete_First;
@@ -397,7 +452,8 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       end if;
 
       if Container.Busy > 0 then
-         raise Program_Error;
+         raise Program_Error with
+           "attempt to tamper with cursors (list is busy)";
       end if;
 
       for I in 1 .. Count loop
@@ -409,17 +465,6 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
          Container.Length := Container.Length - 1;
 
-         X.Prev := null;  --  prevent mischief
-
-         begin
-            Free (X.Element);
-         exception
-            when others =>
-               X.Element := null;
-               Free (X);
-               raise;
-         end;
-
          Free (X);
       end loop;
    end Delete_Last;
@@ -430,25 +475,52 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
    function Element (Position : Cursor) return Element_Type is
    begin
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
-
-      pragma Assert (Position.Node /= null);
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
+      if Position.Node = null then
+         raise Constraint_Error with
+           "Position cursor has no element";
+      end if;
+
+      if Position.Node.Element = null then
+         raise Program_Error with
+           "Position cursor has no element";
+      end if;
+
+      pragma Assert (Vet (Position), "bad cursor in Element");
 
       return Position.Node.Element.all;
    end Element;
 
+   --------------
+   -- Finalize --
+   --------------
+
+   procedure Finalize (Object : in out Iterator) is
+   begin
+      if Object.Container /= null then
+         declare
+            B : Natural renames Object.Container.all.Busy;
+         begin
+            B := B - 1;
+         end;
+      end if;
+   end Finalize;
+
+   procedure Finalize (Control : in out Reference_Control_Type) is
+   begin
+      if Control.Container /= null then
+         declare
+            C : List renames Control.Container.all;
+            B : Natural renames C.Busy;
+            L : Natural renames C.Lock;
+         begin
+            B := B - 1;
+            L := L - 1;
+         end;
+
+         Control.Container := null;
+      end if;
+   end Finalize;
+
    ----------
    -- Find --
    ----------
@@ -465,28 +537,21 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          Node := Container.First;
 
       else
-         if Position.Container /= List_Access'(Container'Unchecked_Access) then
+         if Node.Element = null then
             raise Program_Error;
          end if;
 
-         pragma Assert (Container.Length > 0);
-         pragma Assert (Container.First.Prev = null);
-         pragma Assert (Container.Last.Next = null);
+         if Position.Container /= Container'Unrestricted_Access then
+            raise Program_Error with
+              "Position cursor designates wrong container";
+         end if;
 
-         pragma Assert (Position.Node.Element /= null);
-         pragma Assert (Position.Node.Prev = null
-                          or else Position.Node.Prev.Next = Position.Node);
-         pragma Assert (Position.Node.Next = null
-                          or else Position.Node.Next.Prev = Position.Node);
-         pragma Assert (Position.Node.Prev /= null
-                          or else Position.Node = Container.First);
-         pragma Assert (Position.Node.Next /= null
-                          or else Position.Node = Container.Last);
+         pragma Assert (Vet (Position), "bad cursor in Find");
       end if;
 
       while Node /= null loop
          if Node.Element.all = Item then
-            return Cursor'(Container'Unchecked_Access, Node);
+            return Cursor'(Container'Unrestricted_Access, Node);
          end if;
 
          Node := Node.Next;
@@ -505,7 +570,29 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          return No_Element;
       end if;
 
-      return Cursor'(Container'Unchecked_Access, Container.First);
+      return Cursor'(Container'Unrestricted_Access, Container.First);
+   end First;
+
+   function First (Object : Iterator) return Cursor is
+   begin
+      --  The value of the iterator object's Node component influences the
+      --  behavior of the First (and Last) selector function.
+
+      --  When the Node component is null, this means the iterator object was
+      --  constructed without a start expression, in which case the (forward)
+      --  iteration starts from the (logical) beginning of the entire sequence
+      --  of items (corresponding to Container.First, for a forward iterator).
+
+      --  Otherwise, this is iteration over a partial sequence of items. When
+      --  the Node component is non-null, the iterator object was constructed
+      --  with a start expression, that specifies the position from which the
+      --  (forward) partial iteration begins.
+
+      if Object.Node = null then
+         return Indefinite_Doubly_Linked_Lists.First (Object.Container.all);
+      else
+         return Cursor'(Object.Container, Object.Node);
+      end if;
    end First;
 
    -------------------
@@ -514,9 +601,54 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
    function First_Element (Container : List) return Element_Type is
    begin
+      if Container.First = null then
+         raise Constraint_Error with "list is empty";
+      end if;
+
       return Container.First.Element.all;
    end First_Element;
 
+   ----------
+   -- Free --
+   ----------
+
+   procedure Free (X : in out Node_Access) is
+      procedure Deallocate is
+         new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
+
+   begin
+      --  While a node is in use, as an active link in a list, its Previous and
+      --  Next components must be null, or designate a different node; this is
+      --  a node invariant. For this indefinite list, there is an additional
+      --  invariant: that the element access value be non-null. Before actually
+      --  deallocating the node, we set the node access value components of the
+      --  node to point to the node itself, and set the element access value to
+      --  null (by deallocating the node's element), thus falsifying the node
+      --  invariant. Subprogram Vet inspects the value of the node components
+      --  when interrogating the node, in order to detect whether the cursor's
+      --  node access value is dangling.
+
+      --  Note that we have no guarantee that the storage for the node isn't
+      --  modified when it is deallocated, but there are other tests that Vet
+      --  does if node invariants appear to be satisifed. However, in practice
+      --  this simple test works well enough, detecting dangling references
+      --  immediately, without needing further interrogation.
+
+      X.Next := X;
+      X.Prev := X;
+
+      begin
+         Free (X.Element);
+      exception
+         when others =>
+            X.Element := null;
+            Deallocate (X);
+            raise;
+      end;
+
+      Deallocate (X);
+   end Free;
+
    ---------------------
    -- Generic_Sorting --
    ---------------------
@@ -550,31 +682,57 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
         (Target : in out List;
          Source : in out List)
       is
-         LI : Cursor;
-         RI : Cursor;
+         LI, RI : Cursor;
 
       begin
-         if Target'Address = Source'Address then
+
+         --  The semantics of Merge changed slightly per AI05-0021. It was
+         --  originally the case that if Target and Source denoted the same
+         --  container object, then the GNAT implementation of Merge did
+         --  nothing. However, it was argued that RM05 did not precisely
+         --  specify the semantics for this corner case. The decision of the
+         --  ARG was that if Target and Source denote the same non-empty
+         --  container object, then Program_Error is raised.
+
+         if Source.Is_Empty then
             return;
          end if;
 
-         if Target.Busy > 0
-           or else Source.Busy > 0
-         then
-            raise Program_Error;
+         if Target'Address = Source'Address then
+            raise Program_Error with
+              "Target and Source denote same non-empty container";
+         end if;
+
+         if Target.Busy > 0 then
+            raise Program_Error with
+              "attempt to tamper with cursors of Target (list is busy)";
+         end if;
+
+         if Source.Busy > 0 then
+            raise Program_Error with
+              "attempt to tamper with cursors of Source (list is busy)";
          end if;
 
          LI := First (Target);
          RI := First (Source);
          while RI.Node /= null loop
+            pragma Assert (RI.Node.Next = null
+                             or else not (RI.Node.Next.Element.all <
+                                          RI.Node.Element.all));
+
             if LI.Node = null then
                Splice (Target, No_Element, Source);
                return;
             end if;
 
+            pragma Assert (LI.Node.Next = null
+                             or else not (LI.Node.Next.Element.all <
+                                          LI.Node.Element.all));
+
             if RI.Node.Element.all < LI.Node.Element.all then
                declare
                   RJ : Cursor := RI;
+                  pragma Warnings (Off, RJ);
                begin
                   RI.Node := RI.Node.Next;
                   Splice (Target, LI, Source, RJ);
@@ -642,15 +800,9 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          ----------
 
          procedure Sort (Front, Back : Node_Access) is
-            Pivot : Node_Access;
-
+            Pivot : constant Node_Access :=
+                      (if Front = null then Container.First else Front.Next);
          begin
-            if Front = null then
-               Pivot := Container.First;
-            else
-               Pivot := Front.Next;
-            end if;
-
             if Pivot /= Back then
                Partition (Pivot, Back);
                Sort (Front, Pivot);
@@ -669,7 +821,8 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          pragma Assert (Container.Last.Next = null);
 
          if Container.Busy > 0 then
-            raise Program_Error;
+            raise Program_Error with
+              "attempt to tamper with cursors (list is busy)";
          end if;
 
          Sort (Front => null, Back => null);
@@ -686,27 +839,8 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
    function Has_Element (Position : Cursor) return Boolean is
    begin
-      if Position.Node = null then
-         pragma Assert (Position.Container = null);
-         return False;
-      end if;
-
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
-
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
-
-      return True;
+      pragma Assert (Vet (Position), "bad cursor in Has_Element");
+      return Position.Node /= null;
    end Has_Element;
 
    ------------
@@ -723,24 +857,20 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       New_Node : Node_Access;
 
    begin
-      if Before.Node /= null then
-         if Before.Container /= List_Access'(Container'Unchecked_Access) then
-            raise Program_Error;
+      if Before.Container /= null then
+         if Before.Container /= Container'Unrestricted_Access then
+            raise Program_Error with
+              "attempt to tamper with cursors (list is busy)";
          end if;
 
-         pragma Assert (Container.Length > 0);
-         pragma Assert (Container.First.Prev = null);
-         pragma Assert (Container.Last.Next = null);
+         if Before.Node = null
+           or else Before.Node.Element = null
+         then
+            raise Program_Error with
+              "Before cursor has no element";
+         end if;
 
-         pragma Assert (Before.Node.Element /= null);
-         pragma Assert (Before.Node.Prev = null
-                          or else Before.Node.Prev.Next = Before.Node);
-         pragma Assert (Before.Node.Next = null
-                          or else Before.Node.Next.Prev = Before.Node);
-         pragma Assert (Before.Node.Prev /= null
-                          or else Before.Node = Container.First);
-         pragma Assert (Before.Node.Next /= null
-                          or else Before.Node = Container.Last);
+         pragma Assert (Vet (Before), "bad cursor in Insert");
       end if;
 
       if Count = 0 then
@@ -749,11 +879,12 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       end if;
 
       if Container.Length > Count_Type'Last - Count then
-         raise Constraint_Error;
+         raise Constraint_Error with "new length exceeds maximum";
       end if;
 
       if Container.Busy > 0 then
-         raise Program_Error;
+         raise Program_Error with
+           "attempt to tamper with cursors (list is busy)";
       end if;
 
       declare
@@ -792,6 +923,7 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       Count     : Count_Type := 1)
    is
       Position : Cursor;
+      pragma Unreferenced (Position);
    begin
       Insert (Container, Before, New_Item, Position, Count);
    end Insert;
@@ -859,11 +991,9 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
    procedure Iterate
      (Container : List;
-      Process   : not null access procedure (Position : in Cursor))
+      Process   : not null access procedure (Position : Cursor))
    is
-      C : List renames Container'Unrestricted_Access.all;
-      B : Natural renames C.Busy;
-
+      B    : Natural renames Container'Unrestricted_Access.all.Busy;
       Node : Node_Access := Container.First;
 
    begin
@@ -871,7 +1001,7 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
       begin
          while Node /= null loop
-            Process (Cursor'(Container'Unchecked_Access, Node));
+            Process (Cursor'(Container'Unrestricted_Access, Node));
             Node := Node.Next;
          end loop;
       exception
@@ -883,31 +1013,80 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       B := B - 1;
    end Iterate;
 
-   ----------
-   -- Move --
-   ----------
+   function Iterate
+     (Container : List)
+      return List_Iterator_Interfaces.Reversible_Iterator'class
+   is
+      B : Natural renames Container'Unrestricted_Access.all.Busy;
 
-   procedure Move (Target : in out List; Source : in out List) is
    begin
-      if Target'Address = Source'Address then
-         return;
-      end if;
-
-      if Source.Busy > 0 then
-         raise Program_Error;
-      end if;
-
-      Clear (Target);
-
-      Target.First := Source.First;
-      Source.First := null;
+      --  The value of the Node component influences the behavior of the First
+      --  and Last selector functions of the iterator object. When the Node
+      --  component is null (as is the case here), this means the iterator
+      --  object was constructed without a start expression. This is a
+      --  complete iterator, meaning that the iteration starts from the
+      --  (logical) beginning of the sequence of items.
+
+      --  Note: For a forward iterator, Container.First is the beginning, and
+      --  for a reverse iterator, Container.Last is the beginning.
+
+      return It : constant Iterator :=
+                    Iterator'(Limited_Controlled with
+                                Container => Container'Unrestricted_Access,
+                                Node      => null)
+      do
+         B := B + 1;
+      end return;
+   end Iterate;
 
-      Target.Last := Source.Last;
-      Source.Last := null;
+   function Iterate
+     (Container : List;
+      Start     : Cursor)
+      return List_Iterator_Interfaces.Reversible_Iterator'Class
+   is
+      B  : Natural renames Container'Unrestricted_Access.all.Busy;
 
-      Target.Length := Source.Length;
-      Source.Length := 0;
-   end Move;
+   begin
+      --  It was formerly the case that when Start = No_Element, the partial
+      --  iterator was defined to behave the same as for a complete iterator,
+      --  and iterate over the entire sequence of items. However, those
+      --  semantics were unintuitive and arguably error-prone (it is too easy
+      --  to accidentally create an endless loop), and so they were changed,
+      --  per the ARG meeting in Denver on 2011/11. However, there was no
+      --  consensus about what positive meaning this corner case should have,
+      --  and so it was decided to simply raise an exception. This does imply,
+      --  however, that it is not possible to use a partial iterator to specify
+      --  an empty sequence of items.
+
+      if Start = No_Element then
+         raise Constraint_Error with
+           "Start position for iterator equals No_Element";
+      end if;
+
+      if Start.Container /= Container'Unrestricted_Access then
+         raise Program_Error with
+           "Start cursor of Iterate designates wrong list";
+      end if;
+
+      pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
+
+      --  The value of the Node component influences the behavior of the First
+      --  and Last selector functions of the iterator object. When the Node
+      --  component is non-null (as is the case here), it means that this
+      --  is a partial iteration, over a subset of the complete sequence of
+      --  items. The iterator object was constructed with a start expression,
+      --  indicating the position from which the iteration begins. Note that
+      --  the start position has the same value irrespective of whether this
+      --  is a forward or reverse iteration.
+
+      return It : constant Iterator :=
+                    Iterator'(Limited_Controlled with
+                                Container => Container'Unrestricted_Access,
+                                Node      => Start.Node)
+      do
+         B := B + 1;
+      end return;
+   end Iterate;
 
    ----------
    -- Last --
@@ -919,7 +1098,29 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          return No_Element;
       end if;
 
-      return Cursor'(Container'Unchecked_Access, Container.Last);
+      return Cursor'(Container'Unrestricted_Access, Container.Last);
+   end Last;
+
+   function Last (Object : Iterator) return Cursor is
+   begin
+      --  The value of the iterator object's Node component influences the
+      --  behavior of the Last (and First) selector function.
+
+      --  When the Node component is null, this means the iterator object was
+      --  constructed without a start expression, in which case the (reverse)
+      --  iteration starts from the (logical) beginning of the entire sequence
+      --  (corresponding to Container.Last, for a reverse iterator).
+
+      --  Otherwise, this is iteration over a partial sequence of items. When
+      --  the Node component is non-null, the iterator object was constructed
+      --  with a start expression, that specifies the position from which the
+      --  (reverse) partial iteration begins.
+
+      if Object.Node = null then
+         return Indefinite_Doubly_Linked_Lists.Last (Object.Container.all);
+      else
+         return Cursor'(Object.Container, Object.Node);
+      end if;
    end Last;
 
    ------------------
@@ -928,6 +1129,10 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
    function Last_Element (Container : List) return Element_Type is
    begin
+      if Container.Last = null then
+         raise Constraint_Error with "list is empty";
+      end if;
+
       return Container.Last.Element.all;
    end Last_Element;
 
@@ -941,59 +1146,48 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
    end Length;
 
    ----------
-   -- Next --
+   -- Move --
    ----------
 
-   procedure Next (Position : in out Cursor) is
+   procedure Move (Target : in out List; Source : in out List) is
    begin
-      if Position.Node = null then
-         pragma Assert (Position.Container = null);
+      if Target'Address = Source'Address then
          return;
       end if;
 
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
+      if Source.Busy > 0 then
+         raise Program_Error with
+           "attempt to tamper with cursors of Source (list is busy)";
+      end if;
+
+      Clear (Target);
 
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
+      Target.First := Source.First;
+      Source.First := null;
 
-      Position.Node := Position.Node.Next;
+      Target.Last := Source.Last;
+      Source.Last := null;
 
-      if Position.Node = null then
-         Position.Container := null;
-      end if;
+      Target.Length := Source.Length;
+      Source.Length := 0;
+   end Move;
+
+   ----------
+   -- Next --
+   ----------
+
+   procedure Next (Position : in out Cursor) is
+   begin
+      Position := Next (Position);
    end Next;
 
    function Next (Position : Cursor) return Cursor is
    begin
       if Position.Node = null then
-         pragma Assert (Position.Container = null);
          return No_Element;
       end if;
 
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
-
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
+      pragma Assert (Vet (Position), "bad cursor in Next");
 
       declare
          Next_Node : constant Node_Access := Position.Node.Next;
@@ -1006,11 +1200,25 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       end;
    end Next;
 
-   -------------
-   -- Prepend --
-   -------------
+   function Next (Object : Iterator; Position : Cursor) return Cursor is
+   begin
+      if Position.Container = null then
+         return No_Element;
+      end if;
 
-   procedure Prepend
+      if Position.Container /= Object.Container then
+         raise Program_Error with
+           "Position cursor of Next designates wrong list";
+      end if;
+
+      return Next (Position);
+   end Next;
+
+   -------------
+   -- Prepend --
+   -------------
+
+   procedure Prepend
      (Container : in out List;
       New_Item  : Element_Type;
       Count     : Count_Type := 1)
@@ -1025,54 +1233,16 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
    procedure Previous (Position : in out Cursor) is
    begin
-      if Position.Node = null then
-         pragma Assert (Position.Container = null);
-         return;
-      end if;
-
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
-
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
-
-      Position.Node := Position.Node.Prev;
-
-      if Position.Node = null then
-         Position.Container := null;
-      end if;
+      Position := Previous (Position);
    end Previous;
 
    function Previous (Position : Cursor) return Cursor is
    begin
       if Position.Node = null then
-         pragma Assert (Position.Container = null);
          return No_Element;
       end if;
 
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
-
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
+      pragma Assert (Vet (Position), "bad cursor in Previous");
 
       declare
          Prev_Node : constant Node_Access := Position.Node.Prev;
@@ -1085,51 +1255,62 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       end;
    end Previous;
 
+   function Previous (Object : Iterator; Position : Cursor) return Cursor is
+   begin
+      if Position.Container = null then
+         return No_Element;
+      end if;
+
+      if Position.Container /= Object.Container then
+         raise Program_Error with
+           "Position cursor of Previous designates wrong list";
+      end if;
+
+      return Previous (Position);
+   end Previous;
+
    -------------------
    -- Query_Element --
    -------------------
 
    procedure Query_Element
      (Position : Cursor;
-      Process  : not null access procedure (Element : in Element_Type))
+      Process  : not null access procedure (Element : Element_Type))
    is
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
-
-      pragma Assert (Position.Node /= null);
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
-
-      E : Element_Type renames Position.Node.Element.all;
-
-      C : List renames Position.Container.all'Unrestricted_Access.all;
-      B : Natural renames C.Busy;
-      L : Natural renames C.Lock;
-
    begin
-      B := B + 1;
-      L := L + 1;
+      if Position.Node = null then
+         raise Constraint_Error with
+           "Position cursor has no element";
+      end if;
+
+      if Position.Node.Element = null then
+         raise Program_Error with
+           "Position cursor has no element";
+      end if;
+
+      pragma Assert (Vet (Position), "bad cursor in Query_Element");
+
+      declare
+         C : List renames Position.Container.all'Unrestricted_Access.all;
+         B : Natural renames C.Busy;
+         L : Natural renames C.Lock;
 
       begin
-         Process (E);
-      exception
-         when others =>
-            L := L - 1;
-            B := B - 1;
-            raise;
-      end;
+         B := B + 1;
+         L := L + 1;
 
-      L := L - 1;
-      B := B - 1;
+         begin
+            Process (Position.Node.Element.all);
+         exception
+            when others =>
+               L := L - 1;
+               B := B - 1;
+               raise;
+         end;
+
+         L := L - 1;
+         B := B - 1;
+      end;
    end Query_Element;
 
    ----------
@@ -1137,7 +1318,7 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
    ----------
 
    procedure Read
-     (Stream : access Root_Stream_Type'Class;
+     (Stream : not null access Root_Stream_Type'Class;
       Item   : out List)
    is
       N   : Count_Type'Base;
@@ -1185,122 +1366,114 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       end loop;
    end Read;
 
-   ---------------------
-   -- Replace_Element --
-   ---------------------
-
-   procedure Replace_Element
-     (Position : Cursor;
-      By       : Element_Type)
+   procedure Read
+     (Stream : not null access Root_Stream_Type'Class;
+      Item   : out Cursor)
    is
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
-
-      pragma Assert (Position.Node /= null);
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
-
-      X : Element_Access := Position.Node.Element;
-
    begin
-      if Position.Container.Lock > 0 then
-         raise Program_Error;
-      end if;
-
-      Position.Node.Element := new Element_Type'(By);
-      Free (X);
-   end Replace_Element;
-
-   ------------------
-   -- Reverse_Find --
-   ------------------
+      raise Program_Error with "attempt to stream list cursor";
+   end Read;
 
-   function Reverse_Find
-     (Container : List;
-      Item      : Element_Type;
-      Position  : Cursor := No_Element) return Cursor
+   procedure Read
+     (Stream : not null access Root_Stream_Type'Class;
+      Item   : out Reference_Type)
    is
-      Node : Node_Access := Position.Node;
+   begin
+      raise Program_Error with "attempt to stream reference";
+   end Read;
 
+   procedure Read
+     (Stream : not null access Root_Stream_Type'Class;
+      Item   : out Constant_Reference_Type)
+   is
    begin
-      if Node = null then
-         Node := Container.Last;
+      raise Program_Error with "attempt to stream reference";
+   end Read;
 
-      else
-         if Position.Container /= List_Access'(Container'Unchecked_Access) then
-            raise Program_Error;
-         end if;
+   ---------------
+   -- Reference --
+   ---------------
 
-         pragma Assert (Container.Length > 0);
-         pragma Assert (Container.First.Prev = null);
-         pragma Assert (Container.Last.Next = null);
+   function Reference
+     (Container : aliased in out List;
+      Position  : Cursor) return Reference_Type
+   is
+   begin
+      if Position.Container = null then
+         raise Constraint_Error with "Position cursor has no element";
+      end if;
 
-         pragma Assert (Position.Node.Element /= null);
-         pragma Assert (Position.Node.Prev = null
-                          or else Position.Node.Prev.Next = Position.Node);
-         pragma Assert (Position.Node.Next = null
-                          or else Position.Node.Next.Prev = Position.Node);
-         pragma Assert (Position.Node.Prev /= null
-                          or else Position.Node = Container.First);
-         pragma Assert (Position.Node.Next /= null
-                          or else Position.Node = Container.Last);
+      if Position.Container /= Container'Unrestricted_Access then
+         raise Program_Error with
+           "Position cursor designates wrong container";
       end if;
 
-      while Node /= null loop
-         if Node.Element.all = Item then
-            return Cursor'(Container'Unchecked_Access, Node);
-         end if;
+      if Position.Node.Element = null then
+         raise Program_Error with "Node has no element";
+      end if;
 
-         Node := Node.Prev;
-      end loop;
+      pragma Assert (Vet (Position), "bad cursor in function Reference");
 
-      return No_Element;
-   end Reverse_Find;
+      declare
+         C : List renames Position.Container.all;
+         B : Natural renames C.Busy;
+         L : Natural renames C.Lock;
+      begin
+         return R : constant Reference_Type :=
+                      (Element => Position.Node.Element.all'Access,
+                       Control => (Controlled with Position.Container))
+         do
+            B := B + 1;
+            L := L + 1;
+         end return;
+      end;
+   end Reference;
 
    ---------------------
-   -- Reverse_Iterate --
+   -- Replace_Element --
    ---------------------
 
-   procedure Reverse_Iterate
-     (Container : List;
-      Process   : not null access procedure (Position : in Cursor))
+   procedure Replace_Element
+     (Container : in out List;
+      Position  : Cursor;
+      New_Item  : Element_Type)
    is
-      C : List renames Container'Unrestricted_Access.all;
-      B : Natural renames C.Busy;
+   begin
+      if Position.Container = null then
+         raise Constraint_Error with "Position cursor has no element";
+      end if;
 
-      Node : Node_Access := Container.Last;
+      if Position.Container /= Container'Unchecked_Access then
+         raise Program_Error with
+           "Position cursor designates wrong container";
+      end if;
 
-   begin
-      B := B + 1;
+      if Container.Lock > 0 then
+         raise Program_Error with
+           "attempt to tamper with elements (list is locked)";
+      end if;
+
+      if Position.Node.Element = null then
+         raise Program_Error with
+           "Position cursor has no element";
+      end if;
+
+      pragma Assert (Vet (Position), "bad cursor in Replace_Element");
+
+      declare
+         X : Element_Access := Position.Node.Element;
 
       begin
-         while Node /= null loop
-            Process (Cursor'(Container'Unchecked_Access, Node));
-            Node := Node.Prev;
-         end loop;
-      exception
-         when others =>
-            B := B - 1;
-            raise;
+         Position.Node.Element := new Element_Type'(New_Item);
+         Free (X);
       end;
+   end Replace_Element;
 
-      B := B - 1;
-   end Reverse_Iterate;
-
-   ------------------
-   -- Reverse_List --
-   ------------------
+   ----------------------
+   -- Reverse_Elements --
+   ----------------------
 
-   procedure Reverse_List (Container : in out List) is
+   procedure Reverse_Elements (Container : in out List) is
       I : Node_Access := Container.First;
       J : Node_Access := Container.Last;
 
@@ -1344,7 +1517,7 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          end if;
       end Swap;
 
-   --  Start of processing for Reverse_List
+   --  Start of processing for Reverse_Elements
 
    begin
       if Container.Length <= 1 then
@@ -1355,7 +1528,8 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       pragma Assert (Container.Last.Next = null);
 
       if Container.Busy > 0 then
-         raise Program_Error;
+         raise Program_Error with
+           "attempt to tamper with cursors (list is busy)";
       end if;
 
       Container.First := J;
@@ -1380,7 +1554,76 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
 
       pragma Assert (Container.First.Prev = null);
       pragma Assert (Container.Last.Next = null);
-   end Reverse_List;
+   end Reverse_Elements;
+
+   ------------------
+   -- Reverse_Find --
+   ------------------
+
+   function Reverse_Find
+     (Container : List;
+      Item      : Element_Type;
+      Position  : Cursor := No_Element) return Cursor
+   is
+      Node : Node_Access := Position.Node;
+
+   begin
+      if Node = null then
+         Node := Container.Last;
+
+      else
+         if Node.Element = null then
+            raise Program_Error with "Position cursor has no element";
+         end if;
+
+         if Position.Container /= Container'Unrestricted_Access then
+            raise Program_Error with
+              "Position cursor designates wrong container";
+         end if;
+
+         pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
+      end if;
+
+      while Node /= null loop
+         if Node.Element.all = Item then
+            return Cursor'(Container'Unrestricted_Access, Node);
+         end if;
+
+         Node := Node.Prev;
+      end loop;
+
+      return No_Element;
+   end Reverse_Find;
+
+   ---------------------
+   -- Reverse_Iterate --
+   ---------------------
+
+   procedure Reverse_Iterate
+     (Container : List;
+      Process   : not null access procedure (Position : Cursor))
+   is
+      C : List renames Container'Unrestricted_Access.all;
+      B : Natural renames C.Busy;
+
+      Node : Node_Access := Container.Last;
+
+   begin
+      B := B + 1;
+
+      begin
+         while Node /= null loop
+            Process (Cursor'(Container'Unrestricted_Access, Node));
+            Node := Node.Prev;
+         end loop;
+      exception
+         when others =>
+            B := B - 1;
+            raise;
+      end;
+
+      B := B - 1;
+   end Reverse_Iterate;
 
    ------------
    -- Splice --
@@ -1392,24 +1635,20 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       Source : in out List)
    is
    begin
-      if Before.Node /= null then
-         if Before.Container /= List_Access'(Target'Unchecked_Access) then
-            raise Program_Error;
+      if Before.Container /= null then
+         if Before.Container /= Target'Unrestricted_Access then
+            raise Program_Error with
+              "Before cursor designates wrong container";
          end if;
 
-         pragma Assert (Target.Length >= 1);
-         pragma Assert (Target.First.Prev = null);
-         pragma Assert (Target.Last.Next = null);
+         if Before.Node = null
+           or else Before.Node.Element = null
+         then
+            raise Program_Error with
+              "Before cursor has no element";
+         end if;
 
-         pragma Assert (Before.Node.Element /= null);
-         pragma Assert (Before.Node.Prev = null
-                          or else Before.Node.Prev.Next = Before.Node);
-         pragma Assert (Before.Node.Next = null
-                          or else Before.Node.Next.Prev = Before.Node);
-         pragma Assert (Before.Node.Prev /= null
-                          or else Before.Node = Target.First);
-         pragma Assert (Before.Node.Next /= null
-                          or else Before.Node = Target.Last);
+         pragma Assert (Vet (Before), "bad cursor in Splice");
       end if;
 
       if Target'Address = Source'Address
@@ -1422,13 +1661,17 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       pragma Assert (Source.Last.Next = null);
 
       if Target.Length > Count_Type'Last - Source.Length then
-         raise Constraint_Error;
+         raise Constraint_Error with "new length exceeds maximum";
       end if;
 
-      if Target.Busy > 0
-        or else Source.Busy > 0
-      then
-         raise Program_Error;
+      if Target.Busy > 0 then
+         raise Program_Error with
+           "attempt to tamper with cursors of Target (list is busy)";
+      end if;
+
+      if Source.Busy > 0 then
+         raise Program_Error with
+           "attempt to tamper with cursors of Source (list is busy)";
       end if;
 
       if Target.Length = 0 then
@@ -1472,52 +1715,41 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
    end Splice;
 
    procedure Splice
-     (Target   : in out List;
-      Before   : Cursor;
-      Position : Cursor)
+     (Container : in out List;
+      Before    : Cursor;
+      Position  : Cursor)
    is
    begin
-      if Before.Node /= null then
-         if Before.Container /= List_Access'(Target'Unchecked_Access) then
-            raise Program_Error;
+      if Before.Container /= null then
+         if Before.Container /= Container'Unchecked_Access then
+            raise Program_Error with
+              "Before cursor designates wrong container";
          end if;
 
-         pragma Assert (Target.Length >= 1);
-         pragma Assert (Target.First.Prev = null);
-         pragma Assert (Target.Last.Next = null);
+         if Before.Node = null
+           or else Before.Node.Element = null
+         then
+            raise Program_Error with
+              "Before cursor has no element";
+         end if;
 
-         pragma Assert (Before.Node.Element /= null);
-         pragma Assert (Before.Node.Prev = null
-                          or else Before.Node.Prev.Next = Before.Node);
-         pragma Assert (Before.Node.Next = null
-                          or else Before.Node.Next.Prev = Before.Node);
-         pragma Assert (Before.Node.Prev /= null
-                          or else Before.Node = Target.First);
-         pragma Assert (Before.Node.Next /= null
-                          or else Before.Node = Target.Last);
+         pragma Assert (Vet (Before), "bad Before cursor in Splice");
       end if;
 
       if Position.Node = null then
-         raise Constraint_Error;
+         raise Constraint_Error with "Position cursor has no element";
       end if;
 
-      if Position.Container /= List_Access'(Target'Unchecked_Access) then
-         raise Program_Error;
+      if Position.Node.Element = null then
+         raise Program_Error with "Position cursor has no element";
       end if;
 
-      pragma Assert (Target.Length >= 1);
-      pragma Assert (Target.First.Prev = null);
-      pragma Assert (Target.Last.Next = null);
+      if Position.Container /= Container'Unrestricted_Access then
+         raise Program_Error with
+           "Position cursor designates wrong container";
+      end if;
 
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Target.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Target.Last);
+      pragma Assert (Vet (Position), "bad Position cursor in Splice");
 
       if Position.Node = Before.Node
         or else Position.Node.Next = Before.Node
@@ -1525,59 +1757,60 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          return;
       end if;
 
-      pragma Assert (Target.Length >= 2);
+      pragma Assert (Container.Length >= 2);
 
-      if Target.Busy > 0 then
-         raise Program_Error;
+      if Container.Busy > 0 then
+         raise Program_Error with
+           "attempt to tamper with cursors (list is busy)";
       end if;
 
       if Before.Node = null then
-         pragma Assert (Position.Node /= Target.Last);
+         pragma Assert (Position.Node /= Container.Last);
 
-         if Position.Node = Target.First then
-            Target.First := Position.Node.Next;
-            Target.First.Prev := null;
+         if Position.Node = Container.First then
+            Container.First := Position.Node.Next;
+            Container.First.Prev := null;
          else
             Position.Node.Prev.Next := Position.Node.Next;
             Position.Node.Next.Prev := Position.Node.Prev;
          end if;
 
-         Target.Last.Next := Position.Node;
-         Position.Node.Prev := Target.Last;
+         Container.Last.Next := Position.Node;
+         Position.Node.Prev := Container.Last;
 
-         Target.Last := Position.Node;
-         Target.Last.Next := null;
+         Container.Last := Position.Node;
+         Container.Last.Next := null;
 
          return;
       end if;
 
-      if Before.Node = Target.First then
-         pragma Assert (Position.Node /= Target.First);
+      if Before.Node = Container.First then
+         pragma Assert (Position.Node /= Container.First);
 
-         if Position.Node = Target.Last then
-            Target.Last := Position.Node.Prev;
-            Target.Last.Next := null;
+         if Position.Node = Container.Last then
+            Container.Last := Position.Node.Prev;
+            Container.Last.Next := null;
          else
             Position.Node.Prev.Next := Position.Node.Next;
             Position.Node.Next.Prev := Position.Node.Prev;
          end if;
 
-         Target.First.Prev := Position.Node;
-         Position.Node.Next := Target.First;
+         Container.First.Prev := Position.Node;
+         Position.Node.Next := Container.First;
 
-         Target.First := Position.Node;
-         Target.First.Prev := null;
+         Container.First := Position.Node;
+         Container.First.Prev := null;
 
          return;
       end if;
 
-      if Position.Node = Target.First then
-         Target.First := Position.Node.Next;
-         Target.First.Prev := null;
+      if Position.Node = Container.First then
+         Container.First := Position.Node.Next;
+         Container.First.Prev := null;
 
-      elsif Position.Node = Target.Last then
-         Target.Last := Position.Node.Prev;
-         Target.Last.Next := null;
+      elsif Position.Node = Container.Last then
+         Container.Last := Position.Node.Prev;
+         Container.Last.Next := null;
 
       else
          Position.Node.Prev.Next := Position.Node.Next;
@@ -1590,8 +1823,8 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       Before.Node.Prev := Position.Node;
       Position.Node.Next := Before.Node;
 
-      pragma Assert (Target.First.Prev = null);
-      pragma Assert (Target.Last.Next = null);
+      pragma Assert (Container.First.Prev = null);
+      pragma Assert (Container.Last.Next = null);
    end Splice;
 
    procedure Splice
@@ -1606,66 +1839,62 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          return;
       end if;
 
-      if Before.Node /= null then
-         if Before.Container /= List_Access'(Target'Unchecked_Access) then
-            raise Program_Error;
+      if Before.Container /= null then
+         if Before.Container /= Target'Unrestricted_Access then
+            raise Program_Error with
+              "Before cursor designates wrong container";
          end if;
 
-         pragma Assert (Target.Length >= 1);
-         pragma Assert (Target.First.Prev = null);
-         pragma Assert (Target.Last.Next = null);
+         if Before.Node = null
+           or else Before.Node.Element = null
+         then
+            raise Program_Error with
+              "Before cursor has no element";
+         end if;
 
-         pragma Assert (Before.Node.Element /= null);
-         pragma Assert (Before.Node.Prev = null
-                          or else Before.Node.Prev.Next = Before.Node);
-         pragma Assert (Before.Node.Next = null
-                          or else Before.Node.Next.Prev = Before.Node);
-         pragma Assert (Before.Node.Prev /= null
-                          or else Before.Node = Target.First);
-         pragma Assert (Before.Node.Next /= null
-                          or else Before.Node = Target.Last);
+         pragma Assert (Vet (Before), "bad Before cursor in Splice");
       end if;
 
       if Position.Node = null then
-         raise Constraint_Error;
+         raise Constraint_Error with "Position cursor has no element";
       end if;
 
-      if Position.Container /= List_Access'(Source'Unchecked_Access) then
-         raise Program_Error;
+      if Position.Node.Element = null then
+         raise Program_Error with
+           "Position cursor has no element";
       end if;
 
-      pragma Assert (Source.Length >= 1);
-      pragma Assert (Source.First.Prev = null);
-      pragma Assert (Source.Last.Next = null);
+      if Position.Container /= Source'Unrestricted_Access then
+         raise Program_Error with
+           "Position cursor designates wrong container";
+      end if;
 
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Source.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Source.Last);
+      pragma Assert (Vet (Position), "bad Position cursor in Splice");
 
       if Target.Length = Count_Type'Last then
-         raise Constraint_Error;
+         raise Constraint_Error with "Target is full";
       end if;
 
-      if Target.Busy > 0
-        or else Source.Busy > 0
-      then
-         raise Program_Error;
+      if Target.Busy > 0 then
+         raise Program_Error with
+           "attempt to tamper with cursors of Target (list is busy)";
+      end if;
+
+      if Source.Busy > 0 then
+         raise Program_Error with
+           "attempt to tamper with cursors of Source (list is busy)";
       end if;
 
       if Position.Node = Source.First then
          Source.First := Position.Node.Next;
-         Source.First.Prev := null;
 
          if Position.Node = Source.Last then
             pragma Assert (Source.First = null);
             pragma Assert (Source.Length = 1);
             Source.Last := null;
+
+         else
+            Source.First.Prev := null;
          end if;
 
       elsif Position.Node = Source.Last then
@@ -1725,62 +1954,45 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
    -- Swap --
    ----------
 
-   procedure Swap (I, J : Cursor) is
+   procedure Swap
+     (Container : in out List;
+      I, J      : Cursor)
+   is
    begin
-      if I.Container = null
-        or else J.Container = null
-      then
-         raise Constraint_Error;
+      if I.Node = null then
+         raise Constraint_Error with "I cursor has no element";
       end if;
 
-      if I.Container /= J.Container then
-         raise Program_Error;
+      if J.Node = null then
+         raise Constraint_Error with "J cursor has no element";
       end if;
 
-      declare
-         C : List renames I.Container.all;
-      begin
-         pragma Assert (C.Length > 0);
-         pragma Assert (C.First.Prev = null);
-         pragma Assert (C.Last.Next = null);
-
-         pragma Assert (I.Node /= null);
-         pragma Assert (I.Node.Element /= null);
-         pragma Assert (I.Node.Prev = null
-                          or else I.Node.Prev.Next = I.Node);
-         pragma Assert (I.Node.Next = null
-                          or else I.Node.Next.Prev = I.Node);
-         pragma Assert (I.Node.Prev /= null
-                          or else I.Node = C.First);
-         pragma Assert (I.Node.Next /= null
-                          or else I.Node = C.Last);
-
-         if I.Node = J.Node then
-            return;
-         end if;
+      if I.Container /= Container'Unchecked_Access then
+         raise Program_Error with "I cursor designates wrong container";
+      end if;
 
-         pragma Assert (C.Length > 1);
-         pragma Assert (J.Node /= null);
-         pragma Assert (J.Node.Element /= null);
-         pragma Assert (J.Node.Prev = null
-                          or else J.Node.Prev.Next = J.Node);
-         pragma Assert (J.Node.Next = null
-                          or else J.Node.Next.Prev = J.Node);
-         pragma Assert (J.Node.Prev /= null
-                          or else J.Node = C.First);
-         pragma Assert (J.Node.Next /= null
-                          or else J.Node = C.Last);
-
-         if C.Lock > 0 then
-            raise Program_Error;
-         end if;
+      if J.Container /= Container'Unchecked_Access then
+         raise Program_Error with "J cursor designates wrong container";
+      end if;
 
-         declare
-            EI_Copy : constant Element_Access := I.Node.Element;
-         begin
-            I.Node.Element := J.Node.Element;
-            J.Node.Element := EI_Copy;
-         end;
+      if I.Node = J.Node then
+         return;
+      end if;
+
+      if Container.Lock > 0 then
+         raise Program_Error with
+           "attempt to tamper with elements (list is locked)";
+      end if;
+
+      pragma Assert (Vet (I), "bad I cursor in Swap");
+      pragma Assert (Vet (J), "bad J cursor in Swap");
+
+      declare
+         EI_Copy : constant Element_Access := I.Node.Element;
+
+      begin
+         I.Node.Element := J.Node.Element;
+         J.Node.Element := EI_Copy;
       end;
    end Swap;
 
@@ -1793,55 +2005,34 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
       I, J      : Cursor)
    is
    begin
-      if I.Container = null
-        or else J.Container = null
-      then
-         raise Constraint_Error;
+      if I.Node = null then
+         raise Constraint_Error with "I cursor has no element";
       end if;
 
-      if I.Container /= List_Access'(Container'Unchecked_Access) then
-         raise Program_Error;
+      if J.Node = null then
+         raise Constraint_Error with "J cursor has no element";
       end if;
 
-      if J.Container /= I.Container then
-         raise Program_Error;
+      if I.Container /= Container'Unrestricted_Access then
+         raise Program_Error with "I cursor designates wrong container";
       end if;
 
-      pragma Assert (Container.Length >= 1);
-      pragma Assert (Container.First.Prev = null);
-      pragma Assert (Container.Last.Next = null);
-
-      pragma Assert (I.Node /= null);
-      pragma Assert (I.Node.Element /= null);
-      pragma Assert (I.Node.Prev = null
-                       or else I.Node.Prev.Next = I.Node);
-      pragma Assert (I.Node.Next = null
-                       or else I.Node.Next.Prev = I.Node);
-      pragma Assert (I.Node.Prev /= null
-                       or else I.Node = Container.First);
-      pragma Assert (I.Node.Next /= null
-                       or else I.Node = Container.Last);
+      if J.Container /= Container'Unrestricted_Access then
+         raise Program_Error with "J cursor designates wrong container";
+      end if;
 
       if I.Node = J.Node then
          return;
       end if;
 
-      pragma Assert (Container.Length >= 2);
-      pragma Assert (J.Node /= null);
-      pragma Assert (J.Node.Element /= null);
-      pragma Assert (J.Node.Prev = null
-                       or else J.Node.Prev.Next = J.Node);
-      pragma Assert (J.Node.Next = null
-                       or else J.Node.Next.Prev = J.Node);
-      pragma Assert (J.Node.Prev /= null
-                       or else J.Node = Container.First);
-      pragma Assert (J.Node.Next /= null
-                       or else J.Node = Container.Last);
-
       if Container.Busy > 0 then
-         raise Program_Error;
+         raise Program_Error with
+           "attempt to tamper with cursors (list is busy)";
       end if;
 
+      pragma Assert (Vet (I), "bad I cursor in Swap_Links");
+      pragma Assert (Vet (J), "bad J cursor in Swap_Links");
+
       declare
          I_Next : constant Cursor := Next (I);
 
@@ -1852,6 +2043,7 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
          else
             declare
                J_Next : constant Cursor := Next (J);
+
             begin
                if J_Next = I then
                   Splice (Container, Before => J, Position => I);
@@ -1875,63 +2067,244 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
    --------------------
 
    procedure Update_Element
-     (Position : Cursor;
-      Process  : not null access procedure (Element : in out Element_Type))
+     (Container : in out List;
+      Position  : Cursor;
+      Process   : not null access procedure (Element : in out Element_Type))
    is
-      pragma Assert (Position.Container /= null);
-      pragma Assert (Position.Container.Length > 0);
-      pragma Assert (Position.Container.First.Prev = null);
-      pragma Assert (Position.Container.Last.Next = null);
-
-      pragma Assert (Position.Node /= null);
-      pragma Assert (Position.Node.Element /= null);
-      pragma Assert (Position.Node.Prev = null
-                       or else Position.Node.Prev.Next = Position.Node);
-      pragma Assert (Position.Node.Next = null
-                       or else Position.Node.Next.Prev = Position.Node);
-      pragma Assert (Position.Node.Prev /= null
-                       or else Position.Node = Position.Container.First);
-      pragma Assert (Position.Node.Next /= null
-                       or else Position.Node = Position.Container.Last);
-
-      E : Element_Type renames Position.Node.Element.all;
-
-      C : List renames Position.Container.all'Unrestricted_Access.all;
-      B : Natural renames C.Busy;
-      L : Natural renames C.Lock;
-
    begin
-      B := B + 1;
-      L := L + 1;
+      if Position.Node = null then
+         raise Constraint_Error with "Position cursor has no element";
+      end if;
+
+      if Position.Node.Element = null then
+         raise Program_Error with
+           "Position cursor has no element";
+      end if;
+
+      if Position.Container /= Container'Unchecked_Access then
+         raise Program_Error with
+           "Position cursor designates wrong container";
+      end if;
+
+      pragma Assert (Vet (Position), "bad cursor in Update_Element");
+
+      declare
+         B : Natural renames Container.Busy;
+         L : Natural renames Container.Lock;
 
       begin
-         Process (E);
-      exception
-         when others =>
-            L := L - 1;
-            B := B - 1;
-            raise;
-      end;
+         B := B + 1;
+         L := L + 1;
 
-      L := L - 1;
-      B := B - 1;
+         begin
+            Process (Position.Node.Element.all);
+         exception
+            when others =>
+               L := L - 1;
+               B := B - 1;
+               raise;
+         end;
+
+         L := L - 1;
+         B := B - 1;
+      end;
    end Update_Element;
 
+   ---------
+   -- Vet --
+   ---------
+
+   function Vet (Position : Cursor) return Boolean is
+   begin
+      if Position.Node = null then
+         return Position.Container = null;
+      end if;
+
+      if Position.Container = null then
+         return False;
+      end if;
+
+      --  An invariant of a node is that its Previous and Next components can
+      --  be null, or designate a different node. Also, its element access
+      --  value must be non-null. Operation Free sets the node access value
+      --  components of the node to designate the node itself, and the element
+      --  access value to null, before actually deallocating the node, thus
+      --  deliberately violating the node invariant. This gives us a simple way
+      --  to detect a dangling reference to a node.
+
+      if Position.Node.Next = Position.Node then
+         return False;
+      end if;
+
+      if Position.Node.Prev = Position.Node then
+         return False;
+      end if;
+
+      if Position.Node.Element = null then
+         return False;
+      end if;
+
+      --  In practice the tests above will detect most instances of a dangling
+      --  reference. If we get here, it means that the invariants of the
+      --  designated node are satisfied (they at least appear to be satisfied),
+      --  so we perform some more tests, to determine whether invariants of the
+      --  designated list are satisfied too.
+
+      declare
+         L : List renames Position.Container.all;
+
+      begin
+         if L.Length = 0 then
+            return False;
+         end if;
+
+         if L.First = null then
+            return False;
+         end if;
+
+         if L.Last = null then
+            return False;
+         end if;
+
+         if L.First.Prev /= null then
+            return False;
+         end if;
+
+         if L.Last.Next /= null then
+            return False;
+         end if;
+
+         if Position.Node.Prev = null and then Position.Node /= L.First then
+            return False;
+         end if;
+
+         if Position.Node.Next = null and then Position.Node /= L.Last then
+            return False;
+         end if;
+
+         if L.Length = 1 then
+            return L.First = L.Last;
+         end if;
+
+         if L.First = L.Last then
+            return False;
+         end if;
+
+         if L.First.Next = null then
+            return False;
+         end if;
+
+         if L.Last.Prev = null then
+            return False;
+         end if;
+
+         if L.First.Next.Prev /= L.First then
+            return False;
+         end if;
+
+         if L.Last.Prev.Next /= L.Last then
+            return False;
+         end if;
+
+         if L.Length = 2 then
+            if L.First.Next /= L.Last then
+               return False;
+            end if;
+
+            if L.Last.Prev /= L.First then
+               return False;
+            end if;
+
+            return True;
+         end if;
+
+         if L.First.Next = L.Last then
+            return False;
+         end if;
+
+         if L.Last.Prev = L.First then
+            return False;
+         end if;
+
+         if Position.Node = L.First then
+            return True;
+         end if;
+
+         if Position.Node = L.Last then
+            return True;
+         end if;
+
+         if Position.Node.Next = null then
+            return False;
+         end if;
+
+         if Position.Node.Prev = null then
+            return False;
+         end if;
+
+         if Position.Node.Next.Prev /= Position.Node then
+            return False;
+         end if;
+
+         if Position.Node.Prev.Next /= Position.Node then
+            return False;
+         end if;
+
+         if L.Length = 3 then
+            if L.First.Next /= Position.Node then
+               return False;
+            end if;
+
+            if L.Last.Prev /= Position.Node then
+               return False;
+            end if;
+         end if;
+
+         return True;
+      end;
+   end Vet;
+
    -----------
    -- Write --
    -----------
 
    procedure Write
-     (Stream : access Root_Stream_Type'Class;
+     (Stream : not null access Root_Stream_Type'Class;
       Item   : List)
    is
       Node : Node_Access := Item.First;
+
    begin
       Count_Type'Base'Write (Stream, Item.Length);
+
       while Node /= null loop
-         Element_Type'Output (Stream, Node.Element.all);  --  X.all
+         Element_Type'Output (Stream, Node.Element.all);
          Node := Node.Next;
       end loop;
    end Write;
 
+   procedure Write
+     (Stream : not null access Root_Stream_Type'Class;
+      Item   : Cursor)
+   is
+   begin
+      raise Program_Error with "attempt to stream list cursor";
+   end Write;
+
+   procedure Write
+     (Stream : not null access Root_Stream_Type'Class;
+      Item   : Reference_Type)
+   is
+   begin
+      raise Program_Error with "attempt to stream reference";
+   end Write;
+
+   procedure Write
+     (Stream : not null access Root_Stream_Type'Class;
+      Item   : Constant_Reference_Type)
+   is
+   begin
+      raise Program_Error with "attempt to stream reference";
+   end Write;
+
 end Ada.Containers.Indefinite_Doubly_Linked_Lists;