aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/sem.ads
blob: 3a19088d10e9efdd73c89f0f34340f415fbb9546 (plain)
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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                                  S E M                                   --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--          Copyright (C) 1992-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.      --
--                                                                          --
------------------------------------------------------------------------------

--------------------------------------
-- Semantic Analysis: General Model --
--------------------------------------

--  Semantic processing involves 3 phases which are highly intertwined
--  (i.e. mutually recursive):

--    Analysis     implements the bulk of semantic analysis such as
--                 name analysis and type resolution for declarations,
--                 statements, and expressions. The main routine
--                 driving this process is procedure Analyze given below.
--                 This analysis phase is really a bottom up pass that is
--                 achieved during the recursive traversal performed by the
--                 Analyze_... procedures implemented in the sem_* packages.
--                 For expressions this phase determines unambiguous types
--                 and collects sets of possible types where the
--                 interpretation is potentially ambiguous.

--    Resolution   is carried out only for expressions to finish type
--                 resolution that was initiated but not necessarily
--                 completed during analysis (because of overloading
--                 ambiguities). Specifically, after completing the bottom
--                 up pass carried out during analysis for expressions, the
--                 Resolve routine (see the spec of Sem_Res for more info)
--                 is called to perform a top down resolution with
--                 recursive calls to itself to resolve operands.

--    Expansion    If we are not generating code this phase is a no-op.
--                 Otherwise this phase expands, i.e. transforms, original
--                 source constructs into simpler constructs that can be
--                 handled by the back-end. This phase is also in charge of
--                 generating code which is implicit in the original source
--                 (for instance for default initializations, controlled types,
--                 etc.)  There are two separate instances where expansion is
--                 invoked. For declarations and instructions, expansion is
--                 invoked just after analysis since no resolution needs to be
--                 performed. For expressions, expansion is done just after
--                 resolution. In both cases expansion is done from the bottom
--                 up just before the end of Analyze for instructions and
--                 declarations or the call to Resolve for expressions.  The
--                 main routine driving expansion is Expand.  See the spec of
--                 Expander for more details.

--  To summarize, in normal code generation mode we recursively traverse the
--  abstract syntax tree top-down performing semantic analysis bottom
--  up. For instructions and declarations, before the call to the Analyze
--  routine completes we perform expansion since at that point we have all
--  semantic information needed. For expression nodes, after the call to
--  Analyze terminates we invoke the Resolve routine to transmit top-down
--  the type that was gathered by Analyze which will resolve possible
--  ambiguities in the expression. Just before the call to Resolve
--  terminates, the expression can be expanded since all the semantic
--  information is available at that point.

--  If we are not generating code then the expansion phase is a no-op

--  When generating code there are a number of exceptions to the basic
--  Analysis-Resolution-Expansion model for expressions. The most prominent
--  examples are the handling of default expressions and aggregates.

-----------------------------------------------------------------------
-- Handling of Default and Per-Object Expressions (Spec-Expressions) --
-----------------------------------------------------------------------

--  The default expressions in component declarations and in procedure
--  specifications (but not the ones in object declarations) are quite tricky
--  to handle. The problem is that some processing is required at the point
--  where the expression appears:

--    visibility analysis (including user defined operators)
--    freezing of static expressions

--  but other processing must be deferred until the enclosing entity (record or
--  procedure specification) is frozen:

--    freezing of any other types in the expression expansion
--    generation of code

--  A similar situation occurs with the argument of priority and interrupt
--  priority pragmas that appear in task and protected definition specs and
--  other cases of per-object expressions (see RM 3.8(18)).

--  Another similar case is the conditions in precondition and postcondition
--  pragmas that appear with subprogram specifications rather than in the body.

--  Collectively we call these Spec_Expressions. The routine that performs the
--  special analysis is called Preanalyze_Spec_Expression.

--  Expansion has to be deferred since you can't generate code for expressions
--  that reference types that have not been frozen yet. As an example, consider
--  the following:

