Version 1.1 of ai05s/ai05-0298-1.txt

Unformatted version of ai05s/ai05-0298-1.txt version 1.1
Other versions for file ai05s/ai05-0298-1.txt

!standard 13.11.4(0)          11-05-16 AI05-0298-1/01
!standard 13.11.6(0)
!standard A.4.9(5/2)
!standard A.4.9(2/2)
!standard A.4.9(7/2)
!standard A.4.9(10/2)
!standard A.4.9(11.2/3)
!standard A.4.9(11.5/3)
!standard A.4.9(11.7/3)
!standard A.4.9(11.10/3)
!standard A.4.10(2/3)
!standard A.4.10(5/3)
!standard A.4.10(7/3)
!standard A.4.10(10/3)
!standard A.4.10(13/3)
!standard A.4.10(16/3)
!standard A.4.10(18/3)
!standard A.4.10(21/3)
!standard A.10.8(26)
!class presentation 12-05-16
!status Amendment 2012 11-05-16
!status work item 12-05-16
!status received 12-04-06
!priority Low
!difficulty Easy
!qualifier Omission
!subject Last-minute presentation issues in the Standard
!summary
This AI corrects minor errors in the Standard.
1) Use fully qualified names in Pure and Preelaborare pragmas in A.4.9 and
A.4.10.
2) Remove pragma Pure on library-level renames in A.4.9 and A.4.10.
3) Correct the example in A.10.8(25-27).
4) Correct the example in 13.11.6.
[Editor's note: There are also corrections to AARM 3.10.2(22.rr), A.18.2(254.a/2), A.18.3(156.a/2), A.18.4(82.a/2), A.18.7(103.a/2), A.18.10(230.a/3), and A.18.18(72.a/3) which are not detailed here, but details can be found in the !appendix.]
!question
1) In A.4.9 and A.4.10, there are a number of library subprogram declarations that are followed by Pure or Preelaborate pragmas, e.g.:
with Ada.Containers; function Ada.Strings.Hash (Key : String) return Containers.Hash_Type; pragma Pure(Hash);
The Pure pragma is incorrect, however; it should be
pragma Pure(Ada.Strings.Hash);
since this is a pragma that occurs at the place of a compilation unit, and 10.1.6(5) says that the root libary_item (Ada in this case) is directly visible, implying that the subprogram itself and other ancestors are not. (This only applies to the language-defined subprograms, not to packages.)
Fix this? (Yes.)
2) There are four cases where the Standard defines a subprogram that is a child of Ada.Strings.Fixed that renames the corresponding subprogram in Ada.Strings: Hash, Hash_Case_Insensitive, Equal_Case_Insensitive, Less_Case_Insensitive. In all of those cases, the declarer is followed by a Pure pragma in the standard. However, a pragma Pure is not allowed on a library-level renames (the category is the same as the renamed unit). Fix this? (Yes.)
3) The example A.10.8(26-27) includes an instance for Small_Int, uses the values -126 and 126, and has a comment that says that 'Width is 4.
But Small_Int, is defined in 3.2.2(15/2) and 3.5.4(35) as -10 .. 10, for which 'Width is 3 and the values -126 and 126 would raise Constraint_Error. Should the example be corrected? (Yes.)
4) The example in 13.11.6 does not compile. The errors that prevent that should be fixed.
!recommendation
(See summary.)
!wording
1) In A.4.9(2/2), A.4.9(11.2/3), A.4.9(11.7/3), A.4.9(11.10/3), A.4.10(2/3), A.4.10(7/3), A.4.10(10/3), A.4.10(13/3), A.4.10(18/3), and A.4.10(21/3), put the fully qualified name of the subprogram into the pragma Pure or Preelaborate. [Editor's note: The paragraph numbers were wrong in A.4.9; these have been corrected and the correct numbers used above.]
2) In A.4.9(5/2), A.4.9(11.5/3), A.4.10(5/3), and A.4.10(16/3) remove the pragma Pure.
3) Replace A.10.8(26) with:
subtype Byte_Int is -127 .. 127; package Int_IO is new Integer_IO(Byte_Int); use Int_IO; -- default format used at instantiation, -- Default_Width = 4, Default_Base = 10
4) In 13.11.4(13/3), the Pool parameter should have mode "in out".
In 13.11.4(16/3), modify "return {Storage_Elements.}Storage_Count".
In 13.11.6(12/3), delete "aliased".
In 13.11.6(16/3) and (25/3), the Pool parameter should have mode "in out".
Add before 13.11.6(21/3): "use type Subpool_Handle;"
In each of 13.11.6(21/3), 13.11.6(23/3), and 13.11.6(24/3), in the call of Set_Pool_of_Subpool, remove "'Unchecked_Access" from the Pool parameter.
In 13.11.6(34/3), modify:
{Pool.Markers(Pool.Current_Pool)}[Result].Start := Pool.Next_Allocation;
In 13.11.6(24/3), modify:
Pool.Next_Allocation := Pool.Markers(Pool.Current_Pool){.Start};
!discussion
1) This bug clearly is covered by the Dewar rule (the Standard never says anything obviously silly); in this case, it's clear that the language-defined subprograms and associated pragmas are intended to be legal (why would the Standard want to define illegal pragmas for language-defined subprograms?)
2) The renames are Pure whether or not the (illegal) pragmas are given, so removing these pragmas does not change the meaning of the language. Note that unit categories is one of many properties that are not changed (and thus cannot be specified) for a renaming.
3) This is an example, so the change is non-normative (and correct is better than wrong).
4) The majority of the changes are in the example 13.11.6, so those changes are non-normative (and correct is better than wrong).
There are two changes in 13.11.4; in 13.11.4(16/3), the return type name is written differently than in the parent unit Storage_Pools. This difference is unnecessary and potentially confusing (although legal); in any case there is no significant difference caused by this change.
The other change is to the mode of the Pool parameter to Default_Subpool_for_Pool (13.11.4(13/3)). This parameter needs to be "in out" in order for the example to work as intended. We could have restructured the example significantly in order to avoid the error, but that complicates the implementation of the pool for little benefit. The primary use of this routine is in implicit calls from allocators, and for those the mode does not matter: as a pool is a tagged type, the parameter is always passed by reference, and the pool associated with an access type has to be a variable (by 13.11(15)), so any mode is legal. Moreover, that rule makes constant Storage_Pool objects useless for their primary purpose (as they cannot be specified for an access type), so they should be rare.
Thus we changed the mode of Default_Subpool_for_Pool to "in out".
!corrigendum 13.11.4(0)
Insert new clause:
This is just a placeholder; the real change is found in the conflict file.
!corrigendum 13.11.6(0)
Insert new clause:
This is just a placeholder; the real change is found in the conflict file.
!corrigendum A.4.9(2/2)
Replace the paragraph:
with Ada.Containers; function Ada.Strings.Hash (Key : String) return Containers.Hash_Type; pragma Pure(Hash);
by:
with Ada.Containers; function Ada.Strings.Hash (Key : String) return Containers.Hash_Type; pragma Pure(Ada.Strings.Hash);
!corrigendum A.4.9(5/2)
Replace the paragraph:
with Ada.Containers, Ada.Strings.Hash; function Ada.Strings.Fixed.Hash (Key : String) return Containers.Hash_Type renames Ada.Strings.Hash; pragma Pure(Hash);
by:
with Ada.Containers, Ada.Strings.Hash; function Ada.Strings.Fixed.Hash (Key : String) return Containers.Hash_Type renames Ada.Strings.Hash;
!corrigendum A.4.9(7/2)
Replace the paragraph:
with Ada.Containers; generic with package Bounded is new Ada.Strings.Bounded.Generic_Bounded_Length (<>); function Ada.Strings.Bounded.Hash (Key : Bounded.Bounded_String) return Containers.Hash_Type; pragma Preelaborate(Hash);
by:
with Ada.Containers; generic with package Bounded is new Ada.Strings.Bounded.Generic_Bounded_Length (<>); function Ada.Strings.Bounded.Hash (Key : Bounded.Bounded_String) return Containers.Hash_Type; pragma Preelaborate(Ada.Strings.Bounded.Hash);
!corrigendum A.4.9(10/2)
Replace the paragraph:
with Ada.Containers; function Ada.Strings.Unbounded.Hash (Key : Unbounded_String) return Containers.Hash_Type; pragma Preelaborate(Hash);
by:
with Ada.Containers; function Ada.Strings.Unbounded.Hash (Key : Unbounded_String) return Containers.Hash_Type; pragma Preelaborate(Ada.Strings.Unbounded.Hash);
!corrigendum A.4.9(11/2)
Replace the paragraph:
Strings.Unbounded.Hash is equivalent to the function call Strings.Hash (To_String (Key));
by:
Equivalent to Strings.Hash (To_String (Key));
The library function Strings.Hash_Case_Insensitive has the following declaration:
with Ada.Containers; function Ada.Strings.Hash_Case_Insensitive (Key : String) return Containers.Hash_Type; pragma Pure(Ada.Strings.Hash_Case_Insensitive);
Returns an implementation-defined value which is a function of the value of Key, converted to lower case. If A and B are strings such that Strings.Equal_Case_Insensitive (A, B) (see A.4.10) is True, then Hash_Case_Insensitive(A) equals Hash_Case_Insensitive(B).
The library function Strings.Fixed.Hash_Case_Insensitive has the following declaration:
with Ada.Containers, Ada.Strings.Hash_Case_Insensitive; function Ada.Strings.Fixed.Hash_Case_Insensitive (Key : String) return Containers.Hash_Type renames Ada.Strings.Hash_Case_Insensitive;
The generic library function Strings.Bounded.Hash_Case_Insensitive has the following declaration:
with Ada.Containers; generic with package Bounded is new Ada.Strings.Bounded.Generic_Bounded_Length (<>); function Ada.Strings.Bounded.Hash_Case_Insensitive (Key : Bounded.Bounded_String) return Containers.Hash_Type; pragma Preelaborate(Ada.Strings.Bounded.Hash_Case_Insensitive);
Equivalent to Strings.Hash_Case_Insensitive (Bounded.To_String (Key));
The library function Strings.Unbounded.Hash_Case_Insensitive has the following declaration:
with Ada.Containers; function Ada.Strings.Unbounded.Hash_Case_Insensitive (Key : Unbounded_String) return Containers.Hash_Type; pragma Preelaborate(Ada.Strings.Unbounded.Hash_Case_Insensitive);
Equivalent to Strings.Hash_Case_Insensitive (To_String (Key));
!corrigendum A.4.10(0)
Insert new clause:
This is just a placeholder; the real change is found in the conflict file.
!corrigendum A.10.8(26)
Replace the paragraph:
package
Int_IO is new Integer_IO(Small_Int); use Int_IO; -- default format used at instantiation, -- Default_Width = 4, Default_Base = 10>
by:
subtype Byte_Int is -127 .. 127; package Int_IO is new Integer_IO(Byte_Int); use Int_IO; -- default format used at instantiation, -- Default_Width = 4, Default_Base = 10
!ACATS test
None needed.
!appendix

