[Ada] AI12-0211: Consistency of inherited nonoverridable aspects

gcc/ada/

	* aspects.ads: Introduce the subtype Nonoverridable_Aspect_Id,
	whose Static_Predicate reflects the list of nonoverridable
	aspects given in Ada RM 13.1.1(18.7).
	* sem_util.ads, sem_util.adb: Add two new visible subprograms,
	Check_Inherited_Nonoverridable_Aspects and Is_Confirming. The
	former is used to check the consistency of inherited
	nonoverridable aspects from multiple sources. The latter
	indicates whether two aspect specifications for a nonoverridable
	aspect are confirming. Because of compatibility concerns in
	compiling QGen, Is_Confirming always returns True if
	Relaxed_RM_Semantics (i.e., -gnatd.M) is specified.
	* sem_ch3.adb (Derived_Type_Declaration): Call new
	Check_Inherited_Nonoverridable_Aspects procedure if interface
	list is non-empty.
	* sem_ch9.adb (Check_Interfaces): Call new
	Check_Inherited_Nonoverridable_Aspects procedure if interface
	list is non-empty.
	* sem_ch13.adb (Analyze_Aspect_Specifications): When an explicit
	aspect specification overrides an inherited nonoverridable
	aspect, check that the explicit specification is confirming.
This commit is contained in:
Steve Baird 2020-08-06 11:09:50 -07:00 committed by Pierre-Marie de Rodat
parent 944fed738c
commit 7b3bda2ce2
6 changed files with 317 additions and 3 deletions

View File

@ -229,6 +229,16 @@ package Aspects is
Aspect_Id range Aspect_Id'Succ (No_Aspect) .. Aspect_Id'Last;
-- Aspect_Id's excluding No_Aspect
subtype Nonoverridable_Aspect_Id is Aspect_Id with
Static_Predicate => Nonoverridable_Aspect_Id in
Aspect_Default_Iterator | Aspect_Iterator_Element |
Aspect_Implicit_Dereference | Aspect_Constant_Indexing |
Aspect_Variable_Indexing | Aspect_Aggregate |
Aspect_Max_Entry_Queue_Length
-- | Aspect_No_Controlled_Parts
-- ??? No_Controlled_Parts not yet in Aspect_Id enumeration
; -- see RM 13.1.1(18.7)
-- The following array indicates aspects that accept 'Class
Class_Aspect_OK : constant array (Aspect_Id) of Boolean :=

View File

@ -4159,7 +4159,7 @@ package body Sem_Ch13 is
when Aspect_Aggregate =>
Validate_Aspect_Aggregate (Expr);
Record_Rep_Item (E, Aspect);
return;
goto Continue;
when Aspect_Integer_Literal
| Aspect_Real_Literal
@ -4751,9 +4751,39 @@ package body Sem_Ch13 is
Insert_After (Ins_Node, Aitem);
Ins_Node := Aitem;
end if;
<<Continue>>
-- If a nonoverridable aspect is explicitly specified for a
-- derived type, then check consistency with the parent type.
if A_Id in Nonoverridable_Aspect_Id
and then Nkind (N) = N_Full_Type_Declaration
and then Nkind (Type_Definition (N)) = N_Derived_Type_Definition
and then not In_Instance_Body
then
declare
Parent_Type : constant Entity_Id := Etype (E);
Inherited_Aspect : constant Node_Id :=
Find_Aspect (Parent_Type, A_Id);
begin
if Present (Inherited_Aspect)
and then not Is_Confirming
(A_Id, Inherited_Aspect, Aspect)
then
Error_Msg_Name_1 := Aspect_Names (A_Id);
Error_Msg_Sloc := Sloc (Inherited_Aspect);
Error_Msg
("overriding aspect specification for "
& "nonoverridable aspect % does not confirm "
& "aspect specification inherited from #",
Sloc (Aspect));
end if;
end;
end if;
end Analyze_One_Aspect;
<<Continue>>
Next (Aspect);
end loop Aspect_Loop;

View File

