forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			747 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			747 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
/// \file
 | 
						|
/// \brief This file implements parsing of all OpenMP directives and clauses.
 | 
						|
///
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "RAIIObjectsForParser.h"
 | 
						|
#include "clang/AST/ASTConsumer.h"
 | 
						|
#include "clang/AST/ASTContext.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"
 | 
						|
using namespace clang;
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// OpenMP declarative directives.
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
 | 
						|
  auto Tok = P.getCurToken();
 | 
						|
  auto DKind =
 | 
						|
      Tok.isAnnotation()
 | 
						|
          ? OMPD_unknown
 | 
						|
          : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
 | 
						|
  if (DKind == OMPD_parallel) {
 | 
						|
    Tok = P.getPreprocessor().LookAhead(0);
 | 
						|
    auto SDKind =
 | 
						|
        Tok.isAnnotation()
 | 
						|
            ? OMPD_unknown
 | 
						|
            : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
 | 
						|
    if (SDKind == OMPD_for) {
 | 
						|
      P.ConsumeToken();
 | 
						|
      DKind = OMPD_parallel_for;
 | 
						|
    } else if (SDKind == OMPD_sections) {
 | 
						|
      P.ConsumeToken();
 | 
						|
      DKind = OMPD_parallel_sections;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return DKind;
 | 
						|
}
 | 
						|
 | 
						|
/// \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<Expr *, 5> Identifiers;
 | 
						|
  auto DKind = ParseOpenMPDirectiveKind(*this);
 | 
						|
 | 
						|
  switch (DKind) {
 | 
						|
  case OMPD_threadprivate:
 | 
						|
    ConsumeToken();
 | 
						|
    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, StopBeforeMatch);
 | 
						|
      }
 | 
						|
      // Skip the last annot_pragma_openmp_end.
 | 
						|
      ConsumeToken();
 | 
						|
      return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case OMPD_unknown:
 | 
						|
    Diag(Tok, diag::err_omp_unknown_directive);
 | 
						|
    break;
 | 
						|
  case OMPD_parallel:
 | 
						|
  case OMPD_simd:
 | 
						|
  case OMPD_task:
 | 
						|
  case OMPD_taskyield:
 | 
						|
  case OMPD_barrier:
 | 
						|
  case OMPD_taskwait:
 | 
						|
  case OMPD_flush:
 | 
						|
  case OMPD_for:
 | 
						|
  case OMPD_sections:
 | 
						|
  case OMPD_section:
 | 
						|
  case OMPD_single:
 | 
						|
  case OMPD_master:
 | 
						|
  case OMPD_ordered:
 | 
						|
  case OMPD_critical:
 | 
						|
  case OMPD_parallel_for:
 | 
						|
  case OMPD_parallel_sections:
 | 
						|
  case OMPD_atomic:
 | 
						|
    Diag(Tok, diag::err_omp_unexpected_directive)
 | 
						|
        << getOpenMPDirectiveName(DKind);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  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
 | 
						|
///
 | 
						|
///       executable-directive:
 | 
						|
///         annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
 | 
						|
///         'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
 | 
						|
///         'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
 | 
						|