From: Adam Beneschan
Sent: Friday, April 6, 2012  1:12 PM

!topic Incorrect Pure/Preelaborate pragmas on library subprograms
!reference A.4.9, A.4.10
!from Adam Beneschan xx-xx-xx
!discussion

In A.4.9 and A.4.10, there are a number of library subprogram declarations that
are followed by Pure or Preelaborate pragmas, e.g.:

      with Ada.Containers;
      function Ada.Strings.Hash (Key : String) return Containers.Hash_Type;
      pragma Pure(Hash);

The Pure pragma is incorrect, however; it should be

      pragma Pure(Ada.Strings.Hash);

since this is a pragma that occurs at the place of a compilation unit, and
10.1.6(5) says that the root libary_item (Ada in this case) is directly visible,
implying that the subprogram itself and other ancestors are not.  (This only
applies to the language-defined subprograms, not to packages.)

****************************************************************

From: Adam Beneschan
Sent: Friday, April 6, 2012  1:26 PM

!topic Incorrect Pure on library-level renaming subprograms
!reference A.4.9(5/2), A.4.9(14.2/3), A.4.10(5/3), A.4.10(16/3)
!from Adam Beneschan 12-04-06
!discussion

There are four cases where the Standard defines a subprogram that is a child of
Ada.Strings.Fixed that renames the corresponding subprogram in Ada.Strings:
Hash, Hash_Case_Insensitive, Equal_Case_Insensitive, Less_Case_Insensitive.  In
all of those cases, the declarer is followed by a Pure pragma in the standard,
e.g.:

    with Ada.Containers, Ada.Strings.Hash;
    function Ada.Strings.Fixed.Hash (Key : String) return Containers.Hash_Type
       renames Ada.Strings.Hash;
    pragma Pure(Hash);  -- should be Pure(Ada.Strings.Hash) according
                        -- to my previous note

