50
54
Framework.Language,
51
56
Framework.Rules_Manager,
53
59
pragma Elaborate (Framework.Language);
55
61
package body Rules.Representation_Clauses is
56
62
use Framework, Ada.Strings.Wide_Unbounded, Utilities;
58
type Clause_Names is (Cl_Attribute, Cl_At, CL_At_Mod, Cl_Enumeration, Cl_Record);
60
package Clause_Flags_Utilities is new Framework.Language.Flag_Utilities (Clause_Names, "CL_");
61
use Clause_Flags_Utilities;
64
Storage_Unit : Thick_Queries.Biggest_Int;
66
type Subrules is (Sr_Attribute,
67
Sr_At, Sr_At_Mod, Sr_Enumeration, Sr_Record,
68
Sr_Fractional_Size, Sr_Incomplete_Record, Sr_Non_Contiguous_Record);
70
package Subrules_Flags_Utilities is new Framework.Language.Flag_Utilities (Subrules, "SR_");
71
use Subrules_Flags_Utilities;
64
74
package Context_Map is new Binary_Map (Unbounded_Wide_String, Unbounded_Wide_String);
67
Usage : array (Rule_Types) of Context_Map.Map;
68
Rule_Used : Boolean := False;
70
Key : array (Clause_Names range Clause_Names'Succ (Cl_Attribute) .. Clause_Names'Last)
71
of Unbounded_Wide_String;
77
Usage : array (Control_Kinds) of Context_Map.Map;
79
type Usage_Flags is array (Subrules) of Boolean;
80
Not_Used : constant Usage_Flags := (others => False);
81
Rule_Used : Usage_Flags := Not_Used;
82
Save_Used : Usage_Flags;
83
Key : array (Subrules range Subrules'Succ (Sr_Attribute) .. Subrules'Last) of Unbounded_Wide_String;
72
84
Key_All : constant Unbounded_Wide_String := To_Unbounded_Wide_String ("all");
98
110
User_Message ("Control occurrences of representation clauses");
105
procedure Add_Use (Label : in Wide_String;
106
Rule_Type : in Rule_Types) is
117
procedure Add_Control (Ctl_Label : in Wide_String; Ctl_Kind : in Control_Kinds) is
107
118
use Framework.Language;
108
Clause : Clause_Names;
109
Param : Unbounded_Wide_String;
120
Param : Unbounded_Wide_String;
112
123
if Parameter_Exists then
113
if Is_Present (Usage (Rule_Type), Key_All) then
124
if Is_Present (Usage (Ctl_Kind), Key_All) then
114
125
Parameter_Error (Rule_Id, "rule already specified for all representation clauses");
117
if not Is_Empty (Usage (Rule_Type)) then
128
if not Is_Empty (Usage (Ctl_Kind)) then
118
129
Parameter_Error (Rule_Id, "some representation clauses already specified");
120
Add (Usage (Rule_Type), Key_All, To_Unbounded_Wide_String (Label));
131
Add (Usage (Ctl_Kind), Key_All, To_Unbounded_Wide_String (Ctl_Label));
132
Rule_Used := (others => True);
123
135
while Parameter_Exists loop
124
Clause := Get_Flag_Parameter (Allow_Any => True);
125
if Clause = Cl_Attribute then
126
Param := To_Unbounded_Wide_String (To_Upper (Get_String_Parameter));
136
Subrule := Get_Flag_Parameter (Allow_Any => True);
137
if Subrule = Sr_Attribute then
138
Param := To_Unbounded_Wide_String (Get_Name_Parameter);
127
139
if Element (Param, 1) /= ''' then
128
140
Parameter_Error (Rule_Id, "parameter must be at, at_mod, enumeration, record, or an attribute");
131
Param := To_Unbounded_Wide_String (Clause_Names'Wide_Image (Clause));
143
Param := To_Unbounded_Wide_String (Subrules'Wide_Image (Subrule));
134
if Is_Present (Usage (Rule_Type), Param) then
146
if Is_Present (Usage (Ctl_Kind), Param) then
135
147
Parameter_Error (Rule_Id, "clause already given: " & Proper_Key (Param));
138
Add (Usage (Rule_Type), Param, To_Unbounded_Wide_String (Label));
150
Add (Usage (Ctl_Kind), Param, To_Unbounded_Wide_String (Ctl_Label));
151
Rule_Used (Subrule) := True;
157
169
Save_Used := Rule_Used;
170
Rule_Used := Not_Used;
160
172
Rule_Used := Save_Used;
181
use Asis.Declarations;
182
use Framework.Queries, Thick_Queries;
184
if Rule_Used = Not_Used then
188
Storage_Unit := Discrete_Static_Expression_Value (Initialization_Expression (System_Value ("STORAGE_UNIT")));
164
192
--------------------
165
193
-- Process_Clause --
166
194
--------------------
168
procedure Process_Clause (Element : in Asis.Representation_Clause) is
169
use Asis, Asis.Clauses, Asis.Elements, Asis.Expressions, Framework.Reports, Thick_Queries;
196
procedure Process_Clause (Rep_Clause : in Asis.Representation_Clause) is
197
use Asis, Asis.Clauses, Asis.Elements, Asis.Expressions, Thick_Queries;
198
use Framework.Reports;
170
200
Attribute : Unbounded_Wide_String;
172
procedure Check_Usage (Clause : Clause_Names; Message : Wide_String) is
202
procedure Check_Usage (Clause : Subrules;
203
Message : Wide_String;
204
Loc : Location := Get_Location (Rep_Clause))
173
206
Key_Map : Unbounded_Wide_String;
175
if Clause = Cl_Attribute then
208
if Clause = Sr_Attribute then
176
209
Key_Map := Attribute;
178
211
Key_Map := Key (Clause);
211
244
To_Wide_String (Fetch (Usage (Count), Key_Map)),
213
Get_Location (Element),
215
248
elsif Is_Present (Usage (Count), Key_All) then
217
250
To_Wide_String (Fetch (Usage (Count), Key_All)),
219
Get_Location (Element),
257
procedure Check_Incomplete (Clause : Asis.Representation_Clause) is
258
use Asis.Declarations;
259
use Framework.String_Set;
261
Components : constant Asis.Component_Clause_List := Component_Clauses (Clause);
264
procedure Pre_Procedure (Element : in Asis.Element;
265
Control : in out Asis.Traverse_Control;
266
State : in out Null_State)
268
pragma Unreferenced (Control, State);
270
if Element_Kind (Element) = A_Defining_Name then
271
if not Is_Present (Compo_Set, To_Upper (Defining_Name_Image (Element))) then
272
Check_Usage (Sr_Incomplete_Record,
273
"no component clause for "
274
& Defining_Name_Image (Element)
276
& Image (Get_Location (Element)));
281
procedure Traverse_Type is new Asis.Iterator.Traverse_Element (Null_State,
283
Null_State_Procedure);
284
Control : Asis.Traverse_Control := Continue;
286
Decl : constant Asis.Declaration
287
:= Corresponding_Name_Declaration (Representation_Clause_Name (Clause));
289
for C in Components'Range loop
290
Add (Compo_Set, To_Upper (A4G_Bugs.Name_Image (Representation_Clause_Name (Components (C)))));
293
if not Is_Nil (Discriminant_Part (Decl)) then
294
Traverse_Type (Discriminant_Part (Decl), Control, State);
297
Traverse_Type (Type_Declaration_View (Decl), Control, State);
300
end Check_Incomplete;
302
procedure Check_Contiguous (Clause : Asis.Representation_Clause) is
303
use Asis.Definitions;
305
type Field_Descriptor is
307
Low, High : Biggest_Int;
308
Compo_Inx : Asis.List_Index;
311
Components : constant Asis.Component_Clause_List := Component_Clauses (Clause);
312
Fields : array (Components'Range) of Field_Descriptor;
313
Used_F : ASIS_Natural := Fields'First - 1;
314
Size_Expr : Asis.Expression;
315
Is_Uncheck : Boolean := False;
316
Starting_Unit : Biggest_Int;
318
for C in Components'Range loop
320
Pos : constant Extended_Biggest_Natural
321
:= Discrete_Static_Expression_Value (Component_Clause_Position (Components (C)));
323
R : constant Asis.Discrete_Range := Component_Clause_Range (Components (C));
324
L : constant Extended_Biggest_Natural := Discrete_Static_Expression_Value (Lower_Bound (R));
325
H : constant Extended_Biggest_Natural := Discrete_Static_Expression_Value (Upper_Bound (R));
326
F : Field_Descriptor;
327
Ins : Asis.List_Index;
329
if Pos = Not_Static or L = Not_Static or H = Not_Static then
330
Uncheckable (Rule_Id,
332
Get_Location (Components (C)),
333
"unable to evaluate component position for non_contiguous_record subrule");
336
P := Pos * Storage_Unit;
341
-- Insert F at the right place
342
-- Since it is highly likely that clauses are given in order, start
345
for I in reverse List_Index range Fields'First .. Used_F loop
346
pragma Warnings (Off);
347
-- Gnat warns that "Fields" may be referenced before it has a value
348
-- but this cannot happen since the loop is bounded by Used_F
349
if Fields (I).Low < F.Low then
353
pragma Warnings (On);
354
Fields (I + 1) := Fields (I);
357
if Ins /= Fields'First
358
and then Fields (Ins - 1).High > Fields (Ins).High
360
Fields (Ins).High := Fields (Ins - 1).High;
362
Used_F := Used_F + 1;
370
if Fields (Fields'First).Low /= 0 then
371
Check_Usage (Sr_Non_Contiguous_Record,
372
"gap at 0 range 0.." & Biggest_Int_Img(Fields (Fields'First).Low-1),
373
Get_Location (Components (Fields(Fields'First).Compo_Inx)));
375
for I in List_Index range Fields'First+1 .. Fields'Last loop
376
if Fields (I - 1).High + 1 < Fields (I).Low then
377
Starting_Unit := (Fields (I - 1).High + 1) / Storage_Unit;
378
Check_Usage (Sr_Non_Contiguous_Record,
379
"gap before component, at "
380
& Biggest_Int_Img (Starting_Unit)
382
& Biggest_Int_Img (Fields (I - 1).High + 1 - Starting_Unit * Storage_Unit)
384
& Biggest_Int_Img (Fields (I).Low - 1 - Starting_Unit * Storage_Unit),
385
Get_Location (Components (Fields (I).Compo_Inx)));
389
-- Check gap at the end if size clause given
390
Size_Expr := Attribute_Clause_Expression (A_Size_Attribute, Representation_Clause_Name (Clause));
391
if Is_Nil (Size_Expr) then
395
S : constant Extended_Biggest_Natural := Discrete_Static_Expression_Value (Size_Expr);
397
if S = Not_Static then
398
Uncheckable (Rule_Id,
400
Get_Location (Clause),
401
"unable to evaluate size of "
402
& A4G_Bugs.Name_Image (Representation_Clause_Name (Clause))
403
& "for non_contiguous_record subrule");
407
if Fields (Fields'Last).High /= S - 1 then
408
Starting_Unit := (Fields (Fields'Last).High + 1) / Storage_Unit;
409
Check_Usage (Sr_Non_Contiguous_Record,
410
"gap at end of record, at "
411
& Biggest_Int_Img (Starting_Unit)
413
& Biggest_Int_Img (Fields (Fields'Last).High + 1 - Starting_Unit * Storage_Unit)
415
& Biggest_Int_Img (S - 1 - Starting_Unit * Storage_Unit)
416
& ", size clause line " & Integer_Img (Get_First_Line (Get_Location (Size_Expr))),
417
Get_Location (Components (Fields (Fields'Last).Compo_Inx)));
420
end Check_Contiguous;
224
422
begin -- Process_Clause
225
if not Rule_Used then
423
if Rule_Used = Not_Used then
228
426
Rules_Manager.Enter (Rule_Id);
230
case Representation_Clause_Kind (Element) is
428
case Representation_Clause_Kind (Rep_Clause) is
231
429
when Not_A_Representation_Clause =>
232
430
Failure ("Not a representation clause in " & Rule_Id);
234
432
when An_Attribute_Definition_Clause =>
433
if not Rule_Used (Sr_Attribute) and not Rule_Used (Sr_Fractional_Size) then
235
437
Attribute := To_Unbounded_Wide_String (''' & To_Upper (Attribute_Name_Image
236
(Representation_Clause_Name (Element))));
237
if Expression_Kind (Prefix (Representation_Clause_Name (Element))) = An_Attribute_Reference then
438
(Representation_Clause_Name (Rep_Clause))));
439
if Expression_Kind (Prefix (Representation_Clause_Name (Rep_Clause))) = An_Attribute_Reference then
238
440
-- This happens only in for T'Class'Read and similar
257
459
when An_Output_Attribute =>
258
460
Attribute := To_Unbounded_Wide_String ("'CLASS'OUTPUT");
260
Failure ("Unexpected double attribute in " & Rule_Id, Element);
462
Failure ("Unexpected double attribute in " & Rule_Id, Rep_Clause);
264
Check_Usage (Cl_Attribute, "use of representation clause for " & To_Wide_String (Attribute));
466
Check_Usage (Sr_Attribute, "use of representation clause for " & To_Wide_String (Attribute));
468
if Attribute = "'SIZE" and then Rule_Used (Sr_Fractional_Size) then
470
Value : constant Extended_Biggest_Natural
471
:= Discrete_Static_Expression_Value (Representation_Clause_Expression (Rep_Clause));
473
if Value = Not_Static then
474
Uncheckable (Rule_Id,
476
Get_Location (Representation_Clause_Expression (Rep_Clause)),
477
"unable to evaluate size for fractional_size subrule");
478
elsif Value rem Storage_Unit /= 0 then
479
Check_Usage (Sr_Fractional_Size, "size clause not multiple of Storage_Unit");
266
484
when An_Enumeration_Representation_Clause =>
267
Check_Usage (Cl_Enumeration, "use of enumeration representation clause");
485
Check_Usage (Sr_Enumeration, "use of enumeration representation clause");
269
487
when A_Record_Representation_Clause =>
270
Check_Usage (Cl_Record, "use of record representation clause");
272
if not Is_Nil (Mod_Clause_Expression (Element)) then
273
Check_Usage (CL_At_Mod, "use of Ada 83 alignment clause");
488
Check_Usage (Sr_Record, "use of record representation clause");
490
if Rule_Used (Sr_At_Mod) and then not Is_Nil (Mod_Clause_Expression (Rep_Clause)) then
491
Check_Usage (Sr_At_Mod, "use of Ada 83 alignment clause");
494
if Rule_Used (Sr_Incomplete_Record) then
495
Check_Incomplete (Rep_Clause);
498
if Rule_Used (Sr_Non_Contiguous_Record) then
499
Check_Contiguous (Rep_Clause);
276
502
when An_At_Clause =>
277
Check_Usage (Cl_At, "use of Ada 83 address clause");
503
Check_Usage (Sr_At, "use of Ada 83 address clause");
279
505
end Process_Clause;
282
for K in Clause_Names range Clause_Names'Succ (Cl_Attribute) .. Clause_Names'Last loop
283
Key (K) := To_Unbounded_Wide_String (Clause_Names'Wide_Image (K));
508
for K in Subrules range Subrules'Succ (Sr_Attribute) .. Subrules'Last loop
509
Key (K) := To_Unbounded_Wide_String (Subrules'Wide_Image (K));
286
Framework.Rules_Manager.Register_Semantic (Rule_Id,
288
Add_Use => Add_Use'Access,
289
Command => Command'Access);
512
Framework.Rules_Manager.Register (Rule_Id,
513
Rules_Manager.Semantic,
514
Help_CB => Help'Access,
515
Add_Control_CB => Add_Control'Access,
516
Command_CB => Command'Access,
517
Prepare_CB => Prepare'Access);
290
518
end Rules.Representation_Clauses;