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/Parse/ParseDiagnostic.h"
16 #include "clang/Parse/Parser.h"
17 #include "clang/Sema/Scope.h"
18 #include "llvm/ADT/PointerIntPair.h"
19 #include "RAIIObjectsForParser.h"
20 using namespace clang;
21 
22 //===----------------------------------------------------------------------===//
23 // OpenMP declarative directives.
24 //===----------------------------------------------------------------------===//
25 
26 /// \brief Parsing of declarative OpenMP directives.
27 ///
28 ///       threadprivate-directive:
29 ///         annot_pragma_openmp 'threadprivate' simple-variable-list
30 ///
31 Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
32   assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
33 
34   SourceLocation Loc = ConsumeToken();
35   SmallVector<Expr *, 5> Identifiers;
36   OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
37                                   OMPD_unknown :
38                                   getOpenMPDirectiveKind(PP.getSpelling(Tok));
39 
40   switch (DKind) {
41   case OMPD_threadprivate:
42     ConsumeToken();
43     if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
44       // The last seen token is annot_pragma_openmp_end - need to check for
45       // extra tokens.
46       if (Tok.isNot(tok::annot_pragma_openmp_end)) {
47         Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
48           << getOpenMPDirectiveName(OMPD_threadprivate);
49         SkipUntil(tok::annot_pragma_openmp_end, false, true);
50       }
51       // Skip the last annot_pragma_openmp_end.
52       ConsumeToken();
53       return Actions.ActOnOpenMPThreadprivateDirective(Loc,
54                                                        Identifiers);
55     }
56     break;
57   case OMPD_unknown:
58     Diag(Tok, diag::err_omp_unknown_directive);
59     break;
60   default:
61     Diag(Tok, diag::err_omp_unexpected_directive)
62       << getOpenMPDirectiveName(DKind);
63     break;
64   }
65   SkipUntil(tok::annot_pragma_openmp_end, false);
66   return DeclGroupPtrTy();
67 }
68 
69 /// \brief Parses list of simple variables for '#pragma omp threadprivate'
70 /// directive.
71 ///
72 ///   simple-variable-list:
73 ///         '(' id-expression {, id-expression} ')'
74 ///
75 bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
76                                       SmallVectorImpl<Expr *> &VarList,
77                                       bool AllowScopeSpecifier) {
78   VarList.clear();
79   // Parse '('.
80   BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
81   bool LParen = !T.expectAndConsume(diag::err_expected_lparen_after,
82                                     getOpenMPDirectiveName(Kind));
83   bool IsCorrect = LParen;
84   bool NoIdentIsFound = true;
85 
86   // Read tokens while ')' or annot_pragma_openmp_end is not found.
87   while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
88     CXXScopeSpec SS;
89     SourceLocation TemplateKWLoc;
90     UnqualifiedId Name;
91     // Read var name.
92     Token PrevTok = Tok;
93     NoIdentIsFound = false;
94 
95     if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
96         ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
97       IsCorrect = false;
98       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
99                 false, true);
100     } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
101                                   TemplateKWLoc, Name)) {
102       IsCorrect = false;
103       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
104                 false, true);
105     } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
106                Tok.isNot(tok::annot_pragma_openmp_end)) {
107       IsCorrect = false;
108       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
109                 false, true);
110       Diag(PrevTok.getLocation(), diag::err_expected_ident)
111         << SourceRange(PrevTok.getLocation(), PrevTokLocation);
112     } else {
113       DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
114       ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS,
115                                                        NameInfo);
116       if (Res.isUsable())
117         VarList.push_back(Res.take());
118     }
119     // Consume ','.
120     if (Tok.is(tok::comma)) {
121       ConsumeToken();
122     }
123   }
124 
125   if (NoIdentIsFound) {
126     Diag(Tok, diag::err_expected_ident);
127     IsCorrect = false;
128   }
129 
130   // Parse ')'.
131   IsCorrect = ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose())
132               && IsCorrect;
133 
134   return !IsCorrect && VarList.empty();
135 }
136