xref: /llvm-project/flang/include/flang/Parser/parse-tree.h (revision 15ab7be2e049bc0f4ea6744ca037395686a923bc)
1 //===-- include/flang/Parser/parse-tree.h -----------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef FORTRAN_PARSER_PARSE_TREE_H_
10 #define FORTRAN_PARSER_PARSE_TREE_H_
11 
12 // Defines the classes used to represent successful reductions of productions
13 // in the Fortran grammar.  The names and content of these definitions
14 // adhere closely to the syntax specifications in the language standard (q.v.)
15 // that are transcribed here and referenced via their requirement numbers.
16 // The representations of some productions that may also be of use in the
17 // run-time I/O support library have been isolated into a distinct header file
18 // (viz., format-specification.h).
19 
20 #include "char-block.h"
21 #include "characters.h"
22 #include "format-specification.h"
23 #include "message.h"
24 #include "provenance.h"
25 #include "flang/Common/Fortran.h"
26 #include "flang/Common/idioms.h"
27 #include "flang/Common/indirection.h"
28 #include "llvm/Frontend/OpenACC/ACC.h.inc"
29 #include "llvm/Frontend/OpenMP/OMP.h"
30 #include "llvm/Frontend/OpenMP/OMPConstants.h"
31 #include <cinttypes>
32 #include <list>
33 #include <memory>
34 #include <optional>
35 #include <string>
36 #include <tuple>
37 #include <type_traits>
38 #include <utility>
39 #include <variant>
40 
41 // Parse tree node class types do not have default constructors.  They
42 // explicitly declare "T() {} = delete;" to make this clear.  This restriction
43 // prevents the introduction of what would be a viral requirement to include
44 // std::monostate among most std::variant<> discriminated union members.
45 
46 // Parse tree node class types do not have copy constructors or copy assignment
47 // operators.  They are explicitly declared "= delete;" to make this clear,
48 // although a C++ compiler wouldn't default them anyway due to the presence
49 // of explicitly defaulted move constructors and move assignments.
50 
51 CLASS_TRAIT(EmptyTrait)
52 CLASS_TRAIT(WrapperTrait)
53 CLASS_TRAIT(UnionTrait)
54 CLASS_TRAIT(TupleTrait)
55 CLASS_TRAIT(ConstraintTrait)
56 
57 // Some parse tree nodes have fields in them to cache the results of a
58 // successful semantic analysis later.  Their types are forward declared
59 // here.
60 namespace Fortran::semantics {
61 class Symbol;
62 class DeclTypeSpec;
63 class DerivedTypeSpec;
64 } // namespace Fortran::semantics
65 
66 // Expressions in the parse tree have owning pointers that can be set to
67 // type-checked generic expression representations by semantic analysis.
68 namespace Fortran::evaluate {
69 struct GenericExprWrapper; // forward definition, wraps Expr<SomeType>
70 struct GenericAssignmentWrapper; // forward definition, represent assignment
71 class ProcedureRef; // forward definition, represents a CALL or function ref
72 } // namespace Fortran::evaluate
73 
74 // Most non-template classes in this file use these default definitions
75 // for their move constructor and move assignment operator=, and disable
76 // their copy constructor and copy assignment operator=.
77 #define COPY_AND_ASSIGN_BOILERPLATE(classname) \
78   classname(classname &&) = default; \
79   classname &operator=(classname &&) = default; \
80   classname(const classname &) = delete; \
81   classname &operator=(const classname &) = delete
82 
83 // Almost all classes in this file have no default constructor.
84 #define BOILERPLATE(classname) \
85   COPY_AND_ASSIGN_BOILERPLATE(classname); \
86   classname() = delete
87 
88 // Empty classes are often used below as alternatives in std::variant<>
89 // discriminated unions.
90 #define EMPTY_CLASS(classname) \
91   struct classname { \
92     classname() {} \
93     classname(const classname &) {} \
94     classname(classname &&) {} \
95     classname &operator=(const classname &) { return *this; }; \
96     classname &operator=(classname &&) { return *this; }; \
97     using EmptyTrait = std::true_type; \
98   }
99 
100 // Many classes below simply wrap a std::variant<> discriminated union,
101 // which is conventionally named "u".
102 #define UNION_CLASS_BOILERPLATE(classname) \
103   template <typename A, typename = common::NoLvalue<A>> \
104   classname(A &&x) : u(std::move(x)) {} \
105   using UnionTrait = std::true_type; \
106   BOILERPLATE(classname)
107 
108 // Many other classes below simply wrap a std::tuple<> structure, which
109 // is conventionally named "t".
110 #define TUPLE_CLASS_BOILERPLATE(classname) \
111   template <typename... Ts, typename = common::NoLvalue<Ts...>> \
112   classname(Ts &&...args) : t(std::move(args)...) {} \
113   using TupleTrait = std::true_type; \
114   BOILERPLATE(classname)
115 
116 // Many other classes below simply wrap a single data member, which is
117 // conventionally named "v".
118 #define WRAPPER_CLASS_BOILERPLATE(classname, type) \
119   BOILERPLATE(classname); \
120   classname(type &&x) : v(std::move(x)) {} \
121   using WrapperTrait = std::true_type; \
122   type v
123 
124 #define WRAPPER_CLASS(classname, type) \
125   struct classname { \
126     WRAPPER_CLASS_BOILERPLATE(classname, type); \
127   }
128 
129 namespace Fortran::parser {
130 
131 // These are the unavoidable recursively-defined productions of Fortran.
132 // Some references to the representations of their parses require
133 // indirection.  The Indirect<> pointer wrapper class is used to
134 // enforce ownership semantics and non-nullability.
135 struct SpecificationPart; // R504
136 struct ExecutableConstruct; // R514
137 struct ActionStmt; // R515
138 struct AcImpliedDo; // R774
139 struct DataImpliedDo; // R840
140 struct Designator; // R901
141 struct Variable; // R902
142 struct Expr; // R1001
143 struct WhereConstruct; // R1042
144 struct ForallConstruct; // R1050
145 struct InputImpliedDo; // R1218
146 struct OutputImpliedDo; // R1218
147 struct FunctionReference; // R1520
148 struct FunctionSubprogram; // R1529
149 struct SubroutineSubprogram; // R1534
150 
151 // These additional forward references are declared so that the order of
152 // class definitions in this header file can remain reasonably consistent
153 // with order of the the requirement productions in the grammar.
154 struct DerivedTypeDef; // R726
155 struct EnumDef; // R759
156 struct TypeDeclarationStmt; // R801
157 struct AccessStmt; // R827
158 struct AllocatableStmt; // R829
159 struct AsynchronousStmt; // R831
160 struct BindStmt; // R832
161 struct CodimensionStmt; // R834
162 struct ContiguousStmt; // R836
163 struct DataStmt; // R837
164 struct DataStmtValue; // R843
165 struct DimensionStmt; // R848
166 struct IntentStmt; // R849
167 struct OptionalStmt; // R850
168 struct ParameterStmt; // R851
169 struct OldParameterStmt;
170 struct PointerStmt; // R853
171 struct ProtectedStmt; // R855
172 struct SaveStmt; // R856
173 struct TargetStmt; // R859
174 struct ValueStmt; // R861
175 struct VolatileStmt; // R862
176 struct ImplicitStmt; // R863
177 struct ImportStmt; // R867
178 struct NamelistStmt; // R868
179 struct EquivalenceStmt; // R870
180 struct CommonStmt; // R873
181 struct Substring; // R908
182 struct CharLiteralConstantSubstring;
183 struct SubstringInquiry;
184 struct DataRef; // R911
185 struct StructureComponent; // R913
186 struct CoindexedNamedObject; // R914
187 struct ArrayElement; // R917
188 struct AllocateStmt; // R927
189 struct NullifyStmt; // R939
190 struct DeallocateStmt; // R941
191 struct AssignmentStmt; // R1032
192 struct PointerAssignmentStmt; // R1033
193 struct WhereStmt; // R1041, R1045, R1046
194 struct ForallStmt; // R1055
195 struct AssociateConstruct; // R1102
196 struct BlockConstruct; // R1107
197 struct ChangeTeamConstruct; // R1111
198 struct CriticalConstruct; // R1116
199 struct DoConstruct; // R1119
200 struct LabelDoStmt; // R1121
201 struct ConcurrentHeader; // R1125
202 struct EndDoStmt; // R1132
203 struct CycleStmt; // R1133
204 struct IfConstruct; // R1134
205 struct IfStmt; // R1139
206 struct CaseConstruct; // R1140
207 struct SelectRankConstruct; // R1148
208 struct SelectTypeConstruct; // R1152
209 struct ExitStmt; // R1156
210 struct GotoStmt; // R1157
211 struct ComputedGotoStmt; // R1158
212 struct StopStmt; // R1160, R1161
213 struct NotifyWaitStmt; // F2023: R1166
214 struct SyncAllStmt; // R1164
215 struct SyncImagesStmt; // R1166
216 struct SyncMemoryStmt; // R1168
217 struct SyncTeamStmt; // R1169
218 struct EventPostStmt; // R1170, R1171
219 struct EventWaitSpec; // F2023: R1177
220 struct EventWaitStmt; // R1172, R1173, R1174
221 struct FormTeamStmt; // R1175, R1176, R1177
222 struct LockStmt; // R1178
223 struct UnlockStmt; // R1180
224 struct OpenStmt; // R1204
225 struct CloseStmt; // R1208
226 struct ReadStmt; // R1210
227 struct WriteStmt; // R1211
228 struct PrintStmt; // R1212
229 struct WaitStmt; // R1222
230 struct BackspaceStmt; // R1224
231 struct EndfileStmt; // R1225
232 struct RewindStmt; // R1226
233 struct FlushStmt; // R1228
234 struct InquireStmt; // R1230
235 struct FormatStmt; // R1301
236 struct MainProgram; // R1401
237 struct Module; // R1404
238 struct UseStmt; // R1409
239 struct Submodule; // R1416
240 struct BlockData; // R1420
241 struct InterfaceBlock; // R1501
242 struct GenericSpec; // R1508
243 struct GenericStmt; // R1510
244 struct ExternalStmt; // R1511
245 struct ProcedureDeclarationStmt; // R1512
246 struct IntrinsicStmt; // R1519
247 struct Call; // R1520 & R1521
248 struct CallStmt; // R1521
249 struct ProcedureDesignator; // R1522
250 struct ActualArg; // R1524
251 struct SeparateModuleSubprogram; // R1538
252 struct EntryStmt; // R1541
253 struct ReturnStmt; // R1542
254 struct StmtFunctionStmt; // R1544
255 
256 // Directives, extensions, and deprecated statements
257 struct CompilerDirective;
258 struct BasedPointerStmt;
259 struct CUDAAttributesStmt;
260 struct StructureDef;
261 struct ArithmeticIfStmt;
262 struct AssignStmt;
263 struct AssignedGotoStmt;
264 struct PauseStmt;
265 struct OpenACCConstruct;
266 struct AccEndCombinedDirective;
267 struct OpenACCDeclarativeConstruct;
268 struct OpenACCRoutineConstruct;
269 struct OpenMPConstruct;
270 struct OpenMPDeclarativeConstruct;
271 struct OmpEndLoopDirective;
272 struct OmpMemoryOrderClause;
273 struct CUFKernelDoConstruct;
274 
275 // Cooked character stream locations
276 using Location = const char *;
277 
278 // A parse tree node with provenance only
279 struct Verbatim {
280   // Allow a no-arg constructor for Verbatim so parsers can return `RESULT{}`.
281   constexpr Verbatim() {}
282   COPY_AND_ASSIGN_BOILERPLATE(Verbatim);
283   using EmptyTrait = std::true_type;
284   CharBlock source;
285 };
286 
287 // Implicit definitions of the Standard
288 
289 // R403 scalar-xyz -> xyz
290 // These template class wrappers correspond to the Standard's modifiers
291 // scalar-xyz, constant-xzy, int-xzy, default-char-xyz, & logical-xyz.
292 template <typename A> struct Scalar {
293   using ConstraintTrait = std::true_type;
294   Scalar(Scalar &&that) = default;
295   Scalar(A &&that) : thing(std::move(that)) {}
296   Scalar &operator=(Scalar &&) = default;
297   A thing;
298 };
299 
300 template <typename A> struct Constant {
301   using ConstraintTrait = std::true_type;
302   Constant(Constant &&that) = default;
303   Constant(A &&that) : thing(std::move(that)) {}
304   Constant &operator=(Constant &&) = default;
305   A thing;
306 };
307 
308 template <typename A> struct Integer {
309   using ConstraintTrait = std::true_type;
310   Integer(Integer &&that) = default;
311   Integer(A &&that) : thing(std::move(that)) {}
312   Integer &operator=(Integer &&) = default;
313   A thing;
314 };
315 
316 template <typename A> struct Logical {
317   using ConstraintTrait = std::true_type;
318   Logical(Logical &&that) = default;
319   Logical(A &&that) : thing(std::move(that)) {}
320   Logical &operator=(Logical &&) = default;
321   A thing;
322 };
323 
324 template <typename A> struct DefaultChar {
325   using ConstraintTrait = std::true_type;
326   DefaultChar(DefaultChar &&that) = default;
327   DefaultChar(A &&that) : thing(std::move(that)) {}
328   DefaultChar &operator=(DefaultChar &&) = default;
329   A thing;
330 };
331 
332 using LogicalExpr = Logical<common::Indirection<Expr>>; // R1024
333 using DefaultCharExpr = DefaultChar<common::Indirection<Expr>>; // R1025
334 using IntExpr = Integer<common::Indirection<Expr>>; // R1026
335 using ConstantExpr = Constant<common::Indirection<Expr>>; // R1029
336 using IntConstantExpr = Integer<ConstantExpr>; // R1031
337 using ScalarLogicalExpr = Scalar<LogicalExpr>;
338 using ScalarIntExpr = Scalar<IntExpr>;
339 using ScalarIntConstantExpr = Scalar<IntConstantExpr>;
340 using ScalarDefaultCharExpr = Scalar<DefaultCharExpr>;
341 // R1030 default-char-constant-expr is used in the Standard only as part of
342 // scalar-default-char-constant-expr.
343 using ScalarDefaultCharConstantExpr = Scalar<DefaultChar<ConstantExpr>>;
344 
345 // R611 label -> digit [digit]...
346 using Label = common::Label; // validated later, must be in [1..99999]
347 
348 // A wrapper for xzy-stmt productions that are statements, so that
349 // source provenances and labels have a uniform representation.
350 template <typename A> struct UnlabeledStatement {
351   explicit UnlabeledStatement(A &&s) : statement(std::move(s)) {}
352   CharBlock source;
353   A statement;
354 };
355 template <typename A> struct Statement : public UnlabeledStatement<A> {
356   Statement(std::optional<long> &&lab, A &&s)
357       : UnlabeledStatement<A>{std::move(s)}, label(std::move(lab)) {}
358   std::optional<Label> label;
359 };
360 
361 // Error recovery marker
362 EMPTY_CLASS(ErrorRecovery);
363 
364 // R513 other-specification-stmt ->
365 //        access-stmt | allocatable-stmt | asynchronous-stmt | bind-stmt |
366 //        codimension-stmt | contiguous-stmt | dimension-stmt | external-stmt |
367 //        intent-stmt | intrinsic-stmt | namelist-stmt | optional-stmt |
368 //        pointer-stmt | protected-stmt | save-stmt | target-stmt |
369 //        volatile-stmt | value-stmt | common-stmt | equivalence-stmt
370 // Extension: (Cray) based POINTER statement
371 // Extension: CUDA data attribute statement
372 struct OtherSpecificationStmt {
373   UNION_CLASS_BOILERPLATE(OtherSpecificationStmt);
374   std::variant<common::Indirection<AccessStmt>,
375       common::Indirection<AllocatableStmt>,
376       common::Indirection<AsynchronousStmt>, common::Indirection<BindStmt>,
377       common::Indirection<CodimensionStmt>, common::Indirection<ContiguousStmt>,
378       common::Indirection<DimensionStmt>, common::Indirection<ExternalStmt>,
379       common::Indirection<IntentStmt>, common::Indirection<IntrinsicStmt>,
380       common::Indirection<NamelistStmt>, common::Indirection<OptionalStmt>,
381       common::Indirection<PointerStmt>, common::Indirection<ProtectedStmt>,
382       common::Indirection<SaveStmt>, common::Indirection<TargetStmt>,
383       common::Indirection<ValueStmt>, common::Indirection<VolatileStmt>,
384       common::Indirection<CommonStmt>, common::Indirection<EquivalenceStmt>,
385       common::Indirection<BasedPointerStmt>,
386       common::Indirection<CUDAAttributesStmt>>
387       u;
388 };
389 
390 // R508 specification-construct ->
391 //        derived-type-def | enum-def | generic-stmt | interface-block |
392 //        parameter-stmt | procedure-declaration-stmt |
393 //        other-specification-stmt | type-declaration-stmt
394 struct SpecificationConstruct {
395   UNION_CLASS_BOILERPLATE(SpecificationConstruct);
396   std::variant<common::Indirection<DerivedTypeDef>,
397       common::Indirection<EnumDef>, Statement<common::Indirection<GenericStmt>>,
398       common::Indirection<InterfaceBlock>,
399       Statement<common::Indirection<ParameterStmt>>,
400       Statement<common::Indirection<OldParameterStmt>>,
401       Statement<common::Indirection<ProcedureDeclarationStmt>>,
402       Statement<OtherSpecificationStmt>,
403       Statement<common::Indirection<TypeDeclarationStmt>>,
404       common::Indirection<StructureDef>,
405       common::Indirection<OpenACCDeclarativeConstruct>,
406       common::Indirection<OpenMPDeclarativeConstruct>,
407       common::Indirection<CompilerDirective>>
408       u;
409 };
410 
411 // R506 implicit-part-stmt ->
412 //         implicit-stmt | parameter-stmt | format-stmt | entry-stmt
413 struct ImplicitPartStmt {
414   UNION_CLASS_BOILERPLATE(ImplicitPartStmt);
415   std::variant<Statement<common::Indirection<ImplicitStmt>>,
416       Statement<common::Indirection<ParameterStmt>>,
417       Statement<common::Indirection<OldParameterStmt>>,
418       Statement<common::Indirection<FormatStmt>>,
419       Statement<common::Indirection<EntryStmt>>,
420       common::Indirection<CompilerDirective>,
421       common::Indirection<OpenACCDeclarativeConstruct>>
422       u;
423 };
424 
425 // R505 implicit-part -> [implicit-part-stmt]... implicit-stmt
426 WRAPPER_CLASS(ImplicitPart, std::list<ImplicitPartStmt>);
427 
428 // R507 declaration-construct ->
429 //        specification-construct | data-stmt | format-stmt |
430 //        entry-stmt | stmt-function-stmt
431 struct DeclarationConstruct {
432   UNION_CLASS_BOILERPLATE(DeclarationConstruct);
433   std::variant<SpecificationConstruct, Statement<common::Indirection<DataStmt>>,
434       Statement<common::Indirection<FormatStmt>>,
435       Statement<common::Indirection<EntryStmt>>,
436       Statement<common::Indirection<StmtFunctionStmt>>, ErrorRecovery>
437       u;
438 };
439 
440 // R504 specification-part -> [use-stmt]... [import-stmt]... [implicit-part]
441 //                            [declaration-construct]...
442 // PARAMETER, FORMAT, and ENTRY statements that appear before any other
443 // kind of declaration-construct will be parsed into the implicit-part,
444 // even if there are no IMPLICIT statements.
445 struct SpecificationPart {
446   TUPLE_CLASS_BOILERPLATE(SpecificationPart);
447   std::tuple<std::list<OpenACCDeclarativeConstruct>,
448       std::list<OpenMPDeclarativeConstruct>,
449       std::list<common::Indirection<CompilerDirective>>,
450       std::list<Statement<common::Indirection<UseStmt>>>,
451       std::list<Statement<common::Indirection<ImportStmt>>>, ImplicitPart,
452       std::list<DeclarationConstruct>>
453       t;
454 };
455 
456 // R512 internal-subprogram -> function-subprogram | subroutine-subprogram
457 struct InternalSubprogram {
458   UNION_CLASS_BOILERPLATE(InternalSubprogram);
459   std::variant<common::Indirection<FunctionSubprogram>,
460       common::Indirection<SubroutineSubprogram>,
461       common::Indirection<CompilerDirective>>
462       u;
463 };
464 
465 // R1543 contains-stmt -> CONTAINS
466 EMPTY_CLASS(ContainsStmt);
467 
468 // R511 internal-subprogram-part -> contains-stmt [internal-subprogram]...
469 struct InternalSubprogramPart {
470   TUPLE_CLASS_BOILERPLATE(InternalSubprogramPart);
471   std::tuple<Statement<ContainsStmt>, std::list<InternalSubprogram>> t;
472 };
473 
474 // R1159 continue-stmt -> CONTINUE
475 EMPTY_CLASS(ContinueStmt);
476 
477 // R1163 fail-image-stmt -> FAIL IMAGE
478 EMPTY_CLASS(FailImageStmt);
479 
480 // R515 action-stmt ->
481 //        allocate-stmt | assignment-stmt | backspace-stmt | call-stmt |
482 //        close-stmt | continue-stmt | cycle-stmt | deallocate-stmt |
483 //        endfile-stmt | error-stop-stmt | event-post-stmt | event-wait-stmt |
484 //        exit-stmt | fail-image-stmt | flush-stmt | form-team-stmt |
485 //        goto-stmt | if-stmt | inquire-stmt | lock-stmt | notify-wait-stmt |
486 //        nullify-stmt | open-stmt | pointer-assignment-stmt | print-stmt |
487 //        read-stmt | return-stmt | rewind-stmt | stop-stmt | sync-all-stmt |
488 //        sync-images-stmt | sync-memory-stmt | sync-team-stmt | unlock-stmt |
489 //        wait-stmt | where-stmt | write-stmt | computed-goto-stmt | forall-stmt
490 struct ActionStmt {
491   UNION_CLASS_BOILERPLATE(ActionStmt);
492   std::variant<common::Indirection<AllocateStmt>,
493       common::Indirection<AssignmentStmt>, common::Indirection<BackspaceStmt>,
494       common::Indirection<CallStmt>, common::Indirection<CloseStmt>,
495       ContinueStmt, common::Indirection<CycleStmt>,
496       common::Indirection<DeallocateStmt>, common::Indirection<EndfileStmt>,
497       common::Indirection<EventPostStmt>, common::Indirection<EventWaitStmt>,
498       common::Indirection<ExitStmt>, FailImageStmt,
499       common::Indirection<FlushStmt>, common::Indirection<FormTeamStmt>,
500       common::Indirection<GotoStmt>, common::Indirection<IfStmt>,
501       common::Indirection<InquireStmt>, common::Indirection<LockStmt>,
502       common::Indirection<NotifyWaitStmt>, common::Indirection<NullifyStmt>,
503       common::Indirection<OpenStmt>, common::Indirection<PointerAssignmentStmt>,
504       common::Indirection<PrintStmt>, common::Indirection<ReadStmt>,
505       common::Indirection<ReturnStmt>, common::Indirection<RewindStmt>,
506       common::Indirection<StopStmt>, common::Indirection<SyncAllStmt>,
507       common::Indirection<SyncImagesStmt>, common::Indirection<SyncMemoryStmt>,
508       common::Indirection<SyncTeamStmt>, common::Indirection<UnlockStmt>,
509       common::Indirection<WaitStmt>, common::Indirection<WhereStmt>,
510       common::Indirection<WriteStmt>, common::Indirection<ComputedGotoStmt>,
511       common::Indirection<ForallStmt>, common::Indirection<ArithmeticIfStmt>,
512       common::Indirection<AssignStmt>, common::Indirection<AssignedGotoStmt>,
513       common::Indirection<PauseStmt>>
514       u;
515 };
516 
517 // R514 executable-construct ->
518 //        action-stmt | associate-construct | block-construct |
519 //        case-construct | change-team-construct | critical-construct |
520 //        do-construct | if-construct | select-rank-construct |
521 //        select-type-construct | where-construct | forall-construct |
522 // (CUDA) CUF-kernel-do-construct
523 struct ExecutableConstruct {
524   UNION_CLASS_BOILERPLATE(ExecutableConstruct);
525   std::variant<Statement<ActionStmt>, common::Indirection<AssociateConstruct>,
526       common::Indirection<BlockConstruct>, common::Indirection<CaseConstruct>,
527       common::Indirection<ChangeTeamConstruct>,
528       common::Indirection<CriticalConstruct>,
529       Statement<common::Indirection<LabelDoStmt>>,
530       Statement<common::Indirection<EndDoStmt>>,
531       common::Indirection<DoConstruct>, common::Indirection<IfConstruct>,
532       common::Indirection<SelectRankConstruct>,
533       common::Indirection<SelectTypeConstruct>,
534       common::Indirection<WhereConstruct>, common::Indirection<ForallConstruct>,
535       common::Indirection<CompilerDirective>,
536       common::Indirection<OpenACCConstruct>,
537       common::Indirection<AccEndCombinedDirective>,
538       common::Indirection<OpenMPConstruct>,
539       common::Indirection<OmpEndLoopDirective>,
540       common::Indirection<CUFKernelDoConstruct>>
541       u;
542 };
543 
544 // R510 execution-part-construct ->
545 //        executable-construct | format-stmt | entry-stmt | data-stmt
546 // Extension (PGI/Intel): also accept NAMELIST in execution part
547 struct ExecutionPartConstruct {
548   UNION_CLASS_BOILERPLATE(ExecutionPartConstruct);
549   std::variant<ExecutableConstruct, Statement<common::Indirection<FormatStmt>>,
550       Statement<common::Indirection<EntryStmt>>,
551       Statement<common::Indirection<DataStmt>>,
552       Statement<common::Indirection<NamelistStmt>>, ErrorRecovery>
553       u;
554 };
555 
556 // R509 execution-part -> executable-construct [execution-part-construct]...
557 // R1101 block -> [execution-part-construct]...
558 using Block = std::list<ExecutionPartConstruct>;
559 WRAPPER_CLASS(ExecutionPart, Block);
560 
561 // R502 program-unit ->
562 //        main-program | external-subprogram | module | submodule | block-data
563 // R503 external-subprogram -> function-subprogram | subroutine-subprogram
564 struct ProgramUnit {
565   UNION_CLASS_BOILERPLATE(ProgramUnit);
566   std::variant<common::Indirection<MainProgram>,
567       common::Indirection<FunctionSubprogram>,
568       common::Indirection<SubroutineSubprogram>, common::Indirection<Module>,
569       common::Indirection<Submodule>, common::Indirection<BlockData>,
570       common::Indirection<CompilerDirective>,
571       common::Indirection<OpenACCRoutineConstruct>>
572       u;
573 };
574 
575 // R501 program -> program-unit [program-unit]...
576 // This is the top-level production.
577 WRAPPER_CLASS(Program, std::list<ProgramUnit>);
578 
579 // R603 name -> letter [alphanumeric-character]...
580 struct Name {
581   std::string ToString() const { return source.ToString(); }
582   CharBlock source;
583   mutable semantics::Symbol *symbol{nullptr}; // filled in during semantics
584 };
585 
586 // R516 keyword -> name
587 WRAPPER_CLASS(Keyword, Name);
588 
589 // R606 named-constant -> name
590 WRAPPER_CLASS(NamedConstant, Name);
591 
592 // R1003 defined-unary-op -> . letter [letter]... .
593 // R1023 defined-binary-op -> . letter [letter]... .
594 // R1414 local-defined-operator -> defined-unary-op | defined-binary-op
595 // R1415 use-defined-operator -> defined-unary-op | defined-binary-op
596 // The Name here is stored with the dots; e.g., .FOO.
597 WRAPPER_CLASS(DefinedOpName, Name);
598 
599 // R608 intrinsic-operator ->
600 //        ** | * | / | + | - | // | .LT. | .LE. | .EQ. | .NE. | .GE. | .GT. |
601 //        .NOT. | .AND. | .OR. | .EQV. | .NEQV.
602 // R609 defined-operator ->
603 //        defined-unary-op | defined-binary-op | extended-intrinsic-op
604 // R610 extended-intrinsic-op -> intrinsic-operator
605 struct DefinedOperator {
606   UNION_CLASS_BOILERPLATE(DefinedOperator);
607   ENUM_CLASS(IntrinsicOperator, Power, Multiply, Divide, Add, Subtract, Concat,
608       LT, LE, EQ, NE, GE, GT, NOT, AND, OR, EQV, NEQV)
609   std::variant<DefinedOpName, IntrinsicOperator> u;
610 };
611 
612 // R804 object-name -> name
613 using ObjectName = Name;
614 
615 // R867 import-stmt ->
616 //        IMPORT [[::] import-name-list] |
617 //        IMPORT , ONLY : import-name-list | IMPORT , NONE | IMPORT , ALL
618 struct ImportStmt {
619   BOILERPLATE(ImportStmt);
620   ImportStmt(common::ImportKind &&k) : kind{k} {}
621   ImportStmt(std::list<Name> &&n) : names(std::move(n)) {}
622   ImportStmt(common::ImportKind &&, std::list<Name> &&);
623   common::ImportKind kind{common::ImportKind::Default};
624   std::list<Name> names;
625 };
626 
627 // R868 namelist-stmt ->
628 //        NAMELIST / namelist-group-name / namelist-group-object-list
629 //        [[,] / namelist-group-name / namelist-group-object-list]...
630 // R869 namelist-group-object -> variable-name
631 struct NamelistStmt {
632   struct Group {
633     TUPLE_CLASS_BOILERPLATE(Group);
634     std::tuple<Name, std::list<Name>> t;
635   };
636   WRAPPER_CLASS_BOILERPLATE(NamelistStmt, std::list<Group>);
637 };
638 
639 // R701 type-param-value -> scalar-int-expr | * | :
640 EMPTY_CLASS(Star);
641 
642 struct TypeParamValue {
643   UNION_CLASS_BOILERPLATE(TypeParamValue);
644   EMPTY_CLASS(Deferred); // :
645   std::variant<ScalarIntExpr, Star, Deferred> u;
646 };
647 
648 // R706 kind-selector -> ( [KIND =] scalar-int-constant-expr )
649 // Legacy extension: kind-selector -> * digit-string
650 // N.B. These are not semantically identical in the case of COMPLEX.
651 struct KindSelector {
652   UNION_CLASS_BOILERPLATE(KindSelector);
653   WRAPPER_CLASS(StarSize, std::uint64_t);
654   std::variant<ScalarIntConstantExpr, StarSize> u;
655 };
656 
657 // R705 integer-type-spec -> INTEGER [kind-selector]
658 WRAPPER_CLASS(IntegerTypeSpec, std::optional<KindSelector>);
659 
660 WRAPPER_CLASS(UnsignedTypeSpec, std::optional<KindSelector>);
661 
662 // R723 char-length -> ( type-param-value ) | digit-string
663 struct CharLength {
664   UNION_CLASS_BOILERPLATE(CharLength);
665   std::variant<TypeParamValue, std::uint64_t> u;
666 };
667 
668 // R722 length-selector -> ( [LEN =] type-param-value ) | * char-length [,]
669 struct LengthSelector {
670   UNION_CLASS_BOILERPLATE(LengthSelector);
671   std::variant<TypeParamValue, CharLength> u;
672 };
673 
674 // R721 char-selector ->
675 //        length-selector |
676 //        ( LEN = type-param-value , KIND = scalar-int-constant-expr ) |
677 //        ( type-param-value , [KIND =] scalar-int-constant-expr ) |
678 //        ( KIND = scalar-int-constant-expr [, LEN = type-param-value] )
679 struct CharSelector {
680   UNION_CLASS_BOILERPLATE(CharSelector);
681   struct LengthAndKind {
682     BOILERPLATE(LengthAndKind);
683     LengthAndKind(std::optional<TypeParamValue> &&l, ScalarIntConstantExpr &&k)
684         : length(std::move(l)), kind(std::move(k)) {}
685     std::optional<TypeParamValue> length;
686     ScalarIntConstantExpr kind;
687   };
688   CharSelector(TypeParamValue &&l, ScalarIntConstantExpr &&k)
689       : u{LengthAndKind{std::make_optional(std::move(l)), std::move(k)}} {}
690   CharSelector(ScalarIntConstantExpr &&k, std::optional<TypeParamValue> &&l)
691       : u{LengthAndKind{std::move(l), std::move(k)}} {}
692   std::variant<LengthSelector, LengthAndKind> u;
693 };
694 
695 // R704 intrinsic-type-spec ->
696 //        integer-type-spec | REAL [kind-selector] | DOUBLE PRECISION |
697 //        COMPLEX [kind-selector] | CHARACTER [char-selector] |
698 //        LOGICAL [kind-selector]
699 // Extensions: DOUBLE COMPLEX & UNSIGNED [kind-selector]
700 struct IntrinsicTypeSpec {
701   UNION_CLASS_BOILERPLATE(IntrinsicTypeSpec);
702   struct Real {
703     BOILERPLATE(Real);
704     Real(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
705     std::optional<KindSelector> kind;
706   };
707   EMPTY_CLASS(DoublePrecision);
708   struct Complex {
709     BOILERPLATE(Complex);
710     Complex(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
711     std::optional<KindSelector> kind;
712   };
713   struct Character {
714     BOILERPLATE(Character);
715     Character(std::optional<CharSelector> &&s) : selector{std::move(s)} {}
716     std::optional<CharSelector> selector;
717   };
718   struct Logical {
719     BOILERPLATE(Logical);
720     Logical(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
721     std::optional<KindSelector> kind;
722   };
723   EMPTY_CLASS(DoubleComplex);
724   std::variant<IntegerTypeSpec, UnsignedTypeSpec, Real, DoublePrecision,
725       Complex, Character, Logical, DoubleComplex>
726       u;
727 };
728 
729 // Extension: Vector type
730 struct VectorElementType {
731   UNION_CLASS_BOILERPLATE(VectorElementType);
732   std::variant<IntegerTypeSpec, IntrinsicTypeSpec::Real, UnsignedTypeSpec> u;
733 };
734 WRAPPER_CLASS(IntrinsicVectorTypeSpec, VectorElementType);
735 struct VectorTypeSpec {
736   UNION_CLASS_BOILERPLATE(VectorTypeSpec);
737   EMPTY_CLASS(PairVectorTypeSpec);
738   EMPTY_CLASS(QuadVectorTypeSpec);
739   std::variant<IntrinsicVectorTypeSpec, PairVectorTypeSpec, QuadVectorTypeSpec>
740       u;
741 };
742 
743 // R755 type-param-spec -> [keyword =] type-param-value
744 struct TypeParamSpec {
745   TUPLE_CLASS_BOILERPLATE(TypeParamSpec);
746   std::tuple<std::optional<Keyword>, TypeParamValue> t;
747 };
748 
749 // R754 derived-type-spec -> type-name [(type-param-spec-list)]
750 struct DerivedTypeSpec {
751   TUPLE_CLASS_BOILERPLATE(DerivedTypeSpec);
752   mutable const semantics::DerivedTypeSpec *derivedTypeSpec{nullptr};
753   std::tuple<Name, std::list<TypeParamSpec>> t;
754 };
755 
756 // R702 type-spec -> intrinsic-type-spec | derived-type-spec
757 struct TypeSpec {
758   UNION_CLASS_BOILERPLATE(TypeSpec);
759   mutable const semantics::DeclTypeSpec *declTypeSpec{nullptr};
760   std::variant<IntrinsicTypeSpec, DerivedTypeSpec> u;
761 };
762 
763 // R703 declaration-type-spec ->
764 //        intrinsic-type-spec | TYPE ( intrinsic-type-spec ) |
765 //        TYPE ( derived-type-spec ) | CLASS ( derived-type-spec ) |
766 //        CLASS ( * ) | TYPE ( * )
767 // Legacy extension: RECORD /struct/
768 struct DeclarationTypeSpec {
769   UNION_CLASS_BOILERPLATE(DeclarationTypeSpec);
770   struct Type {
771     BOILERPLATE(Type);
772     Type(DerivedTypeSpec &&dt) : derived(std::move(dt)) {}
773     DerivedTypeSpec derived;
774   };
775   struct Class {
776     BOILERPLATE(Class);
777     Class(DerivedTypeSpec &&dt) : derived(std::move(dt)) {}
778     DerivedTypeSpec derived;
779   };
780   EMPTY_CLASS(ClassStar);
781   EMPTY_CLASS(TypeStar);
782   WRAPPER_CLASS(Record, Name);
783   std::variant<IntrinsicTypeSpec, Type, Class, ClassStar, TypeStar, Record,
784       VectorTypeSpec>
785       u;
786 };
787 
788 // R709 kind-param -> digit-string | scalar-int-constant-name
789 struct KindParam {
790   UNION_CLASS_BOILERPLATE(KindParam);
791   std::variant<std::uint64_t, Scalar<Integer<Constant<Name>>>> u;
792 };
793 
794 // R707 signed-int-literal-constant -> [sign] int-literal-constant
795 struct SignedIntLiteralConstant {
796   TUPLE_CLASS_BOILERPLATE(SignedIntLiteralConstant);
797   CharBlock source;
798   std::tuple<CharBlock, std::optional<KindParam>> t;
799 };
800 
801 // R708 int-literal-constant -> digit-string [_ kind-param]
802 struct IntLiteralConstant {
803   TUPLE_CLASS_BOILERPLATE(IntLiteralConstant);
804   std::tuple<CharBlock, std::optional<KindParam>> t;
805 };
806 
807 // extension: unsigned-literal-constant -> digit-string U [_ kind-param]
808 struct UnsignedLiteralConstant {
809   TUPLE_CLASS_BOILERPLATE(UnsignedLiteralConstant);
810   std::tuple<CharBlock, std::optional<KindParam>> t;
811 };
812 
813 // R712 sign -> + | -
814 enum class Sign { Positive, Negative };
815 
816 // R714 real-literal-constant ->
817 //        significand [exponent-letter exponent] [_ kind-param] |
818 //        digit-string exponent-letter exponent [_ kind-param]
819 // R715 significand -> digit-string . [digit-string] | . digit-string
820 // R717 exponent -> signed-digit-string
821 struct RealLiteralConstant {
822   BOILERPLATE(RealLiteralConstant);
823   struct Real {
824     COPY_AND_ASSIGN_BOILERPLATE(Real);
825     Real() {}
826     CharBlock source;
827   };
828   RealLiteralConstant(Real &&r, std::optional<KindParam> &&k)
829       : real{std::move(r)}, kind{std::move(k)} {}
830   Real real;
831   std::optional<KindParam> kind;
832 };
833 
834 // R713 signed-real-literal-constant -> [sign] real-literal-constant
835 struct SignedRealLiteralConstant {
836   TUPLE_CLASS_BOILERPLATE(SignedRealLiteralConstant);
837   std::tuple<std::optional<Sign>, RealLiteralConstant> t;
838 };
839 
840 // R719 real-part ->
841 //        signed-int-literal-constant | signed-real-literal-constant |
842 //        named-constant
843 // R720 imag-part ->
844 //        signed-int-literal-constant | signed-real-literal-constant |
845 //        named-constant
846 struct ComplexPart {
847   UNION_CLASS_BOILERPLATE(ComplexPart);
848   std::variant<SignedIntLiteralConstant, SignedRealLiteralConstant,
849       NamedConstant>
850       u;
851 };
852 
853 // R718 complex-literal-constant -> ( real-part , imag-part )
854 struct ComplexLiteralConstant {
855   TUPLE_CLASS_BOILERPLATE(ComplexLiteralConstant);
856   std::tuple<ComplexPart, ComplexPart> t; // real, imaginary
857 };
858 
859 // Extension: signed COMPLEX constant
860 struct SignedComplexLiteralConstant {
861   TUPLE_CLASS_BOILERPLATE(SignedComplexLiteralConstant);
862   std::tuple<Sign, ComplexLiteralConstant> t;
863 };
864 
865 // R724 char-literal-constant ->
866 //        [kind-param _] ' [rep-char]... ' |
867 //        [kind-param _] " [rep-char]... "
868 struct CharLiteralConstant {
869   TUPLE_CLASS_BOILERPLATE(CharLiteralConstant);
870   std::tuple<std::optional<KindParam>, std::string> t;
871   std::string GetString() const { return std::get<std::string>(t); }
872 };
873 
874 // legacy extension
875 struct HollerithLiteralConstant {
876   WRAPPER_CLASS_BOILERPLATE(HollerithLiteralConstant, std::string);
877   std::string GetString() const { return v; }
878 };
879 
880 // R725 logical-literal-constant ->
881 //        .TRUE. [_ kind-param] | .FALSE. [_ kind-param]
882 struct LogicalLiteralConstant {
883   TUPLE_CLASS_BOILERPLATE(LogicalLiteralConstant);
884   std::tuple<bool, std::optional<KindParam>> t;
885 };
886 
887 // R764 boz-literal-constant -> binary-constant | octal-constant | hex-constant
888 // R765 binary-constant -> B ' digit [digit]... ' | B " digit [digit]... "
889 // R766 octal-constant -> O ' digit [digit]... ' | O " digit [digit]... "
890 // R767 hex-constant ->
891 //        Z ' hex-digit [hex-digit]... ' | Z " hex-digit [hex-digit]... "
892 // The constant must be large enough to hold any real or integer scalar
893 // of any supported kind (F'2018 7.7).
894 WRAPPER_CLASS(BOZLiteralConstant, std::string);
895 
896 // R605 literal-constant ->
897 //        int-literal-constant | real-literal-constant |
898 //        complex-literal-constant | logical-literal-constant |
899 //        char-literal-constant | boz-literal-constant
900 struct LiteralConstant {
901   UNION_CLASS_BOILERPLATE(LiteralConstant);
902   std::variant<HollerithLiteralConstant, IntLiteralConstant,
903       RealLiteralConstant, ComplexLiteralConstant, BOZLiteralConstant,
904       CharLiteralConstant, LogicalLiteralConstant, UnsignedLiteralConstant>
905       u;
906 };
907 
908 // R807 access-spec -> PUBLIC | PRIVATE
909 struct AccessSpec {
910   ENUM_CLASS(Kind, Public, Private)
911   WRAPPER_CLASS_BOILERPLATE(AccessSpec, Kind);
912 };
913 
914 // R728 type-attr-spec ->
915 //        ABSTRACT | access-spec | BIND(C) | EXTENDS ( parent-type-name )
916 EMPTY_CLASS(Abstract);
917 struct TypeAttrSpec {
918   UNION_CLASS_BOILERPLATE(TypeAttrSpec);
919   EMPTY_CLASS(BindC);
920   WRAPPER_CLASS(Extends, Name);
921   std::variant<Abstract, AccessSpec, BindC, Extends> u;
922 };
923 
924 // R727 derived-type-stmt ->
925 //        TYPE [[, type-attr-spec-list] ::] type-name [( type-param-name-list )]
926 struct DerivedTypeStmt {
927   TUPLE_CLASS_BOILERPLATE(DerivedTypeStmt);
928   std::tuple<std::list<TypeAttrSpec>, Name, std::list<Name>> t;
929 };
930 
931 // R731 sequence-stmt -> SEQUENCE
932 EMPTY_CLASS(SequenceStmt);
933 
934 // R745 private-components-stmt -> PRIVATE
935 // R747 binding-private-stmt -> PRIVATE
936 EMPTY_CLASS(PrivateStmt);
937 
938 // R729 private-or-sequence -> private-components-stmt | sequence-stmt
939 struct PrivateOrSequence {
940   UNION_CLASS_BOILERPLATE(PrivateOrSequence);
941   std::variant<PrivateStmt, SequenceStmt> u;
942 };
943 
944 // R733 type-param-decl -> type-param-name [= scalar-int-constant-expr]
945 struct TypeParamDecl {
946   TUPLE_CLASS_BOILERPLATE(TypeParamDecl);
947   std::tuple<Name, std::optional<ScalarIntConstantExpr>> t;
948 };
949 
950 // R732 type-param-def-stmt ->
951 //        integer-type-spec , type-param-attr-spec :: type-param-decl-list
952 // R734 type-param-attr-spec -> KIND | LEN
953 struct TypeParamDefStmt {
954   TUPLE_CLASS_BOILERPLATE(TypeParamDefStmt);
955   std::tuple<IntegerTypeSpec, common::TypeParamAttr, std::list<TypeParamDecl>>
956       t;
957 };
958 
959 // R1028 specification-expr -> scalar-int-expr
960 WRAPPER_CLASS(SpecificationExpr, ScalarIntExpr);
961 
962 // R816 explicit-shape-spec -> [lower-bound :] upper-bound
963 // R817 lower-bound -> specification-expr
964 // R818 upper-bound -> specification-expr
965 struct ExplicitShapeSpec {
966   TUPLE_CLASS_BOILERPLATE(ExplicitShapeSpec);
967   std::tuple<std::optional<SpecificationExpr>, SpecificationExpr> t;
968 };
969 
970 // R810 deferred-coshape-spec -> :
971 // deferred-coshape-spec-list is just a count of the colons (i.e., the rank).
972 WRAPPER_CLASS(DeferredCoshapeSpecList, int);
973 
974 // R811 explicit-coshape-spec ->
975 //        [[lower-cobound :] upper-cobound ,]... [lower-cobound :] *
976 // R812 lower-cobound -> specification-expr
977 // R813 upper-cobound -> specification-expr
978 struct ExplicitCoshapeSpec {
979   TUPLE_CLASS_BOILERPLATE(ExplicitCoshapeSpec);
980   std::tuple<std::list<ExplicitShapeSpec>, std::optional<SpecificationExpr>> t;
981 };
982 
983 // R809 coarray-spec -> deferred-coshape-spec-list | explicit-coshape-spec
984 struct CoarraySpec {
985   UNION_CLASS_BOILERPLATE(CoarraySpec);
986   std::variant<DeferredCoshapeSpecList, ExplicitCoshapeSpec> u;
987 };
988 
989 // R820 deferred-shape-spec -> :
990 // deferred-shape-spec-list is just a count of the colons (i.e., the rank).
991 WRAPPER_CLASS(DeferredShapeSpecList, int);
992 
993 // R740 component-array-spec ->
994 //        explicit-shape-spec-list | deferred-shape-spec-list
995 struct ComponentArraySpec {
996   UNION_CLASS_BOILERPLATE(ComponentArraySpec);
997   std::variant<std::list<ExplicitShapeSpec>, DeferredShapeSpecList> u;
998 };
999 
1000 // R738 component-attr-spec ->
1001 //        access-spec | ALLOCATABLE |
1002 //        CODIMENSION lbracket coarray-spec rbracket |
1003 //        CONTIGUOUS | DIMENSION ( component-array-spec ) | POINTER |
1004 // (CUDA) CONSTANT | DEVICE | MANAGED | PINNED | SHARED | TEXTURE | UNIFIED
1005 EMPTY_CLASS(Allocatable);
1006 EMPTY_CLASS(Pointer);
1007 EMPTY_CLASS(Contiguous);
1008 struct ComponentAttrSpec {
1009   UNION_CLASS_BOILERPLATE(ComponentAttrSpec);
1010   std::variant<AccessSpec, Allocatable, CoarraySpec, Contiguous,
1011       ComponentArraySpec, Pointer, common::CUDADataAttr, ErrorRecovery>
1012       u;
1013 };
1014 
1015 // R806 null-init -> function-reference   ... which must be NULL()
1016 WRAPPER_CLASS(NullInit, common::Indirection<Expr>);
1017 
1018 // R744 initial-data-target -> designator
1019 using InitialDataTarget = common::Indirection<Designator>;
1020 
1021 // R743 component-initialization ->
1022 //        = constant-expr | => null-init | => initial-data-target
1023 // R805 initialization ->
1024 //        = constant-expr | => null-init | => initial-data-target
1025 // Universal extension: initialization -> / data-stmt-value-list /
1026 struct Initialization {
1027   UNION_CLASS_BOILERPLATE(Initialization);
1028   std::variant<ConstantExpr, NullInit, InitialDataTarget,
1029       std::list<common::Indirection<DataStmtValue>>>
1030       u;
1031 };
1032 
1033 // R739 component-decl ->
1034 //        component-name [( component-array-spec )]
1035 //          [lbracket coarray-spec rbracket] [* char-length]
1036 //          [component-initialization] |
1037 //        component-name *char-length [( component-array-spec )]
1038 //          [lbracket coarray-spec rbracket] [component-initialization]
1039 struct ComponentDecl {
1040   TUPLE_CLASS_BOILERPLATE(ComponentDecl);
1041   ComponentDecl(Name &&name, CharLength &&length,
1042       std::optional<ComponentArraySpec> &&aSpec,
1043       std::optional<CoarraySpec> &&coaSpec,
1044       std::optional<Initialization> &&init)
1045       : t{std::move(name), std::move(aSpec), std::move(coaSpec),
1046             std::move(length), std::move(init)} {}
1047   std::tuple<Name, std::optional<ComponentArraySpec>,
1048       std::optional<CoarraySpec>, std::optional<CharLength>,
1049       std::optional<Initialization>>
1050       t;
1051 };
1052 
1053 // A %FILL component for a DEC STRUCTURE.  The name will be replaced
1054 // with a distinct compiler-generated name.
1055 struct FillDecl {
1056   TUPLE_CLASS_BOILERPLATE(FillDecl);
1057   std::tuple<Name, std::optional<ComponentArraySpec>, std::optional<CharLength>>
1058       t;
1059 };
1060 
1061 struct ComponentOrFill {
1062   UNION_CLASS_BOILERPLATE(ComponentOrFill);
1063   std::variant<ComponentDecl, FillDecl> u;
1064 };
1065 
1066 // R737 data-component-def-stmt ->
1067 //        declaration-type-spec [[, component-attr-spec-list] ::]
1068 //        component-decl-list
1069 struct DataComponentDefStmt {
1070   TUPLE_CLASS_BOILERPLATE(DataComponentDefStmt);
1071   std::tuple<DeclarationTypeSpec, std::list<ComponentAttrSpec>,
1072       std::list<ComponentOrFill>>
1073       t;
1074 };
1075 
1076 // R742 proc-component-attr-spec ->
1077 //        access-spec | NOPASS | PASS [(arg-name)] | POINTER
1078 EMPTY_CLASS(NoPass);
1079 WRAPPER_CLASS(Pass, std::optional<Name>);
1080 struct ProcComponentAttrSpec {
1081   UNION_CLASS_BOILERPLATE(ProcComponentAttrSpec);
1082   std::variant<AccessSpec, NoPass, Pass, Pointer> u;
1083 };
1084 
1085 // R1517 proc-pointer-init -> null-init | initial-proc-target
1086 // R1518 initial-proc-target -> procedure-name
1087 struct ProcPointerInit {
1088   UNION_CLASS_BOILERPLATE(ProcPointerInit);
1089   std::variant<NullInit, Name> u;
1090 };
1091 
1092 // R1513 proc-interface -> interface-name | declaration-type-spec
1093 // R1516 interface-name -> name
1094 struct ProcInterface {
1095   UNION_CLASS_BOILERPLATE(ProcInterface);
1096   std::variant<Name, DeclarationTypeSpec> u;
1097 };
1098 
1099 // R1515 proc-decl -> procedure-entity-name [=> proc-pointer-init]
1100 struct ProcDecl {
1101   TUPLE_CLASS_BOILERPLATE(ProcDecl);
1102   std::tuple<Name, std::optional<ProcPointerInit>> t;
1103 };
1104 
1105 // R741 proc-component-def-stmt ->
1106 //        PROCEDURE ( [proc-interface] ) , proc-component-attr-spec-list
1107 //          :: proc-decl-list
1108 struct ProcComponentDefStmt {
1109   TUPLE_CLASS_BOILERPLATE(ProcComponentDefStmt);
1110   std::tuple<std::optional<ProcInterface>, std::list<ProcComponentAttrSpec>,
1111       std::list<ProcDecl>>
1112       t;
1113 };
1114 
1115 // R736 component-def-stmt -> data-component-def-stmt | proc-component-def-stmt
1116 struct ComponentDefStmt {
1117   UNION_CLASS_BOILERPLATE(ComponentDefStmt);
1118   std::variant<DataComponentDefStmt, ProcComponentDefStmt,
1119       common::Indirection<CompilerDirective>, ErrorRecovery
1120       // , TypeParamDefStmt -- PGI accidental extension, not enabled
1121       >
1122       u;
1123 };
1124 
1125 // R752 bind-attr ->
1126 //        access-spec | DEFERRED | NON_OVERRIDABLE | NOPASS | PASS [(arg-name)]
1127 struct BindAttr {
1128   UNION_CLASS_BOILERPLATE(BindAttr);
1129   EMPTY_CLASS(Deferred);
1130   EMPTY_CLASS(Non_Overridable);
1131   std::variant<AccessSpec, Deferred, Non_Overridable, NoPass, Pass> u;
1132 };
1133 
1134 // R750 type-bound-proc-decl -> binding-name [=> procedure-name]
1135 struct TypeBoundProcDecl {
1136   TUPLE_CLASS_BOILERPLATE(TypeBoundProcDecl);
1137   std::tuple<Name, std::optional<Name>> t;
1138 };
1139 
1140 // R749 type-bound-procedure-stmt ->
1141 //        PROCEDURE [[, bind-attr-list] ::] type-bound-proc-decl-list |
1142 //        PROCEDURE ( interface-name ) , bind-attr-list :: binding-name-list
1143 // The second form, with interface-name, requires DEFERRED in bind-attr-list,
1144 // and thus can appear only in an abstract type.
1145 struct TypeBoundProcedureStmt {
1146   UNION_CLASS_BOILERPLATE(TypeBoundProcedureStmt);
1147   struct WithoutInterface {
1148     BOILERPLATE(WithoutInterface);
1149     WithoutInterface(
1150         std::list<BindAttr> &&as, std::list<TypeBoundProcDecl> &&ds)
1151         : attributes(std::move(as)), declarations(std::move(ds)) {}
1152     std::list<BindAttr> attributes;
1153     std::list<TypeBoundProcDecl> declarations;
1154   };
1155   struct WithInterface {
1156     BOILERPLATE(WithInterface);
1157     WithInterface(Name &&n, std::list<BindAttr> &&as, std::list<Name> &&bs)
1158         : interfaceName(std::move(n)), attributes(std::move(as)),
1159           bindingNames(std::move(bs)) {}
1160     Name interfaceName;
1161     std::list<BindAttr> attributes;
1162     std::list<Name> bindingNames;
1163   };
1164   std::variant<WithoutInterface, WithInterface> u;
1165 };
1166 
1167 // R751 type-bound-generic-stmt ->
1168 //        GENERIC [, access-spec] :: generic-spec => binding-name-list
1169 struct TypeBoundGenericStmt {
1170   TUPLE_CLASS_BOILERPLATE(TypeBoundGenericStmt);
1171   std::tuple<std::optional<AccessSpec>, common::Indirection<GenericSpec>,
1172       std::list<Name>>
1173       t;
1174 };
1175 
1176 // R753 final-procedure-stmt -> FINAL [::] final-subroutine-name-list
1177 WRAPPER_CLASS(FinalProcedureStmt, std::list<Name>);
1178 
1179 // R748 type-bound-proc-binding ->
1180 //        type-bound-procedure-stmt | type-bound-generic-stmt |
1181 //        final-procedure-stmt
1182 struct TypeBoundProcBinding {
1183   UNION_CLASS_BOILERPLATE(TypeBoundProcBinding);
1184   std::variant<TypeBoundProcedureStmt, TypeBoundGenericStmt, FinalProcedureStmt,
1185       ErrorRecovery>
1186       u;
1187 };
1188 
1189 // R746 type-bound-procedure-part ->
1190 //        contains-stmt [binding-private-stmt] [type-bound-proc-binding]...
1191 struct TypeBoundProcedurePart {
1192   TUPLE_CLASS_BOILERPLATE(TypeBoundProcedurePart);
1193   std::tuple<Statement<ContainsStmt>, std::optional<Statement<PrivateStmt>>,
1194       std::list<Statement<TypeBoundProcBinding>>>
1195       t;
1196 };
1197 
1198 // R730 end-type-stmt -> END TYPE [type-name]
1199 WRAPPER_CLASS(EndTypeStmt, std::optional<Name>);
1200 
1201 // R726 derived-type-def ->
1202 //        derived-type-stmt [type-param-def-stmt]... [private-or-sequence]...
1203 //        [component-part] [type-bound-procedure-part] end-type-stmt
1204 // R735 component-part -> [component-def-stmt]...
1205 struct DerivedTypeDef {
1206   TUPLE_CLASS_BOILERPLATE(DerivedTypeDef);
1207   std::tuple<Statement<DerivedTypeStmt>, std::list<Statement<TypeParamDefStmt>>,
1208       std::list<Statement<PrivateOrSequence>>,
1209       std::list<Statement<ComponentDefStmt>>,
1210       std::optional<TypeBoundProcedurePart>, Statement<EndTypeStmt>>
1211       t;
1212 };
1213 
1214 // R758 component-data-source -> expr | data-target | proc-target
1215 // R1037 data-target -> expr
1216 // R1040 proc-target -> expr | procedure-name | proc-component-ref
1217 WRAPPER_CLASS(ComponentDataSource, common::Indirection<Expr>);
1218 
1219 // R757 component-spec -> [keyword =] component-data-source
1220 struct ComponentSpec {
1221   TUPLE_CLASS_BOILERPLATE(ComponentSpec);
1222   std::tuple<std::optional<Keyword>, ComponentDataSource> t;
1223 };
1224 
1225 // R756 structure-constructor -> derived-type-spec ( [component-spec-list] )
1226 struct StructureConstructor {
1227   TUPLE_CLASS_BOILERPLATE(StructureConstructor);
1228   std::tuple<DerivedTypeSpec, std::list<ComponentSpec>> t;
1229 };
1230 
1231 // R760 enum-def-stmt -> ENUM, BIND(C)
1232 EMPTY_CLASS(EnumDefStmt);
1233 
1234 // R762 enumerator -> named-constant [= scalar-int-constant-expr]
1235 struct Enumerator {
1236   TUPLE_CLASS_BOILERPLATE(Enumerator);
1237   std::tuple<NamedConstant, std::optional<ScalarIntConstantExpr>> t;
1238 };
1239 
1240 // R761 enumerator-def-stmt -> ENUMERATOR [::] enumerator-list
1241 WRAPPER_CLASS(EnumeratorDefStmt, std::list<Enumerator>);
1242 
1243 // R763 end-enum-stmt -> END ENUM
1244 EMPTY_CLASS(EndEnumStmt);
1245 
1246 // R759 enum-def ->
1247 //        enum-def-stmt enumerator-def-stmt [enumerator-def-stmt]...
1248 //        end-enum-stmt
1249 struct EnumDef {
1250   TUPLE_CLASS_BOILERPLATE(EnumDef);
1251   std::tuple<Statement<EnumDefStmt>, std::list<Statement<EnumeratorDefStmt>>,
1252       Statement<EndEnumStmt>>
1253       t;
1254 };
1255 
1256 // R773 ac-value -> expr | ac-implied-do
1257 struct AcValue {
1258   struct Triplet { // PGI/Intel extension
1259     TUPLE_CLASS_BOILERPLATE(Triplet);
1260     std::tuple<ScalarIntExpr, ScalarIntExpr, std::optional<ScalarIntExpr>> t;
1261   };
1262   UNION_CLASS_BOILERPLATE(AcValue);
1263   std::variant<Triplet, common::Indirection<Expr>,
1264       common::Indirection<AcImpliedDo>>
1265       u;
1266 };
1267 
1268 // R770 ac-spec -> type-spec :: | [type-spec ::] ac-value-list
1269 struct AcSpec {
1270   BOILERPLATE(AcSpec);
1271   AcSpec(std::optional<TypeSpec> &&ts, std::list<AcValue> &&xs)
1272       : type(std::move(ts)), values(std::move(xs)) {}
1273   explicit AcSpec(TypeSpec &&ts) : type{std::move(ts)} {}
1274   std::optional<TypeSpec> type;
1275   std::list<AcValue> values;
1276 };
1277 
1278 // R769 array-constructor -> (/ ac-spec /) | lbracket ac-spec rbracket
1279 WRAPPER_CLASS(ArrayConstructor, AcSpec);
1280 
1281 // R1124 do-variable -> scalar-int-variable-name
1282 using DoVariable = Scalar<Integer<Name>>;
1283 
1284 template <typename VAR, typename BOUND> struct LoopBounds {
1285   LoopBounds(LoopBounds &&that) = default;
1286   LoopBounds(
1287       VAR &&name, BOUND &&lower, BOUND &&upper, std::optional<BOUND> &&step)
1288       : name{std::move(name)}, lower{std::move(lower)}, upper{std::move(upper)},
1289         step{std::move(step)} {}
1290   LoopBounds &operator=(LoopBounds &&) = default;
1291   VAR name;
1292   BOUND lower, upper;
1293   std::optional<BOUND> step;
1294 };
1295 
1296 using ScalarName = Scalar<Name>;
1297 using ScalarExpr = Scalar<common::Indirection<Expr>>;
1298 
1299 // R775 ac-implied-do-control ->
1300 //        [integer-type-spec ::] ac-do-variable = scalar-int-expr ,
1301 //        scalar-int-expr [, scalar-int-expr]
1302 // R776 ac-do-variable -> do-variable
1303 struct AcImpliedDoControl {
1304   TUPLE_CLASS_BOILERPLATE(AcImpliedDoControl);
1305   using Bounds = LoopBounds<DoVariable, ScalarIntExpr>;
1306   std::tuple<std::optional<IntegerTypeSpec>, Bounds> t;
1307 };
1308 
1309 // R774 ac-implied-do -> ( ac-value-list , ac-implied-do-control )
1310 struct AcImpliedDo {
1311   TUPLE_CLASS_BOILERPLATE(AcImpliedDo);
1312   std::tuple<std::list<AcValue>, AcImpliedDoControl> t;
1313 };
1314 
1315 // R808 language-binding-spec ->
1316 //        BIND ( C [, NAME = scalar-default-char-constant-expr ]
1317 //                 [, CDEFINED ] )
1318 // R1528 proc-language-binding-spec -> language-binding-spec
1319 struct LanguageBindingSpec {
1320   TUPLE_CLASS_BOILERPLATE(LanguageBindingSpec);
1321   std::tuple<std::optional<ScalarDefaultCharConstantExpr>, bool> t;
1322 };
1323 
1324 // R852 named-constant-def -> named-constant = constant-expr
1325 struct NamedConstantDef {
1326   TUPLE_CLASS_BOILERPLATE(NamedConstantDef);
1327   std::tuple<NamedConstant, ConstantExpr> t;
1328 };
1329 
1330 // R851 parameter-stmt -> PARAMETER ( named-constant-def-list )
1331 WRAPPER_CLASS(ParameterStmt, std::list<NamedConstantDef>);
1332 
1333 // R819 assumed-shape-spec -> [lower-bound] :
1334 WRAPPER_CLASS(AssumedShapeSpec, std::optional<SpecificationExpr>);
1335 
1336 // R821 assumed-implied-spec -> [lower-bound :] *
1337 WRAPPER_CLASS(AssumedImpliedSpec, std::optional<SpecificationExpr>);
1338 
1339 // R822 assumed-size-spec -> explicit-shape-spec-list , assumed-implied-spec
1340 struct AssumedSizeSpec {
1341   TUPLE_CLASS_BOILERPLATE(AssumedSizeSpec);
1342   std::tuple<std::list<ExplicitShapeSpec>, AssumedImpliedSpec> t;
1343 };
1344 
1345 // R823 implied-shape-or-assumed-size-spec -> assumed-implied-spec
1346 // R824 implied-shape-spec -> assumed-implied-spec , assumed-implied-spec-list
1347 // I.e., when the assumed-implied-spec-list has a single item, it constitutes an
1348 // implied-shape-or-assumed-size-spec; otherwise, an implied-shape-spec.
1349 WRAPPER_CLASS(ImpliedShapeSpec, std::list<AssumedImpliedSpec>);
1350 
1351 // R825 assumed-rank-spec -> ..
1352 EMPTY_CLASS(AssumedRankSpec);
1353 
1354 // R815 array-spec ->
1355 //        explicit-shape-spec-list | assumed-shape-spec-list |
1356 //        deferred-shape-spec-list | assumed-size-spec | implied-shape-spec |
1357 //        implied-shape-or-assumed-size-spec | assumed-rank-spec
1358 struct ArraySpec {
1359   UNION_CLASS_BOILERPLATE(ArraySpec);
1360   std::variant<std::list<ExplicitShapeSpec>, std::list<AssumedShapeSpec>,
1361       DeferredShapeSpecList, AssumedSizeSpec, ImpliedShapeSpec, AssumedRankSpec>
1362       u;
1363 };
1364 
1365 // R826 intent-spec -> IN | OUT | INOUT
1366 struct IntentSpec {
1367   ENUM_CLASS(Intent, In, Out, InOut)
1368   WRAPPER_CLASS_BOILERPLATE(IntentSpec, Intent);
1369 };
1370 
1371 // R802 attr-spec ->
1372 //        access-spec | ALLOCATABLE | ASYNCHRONOUS |
1373 //        CODIMENSION lbracket coarray-spec rbracket | CONTIGUOUS |
1374 //        DIMENSION ( array-spec ) | EXTERNAL | INTENT ( intent-spec ) |
1375 //        INTRINSIC | language-binding-spec | OPTIONAL | PARAMETER | POINTER |
1376 //        PROTECTED | SAVE | TARGET | VALUE | VOLATILE |
1377 // (CUDA) CONSTANT | DEVICE | MANAGED | PINNED | SHARED | TEXTURE
1378 EMPTY_CLASS(Asynchronous);
1379 EMPTY_CLASS(External);
1380 EMPTY_CLASS(Intrinsic);
1381 EMPTY_CLASS(Optional);
1382 EMPTY_CLASS(Parameter);
1383 EMPTY_CLASS(Protected);
1384 EMPTY_CLASS(Save);
1385 EMPTY_CLASS(Target);
1386 EMPTY_CLASS(Value);
1387 EMPTY_CLASS(Volatile);
1388 struct AttrSpec {
1389   UNION_CLASS_BOILERPLATE(AttrSpec);
1390   std::variant<AccessSpec, Allocatable, Asynchronous, CoarraySpec, Contiguous,
1391       ArraySpec, External, IntentSpec, Intrinsic, LanguageBindingSpec, Optional,
1392       Parameter, Pointer, Protected, Save, Target, Value, Volatile,
1393       common::CUDADataAttr>
1394       u;
1395 };
1396 
1397 // R803 entity-decl ->
1398 //        object-name [( array-spec )] [lbracket coarray-spec rbracket]
1399 //          [* char-length] [initialization] |
1400 //        function-name [* char-length] |
1401 // (ext.) object-name *char-length [( array-spec )]
1402 //          [lbracket coarray-spec rbracket] [initialization]
1403 struct EntityDecl {
1404   TUPLE_CLASS_BOILERPLATE(EntityDecl);
1405   EntityDecl(ObjectName &&name, CharLength &&length,
1406       std::optional<ArraySpec> &&aSpec, std::optional<CoarraySpec> &&coaSpec,
1407       std::optional<Initialization> &&init)
1408       : t{std::move(name), std::move(aSpec), std::move(coaSpec),
1409             std::move(length), std::move(init)} {}
1410   std::tuple<ObjectName, std::optional<ArraySpec>, std::optional<CoarraySpec>,
1411       std::optional<CharLength>, std::optional<Initialization>>
1412       t;
1413 };
1414 
1415 // R801 type-declaration-stmt ->
1416 //        declaration-type-spec [[, attr-spec]... ::] entity-decl-list
1417 struct TypeDeclarationStmt {
1418   TUPLE_CLASS_BOILERPLATE(TypeDeclarationStmt);
1419   std::tuple<DeclarationTypeSpec, std::list<AttrSpec>, std::list<EntityDecl>> t;
1420 };
1421 
1422 // R828 access-id -> access-name | generic-spec
1423 // "access-name" is ambiguous with "generic-spec", so that's what's parsed
1424 WRAPPER_CLASS(AccessId, common::Indirection<GenericSpec>);
1425 
1426 // R827 access-stmt -> access-spec [[::] access-id-list]
1427 struct AccessStmt {
1428   TUPLE_CLASS_BOILERPLATE(AccessStmt);
1429   std::tuple<AccessSpec, std::list<AccessId>> t;
1430 };
1431 
1432 // R830 allocatable-decl ->
1433 //        object-name [( array-spec )] [lbracket coarray-spec rbracket]
1434 // R860 target-decl ->
1435 //        object-name [( array-spec )] [lbracket coarray-spec rbracket]
1436 struct ObjectDecl {
1437   TUPLE_CLASS_BOILERPLATE(ObjectDecl);
1438   std::tuple<ObjectName, std::optional<ArraySpec>, std::optional<CoarraySpec>>
1439       t;
1440 };
1441 
1442 // R829 allocatable-stmt -> ALLOCATABLE [::] allocatable-decl-list
1443 WRAPPER_CLASS(AllocatableStmt, std::list<ObjectDecl>);
1444 
1445 // R831 asynchronous-stmt -> ASYNCHRONOUS [::] object-name-list
1446 WRAPPER_CLASS(AsynchronousStmt, std::list<ObjectName>);
1447 
1448 // R833 bind-entity -> entity-name | / common-block-name /
1449 struct BindEntity {
1450   TUPLE_CLASS_BOILERPLATE(BindEntity);
1451   ENUM_CLASS(Kind, Object, Common)
1452   std::tuple<Kind, Name> t;
1453 };
1454 
1455 // R832 bind-stmt -> language-binding-spec [::] bind-entity-list
1456 struct BindStmt {
1457   TUPLE_CLASS_BOILERPLATE(BindStmt);
1458   std::tuple<LanguageBindingSpec, std::list<BindEntity>> t;
1459 };
1460 
1461 // R835 codimension-decl -> coarray-name lbracket coarray-spec rbracket
1462 struct CodimensionDecl {
1463   TUPLE_CLASS_BOILERPLATE(CodimensionDecl);
1464   std::tuple<Name, CoarraySpec> t;
1465 };
1466 
1467 // R834 codimension-stmt -> CODIMENSION [::] codimension-decl-list
1468 WRAPPER_CLASS(CodimensionStmt, std::list<CodimensionDecl>);
1469 
1470 // R836 contiguous-stmt -> CONTIGUOUS [::] object-name-list
1471 WRAPPER_CLASS(ContiguousStmt, std::list<ObjectName>);
1472 
1473 // R847 constant-subobject -> designator
1474 // R846 int-constant-subobject -> constant-subobject
1475 using ConstantSubobject = Constant<common::Indirection<Designator>>;
1476 
1477 // Represents an analyzed expression
1478 using TypedExpr = common::ForwardOwningPointer<evaluate::GenericExprWrapper>;
1479 
1480 // R845 data-stmt-constant ->
1481 //        scalar-constant | scalar-constant-subobject |
1482 //        signed-int-literal-constant | signed-real-literal-constant |
1483 //        null-init | initial-data-target |
1484 //        structure-constructor
1485 // N.B. Parsing ambiguities abound here without recourse to symbols
1486 // (see comments on R845's parser).
1487 struct DataStmtConstant {
1488   UNION_CLASS_BOILERPLATE(DataStmtConstant);
1489   CharBlock source;
1490   mutable TypedExpr typedExpr;
1491   std::variant<common::Indirection<CharLiteralConstantSubstring>,
1492       LiteralConstant, SignedIntLiteralConstant, SignedRealLiteralConstant,
1493       SignedComplexLiteralConstant, NullInit, common::Indirection<Designator>,
1494       StructureConstructor, UnsignedLiteralConstant>
1495       u;
1496 };
1497 
1498 // R844 data-stmt-repeat -> scalar-int-constant | scalar-int-constant-subobject
1499 // R607 int-constant -> constant
1500 // R604 constant -> literal-constant | named-constant
1501 // (only literal-constant -> int-literal-constant applies)
1502 struct DataStmtRepeat {
1503   UNION_CLASS_BOILERPLATE(DataStmtRepeat);
1504   std::variant<IntLiteralConstant, Scalar<Integer<ConstantSubobject>>> u;
1505 };
1506 
1507 // R843 data-stmt-value -> [data-stmt-repeat *] data-stmt-constant
1508 struct DataStmtValue {
1509   TUPLE_CLASS_BOILERPLATE(DataStmtValue);
1510   mutable std::int64_t repetitions{1}; // replaced during semantics
1511   std::tuple<std::optional<DataStmtRepeat>, DataStmtConstant> t;
1512 };
1513 
1514 // R841 data-i-do-object ->
1515 //        array-element | scalar-structure-component | data-implied-do
1516 struct DataIDoObject {
1517   UNION_CLASS_BOILERPLATE(DataIDoObject);
1518   std::variant<Scalar<common::Indirection<Designator>>,
1519       common::Indirection<DataImpliedDo>>
1520       u;
1521 };
1522 
1523 // R840 data-implied-do ->
1524 //        ( data-i-do-object-list , [integer-type-spec ::] data-i-do-variable
1525 //        = scalar-int-constant-expr , scalar-int-constant-expr
1526 //        [, scalar-int-constant-expr] )
1527 // R842 data-i-do-variable -> do-variable
1528 struct DataImpliedDo {
1529   TUPLE_CLASS_BOILERPLATE(DataImpliedDo);
1530   using Bounds = LoopBounds<DoVariable, ScalarIntConstantExpr>;
1531   std::tuple<std::list<DataIDoObject>, std::optional<IntegerTypeSpec>, Bounds>
1532       t;
1533 };
1534 
1535 // R839 data-stmt-object -> variable | data-implied-do
1536 struct DataStmtObject {
1537   UNION_CLASS_BOILERPLATE(DataStmtObject);
1538   std::variant<common::Indirection<Variable>, DataImpliedDo> u;
1539 };
1540 
1541 // R838 data-stmt-set -> data-stmt-object-list / data-stmt-value-list /
1542 struct DataStmtSet {
1543   TUPLE_CLASS_BOILERPLATE(DataStmtSet);
1544   std::tuple<std::list<DataStmtObject>, std::list<DataStmtValue>> t;
1545 };
1546 
1547 // R837 data-stmt -> DATA data-stmt-set [[,] data-stmt-set]...
1548 WRAPPER_CLASS(DataStmt, std::list<DataStmtSet>);
1549 
1550 // R848 dimension-stmt ->
1551 //        DIMENSION [::] array-name ( array-spec )
1552 //        [, array-name ( array-spec )]...
1553 struct DimensionStmt {
1554   struct Declaration {
1555     TUPLE_CLASS_BOILERPLATE(Declaration);
1556     std::tuple<Name, ArraySpec> t;
1557   };
1558   WRAPPER_CLASS_BOILERPLATE(DimensionStmt, std::list<Declaration>);
1559 };
1560 
1561 // R849 intent-stmt -> INTENT ( intent-spec ) [::] dummy-arg-name-list
1562 struct IntentStmt {
1563   TUPLE_CLASS_BOILERPLATE(IntentStmt);
1564   std::tuple<IntentSpec, std::list<Name>> t;
1565 };
1566 
1567 // R850 optional-stmt -> OPTIONAL [::] dummy-arg-name-list
1568 WRAPPER_CLASS(OptionalStmt, std::list<Name>);
1569 
1570 // R854 pointer-decl ->
1571 //        object-name [( deferred-shape-spec-list )] | proc-entity-name
1572 struct PointerDecl {
1573   TUPLE_CLASS_BOILERPLATE(PointerDecl);
1574   std::tuple<Name, std::optional<DeferredShapeSpecList>> t;
1575 };
1576 
1577 // R853 pointer-stmt -> POINTER [::] pointer-decl-list
1578 WRAPPER_CLASS(PointerStmt, std::list<PointerDecl>);
1579 
1580 // R855 protected-stmt -> PROTECTED [::] entity-name-list
1581 WRAPPER_CLASS(ProtectedStmt, std::list<Name>);
1582 
1583 // R857 saved-entity -> object-name | proc-pointer-name | / common-block-name /
1584 // R858 proc-pointer-name -> name
1585 struct SavedEntity {
1586   TUPLE_CLASS_BOILERPLATE(SavedEntity);
1587   ENUM_CLASS(Kind, Entity, Common)
1588   std::tuple<Kind, Name> t;
1589 };
1590 
1591 // R856 save-stmt -> SAVE [[::] saved-entity-list]
1592 WRAPPER_CLASS(SaveStmt, std::list<SavedEntity>);
1593 
1594 // R859 target-stmt -> TARGET [::] target-decl-list
1595 WRAPPER_CLASS(TargetStmt, std::list<ObjectDecl>);
1596 
1597 // R861 value-stmt -> VALUE [::] dummy-arg-name-list
1598 WRAPPER_CLASS(ValueStmt, std::list<Name>);
1599 
1600 // R862 volatile-stmt -> VOLATILE [::] object-name-list
1601 WRAPPER_CLASS(VolatileStmt, std::list<ObjectName>);
1602 
1603 // R865 letter-spec -> letter [- letter]
1604 struct LetterSpec {
1605   TUPLE_CLASS_BOILERPLATE(LetterSpec);
1606   std::tuple<Location, std::optional<Location>> t;
1607 };
1608 
1609 // R864 implicit-spec -> declaration-type-spec ( letter-spec-list )
1610 struct ImplicitSpec {
1611   TUPLE_CLASS_BOILERPLATE(ImplicitSpec);
1612   std::tuple<DeclarationTypeSpec, std::list<LetterSpec>> t;
1613 };
1614 
1615 // R863 implicit-stmt ->
1616 //        IMPLICIT implicit-spec-list |
1617 //        IMPLICIT NONE [( [implicit-name-spec-list] )]
1618 // R866 implicit-name-spec -> EXTERNAL | TYPE
1619 struct ImplicitStmt {
1620   UNION_CLASS_BOILERPLATE(ImplicitStmt);
1621   ENUM_CLASS(ImplicitNoneNameSpec, External, Type) // R866
1622   std::variant<std::list<ImplicitSpec>, std::list<ImplicitNoneNameSpec>> u;
1623 };
1624 
1625 // R874 common-block-object -> variable-name [( array-spec )]
1626 struct CommonBlockObject {
1627   TUPLE_CLASS_BOILERPLATE(CommonBlockObject);
1628   std::tuple<Name, std::optional<ArraySpec>> t;
1629 };
1630 
1631 // R873 common-stmt ->
1632 //        COMMON [/ [common-block-name] /] common-block-object-list
1633 //        [[,] / [common-block-name] / common-block-object-list]...
1634 struct CommonStmt {
1635   struct Block {
1636     TUPLE_CLASS_BOILERPLATE(Block);
1637     std::tuple<std::optional<Name>, std::list<CommonBlockObject>> t;
1638   };
1639   BOILERPLATE(CommonStmt);
1640   CommonStmt(std::optional<Name> &&, std::list<CommonBlockObject> &&,
1641       std::list<Block> &&);
1642   std::list<Block> blocks;
1643 };
1644 
1645 // R872 equivalence-object -> variable-name | array-element | substring
1646 WRAPPER_CLASS(EquivalenceObject, common::Indirection<Designator>);
1647 
1648 // R870 equivalence-stmt -> EQUIVALENCE equivalence-set-list
1649 // R871 equivalence-set -> ( equivalence-object , equivalence-object-list )
1650 WRAPPER_CLASS(EquivalenceStmt, std::list<std::list<EquivalenceObject>>);
1651 
1652 // R910 substring-range -> [scalar-int-expr] : [scalar-int-expr]
1653 struct SubstringRange {
1654   TUPLE_CLASS_BOILERPLATE(SubstringRange);
1655   std::tuple<std::optional<ScalarIntExpr>, std::optional<ScalarIntExpr>> t;
1656 };
1657 
1658 // R919 subscript -> scalar-int-expr
1659 using Subscript = ScalarIntExpr;
1660 
1661 // R921 subscript-triplet -> [subscript] : [subscript] [: stride]
1662 struct SubscriptTriplet {
1663   TUPLE_CLASS_BOILERPLATE(SubscriptTriplet);
1664   std::tuple<std::optional<Subscript>, std::optional<Subscript>,
1665       std::optional<Subscript>>
1666       t;
1667 };
1668 
1669 // R920 section-subscript -> subscript | subscript-triplet | vector-subscript
1670 // R923 vector-subscript -> int-expr
1671 struct SectionSubscript {
1672   UNION_CLASS_BOILERPLATE(SectionSubscript);
1673   std::variant<IntExpr, SubscriptTriplet> u;
1674 };
1675 
1676 // R925 cosubscript -> scalar-int-expr
1677 using Cosubscript = ScalarIntExpr;
1678 
1679 // R1115 team-value -> scalar-expr
1680 WRAPPER_CLASS(TeamValue, Scalar<common::Indirection<Expr>>);
1681 
1682 // R926 image-selector-spec ->
1683 //        STAT = stat-variable | TEAM = team-value |
1684 //        TEAM_NUMBER = scalar-int-expr
1685 struct ImageSelectorSpec {
1686   WRAPPER_CLASS(Stat, Scalar<Integer<common::Indirection<Variable>>>);
1687   WRAPPER_CLASS(Team_Number, ScalarIntExpr);
1688   UNION_CLASS_BOILERPLATE(ImageSelectorSpec);
1689   std::variant<Stat, TeamValue, Team_Number> u;
1690 };
1691 
1692 // R924 image-selector ->
1693 //        lbracket cosubscript-list [, image-selector-spec-list] rbracket
1694 struct ImageSelector {
1695   TUPLE_CLASS_BOILERPLATE(ImageSelector);
1696   std::tuple<std::list<Cosubscript>, std::list<ImageSelectorSpec>> t;
1697 };
1698 
1699 // R1001 - R1022 expressions
1700 struct Expr {
1701   UNION_CLASS_BOILERPLATE(Expr);
1702 
1703   WRAPPER_CLASS(IntrinsicUnary, common::Indirection<Expr>);
1704   struct Parentheses : public IntrinsicUnary {
1705     using IntrinsicUnary::IntrinsicUnary;
1706   };
1707   struct UnaryPlus : public IntrinsicUnary {
1708     using IntrinsicUnary::IntrinsicUnary;
1709   };
1710   struct Negate : public IntrinsicUnary {
1711     using IntrinsicUnary::IntrinsicUnary;
1712   };
1713   struct NOT : public IntrinsicUnary {
1714     using IntrinsicUnary::IntrinsicUnary;
1715   };
1716 
1717   WRAPPER_CLASS(PercentLoc, common::Indirection<Variable>); // %LOC(v) extension
1718 
1719   struct DefinedUnary {
1720     TUPLE_CLASS_BOILERPLATE(DefinedUnary);
1721     std::tuple<DefinedOpName, common::Indirection<Expr>> t;
1722   };
1723 
1724   struct IntrinsicBinary {
1725     TUPLE_CLASS_BOILERPLATE(IntrinsicBinary);
1726     std::tuple<common::Indirection<Expr>, common::Indirection<Expr>> t;
1727   };
1728   struct Power : public IntrinsicBinary {
1729     using IntrinsicBinary::IntrinsicBinary;
1730   };
1731   struct Multiply : public IntrinsicBinary {
1732     using IntrinsicBinary::IntrinsicBinary;
1733   };
1734   struct Divide : public IntrinsicBinary {
1735     using IntrinsicBinary::IntrinsicBinary;
1736   };
1737   struct Add : public IntrinsicBinary {
1738     using IntrinsicBinary::IntrinsicBinary;
1739   };
1740   struct Subtract : public IntrinsicBinary {
1741     using IntrinsicBinary::IntrinsicBinary;
1742   };
1743   struct Concat : public IntrinsicBinary {
1744     using IntrinsicBinary::IntrinsicBinary;
1745   };
1746   struct LT : public IntrinsicBinary {
1747     using IntrinsicBinary::IntrinsicBinary;
1748   };
1749   struct LE : public IntrinsicBinary {
1750     using IntrinsicBinary::IntrinsicBinary;
1751   };
1752   struct EQ : public IntrinsicBinary {
1753     using IntrinsicBinary::IntrinsicBinary;
1754   };
1755   struct NE : public IntrinsicBinary {
1756     using IntrinsicBinary::IntrinsicBinary;
1757   };
1758   struct GE : public IntrinsicBinary {
1759     using IntrinsicBinary::IntrinsicBinary;
1760   };
1761   struct GT : public IntrinsicBinary {
1762     using IntrinsicBinary::IntrinsicBinary;
1763   };
1764   struct AND : public IntrinsicBinary {
1765     using IntrinsicBinary::IntrinsicBinary;
1766   };
1767   struct OR : public IntrinsicBinary {
1768     using IntrinsicBinary::IntrinsicBinary;
1769   };
1770   struct EQV : public IntrinsicBinary {
1771     using IntrinsicBinary::IntrinsicBinary;
1772   };
1773   struct NEQV : public IntrinsicBinary {
1774     using IntrinsicBinary::IntrinsicBinary;
1775   };
1776 
1777   // PGI/XLF extension: (x,y), not both constant
1778   struct ComplexConstructor : public IntrinsicBinary {
1779     using IntrinsicBinary::IntrinsicBinary;
1780   };
1781 
1782   struct DefinedBinary {
1783     TUPLE_CLASS_BOILERPLATE(DefinedBinary);
1784     std::tuple<DefinedOpName, common::Indirection<Expr>,
1785         common::Indirection<Expr>>
1786         t;
1787   };
1788 
1789   explicit Expr(Designator &&);
1790   explicit Expr(FunctionReference &&);
1791 
1792   mutable TypedExpr typedExpr;
1793 
1794   CharBlock source;
1795 
1796   std::variant<common::Indirection<CharLiteralConstantSubstring>,
1797       LiteralConstant, common::Indirection<Designator>, ArrayConstructor,
1798       StructureConstructor, common::Indirection<FunctionReference>, Parentheses,
1799       UnaryPlus, Negate, NOT, PercentLoc, DefinedUnary, Power, Multiply, Divide,
1800       Add, Subtract, Concat, LT, LE, EQ, NE, GE, GT, AND, OR, EQV, NEQV,
1801       DefinedBinary, ComplexConstructor, common::Indirection<SubstringInquiry>>
1802       u;
1803 };
1804 
1805 // R912 part-ref -> part-name [( section-subscript-list )] [image-selector]
1806 struct PartRef {
1807   BOILERPLATE(PartRef);
1808   PartRef(Name &&n, std::list<SectionSubscript> &&ss,
1809       std::optional<ImageSelector> &&is)
1810       : name{std::move(n)}, subscripts(std::move(ss)),
1811         imageSelector{std::move(is)} {}
1812   Name name;
1813   std::list<SectionSubscript> subscripts;
1814   std::optional<ImageSelector> imageSelector;
1815 };
1816 
1817 // R911 data-ref -> part-ref [% part-ref]...
1818 struct DataRef {
1819   UNION_CLASS_BOILERPLATE(DataRef);
1820   explicit DataRef(std::list<PartRef> &&);
1821   std::variant<Name, common::Indirection<StructureComponent>,
1822       common::Indirection<ArrayElement>,
1823       common::Indirection<CoindexedNamedObject>>
1824       u;
1825 };
1826 
1827 // R908 substring -> parent-string ( substring-range )
1828 // R909 parent-string ->
1829 //        scalar-variable-name | array-element | coindexed-named-object |
1830 //        scalar-structure-component | scalar-char-literal-constant |
1831 //        scalar-named-constant
1832 // Substrings of character literals have been factored out into their
1833 // own productions so that they can't appear as designators in any context
1834 // other than a primary expression.
1835 struct Substring {
1836   TUPLE_CLASS_BOILERPLATE(Substring);
1837   std::tuple<DataRef, SubstringRange> t;
1838 };
1839 
1840 struct CharLiteralConstantSubstring {
1841   TUPLE_CLASS_BOILERPLATE(CharLiteralConstantSubstring);
1842   std::tuple<CharLiteralConstant, SubstringRange> t;
1843 };
1844 
1845 // substring%KIND/LEN type parameter inquiry for cases that could not be
1846 // parsed as part-refs and fixed up afterwards.  N.B. we only have to
1847 // handle inquiries into designator-based substrings, not those based on
1848 // char-literal-constants.
1849 struct SubstringInquiry {
1850   CharBlock source;
1851   WRAPPER_CLASS_BOILERPLATE(SubstringInquiry, Substring);
1852 };
1853 
1854 // R901 designator -> object-name | array-element | array-section |
1855 //                    coindexed-named-object | complex-part-designator |
1856 //                    structure-component | substring
1857 struct Designator {
1858   UNION_CLASS_BOILERPLATE(Designator);
1859   bool EndsInBareName() const;
1860   CharBlock source;
1861   std::variant<DataRef, Substring> u;
1862 };
1863 
1864 // R902 variable -> designator | function-reference
1865 struct Variable {
1866   UNION_CLASS_BOILERPLATE(Variable);
1867   mutable TypedExpr typedExpr;
1868   CharBlock GetSource() const;
1869   std::variant<common::Indirection<Designator>,
1870       common::Indirection<FunctionReference>>
1871       u;
1872 };
1873 
1874 // R904 logical-variable -> variable
1875 // Appears only as part of scalar-logical-variable.
1876 using ScalarLogicalVariable = Scalar<Logical<Variable>>;
1877 
1878 // R906 default-char-variable -> variable
1879 // Appears only as part of scalar-default-char-variable.
1880 using ScalarDefaultCharVariable = Scalar<DefaultChar<Variable>>;
1881 
1882 // R907 int-variable -> variable
1883 // Appears only as part of scalar-int-variable.
1884 using ScalarIntVariable = Scalar<Integer<Variable>>;
1885 
1886 // R913 structure-component -> data-ref
1887 struct StructureComponent {
1888   BOILERPLATE(StructureComponent);
1889   StructureComponent(DataRef &&dr, Name &&n)
1890       : base{std::move(dr)}, component(std::move(n)) {}
1891   DataRef base;
1892   Name component;
1893 };
1894 
1895 // R1039 proc-component-ref -> scalar-variable % procedure-component-name
1896 // C1027 constrains the scalar-variable to be a data-ref without coindices.
1897 struct ProcComponentRef {
1898   WRAPPER_CLASS_BOILERPLATE(ProcComponentRef, Scalar<StructureComponent>);
1899 };
1900 
1901 // R914 coindexed-named-object -> data-ref
1902 struct CoindexedNamedObject {
1903   BOILERPLATE(CoindexedNamedObject);
1904   CoindexedNamedObject(DataRef &&dr, ImageSelector &&is)
1905       : base{std::move(dr)}, imageSelector{std::move(is)} {}
1906   DataRef base;
1907   ImageSelector imageSelector;
1908 };
1909 
1910 // R917 array-element -> data-ref
1911 struct ArrayElement {
1912   BOILERPLATE(ArrayElement);
1913   ArrayElement(DataRef &&dr, std::list<SectionSubscript> &&ss)
1914       : base{std::move(dr)}, subscripts(std::move(ss)) {}
1915   Substring ConvertToSubstring();
1916   StructureConstructor ConvertToStructureConstructor(
1917       const semantics::DerivedTypeSpec &);
1918   DataRef base;
1919   std::list<SectionSubscript> subscripts;
1920 };
1921 
1922 // R933 allocate-object -> variable-name | structure-component
1923 struct AllocateObject {
1924   UNION_CLASS_BOILERPLATE(AllocateObject);
1925   mutable TypedExpr typedExpr;
1926   std::variant<Name, StructureComponent> u;
1927 };
1928 
1929 // R935 lower-bound-expr -> scalar-int-expr
1930 // R936 upper-bound-expr -> scalar-int-expr
1931 using BoundExpr = ScalarIntExpr;
1932 
1933 // R934 allocate-shape-spec -> [lower-bound-expr :] upper-bound-expr
1934 // R938 allocate-coshape-spec -> [lower-bound-expr :] upper-bound-expr
1935 struct AllocateShapeSpec {
1936   TUPLE_CLASS_BOILERPLATE(AllocateShapeSpec);
1937   std::tuple<std::optional<BoundExpr>, BoundExpr> t;
1938 };
1939 
1940 using AllocateCoshapeSpec = AllocateShapeSpec;
1941 
1942 // R937 allocate-coarray-spec ->
1943 //      [allocate-coshape-spec-list ,] [lower-bound-expr :] *
1944 struct AllocateCoarraySpec {
1945   TUPLE_CLASS_BOILERPLATE(AllocateCoarraySpec);
1946   std::tuple<std::list<AllocateCoshapeSpec>, std::optional<BoundExpr>> t;
1947 };
1948 
1949 // R932 allocation ->
1950 //        allocate-object [( allocate-shape-spec-list )]
1951 //        [lbracket allocate-coarray-spec rbracket]
1952 struct Allocation {
1953   TUPLE_CLASS_BOILERPLATE(Allocation);
1954   std::tuple<AllocateObject, std::list<AllocateShapeSpec>,
1955       std::optional<AllocateCoarraySpec>>
1956       t;
1957 };
1958 
1959 // R929 stat-variable -> scalar-int-variable
1960 WRAPPER_CLASS(StatVariable, ScalarIntVariable);
1961 
1962 // R930 errmsg-variable -> scalar-default-char-variable
1963 // R1207 iomsg-variable -> scalar-default-char-variable
1964 WRAPPER_CLASS(MsgVariable, ScalarDefaultCharVariable);
1965 
1966 // R942 dealloc-opt -> STAT = stat-variable | ERRMSG = errmsg-variable
1967 // R1165 sync-stat -> STAT = stat-variable | ERRMSG = errmsg-variable
1968 struct StatOrErrmsg {
1969   UNION_CLASS_BOILERPLATE(StatOrErrmsg);
1970   std::variant<StatVariable, MsgVariable> u;
1971 };
1972 
1973 // R928 alloc-opt ->
1974 //        ERRMSG = errmsg-variable | MOLD = source-expr |
1975 //        SOURCE = source-expr | STAT = stat-variable |
1976 // (CUDA) STREAM = scalar-int-expr
1977 //        PINNED = scalar-logical-variable
1978 // R931 source-expr -> expr
1979 struct AllocOpt {
1980   UNION_CLASS_BOILERPLATE(AllocOpt);
1981   WRAPPER_CLASS(Mold, common::Indirection<Expr>);
1982   WRAPPER_CLASS(Source, common::Indirection<Expr>);
1983   WRAPPER_CLASS(Stream, common::Indirection<ScalarIntExpr>);
1984   WRAPPER_CLASS(Pinned, common::Indirection<ScalarLogicalVariable>);
1985   std::variant<Mold, Source, StatOrErrmsg, Stream, Pinned> u;
1986 };
1987 
1988 // R927 allocate-stmt ->
1989 //        ALLOCATE ( [type-spec ::] allocation-list [, alloc-opt-list] )
1990 struct AllocateStmt {
1991   TUPLE_CLASS_BOILERPLATE(AllocateStmt);
1992   std::tuple<std::optional<TypeSpec>, std::list<Allocation>,
1993       std::list<AllocOpt>>
1994       t;
1995 };
1996 
1997 // R940 pointer-object ->
1998 //        variable-name | structure-component | proc-pointer-name
1999 struct PointerObject {
2000   UNION_CLASS_BOILERPLATE(PointerObject);
2001   mutable TypedExpr typedExpr;
2002   std::variant<Name, StructureComponent> u;
2003 };
2004 
2005 // R939 nullify-stmt -> NULLIFY ( pointer-object-list )
2006 WRAPPER_CLASS(NullifyStmt, std::list<PointerObject>);
2007 
2008 // R941 deallocate-stmt ->
2009 //        DEALLOCATE ( allocate-object-list [, dealloc-opt-list] )
2010 struct DeallocateStmt {
2011   TUPLE_CLASS_BOILERPLATE(DeallocateStmt);
2012   std::tuple<std::list<AllocateObject>, std::list<StatOrErrmsg>> t;
2013 };
2014 
2015 // R1032 assignment-stmt -> variable = expr
2016 struct AssignmentStmt {
2017   TUPLE_CLASS_BOILERPLATE(AssignmentStmt);
2018   using TypedAssignment =
2019       common::ForwardOwningPointer<evaluate::GenericAssignmentWrapper>;
2020   mutable TypedAssignment typedAssignment;
2021   std::tuple<Variable, Expr> t;
2022 };
2023 
2024 // R1035 bounds-spec -> lower-bound-expr :
2025 WRAPPER_CLASS(BoundsSpec, BoundExpr);
2026 
2027 // R1036 bounds-remapping -> lower-bound-expr : upper-bound-expr
2028 struct BoundsRemapping {
2029   TUPLE_CLASS_BOILERPLATE(BoundsRemapping);
2030   std::tuple<BoundExpr, BoundExpr> t;
2031 };
2032 
2033 // R1033 pointer-assignment-stmt ->
2034 //         data-pointer-object [( bounds-spec-list )] => data-target |
2035 //         data-pointer-object ( bounds-remapping-list ) => data-target |
2036 //         proc-pointer-object => proc-target
2037 // R1034 data-pointer-object ->
2038 //         variable-name | scalar-variable % data-pointer-component-name
2039 // R1038 proc-pointer-object -> proc-pointer-name | proc-component-ref
2040 struct PointerAssignmentStmt {
2041   struct Bounds {
2042     UNION_CLASS_BOILERPLATE(Bounds);
2043     std::variant<std::list<BoundsRemapping>, std::list<BoundsSpec>> u;
2044   };
2045   TUPLE_CLASS_BOILERPLATE(PointerAssignmentStmt);
2046   mutable AssignmentStmt::TypedAssignment typedAssignment;
2047   std::tuple<DataRef, Bounds, Expr> t;
2048 };
2049 
2050 // R1041 where-stmt -> WHERE ( mask-expr ) where-assignment-stmt
2051 // R1045 where-assignment-stmt -> assignment-stmt
2052 // R1046 mask-expr -> logical-expr
2053 struct WhereStmt {
2054   TUPLE_CLASS_BOILERPLATE(WhereStmt);
2055   std::tuple<LogicalExpr, AssignmentStmt> t;
2056 };
2057 
2058 // R1043 where-construct-stmt -> [where-construct-name :] WHERE ( mask-expr )
2059 struct WhereConstructStmt {
2060   TUPLE_CLASS_BOILERPLATE(WhereConstructStmt);
2061   std::tuple<std::optional<Name>, LogicalExpr> t;
2062 };
2063 
2064 // R1044 where-body-construct ->
2065 //         where-assignment-stmt | where-stmt | where-construct
2066 struct WhereBodyConstruct {
2067   UNION_CLASS_BOILERPLATE(WhereBodyConstruct);
2068   std::variant<Statement<AssignmentStmt>, Statement<WhereStmt>,
2069       common::Indirection<WhereConstruct>>
2070       u;
2071 };
2072 
2073 // R1047 masked-elsewhere-stmt ->
2074 //         ELSEWHERE ( mask-expr ) [where-construct-name]
2075 struct MaskedElsewhereStmt {
2076   TUPLE_CLASS_BOILERPLATE(MaskedElsewhereStmt);
2077   std::tuple<LogicalExpr, std::optional<Name>> t;
2078 };
2079 
2080 // R1048 elsewhere-stmt -> ELSEWHERE [where-construct-name]
2081 WRAPPER_CLASS(ElsewhereStmt, std::optional<Name>);
2082 
2083 // R1049 end-where-stmt -> END WHERE [where-construct-name]
2084 WRAPPER_CLASS(EndWhereStmt, std::optional<Name>);
2085 
2086 // R1042 where-construct ->
2087 //         where-construct-stmt [where-body-construct]...
2088 //         [masked-elsewhere-stmt [where-body-construct]...]...
2089 //         [elsewhere-stmt [where-body-construct]...] end-where-stmt
2090 struct WhereConstruct {
2091   struct MaskedElsewhere {
2092     TUPLE_CLASS_BOILERPLATE(MaskedElsewhere);
2093     std::tuple<Statement<MaskedElsewhereStmt>, std::list<WhereBodyConstruct>> t;
2094   };
2095   struct Elsewhere {
2096     TUPLE_CLASS_BOILERPLATE(Elsewhere);
2097     std::tuple<Statement<ElsewhereStmt>, std::list<WhereBodyConstruct>> t;
2098   };
2099   TUPLE_CLASS_BOILERPLATE(WhereConstruct);
2100   std::tuple<Statement<WhereConstructStmt>, std::list<WhereBodyConstruct>,
2101       std::list<MaskedElsewhere>, std::optional<Elsewhere>,
2102       Statement<EndWhereStmt>>
2103       t;
2104 };
2105 
2106 // R1051 forall-construct-stmt ->
2107 //         [forall-construct-name :] FORALL concurrent-header
2108 struct ForallConstructStmt {
2109   TUPLE_CLASS_BOILERPLATE(ForallConstructStmt);
2110   std::tuple<std::optional<Name>, common::Indirection<ConcurrentHeader>> t;
2111 };
2112 
2113 // R1053 forall-assignment-stmt -> assignment-stmt | pointer-assignment-stmt
2114 struct ForallAssignmentStmt {
2115   UNION_CLASS_BOILERPLATE(ForallAssignmentStmt);
2116   std::variant<AssignmentStmt, PointerAssignmentStmt> u;
2117 };
2118 
2119 // R1055 forall-stmt -> FORALL concurrent-header forall-assignment-stmt
2120 struct ForallStmt {
2121   TUPLE_CLASS_BOILERPLATE(ForallStmt);
2122   std::tuple<common::Indirection<ConcurrentHeader>,
2123       UnlabeledStatement<ForallAssignmentStmt>>
2124       t;
2125 };
2126 
2127 // R1052 forall-body-construct ->
2128 //         forall-assignment-stmt | where-stmt | where-construct |
2129 //         forall-construct | forall-stmt
2130 struct ForallBodyConstruct {
2131   UNION_CLASS_BOILERPLATE(ForallBodyConstruct);
2132   std::variant<Statement<ForallAssignmentStmt>, Statement<WhereStmt>,
2133       WhereConstruct, common::Indirection<ForallConstruct>,
2134       Statement<ForallStmt>>
2135       u;
2136 };
2137 
2138 // R1054 end-forall-stmt -> END FORALL [forall-construct-name]
2139 WRAPPER_CLASS(EndForallStmt, std::optional<Name>);
2140 
2141 // R1050 forall-construct ->
2142 //         forall-construct-stmt [forall-body-construct]... end-forall-stmt
2143 struct ForallConstruct {
2144   TUPLE_CLASS_BOILERPLATE(ForallConstruct);
2145   std::tuple<Statement<ForallConstructStmt>, std::list<ForallBodyConstruct>,
2146       Statement<EndForallStmt>>
2147       t;
2148 };
2149 
2150 // R1105 selector -> expr | variable
2151 struct Selector {
2152   UNION_CLASS_BOILERPLATE(Selector);
2153   std::variant<Expr, Variable> u;
2154 };
2155 
2156 // R1104 association -> associate-name => selector
2157 struct Association {
2158   TUPLE_CLASS_BOILERPLATE(Association);
2159   std::tuple<Name, Selector> t;
2160 };
2161 
2162 // R1103 associate-stmt ->
2163 //        [associate-construct-name :] ASSOCIATE ( association-list )
2164 struct AssociateStmt {
2165   TUPLE_CLASS_BOILERPLATE(AssociateStmt);
2166   std::tuple<std::optional<Name>, std::list<Association>> t;
2167 };
2168 
2169 // R1106 end-associate-stmt -> END ASSOCIATE [associate-construct-name]
2170 WRAPPER_CLASS(EndAssociateStmt, std::optional<Name>);
2171 
2172 // R1102 associate-construct -> associate-stmt block end-associate-stmt
2173 struct AssociateConstruct {
2174   TUPLE_CLASS_BOILERPLATE(AssociateConstruct);
2175   std::tuple<Statement<AssociateStmt>, Block, Statement<EndAssociateStmt>> t;
2176 };
2177 
2178 // R1108 block-stmt -> [block-construct-name :] BLOCK
2179 WRAPPER_CLASS(BlockStmt, std::optional<Name>);
2180 
2181 // R1110 end-block-stmt -> END BLOCK [block-construct-name]
2182 WRAPPER_CLASS(EndBlockStmt, std::optional<Name>);
2183 
2184 // R1109 block-specification-part ->
2185 //         [use-stmt]... [import-stmt]...
2186 //         [[declaration-construct]... specification-construct]
2187 // N.B. Because BlockSpecificationPart just wraps the more general
2188 // SpecificationPart, it can misrecognize an ImplicitPart as part of
2189 // the BlockSpecificationPart during parsing, and we have to detect and
2190 // flag such usage in semantics.
2191 WRAPPER_CLASS(BlockSpecificationPart, SpecificationPart);
2192 
2193 // R1107 block-construct ->
2194 //         block-stmt [block-specification-part] block end-block-stmt
2195 struct BlockConstruct {
2196   TUPLE_CLASS_BOILERPLATE(BlockConstruct);
2197   std::tuple<Statement<BlockStmt>, BlockSpecificationPart, Block,
2198       Statement<EndBlockStmt>>
2199       t;
2200 };
2201 
2202 // R1113 coarray-association -> codimension-decl => selector
2203 struct CoarrayAssociation {
2204   TUPLE_CLASS_BOILERPLATE(CoarrayAssociation);
2205   std::tuple<CodimensionDecl, Selector> t;
2206 };
2207 
2208 // R1112 change-team-stmt ->
2209 //         [team-construct-name :] CHANGE TEAM
2210 //         ( team-value [, coarray-association-list] [, sync-stat-list] )
2211 struct ChangeTeamStmt {
2212   TUPLE_CLASS_BOILERPLATE(ChangeTeamStmt);
2213   std::tuple<std::optional<Name>, TeamValue, std::list<CoarrayAssociation>,
2214       std::list<StatOrErrmsg>>
2215       t;
2216 };
2217 
2218 // R1114 end-change-team-stmt ->
2219 //         END TEAM [( [sync-stat-list] )] [team-construct-name]
2220 struct EndChangeTeamStmt {
2221   TUPLE_CLASS_BOILERPLATE(EndChangeTeamStmt);
2222   std::tuple<std::list<StatOrErrmsg>, std::optional<Name>> t;
2223 };
2224 
2225 // R1111 change-team-construct -> change-team-stmt block end-change-team-stmt
2226 struct ChangeTeamConstruct {
2227   TUPLE_CLASS_BOILERPLATE(ChangeTeamConstruct);
2228   std::tuple<Statement<ChangeTeamStmt>, Block, Statement<EndChangeTeamStmt>> t;
2229 };
2230 
2231 // R1117 critical-stmt ->
2232 //         [critical-construct-name :] CRITICAL [( [sync-stat-list] )]
2233 struct CriticalStmt {
2234   TUPLE_CLASS_BOILERPLATE(CriticalStmt);
2235   std::tuple<std::optional<Name>, std::list<StatOrErrmsg>> t;
2236 };
2237 
2238 // R1118 end-critical-stmt -> END CRITICAL [critical-construct-name]
2239 WRAPPER_CLASS(EndCriticalStmt, std::optional<Name>);
2240 
2241 // R1116 critical-construct -> critical-stmt block end-critical-stmt
2242 struct CriticalConstruct {
2243   TUPLE_CLASS_BOILERPLATE(CriticalConstruct);
2244   std::tuple<Statement<CriticalStmt>, Block, Statement<EndCriticalStmt>> t;
2245 };
2246 
2247 // R1126 concurrent-control ->
2248 //         index-name = concurrent-limit : concurrent-limit [: concurrent-step]
2249 // R1127 concurrent-limit -> scalar-int-expr
2250 // R1128 concurrent-step -> scalar-int-expr
2251 struct ConcurrentControl {
2252   TUPLE_CLASS_BOILERPLATE(ConcurrentControl);
2253   std::tuple<Name, ScalarIntExpr, ScalarIntExpr, std::optional<ScalarIntExpr>>
2254       t;
2255 };
2256 
2257 // R1125 concurrent-header ->
2258 //         ( [integer-type-spec ::] concurrent-control-list
2259 //         [, scalar-mask-expr] )
2260 struct ConcurrentHeader {
2261   TUPLE_CLASS_BOILERPLATE(ConcurrentHeader);
2262   std::tuple<std::optional<IntegerTypeSpec>, std::list<ConcurrentControl>,
2263       std::optional<ScalarLogicalExpr>>
2264       t;
2265 };
2266 
2267 // F'2023 R1131 reduce-operation -> reduction-operator
2268 // CUF reduction-op -> reduction-operator
2269 // OpenACC 3.3 2.5.15 reduction-operator ->
2270 //                      + | * | .AND. | .OR. | .EQV. | .NEQV. |
2271 //                      MAX | MIN | IAND | IOR | IEOR
2272 struct ReductionOperator {
2273   ENUM_CLASS(
2274       Operator, Plus, Multiply, Max, Min, Iand, Ior, Ieor, And, Or, Eqv, Neqv)
2275   WRAPPER_CLASS_BOILERPLATE(ReductionOperator, Operator);
2276   CharBlock source;
2277 };
2278 
2279 // R1130 locality-spec ->
2280 //         LOCAL ( variable-name-list ) | LOCAL_INIT ( variable-name-list ) |
2281 //         REDUCE ( reduce-operation : variable-name-list ) |
2282 //         SHARED ( variable-name-list ) | DEFAULT ( NONE )
2283 struct LocalitySpec {
2284   UNION_CLASS_BOILERPLATE(LocalitySpec);
2285   WRAPPER_CLASS(Local, std::list<Name>);
2286   WRAPPER_CLASS(LocalInit, std::list<Name>);
2287   struct Reduce {
2288     TUPLE_CLASS_BOILERPLATE(Reduce);
2289     using Operator = ReductionOperator;
2290     std::tuple<Operator, std::list<Name>> t;
2291   };
2292   WRAPPER_CLASS(Shared, std::list<Name>);
2293   EMPTY_CLASS(DefaultNone);
2294   std::variant<Local, LocalInit, Reduce, Shared, DefaultNone> u;
2295 };
2296 
2297 // R1123 loop-control ->
2298 //         [,] do-variable = scalar-int-expr , scalar-int-expr
2299 //           [, scalar-int-expr] |
2300 //         [,] WHILE ( scalar-logical-expr ) |
2301 //         [,] CONCURRENT concurrent-header concurrent-locality
2302 // R1129 concurrent-locality -> [locality-spec]...
2303 struct LoopControl {
2304   UNION_CLASS_BOILERPLATE(LoopControl);
2305   struct Concurrent {
2306     TUPLE_CLASS_BOILERPLATE(Concurrent);
2307     std::tuple<ConcurrentHeader, std::list<LocalitySpec>> t;
2308   };
2309   using Bounds = LoopBounds<ScalarName, ScalarExpr>;
2310   std::variant<Bounds, ScalarLogicalExpr, Concurrent> u;
2311 };
2312 
2313 // R1121 label-do-stmt -> [do-construct-name :] DO label [loop-control]
2314 // A label-do-stmt with a do-construct-name is parsed as a non-label-do-stmt.
2315 struct LabelDoStmt {
2316   TUPLE_CLASS_BOILERPLATE(LabelDoStmt);
2317   std::tuple<Label, std::optional<LoopControl>> t;
2318 };
2319 
2320 // R1122 nonlabel-do-stmt -> [do-construct-name :] DO [loop-control]
2321 struct NonLabelDoStmt {
2322   TUPLE_CLASS_BOILERPLATE(NonLabelDoStmt);
2323   std::tuple<std::optional<Name>, std::optional<Label>,
2324       std::optional<LoopControl>>
2325       t;
2326 };
2327 
2328 // R1132 end-do-stmt -> END DO [do-construct-name]
2329 WRAPPER_CLASS(EndDoStmt, std::optional<Name>);
2330 
2331 // R1131 end-do -> end-do-stmt | continue-stmt
2332 
2333 // R1119 do-construct -> do-stmt block end-do
2334 // R1120 do-stmt -> nonlabel-do-stmt | label-do-stmt
2335 // Deprecated, but supported: "label DO" loops ending on statements other
2336 // than END DO and CONTINUE, and multiple "label DO" loops ending on the
2337 // same label.
2338 struct DoConstruct {
2339   TUPLE_CLASS_BOILERPLATE(DoConstruct);
2340   const std::optional<LoopControl> &GetLoopControl() const;
2341   bool IsDoNormal() const;
2342   bool IsDoWhile() const;
2343   bool IsDoConcurrent() const;
2344   std::tuple<Statement<NonLabelDoStmt>, Block, Statement<EndDoStmt>> t;
2345 };
2346 
2347 // R1133 cycle-stmt -> CYCLE [do-construct-name]
2348 WRAPPER_CLASS(CycleStmt, std::optional<Name>);
2349 
2350 // R1135 if-then-stmt -> [if-construct-name :] IF ( scalar-logical-expr ) THEN
2351 struct IfThenStmt {
2352   TUPLE_CLASS_BOILERPLATE(IfThenStmt);
2353   std::tuple<std::optional<Name>, ScalarLogicalExpr> t;
2354 };
2355 
2356 // R1136 else-if-stmt ->
2357 //         ELSE IF ( scalar-logical-expr ) THEN [if-construct-name]
2358 struct ElseIfStmt {
2359   TUPLE_CLASS_BOILERPLATE(ElseIfStmt);
2360   std::tuple<ScalarLogicalExpr, std::optional<Name>> t;
2361 };
2362 
2363 // R1137 else-stmt -> ELSE [if-construct-name]
2364 WRAPPER_CLASS(ElseStmt, std::optional<Name>);
2365 
2366 // R1138 end-if-stmt -> END IF [if-construct-name]
2367 WRAPPER_CLASS(EndIfStmt, std::optional<Name>);
2368 
2369 // R1134 if-construct ->
2370 //         if-then-stmt block [else-if-stmt block]...
2371 //         [else-stmt block] end-if-stmt
2372 struct IfConstruct {
2373   struct ElseIfBlock {
2374     TUPLE_CLASS_BOILERPLATE(ElseIfBlock);
2375     std::tuple<Statement<ElseIfStmt>, Block> t;
2376   };
2377   struct ElseBlock {
2378     TUPLE_CLASS_BOILERPLATE(ElseBlock);
2379     std::tuple<Statement<ElseStmt>, Block> t;
2380   };
2381   TUPLE_CLASS_BOILERPLATE(IfConstruct);
2382   std::tuple<Statement<IfThenStmt>, Block, std::list<ElseIfBlock>,
2383       std::optional<ElseBlock>, Statement<EndIfStmt>>
2384       t;
2385 };
2386 
2387 // R1139 if-stmt -> IF ( scalar-logical-expr ) action-stmt
2388 struct IfStmt {
2389   TUPLE_CLASS_BOILERPLATE(IfStmt);
2390   std::tuple<ScalarLogicalExpr, UnlabeledStatement<ActionStmt>> t;
2391 };
2392 
2393 // R1141 select-case-stmt -> [case-construct-name :] SELECT CASE ( case-expr )
2394 // R1144 case-expr -> scalar-expr
2395 struct SelectCaseStmt {
2396   TUPLE_CLASS_BOILERPLATE(SelectCaseStmt);
2397   std::tuple<std::optional<Name>, Scalar<Expr>> t;
2398 };
2399 
2400 // R1147 case-value -> scalar-constant-expr
2401 using CaseValue = Scalar<ConstantExpr>;
2402 
2403 // R1146 case-value-range ->
2404 //         case-value | case-value : | : case-value | case-value : case-value
2405 struct CaseValueRange {
2406   UNION_CLASS_BOILERPLATE(CaseValueRange);
2407   struct Range {
2408     BOILERPLATE(Range);
2409     Range(std::optional<CaseValue> &&l, std::optional<CaseValue> &&u)
2410         : lower{std::move(l)}, upper{std::move(u)} {}
2411     std::optional<CaseValue> lower, upper; // not both missing
2412   };
2413   std::variant<CaseValue, Range> u;
2414 };
2415 
2416 // R1145 case-selector -> ( case-value-range-list ) | DEFAULT
2417 EMPTY_CLASS(Default);
2418 
2419 struct CaseSelector {
2420   UNION_CLASS_BOILERPLATE(CaseSelector);
2421   std::variant<std::list<CaseValueRange>, Default> u;
2422 };
2423 
2424 // R1142 case-stmt -> CASE case-selector [case-construct-name]
2425 struct CaseStmt {
2426   TUPLE_CLASS_BOILERPLATE(CaseStmt);
2427   std::tuple<CaseSelector, std::optional<Name>> t;
2428 };
2429 
2430 // R1143 end-select-stmt -> END SELECT [case-construct-name]
2431 // R1151 end-select-rank-stmt -> END SELECT [select-construct-name]
2432 // R1155 end-select-type-stmt -> END SELECT [select-construct-name]
2433 WRAPPER_CLASS(EndSelectStmt, std::optional<Name>);
2434 
2435 // R1140 case-construct ->
2436 //         select-case-stmt [case-stmt block]... end-select-stmt
2437 struct CaseConstruct {
2438   struct Case {
2439     TUPLE_CLASS_BOILERPLATE(Case);
2440     std::tuple<Statement<CaseStmt>, Block> t;
2441   };
2442   TUPLE_CLASS_BOILERPLATE(CaseConstruct);
2443   std::tuple<Statement<SelectCaseStmt>, std::list<Case>,
2444       Statement<EndSelectStmt>>
2445       t;
2446 };
2447 
2448 // R1149 select-rank-stmt ->
2449 //         [select-construct-name :] SELECT RANK
2450 //         ( [associate-name =>] selector )
2451 struct SelectRankStmt {
2452   TUPLE_CLASS_BOILERPLATE(SelectRankStmt);
2453   std::tuple<std::optional<Name>, std::optional<Name>, Selector> t;
2454 };
2455 
2456 // R1150 select-rank-case-stmt ->
2457 //         RANK ( scalar-int-constant-expr ) [select-construct-name] |
2458 //         RANK ( * ) [select-construct-name] |
2459 //         RANK DEFAULT [select-construct-name]
2460 struct SelectRankCaseStmt {
2461   struct Rank {
2462     UNION_CLASS_BOILERPLATE(Rank);
2463     std::variant<ScalarIntConstantExpr, Star, Default> u;
2464   };
2465   TUPLE_CLASS_BOILERPLATE(SelectRankCaseStmt);
2466   std::tuple<Rank, std::optional<Name>> t;
2467 };
2468 
2469 // R1148 select-rank-construct ->
2470 //         select-rank-stmt [select-rank-case-stmt block]...
2471 //         end-select-rank-stmt
2472 struct SelectRankConstruct {
2473   TUPLE_CLASS_BOILERPLATE(SelectRankConstruct);
2474   struct RankCase {
2475     TUPLE_CLASS_BOILERPLATE(RankCase);
2476     std::tuple<Statement<SelectRankCaseStmt>, Block> t;
2477   };
2478   std::tuple<Statement<SelectRankStmt>, std::list<RankCase>,
2479       Statement<EndSelectStmt>>
2480       t;
2481 };
2482 
2483 // R1153 select-type-stmt ->
2484 //         [select-construct-name :] SELECT TYPE
2485 //         ( [associate-name =>] selector )
2486 struct SelectTypeStmt {
2487   TUPLE_CLASS_BOILERPLATE(SelectTypeStmt);
2488   std::tuple<std::optional<Name>, std::optional<Name>, Selector> t;
2489 };
2490 
2491 // R1154 type-guard-stmt ->
2492 //         TYPE IS ( type-spec ) [select-construct-name] |
2493 //         CLASS IS ( derived-type-spec ) [select-construct-name] |
2494 //         CLASS DEFAULT [select-construct-name]
2495 struct TypeGuardStmt {
2496   struct Guard {
2497     UNION_CLASS_BOILERPLATE(Guard);
2498     std::variant<TypeSpec, DerivedTypeSpec, Default> u;
2499   };
2500   TUPLE_CLASS_BOILERPLATE(TypeGuardStmt);
2501   std::tuple<Guard, std::optional<Name>> t;
2502 };
2503 
2504 // R1152 select-type-construct ->
2505 //         select-type-stmt [type-guard-stmt block]... end-select-type-stmt
2506 struct SelectTypeConstruct {
2507   TUPLE_CLASS_BOILERPLATE(SelectTypeConstruct);
2508   struct TypeCase {
2509     TUPLE_CLASS_BOILERPLATE(TypeCase);
2510     std::tuple<Statement<TypeGuardStmt>, Block> t;
2511   };
2512   std::tuple<Statement<SelectTypeStmt>, std::list<TypeCase>,
2513       Statement<EndSelectStmt>>
2514       t;
2515 };
2516 
2517 // R1156 exit-stmt -> EXIT [construct-name]
2518 WRAPPER_CLASS(ExitStmt, std::optional<Name>);
2519 
2520 // R1157 goto-stmt -> GO TO label
2521 WRAPPER_CLASS(GotoStmt, Label);
2522 
2523 // R1158 computed-goto-stmt -> GO TO ( label-list ) [,] scalar-int-expr
2524 struct ComputedGotoStmt {
2525   TUPLE_CLASS_BOILERPLATE(ComputedGotoStmt);
2526   std::tuple<std::list<Label>, ScalarIntExpr> t;
2527 };
2528 
2529 // R1162 stop-code -> scalar-default-char-expr | scalar-int-expr
2530 // We can't distinguish character expressions from integer
2531 // expressions during parsing, so we just parse an expr and
2532 // check its type later.
2533 WRAPPER_CLASS(StopCode, Scalar<Expr>);
2534 
2535 // R1160 stop-stmt -> STOP [stop-code] [, QUIET = scalar-logical-expr]
2536 // R1161 error-stop-stmt ->
2537 //         ERROR STOP [stop-code] [, QUIET = scalar-logical-expr]
2538 struct StopStmt {
2539   ENUM_CLASS(Kind, Stop, ErrorStop)
2540   TUPLE_CLASS_BOILERPLATE(StopStmt);
2541   std::tuple<Kind, std::optional<StopCode>, std::optional<ScalarLogicalExpr>> t;
2542 };
2543 
2544 // F2023: R1166 notify-wait-stmt -> NOTIFY WAIT ( notify-variable [,
2545 // event-wait-spec-list] )
2546 struct NotifyWaitStmt {
2547   TUPLE_CLASS_BOILERPLATE(NotifyWaitStmt);
2548   std::tuple<Scalar<Variable>, std::list<EventWaitSpec>> t;
2549 };
2550 
2551 // R1164 sync-all-stmt -> SYNC ALL [( [sync-stat-list] )]
2552 WRAPPER_CLASS(SyncAllStmt, std::list<StatOrErrmsg>);
2553 
2554 // R1166 sync-images-stmt -> SYNC IMAGES ( image-set [, sync-stat-list] )
2555 // R1167 image-set -> int-expr | *
2556 struct SyncImagesStmt {
2557   struct ImageSet {
2558     UNION_CLASS_BOILERPLATE(ImageSet);
2559     std::variant<IntExpr, Star> u;
2560   };
2561   TUPLE_CLASS_BOILERPLATE(SyncImagesStmt);
2562   std::tuple<ImageSet, std::list<StatOrErrmsg>> t;
2563 };
2564 
2565 // R1168 sync-memory-stmt -> SYNC MEMORY [( [sync-stat-list] )]
2566 WRAPPER_CLASS(SyncMemoryStmt, std::list<StatOrErrmsg>);
2567 
2568 // R1169 sync-team-stmt -> SYNC TEAM ( team-value [, sync-stat-list] )
2569 struct SyncTeamStmt {
2570   TUPLE_CLASS_BOILERPLATE(SyncTeamStmt);
2571   std::tuple<TeamValue, std::list<StatOrErrmsg>> t;
2572 };
2573 
2574 // R1171 event-variable -> scalar-variable
2575 using EventVariable = Scalar<Variable>;
2576 
2577 // R1170 event-post-stmt -> EVENT POST ( event-variable [, sync-stat-list] )
2578 struct EventPostStmt {
2579   TUPLE_CLASS_BOILERPLATE(EventPostStmt);
2580   std::tuple<EventVariable, std::list<StatOrErrmsg>> t;
2581 };
2582 
2583 // R1173 event-wait-spec -> until-spec | sync-stat
2584 struct EventWaitSpec {
2585   UNION_CLASS_BOILERPLATE(EventWaitSpec);
2586   std::variant<ScalarIntExpr, StatOrErrmsg> u;
2587 };
2588 
2589 // R1172 event-wait-stmt ->
2590 //         EVENT WAIT ( event-variable [, event-wait-spec-list] )
2591 // R1174 until-spec -> UNTIL_COUNT = scalar-int-expr
2592 struct EventWaitStmt {
2593   TUPLE_CLASS_BOILERPLATE(EventWaitStmt);
2594   std::tuple<EventVariable, std::list<EventWaitSpec>> t;
2595 };
2596 
2597 // R1177 team-variable -> scalar-variable
2598 using TeamVariable = Scalar<Variable>;
2599 
2600 // R1175 form-team-stmt ->
2601 //         FORM TEAM ( team-number , team-variable [, form-team-spec-list] )
2602 // R1176 team-number -> scalar-int-expr
2603 // R1178 form-team-spec -> NEW_INDEX = scalar-int-expr | sync-stat
2604 struct FormTeamStmt {
2605   struct FormTeamSpec {
2606     UNION_CLASS_BOILERPLATE(FormTeamSpec);
2607     std::variant<ScalarIntExpr, StatOrErrmsg> u;
2608   };
2609   TUPLE_CLASS_BOILERPLATE(FormTeamStmt);
2610   std::tuple<ScalarIntExpr, TeamVariable, std::list<FormTeamSpec>> t;
2611 };
2612 
2613 // R1182 lock-variable -> scalar-variable
2614 using LockVariable = Scalar<Variable>;
2615 
2616 // R1179 lock-stmt -> LOCK ( lock-variable [, lock-stat-list] )
2617 // R1180 lock-stat -> ACQUIRED_LOCK = scalar-logical-variable | sync-stat
2618 struct LockStmt {
2619   struct LockStat {
2620     UNION_CLASS_BOILERPLATE(LockStat);
2621     std::variant<Scalar<Logical<Variable>>, StatOrErrmsg> u;
2622   };
2623   TUPLE_CLASS_BOILERPLATE(LockStmt);
2624   std::tuple<LockVariable, std::list<LockStat>> t;
2625 };
2626 
2627 // R1181 unlock-stmt -> UNLOCK ( lock-variable [, sync-stat-list] )
2628 struct UnlockStmt {
2629   TUPLE_CLASS_BOILERPLATE(UnlockStmt);
2630   std::tuple<LockVariable, std::list<StatOrErrmsg>> t;
2631 };
2632 
2633 // R1202 file-unit-number -> scalar-int-expr
2634 WRAPPER_CLASS(FileUnitNumber, ScalarIntExpr);
2635 
2636 // R1201 io-unit -> file-unit-number | * | internal-file-variable
2637 // R1203 internal-file-variable -> char-variable
2638 // R905 char-variable -> variable
2639 // When Variable appears as an IoUnit, it must be character of a default,
2640 // ASCII, or Unicode kind; this constraint is not automatically checked.
2641 // The parse is ambiguous and is repaired if necessary once the types of
2642 // symbols are known.
2643 struct IoUnit {
2644   UNION_CLASS_BOILERPLATE(IoUnit);
2645   std::variant<Variable, FileUnitNumber, Star> u;
2646 };
2647 
2648 // R1206 file-name-expr -> scalar-default-char-expr
2649 using FileNameExpr = ScalarDefaultCharExpr;
2650 
2651 // R1205 connect-spec ->
2652 //         [UNIT =] file-unit-number | ACCESS = scalar-default-char-expr |
2653 //         ACTION = scalar-default-char-expr |
2654 //         ASYNCHRONOUS = scalar-default-char-expr |
2655 //         BLANK = scalar-default-char-expr |
2656 //         DECIMAL = scalar-default-char-expr |
2657 //         DELIM = scalar-default-char-expr |
2658 //         ENCODING = scalar-default-char-expr | ERR = label |
2659 //         FILE = file-name-expr | FORM = scalar-default-char-expr |
2660 //         IOMSG = iomsg-variable | IOSTAT = scalar-int-variable |
2661 //         NEWUNIT = scalar-int-variable | PAD = scalar-default-char-expr |
2662 //         POSITION = scalar-default-char-expr | RECL = scalar-int-expr |
2663 //         ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
2664 //         STATUS = scalar-default-char-expr
2665 //         @ | CARRIAGECONTROL = scalar-default-char-variable
2666 //           | CONVERT = scalar-default-char-variable
2667 //           | DISPOSE = scalar-default-char-variable
2668 WRAPPER_CLASS(StatusExpr, ScalarDefaultCharExpr);
2669 WRAPPER_CLASS(ErrLabel, Label);
2670 
2671 struct ConnectSpec {
2672   UNION_CLASS_BOILERPLATE(ConnectSpec);
2673   struct CharExpr {
2674     ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim,
2675         Encoding, Form, Pad, Position, Round, Sign,
2676         /* extensions: */ Carriagecontrol, Convert, Dispose)
2677     TUPLE_CLASS_BOILERPLATE(CharExpr);
2678     std::tuple<Kind, ScalarDefaultCharExpr> t;
2679   };
2680   WRAPPER_CLASS(Recl, ScalarIntExpr);
2681   WRAPPER_CLASS(Newunit, ScalarIntVariable);
2682   std::variant<FileUnitNumber, FileNameExpr, CharExpr, MsgVariable,
2683       StatVariable, Recl, Newunit, ErrLabel, StatusExpr>
2684       u;
2685 };
2686 
2687 // R1204 open-stmt -> OPEN ( connect-spec-list )
2688 WRAPPER_CLASS(OpenStmt, std::list<ConnectSpec>);
2689 
2690 // R1208 close-stmt -> CLOSE ( close-spec-list )
2691 // R1209 close-spec ->
2692 //         [UNIT =] file-unit-number | IOSTAT = scalar-int-variable |
2693 //         IOMSG = iomsg-variable | ERR = label |
2694 //         STATUS = scalar-default-char-expr
2695 struct CloseStmt {
2696   struct CloseSpec {
2697     UNION_CLASS_BOILERPLATE(CloseSpec);
2698     std::variant<FileUnitNumber, StatVariable, MsgVariable, ErrLabel,
2699         StatusExpr>
2700         u;
2701   };
2702   WRAPPER_CLASS_BOILERPLATE(CloseStmt, std::list<CloseSpec>);
2703 };
2704 
2705 // R1215 format -> default-char-expr | label | *
2706 // deprecated(ASSIGN): | scalar-int-name
2707 struct Format {
2708   UNION_CLASS_BOILERPLATE(Format);
2709   std::variant<Expr, Label, Star> u;
2710 };
2711 
2712 // R1214 id-variable -> scalar-int-variable
2713 WRAPPER_CLASS(IdVariable, ScalarIntVariable);
2714 
2715 // R1213 io-control-spec ->
2716 //         [UNIT =] io-unit | [FMT =] format | [NML =] namelist-group-name |
2717 //         ADVANCE = scalar-default-char-expr |
2718 //         ASYNCHRONOUS = scalar-default-char-constant-expr |
2719 //         BLANK = scalar-default-char-expr |
2720 //         DECIMAL = scalar-default-char-expr |
2721 //         DELIM = scalar-default-char-expr | END = label | EOR = label |
2722 //         ERR = label | ID = id-variable | IOMSG = iomsg-variable |
2723 //         IOSTAT = scalar-int-variable | PAD = scalar-default-char-expr |
2724 //         POS = scalar-int-expr | REC = scalar-int-expr |
2725 //         ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
2726 //         SIZE = scalar-int-variable
2727 WRAPPER_CLASS(EndLabel, Label);
2728 WRAPPER_CLASS(EorLabel, Label);
2729 struct IoControlSpec {
2730   UNION_CLASS_BOILERPLATE(IoControlSpec);
2731   struct CharExpr {
2732     ENUM_CLASS(Kind, Advance, Blank, Decimal, Delim, Pad, Round, Sign)
2733     TUPLE_CLASS_BOILERPLATE(CharExpr);
2734     std::tuple<Kind, ScalarDefaultCharExpr> t;
2735   };
2736   WRAPPER_CLASS(Asynchronous, ScalarDefaultCharConstantExpr);
2737   WRAPPER_CLASS(Pos, ScalarIntExpr);
2738   WRAPPER_CLASS(Rec, ScalarIntExpr);
2739   WRAPPER_CLASS(Size, ScalarIntVariable);
2740   std::variant<IoUnit, Format, Name, CharExpr, Asynchronous, EndLabel, EorLabel,
2741       ErrLabel, IdVariable, MsgVariable, StatVariable, Pos, Rec, Size>
2742       u;
2743 };
2744 
2745 // R1216 input-item -> variable | io-implied-do
2746 struct InputItem {
2747   UNION_CLASS_BOILERPLATE(InputItem);
2748   std::variant<Variable, common::Indirection<InputImpliedDo>> u;
2749 };
2750 
2751 // R1210 read-stmt ->
2752 //         READ ( io-control-spec-list ) [input-item-list] |
2753 //         READ format [, input-item-list]
2754 struct ReadStmt {
2755   BOILERPLATE(ReadStmt);
2756   ReadStmt(std::optional<IoUnit> &&i, std::optional<Format> &&f,
2757       std::list<IoControlSpec> &&cs, std::list<InputItem> &&its)
2758       : iounit{std::move(i)}, format{std::move(f)}, controls(std::move(cs)),
2759         items(std::move(its)) {}
2760   std::optional<IoUnit> iounit; // if first in controls without UNIT= &/or
2761                                 // followed by untagged format/namelist
2762   std::optional<Format> format; // if second in controls without FMT=/NML=, or
2763                                 // no (io-control-spec-list); might be
2764                                 // an untagged namelist group name
2765   std::list<IoControlSpec> controls;
2766   std::list<InputItem> items;
2767 };
2768 
2769 // R1217 output-item -> expr | io-implied-do
2770 struct OutputItem {
2771   UNION_CLASS_BOILERPLATE(OutputItem);
2772   std::variant<Expr, common::Indirection<OutputImpliedDo>> u;
2773 };
2774 
2775 // R1211 write-stmt -> WRITE ( io-control-spec-list ) [output-item-list]
2776 struct WriteStmt {
2777   BOILERPLATE(WriteStmt);
2778   WriteStmt(std::optional<IoUnit> &&i, std::optional<Format> &&f,
2779       std::list<IoControlSpec> &&cs, std::list<OutputItem> &&its)
2780       : iounit{std::move(i)}, format{std::move(f)}, controls(std::move(cs)),
2781         items(std::move(its)) {}
2782   std::optional<IoUnit> iounit; // if first in controls without UNIT= &/or
2783                                 // followed by untagged format/namelist
2784   std::optional<Format> format; // if second in controls without FMT=/NML=;
2785                                 // might be an untagged namelist group, too
2786   std::list<IoControlSpec> controls;
2787   std::list<OutputItem> items;
2788 };
2789 
2790 // R1212 print-stmt PRINT format [, output-item-list]
2791 struct PrintStmt {
2792   TUPLE_CLASS_BOILERPLATE(PrintStmt);
2793   std::tuple<Format, std::list<OutputItem>> t;
2794 };
2795 
2796 // R1220 io-implied-do-control ->
2797 //         do-variable = scalar-int-expr , scalar-int-expr [, scalar-int-expr]
2798 using IoImpliedDoControl = LoopBounds<DoVariable, ScalarIntExpr>;
2799 
2800 // R1218 io-implied-do -> ( io-implied-do-object-list , io-implied-do-control )
2801 // R1219 io-implied-do-object -> input-item | output-item
2802 struct InputImpliedDo {
2803   TUPLE_CLASS_BOILERPLATE(InputImpliedDo);
2804   std::tuple<std::list<InputItem>, IoImpliedDoControl> t;
2805 };
2806 
2807 struct OutputImpliedDo {
2808   TUPLE_CLASS_BOILERPLATE(OutputImpliedDo);
2809   std::tuple<std::list<OutputItem>, IoImpliedDoControl> t;
2810 };
2811 
2812 // R1223 wait-spec ->
2813 //         [UNIT =] file-unit-number | END = label | EOR = label | ERR = label |
2814 //         ID = scalar-int-expr | IOMSG = iomsg-variable |
2815 //         IOSTAT = scalar-int-variable
2816 WRAPPER_CLASS(IdExpr, ScalarIntExpr);
2817 struct WaitSpec {
2818   UNION_CLASS_BOILERPLATE(WaitSpec);
2819   std::variant<FileUnitNumber, EndLabel, EorLabel, ErrLabel, IdExpr,
2820       MsgVariable, StatVariable>
2821       u;
2822 };
2823 
2824 // R1222 wait-stmt -> WAIT ( wait-spec-list )
2825 WRAPPER_CLASS(WaitStmt, std::list<WaitSpec>);
2826 
2827 // R1227 position-spec ->
2828 //         [UNIT =] file-unit-number | IOMSG = iomsg-variable |
2829 //         IOSTAT = scalar-int-variable | ERR = label
2830 // R1229 flush-spec ->
2831 //         [UNIT =] file-unit-number | IOSTAT = scalar-int-variable |
2832 //         IOMSG = iomsg-variable | ERR = label
2833 struct PositionOrFlushSpec {
2834   UNION_CLASS_BOILERPLATE(PositionOrFlushSpec);
2835   std::variant<FileUnitNumber, MsgVariable, StatVariable, ErrLabel> u;
2836 };
2837 
2838 // R1224 backspace-stmt ->
2839 //         BACKSPACE file-unit-number | BACKSPACE ( position-spec-list )
2840 WRAPPER_CLASS(BackspaceStmt, std::list<PositionOrFlushSpec>);
2841 
2842 // R1225 endfile-stmt ->
2843 //         ENDFILE file-unit-number | ENDFILE ( position-spec-list )
2844 WRAPPER_CLASS(EndfileStmt, std::list<PositionOrFlushSpec>);
2845 
2846 // R1226 rewind-stmt -> REWIND file-unit-number | REWIND ( position-spec-list )
2847 WRAPPER_CLASS(RewindStmt, std::list<PositionOrFlushSpec>);
2848 
2849 // R1228 flush-stmt -> FLUSH file-unit-number | FLUSH ( flush-spec-list )
2850 WRAPPER_CLASS(FlushStmt, std::list<PositionOrFlushSpec>);
2851 
2852 // R1231 inquire-spec ->
2853 //         [UNIT =] file-unit-number | FILE = file-name-expr |
2854 //         ACCESS = scalar-default-char-variable |
2855 //         ACTION = scalar-default-char-variable |
2856 //         ASYNCHRONOUS = scalar-default-char-variable |
2857 //         BLANK = scalar-default-char-variable |
2858 //         DECIMAL = scalar-default-char-variable |
2859 //         DELIM = scalar-default-char-variable |
2860 //         DIRECT = scalar-default-char-variable |
2861 //         ENCODING = scalar-default-char-variable |
2862 //         ERR = label | EXIST = scalar-logical-variable |
2863 //         FORM = scalar-default-char-variable |
2864 //         FORMATTED = scalar-default-char-variable |
2865 //         ID = scalar-int-expr | IOMSG = iomsg-variable |
2866 //         IOSTAT = scalar-int-variable |
2867 //         NAME = scalar-default-char-variable |
2868 //         NAMED = scalar-logical-variable |
2869 //         NEXTREC = scalar-int-variable | NUMBER = scalar-int-variable |
2870 //         OPENED = scalar-logical-variable |
2871 //         PAD = scalar-default-char-variable |
2872 //         PENDING = scalar-logical-variable | POS = scalar-int-variable |
2873 //         POSITION = scalar-default-char-variable |
2874 //         READ = scalar-default-char-variable |
2875 //         READWRITE = scalar-default-char-variable |
2876 //         RECL = scalar-int-variable | ROUND = scalar-default-char-variable |
2877 //         SEQUENTIAL = scalar-default-char-variable |
2878 //         SIGN = scalar-default-char-variable |
2879 //         SIZE = scalar-int-variable |
2880 //         STREAM = scalar-default-char-variable |
2881 //         STATUS = scalar-default-char-variable |
2882 //         UNFORMATTED = scalar-default-char-variable |
2883 //         WRITE = scalar-default-char-variable
2884 //         @ | CARRIAGECONTROL = scalar-default-char-variable
2885 //           | CONVERT = scalar-default-char-variable
2886 //           | DISPOSE = scalar-default-char-variable
2887 struct InquireSpec {
2888   UNION_CLASS_BOILERPLATE(InquireSpec);
2889   struct CharVar {
2890     ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim,
2891         Direct, Encoding, Form, Formatted, Iomsg, Name, Pad, Position, Read,
2892         Readwrite, Round, Sequential, Sign, Stream, Status, Unformatted, Write,
2893         /* extensions: */ Carriagecontrol, Convert, Dispose)
2894     TUPLE_CLASS_BOILERPLATE(CharVar);
2895     std::tuple<Kind, ScalarDefaultCharVariable> t;
2896   };
2897   struct IntVar {
2898     ENUM_CLASS(Kind, Iostat, Nextrec, Number, Pos, Recl, Size)
2899     TUPLE_CLASS_BOILERPLATE(IntVar);
2900     std::tuple<Kind, ScalarIntVariable> t;
2901   };
2902   struct LogVar {
2903     ENUM_CLASS(Kind, Exist, Named, Opened, Pending)
2904     TUPLE_CLASS_BOILERPLATE(LogVar);
2905     std::tuple<Kind, Scalar<Logical<Variable>>> t;
2906   };
2907   std::variant<FileUnitNumber, FileNameExpr, CharVar, IntVar, LogVar, IdExpr,
2908       ErrLabel>
2909       u;
2910 };
2911 
2912 // R1230 inquire-stmt ->
2913 //         INQUIRE ( inquire-spec-list ) |
2914 //         INQUIRE ( IOLENGTH = scalar-int-variable ) output-item-list
2915 struct InquireStmt {
2916   UNION_CLASS_BOILERPLATE(InquireStmt);
2917   struct Iolength {
2918     TUPLE_CLASS_BOILERPLATE(Iolength);
2919     std::tuple<ScalarIntVariable, std::list<OutputItem>> t;
2920   };
2921   std::variant<std::list<InquireSpec>, Iolength> u;
2922 };
2923 
2924 // R1301 format-stmt -> FORMAT format-specification
2925 WRAPPER_CLASS(FormatStmt, format::FormatSpecification);
2926 
2927 // R1402 program-stmt -> PROGRAM program-name
2928 WRAPPER_CLASS(ProgramStmt, Name);
2929 
2930 // R1403 end-program-stmt -> END [PROGRAM [program-name]]
2931 WRAPPER_CLASS(EndProgramStmt, std::optional<Name>);
2932 
2933 // R1401 main-program ->
2934 //         [program-stmt] [specification-part] [execution-part]
2935 //         [internal-subprogram-part] end-program-stmt
2936 struct MainProgram {
2937   TUPLE_CLASS_BOILERPLATE(MainProgram);
2938   std::tuple<std::optional<Statement<ProgramStmt>>, SpecificationPart,
2939       ExecutionPart, std::optional<InternalSubprogramPart>,
2940       Statement<EndProgramStmt>>
2941       t;
2942 };
2943 
2944 // R1405 module-stmt -> MODULE module-name
2945 WRAPPER_CLASS(ModuleStmt, Name);
2946 
2947 // R1408 module-subprogram ->
2948 //         function-subprogram | subroutine-subprogram |
2949 //         separate-module-subprogram
2950 struct ModuleSubprogram {
2951   UNION_CLASS_BOILERPLATE(ModuleSubprogram);
2952   std::variant<common::Indirection<FunctionSubprogram>,
2953       common::Indirection<SubroutineSubprogram>,
2954       common::Indirection<SeparateModuleSubprogram>,
2955       common::Indirection<CompilerDirective>>
2956       u;
2957 };
2958 
2959 // R1407 module-subprogram-part -> contains-stmt [module-subprogram]...
2960 struct ModuleSubprogramPart {
2961   TUPLE_CLASS_BOILERPLATE(ModuleSubprogramPart);
2962   std::tuple<Statement<ContainsStmt>, std::list<ModuleSubprogram>> t;
2963 };
2964 
2965 // R1406 end-module-stmt -> END [MODULE [module-name]]
2966 WRAPPER_CLASS(EndModuleStmt, std::optional<Name>);
2967 
2968 // R1404 module ->
2969 //         module-stmt [specification-part] [module-subprogram-part]
2970 //         end-module-stmt
2971 struct Module {
2972   TUPLE_CLASS_BOILERPLATE(Module);
2973   std::tuple<Statement<ModuleStmt>, SpecificationPart,
2974       std::optional<ModuleSubprogramPart>, Statement<EndModuleStmt>>
2975       t;
2976 };
2977 
2978 // R1411 rename ->
2979 //         local-name => use-name |
2980 //         OPERATOR ( local-defined-operator ) =>
2981 //           OPERATOR ( use-defined-operator )
2982 struct Rename {
2983   UNION_CLASS_BOILERPLATE(Rename);
2984   struct Names {
2985     TUPLE_CLASS_BOILERPLATE(Names);
2986     std::tuple<Name, Name> t;
2987   };
2988   struct Operators {
2989     TUPLE_CLASS_BOILERPLATE(Operators);
2990     std::tuple<DefinedOpName, DefinedOpName> t;
2991   };
2992   std::variant<Names, Operators> u;
2993 };
2994 
2995 // R1418 parent-identifier -> ancestor-module-name [: parent-submodule-name]
2996 struct ParentIdentifier {
2997   TUPLE_CLASS_BOILERPLATE(ParentIdentifier);
2998   std::tuple<Name, std::optional<Name>> t;
2999 };
3000 
3001 // R1417 submodule-stmt -> SUBMODULE ( parent-identifier ) submodule-name
3002 struct SubmoduleStmt {
3003   TUPLE_CLASS_BOILERPLATE(SubmoduleStmt);
3004   std::tuple<ParentIdentifier, Name> t;
3005 };
3006 
3007 // R1419 end-submodule-stmt -> END [SUBMODULE [submodule-name]]
3008 WRAPPER_CLASS(EndSubmoduleStmt, std::optional<Name>);
3009 
3010 // R1416 submodule ->
3011 //         submodule-stmt [specification-part] [module-subprogram-part]
3012 //         end-submodule-stmt
3013 struct Submodule {
3014   TUPLE_CLASS_BOILERPLATE(Submodule);
3015   std::tuple<Statement<SubmoduleStmt>, SpecificationPart,
3016       std::optional<ModuleSubprogramPart>, Statement<EndSubmoduleStmt>>
3017       t;
3018 };
3019 
3020 // R1421 block-data-stmt -> BLOCK DATA [block-data-name]
3021 WRAPPER_CLASS(BlockDataStmt, std::optional<Name>);
3022 
3023 // R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]]
3024 WRAPPER_CLASS(EndBlockDataStmt, std::optional<Name>);
3025 
3026 // R1420 block-data -> block-data-stmt [specification-part] end-block-data-stmt
3027 struct BlockData {
3028   TUPLE_CLASS_BOILERPLATE(BlockData);
3029   std::tuple<Statement<BlockDataStmt>, SpecificationPart,
3030       Statement<EndBlockDataStmt>>
3031       t;
3032 };
3033 
3034 // R1508 generic-spec ->
3035 //         generic-name | OPERATOR ( defined-operator ) |
3036 //         ASSIGNMENT ( = ) | defined-io-generic-spec
3037 // R1509 defined-io-generic-spec ->
3038 //         READ ( FORMATTED ) | READ ( UNFORMATTED ) |
3039 //         WRITE ( FORMATTED ) | WRITE ( UNFORMATTED )
3040 struct GenericSpec {
3041   UNION_CLASS_BOILERPLATE(GenericSpec);
3042   EMPTY_CLASS(Assignment);
3043   EMPTY_CLASS(ReadFormatted);
3044   EMPTY_CLASS(ReadUnformatted);
3045   EMPTY_CLASS(WriteFormatted);
3046   EMPTY_CLASS(WriteUnformatted);
3047   CharBlock source;
3048   std::variant<Name, DefinedOperator, Assignment, ReadFormatted,
3049       ReadUnformatted, WriteFormatted, WriteUnformatted>
3050       u;
3051 };
3052 
3053 // R1510 generic-stmt ->
3054 //         GENERIC [, access-spec] :: generic-spec => specific-procedure-list
3055 struct GenericStmt {
3056   TUPLE_CLASS_BOILERPLATE(GenericStmt);
3057   std::tuple<std::optional<AccessSpec>, GenericSpec, std::list<Name>> t;
3058 };
3059 
3060 // R1503 interface-stmt -> INTERFACE [generic-spec] | ABSTRACT INTERFACE
3061 struct InterfaceStmt {
3062   UNION_CLASS_BOILERPLATE(InterfaceStmt);
3063   // Workaround for clang with libstc++10 bug
3064   InterfaceStmt(Abstract x) : u{x} {}
3065 
3066   std::variant<std::optional<GenericSpec>, Abstract> u;
3067 };
3068 
3069 // R1412 only -> generic-spec | only-use-name | rename
3070 // R1413 only-use-name -> use-name
3071 struct Only {
3072   UNION_CLASS_BOILERPLATE(Only);
3073   std::variant<common::Indirection<GenericSpec>, Name, Rename> u;
3074 };
3075 
3076 // R1409 use-stmt ->
3077 //         USE [[, module-nature] ::] module-name [, rename-list] |
3078 //         USE [[, module-nature] ::] module-name , ONLY : [only-list]
3079 // R1410 module-nature -> INTRINSIC | NON_INTRINSIC
3080 struct UseStmt {
3081   BOILERPLATE(UseStmt);
3082   ENUM_CLASS(ModuleNature, Intrinsic, Non_Intrinsic) // R1410
3083   template <typename A>
3084   UseStmt(std::optional<ModuleNature> &&nat, Name &&n, std::list<A> &&x)
3085       : nature(std::move(nat)), moduleName(std::move(n)), u(std::move(x)) {}
3086   std::optional<ModuleNature> nature;
3087   Name moduleName;
3088   std::variant<std::list<Rename>, std::list<Only>> u;
3089 };
3090 
3091 // R1514 proc-attr-spec ->
3092 //         access-spec | proc-language-binding-spec | INTENT ( intent-spec ) |
3093 //         OPTIONAL | POINTER | PROTECTED | SAVE
3094 struct ProcAttrSpec {
3095   UNION_CLASS_BOILERPLATE(ProcAttrSpec);
3096   std::variant<AccessSpec, LanguageBindingSpec, IntentSpec, Optional, Pointer,
3097       Protected, Save>
3098       u;
3099 };
3100 
3101 // R1512 procedure-declaration-stmt ->
3102 //         PROCEDURE ( [proc-interface] ) [[, proc-attr-spec]... ::]
3103 //         proc-decl-list
3104 struct ProcedureDeclarationStmt {
3105   TUPLE_CLASS_BOILERPLATE(ProcedureDeclarationStmt);
3106   std::tuple<std::optional<ProcInterface>, std::list<ProcAttrSpec>,
3107       std::list<ProcDecl>>
3108       t;
3109 };
3110 
3111 // R1527 prefix-spec ->
3112 //         declaration-type-spec | ELEMENTAL | IMPURE | MODULE |
3113 //         NON_RECURSIVE | PURE | RECURSIVE |
3114 // (CUDA)  ATTRIBUTES ( (DEVICE | GLOBAL | GRID_GLOBAL | HOST)... )
3115 //         LAUNCH_BOUNDS(expr-list) | CLUSTER_DIMS(expr-list)
3116 struct PrefixSpec {
3117   UNION_CLASS_BOILERPLATE(PrefixSpec);
3118   EMPTY_CLASS(Elemental);
3119   EMPTY_CLASS(Impure);
3120   EMPTY_CLASS(Module);
3121   EMPTY_CLASS(Non_Recursive);
3122   EMPTY_CLASS(Pure);
3123   EMPTY_CLASS(Recursive);
3124   WRAPPER_CLASS(Attributes, std::list<common::CUDASubprogramAttrs>);
3125   WRAPPER_CLASS(Launch_Bounds, std::list<ScalarIntConstantExpr>);
3126   WRAPPER_CLASS(Cluster_Dims, std::list<ScalarIntConstantExpr>);
3127   std::variant<DeclarationTypeSpec, Elemental, Impure, Module, Non_Recursive,
3128       Pure, Recursive, Attributes, Launch_Bounds, Cluster_Dims>
3129       u;
3130 };
3131 
3132 // R1532 suffix ->
3133 //         proc-language-binding-spec [RESULT ( result-name )] |
3134 //         RESULT ( result-name ) [proc-language-binding-spec]
3135 struct Suffix {
3136   BOILERPLATE(Suffix);
3137   Suffix(LanguageBindingSpec &&lbs, std::optional<Name> &&rn)
3138       : binding(std::move(lbs)), resultName(std::move(rn)) {}
3139   Suffix(Name &&rn, std::optional<LanguageBindingSpec> &&lbs)
3140       : binding(std::move(lbs)), resultName(std::move(rn)) {}
3141   std::optional<LanguageBindingSpec> binding;
3142   std::optional<Name> resultName;
3143 };
3144 
3145 // R1530 function-stmt ->
3146 //         [prefix] FUNCTION function-name ( [dummy-arg-name-list] ) [suffix]
3147 // R1526 prefix -> prefix-spec [prefix-spec]...
3148 // R1531 dummy-arg-name -> name
3149 struct FunctionStmt {
3150   TUPLE_CLASS_BOILERPLATE(FunctionStmt);
3151   std::tuple<std::list<PrefixSpec>, Name, std::list<Name>,
3152       std::optional<Suffix>>
3153       t;
3154 };
3155 
3156 // R1533 end-function-stmt -> END [FUNCTION [function-name]]
3157 WRAPPER_CLASS(EndFunctionStmt, std::optional<Name>);
3158 
3159 // R1536 dummy-arg -> dummy-arg-name | *
3160 struct DummyArg {
3161   UNION_CLASS_BOILERPLATE(DummyArg);
3162   std::variant<Name, Star> u;
3163 };
3164 
3165 // R1535 subroutine-stmt ->
3166 //         [prefix] SUBROUTINE subroutine-name [( [dummy-arg-list] )
3167 //         [proc-language-binding-spec]]
3168 struct SubroutineStmt {
3169   TUPLE_CLASS_BOILERPLATE(SubroutineStmt);
3170   std::tuple<std::list<PrefixSpec>, Name, std::list<DummyArg>,
3171       std::optional<LanguageBindingSpec>>
3172       t;
3173 };
3174 
3175 // R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]]
3176 WRAPPER_CLASS(EndSubroutineStmt, std::optional<Name>);
3177 
3178 // R1505 interface-body ->
3179 //         function-stmt [specification-part] end-function-stmt |
3180 //         subroutine-stmt [specification-part] end-subroutine-stmt
3181 struct InterfaceBody {
3182   UNION_CLASS_BOILERPLATE(InterfaceBody);
3183   struct Function {
3184     TUPLE_CLASS_BOILERPLATE(Function);
3185     std::tuple<Statement<FunctionStmt>, common::Indirection<SpecificationPart>,
3186         Statement<EndFunctionStmt>>
3187         t;
3188   };
3189   struct Subroutine {
3190     TUPLE_CLASS_BOILERPLATE(Subroutine);
3191     std::tuple<Statement<SubroutineStmt>,
3192         common::Indirection<SpecificationPart>, Statement<EndSubroutineStmt>>
3193         t;
3194   };
3195   std::variant<Function, Subroutine> u;
3196 };
3197 
3198 // R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list
3199 struct ProcedureStmt {
3200   ENUM_CLASS(Kind, ModuleProcedure, Procedure)
3201   TUPLE_CLASS_BOILERPLATE(ProcedureStmt);
3202   std::tuple<Kind, std::list<Name>> t;
3203 };
3204 
3205 // R1502 interface-specification -> interface-body | procedure-stmt
3206 struct InterfaceSpecification {
3207   UNION_CLASS_BOILERPLATE(InterfaceSpecification);
3208   std::variant<InterfaceBody, Statement<ProcedureStmt>> u;
3209 };
3210 
3211 // R1504 end-interface-stmt -> END INTERFACE [generic-spec]
3212 WRAPPER_CLASS(EndInterfaceStmt, std::optional<GenericSpec>);
3213 
3214 // R1501 interface-block ->
3215 //         interface-stmt [interface-specification]... end-interface-stmt
3216 struct InterfaceBlock {
3217   TUPLE_CLASS_BOILERPLATE(InterfaceBlock);
3218   std::tuple<Statement<InterfaceStmt>, std::list<InterfaceSpecification>,
3219       Statement<EndInterfaceStmt>>
3220       t;
3221 };
3222 
3223 // R1511 external-stmt -> EXTERNAL [::] external-name-list
3224 WRAPPER_CLASS(ExternalStmt, std::list<Name>);
3225 
3226 // R1519 intrinsic-stmt -> INTRINSIC [::] intrinsic-procedure-name-list
3227 WRAPPER_CLASS(IntrinsicStmt, std::list<Name>);
3228 
3229 // R1522 procedure-designator ->
3230 //         procedure-name | proc-component-ref | data-ref % binding-name
3231 struct ProcedureDesignator {
3232   UNION_CLASS_BOILERPLATE(ProcedureDesignator);
3233   std::variant<Name, ProcComponentRef> u;
3234 };
3235 
3236 // R1525 alt-return-spec -> * label
3237 WRAPPER_CLASS(AltReturnSpec, Label);
3238 
3239 // R1524 actual-arg ->
3240 //         expr | variable | procedure-name | proc-component-ref |
3241 //         alt-return-spec
3242 struct ActualArg {
3243   WRAPPER_CLASS(PercentRef, Expr); // %REF(x) extension
3244   WRAPPER_CLASS(PercentVal, Expr); // %VAL(x) extension
3245   UNION_CLASS_BOILERPLATE(ActualArg);
3246   ActualArg(Expr &&x) : u{common::Indirection<Expr>(std::move(x))} {}
3247   std::variant<common::Indirection<Expr>, AltReturnSpec, PercentRef, PercentVal>
3248       u;
3249 };
3250 
3251 // R1523 actual-arg-spec -> [keyword =] actual-arg
3252 struct ActualArgSpec {
3253   TUPLE_CLASS_BOILERPLATE(ActualArgSpec);
3254   std::tuple<std::optional<Keyword>, ActualArg> t;
3255 };
3256 
3257 // R1520 function-reference -> procedure-designator
3258 //         ( [actual-arg-spec-list] )
3259 struct Call {
3260   TUPLE_CLASS_BOILERPLATE(Call);
3261   std::tuple<ProcedureDesignator, std::list<ActualArgSpec>> t;
3262 };
3263 
3264 struct FunctionReference {
3265   WRAPPER_CLASS_BOILERPLATE(FunctionReference, Call);
3266   CharBlock source;
3267   Designator ConvertToArrayElementRef();
3268   StructureConstructor ConvertToStructureConstructor(
3269       const semantics::DerivedTypeSpec &);
3270 };
3271 
3272 // R1521 call-stmt -> CALL procedure-designator [ chevrons ]
3273 //         [( [actual-arg-spec-list] )]
3274 // (CUDA) chevrons -> <<< * | scalar-expr, scalar-expr [,
3275 //          scalar-int-expr [, scalar-int-expr ] ] >>>
3276 struct CallStmt {
3277   BOILERPLATE(CallStmt);
3278   WRAPPER_CLASS(StarOrExpr, std::optional<ScalarExpr>);
3279   struct Chevrons {
3280     TUPLE_CLASS_BOILERPLATE(Chevrons);
3281     std::tuple<StarOrExpr, ScalarExpr, std::optional<ScalarIntExpr>,
3282         std::optional<ScalarIntExpr>>
3283         t;
3284   };
3285   explicit CallStmt(ProcedureDesignator &&pd, std::optional<Chevrons> &&ch,
3286       std::list<ActualArgSpec> &&args)
3287       : call{std::move(pd), std::move(args)}, chevrons{std::move(ch)} {}
3288   Call call;
3289   std::optional<Chevrons> chevrons;
3290   CharBlock source;
3291   mutable common::ForwardOwningPointer<evaluate::ProcedureRef>
3292       typedCall; // filled by semantics
3293 };
3294 
3295 // R1529 function-subprogram ->
3296 //         function-stmt [specification-part] [execution-part]
3297 //         [internal-subprogram-part] end-function-stmt
3298 struct FunctionSubprogram {
3299   TUPLE_CLASS_BOILERPLATE(FunctionSubprogram);
3300   std::tuple<Statement<FunctionStmt>, SpecificationPart, ExecutionPart,
3301       std::optional<InternalSubprogramPart>, Statement<EndFunctionStmt>>
3302       t;
3303 };
3304 
3305 // R1534 subroutine-subprogram ->
3306 //         subroutine-stmt [specification-part] [execution-part]
3307 //         [internal-subprogram-part] end-subroutine-stmt
3308 struct SubroutineSubprogram {
3309   TUPLE_CLASS_BOILERPLATE(SubroutineSubprogram);
3310   std::tuple<Statement<SubroutineStmt>, SpecificationPart, ExecutionPart,
3311       std::optional<InternalSubprogramPart>, Statement<EndSubroutineStmt>>
3312       t;
3313 };
3314 
3315 // R1539 mp-subprogram-stmt -> MODULE PROCEDURE procedure-name
3316 WRAPPER_CLASS(MpSubprogramStmt, Name);
3317 
3318 // R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]]
3319 WRAPPER_CLASS(EndMpSubprogramStmt, std::optional<Name>);
3320 
3321 // R1538 separate-module-subprogram ->
3322 //         mp-subprogram-stmt [specification-part] [execution-part]
3323 //         [internal-subprogram-part] end-mp-subprogram-stmt
3324 struct SeparateModuleSubprogram {
3325   TUPLE_CLASS_BOILERPLATE(SeparateModuleSubprogram);
3326   std::tuple<Statement<MpSubprogramStmt>, SpecificationPart, ExecutionPart,
3327       std::optional<InternalSubprogramPart>, Statement<EndMpSubprogramStmt>>
3328       t;
3329 };
3330 
3331 // R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]]
3332 struct EntryStmt {
3333   TUPLE_CLASS_BOILERPLATE(EntryStmt);
3334   std::tuple<Name, std::list<DummyArg>, std::optional<Suffix>> t;
3335 };
3336 
3337 // R1542 return-stmt -> RETURN [scalar-int-expr]
3338 WRAPPER_CLASS(ReturnStmt, std::optional<ScalarIntExpr>);
3339 
3340 // R1544 stmt-function-stmt ->
3341 //         function-name ( [dummy-arg-name-list] ) = scalar-expr
3342 struct StmtFunctionStmt {
3343   TUPLE_CLASS_BOILERPLATE(StmtFunctionStmt);
3344   std::tuple<Name, std::list<Name>, Scalar<Expr>> t;
3345   Statement<ActionStmt> ConvertToAssignment();
3346 };
3347 
3348 // Compiler directives
3349 // !DIR$ IGNORE_TKR [ [(tkrdmac...)] name ]...
3350 // !DIR$ LOOP COUNT (n1[, n2]...)
3351 // !DIR$ name[=value] [, name[=value]]...    = can be :
3352 // !DIR$ <anything else>
3353 struct CompilerDirective {
3354   UNION_CLASS_BOILERPLATE(CompilerDirective);
3355   struct IgnoreTKR {
3356     TUPLE_CLASS_BOILERPLATE(IgnoreTKR);
3357     std::tuple<std::optional<std::list<const char *>>, Name> t;
3358   };
3359   struct LoopCount {
3360     WRAPPER_CLASS_BOILERPLATE(LoopCount, std::list<std::uint64_t>);
3361   };
3362   struct AssumeAligned {
3363     TUPLE_CLASS_BOILERPLATE(AssumeAligned);
3364     std::tuple<common::Indirection<Designator>, uint64_t> t;
3365   };
3366   EMPTY_CLASS(VectorAlways);
3367   struct NameValue {
3368     TUPLE_CLASS_BOILERPLATE(NameValue);
3369     std::tuple<Name, std::optional<std::uint64_t>> t;
3370   };
3371   struct Unroll {
3372     WRAPPER_CLASS_BOILERPLATE(Unroll, std::optional<std::uint64_t>);
3373   };
3374   EMPTY_CLASS(Unrecognized);
3375   CharBlock source;
3376   std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
3377       VectorAlways, std::list<NameValue>, Unroll, Unrecognized>
3378       u;
3379 };
3380 
3381 // (CUDA) ATTRIBUTE(attribute) [::] name-list
3382 struct CUDAAttributesStmt {
3383   TUPLE_CLASS_BOILERPLATE(CUDAAttributesStmt);
3384   std::tuple<common::CUDADataAttr, std::list<Name>> t;
3385 };
3386 
3387 // Legacy extensions
3388 struct BasedPointer {
3389   TUPLE_CLASS_BOILERPLATE(BasedPointer);
3390   std::tuple<ObjectName, ObjectName, std::optional<ArraySpec>> t;
3391 };
3392 WRAPPER_CLASS(BasedPointerStmt, std::list<BasedPointer>);
3393 
3394 struct Union;
3395 struct StructureDef;
3396 
3397 struct StructureField {
3398   UNION_CLASS_BOILERPLATE(StructureField);
3399   std::variant<Statement<DataComponentDefStmt>,
3400       common::Indirection<StructureDef>, common::Indirection<Union>>
3401       u;
3402 };
3403 
3404 struct Map {
3405   EMPTY_CLASS(MapStmt);
3406   EMPTY_CLASS(EndMapStmt);
3407   TUPLE_CLASS_BOILERPLATE(Map);
3408   std::tuple<Statement<MapStmt>, std::list<StructureField>,
3409       Statement<EndMapStmt>>
3410       t;
3411 };
3412 
3413 struct Union {
3414   EMPTY_CLASS(UnionStmt);
3415   EMPTY_CLASS(EndUnionStmt);
3416   TUPLE_CLASS_BOILERPLATE(Union);
3417   std::tuple<Statement<UnionStmt>, std::list<Map>, Statement<EndUnionStmt>> t;
3418 };
3419 
3420 struct StructureStmt {
3421   TUPLE_CLASS_BOILERPLATE(StructureStmt);
3422   std::tuple<std::optional<Name>, std::list<EntityDecl>> t;
3423 };
3424 
3425 struct StructureDef {
3426   EMPTY_CLASS(EndStructureStmt);
3427   TUPLE_CLASS_BOILERPLATE(StructureDef);
3428   std::tuple<Statement<StructureStmt>, std::list<StructureField>,
3429       Statement<EndStructureStmt>>
3430       t;
3431 };
3432 
3433 // Old style PARAMETER statement without parentheses.
3434 // Types are determined entirely from the right-hand sides, not the names.
3435 WRAPPER_CLASS(OldParameterStmt, std::list<NamedConstantDef>);
3436 
3437 // Deprecations
3438 struct ArithmeticIfStmt {
3439   TUPLE_CLASS_BOILERPLATE(ArithmeticIfStmt);
3440   std::tuple<Expr, Label, Label, Label> t;
3441 };
3442 
3443 struct AssignStmt {
3444   TUPLE_CLASS_BOILERPLATE(AssignStmt);
3445   std::tuple<Label, Name> t;
3446 };
3447 
3448 struct AssignedGotoStmt {
3449   TUPLE_CLASS_BOILERPLATE(AssignedGotoStmt);
3450   std::tuple<Name, std::list<Label>> t;
3451 };
3452 
3453 WRAPPER_CLASS(PauseStmt, std::optional<StopCode>);
3454 
3455 // Parse tree nodes for OpenMP directives and clauses
3456 
3457 // --- Common definitions
3458 
3459 struct OmpClause;
3460 struct OmpClauseList;
3461 
3462 struct OmpDirectiveSpecification {
3463   TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
3464   std::tuple<llvm::omp::Directive,
3465       std::optional<common::Indirection<OmpClauseList>>>
3466       t;
3467   CharBlock source;
3468 };
3469 
3470 // 2.1 Directives or clauses may accept a list or extended-list.
3471 //     A list item is a variable, array section or common block name (enclosed
3472 //     in slashes). An extended list item is a list item or a procedure Name.
3473 // variable-name | / common-block / | array-sections
3474 struct OmpObject {
3475   UNION_CLASS_BOILERPLATE(OmpObject);
3476   std::variant<Designator, /*common block*/ Name> u;
3477 };
3478 
3479 WRAPPER_CLASS(OmpObjectList, std::list<OmpObject>);
3480 
3481 #define MODIFIER_BOILERPLATE(...) \
3482   struct Modifier { \
3483     using Variant = std::variant<__VA_ARGS__>; \
3484     UNION_CLASS_BOILERPLATE(Modifier); \
3485     CharBlock source; \
3486     Variant u; \
3487   }
3488 
3489 #define MODIFIERS() std::optional<std::list<Modifier>>
3490 
3491 inline namespace traits {
3492 // trait-property-name ->
3493 //    identifier | string-literal
3494 //
3495 // This is a bit of a problematic case. The spec says that a word in quotes,
3496 // and the same word without quotes are equivalent. We currently parse both
3497 // as a string, but it's likely just a temporary solution.
3498 //
3499 // The problem is that trait-property can be (among other things) a
3500 // trait-property-name or a trait-property-expression. A simple identifier
3501 // can be either, there is no reasonably simple way of telling them apart
3502 // in the parser. There is a similar issue with extensions. Some of that
3503 // disambiguation may need to be done in the "canonicalization" pass and
3504 // then some of those AST nodes would be rewritten into different ones.
3505 //
3506 struct OmpTraitPropertyName {
3507   CharBlock source;
3508   WRAPPER_CLASS_BOILERPLATE(OmpTraitPropertyName, std::string);
3509 };
3510 
3511 // trait-score ->
3512 //    SCORE(non-negative-const-integer-expression)
3513 struct OmpTraitScore {
3514   CharBlock source;
3515   WRAPPER_CLASS_BOILERPLATE(OmpTraitScore, ScalarIntExpr);
3516 };
3517 
3518 // trait-property-extension ->
3519 //    trait-property-name |
3520 //    scalar-expr |
3521 //    trait-property-name (trait-property-extension, ...)
3522 //
3523 struct OmpTraitPropertyExtension {
3524   CharBlock source;
3525   UNION_CLASS_BOILERPLATE(OmpTraitPropertyExtension);
3526   struct Complex { // name (prop-ext, prop-ext, ...)
3527     CharBlock source;
3528     TUPLE_CLASS_BOILERPLATE(Complex);
3529     std::tuple<OmpTraitPropertyName,
3530         std::list<common::Indirection<OmpTraitPropertyExtension>>>
3531         t;
3532   };
3533 
3534   std::variant<OmpTraitPropertyName, ScalarExpr, Complex> u;
3535 };
3536 
3537 // trait-property ->
3538 //    trait-property-name | OmpClause |
3539 //    trait-property-expression | trait-property-extension
3540 // trait-property-expression ->
3541 //    scalar-logical-expression | scalar-integer-expression
3542 //
3543 // The parser for a logical expression will accept an integer expression,
3544 // and if it's not logical, it will flag an error later. The same thing
3545 // will happen if the scalar integer expression sees a logical expresion.
3546 // To avoid this, parse all expressions as scalar expressions.
3547 struct OmpTraitProperty {
3548   CharBlock source;
3549   UNION_CLASS_BOILERPLATE(OmpTraitProperty);
3550   std::variant<OmpTraitPropertyName, common::Indirection<OmpClause>,
3551       ScalarExpr, // trait-property-expresion
3552       OmpTraitPropertyExtension>
3553       u;
3554 };
3555 
3556 // trait-selector-name ->
3557 //    KIND |              DT       // name-list (host, nohost, +/add-def-doc)
3558 //    ISA |               DT       // name-list (isa_name, ... /impl-defined)
3559 //    ARCH |              DT       // name-list (arch_name, ... /impl-defined)
3560 //    directive-name |    C        // no properties
3561 //    SIMD |              C        // clause-list (from declare_simd)
3562 //                                 // (at least simdlen, inbranch/notinbranch)
3563 //    DEVICE_NUM |        T        // device-number
3564 //    UID |               T        // unique-string-id /impl-defined
3565 //    VENDOR |            I        // name-list (vendor-id /add-def-doc)
3566 //    EXTENSION |         I        // name-list (ext_name /impl-defined)
3567 //    ATOMIC_DEFAULT_MEM_ORDER I | // clause-list (value of admo)
3568 //    REQUIRES |          I        // clause-list (from requires)
3569 //    CONDITION           U        // logical-expr
3570 //    <other name>        I        // treated as extension
3571 //
3572 // Trait-set-selectors:
3573 //    [D]evice, [T]arget_device, [C]onstruct, [I]mplementation, [U]ser.
3574 struct OmpTraitSelectorName {
3575   CharBlock source;
3576   UNION_CLASS_BOILERPLATE(OmpTraitSelectorName);
3577   ENUM_CLASS(Value, Arch, Atomic_Default_Mem_Order, Condition, Device_Num,
3578       Extension, Isa, Kind, Requires, Simd, Uid, Vendor)
3579   std::variant<Value, llvm::omp::Directive, std::string> u;
3580 };
3581 
3582 // trait-selector ->
3583 //    trait-selector-name |
3584 //    trait-selector-name ([trait-score:] trait-property, ...)
3585 struct OmpTraitSelector {
3586   CharBlock source;
3587   TUPLE_CLASS_BOILERPLATE(OmpTraitSelector);
3588   struct Properties {
3589     TUPLE_CLASS_BOILERPLATE(Properties);
3590     std::tuple<std::optional<OmpTraitScore>, std::list<OmpTraitProperty>> t;
3591   };
3592   std::tuple<OmpTraitSelectorName, std::optional<Properties>> t;
3593 };
3594 
3595 // trait-set-selector-name ->
3596 //    CONSTRUCT | DEVICE | IMPLEMENTATION | USER |  // since 5.0
3597 //    TARGET_DEVICE                                 // since 5.1
3598 struct OmpTraitSetSelectorName {
3599   CharBlock source;
3600   ENUM_CLASS(Value, Construct, Device, Implementation, Target_Device, User)
3601   WRAPPER_CLASS_BOILERPLATE(OmpTraitSetSelectorName, Value);
3602 };
3603 
3604 // trait-set-selector ->
3605 //    trait-set-selector-name = {trait-selector, ...}
3606 struct OmpTraitSetSelector {
3607   CharBlock source;
3608   TUPLE_CLASS_BOILERPLATE(OmpTraitSetSelector);
3609   std::tuple<OmpTraitSetSelectorName, std::list<OmpTraitSelector>> t;
3610 };
3611 
3612 // context-selector-specification ->
3613 //    trait-set-selector, ...
3614 struct OmpContextSelectorSpecification { // Modifier
3615   CharBlock source;
3616   WRAPPER_CLASS_BOILERPLATE(
3617       OmpContextSelectorSpecification, std::list<OmpTraitSetSelector>);
3618 };
3619 } // namespace traits
3620 
3621 inline namespace modifier {
3622 // For uniformity, in all keyword modifiers the name of the type defined
3623 // by ENUM_CLASS is "Value", e.g.
3624 // struct Foo {
3625 //   ENUM_CLASS(Value, Keyword1, Keyword2);
3626 // };
3627 
3628 // Ref: [4.5:72-81], [5.0:110-119], [5.1:134-143], [5.2:169-170]
3629 //
3630 // alignment ->
3631 //    scalar-integer-expression                     // since 4.5
3632 struct OmpAlignment {
3633   WRAPPER_CLASS_BOILERPLATE(OmpAlignment, ScalarIntExpr);
3634 };
3635 
3636 // Ref: [5.1:184-185], [5.2:178-179]
3637 //
3638 // align-modifier ->
3639 //    ALIGN(alignment)                              // since 5.1
3640 struct OmpAlignModifier {
3641   WRAPPER_CLASS_BOILERPLATE(OmpAlignModifier, ScalarIntExpr);
3642 };
3643 
3644 // Ref: [5.0:158-159], [5.1:184-185], [5.2:178-179]
3645 //
3646 // allocator-simple-modifier ->
3647 //    allocator                                     // since 5.0
3648 struct OmpAllocatorSimpleModifier {
3649   WRAPPER_CLASS_BOILERPLATE(OmpAllocatorSimpleModifier, ScalarIntExpr);
3650 };
3651 
3652 // Ref: [5.1:184-185], [5.2:178-179]
3653 //
3654 // allocator-complex-modifier ->
3655 //    ALLOCATOR(allocator)                          // since 5.1
3656 struct OmpAllocatorComplexModifier {
3657   WRAPPER_CLASS_BOILERPLATE(OmpAllocatorComplexModifier, ScalarIntExpr);
3658 };
3659 
3660 // Ref: [5.2:252-254]
3661 //
3662 // chunk-modifier ->
3663 //    SIMD                                          // since 5.2
3664 //
3665 // Prior to 5.2 "chunk-modifier" was a part of "modifier" on SCHEDULE clause.
3666 struct OmpChunkModifier {
3667   ENUM_CLASS(Value, Simd)
3668   WRAPPER_CLASS_BOILERPLATE(OmpChunkModifier, Value);
3669 };
3670 
3671 // Ref: [5.0:47-49], [5.1:49-51], [5.2:67-69]
3672 //
3673 // iterator-specifier ->
3674 //    [iterator-type] iterator-identifier
3675 //        = range-specification |                   // since 5.0
3676 //    [iterator-type ::] iterator-identifier
3677 //        = range-specification                     // since 5.2
3678 struct OmpIteratorSpecifier {
3679   TUPLE_CLASS_BOILERPLATE(OmpIteratorSpecifier);
3680   CharBlock source;
3681   std::tuple<TypeDeclarationStmt, SubscriptTriplet> t;
3682 };
3683 
3684 // Ref: [4.5:169-170], [5.0:255-256], [5.1:288-289]
3685 //
3686 // dependence-type ->
3687 //    SINK | SOURCE |                               // since 4.5
3688 //    IN | OUT | INOUT |                            // since 4.5, until 5.1
3689 //    MUTEXINOUTSET | DEPOBJ |                      // since 5.0, until 5.1
3690 //    INOUTSET                                      // since 5.1, until 5.1
3691 //
3692 // All of these, except SINK and SOURCE became task-dependence-type in 5.2.
3693 //
3694 // Keeping these two as separate types, since having them all together
3695 // creates conflicts when parsing the DEPEND clause. For DEPEND(SINK: ...),
3696 // the SINK may be parsed as 'task-dependence-type', and the list after
3697 // the ':' would then be parsed as OmpObjectList (instead of the iteration
3698 // vector). This would accept the vector "i, j, k" (although interpreted
3699 // incorrectly), while flagging a syntax error for "i+1, j, k".
3700 struct OmpDependenceType {
3701   ENUM_CLASS(Value, Sink, Source);
3702   WRAPPER_CLASS_BOILERPLATE(OmpDependenceType, Value);
3703 };
3704 
3705 // Ref: [5.0:170-176], [5.1:197-205], [5.2:276-277]
3706 //
3707 // device-modifier ->
3708 //    ANCESTOR | DEVICE_NUM                         // since 5.0
3709 struct OmpDeviceModifier {
3710   ENUM_CLASS(Value, Ancestor, Device_Num)
3711   WRAPPER_CLASS_BOILERPLATE(OmpDeviceModifier, Value);
3712 };
3713 
3714 // Ref: [5.2:72-73,230-323], in 4.5-5.1 it's scattered over individual
3715 // directives that allow the IF clause.
3716 //
3717 // directive-name-modifier ->
3718 //    PARALLEL | TARGET | TARGET DATA |
3719 //    TARGET ENTER DATA | TARGET EXIT DATA |
3720 //    TARGET UPDATE | TASK | TASKLOOP |             // since 4.5
3721 //    CANCEL[*] | SIMD |                            // since 5.0
3722 //    TEAMS                                         // since 5.2
3723 //
3724 // [*] The IF clause is allowed on CANCEL in OpenMP 4.5, but only without
3725 // the directive-name-modifier. For the sake of uniformity CANCEL can be
3726 // considered a valid value in 4.5 as well.
3727 struct OmpDirectiveNameModifier {
3728   WRAPPER_CLASS_BOILERPLATE(OmpDirectiveNameModifier, llvm::omp::Directive);
3729 };
3730 
3731 // Ref: [5.1:205-209], [5.2:166-168]
3732 //
3733 // motion-modifier ->
3734 //    PRESENT |                                     // since 5.0, until 5.0
3735 //    mapper | iterator
3736 // expectation ->
3737 //    PRESENT                                       // since 5.1
3738 //
3739 // The PRESENT value was a part of motion-modifier in 5.1, and became a
3740 // value of expectation in 5.2.
3741 struct OmpExpectation {
3742   ENUM_CLASS(Value, Present);
3743   WRAPPER_CLASS_BOILERPLATE(OmpExpectation, Value);
3744 };
3745 
3746 // Ref: [5.0:47-49], [5.1:49-51], [5.2:67-69]
3747 //
3748 // iterator-modifier ->
3749 //    ITERATOR(iterator-specifier [, ...])          // since 5.0
3750 struct OmpIterator {
3751   WRAPPER_CLASS_BOILERPLATE(OmpIterator, std::list<OmpIteratorSpecifier>);
3752 };
3753 
3754 // Ref: [5.0:288-290], [5.1:321-322], [5.2:115-117]
3755 //
3756 // lastprivate-modifier ->
3757 //    CONDITIONAL                                   // since 5.0
3758 struct OmpLastprivateModifier {
3759   ENUM_CLASS(Value, Conditional)
3760   WRAPPER_CLASS_BOILERPLATE(OmpLastprivateModifier, Value);
3761 };
3762 
3763 // Ref: [4.5:207-210], [5.0:290-293], [5.1:323-325], [5.2:117-120]
3764 //
3765 // linear-modifier ->
3766 //    REF | UVAL | VAL                              // since 4.5
3767 struct OmpLinearModifier {
3768   ENUM_CLASS(Value, Ref, Uval, Val);
3769   WRAPPER_CLASS_BOILERPLATE(OmpLinearModifier, Value);
3770 };
3771 
3772 // Ref: [5.0:176-180], [5.1:205-210], [5.2:149-150]
3773 //
3774 // mapper ->
3775 //    identifier                                    // since 4.5
3776 struct OmpMapper {
3777   WRAPPER_CLASS_BOILERPLATE(OmpMapper, Name);
3778 };
3779 
3780 // Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158]
3781 //
3782 // map-type ->
3783 //    ALLOC | DELETE | FROM | RELEASE | TO | TOFROM // since 4.5
3784 struct OmpMapType {
3785   ENUM_CLASS(Value, Alloc, Delete, From, Release, To, Tofrom);
3786   WRAPPER_CLASS_BOILERPLATE(OmpMapType, Value);
3787 };
3788 
3789 // Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158]
3790 //
3791 // map-type-modifier ->
3792 //    ALWAYS |                                      // since 4.5
3793 //    CLOSE |                                       // since 5.0
3794 //    PRESENT                                       // since 5.1
3795 struct OmpMapTypeModifier {
3796   ENUM_CLASS(Value, Always, Close, Present, Ompx_Hold)
3797   WRAPPER_CLASS_BOILERPLATE(OmpMapTypeModifier, Value);
3798 };
3799 
3800 // Ref: [4.5:56-63], [5.0:101-109], [5.1:126-133], [5.2:252-254]
3801 //
3802 // modifier ->
3803 //    MONOTONIC | NONMONOTONIC | SIMD               // since 4.5, until 5.1
3804 // ordering-modifier ->
3805 //    MONOTONIC | NONMONOTONIC                      // since 5.2
3806 //
3807 // Until 5.1, the SCHEDULE clause accepted up to two instances of "modifier".
3808 // Since 5.2 "modifier" was replaced with "ordering-modifier" and "chunk-
3809 // modifier".
3810 struct OmpOrderingModifier {
3811   ENUM_CLASS(Value, Monotonic, Nonmonotonic, Simd)
3812   WRAPPER_CLASS_BOILERPLATE(OmpOrderingModifier, Value);
3813 };
3814 
3815 // Ref: [5.1:125-126], [5.2:233-234]
3816 //
3817 // order-modifier ->
3818 //    REPRODUCIBLE | UNCONSTRAINED                  // since 5.1
3819 struct OmpOrderModifier {
3820   ENUM_CLASS(Value, Reproducible, Unconstrained)
3821   WRAPPER_CLASS_BOILERPLATE(OmpOrderModifier, Value);
3822 };
3823 
3824 // Ref: [5.1:166-171], [5.2:269-270]
3825 //
3826 // prescriptiveness ->
3827 //    STRICT                                        // since 5.1
3828 struct OmpPrescriptiveness {
3829   ENUM_CLASS(Value, Strict)
3830   WRAPPER_CLASS_BOILERPLATE(OmpPrescriptiveness, Value);
3831 };
3832 
3833 // Ref: [4.5:201-207], [5.0:293-299], [5.1:325-331], [5.2:124]
3834 //
3835 // reduction-identifier ->
3836 //    base-language-identifier |                    // since 4.5
3837 //    - |                                           // since 4.5, until 5.2
3838 //    + | * | .AND. | .OR. | .EQV. | .NEQV. |       // since 4.5
3839 //    MIN | MAX | IAND | IOR | IEOR                 // since 4.5
3840 struct OmpReductionIdentifier {
3841   UNION_CLASS_BOILERPLATE(OmpReductionIdentifier);
3842   std::variant<DefinedOperator, ProcedureDesignator> u;
3843 };
3844 
3845 // Ref: [5.0:300-302], [5.1:332-334], [5.2:134-137]
3846 //
3847 // reduction-modifier ->
3848 //    DEFAULT | INSCAN | TASK                       // since 5.0
3849 struct OmpReductionModifier {
3850   ENUM_CLASS(Value, Default, Inscan, Task);
3851   WRAPPER_CLASS_BOILERPLATE(OmpReductionModifier, Value);
3852 };
3853 
3854 // Ref: [5.2:117-120]
3855 //
3856 // step-complex-modifier ->
3857 //    STEP(integer-expression)                      // since 5.2
3858 struct OmpStepComplexModifier {
3859   WRAPPER_CLASS_BOILERPLATE(OmpStepComplexModifier, ScalarIntExpr);
3860 };
3861 
3862 // Ref: [4.5:207-210], [5.0:290-293], [5.1:323-325], [5.2:117-120]
3863 //
3864 // step-simple-modifier ->
3865 //    integer-expresion                             // since 4.5
3866 struct OmpStepSimpleModifier {
3867   WRAPPER_CLASS_BOILERPLATE(OmpStepSimpleModifier, ScalarIntExpr);
3868 };
3869 
3870 // Ref: [4.5:169-170], [5.0:254-256], [5.1:287-289], [5.2:321]
3871 //
3872 // task-dependence-type -> // "dependence-type" in 5.1 and before
3873 //    IN | OUT | INOUT |                            // since 4.5
3874 //    MUTEXINOUTSET | DEPOBJ |                      // since 5.0
3875 //    INOUTSET                                      // since 5.2
3876 struct OmpTaskDependenceType {
3877   ENUM_CLASS(Value, In, Out, Inout, Inoutset, Mutexinoutset, Depobj)
3878   WRAPPER_CLASS_BOILERPLATE(OmpTaskDependenceType, Value);
3879 };
3880 
3881 // Ref: [4.5:229-230], [5.0:324-325], [5.1:357-358], [5.2:161-162]
3882 //
3883 // variable-category ->
3884 //    SCALAR |                                      // since 4.5
3885 //    AGGREGATE | ALLOCATABLE | POINTER |           // since 5.0
3886 //    ALL                                           // since 5.2
3887 struct OmpVariableCategory {
3888   ENUM_CLASS(Value, Aggregate, All, Allocatable, Pointer, Scalar)
3889   WRAPPER_CLASS_BOILERPLATE(OmpVariableCategory, Value);
3890 };
3891 
3892 // context-selector
3893 using OmpContextSelector = traits::OmpContextSelectorSpecification;
3894 } // namespace modifier
3895 
3896 // --- Clauses
3897 
3898 // Ref: [5.0:135-140], [5.1:161-166], [5.2:264-265]
3899 //
3900 // affinity-clause ->
3901 //    AFFINITY([aff-modifier:] locator-list)        // since 5.0
3902 // aff-modifier ->
3903 //    interator-modifier                            // since 5.0
3904 struct OmpAffinityClause {
3905   TUPLE_CLASS_BOILERPLATE(OmpAffinityClause);
3906   MODIFIER_BOILERPLATE(OmpIterator);
3907   std::tuple<MODIFIERS(), OmpObjectList> t;
3908 };
3909 
3910 // Ref: 5.2: [174]
3911 struct OmpAlignClause {
3912   WRAPPER_CLASS_BOILERPLATE(OmpAlignClause, ScalarIntExpr);
3913 };
3914 
3915 // Ref: [4.5:72-81], [5.0:110-119], [5.1:134-143], [5.2:169-170]
3916 //
3917 // aligned-clause ->
3918 //    ALIGNED(list [: alignment])                   // since 4.5
3919 struct OmpAlignedClause {
3920   TUPLE_CLASS_BOILERPLATE(OmpAlignedClause);
3921   MODIFIER_BOILERPLATE(OmpAlignment);
3922   std::tuple<OmpObjectList, MODIFIERS()> t;
3923 };
3924 
3925 // Ref: [5.0:158-159], [5.1:184-185], [5.2:178-179]
3926 //
3927 // allocate-clause ->
3928 //    ALLOCATE(
3929 //        [allocator-simple-modifier:] list) |      // since 5.0
3930 //    ALLOCATE([modifier...:] list)                 // since 5.1
3931 // modifier ->
3932 //    allocator-simple-modifier |
3933 //    allocator-complex-modifier | align-modifier   // since 5.1
3934 struct OmpAllocateClause {
3935   MODIFIER_BOILERPLATE(OmpAlignModifier, OmpAllocatorSimpleModifier,
3936       OmpAllocatorComplexModifier);
3937   TUPLE_CLASS_BOILERPLATE(OmpAllocateClause);
3938   std::tuple<MODIFIERS(), OmpObjectList> t;
3939 };
3940 
3941 // Ref: [5.2:216-217 (sort of, as it's only mentioned in passing)
3942 // AT(compilation|execution)
3943 struct OmpAtClause {
3944   ENUM_CLASS(ActionTime, Compilation, Execution);
3945   WRAPPER_CLASS_BOILERPLATE(OmpAtClause, ActionTime);
3946 };
3947 
3948 // Ref: [5.0:60-63], [5.1:83-86], [5.2:210-213]
3949 //
3950 // atomic-default-mem-order-clause ->
3951 //    ATOMIC_DEFAULT_MEM_ORDER(memory-order)        // since 5.0
3952 // memory-order ->
3953 //    SEQ_CST | ACQ_REL | RELAXED |                 // since 5.0
3954 //    ACQUIRE | RELEASE                             // since 5.2
3955 struct OmpAtomicDefaultMemOrderClause {
3956   using MemoryOrder = common::OmpAtomicDefaultMemOrderType;
3957   WRAPPER_CLASS_BOILERPLATE(OmpAtomicDefaultMemOrderClause, MemoryOrder);
3958 };
3959 
3960 // Ref: [5.0:128-131], [5.1:151-154], [5.2:258-259]
3961 //
3962 // bind-clause ->
3963 //    BIND(binding)                                 // since 5.0
3964 // binding ->
3965 //    TEAMS | PARALLEL | THREAD                     // since 5.0
3966 struct OmpBindClause {
3967   ENUM_CLASS(Binding, Parallel, Teams, Thread)
3968   WRAPPER_CLASS_BOILERPLATE(OmpBindClause, Binding);
3969 };
3970 
3971 // Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:109]
3972 //
3973 // When used as a data-sharing clause:
3974 // default-clause ->
3975 //    DEFAULT(data-sharing-attribute)               // since 4.5
3976 // data-sharing-attribute ->
3977 //    SHARED | NONE |                               // since 4.5
3978 //    PRIVATE | FIRSTPRIVATE                        // since 5.0
3979 //
3980 // When used in METADIRECTIVE:
3981 // default-clause ->
3982 //    DEFAULT(directive-specification)              // since 5.0, until 5.1
3983 // See also otherwise-clause.
3984 struct OmpDefaultClause {
3985   ENUM_CLASS(DataSharingAttribute, Private, Firstprivate, Shared, None)
3986   UNION_CLASS_BOILERPLATE(OmpDefaultClause);
3987   std::variant<DataSharingAttribute, OmpDirectiveSpecification> u;
3988 };
3989 
3990 // Ref: [4.5:103-107], [5.0:324-325], [5.1:357-358], [5.2:161-162]
3991 //
3992 // defaultmap-clause ->
3993 //    DEFAULTMAP(implicit-behavior
3994 //        [: variable-category])                    // since 5.0
3995 // implicit-behavior ->
3996 //    TOFROM |                                      // since 4.5
3997 //    ALLOC | TO | FROM | FIRSTPRIVATE | NONE |
3998 //    DEFAULT |                                     // since 5.0
3999 //    PRESENT                                       // since 5.1
4000 struct OmpDefaultmapClause {
4001   TUPLE_CLASS_BOILERPLATE(OmpDefaultmapClause);
4002   ENUM_CLASS(
4003       ImplicitBehavior, Alloc, To, From, Tofrom, Firstprivate, None, Default)
4004   MODIFIER_BOILERPLATE(OmpVariableCategory);
4005   std::tuple<ImplicitBehavior, MODIFIERS()> t;
4006 };
4007 
4008 // Ref: [4.5:169-172], [5.0:255-259], [5.1:288-292], [5.2:91-93]
4009 //
4010 // iteration-offset ->
4011 //    +|- non-negative-constant                     // since 4.5
4012 struct OmpIterationOffset {
4013   TUPLE_CLASS_BOILERPLATE(OmpIterationOffset);
4014   std::tuple<DefinedOperator, ScalarIntConstantExpr> t;
4015 };
4016 
4017 // Ref: [4.5:169-172], [5.0:255-259], [5.1:288-292], [5.2:91-93]
4018 //
4019 // iteration ->
4020 //    induction-variable [iteration-offset]         // since 4.5
4021 struct OmpIteration {
4022   TUPLE_CLASS_BOILERPLATE(OmpIteration);
4023   std::tuple<Name, std::optional<OmpIterationOffset>> t;
4024 };
4025 
4026 // Ref: [4.5:169-172], [5.0:255-259], [5.1:288-292], [5.2:91-93]
4027 //
4028 // iteration-vector ->
4029 //    [iteration...]                                // since 4.5
4030 WRAPPER_CLASS(OmpIterationVector, std::list<OmpIteration>);
4031 
4032 // Extract this into a separate structure (instead of having it directly in
4033 // OmpDoacrossClause), so that the context in TYPE_CONTEXT_PARSER can be set
4034 // separately for OmpDependClause and OmpDoacrossClause.
4035 //
4036 // See: depend-clause, doacross-clause
4037 struct OmpDoacross {
4038   OmpDependenceType::Value GetDepType() const;
4039 
4040   WRAPPER_CLASS(Sink, OmpIterationVector);
4041   EMPTY_CLASS(Source);
4042   UNION_CLASS_BOILERPLATE(OmpDoacross);
4043   std::variant<Sink, Source> u;
4044 };
4045 
4046 // Ref: [4.5:169-172], [5.0:255-259], [5.1:288-292], [5.2:323-326]
4047 //
4048 // depend-clause ->
4049 //    DEPEND(SOURCE) |                              // since 4.5, until 5.1
4050 //    DEPEND(SINK: iteration-vector) |              // since 4.5, until 5.1
4051 //    DEPEND([depend-modifier,]
4052 //           task-dependence-type: locator-list)    // since 4.5
4053 //
4054 // depend-modifier -> iterator-modifier             // since 5.0
4055 struct OmpDependClause {
4056   UNION_CLASS_BOILERPLATE(OmpDependClause);
4057   struct TaskDep {
4058     OmpTaskDependenceType::Value GetTaskDepType() const;
4059     TUPLE_CLASS_BOILERPLATE(TaskDep);
4060     MODIFIER_BOILERPLATE(OmpIterator, OmpTaskDependenceType);
4061     std::tuple<MODIFIERS(), OmpObjectList> t;
4062   };
4063   std::variant<TaskDep, OmpDoacross> u;
4064 };
4065 
4066 // Ref: [5.2:326-328]
4067 //
4068 // doacross-clause ->
4069 //    DOACROSS(dependence-type: iteration-vector)   // since 5.2
4070 WRAPPER_CLASS(OmpDoacrossClause, OmpDoacross);
4071 
4072 // Ref: [5.0:254-255], [5.1:287-288], [5.2:73]
4073 //
4074 // destroy-clause ->
4075 //    DESTROY |                                     // since 5.0, until 5.1
4076 //    DESTROY(variable)                             // since 5.2
4077 WRAPPER_CLASS(OmpDestroyClause, OmpObject);
4078 
4079 // Ref: [5.0:135-140], [5.1:161-166], [5.2:265-266]
4080 //
4081 // detach-clause ->
4082 //    DETACH(event-handle)                          // since 5.0
4083 struct OmpDetachClause {
4084   WRAPPER_CLASS_BOILERPLATE(OmpDetachClause, OmpObject);
4085 };
4086 
4087 // Ref: [4.5:103-107], [5.0:170-176], [5.1:197-205], [5.2:276-277]
4088 //
4089 // device-clause ->
4090 //    DEVICE(scalar-integer-expression) |           // since 4.5
4091 //    DEVICE([device-modifier:]
4092 //        scalar-integer-expression)                // since 5.0
4093 struct OmpDeviceClause {
4094   TUPLE_CLASS_BOILERPLATE(OmpDeviceClause);
4095   MODIFIER_BOILERPLATE(OmpDeviceModifier);
4096   std::tuple<MODIFIERS(), ScalarIntExpr> t;
4097 };
4098 
4099 // Ref: [5.0:180-185], [5.1:210-216], [5.2:275]
4100 //
4101 // device-type-clause ->
4102 //    DEVICE_TYPE(ANY | HOST | NOHOST)              // since 5.0
4103 struct OmpDeviceTypeClause {
4104   ENUM_CLASS(DeviceTypeDescription, Any, Host, Nohost)
4105   WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, DeviceTypeDescription);
4106 };
4107 
4108 // OMP 5.2 15.8.3 extended-atomic, fail-clause ->
4109 //    FAIL(memory-order)
4110 struct OmpFailClause {
4111   WRAPPER_CLASS_BOILERPLATE(
4112       OmpFailClause, common::Indirection<OmpMemoryOrderClause>);
4113   CharBlock source;
4114 };
4115 
4116 // Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
4117 //
4118 // from-clause ->
4119 //    FROM(locator-list) |
4120 //    FROM(mapper-modifier: locator-list) |         // since 5.0
4121 //    FROM(motion-modifier[,] ...: locator-list)    // since 5.1
4122 //  motion-modifier ->
4123 //    PRESENT | mapper-modifier | iterator-modifier
4124 struct OmpFromClause {
4125   TUPLE_CLASS_BOILERPLATE(OmpFromClause);
4126   MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
4127   std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
4128 };
4129 
4130 // Ref: [4.5:87-91], [5.0:140-146], [5.1:166-171], [5.2:269]
4131 //
4132 // grainsize-clause ->
4133 //    GRAINSIZE(grain-size) |                       // since 4.5
4134 //    GRAINSIZE([prescriptiveness:] grain-size)     // since 5.1
4135 struct OmpGrainsizeClause {
4136   TUPLE_CLASS_BOILERPLATE(OmpGrainsizeClause);
4137   MODIFIER_BOILERPLATE(OmpPrescriptiveness);
4138   std::tuple<MODIFIERS(), ScalarIntExpr> t;
4139 };
4140 
4141 // Ref: [5.2:72-73], in 4.5-5.1 it's scattered over individual directives
4142 // that allow the IF clause.
4143 //
4144 // if-clause ->
4145 //    IF([directive-name-modifier:]
4146 //        scalar-logical-expression)                // since 4.5
4147 struct OmpIfClause {
4148   TUPLE_CLASS_BOILERPLATE(OmpIfClause);
4149   MODIFIER_BOILERPLATE(OmpDirectiveNameModifier);
4150   std::tuple<MODIFIERS(), ScalarLogicalExpr> t;
4151 };
4152 
4153 // Ref: [5.0:170-176], [5.1:197-205], [5.2:138-139]
4154 //
4155 // in-reduction-clause ->
4156 //    IN_REDUCTION(reduction-identifier: list)      // since 5.0
4157 struct OmpInReductionClause {
4158   TUPLE_CLASS_BOILERPLATE(OmpInReductionClause);
4159   MODIFIER_BOILERPLATE(OmpReductionIdentifier);
4160   std::tuple<MODIFIERS(), OmpObjectList> t;
4161 };
4162 
4163 // Ref: [4.5:199-201], [5.0:288-290], [5.1:321-322], [5.2:115-117]
4164 //
4165 // lastprivate-clause ->
4166 //    LASTPRIVATE(list) |                           // since 4.5
4167 //    LASTPRIVATE([lastprivate-modifier:] list)     // since 5.0
4168 struct OmpLastprivateClause {
4169   TUPLE_CLASS_BOILERPLATE(OmpLastprivateClause);
4170   MODIFIER_BOILERPLATE(OmpLastprivateModifier);
4171   std::tuple<MODIFIERS(), OmpObjectList> t;
4172 };
4173 
4174 // Ref: [4.5:207-210], [5.0:290-293], [5.1:323-325], [5.2:117-120]
4175 //
4176 // linear-clause ->
4177 //    LINEAR(list [: step-simple-modifier]) |       // since 4.5
4178 //    LINEAR(linear-modifier(list)
4179 //        [: step-simple-modifier]) |               // since 4.5, until 5.2[*]
4180 //    LINEAR(list [: linear-modifier,
4181 //        step-complex-modifier])                   // since 5.2
4182 // [*] Still allowed in 5.2 when on DECLARE SIMD, but deprecated.
4183 struct OmpLinearClause {
4184   TUPLE_CLASS_BOILERPLATE(OmpLinearClause);
4185   MODIFIER_BOILERPLATE(
4186       OmpLinearModifier, OmpStepSimpleModifier, OmpStepComplexModifier);
4187   std::tuple<OmpObjectList, MODIFIERS(), /*PostModified=*/bool> t;
4188 };
4189 
4190 // Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158]
4191 //
4192 // map-clause ->
4193 //    MAP([modifier...:] locator-list)              // since 4.5
4194 // modifier ->
4195 //    map-type-modifier |                           // since 4.5
4196 //    mapper |                                      // since 5.0
4197 //    iterator |                                    // since 5.1
4198 //    map-type                                      // since 4.5
4199 struct OmpMapClause {
4200   TUPLE_CLASS_BOILERPLATE(OmpMapClause);
4201   MODIFIER_BOILERPLATE(OmpMapTypeModifier, OmpMapper, OmpIterator, OmpMapType);
4202   std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
4203 };
4204 
4205 // Ref: [5.0:58-60], [5.1:63-68], [5.2:194-195]
4206 //
4207 // match-clause ->
4208 //    MATCH (context-selector-specification)        // since 5.0
4209 struct OmpMatchClause {
4210   // The context-selector is an argument.
4211   WRAPPER_CLASS_BOILERPLATE(
4212       OmpMatchClause, traits::OmpContextSelectorSpecification);
4213 };
4214 
4215 // Ref: [5.2:217-218]
4216 // message-clause ->
4217 //    MESSAGE("message-text")
4218 struct OmpMessageClause {
4219   WRAPPER_CLASS_BOILERPLATE(OmpMessageClause, Expr);
4220 };
4221 
4222 // Ref: [4.5:87-91], [5.0:140-146], [5.1:166-171], [5.2:270]
4223 //
4224 // num-tasks-clause ->
4225 //    NUM_TASKS(num-tasks) |                        // since 4.5
4226 //    NUM_TASKS([prescriptiveness:] num-tasks)      // since 5.1
4227 struct OmpNumTasksClause {
4228   TUPLE_CLASS_BOILERPLATE(OmpNumTasksClause);
4229   MODIFIER_BOILERPLATE(OmpPrescriptiveness);
4230   std::tuple<MODIFIERS(), ScalarIntExpr> t;
4231 };
4232 
4233 // Ref: [5.0:101-109], [5.1:126-134], [5.2:233-234]
4234 //
4235 // order-clause ->
4236 //    ORDER(CONCURRENT) |                           // since 5.0
4237 //    ORDER([order-modifier:] CONCURRENT)           // since 5.1
4238 struct OmpOrderClause {
4239   TUPLE_CLASS_BOILERPLATE(OmpOrderClause);
4240   ENUM_CLASS(Ordering, Concurrent)
4241   MODIFIER_BOILERPLATE(OmpOrderModifier);
4242   std::tuple<MODIFIERS(), Ordering> t;
4243 };
4244 
4245 // Ref: [5.0:56-57], [5.1:60-62], [5.2:191]
4246 //
4247 // otherwise-clause ->
4248 //    DEFAULT ([directive-specification])           // since 5.0, until 5.1
4249 // otherwise-clause ->
4250 //    OTHERWISE ([directive-specification])]        // since 5.2
4251 struct OmpOtherwiseClause {
4252   WRAPPER_CLASS_BOILERPLATE(
4253       OmpOtherwiseClause, std::optional<OmpDirectiveSpecification>);
4254 };
4255 
4256 // Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:229-230]
4257 //
4258 // proc-bind-clause ->
4259 //    PROC_BIND(affinity-policy)                    // since 4.5
4260 // affinity-policy ->
4261 //    CLOSE | PRIMARY | SPREAD |                    // since 4.5
4262 //    MASTER                                        // since 4.5, until 5.2
4263 struct OmpProcBindClause {
4264   ENUM_CLASS(AffinityPolicy, Close, Master, Spread, Primary)
4265   WRAPPER_CLASS_BOILERPLATE(OmpProcBindClause, AffinityPolicy);
4266 };
4267 
4268 // Ref: [4.5:201-207], [5.0:300-302], [5.1:332-334], [5.2:134-137]
4269 //
4270 // reduction-clause ->
4271 //    REDUCTION(reduction-identifier: list) |       // since 4.5
4272 //    REDUCTION([reduction-modifier,]
4273 //        reduction-identifier: list)               // since 5.0
4274 struct OmpReductionClause {
4275   TUPLE_CLASS_BOILERPLATE(OmpReductionClause);
4276   MODIFIER_BOILERPLATE(OmpReductionModifier, OmpReductionIdentifier);
4277   std::tuple<MODIFIERS(), OmpObjectList> t;
4278 };
4279 
4280 // Ref: [4.5:56-63], [5.0:101-109], [5.1:126-133], [5.2:252-254]
4281 //
4282 // schedule-clause ->
4283 //    SCHEDULE([modifier[, modifier]:]
4284 //        kind[, chunk-size])                       // since 4.5, until 5.1
4285 // schedule-clause ->
4286 //    SCHEDULE([ordering-modifier], chunk-modifier],
4287 //        kind[, chunk_size])                       // since 5.2
4288 struct OmpScheduleClause {
4289   TUPLE_CLASS_BOILERPLATE(OmpScheduleClause);
4290   ENUM_CLASS(Kind, Static, Dynamic, Guided, Auto, Runtime)
4291   MODIFIER_BOILERPLATE(OmpOrderingModifier, OmpChunkModifier);
4292   std::tuple<MODIFIERS(), Kind, std::optional<ScalarIntExpr>> t;
4293 };
4294 
4295 // REF: [5.2:217]
4296 // severity-clause ->
4297 //    SEVERITY(warning|fatal)
4298 struct OmpSeverityClause {
4299   ENUM_CLASS(Severity, Fatal, Warning);
4300   WRAPPER_CLASS_BOILERPLATE(OmpSeverityClause, Severity);
4301 };
4302 
4303 // Ref: [5.0:232-234], [5.1:264-266], [5.2:137]
4304 //
4305 // task-reduction-clause ->
4306 //    TASK_REDUCTION(reduction-identifier: list)    // since 5.0
4307 struct OmpTaskReductionClause {
4308   TUPLE_CLASS_BOILERPLATE(OmpTaskReductionClause);
4309   MODIFIER_BOILERPLATE(OmpReductionIdentifier);
4310   std::tuple<MODIFIERS(), OmpObjectList> t;
4311 };
4312 
4313 // Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
4314 //
4315 // to-clause (in DECLARE TARGET) ->
4316 //    TO(extended-list) |                           // until 5.1
4317 // to-clause (in TARGET UPDATE) ->
4318 //    TO(locator-list) |
4319 //    TO(mapper-modifier: locator-list) |           // since 5.0
4320 //    TO(motion-modifier[,] ...: locator-list)      // since 5.1
4321 // motion-modifier ->
4322 //    PRESENT | mapper-modifier | iterator-modifier
4323 struct OmpToClause {
4324   TUPLE_CLASS_BOILERPLATE(OmpToClause);
4325   MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
4326   std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
4327 };
4328 
4329 // Ref: [5.0:254-255], [5.1:287-288], [5.2:321-322]
4330 //
4331 // update-clause ->
4332 //    UPDATE(dependence-type)                       // since 5.0, until 5.1
4333 // update-clause ->
4334 //    UPDATE(task-dependence-type)                  // since 5.2
4335 struct OmpUpdateClause {
4336   UNION_CLASS_BOILERPLATE(OmpUpdateClause);
4337   // The dependence type is an argument here, not a modifier.
4338   std::variant<OmpDependenceType, OmpTaskDependenceType> u;
4339 };
4340 
4341 // Ref: [5.0:56-57], [5.1:60-62], [5.2:190-191]
4342 //
4343 // when-clause ->
4344 //    WHEN (context-selector :
4345 //        [directive-specification])                // since 5.0
4346 struct OmpWhenClause {
4347   TUPLE_CLASS_BOILERPLATE(OmpWhenClause);
4348   MODIFIER_BOILERPLATE(OmpContextSelector);
4349   std::tuple<MODIFIERS(), std::optional<OmpDirectiveSpecification>> t;
4350 };
4351 
4352 // OpenMP Clauses
4353 struct OmpClause {
4354   UNION_CLASS_BOILERPLATE(OmpClause);
4355   llvm::omp::Clause Id() const;
4356 
4357 #define GEN_FLANG_CLAUSE_PARSER_CLASSES
4358 #include "llvm/Frontend/OpenMP/OMP.inc"
4359 
4360   CharBlock source;
4361 
4362   std::variant<
4363 #define GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST
4364 #include "llvm/Frontend/OpenMP/OMP.inc"
4365       >
4366       u;
4367 };
4368 
4369 struct OmpClauseList {
4370   WRAPPER_CLASS_BOILERPLATE(OmpClauseList, std::list<OmpClause>);
4371   CharBlock source;
4372 };
4373 
4374 // --- Directives and constructs
4375 
4376 struct OmpMetadirectiveDirective {
4377   TUPLE_CLASS_BOILERPLATE(OmpMetadirectiveDirective);
4378   std::tuple<OmpClauseList> t;
4379   CharBlock source;
4380 };
4381 
4382 // Ref: [5.1:89-90], [5.2:216]
4383 //
4384 // nothing-directive ->
4385 //    NOTHING                                     // since 5.1
4386 struct OmpNothingDirective {
4387   using EmptyTrait = std::true_type;
4388   COPY_AND_ASSIGN_BOILERPLATE(OmpNothingDirective);
4389   CharBlock source;
4390 };
4391 
4392 // Ref: OpenMP [5.2:216-218]
4393 // ERROR AT(compilation|execution) SEVERITY(fatal|warning) MESSAGE("msg-str)
4394 struct OmpErrorDirective {
4395   TUPLE_CLASS_BOILERPLATE(OmpErrorDirective);
4396   CharBlock source;
4397   std::tuple<Verbatim, OmpClauseList> t;
4398 };
4399 
4400 struct OpenMPUtilityConstruct {
4401   UNION_CLASS_BOILERPLATE(OpenMPUtilityConstruct);
4402   CharBlock source;
4403   std::variant<OmpErrorDirective, OmpNothingDirective> u;
4404 };
4405 
4406 // 2.7.2 SECTIONS
4407 // 2.11.2 PARALLEL SECTIONS
4408 struct OmpSectionsDirective {
4409   WRAPPER_CLASS_BOILERPLATE(OmpSectionsDirective, llvm::omp::Directive);
4410   CharBlock source;
4411 };
4412 
4413 struct OmpBeginSectionsDirective {
4414   TUPLE_CLASS_BOILERPLATE(OmpBeginSectionsDirective);
4415   std::tuple<OmpSectionsDirective, OmpClauseList> t;
4416   CharBlock source;
4417 };
4418 struct OmpEndSectionsDirective {
4419   TUPLE_CLASS_BOILERPLATE(OmpEndSectionsDirective);
4420   std::tuple<OmpSectionsDirective, OmpClauseList> t;
4421   CharBlock source;
4422 };
4423 
4424 // [!$omp section]
4425 //    structured-block
4426 // [!$omp section
4427 //    structured-block]
4428 // ...
4429 struct OpenMPSectionConstruct {
4430   WRAPPER_CLASS_BOILERPLATE(OpenMPSectionConstruct, Block);
4431   CharBlock source;
4432 };
4433 
4434 // `OmpSectionBlocks` is a list of section constructs. The parser guarentees
4435 // that the `OpenMPConstruct` here always encapsulates an
4436 // `OpenMPSectionConstruct` and not any other OpenMP construct.
4437 WRAPPER_CLASS(OmpSectionBlocks, std::list<OpenMPConstruct>);
4438 
4439 struct OpenMPSectionsConstruct {
4440   TUPLE_CLASS_BOILERPLATE(OpenMPSectionsConstruct);
4441   std::tuple<OmpBeginSectionsDirective, OmpSectionBlocks,
4442       OmpEndSectionsDirective>
4443       t;
4444 };
4445 
4446 // OpenMP directive beginning or ending a block
4447 struct OmpBlockDirective {
4448   WRAPPER_CLASS_BOILERPLATE(OmpBlockDirective, llvm::omp::Directive);
4449   CharBlock source;
4450 };
4451 
4452 // 2.10.6 declare-target -> DECLARE TARGET (extended-list) |
4453 //                          DECLARE TARGET [declare-target-clause[ [,]
4454 //                                          declare-target-clause]...]
4455 struct OmpDeclareTargetWithList {
4456   WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetWithList, OmpObjectList);
4457   CharBlock source;
4458 };
4459 
4460 struct OmpDeclareTargetWithClause {
4461   WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetWithClause, OmpClauseList);
4462   CharBlock source;
4463 };
4464 
4465 struct OmpDeclareTargetSpecifier {
4466   UNION_CLASS_BOILERPLATE(OmpDeclareTargetSpecifier);
4467   std::variant<OmpDeclareTargetWithList, OmpDeclareTargetWithClause> u;
4468 };
4469 
4470 struct OpenMPDeclareTargetConstruct {
4471   TUPLE_CLASS_BOILERPLATE(OpenMPDeclareTargetConstruct);
4472   CharBlock source;
4473   std::tuple<Verbatim, OmpDeclareTargetSpecifier> t;
4474 };
4475 
4476 struct OmpDeclareMapperSpecifier {
4477   TUPLE_CLASS_BOILERPLATE(OmpDeclareMapperSpecifier);
4478   std::tuple<std::optional<Name>, TypeSpec, Name> t;
4479 };
4480 
4481 // OMP v5.2: 5.8.8
4482 //  declare-mapper -> DECLARE MAPPER ([mapper-name :] type :: var) map-clauses
4483 struct OpenMPDeclareMapperConstruct {
4484   TUPLE_CLASS_BOILERPLATE(OpenMPDeclareMapperConstruct);
4485   CharBlock source;
4486   std::tuple<Verbatim, OmpDeclareMapperSpecifier, OmpClauseList> t;
4487 };
4488 
4489 // 2.16 declare-reduction -> DECLARE REDUCTION (reduction-identifier : type-list
4490 //                                              : combiner) [initializer-clause]
4491 struct OmpReductionCombiner {
4492   UNION_CLASS_BOILERPLATE(OmpReductionCombiner);
4493   WRAPPER_CLASS(FunctionCombiner, Call);
4494   std::variant<AssignmentStmt, FunctionCombiner> u;
4495 };
4496 
4497 WRAPPER_CLASS(OmpReductionInitializerClause, Expr);
4498 
4499 struct OpenMPDeclareReductionConstruct {
4500   TUPLE_CLASS_BOILERPLATE(OpenMPDeclareReductionConstruct);
4501   CharBlock source;
4502   std::tuple<Verbatim, OmpReductionIdentifier, std::list<DeclarationTypeSpec>,
4503       OmpReductionCombiner, std::optional<OmpReductionInitializerClause>>
4504       t;
4505 };
4506 
4507 // 2.8.2 declare-simd -> DECLARE SIMD [(proc-name)] [declare-simd-clause[ [,]
4508 //                                                   declare-simd-clause]...]
4509 struct OpenMPDeclareSimdConstruct {
4510   TUPLE_CLASS_BOILERPLATE(OpenMPDeclareSimdConstruct);
4511   CharBlock source;
4512   std::tuple<Verbatim, std::optional<Name>, OmpClauseList> t;
4513 };
4514 
4515 // 2.4 requires -> REQUIRES requires-clause[ [ [,] requires-clause]...]
4516 struct OpenMPRequiresConstruct {
4517   TUPLE_CLASS_BOILERPLATE(OpenMPRequiresConstruct);
4518   CharBlock source;
4519   std::tuple<Verbatim, OmpClauseList> t;
4520 };
4521 
4522 // 2.15.2 threadprivate -> THREADPRIVATE (variable-name-list)
4523 struct OpenMPThreadprivate {
4524   TUPLE_CLASS_BOILERPLATE(OpenMPThreadprivate);
4525   CharBlock source;
4526   std::tuple<Verbatim, OmpObjectList> t;
4527 };
4528 
4529 // 2.11.3 allocate -> ALLOCATE (variable-name-list) [clause]
4530 struct OpenMPDeclarativeAllocate {
4531   TUPLE_CLASS_BOILERPLATE(OpenMPDeclarativeAllocate);
4532   CharBlock source;
4533   std::tuple<Verbatim, OmpObjectList, OmpClauseList> t;
4534 };
4535 
4536 struct OpenMPDeclarativeConstruct {
4537   UNION_CLASS_BOILERPLATE(OpenMPDeclarativeConstruct);
4538   CharBlock source;
4539   std::variant<OpenMPDeclarativeAllocate, OpenMPDeclareMapperConstruct,
4540       OpenMPDeclareReductionConstruct, OpenMPDeclareSimdConstruct,
4541       OpenMPDeclareTargetConstruct, OpenMPThreadprivate,
4542       OpenMPRequiresConstruct, OpenMPUtilityConstruct>
4543       u;
4544 };
4545 
4546 // 2.13.2 CRITICAL [Name] <block> END CRITICAL [Name]
4547 struct OmpCriticalDirective {
4548   TUPLE_CLASS_BOILERPLATE(OmpCriticalDirective);
4549   CharBlock source;
4550   std::tuple<Verbatim, std::optional<Name>, OmpClauseList> t;
4551 };
4552 struct OmpEndCriticalDirective {
4553   TUPLE_CLASS_BOILERPLATE(OmpEndCriticalDirective);
4554   CharBlock source;
4555   std::tuple<Verbatim, std::optional<Name>> t;
4556 };
4557 struct OpenMPCriticalConstruct {
4558   TUPLE_CLASS_BOILERPLATE(OpenMPCriticalConstruct);
4559   std::tuple<OmpCriticalDirective, Block, OmpEndCriticalDirective> t;
4560 };
4561 
4562 // 2.11.3 allocate -> ALLOCATE [(variable-name-list)] [clause]
4563 //        [ALLOCATE (variable-name-list) [clause] [...]]
4564 //        allocate-statement
4565 //        clause -> allocator-clause
4566 struct OpenMPExecutableAllocate {
4567   TUPLE_CLASS_BOILERPLATE(OpenMPExecutableAllocate);
4568   CharBlock source;
4569   std::tuple<Verbatim, std::optional<OmpObjectList>, OmpClauseList,
4570       std::optional<std::list<OpenMPDeclarativeAllocate>>,
4571       Statement<AllocateStmt>>
4572       t;
4573 };
4574 
4575 EMPTY_CLASS(OmpEndAllocators);
4576 
4577 // 6.7 Allocators construct [OpenMP 5.2]
4578 //     allocators-construct -> ALLOCATORS [allocate-clause [,]]
4579 //                                allocate-stmt
4580 //                             [omp-end-allocators-construct]
4581 struct OpenMPAllocatorsConstruct {
4582   TUPLE_CLASS_BOILERPLATE(OpenMPAllocatorsConstruct);
4583   CharBlock source;
4584   std::tuple<Verbatim, OmpClauseList, Statement<AllocateStmt>,
4585       std::optional<OmpEndAllocators>>
4586       t;
4587 };
4588 
4589 // 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0]
4590 //        memory-order-clause -> acq_rel
4591 //                               release
4592 //                               acquire
4593 //                               seq_cst
4594 //                               relaxed
4595 struct OmpMemoryOrderClause {
4596   WRAPPER_CLASS_BOILERPLATE(OmpMemoryOrderClause, OmpClause);
4597   CharBlock source;
4598 };
4599 
4600 // 2.17.7 Atomic construct
4601 //        atomic-clause -> memory-order-clause | HINT(hint-expression) |
4602 //        FAIL(memory-order)
4603 struct OmpAtomicClause {
4604   UNION_CLASS_BOILERPLATE(OmpAtomicClause);
4605   CharBlock source;
4606   std::variant<OmpMemoryOrderClause, OmpFailClause, OmpClause> u;
4607 };
4608 
4609 // atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
4610 struct OmpAtomicClauseList {
4611   WRAPPER_CLASS_BOILERPLATE(OmpAtomicClauseList, std::list<OmpAtomicClause>);
4612   CharBlock source;
4613 };
4614 
4615 // END ATOMIC
4616 EMPTY_CLASS(OmpEndAtomic);
4617 
4618 // ATOMIC READ
4619 struct OmpAtomicRead {
4620   TUPLE_CLASS_BOILERPLATE(OmpAtomicRead);
4621   CharBlock source;
4622   std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4623       Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4624       t;
4625 };
4626 
4627 // ATOMIC WRITE
4628 struct OmpAtomicWrite {
4629   TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite);
4630   CharBlock source;
4631   std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4632       Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4633       t;
4634 };
4635 
4636 // ATOMIC UPDATE
4637 struct OmpAtomicUpdate {
4638   TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate);
4639   CharBlock source;
4640   std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4641       Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4642       t;
4643 };
4644 
4645 // ATOMIC CAPTURE
4646 struct OmpAtomicCapture {
4647   TUPLE_CLASS_BOILERPLATE(OmpAtomicCapture);
4648   CharBlock source;
4649   WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
4650   WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
4651   std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList, Stmt1, Stmt2,
4652       OmpEndAtomic>
4653       t;
4654 };
4655 
4656 struct OmpAtomicCompareIfStmt {
4657   UNION_CLASS_BOILERPLATE(OmpAtomicCompareIfStmt);
4658   std::variant<common::Indirection<IfStmt>, common::Indirection<IfConstruct>> u;
4659 };
4660 
4661 // ATOMIC COMPARE (OpenMP 5.1, OPenMP 5.2 spec: 15.8.4)
4662 struct OmpAtomicCompare {
4663   TUPLE_CLASS_BOILERPLATE(OmpAtomicCompare);
4664   CharBlock source;
4665   std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4666       OmpAtomicCompareIfStmt, std::optional<OmpEndAtomic>>
4667       t;
4668 };
4669 
4670 // ATOMIC
4671 struct OmpAtomic {
4672   TUPLE_CLASS_BOILERPLATE(OmpAtomic);
4673   CharBlock source;
4674   std::tuple<Verbatim, OmpAtomicClauseList, Statement<AssignmentStmt>,
4675       std::optional<OmpEndAtomic>>
4676       t;
4677 };
4678 
4679 // 2.17.7 atomic ->
4680 //        ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] |
4681 //        ATOMIC [atomic-clause-list]
4682 //        atomic-construct -> READ | WRITE | UPDATE | CAPTURE | COMPARE
4683 struct OpenMPAtomicConstruct {
4684   UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
4685   std::variant<OmpAtomicRead, OmpAtomicWrite, OmpAtomicCapture, OmpAtomicUpdate,
4686       OmpAtomicCompare, OmpAtomic>
4687       u;
4688 };
4689 
4690 // OpenMP directives that associate with loop(s)
4691 struct OmpLoopDirective {
4692   WRAPPER_CLASS_BOILERPLATE(OmpLoopDirective, llvm::omp::Directive);
4693   CharBlock source;
4694 };
4695 
4696 // 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP
4697 struct OmpCancelType {
4698   ENUM_CLASS(Type, Parallel, Sections, Do, Taskgroup)
4699   WRAPPER_CLASS_BOILERPLATE(OmpCancelType, Type);
4700   CharBlock source;
4701 };
4702 
4703 // 2.14.2 cancellation-point -> CANCELLATION POINT construct-type-clause
4704 struct OpenMPCancellationPointConstruct {
4705   TUPLE_CLASS_BOILERPLATE(OpenMPCancellationPointConstruct);
4706   CharBlock source;
4707   std::tuple<Verbatim, OmpCancelType> t;
4708 };
4709 
4710 // 2.14.1 cancel -> CANCEL construct-type-clause [ [,] if-clause]
4711 struct OpenMPCancelConstruct {
4712   TUPLE_CLASS_BOILERPLATE(OpenMPCancelConstruct);
4713   WRAPPER_CLASS(If, ScalarLogicalExpr);
4714   CharBlock source;
4715   std::tuple<Verbatim, OmpCancelType, std::optional<If>> t;
4716 };
4717 
4718 // Ref: [5.0:254-255], [5.1:287-288], [5.2:322-323]
4719 //
4720 // depobj-construct -> DEPOBJ(depend-object) depobj-clause  // since 5.0
4721 // depobj-clause -> depend-clause |                         // until 5.2
4722 //                  destroy-clause |
4723 //                  update-clause
4724 struct OpenMPDepobjConstruct {
4725   TUPLE_CLASS_BOILERPLATE(OpenMPDepobjConstruct);
4726   CharBlock source;
4727   std::tuple<Verbatim, OmpObject, OmpClause> t;
4728 };
4729 
4730 // Ref: [5.2: 200-201]
4731 //
4732 // dispatch-construct -> DISPATCH dispatch-clause
4733 // dispatch-clause -> depend-clause |
4734 //                    device-clause |
4735 //                    is_device_ptr-clause |
4736 //                    nocontext-clause |
4737 //                    novariants-clause |
4738 //                    nowait-clause
4739 struct OmpDispatchDirective {
4740   TUPLE_CLASS_BOILERPLATE(OmpDispatchDirective);
4741   CharBlock source;
4742   std::tuple<Verbatim, OmpClauseList> t;
4743 };
4744 
4745 EMPTY_CLASS(OmpEndDispatchDirective);
4746 
4747 struct OpenMPDispatchConstruct {
4748   TUPLE_CLASS_BOILERPLATE(OpenMPDispatchConstruct);
4749   CharBlock source;
4750   std::tuple<OmpDispatchDirective, Block,
4751       std::optional<OmpEndDispatchDirective>>
4752       t;
4753 };
4754 
4755 // 2.17.8 flush -> FLUSH [memory-order-clause] [(variable-name-list)]
4756 struct OpenMPFlushConstruct {
4757   TUPLE_CLASS_BOILERPLATE(OpenMPFlushConstruct);
4758   CharBlock source;
4759   std::tuple<Verbatim, std::optional<std::list<OmpMemoryOrderClause>>,
4760       std::optional<OmpObjectList>>
4761       t;
4762 };
4763 
4764 struct OmpSimpleStandaloneDirective {
4765   WRAPPER_CLASS_BOILERPLATE(OmpSimpleStandaloneDirective, llvm::omp::Directive);
4766   CharBlock source;
4767 };
4768 
4769 struct OpenMPSimpleStandaloneConstruct {
4770   TUPLE_CLASS_BOILERPLATE(OpenMPSimpleStandaloneConstruct);
4771   CharBlock source;
4772   std::tuple<OmpSimpleStandaloneDirective, OmpClauseList> t;
4773 };
4774 
4775 struct OpenMPStandaloneConstruct {
4776   UNION_CLASS_BOILERPLATE(OpenMPStandaloneConstruct);
4777   CharBlock source;
4778   std::variant<OpenMPSimpleStandaloneConstruct, OpenMPFlushConstruct,
4779       OpenMPCancelConstruct, OpenMPCancellationPointConstruct,
4780       OpenMPDepobjConstruct, OmpMetadirectiveDirective>
4781       u;
4782 };
4783 
4784 struct OmpBeginLoopDirective {
4785   TUPLE_CLASS_BOILERPLATE(OmpBeginLoopDirective);
4786   std::tuple<OmpLoopDirective, OmpClauseList> t;
4787   CharBlock source;
4788 };
4789 
4790 struct OmpEndLoopDirective {
4791   TUPLE_CLASS_BOILERPLATE(OmpEndLoopDirective);
4792   std::tuple<OmpLoopDirective, OmpClauseList> t;
4793   CharBlock source;
4794 };
4795 
4796 struct OmpBeginBlockDirective {
4797   TUPLE_CLASS_BOILERPLATE(OmpBeginBlockDirective);
4798   std::tuple<OmpBlockDirective, OmpClauseList> t;
4799   CharBlock source;
4800 };
4801 
4802 struct OmpEndBlockDirective {
4803   TUPLE_CLASS_BOILERPLATE(OmpEndBlockDirective);
4804   std::tuple<OmpBlockDirective, OmpClauseList> t;
4805   CharBlock source;
4806 };
4807 
4808 struct OpenMPBlockConstruct {
4809   TUPLE_CLASS_BOILERPLATE(OpenMPBlockConstruct);
4810   std::tuple<OmpBeginBlockDirective, Block, OmpEndBlockDirective> t;
4811 };
4812 
4813 // OpenMP directives enclosing do loop
4814 struct OpenMPLoopConstruct {
4815   TUPLE_CLASS_BOILERPLATE(OpenMPLoopConstruct);
4816   OpenMPLoopConstruct(OmpBeginLoopDirective &&a)
4817       : t({std::move(a), std::nullopt, std::nullopt}) {}
4818   std::tuple<OmpBeginLoopDirective, std::optional<DoConstruct>,
4819       std::optional<OmpEndLoopDirective>>
4820       t;
4821 };
4822 
4823 struct OpenMPConstruct {
4824   UNION_CLASS_BOILERPLATE(OpenMPConstruct);
4825   std::variant<OpenMPStandaloneConstruct, OpenMPSectionsConstruct,
4826       OpenMPSectionConstruct, OpenMPLoopConstruct, OpenMPBlockConstruct,
4827       OpenMPAtomicConstruct, OpenMPDeclarativeAllocate, OpenMPDispatchConstruct,
4828       OpenMPUtilityConstruct, OpenMPExecutableAllocate,
4829       OpenMPAllocatorsConstruct, OpenMPCriticalConstruct>
4830       u;
4831 };
4832 
4833 // Parse tree nodes for OpenACC 3.3 directives and clauses
4834 
4835 struct AccObject {
4836   UNION_CLASS_BOILERPLATE(AccObject);
4837   std::variant<Designator, /*common block*/ Name> u;
4838 };
4839 
4840 WRAPPER_CLASS(AccObjectList, std::list<AccObject>);
4841 
4842 // OpenACC directive beginning or ending a block
4843 struct AccBlockDirective {
4844   WRAPPER_CLASS_BOILERPLATE(AccBlockDirective, llvm::acc::Directive);
4845   CharBlock source;
4846 };
4847 
4848 struct AccLoopDirective {
4849   WRAPPER_CLASS_BOILERPLATE(AccLoopDirective, llvm::acc::Directive);
4850   CharBlock source;
4851 };
4852 
4853 struct AccStandaloneDirective {
4854   WRAPPER_CLASS_BOILERPLATE(AccStandaloneDirective, llvm::acc::Directive);
4855   CharBlock source;
4856 };
4857 
4858 // 2.11 Combined constructs
4859 struct AccCombinedDirective {
4860   WRAPPER_CLASS_BOILERPLATE(AccCombinedDirective, llvm::acc::Directive);
4861   CharBlock source;
4862 };
4863 
4864 struct AccDeclarativeDirective {
4865   WRAPPER_CLASS_BOILERPLATE(AccDeclarativeDirective, llvm::acc::Directive);
4866   CharBlock source;
4867 };
4868 
4869 // OpenACC Clauses
4870 struct AccBindClause {
4871   UNION_CLASS_BOILERPLATE(AccBindClause);
4872   std::variant<Name, ScalarDefaultCharExpr> u;
4873   CharBlock source;
4874 };
4875 
4876 struct AccDefaultClause {
4877   WRAPPER_CLASS_BOILERPLATE(AccDefaultClause, llvm::acc::DefaultValue);
4878   CharBlock source;
4879 };
4880 
4881 struct AccDataModifier {
4882   ENUM_CLASS(Modifier, ReadOnly, Zero)
4883   WRAPPER_CLASS_BOILERPLATE(AccDataModifier, Modifier);
4884   CharBlock source;
4885 };
4886 
4887 struct AccObjectListWithModifier {
4888   TUPLE_CLASS_BOILERPLATE(AccObjectListWithModifier);
4889   std::tuple<std::optional<AccDataModifier>, AccObjectList> t;
4890 };
4891 
4892 struct AccObjectListWithReduction {
4893   TUPLE_CLASS_BOILERPLATE(AccObjectListWithReduction);
4894   std::tuple<ReductionOperator, AccObjectList> t;
4895 };
4896 
4897 struct AccWaitArgument {
4898   TUPLE_CLASS_BOILERPLATE(AccWaitArgument);
4899   std::tuple<std::optional<ScalarIntExpr>, std::list<ScalarIntExpr>> t;
4900 };
4901 
4902 struct AccDeviceTypeExpr {
4903   WRAPPER_CLASS_BOILERPLATE(
4904       AccDeviceTypeExpr, Fortran::common::OpenACCDeviceType);
4905   CharBlock source;
4906 };
4907 
4908 struct AccDeviceTypeExprList {
4909   WRAPPER_CLASS_BOILERPLATE(
4910       AccDeviceTypeExprList, std::list<AccDeviceTypeExpr>);
4911 };
4912 
4913 struct AccTileExpr {
4914   TUPLE_CLASS_BOILERPLATE(AccTileExpr);
4915   CharBlock source;
4916   std::tuple<std::optional<ScalarIntConstantExpr>> t; // if null then *
4917 };
4918 
4919 struct AccTileExprList {
4920   WRAPPER_CLASS_BOILERPLATE(AccTileExprList, std::list<AccTileExpr>);
4921 };
4922 
4923 struct AccSizeExpr {
4924   WRAPPER_CLASS_BOILERPLATE(AccSizeExpr, std::optional<ScalarIntExpr>);
4925 };
4926 
4927 struct AccSizeExprList {
4928   WRAPPER_CLASS_BOILERPLATE(AccSizeExprList, std::list<AccSizeExpr>);
4929 };
4930 
4931 struct AccSelfClause {
4932   UNION_CLASS_BOILERPLATE(AccSelfClause);
4933   std::variant<std::optional<ScalarLogicalExpr>, AccObjectList> u;
4934   CharBlock source;
4935 };
4936 
4937 // num, dim, static
4938 struct AccGangArg {
4939   UNION_CLASS_BOILERPLATE(AccGangArg);
4940   WRAPPER_CLASS(Num, ScalarIntExpr);
4941   WRAPPER_CLASS(Dim, ScalarIntExpr);
4942   WRAPPER_CLASS(Static, AccSizeExpr);
4943   std::variant<Num, Dim, Static> u;
4944   CharBlock source;
4945 };
4946 
4947 struct AccGangArgList {
4948   WRAPPER_CLASS_BOILERPLATE(AccGangArgList, std::list<AccGangArg>);
4949 };
4950 
4951 struct AccCollapseArg {
4952   TUPLE_CLASS_BOILERPLATE(AccCollapseArg);
4953   std::tuple<bool, ScalarIntConstantExpr> t;
4954 };
4955 
4956 struct AccClause {
4957   UNION_CLASS_BOILERPLATE(AccClause);
4958 
4959 #define GEN_FLANG_CLAUSE_PARSER_CLASSES
4960 #include "llvm/Frontend/OpenACC/ACC.inc"
4961 
4962   CharBlock source;
4963 
4964   std::variant<
4965 #define GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST
4966 #include "llvm/Frontend/OpenACC/ACC.inc"
4967       >
4968       u;
4969 };
4970 
4971 struct AccClauseList {
4972   WRAPPER_CLASS_BOILERPLATE(AccClauseList, std::list<AccClause>);
4973   CharBlock source;
4974 };
4975 
4976 struct OpenACCRoutineConstruct {
4977   TUPLE_CLASS_BOILERPLATE(OpenACCRoutineConstruct);
4978   CharBlock source;
4979   std::tuple<Verbatim, std::optional<Name>, AccClauseList> t;
4980 };
4981 
4982 struct OpenACCCacheConstruct {
4983   TUPLE_CLASS_BOILERPLATE(OpenACCCacheConstruct);
4984   CharBlock source;
4985   std::tuple<Verbatim, AccObjectListWithModifier> t;
4986 };
4987 
4988 struct OpenACCWaitConstruct {
4989   TUPLE_CLASS_BOILERPLATE(OpenACCWaitConstruct);
4990   CharBlock source;
4991   std::tuple<Verbatim, std::optional<AccWaitArgument>, AccClauseList> t;
4992 };
4993 
4994 struct AccBeginLoopDirective {
4995   TUPLE_CLASS_BOILERPLATE(AccBeginLoopDirective);
4996   std::tuple<AccLoopDirective, AccClauseList> t;
4997   CharBlock source;
4998 };
4999 
5000 struct AccBeginBlockDirective {
5001   TUPLE_CLASS_BOILERPLATE(AccBeginBlockDirective);
5002   CharBlock source;
5003   std::tuple<AccBlockDirective, AccClauseList> t;
5004 };
5005 
5006 struct AccEndBlockDirective {
5007   CharBlock source;
5008   WRAPPER_CLASS_BOILERPLATE(AccEndBlockDirective, AccBlockDirective);
5009 };
5010 
5011 // ACC END ATOMIC
5012 EMPTY_CLASS(AccEndAtomic);
5013 
5014 // ACC ATOMIC READ
5015 struct AccAtomicRead {
5016   TUPLE_CLASS_BOILERPLATE(AccAtomicRead);
5017   std::tuple<Verbatim, Statement<AssignmentStmt>, std::optional<AccEndAtomic>>
5018       t;
5019 };
5020 
5021 // ACC ATOMIC WRITE
5022 struct AccAtomicWrite {
5023   TUPLE_CLASS_BOILERPLATE(AccAtomicWrite);
5024   std::tuple<Verbatim, Statement<AssignmentStmt>, std::optional<AccEndAtomic>>
5025       t;
5026 };
5027 
5028 // ACC ATOMIC UPDATE
5029 struct AccAtomicUpdate {
5030   TUPLE_CLASS_BOILERPLATE(AccAtomicUpdate);
5031   std::tuple<std::optional<Verbatim>, Statement<AssignmentStmt>,
5032       std::optional<AccEndAtomic>>
5033       t;
5034 };
5035 
5036 // ACC ATOMIC CAPTURE
5037 struct AccAtomicCapture {
5038   TUPLE_CLASS_BOILERPLATE(AccAtomicCapture);
5039   WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
5040   WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
5041   std::tuple<Verbatim, Stmt1, Stmt2, AccEndAtomic> t;
5042 };
5043 
5044 struct OpenACCAtomicConstruct {
5045   UNION_CLASS_BOILERPLATE(OpenACCAtomicConstruct);
5046   std::variant<AccAtomicRead, AccAtomicWrite, AccAtomicCapture, AccAtomicUpdate>
5047       u;
5048   CharBlock source;
5049 };
5050 
5051 struct OpenACCBlockConstruct {
5052   TUPLE_CLASS_BOILERPLATE(OpenACCBlockConstruct);
5053   std::tuple<AccBeginBlockDirective, Block, AccEndBlockDirective> t;
5054 };
5055 
5056 struct OpenACCStandaloneDeclarativeConstruct {
5057   TUPLE_CLASS_BOILERPLATE(OpenACCStandaloneDeclarativeConstruct);
5058   CharBlock source;
5059   std::tuple<AccDeclarativeDirective, AccClauseList> t;
5060 };
5061 
5062 struct AccBeginCombinedDirective {
5063   TUPLE_CLASS_BOILERPLATE(AccBeginCombinedDirective);
5064   CharBlock source;
5065   std::tuple<AccCombinedDirective, AccClauseList> t;
5066 };
5067 
5068 struct AccEndCombinedDirective {
5069   WRAPPER_CLASS_BOILERPLATE(AccEndCombinedDirective, AccCombinedDirective);
5070   CharBlock source;
5071 };
5072 
5073 struct OpenACCCombinedConstruct {
5074   TUPLE_CLASS_BOILERPLATE(OpenACCCombinedConstruct);
5075   CharBlock source;
5076   OpenACCCombinedConstruct(AccBeginCombinedDirective &&a)
5077       : t({std::move(a), std::nullopt, std::nullopt}) {}
5078   std::tuple<AccBeginCombinedDirective, std::optional<DoConstruct>,
5079       std::optional<AccEndCombinedDirective>>
5080       t;
5081 };
5082 
5083 struct OpenACCDeclarativeConstruct {
5084   UNION_CLASS_BOILERPLATE(OpenACCDeclarativeConstruct);
5085   CharBlock source;
5086   std::variant<OpenACCStandaloneDeclarativeConstruct, OpenACCRoutineConstruct>
5087       u;
5088 };
5089 
5090 // OpenACC directives enclosing do loop
5091 EMPTY_CLASS(AccEndLoop);
5092 struct OpenACCLoopConstruct {
5093   TUPLE_CLASS_BOILERPLATE(OpenACCLoopConstruct);
5094   OpenACCLoopConstruct(AccBeginLoopDirective &&a)
5095       : t({std::move(a), std::nullopt, std::nullopt}) {}
5096   std::tuple<AccBeginLoopDirective, std::optional<DoConstruct>,
5097       std::optional<AccEndLoop>>
5098       t;
5099 };
5100 
5101 struct OpenACCEndConstruct {
5102   WRAPPER_CLASS_BOILERPLATE(OpenACCEndConstruct, llvm::acc::Directive);
5103   CharBlock source;
5104 };
5105 
5106 struct OpenACCStandaloneConstruct {
5107   TUPLE_CLASS_BOILERPLATE(OpenACCStandaloneConstruct);
5108   CharBlock source;
5109   std::tuple<AccStandaloneDirective, AccClauseList> t;
5110 };
5111 
5112 struct OpenACCConstruct {
5113   UNION_CLASS_BOILERPLATE(OpenACCConstruct);
5114   std::variant<OpenACCBlockConstruct, OpenACCCombinedConstruct,
5115       OpenACCLoopConstruct, OpenACCStandaloneConstruct, OpenACCCacheConstruct,
5116       OpenACCWaitConstruct, OpenACCAtomicConstruct, OpenACCEndConstruct>
5117       u;
5118 };
5119 
5120 // CUF-kernel-do-construct ->
5121 //   !$CUF KERNEL DO [ (scalar-int-constant-expr) ]
5122 //      <<< grid, block [, stream] >>>
5123 //      [ cuf-reduction... ]
5124 //      do-construct
5125 // star-or-expr -> * | scalar-int-expr
5126 // grid -> * | scalar-int-expr | ( star-or-expr-list )
5127 // block -> * | scalar-int-expr | ( star-or-expr-list )
5128 // stream -> 0, scalar-int-expr | STREAM = scalar-int-expr
5129 // cuf-reduction -> [ REDUCE | REDUCTION ] (
5130 //                  reduction-op : scalar-variable-list )
5131 
5132 struct CUFReduction {
5133   TUPLE_CLASS_BOILERPLATE(CUFReduction);
5134   using Operator = ReductionOperator;
5135   std::tuple<Operator, std::list<Scalar<Variable>>> t;
5136 };
5137 
5138 struct CUFKernelDoConstruct {
5139   TUPLE_CLASS_BOILERPLATE(CUFKernelDoConstruct);
5140   WRAPPER_CLASS(StarOrExpr, std::optional<ScalarIntExpr>);
5141   struct LaunchConfiguration {
5142     TUPLE_CLASS_BOILERPLATE(LaunchConfiguration);
5143     std::tuple<std::list<StarOrExpr>, std::list<StarOrExpr>,
5144         std::optional<ScalarIntExpr>>
5145         t;
5146   };
5147   struct Directive {
5148     TUPLE_CLASS_BOILERPLATE(Directive);
5149     CharBlock source;
5150     std::tuple<std::optional<ScalarIntConstantExpr>,
5151         std::optional<LaunchConfiguration>, std::list<CUFReduction>>
5152         t;
5153   };
5154   std::tuple<Directive, std::optional<DoConstruct>> t;
5155 };
5156 
5157 } // namespace Fortran::parser
5158 #endif // FORTRAN_PARSER_PARSE_TREE_H_
5159