--      type x is delta 0.5 range -10.0 .. +10.0;
--      ...
--      type q is record
--        xx : x := y * z;
--      end record;

--      for x'small use 0.25;

--  The expander is in charge of dealing with fixed-point, and of course the
--  small declaration, which is not too late, since the declaration of type q
--  does *not* freeze type x, definitely affects the expanded code.

--  Another reason that we cannot expand early is that expansion can generate
--  range checks. These range checks need to be inserted not at the point of
--  definition but at the point of use. The whole point here is that the value
--  of the expression cannot be obtained at the point of declaration, only at
--  the point of use.

--  Generally our model is to combine analysis, resolution, and expansion, but
--  this is the one case where this model falls down. Here is how we patch
--  it up without causing too much distortion to our basic model.

--  A flag (In_Spec_Expression) is set to show that we are in the initial
--  occurrence of a default expression. The analyzer is then called on this
--  expression with the switch set true. Analysis and resolution proceed almost
--  as usual, except that Freeze_Expression will not freeze non-static
--  expressions if this switch is set, and the call to Expand at the end of
--  resolution is skipped. This also skips the code that normally sets the
--  Analyzed flag to True. The result is that when we are done the tree is
--  still marked as unanalyzed, but all types for static expressions are frozen
--  as required, and all entities of variables have been recorded. We then turn
--  off the switch, and later on reanalyze the expression with the switch off.
--  The effect is that this second analysis freezes the rest of the types as
--  required, and generates code but visibility analysis is not repeated since
--  all the entities are marked.

--  The second analysis (the one that generates code) is in the context
--  where the code is required. For a record field default, this is in the
--  initialization procedure for the record and for a subprogram default
--  parameter, it is at the point the subprogram is frozen. For a priority or
--  storage size pragma it is in the context of the Init_Proc for the task or
--  protected object. For a pre/postcondition pragma it is in the body when
--  code for the pragma is generated.

------------------
-- Preanalysis --
------------------

--  For certain kind of expressions, such as aggregates, we need to defer
--  expansion of the aggregate and its inner expressions until after the whole
--  set of expressions appearing inside the aggregate have been analyzed.
--  Consider, for instance the following example:
--
--     (1 .. 100 => new Thing (Function_Call))
--
--  The normal Analysis-Resolution-Expansion mechanism where expansion of the
--  children is performed before expansion of the parent does not work if the
--  code generated for the children by the expander needs to be evaluated
--  repeatedly (for instance in the above aggregate "new Thing (Function_Call)"
--  needs to be called 100 times).

--  The reason this mechanism does not work is that the expanded code for the
--  children is typically inserted above the parent and thus when the parent
--  gets expanded no re-evaluation takes place. For instance in the case of
--  aggregates if "new Thing (Function_Call)" is expanded before the aggregate
--  the expanded code will be placed outside of the aggregate and when
--  expanding the aggregate the loop from 1 to 100 will not surround the
--  expanded code for "new Thing (Function_Call)".

--  To remedy this situation we introduce a flag that signals whether we want a
--  full analysis (i.e. expansion is enabled) or a preanalysis which performs
--  Analysis and Resolution but no expansion.

--  After the complete preanalysis of an expression has been carried out we
--  can transform the expression and then carry out the full three stage
--  (Analyze-Resolve-Expand) cycle on the transformed expression top-down so
--  that the expansion of inner expressions happens inside the newly generated
--  node for the parent expression.

--  Note that the difference between processing of default expressions and
--  preanalysis of other expressions is that we do carry out freezing in
--  the latter but not in the former (except for static scalar expressions).
--  The routine that performs preanalysis and corresponding resolution is
--  called Preanalyze_And_Resolve and is in Sem_Res.

with Alloc;
with Einfo.Entities; use Einfo.Entities;
with Opt;    use Opt;
with Table;
with Types;  use Types;

