If the renamed object in an object renaming declaration is a function call of a limited type, the expansion of the renaming is complicated by the presence of various temporaries and subtypes that capture constraints of the renamed object. This patch rewrites the renaming as an object declaration, whose expansion is simpler. Given that the object is immutably limited there is no copy involved and no performance hit.
The following must compile quietly: gcc -c -gnat05 smart_pointers-test.adb with Smart_Integer_Pointer; use Smart_Integer_Pointer; procedure Smart_Pointers.Test is P: Smart_Pointer; begin Set (P, Int_Data'(Client_Data with I => -10)); declare A: Accessor renames Get (P); begin null; end; end Smart_Pointers.Test; --- with Smart_Pointers; use Smart_Pointers; package Smart_Integer_Pointer is type Int_Data is new Client_Data with record I: Integer; end record; end Smart_Integer_Pointer; --- with Ada.Unchecked_Deallocation; package body Smart_Pointers is procedure Free is new Ada.Unchecked_Deallocation (Client_Data'Class, Client_Data_Ptr); procedure Set (Self: in out Smart_Pointer; Data: in Client_Data'Class) is begin Self := (Ada.Finalization.Controlled with Pointer => new Client_Data'Class'(Data)); end Set; procedure Unset (Self: in out Smart_Pointer) renames Finalize; function Get (Self: Smart_Pointer) return Accessor is begin if Self.Pointer = null then return Accessor'(Data => null, Hold => <>); else return Accessor'(Data => Self.Pointer, Hold => Self); end if; end Get; procedure Adjust (Self: in out Smart_Pointer) is begin if Self.Pointer /= null then Self.Pointer.Count := Self.Pointer.Count + 1; end if; end Adjust; procedure Finalize (Self: in out Smart_Pointer) is Pointer: Client_Data_Ptr := Self.Pointer; begin Self.Pointer := null; -- idempotence if Pointer /= null then Pointer.Count := Pointer.Count - 1; if Pointer.Count = 0 then Free (Pointer); end if; end if; end Finalize; function Get_Count (Self: Smart_Pointer) return Natural is begin return Self.Pointer.Count; end Get_Count; end Smart_Pointers; --- private with Ada.Finalization; package Smart_Pointers is type Client_Data is abstract tagged private; type Accessor (Data: access Client_Data'Class) is limited private; type Smart_Pointer is private; procedure Set (Self: in out Smart_Pointer; Data: in Client_Data'Class); function Get (Self: Smart_Pointer) return Accessor; procedure Unset (Self: in out Smart_Pointer); private function Get_Count (Self: Smart_Pointer) return Natural; -- Self /= null (for test only) type Client_Data is abstract tagged record Count: Natural := 1; -- the reference count end record; type Accessor (Data: access Client_Data'Class) is limited record Hold: Smart_Pointer; end record; type Client_Data_Ptr is access Client_Data'Class; type Smart_Pointer is new Ada.Finalization.Controlled with record Pointer: Client_Data_Ptr; end record; overriding procedure Adjust (Self: in out Smart_Pointer); overriding procedure Finalize (Self: in out Smart_Pointer); end Smart_Pointers; ` Tested on x86_64-pc-linux-gnu, committed on trunk 2011-08-29 Ed Schonberg <schonb...@adacore.com> * sem_ch8.adb (Analyze_Object_Renaming): If the renamed object is a function call of a limited type, the expansion of the renaming is complicated by the presence of various temporaries and subtypes that capture constraints of the renamed object. Rewrite node as an object declaration, whose expansion is simpler. Given that the object is limited there is no copy involved and no performance hit.
Index: sem_ch8.adb =================================================================== --- sem_ch8.adb (revision 178155) +++ sem_ch8.adb (working copy) @@ -682,9 +682,10 @@ ----------------------------- procedure Analyze_Object_Renaming (N : Node_Id) is - Id : constant Entity_Id := Defining_Identifier (N); + Loc : constant Source_Ptr := Sloc (N); + Id : constant Entity_Id := Defining_Identifier (N); Dec : Node_Id; - Nam : constant Node_Id := Name (N); + Nam : constant Node_Id := Name (N); T : Entity_Id; T2 : Entity_Id; @@ -704,7 +705,6 @@ ------------------------------ procedure Check_Constrained_Object is - Loc : constant Source_Ptr := Sloc (N); Subt : Entity_Id; begin @@ -805,6 +805,29 @@ Resolve (Nam, T); + -- If the renamed object is a function call of a limited type, + -- the expansion of the renaming is complicated by the presence + -- of various temporaries and subtypes that capture constraints + -- of the renamed object. Rewrite node as an object declaration, + -- whose expansion is simpler. Given that the object is limited + -- there is no copy involved and no performance hit. + + if Nkind (Nam) = N_Function_Call + and then Is_Immutably_Limited_Type (Etype (Nam)) + and then not Is_Constrained (T) + and then Comes_From_Source (N) + then + Set_Etype (Id, T); + Set_Ekind (Id, E_Constant); + Rewrite (N, + Make_Object_Declaration (Loc, + Defining_Identifier => Id, + Constant_Present => True, + Object_Definition => New_Occurrence_Of (T, Loc), + Expression => Relocate_Node (Nam))); + return; + end if; + -- Check that a class-wide object is not being renamed as an object -- of a specific type. The test for access types is needed to exclude -- cases where the renamed object is a dynamically tagged access @@ -2330,9 +2353,7 @@ -- of a generic, its entity is set to the first available homonym. -- We must first disambiguate the name, then set the proper entity. - if Is_Actual - and then Is_Overloaded (Nam) - then + if Is_Actual and then Is_Overloaded (Nam) then Set_Entity (Nam, Old_S); end if; end if; @@ -2403,9 +2424,7 @@ end if; if Old_S /= Any_Id then - if Is_Actual - and then From_Default (N) - then + if Is_Actual and then From_Default (N) then -- This is an implicit reference to the default actual Generate_Reference (Old_S, Nam, Typ => 'i', Force => True);