I'm not sure it's legal to have a Pure pragma there.  Pure is a program unit
pragma, and 10.1.5(4) lists this as one of the places a program unit pragma may
appear:

  At the place of a compilation_unit, in which case the pragma shall
  immediately follow in the same compilation (except for other
  pragmas) a library_unit_declaration that is a
  subprogram_declaration, generic_subprogram_declaration, or
  generic_instantiation, ...

subprogram_renaming_declaration is not one of the syntactic categories listed as
something the pragma may follow; and the way the syntax is written, a
subprogram_renaming_declaration is not a subprogram_declaration.  (It may be
that subprogram_renaming_declaration should be added to the list in 10.1.5(4),
and maybe also package_renaming_declaration and generic_renaming_declaration.
But if not, the incorrect Pure pragmas should be removed from the Standard.)

****************************************************************

From: Randy Brukardt
Sent: Friday, April 6, 2012  4:41 PM

> !topic Incorrect Pure/Preelaborate pragmas on library subprograms
> !reference A.4.9, A.4.10 !from Adam Beneschan xx-xx-xx

Cool, it's "xx" month. I thought it was April! :-)

> !discussion
>
> In A.4.9 and A.4.10, there are a number of library subprogram
> declarations that are followed by Pure or Preelaborate pragmas, e.g.:
>
>       with Ada.Containers;
>       function Ada.Strings.Hash (Key : String) return Containers.Hash_Type;
>       pragma Pure(Hash);
>
> The Pure pragma is incorrect, however; it should be
>
>       pragma Pure(Ada.Strings.Hash);

