diff mbox

[Ada] Ada 2012 accessibility of anonymous access stand-alone objects

Message ID 20110830132228.GA11498@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Aug. 30, 2011, 1:22 p.m. UTC
This set of changes implements support for AI05-0148, the Ada2012
rules concerting the accessibility of a stand-alone object of an
anonymous access type (hereafter, a "saooaaat").

The Extra_Accessibility attribute was previously only used for a
formal parameter of an anonymous access type. The use of this
attribute is generalized so that this attribute is set for any
Ada-2012 saooaaat which is not declared at library level.

In this case, an object containing the current accessibility
level of the saooaaat is also declared. The Extra_Accessibility
attribute of the saooaaat refers to this object and the
Is_Local_Anonymous_Access attribute is set to False for the
anonymous access type.

When the object is updated (either by an assignment statement or by
parameter copy-back), the associated Extra_Accessibility object is
also updated. An accessibility check is generated to ensure that the
new value is not greater than the (static) accessibility level of
the saooaaat.

When the dynamic accessibility level of the anonymous access type is
needed, the value of the Extra_Accessibility object is used.

The two attributes RM_Size (defined on types) and Extra_Accessibility
(defined on objects) share storage, so it is now more important to
avoid accessing the RM_Size attribute of an object.

The following tests are intended to test these changes.
The first (AI05_0148_Test1) should execute without
producing output; any exceptions raised should be handled
within the program. The second (AI05_0148_Test2) should fail to
compile and the lines ending in "-- illegal" comments should
be flagged as containing errors.

	  procedure AI05_0148_Test1 is
	
	    subtype Designated is Integer;
	
	    procedure Assert (Condition : Boolean) is
	        Test_Failed : exception;
	    begin
	        if not Condition then
	            raise Test_Failed;
	        end if;
	    end Assert;
	
	    Aaa, Bbb : aliased Designated := 123;
	
	    Ptr1 : access Designated := Aaa'Access;
	
	    type Named1 is access all Designated;
	    for Named1'Storage_Size use 0;
	
	    procedure Test_Assignment is
	        Ccc : aliased Designated := 456;
	        Ptr2 : access Designated := Bbb'Access;
	    begin
	        for Exception_Expected in Boolean loop
	            begin
	                Ptr1 := Ptr2;
	                Assert (not Exception_Expected);
	            exception
	                when Program_Error =>
	                    Assert (Exception_Expected);
	            end;
	            Ptr2 := Ccc'Access;
	        end loop;
	        Assert (Ptr1 = Bbb'Access);
	        Ptr1 := Aaa'Access;
	    end Test_Assignment;
	
	    procedure Test_Rename_Assignment is
	        Ccc : aliased Designated := 456;
	        Ptr2 : access Designated := Bbb'Access;
	    begin
	        for Exception_Expected in Boolean loop
	            declare
	                Intermediate_1 : access Designated renames Ptr1;
	                Ptr1_Ren : access Designated renames Intermediate_1;
	                Intermediate_2 : access Designated renames Ptr2;
	                Ptr2_Ren : access Designated renames Intermediate_2;
	            begin
	                Ptr1_Ren := Ptr2_Ren;
	                Assert (not Exception_Expected);
	            exception
	                when Program_Error =>
	                    Assert (Exception_Expected);
	            end;
	            Ptr2 := Ccc'Access;
	        end loop;
	        Assert (Ptr1 = Bbb'Access);
	        Ptr1 := Aaa'Access;
	    end Test_Rename_Assignment;
	
	    procedure Test_Copy_Back is
	        type Named2 is access all Designated;
	        for Named2'Storage_Size use 0;
	
	        Ptr2 : access Designated;
	
	        procedure Assign1 (Lhs1 : out Named1; Rhs1 : Named1) is
	        begin
	            Lhs1 := Rhs1;
	        end Assign1;
	
	        procedure Assign2 (Lhs2 : out Named2; Rhs2 : Named2) is
	        begin
	            Lhs2 := Rhs2;
	        end Assign2;
	    begin
	        Assign1 (Named1 (Ptr2), Bbb'Access);
	        for Exception_Expected in Boolean loop
	            begin
	                Ptr1 := Ptr2;
	                Assert (not Exception_Expected);
	            exception
	                when Program_Error =>
	                    Assert (Exception_Expected);
	            end;
	            Assign2 (Named2 (Ptr2), Aaa'Access);
	        end loop;
	        Assert (Ptr1 = Bbb'Access);
	        Ptr1 := Aaa'Access;
	    end Test_Copy_Back;
	
	    procedure Test_Rename_Copy_Back is
	        type Named2 is access all Designated;
	        for Named2'Storage_Size use 0;
	
	        Ptr2 : access Designated;
	
	        procedure Assign1 (Lhs1 : out Named1; Rhs1 : Named1) is
	        begin
	            Lhs1 := Rhs1;
	        end Assign1;
	
	        procedure Assign2 (Lhs2 : out Named2; Rhs2 : Named2) is
	        begin
	            Lhs2 := Rhs2;
	        end Assign2;
	    begin
	        declare
	            Intermediate_1 : access Designated renames Ptr1;
	            Ptr1_Ren : access Designated renames Intermediate_1;
	            Intermediate_2 : access Designated renames Ptr2;
	            Ptr2_Ren : access Designated renames Intermediate_2;
	        begin
	            Assign1 (Named1 (Ptr2_Ren), Bbb'Access);
	            for Exception_Expected in Boolean loop
	                begin
	                    Ptr1_Ren := Ptr2_Ren;
	                    Assert (not Exception_Expected);
	                exception
	                    when Program_Error =>
	                        Assert (Exception_Expected);
	                end;
	                Assign2 (Named2 (Ptr2_Ren), Aaa'Access);
	            end loop;
	            Assert (Ptr1_Ren = Bbb'Access);
	            Ptr1_Ren := Aaa'Access;
	        end;
	    end Test_Rename_Copy_Back;
	
	    procedure Test_Access_Params is
	        Ccc : aliased Designated := 456;
	        Ptr2 : access Designated := Bbb'Access;
	
	        procedure Update_Ptr1 (Aap : access Designated) is
	        begin
	            Ptr1 := Aap;
	        end Update_Ptr1;
	    begin
	        for Exception_Expected in Boolean loop
	            begin
	                Update_Ptr1 (Ptr2);
	                Assert (not Exception_Expected);
	            exception
	                when Program_Error =>
	                    Assert (Exception_Expected);
	            end;
	            Ptr2 := Ccc'Access;
	        end loop;
	        Assert (Ptr1 = Bbb'Access);
	        Ptr1 := Aaa'Access;
	    end Test_Access_Params;
	
	    procedure Test_Rename_Access_Params is
	        Ccc : aliased Designated := 456;
	        Ptr2 : access Designated := Bbb'Access;
	    begin
	        declare
	            Intermediate_1 : access Designated renames Ptr1;
	            Ptr1_Ren : access Designated renames Intermediate_1;
	            Intermediate_2 : access Designated renames Ptr2;
	            Ptr2_Ren : access Designated renames Intermediate_2;
	
	            procedure Update_Ptr1 (Aap : access Designated) is
	            begin
	                Ptr1_Ren := Aap;
	            end Update_Ptr1;
	        begin
	            for Exception_Expected in Boolean loop
	                begin
	                    Update_Ptr1 (Ptr2_Ren);
	                    Assert (not Exception_Expected);
	                exception
	                    when Program_Error =>
	                        Assert (Exception_Expected);
	                end;
	                Ptr2_Ren := Ccc'Access;
	            end loop;
	            Assert (Ptr1_Ren = Bbb'Access);
	            Ptr1_Ren := Aaa'Access;
	        end;
	    end Test_Rename_Access_Params;
	
	    procedure Test_Membership is
	        Ccc : aliased Designated := 456;
	        Ptr2 : access Designated := Bbb'Access;
	    begin
	        for Ptr2_Not_In_Named1 In Boolean loop
	            Assert ((Ptr2 not in Named1) = Ptr2_Not_In_Named1);
	            Ptr2 := Ccc'Access;
	        end loop;
	    end Test_Membership;
	
	    procedure Test_Rename_Membership is
	        Ccc : aliased Designated := 456;
	        Ptr2 : access Designated := Bbb'Access;
	    begin
	        for Ptr2_Not_In_Named1 In Boolean loop
	            declare
	                Intermediate_2 : access Designated renames Ptr2;
	                Ptr2_Ren : access Designated renames Intermediate_2;
	            begin
	                Assert ((Ptr2_Ren not in Named1) = Ptr2_Not_In_Named1);
	                Ptr2_Ren := Ccc'Access;
	            end;
	        end loop;
	    end Test_Rename_Membership;
	
	    procedure Test_Conversion is
	        Ccc : aliased Designated := 456;
	        Ptr2 : access Designated := Bbb'Access;
	        Converted : Named1 := Aaa'Access;
	    begin
	        for Exception_Expected in Boolean loop
	            begin
	                Converted := Named1 (Ptr2);
	                Assert (not Exception_Expected);
	            exception
	                when Program_Error =>
	                    Assert (Exception_Expected);
	            end;
	            Ptr2 := Ccc'Access;
	        end loop;
	        Assert (Converted = Bbb'Access);
	    end Test_Conversion;
	
	    procedure Test_Rename_Conversion is
	        Ccc : aliased Designated := 456;
	        Ptr2 : access Designated := Bbb'Access;
	        Converted : Named1 := Aaa'Access;
	    begin
	        declare
	           Intermediate_1 : Named1 renames Converted;
	           Converted_Ren : Named1 renames Intermediate_1;
	           Intermediate_2 : access Designated renames Ptr2;
	           Ptr2_Ren : access Designated renames Intermediate_2;
	        begin
	            for Exception_Expected in Boolean loop
	                begin
	                    Converted_Ren := Named1 (Ptr2_Ren);
	                    Assert (not Exception_Expected);
	                exception
	                    when Program_Error =>
	                        Assert (Exception_Expected);
	                end;
	                Ptr2_Ren := Ccc'Access;
	            end loop;
	            Assert (Converted_Ren = Bbb'Access);
	        end;
	    end Test_Rename_Conversion;
	
	  begin
	    Test_Assignment;
	    Test_Copy_Back;
	    Test_Access_Params;
	    Test_Membership;
	    Test_Conversion;
	
	    Test_Rename_Assignment;
	    Test_Rename_Copy_Back;
	    Test_Rename_Access_Params;
	    Test_Rename_Membership;
	    Test_Rename_Conversion;
	  end AI05_0148_Test1;
	
	  procedure Ai05_0148_Test2 is
	    subtype Designated is Integer;
	    Ptr1 : access Designated;
	    Var1 : aliased Designated;
	  begin
	    declare
	        Var2 : aliased Designated := 456;
	        type Named2 is access all Designated;
	        for Named2'Storage_Size use 0;
	        Ptr2 : Named2;
	        Intermediate : access Designated renames Ptr1;
	        Ptr1_Ren : access Designated renames Intermediate;
	
	        procedure Foo (X : out Named2) is
	           begin X := Var2'Access; end Foo;
	    begin
	        Ptr1 := Var2'Access; -- illegal
	        Ptr1_Ren := Var2'Access; -- illegal
	
	        Ptr1 := Ptr2; -- illegal
	        Ptr1_Ren := Ptr2; -- illegal
	
	        Foo (Ptr1); -- illegal
	        Foo (Ptr1_Ren); -- illegal
	    end;
	  end Ai05_0148_Test2;

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

2011-08-30  Steve Baird  <baird@adacore.com>

	* sem_util.ads (Deepest_Type_Access_Level): New function; for the type
	of a saooaaat (i.e, a stand-alone object of an anonymous access type),
	returns the (static) accessibility level of the object. Otherwise, the
	same as Type_Access_Level.
	(Dynamic_Accessibility_Level): New function; given an expression which
	could occur as the rhs of an assignment to a saooaaat (i.e., an
	expression of an access-to-object type), return the new value for the
	saooaaat's associated Extra_Accessibility object.
	(Effective_Extra_Accessibility): New function; same as
	Einfo.Extra_Accessibility except that object renames are looked through.
	* sem_util.adb 
	(Deepest_Type_Access_Level): New function; see sem_util.ads description.
	(Dynamic_Accessibility_Level): New function; see sem_util.ads
	description.
	(Effective_Extra_Accessibility): New function; see sem_util.ads
	description.
	* einfo.ads (Is_Local_Anonymous_Access): Update comments.
	(Extra_Accessibility): Update comments.
	(Init_Object_Size_Align): New procedure; same as Init_Size_Align
	except RM_Size field (which is only for types) is unaffected.
	* einfo.adb
	(Extra_Accessibility): Expand domain to allow objects, not just formals.
	(Set_Extra_Accessibility): Expand domain to allow objects, not just
	formals.
	(Init_Size): Add assertion that we are not trashing the
	Extra_Accessibility attribute of an object.
	(Init_Size_Align): Add assertion that we are not trashing the
	Extra_Accessibility attribute of an object.
	(Init_Object_Size_Align): New procedure; see einfo.ads description.
	* sem_ch3.adb (Find_Type_Of_Object): Set Is_Local_Anonymous_Access
	differently for the type of a (non-library-level) saooaaat depending
	whether Ada_Version < Ada_2012. This is the only point where Ada_Version
	is queried in this set of changes - everything else (in particular,
	setting of the Extra_Accessibility attribute in exp_ch3.adb) is
	driven off of the setting of the Is_Local_Anonymous_Access attribute.
	The special treatment of library-level saooaaats is an optimization,
	not required for correctnesss. This is based on the observation that the
	Ada2012 rules (static and dynamic) for saooaaats turn out to be
	equivalent to the Ada2005 rules in the case of a library-level saooaaat.
	* exp_ch3.adb
	(Expand_N_Object_Declaration): If Is_Local_Anonymous_Access is
	false for the type of a saooaaat, declare and initialize its
	accessibility level object and set the Extra_Accessibility attribute
	of the saooaaat to refer to this object.
	* checks.adb (Apply_Accessibility_Check): Add Ada 2012 saooaaat support.
	* exp_ch4.adb (Expand_N_In): Replace some Extra_Accessibility calls with
	calls to Effective_Extra_Accessibility in order to support
	renames of saooaaats.
	(Expand_N_Type_Conversion): Add new local function,
	Has_Extra_Accessibility, and call it when determining whether an
	accessibility check is needed.
	It returns True iff Present (Effective_Extra_Accessibility (Id)) would
	evaluate to True (without raising an exception).
	* exp_ch5.adb
	(Expand_N_Assignment_Statement): When assigning to an Ada2012
	saooaaat, update its associated Extra_Accessibility object (if
	it has one). This includes an accessibility check.
	* exp_ch6.adb (Add_Call_By_Copy_Code): When parameter copy-back updates
	a saooaaat, update its Extra_Accessibility object too (if it
	has one).
	(Expand_Call): Replace a couple of calls to Type_Access_Level
	with calls to Dynamic_Access_Level to handle cases where
	passing a literal (any literal) is incorrect.
	* sem_attr.adb (Resolve_Attribute): Handle the static accessibility
	checks associated with "Saooaat := Some_Object'Access;"; this must
	be rejected if Some_Object is declared in a more nested scope
	than Saooaat.
	* sem_ch5.adb (Analyze_Assignment): Force accessibility checking for an
	assignment to a saooaaat even if Is_Local_Anonymous_Access
	returns False for its type (indicating a 2012-style saooaaat).
	* sem_ch8.adb
	(Analyze_Object_Renaming): Replace a call to Init_Size_Align
	(which is only appropriate for objects, not types) with a call
	of Init_Object_Size_Align in order to avoid trashing the
	Extra_Accessibility attribute of a rename (the two attributes
	share storage).
	* sem_res.adb
	(Valid_Conversion) Replace six calls to Type_Access_Level with
	calls to Deepest_Type_Access_Level. This is a bit tricky. For an
	Ada2012 non-library-level saooaaat, the former returns library level
	while the latter returns the (static) accessibility level of the
	saooaaat. A type conversion to the anonymous type of a saooaaat
	can only occur as part of an assignment to the saooaaat, so we
	know that such a conversion must be in a lhs context, so Deepest
	yields the result that we need. If such a conversion could occur,
	say, as the operand of an equality operator, then this might not
	be right. Also add a test so that static accessibilty checks are
	performed for converting to a saooaaat's type even if
	Is_Local_Anonymous_Access yields False for the type.
diff mbox

Patch

Index: exp_ch5.adb
===================================================================
--- exp_ch5.adb	(revision 178293)
+++ exp_ch5.adb	(working copy)
@@ -1885,6 +1885,57 @@ 
          Apply_Constraint_Check (Rhs, Etype (Lhs));
       end if;
 
+      --  Ada 2012 (AI05-148): Update current accessibility level if
+      --  Rhs is a stand-alone obj of an anonymous access type.
+
+      if Is_Access_Type (Typ)
+        and then Is_Entity_Name (Lhs)
+        and then Present (Effective_Extra_Accessibility (Entity (Lhs))) then
+         declare
+            function Lhs_Entity return Entity_Id;
+            --  Look through renames to find the underlying entity.
+            --  For assignment to a rename, we don't care about the
+            --  Enclosing_Dynamic_Scope of the rename declaration.
+
+            ----------------
+            -- Lhs_Entity --
+            ----------------
+
+            function Lhs_Entity return Entity_Id is
+               Result : Entity_Id := Entity (Lhs);
+            begin
+               while Present (Renamed_Object (Result)) loop
+                  --  Renamed_Object must return an Entity_Name here
+                  --  because of preceding "Present (E_E_A (...))" test.
+
+                  Result := Entity (Renamed_Object (Result));
+               end loop;
+               return Result;
+            end Lhs_Entity;
+
+            Access_Check : constant Node_Id :=
+              Make_Raise_Program_Error (Loc,
+                Condition =>
+                  Make_Op_Gt (Loc,
+                    Left_Opnd => Dynamic_Accessibility_Level (Rhs),
+                    Right_Opnd =>
+                      Make_Integer_Literal (Loc,
+                        Scope_Depth (Enclosing_Dynamic_Scope (Lhs_Entity)))),
+                Reason => PE_Accessibility_Check_Failed);
+
+            Access_Level_Update : constant Node_Id :=
+              Make_Assignment_Statement (Loc,
+                Name => New_Occurrence_Of (
+                  Effective_Extra_Accessibility (Entity (Lhs)), Loc),
+                Expression => Dynamic_Accessibility_Level (Rhs));
+         begin
+            if not Accessibility_Checks_Suppressed (Entity (Lhs)) then
+               Insert_Action (N, Access_Check);
+            end if;
+            Insert_Action (N, Access_Level_Update);
+         end;
+      end if;
+
       --  Case of assignment to a bit packed array element. If there is a
       --  change of representation this must be expanded into components,
       --  otherwise this is a bit-field assignment.
Index: sem_ch3.adb
===================================================================
--- sem_ch3.adb	(revision 178293)
+++ sem_ch3.adb	(working copy)
@@ -15122,8 +15122,11 @@ 
 
       elsif Def_Kind = N_Access_Definition then
          T := Access_Definition (Related_Nod, Obj_Def);
-         Set_Is_Local_Anonymous_Access (T);
 
+         Set_Is_Local_Anonymous_Access (T, V => (Ada_Version < Ada_2012)
+           or else (Nkind (P) /= N_Object_Declaration)
+           or else Is_Library_Level_Entity (Defining_Identifier (P)));
+
       --  Otherwise, the object definition is just a subtype_mark
 
       else
Index: sem_ch5.adb
===================================================================
--- sem_ch5.adb	(revision 178293)
+++ sem_ch5.adb	(working copy)
@@ -601,6 +601,14 @@ 
       then
          if Is_Local_Anonymous_Access (T1)
            or else Ekind (T2) = E_Anonymous_Access_Subprogram_Type
+
+           --  Handle assignment to an Ada 2012 stand-alone object
+           --  of an anonymous access type.
+
+           or else (Ekind (T1) = E_Anonymous_Access_Type
+             and then Nkind (Associated_Node_For_Itype (T1))
+               = N_Object_Declaration)
+
          then
             Rewrite (Rhs, Convert_To (T1, Relocate_Node (Rhs)));
             Analyze_And_Resolve (Rhs, T1);
Index: einfo.adb
===================================================================
--- einfo.adb	(revision 178293)
+++ einfo.adb	(working copy)
@@ -1038,7 +1038,8 @@ 
 
    function Extra_Accessibility (Id : E) return E is
    begin
-      pragma Assert (Is_Formal (Id) or else Ekind (Id) = E_Variable);
+      pragma Assert
+        (Is_Formal (Id) or else Ekind_In (Id, E_Variable, E_Constant));
       return Node13 (Id);
    end Extra_Accessibility;
 
@@ -3506,7 +3507,8 @@ 
 
    procedure Set_Extra_Accessibility (Id : E; V : E) is
    begin
-      pragma Assert (Is_Formal (Id) or else Ekind (Id) = E_Variable);
+      pragma Assert
+        (Is_Formal (Id) or else Ekind_In (Id, E_Variable, E_Constant));
       Set_Node13 (Id, V);
    end Set_Extra_Accessibility;
 
@@ -5466,6 +5468,7 @@ 
    procedure Init_Size (Id : E; V : Int) is
    begin
       Set_Uint12 (Id, UI_From_Int (V));  -- Esize
+      pragma Assert (not Is_Object (Id));
       Set_Uint13 (Id, UI_From_Int (V));  -- RM_Size
    end Init_Size;
 
@@ -5476,10 +5479,21 @@ 
    procedure Init_Size_Align (Id : E) is
    begin
       Set_Uint12 (Id, Uint_0);  -- Esize
+      pragma Assert (not Is_Object (Id));
       Set_Uint13 (Id, Uint_0);  -- RM_Size
       Set_Uint14 (Id, Uint_0);  -- Alignment
    end Init_Size_Align;
 
+   ----------------------------
+   -- Init_Object_Size_Align --
+   ----------------------------
+
+   procedure Init_Object_Size_Align (Id : E) is
+   begin
+      Set_Uint12 (Id, Uint_0);  -- Esize
+      Set_Uint14 (Id, Uint_0);  -- Alignment
+   end Init_Object_Size_Align;
+
    ----------------------------------------------
    -- Type Representation Attribute Predicates --
    ----------------------------------------------
Index: einfo.ads
===================================================================
--- einfo.ads	(revision 178293)
+++ einfo.ads	(working copy)
@@ -2446,10 +2446,11 @@ 
 --    Is_Local_Anonymous_Access (Flag194)
 --       Present in access types. Set for an anonymous access type to indicate
 --       that the type is created for a record component with an access
---       definition, an array component, or a stand-alone object. Such
---       anonymous types have an accessibility level equal to that of the
+--       definition, an array component, or (pre-Ada2012) a stand-alone object.
+--       Such anonymous types have an accessibility level equal to that of the
 --       declaration in which they appear, unlike the anonymous access types
---       that are created for access parameters and access discriminants.
+--       that are created for access parameters, access discriminants, and
+--       (as of Ada2012) stand-alone objects.
 
 --    Is_Machine_Code_Subprogram (Flag137)
 --       Present in subprogram entities. Set to indicate that the subprogram
@@ -5050,6 +5051,7 @@ 
    --    Discriminal_Link                    (Node10)   (discriminals only)
    --    Full_View                           (Node11)
    --    Esize                               (Uint12)
+   --    Extra_Accessibility                 (Node13)   (constants only)
    --    Alignment                           (Uint14)
    --    Return_Flag_Or_Transient_Decl       (Node15)   (constants only)
    --    Actual_Subtype                      (Node17)
@@ -7017,6 +7019,10 @@ 
    --  This procedure initializes both size fields and the alignment
    --  field to all be Unknown.
 
+   procedure Init_Object_Size_Align (Id : E);
+   --  Same as Init_Size_Align except RM_Size field (which is only for types)
+   --  is unaffected.
+
    procedure Init_Size (Id : E; V : Int);
    --  Initialize both the Esize and RM_Size fields of E to V
 
Index: checks.adb
===================================================================
--- checks.adb	(revision 178293)
+++ checks.adb	(working copy)
@@ -479,11 +479,26 @@ 
       Insert_Node : Node_Id)
    is
       Loc         : constant Source_Ptr := Sloc (N);
-      Param_Ent   : constant Entity_Id  := Param_Entity (N);
+      Param_Ent   : Entity_Id  := Param_Entity (N);
       Param_Level : Node_Id;
       Type_Level  : Node_Id;
 
    begin
+      if Ada_Version >= Ada_2012
+         and then not Present (Param_Ent)
+         and then Is_Entity_Name (N)
+         and then Ekind_In (Entity (N), E_Constant, E_Variable)
+         and then Present (Effective_Extra_Accessibility (Entity (N)))
+      then
+         Param_Ent := Entity (N);
+         while Present (Renamed_Object (Param_Ent)) loop
+            --  Renamed_Object must return an Entity_Name here
+            --  because of preceding "Present (E_E_A (...))" test.
+
+            Param_Ent := Entity (Renamed_Object (Param_Ent));
+         end loop;
+      end if;
+
       if Inside_A_Generic then
          return;
 
@@ -494,15 +509,16 @@ 
 
       elsif Present (Param_Ent)
          and then Present (Extra_Accessibility (Param_Ent))
-         and then UI_Gt (Object_Access_Level (N), Type_Access_Level (Typ))
+         and then UI_Gt (Object_Access_Level (N),
+           Deepest_Type_Access_Level (Typ))
          and then not Accessibility_Checks_Suppressed (Param_Ent)
          and then not Accessibility_Checks_Suppressed (Typ)
       then
          Param_Level :=
            New_Occurrence_Of (Extra_Accessibility (Param_Ent), Loc);
 
-         Type_Level :=
-           Make_Integer_Literal (Loc, Type_Access_Level (Typ));
+         Type_Level := Make_Integer_Literal (Loc,
+           Deepest_Type_Access_Level (Typ));
 
          --  Raise Program_Error if the accessibility level of the access
          --  parameter is deeper than the level of the target access type.
Index: sem_util.adb
===================================================================
--- sem_util.adb	(revision 178293)
+++ sem_util.adb	(working copy)
@@ -2372,6 +2372,26 @@ 
       end if;
    end Current_Subprogram;
 
+   ----------------------------------
+   -- Deepest_Type_Access_Level --
+   ----------------------------------
+
+   function Deepest_Type_Access_Level (Typ : Entity_Id) return Uint is
+   begin
+      if Ekind (Typ) = E_Anonymous_Access_Type
+        and then not Is_Local_Anonymous_Access (Typ)
+        and then Nkind (Associated_Node_For_Itype (Typ)) = N_Object_Declaration
+      then
+         --  Typ is the type of an Ada 2012 stand-alone object of an
+         --  anonymous access type.
+
+         return Scope_Depth (Enclosing_Dynamic_Scope (Defining_Identifier (
+           Associated_Node_For_Itype (Typ))));
+      else
+         return Type_Access_Level (Typ);
+      end if;
+   end Deepest_Type_Access_Level;
+
    ---------------------
    -- Defining_Entity --
    ---------------------
@@ -2848,6 +2868,99 @@ 
       end if;
    end Designate_Same_Unit;
 
+   ------------------------------------------
+   -- function Dynamic_Accessibility_Level --
+   ------------------------------------------
+
+   function Dynamic_Accessibility_Level (Expr : Node_Id) return Node_Id is
+      E : Entity_Id;
+      Loc : constant Source_Ptr := Sloc (Expr);
+   begin
+      if Is_Entity_Name (Expr) then
+         E := Entity (Expr);
+
+         if Present (Renamed_Object (E)) then
+            return Dynamic_Accessibility_Level (Renamed_Object (E));
+         end if;
+
+         if Is_Formal (E) or else Ekind_In (E, E_Variable, E_Constant) then
+            if Present (Extra_Accessibility (E)) then
+               return New_Occurrence_Of (Extra_Accessibility (E), Loc);
+            end if;
+         end if;
+      end if;
+
+      --  unimplemented: Ptr.all'Access, where Ptr has Extra_Accessibility ???
+
+      case Nkind (Expr) is
+         --  for access discriminant, the level of the enclosing object
+
+         when N_Selected_Component =>
+            if Ekind (Entity (Selector_Name (Expr))) = E_Discriminant
+              and then Ekind (Etype (Entity (Selector_Name (Expr)))) =
+              E_Anonymous_Access_Type then
+
+               return Make_Integer_Literal (Loc, Object_Access_Level (Expr));
+            end if;
+
+         when N_Attribute_Reference =>
+            case Get_Attribute_Id (Attribute_Name (Expr)) is
+
+               --  For X'Access, the level of the prefix X
+
+               when Attribute_Access =>
+                  return Make_Integer_Literal (Loc,
+                    Object_Access_Level (Prefix (Expr)));
+
+               --  Treat the unchecked attributes as library-level
+
+               when Attribute_Unchecked_Access |
+                 Attribute_Unrestricted_Access =>
+                  return Make_Integer_Literal (Loc,
+                    Scope_Depth (Standard_Standard));
+
+               --  No other access-valued attributes
+
+               when others =>
+                  raise Program_Error;
+            end case;
+
+         when N_Allocator =>
+            --  Unimplemented: depends on context. As an actual
+            --  parameter where formal type is anonymous, use
+            --    Scope_Depth (Current_Scope) + 1.
+            --  For other cases, see 3.10.2(14/3) and following. ???
+            null;
+
+         when N_Type_Conversion =>
+            if not Is_Local_Anonymous_Access (Etype (Expr)) then
+               --  Handle type conversions introduced for a
+               --  rename of an Ada2012 stand-alone object of an
+               --  anonymous access type.
+               return Dynamic_Accessibility_Level (Expression (Expr));
+            end if;
+
+         when others =>
+            null;
+      end case;
+
+      return Make_Integer_Literal (Loc, Type_Access_Level (Etype (Expr)));
+   end Dynamic_Accessibility_Level;
+
+   -----------------------------------
+   -- Effective_Extra_Accessibility --
+   -----------------------------------
+
+   function Effective_Extra_Accessibility (Id : Entity_Id) return Entity_Id is
+   begin
+      if Present (Renamed_Object (Id))
+        and then Is_Entity_Name (Renamed_Object (Id)) then
+         return Effective_Extra_Accessibility (Entity (Renamed_Object (Id)));
+      end if;
+
+      return Extra_Accessibility (Id);
+   end Effective_Extra_Accessibility;
+
    --------------------------
    -- Enclosing_CPP_Parent --
    --------------------------
Index: sem_util.ads
===================================================================
--- sem_util.ads	(revision 178293)
+++ sem_util.ads	(working copy)
@@ -292,6 +292,15 @@ 
    --  Current_Scope is returned. The returned value is Empty if this is called
    --  from a library package which is not within any subprogram.
 
+   function Deepest_Type_Access_Level (Typ : Entity_Id) return Uint;
+   --  Same as Type_Access_Level, except that if the
+   --  type is the type of an Ada 2012 stand-alone object of an
+   --  anonymous access type, then return the static accesssibility level
+   --  of the object. In that case, the dynamic accessibility level
+   --  of the object may take on values in a range. The low bound of
+   --  of that range is returned by Type_Access_Level; this
+   --  function yields the high bound of that range.
+
    function Defining_Entity (N : Node_Id) return Entity_Id;
    --  Given a declaration N, returns the associated defining entity. If the
    --  declaration has a specification, the entity is obtained from the
@@ -332,6 +341,16 @@ 
    --  these names is supposed to be a selected component name, an expanded
    --  name, a defining program unit name or an identifier.
 
+   function Dynamic_Accessibility_Level (Expr : Node_Id) return Node_Id;
+   --  Expr should be an expression of an access type.
+   --  Builds an integer literal except in cases involving anonymous
+   --  access types where accessibility levels are tracked at runtime
+   --  (access parameters and Ada 2012 stand-alone objects).
+
+   function Effective_Extra_Accessibility (Id : Entity_Id) return Entity_Id;
+   --  Same as Einfo.Extra_Accessibility except thtat object renames
+   --  are looked through.
+
    function Enclosing_CPP_Parent (Typ : Entity_Id) return Entity_Id;
    --  Returns the closest ancestor of Typ that is a CPP type.
 
Index: sem_res.adb
===================================================================
--- sem_res.adb	(revision 178296)
+++ sem_res.adb	(working copy)
@@ -10530,8 +10530,9 @@ 
 
          if Ekind (Target_Type) /= E_Anonymous_Access_Type then
             if Type_Access_Level (Opnd_Type) >
-               Type_Access_Level (Target_Type)
+              Deepest_Type_Access_Level (Target_Type)
             then
+
                --  In an instance, this is a run-time check, but one we know
                --  will fail, so generate an appropriate warning. The raise
                --  will be generated by Expand_N_Type_Conversion.
@@ -10562,7 +10563,7 @@ 
 
                if Nkind (Operand) = N_Selected_Component
                  and then Object_Access_Level (Operand) >
-                          Type_Access_Level (Target_Type)
+                   Deepest_Type_Access_Level (Target_Type)
                then
                   --  In an instance, this is a run-time check, but one we know
                   --  will fail, so generate an appropriate warning. The raise
@@ -10630,6 +10631,8 @@ 
 
          if Ekind (Target_Type) /= E_Anonymous_Access_Type
            or else Is_Local_Anonymous_Access (Target_Type)
+           or else Nkind (Associated_Node_For_Itype (Target_Type)) =
+             N_Object_Declaration
          then
             --  Ada 2012 (AI05-0149): Perform legality checking on implicit
             --  conversions from an anonymous access type to a named general
@@ -10687,8 +10690,8 @@ 
                   --  statically less deep than that of the target type, else
                   --  implicit conversion is disallowed (by RM12-8.6(27.1/3)).
 
-                  elsif Type_Access_Level (Opnd_Type)
-                          > Type_Access_Level (Target_Type)
+                  elsif Type_Access_Level (Opnd_Type) >
+                    Deepest_Type_Access_Level (Target_Type)
                   then
                      Error_Msg_N
                        ("implicit conversion of anonymous access value " &
@@ -10697,8 +10700,8 @@ 
                   end if;
                end if;
 
-            elsif Type_Access_Level (Opnd_Type)
-                    > Type_Access_Level (Target_Type)
+            elsif Type_Access_Level (Opnd_Type) >
+              Deepest_Type_Access_Level (Target_Type)
             then
 
                --  In an instance, this is a run-time check, but one we know
@@ -10737,7 +10740,7 @@ 
 
                if Nkind (Operand) = N_Selected_Component
                  and then Object_Access_Level (Operand) >
-                          Type_Access_Level (Target_Type)
+                   Deepest_Type_Access_Level (Target_Type)
                then
                   --  In an instance, this is a run-time check, but one we know
                   --  will fail, so generate an appropriate warning. The raise
@@ -10909,7 +10912,7 @@ 
          --  Check the static accessibility rule of 4.6(20)
 
          if Type_Access_Level (Opnd_Type) >
-            Type_Access_Level (Target_Type)
+           Deepest_Type_Access_Level (Target_Type)
          then
             Error_Msg_N
               ("operand type has deeper accessibility level than target",
Index: sem_attr.adb
===================================================================
--- sem_attr.adb	(revision 178293)
+++ sem_attr.adb	(working copy)
@@ -8312,8 +8312,16 @@ 
                --  the level is the same of the enclosing composite type.
 
                if Ada_Version >= Ada_2005
-                 and then Is_Local_Anonymous_Access (Btyp)
-                 and then Object_Access_Level (P) > Type_Access_Level (Btyp)
+                 and then (Is_Local_Anonymous_Access (Btyp)
+
+                           --  Handle cases where Btyp is the
+                           --  anonymous access type of an Ada 2012
+                           --  stand-alone object.
+
+                           or else Nkind (Associated_Node_For_Itype
+                             (Btyp)) = N_Object_Declaration)
+                 and then Object_Access_Level (P)
+                          > Deepest_Type_Access_Level (Btyp)
                  and then Attr_Id = Attribute_Access
                then
                   --  In an instance, this is a runtime check, but one we
Index: exp_ch4.adb
===================================================================
--- exp_ch4.adb	(revision 178296)
+++ exp_ch4.adb	(working copy)
@@ -4996,14 +4996,15 @@ 
 
                   else
                      if Present (Expr_Entity)
-                       and then Present (Extra_Accessibility (Expr_Entity))
+                       and then Present
+                         (Effective_Extra_Accessibility (Expr_Entity))
                        and then UI_Gt
                                   (Object_Access_Level (Lop),
                                    Type_Access_Level (Rtyp))
                      then
                         Param_Level :=
                           New_Occurrence_Of
-                            (Extra_Accessibility (Expr_Entity), Loc);
+                            (Effective_Extra_Accessibility (Expr_Entity), Loc);
 
                         Type_Level :=
                           Make_Integer_Literal (Loc, Type_Access_Level (Rtyp));
@@ -8279,6 +8280,10 @@ 
       procedure Real_Range_Check;
       --  Handles generation of range check for real target value
 
+      function Has_Extra_Accessibility (Id : Entity_Id) return Boolean;
+      --  True iff Present (Effective_Extra_Accessibility (Id)) successfully
+      --  evaluates to True.
+
       -----------------------------------
       -- Handle_Changed_Representation --
       -----------------------------------
@@ -8578,6 +8583,22 @@ 
          Analyze_And_Resolve (N, Btyp);
       end Real_Range_Check;
 
+      -----------------------------
+      -- Has_Extra_Accessibility --
+      -----------------------------
+
+      --  Returns true for a formal of an anonymous access type or for
+      --  an Ada 2012-style stand-alone object of an anonymous access type.
+
+      function Has_Extra_Accessibility (Id : Entity_Id) return Boolean is
+      begin
+         if Is_Formal (Id) or else Ekind_In (Id, E_Constant, E_Variable) then
+            return Present (Effective_Extra_Accessibility (Id));
+         else
+            return False;
+         end if;
+      end Has_Extra_Accessibility;
+
    --  Start of processing for Expand_N_Type_Conversion
 
    begin
@@ -8736,13 +8757,7 @@ 
          --  as tagged type checks).
 
          if Is_Entity_Name (Operand)
-           and then
-             (Is_Formal (Entity (Operand))
-               or else
-                 (Present (Renamed_Object (Entity (Operand)))
-                   and then Is_Entity_Name (Renamed_Object (Entity (Operand)))
-                   and then Is_Formal
-                              (Entity (Renamed_Object (Entity (Operand))))))
+           and then Has_Extra_Accessibility (Entity (Operand))
            and then Ekind (Etype (Operand)) = E_Anonymous_Access_Type
            and then (Nkind (Original_Node (N)) /= N_Attribute_Reference
                       or else Attribute_Name (Original_Node (N)) = Name_Access)
Index: exp_ch6.adb
===================================================================
--- exp_ch6.adb	(revision 178296)
+++ exp_ch6.adb	(working copy)
@@ -1201,10 +1201,46 @@ 
 
                Set_Assignment_OK (Lhs);
 
-               Append_To (Post_Call,
-                 Make_Assignment_Statement (Loc,
-                   Name       => Lhs,
-                   Expression => Expr));
+               if Is_Access_Type (E_Formal)
+                 and then Is_Entity_Name (Lhs)
+                 and then Present (Effective_Extra_Accessibility
+                 (Entity (Lhs)))
+               then
+                  --  Copyback target is an Ada 2012 stand-alone object
+                  --  of an anonymous access type
+
+                  pragma Assert (Ada_Version >= Ada_2012);
+
+                  if Type_Access_Level (E_Formal) >
+                    Object_Access_Level (Lhs) then
+                     Append_To (Post_Call, Make_Raise_Program_Error (Loc,
+                       Reason => PE_Accessibility_Check_Failed));
+                  end if;
+
+                  Append_To (Post_Call,
+                    Make_Assignment_Statement (Loc,
+                      Name       => Lhs,
+                      Expression => Expr));
+
+                  --  We would like to somehow suppress generation of
+                  --  the extra_accessibility assignment generated by
+                  --  the expansion of the above assignment statement.
+                  --  It's not a correctness issue because the following
+                  --  assignment renders it dead, but generating back-to-back
+                  --  assignments to the same target is undesirable. ???
+
+                  Append_To (Post_Call,
+                    Make_Assignment_Statement (Loc,
+                      Name       => New_Occurrence_Of (
+                        Effective_Extra_Accessibility (Entity (Lhs)), Loc),
+                      Expression => Make_Integer_Literal (Loc,
+                        Type_Access_Level (E_Formal))));
+               else
+                  Append_To (Post_Call,
+                    Make_Assignment_Statement (Loc,
+                      Name       => Lhs,
+                      Expression => Expr));
+               end if;
             end;
          end if;
       end Add_Call_By_Copy_Code;
@@ -2406,8 +2442,7 @@ 
 
                else
                   Add_Extra_Actual
-                    (Make_Integer_Literal (Loc,
-                       Intval => Type_Access_Level (Etype (Prev_Orig))),
+                    (Dynamic_Accessibility_Level (Prev_Orig),
                      Extra_Accessibility (Formal));
                end if;
 
@@ -2497,15 +2532,15 @@ 
                           Intval => Scope_Depth (Current_Scope) + 1),
                         Extra_Accessibility (Formal));
 
-                  --  For other cases we simply pass the level of the actual's
-                  --  access type. The type is retrieved from Prev rather than
-                  --  Prev_Orig, because in some cases Prev_Orig denotes an
-                  --  original expression that has not been analyzed.
+                  --  For most other cases we simply pass the level of the
+                  --  actual's access type. The type is retrieved from
+                  --  Prev rather than Prev_Orig, because in some cases
+                  --  Prev_Orig denotes an original expression that has
+                  --  not been analyzed.
 
                   when others =>
                      Add_Extra_Actual
-                       (Make_Integer_Literal (Loc,
-                          Intval => Type_Access_Level (Etype (Prev))),
+                       (Dynamic_Accessibility_Level (Prev),
                         Extra_Accessibility (Formal));
                end case;
             end if;
Index: sem_ch8.adb
===================================================================
--- sem_ch8.adb	(revision 178296)
+++ sem_ch8.adb	(working copy)
@@ -1137,7 +1137,7 @@ 
       end if;
 
       Set_Ekind (Id, E_Variable);
-      Init_Size_Align (Id);
+      Init_Object_Size_Align (Id);
 
       if T = Any_Type or else Etype (Nam) = Any_Type then
          return;
Index: exp_ch3.adb
===================================================================
--- exp_ch3.adb	(revision 178293)
+++ exp_ch3.adb	(working copy)
@@ -5261,6 +5261,47 @@ 
          end if;
       end if;
 
+      if Nkind (N) = N_Object_Declaration
+        and then Nkind (Object_Definition (N)) = N_Access_Definition
+        and then not Is_Local_Anonymous_Access (Etype (Def_Id))
+      then
+         --  An Ada 2012 stand-alone object of an anonymous access type
+
+         declare
+            Loc : constant Source_Ptr := Sloc (N);
+
+            Level : constant Entity_Id :=
+              Make_Defining_Identifier (Sloc (N),
+                Chars  => New_External_Name (Chars (Def_Id),
+                                             Suffix => "L"));
+            Level_Expr : Node_Id;
+            Level_Decl : Node_Id;
+         begin
+            Set_Ekind (Level, Ekind (Def_Id));
+            Set_Etype (Level, Standard_Natural);
+            Set_Scope (Level, Scope (Def_Id));
+
+            if No (Expr) then
+               Level_Expr := Make_Integer_Literal (Loc,
+                 -- accessibility level of null
+                 Intval => Scope_Depth (Standard_Standard));
+            else
+               Level_Expr := Dynamic_Accessibility_Level (Expr);
+            end if;
+
+            Level_Decl := Make_Object_Declaration (Loc,
+             Defining_Identifier => Level,
+             Object_Definition => New_Occurrence_Of (Standard_Natural, Loc),
+             Expression => Level_Expr,
+             Constant_Present => Constant_Present (N),
+             Has_Init_Expression => True);
+
+            Insert_Action_After (Init_After, Level_Decl);
+
+            Set_Extra_Accessibility (Def_Id, Level);
+         end;
+      end if;
+
    --  Exception on library entity not available
 
    exception