@ -16754,6 +16754,14 @@ package body Sem_Ch3 is
Next (Intf);
end loop;
end;
-- Check consistency of any nonoverridable aspects that are
-- inherited from multiple sources.
Check_Inherited_Nonoverridable_Aspects
(Inheritor => T,
Interface_List => Interface_List (Def),
Parent_Type => Parent_Type);
end if;
if Parent_Type = Any_Type

View File

@ -3532,6 +3532,14 @@ package body Sem_Ch9 is
Next (Iface);
end loop;
-- Check consistency of any nonoverridable aspects that are
-- inherited from multiple sources.
Check_Inherited_Nonoverridable_Aspects
(Inheritor => N,
Interface_List => Interface_List (N),
Parent_Type => Empty);
end if;
if not Has_Private_Declaration (T) then

View File

@ -25,7 +25,6 @@
with Treepr; -- ???For debugging code below
with Aspects; use Aspects;
with Casing; use Casing;
with Checks; use Checks;
with Debug; use Debug;
@ -53,6 +52,7 @@ with Sem_Attr; use Sem_Attr;
with Sem_Cat; use Sem_Cat;
with Sem_Ch6; use Sem_Ch6;
with Sem_Ch8; use Sem_Ch8;
with Sem_Ch13; use Sem_Ch13;
with Sem_Disp; use Sem_Disp;
with Sem_Elab; use Sem_Elab;
with Sem_Eval; use Sem_Eval;
@ -4142,6 +4142,132 @@ package body Sem_Util is
end if;
end Check_No_Hidden_State;
---------------------------------------------
-- Check_Nonoverridable_Aspect_Consistency --
---------------------------------------------
procedure Check_Inherited_Nonoverridable_Aspects
(Inheritor : Entity_Id;
Interface_List : List_Id;
Parent_Type : Entity_Id) is
-- array needed for iterating over subtype values
Nonoverridable_Aspects : constant array (Positive range <>) of
Nonoverridable_Aspect_Id :=
(Aspect_Default_Iterator,
Aspect_Iterator_Element,
Aspect_Implicit_Dereference,
Aspect_Constant_Indexing,
Aspect_Variable_Indexing,
Aspect_Aggregate,
Aspect_Max_Entry_Queue_Length
-- , Aspect_No_Controlled_Parts
);
-- Note that none of these 8 aspects can be specified (for a type)
-- via a pragma. For 7 of them, the corresponding pragma does not
-- exist. The Pragma_Id enumeration type does include
-- Pragma_Max_Entry_Queue_Length, but that pragma is only use to
-- specify the aspect for a protected entry or entry family, not for
-- a type, and therefore cannot introduce the sorts of inheritance
-- issues that we are concerned with in this procedure.
type Entity_Array is array (Nat range <>) of Entity_Id;
function Ancestor_Entities return Entity_Array;
-- Returns all progenitors (including parent type, if present)
procedure Check_Consistency_For_One_Aspect_Of_Two_Ancestors
(Aspect : Nonoverridable_Aspect_Id;
Ancestor_1 : Entity_Id;
Aspect_Spec_1 : Node_Id;
Ancestor_2 : Entity_Id;
Aspect_Spec_2 : Node_Id);
-- A given aspect has been specified for each of two ancestors;
-- check that the two aspect specifications are compatible (see
-- RM 13.1.1(18.5) and AI12-0211).
-----------------------
-- Ancestor_Entities --
-----------------------
function Ancestor_Entities return Entity_Array is
Ifc_Count : constant Nat := List_Length (Interface_List);
Ifc_Ancestors : Entity_Array (1 .. Ifc_Count);
Ifc : Node_Id := First (Interface_List);
begin
for Idx in Ifc_Ancestors'Range loop
Ifc_Ancestors (Idx) := Entity (Ifc);
pragma Assert (Present (Ifc_Ancestors (Idx)));
Ifc := Next (Ifc);
end loop;
pragma Assert (not Present (Ifc));
if Present (Parent_Type) then
return Parent_Type & Ifc_Ancestors;
else
return Ifc_Ancestors;
end if;
end Ancestor_Entities;
-------------------------------------------------------
-- Check_Consistency_For_One_Aspect_Of_Two_Ancestors --
-------------------------------------------------------
procedure Check_Consistency_For_One_Aspect_Of_Two_Ancestors
(Aspect : Nonoverridable_Aspect_Id;
Ancestor_1 : Entity_Id;
Aspect_Spec_1 : Node_Id;
Ancestor_2 : Entity_Id;
Aspect_Spec_2 : Node_Id) is
begin
if not Is_Confirming (Aspect, Aspect_Spec_1, Aspect_Spec_2) then
Error_Msg_Name_1 := Aspect_Names (Aspect);
Error_Msg_Name_2 := Chars (Ancestor_1);
Error_Msg_Name_3 := Chars (Ancestor_2);
Error_Msg (
"incompatible % aspects inherited from ancestors % and %",
Sloc (Inheritor));
end if;
end Check_Consistency_For_One_Aspect_Of_Two_Ancestors;
Ancestors : constant Entity_Array := Ancestor_Entities;
-- start of processing for Check_Inherited_Nonoverridable_Aspects
begin
-- No Ada_Version check here; AI12-0211 is a binding interpretation.
if Ancestors'Length < 2 then
return; -- Inconsistency impossible; it takes 2 to disagree.
elsif In_Instance_Body then
return; -- No legality checking in an instance body.
end if;
for Aspect of Nonoverridable_Aspects loop
declare
First_Ancestor_With_Aspect : Entity_Id := Empty;
First_Aspect_Spec, Current_Aspect_Spec : Node_Id := Empty;
begin
for Ancestor of Ancestors loop
Current_Aspect_Spec := Find_Aspect (Ancestor, Aspect);
if Present (Current_Aspect_Spec) then
if Present (First_Ancestor_With_Aspect) then
Check_Consistency_For_One_Aspect_Of_Two_Ancestors
(Aspect => Aspect,
Ancestor_1 => First_Ancestor_With_Aspect,
Aspect_Spec_1 => First_Aspect_Spec,
Ancestor_2 => Ancestor,
Aspect_Spec_2 => Current_Aspect_Spec);
else
First_Ancestor_With_Aspect := Ancestor;
First_Aspect_Spec := Current_Aspect_Spec;
end if;
end if;
end loop;
end;
end loop;
end Check_Inherited_Nonoverridable_Aspects;
----------------------------------------
-- Check_Nonvolatile_Function_Profile --
----------------------------------------
@ -15265,6 +15391,120 @@ package body Sem_Util is
return False;
end Is_Child_Or_Sibling;
-------------------
-- Is_Confirming --
-------------------
function Is_Confirming (Aspect : Nonoverridable_Aspect_Id;
Aspect_Spec_1, Aspect_Spec_2 : Node_Id)
return Boolean is
function Names_Match (Nm1, Nm2 : Node_Id) return Boolean;
function Names_Match (Nm1, Nm2 : Node_Id) return Boolean is
begin
if Nkind (Nm1) /= Nkind (Nm2) then
return False;
end if;
case Nkind (Nm1) is
when N_Identifier =>
return Name_Equals (Chars (Nm1), Chars (Nm2));
when N_Expanded_Name =>
return Names_Match (Prefix (Nm1), Prefix (Nm2))
and then Names_Match (Selector_Name (Nm1),
Selector_Name (Nm2));
when N_Empty =>
return True; -- needed for Aggregate aspect checking
when others =>
-- e.g., 'Class attribute references
if Is_Entity_Name (Nm1) and Is_Entity_Name (Nm2) then
return Entity (Nm1) = Entity (Nm2);
end if;
raise Program_Error;
end case;
end Names_Match;
begin
-- allow users to disable "shall be confirming" check, at least for now
if Relaxed_RM_Semantics then
return True;
end if;
-- ??? Type conversion here (along with "when others =>" below) is a
-- workaround for a bootstrapping problem related to casing on a
-- static-predicate-bearing subtype.
case Aspect_Id (Aspect) is
-- name-valued aspects; compare text of names, not resolution.
when Aspect_Default_Iterator
| Aspect_Iterator_Element
| Aspect_Constant_Indexing
| Aspect_Variable_Indexing
| Aspect_Implicit_Dereference =>
declare
Item_1 : constant Node_Id := Aspect_Rep_Item (Aspect_Spec_1);
Item_2 : constant Node_Id := Aspect_Rep_Item (Aspect_Spec_2);
begin
if (Nkind (Item_1) /= N_Attribute_Definition_Clause)
or (Nkind (Item_2) /= N_Attribute_Definition_Clause)
then
pragma Assert (Serious_Errors_Detected > 0);
return True;
end if;
return Names_Match (Expression (Item_1),
Expression (Item_2));
end;
-- one of a kind
when Aspect_Aggregate =>
declare
Empty_1,
Add_Named_1,
Add_Unnamed_1,
New_Indexed_1,
Assign_Indexed_1,
Empty_2,
Add_Named_2,
Add_Unnamed_2,
New_Indexed_2,
Assign_Indexed_2 : Node_Id := Empty;
begin
Parse_Aspect_Aggregate
(N => Expression (Aspect_Spec_1),
Empty_Subp => Empty_1,
Add_Named_Subp => Add_Named_1,
Add_Unnamed_Subp => Add_Unnamed_1,
New_Indexed_Subp => New_Indexed_1,
Assign_Indexed_Subp => Assign_Indexed_1);
Parse_Aspect_Aggregate
(N => Expression (Aspect_Spec_2),
Empty_Subp => Empty_2,
Add_Named_Subp => Add_Named_2,
Add_Unnamed_Subp => Add_Unnamed_2,
New_Indexed_Subp => New_Indexed_2,
Assign_Indexed_Subp => Assign_Indexed_2);
return
Names_Match (Empty_1, Empty_2) and then
Names_Match (Add_Named_1, Add_Named_2) and then
Names_Match (Add_Unnamed_1, Add_Unnamed_2) and then
Names_Match (New_Indexed_1, New_Indexed_2) and then
Names_Match (Assign_Indexed_1, Assign_Indexed_2);
end;
-- scalar-valued aspects; compare (static) values.
when Aspect_Max_Entry_Queue_Length -- | Aspect_No_Controlled_Parts
=>
-- This should be unreachable. No_Controlled_Parts is
-- not yet supported at all in GNAT and Max_Entry_Queue_Length
-- is supported only for protected entries, not for types.
pragma Assert (Serious_Errors_Detected /= 0);
return True;
when others =>
raise Program_Error;
end case;
end Is_Confirming;
-----------------------------
-- Is_Concurrent_Interface --
-----------------------------

