summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp347
1 files changed, 305 insertions, 42 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp
index 507a6b1..89e4147 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp
@@ -12,8 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
-#include "clang/Parse/Parser.h"
+#include "clang/AST/StmtOpenMP.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Scope.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
@@ -21,98 +24,358 @@ using namespace clang;
// OpenMP declarative directives.
//===----------------------------------------------------------------------===//
-/// \brief Parses OpenMP declarative directive
-/// threadprivate-directive
-/// annot_pragma_openmp threadprivate simple-variable-list
+/// \brief Parsing of declarative OpenMP directives.
+///
+/// threadprivate-directive:
+/// annot_pragma_openmp 'threadprivate' simple-variable-list
///
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+ ParenBraceBracketBalancer BalancerRAIIObj(*this);
SourceLocation Loc = ConsumeToken();
- SmallVector<DeclarationNameInfo, 5> Identifiers;
- OpenMPDirectiveKind Kind = Tok.isAnnotation() ?
- OMPD_unknown :
- getOpenMPDirectiveKind(PP.getSpelling(Tok));
- switch(Kind) {
+ SmallVector<Expr *, 5> Identifiers;
+ OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
+ OMPD_unknown :
+ getOpenMPDirectiveKind(PP.getSpelling(Tok));
+
+ switch (DKind) {
case OMPD_threadprivate:
ConsumeToken();
- if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) {
+ if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
// The last seen token is annot_pragma_openmp_end - need to check for
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
<< getOpenMPDirectiveName(OMPD_threadprivate);
- SkipUntil(tok::annot_pragma_openmp_end, false, true);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
+ // Skip the last annot_pragma_openmp_end.
ConsumeToken();
return Actions.ActOnOpenMPThreadprivateDirective(Loc,
- getCurScope(),
Identifiers);
}
break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
- default:
+ case OMPD_parallel:
+ case OMPD_task:
+ case NUM_OPENMP_DIRECTIVES:
Diag(Tok, diag::err_omp_unexpected_directive)
- << getOpenMPDirectiveName(Kind);
+ << getOpenMPDirectiveName(DKind);
break;
}
- SkipUntil(tok::annot_pragma_openmp_end, false);
+ SkipUntil(tok::annot_pragma_openmp_end);
return DeclGroupPtrTy();
}
+/// \brief Parsing of declarative or executable OpenMP directives.
+///
+/// threadprivate-directive:
+/// annot_pragma_openmp 'threadprivate' simple-variable-list
+/// annot_pragma_openmp_end
+///
+/// parallel-directive:
+/// annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end
+///
+StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
+ assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+ ParenBraceBracketBalancer BalancerRAIIObj(*this);
+ SmallVector<Expr *, 5> Identifiers;
+ SmallVector<OMPClause *, 5> Clauses;
+ SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, NUM_OPENMP_CLAUSES>
+ FirstClauses(NUM_OPENMP_CLAUSES);
+ const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
+ Scope::OpenMPDirectiveScope;
+ SourceLocation Loc = ConsumeToken(), EndLoc;
+ OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
+ OMPD_unknown :
+ getOpenMPDirectiveKind(PP.getSpelling(Tok));
+ // Name of critical directive.
+ DeclarationNameInfo DirName;
+ StmtResult Directive = StmtError();
+
+ switch (DKind) {
+ case OMPD_threadprivate:
+ ConsumeToken();
+ if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
+ // The last seen token is annot_pragma_openmp_end - need to check for
+ // extra tokens.
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(OMPD_threadprivate);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ }
+ DeclGroupPtrTy Res =
+ Actions.ActOnOpenMPThreadprivateDirective(Loc,
+ Identifiers);
+ Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
+ }
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
+ case OMPD_parallel: {
+ ConsumeToken();
+
+ Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope());
+
+ while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ OpenMPClauseKind CKind = Tok.isAnnotation() ?
+ OMPC_unknown :
+ getOpenMPClauseKind(PP.getSpelling(Tok));
+ OMPClause *Clause = ParseOpenMPClause(DKind, CKind,
+ !FirstClauses[CKind].getInt());
+ FirstClauses[CKind].setInt(true);
+ if (Clause) {
+ FirstClauses[CKind].setPointer(Clause);
+ Clauses.push_back(Clause);
+ }
+
+ // Skip ',' if any.
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ }
+ // End location of the directive.
+ EndLoc = Tok.getLocation();
+ // Consume final annot_pragma_openmp_end.
+ ConsumeToken();
+
+ StmtResult AssociatedStmt;
+ bool CreateDirective = true;
+ ParseScope OMPDirectiveScope(this, ScopeFlags);
+ {
+ // The body is a block scope like in Lambdas and Blocks.
+ Sema::CompoundScopeRAII CompoundScope(Actions);
+ Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1);
+ Actions.ActOnStartOfCompoundStmt();
+ // Parse statement
+ AssociatedStmt = ParseStatement();
+ Actions.ActOnFinishOfCompoundStmt();
+ if (!AssociatedStmt.isUsable()) {
+ Actions.ActOnCapturedRegionError();
+ CreateDirective = false;
+ } else {
+ AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take());
+ CreateDirective = AssociatedStmt.isUsable();
+ }
+ }
+ if (CreateDirective)
+ Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses,
+ AssociatedStmt.take(),
+ Loc, EndLoc);
+
+ // Exit scope.
+ Actions.EndOpenMPDSABlock(Directive.get());
+ OMPDirectiveScope.Exit();
+ }
+ break;
+ case OMPD_unknown:
+ Diag(Tok, diag::err_omp_unknown_directive);
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
+ case OMPD_task:
+ case NUM_OPENMP_DIRECTIVES:
+ Diag(Tok, diag::err_omp_unexpected_directive)
+ << getOpenMPDirectiveName(DKind);
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
+ }
+ return Directive;
+}
+
/// \brief Parses list of simple variables for '#pragma omp threadprivate'
-/// directive
-/// simple-variable-list:
-/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end
+/// directive.
+///
+/// simple-variable-list:
+/// '(' id-expression {, id-expression} ')'
///
-bool Parser::ParseOpenMPSimpleVarList(
- OpenMPDirectiveKind Kind,
- SmallVectorImpl<DeclarationNameInfo> &IdList) {
+bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
+ SmallVectorImpl<Expr *> &VarList,
+ bool AllowScopeSpecifier) {
+ VarList.clear();
// Parse '('.
- bool IsCorrect = true;
- BalancedDelimiterTracker T(*this, tok::l_paren);
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPDirectiveName(Kind))) {
- SkipUntil(tok::annot_pragma_openmp_end, false, true);
- return false;
- }
+ getOpenMPDirectiveName(Kind)))
+ return true;
+ bool IsCorrect = true;
+ bool NoIdentIsFound = true;
// Read tokens while ')' or annot_pragma_openmp_end is not found.
- do {
+ while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
CXXScopeSpec SS;
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
// Read var name.
Token PrevTok = Tok;
+ NoIdentIsFound = false;
- if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
- TemplateKWLoc, Name)) {
+ if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- false, true);
- }
- else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
- Tok.isNot(tok::annot_pragma_openmp_end)) {
+ StopBeforeMatch);
+ } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
+ TemplateKWLoc, Name)) {
+ IsCorrect = false;
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- false, true);
- Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id)
- << getLangOpts().CPlusPlus
+ StopBeforeMatch);
+ Diag(PrevTok.getLocation(), diag::err_expected_ident)
<< SourceRange(PrevTok.getLocation(), PrevTokLocation);
} else {
- IdList.push_back(Actions.GetNameFromUnqualifiedId(Name));
+ DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
+ ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS,
+ NameInfo);
+ if (Res.isUsable())
+ VarList.push_back(Res.take());
}
// Consume ','.
if (Tok.is(tok::comma)) {
ConsumeToken();
}
- } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
+ }
+
+ if (NoIdentIsFound) {
+ Diag(Tok, diag::err_expected_ident);
+ IsCorrect = false;
+ }
- if (IsCorrect || Tok.is(tok::r_paren)) {
- IsCorrect = !T.consumeClose() && IsCorrect;
+ // Parse ')'.
+ IsCorrect = !T.consumeClose() && IsCorrect;
+
+ return !IsCorrect && VarList.empty();
+}
+
+/// \brief Parsing of OpenMP clauses.
+///
+/// clause:
+/// default-clause|private-clause|firstprivate-clause|shared-clause
+///
+OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
+ OpenMPClauseKind CKind, bool FirstClause) {
+ OMPClause *Clause = 0;
+ bool ErrorFound = false;
+ // Check if clause is allowed for the given directive.
+ if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) {
+ Diag(Tok, diag::err_omp_unexpected_clause)
+ << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
+ ErrorFound = true;
}
- return !IsCorrect && IdList.empty();
+ switch (CKind) {
+ case OMPC_default:
+ // OpenMP [2.9.3.1, Restrictions]
+ // Only a single default clause may be specified on a parallel or task
+ // directive.
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind);
+ }
+
+ Clause = ParseOpenMPSimpleClause(CKind);
+ break;
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_shared:
+ Clause = ParseOpenMPVarListClause(CKind);
+ break;
+ case OMPC_unknown:
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(DKind);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ break;
+ case OMPC_threadprivate:
+ case NUM_OPENMP_CLAUSES:
+ Diag(Tok, diag::err_omp_unexpected_clause)
+ << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
+ SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
+ break;
+ }
+ return ErrorFound ? 0 : Clause;
}
+
+/// \brief Parsing of simple OpenMP clauses like 'default'.
+///
+/// default-clause:
+/// 'default' '(' 'none' | 'shared' ')
+///
+OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
+ SourceLocation Loc = Tok.getLocation();
+ SourceLocation LOpen = ConsumeToken();
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind)))
+ return 0;
+
+ unsigned Type = Tok.isAnnotation() ?
+ unsigned(OMPC_DEFAULT_unknown) :
+ getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
+ SourceLocation TypeLoc = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+
+ // Parse ')'.
+ T.consumeClose();
+
+ return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc,
+ Tok.getLocation());
+}
+
+/// \brief Parsing of OpenMP clause 'private', 'firstprivate',
+/// 'shared', 'copyin', or 'reduction'.
+///
+/// private-clause:
+/// 'private' '(' list ')'
+/// firstprivate-clause:
+/// 'firstprivate' '(' list ')'
+/// shared-clause:
+/// 'shared' '(' list ')'
+///
+OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
+ SourceLocation Loc = Tok.getLocation();
+ SourceLocation LOpen = ConsumeToken();
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind)))
+ return 0;
+
+ SmallVector<Expr *, 5> Vars;
+ bool IsComma = true;
+ while (IsComma || (Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))) {
+ // Parse variable
+ ExprResult VarExpr = ParseAssignmentExpression();
+ if (VarExpr.isUsable()) {
+ Vars.push_back(VarExpr.take());
+ } else {
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ }
+ // Skip ',' if any
+ IsComma = Tok.is(tok::comma);
+ if (IsComma) {
+ ConsumeToken();
+ } else if (Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::err_omp_expected_punc)
+ << 1 << getOpenMPClauseName(Kind);
+ }
+ }
+
+ // Parse ')'.
+ T.consumeClose();
+ if (Vars.empty())
+ return 0;
+
+ return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen,
+ Tok.getLocation());
+}
+
OpenPOWER on IntegriCloud