This of course is the problem that comes from using pragmas for this. This would
be much better written as an aspect:

       function Ada.Strings.Hash (Key : String) return Containers.Hash_Type
           with Pure => True;

[or just "with Pure"]

and exactly how to describe the unit is not an issue (since you don't have to do
it).

But that's not the default in the Standard because "with Pure" was thought to be
ugly by some people. Grumble.

Anyway, we'll put this into an early Ada 2012 AI.

****************************************************************

From: Yuta Tomino
Sent: Friday, April 27, 2012  2:49 PM

!topic Storage Subpool Example has some errors
!reference Ada 2012 RM 13.11.6 (3/3)(21/3)(23/3)(24/3)(27/3)
!from Yuta Tomino 2012-04-27
!keywords
!discussion

13.11.6 Storage Subpool Example has some errors.
There are the points that I had to fix for compile, in below:

(3/3) Insert use type because operators of Subpool_Handle are required.

   {use type System.Storage_Pools.Subpools.Subpool_Handle;}

(21/3) Remove 'Unchecked_Access because 2nd parameter of Set_Pool_of_Subpool is
       not access but in out, defined in 13.11.4 (10/3)

      Subpools.Set_Pool_of_Subpool
         (Pool.Markers(1)'Unchecked_Access,
          Pool['Unchecked_Access]);
   end Initialize;

(23/3) Insert downcast to MR_Subpool because "Start" component is added
       in the derived type. And, in next line, same as (21/3)

      return Result : constant not null Subpool_Handle :=
        Pool.Markers(Pool.Current_Pool)'Unchecked_Access
      do
         {MR_Subpool (}Result{.all)}.Start := Pool.Next_Allocation;
         Subpools.Set_Pool_of_Subpool (Result, Pool['Unchecked_Access]);
      end return;
   end Create_Subpool;

(24/3) Insert {.Start}. And, same as (21/3)

      if Pool.Current_Pool /= 1 then
         Pool.Next_Allocation := Pool.Markers(Pool.Current_Pool){.Start};
         Pool.Current_Pool := Pool.Current_Pool - 1; -- Move to the previous subpool
      else -- Reinitialize the default subpool:
         Subpools.Set_Pool_of_Subpool
            (Pool.Markers(1)'Unchecked_Access,
             Pool['Unchecked_Access]);
       end if;
   end Deallocate_Subpool;

(27/3) Add +1 for right alignment because Next_Allocation is started from 1.

      -- Correct the alignment if necessary:
      Pool.Next_Allocation := Pool.Next_Allocation +
         (({1} - Pool.Next_Allocation) mod Alignment);

For reference, it's an output by gcc-4.7:

mr_pool.adb:9:15: expected type "System.Storage_Pools.Subpools.Root_Storage_Pool_With_Subpools'Class"
mr_pool.adb:9:15: found type access to "Mark_Release_Pool_Type" defined at line 9
mr_pool.adb:24:16: no selector "Start" for type "System.Storage_Pools.Subpools.Root_Subpool'Class"
mr_pool.adb:25:52: expected type "System.Storage_Pools.Subpools.Root_Storage_Pool_With_Subpools'Class"
mr_pool.adb:25:52: found type access to "Mark_Release_Pool_Type" defined at line 25
mr_pool.adb:33:18: operator for type "System.Storage_Pools.Subpools.Subpool_Handle" is not directly visible
mr_pool.adb:33:18: add with_clause and use_clause for "MR_Pool"
mr_pool.adb:37:38: expected type "System.Storage_Elements.Storage_Offset"
mr_pool.adb:37:38: found type "MR_Subpool" defined at mr_pool.ads:28
mr_pool.adb:43:18: expected type "System.Storage_Pools.Subpools.Root_Storage_Pool_With_Subpools'Class"
mr_pool.adb:43:18: found type access to "Mark_Release_Pool_Type" defined at line 43
mr_pool.adb:50:14: access-to-variable designates constant
mr_pool.adb:60:18: operator for type "System.Storage_Pools.Subpools.Subpool_Handle" is not directly visible
mr_pool.adb:60:18: add with_clause and use_clause for "MR_Pool"

****************************************************************

From: Pascal Pignard
Sent: Monday, May 7, 2012  3:29 PM

!topic Missing limited in example in 3.10.2?
!reference Ada 2012 draft 17 3.10.2
!from Pascal Pignard 12-05-07
!keywords limited
!discussion

Here is the draft 17 text:
3.10.2 Operations of Access Types
...
22.rr           package P is
                    type Int_Ptr is access all Integer;
                    type Rec(D: access Integer) is limited private;
                private
                    type Rec_Ptr is access all Rec;
                    function F(X: Rec_Ptr) return Boolean;
                    function G(X: access Rec) return Boolean;
                    type Rec(D: access Integer) is            -- missing limited?
                        record
                            C1: Int_Ptr := Int_Ptr(D); -- Illegal!
                            C2: Rec_Ptr := Rec'Access; -- Illegal!
                            C3: Boolean := F(Rec'Access); -- Illegal!
                            C4: Boolean := G(Rec'Access);
                        end record;
                end P;

Seems that "limited" should be added in private part for type "Rec"?
GNAT complains about: "current instance must be a limited type".

****************************************************************

From: Randy Brukardt
Sent: Monday, May 7, 2012  3:48 PM

...
> Here is the draft 17 text:
> 3.10.2 Operations of Access Types
> ...
> 22.rr           package P is
>                     type Int_Ptr is access all Integer;
>                     type Rec(D: access Integer) is limited private;
>                 private
>                     type Rec_Ptr is access all Rec;
>                     function F(X: Rec_Ptr) return Boolean;
>                     function G(X: access Rec) return Boolean;
>                     type Rec(D: access Integer) is
> -- missing limited?

No.

> Seems that "limited" should be added in private part for type "Rec"?
> GNAT complains about: "current instance must be a limited type".

This text is unchanged since the Ada 95 RM. Even so, I think you would be right
for Ada 95, but the rule in question was changed for Ada 2005 (3.7(10/3); the
Ada 2012 terminology change is irrelevant for this purpose). Only access
discriminants with defaults have to be on a limited type; without defaults (as
here) are allowed on any type.

So, if you ran GNAT in Ada 2005 or Ada 2012 mode, then GNAT is wrong; otherwise,
it is irrelevant, since the rules were changed.

****************************************************************

From: Adam Beneschan
Sent: Monday, May 7, 2012  4:55 PM

I think the problem is the use of Rec'Access in the default expression for C4,
not the access discriminant.  If I remove all four fields C1 through C4 (and
replace them with "null"), GNAT doesn't complain; but adding back C4 does lead
to the error Pascal described.  ICC's compiler has the same behavior, except
with <PLUG> a more explanatory error message</PLUG>.  (The issue is that 3.10(9)
says that the current instance of an immutably limited type is defined to be
aliased, but the current instance of other records is not, and therefore 'Access
isn't allowed in that case.)

****************************************************************

From: Steve Baird
Sent: Monday, May 7, 2012  5:14 PM

Agreed.
Note that this was not the rule in Ada95 when the example was written.

****************************************************************

From: Adam Beneschan
Sent: Monday, May 7, 2012  5:42 PM

My Ada 95 book (the original one, from December 1994) says it was, except that
there was no "immutably" limited concept.  But 3.10(9) still said "the current
instance of a limited type ... [is] defined to be aliased", and the rules have
always said that a view has to be aliased to apply 'Access.  So the declaration
of C4 would have been illegal even back then, even if the type didn't have an
access discriminant (which was itself illegal on a record type that didn't use
the word "limited").

****************************************************************

From: Steve Baird
Sent: Monday, May 7, 2012  5:48 PM

> So the declaration of C4 would have been illegal even back then, even
> if the type didn't have an access discriminant

You're right. I was somehow thinking that the type in the example had a limited
component, which would make it (in Ada2012 terminology) limited but not
immutably limited.

****************************************************************

From: Tucker Taft
Sent: Monday, May 7, 2012  4:14 PM

> This text is unchanged since the Ada 95 RM. Even so, I think you would
> be right for Ada 95, but the rule in question was changed for Ada 2005
> (3.7(10/3); the Ada 2012 terminology change is irrelevant for this purpose).
> Only access discriminants with defaults have to be on a limited type;
> without defaults (as here) are allowed on any type.

Access discriminants are allowed, but self-referential 'Access requires the
enclosing type be limited, I believe.

****************************************************************

From: Randy Brukardt
Sent: Monday, May 7, 2012  5:56 PM

> I think the problem is the use of Rec'Access in the default expression
> for C4, not the access discriminant.  If I remove all four fields C1
> through C4 (and replace them with "null"), GNAT doesn't complain; but
> adding back C4 does lead to the error Pascal described.  ICC's
> compiler has the same behavior, except with <PLUG> a more explanatory
> error message</PLUG>.  (The issue is that 3.10(9) says that the
> current instance of an immutably limited type is defined to be
> aliased, but the current instance of other records is not, and
> therefore 'Access isn't allowed in that case.)

Thanks, I think.

I was thrown off by the fact that this code was written for Ada 95, but it
appears to be illegal Ada 95 (an access discriminant is never allowed on a
non-limited type in Ada 95, and this type is not limited). Plus he didn't say
what was rejected with that message, so I never looked at the uses of 'Access, I
just assumed the message was bogus.

So it looks like the type should be "limited record", and it should have been
that for any version of Ada (even Ada 95).

****************************************************************

From: Tucker Taft
Sent: Monday, May 7, 2012  8:02 PM

>> (The issue is that 3.10(9) says that
>> the current instance of an immutably limited type is defined to be
>> aliased, but the current instance of other records is not, and
>> therefore 'Access isn't allowed in that case.)
>
> Agreed.
> Note that this was not the rule in Ada95 when the example was written.

Are you sure? I think Ada95 only allowed 'Access when inside a limited type as
well.

****************************************************************

From: Randy Brukardt
Sent: Monday, May 7, 2012  8:21 PM

Steve is thinking in his typical Bairdian way: Ada 95 required "limited", but
Ada 2005 requires "immutably limited". Of course, this example is still wrong
for Ada 95, because it isn't limited at all, but if a limited component was
added (say of "File_Type"), then it would have been legal. (But we know this
rule was murky at best, which is why we changed it.)

****************************************************************

From: Pascal Pignard
Sent: Tuesday, May 8, 2012  3:32 PM

If needed, here is the full GNAT report:
(GNAT GPL 2011 on Mac OS 10.6)

bash-3.2$ gnatmake -gnatlf essai_p2.ads gcc -c -gnatlf essai_p2.ads GNAT GPL 2011 (20110419) Copyright 1992-2011, Free Software Foundation, Inc.
Compiling: essai_p2.ads (source file time stamp: 2012-05-08 12:49:37)
    1.    package Essai_P2 is
    2.       type Int_Ptr is access all Integer;
    3.       type Rec(D: access Integer) is limited private;
    4.    private
    5.       type Rec_Ptr is access all Rec;
    6.       function F(X: Rec_Ptr) return Boolean;
    7.       function G(X: access Rec) return Boolean;
    8.       type Rec(D: access Integer) is
    9.          record
   10.             --C1: Int_Ptr := Int_Ptr(D); -- Illegal!
   11.             --C2: Rec_Ptr := Rec'Access; -- Illegal!
   12.             --C3: Boolean := F(Rec'Access); -- Illegal!
   13.             C4: Boolean := G(Rec'Access);
                                     |
> > > current instance must be a limited type
   14.          end record;
   15.    end ;
15 lines: 1 error
gnatmake: "essai_p2.ads" compilation error

At line 13, Rec is pointed by error pointer.

Changing GNAT option to Ada 95, 2005 or 2012 gives the same.

****************************************************************

From: Adam Beneschan
Sent: Tuesday, May 8, 2012  12:39 PM

!topic Implementation note on Ada.Containers.Vectors is no longer true
!reference AARM A.18.2(254.a/2)
!from Adam Beneschan 12-05-08
!discussion

The AARM says this, in the description of Ada.Containers.Vectors:

254/2 The execution of an assignment_statement for a vector shall have the
effect of copying the elements from the source vector object to the target
vector object.

    254.a/2 Implementation Note: An assignment of a Vector is a "deep" copy;
          that is the elements are copied as well as the data structures. We
          say "effect of" in order to allow the implementation to avoid
          copying elements immediately if it wishes. For instance, an
          implementation that avoided copying until one of the containers is
          modified would be allowed.

However, I believe that the last statement is no longer true, now that Reference
and Constant_Reference have been added.  Consider:

   package Rec_Vectors is new Ada.Containers.Vectors (Positive, Rec);

   V1 : aliased Rec_Vectors.Vector;
   V2 : aliased Rec_Vectors.Vector;

   Ref1 : Rec_Vectors.Constant_Reference_Type;
   Ref2 : Rec_Vectors.Constant_Reference_Type;

   ... code to set elements up in V1

   V2 := V1;

   Ref1 := Rec_Vectors.Constant_Reference (V1, 1);
   Ref2 := Rec_Vectors.Constant_Reference (V2, 1);

If the implementation avoided copying Rec objects until one of the containers is
modified, as suggested by 254.a, then after the two Constant_Reference calls,
Ref1.Element and Ref2.Element would have the same value.  Then, if element 1 is
later modified in one of the vectors, the Rec object of one of the elements
would have to be relocated, which means that at that point, either Ref1 or Ref2
is wrong.  (An implementation that went ahead and copied Rec objects as soon as
one of them were *referenced*, even by Constant_Reference, would probably be OK.
But I'd think that would defeat the purpose of avoiding the copy.  Maybe there's
a way to work things out so that a Rec object is copied when an Adjust on the
Constant_Reference_Type is performed...  But the last sentence of 254.a still
wouldn't be quite correct.)

****************************************************************

From: Randy Brukardt
Sent: Wednesday, May 16, 2012  11:25 PM

...
> The AARM says this, in the description of Ada.Containers.Vectors:
>
> 254/2 The execution of an assignment_statement for a vector shall have
> the effect of copying the elements from the source vector object to
> the target vector object.
>
>     254.a/2 Implementation Note: An assignment of a Vector is a "deep" copy;
>           that is the elements are copied as well as the data structures. We
>           say "effect of" in order to allow the implementation to avoid
>           copying elements immediately if it wishes. For instance, an
>           implementation that avoided copying until one of the containers is
>           modified would be allowed.
>
> However, I believe that the last statement is no longer true, now that
> Reference and Constant_Reference have been added.

Reference and Constant_Reference should change nothing, since they are
semantically equivalent to Update_Element and Query_Element, respectively. I can
believe that the statement was *never* really true, though.

> Consider:
>
>    package Rec_Vectors is new Ada.Containers.Vectors (Positive, Rec);
>
>    V1 : aliased Rec_Vectors.Vector;
>    V2 : aliased Rec_Vectors.Vector;
>
>    Ref1 : Rec_Vectors.Constant_Reference_Type;
>    Ref2 : Rec_Vectors.Constant_Reference_Type;
>
>    ... code to set elements up in V1
>
>    V2 := V1;
>
>    Ref1 := Rec_Vectors.Constant_Reference (V1, 1);
>    Ref2 := Rec_Vectors.Constant_Reference (V2, 1);
>
> If the implementation avoided copying Rec objects until one of the
> containers is modified, as suggested by 254.a, then after the two
> Constant_Reference calls, Ref1.Element and Ref2.Element would have the
> same value.  Then, if element 1 is later modified in one of the
> vectors, the Rec object of one of the elements would have to be
> relocated, which means that at that point, either Ref1 or Ref2 is
> wrong.  (An implementation that went ahead and copied Rec objects as
> soon as one of them were *referenced*, even by Constant_Reference,
> would probably be OK.  But I'd think that would defeat the purpose of
> avoiding the copy.  Maybe there's a way to work things out so that a
> Rec object is copied when an Adjust on the Constant_Reference_Type is
> performed...  But the last sentence of 254.a still wouldn't be quite
> correct.)

As I said, you can write an example of this problem using Query_Element, if Rec
is passed by reference (which it must be if it is tagged, and which is probably
is if it is composite):

     -- Assume Rec has a component C1 whose type is Natural.

     procedure Inc_C1 (Element : in out Rec) is
     begin
        Element.C1 := Element.C1 + 1;
     end Inc_C1;

     procedure Deal_with_V1 (Element : in Rec) is
         Val : Natural := Element.C1;
     begin
         Update_Element (V2, Inc_C1'access);
         if Val /= Element.C1 then raise Program_Error; end if;
     end Deal_with_V1;

     procedure Deal_with_V2 (Element : in Rec) is
         Val : Natural := Element.C1;
     begin
         Query_Element (V1, Deal_with_V1'access);
         if Val+1 /= Element.C1 then raise Program_Error; end if;
     end Deal_with_V1;

     V2 := V1;

     Query_Element (V2, Deal_with_V2'access); -- !!

If the copying of elements is delayed until V2 is modified, then the one of the
parameters to Deal_with_V1 or Deal_with_V2 is going to end pointing to the wrong
element (since they start out the same, but one of them must be copied when
Update_Element is called).

Of course, neither of these examples is very likely, but it's certainly true
that a language-defined container must be prepared for this problem. The main
point is that it is not new; (almost) nothing changed when Ada 2012 added
Constant_Reference and Reference.

This is the exact situation that the tampering checks are intended to prevent;
but they allow this case to increase usability (and because we assumed the
effect of a deep copy on assignment). (Note, however, that whether Deal_with_V2
works as expected here depends on the parameters passing mechanism, which
depends on the element type and is implementation-defined in some cases. So it
is not a good idea to depend on this unless the element type is always going to
be a tagged type; or in the reverse [assuming the parameter never changes], if
the element type is always scalar.)

A container implementation with delayed copying would have to copy any element
as soon as Query_Element or Constant_Reference is used on it. That would reduce
the value of the implementation technique (but it still could be worthwhile, so
long as function Element is used to read elements frequently). It also could
avoid the copying for Query_Element if it knew that the element type was
guaranteed to be passed by copy; this is the only difference caused by Ada 2012.
(Note that this is the reason that this technique works for
Ada.Strings.Unbounded: the element type is discrete.)

It probably was a mistake to suggest this possible implementation, but the
intent is unchanged: to specify as little as possible so that implementers can
use innovative implementations.

****************************************************************


Questions? Ask the ACAA Technical Agent