[Ada] Implement conventions Ada_Pass_By_Copy and Ada_Pass_By_Reference

Arnaud Charlet charlet@adacore.com
Wed Dec 21 13:43:00 GMT 2011


These conventions allow the programmer to control the parameter passing
method used in cases where it would normally be up to the implementation.
The convention is applied to the type, and then affects how parameters
with this type are passed. It is not allowed to specify Ada_Pass_By_Copy
for types for which the language requires pass by reference (for example,
limited types), and it is not allowed to specify Ada_Pass_By_Reference
for types for which the language requires pass by copy (for example
scalar types). Also if a parameter is marked as aliased, it is passed
by reference even if the convention is Pass_By_Copy (this situation
generates a warning, but is not considered to be an error).

The following test shows detection of errors (the output is compiled
with -gnatj60 -gnatld7):

     1. procedure pbycopref1 is
     2.    type R is tagged null record;
     3.    pragma Convention (Ada_Pass_By_Copy, R);
                              |
        >>> convention "Ada_Pass_By_Copy" not allowed for
            by-reference type

     4.    type X is new Integer;
     5.    pragma Convention (Ada_Pass_By_Reference, X);
                              |
        >>> convention "Ada_Pass_By_Reference" not allowed
            for by-copy type

     6.    procedure Q is begin null; end;
     7.    pragma Convention (Ada_Pass_By_Copy, Q);
                                                |
        >>> convention "Ada_Pass_By_Copy" only allowed for
            types

     8.    pragma Convention (Ada_Pass_By_Reference, Q);
                                                     |
        >>> convention "Ada_Pass_By_Reference" only allowed
            for types

     9. begin
    10.    null;
    11. end;

The following program compiles clean:

     1. with System; use System;
     2. with Text_IO; use Text_IO;
     3. procedure pbycopref2 is
     4.    type Typ1 is array (1 .. 100) of Integer;
     5.    pragma Convention (Ada_Pass_By_Copy, Typ1);
     6.    procedure Test_By_Copy (A, B : in out Typ1) is
     7.    begin
     8.       if A'Address = B'Address then
     9.          Put_Line ("Error, unexpected pass by reference");
    10.       else
    11.          Put_Line (A (1)'Img);
    12.          Put_Line (A (2)'Img);
    13.          Put_line ("OK");
    14.       end if;
    15.    end;
    16.
    17.    A1 : Typ1 := (others => 0);
    18.
    19.    type Typ2 is array (1 .. 32) of Boolean;
    20.    pragma Pack (Typ2);
    21.    pragma Convention (Ada_Pass_By_Reference, Typ2);
    22.
    23.    procedure Test_By_Reference (A, B : in out Typ2) is
    24.    begin
    25.       if A'Address /= B'Address then
    26.          Put_Line ("Error, unexpected pass by copy");
    27.       else
    28.          Put_line ("OK");
    29.       end if;
    30.    end;
    31.
    32.    B1 : Typ2 := (others => False);
    33.
    34. begin
    35.    Test_By_Copy (A1, A1);
    36.    Test_By_Reference (B1, B1);
    37. end;

and generates the output:

 0
 0
OK
OK

The following program generates warnings as shown:

     1. pragma Ada_2012;
     2. with System; use System;
     3. with Text_IO; use Text_IO;
     4. procedure pbycopref3 is
     5.    type Typ1 is array (1 .. 100) of Integer;
     6.    pragma Convention (Ada_Pass_By_Copy, Typ1);
     7.    procedure Test_By_Ref (A, B : aliased in out Typ1) is
                                  1  2
        >>> warning: cannot pass aliased parameter "A" by copy
        >>> warning: cannot pass aliased parameter "B" by copy

     8.    begin
     9.       if A'Address = B'Address then
    10.          Put_Line ("Error, unexpected pass by copy");
    11.       else
    12.          Put_Line (A (1)'Img);
    13.          Put_Line (A (2)'Img);
    14.          Put_line ("OK");
    15.       end if;
    16.    end;
    17.    X, Y : aliased Typ1 := (1 => 1, 2 => 2, others => 0);
    18. begin
    19.    Test_By_Ref (X, Y);
    20. end;

and generates the output:

 1
 2
OK

Tested on x86_64-pc-linux-gnu, committed on trunk

2011-12-21  Robert Dewar  <dewar@adacore.com>

	* sem_ch6.adb (Process_Formals): Set proper mechanism for
	formals whose types have conventions Ada_Pass_By_Copy or
	Ada_Pass_By_Reference.

-------------- next part --------------
Index: sem_ch6.adb
===================================================================
--- sem_ch6.adb	(revision 182572)
+++ sem_ch6.adb	(working copy)
@@ -9527,14 +9527,14 @@
                Default :=  Expression (Param_Spec);
 
                if Is_Scalar_Type (Etype (Default)) then
-                  if Nkind
-                       (Parameter_Type (Param_Spec)) /= N_Access_Definition
+                  if Nkind (Parameter_Type (Param_Spec)) /=
+                                              N_Access_Definition
                   then
                      Formal_Type := Entity (Parameter_Type (Param_Spec));
-
                   else
-                     Formal_Type := Access_Definition
-                       (Related_Nod, Parameter_Type (Param_Spec));
+                     Formal_Type :=
+                       Access_Definition
+                         (Related_Nod, Parameter_Type (Param_Spec));
                   end if;
 
                   Apply_Scalar_Range_Check (Default, Formal_Type);
@@ -9556,6 +9556,21 @@
 
          if Is_Aliased (Formal) then
             Set_Mechanism (Formal, By_Reference);
+
+            --  Warn if user asked this to be passed by copy
+
+            if Convention (Formal_Type) = Convention_Ada_Pass_By_Copy then
+               Error_Msg_N
+                 ("?cannot pass aliased parameter & by copy", Formal);
+            end if;
+
+         --  Force mechanism if type has Convention Ada_Pass_By_Ref/Copy
+
+         elsif Convention (Formal_Type) = Convention_Ada_Pass_By_Copy then
+            Set_Mechanism (Formal, By_Copy);
+
+         elsif Convention (Formal_Type) = Convention_Ada_Pass_By_Reference then
+            Set_Mechanism (Formal, By_Reference);
          end if;
 
          Next (Param_Spec);


More information about the Gcc-patches mailing list