-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2020, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2021, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- --
------------------------------------------------------------------------------
-with Atree; use Atree;
-with Debug; use Debug;
-with Einfo; use Einfo;
-with Elists; use Elists;
-with Errout; use Errout;
-with Exp_Disp; use Exp_Disp;
-with Exp_Tss; use Exp_Tss;
-with Exp_Util; use Exp_Util;
-with Freeze; use Freeze;
-with Ghost; use Ghost;
-with Impunit; use Impunit;
-with Lib; use Lib;
-with Lib.Load; use Lib.Load;
-with Lib.Xref; use Lib.Xref;
-with Namet; use Namet;
-with Namet.Sp; use Namet.Sp;
-with Nlists; use Nlists;
-with Nmake; use Nmake;
-with Opt; use Opt;
-with Output; use Output;
-with Restrict; use Restrict;
-with Rident; use Rident;
-with Rtsfind; use Rtsfind;
-with Sem; use Sem;
-with Sem_Aux; use Sem_Aux;
-with Sem_Cat; use Sem_Cat;
-with Sem_Ch3; use Sem_Ch3;
-with Sem_Ch4; use Sem_Ch4;
-with Sem_Ch6; use Sem_Ch6;
-with Sem_Ch12; use Sem_Ch12;
-with Sem_Ch13; use Sem_Ch13;
-with Sem_Dim; use Sem_Dim;
-with Sem_Disp; use Sem_Disp;
-with Sem_Dist; use Sem_Dist;
-with Sem_Elab; use Sem_Elab;
-with Sem_Eval; use Sem_Eval;
-with Sem_Prag; use Sem_Prag;
-with Sem_Res; use Sem_Res;
-with Sem_Util; use Sem_Util;
-with Sem_Type; use Sem_Type;
-with Stand; use Stand;
-with Sinfo; use Sinfo;
-with Sinfo.CN; use Sinfo.CN;
-with Snames; use Snames;
+with Atree; use Atree;
+with Debug; use Debug;
+with Einfo; use Einfo;
+with Einfo.Entities; use Einfo.Entities;
+with Einfo.Utils; use Einfo.Utils;
+with Elists; use Elists;
+with Errout; use Errout;
+with Exp_Disp; use Exp_Disp;
+with Exp_Tss; use Exp_Tss;
+with Exp_Util; use Exp_Util;
+with Freeze; use Freeze;
+with Ghost; use Ghost;
+with Impunit; use Impunit;
+with Lib; use Lib;
+with Lib.Load; use Lib.Load;
+with Lib.Xref; use Lib.Xref;
+with Namet; use Namet;
+with Namet.Sp; use Namet.Sp;
+with Nlists; use Nlists;
+with Nmake; use Nmake;
+with Opt; use Opt;
+with Output; use Output;
+with Restrict; use Restrict;
+with Rident; use Rident;
+with Rtsfind; use Rtsfind;
+with Sem; use Sem;
+with Sem_Aux; use Sem_Aux;
+with Sem_Cat; use Sem_Cat;
+with Sem_Ch3; use Sem_Ch3;
+with Sem_Ch4; use Sem_Ch4;
+with Sem_Ch6; use Sem_Ch6;
+with Sem_Ch10; use Sem_Ch10;
+with Sem_Ch12; use Sem_Ch12;
+with Sem_Ch13; use Sem_Ch13;
+with Sem_Dim; use Sem_Dim;
+with Sem_Disp; use Sem_Disp;
+with Sem_Dist; use Sem_Dist;
+with Sem_Elab; use Sem_Elab;
+with Sem_Eval; use Sem_Eval;
+with Sem_Prag; use Sem_Prag;
+with Sem_Res; use Sem_Res;
+with Sem_Util; use Sem_Util;
+with Sem_Type; use Sem_Type;
+with Stand; use Stand;
+with Sinfo; use Sinfo;
+with Sinfo.Nodes; use Sinfo.Nodes;
+with Sinfo.Utils; use Sinfo.Utils;
+with Sinfo.CN; use Sinfo.CN;
+with Snames; use Snames;
with Style;
with Table;
-with Tbuild; use Tbuild;
-with Uintp; use Uintp;
+with Tbuild; use Tbuild;
+with Uintp; use Uintp;
package body Sem_Ch8 is
-- body at the point of freezing will not work. Subp is the subprogram
-- for which N provides the Renaming_As_Body.
- procedure Check_In_Previous_With_Clause
- (N : Node_Id;
- Nam : Node_Id);
+ procedure Check_In_Previous_With_Clause (N, Nam : Node_Id);
-- N is a use_package clause and Nam the package name, or N is a use_type
-- clause and Nam is the prefix of the type name. In either case, verify
- -- that the package is visible at that point in the context: either it
+ -- that the package is visible at that point in the context: either it
-- appears in a previous with_clause, or because it is a fully qualified
-- name and the root ancestor appears in a previous with_clause.
-- legality of selector given the scope denoted by prefix, and change node
-- N into a expanded name with a properly set Entity field.
- function Find_Most_Prev (Use_Clause : Node_Id) return Node_Id;
+ function Find_First_Use (Use_Clause : Node_Id) return Node_Id;
-- Find the most previous use clause (that is, the first one to appear in
-- the source) by traversing the previous clause chain that exists in both
-- N_Use_Package_Clause nodes and N_Use_Type_Clause nodes.
- -- ??? a better subprogram name is in order
function Find_Renamed_Entity
(N : Node_Id;
Clause2 : Entity_Id) return Entity_Id;
-- Determine which use clause parameter is the most descendant in terms of
-- scope.
- -- ??? a better subprogram name is in order
procedure Premature_Usage (N : Node_Id);
-- Diagnose usage of an entity before it is visible
Enter_Name (Id);
Analyze (Nam);
- Set_Ekind (Id, E_Exception);
+ Mutate_Ekind (Id, E_Exception);
Set_Etype (Id, Standard_Exception_Type);
Set_Is_Pure (Id, Is_Pure (Current_Scope));
and then Present (Entity (Nam))
and then Ekind (Entity (Nam)) = E_Exception
then
- if Present (Renamed_Object (Entity (Nam))) then
- Set_Renamed_Object (Id, Renamed_Object (Entity (Nam)));
+ if Present (Renamed_Entity (Entity (Nam))) then
+ Set_Renamed_Entity (Id, Renamed_Entity (Entity (Nam)));
else
- Set_Renamed_Object (Id, Entity (Nam));
+ Set_Renamed_Entity (Id, Entity (Nam));
end if;
-- The exception renaming declaration may become Ghost if it renames
end if;
Enter_Name (New_P);
- Set_Ekind (New_P, K);
+ Mutate_Ekind (New_P, K);
if Etype (Old_P) = Any_Type then
null;
Error_Msg_N ("invalid generic unit name", Name (N));
else
- if Present (Renamed_Object (Old_P)) then
- Set_Renamed_Object (New_P, Renamed_Object (Old_P));
+ if Present (Renamed_Entity (Old_P)) then
+ Set_Renamed_Entity (New_P, Renamed_Entity (Old_P));
else
- Set_Renamed_Object (New_P, Old_P);
+ Set_Renamed_Entity (New_P, Old_P);
end if;
-- The generic renaming declaration may become Ghost if it renames a
-- For subprograms, propagate the Intrinsic flag, to allow, e.g.
-- renamings and subsequent instantiations of Unchecked_Conversion.
- if Ekind_In (Old_P, E_Generic_Function, E_Generic_Procedure) then
+ if Is_Generic_Subprogram (Old_P) then
Set_Is_Intrinsic_Subprogram
(New_P, Is_Intrinsic_Subprogram (Old_P));
end if;
Dec : Node_Id;
T : Entity_Id;
T2 : Entity_Id;
+ Q : Node_Id;
procedure Check_Constrained_Object;
-- If the nominal type is unconstrained but the renamed object is
-- Obtain the name of the object from node Nod which is being renamed by
-- the object renaming declaration N.
+ function Find_Raise_Node (N : Node_Id) return Traverse_Result;
+ -- Process one node in search for N_Raise_xxx_Error nodes.
+ -- Return Abandon if found, OK otherwise.
+
+ ---------------------
+ -- Find_Raise_Node --
+ ---------------------
+
+ function Find_Raise_Node (N : Node_Id) return Traverse_Result is
+ begin
+ if Nkind (N) in N_Raise_xxx_Error then
+ return Abandon;
+ else
+ return OK;
+ end if;
+ end Find_Raise_Node;
+
+ ------------------------
+ -- No_Raise_xxx_Error --
+ ------------------------
+
+ function No_Raise_xxx_Error is new Traverse_Func (Find_Raise_Node);
+ -- Traverse tree to look for a N_Raise_xxx_Error node and returns
+ -- Abandon if so and OK if none found.
+
------------------------------
-- Check_Constrained_Object --
------------------------------
procedure Check_Constrained_Object is
- Typ : constant Entity_Id := Etype (Nam);
- Subt : Entity_Id;
+ Typ : constant Entity_Id := Etype (Nam);
+ Subt : Entity_Id;
+ Loop_Scheme : Node_Id;
begin
- if Nkind_In (Nam, N_Function_Call, N_Explicit_Dereference)
+ if Nkind (Nam) in N_Function_Call | N_Explicit_Dereference
and then Is_Composite_Type (Typ)
and then not Is_Constrained (Typ)
and then not Has_Unknown_Discriminants (Typ)
then
-- If Actual_Subtype is already set, nothing to do
- if Ekind_In (Id, E_Variable, E_Constant)
+ if Ekind (Id) in E_Variable | E_Constant
and then Present (Actual_Subtype (Id))
then
null;
-- that are used in iterators. This is an optimization, but it
-- also prevents typing anomalies when the prefix is further
-- expanded.
+
-- Note that we cannot just use the Is_Limited_Record flag because
-- it does not apply to records with limited components, for which
-- this syntactic flag is not set, but whose size is also fixed.
- elsif Is_Limited_Type (Typ) then
+ -- Note also that we need to build the constrained subtype for an
+ -- array in order to make the bounds explicit in most cases, but
+ -- not if the object comes from an extended return statement, as
+ -- this would create dangling references to them later on.
+
+ elsif Is_Limited_Type (Typ)
+ and then (not Is_Array_Type (Typ) or else Is_Return_Object (Id))
+ then
null;
else
Rewrite (Subtype_Mark (N), New_Occurrence_Of (Subt, Loc));
Set_Etype (Nam, Subt);
+ -- Suppress discriminant checks on this subtype if the original
+ -- type has defaulted discriminants and Id is a "for of" loop
+ -- iterator.
+
+ if Has_Defaulted_Discriminants (Typ)
+ and then Nkind (Original_Node (Parent (N))) = N_Loop_Statement
+ then
+ Loop_Scheme := Iteration_Scheme (Original_Node (Parent (N)));
+
+ if Present (Loop_Scheme)
+ and then Present (Iterator_Specification (Loop_Scheme))
+ and then
+ Defining_Identifier
+ (Iterator_Specification (Loop_Scheme)) = Id
+ then
+ Set_Checks_May_Be_Suppressed (Subt);
+ Push_Local_Suppress_Stack_Entry
+ (Entity => Subt,
+ Check => Discriminant_Check,
+ Suppress => True);
+ end if;
+ end if;
+
-- Freeze subtype at once, to prevent order of elaboration
-- issues in the backend. The renamed object exists, so its
-- type is already frozen in any case.
if No (Etype (Nam))
or else Etype (Nam) = Standard_Void_Type
then
- Error_Msg_N ("object name expected in renaming", Nam);
+ Error_Msg_N
+ ("object name or value expected in renaming", Nam);
- Set_Ekind (Id, E_Variable);
+ Mutate_Ekind (Id, E_Variable);
Set_Etype (Id, Any_Type);
return;
-- as overloaded procedures named in the object renaming).
if No (It.Typ) then
- Error_Msg_N ("object name expected in renaming", Nam);
+ Error_Msg_N
+ ("object name or value expected in renaming", Nam);
- Set_Ekind (Id, E_Variable);
+ Mutate_Ekind (Id, E_Variable);
Set_Etype (Id, Any_Type);
return;
T := It1.Typ;
end;
end if;
+
+ if Etype (Nam) = Standard_Exception_Type then
+ Error_Msg_N
+ ("exception requires a subtype mark in renaming", Nam);
+ return;
+ end if;
end if;
-- The object renaming declaration may become Ghost if it renames a
Mark_Ghost_Renaming (N, Entity (Nam));
end if;
+ -- Check against AI12-0401 here before Resolve may rewrite Nam and
+ -- potentially generate spurious warnings.
+
+ -- In the case where the object_name is a qualified_expression with
+ -- a nominal subtype T and whose expression is a name that denotes
+ -- an object Q:
+ -- * if T is an elementary subtype, then:
+ -- * Q shall be a constant other than a dereference of an access
+ -- type; or
+ -- * the nominal subtype of Q shall be statically compatible with
+ -- T; or
+ -- * T shall statically match the base subtype of its type if
+ -- scalar, or the first subtype of its type if an access type.
+ -- * if T is a composite subtype, then Q shall be known to be
+ -- constrained or T shall statically match the first subtype of
+ -- its type.
+
+ if Nkind (Nam) = N_Qualified_Expression
+ and then Is_Object_Reference (Expression (Nam))
+ then
+ Q := Expression (Nam);
+
+ if (Is_Elementary_Type (T)
+ and then
+ not ((not Is_Variable (Q)
+ and then Nkind (Q) /= N_Explicit_Dereference)
+ or else Subtypes_Statically_Compatible (Etype (Q), T)
+ or else (Is_Scalar_Type (T)
+ and then Subtypes_Statically_Match
+ (T, Base_Type (T)))
+ or else (Is_Access_Type (T)
+ and then Subtypes_Statically_Match
+ (T, First_Subtype (T)))))
+ or else (Is_Composite_Type (T)
+ and then
+
+ -- If Q is an aggregate, Is_Constrained may not be set
+ -- yet and its type may not be resolved yet.
+ -- This doesn't quite correspond to the complex notion
+ -- of "known to be constrained" but this is good enough
+ -- for a rule which is in any case too complex.
+
+ not (Is_Constrained (Etype (Q))
+ or else Nkind (Q) = N_Aggregate
+ or else Subtypes_Statically_Match
+ (T, First_Subtype (T))))
+ then
+ Error_Msg_N
+ ("subtype of renamed qualified expression does not " &
+ "statically match", N);
+ return;
+ end if;
+ end if;
+
Resolve (Nam, T);
-- If the renamed object is a function call of a limited type,
and then Comes_From_Source (N)
then
Set_Etype (Id, T);
- Set_Ekind (Id, E_Constant);
+ Mutate_Ekind (Id, E_Constant);
Rewrite (N,
Make_Object_Declaration (Loc,
Defining_Identifier => Id,
and then Is_Anonymous_Access_Type (Etype (Expression (Nam)))
and then not Is_Anonymous_Access_Type (T)
then
- Wrong_Type (Expression (Nam), T); -- Should we give better error???
+ Error_Msg_NE
+ ("cannot rename anonymous access object "
+ & "as a named access type", Expression (Nam), T);
end if;
-- Check that a class-wide object is not being renamed as an object
and then Comes_From_Source (Nam)
then
Error_Msg_N
- ("renaming function result object is suspicious?R?", Nam);
+ ("renaming function result object is suspicious?.r?", Nam);
Error_Msg_NE
- ("\function & will be called only once?R?", Nam,
+ ("\function & will be called only once?.r?", Nam,
Entity (Name (Nam)));
Error_Msg_N -- CODEFIX
("\suggest using an initialized constant object "
- & "instead?R?", Nam);
+ & "instead?.r?", Nam);
end if;
end case;
end if;
-- want to change it to a variable.
if Ekind (Id) /= E_Constant then
- Set_Ekind (Id, E_Variable);
+ Mutate_Ekind (Id, E_Variable);
end if;
- -- Initialize the object size and alignment. Note that we used to call
- -- Init_Size_Align here, but that's wrong for objects which have only
- -- an Esize, not an RM_Size field.
-
- Init_Object_Size_Align (Id);
+ Reinit_Object_Size_Align (Id);
-- If N comes from source then check that the original node is an
-- object reference since there may have been several rewritting and
-- check.
if Comes_From_Source (N) then
- if Nkind_In (Nam, N_Function_Call, N_Explicit_Dereference) then
+ if Nkind (Nam) in N_Function_Call | N_Explicit_Dereference then
Is_Object_Ref := Is_Object_Reference (Nam);
else
Is_Object_Ref := Is_Object_Reference (Original_Node (Nam));
and then Nkind (Original_Node (Nam)) /= N_Attribute_Reference
then
null;
- else
- Error_Msg_N ("expect object name in renaming", Nam);
+
+ -- A named number can only be renamed without a subtype mark
+
+ elsif Nkind (Nam) in N_Real_Literal | N_Integer_Literal
+ and then Present (Subtype_Mark (N))
+ and then Present (Original_Entity (Nam))
+ then
+ Error_Msg_N ("incompatible types in renaming", Nam);
+
+ -- AI12-0383: Names that denote values can be renamed.
+ -- Ignore (accept) N_Raise_xxx_Error nodes in this context.
+
+ elsif No_Raise_xxx_Error (Nam) = OK then
+ Error_Msg_Ada_2022_Feature ("value in renaming", Sloc (Nam));
end if;
Set_Etype (Id, T2);
if not Is_Variable (Nam) then
- Set_Ekind (Id, E_Constant);
+ Mutate_Ekind (Id, E_Constant);
Set_Never_Set_In_Source (Id, True);
Set_Is_True_Constant (Id, True);
end if;
-- renamed object is atomic, independent, volatile or VFA. These flags
-- are set on the renamed object in the RM legality sense.
- Set_Is_Atomic (Id, Is_Atomic_Object (Nam));
- Set_Is_Independent (Id, Is_Independent_Object (Nam));
- Set_Is_Volatile (Id, Is_Volatile_Object (Nam));
- Set_Is_Volatile_Full_Access (Id, Is_Volatile_Full_Access_Object (Nam));
+ Set_Is_Atomic (Id, Is_Atomic_Object (Nam));
+ Set_Is_Independent (Id, Is_Independent_Object (Nam));
+ Set_Is_Volatile (Id, Is_Volatile_Object_Ref (Nam));
+ Set_Is_Volatile_Full_Access
+ (Id, Is_Volatile_Full_Access_Object_Ref (Nam));
-- Treat as volatile if we just set the Volatile flag
-- Set basic attributes to minimize cascaded errors
- Set_Ekind (New_P, E_Package);
+ Mutate_Ekind (New_P, E_Package);
+ Set_Etype (New_P, Standard_Void_Type);
+
+ elsif Present (Renamed_Entity (Old_P))
+ and then (From_Limited_With (Renamed_Entity (Old_P))
+ or else Has_Limited_View (Renamed_Entity (Old_P)))
+ and then not
+ Unit_Is_Visible (Cunit (Get_Source_Unit (Renamed_Entity (Old_P))))
+ then
+ Error_Msg_NE
+ ("renaming of limited view of package & not usable in this context"
+ & " (RM 8.5.3(3.1/2))", Name (N), Renamed_Entity (Old_P));
+
+ -- Set basic attributes to minimize cascaded errors
+
+ Mutate_Ekind (New_P, E_Package);
Set_Etype (New_P, Standard_Void_Type);
-- Here for OK package renaming
-- entity. The simplest implementation is to have both packages share
-- the entity list.
- Set_Ekind (New_P, E_Package);
+ Mutate_Ekind (New_P, E_Package);
Set_Etype (New_P, Standard_Void_Type);
- if Present (Renamed_Object (Old_P)) then
- Set_Renamed_Object (New_P, Renamed_Object (Old_P));
+ if Present (Renamed_Entity (Old_P)) then
+ Set_Renamed_Entity (New_P, Renamed_Entity (Old_P));
else
- Set_Renamed_Object (New_P, Old_P);
+ Set_Renamed_Entity (New_P, Old_P);
end if;
-- The package renaming declaration may become Ghost if it renames a
Old_S := Find_Renamed_Entity (N, Selector_Name (Nam), New_S);
if Old_S = Any_Id then
- Error_Msg_N (" no subprogram or entry matches specification", N);
+ Error_Msg_N ("no subprogram or entry matches specification", N);
else
if Is_Body then
Check_Subtype_Conformant (New_S, Old_S, N);
Old_S : Entity_Id := Empty;
Rename_Spec : Entity_Id;
- procedure Build_Class_Wide_Wrapper
- (Ren_Id : out Entity_Id;
- Wrap_Id : out Entity_Id);
- -- Ada 2012 (AI05-0071): A generic/instance scenario involving a formal
- -- type with unknown discriminants and a generic primitive operation of
- -- the said type with a box require special processing when the actual
- -- is a class-wide type:
- --
- -- generic
- -- type Formal_Typ (<>) is private;
- -- with procedure Prim_Op (Param : Formal_Typ) is <>;
- -- package Gen is ...
- --
- -- package Inst is new Gen (Actual_Typ'Class);
- --
- -- In this case the general renaming mechanism used in the prologue of
- -- an instance no longer applies:
- --
- -- procedure Prim_Op (Param : Formal_Typ) renames Prim_Op;
- --
- -- The above is replaced the following wrapper/renaming combination:
- --
- -- procedure Wrapper (Param : Formal_Typ) is -- wrapper
- -- begin
- -- Prim_Op (Param); -- primitive
- -- end Wrapper;
- --
- -- procedure Prim_Op (Param : Formal_Typ) renames Wrapper;
- --
- -- This transformation applies only if there is no explicit visible
- -- class-wide operation at the point of the instantiation. Ren_Id is
- -- the entity of the renaming declaration. When the transformation
- -- applies, Wrap_Id is the entity of the generated class-wide wrapper
- -- (or Any_Id). Otherwise, Wrap_Id is the entity of the class-wide
- -- operation.
-
procedure Check_Null_Exclusion
(Ren : Entity_Id;
Sub : Entity_Id);
-- incomplete untagged formal (RM 13.14(10.2/3)).
function Has_Class_Wide_Actual return Boolean;
- -- Ada 2012 (AI05-071, AI05-0131): True if N is the renaming for a
- -- defaulted formal subprogram where the actual for the controlling
- -- formal type is class-wide.
+ -- Ada 2012 (AI05-071, AI05-0131) and Ada 2022 (AI12-0165): True if N is
+ -- the renaming for a defaulted formal subprogram where the actual for
+ -- the controlling formal type is class-wide.
+
+ procedure Handle_Instance_With_Class_Wide_Type
+ (Inst_Node : Node_Id;
+ Ren_Id : Entity_Id;
+ Wrapped_Prim : out Entity_Id;
+ Wrap_Id : out Entity_Id);
+ -- Ada 2012 (AI05-0071), Ada 2022 (AI12-0165): when the actual type
+ -- of an instantiation is a class-wide type T'Class we may need to
+ -- wrap a primitive operation of T; this routine looks for a suitable
+ -- primitive to be wrapped and (if the wrapper is required) returns the
+ -- Id of the wrapped primitive and the Id of the built wrapper. Ren_Id
+ -- is the defining entity for the renamed subprogram specification.
function Original_Subprogram (Subp : Entity_Id) return Entity_Id;
-- Find renamed entity when the declaration is a renaming_as_body and
-- before the subprogram it completes is frozen, and renaming indirectly
-- renames the subprogram itself.(Defect Report 8652/0027).
- ------------------------------
- -- Build_Class_Wide_Wrapper --
- ------------------------------
+ --------------------------
+ -- Check_Null_Exclusion --
+ --------------------------
- procedure Build_Class_Wide_Wrapper
- (Ren_Id : out Entity_Id;
- Wrap_Id : out Entity_Id)
+ procedure Check_Null_Exclusion
+ (Ren : Entity_Id;
+ Sub : Entity_Id)
is
- Loc : constant Source_Ptr := Sloc (N);
-
- function Build_Call
- (Subp_Id : Entity_Id;
- Params : List_Id) return Node_Id;
- -- Create a dispatching call to invoke routine Subp_Id with actuals
- -- built from the parameter specifications of list Params.
-
- function Build_Expr_Fun_Call
- (Subp_Id : Entity_Id;
- Params : List_Id) return Node_Id;
- -- Create a dispatching call to invoke function Subp_Id with actuals
- -- built from the parameter specifications of list Params. Return
- -- directly the call, so that it can be used inside an expression
- -- function. This is a specificity of the GNATprove mode.
-
- function Build_Spec (Subp_Id : Entity_Id) return Node_Id;
- -- Create a subprogram specification based on the subprogram profile
- -- of Subp_Id.
-
- function Find_Primitive (Typ : Entity_Id) return Entity_Id;
- -- Find a primitive subprogram of type Typ which matches the profile
- -- of the renaming declaration.
-
- procedure Interpretation_Error (Subp_Id : Entity_Id);
- -- Emit a continuation error message suggesting subprogram Subp_Id as
- -- a possible interpretation.
-
- function Is_Intrinsic_Equality (Subp_Id : Entity_Id) return Boolean;
- -- Determine whether subprogram Subp_Id denotes the intrinsic "="
- -- operator.
-
- function Is_Suitable_Candidate (Subp_Id : Entity_Id) return Boolean;
- -- Determine whether subprogram Subp_Id is a suitable candidate for
- -- the role of a wrapped subprogram.
-
- ----------------
- -- Build_Call --
- ----------------
-
- function Build_Call
- (Subp_Id : Entity_Id;
- Params : List_Id) return Node_Id
- is
- Actuals : constant List_Id := New_List;
- Call_Ref : constant Node_Id := New_Occurrence_Of (Subp_Id, Loc);
- Formal : Node_Id;
+ Ren_Formal : Entity_Id;
+ Sub_Formal : Entity_Id;
+
+ function Null_Exclusion_Mismatch
+ (Renaming : Entity_Id; Renamed : Entity_Id) return Boolean;
+ -- Return True if there is a null exclusion mismatch between
+ -- Renaming and Renamed, False otherwise.
+ -----------------------------
+ -- Null_Exclusion_Mismatch --
+ -----------------------------
+
+ function Null_Exclusion_Mismatch
+ (Renaming : Entity_Id; Renamed : Entity_Id) return Boolean is
begin
- -- Build the actual parameters of the call
+ return Has_Null_Exclusion (Parent (Renaming))
+ and then
+ not (Has_Null_Exclusion (Parent (Renamed))
+ or else (Can_Never_Be_Null (Etype (Renamed))
+ and then not
+ (Is_Formal_Subprogram (Sub)
+ and then In_Generic_Body (Current_Scope))));
+ end Null_Exclusion_Mismatch;
- Formal := First (Params);
- while Present (Formal) loop
- Append_To (Actuals,
- Make_Identifier (Loc, Chars (Defining_Identifier (Formal))));
- Next (Formal);
- end loop;
+ begin
+ -- Parameter check
- -- Generate:
- -- return Subp_Id (Actuals);
+ Ren_Formal := First_Formal (Ren);
+ Sub_Formal := First_Formal (Sub);
+ while Present (Ren_Formal) and then Present (Sub_Formal) loop
+ if Null_Exclusion_Mismatch (Ren_Formal, Sub_Formal) then
+ Error_Msg_Sloc := Sloc (Sub_Formal);
+ Error_Msg_NE
+ ("`NOT NULL` required for parameter &#",
+ Ren_Formal, Sub_Formal);
+ end if;
- if Ekind_In (Subp_Id, E_Function, E_Operator) then
- return
- Make_Simple_Return_Statement (Loc,
- Expression =>
- Make_Function_Call (Loc,
- Name => Call_Ref,
- Parameter_Associations => Actuals));
+ Next_Formal (Ren_Formal);
+ Next_Formal (Sub_Formal);
+ end loop;
- -- Generate:
- -- Subp_Id (Actuals);
+ -- Return profile check
- else
- return
- Make_Procedure_Call_Statement (Loc,
- Name => Call_Ref,
- Parameter_Associations => Actuals);
- end if;
- end Build_Call;
+ if Nkind (Parent (Ren)) = N_Function_Specification
+ and then Nkind (Parent (Sub)) = N_Function_Specification
+ and then Null_Exclusion_Mismatch (Ren, Sub)
+ then
+ Error_Msg_Sloc := Sloc (Sub);
+ Error_Msg_N ("return must specify `NOT NULL`#", Ren);
+ end if;
+ end Check_Null_Exclusion;
- -------------------------
- -- Build_Expr_Fun_Call --
- -------------------------
+ -------------------------------------
+ -- Check_SPARK_Primitive_Operation --
+ -------------------------------------
- function Build_Expr_Fun_Call
- (Subp_Id : Entity_Id;
- Params : List_Id) return Node_Id
- is
- Actuals : constant List_Id := New_List;
- Call_Ref : constant Node_Id := New_Occurrence_Of (Subp_Id, Loc);
- Formal : Node_Id;
+ procedure Check_SPARK_Primitive_Operation (Subp_Id : Entity_Id) is
+ Prag : constant Node_Id := SPARK_Pragma (Subp_Id);
+ Typ : Entity_Id;
- begin
- pragma Assert (Ekind_In (Subp_Id, E_Function, E_Operator));
+ begin
+ -- Nothing to do when the subprogram is not subject to SPARK_Mode On
+ -- because this check applies to SPARK code only.
- -- Build the actual parameters of the call
+ if not (Present (Prag)
+ and then Get_SPARK_Mode_From_Annotation (Prag) = On)
+ then
+ return;
- Formal := First (Params);
- while Present (Formal) loop
- Append_To (Actuals,
- Make_Identifier (Loc, Chars (Defining_Identifier (Formal))));
- Next (Formal);
- end loop;
+ -- Nothing to do when the subprogram is not a primitive operation
- -- Generate:
- -- Subp_Id (Actuals);
+ elsif not Is_Primitive (Subp_Id) then
+ return;
+ end if;
- return
- Make_Function_Call (Loc,
- Name => Call_Ref,
- Parameter_Associations => Actuals);
- end Build_Expr_Fun_Call;
+ Typ := Find_Dispatching_Type (Subp_Id);
- ----------------
- -- Build_Spec --
- ----------------
+ -- Nothing to do when the subprogram is a primitive operation of an
+ -- untagged type.
- function Build_Spec (Subp_Id : Entity_Id) return Node_Id is
- Params : constant List_Id := Copy_Parameter_List (Subp_Id);
- Spec_Id : constant Entity_Id :=
- Make_Defining_Identifier (Loc,
- Chars => New_External_Name (Chars (Subp_Id), 'R'));
+ if No (Typ) then
+ return;
+ end if;
- begin
- if Ekind (Formal_Spec) = E_Procedure then
- return
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Spec_Id,
- Parameter_Specifications => Params);
- else
- return
- Make_Function_Specification (Loc,
- Defining_Unit_Name => Spec_Id,
- Parameter_Specifications => Params,
- Result_Definition =>
- New_Copy_Tree (Result_Definition (Spec)));
- end if;
- end Build_Spec;
+ -- At this point a renaming declaration introduces a new primitive
+ -- operation for a tagged type.
- --------------------
- -- Find_Primitive --
- --------------------
+ Error_Msg_Node_2 := Typ;
+ Error_Msg_NE
+ ("subprogram renaming & cannot declare primitive for type & "
+ & "(SPARK RM 6.1.1(3))", N, Subp_Id);
+ end Check_SPARK_Primitive_Operation;
- function Find_Primitive (Typ : Entity_Id) return Entity_Id is
- procedure Replace_Parameter_Types (Spec : Node_Id);
- -- Given a specification Spec, replace all class-wide parameter
- -- types with reference to type Typ.
+ ---------------------------
+ -- Freeze_Actual_Profile --
+ ---------------------------
- -----------------------------
- -- Replace_Parameter_Types --
- -----------------------------
+ procedure Freeze_Actual_Profile is
+ F : Entity_Id;
+ Has_Untagged_Inc : Boolean;
+ Instantiation_Node : constant Node_Id := Parent (N);
- procedure Replace_Parameter_Types (Spec : Node_Id) is
- Formal : Node_Id;
- Formal_Id : Entity_Id;
- Formal_Typ : Node_Id;
+ begin
+ if Ada_Version >= Ada_2012 then
+ F := First_Formal (Formal_Spec);
+ Has_Untagged_Inc := False;
+ while Present (F) loop
+ if Ekind (Etype (F)) = E_Incomplete_Type
+ and then not Is_Tagged_Type (Etype (F))
+ then
+ Has_Untagged_Inc := True;
+ exit;
+ end if;
- begin
- Formal := First (Parameter_Specifications (Spec));
- while Present (Formal) loop
- Formal_Id := Defining_Identifier (Formal);
- Formal_Typ := Parameter_Type (Formal);
+ Next_Formal (F);
+ end loop;
+
+ if Ekind (Formal_Spec) = E_Function
+ and then not Is_Tagged_Type (Etype (Formal_Spec))
+ then
+ Has_Untagged_Inc := True;
+ end if;
- -- Create a new entity for each class-wide formal to prevent
- -- aliasing with the original renaming. Replace the type of
- -- such a parameter with the candidate type.
+ if not Has_Untagged_Inc then
+ F := First_Formal (Old_S);
+ while Present (F) loop
+ Freeze_Before (Instantiation_Node, Etype (F));
- if Nkind (Formal_Typ) = N_Identifier
- and then Is_Class_Wide_Type (Etype (Formal_Typ))
+ if Is_Incomplete_Or_Private_Type (Etype (F))
+ and then No (Underlying_Type (Etype (F)))
then
- Set_Defining_Identifier (Formal,
- Make_Defining_Identifier (Loc, Chars (Formal_Id)));
+ -- Exclude generic types, or types derived from them.
+ -- They will be frozen in the enclosing instance.
- Set_Parameter_Type (Formal, New_Occurrence_Of (Typ, Loc));
+ if Is_Generic_Type (Etype (F))
+ or else Is_Generic_Type (Root_Type (Etype (F)))
+ then
+ null;
+
+ -- A limited view of a type declared elsewhere needs no
+ -- freezing actions.
+
+ elsif From_Limited_With (Etype (F)) then
+ null;
+
+ else
+ Error_Msg_NE
+ ("type& must be frozen before this point",
+ Instantiation_Node, Etype (F));
+ end if;
end if;
- Next (Formal);
+ Next_Formal (F);
end loop;
- end Replace_Parameter_Types;
-
- -- Local variables
+ end if;
+ end if;
+ end Freeze_Actual_Profile;
- Alt_Ren : constant Node_Id := New_Copy_Tree (N);
- Alt_Nam : constant Node_Id := Name (Alt_Ren);
- Alt_Spec : constant Node_Id := Specification (Alt_Ren);
- Subp_Id : Entity_Id;
+ ---------------------------
+ -- Has_Class_Wide_Actual --
+ ---------------------------
- -- Start of processing for Find_Primitive
+ function Has_Class_Wide_Actual return Boolean is
+ Formal : Entity_Id;
+ Formal_Typ : Entity_Id;
- begin
- -- Each attempt to find a suitable primitive of a particular type
- -- operates on its own copy of the original renaming. As a result
- -- the original renaming is kept decoration and side-effect free.
+ begin
+ if Is_Actual then
+ Formal := First_Formal (Formal_Spec);
+ while Present (Formal) loop
+ Formal_Typ := Etype (Formal);
- -- Inherit the overloaded status of the renamed subprogram name
+ if Has_Unknown_Discriminants (Formal_Typ)
+ and then not Is_Class_Wide_Type (Formal_Typ)
+ and then Is_Class_Wide_Type (Get_Instance_Of (Formal_Typ))
+ then
+ return True;
+ end if;
- if Is_Overloaded (Nam) then
- Set_Is_Overloaded (Alt_Nam);
- Save_Interps (Nam, Alt_Nam);
- end if;
+ Next_Formal (Formal);
+ end loop;
+ end if;
- -- The copied renaming is hidden from visibility to prevent the
- -- pollution of the enclosing context.
+ return False;
+ end Has_Class_Wide_Actual;
- Set_Defining_Unit_Name (Alt_Spec, Make_Temporary (Loc, 'R'));
+ ------------------------------------------
+ -- Handle_Instance_With_Class_Wide_Type --
+ ------------------------------------------
- -- The types of all class-wide parameters must be changed to the
- -- candidate type.
+ procedure Handle_Instance_With_Class_Wide_Type
+ (Inst_Node : Node_Id;
+ Ren_Id : Entity_Id;
+ Wrapped_Prim : out Entity_Id;
+ Wrap_Id : out Entity_Id)
+ is
+ procedure Build_Class_Wide_Wrapper
+ (Ren_Id : Entity_Id;
+ Prim_Op : Entity_Id;
+ Wrap_Id : out Entity_Id);
+ -- Build a wrapper for the renaming Ren_Id of subprogram Prim_Op.
+
+ procedure Find_Suitable_Candidate
+ (Prim_Op : out Entity_Id;
+ Is_CW_Prim : out Boolean);
+ -- Look for a suitable primitive to be wrapped (Prim_Op); Is_CW_Prim
+ -- indicates that the found candidate is a class-wide primitive (to
+ -- help the caller decide if the wrapper is required).
+
+ ------------------------------
+ -- Build_Class_Wide_Wrapper --
+ ------------------------------
+
+ procedure Build_Class_Wide_Wrapper
+ (Ren_Id : Entity_Id;
+ Prim_Op : Entity_Id;
+ Wrap_Id : out Entity_Id)
+ is
+ Loc : constant Source_Ptr := Sloc (N);
+
+ function Build_Call
+ (Subp_Id : Entity_Id;
+ Params : List_Id) return Node_Id;
+ -- Create a dispatching call to invoke routine Subp_Id with
+ -- actuals built from the parameter specifications of list Params.
+
+ function Build_Expr_Fun_Call
+ (Subp_Id : Entity_Id;
+ Params : List_Id) return Node_Id;
+ -- Create a dispatching call to invoke function Subp_Id with
+ -- actuals built from the parameter specifications of list Params.
+ -- Directly return the call, so that it can be used inside an
+ -- expression function. This is a requirement of GNATprove mode.
+
+ function Build_Spec (Subp_Id : Entity_Id) return Node_Id;
+ -- Create a subprogram specification based on the subprogram
+ -- profile of Subp_Id.
+
+ ----------------
+ -- Build_Call --
+ ----------------
+
+ function Build_Call
+ (Subp_Id : Entity_Id;
+ Params : List_Id) return Node_Id
+ is
+ Actuals : constant List_Id := New_List;
+ Call_Ref : constant Node_Id := New_Occurrence_Of (Subp_Id, Loc);
+ Formal : Node_Id;
- Replace_Parameter_Types (Alt_Spec);
+ begin
+ -- Build the actual parameters of the call
- -- Try to find a suitable primitive which matches the altered
- -- profile of the renaming specification.
+ Formal := First (Params);
+ while Present (Formal) loop
+ Append_To (Actuals,
+ Make_Identifier (Loc,
+ Chars (Defining_Identifier (Formal))));
+ Next (Formal);
+ end loop;
- Subp_Id :=
- Find_Renamed_Entity
- (N => Alt_Ren,
- Nam => Name (Alt_Ren),
- New_S => Analyze_Subprogram_Specification (Alt_Spec),
- Is_Actual => Is_Actual);
+ -- Generate:
+ -- return Subp_Id (Actuals);
- -- Do not return Any_Id if the resolion of the altered profile
- -- failed as this complicates further checks on the caller side,
- -- return Empty instead.
+ if Ekind (Subp_Id) in E_Function | E_Operator then
+ return
+ Make_Simple_Return_Statement (Loc,
+ Expression =>
+ Make_Function_Call (Loc,
+ Name => Call_Ref,
+ Parameter_Associations => Actuals));
- if Subp_Id = Any_Id then
- return Empty;
- else
- return Subp_Id;
- end if;
- end Find_Primitive;
+ -- Generate:
+ -- Subp_Id (Actuals);
- --------------------------
- -- Interpretation_Error --
- --------------------------
+ else
+ return
+ Make_Procedure_Call_Statement (Loc,
+ Name => Call_Ref,
+ Parameter_Associations => Actuals);
+ end if;
+ end Build_Call;
- procedure Interpretation_Error (Subp_Id : Entity_Id) is
- begin
- Error_Msg_Sloc := Sloc (Subp_Id);
+ -------------------------
+ -- Build_Expr_Fun_Call --
+ -------------------------
- if Is_Internal (Subp_Id) then
- Error_Msg_NE
- ("\\possible interpretation: predefined & #",
- Spec, Formal_Spec);
- else
- Error_Msg_NE
- ("\\possible interpretation: & defined #", Spec, Formal_Spec);
- end if;
- end Interpretation_Error;
+ function Build_Expr_Fun_Call
+ (Subp_Id : Entity_Id;
+ Params : List_Id) return Node_Id
+ is
+ Actuals : constant List_Id := New_List;
+ Call_Ref : constant Node_Id := New_Occurrence_Of (Subp_Id, Loc);
+ Formal : Node_Id;
- ---------------------------
- -- Is_Intrinsic_Equality --
- ---------------------------
+ begin
+ pragma Assert (Ekind (Subp_Id) in E_Function | E_Operator);
- function Is_Intrinsic_Equality (Subp_Id : Entity_Id) return Boolean is
- begin
- return
- Ekind (Subp_Id) = E_Operator
- and then Chars (Subp_Id) = Name_Op_Eq
- and then Is_Intrinsic_Subprogram (Subp_Id);
- end Is_Intrinsic_Equality;
+ -- Build the actual parameters of the call
- ---------------------------
- -- Is_Suitable_Candidate --
- ---------------------------
+ Formal := First (Params);
+ while Present (Formal) loop
+ Append_To (Actuals,
+ Make_Identifier (Loc,
+ Chars (Defining_Identifier (Formal))));
+ Next (Formal);
+ end loop;
- function Is_Suitable_Candidate (Subp_Id : Entity_Id) return Boolean is
- begin
- if No (Subp_Id) then
- return False;
+ -- Generate:
+ -- Subp_Id (Actuals);
- -- An intrinsic subprogram is never a good candidate. This is an
- -- indication of a missing primitive, either defined directly or
- -- inherited from a parent tagged type.
+ return
+ Make_Function_Call (Loc,
+ Name => Call_Ref,
+ Parameter_Associations => Actuals);
+ end Build_Expr_Fun_Call;
- elsif Is_Intrinsic_Subprogram (Subp_Id) then
- return False;
+ ----------------
+ -- Build_Spec --
+ ----------------
- else
- return True;
- end if;
- end Is_Suitable_Candidate;
+ function Build_Spec (Subp_Id : Entity_Id) return Node_Id is
+ Params : constant List_Id := Copy_Parameter_List (Subp_Id);
+ Spec_Id : constant Entity_Id :=
+ Make_Defining_Identifier (Loc,
+ New_External_Name (Chars (Subp_Id), 'R'));
- -- Local variables
+ begin
+ if Ekind (Formal_Spec) = E_Procedure then
+ return
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Spec_Id,
+ Parameter_Specifications => Params);
+ else
+ return
+ Make_Function_Specification (Loc,
+ Defining_Unit_Name => Spec_Id,
+ Parameter_Specifications => Params,
+ Result_Definition =>
+ New_Copy_Tree (Result_Definition (Spec)));
+ end if;
+ end Build_Spec;
- Actual_Typ : Entity_Id := Empty;
- -- The actual class-wide type for Formal_Typ
+ -- Local variables
- CW_Prim_OK : Boolean;
- CW_Prim_Op : Entity_Id;
- -- The class-wide subprogram (if available) which corresponds to the
- -- renamed generic formal subprogram.
+ Body_Decl : Node_Id;
+ Spec_Decl : Node_Id;
+ New_Spec : Node_Id;
- Formal_Typ : Entity_Id := Empty;
- -- The generic formal type with unknown discriminants
+ -- Start of processing for Build_Class_Wide_Wrapper
- Root_Prim_OK : Boolean;
- Root_Prim_Op : Entity_Id;
- -- The root type primitive (if available) which corresponds to the
- -- renamed generic formal subprogram.
+ begin
+ pragma Assert (not Error_Posted (Nam));
- Root_Typ : Entity_Id := Empty;
- -- The root type of Actual_Typ
+ -- Step 1: Create the declaration and the body of the wrapper,
+ -- insert all the pieces into the tree.
- Body_Decl : Node_Id;
- Formal : Node_Id;
- Prim_Op : Entity_Id;
- Spec_Decl : Node_Id;
- New_Spec : Node_Id;
+ -- In GNATprove mode, create a function wrapper in the form of an
+ -- expression function, so that an implicit postcondition relating
+ -- the result of calling the wrapper function and the result of
+ -- the dispatching call to the wrapped function is known during
+ -- proof.
- -- Start of processing for Build_Class_Wide_Wrapper
+ if GNATprove_Mode
+ and then Ekind (Ren_Id) in E_Function | E_Operator
+ then
+ New_Spec := Build_Spec (Ren_Id);
+ Body_Decl :=
+ Make_Expression_Function (Loc,
+ Specification => New_Spec,
+ Expression =>
+ Build_Expr_Fun_Call
+ (Subp_Id => Prim_Op,
+ Params => Parameter_Specifications (New_Spec)));
- begin
- -- Analyze the specification of the renaming in case the generation
- -- of the class-wide wrapper fails.
+ Wrap_Id := Defining_Entity (Body_Decl);
- Ren_Id := Analyze_Subprogram_Specification (Spec);
- Wrap_Id := Any_Id;
+ -- Otherwise, create separate spec and body for the subprogram
- -- Do not attempt to build a wrapper if the renaming is in error
+ else
+ Spec_Decl :=
+ Make_Subprogram_Declaration (Loc,
+ Specification => Build_Spec (Ren_Id));
+ Insert_Before_And_Analyze (N, Spec_Decl);
+
+ Wrap_Id := Defining_Entity (Spec_Decl);
+
+ Body_Decl :=
+ Make_Subprogram_Body (Loc,
+ Specification => Build_Spec (Ren_Id),
+ Declarations => New_List,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (
+ Build_Call
+ (Subp_Id => Prim_Op,
+ Params =>
+ Parameter_Specifications
+ (Specification (Spec_Decl))))));
+
+ Set_Corresponding_Body (Spec_Decl, Defining_Entity (Body_Decl));
+ end if;
- if Error_Posted (Nam) then
- return;
- end if;
+ Set_Is_Class_Wide_Wrapper (Wrap_Id);
- -- Analyze the renamed name, but do not resolve it. The resolution is
- -- completed once a suitable subprogram is found.
+ -- If the operator carries an Eliminated pragma, indicate that
+ -- the wrapper is also to be eliminated, to prevent spurious
+ -- errors when using gnatelim on programs that include box-
+ -- defaulted initialization of equality operators.
- Analyze (Nam);
+ Set_Is_Eliminated (Wrap_Id, Is_Eliminated (Prim_Op));
- -- When the renamed name denotes the intrinsic operator equals, the
- -- name must be treated as overloaded. This allows for a potential
- -- match against the root type's predefined equality function.
+ -- In GNATprove mode, insert the body in the tree for analysis
- if Is_Intrinsic_Equality (Entity (Nam)) then
- Set_Is_Overloaded (Nam);
- Collect_Interps (Nam);
- end if;
+ if GNATprove_Mode then
+ Insert_Before_And_Analyze (N, Body_Decl);
+ end if;
- -- Step 1: Find the generic formal type with unknown discriminants
- -- and its corresponding class-wide actual type from the renamed
- -- generic formal subprogram.
+ -- The generated body does not freeze and must be analyzed when
+ -- the class-wide wrapper is frozen. The body is only needed if
+ -- expansion is enabled.
- Formal := First_Formal (Formal_Spec);
- while Present (Formal) loop
- if Has_Unknown_Discriminants (Etype (Formal))
- and then not Is_Class_Wide_Type (Etype (Formal))
- and then Is_Class_Wide_Type (Get_Instance_Of (Etype (Formal)))
- then
- Formal_Typ := Etype (Formal);
- Actual_Typ := Get_Instance_Of (Formal_Typ);
- Root_Typ := Etype (Actual_Typ);
- exit;
+ if Expander_Active then
+ Append_Freeze_Action (Wrap_Id, Body_Decl);
end if;
- Next_Formal (Formal);
- end loop;
+ -- Step 2: The subprogram renaming aliases the wrapper
- -- The specification of the generic formal subprogram should always
- -- contain a formal type with unknown discriminants whose actual is
- -- a class-wide type, otherwise this indicates a failure in routine
- -- Has_Class_Wide_Actual.
+ Rewrite (Name (N), New_Occurrence_Of (Wrap_Id, Loc));
+ end Build_Class_Wide_Wrapper;
- pragma Assert (Present (Formal_Typ));
+ -----------------------------
+ -- Find_Suitable_Candidate --
+ -----------------------------
- -- Step 2: Find the proper class-wide subprogram or primitive which
- -- corresponds to the renamed generic formal subprogram.
+ procedure Find_Suitable_Candidate
+ (Prim_Op : out Entity_Id;
+ Is_CW_Prim : out Boolean)
+ is
+ Loc : constant Source_Ptr := Sloc (N);
- CW_Prim_Op := Find_Primitive (Actual_Typ);
- CW_Prim_OK := Is_Suitable_Candidate (CW_Prim_Op);
- Root_Prim_Op := Find_Primitive (Root_Typ);
- Root_Prim_OK := Is_Suitable_Candidate (Root_Prim_Op);
+ function Find_Primitive (Typ : Entity_Id) return Entity_Id;
+ -- Find a primitive subprogram of type Typ which matches the
+ -- profile of the renaming declaration.
- -- The class-wide actual type has two subprograms which correspond to
- -- the renamed generic formal subprogram:
+ procedure Interpretation_Error (Subp_Id : Entity_Id);
+ -- Emit a continuation error message suggesting subprogram Subp_Id
+ -- as a possible interpretation.
- -- with procedure Prim_Op (Param : Formal_Typ);
+ function Is_Intrinsic_Equality
+ (Subp_Id : Entity_Id) return Boolean;
+ -- Determine whether subprogram Subp_Id denotes the intrinsic "="
+ -- operator.
- -- procedure Prim_Op (Param : Actual_Typ); -- may be inherited
- -- procedure Prim_Op (Param : Actual_Typ'Class);
+ function Is_Suitable_Candidate
+ (Subp_Id : Entity_Id) return Boolean;
+ -- Determine whether subprogram Subp_Id is a suitable candidate
+ -- for the role of a wrapped subprogram.
- -- Even though the declaration of the two subprograms is legal, a
- -- call to either one is ambiguous and therefore illegal.
+ --------------------
+ -- Find_Primitive --
+ --------------------
- if CW_Prim_OK and Root_Prim_OK then
+ function Find_Primitive (Typ : Entity_Id) return Entity_Id is
+ procedure Replace_Parameter_Types (Spec : Node_Id);
+ -- Given a specification Spec, replace all class-wide parameter
+ -- types with reference to type Typ.
- -- A user-defined primitive has precedence over a predefined one
+ -----------------------------
+ -- Replace_Parameter_Types --
+ -----------------------------
- if Is_Internal (CW_Prim_Op)
- and then not Is_Internal (Root_Prim_Op)
- then
- Prim_Op := Root_Prim_Op;
+ procedure Replace_Parameter_Types (Spec : Node_Id) is
+ Formal : Node_Id;
+ Formal_Id : Entity_Id;
+ Formal_Typ : Node_Id;
- elsif Is_Internal (Root_Prim_Op)
- and then not Is_Internal (CW_Prim_Op)
- then
- Prim_Op := CW_Prim_Op;
+ begin
+ Formal := First (Parameter_Specifications (Spec));
+ while Present (Formal) loop
+ Formal_Id := Defining_Identifier (Formal);
+ Formal_Typ := Parameter_Type (Formal);
- elsif CW_Prim_Op = Root_Prim_Op then
- Prim_Op := Root_Prim_Op;
+ -- Create a new entity for each class-wide formal to
+ -- prevent aliasing with the original renaming. Replace
+ -- the type of such a parameter with the candidate type.
- -- Otherwise both candidate subprograms are user-defined and
- -- ambiguous.
+ if Nkind (Formal_Typ) = N_Identifier
+ and then Is_Class_Wide_Type (Etype (Formal_Typ))
+ then
+ Set_Defining_Identifier (Formal,
+ Make_Defining_Identifier (Loc, Chars (Formal_Id)));
- else
- Error_Msg_NE
- ("ambiguous actual for generic subprogram &",
- Spec, Formal_Spec);
- Interpretation_Error (Root_Prim_Op);
- Interpretation_Error (CW_Prim_Op);
- return;
- end if;
+ Set_Parameter_Type (Formal,
+ New_Occurrence_Of (Typ, Loc));
+ end if;
- elsif CW_Prim_OK and not Root_Prim_OK then
- Prim_Op := CW_Prim_Op;
+ Next (Formal);
+ end loop;
+ end Replace_Parameter_Types;
- elsif not CW_Prim_OK and Root_Prim_OK then
- Prim_Op := Root_Prim_Op;
+ -- Local variables
- -- An intrinsic equality may act as a suitable candidate in the case
- -- of a null type extension where the parent's equality is hidden. A
- -- call to an intrinsic equality is expanded as dispatching.
+ Alt_Ren : constant Node_Id := New_Copy_Tree (N);
+ Alt_Nam : constant Node_Id := Name (Alt_Ren);
+ Alt_Spec : constant Node_Id := Specification (Alt_Ren);
+ Subp_Id : Entity_Id;
- elsif Present (Root_Prim_Op)
- and then Is_Intrinsic_Equality (Root_Prim_Op)
- then
- Prim_Op := Root_Prim_Op;
+ -- Start of processing for Find_Primitive
- -- Otherwise there are no candidate subprograms. Let the caller
- -- diagnose the error.
+ begin
+ -- Each attempt to find a suitable primitive of a particular
+ -- type operates on its own copy of the original renaming.
+ -- As a result the original renaming is kept decoration and
+ -- side-effect free.
- else
- return;
- end if;
+ -- Inherit the overloaded status of the renamed subprogram name
- -- At this point resolution has taken place and the name is no longer
- -- overloaded. Mark the primitive as referenced.
+ if Is_Overloaded (Nam) then
+ Set_Is_Overloaded (Alt_Nam);
+ Save_Interps (Nam, Alt_Nam);
+ end if;
- Set_Is_Overloaded (Name (N), False);
- Set_Referenced (Prim_Op);
+ -- The copied renaming is hidden from visibility to prevent the
+ -- pollution of the enclosing context.
- -- Do not generate a wrapper when the only candidate is a class-wide
- -- subprogram. Instead modify the renaming to directly map the actual
- -- to the generic formal.
+ Set_Defining_Unit_Name (Alt_Spec, Make_Temporary (Loc, 'R'));
- if CW_Prim_OK and then Prim_Op = CW_Prim_Op then
- Wrap_Id := Prim_Op;
- Rewrite (Nam, New_Occurrence_Of (Prim_Op, Loc));
- return;
- end if;
+ -- The types of all class-wide parameters must be changed to
+ -- the candidate type.
- -- Step 3: Create the declaration and the body of the wrapper, insert
- -- all the pieces into the tree.
+ Replace_Parameter_Types (Alt_Spec);
- -- In GNATprove mode, create a function wrapper in the form of an
- -- expression function, so that an implicit postcondition relating
- -- the result of calling the wrapper function and the result of the
- -- dispatching call to the wrapped function is known during proof.
+ -- Try to find a suitable primitive that matches the altered
+ -- profile of the renaming specification.
- if GNATprove_Mode
- and then Ekind_In (Ren_Id, E_Function, E_Operator)
- then
- New_Spec := Build_Spec (Ren_Id);
- Body_Decl :=
- Make_Expression_Function (Loc,
- Specification => New_Spec,
- Expression =>
- Build_Expr_Fun_Call
- (Subp_Id => Prim_Op,
- Params => Parameter_Specifications (New_Spec)));
+ Subp_Id :=
+ Find_Renamed_Entity
+ (N => Alt_Ren,
+ Nam => Name (Alt_Ren),
+ New_S => Analyze_Subprogram_Specification (Alt_Spec),
+ Is_Actual => Is_Actual);
- Wrap_Id := Defining_Entity (Body_Decl);
+ -- Do not return Any_Id if the resolution of the altered
+ -- profile failed as this complicates further checks on
+ -- the caller side; return Empty instead.
- -- Otherwise, create separate spec and body for the subprogram
+ if Subp_Id = Any_Id then
+ return Empty;
+ else
+ return Subp_Id;
+ end if;
+ end Find_Primitive;
- else
- Spec_Decl :=
- Make_Subprogram_Declaration (Loc,
- Specification => Build_Spec (Ren_Id));
- Insert_Before_And_Analyze (N, Spec_Decl);
+ --------------------------
+ -- Interpretation_Error --
+ --------------------------
- Wrap_Id := Defining_Entity (Spec_Decl);
+ procedure Interpretation_Error (Subp_Id : Entity_Id) is
+ begin
+ Error_Msg_Sloc := Sloc (Subp_Id);
- Body_Decl :=
- Make_Subprogram_Body (Loc,
- Specification => Build_Spec (Ren_Id),
- Declarations => New_List,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (
- Build_Call
- (Subp_Id => Prim_Op,
- Params =>
- Parameter_Specifications
- (Specification (Spec_Decl))))));
+ if Is_Internal (Subp_Id) then
+ Error_Msg_NE
+ ("\\possible interpretation: predefined & #",
+ Spec, Formal_Spec);
+ else
+ Error_Msg_NE
+ ("\\possible interpretation: & defined #",
+ Spec, Formal_Spec);
+ end if;
+ end Interpretation_Error;
- Set_Corresponding_Body (Spec_Decl, Defining_Entity (Body_Decl));
- end if;
+ ---------------------------
+ -- Is_Intrinsic_Equality --
+ ---------------------------
- -- If the operator carries an Eliminated pragma, indicate that the
- -- wrapper is also to be eliminated, to prevent spurious error when
- -- using gnatelim on programs that include box-initialization of
- -- equality operators.
+ function Is_Intrinsic_Equality (Subp_Id : Entity_Id) return Boolean
+ is
+ begin
+ return
+ Ekind (Subp_Id) = E_Operator
+ and then Chars (Subp_Id) = Name_Op_Eq
+ and then Is_Intrinsic_Subprogram (Subp_Id);
+ end Is_Intrinsic_Equality;
- Set_Is_Eliminated (Wrap_Id, Is_Eliminated (Prim_Op));
+ ---------------------------
+ -- Is_Suitable_Candidate --
+ ---------------------------
- -- In GNATprove mode, insert the body in the tree for analysis
+ function Is_Suitable_Candidate (Subp_Id : Entity_Id) return Boolean
+ is
+ begin
+ if No (Subp_Id) then
+ return False;
- if GNATprove_Mode then
- Insert_Before_And_Analyze (N, Body_Decl);
- end if;
+ -- An intrinsic subprogram is never a good candidate. This
+ -- is an indication of a missing primitive, either defined
+ -- directly or inherited from a parent tagged type.
- -- The generated body does not freeze and must be analyzed when the
- -- class-wide wrapper is frozen. The body is only needed if expansion
- -- is enabled.
+ elsif Is_Intrinsic_Subprogram (Subp_Id) then
+ return False;
- if Expander_Active then
- Append_Freeze_Action (Wrap_Id, Body_Decl);
- end if;
+ else
+ return True;
+ end if;
+ end Is_Suitable_Candidate;
- -- Step 4: The subprogram renaming aliases the wrapper
+ -- Local variables
- Rewrite (Nam, New_Occurrence_Of (Wrap_Id, Loc));
- end Build_Class_Wide_Wrapper;
+ Actual_Typ : Entity_Id := Empty;
+ -- The actual class-wide type for Formal_Typ
- --------------------------
- -- Check_Null_Exclusion --
- --------------------------
+ CW_Prim_OK : Boolean;
+ CW_Prim_Op : Entity_Id;
+ -- The class-wide subprogram (if available) that corresponds to
+ -- the renamed generic formal subprogram.
- procedure Check_Null_Exclusion
- (Ren : Entity_Id;
- Sub : Entity_Id)
- is
- Ren_Formal : Entity_Id;
- Sub_Formal : Entity_Id;
+ Formal_Typ : Entity_Id := Empty;
+ -- The generic formal type with unknown discriminants
- function Null_Exclusion_Mismatch
- (Renaming : Entity_Id; Renamed : Entity_Id) return Boolean;
- -- Return True if there is a null exclusion mismatch between
- -- Renaming and Renamed, False otherwise.
+ Root_Prim_OK : Boolean;
+ Root_Prim_Op : Entity_Id;
+ -- The root type primitive (if available) that corresponds to the
+ -- renamed generic formal subprogram.
- -----------------------------
- -- Null_Exclusion_Mismatch --
- -----------------------------
+ Root_Typ : Entity_Id := Empty;
+ -- The root type of Actual_Typ
+
+ Formal : Node_Id;
+
+ -- Start of processing for Find_Suitable_Candidate
- function Null_Exclusion_Mismatch
- (Renaming : Entity_Id; Renamed : Entity_Id) return Boolean is
begin
- return Has_Null_Exclusion (Parent (Renaming))
- and then
- not (Has_Null_Exclusion (Parent (Renamed))
- or else (Can_Never_Be_Null (Etype (Renamed))
- and then not
- (Is_Formal_Subprogram (Sub)
- and then In_Generic_Body (Current_Scope))));
- end Null_Exclusion_Mismatch;
+ pragma Assert (not Error_Posted (Nam));
- begin
- -- Parameter check
+ Prim_Op := Empty;
+ Is_CW_Prim := False;
- Ren_Formal := First_Formal (Ren);
- Sub_Formal := First_Formal (Sub);
- while Present (Ren_Formal) and then Present (Sub_Formal) loop
- if Null_Exclusion_Mismatch (Ren_Formal, Sub_Formal) then
- Error_Msg_Sloc := Sloc (Sub_Formal);
- Error_Msg_NE
- ("`NOT NULL` required for parameter &#",
- Ren_Formal, Sub_Formal);
+ -- Analyze the renamed name, but do not resolve it. The resolution
+ -- is completed once a suitable subprogram is found.
+
+ Analyze (Nam);
+
+ -- When the renamed name denotes the intrinsic operator equals,
+ -- the name must be treated as overloaded. This allows for a
+ -- potential match against the root type's predefined equality
+ -- function.
+
+ if Is_Intrinsic_Equality (Entity (Nam)) then
+ Set_Is_Overloaded (Nam);
+ Collect_Interps (Nam);
end if;
- Next_Formal (Ren_Formal);
- Next_Formal (Sub_Formal);
- end loop;
+ -- Step 1: Find the generic formal type and its corresponding
+ -- class-wide actual type from the renamed generic formal
+ -- subprogram.
- -- Return profile check
+ Formal := First_Formal (Formal_Spec);
+ while Present (Formal) loop
+ if Has_Unknown_Discriminants (Etype (Formal))
+ and then not Is_Class_Wide_Type (Etype (Formal))
+ and then Is_Class_Wide_Type (Get_Instance_Of (Etype (Formal)))
+ then
+ Formal_Typ := Etype (Formal);
+ Actual_Typ := Base_Type (Get_Instance_Of (Formal_Typ));
+ Root_Typ := Root_Type (Actual_Typ);
+ exit;
+ end if;
- if Nkind (Parent (Ren)) = N_Function_Specification
- and then Nkind (Parent (Sub)) = N_Function_Specification
- and then Null_Exclusion_Mismatch (Ren, Sub)
- then
- Error_Msg_Sloc := Sloc (Sub);
- Error_Msg_N ("return must specify `NOT NULL`#", Ren);
- end if;
- end Check_Null_Exclusion;
+ Next_Formal (Formal);
+ end loop;
- -------------------------------------
- -- Check_SPARK_Primitive_Operation --
- -------------------------------------
+ -- The specification of the generic formal subprogram should
+ -- always contain a formal type with unknown discriminants whose
+ -- actual is a class-wide type; otherwise this indicates a failure
+ -- in function Has_Class_Wide_Actual.
- procedure Check_SPARK_Primitive_Operation (Subp_Id : Entity_Id) is
- Prag : constant Node_Id := SPARK_Pragma (Subp_Id);
- Typ : Entity_Id;
+ pragma Assert (Present (Formal_Typ));
- begin
- -- Nothing to do when the subprogram is not subject to SPARK_Mode On
- -- because this check applies to SPARK code only.
+ -- Step 2: Find the proper class-wide subprogram or primitive
+ -- that corresponds to the renamed generic formal subprogram.
- if not (Present (Prag)
- and then Get_SPARK_Mode_From_Annotation (Prag) = On)
- then
- return;
+ CW_Prim_Op := Find_Primitive (Actual_Typ);
+ CW_Prim_OK := Is_Suitable_Candidate (CW_Prim_Op);
+ Root_Prim_Op := Find_Primitive (Root_Typ);
+ Root_Prim_OK := Is_Suitable_Candidate (Root_Prim_Op);
- -- Nothing to do when the subprogram is not a primitive operation
+ -- The class-wide actual type has two subprograms that correspond
+ -- to the renamed generic formal subprogram:
- elsif not Is_Primitive (Subp_Id) then
- return;
- end if;
+ -- with procedure Prim_Op (Param : Formal_Typ);
- Typ := Find_Dispatching_Type (Subp_Id);
+ -- procedure Prim_Op (Param : Actual_Typ); -- may be inherited
+ -- procedure Prim_Op (Param : Actual_Typ'Class);
- -- Nothing to do when the subprogram is a primitive operation of an
- -- untagged type.
+ -- Even though the declaration of the two subprograms is legal, a
+ -- call to either one is ambiguous and therefore illegal.
- if No (Typ) then
- return;
- end if;
+ if CW_Prim_OK and Root_Prim_OK then
- -- At this point a renaming declaration introduces a new primitive
- -- operation for a tagged type.
+ -- A user-defined primitive has precedence over a predefined
+ -- one.
- Error_Msg_Node_2 := Typ;
- Error_Msg_NE
- ("subprogram renaming & cannot declare primitive for type & "
- & "(SPARK RM 6.1.1(3))", N, Subp_Id);
- end Check_SPARK_Primitive_Operation;
+ if Is_Internal (CW_Prim_Op)
+ and then not Is_Internal (Root_Prim_Op)
+ then
+ Prim_Op := Root_Prim_Op;
- ---------------------------
- -- Freeze_Actual_Profile --
- ---------------------------
+ elsif Is_Internal (Root_Prim_Op)
+ and then not Is_Internal (CW_Prim_Op)
+ then
+ Prim_Op := CW_Prim_Op;
+ Is_CW_Prim := True;
- procedure Freeze_Actual_Profile is
- F : Entity_Id;
- Has_Untagged_Inc : Boolean;
- Instantiation_Node : constant Node_Id := Parent (N);
+ elsif CW_Prim_Op = Root_Prim_Op then
+ Prim_Op := Root_Prim_Op;
- begin
- if Ada_Version >= Ada_2012 then
- F := First_Formal (Formal_Spec);
- Has_Untagged_Inc := False;
- while Present (F) loop
- if Ekind (Etype (F)) = E_Incomplete_Type
- and then not Is_Tagged_Type (Etype (F))
+ -- The two subprograms are legal but the class-wide subprogram
+ -- is a class-wide wrapper built for a previous instantiation;
+ -- the wrapper has precedence.
+
+ elsif Present (Alias (CW_Prim_Op))
+ and then Is_Class_Wide_Wrapper (Ultimate_Alias (CW_Prim_Op))
then
- Has_Untagged_Inc := True;
- exit;
+ Prim_Op := CW_Prim_Op;
+ Is_CW_Prim := True;
+
+ -- Otherwise both candidate subprograms are user-defined and
+ -- ambiguous.
+
+ else
+ Error_Msg_NE
+ ("ambiguous actual for generic subprogram &",
+ Spec, Formal_Spec);
+ Interpretation_Error (Root_Prim_Op);
+ Interpretation_Error (CW_Prim_Op);
+ return;
end if;
- Next_Formal (F);
- end loop;
+ elsif CW_Prim_OK and not Root_Prim_OK then
+ Prim_Op := CW_Prim_Op;
+ Is_CW_Prim := True;
- if Ekind (Formal_Spec) = E_Function
- and then not Is_Tagged_Type (Etype (Formal_Spec))
+ elsif not CW_Prim_OK and Root_Prim_OK then
+ Prim_Op := Root_Prim_Op;
+
+ -- An intrinsic equality may act as a suitable candidate in the
+ -- case of a null type extension where the parent's equality
+ -- is hidden. A call to an intrinsic equality is expanded as
+ -- dispatching.
+
+ elsif Present (Root_Prim_Op)
+ and then Is_Intrinsic_Equality (Root_Prim_Op)
then
- Has_Untagged_Inc := True;
- end if;
+ Prim_Op := Root_Prim_Op;
- if not Has_Untagged_Inc then
- F := First_Formal (Old_S);
- while Present (F) loop
- Freeze_Before (Instantiation_Node, Etype (F));
+ -- Otherwise there are no candidate subprograms. Let the caller
+ -- diagnose the error.
+
+ else
+ return;
+ end if;
- if Is_Incomplete_Or_Private_Type (Etype (F))
- and then No (Underlying_Type (Etype (F)))
- then
- -- Exclude generic types, or types derived from them.
- -- They will be frozen in the enclosing instance.
+ -- At this point resolution has taken place and the name is no
+ -- longer overloaded. Mark the primitive as referenced.
- if Is_Generic_Type (Etype (F))
- or else Is_Generic_Type (Root_Type (Etype (F)))
- then
- null;
+ Set_Is_Overloaded (Name (N), False);
+ Set_Referenced (Prim_Op);
+ end Find_Suitable_Candidate;
- -- A limited view of a type declared elsewhere needs no
- -- freezing actions.
+ -- Local variables
- elsif From_Limited_With (Etype (F)) then
- null;
+ Is_CW_Prim : Boolean;
- else
- Error_Msg_NE
- ("type& must be frozen before this point",
- Instantiation_Node, Etype (F));
- end if;
- end if;
+ -- Start of processing for Handle_Instance_With_Class_Wide_Type
- Next_Formal (F);
- end loop;
+ begin
+ Wrapped_Prim := Empty;
+ Wrap_Id := Empty;
+
+ -- Ada 2012 (AI05-0071): A generic/instance scenario involving a
+ -- formal type with unknown discriminants and a generic primitive
+ -- operation of the said type with a box require special processing
+ -- when the actual is a class-wide type:
+ --
+ -- generic
+ -- type Formal_Typ (<>) is private;
+ -- with procedure Prim_Op (Param : Formal_Typ) is <>;
+ -- package Gen is ...
+ --
+ -- package Inst is new Gen (Actual_Typ'Class);
+ --
+ -- In this case the general renaming mechanism used in the prologue
+ -- of an instance no longer applies:
+ --
+ -- procedure Prim_Op (Param : Formal_Typ) renames Prim_Op;
+ --
+ -- The above is replaced the following wrapper/renaming combination:
+ --
+ -- procedure Wrapper (Param : Formal_Typ) is -- wrapper
+ -- begin
+ -- Prim_Op (Param); -- primitive
+ -- end Wrapper;
+ --
+ -- procedure Prim_Op (Param : Formal_Typ) renames Wrapper;
+ --
+ -- This transformation applies only if there is no explicit visible
+ -- class-wide operation at the point of the instantiation. Ren_Id is
+ -- the entity of the renaming declaration. When the transformation
+ -- applies, Wrapped_Prim is the entity of the wrapped primitive.
+
+ if Box_Present (Inst_Node) then
+ Find_Suitable_Candidate
+ (Prim_Op => Wrapped_Prim,
+ Is_CW_Prim => Is_CW_Prim);
+
+ if Present (Wrapped_Prim) then
+ if not Is_CW_Prim then
+ Build_Class_Wide_Wrapper (Ren_Id, Wrapped_Prim, Wrap_Id);
+
+ -- Small optimization: When the candidate is a class-wide
+ -- subprogram we don't build the wrapper; we modify the
+ -- renaming declaration to directly map the actual to the
+ -- generic formal and discard the candidate.
+
+ else
+ Rewrite (Nam, New_Occurrence_Of (Wrapped_Prim, Sloc (N)));
+ Wrapped_Prim := Empty;
+ end if;
end if;
- end if;
- end Freeze_Actual_Profile;
- ---------------------------
- -- Has_Class_Wide_Actual --
- ---------------------------
+ -- Ada 2022 (AI12-0165, RM 12.6(8.5/3)): The actual subprogram for a
+ -- formal_abstract_subprogram_declaration shall be:
+ -- a) a dispatching operation of the controlling type; or
+ -- b) if the controlling type is a formal type, and the actual
+ -- type corresponding to that formal type is a specific type T,
+ -- a dispatching operation of type T; or
+ -- c) if the controlling type is a formal type, and the actual
+ -- type is a class-wide type T'Class, an implicitly declared
+ -- subprogram corresponding to a primitive operation of type T.
+
+ elsif Nkind (Inst_Node) = N_Formal_Abstract_Subprogram_Declaration
+ and then Is_Entity_Name (Nam)
+ then
+ Find_Suitable_Candidate
+ (Prim_Op => Wrapped_Prim,
+ Is_CW_Prim => Is_CW_Prim);
- function Has_Class_Wide_Actual return Boolean is
- Formal : Entity_Id;
- Formal_Typ : Entity_Id;
+ if Present (Wrapped_Prim) then
- begin
- if Is_Actual then
- Formal := First_Formal (Formal_Spec);
- while Present (Formal) loop
- Formal_Typ := Etype (Formal);
+ -- Cases (a) and (b); see previous description.
- if Has_Unknown_Discriminants (Formal_Typ)
- and then not Is_Class_Wide_Type (Formal_Typ)
- and then Is_Class_Wide_Type (Get_Instance_Of (Formal_Typ))
+ if not Is_CW_Prim then
+ Build_Class_Wide_Wrapper (Ren_Id, Wrapped_Prim, Wrap_Id);
+
+ -- Case (c); see previous description.
+
+ -- Implicit operations of T'Class for subtype declarations
+ -- are built by Derive_Subprogram, and their Alias attribute
+ -- references the primitive operation of T.
+
+ elsif not Comes_From_Source (Wrapped_Prim)
+ and then Nkind (Parent (Wrapped_Prim)) = N_Subtype_Declaration
+ and then Present (Alias (Wrapped_Prim))
then
- return True;
- end if;
+ -- We don't need to build the wrapper; we modify the
+ -- renaming declaration to directly map the actual to
+ -- the generic formal and discard the candidate.
- Next_Formal (Formal);
- end loop;
- end if;
+ Rewrite (Nam,
+ New_Occurrence_Of (Alias (Wrapped_Prim), Sloc (N)));
+ Wrapped_Prim := Empty;
- return False;
- end Has_Class_Wide_Actual;
+ -- Legality rules do not apply; discard the candidate.
+
+ else
+ Wrapped_Prim := Empty;
+ end if;
+ end if;
+ end if;
+ end Handle_Instance_With_Class_Wide_Type;
-------------------------
-- Original_Subprogram --
-- Local variables
CW_Actual : constant Boolean := Has_Class_Wide_Actual;
- -- Ada 2012 (AI05-071, AI05-0131): True if the renaming is for a
- -- defaulted formal subprogram when the actual for a related formal
- -- type is class-wide.
+ -- Ada 2012 (AI05-071, AI05-0131) and Ada 2022 (AI12-0165): True if the
+ -- renaming is for a defaulted formal subprogram when the actual for a
+ -- related formal type is class-wide.
- Inst_Node : Node_Id := Empty;
- New_S : Entity_Id;
+ Inst_Node : Node_Id := Empty;
+ New_S : Entity_Id := Empty;
+ Wrapped_Prim : Entity_Id := Empty;
-- Start of processing for Analyze_Subprogram_Renaming
if Is_Actual then
Inst_Node := Unit_Declaration_Node (Formal_Spec);
- -- Check whether the renaming is for a defaulted actual subprogram
- -- with a class-wide actual.
+ -- Ada 2012 (AI05-0071) and Ada 2022 (AI12-0165): when the actual
+ -- type is a class-wide type T'Class we may need to wrap a primitive
+ -- operation of T. Search for the wrapped primitive and (if required)
+ -- build a wrapper whose body consists of a dispatching call to the
+ -- wrapped primitive of T, with its formal parameters as the actual
+ -- parameters.
+
+ if CW_Actual and then
+
+ -- Ada 2012 (AI05-0071): Check whether the renaming is for a
+ -- defaulted actual subprogram with a class-wide actual.
- -- The class-wide wrapper is not needed in GNATprove_Mode and there
- -- is an external axiomatization on the package.
+ (Box_Present (Inst_Node)
- if CW_Actual
- and then Box_Present (Inst_Node)
- and then not
- (GNATprove_Mode
- and then
- Present (Containing_Package_With_Ext_Axioms (Formal_Spec)))
+ or else
+
+ -- Ada 2022 (AI12-0165): Check whether the renaming is for a formal
+ -- abstract subprogram declaration with a class-wide actual.
+
+ (Nkind (Inst_Node) = N_Formal_Abstract_Subprogram_Declaration
+ and then Is_Entity_Name (Nam)))
then
- Build_Class_Wide_Wrapper (New_S, Old_S);
+ New_S := Analyze_Subprogram_Specification (Spec);
+
+ -- Do not attempt to build the wrapper if the renaming is in error
+
+ if not Error_Posted (Nam) then
+ Handle_Instance_With_Class_Wide_Type
+ (Inst_Node => Inst_Node,
+ Ren_Id => New_S,
+ Wrapped_Prim => Wrapped_Prim,
+ Wrap_Id => Old_S);
+
+ -- If several candidates were found, then we reported the
+ -- ambiguity; stop processing the renaming declaration to
+ -- avoid reporting further (spurious) errors.
+
+ if Error_Posted (Spec) then
+ return;
+ end if;
+
+ end if;
+ end if;
+
+ if Present (Wrapped_Prim) then
+
+ -- When the wrapper is built, the subprogram renaming aliases
+ -- the wrapper.
+
+ Analyze (Nam);
+
+ pragma Assert (Old_S = Entity (Nam)
+ and then Is_Class_Wide_Wrapper (Old_S));
+
+ -- The subprogram renaming declaration may become Ghost if it
+ -- renames a wrapper of a Ghost entity.
+
+ Mark_Ghost_Renaming (N, Wrapped_Prim);
elsif Is_Entity_Name (Nam)
and then Present (Entity (Nam))
-- constructed later at the freeze point, so indicate that the
-- completion has not been seen yet.
- Set_Ekind (New_S, E_Subprogram_Body);
+ Reinit_Field_To_Zero (New_S, F_Has_Out_Or_In_Out_Parameter);
+ Reinit_Field_To_Zero (New_S, F_Needs_No_Actuals,
+ Old_Ekind => (E_Function | E_Procedure => True, others => False));
+ Mutate_Ekind (New_S, E_Subprogram_Body);
New_S := Rename_Spec;
Set_Has_Completion (Rename_Spec, False);
Style.Missing_Overriding (N, Rename_Spec);
end if;
- elsif Must_Override (Specification (N)) then
+ elsif Must_Override (Specification (N))
+ and then not Can_Override_Operator (Rename_Spec)
+ then
Error_Msg_NE ("subprogram& is not overriding", N, Rename_Spec);
end if;
+ -- AI12-0132: a renames-as-body freezes the expression of any
+ -- expression function that it renames.
+
+ if Is_Entity_Name (Nam)
+ and then Is_Expression_Function (Entity (Nam))
+ and then not Inside_A_Generic
+ then
+ Freeze_Expr_Types
+ (Def_Id => Entity (Nam),
+ Typ => Etype (Entity (Nam)),
+ Expr =>
+ Expression
+ (Original_Node (Unit_Declaration_Node (Entity (Nam)))),
+ N => N);
+ end if;
+
-- Normal subprogram renaming (not renaming as body)
else
-- Guard against previous errors, and omit renamings of predefined
-- operators.
- elsif not Ekind_In (Old_S, E_Function, E_Procedure) then
+ elsif Ekind (Old_S) not in E_Function | E_Procedure then
null;
elsif Requires_Overriding (Old_S)
end if;
if Original_Subprogram (Old_S) = Rename_Spec then
- Error_Msg_N ("unfrozen subprogram cannot rename itself ", N);
+ Error_Msg_N ("unfrozen subprogram cannot rename itself", N);
else
Check_Formal_Subprogram_Conformance (New_S, Old_S, Spec);
end if;
-- indicate that the renaming is an abstract dispatching operation
-- with a controlling type.
- if Is_Actual and then Is_Abstract_Subprogram (Formal_Spec) then
+ -- Skip this decoration when the renaming corresponds to an
+ -- association with class-wide wrapper (see above) because such
+ -- wrapper is neither abstract nor a dispatching operation (its
+ -- body has the dispatching call to the wrapped primitive).
+
+ if Is_Actual
+ and then Is_Abstract_Subprogram (Formal_Spec)
+ and then No (Wrapped_Prim)
+ then
-- Mark the renaming as abstract here, so Find_Dispatching_Type
-- see it as corresponding to a generic association for a
Set_Has_Delayed_Freeze (New_S, False);
Freeze_Before (N, New_S);
- -- An abstract subprogram is only allowed as an actual in the case
- -- where the formal subprogram is also abstract.
-
if (Ekind (Old_S) = E_Procedure or else Ekind (Old_S) = E_Function)
- and then Is_Abstract_Subprogram (Old_S)
and then not Is_Abstract_Subprogram (Formal_Spec)
then
- Error_Msg_N
- ("abstract subprogram not allowed as generic actual", Nam);
+ -- An abstract subprogram is only allowed as an actual in the
+ -- case where the formal subprogram is also abstract.
+
+ if Is_Abstract_Subprogram (Old_S) then
+ Error_Msg_N
+ ("abstract subprogram not allowed as generic actual", Nam);
+ end if;
+
+ -- AI12-0412: A primitive of an abstract type with Pre'Class
+ -- or Post'Class aspects specified with nonstatic expressions
+ -- is not allowed as actual for a nonabstract formal subprogram
+ -- (see RM 6.1.1(18.2/5).
+
+ if Is_Dispatching_Operation (Old_S)
+ and then
+ Is_Prim_Of_Abst_Type_With_Nonstatic_CW_Pre_Post (Old_S)
+ then
+ Error_Msg_N
+ ("primitive of abstract type with nonstatic class-wide "
+ & "pre/postconditions not allowed as actual",
+ Nam);
+ end if;
end if;
end if;
Ada_Version_Pragma := Save_AVP;
Ada_Version_Explicit := Save_AV_Exp;
- -- In GNATprove mode, the renamings of actual subprograms are replaced
- -- with wrapper functions that make it easier to propagate axioms to the
- -- points of call within an instance. Wrappers are generated if formal
- -- subprogram is subject to axiomatization.
-
- -- The types in the wrapper profiles are obtained from (instances of)
- -- the types of the formal subprogram.
-
- if Is_Actual
- and then GNATprove_Mode
- and then Present (Containing_Package_With_Ext_Axioms (Formal_Spec))
- and then not Inside_A_Generic
- then
- if Ekind (Old_S) = E_Function then
- Rewrite (N, Build_Function_Wrapper (Formal_Spec, Old_S));
- Analyze (N);
-
- elsif Ekind (Old_S) = E_Operator then
- Rewrite (N, Build_Operator_Wrapper (Formal_Spec, Old_S));
- Analyze (N);
- end if;
- end if;
-
-- Check if we are looking at an Ada 2012 defaulted formal subprogram
-- and mark any use_package_clauses that affect the visibility of the
-- implicit generic actual.
elsif Present (Expressions (Nam)) then
Error_Msg_N ("illegal expressions in attribute reference", Nam);
- elsif
- Nam_In (Aname, Name_Compose, Name_Exponent, Name_Leading_Part,
- Name_Pos, Name_Round, Name_Scaling,
- Name_Val)
+ elsif Aname in Name_Compose | Name_Exponent | Name_Leading_Part |
+ Name_Pos | Name_Round | Name_Scaling |
+ Name_Val
then
if Nkind (N) = N_Subprogram_Renaming_Declaration
and then Present (Corresponding_Formal_Spec (N))
if not Configurable_Run_Time_Mode
and then not Present (Corresponding_Formal_Spec (N))
- and then Etype (Nam) /= RTE (RE_AST_Handler)
+ and then not Is_RTE (Etype (Nam), RE_AST_Handler)
then
declare
P : constant Node_Id := Prefix (Nam);
elsif Is_Concurrent_Type (Scope (E)) then
P := Parent (N);
while Present (P)
- and then not Nkind_In (P, N_Parameter_Specification,
- N_Component_Declaration)
+ and then Nkind (P) not in
+ N_Parameter_Specification | N_Component_Declaration
loop
P := Parent (P);
end loop;
-- Check_In_Previous_With_Clause --
-----------------------------------
- procedure Check_In_Previous_With_Clause
- (N : Node_Id;
- Nam : Entity_Id)
- is
+ procedure Check_In_Previous_With_Clause (N, Nam : Node_Id) is
Pack : constant Entity_Id := Entity (Original_Node (Nam));
Item : Node_Id;
Par : Node_Id;
Pop_Scope;
- while not (Is_List_Member (Decl))
- or else Nkind_In (Parent (Decl), N_Protected_Definition,
- N_Task_Definition)
+ while not Is_List_Member (Decl)
+ or else Nkind (Parent (Decl)) in N_Protected_Definition
+ | N_Task_Definition
loop
Decl := Parent (Decl);
end loop;
Next_Entity (Id);
end loop;
- if Present (Renamed_Object (Pack)) then
- Set_In_Use (Renamed_Object (Pack), False);
- Set_Current_Use_Clause (Renamed_Object (Pack), Empty);
+ if Present (Renamed_Entity (Pack)) then
+ Set_In_Use (Renamed_Entity (Pack), False);
+ Set_Current_Use_Clause (Renamed_Entity (Pack), Empty);
end if;
if Chars (Pack) = Name_System
-- Find_Direct_Name --
----------------------
- procedure Find_Direct_Name
- (N : Node_Id;
- Errors_OK : Boolean := True;
- Marker_OK : Boolean := True;
- Reference_OK : Boolean := True)
- is
+ procedure Find_Direct_Name (N : Node_Id) is
E : Entity_Id;
E2 : Entity_Id;
Msg : Boolean;
-- not know what procedure is being called if the procedure might be
-- overloaded, so it is premature to go setting referenced flags or
-- making calls to Generate_Reference. We will wait till Resolve_Actuals
- -- for that processing
+ -- for that processing.
+ -- Note: there is a similar routine Sem_Util.Is_Actual_Parameter, but
+ -- it works for both function and procedure calls, while here we are
+ -- only concerned with procedure calls (and with entry calls as well,
+ -- but they are parsed as procedure calls and only later rewritten to
+ -- entry calls).
function Known_But_Invisible (E : Entity_Id) return Boolean;
-- This function determines whether a reference to the entity E, which
------------------------
function Declared_In_Actual (Pack : Entity_Id) return Boolean is
+ pragma Assert (Ekind (Pack) = E_Package);
Act : Entity_Id;
-
begin
if No (Associated_Formal_Package (Pack)) then
return False;
else
Act := First_Entity (Pack);
while Present (Act) loop
- if Renamed_Object (Pack) = Scop then
+ if Renamed_Entity (Pack) = Scop then
return True;
-- Check for end of list of actuals
elsif Ekind (Act) = E_Package
- and then Renamed_Object (Act) = Pack
+ and then Renamed_Entity (Act) = Pack
then
return False;
function Is_Actual_Parameter return Boolean is
begin
- return
- Nkind (N) = N_Identifier
- and then
- (Nkind (Parent (N)) = N_Procedure_Call_Statement
- or else
- (Nkind (Parent (N)) = N_Parameter_Association
- and then N = Explicit_Actual_Parameter (Parent (N))
- and then Nkind (Parent (Parent (N))) =
- N_Procedure_Call_Statement));
+ if Nkind (N) = N_Identifier then
+ case Nkind (Parent (N)) is
+ when N_Procedure_Call_Statement =>
+ return Is_List_Member (N)
+ and then List_Containing (N) =
+ Parameter_Associations (Parent (N));
+
+ when N_Parameter_Association =>
+ return N = Explicit_Actual_Parameter (Parent (N))
+ and then Nkind (Parent (Parent (N))) =
+ N_Procedure_Call_Statement;
+
+ when others =>
+ return False;
+ end case;
+ else
+ return False;
+ end if;
end Is_Actual_Parameter;
-------------------------
elsif not Comes_From_Source (E) then
return False;
-
- -- In gnat internal mode, we consider all entities known. The
- -- historical reason behind this discrepancy is not known??? But the
- -- only effect is to modify the error message given, so it is not
- -- critical. Since it only affects the exact wording of error
- -- messages in illegal programs, we do not mention this as an
- -- effect of -gnatg, since it is not a language modification.
-
- elsif GNAT_Mode then
- return True;
end if;
-- Here we have an entity that is not from package Standard, and
Item : Node_Id;
begin
- if not Errors_OK then
- return;
- end if;
-
-- Ada 2005 (AI-262): Generate a precise error concerning the
-- Beaujolais effect that was previously detected
-- Named aggregate should also be handled similarly ???
- if Errors_OK
- and then Nkind (N) = N_Identifier
+ if Nkind (N) = N_Identifier
and then Nkind (Parent (N)) = N_Case_Statement_Alternative
then
declare
Set_Entity (N, Any_Id);
Set_Etype (N, Any_Type);
- if Errors_OK then
-
- -- We use the table Urefs to keep track of entities for which we
- -- have issued errors for undefined references. Multiple errors
- -- for a single name are normally suppressed, however we modify
- -- the error message to alert the programmer to this effect.
-
- for J in Urefs.First .. Urefs.Last loop
- if Chars (N) = Chars (Urefs.Table (J).Node) then
- if Urefs.Table (J).Err /= No_Error_Msg
- and then Sloc (N) /= Urefs.Table (J).Loc
- then
- Error_Msg_Node_1 := Urefs.Table (J).Node;
+ -- We use the table Urefs to keep track of entities for which we
+ -- have issued errors for undefined references. Multiple errors
+ -- for a single name are normally suppressed, however we modify
+ -- the error message to alert the programmer to this effect.
- if Urefs.Table (J).Nvis then
- Change_Error_Text (Urefs.Table (J).Err,
- "& is not visible (more references follow)");
- else
- Change_Error_Text (Urefs.Table (J).Err,
- "& is undefined (more references follow)");
- end if;
+ for J in Urefs.First .. Urefs.Last loop
+ if Chars (N) = Chars (Urefs.Table (J).Node) then
+ if Urefs.Table (J).Err /= No_Error_Msg
+ and then Sloc (N) /= Urefs.Table (J).Loc
+ then
+ Error_Msg_Node_1 := Urefs.Table (J).Node;
- Urefs.Table (J).Err := No_Error_Msg;
+ if Urefs.Table (J).Nvis then
+ Change_Error_Text (Urefs.Table (J).Err,
+ "& is not visible (more references follow)");
+ else
+ Change_Error_Text (Urefs.Table (J).Err,
+ "& is undefined (more references follow)");
end if;
- -- Although we will set Msg False, and thus suppress the
- -- message, we also set Error_Posted True, to avoid any
- -- cascaded messages resulting from the undefined reference.
-
- Msg := False;
- Set_Error_Posted (N);
- return;
+ Urefs.Table (J).Err := No_Error_Msg;
end if;
- end loop;
- -- If entry not found, this is first undefined occurrence
+ -- Although we will set Msg False, and thus suppress the
+ -- message, we also set Error_Posted True, to avoid any
+ -- cascaded messages resulting from the undefined reference.
- if Nvis then
- Error_Msg_N ("& is not visible!", N);
- Emsg := Get_Msg_Id;
+ Msg := False;
+ Set_Error_Posted (N);
+ return;
+ end if;
+ end loop;
- else
- Error_Msg_N ("& is undefined!", N);
- Emsg := Get_Msg_Id;
+ -- If entry not found, this is first undefined occurrence
- -- A very bizarre special check, if the undefined identifier
- -- is Put or Put_Line, then add a special error message (since
- -- this is a very common error for beginners to make).
+ if Nvis then
+ Error_Msg_N ("& is not visible!", N);
+ Emsg := Get_Msg_Id;
- if Nam_In (Chars (N), Name_Put, Name_Put_Line) then
- Error_Msg_N -- CODEFIX
- ("\\possible missing `WITH Ada.Text_'I'O; " &
- "USE Ada.Text_'I'O`!", N);
+ else
+ Error_Msg_N ("& is undefined!", N);
+ Emsg := Get_Msg_Id;
- -- Another special check if N is the prefix of a selected
- -- component which is a known unit: add message complaining
- -- about missing with for this unit.
+ -- A very bizarre special check, if the undefined identifier
+ -- is Put or Put_Line, then add a special error message (since
+ -- this is a very common error for beginners to make).
- elsif Nkind (Parent (N)) = N_Selected_Component
- and then N = Prefix (Parent (N))
- and then Is_Known_Unit (Parent (N))
- then
- Error_Msg_Node_2 := Selector_Name (Parent (N));
- Error_Msg_N -- CODEFIX
- ("\\missing `WITH &.&;`", Prefix (Parent (N)));
- end if;
+ if Chars (N) in Name_Put | Name_Put_Line then
+ Error_Msg_N -- CODEFIX
+ ("\\possible missing `WITH Ada.Text_'I'O; " &
+ "USE Ada.Text_'I'O`!", N);
- -- Now check for possible misspellings
+ -- Another special check if N is the prefix of a selected
+ -- component which is a known unit: add message complaining
+ -- about missing with for this unit.
+ elsif Nkind (Parent (N)) = N_Selected_Component
+ and then N = Prefix (Parent (N))
+ and then Is_Known_Unit (Parent (N))
+ then
declare
- E : Entity_Id;
- Ematch : Entity_Id := Empty;
-
- Last_Name_Id : constant Name_Id :=
- Name_Id (Nat (First_Name_Id) +
- Name_Entries_Count - 1);
-
+ P : Node_Id := Parent (N);
begin
- for Nam in First_Name_Id .. Last_Name_Id loop
- E := Get_Name_Entity_Id (Nam);
+ Error_Msg_Name_1 := Chars (N);
+ Error_Msg_Name_2 := Chars (Selector_Name (P));
- if Present (E)
- and then (Is_Immediately_Visible (E)
- or else
- Is_Potentially_Use_Visible (E))
- then
- if Is_Bad_Spelling_Of (Chars (N), Nam) then
- Ematch := E;
- exit;
- end if;
- end if;
- end loop;
+ if Nkind (Parent (P)) = N_Selected_Component
+ and then Is_Known_Unit (Parent (P))
+ then
+ P := Parent (P);
+ Error_Msg_Name_3 := Chars (Selector_Name (P));
+ Error_Msg_N -- CODEFIX
+ ("\\missing `WITH %.%.%;`", N);
- if Present (Ematch) then
- Error_Msg_NE -- CODEFIX
- ("\possible misspelling of&", N, Ematch);
+ else
+ Error_Msg_N -- CODEFIX
+ ("\\missing `WITH %.%;`", N);
end if;
end;
end if;
- -- Make entry in undefined references table unless the full errors
- -- switch is set, in which case by refraining from generating the
- -- table entry we guarantee that we get an error message for every
- -- undefined reference. The entry is not added if we are ignoring
- -- errors.
+ -- Now check for possible misspellings
- if not All_Errors_Mode and then Ignore_Errors_Enable = 0 then
- Urefs.Append (
- (Node => N,
- Err => Emsg,
- Nvis => Nvis,
- Loc => Sloc (N)));
- end if;
+ declare
+ E : Entity_Id;
+ Ematch : Entity_Id := Empty;
+ begin
+ for Nam in First_Name_Id .. Last_Name_Id loop
+ E := Get_Name_Entity_Id (Nam);
+
+ if Present (E)
+ and then (Is_Immediately_Visible (E)
+ or else
+ Is_Potentially_Use_Visible (E))
+ then
+ if Is_Bad_Spelling_Of (Chars (N), Nam) then
+ Ematch := E;
+ exit;
+ end if;
+ end if;
+ end loop;
+
+ if Present (Ematch) then
+ Error_Msg_NE -- CODEFIX
+ ("\possible misspelling of&", N, Ematch);
+ end if;
+ end;
+ end if;
- Msg := True;
+ -- Make entry in undefined references table unless the full errors
+ -- switch is set, in which case by refraining from generating the
+ -- table entry we guarantee that we get an error message for every
+ -- undefined reference. The entry is not added if we are ignoring
+ -- errors.
+
+ if not All_Errors_Mode
+ and then Ignore_Errors_Enable = 0
+ and then not Get_Ignore_Errors
+ then
+ Urefs.Append (
+ (Node => N,
+ Err => Emsg,
+ Nvis => Nvis,
+ Loc => Sloc (N)));
end if;
+
+ Msg := True;
end Undefined;
-- Local variables
if Is_Type (Entity (N)) then
Set_Etype (N, Entity (N));
+ -- The exception to this general rule are constants associated with
+ -- discriminals of protected types because for each protected op
+ -- a new set of discriminals is internally created by the frontend
+ -- (see Exp_Ch9.Set_Discriminals), and the current decoration of the
+ -- entity pointer may have been set as part of a preanalysis, where
+ -- discriminals still reference the first subprogram or entry to be
+ -- expanded (see Expand_Protected_Body_Declarations).
+
+ elsif Full_Analysis
+ and then Ekind (Entity (N)) = E_Constant
+ and then Present (Discriminal_Link (Entity (N)))
+ and then Is_Protected_Type (Scope (Discriminal_Link (Entity (N))))
+ then
+ goto Find_Name;
+
else
declare
Entyp : constant Entity_Id := Etype (Entity (N));
-- happens for trees generated from Exp_Pakd, where expressions
-- can be deliberately "mis-typed" to the packed array type.
- if Is_Array_Type (Entyp)
- and then Is_Packed (Entyp)
+ if Is_Packed_Array (Entyp)
and then Present (Etype (N))
and then Etype (N) = Packed_Array_Impl_Type (Entyp)
then
return;
end if;
+ <<Find_Name>>
+
-- Preserve relevant elaboration-related attributes of the context which
-- are no longer available or very expensive to recompute once analysis,
-- resolution, and expansion are over.
-- outside the instance.
if From_Actual_Package (E)
- and then Scope_Depth (E2) < Scope_Depth (Inst)
+ and then Scope_Depth (Scope (E2)) < Scope_Depth (Inst)
then
goto Found;
else
if Scope (E) = Scope (E2)
and then Ekind (E) = E_Package
- and then Present (Renamed_Object (E))
- and then Is_Generic_Instance (Renamed_Object (E))
- and then In_Open_Scopes (Renamed_Object (E))
+ and then Present (Renamed_Entity (E))
+ and then Is_Generic_Instance (Renamed_Entity (E))
+ and then In_Open_Scopes (Renamed_Entity (E))
and then Comes_From_Source (N)
then
Set_Is_Immediately_Visible (E, False);
-- If no homonyms were visible, the entity is unambiguous
if not Is_Overloaded (N) then
- if Reference_OK and then not Is_Actual_Parameter then
+ if not Is_Actual_Parameter then
Generate_Reference (E, N);
end if;
end if;
-- in SPARK mode where renamings are traversed for generating
-- local effects of subprograms.
- if Reference_OK
- and then Is_Object (E)
+ if Is_Object (E)
and then Present (Renamed_Object (E))
and then not GNATprove_Mode
then
begin
-- Generate reference unless this is an actual parameter
- -- (see comment below)
+ -- (see comment below).
- if Reference_OK and then Is_Actual_Parameter then
+ if not Is_Actual_Parameter then
Generate_Reference (E, N);
Set_Referenced (E, R);
end if;
-- Normal case, not a label: generate reference
else
- if Reference_OK and then not Is_Actual_Parameter then
+ if not Is_Actual_Parameter then
-- Package or generic package is always a simple reference
-- If we don't know now, generate reference later
when Unknown =>
- Deferred_References.Append ((E, N));
+ Defer_Reference ((E, N));
end case;
end if;
end if;
if Ada_Version >= Ada_2012
and then
(Nkind (Parent (N)) in N_Subexpr
- or else Nkind_In (Parent (N), N_Assignment_Statement,
- N_Object_Declaration,
- N_Parameter_Association))
+ or else Nkind (Parent (N)) in N_Assignment_Statement
+ | N_Object_Declaration
+ | N_Parameter_Association)
then
Check_Implicit_Dereference (N, Etype (E));
end if;
-- reference is a write when it appears on the left hand side of an
-- assignment.
- if Marker_OK
- and then Needs_Variable_Reference_Marker
- (N => N,
- Calls_OK => False)
- then
+ if Needs_Variable_Reference_Marker (N => N, Calls_OK => False) then
declare
Is_Assignment_LHS : constant Boolean := Is_LHS (N) = Yes;
Par := Nod;
while Present (Par) loop
if Nkind (Par) = N_Pragma then
- if Nam_In (Pragma_Name_Unmapped (Par),
- Name_Abstract_State,
- Name_Depends,
- Name_Global,
- Name_Initializes,
- Name_Refined_Depends,
- Name_Refined_Global)
+ if Pragma_Name_Unmapped (Par)
+ in Name_Abstract_State
+ | Name_Depends
+ | Name_Global
+ | Name_Initializes
+ | Name_Refined_Depends
+ | Name_Refined_Global
then
return True;
-- original package.
if Ekind (P_Name) = E_Package
- and then Present (Renamed_Object (P_Name))
+ and then Present (Renamed_Entity (P_Name))
then
- P_Name := Renamed_Object (P_Name);
+ P_Name := Renamed_Entity (P_Name);
+
+ if From_Limited_With (P_Name)
+ and then not Unit_Is_Visible (Cunit (Get_Source_Unit (P_Name)))
+ then
+ Error_Msg_NE
+ ("renaming of limited view of package & not usable in this"
+ & " context (RM 8.5.3(3.1/2))", Prefix (N), P_Name);
+
+ elsif Has_Limited_View (P_Name)
+ and then not Unit_Is_Visible (Cunit (Get_Source_Unit (P_Name)))
+ and then not Is_Visible_Through_Renamings (P_Name)
+ then
+ Error_Msg_NE
+ ("renaming of limited view of package & not usable in this"
+ & " context (RM 8.5.3(3.1/2))", Prefix (N), P_Name);
+ end if;
-- Rewrite node with entity field pointing to renamed object
-- The non-limited view may itself be incomplete, in which case
-- get the full view if available.
- elsif Ekind_In (Id, E_Incomplete_Type, E_Class_Wide_Type)
+ elsif Ekind (Id) in E_Incomplete_Type | E_Class_Wide_Type
and then From_Limited_With (Id)
and then Present (Non_Limited_View (Id))
and then Scope (Non_Limited_View (Id)) = P_Name
Candidate := Get_Full_View (Non_Limited_View (Id));
Is_New_Candidate := True;
+ -- Handle special case where the prefix is a renaming of a shadow
+ -- package which is visible. Required to avoid reporting spurious
+ -- errors.
+
+ elsif Ekind (P_Name) = E_Package
+ and then From_Limited_With (P_Name)
+ and then not From_Limited_With (Id)
+ and then Sloc (Scope (Id)) = Sloc (P_Name)
+ and then Unit_Is_Visible (Cunit (Get_Source_Unit (P_Name)))
+ then
+ Candidate := Get_Full_View (Id);
+ Is_New_Candidate := True;
+
-- An unusual case arises with a fully qualified name for an
-- entity local to a generic child unit package, within an
-- instantiation of that package. The name of the unit now
end;
if No (Id)
- and then Ekind_In (P_Name, E_Procedure, E_Function)
+ and then Ekind (P_Name) in E_Procedure | E_Function
and then Is_Generic_Instance (P_Name)
then
-- Expanded name denotes entity in (instance of) generic subprogram.
exit when S = Standard_Standard;
- if Ekind_In (S, E_Function,
- E_Package,
- E_Procedure)
+ if Ekind (S) in E_Function | E_Package | E_Procedure
then
P :=
Generic_Parent (Specification
end if;
end if;
- Change_Selected_Component_To_Expanded_Name (N);
+ case Nkind (N) is
+ when N_Selected_Component =>
+ Reinit_Field_To_Zero (N, F_Is_Prefixed_Call);
+ Change_Selected_Component_To_Expanded_Name (N);
+
+ when N_Expanded_Name =>
+ null;
+
+ when others =>
+ pragma Assert (False);
+ end case;
-- Preserve relevant elaboration-related attributes of the context which
-- are no longer available or very expensive to recompute once analysis,
Generate_Reference (Id, N, 'r');
when Unknown =>
- Deferred_References.Append ((Id, N));
+ Defer_Reference ((Id, N));
end case;
end if;
end Find_Expanded_Name;
--------------------
- -- Find_Most_Prev --
+ -- Find_First_Use --
--------------------
- function Find_Most_Prev (Use_Clause : Node_Id) return Node_Id is
+ function Find_First_Use (Use_Clause : Node_Id) return Node_Id is
Curr : Node_Id;
begin
end loop;
return Curr;
- end Find_Most_Prev;
+ end Find_First_Use;
-------------------------
-- Find_Renamed_Entity --
Scop := Entity (Prefix (Nam));
if Ekind (Scop) = E_Package
- and then Present (Renamed_Object (Scop))
+ and then Present (Renamed_Entity (Scop))
then
- Scop := Renamed_Object (Scop);
+ Scop := Renamed_Entity (Scop);
end if;
-- Operator is visible if prefix of expanded name denotes
if Within (It.Nam, Inst) then
if Within (Old_S, Inst) then
declare
- It_D : constant Uint := Scope_Depth (It.Nam);
- Old_D : constant Uint := Scope_Depth (Old_S);
+ It_D : constant Uint :=
+ Scope_Depth_Default_0 (It.Nam);
+ Old_D : constant Uint :=
+ Scope_Depth_Default_0 (Old_S);
N_Ent : Entity_Id;
begin
-- Choose the innermost subprogram, which
-- dispatch table wrappers. Required to avoid generating
-- elaboration code with HI runtimes.
- elsif RTU_Loaded (Ada_Tags)
- and then
- ((RTE_Available (RE_Dispatch_Table_Wrapper)
- and then Scope (Selector) =
- RTE (RE_Dispatch_Table_Wrapper))
- or else
- (RTE_Available (RE_No_Dispatch_Table_Wrapper)
- and then Scope (Selector) =
- RTE (RE_No_Dispatch_Table_Wrapper)))
+ elsif Is_RTE (Scope (Selector), RE_Dispatch_Table_Wrapper)
+ or else
+ Is_RTE (Scope (Selector), RE_No_Dispatch_Table_Wrapper)
then
C_Etype := Empty;
else
P_Type := Implicitly_Designated_Type (P_Type);
end if;
- -- First check for components of a record object (not the
- -- result of a call, which is handled below).
+ -- First check for components of a record object (not the result of
+ -- a call, which is handled below). This also covers the case where
+ -- where the extension feature that supports the prefixed form of
+ -- calls for primitives of untagged types is enabled (excluding
+ -- concurrent cases, which are handled further below).
- if Has_Components (P_Type)
+ if Is_Type (P_Type)
+ and then (Has_Components (P_Type)
+ or else (Extensions_Allowed
+ and then not Is_Concurrent_Type (P_Type)))
and then not Is_Overloadable (P_Name)
and then not Is_Type (P_Name)
then
-- Reference to type name in predicate/invariant expression
- elsif (Is_Task_Type (P_Type) or else Is_Protected_Type (P_Type))
+ elsif Is_Concurrent_Type (P_Type)
and then not In_Open_Scopes (P_Name)
and then (not Is_Concurrent_Type (Etype (P_Name))
or else not In_Open_Scopes (Etype (P_Name)))
-- The subprogram may be a renaming (of an enclosing scope) as
-- in the case of the name of the generic within an instantiation.
- if Ekind_In (P_Name, E_Procedure, E_Function)
+ if Ekind (P_Name) in E_Procedure | E_Function
and then Present (Alias (P_Name))
and then Is_Generic_Instance (Alias (P_Name))
then
Set_Entity (N, Any_Type);
return;
- -- ??? This test is temporarily disabled (always
- -- False) because it causes an unwanted warning on
- -- GNAT sources (built with -gnatg, which includes
- -- Warn_On_Obsolescent_ Feature). Once this issue
- -- is cleared in the sources, it can be enabled.
+ else
+ if Restriction_Check_Required (No_Obsolescent_Features)
+ then
+ Check_Restriction
+ (No_Obsolescent_Features, Prefix (N));
+ end if;
- elsif Warn_On_Obsolescent_Feature and then False then
- Error_Msg_N
- ("applying 'Class to an untagged incomplete type"
- & " is an obsolescent feature (RM J.11)?r?", N);
+ if Warn_On_Obsolescent_Feature then
+ Error_Msg_N
+ ("applying ''Class to an untagged incomplete type"
+ & " is an obsolescent feature (RM J.11)?r?", N);
+ end if;
end if;
end if;
if Ekind (Base_Type (T_Name)) = E_Task_Type then
-- In Ada 2005, a task name can be used in an access
- -- definition within its own body. It cannot be used
- -- in the discriminant part of the task declaration,
- -- nor anywhere else in the declaration because entries
- -- cannot have access parameters.
+ -- definition within its own body.
if Ada_Version >= Ada_2005
and then Nkind (Parent (N)) = N_Access_Definition
then
Set_Entity (N, T_Name);
Set_Etype (N, T_Name);
-
- if Has_Completion (T_Name) then
- return;
-
- else
- Error_Msg_N
- ("task type cannot be used as type mark " &
- "within its own declaration", N);
- end if;
+ return;
else
Error_Msg_N
else
Add_One_Interp (N, Predef_Op2, T);
end if;
-
else
if not Is_Binary_Op then
Add_One_Interp (N, Predef_Op, T);
- else
+
+ -- Predef_Op2 may be empty in case of previous errors
+
+ elsif Present (Predef_Op2) then
Add_One_Interp (N, Predef_Op2, T);
end if;
end if;
pragma Assert (No (Old_F));
- if Ekind_In (Old_S, E_Function, E_Enumeration_Literal) then
+ if Ekind (Old_S) in E_Function | E_Enumeration_Literal then
Set_Etype (New_S, Etype (Old_S));
end if;
end if;
-- Use clauses in and of themselves do not count as a "use" of a
-- package.
- if Nkind_In (Parent (Id), N_Use_Package_Clause, N_Use_Type_Clause) then
+ if Nkind (Parent (Id)) in N_Use_Package_Clause | N_Use_Type_Clause then
return;
end if;
-- Mark primitives
- elsif (Ekind (Id) in Overloadable_Kind
- or else Ekind_In (Id, E_Generic_Function,
- E_Generic_Procedure))
+ elsif (Is_Overloadable (Id)
+ or else Is_Generic_Subprogram (Id))
and then (Is_Potentially_Use_Visible (Id)
or else Is_Intrinsic_Subprogram (Id)
- or else (Ekind_In (Id, E_Function, E_Procedure)
+ or else (Ekind (Id) in E_Function | E_Procedure
and then Is_Generic_Actual_Subprogram (Id)))
then
Mark_Parameters (Id);
-- Ignore fully qualified names as they do not count as a "use" of
-- a package.
- if Nkind_In (Id, N_Identifier, N_Operator_Symbol)
+ if Nkind (Id) in N_Identifier | N_Operator_Symbol
or else (Present (Prefix (Id))
and then Scope (Entity (Id)) /= Entity (Prefix (Id)))
then
procedure Push_Scope (S : Entity_Id) is
E : constant Entity_Id := Scope (S);
+ function Component_Alignment_Default return Component_Alignment_Kind;
+ -- Return Component_Alignment_Kind for the newly-pushed scope.
+
+ function Component_Alignment_Default return Component_Alignment_Kind is
+ begin
+ -- Each new scope pushed onto the scope stack inherits the component
+ -- alignment of the previous scope. This emulates the "visibility"
+ -- semantics of pragma Component_Alignment.
+
+ if Scope_Stack.Last > Scope_Stack.First then
+ return Scope_Stack.Table
+ (Scope_Stack.Last - 1).Component_Alignment_Default;
+
+ -- Otherwise, this is the first scope being pushed on the scope
+ -- stack. Inherit the component alignment from the configuration
+ -- form of pragma Component_Alignment (if any).
+
+ else
+ return Configuration_Component_Alignment;
+ end if;
+ end Component_Alignment_Default;
+
begin
if Ekind (S) = E_Void then
null;
- -- Set scope depth if not a non-concurrent type, and we have not yet set
+ -- Set scope depth if not a nonconcurrent type, and we have not yet set
-- the scope depth. This means that we have the first occurrence of the
-- scope, and this is where the depth is set.
Set_Scope_Depth_Value (S, Uint_1);
elsif not Is_Record_Type (Current_Scope) then
- if Ekind (S) = E_Loop then
- Set_Scope_Depth_Value (S, Scope_Depth (Current_Scope));
- else
- Set_Scope_Depth_Value (S, Scope_Depth (Current_Scope) + 1);
+ if Scope_Depth_Set (Current_Scope) then
+ if Ekind (S) = E_Loop then
+ Set_Scope_Depth_Value (S, Scope_Depth (Current_Scope));
+ else
+ Set_Scope_Depth_Value (S, Scope_Depth (Current_Scope) + 1);
+ end if;
end if;
end if;
end if;
Scope_Stack.Increment_Last;
- declare
- SST : Scope_Stack_Entry renames Scope_Stack.Table (Scope_Stack.Last);
-
- begin
- SST.Entity := S;
- SST.Save_Scope_Suppress := Scope_Suppress;
- SST.Save_Local_Suppress_Stack_Top := Local_Suppress_Stack_Top;
- SST.Save_Check_Policy_List := Check_Policy_List;
- SST.Save_Default_Storage_Pool := Default_Pool;
- SST.Save_No_Tagged_Streams := No_Tagged_Streams;
- SST.Save_SPARK_Mode := SPARK_Mode;
- SST.Save_SPARK_Mode_Pragma := SPARK_Mode_Pragma;
- SST.Save_Default_SSO := Default_SSO;
- SST.Save_Uneval_Old := Uneval_Old;
-
- -- Each new scope pushed onto the scope stack inherits the component
- -- alignment of the previous scope. This emulates the "visibility"
- -- semantics of pragma Component_Alignment.
-
- if Scope_Stack.Last > Scope_Stack.First then
- SST.Component_Alignment_Default :=
- Scope_Stack.Table
- (Scope_Stack.Last - 1).Component_Alignment_Default;
-
- -- Otherwise, this is the first scope being pushed on the scope
- -- stack. Inherit the component alignment from the configuration
- -- form of pragma Component_Alignment (if any).
-
- else
- SST.Component_Alignment_Default :=
- Configuration_Component_Alignment;
- end if;
-
- SST.Last_Subprogram_Name := null;
- SST.Is_Transient := False;
- SST.Node_To_Be_Wrapped := Empty;
- SST.Pending_Freeze_Actions := No_List;
- SST.Actions_To_Be_Wrapped := (others => No_List);
- SST.First_Use_Clause := Empty;
- SST.Is_Active_Stack_Base := False;
- SST.Previous_Visibility := False;
- SST.Locked_Shared_Objects := No_Elist;
- end;
+ Scope_Stack.Table (Scope_Stack.Last) :=
+ (Entity => S,
+ Save_Scope_Suppress => Scope_Suppress,
+ Save_Local_Suppress_Stack_Top => Local_Suppress_Stack_Top,
+ Save_Check_Policy_List => Check_Policy_List,
+ Save_Default_Storage_Pool => Default_Pool,
+ Save_No_Tagged_Streams => No_Tagged_Streams,
+ Save_SPARK_Mode => SPARK_Mode,
+ Save_SPARK_Mode_Pragma => SPARK_Mode_Pragma,
+ Save_Default_SSO => Default_SSO,
+ Save_Uneval_Old => Uneval_Old,
+ Component_Alignment_Default => Component_Alignment_Default,
+ Last_Subprogram_Name => null,
+ Is_Transient => False,
+ Node_To_Be_Wrapped => Empty,
+ Pending_Freeze_Actions => No_List,
+ Actions_To_Be_Wrapped => (others => No_List),
+ First_Use_Clause => Empty,
+ Is_Active_Stack_Base => False,
+ Previous_Visibility => False,
+ Locked_Shared_Objects => No_Elist);
if Debug_Flag_W then
Write_Str ("--> new scope: ");
Set_Redundant_Use (Clause, True);
+ -- Do not check for redundant use if clause is generated, or in an
+ -- instance, or in a predefined unit to avoid misleading warnings
+ -- that may occur as part of a rtsfind load.
+
if not Comes_From_Source (Clause)
or else In_Instance
or else not Warn_On_Redundant_Constructs
+ or else Is_Predefined_Unit (Current_Sem_Unit)
then
return;
end if;
Private_Declarations (Parent (Decl))
then
declare
- Par : constant Entity_Id := Defining_Entity (Parent (Decl));
- Spec : constant Node_Id :=
- Specification (Unit (Cunit (Current_Sem_Unit)));
+ Par : constant Entity_Id :=
+ Defining_Entity (Parent (Decl));
+ Spec : constant Node_Id :=
+ Specification (Unit (Cunit (Current_Sem_Unit)));
Cur_List : constant List_Id := List_Containing (Cur_Use);
+
begin
if Is_Compilation_Unit (Par)
and then Par /= Cunit_Entity (Current_Sem_Unit)
if Present (Redundant) and then Parent (Redundant) /= Prev_Use then
-- Make sure we are looking at most-descendant use_package_clause
- -- by traversing the chain with Find_Most_Prev and then verifying
+ -- by traversing the chain with Find_First_Use and then verifying
-- there is no scope manipulation via Most_Descendant_Use_Clause.
if Nkind (Prev_Use) = N_Use_Package_Clause
and then
(Nkind (Parent (Prev_Use)) /= N_Compilation_Unit
or else Most_Descendant_Use_Clause
- (Prev_Use, Find_Most_Prev (Prev_Use)) /= Prev_Use)
+ (Prev_Use, Find_First_Use (Prev_Use)) /= Prev_Use)
then
- Prev_Use := Find_Most_Prev (Prev_Use);
+ Prev_Use := Find_First_Use (Prev_Use);
end if;
Error_Msg_Sloc := Sloc (Prev_Use);
Error_Msg_NE -- CODEFIX
- ("& is already use-visible through previous use_clause #??",
+ ("& is already use-visible through previous use_clause #?r?",
Redundant, Pack_Name);
end if;
end Note_Redundant_Use;
-- When a renaming exists we must check it for redundancy. The
-- original package would have already been seen at this point.
- if Present (Renamed_Object (Entity (Pack_Name))) then
- P := Renamed_Object (Entity (Pack_Name));
+ if Present (Renamed_Entity (Entity (Pack_Name))) then
+ P := Renamed_Entity (Entity (Pack_Name));
else
P := Entity (Pack_Name);
end if;
-- also in use (the flags on both entities must remain consistent, and a
-- subsequent use of either of them should be recognized as redundant).
- if Present (Renamed_Object (P)) then
- Set_In_Use (Renamed_Object (P));
- Set_Current_Use_Clause (Renamed_Object (P), N);
- Real_P := Renamed_Object (P);
+ if Present (Renamed_Entity (P)) then
+ Set_In_Use (Renamed_Entity (P));
+ Set_Current_Use_Clause (Renamed_Entity (P), N);
+ Real_P := Renamed_Entity (P);
else
Real_P := P;
end if;
if Present (Current_Use_Clause (T)) then
Use_Clause_Known : declare
Clause1 : constant Node_Id :=
- Find_Most_Prev (Current_Use_Clause (T));
+ Find_First_Use (Current_Use_Clause (T));
Clause2 : constant Node_Id := Parent (Id);
Ent1 : Entity_Id;
Ent2 : Entity_Id;
& "use_type_clause #??", Clause1, T);
return;
- elsif Nkind_In (Unit2, N_Package_Body, N_Subprogram_Body)
+ elsif Nkind (Unit2) in N_Package_Body | N_Subprogram_Body
and then Nkind (Unit1) /= Nkind (Unit2)
and then Nkind (Unit1) /= N_Subunit
then
-- a spurious warning - so verify there is a previous use clause.
if Current_Use_Clause (Scope (T)) /=
- Find_Most_Prev (Current_Use_Clause (Scope (T)))
+ Find_First_Use (Current_Use_Clause (Scope (T)))
then
Error_Msg_Sloc :=
- Sloc (Find_Most_Prev (Current_Use_Clause (Scope (T))));
+ Sloc (Find_First_Use (Current_Use_Clause (Scope (T))));
Error_Msg_NE -- CODEFIX
("& is already use-visible through package use clause #??",
Id, T);