View File

@ -25,6 +25,7 @@
-- Package containing utility procedures used throughout the semantics
with Aspects; use Aspects;
with Atree; use Atree;
with Einfo; use Einfo;
with Exp_Tss; use Exp_Tss;
@ -413,6 +414,17 @@ package Sem_Util is
-- Determine whether object or state Id introduces a hidden state. If this
-- is the case, emit an error.
procedure Check_Inherited_Nonoverridable_Aspects
(Inheritor : Entity_Id;
Interface_List : List_Id;
Parent_Type : Entity_Id);
-- Verify consistency of inherited nonoverridable aspects
-- when aspects are inherited from more than one source.
-- Parent_Type may be void (e.g., for a tagged task/protected type
-- whose declaration includes a non-empty interface list).
-- In the error case, error message is associate with Inheritor;
-- Inheritor parameter is otherwise unused.
procedure Check_Nonvolatile_Function_Profile (Func_Id : Entity_Id);
-- Verify that the profile of nonvolatile function Func_Id does not contain
-- effectively volatile parameters or return type for reading.
@ -1685,6 +1697,12 @@ package Sem_Util is
-- Determine whether entity Id denotes a procedure with synchronization
-- kind By_Protected_Procedure.
function Is_Confirming (Aspect : Nonoverridable_Aspect_Id;
Aspect_Spec_1, Aspect_Spec_2 : Node_Id)
return Boolean;
-- Returns true if the two specifications of the given
-- nonoverridable aspect are compatible.
function Is_Constant_Bound (Exp : Node_Id) return Boolean;
-- Exp is the expression for an array bound. Determines whether the
-- bound is a compile-time known value, or a constant entity, or an