===================================================================
@@ -1732,6 +1732,7 @@
(N : Node_Id) return Boolean is
begin
pragma Assert (False
+ or else NT (N).Nkind = N_Aspect_Specification
or else NT (N).Nkind = N_Attribute_Definition_Clause
or else NT (N).Nkind = N_Pragma);
return Flag14 (N);
@@ -4760,6 +4761,7 @@
(N : Node_Id; Val : Boolean := True) is
begin
pragma Assert (False
+ or else NT (N).Nkind = N_Aspect_Specification
or else NT (N).Nkind = N_Attribute_Definition_Clause
or else NT (N).Nkind = N_Pragma);
Set_Flag14 (N, Val);
===================================================================
@@ -1265,7 +1265,8 @@
-- Is_Delayed_Aspect (Flag14-Sem)
-- Present in N_Pragma and N_Attribute_Definition_Clause nodes which
-- come from aspect specifications, where the evaluation of the aspect
- -- must be delayed to the freeze point.
+ -- must be delayed to the freeze point. This flag is also set True in
+ -- the corresponding N_Aspect_Specification node.
-- Is_Controlling_Actual (Flag16-Sem)
-- This flag is set on in an expression that is a controlling argument in
@@ -6548,9 +6549,17 @@
-- Next_Rep_Item (Node5-Sem)
-- Split_PPC (Flag17) Set if split pre/post attribute
-- Is_Boolean_Aspect (Flag16-Sem)
+ -- Is_Delayed_Aspect (Flag14-Sem)
-- Note: Aspect_Specification is an Ada 2012 feature
+ -- Note: The Identifier serves to identify the aspect involved (it
+ -- is the aspect whose name corresponds to the Chars field). This
+ -- means that the other fields of this identifier are unused, and
+ -- in particular we use the Entity field of this identifier to save
+ -- a copy of the expression for visibility analysis, see spec of
+ -- Sem_Ch13 for full details of this usage.
+
-- Note: When a Pre or Post aspect specification is processed, it is
-- broken into AND THEN sections. The left most section has Split_PPC
-- set to False, indicating that it is the original specification (e.g.
===================================================================
@@ -1323,6 +1323,27 @@
if not Is_Frozen (E) then
Flist := Freeze_Entity (E, After);
Process_Flist;
+
+ -- If already frozen, and there are delayed aspects, this is where
+ -- we do the visibility check for these aspects (see Sem_Ch13 spec
+ -- for a description of how we handle aspect visibility).
+
+ elsif Has_Delayed_Aspects (E) then
+ declare
+ Ritem : Node_Id;
+
+ begin
+ Ritem := First_Rep_Item (E);
+ while Present (Ritem) loop
+ if Nkind (Ritem) = N_Aspect_Specification
+ and then Is_Delayed_Aspect (Ritem)
+ then
+ Check_Aspect_At_End_Of_Declarations (Ritem);
+ end if;
+
+ Ritem := Next_Rep_Item (Ritem);
+ end loop;
+ end;
end if;
-- If an incomplete type is still not frozen, this may be a
@@ -2390,9 +2411,9 @@
while Present (Ritem) loop
if Nkind (Ritem) = N_Aspect_Specification
and then Entity (Ritem) = E
+ and then Is_Delayed_Aspect (Ritem)
then
Aitem := Aspect_Rep_Item (Ritem);
- pragma Assert (Is_Delayed_Aspect (Aitem));
Set_Parent (Aitem, Ritem);
-- Deal with Boolean case, if no expression, True, otherwise
@@ -2423,6 +2444,10 @@
-- Analyze the pragma after possibly setting Aspect_Cancel
Analyze (Aitem);
+
+ -- Do visibility analysis for aspect at freeze point
+
+ Check_Aspect_At_Freeze_Point (Ritem);
end if;
Next_Rep_Item (Ritem);
===================================================================
@@ -700,11 +700,10 @@
-- one of two things happens:
-- If we are required to delay the evaluation of this aspect to the
- -- freeze point, we preanalyze the relevant argument, and then attach
- -- the corresponding pragma/attribute definition clause to the aspect
- -- specification node, which is then placed in the Rep Item chain.
- -- In this case we mark the entity with the Has_Delayed_Aspects flag,
- -- and we evaluate the rep item at the freeze point.
+ -- freeze point, we attach the corresponding pragma/attribute definition
+ -- clause to the aspect specification node, which is then placed in the
+ -- Rep Item chain. In this case we mark the entity by setting the flag
+ -- Has_Delayed_Aspects and we evaluate the rep item at the freeze point.
-- If no delay is required, we just insert the pragma or attribute
-- after the declaration, and it will get processed by the normal
@@ -800,6 +799,11 @@
Next (Anod);
end loop;
+ -- Copy expression for later processing by the procedures
+ -- Check_Aspect_At_[Freeze_Point | End_Of_Declarations]
+
+ Set_Entity (Id, New_Copy_Tree (Expr));
+
-- Processing based on specific aspect
case A_Id is
@@ -836,6 +840,7 @@
else
Delay_Required := True;
+ Set_Is_Delayed_Aspect (Aspect);
end if;
-- Aspects corresponding to attribute definition clauses
@@ -868,6 +873,7 @@
-- Here a delay is required
Delay_Required := True;
+ Set_Is_Delayed_Aspect (Aspect);
-- Aspects corresponding to pragmas with two arguments, where
-- the first argument is a local name referring to the entity,
@@ -981,6 +987,7 @@
end if;
Set_From_Aspect_Specification (Aitem, True);
+ Set_Is_Delayed_Aspect (Aspect);
-- For Pre/Post cases, insert immediately after the entity
-- declaration, since that is the required pragma placement.
@@ -1032,6 +1039,7 @@
end if;
Set_From_Aspect_Specification (Aitem, True);
+ Set_Is_Delayed_Aspect (Aspect);
-- For Invariant case, insert immediately after the entity
-- declaration. We do not have to worry about delay issues
@@ -1065,6 +1073,7 @@
-- have a place to build the predicate function).
Ensure_Freeze_Node (E);
+ Set_Is_Delayed_Aspect (Aspect);
-- For Predicate case, insert immediately after the entity
-- declaration. We do not have to worry about delay issues
@@ -4850,6 +4859,161 @@
return;
end Build_Static_Predicate;
+ -----------------------------------------
+ -- Check_Aspect_At_End_Of_Declarations --
+ -----------------------------------------
+
+ procedure Check_Aspect_At_End_Of_Declarations (ASN : Node_Id) is
+ Ent : constant Entity_Id := Entity (ASN);
+ Ident : constant Node_Id := Identifier (ASN);
+
+ Freeze_Expr : constant Node_Id := Expression (ASN);
+ -- Preanalyzed expression from call to Check_Aspect_At_Freeze_Point
+
+ End_Decl_Expr : constant Node_Id := Entity (Ident);
+ -- Expression to be analyzed at end of declarations
+
+ T : constant Entity_Id := Etype (Freeze_Expr);
+ -- Type required for preanalyze call
+
+ A_Id : constant Aspect_Id := Get_Aspect_Id (Chars (Ident));
+
+ Err : Boolean;
+ -- Set False if error
+
+ -- On entry to this procedure, Entity (Ident) contains a copy of the
+ -- original expression from the aspect, saved for this purpose, and
+ -- but Expression (Ident) is a preanalyzed copy of the expression,
+ -- preanalyzed just after the freeze point.
+
+ begin
+ -- Case of stream attributes, just have to compare entities
+
+ if A_Id = Aspect_Input or else
+ A_Id = Aspect_Output or else
+ A_Id = Aspect_Read or else
+ A_Id = Aspect_Write
+ then
+ Analyze (End_Decl_Expr);
+ Err := Entity (End_Decl_Expr) /= Entity (Freeze_Expr);
+
+ -- All other cases
+
+ else
+ Preanalyze_Spec_Expression (End_Decl_Expr, T);
+ Err := not Fully_Conformant_Expressions (End_Decl_Expr, Freeze_Expr);
+ end if;
+
+ -- Output error message if error
+
+ if Err then
+ Error_Msg_NE
+ ("visibility of aspect for& changes after freeze point",
+ ASN, Ent);
+ Error_Msg_NE
+ ("?info: & is frozen here, aspects evaluated at this point",
+ Freeze_Node (Ent), Ent);
+ end if;
+ end Check_Aspect_At_End_Of_Declarations;
+
+ ----------------------------------
+ -- Check_Aspect_At_Freeze_Point --
+ ----------------------------------
+
+ procedure Check_Aspect_At_Freeze_Point (ASN : Node_Id) is
+ Ident : constant Node_Id := Identifier (ASN);
+ -- Identifier (use Entity field to save expression)
+
+ T : Entity_Id;
+ -- Type required for preanalyze call
+
+ A_Id : constant Aspect_Id := Get_Aspect_Id (Chars (Ident));
+
+ begin
+ -- On entry to this procedure, Entity (Ident) contains a copy of the
+ -- original expression from the aspect, saved for this purpose.
+
+ -- On exit from this procedure Entity (Ident) is unchanged, still
+ -- containing that copy, but Expression (Ident) is a preanalyzed copy
+ -- of the expression, preanalyzed just after the freeze point.
+
+ -- Make a copy of the expression to be preanalyed
+
+ Set_Expression (ASN, New_Copy_Tree (Entity (Ident)));
+
+ -- Find type for preanalyze call
+
+ case A_Id is
+
+ -- No_Aspect should be impossible
+
+ when No_Aspect =>
+ raise Program_Error;
+
+ -- Aspects taking an optional boolean argument. Note that we will
+ -- never be called with an empty expression, because such aspects
+ -- never need to be delayed anyway.
+
+ when Boolean_Aspects =>
+ pragma Assert (Present (Expression (ASN)));
+ T := Standard_Boolean;
+
+ -- Aspects corresponding to attribute definition clauses
+
+ when Aspect_Address =>
+ T := RTE (RE_Address);
+
+ when Aspect_Bit_Order =>
+ T := RTE (RE_Bit_Order);
+
+ when Aspect_External_Tag =>
+ T := Standard_String;
+
+ when Aspect_Storage_Pool =>
+ T := Class_Wide_Type (RTE (RE_Root_Storage_Pool));
+
+ when
+ Aspect_Alignment |
+ Aspect_Component_Size |
+ Aspect_Machine_Radix |
+ Aspect_Object_Size |
+ Aspect_Size |
+ Aspect_Storage_Size |
+ Aspect_Stream_Size |
+ Aspect_Value_Size =>
+ T := Any_Integer;
+
+ -- Stream attribute. Special case, the expression is just an entity
+ -- that does not need any resolution, so just analyze.
+
+ when Aspect_Input |
+ Aspect_Output |
+ Aspect_Read |
+ Aspect_Write =>
+ Analyze (Expression (ASN));
+ return;
+
+ -- Suppress/Unsupress/Warnings should never be delayed
+
+ when Aspect_Suppress |
+ Aspect_Unsuppress |
+ Aspect_Warnings =>
+ raise Program_Error;
+
+ -- Pre/Post/Invariant/Predicate take boolean expressions
+
+ when Aspect_Pre |
+ Aspect_Post |
+ Aspect_Invariant |
+ Aspect_Predicate =>
+ T := Standard_Boolean;
+ end case;
+
+ -- Do the preanalyze call
+
+ Preanalyze_Spec_Expression (Expression (ASN), T);
+ end Check_Aspect_At_Freeze_Point;
+
-----------------------------------
-- Check_Constant_Address_Clause --
-----------------------------------
===================================================================
@@ -236,4 +236,81 @@
Table_Increment => 200,
Table_Name => "Independence_Checks");
+ -----------------------------------
+ -- Handling of Aspect Visibility --
+ -----------------------------------
+
+ -- The visibility of aspects is tricky. First, the visibility is delayed
+ -- to the freeze point. This is not too complicated, what we do is simply
+ -- to leave the aspect "laying in wait" for the freeze point, and at that
+ -- point materialize and analye the corresponding attribute definition
+ -- clause or pragma. There is some special processing for preconditions
+ -- and postonditions, where the pragmas themselves deal with the required
+ -- delay, but basically the approach is the same, delay analysis of the
+ -- expression to the freeze point.
+
+ -- Much harder is the requirement for diagnosing cases in which an early
+ -- freeze causes a change in visibility. Consider:
+
+ -- package AspectVis is
+ -- R_Size : constant Integer := 32;
+ --
+ -- package Inner is
+ -- type R is new Integer with
+ -- Size => R_Size;
+ -- F : R; -- freezes
+ -- R_Size : constant Integer := 64;
+ -- S : constant Integer := R'Size; -- 32 not 64
+ -- end Inner;
+ -- end AspectVis;
+
+ -- Here the 32 not 64 shows what would be expected if this program were
+ -- legal, since the evaluation of R_Size has to be done at the freeze
+ -- point and gets the outer definition not the inner one.
+
+ -- But the language rule requires this program to be diagnosed as illegal
+ -- because the visibility changes between the freeze point and the end of
+ -- the declarative region.
+
+ -- To meet this requirement, we first note that the Expression field of the
+ -- N_Aspect_Specification node holds the raw unanalyzed expression, which
+ -- will get used in processing the aspect. At the time of analyzing the
+ -- N_Aspect_Specification node, we create a complete copy of the expression
+ -- and store it in the entity field of the Identifier (an odd usage, but
+ -- the identifier is not used except to identify the aspect, so its Entity
+ -- field is otherwise unused, and we are short of room in the node).
+
+ -- This copy stays unanalyzed up to the freeze point, where we analyze the
+ -- resulting pragma or attribute definition clause, except that in the
+ -- case of invariants and predicates, we mark occurrences of the subtype
+ -- name as having the entity of the subprogram parameter, so that they
+ -- will not cause trouble in the following steps.
+
+ -- Then at the freeze point, we create another copy of this unanalyzed
+ -- expression. By this time we no longer need the Expression field for
+ -- other purposes, so we can store it there. Now we have two copies of
+ -- the original unanalyzed expression. One of them gets preanalyzed at
+ -- the freeze point to capture the visibility at the freeze point.
+
+ -- Now when we hit the freeze all at the end of the declarative part, if
+ -- we come across a frozen entity with delayed aspects, we still have one
+ -- copy of the unanalyzed expression available in the node, and we again
+ -- do a preanalysis using that copy and the visibility at the end of the
+ -- declarative part. Now we have two preanalyzed expression (preanalysis
+ -- is good enough, since we are only interested in referenced entities).
+ -- One captures the visibility at the freeze point, the other captures the
+ -- visibility at the end of the declarative part. We see if the entities
+ -- in these two expressions are the same, by seeing if the two expressions
+ -- are fully conformant, and if not, issue appropriate error messages.
+
+ -- Quite an awkward procedure, but this is an awkard requirement!
+
+ procedure Check_Aspect_At_Freeze_Point (ASN : Node_Id);
+ -- Performs the processing described above at the freeze point, ASN is the
+ -- N_Aspect_Specification node for the aspect.
+
+ procedure Check_Aspect_At_End_Of_Declarations (ASN : Node_Id);
+ -- Performs the processing described above at the freeze all point, and
+ -- issues appropriate error messages if the visibility has indeed changed.
+ -- Again, ASN is the N_Aspect_Specification node for the aspect.
end Sem_Ch13;