• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \file
10 /// \brief This file implements parsing of all OpenMP directives and clauses.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "RAIIObjectsForParser.h"
15 #include "clang/AST/ASTConsumer.h"
16 #include "clang/AST/ASTContext.h"
17 #include "clang/AST/StmtOpenMP.h"
18 #include "clang/Parse/ParseDiagnostic.h"
19 #include "clang/Parse/Parser.h"
20 #include "clang/Sema/Scope.h"
21 #include "llvm/ADT/PointerIntPair.h"
22 using namespace clang;
23 
24 //===----------------------------------------------------------------------===//
25 // OpenMP declarative directives.
26 //===----------------------------------------------------------------------===//
27 
ParseOpenMPDirectiveKind(Parser & P)28 static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
29   auto Tok = P.getCurToken();
30   auto DKind =
31       Tok.isAnnotation()
32           ? OMPD_unknown
33           : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
34   if (DKind == OMPD_parallel) {
35     Tok = P.getPreprocessor().LookAhead(0);
36     auto SDKind =
37         Tok.isAnnotation()
38             ? OMPD_unknown
39             : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
40     if (SDKind == OMPD_for) {
41       P.ConsumeToken();
42       DKind = OMPD_parallel_for;
43     } else if (SDKind == OMPD_sections) {
44       P.ConsumeToken();
45       DKind = OMPD_parallel_sections;
46     }
47   }
48   return DKind;
49 }
50 
51 /// \brief Parsing of declarative OpenMP directives.
52 ///
53 ///       threadprivate-directive:
54 ///         annot_pragma_openmp 'threadprivate' simple-variable-list
55 ///
ParseOpenMPDeclarativeDirective()56 Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
57   assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
58   ParenBraceBracketBalancer BalancerRAIIObj(*this);
59 
60   SourceLocation Loc = ConsumeToken();
61   SmallVector<Expr *, 5> Identifiers;
62   auto DKind = ParseOpenMPDirectiveKind(*this);
63 
64   switch (DKind) {
65   case OMPD_threadprivate:
66     ConsumeToken();
67     if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
68       // The last seen token is annot_pragma_openmp_end - need to check for
69       // extra tokens.
70       if (Tok.isNot(tok::annot_pragma_openmp_end)) {
71         Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
72             << getOpenMPDirectiveName(OMPD_threadprivate);
73         SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
74       }
75       // Skip the last annot_pragma_openmp_end.
76       ConsumeToken();
77       return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
78     }
79     break;
80   case OMPD_unknown:
81     Diag(Tok, diag::err_omp_unknown_directive);
82     break;
83   case OMPD_parallel:
84   case OMPD_simd:
85   case OMPD_task:
86   case OMPD_for:
87   case OMPD_sections:
88   case OMPD_section:
89   case OMPD_single:
90   case OMPD_parallel_for:
91   case OMPD_parallel_sections:
92     Diag(Tok, diag::err_omp_unexpected_directive)
93         << getOpenMPDirectiveName(DKind);
94     break;
95   }
96   SkipUntil(tok::annot_pragma_openmp_end);
97   return DeclGroupPtrTy();
98 }
99 
100 /// \brief Parsing of declarative or executable OpenMP directives.
101 ///
102 ///       threadprivate-directive:
103 ///         annot_pragma_openmp 'threadprivate' simple-variable-list
104 ///         annot_pragma_openmp_end
105 ///
106 ///       executable-directive:
107 ///         annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
108 ///         'section' | 'single' | 'parallel for' | 'parallel sections' {clause}
109 ///         annot_pragma_openmp_end
110 ///
ParseOpenMPDeclarativeOrExecutableDirective()111 StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
112   assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
113   ParenBraceBracketBalancer BalancerRAIIObj(*this);
114   SmallVector<Expr *, 5> Identifiers;
115   SmallVector<OMPClause *, 5> Clauses;
116   SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
117   FirstClauses(OMPC_unknown + 1);
118   unsigned ScopeFlags =
119       Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
120   SourceLocation Loc = ConsumeToken(), EndLoc;
121   auto DKind = ParseOpenMPDirectiveKind(*this);
122   // Name of critical directive.
123   DeclarationNameInfo DirName;
124   StmtResult Directive = StmtError();
125 
126   switch (DKind) {
127   case OMPD_threadprivate:
128     ConsumeToken();
129     if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
130       // The last seen token is annot_pragma_openmp_end - need to check for
131       // extra tokens.
132       if (Tok.isNot(tok::annot_pragma_openmp_end)) {
133         Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
134             << getOpenMPDirectiveName(OMPD_threadprivate);
135         SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
136       }
137       DeclGroupPtrTy Res =
138           Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
139       Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
140     }
141     SkipUntil(tok::annot_pragma_openmp_end);
142     break;
143   case OMPD_parallel:
144   case OMPD_simd:
145   case OMPD_for:
146   case OMPD_sections:
147   case OMPD_single:
148   case OMPD_section:
149   case OMPD_parallel_for:
150   case OMPD_parallel_sections: {
151     ConsumeToken();
152 
153     if (isOpenMPLoopDirective(DKind))
154       ScopeFlags |= Scope::OpenMPLoopDirectiveScope;
155     if (isOpenMPSimdDirective(DKind))
156       ScopeFlags |= Scope::OpenMPSimdDirectiveScope;
157     ParseScope OMPDirectiveScope(this, ScopeFlags);
158     Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);
159 
160     while (Tok.isNot(tok::annot_pragma_openmp_end)) {
161       OpenMPClauseKind CKind = Tok.isAnnotation()
162                                    ? OMPC_unknown
163                                    : getOpenMPClauseKind(PP.getSpelling(Tok));
164       OMPClause *Clause =
165           ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
166       FirstClauses[CKind].setInt(true);
167       if (Clause) {
168         FirstClauses[CKind].setPointer(Clause);
169         Clauses.push_back(Clause);
170       }
171 
172       // Skip ',' if any.
173       if (Tok.is(tok::comma))
174         ConsumeToken();
175     }
176     // End location of the directive.
177     EndLoc = Tok.getLocation();
178     // Consume final annot_pragma_openmp_end.
179     ConsumeToken();
180 
181     StmtResult AssociatedStmt;
182     bool CreateDirective = true;
183     {
184       // The body is a block scope like in Lambdas and Blocks.
185       Sema::CompoundScopeRAII CompoundScope(Actions);
186       Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
187       Actions.ActOnStartOfCompoundStmt();
188       // Parse statement
189       AssociatedStmt = ParseStatement();
190       Actions.ActOnFinishOfCompoundStmt();
191       if (!AssociatedStmt.isUsable()) {
192         Actions.ActOnCapturedRegionError();
193         CreateDirective = false;
194       } else {
195         AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.get());
196         CreateDirective = AssociatedStmt.isUsable();
197       }
198     }
199     if (CreateDirective)
200       Directive = Actions.ActOnOpenMPExecutableDirective(
201           DKind, Clauses, AssociatedStmt.get(), Loc, EndLoc);
202 
203     // Exit scope.
204     Actions.EndOpenMPDSABlock(Directive.get());
205     OMPDirectiveScope.Exit();
206     break;
207   }
208   case OMPD_unknown:
209     Diag(Tok, diag::err_omp_unknown_directive);
210     SkipUntil(tok::annot_pragma_openmp_end);
211     break;
212   case OMPD_task:
213     Diag(Tok, diag::err_omp_unexpected_directive)
214         << getOpenMPDirectiveName(DKind);
215     SkipUntil(tok::annot_pragma_openmp_end);
216     break;
217   }
218   return Directive;
219 }
220 
221 /// \brief Parses list of simple variables for '#pragma omp threadprivate'
222 /// directive.
223 ///
224 ///   simple-variable-list:
225 ///         '(' id-expression {, id-expression} ')'
226 ///
ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,SmallVectorImpl<Expr * > & VarList,bool AllowScopeSpecifier)227 bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
228                                       SmallVectorImpl<Expr *> &VarList,
229                                       bool AllowScopeSpecifier) {
230   VarList.clear();
231   // Parse '('.
232   BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
233   if (T.expectAndConsume(diag::err_expected_lparen_after,
234                          getOpenMPDirectiveName(Kind)))
235     return true;
236   bool IsCorrect = true;
237   bool NoIdentIsFound = true;
238 
239   // Read tokens while ')' or annot_pragma_openmp_end is not found.
240   while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
241     CXXScopeSpec SS;
242     SourceLocation TemplateKWLoc;
243     UnqualifiedId Name;
244     // Read var name.
245     Token PrevTok = Tok;
246     NoIdentIsFound = false;
247 
248     if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
249         ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
250       IsCorrect = false;
251       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
252                 StopBeforeMatch);
253     } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
254                                   TemplateKWLoc, Name)) {
255       IsCorrect = false;
256       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
257                 StopBeforeMatch);
258     } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
259                Tok.isNot(tok::annot_pragma_openmp_end)) {
260       IsCorrect = false;
261       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
262                 StopBeforeMatch);
263       Diag(PrevTok.getLocation(), diag::err_expected)
264           << tok::identifier
265           << SourceRange(PrevTok.getLocation(), PrevTokLocation);
266     } else {
267       DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
268       ExprResult Res =
269           Actions.ActOnOpenMPIdExpression(getCurScope(), SS, NameInfo);
270       if (Res.isUsable())
271         VarList.push_back(Res.get());
272     }
273     // Consume ','.
274     if (Tok.is(tok::comma)) {
275       ConsumeToken();
276     }
277   }
278 
279   if (NoIdentIsFound) {
280     Diag(Tok, diag::err_expected) << tok::identifier;
281     IsCorrect = false;
282   }
283 
284   // Parse ')'.
285   IsCorrect = !T.consumeClose() && IsCorrect;
286 
287   return !IsCorrect && VarList.empty();
288 }
289 
290 /// \brief Parsing of OpenMP clauses.
291 ///
292 ///    clause:
293 ///       if-clause | num_threads-clause | safelen-clause | default-clause |
294 ///       private-clause | firstprivate-clause | shared-clause | linear-clause |
295 ///       aligned-clause | collapse-clause | lastprivate-clause |
296 ///       reduction-clause | proc_bind-clause | schedule-clause |
297 ///       copyin-clause | copyprivate-clause
298 ///
ParseOpenMPClause(OpenMPDirectiveKind DKind,OpenMPClauseKind CKind,bool FirstClause)299 OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
300                                      OpenMPClauseKind CKind, bool FirstClause) {
301   OMPClause *Clause = nullptr;
302   bool ErrorFound = false;
303   // Check if clause is allowed for the given directive.
304   if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) {
305     Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
306                                                << getOpenMPDirectiveName(DKind);
307     ErrorFound = true;
308   }
309 
310   switch (CKind) {
311   case OMPC_if:
312   case OMPC_num_threads:
313   case OMPC_safelen:
314   case OMPC_collapse:
315     // OpenMP [2.5, Restrictions]
316     //  At most one if clause can appear on the directive.
317     //  At most one num_threads clause can appear on the directive.
318     // OpenMP [2.8.1, simd construct, Restrictions]
319     //  Only one safelen  clause can appear on a simd directive.
320     //  Only one collapse clause can appear on a simd directive.
321     if (!FirstClause) {
322       Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
323                                                << getOpenMPClauseName(CKind);
324     }
325 
326     Clause = ParseOpenMPSingleExprClause(CKind);
327     break;
328   case OMPC_default:
329   case OMPC_proc_bind:
330     // OpenMP [2.14.3.1, Restrictions]
331     //  Only a single default clause may be specified on a parallel, task or
332     //  teams directive.
333     // OpenMP [2.5, parallel Construct, Restrictions]
334     //  At most one proc_bind clause can appear on the directive.
335     if (!FirstClause) {
336       Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
337                                                << getOpenMPClauseName(CKind);
338     }
339 
340     Clause = ParseOpenMPSimpleClause(CKind);
341     break;
342   case OMPC_schedule:
343     // OpenMP [2.7.1, Restrictions, p. 3]
344     //  Only one schedule clause can appear on a loop directive.
345     if (!FirstClause) {
346       Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
347                                                << getOpenMPClauseName(CKind);
348     }
349 
350     Clause = ParseOpenMPSingleExprWithArgClause(CKind);
351     break;
352   case OMPC_ordered:
353   case OMPC_nowait:
354     // OpenMP [2.7.1, Restrictions, p. 9]
355     //  Only one ordered clause can appear on a loop directive.
356     // OpenMP [2.7.1, Restrictions, C/C++, p. 4]
357     //  Only one nowait clause can appear on a for directive.
358     if (!FirstClause) {
359       Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
360                                                << getOpenMPClauseName(CKind);
361     }
362 
363     Clause = ParseOpenMPClause(CKind);
364     break;
365   case OMPC_private:
366   case OMPC_firstprivate:
367   case OMPC_lastprivate:
368   case OMPC_shared:
369   case OMPC_reduction:
370   case OMPC_linear:
371   case OMPC_aligned:
372   case OMPC_copyin:
373   case OMPC_copyprivate:
374     Clause = ParseOpenMPVarListClause(CKind);
375     break;
376   case OMPC_unknown:
377     Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
378         << getOpenMPDirectiveName(DKind);
379     SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
380     break;
381   case OMPC_threadprivate:
382     Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
383                                                << getOpenMPDirectiveName(DKind);
384     SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
385     break;
386   }
387   return ErrorFound ? nullptr : Clause;
388 }
389 
390 /// \brief Parsing of OpenMP clauses with single expressions like 'if',
391 /// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams' or
392 /// 'thread_limit'.
393 ///
394 ///    if-clause:
395 ///      'if' '(' expression ')'
396 ///
397 ///    num_threads-clause:
398 ///      'num_threads' '(' expression ')'
399 ///
400 ///    safelen-clause:
401 ///      'safelen' '(' expression ')'
402 ///
403 ///    collapse-clause:
404 ///      'collapse' '(' expression ')'
405 ///
ParseOpenMPSingleExprClause(OpenMPClauseKind Kind)406 OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
407   SourceLocation Loc = ConsumeToken();
408 
409   BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
410   if (T.expectAndConsume(diag::err_expected_lparen_after,
411                          getOpenMPClauseName(Kind)))
412     return nullptr;
413 
414   ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
415   ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
416 
417   // Parse ')'.
418   T.consumeClose();
419 
420   if (Val.isInvalid())
421     return nullptr;
422 
423   return Actions.ActOnOpenMPSingleExprClause(
424       Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation());
425 }
426 
427 /// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
428 ///
429 ///    default-clause:
430 ///         'default' '(' 'none' | 'shared' ')
431 ///
432 ///    proc_bind-clause:
433 ///         'proc_bind' '(' 'master' | 'close' | 'spread' ')
434 ///
ParseOpenMPSimpleClause(OpenMPClauseKind Kind)435 OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
436   SourceLocation Loc = Tok.getLocation();
437   SourceLocation LOpen = ConsumeToken();
438   // Parse '('.
439   BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
440   if (T.expectAndConsume(diag::err_expected_lparen_after,
441                          getOpenMPClauseName(Kind)))
442     return nullptr;
443 
444   unsigned Type = getOpenMPSimpleClauseType(
445       Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
446   SourceLocation TypeLoc = Tok.getLocation();
447   if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
448       Tok.isNot(tok::annot_pragma_openmp_end))
449     ConsumeAnyToken();
450 
451   // Parse ')'.
452   T.consumeClose();
453 
454   return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc,
455                                          Tok.getLocation());
456 }
457 
458 /// \brief Parsing of OpenMP clauses like 'ordered'.
459 ///
460 ///    ordered-clause:
461 ///         'ordered'
462 ///
463 ///    nowait-clause:
464 ///         'nowait'
465 ///
ParseOpenMPClause(OpenMPClauseKind Kind)466 OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) {
467   SourceLocation Loc = Tok.getLocation();
468   ConsumeAnyToken();
469 
470   return Actions.ActOnOpenMPClause(Kind, Loc, Tok.getLocation());
471 }
472 
473 
474 /// \brief Parsing of OpenMP clauses with single expressions and some additional
475 /// argument like 'schedule' or 'dist_schedule'.
476 ///
477 ///    schedule-clause:
478 ///      'schedule' '(' kind [',' expression ] ')'
479 ///
ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind)480 OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) {
481   SourceLocation Loc = ConsumeToken();
482   SourceLocation CommaLoc;
483   // Parse '('.
484   BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
485   if (T.expectAndConsume(diag::err_expected_lparen_after,
486                          getOpenMPClauseName(Kind)))
487     return nullptr;
488 
489   ExprResult Val;
490   unsigned Type = getOpenMPSimpleClauseType(
491       Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
492   SourceLocation KLoc = Tok.getLocation();
493   if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
494       Tok.isNot(tok::annot_pragma_openmp_end))
495     ConsumeAnyToken();
496 
497   if (Kind == OMPC_schedule &&
498       (Type == OMPC_SCHEDULE_static || Type == OMPC_SCHEDULE_dynamic ||
499        Type == OMPC_SCHEDULE_guided) &&
500       Tok.is(tok::comma)) {
501     CommaLoc = ConsumeAnyToken();
502     ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
503     Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
504     if (Val.isInvalid())
505       return nullptr;
506   }
507 
508   // Parse ')'.
509   T.consumeClose();
510 
511   return Actions.ActOnOpenMPSingleExprWithArgClause(
512       Kind, Type, Val.get(), Loc, T.getOpenLocation(), KLoc, CommaLoc,
513       T.getCloseLocation());
514 }
515 
ParseReductionId(Parser & P,CXXScopeSpec & ReductionIdScopeSpec,UnqualifiedId & ReductionId)516 static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
517                              UnqualifiedId &ReductionId) {
518   SourceLocation TemplateKWLoc;
519   if (ReductionIdScopeSpec.isEmpty()) {
520     auto OOK = OO_None;
521     switch (P.getCurToken().getKind()) {
522     case tok::plus:
523       OOK = OO_Plus;
524       break;
525     case tok::minus:
526       OOK = OO_Minus;
527       break;
528     case tok::star:
529       OOK = OO_Star;
530       break;
531     case tok::amp:
532       OOK = OO_Amp;
533       break;
534     case tok::pipe:
535       OOK = OO_Pipe;
536       break;
537     case tok::caret:
538       OOK = OO_Caret;
539       break;
540     case tok::ampamp:
541       OOK = OO_AmpAmp;
542       break;
543     case tok::pipepipe:
544       OOK = OO_PipePipe;
545       break;
546     default:
547       break;
548     }
549     if (OOK != OO_None) {
550       SourceLocation OpLoc = P.ConsumeToken();
551       SourceLocation SymbolLocations[] = {OpLoc, OpLoc, SourceLocation()};
552       ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);
553       return false;
554     }
555   }
556   return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
557                               /*AllowDestructorName*/ false,
558                               /*AllowConstructorName*/ false, ParsedType(),
559                               TemplateKWLoc, ReductionId);
560 }
561 
562 /// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
563 /// 'shared', 'copyin', or 'reduction'.
564 ///
565 ///    private-clause:
566 ///       'private' '(' list ')'
567 ///    firstprivate-clause:
568 ///       'firstprivate' '(' list ')'
569 ///    lastprivate-clause:
570 ///       'lastprivate' '(' list ')'
571 ///    shared-clause:
572 ///       'shared' '(' list ')'
573 ///    linear-clause:
574 ///       'linear' '(' list [ ':' linear-step ] ')'
575 ///    aligned-clause:
576 ///       'aligned' '(' list [ ':' alignment ] ')'
577 ///    reduction-clause:
578 ///       'reduction' '(' reduction-identifier ':' list ')'
579 ///
ParseOpenMPVarListClause(OpenMPClauseKind Kind)580 OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
581   SourceLocation Loc = Tok.getLocation();
582   SourceLocation LOpen = ConsumeToken();
583   SourceLocation ColonLoc = SourceLocation();
584   // Optional scope specifier and unqualified id for reduction identifier.
585   CXXScopeSpec ReductionIdScopeSpec;
586   UnqualifiedId ReductionId;
587   bool InvalidReductionId = false;
588   // Parse '('.
589   BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
590   if (T.expectAndConsume(diag::err_expected_lparen_after,
591                          getOpenMPClauseName(Kind)))
592     return nullptr;
593 
594   // Handle reduction-identifier for reduction clause.
595   if (Kind == OMPC_reduction) {
596     ColonProtectionRAIIObject ColonRAII(*this);
597     if (getLangOpts().CPlusPlus) {
598       ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false);
599     }
600     InvalidReductionId =
601         ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
602     if (InvalidReductionId) {
603       SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
604                 StopBeforeMatch);
605     }
606     if (Tok.is(tok::colon)) {
607       ColonLoc = ConsumeToken();
608     } else {
609       Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
610     }
611   }
612 
613   SmallVector<Expr *, 5> Vars;
614   bool IsComma = !InvalidReductionId;
615   const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
616   while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
617                      Tok.isNot(tok::annot_pragma_openmp_end))) {
618     ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
619     // Parse variable
620     ExprResult VarExpr = ParseAssignmentExpression();
621     if (VarExpr.isUsable()) {
622       Vars.push_back(VarExpr.get());
623     } else {
624       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
625                 StopBeforeMatch);
626     }
627     // Skip ',' if any
628     IsComma = Tok.is(tok::comma);
629     if (IsComma)
630       ConsumeToken();
631     else if (Tok.isNot(tok::r_paren) &&
632              Tok.isNot(tok::annot_pragma_openmp_end) &&
633              (!MayHaveTail || Tok.isNot(tok::colon)))
634       Diag(Tok, diag::err_omp_expected_punc) << getOpenMPClauseName(Kind);
635   }
636 
637   // Parse ':' linear-step (or ':' alignment).
638   Expr *TailExpr = nullptr;
639   const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
640   if (MustHaveTail) {
641     ColonLoc = Tok.getLocation();
642     ConsumeToken();
643     ExprResult Tail = ParseAssignmentExpression();
644     if (Tail.isUsable())
645       TailExpr = Tail.get();
646     else
647       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
648                 StopBeforeMatch);
649   }
650 
651   // Parse ')'.
652   T.consumeClose();
653   if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId)
654     return nullptr;
655 
656   return Actions.ActOnOpenMPVarListClause(
657       Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
658       ReductionIdScopeSpec,
659       ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
660                             : DeclarationNameInfo());
661 }
662 
663