Aspect_Export,
Aspect_Extensions_Visible, -- GNAT
Aspect_Favor_Top_Level, -- GNAT
+ Aspect_First_Controlling_Parameter, -- GNAT
Aspect_Full_Access_Only,
Aspect_Ghost, -- GNAT
Aspect_Import,
Aspect_Extensions_Visible => True,
Aspect_Favor_Top_Level => True,
Aspect_Finalizable => True,
+ Aspect_First_Controlling_Parameter => True,
Aspect_Ghost => True,
Aspect_Ghost_Predicate => True,
Aspect_Global => True,
Aspect_External_Name => False,
Aspect_External_Tag => False,
Aspect_Finalizable => False,
+ Aspect_First_Controlling_Parameter => False,
Aspect_Ghost_Predicate => False,
Aspect_Global => False,
Aspect_GNAT_Annotate => False,
Aspect_External_Tag => Name_External_Tag,
Aspect_Favor_Top_Level => Name_Favor_Top_Level,
Aspect_Finalizable => Name_Finalizable,
+ Aspect_First_Controlling_Parameter => Name_First_Controlling_Parameter,
Aspect_Full_Access_Only => Name_Full_Access_Only,
Aspect_Ghost => Name_Ghost,
Aspect_Ghost_Predicate => Name_Ghost_Predicate,
Aspect_Exceptional_Cases => Never_Delay,
Aspect_Export => Never_Delay,
Aspect_Extensions_Visible => Never_Delay,
+ Aspect_First_Controlling_Parameter => Never_Delay,
Aspect_Ghost => Never_Delay,
Aspect_Global => Never_Delay,
Aspect_GNAT_Annotate => Never_Delay,
-- that this does not imply a representation with holes, since the rep
-- clause may merely confirm the default 0..N representation.
+-- Has_First_Controlling_Parameter_Aspect
+-- Defined in tagged types, concurrent types and concurrent record types.
+-- Set to indicate that the type has a First_Controlling_Parameter of
+-- True (whether by an aspect_specification, a pragma, or inheritance).
+
-- Has_Exit
-- Defined in loop entities. Set if the loop contains an exit statement.
-- First_Entity
-- Corresponding_Record_Type
-- Entry_Bodies_Array
+ -- Has_First_Controlling_Parameter_Aspect
-- Last_Entity
-- Discriminant_Constraint
-- Scope_Depth_Value
-- Component_Alignment (special) (base type only)
-- C_Pass_By_Copy (base type only)
-- Has_Dispatch_Table (base tagged type only)
+ -- Has_First_Controlling_Parameter_Aspect
-- Has_Pragma_Pack (impl base type only)
-- Has_Private_Ancestor
-- Has_Private_Extension
-- Underlying_Record_View $$$ (base type only)
-- Predicated_Parent (subtype only)
-- Has_Completion
+ -- Has_First_Controlling_Parameter_Aspect
-- Has_Private_Ancestor
-- Has_Private_Extension
-- Has_Record_Rep_Clause (base type only)
-- Corresponding_Record_Type
-- Last_Entity
-- Discriminant_Constraint
+ -- Has_First_Controlling_Parameter_Aspect
-- Scope_Depth_Value
-- Stored_Constraint
-- Task_Body_Procedure
Rec_Ent : constant Entity_Id :=
Make_Defining_Identifier
(Loc, New_External_Name (Chars (Ctyp), 'V'));
+ Alist : List_Id;
+ Asp_Copy : Node_Id;
+ Aspect : Node_Id;
Disc : Entity_Id;
Dlist : List_Id;
New_Disc : Entity_Id;
Dlist := No_List;
end if;
+ -- Propagate the aspect First_Controlling_Parameter to the corresponding
+ -- record to reuse the tagged types machinery. This is not needed if
+ -- the concurrent type does not implement interface types, as the
+ -- corresponding record will not be a tagged type in such case.
+
+ Alist := No_List;
+
+ if Present (Parent (Ctyp))
+ and then Present (Interface_List (Parent (Ctyp)))
+ and then Present (Aspect_Specifications (N))
+ then
+ Aspect := First (Aspect_Specifications (N));
+ while Present (Aspect) loop
+ if Chars (Identifier (Aspect))
+ = Name_First_Controlling_Parameter
+ then
+ Alist := New_List;
+ Asp_Copy := New_Copy_Tree (Aspect);
+
+ -- Force its analysis in the corresponding record to add
+ -- the pragma.
+
+ Set_Analyzed (Asp_Copy, False);
+ Append_To (Alist, Asp_Copy);
+ exit;
+ end if;
+
+ Next (Aspect);
+ end loop;
+ end if;
+
-- Now we can construct the record type declaration. Note that this
-- record is "limited tagged". It is "limited" to reflect the underlying
-- limitedness of the task or protected object that it represents, and
return
Make_Full_Type_Declaration (Loc,
Defining_Identifier => Rec_Ent,
+ Aspect_Specifications => Alist,
Discriminant_Specifications => Dlist,
Type_Definition =>
Make_Record_Definition (Loc,
Analyze (Rec_Decl, Suppress => All_Checks);
+ -- Analyze aspects of the corresponding record type. They may have been
+ -- propagated to it and its analysis is required to add the pragma (see
+ -- propagation of aspect First_Controlling_Parameter in the subprogram
+ -- Build_Corresponding_Record).
+
+ if Has_Aspects (Rec_Decl) then
+ Analyze_Aspect_Specifications (Rec_Decl, Rec_Id);
+
+ -- Handle aspects that may have been implicitly inherited and must be
+ -- explicitly propagated to the corresponding record type. This applies
+ -- specifically when the First_Controlling_Parameter aspect has been
+ -- implicitly inherited from an implemented interface.
+
+ elsif Present (Interface_List (Parent (Prot_Typ)))
+ and then Has_First_Controlling_Parameter_Aspect (Prot_Typ)
+ then
+ Set_Has_First_Controlling_Parameter_Aspect (Rec_Id);
+ end if;
+
-- Ada 2005 (AI-345): Construct the primitive entry wrappers before
-- the corresponding record is frozen. If any wrappers are generated,
-- Current_Node is updated accordingly.
Analyze (Rec_Decl);
+ -- Analyze aspects of the corresponding record type. They may have been
+ -- propagated to it and its analysis is required to add the pragma (see
+ -- propagation of aspect First_Controlling_Parameter in the subprogram
+ -- Build_Corresponding_Record).
+
+ if Has_Aspects (Rec_Decl) then
+ Analyze_Aspect_Specifications (Rec_Decl, Rec_Ent);
+
+ -- Handle aspects that may have been implicitly inherited and must be
+ -- explicitly propagated to the corresponding record type. This applies
+ -- specifically when the First_Controlling_Parameter aspect has been
+ -- implicitly inherited from an implemented interface.
+
+ elsif Present (Interface_List (Parent (Tasktyp)))
+ and then Has_First_Controlling_Parameter_Aspect (Tasktyp)
+ then
+ Set_Has_First_Controlling_Parameter_Aspect (Rec_Ent);
+ end if;
+
-- Create the declaration of the task body procedure
Proc_Spec := Build_Task_Proc_Specification (Tasktyp);
-- variants referenceed by the Variant_Part VP are frozen. This is
-- a recursive routine to deal with nested variants.
+ procedure Warn_If_Implicitly_Inherited_Aspects (Tag_Typ : Entity_Id);
+ -- Report a warning for Tag_Typ when it implicitly inherits the
+ -- First_Controlling_Parameter aspect but does not explicitly
+ -- specify it.
+
-----------------
-- Check_Itype --
-----------------
end loop;
end Freeze_Choices_In_Variant_Part;
+ ------------------------------------------
+ -- Warn_If_Implicitly_Inherited_Aspects --
+ ------------------------------------------
+
+ procedure Warn_If_Implicitly_Inherited_Aspects (Tag_Typ : Entity_Id)
+ is
+ function Has_First_Ctrl_Param_Aspect return Boolean;
+ -- Determines if Tag_Typ explicitly has the aspect/pragma
+ -- First_Controlling_Parameter.
+
+ ---------------------------------
+ -- Has_First_Ctrl_Param_Aspect --
+ ---------------------------------
+
+ function Has_First_Ctrl_Param_Aspect return Boolean is
+ Decl_Nod : constant Node_Id := Parent (Tag_Typ);
+ Asp_Nod : Node_Id;
+ Nod : Node_Id;
+ Pragma_Arg : Node_Id;
+ Pragma_Ent : Entity_Id;
+
+ begin
+ pragma Assert (Nkind (Decl_Nod) = N_Full_Type_Declaration);
+
+ if Present (Aspect_Specifications (Decl_Nod)) then
+ Asp_Nod := First (Aspect_Specifications (Decl_Nod));
+ while Present (Asp_Nod) loop
+ if Chars (Identifier (Asp_Nod))
+ = Name_First_Controlling_Parameter
+ then
+ return True;
+ end if;
+
+ Next (Asp_Nod);
+ end loop;
+ end if;
+
+ -- Search for the occurrence of the pragma
+
+ Nod := Next (Decl_Nod);
+ while Present (Nod) loop
+ if Nkind (Nod) = N_Pragma
+ and then Chars (Pragma_Identifier (Nod))
+ = Name_First_Controlling_Parameter
+ and then Present (Pragma_Argument_Associations (Nod))
+ then
+ Pragma_Arg :=
+ Expression (First (Pragma_Argument_Associations (Nod)));
+
+ if Nkind (Pragma_Arg) = N_Identifier
+ and then Present (Entity (Pragma_Arg))
+ then
+ Pragma_Ent := Entity (Pragma_Arg);
+
+ if Pragma_Ent = Tag_Typ
+ or else
+ (Is_Concurrent_Type (Pragma_Ent)
+ and then
+ Corresponding_Record_Type (Pragma_Ent)
+ = Tag_Typ)
+ then
+ return True;
+ end if;
+ end if;
+ end if;
+
+ Next (Nod);
+ end loop;
+
+ return False;
+ end Has_First_Ctrl_Param_Aspect;
+
+ -- Local Variables
+
+ Has_Aspect_First_Ctrl_Param : constant Boolean :=
+ Has_First_Ctrl_Param_Aspect;
+
+ -- Start of processing for Warn_Implicitly_Inherited_Aspects
+
+ begin
+ -- Handle cases where reporting the warning is not needed
+
+ if not Warn_On_Non_Dispatching_Primitives then
+ return;
+
+ -- No check needed when this is the full view of a private type
+ -- declaration since the pragma/aspect must be placed and checked
+ -- in the partial view, and it is implicitly propagated to the
+ -- full view.
+
+ elsif Has_Private_Declaration (Tag_Typ)
+ and then Is_Tagged_Type (Incomplete_Or_Partial_View (Tag_Typ))
+ then
+ return;
+
+ -- Similar case but applied to concurrent types
+
+ elsif Is_Concurrent_Record_Type (Tag_Typ)
+ and then Has_Private_Declaration
+ (Corresponding_Concurrent_Type (Tag_Typ))
+ and then Is_Tagged_Type
+ (Incomplete_Or_Partial_View
+ (Corresponding_Concurrent_Type (Tag_Typ)))
+ then
+ return;
+ end if;
+
+ if Etype (Tag_Typ) /= Tag_Typ
+ and then Has_First_Controlling_Parameter_Aspect (Etype (Tag_Typ))
+ then
+ -- The attribute was implicitly inherited
+ pragma Assert
+ (Has_First_Controlling_Parameter_Aspect (Tag_Typ));
+
+ -- No warning needed when the current tagged type is not
+ -- an interface type since by definition the aspect is
+ -- implicitly propagated from its parent type; the warning
+ -- is reported on interface types since it may not be so
+ -- clear when some implemented interface types have the
+ -- aspect and other interface types don't have it. For
+ -- interface types, we don't report the warning when the
+ -- interface type is an extension of a single interface
+ -- type (for similarity with the behavior with regular
+ -- tagged types).
+
+ if not Has_Aspect_First_Ctrl_Param
+ and then Is_Interface (Tag_Typ)
+ and then not Is_Empty_Elmt_List (Interfaces (Tag_Typ))
+ then
+ Error_Msg_N
+ ("?_j?implicitly inherits aspect 'First_'Controlling_'"
+ & "Parameter!", Tag_Typ);
+ Error_Msg_NE
+ ("\?_j?from & and must be confirmed explicitly!",
+ Tag_Typ, Etype (Tag_Typ));
+ end if;
+
+ elsif Present (Interfaces (Tag_Typ))
+ and then not Is_Empty_Elmt_List (Interfaces (Tag_Typ))
+ then
+ -- To maintain consistency with the behavior when the aspect
+ -- is implicitly inherited from its parent type, we do not
+ -- report a warning for concurrent record types that implement
+ -- a single interface type. By definition, the aspect is
+ -- propagated from that interface type as if it were the parent
+ -- type. For example:
+
+ -- type Iface is interface with First_Controlling_Parameter;
+ -- task type T is new Iface with ...
+
+ if Is_Concurrent_Record_Type (Tag_Typ)
+ and then No (Next_Elmt (First_Elmt (Interfaces (Tag_Typ))))
+ then
+ null;
+
+ else
+ declare
+ Elmt : Elmt_Id := First_Elmt (Interfaces (Tag_Typ));
+ Iface : Entity_Id;
+
+ begin
+ while Present (Elmt) loop
+ Iface := Node (Elmt);
+ pragma Assert (Present (Iface));
+
+ if Has_First_Controlling_Parameter_Aspect (Iface)
+ and then not Has_Aspect_First_Ctrl_Param
+ then
+ pragma Assert
+ (Has_First_Controlling_Parameter_Aspect
+ (Tag_Typ));
+ Error_Msg_N
+ ("?_j?implicitly inherits aspect 'First_'"
+ & "Controlling_'Parameter", Tag_Typ);
+ Error_Msg_NE
+ ("\?_j?from & and must be confirmed explicitly!",
+ Tag_Typ, Iface);
+ exit;
+ end if;
+
+ Next_Elmt (Elmt);
+ end loop;
+ end;
+ end if;
+ end if;
+ end Warn_If_Implicitly_Inherited_Aspects;
+
-- Start of processing for Freeze_Record_Type
begin
end loop;
end;
end if;
+
+ -- For tagged types, warn on an implicitly inherited aspect/pragma
+ -- First_Controlling_Parameter that is not explicitly set.
+
+ if Is_Tagged_Type (Rec) then
+ Warn_If_Implicitly_Inherited_Aspects (Rec);
+ end if;
end Freeze_Record_Type;
-------------------------------
then
Check_Overriding_Indicator (E, Empty, Is_Primitive (E));
end if;
+
+ -- Check illegal subprograms of tagged types and interface types that
+ -- have aspect/pragma First_Controlling_Parameter.
+
+ if Comes_From_Source (E)
+ and then Is_Abstract_Subprogram (E)
+ then
+ if Is_Dispatching_Operation (E) then
+ if Ekind (E) = E_Function
+ and then Is_Interface (Etype (E))
+ and then not Is_Class_Wide_Type (Etype (E))
+ and then Has_First_Controlling_Parameter_Aspect
+ (Find_Dispatching_Type (E))
+ then
+ Error_Msg_NE
+ ("'First_'Controlling_'Parameter disallows returning a "
+ & "non-class-wide interface type",
+ E, Etype (E));
+ end if;
+
+ else
+ -- The type of the formals cannot be an interface type
+
+ if Present (First_Formal (E)) then
+ declare
+ Formal : Entity_Id := First_Formal (E);
+ Has_Aspect : Boolean := False;
+
+ begin
+ -- Check if some formal has the aspect
+
+ while Present (Formal) loop
+ if Is_Tagged_Type (Etype (Formal))
+ and then
+ Has_First_Controlling_Parameter_Aspect
+ (Etype (Formal))
+ then
+ Has_Aspect := True;
+ end if;
+
+ Next_Formal (Formal);
+ end loop;
+
+ -- If the aspect is present then report the error
+
+ if Has_Aspect then
+ Formal := First_Formal (E);
+
+ while Present (Formal) loop
+ if Is_Interface (Etype (Formal))
+ and then not Is_Class_Wide_Type (Etype (Formal))
+ then
+ Error_Msg_NE
+ ("not a dispatching primitive of interface type&",
+ E, Etype (Formal));
+ Error_Msg_N
+ ("\disallowed by 'First_'Controlling_'Parameter "
+ & "aspect", E);
+ end if;
+
+ Next_Formal (Formal);
+ end loop;
+ end if;
+ end;
+ end if;
+
+ if Ekind (E) = E_Function
+ and then Is_Interface (Etype (E))
+ and then not Is_Class_Wide_Type (Etype (E))
+ and then Has_First_Controlling_Parameter_Aspect (Etype (E))
+ then
+ Error_Msg_NE
+ ("not a dispatching primitive of interface type&",
+ E, Etype (E));
+ Error_Msg_N
+ ("\disallowed by 'First_'Controlling_'Parameter "
+ & "aspect", E);
+ end if;
+ end if;
+ end if;
end Freeze_Subprogram;
----------------------
Has_Enumeration_Rep_Clause,
Has_Exit,
Has_Expanded_Contract,
+ Has_First_Controlling_Parameter_Aspect,
Has_Forward_Instantiation,
Has_Fully_Qualified_Name,
Has_Ghost_Predicate_Aspect,
Sm (Has_Dispatch_Table, Flag,
Pre => "Is_Tagged_Type (N)"),
Sm (Has_Dynamic_Predicate_Aspect, Flag),
+ Sm (Has_First_Controlling_Parameter_Aspect, Flag,
+ Pre => "Is_Tagged_Type (N) or else Is_Concurrent_Type (N)"
+ & " or else Is_Concurrent_Record_Type (N)"),
Sm (Has_Ghost_Predicate_Aspect, Flag),
Sm (Has_Inheritable_Invariants, Flag, Base_Type_Only),
Sm (Has_Inherited_DIC, Flag, Base_Type_Only),
return "DT_Position";
when Forwards_OK =>
return "Forwards_OK";
+ when Has_First_Controlling_Parameter_Aspect =>
+ return "Has_First_Controlling_Parameter_Aspect";
when Has_Inherited_DIC =>
return "Has_Inherited_DIC";
when Has_Own_DIC =>
| Pragma_Fast_Math
| Pragma_Favor_Top_Level
| Pragma_Finalize_Storage_Only
+ | Pragma_First_Controlling_Parameter
| Pragma_Ghost
| Pragma_Global
| Pragma_GNAT_Annotate
then
Error_Msg_NE
("actual for & must be a tagged type", Actual, Gen_T);
+
+ -- For generic formal tagged types with the First_Controlling_Param
+ -- aspect, ensure that the actual type also has this aspect.
+
+ elsif Is_Tagged_Type (Act_T)
+ and then Is_Tagged_Type (A_Gen_T)
+ and then not Has_First_Controlling_Parameter_Aspect (Act_T)
+ and then Has_First_Controlling_Parameter_Aspect (A_Gen_T)
+ then
+ Error_Msg_NE
+ ("actual for & must be a 'First_'Controlling_'Parameter tagged "
+ & "type", Actual, Gen_T);
end if;
Validate_Discriminated_Formal_Type;
Pragma_Name => Nam);
end if;
+ -- Minimum check of First_Controlling_Parameter aspect;
+ -- the checks shared by the aspect and its corresponding
+ -- pragma are performed when the pragma is analyzed.
+
+ if A_Id = Aspect_First_Controlling_Parameter then
+ if Present (Expr) then
+ Analyze (Expr);
+ end if;
+
+ if (No (Expr) or else Entity (Expr) = Standard_True)
+ and then not Core_Extensions_Allowed
+ then
+ Error_Msg_GNAT_Extension
+ ("'First_'Controlling_'Parameter", Sloc (Aspect),
+ Is_Core_Extension => True);
+ goto Continue;
+ end if;
+
+ if not (Is_Type (E)
+ and then
+ (Is_Tagged_Type (E)
+ or else Is_Concurrent_Type (E)))
+ then
+ Error_Msg_N
+ ("aspect 'First_'Controlling_'Parameter can only "
+ & "apply to tagged type or concurrent type",
+ Aspect);
+ goto Continue;
+ end if;
+
+ -- If the aspect is specified for a derived type, the
+ -- specified value shall be confirming.
+
+ if Present (Expr)
+ and then Is_Derived_Type (E)
+ and then
+ Has_First_Controlling_Parameter_Aspect (Etype (E))
+ and then Entity (Expr) = Standard_False
+ then
+ Error_Msg_Name_1 := Nam;
+ Error_Msg_N
+ ("specification of inherited aspect% can only "
+ & "confirm parent value", Id);
+ end if;
+
+ -- Given that the aspect has been explicitly given,
+ -- we take note to avoid checking for its implicit
+ -- inheritance (see Analyze_Full_Type_Declaration).
+
+ Set_Has_First_Controlling_Parameter_Aspect (E);
+ end if;
+
-- In general cases, the corresponding pragma/attribute
-- definition clause will be inserted later at the freezing
-- point, and we do not need to build it now.
then
Check_Restriction (No_Local_Tagged_Types, T);
end if;
+
+ -- Derived tagged types inherit aspect First_Controlling_Parameter
+ -- from their parent type and also from implemented interface types.
+ -- We implicitly perform inheritance here and will check for the
+ -- explicit confirming pragma or aspect in the sources when this type
+ -- is frozen (required for pragmas since they are placed at any place
+ -- after the type declaration; otherwise, when the pragma is used after
+ -- some non-first-controlling-parameter primitive, the reported errors
+ -- and warning would differ when the pragma is used).
+
+ if Is_Tagged_Type (T)
+ and then Is_Derived_Type (T)
+ and then not Has_First_Controlling_Parameter_Aspect (T)
+ then
+ pragma Assert (Etype (T) /= T);
+
+ if Has_First_Controlling_Parameter_Aspect (Etype (T)) then
+ Set_Has_First_Controlling_Parameter_Aspect (T);
+
+ elsif Present (Interfaces (T))
+ and then not Is_Empty_Elmt_List (Interfaces (T))
+ then
+ declare
+ Elmt : Elmt_Id := First_Elmt (Interfaces (T));
+ Iface : Entity_Id;
+
+ begin
+ while Present (Elmt) loop
+ Iface := Node (Elmt);
+
+ if Has_First_Controlling_Parameter_Aspect (Iface) then
+ Set_Has_First_Controlling_Parameter_Aspect (T);
+ exit;
+ end if;
+
+ Next_Elmt (Elmt);
+ end loop;
+ end;
+ end if;
+ end if;
end Analyze_Full_Type_Declaration;
----------------------------------
end;
end if;
+ -- Propagate First_Controlling_Parameter aspect to the full type
+
+ if Is_Tagged_Type (Priv_T)
+ and then Has_First_Controlling_Parameter_Aspect (Priv_T)
+ then
+ Set_Has_First_Controlling_Parameter_Aspect (Full_T);
+ end if;
+
-- Propagate predicates to full type, and predicate function if already
-- defined. It is not clear that this can actually happen? the partial
-- view cannot be frozen yet, and the predicate function has not been
-- replace the overridden primitive in Typ's primitives list with
-- the new subprogram.
- function Visible_Part_Type (T : Entity_Id) return Boolean;
- -- Returns true if T is declared in the visible part of the current
- -- package scope; otherwise returns false. Assumes that T is declared
- -- in a package.
-
procedure Check_Private_Overriding (T : Entity_Id);
-- Checks that if a primitive abstract subprogram of a visible
-- abstract type is declared in a private part, then it must override
-- in a private part, then it must override a function declared in
-- the visible part.
+ function Is_A_Primitive
+ (Typ : Entity_Id;
+ Subp : Entity_Id) return Boolean;
+ -- Typ is either the return type of function Subp or the type of one
+ -- of its formals; determine if Subp is a primitive of type Typ.
+
+ function Visible_Part_Type (T : Entity_Id) return Boolean;
+ -- Returns true if T is declared in the visible part of the current
+ -- package scope; otherwise returns false. Assumes that T is declared
+ -- in a package.
+
---------------------------------------
-- Add_Or_Replace_Untagged_Primitive --
---------------------------------------
-- operation. That's illegal in the tagged case
-- (but not if the private type is untagged).
- if T = Base_Type (Etype (S)) then
+ if T = Base_Type (Etype (S))
+ and then Has_Controlling_Result (S)
+ then
Error_Msg_N
("private function with controlling result must"
& " override visible-part function", S);
elsif Ekind (Etype (S)) = E_Anonymous_Access_Type
and then T = Base_Type (Designated_Type (Etype (S)))
+ and then Has_Controlling_Result (S)
and then Ada_Version >= Ada_2012
then
Error_Msg_N
end if;
end Check_Private_Overriding;
+ --------------------
+ -- Is_A_Primitive --
+ --------------------
+
+ function Is_A_Primitive
+ (Typ : Entity_Id;
+ Subp : Entity_Id) return Boolean is
+ begin
+ if Scope (Typ) /= Current_Scope
+ or else Is_Class_Wide_Type (Typ)
+ or else Is_Generic_Type (Typ)
+ then
+ return False;
+
+ -- Untagged type primitive
+
+ elsif not Is_Tagged_Type (Typ) then
+ return True;
+
+ -- Primitive of a tagged type without the First_Controlling_Param
+ -- aspect.
+
+ elsif not Has_First_Controlling_Parameter_Aspect (Typ) then
+ return True;
+
+ -- Non-overriding primitive of a tagged type with the
+ -- First_Controlling_Parameter aspect
+
+ elsif No (Overridden_Operation (Subp)) then
+ return Present (First_Formal (Subp))
+ and then Etype (First_Formal (Subp)) = Typ;
+
+ -- Primitive of a tagged type with the First_Controlling_Parameter
+ -- aspect, overriding an inherited primitive of a tagged type
+ -- without this aspect.
+
+ else
+ if Ekind (Subp) = E_Function
+ and then Has_Controlling_Result (Overridden_Operation (Subp))
+ then
+ return True;
+
+ elsif Is_Dispatching_Operation
+ (Overridden_Operation (Subp))
+ then
+ return True;
+ end if;
+ end if;
+
+ return False;
+ end Is_A_Primitive;
+
-----------------------
-- Visible_Part_Type --
-----------------------
B_Typ := Base_Type (F_Typ);
- if Scope (B_Typ) = Current_Scope
- and then not Is_Class_Wide_Type (B_Typ)
- and then not Is_Generic_Type (B_Typ)
- then
+ if Is_A_Primitive (B_Typ, S) then
Is_Primitive := True;
Set_Has_Primitive_Operations (B_Typ);
Set_Is_Primitive (S);
B_Typ := Base_Type (B_Typ);
end if;
- if Scope (B_Typ) = Current_Scope
- and then not Is_Class_Wide_Type (B_Typ)
- and then not Is_Generic_Type (B_Typ)
- then
+ if Is_A_Primitive (B_Typ, S) then
Is_Primitive := True;
Set_Is_Primitive (S);
Set_Has_Primitive_Operations (B_Typ);
Freeze_Before (N, Etype (Iface));
+ -- Implicit inheritance of attribute
+
+ if not Has_First_Controlling_Parameter_Aspect (T)
+ and then Has_First_Controlling_Parameter_Aspect (Iface_Typ)
+ then
+ Set_Has_First_Controlling_Parameter_Aspect (T);
+ end if;
+
if Nkind (N) = N_Protected_Type_Declaration then
-- Ada 2005 (AI-345): Protected types can only implement
Formal := First_Formal (Subp);
while Present (Formal) loop
- Ctrl_Type := Check_Controlling_Type (Etype (Formal), Subp);
+ Ctrl_Type := Empty;
+
+ -- Common Ada case
+
+ if not Has_First_Controlling_Parameter_Aspect (Typ) then
+ Ctrl_Type := Check_Controlling_Type (Etype (Formal), Subp);
+
+ -- Type with the First_Controlling_Parameter aspect: for overriding
+ -- primitives of a parent type that lacks this aspect, we cannot be
+ -- more restrictive than the overridden primitive. This also applies
+ -- to renamings of dispatching primitives. Dispatching operators can
+ -- have one or two controlling parameters, as long as one of them is
+ -- the first one, and none of the parameters have the same type as
+ -- the operator's result type.
+
+ -- Internal subprograms added by the frontend bypass the restrictions
+ -- of First_Controlling_Parameter aspect.
+
+ elsif Formal = First_Formal (Subp)
+ or else Is_Internal (Subp)
+ or else Present (Overridden_Operation (Subp))
+ or else
+ (Present (Alias (Subp))
+ and then Is_Dispatching_Operation (Ultimate_Alias (Subp)))
+ or else
+ (Ekind (Subp) = E_Function
+ and then Is_Operator_Name (Chars (Subp)))
+ then
+ Ctrl_Type := Check_Controlling_Type (Etype (Formal), Subp);
+ end if;
if Present (Ctrl_Type) then
Next_Formal (Formal);
end loop;
- if Ekind (Subp) in E_Function | E_Generic_Function then
+ -- Functions overriding parent type primitives that lack the aspect
+ -- First_Controlling_Param cannot be more restrictive than the
+ -- overridden function. This also applies to renamings of dispatching
+ -- primitives. Internal subprograms added by the frontend bypass these
+ -- restrictions.
+
+ if Ekind (Subp) in E_Function | E_Generic_Function
+ and then (not Has_First_Controlling_Parameter_Aspect (Typ)
+ or else Is_Internal (Subp)
+ or else
+ (Present (Overridden_Operation (Subp))
+ and then
+ Has_Controlling_Result (Overridden_Operation (Subp)))
+ or else
+ (Present (Alias (Subp))
+ and then
+ Has_Controlling_Result (Ultimate_Alias (Subp))))
+ then
Ctrl_Type := Check_Controlling_Type (Etype (Subp), Subp);
if Present (Ctrl_Type) then
Typ := Etype (Subp);
end if;
- -- The following should be better commented, especially since
- -- we just added several new conditions here ???
+ -- Report warning on non dispatching primitives of interface
+ -- type Typ; this warning is disabled when the type has the
+ -- aspect First_Controlling_Parameter because we will report
+ -- an error when the interface type is frozen.
if Comes_From_Source (Subp)
and then Is_Interface (Typ)
and then not Is_Derived_Type (Typ)
and then not Is_Generic_Type (Typ)
and then not In_Instance
+ and then not Has_First_Controlling_Parameter_Aspect (Typ)
then
Error_Msg_N ("??declaration of& is too late!", Subp);
Error_Msg_NE
-- cascaded errors.
elsif not Error_Posted (Subp) then
+
+ -- When aspect First_Controlling_Parameter applies, check if the
+ -- subprogram is a primitive. Internal subprograms added by the
+ -- frontend bypass its restrictions.
+
+ if Has_First_Controlling_Parameter_Aspect (Tagged_Type)
+ and then not Is_Internal (Subp)
+ and then not
+ (Present (Overridden_Operation (Subp))
+ and then
+ Is_Dispatching_Operation (Overridden_Operation (Subp)))
+ and then not
+ (Present (Alias (Subp))
+ and then
+ Is_Dispatching_Operation (Ultimate_Alias (Subp)))
+ and then (No (First_Formal (Subp))
+ or else not
+ Is_Controlling_Formal (First_Formal (Subp)))
+ then
+ if Warn_On_Non_Dispatching_Primitives then
+ Error_Msg_NE
+ ("?_j?not a dispatching primitive of tagged type&",
+ Subp, Tagged_Type);
+ Error_Msg_NE
+ ("\?_j?disallowed by 'First_'Controlling_'Parameter on &",
+ Subp, Tagged_Type);
+ end if;
+
+ return;
+ end if;
+
Add_Dispatching_Operation (Tagged_Type, Subp);
end if;
---------------------------
function Find_Dispatching_Type (Subp : Entity_Id) return Entity_Id is
+
+ function Has_Predefined_Dispatching_Operation_Name return Boolean;
+ -- Determines if Subp has the name of a predefined dispatching
+ -- operation.
+
+ -----------------------------------------------
+ -- Has_Predefined_Dispatching_Operation_Name --
+ -----------------------------------------------
+
+ function Has_Predefined_Dispatching_Operation_Name return Boolean is
+ TSS_Name : TSS_Name_Type;
+
+ begin
+ Get_Name_String (Chars (Subp));
+
+ if Name_Len > TSS_Name_Type'Last then
+ TSS_Name :=
+ TSS_Name_Type
+ (Name_Buffer (Name_Len - TSS_Name'Length + 1 .. Name_Len));
+
+ if Chars (Subp) in Name_uAssign
+ | Name_uSize
+ | Name_Op_Eq
+ or else TSS_Name = TSS_Deep_Adjust
+ or else TSS_Name = TSS_Deep_Finalize
+ or else TSS_Name = TSS_Stream_Input
+ or else TSS_Name = TSS_Stream_Output
+ or else TSS_Name = TSS_Stream_Read
+ or else TSS_Name = TSS_Stream_Write
+ or else TSS_Name = TSS_Put_Image
+
+ -- Name of predefined interface type primitives
+
+ or else Chars (Subp) in Name_uDisp_Asynchronous_Select
+ | Name_uDisp_Conditional_Select
+ | Name_uDisp_Get_Prim_Op_Kind
+ | Name_uDisp_Get_Task_Id
+ | Name_uDisp_Requeue
+ | Name_uDisp_Timed_Select
+ then
+ return True;
+ end if;
+ end if;
+
+ return False;
+ end Has_Predefined_Dispatching_Operation_Name;
+
+ -- Local variables
+
A_Formal : Entity_Id;
Formal : Entity_Id;
Ctrl_Type : Entity_Id;
-- The subprogram may also be dispatching on result
if Present (Etype (Subp)) then
- return Check_Controlling_Type (Etype (Subp), Subp);
+ if Is_Tagged_Type (Etype (Subp))
+ and then Has_First_Controlling_Parameter_Aspect (Etype (Subp))
+ then
+ if Present (Overridden_Operation (Subp))
+ and then Has_Controlling_Result (Overridden_Operation (Subp))
+ then
+ return Check_Controlling_Type (Etype (Subp), Subp);
+
+ -- Internal subprograms added by the frontend bypass the
+ -- restrictions of First_Controlling_Parameter aspect.
+
+ elsif Is_Internal (Subp)
+ and then Has_Predefined_Dispatching_Operation_Name
+ then
+ return Check_Controlling_Type (Etype (Subp), Subp);
+ end if;
+ else
+ return Check_Controlling_Type (Etype (Subp), Subp);
+ end if;
end if;
end if;
(Tagged_Type : Entity_Id;
Iface_Prim : Entity_Id) return Entity_Id
is
+ Is_FCP_Type : constant Boolean :=
+ Has_First_Controlling_Parameter_Aspect (Tagged_Type);
E : Entity_Id;
El : Elmt_Id;
while Present (E) loop
if Is_Subprogram (E)
and then Is_Dispatching_Operation (E)
- and then Is_Interface_Conformant (Tagged_Type, Iface_Prim, E)
then
- return E;
+ -- For overriding primitives of parent or interface types that
+ -- do not have the aspect First_Controlling_Parameter, we must
+ -- temporarily unset this attribute to check conformance.
+
+ if Ekind (E) = E_Function
+ and then Is_FCP_Type
+ and then Present (Overridden_Operation (E))
+ and then Has_Controlling_Result (Overridden_Operation (E))
+ then
+ Set_Has_First_Controlling_Parameter_Aspect (Tagged_Type, False);
+
+ if Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
+ Set_Has_First_Controlling_Parameter_Aspect
+ (Tagged_Type, Is_FCP_Type);
+ return E;
+ end if;
+
+ Set_Has_First_Controlling_Parameter_Aspect
+ (Tagged_Type, Is_FCP_Type);
+
+ elsif Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
+ return E;
+ end if;
end if;
E := Homonym (E);
-- Check if E covers the interface primitive (includes case in
-- which E is an inherited private primitive).
- if Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
+ -- For overriding primitives of parent or interface types that
+ -- do not have the aspect First_Controlling_Parameter, we must
+ -- temporarily unset this attribute to check conformance.
+
+ if Present (Overridden_Operation (E))
+ and then Is_FCP_Type
+ and then not
+ Has_First_Controlling_Parameter_Aspect
+ (Find_Dispatching_Type (Overridden_Operation (E)))
+ then
+ Set_Has_First_Controlling_Parameter_Aspect (Tagged_Type, False);
+
+ if Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
+ Set_Has_First_Controlling_Parameter_Aspect
+ (Tagged_Type, Is_FCP_Type);
+ return E;
+ end if;
+
+ Set_Has_First_Controlling_Parameter_Aspect
+ (Tagged_Type, Is_FCP_Type);
+
+ elsif Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
return E;
end if;
end if;
end Finalize_Storage;
+ ----------------------------------------
+ -- Pragma_First_Controlling_Parameter --
+ ----------------------------------------
+
+ when Pragma_First_Controlling_Parameter => First_Ctrl_Param : declare
+ Arg : Node_Id;
+ E : Entity_Id := Empty;
+
+ begin
+ if not Core_Extensions_Allowed then
+ return;
+ end if;
+
+ GNAT_Pragma;
+ Check_Arg_Count (1);
+
+ Arg := Get_Pragma_Arg (Arg1);
+
+ if Nkind (Arg) = N_Identifier then
+ Analyze (Arg);
+ E := Entity (Arg);
+ end if;
+
+ if No (E)
+ or else not Is_Type (E)
+ or else not (Is_Tagged_Type (E)
+ or else Is_Concurrent_Type (E))
+ then
+ Error_Pragma
+ ("pragma% must specify tagged type or concurrent type");
+ end if;
+
+ -- Check use of the pragma on private types
+
+ if Has_Private_Declaration (E) then
+ declare
+ Prev_Id : constant Entity_Id :=
+ Incomplete_Or_Partial_View (E);
+ begin
+ if Is_Tagged_Type (Prev_Id) then
+ if Has_First_Controlling_Parameter_Aspect (Prev_Id) then
+ Error_Pragma
+ ("pragma already specified in private declaration");
+ else
+ Error_Msg_N
+ ("hidden 'First_'Controlling_'Parameter tagged type"
+ & " not allowed", N);
+ end if;
+
+ -- No action needed if the partial view is not tagged. For
+ -- example:
+
+ -- package Example is
+ -- type Private_Type is private;
+ -- private
+ -- type Private_Type is new ... with null record
+ -- with First_Controlling_Parameter; -- Legal
+ -- end;
+
+ else
+ null;
+ end if;
+ end;
+ end if;
+
+ -- The corresponding record type of concurrent types will not be
+ -- a tagged type when it does not implement some interface type.
+
+ if Is_Concurrent_Type (E)
+ and then Present (Parent (E))
+ and then No (Interface_List (Parent (E)))
+ then
+ if Warn_On_Non_Dispatching_Primitives then
+ Error_Msg_N
+ ("?_j?'First_'Controlling_'Parameter has no effect", N);
+ Error_Msg_NE
+ ("?_j?because & does not implement interface types",
+ N, E);
+ end if;
+
+ else
+ Set_Has_First_Controlling_Parameter_Aspect (E);
+ end if;
+ end First_Ctrl_Param;
+
-----------
-- Ghost --
-----------
Pragma_Fast_Math => 0,
Pragma_Favor_Top_Level => 0,
Pragma_Finalize_Storage_Only => 0,
+ Pragma_First_Controlling_Parameter => 0,
Pragma_Ghost => 0,
Pragma_Global => -1,
Pragma_GNAT_Annotate => 93,
Pragma_Export => True,
Pragma_Extensions_Visible => True,
Pragma_Favor_Top_Level => True,
+ Pragma_First_Controlling_Parameter => True,
Pragma_Ghost => True,
Pragma_Global => True,
Pragma_GNAT_Annotate => True,
Name_Extensions_Visible : constant Name_Id := N + $; -- GNAT
Name_External : constant Name_Id := N + $; -- GNAT
Name_Finalize_Storage_Only : constant Name_Id := N + $; -- GNAT
+ Name_First_Controlling_Parameter : constant Name_Id := N + $;
Name_Ghost : constant Name_Id := N + $; -- GNAT
Name_Global : constant Name_Id := N + $; -- GNAT
Name_Ident : constant Name_Id := N + $; -- GNAT
Pragma_Extensions_Visible,
Pragma_External,
Pragma_Finalize_Storage_Only,
+ Pragma_First_Controlling_Parameter,
Pragma_Ghost,
Pragma_Global,
Pragma_Ident,
'z' => X.Warn_On_Size_Alignment),
'_' =>
- ('b' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' |
+ ('b' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'k' | 'l' | 'm' |
'n' | 'o' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' =>
No_Such_Warning,
'a' => X.Warn_On_Anonymous_Allocators,
'c' => X.Warn_On_Unknown_Compile_Time_Warning,
+ 'j' => X.Warn_On_Non_Dispatching_Primitives,
'p' => X.Warn_On_Pedantic_Checks,
'q' => X.Warn_On_Ignored_Equality,
'r' => X.Warn_On_Component_Order,
-- These warnings are removed from the -gnatwa set
Implementation_Unit_Warnings := False;
+ Warn_On_Non_Dispatching_Primitives := False;
Warn_On_Non_Local_Exception := False;
No_Warn_On_Non_Local_Exception := True;
Warn_On_Reverse_Bit_Order := False;
Warn_On_Late_Primitives,
Warn_On_Modified_Unread,
Warn_On_No_Value_Assigned,
+ Warn_On_Non_Dispatching_Primitives,
Warn_On_Non_Local_Exception,
No_Warn_On_Non_Local_Exception,
Warn_On_Object_Renames_Function,
Warn_On_Ineffective_Predicate_Test |
Warn_On_Late_Primitives |
Warn_On_Modified_Unread |
+ Warn_On_Non_Dispatching_Primitives |
Warn_On_Non_Local_Exception |
No_Warn_On_Non_Local_Exception |
Warn_On_Object_Renames_Function |
-- suppress such warnings. The default is that such warnings are enabled.
-- Modified by use of -gnatwv/V.
+ Warn_On_Non_Dispatching_Primitives : Boolean renames F (X.Warn_On_Non_Dispatching_Primitives);
+ -- Set to True to generate warnings for non dispatching primitives of tagged
+ -- types that have aspect/pragma First_Controlling_Parameter set to True.
+ -- This is turned on by -gnatw_j and turned off by -gnatw_J
+
Warn_On_Non_Local_Exception : Boolean renames F (X.Warn_On_Non_Local_Exception);
-- Set to True to generate warnings for non-local exception raises and also
-- handlers that can never handle a local raise. This warning is only ever