xref: /llvm-project/clang/include/clang/AST/StmtOpenACC.h (revision db81e8c42e121e62a00587b12d2b972dfcfb98c0)
1 //===- StmtOpenACC.h - Classes for OpenACC directives  ----------*- 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 /// \file
9 /// This file defines OpenACC AST classes for statement-level contructs.
10 ///
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_AST_STMTOPENACC_H
14 #define LLVM_CLANG_AST_STMTOPENACC_H
15 
16 #include "clang/AST/OpenACCClause.h"
17 #include "clang/AST/Stmt.h"
18 #include "clang/Basic/OpenACCKinds.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include <memory>
21 
22 namespace clang {
23 /// This is the base class for an OpenACC statement-level construct, other
24 /// construct types are expected to inherit from this.
25 class OpenACCConstructStmt : public Stmt {
26   friend class ASTStmtWriter;
27   friend class ASTStmtReader;
28   /// The directive kind. Each implementation of this interface should handle
29   /// specific kinds.
30   OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid;
31   /// The location of the directive statement, from the '#' to the last token of
32   /// the directive.
33   SourceRange Range;
34   /// The location of the directive name.
35   SourceLocation DirectiveLoc;
36 
37   /// The list of clauses.  This is stored here as an ArrayRef, as this is the
38   /// most convienient place to access the list, however the list itself should
39   /// be stored in leaf nodes, likely in trailing-storage.
40   MutableArrayRef<const OpenACCClause *> Clauses;
41 
42 protected:
43   OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K,
44                        SourceLocation Start, SourceLocation DirectiveLoc,
45                        SourceLocation End)
46       : Stmt(SC), Kind(K), Range(Start, End), DirectiveLoc(DirectiveLoc) {}
47 
48   // Used only for initialization, the leaf class can initialize this to
49   // trailing storage.
50   void setClauseList(MutableArrayRef<const OpenACCClause *> NewClauses) {
51     assert(Clauses.empty() && "Cannot change clause list");
52     Clauses = NewClauses;
53   }
54 
55 public:
56   OpenACCDirectiveKind getDirectiveKind() const { return Kind; }
57 
58   static bool classof(const Stmt *S) {
59     return S->getStmtClass() >= firstOpenACCConstructStmtConstant &&
60            S->getStmtClass() <= lastOpenACCConstructStmtConstant;
61   }
62 
63   SourceLocation getBeginLoc() const { return Range.getBegin(); }
64   SourceLocation getEndLoc() const { return Range.getEnd(); }
65   SourceLocation getDirectiveLoc() const { return DirectiveLoc; }
66   ArrayRef<const OpenACCClause *> clauses() const { return Clauses; }
67 
68   child_range children() {
69     return child_range(child_iterator(), child_iterator());
70   }
71 
72   const_child_range children() const {
73     return const_cast<OpenACCConstructStmt *>(this)->children();
74   }
75 };
76 
77 /// This is a base class for any OpenACC statement-level constructs that have an
78 /// associated statement. This class is not intended to be instantiated, but is
79 /// a convenient place to hold the associated statement.
80 class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
81   friend class ASTStmtWriter;
82   friend class ASTStmtReader;
83   template <typename Derived> friend class RecursiveASTVisitor;
84   Stmt *AssociatedStmt = nullptr;
85 
86 protected:
87   OpenACCAssociatedStmtConstruct(StmtClass SC, OpenACCDirectiveKind K,
88                                  SourceLocation Start,
89                                  SourceLocation DirectiveLoc,
90                                  SourceLocation End, Stmt *AssocStmt)
91       : OpenACCConstructStmt(SC, K, Start, DirectiveLoc, End),
92         AssociatedStmt(AssocStmt) {}
93 
94   void setAssociatedStmt(Stmt *S) { AssociatedStmt = S; }
95   Stmt *getAssociatedStmt() { return AssociatedStmt; }
96   const Stmt *getAssociatedStmt() const {
97     return const_cast<OpenACCAssociatedStmtConstruct *>(this)
98         ->getAssociatedStmt();
99   }
100 
101 public:
102   static bool classof(const Stmt *T) {
103     return false;
104   }
105 
106   child_range children() {
107     if (getAssociatedStmt())
108       return child_range(&AssociatedStmt, &AssociatedStmt + 1);
109     return child_range(child_iterator(), child_iterator());
110   }
111 
112   const_child_range children() const {
113     return const_cast<OpenACCAssociatedStmtConstruct *>(this)->children();
114   }
115 };
116 
117 /// This class represents a compute construct, representing a 'Kind' of
118 /// `parallel', 'serial', or 'kernel'. These constructs are associated with a
119 /// 'structured block', defined as:
120 ///
121 ///  in C or C++, an executable statement, possibly compound, with a single
122 ///  entry at the top and a single exit at the bottom
123 ///
124 /// At the moment there is no real motivation to have a different AST node for
125 /// those three, as they are semantically identical, and have only minor
126 /// differences in the permitted list of clauses, which can be differentiated by
127 /// the 'Kind'.
128 class OpenACCComputeConstruct final
129     : public OpenACCAssociatedStmtConstruct,
130       private llvm::TrailingObjects<OpenACCComputeConstruct,
131                                     const OpenACCClause *> {
132   friend class ASTStmtWriter;
133   friend class ASTStmtReader;
134   friend class ASTContext;
135   friend TrailingObjects;
136   OpenACCComputeConstruct(unsigned NumClauses)
137       : OpenACCAssociatedStmtConstruct(
138             OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid,
139             SourceLocation{}, SourceLocation{}, SourceLocation{},
140             /*AssociatedStmt=*/nullptr) {
141     // We cannot send the TrailingObjects storage to the base class (which holds
142     // a reference to the data) until it is constructed, so we have to set it
143     // separately here.
144     std::uninitialized_value_construct(
145         getTrailingObjects<const OpenACCClause *>(),
146         getTrailingObjects<const OpenACCClause *>() + NumClauses);
147     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
148                                   NumClauses));
149   }
150 
151   OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start,
152                           SourceLocation DirectiveLoc, SourceLocation End,
153                           ArrayRef<const OpenACCClause *> Clauses,
154                           Stmt *StructuredBlock)
155       : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start,
156                                        DirectiveLoc, End, StructuredBlock) {
157     assert(isOpenACCComputeDirectiveKind(K) &&
158            "Only parallel, serial, and kernels constructs should be "
159            "represented by this type");
160 
161     // Initialize the trailing storage.
162     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
163                             getTrailingObjects<const OpenACCClause *>());
164 
165     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
166                                   Clauses.size()));
167   }
168 
169   void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
170 
171 public:
172   static bool classof(const Stmt *T) {
173     return T->getStmtClass() == OpenACCComputeConstructClass;
174   }
175 
176   static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C,
177                                               unsigned NumClauses);
178   static OpenACCComputeConstruct *
179   Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
180          SourceLocation DirectiveLoc, SourceLocation EndLoc,
181          ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock);
182 
183   Stmt *getStructuredBlock() { return getAssociatedStmt(); }
184   const Stmt *getStructuredBlock() const {
185     return const_cast<OpenACCComputeConstruct *>(this)->getStructuredBlock();
186   }
187 };
188 /// This class represents a 'loop' construct.  The 'loop' construct applies to a
189 /// 'for' loop (or range-for loop), and is optionally associated with a Compute
190 /// Construct.
191 class OpenACCLoopConstruct final
192     : public OpenACCAssociatedStmtConstruct,
193       private llvm::TrailingObjects<OpenACCLoopConstruct,
194                                    const OpenACCClause *> {
195   // The compute/combined construct kind this loop is associated with, or
196   // invalid if this is an orphaned loop construct.
197   OpenACCDirectiveKind ParentComputeConstructKind =
198       OpenACCDirectiveKind::Invalid;
199 
200   friend class ASTStmtWriter;
201   friend class ASTStmtReader;
202   friend class ASTContext;
203   friend class OpenACCAssociatedStmtConstruct;
204   friend class OpenACCCombinedConstruct;
205   friend class OpenACCComputeConstruct;
206   friend TrailingObjects;
207 
208   OpenACCLoopConstruct(unsigned NumClauses);
209 
210   OpenACCLoopConstruct(OpenACCDirectiveKind ParentKind, SourceLocation Start,
211                        SourceLocation DirLoc, SourceLocation End,
212                        ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);
213 
214 public:
215   static bool classof(const Stmt *T) {
216     return T->getStmtClass() == OpenACCLoopConstructClass;
217   }
218 
219   static OpenACCLoopConstruct *CreateEmpty(const ASTContext &C,
220                                            unsigned NumClauses);
221 
222   static OpenACCLoopConstruct *
223   Create(const ASTContext &C, OpenACCDirectiveKind ParentKind,
224          SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation EndLoc,
225          ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);
226 
227   Stmt *getLoop() { return getAssociatedStmt(); }
228   const Stmt *getLoop() const {
229     return const_cast<OpenACCLoopConstruct *>(this)->getLoop();
230   }
231 
232   /// OpenACC 3.3 2.9:
233   /// An orphaned loop construct is a loop construct that is not lexically
234   /// enclosed within a compute construct. The parent compute construct of a
235   /// loop construct is the nearest compute construct that lexically contains
236   /// the loop construct.
237   bool isOrphanedLoopConstruct() const {
238     return ParentComputeConstructKind == OpenACCDirectiveKind::Invalid;
239   }
240 
241   OpenACCDirectiveKind getParentComputeConstructKind() const {
242     return ParentComputeConstructKind;
243   }
244 };
245 
246 // This class represents a 'combined' construct, which has a bunch of rules
247 // shared with both loop and compute constructs.
248 class OpenACCCombinedConstruct final
249     : public OpenACCAssociatedStmtConstruct,
250       private llvm::TrailingObjects<OpenACCCombinedConstruct,
251                                    const OpenACCClause *> {
252   friend TrailingObjects;
253   OpenACCCombinedConstruct(unsigned NumClauses)
254       : OpenACCAssociatedStmtConstruct(
255             OpenACCCombinedConstructClass, OpenACCDirectiveKind::Invalid,
256             SourceLocation{}, SourceLocation{}, SourceLocation{},
257             /*AssociatedStmt=*/nullptr) {
258     std::uninitialized_value_construct(
259         getTrailingObjects<const OpenACCClause *>(),
260         getTrailingObjects<const OpenACCClause *>() + NumClauses);
261     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
262                                   NumClauses));
263   }
264 
265   OpenACCCombinedConstruct(OpenACCDirectiveKind K, SourceLocation Start,
266                            SourceLocation DirectiveLoc, SourceLocation End,
267                            ArrayRef<const OpenACCClause *> Clauses,
268                            Stmt *StructuredBlock)
269       : OpenACCAssociatedStmtConstruct(OpenACCCombinedConstructClass, K, Start,
270                                        DirectiveLoc, End, StructuredBlock) {
271     assert(isOpenACCCombinedDirectiveKind(K) &&
272            "Only parallel loop, serial loop, and kernels loop constructs "
273            "should be represented by this type");
274 
275     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
276                             getTrailingObjects<const OpenACCClause *>());
277     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
278                                   Clauses.size()));
279   }
280   void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
281 
282 public:
283   static bool classof(const Stmt *T) {
284     return T->getStmtClass() == OpenACCCombinedConstructClass;
285   }
286 
287   static OpenACCCombinedConstruct *CreateEmpty(const ASTContext &C,
288                                                unsigned NumClauses);
289   static OpenACCCombinedConstruct *
290   Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation Start,
291          SourceLocation DirectiveLoc, SourceLocation End,
292          ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock);
293   Stmt *getLoop() { return getAssociatedStmt(); }
294   const Stmt *getLoop() const {
295     return const_cast<OpenACCCombinedConstruct *>(this)->getLoop();
296   }
297 };
298 
299 // This class represents a 'data' construct, which has an associated statement
300 // and clauses, but is otherwise pretty simple.
301 class OpenACCDataConstruct final
302     : public OpenACCAssociatedStmtConstruct,
303       private llvm::TrailingObjects<OpenACCDataConstruct,
304                                    const OpenACCClause *> {
305   friend TrailingObjects;
306   OpenACCDataConstruct(unsigned NumClauses)
307       : OpenACCAssociatedStmtConstruct(
308             OpenACCDataConstructClass, OpenACCDirectiveKind::Data,
309             SourceLocation{}, SourceLocation{}, SourceLocation{},
310             /*AssociatedStmt=*/nullptr) {
311     std::uninitialized_value_construct(
312         getTrailingObjects<const OpenACCClause *>(),
313         getTrailingObjects<const OpenACCClause *>() + NumClauses);
314     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
315                                   NumClauses));
316   }
317 
318   OpenACCDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
319                        SourceLocation End,
320                        ArrayRef<const OpenACCClause *> Clauses,
321                        Stmt *StructuredBlock)
322       : OpenACCAssociatedStmtConstruct(OpenACCDataConstructClass,
323                                        OpenACCDirectiveKind::Data, Start,
324                                        DirectiveLoc, End, StructuredBlock) {
325     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
326                             getTrailingObjects<const OpenACCClause *>());
327     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
328                                   Clauses.size()));
329   }
330   void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
331 
332 public:
333   static bool classof(const Stmt *T) {
334     return T->getStmtClass() == OpenACCDataConstructClass;
335   }
336 
337   static OpenACCDataConstruct *CreateEmpty(const ASTContext &C,
338                                            unsigned NumClauses);
339   static OpenACCDataConstruct *Create(const ASTContext &C, SourceLocation Start,
340                                       SourceLocation DirectiveLoc,
341                                       SourceLocation End,
342                                       ArrayRef<const OpenACCClause *> Clauses,
343                                       Stmt *StructuredBlock);
344   Stmt *getStructuredBlock() { return getAssociatedStmt(); }
345   const Stmt *getStructuredBlock() const {
346     return const_cast<OpenACCDataConstruct *>(this)->getStructuredBlock();
347   }
348 };
349 // This class represents a 'enter data' construct, which JUST has clauses.
350 class OpenACCEnterDataConstruct final
351     : public OpenACCConstructStmt,
352       private llvm::TrailingObjects<OpenACCEnterDataConstruct,
353                                    const OpenACCClause *> {
354   friend TrailingObjects;
355   OpenACCEnterDataConstruct(unsigned NumClauses)
356       : OpenACCConstructStmt(OpenACCEnterDataConstructClass,
357                              OpenACCDirectiveKind::EnterData, SourceLocation{},
358                              SourceLocation{}, SourceLocation{}) {
359     std::uninitialized_value_construct(
360         getTrailingObjects<const OpenACCClause *>(),
361         getTrailingObjects<const OpenACCClause *>() + NumClauses);
362     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
363                                   NumClauses));
364   }
365   OpenACCEnterDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
366                             SourceLocation End,
367                             ArrayRef<const OpenACCClause *> Clauses)
368       : OpenACCConstructStmt(OpenACCEnterDataConstructClass,
369                              OpenACCDirectiveKind::EnterData, Start,
370                              DirectiveLoc, End) {
371     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
372                             getTrailingObjects<const OpenACCClause *>());
373     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
374                                   Clauses.size()));
375   }
376 
377 public:
378   static bool classof(const Stmt *T) {
379     return T->getStmtClass() == OpenACCEnterDataConstructClass;
380   }
381   static OpenACCEnterDataConstruct *CreateEmpty(const ASTContext &C,
382                                                 unsigned NumClauses);
383   static OpenACCEnterDataConstruct *
384   Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
385          SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
386 };
387 // This class represents a 'exit data' construct, which JUST has clauses.
388 class OpenACCExitDataConstruct final
389     : public OpenACCConstructStmt,
390       private llvm::TrailingObjects<OpenACCExitDataConstruct,
391                                    const OpenACCClause *> {
392   friend TrailingObjects;
393   OpenACCExitDataConstruct(unsigned NumClauses)
394       : OpenACCConstructStmt(OpenACCExitDataConstructClass,
395                              OpenACCDirectiveKind::ExitData, SourceLocation{},
396                              SourceLocation{}, SourceLocation{}) {
397     std::uninitialized_value_construct(
398         getTrailingObjects<const OpenACCClause *>(),
399         getTrailingObjects<const OpenACCClause *>() + NumClauses);
400     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
401                                   NumClauses));
402   }
403   OpenACCExitDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
404                            SourceLocation End,
405                            ArrayRef<const OpenACCClause *> Clauses)
406       : OpenACCConstructStmt(OpenACCExitDataConstructClass,
407                              OpenACCDirectiveKind::ExitData, Start,
408                              DirectiveLoc, End) {
409     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
410                             getTrailingObjects<const OpenACCClause *>());
411     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
412                                   Clauses.size()));
413   }
414 
415 public:
416   static bool classof(const Stmt *T) {
417     return T->getStmtClass() == OpenACCExitDataConstructClass;
418   }
419   static OpenACCExitDataConstruct *CreateEmpty(const ASTContext &C,
420                                                unsigned NumClauses);
421   static OpenACCExitDataConstruct *
422   Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
423          SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
424 };
425 // This class represents a 'host_data' construct, which has an associated
426 // statement and clauses, but is otherwise pretty simple.
427 class OpenACCHostDataConstruct final
428     : public OpenACCAssociatedStmtConstruct,
429       private llvm::TrailingObjects<OpenACCHostDataConstruct,
430                                    const OpenACCClause *> {
431   friend TrailingObjects;
432   OpenACCHostDataConstruct(unsigned NumClauses)
433       : OpenACCAssociatedStmtConstruct(
434             OpenACCHostDataConstructClass, OpenACCDirectiveKind::HostData,
435             SourceLocation{}, SourceLocation{}, SourceLocation{},
436             /*AssociatedStmt=*/nullptr) {
437     std::uninitialized_value_construct(
438         getTrailingObjects<const OpenACCClause *>(),
439         getTrailingObjects<const OpenACCClause *>() + NumClauses);
440     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
441                                   NumClauses));
442   }
443   OpenACCHostDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
444                            SourceLocation End,
445                            ArrayRef<const OpenACCClause *> Clauses,
446                            Stmt *StructuredBlock)
447       : OpenACCAssociatedStmtConstruct(OpenACCHostDataConstructClass,
448                                        OpenACCDirectiveKind::HostData, Start,
449                                        DirectiveLoc, End, StructuredBlock) {
450     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
451                             getTrailingObjects<const OpenACCClause *>());
452     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
453                                   Clauses.size()));
454   }
455   void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
456 
457 public:
458   static bool classof(const Stmt *T) {
459     return T->getStmtClass() == OpenACCHostDataConstructClass;
460   }
461   static OpenACCHostDataConstruct *CreateEmpty(const ASTContext &C,
462                                                unsigned NumClauses);
463   static OpenACCHostDataConstruct *
464   Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
465          SourceLocation End, ArrayRef<const OpenACCClause *> Clauses,
466          Stmt *StructuredBlock);
467   Stmt *getStructuredBlock() { return getAssociatedStmt(); }
468   const Stmt *getStructuredBlock() const {
469     return const_cast<OpenACCHostDataConstruct *>(this)->getStructuredBlock();
470   }
471 };
472 
473 // This class represents a 'wait' construct, which has some expressions plus a
474 // clause list.
475 class OpenACCWaitConstruct final
476     : public OpenACCConstructStmt,
477       private llvm::TrailingObjects<OpenACCWaitConstruct, Expr *,
478                                     OpenACCClause *> {
479   // FIXME: We should be storing a `const OpenACCClause *` to be consistent with
480   // the rest of the constructs, but TrailingObjects doesn't allow for mixing
481   // constness in its implementation of `getTrailingObjects`.
482 
483   friend TrailingObjects;
484   friend class ASTStmtWriter;
485   friend class ASTStmtReader;
486   // Locations of the left and right parens of the 'wait-argument'
487   // expression-list.
488   SourceLocation LParenLoc, RParenLoc;
489   // Location of the 'queues' keyword, if present.
490   SourceLocation QueuesLoc;
491 
492   // Number of the expressions being represented.  Index '0' is always the
493   // 'devnum' expression, even if it not present.
494   unsigned NumExprs = 0;
495 
496   OpenACCWaitConstruct(unsigned NumExprs, unsigned NumClauses)
497       : OpenACCConstructStmt(OpenACCWaitConstructClass,
498                              OpenACCDirectiveKind::Wait, SourceLocation{},
499                              SourceLocation{}, SourceLocation{}),
500         NumExprs(NumExprs) {
501     assert(NumExprs >= 1 &&
502            "NumExprs should always be >= 1 because the 'devnum' "
503            "expr is represented by a null if necessary");
504     std::uninitialized_value_construct(getExprPtr(),
505                                        getExprPtr() + NumExprs);
506     std::uninitialized_value_construct(getTrailingObjects<OpenACCClause *>(),
507                                        getTrailingObjects<OpenACCClause *>() +
508                                            NumClauses);
509     setClauseList(MutableArrayRef(const_cast<const OpenACCClause **>(
510                                       getTrailingObjects<OpenACCClause *>()),
511                                   NumClauses));
512   }
513 
514   OpenACCWaitConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
515                        SourceLocation LParenLoc, Expr *DevNumExpr,
516                        SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs,
517                        SourceLocation RParenLoc, SourceLocation End,
518                        ArrayRef<const OpenACCClause *> Clauses)
519       : OpenACCConstructStmt(OpenACCWaitConstructClass,
520                              OpenACCDirectiveKind::Wait, Start, DirectiveLoc,
521                              End),
522         LParenLoc(LParenLoc), RParenLoc(RParenLoc), QueuesLoc(QueuesLoc),
523         NumExprs(QueueIdExprs.size() + 1) {
524     assert(NumExprs >= 1 &&
525            "NumExprs should always be >= 1 because the 'devnum' "
526            "expr is represented by a null if necessary");
527 
528     std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1,
529                             getExprPtr());
530     std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(),
531                             getExprPtr() + 1);
532 
533     std::uninitialized_copy(const_cast<OpenACCClause **>(Clauses.begin()),
534                             const_cast<OpenACCClause **>(Clauses.end()),
535                             getTrailingObjects<OpenACCClause *>());
536     setClauseList(MutableArrayRef(const_cast<const OpenACCClause **>(
537                                       getTrailingObjects<OpenACCClause *>()),
538                                   Clauses.size()));
539   }
540 
541   size_t numTrailingObjects(OverloadToken<Expr *>) const { return NumExprs; }
542   size_t numTrailingObjects(OverloadToken<const OpenACCClause *>) const {
543     return clauses().size();
544   }
545 
546   Expr **getExprPtr() const {
547     return const_cast<Expr**>(getTrailingObjects<Expr *>());
548   }
549 
550   llvm::ArrayRef<Expr *> getExprs() const {
551     return llvm::ArrayRef<Expr *>(getExprPtr(), NumExprs);
552   }
553 
554   llvm::ArrayRef<Expr *> getExprs() {
555     return llvm::ArrayRef<Expr *>(getExprPtr(), NumExprs);
556   }
557 
558 public:
559   static bool classof(const Stmt *T) {
560     return T->getStmtClass() == OpenACCWaitConstructClass;
561   }
562 
563   static OpenACCWaitConstruct *
564   CreateEmpty(const ASTContext &C, unsigned NumExprs, unsigned NumClauses);
565 
566   static OpenACCWaitConstruct *
567   Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
568          SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc,
569          ArrayRef<Expr *> QueueIdExprs, SourceLocation RParenLoc,
570          SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
571 
572   SourceLocation getLParenLoc() const { return LParenLoc; }
573   SourceLocation getRParenLoc() const { return RParenLoc; }
574   bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); }
575   SourceLocation getQueuesLoc() const { return QueuesLoc; }
576 
577   bool hasDevNumExpr() const { return getExprs()[0]; }
578   Expr *getDevNumExpr() const { return getExprs()[0]; }
579   llvm::ArrayRef<Expr *> getQueueIdExprs() { return getExprs().drop_front(); }
580   llvm::ArrayRef<Expr *> getQueueIdExprs() const {
581     return getExprs().drop_front();
582   }
583 
584   child_range children() {
585     Stmt **Begin = reinterpret_cast<Stmt **>(getExprPtr());
586     return child_range(Begin, Begin + NumExprs);
587   }
588 
589   const_child_range children() const {
590     Stmt *const *Begin =
591         reinterpret_cast<Stmt *const *>(getExprPtr());
592     return const_child_range(Begin, Begin + NumExprs);
593   }
594 };
595 
596 // This class represents an 'init' construct, which has just a clause list.
597 class OpenACCInitConstruct final
598     : public OpenACCConstructStmt,
599       private llvm::TrailingObjects<OpenACCInitConstruct,
600                                     const OpenACCClause *> {
601   friend TrailingObjects;
602   OpenACCInitConstruct(unsigned NumClauses)
603       : OpenACCConstructStmt(OpenACCInitConstructClass,
604                              OpenACCDirectiveKind::Init, SourceLocation{},
605                              SourceLocation{}, SourceLocation{}) {
606     std::uninitialized_value_construct(
607         getTrailingObjects<const OpenACCClause *>(),
608         getTrailingObjects<const OpenACCClause *>() + NumClauses);
609     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
610                                   NumClauses));
611   }
612   OpenACCInitConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
613                        SourceLocation End,
614                        ArrayRef<const OpenACCClause *> Clauses)
615       : OpenACCConstructStmt(OpenACCInitConstructClass,
616                              OpenACCDirectiveKind::Init, Start, DirectiveLoc,
617                              End) {
618     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
619                             getTrailingObjects<const OpenACCClause *>());
620     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
621                                   Clauses.size()));
622   }
623 
624 public:
625   static bool classof(const Stmt *T) {
626     return T->getStmtClass() == OpenACCInitConstructClass;
627   }
628   static OpenACCInitConstruct *CreateEmpty(const ASTContext &C,
629                                            unsigned NumClauses);
630   static OpenACCInitConstruct *Create(const ASTContext &C, SourceLocation Start,
631                                       SourceLocation DirectiveLoc,
632                                       SourceLocation End,
633                                       ArrayRef<const OpenACCClause *> Clauses);
634 };
635 
636 // This class represents a 'shutdown' construct, which has just a clause list.
637 class OpenACCShutdownConstruct final
638     : public OpenACCConstructStmt,
639       private llvm::TrailingObjects<OpenACCShutdownConstruct,
640                                     const OpenACCClause *> {
641   friend TrailingObjects;
642   OpenACCShutdownConstruct(unsigned NumClauses)
643       : OpenACCConstructStmt(OpenACCShutdownConstructClass,
644                              OpenACCDirectiveKind::Shutdown, SourceLocation{},
645                              SourceLocation{}, SourceLocation{}) {
646     std::uninitialized_value_construct(
647         getTrailingObjects<const OpenACCClause *>(),
648         getTrailingObjects<const OpenACCClause *>() + NumClauses);
649     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
650                                   NumClauses));
651   }
652   OpenACCShutdownConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
653                            SourceLocation End,
654                            ArrayRef<const OpenACCClause *> Clauses)
655       : OpenACCConstructStmt(OpenACCShutdownConstructClass,
656                              OpenACCDirectiveKind::Shutdown, Start,
657                              DirectiveLoc, End) {
658     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
659                             getTrailingObjects<const OpenACCClause *>());
660     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
661                                   Clauses.size()));
662   }
663 
664 public:
665   static bool classof(const Stmt *T) {
666     return T->getStmtClass() == OpenACCShutdownConstructClass;
667   }
668   static OpenACCShutdownConstruct *CreateEmpty(const ASTContext &C,
669                                                unsigned NumClauses);
670   static OpenACCShutdownConstruct *
671   Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
672          SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
673 };
674 
675 // This class represents a 'set' construct, which has just a clause list.
676 class OpenACCSetConstruct final
677     : public OpenACCConstructStmt,
678       private llvm::TrailingObjects<OpenACCSetConstruct,
679                                     const OpenACCClause *> {
680   friend TrailingObjects;
681   OpenACCSetConstruct(unsigned NumClauses)
682       : OpenACCConstructStmt(OpenACCSetConstructClass,
683                              OpenACCDirectiveKind::Set, SourceLocation{},
684                              SourceLocation{}, SourceLocation{}) {
685     std::uninitialized_value_construct(
686         getTrailingObjects<const OpenACCClause *>(),
687         getTrailingObjects<const OpenACCClause *>() + NumClauses);
688     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
689                                   NumClauses));
690   }
691 
692   OpenACCSetConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
693                       SourceLocation End,
694                       ArrayRef<const OpenACCClause *> Clauses)
695       : OpenACCConstructStmt(OpenACCSetConstructClass,
696                              OpenACCDirectiveKind::Set, Start, DirectiveLoc,
697                              End) {
698     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
699                             getTrailingObjects<const OpenACCClause *>());
700     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
701                                   Clauses.size()));
702   }
703 
704 public:
705   static bool classof(const Stmt *T) {
706     return T->getStmtClass() == OpenACCSetConstructClass;
707   }
708   static OpenACCSetConstruct *CreateEmpty(const ASTContext &C,
709                                           unsigned NumClauses);
710   static OpenACCSetConstruct *Create(const ASTContext &C, SourceLocation Start,
711                                      SourceLocation DirectiveLoc,
712                                      SourceLocation End,
713                                      ArrayRef<const OpenACCClause *> Clauses);
714 };
715 // This class represents an 'update' construct, which has just a clause list.
716 class OpenACCUpdateConstruct final
717     : public OpenACCConstructStmt,
718       private llvm::TrailingObjects<OpenACCUpdateConstruct,
719                                     const OpenACCClause *> {
720   friend TrailingObjects;
721   OpenACCUpdateConstruct(unsigned NumClauses)
722       : OpenACCConstructStmt(OpenACCUpdateConstructClass,
723                              OpenACCDirectiveKind::Update, SourceLocation{},
724                              SourceLocation{}, SourceLocation{}) {
725     std::uninitialized_value_construct(
726         getTrailingObjects<const OpenACCClause *>(),
727         getTrailingObjects<const OpenACCClause *>() + NumClauses);
728     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
729                                   NumClauses));
730   }
731 
732   OpenACCUpdateConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
733                          SourceLocation End,
734                          ArrayRef<const OpenACCClause *> Clauses)
735       : OpenACCConstructStmt(OpenACCUpdateConstructClass,
736                              OpenACCDirectiveKind::Update, Start, DirectiveLoc,
737                              End) {
738     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
739                             getTrailingObjects<const OpenACCClause *>());
740     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
741                                   Clauses.size()));
742   }
743 
744 public:
745   static bool classof(const Stmt *T) {
746     return T->getStmtClass() == OpenACCUpdateConstructClass;
747   }
748   static OpenACCUpdateConstruct *CreateEmpty(const ASTContext &C,
749                                              unsigned NumClauses);
750   static OpenACCUpdateConstruct *
751   Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
752          SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
753 };
754 } // namespace clang
755 #endif // LLVM_CLANG_AST_STMTOPENACC_H
756