Commit d3b1cbdd by Bob Duff Committed by Arnaud Charlet

sem_util.adb (Requires_Transient_Scope): Avoid returning function results on the…

sem_util.adb (Requires_Transient_Scope): Avoid returning function results on the secondary stack in so many cases.

2015-05-28  Bob Duff  <duff@adacore.com>

	* sem_util.adb (Requires_Transient_Scope): Avoid returning
	function results on the secondary stack in so many cases.

From-SVN: r223814
parent 98fc3d49
2015-05-28 Bob Duff <duff@adacore.com>
* sem_util.adb (Requires_Transient_Scope): Avoid returning
function results on the secondary stack in so many cases.
2015-05-28 Ed Schonberg <schonberg@adacore.com> 2015-05-28 Ed Schonberg <schonberg@adacore.com>
* sem_util.adb (Wrong_Type): In any instance, do not emit error * sem_util.adb (Wrong_Type): In any instance, do not emit error
......
...@@ -16951,13 +16951,49 @@ package body Sem_Util is ...@@ -16951,13 +16951,49 @@ package body Sem_Util is
------------------------------ ------------------------------
-- A transient scope is required when variable-sized temporaries are -- A transient scope is required when variable-sized temporaries are
-- allocated in the primary or secondary stack, or when finalization -- allocated on the secondary stack, or when finalization actions must be
-- actions must be generated before the next instruction. -- generated before the next instruction.
function Old_Requires_Transient_Scope (Id : Entity_Id) return Boolean;
function New_Requires_Transient_Scope (Id : Entity_Id) return Boolean;
-- ???We retain the old and new algorithms for Requires_Transient_Scope for
-- the time being. New_Requires_Transient_Scope is used by default; the
-- debug switch -gnatdQ can be used to do Old_Requires_Transient_Scope
-- instead. The intent is to use this temporarily to measure before/after
-- efficiency. Note: when this temporary code is removed, the documentation
-- of dQ in debug.adb should be removed.
function Requires_Transient_Scope (Id : Entity_Id) return Boolean is function Requires_Transient_Scope (Id : Entity_Id) return Boolean is
Typ : constant Entity_Id := Underlying_Type (Id); Old_Result : constant Boolean := Old_Requires_Transient_Scope (Id);
begin
if Debug_Flag_QQ then
return Old_Result;
end if;
declare
New_Result : constant Boolean := New_Requires_Transient_Scope (Id);
begin
-- Assert that we're not putting things on the secondary stack if we
-- didn't before; we are trying to AVOID secondary stack when
-- possible.
if not Old_Result then
pragma Assert (not New_Result);
null;
end if;
return New_Result;
end;
end Requires_Transient_Scope;
----------------------------------
-- Old_Requires_Transient_Scope --
----------------------------------
-- Start of processing for Requires_Transient_Scope function Old_Requires_Transient_Scope (Id : Entity_Id) return Boolean is
Typ : constant Entity_Id := Underlying_Type (Id);
begin begin
-- This is a private type which is not completed yet. This can only -- This is a private type which is not completed yet. This can only
...@@ -16989,9 +17025,7 @@ package body Sem_Util is ...@@ -16989,9 +17025,7 @@ package body Sem_Util is
-- returned value is allocated on the secondary stack. Controlled -- returned value is allocated on the secondary stack. Controlled
-- type temporaries need finalization. -- type temporaries need finalization.
elsif Is_Tagged_Type (Typ) elsif Is_Tagged_Type (Typ) or else Has_Controlled_Component (Typ) then
or else Has_Controlled_Component (Typ)
then
return not Is_Value_Type (Typ); return not Is_Value_Type (Typ);
-- Record type -- Record type
...@@ -16999,18 +17033,20 @@ package body Sem_Util is ...@@ -16999,18 +17033,20 @@ package body Sem_Util is
elsif Is_Record_Type (Typ) then elsif Is_Record_Type (Typ) then
declare declare
Comp : Entity_Id; Comp : Entity_Id;
begin begin
Comp := First_Entity (Typ); Comp := First_Entity (Typ);
while Present (Comp) loop while Present (Comp) loop
if Ekind (Comp) = E_Component then if Ekind (Comp) = E_Component then
-- ???It's not clear we need a full recursive call to -- ???It's not clear we need a full recursive call to
-- Requires_Transient_Scope here. Note that the following -- Old_Requires_Transient_Scope here. Note that the
-- can't happen. -- following can't happen.
pragma Assert (Is_Definite_Subtype (Etype (Comp))); pragma Assert (Is_Definite_Subtype (Etype (Comp)));
pragma Assert (not Has_Controlled_Component (Etype (Comp))); pragma Assert (not Has_Controlled_Component (Etype (Comp)));
if Requires_Transient_Scope (Etype (Comp)) then if Old_Requires_Transient_Scope (Etype (Comp)) then
return True; return True;
end if; end if;
end if; end if;
...@@ -17033,7 +17069,7 @@ package body Sem_Util is ...@@ -17033,7 +17069,7 @@ package body Sem_Util is
-- If component type requires a transient scope, the array does too -- If component type requires a transient scope, the array does too
if Requires_Transient_Scope (Component_Type (Typ)) then if Old_Requires_Transient_Scope (Component_Type (Typ)) then
return True; return True;
-- Otherwise, we only need a transient scope if the size depends on -- Otherwise, we only need a transient scope if the size depends on
...@@ -17049,7 +17085,132 @@ package body Sem_Util is ...@@ -17049,7 +17085,132 @@ package body Sem_Util is
pragma Assert (Is_Protected_Type (Typ) or else Is_Task_Type (Typ)); pragma Assert (Is_Protected_Type (Typ) or else Is_Task_Type (Typ));
return False; return False;
end if; end if;
end Requires_Transient_Scope; end Old_Requires_Transient_Scope;
----------------------------------
-- New_Requires_Transient_Scope --
----------------------------------
function New_Requires_Transient_Scope (Id : Entity_Id) return Boolean is
function Caller_Known_Size_Record (Typ : Entity_Id) return Boolean;
-- This is called for untagged records and protected types, with
-- nondefaulted discriminants. Returns True if the size of function
-- results is known at the call site, False otherwise. Returns False
-- if there is a variant part that depends on the discriminants of
-- this type, or if there is an array constrained by the discriminants
-- of this type. ???Currently, this is overly conservative (the array
-- could be nested inside some other record that is constrained by
-- nondiscriminants). That is, the recursive calls are too conservative.
function Caller_Known_Size_Record (Typ : Entity_Id) return Boolean is
pragma Assert (Typ = Underlying_Type (Typ));
begin
if Has_Variant_Part (Typ) and then not Is_Definite_Subtype (Typ) then
return False;
end if;
declare
Comp : Entity_Id := First_Entity (Typ);
begin
while Present (Comp) loop
-- Only look at E_Component entities. No need to look at
-- E_Discriminant entities, and we must ignore internal
-- subtypes generated for constrained components.
if Ekind (Comp) = E_Component then
declare
Comp_Type : constant Entity_Id :=
Underlying_Type (Etype (Comp));
begin
if Is_Record_Type (Comp_Type)
or else
Is_Protected_Type (Comp_Type)
then
if not Caller_Known_Size_Record (Comp_Type) then
return False;
end if;
elsif Is_Array_Type (Comp_Type) then
if Size_Depends_On_Discriminant (Comp_Type) then
return False;
end if;
end if;
end;
end if;
Next_Entity (Comp);
end loop;
end;
return True;
end Caller_Known_Size_Record;
-- Local deeclarations
Typ : constant Entity_Id := Underlying_Type (Id);
-- Start of processing for New_Requires_Transient_Scope
begin
-- This is a private type which is not completed yet. This can only
-- happen in a default expression (of a formal parameter or of a
-- record component). Do not expand transient scope in this case
if No (Typ) then
return False;
-- Do not expand transient scope for non-existent procedure return or
-- string literal types.
elsif Typ = Standard_Void_Type
or else Ekind (Typ) = E_String_Literal_Subtype
then
return False;
-- Functions returning tagged types may dispatch on result so their
-- returned value is allocated on the secondary stack, even in the
-- definite case. Is_Tagged_Type includes controlled types and
-- class-wide types. Controlled type temporaries need finalization.
-- ???It's not clear why we need to return noncontrolled types with
-- controlled components on the secondary stack. Also, it's not clear
-- why nonprimitive tagged type functions need the secondary stack,
-- since they can't be called via dispatching.
elsif Is_Tagged_Type (Typ) or else Has_Controlled_Component (Typ) then
return not Is_Value_Type (Typ);
-- Indefinite (discriminated) untagged record or protected type
elsif Is_Record_Type (Typ) or else Is_Protected_Type (Typ) then
return not Caller_Known_Size_Record (Typ);
-- ???Should come after Is_Definite_Subtype below
-- Untagged definite subtypes are known size. This includes all
-- elementary [sub]types. Tasks are known size even if they have
-- discriminants.
elsif Is_Definite_Subtype (Typ) or else Is_Task_Type (Typ) then
if Is_Array_Type (Typ) -- ???Shouldn't be necessary
and then New_Requires_Transient_Scope
(Underlying_Type (Component_Type (Typ)))
then
return True;
end if;
return False;
-- Unconstrained array
else
pragma Assert (Is_Array_Type (Typ) and not Is_Definite_Subtype (Typ));
return True;
end if;
end New_Requires_Transient_Scope;
-------------------------- --------------------------
-- Reset_Analyzed_Flags -- -- Reset_Analyzed_Flags --
...@@ -19028,14 +19189,12 @@ package body Sem_Util is ...@@ -19028,14 +19189,12 @@ package body Sem_Util is
then then
return; return;
-- Conversely, type of expression may be the private one. -- Conversely, type of expression may be the private one
elsif Is_Private_Type (Base_Type (Etype (Expr))) elsif Is_Private_Type (Base_Type (Etype (Expr)))
and then Full_View (Base_Type (Etype (Expr))) = and then Full_View (Base_Type (Etype (Expr))) = Expected_Type
Expected_Type
then then
return; return;
end if; end if;
end if; end if;
...@@ -19049,11 +19208,11 @@ package body Sem_Util is ...@@ -19049,11 +19208,11 @@ package body Sem_Util is
and then Has_One_Matching_Field and then Has_One_Matching_Field
then then
Error_Msg_N ("positional aggregate cannot have one component", Expr); Error_Msg_N ("positional aggregate cannot have one component", Expr);
if Present (Matching_Field) then if Present (Matching_Field) then
if Is_Array_Type (Expec_Type) then if Is_Array_Type (Expec_Type) then
Error_Msg_NE Error_Msg_NE
("\write instead `&''First ='> ...`", Expr, Matching_Field); ("\write instead `&''First ='> ...`", Expr, Matching_Field);
else else
Error_Msg_NE Error_Msg_NE
("\write instead `& ='> ...`", Expr, Matching_Field); ("\write instead `& ='> ...`", Expr, Matching_Field);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment