1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
|
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- L I B . X R E F . S P A R K _ S P E C I F I C --
-- --
-- B o d y --
-- --
-- Copyright (C) 2011-2024, 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 Einfo.Entities; use Einfo.Entities;
with Nmake; use Nmake;
with SPARK_Xrefs; use SPARK_Xrefs;
separate (Lib.Xref)
package body SPARK_Specific is
---------------------
-- Local Constants --
---------------------
-- Table of SPARK_Entities, True for each entity kind used in SPARK
SPARK_Entities : constant array (Entity_Kind) of Boolean :=
(E_Constant => True,
E_Entry => True,
E_Function => True,
E_In_Out_Parameter => True,
E_In_Parameter => True,
E_Loop_Parameter => True,
E_Operator => True,
E_Out_Parameter => True,
E_Procedure => True,
E_Variable => True,
others => False);
-- True for each reference type used in SPARK
SPARK_References : constant array (Character) of Boolean :=
('m' => True,
'r' => True,
's' => True,
others => False);
---------------------
-- Local Variables --
---------------------
package Drefs is new Table.Table (
Table_Component_Type => Xref_Entry,
Table_Index_Type => Xref_Entry_Number,
Table_Low_Bound => 1,
Table_Initial => Alloc.Drefs_Initial,
Table_Increment => Alloc.Drefs_Increment,
Table_Name => "Drefs");
-- Table of cross-references for reads and writes through explicit
-- dereferences, that are output as reads/writes to the special variable
-- "Heap". These references are added to the regular references when
-- computing SPARK cross-references.
-------------------------
-- Iterate_SPARK_Xrefs --
-------------------------
procedure Iterate_SPARK_Xrefs is
procedure Add_SPARK_Xref (Index : Int; Xref : Xref_Entry);
function Is_SPARK_Reference
(E : Entity_Id;
Typ : Character) return Boolean;
-- Return whether entity reference E meets SPARK requirements. Typ is
-- the reference type.
function Is_SPARK_Scope (E : Entity_Id) return Boolean;
-- Return whether the entity or reference scope meets requirements for
-- being a SPARK scope.
--------------------
-- Add_SPARK_Xref --
--------------------
procedure Add_SPARK_Xref (Index : Int; Xref : Xref_Entry) is
Ref : Xref_Key renames Xref.Key;
begin
-- Eliminate entries not appropriate for SPARK
if SPARK_Entities (Ekind (Ref.Ent))
and then SPARK_References (Ref.Typ)
and then Is_SPARK_Scope (Ref.Ent_Scope)
and then Is_SPARK_Scope (Ref.Ref_Scope)
and then Is_SPARK_Reference (Ref.Ent, Ref.Typ)
then
Process
(Index,
(Entity => Ref.Ent,
Ref_Scope => Ref.Ref_Scope,
Rtype => Ref.Typ));
end if;
end Add_SPARK_Xref;
------------------------
-- Is_SPARK_Reference --
------------------------
function Is_SPARK_Reference
(E : Entity_Id;
Typ : Character) return Boolean
is
begin
-- The only references of interest on callable entities are calls. On
-- uncallable entities, the only references of interest are reads and
-- writes.
if Ekind (E) in Overloadable_Kind then
return Typ = 's';
-- In all other cases, result is true for reference/modify cases,
-- and false for all other cases.
else
return Typ = 'r' or else Typ = 'm';
end if;
end Is_SPARK_Reference;
--------------------
-- Is_SPARK_Scope --
--------------------
function Is_SPARK_Scope (E : Entity_Id) return Boolean is
Can_Be_Renamed : constant Boolean :=
Present (E)
and then (Is_Subprogram_Or_Entry (E)
or else Ekind (E) = E_Package);
begin
return Present (E)
and then not Is_Generic_Unit (E)
and then (not Can_Be_Renamed or else No (Renamed_Entity (E)));
end Is_SPARK_Scope;
-- Start of processing for Add_SPARK_Xrefs
begin
-- Expose cross-references from private frontend tables to the backend
for Index in Drefs.First .. Drefs.Last loop
Add_SPARK_Xref (Index, Drefs.Table (Index));
end loop;
for Index in Xrefs.First .. Xrefs.Last loop
Add_SPARK_Xref (-Index, Xrefs.Table (Index));
end loop;
end Iterate_SPARK_Xrefs;
---------------------------------------------
-- Enclosing_Subprogram_Or_Library_Package --
---------------------------------------------
function Enclosing_Subprogram_Or_Library_Package
(N : Node_Id) return Entity_Id
is
Context : Entity_Id;
begin
-- If N is the defining identifier for a subprogram, then return the
-- enclosing subprogram or package, not this subprogram.
if Nkind (N) in N_Defining_Identifier | N_Defining_Operator_Symbol
and then Ekind (N) in Entry_Kind
| E_Subprogram_Body
| Generic_Subprogram_Kind
| Subprogram_Kind
then
if No (Unit_Declaration_Node (N)) then
return Empty;
end if;
Context := Parent (Unit_Declaration_Node (N));
-- If this was a library-level subprogram then replace Context with
-- its Unit, which points to N_Subprogram_* node.
if Nkind (Context) = N_Compilation_Unit then
Context := Unit (Context);
end if;
else
Context := N;
end if;
while Present (Context) loop
case Nkind (Context) is
when N_Package_Body
| N_Package_Specification
=>
-- Only return a library-level package
if Is_Library_Level_Entity (Defining_Entity (Context)) then
Context := Defining_Entity (Context);
exit;
else
Context := Parent (Context);
end if;
when N_Pragma =>
-- The enclosing subprogram for a precondition, postcondition,
-- or contract case should be the declaration preceding the
-- pragma (skipping any other pragmas between this pragma and
-- this declaration.
while Nkind (Context) = N_Pragma
and then Is_List_Member (Context)
and then Present (Prev (Context))
loop
Context := Prev (Context);
end loop;
if Nkind (Context) = N_Pragma then
-- When used for cross-references then aspects might not be
-- yet linked to pragmas; when used for AST navigation in
-- GNATprove this routine is expected to follow those links.
if From_Aspect_Specification (Context) then
Context := Corresponding_Aspect (Context);
pragma Assert (Nkind (Context) = N_Aspect_Specification);
Context := Entity (Context);
else
Context := Parent (Context);
end if;
end if;
when N_Entry_Body
| N_Entry_Declaration
| N_Protected_Type_Declaration
| N_Subprogram_Body
| N_Subprogram_Declaration
| N_Subprogram_Specification
| N_Task_Body
| N_Task_Type_Declaration
=>
Context := Defining_Entity (Context);
exit;
when others =>
Context := Parent (Context);
end case;
end loop;
if Nkind (Context) = N_Defining_Program_Unit_Name then
Context := Defining_Identifier (Context);
end if;
-- Do not return a scope without a proper location
if Present (Context)
and then Sloc (Context) = No_Location
then
return Empty;
end if;
return Context;
end Enclosing_Subprogram_Or_Library_Package;
--------------------------
-- Generate_Dereference --
--------------------------
procedure Generate_Dereference
(N : Node_Id;
Typ : Character := 'r')
is
procedure Create_Heap;
-- Create and decorate the special entity which denotes the heap
-----------------
-- Create_Heap --
-----------------
procedure Create_Heap is
begin
Heap :=
Make_Defining_Identifier
(Standard_Location,
Name_Enter (Name_Of_Heap_Variable));
Mutate_Ekind (Heap, E_Variable);
Set_Is_Internal (Heap, True);
Set_Etype (Heap, Standard_Void_Type);
Set_Scope (Heap, Standard_Standard);
Set_Has_Fully_Qualified_Name (Heap);
end Create_Heap;
-- Local variables
Loc : constant Source_Ptr := Sloc (N);
-- Start of processing for Generate_Dereference
begin
if Loc > No_Location then
Drefs.Increment_Last;
declare
Deref_Entry : Xref_Entry renames Drefs.Table (Drefs.Last);
Deref : Xref_Key renames Deref_Entry.Key;
begin
if No (Heap) then
Create_Heap;
end if;
Deref.Ent := Heap;
Deref.Loc := Loc;
Deref.Typ := Typ;
-- It is as if the special "Heap" was defined in the main unit,
-- in the scope of the entity for the main unit. This single
-- definition point is required to ensure that sorting cross
-- references works for "Heap" references as well.
Deref.Eun := Main_Unit;
Deref.Lun := Get_Top_Level_Code_Unit (Loc);
Deref.Ref_Scope := Enclosing_Subprogram_Or_Library_Package (N);
Deref.Ent_Scope := Cunit_Entity (Main_Unit);
Deref_Entry.Def := No_Location;
Deref_Entry.Ent_Scope_File := Main_Unit;
end;
end if;
end Generate_Dereference;
end SPARK_Specific;
|