///         'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' {clause}
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
StmtResult
 | 
						|
Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
 | 
						|
  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>, OMPC_unknown + 1>
 | 
						|
  FirstClauses(OMPC_unknown + 1);
 | 
						|
  unsigned ScopeFlags =
 | 
						|
      Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
 | 
						|
  SourceLocation Loc = ConsumeToken(), EndLoc;
 | 
						|
  auto DKind = ParseOpenMPDirectiveKind(*this);
 | 
						|
  // Name of critical directive.
 | 
						|
  DeclarationNameInfo DirName;
 | 
						|
  StmtResult Directive = StmtError();
 | 
						|
  bool HasAssociatedStatement = true;
 | 
						|
  bool FlushHasClause = false;
 | 
						|
 | 
						|
  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_flush:
 | 
						|
    if (PP.LookAhead(0).is(tok::l_paren)) {
 | 
						|
      FlushHasClause = true;
 | 
						|
      // Push copy of the current token back to stream to properly parse
 | 
						|
      // pseudo-clause OMPFlushClause.
 | 
						|
      PP.EnterToken(Tok);
 | 
						|
    }
 | 
						|
  case OMPD_taskyield:
 | 
						|
  case OMPD_barrier:
 | 
						|
  case OMPD_taskwait:
 | 
						|
    if (!StandAloneAllowed) {
 | 
						|
      Diag(Tok, diag::err_omp_immediate_directive)
 | 
						|
          << getOpenMPDirectiveName(DKind);
 | 
						|
    }
 | 
						|
    HasAssociatedStatement = false;
 | 
						|
    // Fall through for further analysis.
 | 
						|
  case OMPD_parallel:
 | 
						|
  case OMPD_simd:
 | 
						|
  case OMPD_for:
 | 
						|
  case OMPD_sections:
 | 
						|
  case OMPD_single:
 | 
						|
  case OMPD_section:
 | 
						|
  case OMPD_master:
 | 
						|
  case OMPD_critical:
 | 
						|
  case OMPD_parallel_for:
 | 
						|
  case OMPD_parallel_sections:
 | 
						|
  case OMPD_task:
 | 
						|
  case OMPD_ordered:
 | 
						|
  case OMPD_atomic: {
 | 
						|
    ConsumeToken();
 | 
						|
    // Parse directive name of the 'critical' directive if any.
 | 
						|
    if (DKind == OMPD_critical) {
 | 
						|
      BalancedDelimiterTracker T(*this, tok::l_paren,
 | 
						|
                                 tok::annot_pragma_openmp_end);
 | 
						|
      if (!T.consumeOpen()) {
 | 
						|
        if (Tok.isAnyIdentifier()) {
 | 
						|
          DirName =
 | 
						|
              DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation());
 | 
						|
          ConsumeAnyToken();
 | 
						|
        } else {
 | 
						|
          Diag(Tok, diag::err_omp_expected_identifier_for_critical);
 | 
						|
        }
 | 
						|
        T.consumeClose();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (isOpenMPLoopDirective(DKind))
 | 
						|
      ScopeFlags |= Scope::OpenMPLoopDirectiveScope;
 | 
						|
    if (isOpenMPSimdDirective(DKind))
 | 
						|
      ScopeFlags |= Scope::OpenMPSimdDirectiveScope;
 | 
						|
    ParseScope OMPDirectiveScope(this, ScopeFlags);
 | 
						|
    Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);
 | 
						|
 | 
						|
    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
      OpenMPClauseKind CKind =
 | 
						|
          Tok.isAnnotation()
 | 
						|
              ? OMPC_unknown
 | 
						|
              : FlushHasClause ? OMPC_flush
 | 
						|
                               : getOpenMPClauseKind(PP.getSpelling(Tok));
 | 
						|
      FlushHasClause = false;
 | 
						|
      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;
 | 
						|
    if (HasAssociatedStatement) {
 | 
						|
      // The body is a block scope like in Lambdas and Blocks.
 | 
						|
      Sema::CompoundScopeRAII CompoundScope(Actions);
 | 
						|
      Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
 | 
						|
      Actions.ActOnStartOfCompoundStmt();
 | 
						|
      // Parse statement
 | 
						|
      AssociatedStmt = ParseStatement();
 | 
						|
      Actions.ActOnFinishOfCompoundStmt();
 | 
						|
      if (!AssociatedStmt.isUsable()) {
 | 
						|
        Actions.ActOnCapturedRegionError();
 | 
						|
        CreateDirective = false;
 | 
						|
      } else {
 | 
						|
        AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.get());
 | 
						|
        CreateDirective = AssociatedStmt.isUsable();
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (CreateDirective)
 | 
						|
      Directive = Actions.ActOnOpenMPExecutableDirective(
 | 
						|
          DKind, DirName, Clauses, AssociatedStmt.get(), 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;
 | 
						|
  }
 | 
						|
  return Directive;
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Parses list of simple variables for '#pragma omp threadprivate'
 | 
						|
/// directive.
 | 
						|
///
 | 
						|
///   simple-variable-list:
 | 
						|
///         '(' id-expression {, id-expression} ')'
 | 
						|
///
 | 
						|
bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
 | 
						|
                                      SmallVectorImpl<Expr *> &VarList,
 | 
						|
                                      bool AllowScopeSpecifier) {
 | 
						|
  VarList.clear();
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPDirectiveName(Kind)))
 | 
						|
    return true;
 | 
						|
  bool IsCorrect = true;
 | 
						|
  bool NoIdentIsFound = true;
 | 
						|
 | 
						|
  // Read tokens while ')' or annot_pragma_openmp_end is not found.
 | 
						|
  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 (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
 | 
						|
        ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
 | 
						|
      IsCorrect = false;
 | 
						|
      SkipUntil(tok::comma, tok::r_paren, 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,
 | 
						|
                StopBeforeMatch);
 | 
						|
      Diag(PrevTok.getLocation(), diag::err_expected)
 | 
						|
          << tok::identifier
 | 
						|
          << SourceRange(PrevTok.getLocation(), PrevTokLocation);
 | 
						|
    } else {
 | 
						|
      DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
 | 
						|
      ExprResult Res =
 | 
						|
          Actions.ActOnOpenMPIdExpression(getCurScope(), SS, NameInfo);
 | 
						|
      if (Res.isUsable())
 | 
						|
        VarList.push_back(Res.get());
 | 
						|
    }
 | 
						|
    // Consume ','.
 | 
						|
    if (Tok.is(tok::comma)) {
 | 
						|
      ConsumeToken();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (NoIdentIsFound) {
 | 
						|
    Diag(Tok, diag::err_expected) << tok::identifier;
 | 
						|
    IsCorrect = false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  IsCorrect = !T.consumeClose() && IsCorrect;
 | 
						|
 | 
						|
  return !IsCorrect && VarList.empty();
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Parsing of OpenMP clauses.
 | 
						|
///
 | 
						|
///    clause:
 | 
						|
///       if-clause | final-clause | num_threads-clause | safelen-clause |
 | 
						|
///       default-clause | private-clause | firstprivate-clause | shared-clause
 | 
						|
///       | linear-clause | aligned-clause | collapse-clause |
 | 
						|
///       lastprivate-clause | reduction-clause | proc_bind-clause |
 | 
						|
///       schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
 | 
						|
///       mergeable-clause | flush-clause | read-clause | write-clause |
 | 
						|
///       update-clause | capture-clause | seq_cst-clause
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
 | 
						|
                                     OpenMPClauseKind CKind, bool FirstClause) {
 | 
						|
  OMPClause *Clause = nullptr;
 | 
						|
  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;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (CKind) {
 | 
						|
  case OMPC_if:
 | 
						|
  case OMPC_final:
 | 
						|
  case OMPC_num_threads:
 | 
						|
  case OMPC_safelen:
 | 
						|
  case OMPC_collapse:
 | 
						|
    // OpenMP [2.5, Restrictions]
 | 
						|
    //  At most one if clause can appear on the directive.
 | 
						|
    //  At most one num_threads clause can appear on the directive.
 | 
						|
    // OpenMP [2.8.1, simd construct, Restrictions]
 | 
						|
    //  Only one safelen  clause can appear on a simd directive.
 | 
						|
    //  Only one collapse clause can appear on a simd directive.
 | 
						|
    // OpenMP [2.11.1, task Construct, Restrictions]
 | 
						|
    //  At most one if clause can appear on the directive.
 | 
						|
    //  At most one final clause can appear on the directive.
 | 
						|
    if (!FirstClause) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
 | 
						|
                                               << getOpenMPClauseName(CKind);
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
 | 
						|
    Clause = ParseOpenMPSingleExprClause(CKind);
 | 
						|
    break;
 | 
						|
  case OMPC_default:
 | 
						|
  case OMPC_proc_bind:
 | 
						|
    // OpenMP [2.14.3.1, Restrictions]
 | 
						|
    //  Only a single default clause may be specified on a parallel, task or
 | 
						|
    //  teams directive.
 | 
						|
    // OpenMP [2.5, parallel Construct, Restrictions]
 | 
						|
    //  At most one proc_bind clause can appear on the directive.
 | 
						|
    if (!FirstClause) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
 | 
						|
                                               << getOpenMPClauseName(CKind);
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
 | 
						|
    Clause = ParseOpenMPSimpleClause(CKind);
 | 
						|
    break;
 | 
						|
  case OMPC_schedule:
 | 
						|
    // OpenMP [2.7.1, Restrictions, p. 3]
 | 
						|
    //  Only one schedule clause can appear on a loop directive.
 | 
						|
    if (!FirstClause) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
 | 
						|
                                               << getOpenMPClauseName(CKind);
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
 | 
						|
    Clause = ParseOpenMPSingleExprWithArgClause(CKind);
 | 
						|
    break;
 | 
						|
  case OMPC_ordered:
 | 
						|
  case OMPC_nowait:
 | 
						|
  case OMPC_untied:
 | 
						|
  case OMPC_mergeable:
 | 
						|
  case OMPC_read:
 | 
						|
  case OMPC_write:
 | 
						|
  case OMPC_update:
 | 
						|
  case OMPC_capture:
 | 
						|
  case OMPC_seq_cst:
 | 
						|
    // OpenMP [2.7.1, Restrictions, p. 9]
 | 
						|
    //  Only one ordered clause can appear on a loop directive.
 | 
						|
    // OpenMP [2.7.1, Restrictions, C/C++, p. 4]
 | 
						|
    //  Only one nowait clause can appear on a for directive.
 | 
						|
    if (!FirstClause) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
 | 
						|
                                               << getOpenMPClauseName(CKind);
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
 | 
						|
    Clause = ParseOpenMPClause(CKind);
 | 
						|
    break;
 | 
						|
  case OMPC_private:
 | 
						|
  case OMPC_firstprivate:
 | 
						|
  case OMPC_lastprivate:
 | 
						|
  case OMPC_shared:
 | 
						|
  case OMPC_reduction:
 | 
						|
  case OMPC_linear:
 | 
						|
  case OMPC_aligned:
 | 
						|
  case OMPC_copyin:
 | 
						|
  case OMPC_copyprivate:
 | 
						|
  case OMPC_flush:
 | 
						|
    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:
 | 
						|
    Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
 | 
						|
                                               << getOpenMPDirectiveName(DKind);
 | 
						|
    SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  return ErrorFound ? nullptr : Clause;
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Parsing of OpenMP clauses with single expressions like 'if',
 | 
						|
/// 'final', 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams' or
 | 
						|
/// 'thread_limit'.
 | 
						|
///
 | 
						|
///    if-clause:
 | 
						|
///      'if' '(' expression ')'
 | 
						|
///
 | 
						|
///    final-clause:
 | 
						|
///      'final' '(' expression ')'
 | 
						|
///
 | 
						|
///    num_threads-clause:
 | 
						|
///      'num_threads' '(' expression ')'
 | 
						|
///
 | 
						|
///    safelen-clause:
 | 
						|
///      'safelen' '(' expression ')'
 | 
						|
///
 | 
						|
///    collapse-clause:
 | 
						|
///      'collapse' '(' expression ')'
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
 | 
						|
  SourceLocation Loc = ConsumeToken();
 | 
						|
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPClauseName(Kind)))
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
 | 
						|
  ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  T.consumeClose();
 | 
						|
 | 
						|
  if (Val.isInvalid())
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  return Actions.ActOnOpenMPSingleExprClause(
 | 
						|
      Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation());
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
 | 
						|
///
 | 
						|
///    default-clause:
 | 
						|
///         'default' '(' 'none' | 'shared' ')
 | 
						|
///
 | 
						|
///    proc_bind-clause:
 | 
						|
///         'proc_bind' '(' 'master' | 'close' | 'spread' ')
 | 
						|
///
 | 
						|
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 nullptr;
 | 
						|
 | 
						|
  unsigned Type = getOpenMPSimpleClauseType(
 | 
						|
      Kind, Tok.isAnnotation() ? "" : 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 clauses like 'ordered'.
 | 
						|
///
 | 
						|
///    ordered-clause:
 | 
						|
///         'ordered'
 | 
						|
///
 | 
						|
///    nowait-clause:
 | 
						|
///         'nowait'
 | 
						|
///
 | 
						|
///    untied-clause:
 | 
						|
///         'untied'
 | 
						|
///
 | 
						|
///    mergeable-clause:
 | 
						|
///         'mergeable'
 | 
						|
///
 | 
						|
///    read-clause:
 | 
						|
///         'read'
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) {
 | 
						|
  SourceLocation Loc = Tok.getLocation();
 | 
						|
  ConsumeAnyToken();
 | 
						|
 | 
						|
  return Actions.ActOnOpenMPClause(Kind, Loc, Tok.getLocation());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/// \brief Parsing of OpenMP clauses with single expressions and some additional
 | 
						|
/// argument like 'schedule' or 'dist_schedule'.
 | 
						|
///
 | 
						|
///    schedule-clause:
 | 
						|
///      'schedule' '(' kind [',' expression ] ')'
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) {
 | 
						|
  SourceLocation Loc = ConsumeToken();
 | 
						|
  SourceLocation CommaLoc;
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPClauseName(Kind)))
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  ExprResult Val;
 | 
						|
  unsigned Type = getOpenMPSimpleClauseType(
 | 
						|
      Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
 | 
						|
  SourceLocation KLoc = Tok.getLocation();
 | 
						|
  if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
 | 
						|
      Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
    ConsumeAnyToken();
 | 
						|
 | 
						|
  if (Kind == OMPC_schedule &&
 | 
						|
      (Type == OMPC_SCHEDULE_static || Type == OMPC_SCHEDULE_dynamic ||
 | 
						|
       Type == OMPC_SCHEDULE_guided) &&
 | 
						|
      Tok.is(tok::comma)) {
 | 
						|
    CommaLoc = ConsumeAnyToken();
 | 
						|
    ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
 | 
						|
    Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
 | 
						|
    if (Val.isInvalid())
 | 
						|
      return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  T.consumeClose();
 | 
						|
 | 
						|
  return Actions.ActOnOpenMPSingleExprWithArgClause(
 | 
						|
      Kind, Type, Val.get(), Loc, T.getOpenLocation(), KLoc, CommaLoc,
 | 
						|
      T.getCloseLocation());
 | 
						|
}
 | 
						|
 | 
						|
static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
 | 
						|
                             UnqualifiedId &ReductionId) {
 | 
						|
  SourceLocation TemplateKWLoc;
 | 
						|
  if (ReductionIdScopeSpec.isEmpty()) {
 | 
						|
    auto OOK = OO_None;
 | 
						|
    switch (P.getCurToken().getKind()) {
 | 
						|
    case tok::plus:
 | 
						|
      OOK = OO_Plus;
 | 
						|
      break;
 | 
						|
    case tok::minus:
 | 
						|
      OOK = OO_Minus;
 | 
						|
      break;
 | 
						|
    case tok::star:
 | 
						|
      OOK = OO_Star;
 | 
						|
      break;
 | 
						|
    case tok::amp:
 | 
						|
      OOK = OO_Amp;
 | 
						|
      break;
 | 
						|
    case tok::pipe:
 | 
						|
      OOK = OO_Pipe;
 | 
						|
      break;
 | 
						|
    case tok::caret:
 | 
						|
      OOK = OO_Caret;
 | 
						|
      break;
 | 
						|
    case tok::ampamp:
 | 
						|
      OOK = OO_AmpAmp;
 | 
						|
      break;
 | 
						|
    case tok::pipepipe:
 | 
						|
      OOK = OO_PipePipe;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if (OOK != OO_None) {
 | 
						|
      SourceLocation OpLoc = P.ConsumeToken();
 | 
						|
      SourceLocation SymbolLocations[] = {OpLoc, OpLoc, SourceLocation()};
 | 
						|
      ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
 | 
						|
                              /*AllowDestructorName*/ false,
 | 
						|
                              /*AllowConstructorName*/ false, ParsedType(),
 | 
						|
                              TemplateKWLoc, ReductionId);
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
 | 
						|
/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
 | 
						|
///
 | 
						|
///    private-clause:
 | 
						|
///       'private' '(' list ')'
 | 
						|
///    firstprivate-clause:
 | 
						|
///       'firstprivate' '(' list ')'
 | 
						|
///    lastprivate-clause:
 | 
						|
///       'lastprivate' '(' list ')'
 | 
						|
///    shared-clause:
 | 
						|
///       'shared' '(' list ')'
 | 
						|
///    linear-clause:
 | 
						|
///       'linear' '(' list [ ':' linear-step ] ')'
 | 
						|
///    aligned-clause:
 | 
						|
///       'aligned' '(' list [ ':' alignment ] ')'
 | 
						|
///    reduction-clause:
 | 
						|
///       'reduction' '(' reduction-identifier ':' list ')'
 | 
						|
///    copyprivate-clause:
 | 
						|
///       'copyprivate' '(' list ')'
 | 
						|
///    flush-clause:
 | 
						|
///       'flush' '(' list ')'
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
 | 
						|
  SourceLocation Loc = Tok.getLocation();
 | 
						|
  SourceLocation LOpen = ConsumeToken();
 | 
						|
  SourceLocation ColonLoc = SourceLocation();
 | 
						|
  // Optional scope specifier and unqualified id for reduction identifier.
 | 
						|
  CXXScopeSpec ReductionIdScopeSpec;
 | 
						|
  UnqualifiedId ReductionId;
 | 
						|
  bool InvalidReductionId = false;
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPClauseName(Kind)))
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  // Handle reduction-identifier for reduction clause.
 | 
						|
  if (Kind == OMPC_reduction) {
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this);
 | 
						|
    if (getLangOpts().CPlusPlus) {
 | 
						|
      ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false);
 | 
						|
    }
 | 
						|
    InvalidReductionId =
 | 
						|
        ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
 | 
						|
    if (InvalidReductionId) {
 | 
						|
      SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
    }
 | 
						|
    if (Tok.is(tok::colon)) {
 | 
						|
      ColonLoc = ConsumeToken();
 | 
						|
    } else {
 | 
						|
      Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  SmallVector<Expr *, 5> Vars;
 | 
						|
  bool IsComma = !InvalidReductionId;
 | 
						|
  const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
 | 
						|
  while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
 | 
						|
                     Tok.isNot(tok::annot_pragma_openmp_end))) {
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
 | 
						|
    // Parse variable
 | 
						|
    ExprResult VarExpr = ParseAssignmentExpression();
 | 
						|
    if (VarExpr.isUsable()) {
 | 
						|
      Vars.push_back(VarExpr.get());
 | 
						|
    } 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) &&
 | 
						|
             (!MayHaveTail || Tok.isNot(tok::colon)))
 | 
						|
      Diag(Tok, diag::err_omp_expected_punc)
 | 
						|
          << ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush)
 | 
						|
                                   : getOpenMPClauseName(Kind))
 | 
						|
          << (Kind == OMPC_flush);
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse ':' linear-step (or ':' alignment).
 | 
						|
  Expr *TailExpr = nullptr;
 | 
						|
  const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
 | 
						|
  if (MustHaveTail) {
 | 
						|
    ColonLoc = Tok.getLocation();
 | 
						|
    ConsumeToken();
 | 
						|
    ExprResult Tail = ParseAssignmentExpression();
 | 
						|
    if (Tail.isUsable())
 | 
						|
      TailExpr = Tail.get();
 | 
						|
    else
 | 
						|
      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  T.consumeClose();
 | 
						|
  if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId)
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  return Actions.ActOnOpenMPVarListClause(
 | 
						|
      Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
 | 
						|
      ReductionIdScopeSpec,
 | 
						|
      ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
 | 
						|
                            : DeclarationNameInfo());
 | 
						|
}
 | 
						|
 |