1 //===- DeclOpenMP.h - Classes for representing OpenMP 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 ///
9 /// \file
10 /// This file defines OpenMP nodes for declarative directives.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_AST_DECLOPENMP_H
15 #define LLVM_CLANG_AST_DECLOPENMP_H
16 
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/Expr.h"
19 #include "clang/AST/ExternalASTSource.h"
20 #include "clang/AST/OpenMPClause.h"
21 #include "clang/AST/Type.h"
22 #include "llvm/ADT/ArrayRef.h"
23 #include "llvm/Support/TrailingObjects.h"
24 
25 namespace clang {
26 
27 /// This represents '#pragma omp threadprivate ...' directive.
28 /// For example, in the following, both 'a' and 'A::b' are threadprivate:
29 ///
30 /// \code
31 /// int a;
32 /// #pragma omp threadprivate(a)
33 /// struct A {
34 ///   static int b;
35 /// #pragma omp threadprivate(b)
36 /// };
37 /// \endcode
38 ///
39 class OMPThreadPrivateDecl final
40     : public Decl,
41       private llvm::TrailingObjects<OMPThreadPrivateDecl, Expr *> {
42   friend class ASTDeclReader;
43   friend TrailingObjects;
44 
45   unsigned NumVars;
46 
47   virtual void anchor();
48 
OMPThreadPrivateDecl(Kind DK,DeclContext * DC,SourceLocation L)49   OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) :
50     Decl(DK, DC, L), NumVars(0) { }
51 
getVars()52   ArrayRef<const Expr *> getVars() const {
53     return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumVars);
54   }
55 
getVars()56   MutableArrayRef<Expr *> getVars() {
57     return MutableArrayRef<Expr *>(getTrailingObjects<Expr *>(), NumVars);
58   }
59 
60   void setVars(ArrayRef<Expr *> VL);
61 
62 public:
63   static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
64                                       SourceLocation L,
65                                       ArrayRef<Expr *> VL);
66   static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
67                                                   unsigned ID, unsigned N);
68 
69   typedef MutableArrayRef<Expr *>::iterator varlist_iterator;
70   typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
71   typedef llvm::iterator_range<varlist_iterator> varlist_range;
72   typedef llvm::iterator_range<varlist_const_iterator> varlist_const_range;
73 
varlist_size()74   unsigned varlist_size() const { return NumVars; }
varlist_empty()75   bool varlist_empty() const { return NumVars == 0; }
76 
varlists()77   varlist_range varlists() {
78     return varlist_range(varlist_begin(), varlist_end());
79   }
varlists()80   varlist_const_range varlists() const {
81     return varlist_const_range(varlist_begin(), varlist_end());
82   }
varlist_begin()83   varlist_iterator varlist_begin() { return getVars().begin(); }
varlist_end()84   varlist_iterator varlist_end() { return getVars().end(); }
varlist_begin()85   varlist_const_iterator varlist_begin() const { return getVars().begin(); }
varlist_end()86   varlist_const_iterator varlist_end() const { return getVars().end(); }
87 
classof(const Decl * D)88   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
classofKind(Kind K)89   static bool classofKind(Kind K) { return K == OMPThreadPrivate; }
90 };
91 
92 /// This represents '#pragma omp declare reduction ...' directive.
93 /// For example, in the following, declared reduction 'foo' for types 'int' and
94 /// 'float':
95 ///
96 /// \code
97 /// #pragma omp declare reduction (foo : int,float : omp_out += omp_in) \
98 ///                     initializer (omp_priv = 0)
99 /// \endcode
100 ///
101 /// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer.
102 class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext {
103   // This class stores some data in DeclContext::OMPDeclareReductionDeclBits
104   // to save some space. Use the provided accessors to access it.
105 public:
106   enum InitKind {
107     CallInit,   // Initialized by function call.
108     DirectInit, // omp_priv(<expr>)
109     CopyInit    // omp_priv = <expr>
110   };
111 
112 private:
113   friend class ASTDeclReader;
114   /// Combiner for declare reduction construct.
115   Expr *Combiner = nullptr;
116   /// Initializer for declare reduction construct.
117   Expr *Initializer = nullptr;
118   /// In parameter of the combiner.
119   Expr *In = nullptr;
120   /// Out parameter of the combiner.
121   Expr *Out = nullptr;
122   /// Priv parameter of the initializer.
123   Expr *Priv = nullptr;
124   /// Orig parameter of the initializer.
125   Expr *Orig = nullptr;
126 
127   /// Reference to the previous declare reduction construct in the same
128   /// scope with the same name. Required for proper templates instantiation if
129   /// the declare reduction construct is declared inside compound statement.
130   LazyDeclPtr PrevDeclInScope;
131 
132   virtual void anchor();
133 
134   OMPDeclareReductionDecl(Kind DK, DeclContext *DC, SourceLocation L,
135                           DeclarationName Name, QualType Ty,
136                           OMPDeclareReductionDecl *PrevDeclInScope);
137 
setPrevDeclInScope(OMPDeclareReductionDecl * Prev)138   void setPrevDeclInScope(OMPDeclareReductionDecl *Prev) {
139     PrevDeclInScope = Prev;
140   }
141 
142 public:
143   /// Create declare reduction node.
144   static OMPDeclareReductionDecl *
145   Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name,
146          QualType T, OMPDeclareReductionDecl *PrevDeclInScope);
147   /// Create deserialized declare reduction node.
148   static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C,
149                                                      unsigned ID);
150 
151   /// Get combiner expression of the declare reduction construct.
getCombiner()152   Expr *getCombiner() { return Combiner; }
getCombiner()153   const Expr *getCombiner() const { return Combiner; }
154   /// Get In variable of the combiner.
getCombinerIn()155   Expr *getCombinerIn() { return In; }
getCombinerIn()156   const Expr *getCombinerIn() const { return In; }
157   /// Get Out variable of the combiner.
getCombinerOut()158   Expr *getCombinerOut() { return Out; }
getCombinerOut()159   const Expr *getCombinerOut() const { return Out; }
160   /// Set combiner expression for the declare reduction construct.
setCombiner(Expr * E)161   void setCombiner(Expr *E) { Combiner = E; }
162   /// Set combiner In and Out vars.
setCombinerData(Expr * InE,Expr * OutE)163   void setCombinerData(Expr *InE, Expr *OutE) {
164     In = InE;
165     Out = OutE;
166   }
167 
168   /// Get initializer expression (if specified) of the declare reduction
169   /// construct.
getInitializer()170   Expr *getInitializer() { return Initializer; }
getInitializer()171   const Expr *getInitializer() const { return Initializer; }
172   /// Get initializer kind.
getInitializerKind()173   InitKind getInitializerKind() const {
174     return static_cast<InitKind>(OMPDeclareReductionDeclBits.InitializerKind);
175   }
176   /// Get Orig variable of the initializer.
getInitOrig()177   Expr *getInitOrig() { return Orig; }
getInitOrig()178   const Expr *getInitOrig() const { return Orig; }
179   /// Get Priv variable of the initializer.
getInitPriv()180   Expr *getInitPriv() { return Priv; }
getInitPriv()181   const Expr *getInitPriv() const { return Priv; }
182   /// Set initializer expression for the declare reduction construct.
setInitializer(Expr * E,InitKind IK)183   void setInitializer(Expr *E, InitKind IK) {
184     Initializer = E;
185     OMPDeclareReductionDeclBits.InitializerKind = IK;
186   }
187   /// Set initializer Orig and Priv vars.
setInitializerData(Expr * OrigE,Expr * PrivE)188   void setInitializerData(Expr *OrigE, Expr *PrivE) {
189     Orig = OrigE;
190     Priv = PrivE;
191   }
192 
193   /// Get reference to previous declare reduction construct in the same
194   /// scope with the same name.
195   OMPDeclareReductionDecl *getPrevDeclInScope();
196   const OMPDeclareReductionDecl *getPrevDeclInScope() const;
197 
classof(const Decl * D)198   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
classofKind(Kind K)199   static bool classofKind(Kind K) { return K == OMPDeclareReduction; }
castToDeclContext(const OMPDeclareReductionDecl * D)200   static DeclContext *castToDeclContext(const OMPDeclareReductionDecl *D) {
201     return static_cast<DeclContext *>(const_cast<OMPDeclareReductionDecl *>(D));
202   }
castFromDeclContext(const DeclContext * DC)203   static OMPDeclareReductionDecl *castFromDeclContext(const DeclContext *DC) {
204     return static_cast<OMPDeclareReductionDecl *>(
205         const_cast<DeclContext *>(DC));
206   }
207 };
208 
209 /// This represents '#pragma omp declare mapper ...' directive. Map clauses are
210 /// allowed to use with this directive. The following example declares a user
211 /// defined mapper for the type 'struct vec'. This example instructs the fields
212 /// 'len' and 'data' should be mapped when mapping instances of 'struct vec'.
213 ///
214 /// \code
215 /// #pragma omp declare mapper(mid: struct vec v) map(v.len, v.data[0:N])
216 /// \endcode
217 class OMPDeclareMapperDecl final : public ValueDecl, public DeclContext {
218   friend class ASTDeclReader;
219 
220   /// Clauses associated with this mapper declaration
221   MutableArrayRef<OMPClause *> Clauses;
222 
223   /// Mapper variable, which is 'v' in the example above
224   Expr *MapperVarRef = nullptr;
225 
226   /// Name of the mapper variable
227   DeclarationName VarName;
228 
229   LazyDeclPtr PrevDeclInScope;
230 
231   virtual void anchor();
232 
OMPDeclareMapperDecl(Kind DK,DeclContext * DC,SourceLocation L,DeclarationName Name,QualType Ty,DeclarationName VarName,OMPDeclareMapperDecl * PrevDeclInScope)233   OMPDeclareMapperDecl(Kind DK, DeclContext *DC, SourceLocation L,
234                        DeclarationName Name, QualType Ty,
235                        DeclarationName VarName,
236                        OMPDeclareMapperDecl *PrevDeclInScope)
237       : ValueDecl(DK, DC, L, Name, Ty), DeclContext(DK), VarName(VarName),
238         PrevDeclInScope(PrevDeclInScope) {}
239 
setPrevDeclInScope(OMPDeclareMapperDecl * Prev)240   void setPrevDeclInScope(OMPDeclareMapperDecl *Prev) {
241     PrevDeclInScope = Prev;
242   }
243 
244   /// Sets an array of clauses to this mapper declaration
245   void setClauses(ArrayRef<OMPClause *> CL);
246 
247 public:
248   /// Creates declare mapper node.
249   static OMPDeclareMapperDecl *Create(ASTContext &C, DeclContext *DC,
250                                       SourceLocation L, DeclarationName Name,
251                                       QualType T, DeclarationName VarName,
252                                       OMPDeclareMapperDecl *PrevDeclInScope);
253   /// Creates deserialized declare mapper node.
254   static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, unsigned ID,
255                                                   unsigned N);
256 
257   /// Creates an array of clauses to this mapper declaration and intializes
258   /// them.
259   void CreateClauses(ASTContext &C, ArrayRef<OMPClause *> CL);
260 
261   using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator;
262   using clauselist_const_iterator = ArrayRef<const OMPClause *>::iterator;
263   using clauselist_range = llvm::iterator_range<clauselist_iterator>;
264   using clauselist_const_range =
265       llvm::iterator_range<clauselist_const_iterator>;
266 
clauselist_size()267   unsigned clauselist_size() const { return Clauses.size(); }
clauselist_empty()268   bool clauselist_empty() const { return Clauses.empty(); }
269 
clauselists()270   clauselist_range clauselists() {
271     return clauselist_range(clauselist_begin(), clauselist_end());
272   }
clauselists()273   clauselist_const_range clauselists() const {
274     return clauselist_const_range(clauselist_begin(), clauselist_end());
275   }
clauselist_begin()276   clauselist_iterator clauselist_begin() { return Clauses.begin(); }
clauselist_end()277   clauselist_iterator clauselist_end() { return Clauses.end(); }
clauselist_begin()278   clauselist_const_iterator clauselist_begin() const { return Clauses.begin(); }
clauselist_end()279   clauselist_const_iterator clauselist_end() const { return Clauses.end(); }
280 
281   /// Get the variable declared in the mapper
getMapperVarRef()282   Expr *getMapperVarRef() { return MapperVarRef; }
getMapperVarRef()283   const Expr *getMapperVarRef() const { return MapperVarRef; }
284   /// Set the variable declared in the mapper
setMapperVarRef(Expr * MapperVarRefE)285   void setMapperVarRef(Expr *MapperVarRefE) { MapperVarRef = MapperVarRefE; }
286 
287   /// Get the name of the variable declared in the mapper
getVarName()288   DeclarationName getVarName() { return VarName; }
289 
290   /// Get reference to previous declare mapper construct in the same
291   /// scope with the same name.
292   OMPDeclareMapperDecl *getPrevDeclInScope();
293   const OMPDeclareMapperDecl *getPrevDeclInScope() const;
294 
classof(const Decl * D)295   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
classofKind(Kind K)296   static bool classofKind(Kind K) { return K == OMPDeclareMapper; }
castToDeclContext(const OMPDeclareMapperDecl * D)297   static DeclContext *castToDeclContext(const OMPDeclareMapperDecl *D) {
298     return static_cast<DeclContext *>(const_cast<OMPDeclareMapperDecl *>(D));
299   }
castFromDeclContext(const DeclContext * DC)300   static OMPDeclareMapperDecl *castFromDeclContext(const DeclContext *DC) {
301     return static_cast<OMPDeclareMapperDecl *>(const_cast<DeclContext *>(DC));
302   }
303 };
304 
305 /// Pseudo declaration for capturing expressions. Also is used for capturing of
306 /// non-static data members in non-static member functions.
307 ///
308 /// Clang supports capturing of variables only, but OpenMP 4.5 allows to
309 /// privatize non-static members of current class in non-static member
310 /// functions. This pseudo-declaration allows properly handle this kind of
311 /// capture by wrapping captured expression into a variable-like declaration.
312 class OMPCapturedExprDecl final : public VarDecl {
313   friend class ASTDeclReader;
314   void anchor() override;
315 
OMPCapturedExprDecl(ASTContext & C,DeclContext * DC,IdentifierInfo * Id,QualType Type,TypeSourceInfo * TInfo,SourceLocation StartLoc)316   OMPCapturedExprDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id,
317                       QualType Type, TypeSourceInfo *TInfo,
318                       SourceLocation StartLoc)
319       : VarDecl(OMPCapturedExpr, C, DC, StartLoc, StartLoc, Id, Type, TInfo,
320                 SC_None) {
321     setImplicit();
322   }
323 
324 public:
325   static OMPCapturedExprDecl *Create(ASTContext &C, DeclContext *DC,
326                                      IdentifierInfo *Id, QualType T,
327                                      SourceLocation StartLoc);
328 
329   static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C, unsigned ID);
330 
331   SourceRange getSourceRange() const override LLVM_READONLY;
332 
333   // Implement isa/cast/dyncast/etc.
classof(const Decl * D)334   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
classofKind(Kind K)335   static bool classofKind(Kind K) { return K == OMPCapturedExpr; }
336 };
337 
338 /// This represents '#pragma omp requires...' directive.
339 /// For example
340 ///
341 /// \code
342 /// #pragma omp requires unified_address
343 /// \endcode
344 ///
345 class OMPRequiresDecl final
346     : public Decl,
347       private llvm::TrailingObjects<OMPRequiresDecl, OMPClause *> {
348   friend class ASTDeclReader;
349   friend TrailingObjects;
350 
351   // Number of clauses associated with this requires declaration
352   unsigned NumClauses = 0;
353 
354   virtual void anchor();
355 
OMPRequiresDecl(Kind DK,DeclContext * DC,SourceLocation L)356   OMPRequiresDecl(Kind DK, DeclContext *DC, SourceLocation L)
357       : Decl(DK, DC, L), NumClauses(0) {}
358 
359   /// Returns an array of immutable clauses associated with this requires
360   /// declaration
getClauses()361   ArrayRef<const OMPClause *> getClauses() const {
362     return llvm::makeArrayRef(getTrailingObjects<OMPClause *>(), NumClauses);
363   }
364 
365   /// Returns an array of clauses associated with this requires declaration
getClauses()366   MutableArrayRef<OMPClause *> getClauses() {
367     return MutableArrayRef<OMPClause *>(getTrailingObjects<OMPClause *>(),
368                                         NumClauses);
369   }
370 
371   /// Sets an array of clauses to this requires declaration
372   void setClauses(ArrayRef<OMPClause *> CL);
373 
374 public:
375   /// Create requires node.
376   static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC,
377                                  SourceLocation L, ArrayRef<OMPClause *> CL);
378   /// Create deserialized requires node.
379   static OMPRequiresDecl *CreateDeserialized(ASTContext &C, unsigned ID,
380                                              unsigned N);
381 
382   using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator;
383   using clauselist_const_iterator = ArrayRef<const OMPClause *>::iterator;
384   using clauselist_range = llvm::iterator_range<clauselist_iterator>;
385   using clauselist_const_range = llvm::iterator_range<clauselist_const_iterator>;
386 
clauselist_size()387   unsigned clauselist_size() const { return NumClauses; }
clauselist_empty()388   bool clauselist_empty() const { return NumClauses == 0; }
389 
clauselists()390   clauselist_range clauselists() {
391     return clauselist_range(clauselist_begin(), clauselist_end());
392   }
clauselists()393   clauselist_const_range clauselists() const {
394     return clauselist_const_range(clauselist_begin(), clauselist_end());
395   }
clauselist_begin()396   clauselist_iterator clauselist_begin() { return getClauses().begin(); }
clauselist_end()397   clauselist_iterator clauselist_end() { return getClauses().end(); }
clauselist_begin()398   clauselist_const_iterator clauselist_begin() const {
399     return getClauses().begin();
400   }
clauselist_end()401   clauselist_const_iterator clauselist_end() const {
402     return getClauses().end();
403   }
404 
classof(const Decl * D)405   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
classofKind(Kind K)406   static bool classofKind(Kind K) { return K == OMPRequires; }
407 };
408 
409 /// This represents '#pragma omp allocate ...' directive.
410 /// For example, in the following, the default allocator is used for both 'a'
411 /// and 'A::b':
412 ///
413 /// \code
414 /// int a;
415 /// #pragma omp allocate(a)
416 /// struct A {
417 ///   static int b;
418 /// #pragma omp allocate(b)
419 /// };
420 /// \endcode
421 ///
422 class OMPAllocateDecl final
423     : public Decl,
424       private llvm::TrailingObjects<OMPAllocateDecl, Expr *, OMPClause *> {
425   friend class ASTDeclReader;
426   friend TrailingObjects;
427 
428   /// Number of variable within the allocate directive.
429   unsigned NumVars = 0;
430   /// Number of clauses associated with the allocate directive.
431   unsigned NumClauses = 0;
432 
numTrailingObjects(OverloadToken<Expr * >)433   size_t numTrailingObjects(OverloadToken<Expr *>) const {
434     return NumVars;
435   }
numTrailingObjects(OverloadToken<OMPClause * >)436   size_t numTrailingObjects(OverloadToken<OMPClause *>) const {
437     return NumClauses;
438   }
439 
440   virtual void anchor();
441 
OMPAllocateDecl(Kind DK,DeclContext * DC,SourceLocation L)442   OMPAllocateDecl(Kind DK, DeclContext *DC, SourceLocation L)
443       : Decl(DK, DC, L) {}
444 
getVars()445   ArrayRef<const Expr *> getVars() const {
446     return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumVars);
447   }
448 
getVars()449   MutableArrayRef<Expr *> getVars() {
450     return MutableArrayRef<Expr *>(getTrailingObjects<Expr *>(), NumVars);
451   }
452 
453   void setVars(ArrayRef<Expr *> VL);
454 
455   /// Returns an array of immutable clauses associated with this directive.
getClauses()456   ArrayRef<OMPClause *> getClauses() const {
457     return llvm::makeArrayRef(getTrailingObjects<OMPClause *>(), NumClauses);
458   }
459 
460   /// Returns an array of clauses associated with this directive.
getClauses()461   MutableArrayRef<OMPClause *> getClauses() {
462     return MutableArrayRef<OMPClause *>(getTrailingObjects<OMPClause *>(),
463                                         NumClauses);
464   }
465 
466   /// Sets an array of clauses to this requires declaration
467   void setClauses(ArrayRef<OMPClause *> CL);
468 
469 public:
470   static OMPAllocateDecl *Create(ASTContext &C, DeclContext *DC,
471                                  SourceLocation L, ArrayRef<Expr *> VL,
472                                  ArrayRef<OMPClause *> CL);
473   static OMPAllocateDecl *CreateDeserialized(ASTContext &C, unsigned ID,
474                                              unsigned NVars, unsigned NClauses);
475 
476   typedef MutableArrayRef<Expr *>::iterator varlist_iterator;
477   typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
478   typedef llvm::iterator_range<varlist_iterator> varlist_range;
479   typedef llvm::iterator_range<varlist_const_iterator> varlist_const_range;
480   using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator;
481   using clauselist_const_iterator = ArrayRef<const OMPClause *>::iterator;
482   using clauselist_range = llvm::iterator_range<clauselist_iterator>;
483   using clauselist_const_range = llvm::iterator_range<clauselist_const_iterator>;
484 
485 
varlist_size()486   unsigned varlist_size() const { return NumVars; }
varlist_empty()487   bool varlist_empty() const { return NumVars == 0; }
clauselist_size()488   unsigned clauselist_size() const { return NumClauses; }
clauselist_empty()489   bool clauselist_empty() const { return NumClauses == 0; }
490 
varlists()491   varlist_range varlists() {
492     return varlist_range(varlist_begin(), varlist_end());
493   }
varlists()494   varlist_const_range varlists() const {
495     return varlist_const_range(varlist_begin(), varlist_end());
496   }
varlist_begin()497   varlist_iterator varlist_begin() { return getVars().begin(); }
varlist_end()498   varlist_iterator varlist_end() { return getVars().end(); }
varlist_begin()499   varlist_const_iterator varlist_begin() const { return getVars().begin(); }
varlist_end()500   varlist_const_iterator varlist_end() const { return getVars().end(); }
501 
clauselists()502   clauselist_range clauselists() {
503     return clauselist_range(clauselist_begin(), clauselist_end());
504   }
clauselists()505   clauselist_const_range clauselists() const {
506     return clauselist_const_range(clauselist_begin(), clauselist_end());
507   }
clauselist_begin()508   clauselist_iterator clauselist_begin() { return getClauses().begin(); }
clauselist_end()509   clauselist_iterator clauselist_end() { return getClauses().end(); }
clauselist_begin()510   clauselist_const_iterator clauselist_begin() const {
511     return getClauses().begin();
512   }
clauselist_end()513   clauselist_const_iterator clauselist_end() const {
514     return getClauses().end();
515   }
516 
classof(const Decl * D)517   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
classofKind(Kind K)518   static bool classofKind(Kind K) { return K == OMPAllocate; }
519 };
520 
521 } // end namespace clang
522 
523 #endif
524