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 "clang/AST/ASTConsumer.h"
15#include "clang/AST/StmtOpenMP.h"
16#include "clang/Parse/ParseDiagnostic.h"
17#include "clang/Parse/Parser.h"
18#include "clang/Sema/Scope.h"
19#include "llvm/ADT/PointerIntPair.h"
20#include "RAIIObjectsForParser.h"
21using namespace clang;
22
23//===----------------------------------------------------------------------===//
24// OpenMP declarative directives.
25//===----------------------------------------------------------------------===//
26
27/// \brief Parsing of declarative OpenMP directives.
28///
29///       threadprivate-directive:
30///         annot_pragma_openmp 'threadprivate' simple-variable-list
31///
32Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
33  assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
34  ParenBraceBracketBalancer BalancerRAIIObj(*this);
35
36  SourceLocation Loc = ConsumeToken();
37  SmallVector<Expr *, 5> Identifiers;
38  OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
39                                  OMPD_unknown :
40                                  getOpenMPDirectiveKind(PP.getSpelling(Tok));
41
42  switch (DKind) {
43  case OMPD_threadprivate:
44    ConsumeToken();
45    if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
46      // The last seen token is annot_pragma_openmp_end - need to check for
47      // extra tokens.
48      if (Tok.isNot(tok::annot_pragma_openmp_end)) {
49        Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
50          << getOpenMPDirectiveName(OMPD_threadprivate);
51        SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
52      }
53      // Skip the last annot_pragma_openmp_end.
54      ConsumeToken();
55      return Actions.ActOnOpenMPThreadprivateDirective(Loc,
56                                                       Identifiers);
57    }
58    break;
59  case OMPD_unknown:
60    Diag(Tok, diag::err_omp_unknown_directive);
61    break;
62  case OMPD_parallel:
63  case OMPD_task:
64  case NUM_OPENMP_DIRECTIVES:
65    Diag(Tok, diag::err_omp_unexpected_directive)
66      << getOpenMPDirectiveName(DKind);
67    break;
68  }
69  SkipUntil(tok::annot_pragma_openmp_end);
70  return DeclGroupPtrTy();
71}
72
73/// \brief Parsing of declarative or executable OpenMP directives.
74///
75///       threadprivate-directive:
76///         annot_pragma_openmp 'threadprivate' simple-variable-list
77///         annot_pragma_openmp_end
78///
79///       parallel-directive:
80///         annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end
81///
82StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
83  assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
84  ParenBraceBracketBalancer BalancerRAIIObj(*this);
85  SmallVector<Expr *, 5> Identifiers;
86  SmallVector<OMPClause *, 5> Clauses;
87  SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, NUM_OPENMP_CLAUSES>
88                                               FirstClauses(NUM_OPENMP_CLAUSES);
89  const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
90                              Scope::OpenMPDirectiveScope;
91  SourceLocation Loc = ConsumeToken(), EndLoc;
92  OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
93                                  OMPD_unknown :
94                                  getOpenMPDirectiveKind(PP.getSpelling(Tok));
95  // Name of critical directive.
96  DeclarationNameInfo DirName;
97  StmtResult Directive = StmtError();
98
99  switch (DKind) {
100  case OMPD_threadprivate:
101    ConsumeToken();
102    if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
103      // The last seen token is annot_pragma_openmp_end - need to check for
104      // extra tokens.
105      if (Tok.isNot(tok::annot_pragma_openmp_end)) {
106        Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
107          << getOpenMPDirectiveName(OMPD_threadprivate);
108        SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
109      }
110      DeclGroupPtrTy Res =
111        Actions.ActOnOpenMPThreadprivateDirective(Loc,
112                                                  Identifiers);
113      Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
114    }
115    SkipUntil(tok::annot_pragma_openmp_end);
116    break;
117  case OMPD_parallel: {
118    ConsumeToken();
119
120    Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope());
121
122    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
123      OpenMPClauseKind CKind = Tok.isAnnotation() ?
124                                  OMPC_unknown :
125                                  getOpenMPClauseKind(PP.getSpelling(Tok));
126      OMPClause *Clause = ParseOpenMPClause(DKind, CKind,
127                                            !FirstClauses[CKind].getInt());
128      FirstClauses[CKind].setInt(true);
129      if (Clause) {
130        FirstClauses[CKind].setPointer(Clause);
131        Clauses.push_back(Clause);
132      }
133
134      // Skip ',' if any.
135      if (Tok.is(tok::comma))
136        ConsumeToken();
137    }
138    // End location of the directive.
139    EndLoc = Tok.getLocation();
140    // Consume final annot_pragma_openmp_end.
141    ConsumeToken();
142
143    StmtResult AssociatedStmt;
144    bool CreateDirective = true;
145    ParseScope OMPDirectiveScope(this, ScopeFlags);
146    {
147      // The body is a block scope like in Lambdas and Blocks.
148      Sema::CompoundScopeRAII CompoundScope(Actions);
149      Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1);
150      Actions.ActOnStartOfCompoundStmt();
151      // Parse statement
152      AssociatedStmt = ParseStatement();
153      Actions.ActOnFinishOfCompoundStmt();
154      if (!AssociatedStmt.isUsable()) {
155        Actions.ActOnCapturedRegionError();
156        CreateDirective = false;
157      } else {
158        AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take());
159        CreateDirective = AssociatedStmt.isUsable();
160      }
161    }
162    if (CreateDirective)
163      Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses,
164                                                         AssociatedStmt.take(),
165                                                         Loc, EndLoc);
166
167    // Exit scope.
168    Actions.EndOpenMPDSABlock(Directive.get());
169    OMPDirectiveScope.Exit();
170    }
171    break;
172  case OMPD_unknown:
173    Diag(Tok, diag::err_omp_unknown_directive);
174    SkipUntil(tok::annot_pragma_openmp_end);
175    break;
176  case OMPD_task:
177  case NUM_OPENMP_DIRECTIVES:
178    Diag(Tok, diag::err_omp_unexpected_directive)
179      << getOpenMPDirectiveName(DKind);
180    SkipUntil(tok::annot_pragma_openmp_end);
181    break;
182  }
183  return Directive;
184}
185
186/// \brief Parses list of simple variables for '#pragma omp threadprivate'
187/// directive.
188///
189///   simple-variable-list:
190///         '(' id-expression {, id-expression} ')'
191///
192bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
193                                      SmallVectorImpl<Expr *> &VarList,
194                                      bool AllowScopeSpecifier) {
195  VarList.clear();
196  // Parse '('.
197  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
198  if (T.expectAndConsume(diag::err_expected_lparen_after,
199                         getOpenMPDirectiveName(Kind)))
200    return true;
201  bool IsCorrect = true;
202  bool NoIdentIsFound = true;
203
204  // Read tokens while ')' or annot_pragma_openmp_end is not found.
205  while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
206    CXXScopeSpec SS;
207    SourceLocation TemplateKWLoc;
208    UnqualifiedId Name;
209    // Read var name.
210    Token PrevTok = Tok;
211    NoIdentIsFound = false;
212
213    if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
214        ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
215      IsCorrect = false;
216      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
217                StopBeforeMatch);
218    } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
219                                  TemplateKWLoc, Name)) {
220      IsCorrect = false;
221      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
222                StopBeforeMatch);
223    } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
224               Tok.isNot(tok::annot_pragma_openmp_end)) {
225      IsCorrect = false;
226      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
227                StopBeforeMatch);
228      Diag(PrevTok.getLocation(), diag::err_expected_ident)
229        << SourceRange(PrevTok.getLocation(), PrevTokLocation);
230    } else {
231      DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
232      ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS,
233                                                       NameInfo);
234      if (Res.isUsable())
235        VarList.push_back(Res.take());
236    }
237    // Consume ','.
238    if (Tok.is(tok::comma)) {
239      ConsumeToken();
240    }
241  }
242
243  if (NoIdentIsFound) {
244    Diag(Tok, diag::err_expected_ident);
245    IsCorrect = false;
246  }
247
248  // Parse ')'.
249  IsCorrect = !T.consumeClose() && IsCorrect;
250
251  return !IsCorrect && VarList.empty();
252}
253
254/// \brief Parsing of OpenMP clauses.
255///
256///    clause:
257///       default-clause|private-clause|firstprivate-clause|shared-clause
258///
259OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
260                                     OpenMPClauseKind CKind, bool FirstClause) {
261  OMPClause *Clause = 0;
262  bool ErrorFound = false;
263  // Check if clause is allowed for the given directive.
264  if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) {
265    Diag(Tok, diag::err_omp_unexpected_clause)
266      << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
267    ErrorFound = true;
268  }
269
270  switch (CKind) {
271  case OMPC_default:
272    // OpenMP [2.9.3.1, Restrictions]
273    //  Only a single default clause may be specified on a parallel or task
274    //  directive.
275    if (!FirstClause) {
276      Diag(Tok, diag::err_omp_more_one_clause)
277           << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind);
278    }
279
280    Clause = ParseOpenMPSimpleClause(CKind);
281    break;
282  case OMPC_private:
283  case OMPC_firstprivate:
284  case OMPC_shared:
285    Clause = ParseOpenMPVarListClause(CKind);
286    break;
287  case OMPC_unknown:
288    Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
289      << getOpenMPDirectiveName(DKind);
290    SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
291    break;
292  case OMPC_threadprivate:
293  case NUM_OPENMP_CLAUSES:
294    Diag(Tok, diag::err_omp_unexpected_clause)
295      << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
296    SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
297    break;
298  }
299  return ErrorFound ? 0 : Clause;
300}
301
302/// \brief Parsing of simple OpenMP clauses like 'default'.
303///
304///    default-clause:
305///         'default' '(' 'none' | 'shared' ')
306///
307OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
308  SourceLocation Loc = Tok.getLocation();
309  SourceLocation LOpen = ConsumeToken();
310  // Parse '('.
311  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
312  if (T.expectAndConsume(diag::err_expected_lparen_after,
313                         getOpenMPClauseName(Kind)))
314    return 0;
315
316  unsigned Type = Tok.isAnnotation() ?
317                     unsigned(OMPC_DEFAULT_unknown) :
318                     getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
319  SourceLocation TypeLoc = Tok.getLocation();
320  if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
321      Tok.isNot(tok::annot_pragma_openmp_end))
322    ConsumeAnyToken();
323
324  // Parse ')'.
325  T.consumeClose();
326
327  return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc,
328                                         Tok.getLocation());
329}
330
331/// \brief Parsing of OpenMP clause 'private', 'firstprivate',
332/// 'shared', 'copyin', or 'reduction'.
333///
334///    private-clause:
335///       'private' '(' list ')'
336///    firstprivate-clause:
337///       'firstprivate' '(' list ')'
338///    shared-clause:
339///       'shared' '(' list ')'
340///
341OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
342  SourceLocation Loc = Tok.getLocation();
343  SourceLocation LOpen = ConsumeToken();
344  // Parse '('.
345  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
346  if (T.expectAndConsume(diag::err_expected_lparen_after,
347                         getOpenMPClauseName(Kind)))
348    return 0;
349
350  SmallVector<Expr *, 5> Vars;
351  bool IsComma = true;
352  while (IsComma || (Tok.isNot(tok::r_paren) &&
353                     Tok.isNot(tok::annot_pragma_openmp_end))) {
354    // Parse variable
355    ExprResult VarExpr = ParseAssignmentExpression();
356    if (VarExpr.isUsable()) {
357      Vars.push_back(VarExpr.take());
358    } else {
359      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
360                StopBeforeMatch);
361    }
362    // Skip ',' if any
363    IsComma = Tok.is(tok::comma);
364    if (IsComma) {
365      ConsumeToken();
366    } else if (Tok.isNot(tok::r_paren) &&
367               Tok.isNot(tok::annot_pragma_openmp_end)) {
368      Diag(Tok, diag::err_omp_expected_punc)
369        << 1 << getOpenMPClauseName(Kind);
370    }
371  }
372
373  // Parse ')'.
374  T.consumeClose();
375  if (Vars.empty())
376    return 0;
377
378  return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen,
379                                          Tok.getLocation());
380}
381
382