//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file /// This file implements parsing of all OpenMP directives and clauses. /// //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaAMDGPU.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaOpenMP.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPContext.h" #include <optional> usingnamespaceclang; usingnamespacellvm::omp; //===----------------------------------------------------------------------===// // OpenMP declarative directives. //===----------------------------------------------------------------------===// namespace { enum OpenMPDirectiveKindEx { … }; // Helper to unify the enum class OpenMPDirectiveKind with its extension // the OpenMPDirectiveKindEx enum which allows to use them together as if they // are unsigned values. struct OpenMPDirectiveKindExWrapper { … }; class DeclDirectiveListParserHelper final { … }; } // namespace // Map token string to extended OMP token kind that are // OpenMPDirectiveKind + OpenMPDirectiveKindEx. static unsigned getOpenMPDirectiveKindEx(StringRef S) { … } static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) { … } static DeclarationName parseOpenMPReductionId(Parser &P) { … } /// Parse 'omp declare reduction' construct. /// /// declare-reduction-directive: /// annot_pragma_openmp 'declare' 'reduction' /// '(' <reduction_id> ':' <type> {',' <type>} ':' <expression> ')' /// ['initializer' '(' ('omp_priv' '=' <expression>)|<function_call> ')'] /// annot_pragma_openmp_end /// <reduction_id> is either a base language identifier or one of the following /// operators: '+', '-', '*', '&', '|', '^', '&&' and '||'. /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { … } void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { … } /// Parses 'omp declare mapper' directive. /// /// declare-mapper-directive: /// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifier> ':'] /// <type> <var> ')' [<clause>[[,] <clause>] ... ] /// annot_pragma_openmp_end /// <mapper-identifier> and <var> are base language identifiers. /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) { … } TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range, DeclarationName &Name, AccessSpecifier AS) { … } namespace { /// RAII that recreates function context for correct parsing of clauses of /// 'declare simd' construct. /// OpenMP, 2.8.2 declare simd Construct /// The expressions appearing in the clauses of this directive are evaluated in /// the scope of the arguments of the function declaration or definition. class FNContextRAII final { … }; } // namespace /// Parses clauses for 'declare simd' directive. /// clause: /// 'inbranch' | 'notinbranch' /// 'simdlen' '(' <expr> ')' /// { 'uniform' '(' <argument_list> ')' } /// { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' } /// { 'linear '(' <argument_list> [ ':' <step> ] ')' } static bool parseDeclareSimdClauses( Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen, SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds, SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears, SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) { … } /// Parse clauses for '#pragma omp declare simd'. Parser::DeclGroupPtrTy Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, CachedTokens &Toks, SourceLocation Loc) { … } namespace { /// Constant used in the diagnostics to distinguish the levels in an OpenMP /// contexts: selector-set={selector(trait, ...), ...}, .... enum OMPContextLvl { … }; static StringRef stringLiteralParser(Parser &P) { … } static StringRef getNameFromIdOrString(Parser &P, Token &Tok, OMPContextLvl Lvl) { … } static bool checkForDuplicates(Parser &P, StringRef Name, SourceLocation NameLoc, llvm::StringMap<SourceLocation> &Seen, OMPContextLvl Lvl) { … } } // namespace void Parser::parseOMPTraitPropertyKind(OMPTraitProperty &TIProperty, llvm::omp::TraitSet Set, llvm::omp::TraitSelector Selector, llvm::StringMap<SourceLocation> &Seen) { … } static bool checkExtensionProperty(Parser &P, SourceLocation Loc, OMPTraitProperty &TIProperty, OMPTraitSelector &TISelector, llvm::StringMap<SourceLocation> &Seen) { … } void Parser::parseOMPContextProperty(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap<SourceLocation> &Seen) { … } void Parser::parseOMPTraitSelectorKind(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap<SourceLocation> &Seen) { … } /// Parse optional 'score' '(' <expr> ')' ':'. static ExprResult parseContextScore(Parser &P) { … } /// Parses an OpenMP context selector. /// /// <trait-selector-name> ['('[<trait-score>] <trait-property> [, <t-p>]* ')'] void Parser::parseOMPContextSelector( OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap<SourceLocation> &SeenSelectors) { … } void Parser::parseOMPTraitSetKind(OMPTraitSet &TISet, llvm::StringMap<SourceLocation> &Seen) { … } /// Parses an OpenMP context selector set. /// /// <trait-set-selector-name> '=' '{' <trait-selector> [, <trait-selector>]* '}' void Parser::parseOMPContextSelectorSet( OMPTraitSet &TISet, llvm::StringMap<SourceLocation> &SeenSets) { … } /// Parse OpenMP context selectors: /// /// <trait-set-selector> [, <trait-set-selector>]* bool Parser::parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI) { … } /// Parse clauses for '#pragma omp declare variant ( variant-func-id ) clause'. void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, CachedTokens &Toks, SourceLocation Loc) { … } bool Parser::parseOpenMPAppendArgs( SmallVectorImpl<OMPInteropInfo> &InteropInfos) { … } bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI, OMPTraitInfo *ParentTI) { … } /// <clause> [clause[ [,] clause] ... ] /// /// clauses: for error directive /// 'at' '(' compilation | execution ')' /// 'severity' '(' fatal | warning ')' /// 'message' '(' msg-string ')' /// .... void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind, SmallVectorImpl<OMPClause *> &Clauses, SourceLocation Loc) { … } /// `omp assumes` or `omp begin/end assumes` <clause> [[,]<clause>]... /// where /// /// clause: /// 'ext_IMPL_DEFINED' /// 'absent' '(' directive-name [, directive-name]* ')' /// 'contains' '(' directive-name [, directive-name]* ')' /// 'holds' '(' scalar-expression ')' /// 'no_openmp' /// 'no_openmp_routines' /// 'no_parallelism' /// void Parser::ParseOpenMPAssumesDirective(OpenMPDirectiveKind DKind, SourceLocation Loc) { … } void Parser::ParseOpenMPEndAssumesDirective(SourceLocation Loc) { … } /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: /// 'default' '(' 'none' | 'shared' | 'private' | 'firstprivate' ') /// /// proc_bind-clause: /// 'proc_bind' '(' 'master' | 'close' | 'spread' ') /// /// device_type-clause: /// 'device_type' '(' 'host' | 'nohost' | 'any' )' namespace { struct SimpleClauseData { … }; } // anonymous namespace static std::optional<SimpleClauseData> parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) { … } void Parser::ParseOMPDeclareTargetClauses( SemaOpenMP::DeclareTargetContextInfo &DTCI) { … } void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) { … } void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind, OpenMPDirectiveKind ExpectedKind, OpenMPDirectiveKind FoundKind, SourceLocation BeginLoc, SourceLocation FoundLoc, bool SkipUntilOpenMPEnd) { … } void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind, OpenMPDirectiveKind EndDKind, SourceLocation DKLoc) { … } /// Parsing of declarative OpenMP directives. /// /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// /// allocate-directive: /// annot_pragma_openmp 'allocate' simple-variable-list [<clause>] /// annot_pragma_openmp_end /// /// declare-reduction-directive: /// annot_pragma_openmp 'declare' 'reduction' [...] /// annot_pragma_openmp_end /// /// declare-mapper-directive: /// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':'] /// <type> <var> ')' [<clause>[[,] <clause>] ... ] /// annot_pragma_openmp_end /// /// declare-simd-directive: /// annot_pragma_openmp 'declare simd' {<clause> [,]} /// annot_pragma_openmp_end /// <function declaration/definition> /// /// requires directive: /// annot_pragma_openmp 'requires' <clause> [[[,] <clause>] ... ] /// annot_pragma_openmp_end /// /// assumes directive: /// annot_pragma_openmp 'assumes' <clause> [[[,] <clause>] ... ] /// annot_pragma_openmp_end /// or /// annot_pragma_openmp 'begin assumes' <clause> [[[,] <clause>] ... ] /// annot_pragma_openmp 'end assumes' /// annot_pragma_openmp_end /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( AccessSpecifier &AS, ParsedAttributes &Attrs, bool Delayed, DeclSpec::TST TagType, Decl *Tag) { … } StmtResult Parser::ParseOpenMPExecutableDirective( ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc, bool ReadDirectiveWithinMetadirective) { … } StmtResult Parser::ParseOpenMPInformationalDirective( ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc, bool ReadDirectiveWithinMetadirective) { … } /// Parsing of declarative or executable OpenMP directives. /// /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// /// allocate-directive: /// annot_pragma_openmp 'allocate' simple-variable-list /// annot_pragma_openmp_end /// /// declare-reduction-directive: /// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':' /// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' /// ('omp_priv' '=' <expression>|<function_call>) ')'] /// annot_pragma_openmp_end /// /// declare-mapper-directive: /// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':'] /// <type> <var> ')' [<clause>[[,] <clause>] ... ] /// annot_pragma_openmp_end /// /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | /// 'parallel for' | 'parallel sections' | 'parallel master' | 'task' | /// 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'error' /// | 'atomic' | 'for simd' | 'parallel for simd' | 'target' | 'target /// data' | 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | /// 'master taskloop' | 'master taskloop simd' | 'parallel master /// taskloop' | 'parallel master taskloop simd' | 'distribute' | 'target /// enter data' | 'target exit data' | 'target parallel' | 'target /// parallel for' | 'target update' | 'distribute parallel for' | /// 'distribute paralle for simd' | 'distribute simd' | 'target parallel /// for simd' | 'target simd' | 'teams distribute' | 'teams distribute /// simd' | 'teams distribute parallel for simd' | 'teams distribute /// parallel for' | 'target teams' | 'target teams distribute' | 'target /// teams distribute parallel for' | 'target teams distribute parallel /// for simd' | 'target teams distribute simd' | 'masked' | /// 'parallel masked' {clause} annot_pragma_openmp_end /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective) { … } // Parses simple list: // simple-variable-list: // '(' id-expression {, id-expression} ')' // bool Parser::ParseOpenMPSimpleVarList( OpenMPDirectiveKind Kind, const llvm::function_ref<void(CXXScopeSpec &, DeclarationNameInfo)> &Callback, bool AllowScopeSpecifier) { … } OMPClause *Parser::ParseOpenMPSizesClause() { … } OMPClause *Parser::ParseOpenMPPermutationClause() { … } OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { … } /// Parsing of OpenMP clauses. /// /// clause: /// if-clause | final-clause | num_threads-clause | safelen-clause | /// default-clause | private-clause | firstprivate-clause | shared-clause /// | linear-clause | aligned-clause | collapse-clause | bind-clause | /// lastprivate-clause | reduction-clause | proc_bind-clause | /// schedule-clause | copyin-clause | copyprivate-clause | untied-clause | /// mergeable-clause | flush-clause | read-clause | write-clause | /// update-clause | capture-clause | seq_cst-clause | device-clause | /// simdlen-clause | threads-clause | simd-clause | num_teams-clause | /// thread_limit-clause | priority-clause | grainsize-clause | /// nogroup-clause | num_tasks-clause | hint-clause | to-clause | /// from-clause | is_device_ptr-clause | task_reduction-clause | /// in_reduction-clause | allocator-clause | allocate-clause | /// acq_rel-clause | acquire-clause | release-clause | relaxed-clause | /// depobj-clause | destroy-clause | detach-clause | inclusive-clause | /// exclusive-clause | uses_allocators-clause | use_device_addr-clause | /// has_device_addr /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { … } /// Parses simple expression in parens for single-expression clauses of OpenMP /// constructs. /// \param RLoc Returned location of right paren. ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc, bool IsAddressOfOperand) { … } /// Parsing of OpenMP clauses with single expressions like 'final', /// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams', /// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks', 'hint' or /// 'detach'. /// /// final-clause: /// 'final' '(' expression ')' /// /// num_threads-clause: /// 'num_threads' '(' expression ')' /// /// safelen-clause: /// 'safelen' '(' expression ')' /// /// simdlen-clause: /// 'simdlen' '(' expression ')' /// /// collapse-clause: /// 'collapse' '(' expression ')' /// /// priority-clause: /// 'priority' '(' expression ')' /// /// grainsize-clause: /// 'grainsize' '(' expression ')' /// /// num_tasks-clause: /// 'num_tasks' '(' expression ')' /// /// hint-clause: /// 'hint' '(' expression ')' /// /// allocator-clause: /// 'allocator' '(' expression ')' /// /// detach-clause: /// 'detach' '(' event-handler-expression ')' /// /// align-clause /// 'align' '(' positive-integer-constant ')' /// /// holds-clause /// 'holds' '(' expression ')' /// OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, bool ParseOnly) { … } /// Parse indirect clause for '#pragma omp declare target' directive. /// 'indirect' '[' '(' invoked-by-fptr ')' ']' /// where invoked-by-fptr is a constant boolean expression that evaluates to /// true or false at compile time. bool Parser::ParseOpenMPIndirectClause( SemaOpenMP::DeclareTargetContextInfo &DTCI, bool ParseOnly) { … } /// Parses a comma-separated list of interop-types and a prefer_type list. /// bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo, OpenMPClauseKind Kind) { … } /// Parsing of OpenMP clauses that use an interop-var. /// /// init-clause: /// init([interop-modifier, ]interop-type[[, interop-type] ... ]:interop-var) /// /// destroy-clause: /// destroy(interop-var) /// /// use-clause: /// use(interop-var) /// /// interop-modifier: /// prefer_type(preference-list) /// /// preference-list: /// foreign-runtime-id [, foreign-runtime-id]... /// /// foreign-runtime-id: /// <string-literal> | <constant-integral-expression> /// /// interop-type: /// target | targetsync /// OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind, bool ParseOnly) { … } OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) { … } /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: /// 'default' '(' 'none' | 'shared' | 'private' | 'firstprivate' ')' /// /// proc_bind-clause: /// 'proc_bind' '(' 'master' | 'close' | 'spread' ')' /// /// bind-clause: /// 'bind' '(' 'teams' | 'parallel' | 'thread' ')' /// /// update-clause: /// 'update' '(' 'in' | 'out' | 'inout' | 'mutexinoutset' | /// 'inoutset' ')' /// OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind, bool ParseOnly) { … } /// Parsing of OpenMP clauses like 'ordered'. /// /// ordered-clause: /// 'ordered' /// /// nowait-clause: /// 'nowait' /// /// untied-clause: /// 'untied' /// /// mergeable-clause: /// 'mergeable' /// /// read-clause: /// 'read' /// /// threads-clause: /// 'threads' /// /// simd-clause: /// 'simd' /// /// nogroup-clause: /// 'nogroup' /// OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind, bool ParseOnly) { … } /// Parsing of OpenMP clauses with single expressions and some additional /// argument like 'schedule' or 'dist_schedule'. /// /// schedule-clause: /// 'schedule' '(' [ modifier [ ',' modifier ] ':' ] kind [',' expression ] /// ')' /// /// if-clause: /// 'if' '(' [ directive-name-modifier ':' ] expression ')' /// /// defaultmap: /// 'defaultmap' '(' modifier [ ':' kind ] ')' /// /// device-clause: /// 'device' '(' [ device-modifier ':' ] expression ')' /// OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, bool ParseOnly) { … } static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, UnqualifiedId &ReductionId) { … } /// Checks if the token is a valid map-type-modifier. /// FIXME: It will return an OpenMPMapClauseKind if that's what it parses. static OpenMPMapModifierKind isMapModifier(Parser &P) { … } /// Parse the mapper modifier in map, to, and from clauses. bool Parser::parseMapperModifier(SemaOpenMP::OpenMPVarListDataTy &Data) { … } static OpenMPMapClauseKind isMapType(Parser &P); /// Parse map-type-modifiers in map clause. /// map([ [map-type-modifier[,] [map-type-modifier[,] ...] [map-type] : ] list) /// where, map-type-modifier ::= always | close | mapper(mapper-identifier) | /// present /// where, map-type ::= alloc | delete | from | release | to | tofrom bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) { … } /// Checks if the token is a valid map-type. /// If it is not MapType kind, OMPC_MAP_unknown is returned. static OpenMPMapClauseKind isMapType(Parser &P) { … } /// Parse map-type in map clause. /// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list) /// where, map-type ::= to | from | tofrom | alloc | release | delete static void parseMapType(Parser &P, SemaOpenMP::OpenMPVarListDataTy &Data) { … } /// Parses simple expression in parens for single-expression clauses of OpenMP /// constructs. ExprResult Parser::ParseOpenMPIteratorsExpr() { … } bool Parser::ParseOpenMPReservedLocator(OpenMPClauseKind Kind, SemaOpenMP::OpenMPVarListDataTy &Data, const LangOptions &LangOpts) { … } /// Parse step size expression. Returns true if parsing is successfull, /// otherwise returns false. static bool parseStepSize(Parser &P, SemaOpenMP::OpenMPVarListDataTy &Data, OpenMPClauseKind CKind, SourceLocation ELoc) { … } /// Parses clauses with list. bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, SmallVectorImpl<Expr *> &Vars, SemaOpenMP::OpenMPVarListDataTy &Data) { … } /// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', /// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction', /// 'in_reduction', 'nontemporal', 'exclusive' or 'inclusive'. /// /// private-clause: /// 'private' '(' list ')' /// firstprivate-clause: /// 'firstprivate' '(' list ')' /// lastprivate-clause: /// 'lastprivate' '(' list ')' /// shared-clause: /// 'shared' '(' list ')' /// linear-clause: /// 'linear' '(' linear-list [ ':' linear-step ] ')' /// aligned-clause: /// 'aligned' '(' list [ ':' alignment ] ')' /// reduction-clause: /// 'reduction' '(' [ modifier ',' ] reduction-identifier ':' list ')' /// task_reduction-clause: /// 'task_reduction' '(' reduction-identifier ':' list ')' /// in_reduction-clause: /// 'in_reduction' '(' reduction-identifier ':' list ')' /// copyprivate-clause: /// 'copyprivate' '(' list ')' /// flush-clause: /// 'flush' '(' list ')' /// depend-clause: /// 'depend' '(' in | out | inout : list | source ')' /// map-clause: /// 'map' '(' [ [ always [,] ] [ close [,] ] /// [ mapper '(' mapper-identifier ')' [,] ] /// to | from | tofrom | alloc | release | delete ':' ] list ')'; /// to-clause: /// 'to' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')' /// from-clause: /// 'from' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')' /// use_device_ptr-clause: /// 'use_device_ptr' '(' list ')' /// use_device_addr-clause: /// 'use_device_addr' '(' list ')' /// is_device_ptr-clause: /// 'is_device_ptr' '(' list ')' /// has_device_addr-clause: /// 'has_device_addr' '(' list ')' /// allocate-clause: /// 'allocate' '(' [ allocator ':' ] list ')' /// nontemporal-clause: /// 'nontemporal' '(' list ')' /// inclusive-clause: /// 'inclusive' '(' list ')' /// exclusive-clause: /// 'exclusive' '(' list ')' /// /// For 'linear' clause linear-list may have the following forms: /// list /// modifier(list) /// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++). OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, bool ParseOnly) { … } bool Parser::ParseOpenMPExprListClause(OpenMPClauseKind Kind, SourceLocation &ClauseNameLoc, SourceLocation &OpenLoc, SourceLocation &CloseLoc, SmallVectorImpl<Expr *> &Exprs, bool ReqIntConst) { … }