+ -- If the node is an object declaration without initial
+ -- value, some code has been expanded, and the expression
+ -- is not constant, even if the constituents might be
+ -- acceptable, as in A'Address + offset.
+
+ if Ekind (Ent) = E_Variable
+ and then
+ Nkind (Declaration_Node (Ent)) = N_Object_Declaration
+ and then
+ No (Expression (Declaration_Node (Ent)))
+ then
+ Error_Msg_NE
+ ("invalid address clause for initialized object &!",
+ Nod, U_Ent);
+
+ -- If entity is constant, it may be the result of expanding
+ -- a check. We must verify that its declaration appears
+ -- before the object in question, else we also reject the
+ -- address clause.
+
+ elsif Ekind (Ent) = E_Constant
+ and then In_Same_Source_Unit (Ent, U_Ent)
+ and then Sloc (Ent) > Loc_U_Ent
+ then
+ Error_Msg_NE
+ ("invalid address clause for initialized object &!",
+ Nod, U_Ent);
+ end if;
+
+ return;
+ end if;
+
+ -- Otherwise look at the identifier and see if it is OK
+
+ if Ekind_In (Ent, E_Named_Integer, E_Named_Real)
+ or else Is_Type (Ent)
+ then
+ return;
+
+ elsif
+ Ekind (Ent) = E_Constant
+ or else
+ Ekind (Ent) = E_In_Parameter
+ then
+ -- This is the case where we must have Ent defined before
+ -- U_Ent. Clearly if they are in different units this
+ -- requirement is met since the unit containing Ent is
+ -- already processed.
+
+ if not In_Same_Source_Unit (Ent, U_Ent) then
+ return;
+
+ -- Otherwise location of Ent must be before the location
+ -- of U_Ent, that's what prior defined means.
+
+ elsif Sloc (Ent) < Loc_U_Ent then
+ return;
+
+ else
+ Error_Msg_NE
+ ("invalid address clause for initialized object &!",
+ Nod, U_Ent);
+ Error_Msg_Node_2 := U_Ent;
+ Error_Msg_NE
+ ("\& must be defined before & (RM 13.1(22))!",
+ Nod, Ent);
+ end if;
+
+ elsif Nkind (Original_Node (Nod)) = N_Function_Call then
+ Check_Expr_Constants (Original_Node (Nod));
+
+ else
+ Error_Msg_NE
+ ("invalid address clause for initialized object &!",
+ Nod, U_Ent);
+
+ if Comes_From_Source (Ent) then
+ Error_Msg_NE
+ ("\reference to variable& not allowed"
+ & " (RM 13.1(22))!", Nod, Ent);
+ else
+ Error_Msg_N
+ ("non-static expression not allowed"
+ & " (RM 13.1(22))!", Nod);
+ end if;
+ end if;
+
+ when N_Integer_Literal =>
+
+ -- If this is a rewritten unchecked conversion, in a system
+ -- where Address is an integer type, always use the base type
+ -- for a literal value. This is user-friendly and prevents
+ -- order-of-elaboration issues with instances of unchecked
+ -- conversion.
+
+ if Nkind (Original_Node (Nod)) = N_Function_Call then
+ Set_Etype (Nod, Base_Type (Etype (Nod)));
+ end if;
+
+ when N_Real_Literal |
+ N_String_Literal |
+ N_Character_Literal =>
+ return;
+
+ when N_Range =>
+ Check_Expr_Constants (Low_Bound (Nod));
+ Check_Expr_Constants (High_Bound (Nod));
+
+ when N_Explicit_Dereference =>
+ Check_Expr_Constants (Prefix (Nod));
+
+ when N_Indexed_Component =>
+ Check_Expr_Constants (Prefix (Nod));
+ Check_List_Constants (Expressions (Nod));
+
+ when N_Slice =>
+ Check_Expr_Constants (Prefix (Nod));
+ Check_Expr_Constants (Discrete_Range (Nod));
+
+ when N_Selected_Component =>
+ Check_Expr_Constants (Prefix (Nod));
+
+ when N_Attribute_Reference =>
+ if Attribute_Name (Nod) = Name_Address
+ or else
+ Attribute_Name (Nod) = Name_Access
+ or else
+ Attribute_Name (Nod) = Name_Unchecked_Access
+ or else
+ Attribute_Name (Nod) = Name_Unrestricted_Access
+ then
+ Check_At_Constant_Address (Prefix (Nod));
+
+ else
+ Check_Expr_Constants (Prefix (Nod));
+ Check_List_Constants (Expressions (Nod));
+ end if;
+
+ when N_Aggregate =>
+ Check_List_Constants (Component_Associations (Nod));
+ Check_List_Constants (Expressions (Nod));
+
+ when N_Component_Association =>
+ Check_Expr_Constants (Expression (Nod));
+
+ when N_Extension_Aggregate =>
+ Check_Expr_Constants (Ancestor_Part (Nod));
+ Check_List_Constants (Component_Associations (Nod));
+ Check_List_Constants (Expressions (Nod));
+
+ when N_Null =>
+ return;
+
+ when N_Binary_Op | N_Short_Circuit | N_Membership_Test =>
+ Check_Expr_Constants (Left_Opnd (Nod));
+ Check_Expr_Constants (Right_Opnd (Nod));
+
+ when N_Unary_Op =>
+ Check_Expr_Constants (Right_Opnd (Nod));
+
+ when N_Type_Conversion |
+ N_Qualified_Expression |
+ N_Allocator =>
+ Check_Expr_Constants (Expression (Nod));
+
+ when N_Unchecked_Type_Conversion =>
+ Check_Expr_Constants (Expression (Nod));
+
+ -- If this is a rewritten unchecked conversion, subtypes in
+ -- this node are those created within the instance. To avoid
+ -- order of elaboration issues, replace them with their base
+ -- types. Note that address clauses can cause order of
+ -- elaboration problems because they are elaborated by the
+ -- back-end at the point of definition, and may mention
+ -- entities declared in between (as long as everything is
+ -- static). It is user-friendly to allow unchecked conversions
+ -- in this context.
+
+ if Nkind (Original_Node (Nod)) = N_Function_Call then
+ Set_Etype (Expression (Nod),
+ Base_Type (Etype (Expression (Nod))));
+ Set_Etype (Nod, Base_Type (Etype (Nod)));
+ end if;
+
+ when N_Function_Call =>
+ if not Is_Pure (Entity (Name (Nod))) then
+ Error_Msg_NE
+ ("invalid address clause for initialized object &!",
+ Nod, U_Ent);
+
+ Error_Msg_NE
+ ("\function & is not pure (RM 13.1(22))!",
+ Nod, Entity (Name (Nod)));
+
+ else
+ Check_List_Constants (Parameter_Associations (Nod));
+ end if;
+
+ when N_Parameter_Association =>
+ Check_Expr_Constants (Explicit_Actual_Parameter (Nod));
+
+ when others =>
+ Error_Msg_NE
+ ("invalid address clause for initialized object &!",
+ Nod, U_Ent);
+ Error_Msg_NE
+ ("\must be constant defined before& (RM 13.1(22))!",
+ Nod, U_Ent);
+ end case;
+ end Check_Expr_Constants;
+
+ --------------------------
+ -- Check_List_Constants --
+ --------------------------
+
+ procedure Check_List_Constants (Lst : List_Id) is
+ Nod1 : Node_Id;
+
+ begin
+ if Present (Lst) then
+ Nod1 := First (Lst);
+ while Present (Nod1) loop
+ Check_Expr_Constants (Nod1);
+ Next (Nod1);
+ end loop;
+ end if;
+ end Check_List_Constants;
+
+ -- Start of processing for Check_Constant_Address_Clause
+
+ begin
+ -- If rep_clauses are to be ignored, no need for legality checks. In
+ -- particular, no need to pester user about rep clauses that violate
+ -- the rule on constant addresses, given that these clauses will be
+ -- removed by Freeze before they reach the back end.
+
+ if not Ignore_Rep_Clauses then
+ Check_Expr_Constants (Expr);
+ end if;
+ end Check_Constant_Address_Clause;
+
+ ----------------------------------------
+ -- Check_Record_Representation_Clause --
+ ----------------------------------------
+
+ procedure Check_Record_Representation_Clause (N : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (N);
+ Ident : constant Node_Id := Identifier (N);
+ Rectype : Entity_Id;
+ Fent : Entity_Id;
+ CC : Node_Id;
+ Fbit : Uint;
+ Lbit : Uint;
+ Hbit : Uint := Uint_0;
+ Comp : Entity_Id;
+ Pcomp : Entity_Id;
+
+ Max_Bit_So_Far : Uint;
+ -- Records the maximum bit position so far. If all field positions
+ -- are monotonically increasing, then we can skip the circuit for
+ -- checking for overlap, since no overlap is possible.
+
+ Tagged_Parent : Entity_Id := Empty;
+ -- This is set in the case of a derived tagged type for which we have
+ -- Is_Fully_Repped_Tagged_Type True (indicating that all components are
+ -- positioned by record representation clauses). In this case we must
+ -- check for overlap between components of this tagged type, and the
+ -- components of its parent. Tagged_Parent will point to this parent
+ -- type. For all other cases Tagged_Parent is left set to Empty.
+
+ Parent_Last_Bit : Uint;
+ -- Relevant only if Tagged_Parent is set, Parent_Last_Bit indicates the
+ -- last bit position for any field in the parent type. We only need to
+ -- check overlap for fields starting below this point.
+
+ Overlap_Check_Required : Boolean;
+ -- Used to keep track of whether or not an overlap check is required
+
+ Overlap_Detected : Boolean := False;
+ -- Set True if an overlap is detected
+
+ Ccount : Natural := 0;
+ -- Number of component clauses in record rep clause
+
+ procedure Check_Component_Overlap (C1_Ent, C2_Ent : Entity_Id);
+ -- Given two entities for record components or discriminants, checks
+ -- if they have overlapping component clauses and issues errors if so.
+
+ procedure Find_Component;
+ -- Finds component entity corresponding to current component clause (in
+ -- CC), and sets Comp to the entity, and Fbit/Lbit to the zero origin
+ -- start/stop bits for the field. If there is no matching component or
+ -- if the matching component does not have a component clause, then
+ -- that's an error and Comp is set to Empty, but no error message is
+ -- issued, since the message was already given. Comp is also set to
+ -- Empty if the current "component clause" is in fact a pragma.
+
+ -----------------------------
+ -- Check_Component_Overlap --
+ -----------------------------
+
+ procedure Check_Component_Overlap (C1_Ent, C2_Ent : Entity_Id) is
+ CC1 : constant Node_Id := Component_Clause (C1_Ent);
+ CC2 : constant Node_Id := Component_Clause (C2_Ent);
+
+ begin
+ if Present (CC1) and then Present (CC2) then
+
+ -- Exclude odd case where we have two tag fields in the same
+ -- record, both at location zero. This seems a bit strange, but
+ -- it seems to happen in some circumstances, perhaps on an error.
+
+ if Chars (C1_Ent) = Name_uTag
+ and then
+ Chars (C2_Ent) = Name_uTag
+ then
+ return;
+ end if;
+
+ -- Here we check if the two fields overlap
+
+ declare
+ S1 : constant Uint := Component_Bit_Offset (C1_Ent);
+ S2 : constant Uint := Component_Bit_Offset (C2_Ent);
+ E1 : constant Uint := S1 + Esize (C1_Ent);
+ E2 : constant Uint := S2 + Esize (C2_Ent);
+
+ begin
+ if E2 <= S1 or else E1 <= S2 then
+ null;
+ else
+ Error_Msg_Node_2 := Component_Name (CC2);
+ Error_Msg_Sloc := Sloc (Error_Msg_Node_2);
+ Error_Msg_Node_1 := Component_Name (CC1);
+ Error_Msg_N
+ ("component& overlaps & #", Component_Name (CC1));
+ Overlap_Detected := True;
+ end if;
+ end;
+ end if;
+ end Check_Component_Overlap;
+
+ --------------------
+ -- Find_Component --
+ --------------------
+
+ procedure Find_Component is
+
+ procedure Search_Component (R : Entity_Id);
+ -- Search components of R for a match. If found, Comp is set.
+
+ ----------------------
+ -- Search_Component --
+ ----------------------
+
+ procedure Search_Component (R : Entity_Id) is
+ begin
+ Comp := First_Component_Or_Discriminant (R);
+ while Present (Comp) loop
+
+ -- Ignore error of attribute name for component name (we
+ -- already gave an error message for this, so no need to
+ -- complain here)
+
+ if Nkind (Component_Name (CC)) = N_Attribute_Reference then
+ null;
+ else
+ exit when Chars (Comp) = Chars (Component_Name (CC));
+ end if;
+
+ Next_Component_Or_Discriminant (Comp);
+ end loop;
+ end Search_Component;
+
+ -- Start of processing for Find_Component
+
+ begin
+ -- Return with Comp set to Empty if we have a pragma
+
+ if Nkind (CC) = N_Pragma then
+ Comp := Empty;
+ return;
+ end if;
+
+ -- Search current record for matching component
+
+ Search_Component (Rectype);
+
+ -- If not found, maybe component of base type that is absent from
+ -- statically constrained first subtype.
+
+ if No (Comp) then
+ Search_Component (Base_Type (Rectype));
+ end if;
+
+ -- If no component, or the component does not reference the component
+ -- clause in question, then there was some previous error for which
+ -- we already gave a message, so just return with Comp Empty.
+
+ if No (Comp)
+ or else Component_Clause (Comp) /= CC
+ then
+ Comp := Empty;
+
+ -- Normal case where we have a component clause
+
+ else
+ Fbit := Component_Bit_Offset (Comp);
+ Lbit := Fbit + Esize (Comp) - 1;
+ end if;
+ end Find_Component;
+
+ -- Start of processing for Check_Record_Representation_Clause
+
+ begin
+ Find_Type (Ident);
+ Rectype := Entity (Ident);
+
+ if Rectype = Any_Type then
+ return;
+ else
+ Rectype := Underlying_Type (Rectype);
+ end if;
+
+ -- See if we have a fully repped derived tagged type
+
+ declare
+ PS : constant Entity_Id := Parent_Subtype (Rectype);
+
+ begin
+ if Present (PS) and then Is_Fully_Repped_Tagged_Type (PS) then
+ Tagged_Parent := PS;
+
+ -- Find maximum bit of any component of the parent type
+
+ Parent_Last_Bit := UI_From_Int (System_Address_Size - 1);
+ Pcomp := First_Entity (Tagged_Parent);
+ while Present (Pcomp) loop
+ if Ekind_In (Pcomp, E_Discriminant, E_Component) then
+ if Component_Bit_Offset (Pcomp) /= No_Uint
+ and then Known_Static_Esize (Pcomp)
+ then
+ Parent_Last_Bit :=
+ UI_Max
+ (Parent_Last_Bit,
+ Component_Bit_Offset (Pcomp) + Esize (Pcomp) - 1);
+ end if;
+
+ Next_Entity (Pcomp);
+ end if;
+ end loop;
+ end if;
+ end;
+
+ -- All done if no component clauses
+
+ CC := First (Component_Clauses (N));
+
+ if No (CC) then
+ return;
+ end if;
+
+ -- If a tag is present, then create a component clause that places it
+ -- at the start of the record (otherwise gigi may place it after other
+ -- fields that have rep clauses).
+
+ Fent := First_Entity (Rectype);
+
+ if Nkind (Fent) = N_Defining_Identifier
+ and then Chars (Fent) = Name_uTag
+ then
+ Set_Component_Bit_Offset (Fent, Uint_0);
+ Set_Normalized_Position (Fent, Uint_0);
+ Set_Normalized_First_Bit (Fent, Uint_0);
+ Set_Normalized_Position_Max (Fent, Uint_0);
+ Init_Esize (Fent, System_Address_Size);
+
+ Set_Component_Clause (Fent,
+ Make_Component_Clause (Loc,
+ Component_Name =>
+ Make_Identifier (Loc,
+ Chars => Name_uTag),
+
+ Position =>
+ Make_Integer_Literal (Loc,
+ Intval => Uint_0),
+
+ First_Bit =>
+ Make_Integer_Literal (Loc,
+ Intval => Uint_0),
+
+ Last_Bit =>
+ Make_Integer_Literal (Loc,
+ UI_From_Int (System_Address_Size))));
+
+ Ccount := Ccount + 1;
+ end if;
+
+ Max_Bit_So_Far := Uint_Minus_1;
+ Overlap_Check_Required := False;
+
+ -- Process the component clauses
+
+ while Present (CC) loop
+ Find_Component;
+
+ if Present (Comp) then
+ Ccount := Ccount + 1;
+
+ -- We need a full overlap check if record positions non-monotonic
+
+ if Fbit <= Max_Bit_So_Far then
+ Overlap_Check_Required := True;
+ end if;
+
+ Max_Bit_So_Far := Lbit;
+
+ -- Check bit position out of range of specified size
+
+ if Has_Size_Clause (Rectype)
+ and then Esize (Rectype) <= Lbit
+ then
+ Error_Msg_N
+ ("bit number out of range of specified size",
+ Last_Bit (CC));
+
+ -- Check for overlap with tag field
+
+ else
+ if Is_Tagged_Type (Rectype)
+ and then Fbit < System_Address_Size
+ then
+ Error_Msg_NE
+ ("component overlaps tag field of&",
+ Component_Name (CC), Rectype);
+ Overlap_Detected := True;
+ end if;
+
+ if Hbit < Lbit then
+ Hbit := Lbit;
+ end if;
+ end if;
+
+ -- Check parent overlap if component might overlap parent field
+
+ if Present (Tagged_Parent)
+ and then Fbit <= Parent_Last_Bit
+ then
+ Pcomp := First_Component_Or_Discriminant (Tagged_Parent);
+ while Present (Pcomp) loop
+ if not Is_Tag (Pcomp)
+ and then Chars (Pcomp) /= Name_uParent
+ then
+ Check_Component_Overlap (Comp, Pcomp);
+ end if;
+
+ Next_Component_Or_Discriminant (Pcomp);
+ end loop;
+ end if;
+ end if;
+
+ Next (CC);
+ end loop;
+
+ -- Now that we have processed all the component clauses, check for
+ -- overlap. We have to leave this till last, since the components can
+ -- appear in any arbitrary order in the representation clause.
+
+ -- We do not need this check if all specified ranges were monotonic,
+ -- as recorded by Overlap_Check_Required being False at this stage.
+
+ -- This first section checks if there are any overlapping entries at
+ -- all. It does this by sorting all entries and then seeing if there are
+ -- any overlaps. If there are none, then that is decisive, but if there
+ -- are overlaps, they may still be OK (they may result from fields in
+ -- different variants).
+
+ if Overlap_Check_Required then
+ Overlap_Check1 : declare
+
+ OC_Fbit : array (0 .. Ccount) of Uint;
+ -- First-bit values for component clauses, the value is the offset
+ -- of the first bit of the field from start of record. The zero
+ -- entry is for use in sorting.
+
+ OC_Lbit : array (0 .. Ccount) of Uint;
+ -- Last-bit values for component clauses, the value is the offset
+ -- of the last bit of the field from start of record. The zero
+ -- entry is for use in sorting.
+
+ OC_Count : Natural := 0;
+ -- Count of entries in OC_Fbit and OC_Lbit
+
+ function OC_Lt (Op1, Op2 : Natural) return Boolean;
+ -- Compare routine for Sort
+
+ procedure OC_Move (From : Natural; To : Natural);
+ -- Move routine for Sort
+
+ package Sorting is new GNAT.Heap_Sort_G (OC_Move, OC_Lt);
+
+ -----------
+ -- OC_Lt --
+ -----------
+
+ function OC_Lt (Op1, Op2 : Natural) return Boolean is
+ begin
+ return OC_Fbit (Op1) < OC_Fbit (Op2);
+ end OC_Lt;
+
+ -------------
+ -- OC_Move --
+ -------------
+
+ procedure OC_Move (From : Natural; To : Natural) is
+ begin
+ OC_Fbit (To) := OC_Fbit (From);
+ OC_Lbit (To) := OC_Lbit (From);
+ end OC_Move;
+
+ -- Start of processing for Overlap_Check
+
+ begin
+ CC := First (Component_Clauses (N));
+ while Present (CC) loop
+
+ -- Exclude component clause already marked in error
+
+ if not Error_Posted (CC) then
+ Find_Component;
+
+ if Present (Comp) then
+ OC_Count := OC_Count + 1;
+ OC_Fbit (OC_Count) := Fbit;
+ OC_Lbit (OC_Count) := Lbit;
+ end if;
+ end if;
+
+ Next (CC);
+ end loop;
+
+ Sorting.Sort (OC_Count);
+
+ Overlap_Check_Required := False;
+ for J in 1 .. OC_Count - 1 loop
+ if OC_Lbit (J) >= OC_Fbit (J + 1) then
+ Overlap_Check_Required := True;
+ exit;
+ end if;
+ end loop;
+ end Overlap_Check1;
+ end if;
+
+ -- If Overlap_Check_Required is still True, then we have to do the full
+ -- scale overlap check, since we have at least two fields that do
+ -- overlap, and we need to know if that is OK since they are in
+ -- different variant, or whether we have a definite problem.
+
+ if Overlap_Check_Required then
+ Overlap_Check2 : declare
+ C1_Ent, C2_Ent : Entity_Id;
+ -- Entities of components being checked for overlap
+
+ Clist : Node_Id;
+ -- Component_List node whose Component_Items are being checked
+
+ Citem : Node_Id;
+ -- Component declaration for component being checked
+
+ begin
+ C1_Ent := First_Entity (Base_Type (Rectype));
+
+ -- Loop through all components in record. For each component check
+ -- for overlap with any of the preceding elements on the component
+ -- list containing the component and also, if the component is in
+ -- a variant, check against components outside the case structure.
+ -- This latter test is repeated recursively up the variant tree.
+
+ Main_Component_Loop : while Present (C1_Ent) loop
+ if not Ekind_In (C1_Ent, E_Component, E_Discriminant) then
+ goto Continue_Main_Component_Loop;
+ end if;
+
+ -- Skip overlap check if entity has no declaration node. This
+ -- happens with discriminants in constrained derived types.
+ -- Possibly we are missing some checks as a result, but that
+ -- does not seem terribly serious.
+
+ if No (Declaration_Node (C1_Ent)) then
+ goto Continue_Main_Component_Loop;
+ end if;
+
+ Clist := Parent (List_Containing (Declaration_Node (C1_Ent)));
+
+ -- Loop through component lists that need checking. Check the
+ -- current component list and all lists in variants above us.
+
+ Component_List_Loop : loop
+
+ -- If derived type definition, go to full declaration
+ -- If at outer level, check discriminants if there are any.
+
+ if Nkind (Clist) = N_Derived_Type_Definition then
+ Clist := Parent (Clist);
+ end if;
+
+ -- Outer level of record definition, check discriminants
+
+ if Nkind_In (Clist, N_Full_Type_Declaration,
+ N_Private_Type_Declaration)
+ then
+ if Has_Discriminants (Defining_Identifier (Clist)) then
+ C2_Ent :=
+ First_Discriminant (Defining_Identifier (Clist));
+ while Present (C2_Ent) loop
+ exit when C1_Ent = C2_Ent;
+ Check_Component_Overlap (C1_Ent, C2_Ent);
+ Next_Discriminant (C2_Ent);
+ end loop;
+ end if;
+
+ -- Record extension case
+
+ elsif Nkind (Clist) = N_Derived_Type_Definition then
+ Clist := Empty;
+
+ -- Otherwise check one component list
+
+ else
+ Citem := First (Component_Items (Clist));
+ while Present (Citem) loop
+ if Nkind (Citem) = N_Component_Declaration then
+ C2_Ent := Defining_Identifier (Citem);
+ exit when C1_Ent = C2_Ent;
+ Check_Component_Overlap (C1_Ent, C2_Ent);
+ end if;
+
+ Next (Citem);
+ end loop;
+ end if;
+
+ -- Check for variants above us (the parent of the Clist can
+ -- be a variant, in which case its parent is a variant part,
+ -- and the parent of the variant part is a component list
+ -- whose components must all be checked against the current
+ -- component for overlap).
+
+ if Nkind (Parent (Clist)) = N_Variant then
+ Clist := Parent (Parent (Parent (Clist)));
+
+ -- Check for possible discriminant part in record, this
+ -- is treated essentially as another level in the
+ -- recursion. For this case the parent of the component
+ -- list is the record definition, and its parent is the
+ -- full type declaration containing the discriminant
+ -- specifications.