blob: 6059cee002276144de4e538eed80d56c6b2da0a9 [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S E M _ C H 1 3 --
-- --
-- B o d y --
-- --
-- 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- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
-- for more details. You should have received a copy of the GNU General --
-- Public License distributed with GNAT; see file COPYING3. If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
with Contracts; use Contracts;
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 Lib; use Lib;
with Lib.Xref; use Lib.Xref;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Opt; use Opt;
with Par_SCO; use Par_SCO;
with Restrict; use Restrict;
with Rident; use Rident;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Case; use Sem_Case;
with Sem_Cat; use Sem_Cat;
with Sem_Ch3; use Sem_Ch3;
with Sem_Ch6; use Sem_Ch6;
with Sem_Ch7; use Sem_Ch7;
with Sem_Ch8; use Sem_Ch8;
with Sem_Dim; use Sem_Dim;
with Sem_Eval; use Sem_Eval;
with Sem_Prag; use Sem_Prag;
with Sem_Res; use Sem_Res;
with Sem_Type; use Sem_Type;
with Sem_Util; use Sem_Util;
with Sem_Warn; use Sem_Warn;
with Sinfo; use Sinfo;
with Sinfo.Nodes; use Sinfo.Nodes;
with Sinfo.Utils; use Sinfo.Utils;
with Sinput; use Sinput;
with Snames; use Snames;
with Stand; use Stand;
with Table;
with Targparm; use Targparm;
with Ttypes; use Ttypes;
with Tbuild; use Tbuild;
with Urealp; use Urealp;
with Warnsw; use Warnsw;
with GNAT.Heap_Sort_G;
package body Sem_Ch13 is
SSU : constant Pos := System_Storage_Unit;
-- Convenient short hand for commonly used constant
-----------------------
-- Local Subprograms --
-----------------------
procedure Adjust_Record_For_Reverse_Bit_Order_Ada_95 (R : Entity_Id);
-- Helper routine providing the original (pre-AI95-0133) behavior for
-- Adjust_Record_For_Reverse_Bit_Order.
procedure Alignment_Check_For_Size_Change (Typ : Entity_Id; Size : Uint);
-- This routine is called after setting one of the sizes of type entity
-- Typ to Size. The purpose is to deal with the situation of a derived
-- type whose inherited alignment is no longer appropriate for the new
-- size value. In this case, we reset the Alignment to unknown.
function All_Static_Choices (L : List_Id) return Boolean;
-- Returns true if all elements of the list are OK static choices
-- as defined below for Is_Static_Choice. Used for case expression
-- alternatives and for the right operand of a membership test. An
-- others_choice is static if the corresponding expression is static.
-- The staticness of the bounds is checked separately.
procedure Build_Discrete_Static_Predicate
(Typ : Entity_Id;
Expr : Node_Id;
Nam : Name_Id);
-- Given a predicated type Typ, where Typ is a discrete static subtype,
-- whose predicate expression is Expr, tests if Expr is a static predicate,
-- and if so, builds the predicate range list. Nam is the name of the one
-- argument to the predicate function. Occurrences of the type name in the
-- predicate expression have been replaced by identifier references to this
-- name, which is unique, so any identifier with Chars matching Nam must be
-- a reference to the type. If the predicate is non-static, this procedure
-- returns doing nothing. If the predicate is static, then the predicate
-- list is stored in Static_Discrete_Predicate (Typ), and the Expr is
-- rewritten as a canonicalized membership operation.
function Build_Export_Import_Pragma
(Asp : Node_Id;
Id : Entity_Id) return Node_Id;
-- Create the corresponding pragma for aspect Export or Import denoted by
-- Asp. Id is the related entity subject to the aspect. Return Empty when
-- the expression of aspect Asp evaluates to False or is erroneous.
function Build_Predicate_Function_Declaration
(Typ : Entity_Id) return Node_Id;
-- Build the declaration for a predicate function. The declaration is built
-- at the end of the declarative part containing the type definition, which
-- may be before the freeze point of the type. The predicate expression is
-- preanalyzed at this point, to catch visibility errors.
procedure Build_Predicate_Functions (Typ : Entity_Id; N : Node_Id);
-- If Typ has predicates (indicated by Has_Predicates being set for Typ),
-- then either there are pragma Predicate entries on the rep chain for the
-- type (note that Predicate aspects are converted to pragma Predicate), or
-- there are inherited aspects from a parent type, or ancestor subtypes.
-- This procedure builds body for the Predicate function that tests these
-- predicates. N is the freeze node for the type. The spec of the function
-- is inserted before the freeze node, and the body of the function is
-- inserted after the freeze node. If the predicate expression has a least
-- one Raise_Expression, then this procedure also builds the M version of
-- the predicate function for use in membership tests.
procedure Check_Pool_Size_Clash (Ent : Entity_Id; SP, SS : Node_Id);
-- Called if both Storage_Pool and Storage_Size attribute definition
-- clauses (SP and SS) are present for entity Ent. Issue error message.
procedure Freeze_Entity_Checks (N : Node_Id);
-- Called from Analyze_Freeze_Entity and Analyze_Generic_Freeze Entity
-- to generate appropriate semantic checks that are delayed until this
-- point (they had to be delayed this long for cases of delayed aspects,
-- e.g. analysis of statically predicated subtypes in choices, for which
-- we have to be sure the subtypes in question are frozen before checking).
function Get_Alignment_Value (Expr : Node_Id) return Uint;
-- Given the expression for an alignment value, returns the corresponding
-- Uint value. If the value is inappropriate, then error messages are
-- posted as required, and a value of No_Uint is returned.
function Is_Operational_Item (N : Node_Id) return Boolean;
-- A specification for a stream attribute is allowed before the full type
-- is declared, as explained in AI-00137 and the corrigendum. Attributes
-- that do not specify a representation characteristic are operational
-- attributes.
function Is_Static_Choice (N : Node_Id) return Boolean;
-- Returns True if N represents a static choice (static subtype, or
-- static subtype indication, or static expression, or static range).
--
-- Note that this is a bit more inclusive than we actually need
-- (in particular membership tests do not allow the use of subtype
-- indications). But that doesn't matter, we have already checked
-- that the construct is legal to get this far.
function Is_Type_Related_Rep_Item (N : Node_Id) return Boolean;
-- Returns True for a representation clause/pragma that specifies a
-- type-related representation (as opposed to operational) aspect.
function Is_Predicate_Static
(Expr : Node_Id;
Nam : Name_Id) return Boolean;
-- Given predicate expression Expr, tests if Expr is predicate-static in
-- the sense of the rules in (RM 3.2.4 (15-24)). Occurrences of the type
-- name in the predicate expression have been replaced by references to
-- an identifier whose Chars field is Nam. This name is unique, so any
-- identifier with Chars matching Nam must be a reference to the type.
-- Returns True if the expression is predicate-static and False otherwise,
-- but is not in the business of setting flags or issuing error messages.
--
-- Only scalar types can have static predicates, so False is always
-- returned for non-scalar types.
--
-- Note: the RM seems to suggest that string types can also have static
-- predicates. But that really makes lttle sense as very few useful
-- predicates can be constructed for strings. Remember that:
--
-- "ABC" < "DEF"
--
-- is not a static expression. So even though the clearly faulty RM wording
-- allows the following:
--
-- subtype S is String with Static_Predicate => S < "DEF"
--
-- We can't allow this, otherwise we have predicate-static applying to a
-- larger class than static expressions, which was never intended.
procedure New_Put_Image_Subprogram
(N : Node_Id;
Ent : Entity_Id;
Subp : Entity_Id);
-- Similar to New_Stream_Subprogram, but for the Put_Image attribute
procedure New_Stream_Subprogram
(N : Node_Id;
Ent : Entity_Id;
Subp : Entity_Id;
Nam : TSS_Name_Type);
-- Create a subprogram renaming of a given stream attribute to the
-- designated subprogram and then in the tagged case, provide this as a
-- primitive operation, or in the untagged case make an appropriate TSS
-- entry. This is more properly an expansion activity than just semantics,
-- but the presence of user-defined stream functions for limited types
-- is a legality check, which is why this takes place here rather than in
-- exp_ch13, where it was previously. Nam indicates the name of the TSS
-- function to be generated.
--
-- To avoid elaboration anomalies with freeze nodes, for untagged types
-- we generate both a subprogram declaration and a subprogram renaming
-- declaration, so that the attribute specification is handled as a
-- renaming_as_body. For tagged types, the specification is one of the
-- primitive specs.
procedure No_Type_Rep_Item (N : Node_Id);
-- Output message indicating that no type-related aspects can be
-- specified due to some property of the parent type.
procedure Register_Address_Clause_Check
(N : Node_Id;
X : Entity_Id;
A : Uint;
Y : Entity_Id;
Off : Boolean);
-- Register a check for the address clause N. The rest of the parameters
-- are in keeping with the components of Address_Clause_Check_Record below.
procedure Validate_Aspect_Aggregate (N : Node_Id);
-- Check legality of operations given in the Ada 2022 Aggregate aspect for
-- containers.
procedure Resolve_Aspect_Aggregate
(Typ : Entity_Id;
Expr : Node_Id);
-- Resolve each one of the operations specified in the specification of
-- Aspect_Aggregate.
procedure Validate_Aspect_Stable_Properties
(E : Entity_Id; N : Node_Id; Class_Present : Boolean);
-- Check legality of functions given in the Ada 2022 Stable_Properties
-- (or Stable_Properties'Class) aspect.
procedure Validate_Storage_Model_Type_Aspect
(Typ : Entity_Id; ASN : Node_Id);
-- Check legality and completeness of the aggregate associations given in
-- the Storage_Model_Type aspect associated with Typ.
procedure Resolve_Storage_Model_Type_Argument
(N : Node_Id;
Typ : Entity_Id;
Addr_Type : in out Entity_Id;
Nam : Name_Id);
-- Resolve argument N to be of the proper kind (when a type or constant)
-- or to have the proper profile (when a subprogram).
procedure Resolve_Aspect_Stable_Properties
(Typ_Or_Subp : Entity_Id;
Expr : Node_Id;
Class_Present : Boolean);
-- Resolve each one of the functions specified in the specification of
-- aspect Stable_Properties (or Stable_Properties'Class).
procedure Resolve_Iterable_Operation
(N : Node_Id;
Cursor : Entity_Id;
Typ : Entity_Id;
Nam : Name_Id);
-- If the name of a primitive operation for an Iterable aspect is
-- overloaded, resolve according to required signature.
procedure Set_Biased
(E : Entity_Id;
N : Node_Id;
Msg : String;
Biased : Boolean := True);
-- If Biased is True, sets Has_Biased_Representation flag for E, and
-- outputs a warning message at node N if Warn_On_Biased_Representation is
-- is True. This warning inserts the string Msg to describe the construct
-- causing biasing.
-----------------------------------------------------------
-- Visibility of Discriminants in Aspect Specifications --
-----------------------------------------------------------
-- The discriminants of a type are visible when analyzing the aspect
-- specifications of a type declaration or protected type declaration,
-- but not when analyzing those of a subtype declaration. The following
-- routines enforce this distinction.
procedure Push_Type (E : Entity_Id);
-- Push scope E and make visible the discriminants of type entity E if E
-- has discriminants and is not a subtype.
procedure Pop_Type (E : Entity_Id);
-- Remove visibility to the discriminants of type entity E and pop the
-- scope stack if E has discriminants and is not a subtype.
----------------------------------------------
-- Table for Validate_Unchecked_Conversions --
----------------------------------------------
-- The following table collects unchecked conversions for validation.
-- Entries are made by Validate_Unchecked_Conversion and then the call
-- to Validate_Unchecked_Conversions does the actual error checking and
-- posting of warnings. The reason for this delayed processing is to take
-- advantage of back-annotations of size and alignment values performed by
-- the back end.
-- Note: the reason we store a Source_Ptr value instead of a Node_Id is
-- that by the time Validate_Unchecked_Conversions is called, Sprint will
-- already have modified all Sloc values if the -gnatD option is set.
type UC_Entry is record
Eloc : Source_Ptr; -- node used for posting warnings
Source : Entity_Id; -- source type for unchecked conversion
Target : Entity_Id; -- target type for unchecked conversion
Act_Unit : Entity_Id; -- actual function instantiated
end record;
package Unchecked_Conversions is new Table.Table (
Table_Component_Type => UC_Entry,
Table_Index_Type => Int,
Table_Low_Bound => 1,
Table_Initial => 50,
Table_Increment => 200,
Table_Name => "Unchecked_Conversions");
----------------------------------------
-- Table for Validate_Address_Clauses --
----------------------------------------
-- If an address clause has the form
-- for X'Address use Expr
-- where Expr has a value known at compile time or is of the form Y'Address
-- or recursively is a reference to a constant initialized with either of
-- these forms, and the value of Expr is not a multiple of X's alignment,
-- or if Y has a smaller alignment than X, then that merits a warning about
-- possible bad alignment. The following table collects address clauses of
-- this kind. We put these in a table so that they can be checked after the
-- back end has completed annotation of the alignments of objects, since we
-- can catch more cases that way.
type Address_Clause_Check_Record is record
N : Node_Id;
-- The address clause
X : Entity_Id;
-- The entity of the object subject to the address clause
A : Uint;
-- The value of the address in the first case
Y : Entity_Id;
-- The entity of the object being overlaid in the second case
Off : Boolean;
-- Whether the address is offset within Y in the second case
Alignment_Checks_Suppressed : Boolean;
-- Whether alignment checks are suppressed by an active scope suppress
-- setting. We need to save the value in order to be able to reuse it
-- after the back end has been run.
end record;
package Address_Clause_Checks is new Table.Table (
Table_Component_Type => Address_Clause_Check_Record,
Table_Index_Type => Int,
Table_Low_Bound => 1,
Table_Initial => 20,
Table_Increment => 200,
Table_Name => "Address_Clause_Checks");
function Alignment_Checks_Suppressed
(ACCR : Address_Clause_Check_Record) return Boolean;
-- Return whether the alignment check generated for the address clause
-- is suppressed.
---------------------------------
-- Alignment_Checks_Suppressed --
---------------------------------
function Alignment_Checks_Suppressed
(ACCR : Address_Clause_Check_Record) return Boolean
is
begin
if Checks_May_Be_Suppressed (ACCR.X) then
return Is_Check_Suppressed (ACCR.X, Alignment_Check);
else
return ACCR.Alignment_Checks_Suppressed;
end if;
end Alignment_Checks_Suppressed;
-----------------------------------------
-- Adjust_Record_For_Reverse_Bit_Order --
-----------------------------------------
procedure Adjust_Record_For_Reverse_Bit_Order (R : Entity_Id) is
Max_Machine_Scalar_Size : constant Uint :=
UI_From_Int (System_Max_Integer_Size);
-- We use this as the maximum machine scalar size
SSU : constant Uint := UI_From_Int (System_Storage_Unit);
CC : Node_Id;
Comp : Node_Id;
Num_CC : Natural;
begin
-- The processing done here used to depend on the Ada version, but the
-- behavior has been changed by AI95-0133. However this AI is a Binding
-- Interpretation, so we now implement it even in Ada 95 mode. But the
-- original behavior from unamended Ada 95 is available for the sake of
-- compatibility under the debugging switch -gnatd.p in Ada 95 mode.
if Ada_Version < Ada_2005 and then Debug_Flag_Dot_P then
Adjust_Record_For_Reverse_Bit_Order_Ada_95 (R);
return;
end if;
-- For Ada 2005, we do machine scalar processing, as fully described In
-- AI-133. This involves gathering all components which start at the
-- same byte offset and processing them together. Same approach is still
-- valid in later versions including Ada 2012.
-- Note that component clauses found on record types may be inherited,
-- in which case the layout of the component with such a clause still
-- has to be done at this point. Therefore, the processing done here
-- must exclusively rely on the Component_Clause of the component.
-- This first loop through components does two things. First it deals
-- with the case of components with component clauses whose length is
-- greater than the maximum machine scalar size (either accepting them
-- or rejecting as needed). Second, it counts the number of components
-- with component clauses whose length does not exceed this maximum for
-- later processing.
Num_CC := 0;
Comp := First_Component_Or_Discriminant (R);
while Present (Comp) loop
CC := Component_Clause (Comp);
if Present (CC) then
declare
Fbit : constant Uint := Static_Integer (First_Bit (CC));
Lbit : constant Uint := Static_Integer (Last_Bit (CC));
begin
-- Case of component with last bit >= max machine scalar
if Lbit >= Max_Machine_Scalar_Size then
-- This is allowed only if first bit is zero, and last bit
-- + 1 is a multiple of storage unit size.
if Fbit = 0 and then (Lbit + 1) mod SSU = 0 then
-- This is the case to give a warning if enabled
if Warn_On_Reverse_Bit_Order then
Error_Msg_N
("info: multi-byte field specified with "
& "non-standard Bit_Order?.v?", CC);
if Bytes_Big_Endian then
Error_Msg_N
("\bytes are not reversed "
& "(component is big-endian)?.v?", CC);
else
Error_Msg_N
("\bytes are not reversed "
& "(component is little-endian)?.v?", CC);
end if;
end if;
-- Give error message for RM 13.5.1(10) violation
else
Error_Msg_FE
("machine scalar rules not followed for&",
First_Bit (CC), Comp);
Error_Msg_Uint_1 := Lbit + 1;
Error_Msg_Uint_2 := Max_Machine_Scalar_Size;
Error_Msg_F
("\last bit + 1 (^) exceeds maximum machine scalar "
& "size (^)", First_Bit (CC));
if (Lbit + 1) mod SSU /= 0 then
Error_Msg_Uint_1 := SSU;
Error_Msg_F
("\and is not a multiple of Storage_Unit (^) "
& "(RM 13.5.1(10))", First_Bit (CC));
else
Error_Msg_Uint_1 := Fbit;
Error_Msg_F
("\and first bit (^) is non-zero "
& "(RM 13.4.1(10))", First_Bit (CC));
end if;
end if;
-- OK case of machine scalar related component clause. For now,
-- just count them.
else
Num_CC := Num_CC + 1;
end if;
end;
end if;
Next_Component_Or_Discriminant (Comp);
end loop;
-- We need to sort the component clauses on the basis of the Position
-- values in the clause, so we can group clauses with the same Position
-- together to determine the relevant machine scalar size.
Sort_CC : declare
Comps : array (0 .. Num_CC) of Entity_Id;
-- Array to collect component and discriminant entities. The data
-- starts at index 1, the 0'th entry is for the sort routine.
function CP_Lt (Op1, Op2 : Natural) return Boolean;
-- Compare routine for Sort
procedure CP_Move (From : Natural; To : Natural);
-- Move routine for Sort
package Sorting is new GNAT.Heap_Sort_G (CP_Move, CP_Lt);
MaxL : Uint;
-- Maximum last bit value of any component in this set
MSS : Uint;
-- Corresponding machine scalar size
Start : Natural;
Stop : Natural;
-- Start and stop positions in the component list of the set of
-- components with the same starting position (that constitute
-- components in a single machine scalar).
-----------
-- CP_Lt --
-----------
function CP_Lt (Op1, Op2 : Natural) return Boolean is
begin
return
Position (Component_Clause (Comps (Op1))) <
Position (Component_Clause (Comps (Op2)));
end CP_Lt;
-------------
-- CP_Move --
-------------
procedure CP_Move (From : Natural; To : Natural) is
begin
Comps (To) := Comps (From);
end CP_Move;
-- Start of processing for Sort_CC
begin
-- Collect the machine scalar relevant component clauses
Num_CC := 0;
Comp := First_Component_Or_Discriminant (R);
while Present (Comp) loop
declare
CC : constant Node_Id := Component_Clause (Comp);
begin
-- Collect only component clauses whose last bit is less than
-- machine scalar size. Any component clause whose last bit
-- exceeds this value does not take part in machine scalar
-- layout considerations. The test for Error_Posted makes sure
-- we exclude component clauses for which we already posted an
-- error.
if Present (CC)
and then not Error_Posted (Last_Bit (CC))
and then Static_Integer (Last_Bit (CC)) <
Max_Machine_Scalar_Size
then
Num_CC := Num_CC + 1;
Comps (Num_CC) := Comp;
end if;
end;
Next_Component_Or_Discriminant (Comp);
end loop;
-- Sort by ascending position number
Sorting.Sort (Num_CC);
-- We now have all the components whose size does not exceed the max
-- machine scalar value, sorted by starting position. In this loop we
-- gather groups of clauses starting at the same position, to process
-- them in accordance with AI-133.
Stop := 0;
while Stop < Num_CC loop
Start := Stop + 1;
Stop := Start;
MaxL :=
Static_Integer
(Last_Bit (Component_Clause (Comps (Start))));
while Stop < Num_CC loop
if Static_Integer
(Position (Component_Clause (Comps (Stop + 1)))) =
Static_Integer
(Position (Component_Clause (Comps (Stop))))
then
Stop := Stop + 1;
MaxL :=
UI_Max
(MaxL,
Static_Integer
(Last_Bit
(Component_Clause (Comps (Stop)))));
else
exit;
end if;
end loop;
-- Now we have a group of component clauses from Start to Stop
-- whose positions are identical, and MaxL is the maximum last
-- bit value of any of these components.
-- We need to determine the corresponding machine scalar size.
-- This loop assumes that machine scalar sizes are even, and that
-- each possible machine scalar has twice as many bits as the next
-- smaller one.
MSS := Max_Machine_Scalar_Size;
while MSS mod 2 = 0
and then (MSS / 2) >= SSU
and then (MSS / 2) > MaxL
loop
MSS := MSS / 2;
end loop;
-- Here is where we fix up the Component_Bit_Offset value to
-- account for the reverse bit order. Some examples of what needs
-- to be done for the case of a machine scalar size of 8 are:
-- First_Bit .. Last_Bit Component_Bit_Offset
-- old new old new
-- 0 .. 0 7 .. 7 0 7
-- 0 .. 1 6 .. 7 0 6
-- 0 .. 2 5 .. 7 0 5
-- 0 .. 7 0 .. 7 0 4
-- 1 .. 1 6 .. 6 1 6
-- 1 .. 4 3 .. 6 1 3
-- 4 .. 7 0 .. 3 4 0
-- The rule is that the first bit is obtained by subtracting the
-- old ending bit from machine scalar size - 1.
for C in Start .. Stop loop
declare
Comp : constant Entity_Id := Comps (C);
CC : constant Node_Id := Component_Clause (Comp);
FB : constant Uint := Static_Integer (First_Bit (CC));
LB : constant Uint := Static_Integer (Last_Bit (CC));
NFB : constant Uint := MSS - 1 - LB;
NLB : constant Uint := NFB + LB - FB;
Pos : constant Uint := Static_Integer (Position (CC));
begin
-- Do not warn for the artificial clause built for the tag
-- in Check_Record_Representation_Clause if it is inherited.
if Warn_On_Reverse_Bit_Order
and then Chars (Comp) /= Name_uTag
then
Error_Msg_Uint_1 := MSS;
Error_Msg_N
("info: reverse bit order in machine scalar of "
& "length^?.v?", First_Bit (CC));
Error_Msg_Uint_1 := NFB;
Error_Msg_Uint_2 := NLB;
if Bytes_Big_Endian then
Error_Msg_NE
("\big-endian range for component & is ^ .. ^?.v?",
First_Bit (CC), Comp);
else
Error_Msg_NE
("\little-endian range for component " &
"& is ^ .. ^?.v?",
First_Bit (CC), Comp);
end if;
end if;
Set_Component_Bit_Offset (Comp, Pos * SSU + NFB);
Set_Esize (Comp, 1 + (NLB - NFB));
Set_Normalized_First_Bit (Comp, NFB mod SSU);
Set_Normalized_Position (Comp, Pos + NFB / SSU);
end;
end loop;
end loop;
end Sort_CC;
end Adjust_Record_For_Reverse_Bit_Order;
------------------------------------------------
-- Adjust_Record_For_Reverse_Bit_Order_Ada_95 --
------------------------------------------------
procedure Adjust_Record_For_Reverse_Bit_Order_Ada_95 (R : Entity_Id) is
CC : Node_Id;
Comp : Node_Id;
begin
-- For Ada 95, we just renumber bits within a storage unit. We do the
-- same for Ada 83 mode, since we recognize the Bit_Order attribute in
-- Ada 83, and are free to add this extension.
Comp := First_Component_Or_Discriminant (R);
while Present (Comp) loop
CC := Component_Clause (Comp);
-- If component clause is present, then deal with the non-default
-- bit order case for Ada 95 mode.
-- We only do this processing for the base type, and in fact that
-- is important, since otherwise if there are record subtypes, we
-- could reverse the bits once for each subtype, which is wrong.
if Present (CC) and then Ekind (R) = E_Record_Type then
declare
CFB : constant Uint := Component_Bit_Offset (Comp);
CSZ : constant Uint := Esize (Comp);
CLC : constant Node_Id := Component_Clause (Comp);
Pos : constant Node_Id := Position (CLC);
FB : constant Node_Id := First_Bit (CLC);
Storage_Unit_Offset : constant Uint :=
CFB / System_Storage_Unit;
Start_Bit : constant Uint :=
CFB mod System_Storage_Unit;
begin
-- Cases where field goes over storage unit boundary
if Start_Bit + CSZ > System_Storage_Unit then
-- Allow multi-byte field but generate warning
if Start_Bit mod System_Storage_Unit = 0
and then CSZ mod System_Storage_Unit = 0
then
Error_Msg_N
("info: multi-byte field specified with non-standard "
& "Bit_Order?.v?", CLC);
if Bytes_Big_Endian then
Error_Msg_N
("\bytes are not reversed "
& "(component is big-endian)?.v?", CLC);
else
Error_Msg_N
("\bytes are not reversed "
& "(component is little-endian)?.v?", CLC);
end if;
-- Do not allow non-contiguous field
else
Error_Msg_N
("attempt to specify non-contiguous field not "
& "permitted", CLC);
Error_Msg_N
("\caused by non-standard Bit_Order specified in "
& "legacy Ada 95 mode", CLC);
end if;
-- Case where field fits in one storage unit
else
-- Give warning if suspicious component clause
if Intval (FB) >= System_Storage_Unit
and then Warn_On_Reverse_Bit_Order
then
Error_Msg_N
("info: Bit_Order clause does not affect byte "
& "ordering?.v?", Pos);
Error_Msg_Uint_1 :=
Intval (Pos) + Intval (FB) /
System_Storage_Unit;
Error_Msg_N
("info: position normalized to ^ before bit order "
& "interpreted?.v?", Pos);
end if;
-- Here is where we fix up the Component_Bit_Offset value
-- to account for the reverse bit order. Some examples of
-- what needs to be done are:
-- First_Bit .. Last_Bit Component_Bit_Offset
-- old new old new
-- 0 .. 0 7 .. 7 0 7
-- 0 .. 1 6 .. 7 0 6
-- 0 .. 2 5 .. 7 0 5
-- 0 .. 7 0 .. 7 0 4
-- 1 .. 1 6 .. 6 1 6
-- 1 .. 4 3 .. 6 1 3
-- 4 .. 7 0 .. 3 4 0
-- The rule is that the first bit is obtained by subtracting
-- the old ending bit from storage_unit - 1.
Set_Component_Bit_Offset (Comp,
(Storage_Unit_Offset * System_Storage_Unit) +
(System_Storage_Unit - 1) -
(Start_Bit + CSZ - 1));
Set_Normalized_Position (Comp,
Component_Bit_Offset (Comp) / System_Storage_Unit);
Set_Normalized_First_Bit (Comp,
Component_Bit_Offset (Comp) mod System_Storage_Unit);
end if;
end;
end if;
Next_Component_Or_Discriminant (Comp);
end loop;
end Adjust_Record_For_Reverse_Bit_Order_Ada_95;
-------------------------------------
-- Alignment_Check_For_Size_Change --
-------------------------------------
procedure Alignment_Check_For_Size_Change (Typ : Entity_Id; Size : Uint) is
begin
-- If the alignment is known, and not set by a rep clause, and is
-- inconsistent with the size being set, then reset it to unknown,
-- we assume in this case that the size overrides the inherited
-- alignment, and that the alignment must be recomputed.
if Known_Alignment (Typ)
and then not Has_Alignment_Clause (Typ)
and then Present (Size)
and then Size mod (Alignment (Typ) * SSU) /= 0
then
Reinit_Alignment (Typ);
end if;
end Alignment_Check_For_Size_Change;
-----------------------------------
-- All_Membership_Choices_Static --
-----------------------------------
function All_Membership_Choices_Static (Expr : Node_Id) return Boolean is
pragma Assert (Nkind (Expr) in N_Membership_Test);
begin
pragma Assert
(Present (Right_Opnd (Expr))
xor
Present (Alternatives (Expr)));
if Present (Right_Opnd (Expr)) then
return Is_Static_Choice (Right_Opnd (Expr));
else
return All_Static_Choices (Alternatives (Expr));
end if;
end All_Membership_Choices_Static;
------------------------
-- All_Static_Choices --
------------------------
function All_Static_Choices (L : List_Id) return Boolean is
N : Node_Id;
begin
N := First (L);
while Present (N) loop
if not Is_Static_Choice (N) then
return False;
end if;
Next (N);
end loop;
return True;
end All_Static_Choices;
-------------------------------------
-- Analyze_Aspects_At_Freeze_Point --
-------------------------------------
procedure Analyze_Aspects_At_Freeze_Point (E : Entity_Id) is
procedure Analyze_Aspect_Default_Value (ASN : Node_Id);
-- This routine analyzes an Aspect_Default_[Component_]Value denoted by
-- the aspect specification node ASN.
procedure Check_Aspect_Too_Late (N : Node_Id);
-- This procedure is similar to Rep_Item_Too_Late for representation
-- aspects that apply to type and that do not have a corresponding
-- pragma.
-- Used to check in particular that the expression associated with
-- aspect node N for the given type (entity) of the aspect does not
-- appear too late according to the rules in RM 13.1(9) and 13.1(10).
procedure Inherit_Delayed_Rep_Aspects (ASN : Node_Id);
-- As discussed in the spec of Aspects (see Aspect_Delay declaration),
-- a derived type can inherit aspects from its parent which have been
-- specified at the time of the derivation using an aspect, as in:
--
-- type A is range 1 .. 10
-- with Size => Not_Defined_Yet;
-- ..
-- type B is new A;
-- ..
-- Not_Defined_Yet : constant := 64;
--
-- In this example, the Size of A is considered to be specified prior
-- to the derivation, and thus inherited, even though the value is not
-- known at the time of derivation. To deal with this, we use two entity
-- flags. The flag Has_Derived_Rep_Aspects is set in the parent type (A
-- here), and then the flag May_Inherit_Delayed_Rep_Aspects is set in
-- the derived type (B here). If this flag is set when the derived type
-- is frozen, then this procedure is called to ensure proper inheritance
-- of all delayed aspects from the parent type. The derived type is E,
-- the argument to Analyze_Aspects_At_Freeze_Point. ASN is the first
-- aspect specification node in the Rep_Item chain for the parent type.
procedure Make_Pragma_From_Boolean_Aspect (ASN : Node_Id);
-- Given an aspect specification node ASN whose expression is an
-- optional Boolean, this routines creates the corresponding pragma
-- at the freezing point.
----------------------------------
-- Analyze_Aspect_Default_Value --
----------------------------------
procedure Analyze_Aspect_Default_Value (ASN : Node_Id) is
Ent : constant Entity_Id := Entity (ASN);
Expr : constant Node_Id := Expression (ASN);
begin
Set_Has_Default_Aspect (Base_Type (Ent));
if Is_Scalar_Type (Ent) then
Set_Default_Aspect_Value (Base_Type (Ent), Expr);
else
Set_Default_Aspect_Component_Value (Base_Type (Ent), Expr);
end if;
Check_Aspect_Too_Late (ASN);
end Analyze_Aspect_Default_Value;
---------------------------
-- Check_Aspect_Too_Late --
---------------------------
procedure Check_Aspect_Too_Late (N : Node_Id) is
Typ : constant Entity_Id := Entity (N);
Expr : constant Node_Id := Expression (N);
function Find_Type_Reference
(Typ : Entity_Id; Expr : Node_Id) return Boolean;
-- Return True if a reference to type Typ is found in the expression
-- Expr.
-------------------------
-- Find_Type_Reference --
-------------------------
function Find_Type_Reference
(Typ : Entity_Id; Expr : Node_Id) return Boolean
is
function Find_Type (N : Node_Id) return Traverse_Result;
-- Set Found to True if N refers to Typ
---------------
-- Find_Type --
---------------
function Find_Type (N : Node_Id) return Traverse_Result is
begin
if N = Typ
or else (Nkind (N) in N_Identifier | N_Expanded_Name
and then Present (Entity (N))
and then Entity (N) = Typ)
then
return Abandon;
else
return OK;
end if;
end Find_Type;
function Search_Type_Reference is new Traverse_Func (Find_Type);
begin
return Search_Type_Reference (Expr) = Abandon;
end Find_Type_Reference;
Parent_Type : Entity_Id;
begin
-- Ensure Expr is analyzed so that e.g. all types are properly
-- resolved for Find_Type_Reference.
Analyze (Expr);
-- A self-referential aspect is illegal if it forces freezing the
-- entity before the corresponding aspect has been analyzed.
if Find_Type_Reference (Typ, Expr) then
Error_Msg_NE
("aspect specification causes premature freezing of&", N, Typ);
end if;
-- For representation aspects, check for case of untagged derived
-- type whose parent either has primitive operations (pre Ada 2022),
-- or is a by-reference type (RM 13.1(10)).
-- Strictly speaking the check also applies to Ada 2012 but it is
-- really too constraining for existing code already, so relax it.
-- ??? Confirming aspects should be allowed here.
if Is_Representation_Aspect (Get_Aspect_Id (N))
and then Is_Derived_Type (Typ)
and then not Is_Tagged_Type (Typ)
then
Parent_Type := Etype (Base_Type (Typ));
if Ada_Version <= Ada_2012
and then Has_Primitive_Operations (Parent_Type)
then
Error_Msg_N
("|representation aspect not permitted before Ada 2022: " &
"use -gnat2022!", N);
Error_Msg_NE
("\parent type & has primitive operations!", N, Parent_Type);
elsif Is_By_Reference_Type (Parent_Type) then
No_Type_Rep_Item (N);
Error_Msg_NE
("\parent type & is a by-reference type!", N, Parent_Type);
end if;
end if;
end Check_Aspect_Too_Late;
---------------------------------
-- Inherit_Delayed_Rep_Aspects --
---------------------------------
procedure Inherit_Delayed_Rep_Aspects (ASN : Node_Id) is
A_Id : constant Aspect_Id := Get_Aspect_Id (ASN);
P : constant Entity_Id := Entity (ASN);
-- Entity for parent type
N : Node_Id;
-- Item from Rep_Item chain
A : Aspect_Id;
begin
-- Loop through delayed aspects for the parent type
N := ASN;
while Present (N) loop
if Nkind (N) = N_Aspect_Specification then
exit when Entity (N) /= P;
if Is_Delayed_Aspect (N) then
A := Get_Aspect_Id (Chars (Identifier (N)));
-- Process delayed rep aspect. For Boolean attributes it is
-- not possible to cancel an attribute once set (the attempt
-- to use an aspect with xxx => False is an error) for a
-- derived type. So for those cases, we do not have to check
-- if a clause has been given for the derived type, since it
-- is harmless to set it again if it is already set.
case A is
-- Alignment
when Aspect_Alignment =>
if not Has_Alignment_Clause (E) then
Set_Alignment (E, Alignment (P));
end if;
-- Atomic
when Aspect_Atomic =>
if Is_Atomic (P) then
Set_Is_Atomic (E);
end if;
-- Atomic_Components
when Aspect_Atomic_Components =>
if Has_Atomic_Components (P) then
Set_Has_Atomic_Components (Base_Type (E));
end if;
-- Bit_Order
when Aspect_Bit_Order =>
if Is_Record_Type (E)
and then No (Get_Attribute_Definition_Clause
(E, Attribute_Bit_Order))
and then Reverse_Bit_Order (P)
then
Set_Reverse_Bit_Order (Base_Type (E));
end if;
-- Component_Size
when Aspect_Component_Size =>
if Is_Array_Type (E)
and then not Has_Component_Size_Clause (E)
then
Set_Component_Size
(Base_Type (E), Component_Size (P));
end if;
-- Machine_Radix
when Aspect_Machine_Radix =>
if Is_Decimal_Fixed_Point_Type (E)
and then not Has_Machine_Radix_Clause (E)
then
Set_Machine_Radix_10 (E, Machine_Radix_10 (P));
end if;
-- Object_Size (also Size which also sets Object_Size)
when Aspect_Object_Size
| Aspect_Size
=>
if not Has_Size_Clause (E)
and then
No (Get_Attribute_Definition_Clause
(E, Attribute_Object_Size))
then
Set_Esize (E, Esize (P));
end if;
-- Pack
when Aspect_Pack =>
if not Is_Packed (E) then
Set_Is_Packed (Base_Type (E));
if Is_Bit_Packed_Array (P) then
Set_Is_Bit_Packed_Array (Base_Type (E));
Set_Packed_Array_Impl_Type
(E, Packed_Array_Impl_Type (P));
end if;
end if;
-- Scalar_Storage_Order
when Aspect_Scalar_Storage_Order =>
if (Is_Record_Type (E) or else Is_Array_Type (E))
and then No (Get_Attribute_Definition_Clause
(E, Attribute_Scalar_Storage_Order))
and then Reverse_Storage_Order (P)
then
Set_Reverse_Storage_Order (Base_Type (E));
-- Clear default SSO indications, since the aspect
-- overrides the default.
Set_SSO_Set_Low_By_Default (Base_Type (E), False);
Set_SSO_Set_High_By_Default (Base_Type (E), False);
end if;
-- Small
when Aspect_Small =>
if Is_Fixed_Point_Type (E)
and then not Has_Small_Clause (E)
then
Set_Small_Value (E, Small_Value (P));
end if;
-- Storage_Size
when Aspect_Storage_Size =>
if (Is_Access_Type (E) or else Is_Task_Type (E))
and then not Has_Storage_Size_Clause (E)
then
Set_Storage_Size_Variable
(Base_Type (E), Storage_Size_Variable (P));
end if;
-- Value_Size
when Aspect_Value_Size =>
-- Value_Size is never inherited, it is either set by
-- default, or it is explicitly set for the derived
-- type. So nothing to do here.
null;
-- Volatile
when Aspect_Volatile =>
if Is_Volatile (P) then
Set_Is_Volatile (E);
end if;
-- Volatile_Full_Access (also Full_Access_Only)
when Aspect_Volatile_Full_Access
| Aspect_Full_Access_Only
=>
if Is_Volatile_Full_Access (P) then
Set_Is_Volatile_Full_Access (E);
end if;
-- Volatile_Components
when Aspect_Volatile_Components =>
if Has_Volatile_Components (P) then
Set_Has_Volatile_Components (Base_Type (E));
end if;
-- That should be all the Rep Aspects
when others =>
pragma Assert (Aspect_Delay (A_Id) /= Rep_Aspect);
null;
end case;
end if;
end if;
Next_Rep_Item (N);
end loop;
end Inherit_Delayed_Rep_Aspects;
-------------------------------------
-- Make_Pragma_From_Boolean_Aspect --
-------------------------------------
procedure Make_Pragma_From_Boolean_Aspect (ASN : Node_Id) is
Ident : constant Node_Id := Identifier (ASN);
A_Name : constant Name_Id := Chars (Ident);
A_Id : constant Aspect_Id := Get_Aspect_Id (A_Name);
Ent : constant Entity_Id := Entity (ASN);
Expr : constant Node_Id := Expression (ASN);
Loc : constant Source_Ptr := Sloc (ASN);
procedure Check_False_Aspect_For_Derived_Type;
-- This procedure checks for the case of a false aspect for a derived
-- type, which improperly tries to cancel an aspect inherited from
-- the parent.
-----------------------------------------
-- Check_False_Aspect_For_Derived_Type --
-----------------------------------------
procedure Check_False_Aspect_For_Derived_Type is
Par : Node_Id;
begin
-- We are only checking derived types
if not Is_Derived_Type (E) then
return;
end if;
Par := Nearest_Ancestor (E);
case A_Id is
when Aspect_Atomic
| Aspect_Shared
=>
if not Is_Atomic (Par) then
return;
end if;
when Aspect_Atomic_Components =>
if not Has_Atomic_Components (Par) then
return;
end if;
when Aspect_Discard_Names =>
if not Discard_Names (Par) then
return;
end if;
when Aspect_Pack =>
if not Is_Packed (Par) then
return;
end if;
when Aspect_Unchecked_Union =>
if not Is_Unchecked_Union (Par) then
return;
end if;
when Aspect_Volatile =>
if not Is_Volatile (Par) then
return;
end if;
when Aspect_Volatile_Components =>
if not Has_Volatile_Components (Par) then
return;
end if;
when Aspect_Volatile_Full_Access
| Aspect_Full_Access_Only
=>
if not Is_Volatile_Full_Access (Par) then
return;
end if;
when others =>
return;
end case;
-- Fall through means we are canceling an inherited aspect
Error_Msg_Name_1 := A_Name;
Error_Msg_NE
("derived type& inherits aspect%, cannot cancel", Expr, E);
end Check_False_Aspect_For_Derived_Type;
-- Local variables
Prag : Node_Id;
P_Name : Name_Id;
-- Start of processing for Make_Pragma_From_Boolean_Aspect
begin
if Present (Expr) and then Is_False (Static_Boolean (Expr)) then
Check_False_Aspect_For_Derived_Type;
else
-- There is no Full_Access_Only pragma so use VFA instead
if A_Name = Name_Full_Access_Only then
P_Name := Name_Volatile_Full_Access;
else
P_Name := A_Name;
end if;
Prag :=
Make_Pragma (Loc,
Pragma_Identifier =>
Make_Identifier (Sloc (Ident), P_Name),
Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Sloc (Ident),
Expression => New_Occurrence_Of (Ent, Sloc (Ident)))));
Set_From_Aspect_Specification (Prag, True);
Set_Corresponding_Aspect (Prag, ASN);
Set_Aspect_Rep_Item (ASN, Prag);
Set_Is_Delayed_Aspect (Prag);
Set_Parent (Prag, ASN);
end if;
end Make_Pragma_From_Boolean_Aspect;
-- Local variables
A_Id : Aspect_Id;
ASN : Node_Id;
Ritem : Node_Id;
-- Start of processing for Analyze_Aspects_At_Freeze_Point
begin
-- Must be visible in current scope, but if this is a type from a nested
-- package it may be frozen from an object declaration in the enclosing
-- scope, so install the package declarations to complete the analysis
-- of the aspects, if any. If the package itself is frozen the type will
-- have been frozen as well.
if not Scope_Within_Or_Same (Current_Scope, Scope (E)) then
if Is_Type (E) and then From_Nested_Package (E) then
declare
Pack : constant Entity_Id := Scope (E);
begin
Push_Scope (Pack);
Install_Visible_Declarations (Pack);
Install_Private_Declarations (Pack);
Analyze_Aspects_At_Freeze_Point (E);
if Is_Private_Type (E)
and then Present (Full_View (E))
then
Analyze_Aspects_At_Freeze_Point (Full_View (E));
end if;
End_Package_Scope (Pack);
return;
end;
-- Aspects from other entities in different contexts are analyzed
-- elsewhere.
else
return;
end if;
end if;
-- Look for aspect specification entries for this entity
ASN := First_Rep_Item (E);
while Present (ASN) loop
if Nkind (ASN) = N_Aspect_Specification then
exit when Entity (ASN) /= E;
if Is_Delayed_Aspect (ASN) then
A_Id := Get_Aspect_Id (ASN);
case A_Id is
-- For aspects whose expression is an optional Boolean, make
-- the corresponding pragma at the freeze point.
when Boolean_Aspects
| Library_Unit_Aspects
=>
-- Aspects Export and Import require special handling.
-- Both are by definition Boolean and may benefit from
-- forward references, however their expressions are
-- treated as static. In addition, the syntax of their
-- corresponding pragmas requires extra "pieces" which
-- may also contain forward references. To account for
-- all of this, the corresponding pragma is created by
-- Analyze_Aspect_Export_Import, but is not analyzed as
-- the complete analysis must happen now.
-- Aspect Full_Access_Only must be analyzed last so that
-- aspects Volatile and Atomic, if any, are analyzed.
-- Skip creation of pragma Preelaborable_Initialization
-- in the case where the aspect has an expression,
-- because the pragma is only needed for setting flag
-- Known_To_Have_Preelab_Init, which is set by other
-- means following resolution of the aspect expression.
if A_Id not in Aspect_Export
| Aspect_Full_Access_Only
| Aspect_Import
and then (A_Id /= Aspect_Preelaborable_Initialization
or else not Present (Expression (ASN)))
then
Make_Pragma_From_Boolean_Aspect (ASN);
end if;
-- Special handling for aspects that don't correspond to
-- pragmas/attributes.
when Aspect_Default_Value
| Aspect_Default_Component_Value
=>
-- Do not inherit aspect for anonymous base type of a
-- scalar or array type, because they apply to the first
-- subtype of the type, and will be processed when that
-- first subtype is frozen.
if Is_Derived_Type (E)
and then not Comes_From_Source (E)
and then E /= First_Subtype (E)
then
null;
else
Analyze_Aspect_Default_Value (ASN);
end if;
-- Ditto for iterator aspects, because the corresponding
-- attributes may not have been analyzed yet.
when Aspect_Constant_Indexing
| Aspect_Default_Iterator
| Aspect_Iterator_Element
| Aspect_Variable_Indexing
=>
Analyze (Expression (ASN));
if Etype (Expression (ASN)) = Any_Type then
Error_Msg_NE
("\aspect must be fully defined before & is frozen",
ASN, E);
end if;
when Aspect_Integer_Literal
| Aspect_Real_Literal
| Aspect_String_Literal
=>
Validate_Literal_Aspect (E, ASN);
when Aspect_Iterable =>
Validate_Iterable_Aspect (E, ASN);
when Aspect_Designated_Storage_Model =>
Analyze_And_Resolve (Expression (ASN));
if not Is_Entity_Name (Expression (ASN))
or else not Is_Object (Entity (Expression (ASN)))
or else
not Present (Find_Aspect (Etype (Expression (ASN)),
Aspect_Storage_Model_Type))
then
Error_Msg_N
("must specify name of stand-alone object of type "
& "with aspect Storage_Model_Type",
Expression (ASN));
-- Set access type's Associated_Storage_Pool to denote
-- the Storage_Model_Type object given for the aspect
-- (even though that isn't actually an Ada storage pool).
else
Set_Associated_Storage_Pool
(E, Entity (Expression (ASN)));
end if;
when Aspect_Storage_Model_Type =>
Validate_Storage_Model_Type_Aspect (E, ASN);
when Aspect_Aggregate =>
null;
when others =>
null;
end case;
Ritem := Aspect_Rep_Item (ASN);
if Present (Ritem) then
Analyze (Ritem);
end if;
end if;
end if;
Next_Rep_Item (ASN);
end loop;
-- Make a second pass for a Full_Access_Only entry
ASN := First_Rep_Item (E);
while Present (ASN) loop
if Nkind (ASN) = N_Aspect_Specification then
exit when Entity (ASN) /= E;
if Get_Aspect_Id (ASN) = Aspect_Full_Access_Only then
Make_Pragma_From_Boolean_Aspect (ASN);
Ritem := Aspect_Rep_Item (ASN);
if Present (Ritem) then
Analyze (Ritem);
end if;
end if;
end if;
Next_Rep_Item (ASN);
end loop;
-- This is where we inherit delayed rep aspects from our parent. Note
-- that if we fell out of the above loop with ASN non-empty, it means
-- we hit an aspect for an entity other than E, and it must be the
-- type from which we were derived.
if May_Inherit_Delayed_Rep_Aspects (E) then
Inherit_Delayed_Rep_Aspects (ASN);
end if;
if In_Instance
and then E /= Base_Type (E)
and then Is_First_Subtype (E)
then
Inherit_Rep_Item_Chain (Base_Type (E), E);
end if;
end Analyze_Aspects_At_Freeze_Point;
-----------------------------------
-- Analyze_Aspect_Specifications --
-----------------------------------
procedure Analyze_Aspect_Specifications (N : Node_Id; E : Entity_Id) is
pragma Assert (Present (E));
procedure Decorate (Asp : Node_Id; Prag : Node_Id);
-- Establish linkages between an aspect and its corresponding pragma
procedure Insert_Pragma
(Prag : Node_Id;
Is_Instance : Boolean := False);
-- Subsidiary to the analysis of aspects
-- Abstract_State
-- Attach_Handler
-- Contract_Cases
-- Depends
-- Ghost
-- Global
-- Initial_Condition
-- Initializes
-- Post
-- Pre
-- Refined_Depends
-- Refined_Global
-- Refined_State
-- SPARK_Mode
-- Subprogram_Variant
-- Warnings
-- Insert pragma Prag such that it mimics the placement of a source
-- pragma of the same kind. Flag Is_Generic should be set when the
-- context denotes a generic instance.
--------------
-- Decorate --
--------------
procedure Decorate (Asp : Node_Id; Prag : Node_Id) is
begin
Set_Aspect_Rep_Item (Asp, Prag);
Set_Corresponding_Aspect (Prag, Asp);
Set_From_Aspect_Specification (Prag);
Set_Parent (Prag, Asp);
end Decorate;
-------------------
-- Insert_Pragma --
-------------------
procedure Insert_Pragma
(Prag : Node_Id;
Is_Instance : Boolean := False)
is
Aux : Node_Id;
Decl : Node_Id;
Decls : List_Id;
Def : Node_Id;
Inserted : Boolean := False;
begin
-- When the aspect appears on an entry, package, protected unit,
-- subprogram, or task unit body, insert the generated pragma at the
-- top of the body declarations to emulate the behavior of a source
-- pragma.
-- package body Pack with Aspect is
-- package body Pack is
-- pragma Prag;
if Nkind (N) in N_Entry_Body
| N_Package_Body
| N_Protected_Body
| N_Subprogram_Body
| N_Task_Body
then
Decls := Declarations (N);
if No (Decls) then
Decls := New_List;
Set_Declarations (N, Decls);
end if;
Prepend_To (Decls, Prag);
-- When the aspect is associated with a [generic] package declaration
-- insert the generated pragma at the top of the visible declarations
-- to emulate the behavior of a source pragma.
-- package Pack with Aspect is
-- package Pack is
-- pragma Prag;
elsif Nkind (N) in N_Generic_Package_Declaration
| N_Package_Declaration
then
Decls := Visible_Declarations (Specification (N));
if No (Decls) then
Decls := New_List;
Set_Visible_Declarations (Specification (N), Decls);
end if;
-- The visible declarations of a generic instance have the
-- following structure:
-- <renamings of generic formals>
-- <renamings of internally-generated spec and body>
-- <first source declaration>
-- Insert the pragma before the first source declaration by
-- skipping the instance "header" to ensure proper visibility of
-- all formals.
if Is_Instance then
Decl := First (Decls);
while Present (Decl) loop
if Comes_From_Source (Decl) then
Insert_Before (Decl, Prag);
Inserted := True;
exit;
else
Next (Decl);
end if;
end loop;
-- The pragma is placed after the instance "header"
if not Inserted then
Append_To (Decls, Prag);
end if;
-- Otherwise this is not a generic instance
else
Prepend_To (Decls, Prag);
end if;
-- When the aspect is associated with a protected unit declaration,
-- insert the generated pragma at the top of the visible declarations
-- the emulate the behavior of a source pragma.
-- protected [type] Prot with Aspect is
-- protected [type] Prot is
-- pragma Prag;
elsif Nkind (N) = N_Protected_Type_Declaration then
Def := Protected_Definition (N);
if No (Def) then
Def :=
Make_Protected_Definition (Sloc (N),
Visible_Declarations => New_List,
End_Label => Empty);
Set_Protected_Definition (N, Def);
end if;
Decls := Visible_Declarations (Def);
if No (Decls) then
Decls := New_List;
Set_Visible_Declarations (Def, Decls);
end if;
Prepend_To (Decls, Prag);
-- When the aspect is associated with a task unit declaration, insert
-- insert the generated pragma at the top of the visible declarations
-- the emulate the behavior of a source pragma.
-- task [type] Prot with Aspect is
-- task [type] Prot is
-- pragma Prag;
elsif Nkind (N) = N_Task_Type_Declaration then
Def := Task_Definition (N);
if No (Def) then
Def :=
Make_Task_Definition (Sloc (N),
Visible_Declarations => New_List,
End_Label => Empty);
Set_Task_Definition (N, Def);
end if;
Decls := Visible_Declarations (Def);
if No (Decls) then
Decls := New_List;
Set_Visible_Declarations (Def, Decls);
end if;
Prepend_To (Decls, Prag);
-- When the context is a library unit, the pragma is added to the
-- Pragmas_After list.
elsif Nkind (Parent (N)) = N_Compilation_Unit then
Aux := Aux_Decls_Node (Parent (N));
if No (Pragmas_After (Aux)) then
Set_Pragmas_After (Aux, New_List);
end if;
Prepend (Prag, Pragmas_After (Aux));
-- Default, the pragma is inserted after the context
else
Insert_After (N, Prag);
end if;
end Insert_Pragma;
-- Local variables
Aspect : Node_Id;
Aitem : Node_Id := Empty;
Ent : Node_Id;
L : constant List_Id := Aspect_Specifications (N);
pragma Assert (Present (L));
Ins_Node : Node_Id := N;
-- Insert pragmas/attribute definition clause after this node when no
-- delayed analysis is required.
-- Start of processing for Analyze_Aspect_Specifications
begin
-- The general processing involves building an attribute definition
-- clause or a pragma node that corresponds to the aspect. Then in order
-- to delay the evaluation of this aspect to the 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. When the aspect
-- doesn't have a corresponding pragma/attribute definition clause, then
-- its analysis is simply delayed at the freeze point.
-- Some special cases don't require delay analysis, thus the aspect is
-- analyzed right now.
-- Note that there is a special handling for Pre, Post, Test_Case,
-- Contract_Cases and Subprogram_Variant aspects. In these cases, we do
-- not have to worry about delay issues, since the pragmas themselves
-- deal with delay of visibility for the expression analysis. Thus, we
-- just insert the pragma after the node N.
-- Loop through aspects
Aspect := First (L);
Aspect_Loop : while Present (Aspect) loop
Analyze_One_Aspect : declare
Aspect_Exit : exception;
-- This exception is used to exit aspect processing completely. It
-- is used when an error is detected, and no further processing is
-- required. It is also used if an earlier error has left the tree
-- in a state where the aspect should not be processed.
Expr : constant Node_Id := Expression (Aspect);
Id : constant Node_Id := Identifier (Aspect);
Loc : constant Source_Ptr := Sloc (Aspect);
Nam : constant Name_Id := Chars (Id);
A_Id : constant Aspect_Id := Get_Aspect_Id (Nam);
Anod : Node_Id;
Delay_Required : Boolean;
-- Set False if delay is not required
Eloc : Source_Ptr := No_Location;
-- Source location of expression, modified when we split PPC's. It
-- is set below when Expr is present.
procedure Analyze_Aspect_Convention;
-- Perform analysis of aspect Convention
procedure Analyze_Aspect_Disable_Controlled;
-- Perform analysis of aspect Disable_Controlled
procedure Analyze_Aspect_Export_Import;
-- Perform analysis of aspects Export or Import
procedure Analyze_Aspect_External_Link_Name;
-- Perform analysis of aspects External_Name or Link_Name
procedure Analyze_Aspect_Implicit_Dereference;
-- Perform analysis of the Implicit_Dereference aspects
procedure Analyze_Aspect_Relaxed_Initialization;
-- Perform analysis of aspect Relaxed_Initialization
procedure Analyze_Aspect_Yield;
-- Perform analysis of aspect Yield
procedure Analyze_Aspect_Static;
-- Ada 2022 (AI12-0075): Perform analysis of aspect Static
procedure Check_Expr_Is_OK_Static_Expression
(Expr : Node_Id;
Typ : Entity_Id := Empty);
-- Check the specified expression Expr to make sure that it is a
-- static expression of the given type (i.e. it will be analyzed
-- and resolved using this type, which can be any valid argument
-- to Resolve, e.g. Any_Integer is OK). If not, give an error
-- and raise Aspect_Exit. If Typ is left Empty, then any static
-- expression is allowed. Includes checking that the expression
-- does not raise Constraint_Error.
function Directly_Specified
(Id : Entity_Id; A : Aspect_Id) return Boolean;
-- Returns True if the given aspect is directly (as opposed to
-- via any form of inheritance) specified for the given entity.
function Make_Aitem_Pragma
(Pragma_Argument_Associations : List_Id;
Pragma_Name : Name_Id) return Node_Id;
-- This is a wrapper for Make_Pragma used for converting aspects
-- to pragmas. It takes care of Sloc (set from Loc) and building
-- the pragma identifier from the given name. In addition the
-- flags Class_Present and Split_PPC are set from the aspect
-- node, as well as Is_Ignored. This routine also sets the
-- From_Aspect_Specification in the resulting pragma node to
-- True, and sets Corresponding_Aspect to point to the aspect.
-- The resulting pragma is assigned to Aitem.
-------------------------------
-- Analyze_Aspect_Convention --
-------------------------------
procedure Analyze_Aspect_Convention is
Conv : Node_Id;
Dummy_1 : Node_Id;
Dummy_2 : Node_Id;
Dummy_3 : Node_Id;
Expo : Node_Id;
Imp : Node_Id;
begin
-- Obtain all interfacing aspects that apply to the related
-- entity.
Get_Interfacing_Aspects
(Iface_Asp => Aspect,
Conv_Asp => Dummy_1,
EN_Asp => Dummy_2,
Expo_Asp => Expo,
Imp_Asp => Imp,
LN_Asp => Dummy_3,
Do_Checks => True);
-- The related entity is subject to aspect Export or Import.
-- Do not process Convention now because it must be analysed
-- as part of Export or Import.
if Present (Expo) or else Present (Imp) then
return;
-- Otherwise Convention appears by itself
else
-- The aspect specifies a particular convention
if Present (Expr) then
Conv := New_Copy_Tree (Expr);
-- Otherwise assume convention Ada
else
Conv := Make_Identifier (Loc, Name_Ada);
end if;
-- Generate:
-- pragma Convention (<Conv>, <E>);
Aitem := Make_Aitem_Pragma
(Pragma_Name => Name_Convention,
Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Loc,
Expression => Conv),
Make_Pragma_Argument_Association (Loc,
Expression => New_Occurrence_Of (E, Loc))));
Decorate (Aspect, Aitem);
Insert_Pragma (Aitem);
end if;
end Analyze_Aspect_Convention;
---------------------------------------
-- Analyze_Aspect_Disable_Controlled --
---------------------------------------
procedure Analyze_Aspect_Disable_Controlled is
begin
-- The aspect applies only to controlled records
if not (Ekind (E) = E_Record_Type
and then Is_Controlled_Active (E))
then
Error_Msg_N
("aspect % requires controlled record type", Aspect);
return;
end if;
-- Preanalyze the expression (if any) when the aspect resides
-- in a generic unit.
if Inside_A_Generic then
if Present (Expr) then
Preanalyze_And_Resolve (Expr, Any_Boolean);
end if;
-- Otherwise the aspect resides in a nongeneric context
else
-- A controlled record type loses its controlled semantics
-- when the expression statically evaluates to True.
if Present (Expr) then
Analyze_And_Resolve (Expr, Any_Boolean);
if Is_OK_Static_Expression (Expr) then
if Is_True (Static_Boolean (Expr)) then
Set_Disable_Controlled (E);
end if;
-- Otherwise the expression is not static
else
Error_Msg_N
("expression of aspect % must be static", Aspect);
end if;
-- Otherwise the aspect appears without an expression and
-- defaults to True.
else
Set_Disable_Controlled (E);
end if;
end if;
end Analyze_Aspect_Disable_Controlled;
----------------------------------
-- Analyze_Aspect_Export_Import --
----------------------------------
procedure Analyze_Aspect_Export_Import is
Dummy_1 : Node_Id;
Dummy_2 : Node_Id;
Dummy_3 : Node_Id;
Expo : Node_Id;
Imp : Node_Id;
begin
-- Obtain all interfacing aspects that apply to the related
-- entity.
Get_Interfacing_Aspects
(Iface_Asp => Aspect,
Conv_Asp => Dummy_1,
EN_Asp => Dummy_2,
Expo_Asp => Expo,
Imp_Asp => Imp,
LN_Asp => Dummy_3,
Do_Checks => True);
-- The related entity cannot be subject to both aspects Export
-- and Import.
if Present (Expo) and then Present (Imp) then
Error_Msg_N
("incompatible interfacing aspects given for &", E);
Error_Msg_Sloc := Sloc (Expo);
Error_Msg_N ("\aspect Export #", E);
Error_Msg_Sloc := Sloc (Imp);
Error_Msg_N ("\aspect Import #", E);
end if;
-- A variable is most likely modified from the outside. Take
-- the optimistic approach to avoid spurious errors.
if Ekind (E) = E_Variable then
Set_Never_Set_In_Source (E, False);
end if;
-- Resolve the expression of an Import or Export here, and
-- require it to be of type Boolean and static. This is not
-- quite right, because in general this should be delayed,
-- but that seems tricky for these, because normally Boolean
-- aspects are replaced with pragmas at the freeze point in
-- Make_Pragma_From_Boolean_Aspect.
if not Present (Expr)
or else Is_True (Static_Boolean (Expr))
then
if A_Id = Aspect_Import then
Set_Has_Completion (E);
Set_Is_Imported (E);
-- An imported object cannot be explicitly initialized
if Nkind (N) = N_Object_Declaration
and then Present (Expression (N))
then
Error_Msg_N
("imported entities cannot be initialized "
& "(RM B.1(24))", Expression (N));
end if;
else
pragma Assert (A_Id = Aspect_Export);
Set_Is_Exported (E);
end if;
-- Create the proper form of pragma Export or Import taking
-- into account Conversion, External_Name, and Link_Name.
Aitem := Build_Export_Import_Pragma (Aspect, E);
-- Otherwise the expression is either False or erroneous. There
-- is no corresponding pragma.
else
Aitem := Empty;
end if;
end Analyze_Aspect_Export_Import;
---------------------------------------
-- Analyze_Aspect_External_Link_Name --
---------------------------------------
procedure Analyze_Aspect_External_Link_Name is
Dummy_1 : Node_Id;
Dummy_2 : Node_Id;
Dummy_3 : Node_Id;
Expo : Node_Id;
Imp : Node_Id;
begin
-- Obtain all interfacing aspects that apply to the related
-- entity.
Get_Interfacing_Aspects
(Iface_Asp => Aspect,
Conv_Asp => Dummy_1,
EN_Asp => Dummy_2,
Expo_Asp => Expo,
Imp_Asp => Imp,
LN_Asp => Dummy_3,
Do_Checks => True);
-- Ensure that aspect External_Name applies to aspect Export or
-- Import.
if A_Id = Aspect_External_Name then
if No (Expo) and then No (Imp) then
Error_Msg_N
("aspect External_Name requires aspect Import or "
& "Export", Aspect);
end if;
-- Otherwise ensure that aspect Link_Name applies to aspect
-- Export or Import.
else
pragma Assert (A_Id = Aspect_Link_Name);
if No (Expo) and then No (Imp) then
Error_Msg_N
("aspect Link_Name requires aspect Import or Export",
Aspect);
end if;
end if;
end Analyze_Aspect_External_Link_Name;
-----------------------------------------
-- Analyze_Aspect_Implicit_Dereference --
-----------------------------------------
procedure Analyze_Aspect_Implicit_Dereference is
begin
if not Is_Type (E) or else not Has_Discriminants (E) then
Error_Msg_N
("aspect must apply to a type with discriminants", Expr);
elsif not Is_Entity_Name (Expr) then
Error_Msg_N
("aspect must name a discriminant of current type", Expr);
else
-- Discriminant type be an anonymous access type or an
-- anonymous access to subprogram.
-- Missing synchronized types???
declare
Disc : Entity_Id := First_Discriminant (E);
begin
while Present (Disc) loop
if Chars (Expr) = Chars (Disc)
and then Ekind (Etype (Disc)) in
E_Anonymous_Access_Subprogram_Type |
E_Anonymous_Access_Type
then
Set_Has_Implicit_Dereference (E);
Set_Has_Implicit_Dereference (Disc);
exit;
end if;
Next_Discriminant (Disc);
end loop;
-- Error if no proper access discriminant
if Present (Disc) then
-- For a type extension, check whether parent has
-- a reference discriminant, to verify that use is
-- proper.
if Is_Derived_Type (E)
and then Has_Discriminants (Etype (E))
then
declare
Parent_Disc : constant Entity_Id :=
Get_Reference_Discriminant (Etype (E));
begin
if Present (Parent_Disc)
and then Corresponding_Discriminant (Disc) /=
Parent_Disc
then
Error_Msg_N
("reference discriminant does not match "
& "discriminant of parent type", Expr);
end if;
end;
end if;
else
Error_Msg_NE
("not an access discriminant of&", Expr, E);
end if;
end;
end if;
end Analyze_Aspect_Implicit_Dereference;
-------------------------------------------
-- Analyze_Aspect_Relaxed_Initialization --
-------------------------------------------
procedure Analyze_Aspect_Relaxed_Initialization is
procedure Analyze_Relaxed_Parameter
(Subp_Id : Entity_Id;
Param : Node_Id;
Seen : in out Elist_Id);
-- Analyze parameter that appears in the expression of the
-- aspect Relaxed_Initialization.
-------------------------------
-- Analyze_Relaxed_Parameter --
-------------------------------
procedure Analyze_Relaxed_Parameter
(Subp_Id : Entity_Id;
Param : Node_Id;
Seen : in out Elist_Id)
is
begin
-- Set name of the aspect for error messages
Error_Msg_Name_1 := Nam;
-- The relaxed parameter is a formal parameter
if Nkind (Param) in N_Identifier | N_Expanded_Name then
Analyze (Param);
declare
Item : constant Entity_Id := Entity (Param);
begin
-- It must be a formal of the analyzed subprogram
if Scope (Item) = Subp_Id then
pragma Assert (Is_Formal (Item));
-- It must not have scalar or access type
if Is_Elementary_Type (Etype (Item)) then
Error_Msg_N ("illegal aspect % item", Param);
Error_Msg_N
("\item must not have elementary type", Param);
end if;
-- Detect duplicated items
if Contains (Seen, Item) then
Error_Msg_N ("duplicate aspect % item", Param);
else
Append_New_Elmt (Item, Seen);
end if;
else
Error_Msg_N ("illegal aspect % item", Param);
end if;
end;
-- The relaxed parameter is the function's Result attribute
elsif Is_Attribute_Result (Param) then
Analyze (Param);
declare
Pref : constant Node_Id := Prefix (Param);
begin
if Present (Pref)
and then
Nkind (Pref) in N_Identifier | N_Expanded_Name
and then
Entity (Pref) = Subp_Id
then
-- Function result must not have scalar or access
-- type.
if Is_Elementary_Type (Etype (Pref)) then
Error_Msg_N ("illegal aspect % item", Param);
Error_Msg_N
("\function result must not have elementary"
& " type", Param);
end if;
-- Detect duplicated items
if Contains (Seen, Subp_Id) then
Error_Msg_N ("duplicate aspect % item", Param);
else
Append_New_Elmt (Entity (Pref), Seen);
end if;
else
Error_Msg_N ("illegal aspect % item", Param);
end if;
end;
else
Error_Msg_N ("illegal aspect % item", Param);
end if;
end Analyze_Relaxed_Parameter;
-- Local variables
Seen : Elist_Id := No_Elist;
-- Items that appear in the relaxed initialization aspect
-- expression of a subprogram; for detecting duplicates.
Restore_Scope : Boolean;
-- Will be set to True if we need to restore the scope table
-- after analyzing the aspect expression.
Prev_Id : Entity_Id;
-- Start of processing for Analyze_Aspect_Relaxed_Initialization
begin
-- Set name of the aspect for error messages
Error_Msg_Name_1 := Nam;
-- Annotation of a type; no aspect expression is allowed.
-- For a private type, the aspect must be attached to the
-- partial view.
--
-- ??? Once the exact rule for this aspect is ready, we will
-- likely reject concurrent types, etc., so let's keep the code
-- for types and variable separate.
if Is_First_Subtype (E) then
Prev_Id := Incomplete_Or_Partial_View (E);
if Present (Prev_Id) then
-- Aspect may appear on the full view of an incomplete
-- type because the incomplete declaration cannot have
-- any aspects.
if Ekind (Prev_Id) = E_Incomplete_Type then
null;
else
Error_Msg_N ("aspect % must apply to partial view", N);
end if;
elsif Present (Expr) then
Error_Msg_N ("illegal aspect % expression", Expr);
end if;
-- Annotation of a variable; no aspect expression is allowed
elsif Ekind (E) = E_Variable then
if Present (Expr) then
Error_Msg_N ("illegal aspect % expression", Expr);
end if;
-- Annotation of a constant; no aspect expression is allowed.
-- For a deferred constant, the aspect must be attached to the
-- partial view.
elsif Ekind (E) = E_Constant then
if Present (Incomplete_Or_Partial_View (E)) then
Error_Msg_N
("aspect % must apply to deferred constant", N);
elsif Present (Expr) then
Error_Msg_N ("illegal aspect % expression", Expr);
end if;
-- Annotation of a subprogram; aspect expression is required
elsif Is_Subprogram_Or_Entry (E)
or else Is_Generic_Subprogram (E)
then
if Present (Expr) then
-- If we analyze subprogram body that acts as its own
-- spec, then the subprogram itself and its formals are
-- already installed; otherwise, we need to install them,
-- as they must be visible when analyzing the aspect
-- expression.
if In_Open_Scopes (E) then
Restore_Scope := False;
else
Restore_Scope := True;
Push_Scope (E);
-- Only formals of the subprogram itself can appear
-- in Relaxed_Initialization aspect expression, not
-- formals of the enclosing generic unit. (This is
-- different than in Precondition or Depends aspects,
-- where both kinds of formals are allowed.)
Install_Formals (E);
end if;
-- Aspect expression is either an aggregate with list of
-- parameters (and possibly the Result attribute for a
-- function).
if Nkind (Expr) = N_Aggregate then
-- Component associations in the aggregate must be a
-- parameter name followed by a static boolean
-- expression.
if Present (Component_Associations (Expr)) then
declare
Assoc : Node_Id :=
First (Component_Associations (Expr));
begin
while Present (Assoc) loop
if List_Length (Choices (Assoc)) = 1 then
Analyze_Relaxed_Parameter
(E, First (Choices (Assoc)), Seen);
if Inside_A_Generic then
Preanalyze_And_Resolve
(Expression (Assoc), Any_Boolean);
else
Analyze_And_Resolve
(Expression (Assoc), Any_Boolean);
end if;
if not Is_OK_Static_Expression
(Expression (Assoc))
then
Error_Msg_Name_1 := Nam;
Error_Msg_N
("expression of aspect %" &
"must be static", Aspect);
end if;
else
Error_Msg_Name_1 := Nam;
Error_Msg_N
("illegal aspect % expression", Expr);
end if;
Next (Assoc);
end loop;
end;
end if;
-- Expressions of the aggregate are parameter names
if Present (Expressions (Expr)) then
declare
Param : Node_Id := First (Expressions (Expr));
begin
while Present (Param) loop
Analyze_Relaxed_Parameter (E, Param, Seen);
Next (Param);
end loop;
end;
end if;
-- Mark the aggregate expression itself as analyzed;
-- its subexpressions were marked when they themselves
-- were analyzed.
Set_Analyzed (Expr);
-- Otherwise, it is a single name of a subprogram
-- parameter (or possibly the Result attribute for
-- a function).
else
Analyze_Relaxed_Parameter (E, Expr, Seen);
end if;
if Restore_Scope then
End_Scope;
end if;
else
Error_Msg_N ("missing expression for aspect %", N);
end if;
else
Error_Msg_N ("inappropriate entity for aspect %", E);
end if;
end Analyze_Aspect_Relaxed_Initialization;
---------------------------
-- Analyze_Aspect_Static --
---------------------------
procedure Analyze_Aspect_Static is
function Has_Convention_Intrinsic (L : List_Id) return Boolean;
-- Return True if L contains a pragma argument association
-- node representing a convention Intrinsic.
------------------------------
-- Has_Convention_Intrinsic --
------------------------------
function Has_Convention_Intrinsic
(L : List_Id) return Boolean
is
Arg : Node_Id := First (L);
begin
while Present (Arg) loop
if Nkind (Arg) = N_Pragma_Argument_Association
and then Chars (Arg) = Name_Convention
and then Chars (Expression (Arg)) = Name_Intrinsic
then
return True;
end if;
Next (Arg);
end loop;
return False;
end Has_Convention_Intrinsic;
Is_Imported_Intrinsic : Boolean;
begin
if Ada_Version < Ada_2022 then
Error_Msg_Ada_2022_Feature ("aspect %", Sloc (Aspect));
return;
end if;
Is_Imported_Intrinsic := Is_Imported (E)
and then
Has_Convention_Intrinsic
(Pragma_Argument_Associations (Import_Pragma (E)));
-- The aspect applies only to expression functions that
-- statisfy the requirements for a static expression function
-- (such as having an expression that is predicate-static) as
-- well as Intrinsic imported functions as a -gnatX extension.
if not Is_Expression_Function (E)
and then
not (Extensions_Allowed and then Is_Imported_Intrinsic)
then
if Extensions_Allowed then
Error_Msg_N
("aspect % requires intrinsic or expression function",
Aspect);
elsif Is_Imported_Intrinsic then
Error_Msg_N
("aspect % on intrinsic function is an extension: " &
"use -gnatX",
Aspect);
else
Error_Msg_N
("aspect % requires expression function", Aspect);
end if;
return;
-- Ada 2022 (AI12-0075): Check that the function satisfies
-- several requirements of static functions as specified in
-- RM 6.8(5.1-5.8). Note that some of the requirements given
-- there are checked elsewhere.
else
-- The expression of the expression function must be a
-- potentially static expression (RM 2022 6.8(3.2-3.4)).
-- That's checked in Sem_Ch6.Analyze_Expression_Function.
-- The function must not contain any calls to itself, which
-- is checked in Sem_Res.Resolve_Call.
-- Each formal must be of mode in and have a static subtype
declare
Formal : Entity_Id := First_Formal (E);
begin
while Present (Formal) loop
if Ekind (Formal) /= E_In_Parameter then
Error_Msg_N
("aspect % requires formals of mode IN",
Aspect);
return;
end if;
if not Is_Static_Subtype (Etype (Formal)) then
Error_Msg_N
("aspect % requires formals with static subtypes",
Aspect);
return;
end if;
Next_Formal (Formal);
end loop;
end;
-- The function's result subtype must be a static subtype
if not Is_Static_Subtype (Etype (E)) then
Error_Msg_N
("aspect % requires function with result of "
& "a static subtype",
Aspect);
return;
end if;
-- Check that the function does not have any applicable
-- precondition or postcondition expression.
for Asp in Pre_Post_Aspects loop
if Has_Aspect (E, Asp) then
Error_Msg_Name_1 := Aspect_Names (Asp);
Error_Msg_N
("aspect % is not allowed for a static "
& "expression function",
Find_Aspect (E, Asp));
return;
end if;
end loop;
-- ??? Must check that "for result type R, if the
-- function is a boundary entity for type R (see 7.3.2),
-- no type invariant applies to type R; if R has a
-- component type C, a similar rule applies to C."
end if;
-- When the expression is present, it must be static. If it
-- evaluates to True, the expression function is treated as
-- a static function. Otherwise the aspect appears without
-- an expression and defaults to True.
if Present (Expr) then
-- Preanalyze the expression when the aspect resides in a
-- generic unit. (Is this generic-related code necessary
-- for this aspect? It's modeled on what's done for aspect
-- Disable_Controlled. ???)
if Inside_A_Generic then
Preanalyze_And_Resolve (Expr, Any_Boolean);
-- Otherwise the aspect resides in a nongeneric context
else
Analyze_And_Resolve (Expr, Any_Boolean);
-- Error if the boolean expression is not static
if not Is_OK_Static_Expression (Expr) then
Error_Msg_N
("expression of aspect % must be static", Aspect);
end if;
end if;
end if;
end Analyze_Aspect_Static;
--------------------------
-- Analyze_Aspect_Yield --
--------------------------
procedure Analyze_Aspect_Yield is
Expr_Value : Boolean := False;
begin
-- Check valid declarations for 'Yield
if Nkind (N) in N_Abstract_Subprogram_Declaration
| N_Entry_Declaration
| N_Generic_Subprogram_Declaration
| N_Subprogram_Declaration
| N_Formal_Subprogram_Declaration
and then not Within_Protected_Type (E)
then
null;
elsif Within_Protected_Type (E) then
Error_Msg_N
("aspect% not applicable to protected operation", Id);
return;
else
Error_Msg_N
("aspect% only applicable to subprogram and entry "
& "declarations", Id);
return;
end if;
-- Evaluate its static expression (if available); otherwise it
-- defaults to True.
if No (Expr) then
Expr_Value := True;
-- Otherwise it must have a static boolean expression
else
if Inside_A_Generic then
Preanalyze_And_Resolve (Expr, Any_Boolean);
else
Analyze_And_Resolve (Expr, Any_Boolean);
end if;
if Is_OK_Static_Expression (Expr) then
if Is_True (Static_Boolean (Expr)) then
Expr_Value := True;
end if;
else
Error_Msg_N
("expression of aspect % must be static", Aspect);
end if;
end if;
if Expr_Value then
Set_Has_Yield_Aspect (E);
end if;
-- If the Yield aspect is specified for a dispatching
-- subprogram that inherits the aspect, the specified
-- value shall be confirming.
if Present (Expr)
and then Is_Dispatching_Operation (E)
and then Present (Overridden_Operation (E))
and then Has_Yield_Aspect (Overridden_Operation (E))
/= Is_True (Static_Boolean (Expr))
then
Error_Msg_N ("specification of inherited aspect% can only " &
"confirm parent value", Id);
end if;
end Analyze_Aspect_Yield;
----------------------------------------
-- Check_Expr_Is_OK_Static_Expression --
----------------------------------------
procedure Check_Expr_Is_OK_Static_Expression
(Expr : Node_Id;
Typ : Entity_Id := Empty)
is
begin
if Present (Typ) then
Analyze_And_Resolve (Expr, Typ);
else
Analyze_And_Resolve (Expr);
end if;
-- An expression cannot be considered static if its resolution
-- failed or if it's erroneous. Stop the analysis of the
-- related aspect.
if Etype (Expr) = Any_Type or else Error_Posted (Expr) then
raise Aspect_Exit;
elsif Is_OK_Static_Expression (Expr) then
return;
-- Finally, we have a real error
else
Error_Msg_Name_1 := Nam;
Flag_Non_Static_Expr
("entity for aspect% must be a static expression",
Expr);
raise Aspect_Exit;
end if;
end Check_Expr_Is_OK_Static_Expression;
------------------------
-- Directly_Specified --
------------------------
function Directly_Specified
(Id : Entity_Id; A : Aspect_Id) return Boolean
is
Aspect_Spec : constant Node_Id := Find_Aspect (Id, A);
begin
return Present (Aspect_Spec) and then Entity (Aspect_Spec) = Id;
end Directly_Specified;
-----------------------
-- Make_Aitem_Pragma --
-----------------------
function Make_Aitem_Pragma
(Pragma_Argument_Associations : List_Id;
Pragma_Name : Name_Id) return Node_Id
is
Args : List_Id := Pragma_Argument_Associations;
Aitem : Node_Id;
begin
-- We should never get here if aspect was disabled
pragma Assert (not Is_Disabled (Aspect));
-- Certain aspects allow for an optional name or expression. Do
-- not generate a pragma with empty argument association list.
if No (Args) or else No (Expression (First (Args))) then
Args := No_List;
end if;
-- Build the pragma
Aitem :=
Make_Pragma (Loc,
Pragma_Argument_Associations => Args,
Pragma_Identifier =>
Make_Identifier (Sloc (Id), Pragma_Name),
Class_Present => Class_Present (Aspect),
Split_PPC => Split_PPC (Aspect));
-- Set additional semantic fields
if Is_Ignored (Aspect) then
Set_Is_Ignored (Aitem);
elsif Is_Checked (Aspect) then
Set_Is_Checked (Aitem);
end if;
Set_Corresponding_Aspect (Aitem, Aspect);
Set_From_Aspect_Specification (Aitem);
return Aitem;
end Make_Aitem_Pragma;
-- Start of processing for Analyze_One_Aspect
begin
-- Skip aspect if already analyzed, to avoid looping in some cases
if Analyzed (Aspect) then
goto Continue;
end if;
-- Skip looking at aspect if it is totally disabled. Just mark it
-- as such for later reference in the tree. This also sets the
-- Is_Ignored and Is_Checked flags appropriately.
Check_Applicable_Policy (Aspect);
if Is_Disabled (Aspect) then
goto Continue;
end if;
-- Set the source location of expression, used in the case of
-- a failed precondition/postcondition or invariant. Note that
-- the source location of the expression is not usually the best
-- choice here. For example, it gets located on the last AND
-- keyword in a chain of boolean expressiond AND'ed together.
-- It is best to put the message on the first character of the
-- assertion, which is the effect of the First_Node call here.
if Present (Expr) then
Eloc := Sloc (First_Node (Expr));
end if;
-- Check restriction No_Implementation_Aspect_Specifications
if Implementation_Defined_Aspect (A_Id) then
Check_Restriction
(No_Implementation_Aspect_Specifications, Aspect);
end if;
-- Check restriction No_Specification_Of_Aspect
Check_Restriction_No_Specification_Of_Aspect (Aspect);
-- Mark aspect analyzed (actual analysis is delayed till later)
Set_Analyzed (Aspect);
Set_Entity (Aspect, E);
-- Build the reference to E that will be used in the built pragmas
Ent := New_Occurrence_Of (E, Sloc (Id));
if A_Id in Aspect_Attach_Handler | Aspect_Interrupt_Handler then
-- Treat the specification as a reference to the protected
-- operation, which might otherwise appear unreferenced and
-- generate spurious warnings.
Generate_Reference (E, Id);
end if;
-- Check for duplicate aspect. Note that the Comes_From_Source
-- test allows duplicate Pre/Post's that we generate internally
-- to escape being flagged here.
if No_Duplicates_Allowed (A_Id) then
Anod := First (L);
while Anod /= Aspect loop
if Comes_From_Source (Aspect)
and then Same_Aspect (A_Id, Get_Aspect_Id (Anod))
then
Error_Msg_Name_1 := Nam;
Error_Msg_Sloc := Sloc (Anod);
-- Case of same aspect specified twice
if Class_Present (Anod) = Class_Present (Aspect) then
if not Class_Present (Anod) then
Error_Msg_NE
("aspect% for & previously given#",
Id, E);
else
Error_Msg_NE
("aspect `%''Class` for & previously given#",
Id, E);
end if;
end if;
end if;
Next (Anod);
end loop;
end if;
-- Check some general restrictions on language defined aspects
if not Implementation_Defined_Aspect (A_Id)
or else A_Id in Aspect_Async_Readers
| Aspect_Async_Writers
| Aspect_Effective_Reads
| Aspect_Effective_Writes
| Aspect_Preelaborable_Initialization
then
Error_Msg_Name_1 := Nam;
-- Not allowed for renaming declarations. Examine the original
-- node because a subprogram renaming may have been rewritten
-- as a body.
if Nkind (Original_Node (N)) in N_Renaming_Declaration then
Error_Msg_N
("aspect % not allowed for renaming declaration",
Aspect);
end if;
-- Not allowed for formal type declarations in previous
-- versions of the language. Allowed for them only for
-- shared variable control aspects.
-- Original node is used in case expansion rewrote the node -
-- as is the case with generic derived types.
if Nkind (Original_Node (N)) = N_Formal_Type_Declaration then
if Ada_Version < Ada_2022 then
Error_Msg_N
("aspect % not allowed for formal type declaration",
Aspect);
elsif A_Id not in Aspect_Atomic
| Aspect_Volatile
| Aspect_Independent
| Aspect_Atomic_Components
| Aspect_Independent_Components
| Aspect_Volatile_Components
| Aspect_Async_Readers
| Aspect_Async_Writers
| Aspect_Effective_Reads
| Aspect_Effective_Writes
| Aspect_Preelaborable_Initialization
then
Error_Msg_N
("aspect % not allowed for formal type declaration",
Aspect);
end if;
end if;
end if;
-- Copy expression for later processing by the procedures
-- Check_Aspect_At_[Freeze_Point | End_Of_Declarations]
-- The expression may be a subprogram name, and can
-- be an operator name that appears as a string, but
-- requires its own analysis procedure (see sem_ch6).
if Nkind (Expr) = N_Operator_Symbol then
Set_Entity (Id, Expr);
else
Set_Entity (Id, New_Copy_Tree (Expr));
end if;
-- Set Delay_Required as appropriate to aspect
case Aspect_Delay (A_Id) is
when Always_Delay =>
-- For Boolean aspects, do not delay if no expression
if A_Id in Boolean_Aspects | Library_Unit_Aspects then
Delay_Required := Present (Expr);
else
Delay_Required := True;
end if;
when Never_Delay =>
Delay_Required := False;
when Rep_Aspect =>
-- For Boolean aspects, do not delay if no expression except
-- for Full_Access_Only because we need to process it after
-- Volatile and Atomic, which can be independently delayed.
if A_Id in Boolean_Aspects
and then A_Id /= Aspect_Full_Access_Only
and then No (Expr)
then
Delay_Required := False;
-- For non-Boolean aspects, if the expression has the form
-- of an integer literal, then do not delay, since we know
-- the value cannot change. This optimization catches most
-- rep clause cases.
elsif A_Id not in Boolean_Aspects
and then Present (Expr)
and then Nkind (Expr) = N_Integer_Literal
then
Delay_Required := False;
-- For Alignment and various Size aspects, do not delay for
-- an attribute reference whose prefix is Standard, for
-- example Standard'Maximum_Alignment or Standard'Word_Size.
elsif A_Id in Aspect_Alignment
| Aspect_Component_Size
| Aspect_Object_Size
| Aspect_Size
| Aspect_Value_Size
and then Present (Expr)
and then Nkind (Expr) = N_Attribute_Reference
and then Nkind (Prefix (Expr)) = N_Identifier
and then Chars (Prefix (Expr)) = Name_Standard
then
Delay_Required := False;
-- All other cases are delayed
else
Delay_Required := True;
Set_Has_Delayed_Rep_Aspects (E);
end if;
end case;
if Delay_Required
and then (A_Id = Aspect_Stable_Properties
or else A_Id = Aspect_Designated_Storage_Model
or else A_Id = Aspect_Storage_Model_Type)
-- ??? It seems like we should do this for all aspects, not
-- just these, but that causes as-yet-undiagnosed regressions.
then
Set_Has_Delayed_Aspects (E);
Set_Is_Delayed_Aspect (Aspect);
end if;
-- Check 13.1(9.2/5): A representation aspect of a subtype or type
-- shall not be specified (whether by a representation item or an
-- aspect_specification) before the type is completely defined
-- (see 3.11.1).
if Is_Representation_Aspect (A_Id)
and then Rep_Item_Too_Early (E, N)
then
goto Continue;
end if;
-- Processing based on specific aspect
case A_Id is
when Aspect_Unimplemented =>
null; -- ??? temp for now
-- No_Aspect should be impossible
when No_Aspect =>
raise Program_Error;
-- Case 1: Aspects corresponding to attribute definition
-- clauses.
when Aspect_Address
| Aspect_Alignment
| Aspect_Bit_Order
| Aspect_Component_Size
| Aspect_Constant_Indexing
| Aspect_Default_Iterator
| Aspect_Dispatching_Domain
| Aspect_External_Tag
| Aspect_Input
| Aspect_Iterable
| Aspect_Iterator_Element
| Aspect_Machine_Radix
| Aspect_Object_Size
| Aspect_Output
| Aspect_Put_Image
| Aspect_Read
| Aspect_Scalar_Storage_Order
| Aspect_Simple_Storage_Pool
| Aspect_Size
| Aspect_Small
| Aspect_Storage_Pool
| Aspect_Stream_Size
| Aspect_Value_Size
| Aspect_Variable_Indexing
| Aspect_Write
=>
-- Indexing aspects apply only to tagged type
if A_Id in Aspect_Constant_Indexing
| Aspect_Variable_Indexing
and then not (Is_Type (E)
and then Is_Tagged_Type (E))
then
Error_Msg_N
("indexing aspect can only apply to a tagged type",
Aspect);
goto Continue;
end if;
-- For the case of aspect Address, we don't consider that we
-- know the entity is never set in the source, since it is
-- is likely aliasing is occurring.
-- Note: one might think that the analysis of the resulting
-- attribute definition clause would take care of that, but
-- that's not the case since it won't be from source.
if A_Id = Aspect_Address then
Set_Never_Set_In_Source (E, False);
end if;
-- Correctness of the profile of a stream operation is
-- verified at the freeze point, but we must detect the
-- illegal specification of this aspect for a subtype now,
-- to prevent malformed rep_item chains.
if A_Id in Aspect_Input
| Aspect_Output
| Aspect_Read
| Aspect_Write
then
if not Is_First_Subtype (E) then
Error_Msg_N
("local name must be a first subtype", Aspect);
goto Continue;
-- If stream aspect applies to the class-wide type,
-- the generated attribute definition applies to the
-- class-wide type as well.
elsif Class_Present (Aspect) then
Ent :=
Make_Attribute_Reference (Loc,
Prefix => Ent,
Attribute_Name => Name_Class);
end if;
end if;
-- Construct the attribute_definition_clause. The expression
-- in the aspect specification is simply shared with the
-- constructed attribute, because it will be fully analyzed
-- when the attribute is processed.
Aitem :=
Make_Attribute_Definition_Clause (Loc,
Name => Ent,
Chars => Nam,
Expression => Relocate_Node (Expr));
-- If the address is specified, then we treat the entity as
-- referenced, to avoid spurious warnings. This is analogous
-- to what is done with an attribute definition clause, but
-- here we don't want to generate a reference because this
-- is the point of definition of the entity.
if A_Id = Aspect_Address then
Set_Referenced (E);
end if;
-- Case 2: Aspects corresponding to pragmas
-- Case 2a: Aspects corresponding to pragmas with two
-- arguments, where the first argument is a local name
-- referring to the entity, and the second argument is the
-- aspect definition expression.
-- Linker_Section
when Aspect_Linker_Section =>
Aitem := Make_Aitem_Pragma
(Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Loc,
Expression => New_Occurrence_Of (E, Loc)),
Make_Pragma_Argument_Association (Sloc (Expr),
Expression => Relocate_Node (Expr))),
Pragma_Name => Name_Linker_Section);
-- Linker_Section does not need delaying, as its argument
-- must be a static string. Furthermore, if applied to
-- an object with an explicit initialization, the object
-- must be frozen in order to elaborate the initialization
-- code. (This is already done for types with implicit
-- initialization, such as protected types.)
if Nkind (N) = N_Object_Declaration
and then Has_Init_Expression (N)
then
Delay_Required := False;
end if;
-- Synchronization
-- Corresponds to pragma Implemented, construct the pragma
when Aspect_Synchronization =>
Aitem := Make_Aitem_Pragma
(Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Loc,
Expression => New_Occurrence_Of (E, Loc)),
Make_Pragma_Argument_Association (Sloc (Expr),
Expression => Relocate_Node (Expr))),
Pragma_Name => Name_Implemented);
-- Attach_Handler
when Aspect_Attach_Handler =>
Aitem := Make_Aitem_Pragma
(Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Sloc (Ent),
Expression => Ent),
Make_Pragma_Argument_Association (Sloc (Expr),
Expression => Relocate_Node (Expr))),
Pragma_Name => Name_Attach_Handler);
-- We need to insert this pragma into the tree to get proper
-- processing and to look valid from a placement viewpoint.
Insert_Pragma (Aitem);
goto Continue;
-- Dynamic_Predicate, Predicate, Static_Predicate
when Aspect_Dynamic_Predicate
| Aspect_Predicate
| Aspect_Static_Predicate
=>
-- These aspects apply only to subtypes
if not Is_Type (E) then
Error_Msg_N
("predicate can only be specified for a subtype",
Aspect);
goto Continue;
elsif Is_Incomplete_Type (E) then
Error_Msg_N
("predicate cannot apply to incomplete view", Aspect);
elsif Is_Generic_Type (E) then
Error_Msg_N
("predicate cannot apply to formal type", Aspect);
goto Continue;
end if;
-- Construct the pragma (always a pragma Predicate, with
-- flags recording whether it is static/dynamic). We also
-- set flags recording this in the type itself.
Aitem := Make_Aitem_Pragma
(Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Sloc (Ent),
Expression => Ent),
Make_Pragma_Argument_Association (Sloc (Expr),
Expression => Relocate_Node (Expr))),
Pragma_Name => Name_Predicate);
-- Mark type has predicates, and remember what kind of
-- aspect lead to this predicate (we need this to access
-- the right set of check policies later on).
Set_Has_Predicates (E);
if A_Id = Aspect_Dynamic_Predicate then
Set_Has_Dynamic_Predicate_Aspect (E);
-- If the entity has a dynamic predicate, any inherited
-- static predicate becomes dynamic as well, and the
-- predicate function includes the conjunction of both.
Set_Has_Static_Predicate_Aspect (E, False);
elsif A_Id = Aspect_Static_Predicate then
Set_Has_Static_Predicate_Aspect (E);
end if;
-- If the type is private, indicate that its completion
-- has a freeze node, because that is the one that will
-- be visible at freeze time.
if Is_Private_Type (E) and then Present (Full_View (E)) then
Set_Has_Predicates (Full_View (E));
if A_Id = Aspect_Dynamic_Predicate then
Set_Has_Dynamic_Predicate_Aspect (Full_View (E));
elsif A_Id = Aspect_Static_Predicate then
Set_Has_Static_Predicate_Aspect (Full_View (E));
end if;
Set_Has_Delayed_Aspects (Full_View (E));
Ensure_Freeze_Node (Full_View (E));
-- If there is an Underlying_Full_View, also create a
-- freeze node for that one.
if Is_Private_Type (Full_View (E)) then
declare
U_Full : constant Entity_Id :=
Underlying_Full_View (Full_View (E));
begin
if Present (U_Full) then
Set_Has_Delayed_Aspects (U_Full);
Ensure_Freeze_Node (U_Full);
end if;
end;
end if;
end if;
-- Predicate_Failure
when Aspect_Predicate_Failure =>
-- This aspect applies only to subtypes
if not Is_Type (E) then
Error_Msg_N
("predicate can only be specified for a subtype",
Aspect);
goto Continue;
elsif Is_Incomplete_Type (E) then
Error_Msg_N
("predicate cannot apply to incomplete view", Aspect);
goto Continue;
elsif not Has_Predicates (E) then
Error_Msg_N
("Predicate_Failure requires previous predicate" &
" specification", Aspect);
goto Continue;
elsif not (Directly_Specified (E, Aspect_Dynamic_Predicate)
or else Directly_Specified (E, Aspect_Static_Predicate)
or else Directly_Specified (E, Aspect_Predicate))
then
Error_Msg_N
("Predicate_Failure requires accompanying" &
" noninherited predicate specification", Aspect);
goto Continue;
end if;
-- Construct the pragma
Aitem := Make_Aitem_Pragma
(Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Sloc (Ent),
Expression => Ent),
Make_Pragma_Argument_Association (Sloc (Expr),
Expression => Relocate_Node (Expr))),
Pragma_Name => Name_Predicate_Failure);
-- Case 2b: Aspects corresponding to pragmas with two
-- arguments, where the second argument is a local name
-- referring to the entity, and the first argument is the
-- aspect definition expression.
-- Convention
when Aspect_Convention =>
Analyze_Aspect_Convention;
goto Continue;
-- External_Name, Link_Name
when Aspect_External_Name
| Aspect_Link_Name
=>
Analyze_Aspect_External_Link_Name;
goto Continue;
-- CPU, Interrupt_Priority, Priority
-- These three aspects can be specified for a subprogram spec
-- or body, in which case we analyze the expression and export
-- the value of the aspect.
-- Previously, we generated an equivalent pragma for bodies
-- (note that the specs cannot contain these pragmas). The
-- pragma was inserted ahead of local declarations, rather than
-- after the body. This leads to a certain duplication between
-- the processing performed for the aspect and the pragma, but
-- given the straightforward handling required it is simpler
-- to duplicate than to translate the aspect in the spec into
-- a pragma in the declarative part of the body.
when Aspect_CPU
| Aspect_Interrupt_Priority
| Aspect_Priority
=>
-- Verify the expression is static when Static_Priorities is
-- enabled.
if not Is_OK_Static_Expression (Expr) then
Check_Restriction (Static_Priorities, Expr);
end if;
if Nkind (N) in N_Subprogram_Body | N_Subprogram_Declaration
then
-- Analyze the aspect expression
Analyze_And_Resolve (Expr, Standard_Integer);
-- Interrupt_Priority aspect not allowed for main
-- subprograms. RM D.1 does not forbid this explicitly,
-- but RM J.15.11(6/3) does not permit pragma
-- Interrupt_Priority for subprograms.
if A_Id = Aspect_Interrupt_Priority then
Error_Msg_N
("Interrupt_Priority aspect cannot apply to "
& "subprogram", Expr);
-- The expression must be static
elsif not Is_OK_Static_Expression (Expr) then
Flag_Non_Static_Expr
("aspect requires static expression!", Expr);
-- Check whether this is the main subprogram. Issue a
-- warning only if it is obviously not a main program
-- (when it has parameters or when the subprogram is
-- within a package).
elsif Present (Parameter_Specifications
(Specification (N)))
or else not Is_Compilation_Unit (Defining_Entity (N))
then
-- See RM D.1(14/3) and D.16(12/3)
Error_Msg_N
("aspect applied to subprogram other than the "
& "main subprogram has no effect??", Expr);
-- Otherwise check in range and export the value
-- For the CPU aspect
elsif A_Id = Aspect_CPU then
if Is_In_Range (Expr, RTE (RE_CPU_Range)) then
-- Value is correct so we export the value to make
-- it available at execution time.
Set_Main_CPU
(Main_Unit, UI_To_Int (Expr_Value (Expr)));
else
Error_Msg_N
("main subprogram 'C'P'U is out of range", Expr);
end if;
-- For the Priority aspect
elsif A_Id = Aspect_Priority then
if Is_In_Range (Expr, RTE (RE_Priority)) then
-- Value is correct so we export the value to make
-- it available at execution time.
Set_Main_Priority
(Main_Unit, UI_To_Int (Expr_Value (Expr)));
-- Ignore pragma if Relaxed_RM_Semantics to support
-- other targets/non GNAT compilers.
elsif not Relaxed_RM_Semantics then
Error_Msg_N
("main subprogram priority is out of range",
Expr);
end if;
end if;
-- Load an arbitrary entity from System.Tasking.Stages
-- or System.Tasking.Restricted.Stages (depending on
-- the supported profile) to make sure that one of these
-- packages is implicitly with'ed, since we need to have
-- the tasking run time active for the pragma Priority to
-- have any effect. Previously we with'ed the package
-- System.Tasking, but this package does not trigger the
-- required initialization of the run-time library.
if Restricted_Profile then
Discard_Node (RTE (RE_Activate_Restricted_Tasks));
else
Discard_Node (RTE (RE_Activate_Tasks));
end if;
-- Handling for these aspects in subprograms is complete
goto Continue;
-- For task and protected types pass the aspect as an
-- attribute.
else
Aitem :=
Make_Attribute_Definition_Clause (Loc,
Name => Ent,
Chars => Nam,
Expression => Relocate_Node (Expr));
end if;
-- Suppress/Unsuppress
when Aspect_Suppress
| Aspect_Unsuppress
=>
Aitem := Make_Aitem_Pragma
(Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Loc,
Expression => Relocate_Node (Expr)),
Make_Pragma_Argument_Association (Sloc (Expr),
Expression => New_Occurrence_Of (E, Loc))),
Pragma_Name => Nam);
Delay_Required := False;
-- Warnings
when Aspect_Warnings =>
Aitem := Make_Aitem_Pragma
(Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Sloc (Expr),
Expression => Relocate_Node (Expr)),
Make_Pragma_Argument_Association (Loc,
Expression => New_Occurrence_Of (E, Loc))),
Pragma_Name => Name_Warnings);
Decorate (Aspect, Aitem);
Insert_Pragma (Aitem);
goto Continue;
-- Case 2c: Aspects corresponding to pragmas with three
-- arguments.
-- Invariant aspects have a first argument that references the
-- entity, a second argument that is the expression and a third
-- argument that is an appropriate message.
-- Invariant, Type_Invariant
when Aspect_Invariant
| Aspect_Type_Invariant
=>
-- Analysis of the pragma will verify placement legality:
-- an invariant must apply to a private type, or appear in
-- the private part of a spec and apply to a completion.
Aitem := Make_Aitem_Pragma
(Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Sloc (Ent),
Expression => Ent),
Make_Pragma_Argument_Association (Sloc (Expr),
Expression => Relocate_Node (Expr))),
Pragma_Name => Name_Invariant);
-- Add message unless exception messages are suppressed
if not Opt.Exception_Locations_Suppressed then
Append_To (Pragma_Argument_Associations (Aitem),
Make_Pragma_Argument_Association (Eloc,
Chars => Name_Message,
Expression =>
Make_String_Literal (Eloc,
Strval => "failed invariant from "
& Build_Location_String (Eloc))));
end if;
-- For Invariant case, insert immediately after the entity
-- declaration. We do not have to worry about delay issues
-- since the pragma processing takes care of this.