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