package Sem is

   -----------------------------
   -- Semantic Analysis Flags --
   -----------------------------

   Full_Analysis : Boolean := True;
   --  Switch to indicate if we are doing a full analysis or a preanalysis.
   --  In normal analysis mode (Analysis-Expansion for instructions or
   --  declarations) or (Analysis-Resolution-Expansion for expressions) this
   --  flag is set. Note that if we are not generating code the expansion phase
   --  merely sets the Analyzed flag to True in this case. If we are in
   --  Preanalysis mode (see above) this flag is set to False then the
   --  expansion phase is skipped.
   --
   --  When this flag is False the flag Expander_Active is also False (the
   --  Expander_Active flag defined in the spec of package Expander tells you
   --  whether expansion is currently enabled). You should really regard this
   --  as a read only flag.

   In_Spec_Expression : Boolean := False;
   --  Switch to indicate that we are in a spec-expression, as described
   --  above. Note that this must be recursively saved on a Semantics call
   --  since it is possible for the analysis of an expression to result in a
   --  recursive call (e.g. to get the entity for System.Address as part of the
   --  processing of an Address attribute reference). When this switch is True
   --  then Full_Analysis above must be False. You should really regard this as
   --  a read only flag.

   In_Deleted_Code : Boolean := False;
   --  If the condition in an if-statement is statically known, the branch
   --  that is not taken is analyzed with expansion disabled, and the tree
   --  is deleted after analysis. Itypes generated in deleted code must be
   --  frozen from start, because the tree on which they depend will not
   --  be available at the freeze point.

   In_Assertion_Expr : Nat := 0;
   --  This is set non-zero if we are within the expression of an assertion
   --  pragma or aspect. It is incremented at the start of expanding such an
   --  expression, and decremented on completion of expanding that
   --  expression. This needs to be a counter, rather than a Boolean, because
   --  assertions can contain declare_expressions, which can contain
   --  assertions. As with In_Spec_Expression, it must be recursively saved and
   --  restored for a Semantics call.

   In_Declare_Expr : Nat := 0;
   --  This is set non-zero if we are within a declare_expression. It is
   --  incremented at the start of expanding such an expression, and
   --  decremented on completion of expanding that expression. This needs to be
   --  a counter, rather than a Boolean, because declare_expressions can
   --  nest. As with In_Spec_Expression, it must be recursively saved and
   --  restored for a Semantics call.

   In_Compile_Time_Warning_Or_Error : Boolean := False;
   --  Switch to indicate that we are validating a pragma Compile_Time_Warning
   --  or Compile_Time_Error after the back end has been called (to check these
   --  pragmas for size and alignment appropriateness).

   In_Default_Expr : Boolean := False;
   --  Switch to indicate that we are analyzing a default component expression.
   --  As with In_Spec_Expression, it must be recursively saved and restored
   --  for a Semantics call.

   In_Inlined_Body : Boolean := False;
   --  Switch to indicate that we are analyzing and resolving an inlined body.
   --  Type checking is disabled in this context, because types are known to be
   --  compatible. This avoids problems with private types whose full view is
   --  derived from private types.

   Inside_A_Generic : Boolean := False;
   --  This flag is set if we are processing a generic specification, generic
   --  definition, or generic body. When this flag is True the Expander_Active
   --  flag is False to disable any code expansion (see package Expander). Only
   --  the generic processing can modify the status of this flag, any other
   --  client should regard it as read-only.

   Inside_Freezing_Actions : Nat := 0;
   --  Flag indicating whether we are within a call to Expand_N_Freeze_Actions.
   --  Non-zero means we are inside (it is actually a level counter to deal
   --  with nested calls). Used to avoid traversing the tree each time a
   --  subprogram call is processed to know if we must not clear all constant
   --  indications from entities in the current scope. Only the expansion of
   --  freezing nodes can modify the status of this flag, any other client
   --  should regard it as read-only.

   Inside_Class_Condition_Preanalysis : Boolean := False;
   --  Flag indicating whether we are preanalyzing a class-wide precondition
   --  or postcondition.

   Inside_Preanalysis_Without_Freezing : Nat := 0;
   --  Flag indicating whether we are preanalyzing an expression performing no
   --  freezing. Non-zero means we are inside (it is actually a level counter
   --  to deal with nested calls).

   Unloaded_Subunits : Boolean := False;
   --  This flag is set True if we have subunits that are not loaded. This
   --  occurs when the main unit is a subunit, and contains lower level
   --  subunits that are not loaded. We use this flag to suppress warnings
   --  about unused variables, since these warnings are unreliable in this
   --  case. We could perhaps do a more accurate job and retain some of the
   --  warnings, but it is quite a tricky job.

   -----------------------------------
   -- Handling of Check Suppression --
   -----------------------------------

   --  There are two kinds of suppress checks: scope based suppress checks,
   --  and entity based suppress checks.

   --  Scope based suppress checks for the predefined checks (from initial
   --  command line arguments, or from Suppress pragmas not including an entity
   --  name) are recorded in the Sem.Scope_Suppress variable, and all that
   --  is necessary is to save the state of this variable on scope entry, and
   --  restore it on scope exit. This mechanism allows for fast checking of the
   --  scope suppress state without needing complex data structures.

   --  Entity based checks, from Suppress/Unsuppress pragmas giving an
   --  Entity_Id and scope based checks for non-predefined checks (introduced
   --  using pragma Check_Name), are handled as follows. If a suppress or
   --  unsuppress pragma is encountered for a given entity, then the flag
   --  Checks_May_Be_Suppressed is set in the entity and an entry is made in
   --  either the local suppress stack (case of pragma that appears in
   --  other than a package spec), or in the global suppress stack (case
   --  of pragma that appears in a package spec, which is by the rule of RM
   --  11.5(7) applicable throughout the life of the entity). Similarly, a
   --  Suppress/Unsuppress pragma for a non-predefined check which does not
   --  specify an entity is also stored in one of these stacks.

   --  If the Checks_May_Be_Suppressed flag is set in an entity then the
   --  procedure is to search first the local and then the global suppress
   --  stacks (we search these in reverse order, top element first). The only
   --  other point is that we have to make sure that we have proper nested
   --  interaction between such specific pragmas and locally applied general
   --  pragmas applying to all entities. This is achieved by including in the
   --  local suppress stack dummy entries with an empty Entity field
   --  that are applicable to all entities. A similar search is needed for any
   --  non-predefined check even if no specific entity is involved.

   Scope_Suppress : Suppress_Record;
   --  This variable contains the current scope based settings of the suppress
   --  switches. It is initialized from Suppress_Options in Gnat1drv, and then
   --  modified by pragma Suppress. On entry to each scope, the current setting
   --  is saved on the scope stack, and then restored on exit from the scope.
   --  This record may be rapidly checked to determine the current status of
   --  a check if no specific entity is involved or if the specific entity
   --  involved is one for which no specific Suppress/Unsuppress pragma has
   --  been set (as indicated by the Checks_May_Be_Suppressed flag being set).

   --  This scheme is a little complex, but serves the purpose of enabling
   --  a very rapid check in the common case where no entity specific pragma
   --  applies, and gives the right result when such pragmas are used even
   --  in complex cases of nested Suppress and Unsuppress pragmas.

   --  The local and global suppress stacks are handled using dynamic
   --  allocation and linked lists. We do not often use this approach in the
   --  compiler (preferring to use extensible tables instead). The reason we do
   --  it here is that scope stack entries save a pointer to the current local
   --  stack top, which is also saved and restored on scope exit. Furthermore
   --  for processing of generics we save pointers to the top of the stack, so
   --  that the local stack is actually a tree of stacks rather than a single
   --  stack, a structure that is easy to represent using linked lists, but
   --  impossible to represent using a single table. Note that because of the
   --  generic issue, we never release entries in these stacks, but that's no
   --  big deal, since we are unlikely to have a huge number of
   --  Suppress/Unsuppress entries in a single compilation.

   type Suppress_Stack_Entry;
   type Suppress_Stack_Entry_Ptr is access all Suppress_Stack_Entry;

   type Suppress_Stack_Entry is record
      Entity : Entity_Id;
      --  Entity to which the check applies, or Empty for a check that has
      --  no entity name (and thus applies to all entities).

      Check : Check_Id;
      --  Check which is set (can be All_Checks for the All_Checks case)

      Suppress : Boolean;
      --  Set True for Suppress, and False for Unsuppress

      Prev : Suppress_Stack_Entry_Ptr;
      --  Pointer to previous entry on stack

      Next : Suppress_Stack_Entry_Ptr;
      --  All allocated Suppress_Stack_Entry records are chained together in
      --  a linked list whose head is Suppress_Stack_Entries, and the Next
      --  field is used as a forward pointer (null ends the list). This is
      --  used to free all entries in Sem.Init (which will be important if
      --  we ever setup the compiler to be reused).
   end record;

   Suppress_Stack_Entries : Suppress_Stack_Entry_Ptr := null;
   --  Pointer to linked list of records (see comments for Next above)

   Local_Suppress_Stack_Top : Suppress_Stack_Entry_Ptr;
   --  Pointer to top element of local suppress stack. This is the entry that
   --  is saved and restored in the scope stack, and also saved for generic
   --  body expansion.

   Global_Suppress_Stack_Top : Suppress_Stack_Entry_Ptr;
   --  Pointer to top element of global suppress stack

   procedure Push_Local_Suppress_Stack_Entry
     (Entity   : Entity_Id;
      Check    : Check_Id;
      Suppress : Boolean);
   --  Push a new entry on to the top of the local suppress stack, updating
   --  the value in Local_Suppress_Stack_Top;

   procedure Push_Global_Suppress_Stack_Entry
     (Entity   : Entity_Id;
      Check    : Check_Id;
      Suppress : Boolean);
   --  Push a new entry on to the top of the global suppress stack, updating
   --  the value in Global_Suppress_Stack_Top;

   -----------------
   -- Scope Stack --
   -----------------

   --  The scope stack indicates the declarative regions that are currently
   --  being processed (analyzed and/or expanded). The scope stack is one of
   --  the basic visibility structures in the compiler: entities that are
   --  declared in a scope that is currently on the scope stack are immediately
   --  visible (leaving aside issues of hiding and overloading).

   --  Initially, the scope stack only contains an entry for package Standard.
   --  When a compilation unit, subprogram unit, block or declarative region
   --  is being processed, the corresponding entity is pushed on the scope
   --  stack. It is removed after the processing step is completed. A given
   --  entity can be placed several times on the scope stack, for example
   --  when processing derived type declarations, freeze nodes, etc. The top
   --  of the scope stack is the innermost scope currently being processed.
   --  It is obtained through function Current_Scope. After a compilation unit
   --  has been processed, the scope stack must contain only Standard.
   --  The predicate In_Open_Scopes specifies whether a scope is currently
   --  on the scope stack.

   --  This model is complicated by the need to compile units on the fly, in
   --  the middle of the compilation of other units. This arises when compiling
   --  instantiations, and when compiling run-time packages obtained through
   --  rtsfind. Given that the scope stack is a single static and global
   --  structure (not originally designed for the recursive processing required
   --  by rtsfind for example) additional machinery is needed to indicate what
   --  is currently being compiled. As a result, the scope stack holds several
   --  contiguous sections that correspond to the compilation of a given
   --  compilation unit. These sections are separated by distinct occurrences
   --  of package Standard. The currently active section of the scope stack
   --  goes from the current scope to the first (innermost) occurrence of
   --  Standard, which is additionally marked with flag Is_Active_Stack_Base.
   --  The basic visibility routine (Find_Direct_Name, in Sem_Ch8) uses this
   --  contiguous section of the scope stack to determine whether a given
   --  entity is or is not visible at a point. In_Open_Scopes only examines
   --  the currently active section of the scope stack.

   --  Similar complications arise when processing child instances. These
   --  must be compiled in the context of parent instances, and therefore the
   --  parents must be pushed on the stack before compiling the child, and
   --  removed afterwards. Routines Save_Scope_Stack and Restore_Scope_Stack
   --  are used to set/reset the visibility of entities declared in scopes
   --  that are currently on the scope stack, and are used when compiling
   --  instance bodies on the fly.

   --  It is clear in retrospect that all semantic processing and visibility
   --  structures should have been fully recursive. The rtsfind mechanism,
   --  and the complexities brought about by subunits and by generic child
   --  units and their instantiations, have led to a hybrid model that carries
   --  more state than one would wish.

   type Scope_Action_Kind is (Before, After, Cleanup);
   type Scope_Actions is array (Scope_Action_Kind) of List_Id;
   --  Transient blocks have three associated actions list, to be inserted
   --  before and after the block's statements, and as cleanup actions.

   Configuration_Component_Alignment : Component_Alignment_Kind :=
                                         Calign_Default;
   --  Used for handling the pragma Component_Alignment in the context of a
   --  configuration file.

   type Scope_Stack_Entry is record
      Entity : Scope_Kind_Id;
      --  Entity representing the scope

      Last_Subprogram_Name : String_Ptr;
      --  Pointer to name of last subprogram body in this scope. Used for
      --  testing proper alpha ordering of subprogram bodies in scope.

      Save_Scope_Suppress : Suppress_Record;
      --  Save contents of Scope_Suppress on entry

      Save_Local_Suppress_Stack_Top : Suppress_Stack_Entry_Ptr;
      --  Save contents of Local_Suppress_Stack on entry to restore on exit

      Save_Check_Policy_List : Node_Id;
      --  Save contents of Check_Policy_List on entry to restore on exit. The
      --  Check_Policy pragmas are chained with Check_Policy_List pointing to
      --  the most recent entry. This list is searched starting here, so that
      --  the search finds the most recent applicable entry. When we restore
      --  Check_Policy_List on exit from the scope, the effect is to remove
      --  all entries set in the scope being exited.

      Save_Default_Storage_Pool : Node_Id;
      --  Save contents of Default_Storage_Pool on entry to restore on exit

      Save_SPARK_Mode : SPARK_Mode_Type;
      --  Setting of SPARK_Mode on entry to restore on exit

      Save_SPARK_Mode_Pragma : Node_Id;
      --  Setting of SPARK_Mode_Pragma on entry to restore on exit

      Save_No_Tagged_Streams : Node_Id;
      --  Setting of No_Tagged_Streams to restore on exit

      Save_Default_SSO : Character;
      --  Setting of Default_SSO on entry to restore on exit

      Save_Uneval_Old : Character;
      --  Setting of Uneval_Old on entry to restore on exit

      Is_Transient : Boolean;
      --  Marks transient scopes (see Exp_Ch7 body for details)

      Previous_Visibility : Boolean;
      --  Used when installing the parent(s) of the current compilation unit.
      --  The parent may already be visible because of an ongoing compilation,
      --  and the proper visibility must be restored on exit. The flag is
      --  typically needed when the context of a child unit requires
      --  compilation of a sibling. In other cases the flag is set to False.
      --  See Sem_Ch10 (Install_Parents, Remove_Parents).

      Node_To_Be_Wrapped : Node_Id;
      --  Only used in transient scopes. Records the node that will be wrapped
      --  by the transient block.

      Actions_To_Be_Wrapped : Scope_Actions;
      --  Actions that have to be inserted at the start, at the end, or as
      --  cleanup actions of a transient block. Used to temporarily hold these
      --  actions until the block is created, at which time the actions are
      --  moved to the block.

      Pending_Freeze_Actions : List_Id;
      --  Used to collect freeze entity nodes and associated actions that are
      --  generated in an inner context but need to be analyzed outside, such
      --  as records and initialization procedures. On exit from the scope,
      --  this list of actions is inserted before the scope construct and
      --  analyzed to generate the corresponding freeze processing and
      --  elaboration of other associated actions.

      First_Use_Clause : Node_Id;
      --  Head of list of Use_Clauses in current scope. The list is built when
      --  the declarations in the scope are processed. The list is traversed
      --  on scope exit to undo the effect of the use clauses.

      Component_Alignment_Default : Component_Alignment_Kind;
      --  Component alignment to be applied to any record or array types that
      --  are declared for which a specific component alignment pragma does not
      --  set the alignment.

      Is_Active_Stack_Base : Boolean;
      --  Set to true only when entering the scope for Standard_Standard from
      --  from within procedure Semantics. Indicates the base of the current
      --  active set of scopes. Needed by In_Open_Scopes to handle cases where
      --  Standard_Standard can be pushed anew on the scope stack to start a
      --  new active section (see comment above).

      Locked_Shared_Objects : Elist_Id;
      --  List of shared passive protected objects that have been locked in
      --  this transient scope (always No_Elist for non-transient scopes).
   end record;

   package Scope_Stack is new Table.Table (
     Table_Component_Type => Scope_Stack_Entry,
     Table_Index_Type     => Int,
     Table_Low_Bound      => 0,
     Table_Initial        => Alloc.Scope_Stack_Initial,
     Table_Increment      => Alloc.Scope_Stack_Increment,
     Table_Name           => "Sem.Scope_Stack");

   -----------------
   -- Subprograms --
   -----------------

   procedure Initialize;
   --  Initialize internal tables

   procedure Lock;
   --  Lock internal tables before calling back end

   procedure Unlock;
   --  Unlock internal tables

   procedure Semantics (Comp_Unit : Node_Id);
   --  This procedure is called to perform semantic analysis on the specified
   --  node which is the N_Compilation_Unit node for the unit.

   procedure Analyze (N : Node_Id);
   procedure Analyze (N : Node_Id; Suppress : Check_Id);
   --  This is the recursive procedure that is applied to individual nodes of
   --  the tree, starting at the top level node (compilation unit node) and
   --  then moving down the tree in a top down traversal. It calls individual
   --  routines with names Analyze_xxx to analyze node xxx. Each of these
   --  routines is responsible for calling Analyze on the components of the
   --  subtree.
   --
   --  Note: In the case of expression components (nodes whose Nkind is in
   --  N_Subexpr), the call to Analyze does not complete the semantic analysis
   --  of the node, since the type resolution cannot be completed until the
   --  complete context is analyzed. The completion of the type analysis occurs
   --  in the corresponding Resolve routine (see Sem_Res).
   --
   --  Note: for integer and real literals, the analyzer sets the flag to
   --  indicate that the result is a static expression. If the expander
   --  generates a literal that does NOT correspond to a static expression,
   --  e.g. by folding an expression whose value is known at compile time,
   --  but is not technically static, then the caller should reset the
   --  Is_Static_Expression flag after analyzing but before resolving.
   --
   --  If the Suppress argument is present, then the analysis is done
   --  with the specified check suppressed (can be All_Checks to suppress
   --  all checks).

   procedure Analyze_List (L : List_Id);
   procedure Analyze_List (L : List_Id; Suppress : Check_Id);
   --  Analyzes each element of a list. If the Suppress argument is present,
   --  then the analysis is done with the specified check suppressed (can
   --  be All_Checks to suppress all checks).

   procedure Copy_Suppress_Status
     (C    : Check_Id;
      From : Entity_Id;
      To   : Entity_Id);
   --  If From is an entity for which check C is explicitly suppressed
   --  then also explicitly suppress the corresponding check in To.

   procedure Insert_List_After_And_Analyze
     (N : Node_Id; L : List_Id);
   --  Inserts list L after node N using Nlists.Insert_List_After, and then,
   --  after this insertion is complete, analyzes all the nodes in the list,
   --  including any additional nodes generated by this analysis. If the list
   --  is empty or No_List, the call has no effect.

   procedure Insert_List_Before_And_Analyze
     (N : Node_Id; L : List_Id);
   --  Inserts list L before node N using Nlists.Insert_List_Before, and then,
   --  after this insertion is complete, analyzes all the nodes in the list,
   --  including any additional nodes generated by this analysis. If the list
   --  is empty or No_List, the call has no effect.

   procedure Insert_After_And_Analyze
     (N : Node_Id; M : Node_Id);
   procedure Insert_After_And_Analyze
     (N : Node_Id; M : Node_Id; Suppress : Check_Id);
   --  Inserts node M after node N and then after the insertion is complete,
   --  analyzes the inserted node and all nodes that are generated by
   --  this analysis. If the node is empty, the call has no effect. If the
   --  Suppress argument is present, then the analysis is done with the
   --  specified check suppressed (can be All_Checks to suppress all checks).

   procedure Insert_Before_And_Analyze
     (N : Node_Id; M : Node_Id);
   procedure Insert_Before_And_Analyze
     (N : Node_Id; M : Node_Id; Suppress : Check_Id);
   --  Inserts node M before node N and then after the insertion is complete,
   --  analyzes the inserted node and all nodes that could be generated by
   --  this analysis. If the node is empty, the call has no effect. If the
   --  Suppress argument is present, then the analysis is done with the
   --  specified check suppressed (can be All_Checks to suppress all checks).

   procedure Insert_Before_First_Source_Declaration
     (Stmt  : Node_Id;
      Decls : List_Id);
   --  Insert node Stmt before the first source declaration of the related
   --  subprogram's body. If no such declaration exists, Stmt becomes the last
   --  declaration.

   function External_Ref_In_Generic (E : Entity_Id) return Boolean;
   --  Return True if we are in the context of a generic and E is
   --  external (more global) to it.

   procedure Enter_Generic_Scope (S : Entity_Id);
   --  Called each time a Generic subprogram or package scope is entered. S is
   --  the entity of the scope.
   --
   --  ??? At the moment, only called for package specs because this mechanism
   --  is only used for avoiding freezing of external references in generics
   --  and this can only be an issue if the outer generic scope is a package
   --  spec (otherwise all external entities are already frozen)

   procedure Exit_Generic_Scope  (S : Entity_Id);
   --  Called each time a Generic subprogram or package scope is exited. S is
   --  the entity of the scope.
   --
   --  ??? At the moment, only called for package specs exit.

   function Explicit_Suppress (E : Entity_Id; C : Check_Id) return Boolean;
   --  This function returns True if an explicit pragma Suppress for check C
   --  is present in the package defining E.

   function Preanalysis_Active return Boolean;
   pragma Inline (Preanalysis_Active);
   --  Determine whether preanalysis is active at the point of invocation

   procedure Preanalyze (N : Node_Id);
   --  Performs a preanalysis of node N. During preanalysis no expansion is
   --  carried out for N or its children. See above for more info on
   --  preanalysis.

   generic
      with procedure Action (Item : Node_Id);
   procedure Walk_Library_Items;
   --  Primarily for use by CodePeer and GNATprove. Must be called after
   --  semantic analysis (and expansion in the case of CodePeer) are complete.
   --  Walks each relevant library item, calling Action for each, in an order
   --  such that one will not run across forward references. Each Item passed
   --  to Action is the declaration or body of a library unit, including
   --  generics and renamings. The first item is the N_Package_Declaration node
   --  for package Standard. Bodies are not included, except for the main unit
   --  itself, which always comes last.
   --
   --  Item is never a subunit
   --
   --  Item is never an instantiation. Instead, the instance declaration is
   --  passed, and (if the instantiation is the main unit), the instance body.

   ------------------------
   -- Debugging Routines --
   ------------------------

   function ss (Index : Int) return Scope_Stack_Entry;
   pragma Export (Ada, ss);
   --  "ss" = "scope stack"; returns the Index'th entry in the Scope_Stack

   function sst return Scope_Stack_Entry;
   pragma Export (Ada, sst);
   --  "sst" = "scope stack top"; same as ss(Scope_Stack.Last)

end Sem;