forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			3631 lines
		
	
	
		
			132 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			3631 lines
		
	
	
		
			132 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
/// \file
 | 
						|
/// This file implements parsing of all OpenMP directives and clauses.
 | 
						|
///
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "clang/AST/ASTContext.h"
 | 
						|
#include "clang/AST/OpenMPClause.h"
 | 
						|
#include "clang/AST/StmtOpenMP.h"
 | 
						|
#include "clang/Basic/OpenMPKinds.h"
 | 
						|
#include "clang/Basic/TargetInfo.h"
 | 
						|
#include "clang/Basic/TokenKinds.h"
 | 
						|
#include "clang/Parse/ParseDiagnostic.h"
 | 
						|
#include "clang/Parse/Parser.h"
 | 
						|
#include "clang/Parse/RAIIObjectsForParser.h"
 | 
						|
#include "clang/Sema/Scope.h"
 | 
						|
#include "llvm/ADT/PointerIntPair.h"
 | 
						|
#include "llvm/ADT/UniqueVector.h"
 | 
						|
#include "llvm/Frontend/OpenMP/OMPContext.h"
 | 
						|
 | 
						|
using namespace clang;
 | 
						|
using namespace llvm::omp;
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// OpenMP declarative directives.
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
namespace {
 | 
						|
enum OpenMPDirectiveKindEx {
 | 
						|
  OMPD_cancellation = llvm::omp::Directive_enumSize + 1,
 | 
						|
  OMPD_data,
 | 
						|
  OMPD_declare,
 | 
						|
  OMPD_end,
 | 
						|
  OMPD_end_declare,
 | 
						|
  OMPD_enter,
 | 
						|
  OMPD_exit,
 | 
						|
  OMPD_point,
 | 
						|
  OMPD_reduction,
 | 
						|
  OMPD_target_enter,
 | 
						|
  OMPD_target_exit,
 | 
						|
  OMPD_update,
 | 
						|
  OMPD_distribute_parallel,
 | 
						|
  OMPD_teams_distribute_parallel,
 | 
						|
  OMPD_target_teams_distribute_parallel,
 | 
						|
  OMPD_mapper,
 | 
						|
  OMPD_variant,
 | 
						|
  OMPD_begin,
 | 
						|
  OMPD_begin_declare,
 | 
						|
};
 | 
						|
 | 
						|
// Helper to unify the enum class OpenMPDirectiveKind with its extension
 | 
						|
// the OpenMPDirectiveKindEx enum which allows to use them together as if they
 | 
						|
// are unsigned values.
 | 
						|
struct OpenMPDirectiveKindExWrapper {
 | 
						|
  OpenMPDirectiveKindExWrapper(unsigned Value) : Value(Value) {}
 | 
						|
  OpenMPDirectiveKindExWrapper(OpenMPDirectiveKind DK) : Value(unsigned(DK)) {}
 | 
						|
  bool operator==(OpenMPDirectiveKind V) const { return Value == unsigned(V); }
 | 
						|
  bool operator!=(OpenMPDirectiveKind V) const { return Value != unsigned(V); }
 | 
						|
  bool operator<(OpenMPDirectiveKind V) const { return Value < unsigned(V); }
 | 
						|
  operator unsigned() const { return Value; }
 | 
						|
  operator OpenMPDirectiveKind() const { return OpenMPDirectiveKind(Value); }
 | 
						|
  unsigned Value;
 | 
						|
};
 | 
						|
 | 
						|
class DeclDirectiveListParserHelper final {
 | 
						|
  SmallVector<Expr *, 4> Identifiers;
 | 
						|
  Parser *P;
 | 
						|
  OpenMPDirectiveKind Kind;
 | 
						|
 | 
						|
public:
 | 
						|
  DeclDirectiveListParserHelper(Parser *P, OpenMPDirectiveKind Kind)
 | 
						|
      : P(P), Kind(Kind) {}
 | 
						|
  void operator()(CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {
 | 
						|
    ExprResult Res = P->getActions().ActOnOpenMPIdExpression(
 | 
						|
        P->getCurScope(), SS, NameInfo, Kind);
 | 
						|
    if (Res.isUsable())
 | 
						|
      Identifiers.push_back(Res.get());
 | 
						|
  }
 | 
						|
  llvm::ArrayRef<Expr *> getIdentifiers() const { return Identifiers; }
 | 
						|
};
 | 
						|
} // namespace
 | 
						|
 | 
						|
// Map token string to extended OMP token kind that are
 | 
						|
// OpenMPDirectiveKind + OpenMPDirectiveKindEx.
 | 
						|
static unsigned getOpenMPDirectiveKindEx(StringRef S) {
 | 
						|
  OpenMPDirectiveKindExWrapper DKind = getOpenMPDirectiveKind(S);
 | 
						|
  if (DKind != OMPD_unknown)
 | 
						|
    return DKind;
 | 
						|
 | 
						|
  return llvm::StringSwitch<OpenMPDirectiveKindExWrapper>(S)
 | 
						|
      .Case("cancellation", OMPD_cancellation)
 | 
						|
      .Case("data", OMPD_data)
 | 
						|
      .Case("declare", OMPD_declare)
 | 
						|
      .Case("end", OMPD_end)
 | 
						|
      .Case("enter", OMPD_enter)
 | 
						|
      .Case("exit", OMPD_exit)
 | 
						|
      .Case("point", OMPD_point)
 | 
						|
      .Case("reduction", OMPD_reduction)
 | 
						|
      .Case("update", OMPD_update)
 | 
						|
      .Case("mapper", OMPD_mapper)
 | 
						|
      .Case("variant", OMPD_variant)
 | 
						|
      .Case("begin", OMPD_begin)
 | 
						|
      .Default(OMPD_unknown);
 | 
						|
}
 | 
						|
 | 
						|
static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) {
 | 
						|
  // Array of foldings: F[i][0] F[i][1] ===> F[i][2].
 | 
						|
  // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
 | 
						|
  // TODO: add other combined directives in topological order.
 | 
						|
  static const OpenMPDirectiveKindExWrapper F[][3] = {
 | 
						|
      {OMPD_begin, OMPD_declare, OMPD_begin_declare},
 | 
						|
      {OMPD_end, OMPD_declare, OMPD_end_declare},
 | 
						|
      {OMPD_cancellation, OMPD_point, OMPD_cancellation_point},
 | 
						|
      {OMPD_declare, OMPD_reduction, OMPD_declare_reduction},
 | 
						|
      {OMPD_declare, OMPD_mapper, OMPD_declare_mapper},
 | 
						|
      {OMPD_declare, OMPD_simd, OMPD_declare_simd},
 | 
						|
      {OMPD_declare, OMPD_target, OMPD_declare_target},
 | 
						|
      {OMPD_declare, OMPD_variant, OMPD_declare_variant},
 | 
						|
      {OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant},
 | 
						|
      {OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant},
 | 
						|
      {OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel},
 | 
						|
      {OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for},
 | 
						|
      {OMPD_distribute_parallel_for, OMPD_simd,
 | 
						|
       OMPD_distribute_parallel_for_simd},
 | 
						|
      {OMPD_distribute, OMPD_simd, OMPD_distribute_simd},
 | 
						|
      {OMPD_end_declare, OMPD_target, OMPD_end_declare_target},
 | 
						|
      {OMPD_target, OMPD_data, OMPD_target_data},
 | 
						|
      {OMPD_target, OMPD_enter, OMPD_target_enter},
 | 
						|
      {OMPD_target, OMPD_exit, OMPD_target_exit},
 | 
						|
      {OMPD_target, OMPD_update, OMPD_target_update},
 | 
						|
      {OMPD_target_enter, OMPD_data, OMPD_target_enter_data},
 | 
						|
      {OMPD_target_exit, OMPD_data, OMPD_target_exit_data},
 | 
						|
      {OMPD_for, OMPD_simd, OMPD_for_simd},
 | 
						|
      {OMPD_parallel, OMPD_for, OMPD_parallel_for},
 | 
						|
      {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd},
 | 
						|
      {OMPD_parallel, OMPD_sections, OMPD_parallel_sections},
 | 
						|
      {OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd},
 | 
						|
      {OMPD_target, OMPD_parallel, OMPD_target_parallel},
 | 
						|
      {OMPD_target, OMPD_simd, OMPD_target_simd},
 | 
						|
      {OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for},
 | 
						|
      {OMPD_target_parallel_for, OMPD_simd, OMPD_target_parallel_for_simd},
 | 
						|
      {OMPD_teams, OMPD_distribute, OMPD_teams_distribute},
 | 
						|
      {OMPD_teams_distribute, OMPD_simd, OMPD_teams_distribute_simd},
 | 
						|
      {OMPD_teams_distribute, OMPD_parallel, OMPD_teams_distribute_parallel},
 | 
						|
      {OMPD_teams_distribute_parallel, OMPD_for,
 | 
						|
       OMPD_teams_distribute_parallel_for},
 | 
						|
      {OMPD_teams_distribute_parallel_for, OMPD_simd,
 | 
						|
       OMPD_teams_distribute_parallel_for_simd},
 | 
						|
      {OMPD_target, OMPD_teams, OMPD_target_teams},
 | 
						|
      {OMPD_target_teams, OMPD_distribute, OMPD_target_teams_distribute},
 | 
						|
      {OMPD_target_teams_distribute, OMPD_parallel,
 | 
						|
       OMPD_target_teams_distribute_parallel},
 | 
						|
      {OMPD_target_teams_distribute, OMPD_simd,
 | 
						|
       OMPD_target_teams_distribute_simd},
 | 
						|
      {OMPD_target_teams_distribute_parallel, OMPD_for,
 | 
						|
       OMPD_target_teams_distribute_parallel_for},
 | 
						|
      {OMPD_target_teams_distribute_parallel_for, OMPD_simd,
 | 
						|
       OMPD_target_teams_distribute_parallel_for_simd},
 | 
						|
      {OMPD_master, OMPD_taskloop, OMPD_master_taskloop},
 | 
						|
      {OMPD_master_taskloop, OMPD_simd, OMPD_master_taskloop_simd},
 | 
						|
      {OMPD_parallel, OMPD_master, OMPD_parallel_master},
 | 
						|
      {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop},
 | 
						|
      {OMPD_parallel_master_taskloop, OMPD_simd,
 | 
						|
       OMPD_parallel_master_taskloop_simd}};
 | 
						|
  enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 };
 | 
						|
  Token Tok = P.getCurToken();
 | 
						|
  OpenMPDirectiveKindExWrapper DKind =
 | 
						|
      Tok.isAnnotation()
 | 
						|
          ? static_cast<unsigned>(OMPD_unknown)
 | 
						|
          : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));
 | 
						|
  if (DKind == OMPD_unknown)
 | 
						|
    return OMPD_unknown;
 | 
						|
 | 
						|
  for (unsigned I = 0; I < llvm::array_lengthof(F); ++I) {
 | 
						|
    if (DKind != F[I][0])
 | 
						|
      continue;
 | 
						|
 | 
						|
    Tok = P.getPreprocessor().LookAhead(0);
 | 
						|
    OpenMPDirectiveKindExWrapper SDKind =
 | 
						|
        Tok.isAnnotation()
 | 
						|
            ? static_cast<unsigned>(OMPD_unknown)
 | 
						|
            : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));
 | 
						|
    if (SDKind == OMPD_unknown)
 | 
						|
      continue;
 | 
						|
 | 
						|
    if (SDKind == F[I][1]) {
 | 
						|
      P.ConsumeToken();
 | 
						|
      DKind = F[I][2];
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return unsigned(DKind) < llvm::omp::Directive_enumSize
 | 
						|
             ? static_cast<OpenMPDirectiveKind>(DKind)
 | 
						|
             : OMPD_unknown;
 | 
						|
}
 | 
						|
 | 
						|
static DeclarationName parseOpenMPReductionId(Parser &P) {
 | 
						|
  Token Tok = P.getCurToken();
 | 
						|
  Sema &Actions = P.getActions();
 | 
						|
  OverloadedOperatorKind OOK = OO_None;
 | 
						|
  // Allow to use 'operator' keyword for C++ operators
 | 
						|
  bool WithOperator = false;
 | 
						|
  if (Tok.is(tok::kw_operator)) {
 | 
						|
    P.ConsumeToken();
 | 
						|
    Tok = P.getCurToken();
 | 
						|
    WithOperator = true;
 | 
						|
  }
 | 
						|
  switch (Tok.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;
 | 
						|
  case tok::identifier: // identifier
 | 
						|
    if (!WithOperator)
 | 
						|
      break;
 | 
						|
    LLVM_FALLTHROUGH;
 | 
						|
  default:
 | 
						|
    P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier);
 | 
						|
    P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                Parser::StopBeforeMatch);
 | 
						|
    return DeclarationName();
 | 
						|
  }
 | 
						|
  P.ConsumeToken();
 | 
						|
  auto &DeclNames = Actions.getASTContext().DeclarationNames;
 | 
						|
  return OOK == OO_None ? DeclNames.getIdentifier(Tok.getIdentifierInfo())
 | 
						|
                        : DeclNames.getCXXOperatorName(OOK);
 | 
						|
}
 | 
						|
 | 
						|
/// Parse 'omp declare reduction' construct.
 | 
						|
///
 | 
						|
///       declare-reduction-directive:
 | 
						|
///        annot_pragma_openmp 'declare' 'reduction'
 | 
						|
///        '(' <reduction_id> ':' <type> {',' <type>} ':' <expression> ')'
 | 
						|
///        ['initializer' '(' ('omp_priv' '=' <expression>)|<function_call> ')']
 | 
						|
///        annot_pragma_openmp_end
 | 
						|
/// <reduction_id> is either a base language identifier or one of the following
 | 
						|
/// operators: '+', '-', '*', '&', '|', '^', '&&' and '||'.
 | 
						|
///
 | 
						|
Parser::DeclGroupPtrTy
 | 
						|
Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(
 | 
						|
          diag::err_expected_lparen_after,
 | 
						|
          getOpenMPDirectiveName(OMPD_declare_reduction).data())) {
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
  }
 | 
						|
 | 
						|
  DeclarationName Name = parseOpenMPReductionId(*this);
 | 
						|
  if (Name.isEmpty() && Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
 | 
						|
  // Consume ':'.
 | 
						|
  bool IsCorrect = !ExpectAndConsume(tok::colon);
 | 
						|
 | 
						|
  if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
 | 
						|
  IsCorrect = IsCorrect && !Name.isEmpty();
 | 
						|
 | 
						|
  if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) {
 | 
						|
    Diag(Tok.getLocation(), diag::err_expected_type);
 | 
						|
    IsCorrect = false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
 | 
						|
  SmallVector<std::pair<QualType, SourceLocation>, 8> ReductionTypes;
 | 
						|
  // Parse list of types until ':' token.
 | 
						|
  do {
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this);
 | 
						|
    SourceRange Range;
 | 
						|
    TypeResult TR =
 | 
						|
        ParseTypeName(&Range, DeclaratorContext::PrototypeContext, AS);
 | 
						|
    if (TR.isUsable()) {
 | 
						|
      QualType ReductionType =
 | 
						|
          Actions.ActOnOpenMPDeclareReductionType(Range.getBegin(), TR);
 | 
						|
      if (!ReductionType.isNull()) {
 | 
						|
        ReductionTypes.push_back(
 | 
						|
            std::make_pair(ReductionType, Range.getBegin()));
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
    }
 | 
						|
 | 
						|
    if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
      break;
 | 
						|
 | 
						|
    // Consume ','.
 | 
						|
    if (ExpectAndConsume(tok::comma)) {
 | 
						|
      IsCorrect = false;
 | 
						|
      if (Tok.is(tok::annot_pragma_openmp_end)) {
 | 
						|
        Diag(Tok.getLocation(), diag::err_expected_type);
 | 
						|
        return DeclGroupPtrTy();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } while (Tok.isNot(tok::annot_pragma_openmp_end));
 | 
						|
 | 
						|
  if (ReductionTypes.empty()) {
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
 | 
						|
  // Consume ':'.
 | 
						|
  if (ExpectAndConsume(tok::colon))
 | 
						|
    IsCorrect = false;
 | 
						|
 | 
						|
  if (Tok.is(tok::annot_pragma_openmp_end)) {
 | 
						|
    Diag(Tok.getLocation(), diag::err_expected_expression);
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
  }
 | 
						|
 | 
						|
  DeclGroupPtrTy DRD = Actions.ActOnOpenMPDeclareReductionDirectiveStart(
 | 
						|
      getCurScope(), Actions.getCurLexicalContext(), Name, ReductionTypes, AS);
 | 
						|
 | 
						|
  // Parse <combiner> expression and then parse initializer if any for each
 | 
						|
  // correct type.
 | 
						|
  unsigned I = 0, E = ReductionTypes.size();
 | 
						|
  for (Decl *D : DRD.get()) {
 | 
						|
    TentativeParsingAction TPA(*this);
 | 
						|
    ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
 | 
						|
                                    Scope::CompoundStmtScope |
 | 
						|
                                    Scope::OpenMPDirectiveScope);
 | 
						|
    // Parse <combiner> expression.
 | 
						|
    Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D);
 | 
						|
    ExprResult CombinerResult = Actions.ActOnFinishFullExpr(
 | 
						|
        ParseExpression().get(), D->getLocation(), /*DiscardedValue*/ false);
 | 
						|
    Actions.ActOnOpenMPDeclareReductionCombinerEnd(D, CombinerResult.get());
 | 
						|
 | 
						|
    if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) &&
 | 
						|
        Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
      TPA.Commit();
 | 
						|
      IsCorrect = false;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    IsCorrect = !T.consumeClose() && IsCorrect && CombinerResult.isUsable();
 | 
						|
    ExprResult InitializerResult;
 | 
						|
    if (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
      // Parse <initializer> expression.
 | 
						|
      if (Tok.is(tok::identifier) &&
 | 
						|
          Tok.getIdentifierInfo()->isStr("initializer")) {
 | 
						|
        ConsumeToken();
 | 
						|
      } else {
 | 
						|
        Diag(Tok.getLocation(), diag::err_expected) << "'initializer'";
 | 
						|
        TPA.Commit();
 | 
						|
        IsCorrect = false;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      // Parse '('.
 | 
						|
      BalancedDelimiterTracker T(*this, tok::l_paren,
 | 
						|
                                 tok::annot_pragma_openmp_end);
 | 
						|
      IsCorrect =
 | 
						|
          !T.expectAndConsume(diag::err_expected_lparen_after, "initializer") &&
 | 
						|
          IsCorrect;
 | 
						|
      if (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
        ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
 | 
						|
                                        Scope::CompoundStmtScope |
 | 
						|
                                        Scope::OpenMPDirectiveScope);
 | 
						|
        // Parse expression.
 | 
						|
        VarDecl *OmpPrivParm =
 | 
						|
            Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(),
 | 
						|
                                                                D);
 | 
						|
        // Check if initializer is omp_priv <init_expr> or something else.
 | 
						|
        if (Tok.is(tok::identifier) &&
 | 
						|
            Tok.getIdentifierInfo()->isStr("omp_priv")) {
 | 
						|
          ConsumeToken();
 | 
						|
          ParseOpenMPReductionInitializerForDecl(OmpPrivParm);
 | 
						|
        } else {
 | 
						|
          InitializerResult = Actions.ActOnFinishFullExpr(
 | 
						|
              ParseAssignmentExpression().get(), D->getLocation(),
 | 
						|
              /*DiscardedValue*/ false);
 | 
						|
        }
 | 
						|
        Actions.ActOnOpenMPDeclareReductionInitializerEnd(
 | 
						|
            D, InitializerResult.get(), OmpPrivParm);
 | 
						|
        if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) &&
 | 
						|
            Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
          TPA.Commit();
 | 
						|
          IsCorrect = false;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        IsCorrect =
 | 
						|
            !T.consumeClose() && IsCorrect && !InitializerResult.isInvalid();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    ++I;
 | 
						|
    // Revert parsing if not the last type, otherwise accept it, we're done with
 | 
						|
    // parsing.
 | 
						|
    if (I != E)
 | 
						|
      TPA.Revert();
 | 
						|
    else
 | 
						|
      TPA.Commit();
 | 
						|
  }
 | 
						|
  return Actions.ActOnOpenMPDeclareReductionDirectiveEnd(getCurScope(), DRD,
 | 
						|
                                                         IsCorrect);
 | 
						|
}
 | 
						|
 | 
						|
void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
 | 
						|
  // Parse declarator '=' initializer.
 | 
						|
  // If a '==' or '+=' is found, suggest a fixit to '='.
 | 
						|
  if (isTokenEqualOrEqualTypo()) {
 | 
						|
    ConsumeToken();
 | 
						|
 | 
						|
    if (Tok.is(tok::code_completion)) {
 | 
						|
      Actions.CodeCompleteInitializer(getCurScope(), OmpPrivParm);
 | 
						|
      Actions.FinalizeDeclaration(OmpPrivParm);
 | 
						|
      cutOffParsing();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    PreferredType.enterVariableInit(Tok.getLocation(), OmpPrivParm);
 | 
						|
    ExprResult Init = ParseInitializer();
 | 
						|
 | 
						|
    if (Init.isInvalid()) {
 | 
						|
      SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
      Actions.ActOnInitializerError(OmpPrivParm);
 | 
						|
    } else {
 | 
						|
      Actions.AddInitializerToDecl(OmpPrivParm, Init.get(),
 | 
						|
                                   /*DirectInit=*/false);
 | 
						|
    }
 | 
						|
  } else if (Tok.is(tok::l_paren)) {
 | 
						|
    // Parse C++ direct initializer: '(' expression-list ')'
 | 
						|
    BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
    T.consumeOpen();
 | 
						|
 | 
						|
    ExprVector Exprs;
 | 
						|
    CommaLocsTy CommaLocs;
 | 
						|
 | 
						|
    SourceLocation LParLoc = T.getOpenLocation();
 | 
						|
    auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() {
 | 
						|
      QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
 | 
						|
          getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(),
 | 
						|
          OmpPrivParm->getLocation(), Exprs, LParLoc);
 | 
						|
      CalledSignatureHelp = true;
 | 
						|
      return PreferredType;
 | 
						|
    };
 | 
						|
    if (ParseExpressionList(Exprs, CommaLocs, [&] {
 | 
						|
          PreferredType.enterFunctionArgument(Tok.getLocation(),
 | 
						|
                                              RunSignatureHelp);
 | 
						|
        })) {
 | 
						|
      if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
 | 
						|
        RunSignatureHelp();
 | 
						|
      Actions.ActOnInitializerError(OmpPrivParm);
 | 
						|
      SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
    } else {
 | 
						|
      // Match the ')'.
 | 
						|
      SourceLocation RLoc = Tok.getLocation();
 | 
						|
      if (!T.consumeClose())
 | 
						|
        RLoc = T.getCloseLocation();
 | 
						|
 | 
						|
      assert(!Exprs.empty() && Exprs.size() - 1 == CommaLocs.size() &&
 | 
						|
             "Unexpected number of commas!");
 | 
						|
 | 
						|
      ExprResult Initializer =
 | 
						|
          Actions.ActOnParenListExpr(T.getOpenLocation(), RLoc, Exprs);
 | 
						|
      Actions.AddInitializerToDecl(OmpPrivParm, Initializer.get(),
 | 
						|
                                   /*DirectInit=*/true);
 | 
						|
    }
 | 
						|
  } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
 | 
						|
    // Parse C++0x braced-init-list.
 | 
						|
    Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
 | 
						|
 | 
						|
    ExprResult Init(ParseBraceInitializer());
 | 
						|
 | 
						|
    if (Init.isInvalid()) {
 | 
						|
      Actions.ActOnInitializerError(OmpPrivParm);
 | 
						|
    } else {
 | 
						|
      Actions.AddInitializerToDecl(OmpPrivParm, Init.get(),
 | 
						|
                                   /*DirectInit=*/true);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Actions.ActOnUninitializedDecl(OmpPrivParm);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// Parses 'omp declare mapper' directive.
 | 
						|
///
 | 
						|
///       declare-mapper-directive:
 | 
						|
///         annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifier> ':']
 | 
						|
///         <type> <var> ')' [<clause>[[,] <clause>] ... ]
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
/// <mapper-identifier> and <var> are base language identifiers.
 | 
						|
///
 | 
						|
Parser::DeclGroupPtrTy
 | 
						|
Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) {
 | 
						|
  bool IsCorrect = true;
 | 
						|
  // Parse '('
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPDirectiveName(OMPD_declare_mapper).data())) {
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse <mapper-identifier>
 | 
						|
  auto &DeclNames = Actions.getASTContext().DeclarationNames;
 | 
						|
  DeclarationName MapperId;
 | 
						|
  if (PP.LookAhead(0).is(tok::colon)) {
 | 
						|
    if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) {
 | 
						|
      Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier);
 | 
						|
      IsCorrect = false;
 | 
						|
    } else {
 | 
						|
      MapperId = DeclNames.getIdentifier(Tok.getIdentifierInfo());
 | 
						|
    }
 | 
						|
    ConsumeToken();
 | 
						|
    // Consume ':'.
 | 
						|
    ExpectAndConsume(tok::colon);
 | 
						|
  } else {
 | 
						|
    // If no mapper identifier is provided, its name is "default" by default
 | 
						|
    MapperId =
 | 
						|
        DeclNames.getIdentifier(&Actions.getASTContext().Idents.get("default"));
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
 | 
						|
  // Parse <type> <var>
 | 
						|
  DeclarationName VName;
 | 
						|
  QualType MapperType;
 | 
						|
  SourceRange Range;
 | 
						|
  TypeResult ParsedType = parseOpenMPDeclareMapperVarDecl(Range, VName, AS);
 | 
						|
  if (ParsedType.isUsable())
 | 
						|
    MapperType =
 | 
						|
        Actions.ActOnOpenMPDeclareMapperType(Range.getBegin(), ParsedType);
 | 
						|
  if (MapperType.isNull())
 | 
						|
    IsCorrect = false;
 | 
						|
  if (!IsCorrect) {
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch);
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
  }
 | 
						|
 | 
						|
  // Consume ')'.
 | 
						|
  IsCorrect &= !T.consumeClose();
 | 
						|
  if (!IsCorrect) {
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch);
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
  }
 | 
						|
 | 
						|
  // Enter scope.
 | 
						|
  OMPDeclareMapperDecl *DMD = Actions.ActOnOpenMPDeclareMapperDirectiveStart(
 | 
						|
      getCurScope(), Actions.getCurLexicalContext(), MapperId, MapperType,
 | 
						|
      Range.getBegin(), VName, AS);
 | 
						|
  DeclarationNameInfo DirName;
 | 
						|
  SourceLocation Loc = Tok.getLocation();
 | 
						|
  unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
 | 
						|
                        Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
 | 
						|
  ParseScope OMPDirectiveScope(this, ScopeFlags);
 | 
						|
  Actions.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, getCurScope(), Loc);
 | 
						|
 | 
						|
  // Add the mapper variable declaration.
 | 
						|
  Actions.ActOnOpenMPDeclareMapperDirectiveVarDecl(
 | 
						|
      DMD, getCurScope(), MapperType, Range.getBegin(), VName);
 | 
						|
 | 
						|
  // Parse map clauses.
 | 
						|
  SmallVector<OMPClause *, 6> Clauses;
 | 
						|
  while (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
    OpenMPClauseKind CKind = Tok.isAnnotation()
 | 
						|
                                 ? OMPC_unknown
 | 
						|
                                 : getOpenMPClauseKind(PP.getSpelling(Tok));
 | 
						|
    Actions.StartOpenMPClause(CKind);
 | 
						|
    OMPClause *Clause =
 | 
						|
        ParseOpenMPClause(OMPD_declare_mapper, CKind, Clauses.size() == 0);
 | 
						|
    if (Clause)
 | 
						|
      Clauses.push_back(Clause);
 | 
						|
    else
 | 
						|
      IsCorrect = false;
 | 
						|
    // Skip ',' if any.
 | 
						|
    if (Tok.is(tok::comma))
 | 
						|
      ConsumeToken();
 | 
						|
    Actions.EndOpenMPClause();
 | 
						|
  }
 | 
						|
  if (Clauses.empty()) {
 | 
						|
    Diag(Tok, diag::err_omp_expected_clause)
 | 
						|
        << getOpenMPDirectiveName(OMPD_declare_mapper);
 | 
						|
    IsCorrect = false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Exit scope.
 | 
						|
  Actions.EndOpenMPDSABlock(nullptr);
 | 
						|
  OMPDirectiveScope.Exit();
 | 
						|
 | 
						|
  DeclGroupPtrTy DGP =
 | 
						|
      Actions.ActOnOpenMPDeclareMapperDirectiveEnd(DMD, getCurScope(), Clauses);
 | 
						|
  if (!IsCorrect)
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
  return DGP;
 | 
						|
}
 | 
						|
 | 
						|
TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range,
 | 
						|
                                                   DeclarationName &Name,
 | 
						|
                                                   AccessSpecifier AS) {
 | 
						|
  // Parse the common declaration-specifiers piece.
 | 
						|
  Parser::DeclSpecContext DSC = Parser::DeclSpecContext::DSC_type_specifier;
 | 
						|
  DeclSpec DS(AttrFactory);
 | 
						|
  ParseSpecifierQualifierList(DS, AS, DSC);
 | 
						|
 | 
						|
  // Parse the declarator.
 | 
						|
  DeclaratorContext Context = DeclaratorContext::PrototypeContext;
 | 
						|
  Declarator DeclaratorInfo(DS, Context);
 | 
						|
  ParseDeclarator(DeclaratorInfo);
 | 
						|
  Range = DeclaratorInfo.getSourceRange();
 | 
						|
  if (DeclaratorInfo.getIdentifier() == nullptr) {
 | 
						|
    Diag(Tok.getLocation(), diag::err_omp_mapper_expected_declarator);
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  Name = Actions.GetNameForDeclarator(DeclaratorInfo).getName();
 | 
						|
 | 
						|
  return Actions.ActOnOpenMPDeclareMapperVarDecl(getCurScope(), DeclaratorInfo);
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
/// RAII that recreates function context for correct parsing of clauses of
 | 
						|
/// 'declare simd' construct.
 | 
						|
/// OpenMP, 2.8.2 declare simd Construct
 | 
						|
/// The expressions appearing in the clauses of this directive are evaluated in
 | 
						|
/// the scope of the arguments of the function declaration or definition.
 | 
						|
class FNContextRAII final {
 | 
						|
  Parser &P;
 | 
						|
  Sema::CXXThisScopeRAII *ThisScope;
 | 
						|
  Parser::MultiParseScope Scopes;
 | 
						|
  bool HasFunScope = false;
 | 
						|
  FNContextRAII() = delete;
 | 
						|
  FNContextRAII(const FNContextRAII &) = delete;
 | 
						|
  FNContextRAII &operator=(const FNContextRAII &) = delete;
 | 
						|
 | 
						|
public:
 | 
						|
  FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P), Scopes(P) {
 | 
						|
    Decl *D = *Ptr.get().begin();
 | 
						|
    NamedDecl *ND = dyn_cast<NamedDecl>(D);
 | 
						|
    RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
 | 
						|
    Sema &Actions = P.getActions();
 | 
						|
 | 
						|
    // Allow 'this' within late-parsed attributes.
 | 
						|
    ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, Qualifiers(),
 | 
						|
                                           ND && ND->isCXXInstanceMember());
 | 
						|
 | 
						|
    // If the Decl is templatized, add template parameters to scope.
 | 
						|
    // FIXME: Track CurTemplateDepth?
 | 
						|
    P.ReenterTemplateScopes(Scopes, D);
 | 
						|
 | 
						|
    // If the Decl is on a function, add function parameters to the scope.
 | 
						|
    if (D->isFunctionOrFunctionTemplate()) {
 | 
						|
      HasFunScope = true;
 | 
						|
      Scopes.Enter(Scope::FnScope | Scope::DeclScope |
 | 
						|
                   Scope::CompoundStmtScope);
 | 
						|
      Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  ~FNContextRAII() {
 | 
						|
    if (HasFunScope)
 | 
						|
      P.getActions().ActOnExitFunctionContext();
 | 
						|
    delete ThisScope;
 | 
						|
  }
 | 
						|
};
 | 
						|
} // namespace
 | 
						|
 | 
						|
/// Parses clauses for 'declare simd' directive.
 | 
						|
///    clause:
 | 
						|
///      'inbranch' | 'notinbranch'
 | 
						|
///      'simdlen' '(' <expr> ')'
 | 
						|
///      { 'uniform' '(' <argument_list> ')' }
 | 
						|
///      { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' }
 | 
						|
///      { 'linear '(' <argument_list> [ ':' <step> ] ')' }
 | 
						|
static bool parseDeclareSimdClauses(
 | 
						|
    Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen,
 | 
						|
    SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds,
 | 
						|
    SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears,
 | 
						|
    SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) {
 | 
						|
  SourceRange BSRange;
 | 
						|
  const Token &Tok = P.getCurToken();
 | 
						|
  bool IsError = false;
 | 
						|
  while (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
    if (Tok.isNot(tok::identifier))
 | 
						|
      break;
 | 
						|
    OMPDeclareSimdDeclAttr::BranchStateTy Out;
 | 
						|
    IdentifierInfo *II = Tok.getIdentifierInfo();
 | 
						|
    StringRef ClauseName = II->getName();
 | 
						|
    // Parse 'inranch|notinbranch' clauses.
 | 
						|
    if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) {
 | 
						|
      if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) {
 | 
						|
        P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch)
 | 
						|
            << ClauseName
 | 
						|
            << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange;
 | 
						|
        IsError = true;
 | 
						|
      }
 | 
						|
      BS = Out;
 | 
						|
      BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc());
 | 
						|
      P.ConsumeToken();
 | 
						|
    } else if (ClauseName.equals("simdlen")) {
 | 
						|
      if (SimdLen.isUsable()) {
 | 
						|
        P.Diag(Tok, diag::err_omp_more_one_clause)
 | 
						|
            << getOpenMPDirectiveName(OMPD_declare_simd) << ClauseName << 0;
 | 
						|
        IsError = true;
 | 
						|
      }
 | 
						|
      P.ConsumeToken();
 | 
						|
      SourceLocation RLoc;
 | 
						|
      SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc);
 | 
						|
      if (SimdLen.isInvalid())
 | 
						|
        IsError = true;
 | 
						|
    } else {
 | 
						|
      OpenMPClauseKind CKind = getOpenMPClauseKind(ClauseName);
 | 
						|
      if (CKind == OMPC_uniform || CKind == OMPC_aligned ||
 | 
						|
          CKind == OMPC_linear) {
 | 
						|
        Parser::OpenMPVarListDataTy Data;
 | 
						|
        SmallVectorImpl<Expr *> *Vars = &Uniforms;
 | 
						|
        if (CKind == OMPC_aligned) {
 | 
						|
          Vars = &Aligneds;
 | 
						|
        } else if (CKind == OMPC_linear) {
 | 
						|
          Data.ExtraModifier = OMPC_LINEAR_val;
 | 
						|
          Vars = &Linears;
 | 
						|
        }
 | 
						|
 | 
						|
        P.ConsumeToken();
 | 
						|
        if (P.ParseOpenMPVarList(OMPD_declare_simd,
 | 
						|
                                 getOpenMPClauseKind(ClauseName), *Vars, Data))
 | 
						|
          IsError = true;
 | 
						|
        if (CKind == OMPC_aligned) {
 | 
						|
          Alignments.append(Aligneds.size() - Alignments.size(),
 | 
						|
                            Data.DepModOrTailExpr);
 | 
						|
        } else if (CKind == OMPC_linear) {
 | 
						|
          assert(0 <= Data.ExtraModifier &&
 | 
						|
                 Data.ExtraModifier <= OMPC_LINEAR_unknown &&
 | 
						|
                 "Unexpected linear modifier.");
 | 
						|
          if (P.getActions().CheckOpenMPLinearModifier(
 | 
						|
                  static_cast<OpenMPLinearClauseKind>(Data.ExtraModifier),
 | 
						|
                  Data.ExtraModifierLoc))
 | 
						|
            Data.ExtraModifier = OMPC_LINEAR_val;
 | 
						|
          LinModifiers.append(Linears.size() - LinModifiers.size(),
 | 
						|
                              Data.ExtraModifier);
 | 
						|
          Steps.append(Linears.size() - Steps.size(), Data.DepModOrTailExpr);
 | 
						|
        }
 | 
						|
      } else
 | 
						|
        // TODO: add parsing of other clauses.
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    // Skip ',' if any.
 | 
						|
    if (Tok.is(tok::comma))
 | 
						|
      P.ConsumeToken();
 | 
						|
  }
 | 
						|
  return IsError;
 | 
						|
}
 | 
						|
 | 
						|
/// Parse clauses for '#pragma omp declare simd'.
 | 
						|
Parser::DeclGroupPtrTy
 | 
						|
Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
 | 
						|
                                   CachedTokens &Toks, SourceLocation Loc) {
 | 
						|
  PP.EnterToken(Tok, /*IsReinject*/ true);
 | 
						|
  PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
 | 
						|
                      /*IsReinject*/ true);
 | 
						|
  // Consume the previously pushed token.
 | 
						|
  ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
 | 
						|
  ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
 | 
						|
 | 
						|
  FNContextRAII FnContext(*this, Ptr);
 | 
						|
  OMPDeclareSimdDeclAttr::BranchStateTy BS =
 | 
						|
      OMPDeclareSimdDeclAttr::BS_Undefined;
 | 
						|
  ExprResult Simdlen;
 | 
						|
  SmallVector<Expr *, 4> Uniforms;
 | 
						|
  SmallVector<Expr *, 4> Aligneds;
 | 
						|
  SmallVector<Expr *, 4> Alignments;
 | 
						|
  SmallVector<Expr *, 4> Linears;
 | 
						|
  SmallVector<unsigned, 4> LinModifiers;
 | 
						|
  SmallVector<Expr *, 4> Steps;
 | 
						|
  bool IsError =
 | 
						|
      parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds,
 | 
						|
                              Alignments, Linears, LinModifiers, Steps);
 | 
						|
  skipUntilPragmaOpenMPEnd(OMPD_declare_simd);
 | 
						|
  // Skip the last annot_pragma_openmp_end.
 | 
						|
  SourceLocation EndLoc = ConsumeAnnotationToken();
 | 
						|
  if (IsError)
 | 
						|
    return Ptr;
 | 
						|
  return Actions.ActOnOpenMPDeclareSimdDirective(
 | 
						|
      Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears,
 | 
						|
      LinModifiers, Steps, SourceRange(Loc, EndLoc));
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
/// Constant used in the diagnostics to distinguish the levels in an OpenMP
 | 
						|
/// contexts: selector-set={selector(trait, ...), ...}, ....
 | 
						|
enum OMPContextLvl {
 | 
						|
  CONTEXT_SELECTOR_SET_LVL = 0,
 | 
						|
  CONTEXT_SELECTOR_LVL = 1,
 | 
						|
  CONTEXT_TRAIT_LVL = 2,
 | 
						|
};
 | 
						|
 | 
						|
static StringRef stringLiteralParser(Parser &P) {
 | 
						|
  ExprResult Res = P.ParseStringLiteralExpression(true);
 | 
						|
  return Res.isUsable() ? Res.getAs<StringLiteral>()->getString() : "";
 | 
						|
}
 | 
						|
 | 
						|
static StringRef getNameFromIdOrString(Parser &P, Token &Tok,
 | 
						|
                                       OMPContextLvl Lvl) {
 | 
						|
  if (Tok.is(tok::identifier)) {
 | 
						|
    llvm::SmallString<16> Buffer;
 | 
						|
    StringRef Name = P.getPreprocessor().getSpelling(Tok, Buffer);
 | 
						|
    (void)P.ConsumeToken();
 | 
						|
    return Name;
 | 
						|
  }
 | 
						|
 | 
						|
  if (tok::isStringLiteral(Tok.getKind()))
 | 
						|
    return stringLiteralParser(P);
 | 
						|
 | 
						|
  P.Diag(Tok.getLocation(),
 | 
						|
         diag::warn_omp_declare_variant_string_literal_or_identifier)
 | 
						|
      << Lvl;
 | 
						|
  return "";
 | 
						|
}
 | 
						|
 | 
						|
static bool checkForDuplicates(Parser &P, StringRef Name,
 | 
						|
                               SourceLocation NameLoc,
 | 
						|
                               llvm::StringMap<SourceLocation> &Seen,
 | 
						|
                               OMPContextLvl Lvl) {
 | 
						|
  auto Res = Seen.try_emplace(Name, NameLoc);
 | 
						|
  if (Res.second)
 | 
						|
    return false;
 | 
						|
 | 
						|
  // Each trait-set-selector-name, trait-selector-name and trait-name can
 | 
						|
  // only be specified once.
 | 
						|
  P.Diag(NameLoc, diag::warn_omp_declare_variant_ctx_mutiple_use)
 | 
						|
      << Lvl << Name;
 | 
						|
  P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here)
 | 
						|
      << Lvl << Name;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
} // namespace
 | 
						|
 | 
						|
void Parser::parseOMPTraitPropertyKind(
 | 
						|
    OMPTraitProperty &TIProperty, llvm::omp::TraitSet Set,
 | 
						|
    llvm::omp::TraitSelector Selector, llvm::StringMap<SourceLocation> &Seen) {
 | 
						|
  TIProperty.Kind = TraitProperty::invalid;
 | 
						|
 | 
						|
  SourceLocation NameLoc = Tok.getLocation();
 | 
						|
  StringRef Name =
 | 
						|
      getNameFromIdOrString(*this, Tok, CONTEXT_TRAIT_LVL);
 | 
						|
  if (Name.empty()) {
 | 
						|
    Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)
 | 
						|
        << CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  TIProperty.Kind = getOpenMPContextTraitPropertyKind(Set, Name);
 | 
						|
  if (TIProperty.Kind != TraitProperty::invalid) {
 | 
						|
    if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_TRAIT_LVL))
 | 
						|
      TIProperty.Kind = TraitProperty::invalid;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // It follows diagnosis and helping notes.
 | 
						|
  // FIXME: We should move the diagnosis string generation into libFrontend.
 | 
						|
  Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_property)
 | 
						|
      << Name << getOpenMPContextTraitSelectorName(Selector)
 | 
						|
      << getOpenMPContextTraitSetName(Set);
 | 
						|
 | 
						|
  TraitSet SetForName = getOpenMPContextTraitSetKind(Name);
 | 
						|
  if (SetForName != TraitSet::invalid) {
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)
 | 
						|
        << Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_TRAIT_LVL;
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)
 | 
						|
        << Name << "<selector-name>"
 | 
						|
        << "(<property-name>)";
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  TraitSelector SelectorForName = getOpenMPContextTraitSelectorKind(Name);
 | 
						|
  if (SelectorForName != TraitSelector::invalid) {
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)
 | 
						|
        << Name << CONTEXT_SELECTOR_LVL << CONTEXT_TRAIT_LVL;
 | 
						|
    bool AllowsTraitScore = false;
 | 
						|
    bool RequiresProperty = false;
 | 
						|
    isValidTraitSelectorForTraitSet(
 | 
						|
        SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName),
 | 
						|
        AllowsTraitScore, RequiresProperty);
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)
 | 
						|
        << getOpenMPContextTraitSetName(
 | 
						|
               getOpenMPContextTraitSetForSelector(SelectorForName))
 | 
						|
        << Name << (RequiresProperty ? "(<property-name>)" : "");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  for (const auto &PotentialSet :
 | 
						|
       {TraitSet::construct, TraitSet::user, TraitSet::implementation,
 | 
						|
        TraitSet::device}) {
 | 
						|
    TraitProperty PropertyForName =
 | 
						|
        getOpenMPContextTraitPropertyKind(PotentialSet, Name);
 | 
						|
    if (PropertyForName == TraitProperty::invalid)
 | 
						|
      continue;
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)
 | 
						|
        << getOpenMPContextTraitSetName(
 | 
						|
               getOpenMPContextTraitSetForProperty(PropertyForName))
 | 
						|
        << getOpenMPContextTraitSelectorName(
 | 
						|
               getOpenMPContextTraitSelectorForProperty(PropertyForName))
 | 
						|
        << ("(" + Name + ")").str();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)
 | 
						|
      << CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector);
 | 
						|
}
 | 
						|
 | 
						|
static bool checkExtensionProperty(Parser &P, SourceLocation Loc,
 | 
						|
                                   OMPTraitProperty &TIProperty,
 | 
						|
                                   OMPTraitSelector &TISelector,
 | 
						|
                                   llvm::StringMap<SourceLocation> &Seen) {
 | 
						|
  assert(TISelector.Kind ==
 | 
						|
             llvm::omp::TraitSelector::implementation_extension &&
 | 
						|
         "Only for extension properties, e.g., "
 | 
						|
         "`implementation={extension(PROPERTY)}`");
 | 
						|
  if (TIProperty.Kind == TraitProperty::invalid)
 | 
						|
    return false;
 | 
						|
 | 
						|
  auto IsMatchExtension = [](OMPTraitProperty &TP) {
 | 
						|
    return (TP.Kind ==
 | 
						|
                llvm::omp::TraitProperty::implementation_extension_match_all ||
 | 
						|
            TP.Kind ==
 | 
						|
                llvm::omp::TraitProperty::implementation_extension_match_any ||
 | 
						|
            TP.Kind ==
 | 
						|
                llvm::omp::TraitProperty::implementation_extension_match_none);
 | 
						|
  };
 | 
						|
 | 
						|
  if (IsMatchExtension(TIProperty)) {
 | 
						|
    for (OMPTraitProperty &SeenProp : TISelector.Properties)
 | 
						|
      if (IsMatchExtension(SeenProp)) {
 | 
						|
        P.Diag(Loc, diag::err_omp_variant_ctx_second_match_extension);
 | 
						|
        StringRef SeenName =
 | 
						|
            llvm::omp::getOpenMPContextTraitPropertyName(SeenProp.Kind);
 | 
						|
        SourceLocation SeenLoc = Seen[SeenName];
 | 
						|
        P.Diag(SeenLoc, diag::note_omp_declare_variant_ctx_used_here)
 | 
						|
            << CONTEXT_TRAIT_LVL << SeenName;
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  llvm_unreachable("Unknown extension property!");
 | 
						|
}
 | 
						|
 | 
						|
void Parser::parseOMPContextProperty(OMPTraitSelector &TISelector,
 | 
						|
                                     llvm::omp::TraitSet Set,
 | 
						|
                                     llvm::StringMap<SourceLocation> &Seen) {
 | 
						|
  assert(TISelector.Kind != TraitSelector::user_condition &&
 | 
						|
         "User conditions are special properties not handled here!");
 | 
						|
 | 
						|
  SourceLocation PropertyLoc = Tok.getLocation();
 | 
						|
  OMPTraitProperty TIProperty;
 | 
						|
  parseOMPTraitPropertyKind(TIProperty, Set, TISelector.Kind, Seen);
 | 
						|
 | 
						|
  if (TISelector.Kind == llvm::omp::TraitSelector::implementation_extension)
 | 
						|
    if (!checkExtensionProperty(*this, Tok.getLocation(), TIProperty,
 | 
						|
                                TISelector, Seen))
 | 
						|
      TIProperty.Kind = TraitProperty::invalid;
 | 
						|
 | 
						|
  // If we have an invalid property here we already issued a warning.
 | 
						|
  if (TIProperty.Kind == TraitProperty::invalid) {
 | 
						|
    if (PropertyLoc != Tok.getLocation())
 | 
						|
      Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)
 | 
						|
          << CONTEXT_TRAIT_LVL;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (isValidTraitPropertyForTraitSetAndSelector(TIProperty.Kind,
 | 
						|
                                                 TISelector.Kind, Set)) {
 | 
						|
 | 
						|
    // If we make it here the property, selector, set, score, condition, ... are
 | 
						|
    // all valid (or have been corrected). Thus we can record the property.
 | 
						|
    TISelector.Properties.push_back(TIProperty);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Diag(PropertyLoc, diag::warn_omp_ctx_incompatible_property_for_selector)
 | 
						|
      << getOpenMPContextTraitPropertyName(TIProperty.Kind)
 | 
						|
      << getOpenMPContextTraitSelectorName(TISelector.Kind)
 | 
						|
      << getOpenMPContextTraitSetName(Set);
 | 
						|
  Diag(PropertyLoc, diag::note_omp_ctx_compatible_set_and_selector_for_property)
 | 
						|
      << getOpenMPContextTraitPropertyName(TIProperty.Kind)
 | 
						|
      << getOpenMPContextTraitSelectorName(
 | 
						|
             getOpenMPContextTraitSelectorForProperty(TIProperty.Kind))
 | 
						|
      << getOpenMPContextTraitSetName(
 | 
						|
             getOpenMPContextTraitSetForProperty(TIProperty.Kind));
 | 
						|
  Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)
 | 
						|
      << CONTEXT_TRAIT_LVL;
 | 
						|
}
 | 
						|
 | 
						|
void Parser::parseOMPTraitSelectorKind(
 | 
						|
    OMPTraitSelector &TISelector, llvm::omp::TraitSet Set,
 | 
						|
    llvm::StringMap<SourceLocation> &Seen) {
 | 
						|
  TISelector.Kind = TraitSelector::invalid;
 | 
						|
 | 
						|
  SourceLocation NameLoc = Tok.getLocation();
 | 
						|
  StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_LVL
 | 
						|
                    );
 | 
						|
  if (Name.empty()) {
 | 
						|
    Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)
 | 
						|
        << CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  TISelector.Kind = getOpenMPContextTraitSelectorKind(Name);
 | 
						|
  if (TISelector.Kind != TraitSelector::invalid) {
 | 
						|
    if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_SELECTOR_LVL))
 | 
						|
      TISelector.Kind = TraitSelector::invalid;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // It follows diagnosis and helping notes.
 | 
						|
  Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_selector)
 | 
						|
      << Name << getOpenMPContextTraitSetName(Set);
 | 
						|
 | 
						|
  TraitSet SetForName = getOpenMPContextTraitSetKind(Name);
 | 
						|
  if (SetForName != TraitSet::invalid) {
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)
 | 
						|
        << Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_SELECTOR_LVL;
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)
 | 
						|
        << Name << "<selector-name>"
 | 
						|
        << "<property-name>";
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  for (const auto &PotentialSet :
 | 
						|
       {TraitSet::construct, TraitSet::user, TraitSet::implementation,
 | 
						|
        TraitSet::device}) {
 | 
						|
    TraitProperty PropertyForName =
 | 
						|
        getOpenMPContextTraitPropertyKind(PotentialSet, Name);
 | 
						|
    if (PropertyForName == TraitProperty::invalid)
 | 
						|
      continue;
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)
 | 
						|
        << Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_LVL;
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)
 | 
						|
        << getOpenMPContextTraitSetName(
 | 
						|
               getOpenMPContextTraitSetForProperty(PropertyForName))
 | 
						|
        << getOpenMPContextTraitSelectorName(
 | 
						|
               getOpenMPContextTraitSelectorForProperty(PropertyForName))
 | 
						|
        << ("(" + Name + ")").str();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)
 | 
						|
      << CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set);
 | 
						|
}
 | 
						|
 | 
						|
/// Parse optional 'score' '(' <expr> ')' ':'.
 | 
						|
static ExprResult parseContextScore(Parser &P) {
 | 
						|
  ExprResult ScoreExpr;
 | 
						|
  llvm::SmallString<16> Buffer;
 | 
						|
  StringRef SelectorName =
 | 
						|
      P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);
 | 
						|
  if (!SelectorName.equals("score"))
 | 
						|
    return ScoreExpr;
 | 
						|
  (void)P.ConsumeToken();
 | 
						|
  SourceLocation RLoc;
 | 
						|
  ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc);
 | 
						|
  // Parse ':'
 | 
						|
  if (P.getCurToken().is(tok::colon))
 | 
						|
    (void)P.ConsumeAnyToken();
 | 
						|
  else
 | 
						|
    P.Diag(P.getCurToken(), diag::warn_omp_declare_variant_expected)
 | 
						|
        << "':'"
 | 
						|
        << "score expression";
 | 
						|
  return ScoreExpr;
 | 
						|
}
 | 
						|
 | 
						|
/// Parses an OpenMP context selector.
 | 
						|
///
 | 
						|
/// <trait-selector-name> ['('[<trait-score>] <trait-property> [, <t-p>]* ')']
 | 
						|
void Parser::parseOMPContextSelector(
 | 
						|
    OMPTraitSelector &TISelector, llvm::omp::TraitSet Set,
 | 
						|
    llvm::StringMap<SourceLocation> &SeenSelectors) {
 | 
						|
  unsigned short OuterPC = ParenCount;
 | 
						|
 | 
						|
  // If anything went wrong we issue an error or warning and then skip the rest
 | 
						|
  // of the selector. However, commas are ambiguous so we look for the nesting
 | 
						|
  // of parentheses here as well.
 | 
						|
  auto FinishSelector = [OuterPC, this]() -> void {
 | 
						|
    bool Done = false;
 | 
						|
    while (!Done) {
 | 
						|
      while (!SkipUntil({tok::r_brace, tok::r_paren, tok::comma,
 | 
						|
                         tok::annot_pragma_openmp_end},
 | 
						|
                        StopBeforeMatch))
 | 
						|
        ;
 | 
						|
      if (Tok.is(tok::r_paren) && OuterPC > ParenCount)
 | 
						|
        (void)ConsumeParen();
 | 
						|
      if (OuterPC <= ParenCount) {
 | 
						|
        Done = true;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      if (!Tok.is(tok::comma) && !Tok.is(tok::r_paren)) {
 | 
						|
        Done = true;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      (void)ConsumeAnyToken();
 | 
						|
    }
 | 
						|
    Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)
 | 
						|
        << CONTEXT_SELECTOR_LVL;
 | 
						|
  };
 | 
						|
 | 
						|
  SourceLocation SelectorLoc = Tok.getLocation();
 | 
						|
  parseOMPTraitSelectorKind(TISelector, Set, SeenSelectors);
 | 
						|
  if (TISelector.Kind == TraitSelector::invalid)
 | 
						|
    return FinishSelector();
 | 
						|
 | 
						|
  bool AllowsTraitScore = false;
 | 
						|
  bool RequiresProperty = false;
 | 
						|
  if (!isValidTraitSelectorForTraitSet(TISelector.Kind, Set, AllowsTraitScore,
 | 
						|
                                       RequiresProperty)) {
 | 
						|
    Diag(SelectorLoc, diag::warn_omp_ctx_incompatible_selector_for_set)
 | 
						|
        << getOpenMPContextTraitSelectorName(TISelector.Kind)
 | 
						|
        << getOpenMPContextTraitSetName(Set);
 | 
						|
    Diag(SelectorLoc, diag::note_omp_ctx_compatible_set_for_selector)
 | 
						|
        << getOpenMPContextTraitSelectorName(TISelector.Kind)
 | 
						|
        << getOpenMPContextTraitSetName(
 | 
						|
               getOpenMPContextTraitSetForSelector(TISelector.Kind))
 | 
						|
        << RequiresProperty;
 | 
						|
    return FinishSelector();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!RequiresProperty) {
 | 
						|
    TISelector.Properties.push_back(
 | 
						|
        {getOpenMPContextTraitPropertyForSelector(TISelector.Kind)});
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Tok.is(tok::l_paren)) {
 | 
						|
    Diag(SelectorLoc, diag::warn_omp_ctx_selector_without_properties)
 | 
						|
        << getOpenMPContextTraitSelectorName(TISelector.Kind)
 | 
						|
        << getOpenMPContextTraitSetName(Set);
 | 
						|
    return FinishSelector();
 | 
						|
  }
 | 
						|
 | 
						|
  if (TISelector.Kind == TraitSelector::user_condition) {
 | 
						|
    SourceLocation RLoc;
 | 
						|
    ExprResult Condition = ParseOpenMPParensExpr("user condition", RLoc);
 | 
						|
    if (!Condition.isUsable())
 | 
						|
      return FinishSelector();
 | 
						|
    TISelector.ScoreOrCondition = Condition.get();
 | 
						|
    TISelector.Properties.push_back({TraitProperty::user_condition_unknown});
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  BalancedDelimiterTracker BDT(*this, tok::l_paren,
 | 
						|
                               tok::annot_pragma_openmp_end);
 | 
						|
  // Parse '('.
 | 
						|
  (void)BDT.consumeOpen();
 | 
						|
 | 
						|
  SourceLocation ScoreLoc = Tok.getLocation();
 | 
						|
  ExprResult Score = parseContextScore(*this);
 | 
						|
 | 
						|
  if (!AllowsTraitScore && !Score.isUnset()) {
 | 
						|
    if (Score.isUsable()) {
 | 
						|
      Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property)
 | 
						|
          << getOpenMPContextTraitSelectorName(TISelector.Kind)
 | 
						|
          << getOpenMPContextTraitSetName(Set) << Score.get();
 | 
						|
    } else {
 | 
						|
      Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property)
 | 
						|
          << getOpenMPContextTraitSelectorName(TISelector.Kind)
 | 
						|
          << getOpenMPContextTraitSetName(Set) << "<invalid>";
 | 
						|
    }
 | 
						|
    Score = ExprResult();
 | 
						|
  }
 | 
						|
 | 
						|
  if (Score.isUsable())
 | 
						|
    TISelector.ScoreOrCondition = Score.get();
 | 
						|
 | 
						|
  llvm::StringMap<SourceLocation> SeenProperties;
 | 
						|
  do {
 | 
						|
    parseOMPContextProperty(TISelector, Set, SeenProperties);
 | 
						|
  } while (TryConsumeToken(tok::comma));
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  BDT.consumeClose();
 | 
						|
}
 | 
						|
 | 
						|
void Parser::parseOMPTraitSetKind(OMPTraitSet &TISet,
 | 
						|
                                  llvm::StringMap<SourceLocation> &Seen) {
 | 
						|
  TISet.Kind = TraitSet::invalid;
 | 
						|
 | 
						|
  SourceLocation NameLoc = Tok.getLocation();
 | 
						|
  StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_SET_LVL
 | 
						|
                   );
 | 
						|
  if (Name.empty()) {
 | 
						|
    Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)
 | 
						|
        << CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  TISet.Kind = getOpenMPContextTraitSetKind(Name);
 | 
						|
  if (TISet.Kind != TraitSet::invalid) {
 | 
						|
    if (checkForDuplicates(*this, Name, NameLoc, Seen,
 | 
						|
                           CONTEXT_SELECTOR_SET_LVL))
 | 
						|
      TISet.Kind = TraitSet::invalid;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // It follows diagnosis and helping notes.
 | 
						|
  Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_set) << Name;
 | 
						|
 | 
						|
  TraitSelector SelectorForName = getOpenMPContextTraitSelectorKind(Name);
 | 
						|
  if (SelectorForName != TraitSelector::invalid) {
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)
 | 
						|
        << Name << CONTEXT_SELECTOR_LVL << CONTEXT_SELECTOR_SET_LVL;
 | 
						|
    bool AllowsTraitScore = false;
 | 
						|
    bool RequiresProperty = false;
 | 
						|
    isValidTraitSelectorForTraitSet(
 | 
						|
        SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName),
 | 
						|
        AllowsTraitScore, RequiresProperty);
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)
 | 
						|
        << getOpenMPContextTraitSetName(
 | 
						|
               getOpenMPContextTraitSetForSelector(SelectorForName))
 | 
						|
        << Name << (RequiresProperty ? "(<property-name>)" : "");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  for (const auto &PotentialSet :
 | 
						|
       {TraitSet::construct, TraitSet::user, TraitSet::implementation,
 | 
						|
        TraitSet::device}) {
 | 
						|
    TraitProperty PropertyForName =
 | 
						|
        getOpenMPContextTraitPropertyKind(PotentialSet, Name);
 | 
						|
    if (PropertyForName == TraitProperty::invalid)
 | 
						|
      continue;
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)
 | 
						|
        << Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_SET_LVL;
 | 
						|
    Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)
 | 
						|
        << getOpenMPContextTraitSetName(
 | 
						|
               getOpenMPContextTraitSetForProperty(PropertyForName))
 | 
						|
        << getOpenMPContextTraitSelectorName(
 | 
						|
               getOpenMPContextTraitSelectorForProperty(PropertyForName))
 | 
						|
        << ("(" + Name + ")").str();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)
 | 
						|
      << CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets();
 | 
						|
}
 | 
						|
 | 
						|
/// Parses an OpenMP context selector set.
 | 
						|
///
 | 
						|
/// <trait-set-selector-name> '=' '{' <trait-selector> [, <trait-selector>]* '}'
 | 
						|
void Parser::parseOMPContextSelectorSet(
 | 
						|
    OMPTraitSet &TISet,
 | 
						|
    llvm::StringMap<SourceLocation> &SeenSets) {
 | 
						|
  auto OuterBC = BraceCount;
 | 
						|
 | 
						|
  // If anything went wrong we issue an error or warning and then skip the rest
 | 
						|
  // of the set. However, commas are ambiguous so we look for the nesting
 | 
						|
  // of braces here as well.
 | 
						|
  auto FinishSelectorSet = [this, OuterBC]() -> void {
 | 
						|
    bool Done = false;
 | 
						|
    while (!Done) {
 | 
						|
      while (!SkipUntil({tok::comma, tok::r_brace, tok::r_paren,
 | 
						|
                         tok::annot_pragma_openmp_end},
 | 
						|
                        StopBeforeMatch))
 | 
						|
        ;
 | 
						|
      if (Tok.is(tok::r_brace) && OuterBC > BraceCount)
 | 
						|
        (void)ConsumeBrace();
 | 
						|
      if (OuterBC <= BraceCount) {
 | 
						|
        Done = true;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      if (!Tok.is(tok::comma) && !Tok.is(tok::r_brace)) {
 | 
						|
        Done = true;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      (void)ConsumeAnyToken();
 | 
						|
    }
 | 
						|
    Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)
 | 
						|
        << CONTEXT_SELECTOR_SET_LVL;
 | 
						|
  };
 | 
						|
 | 
						|
  parseOMPTraitSetKind(TISet, SeenSets);
 | 
						|
  if (TISet.Kind == TraitSet::invalid)
 | 
						|
    return FinishSelectorSet();
 | 
						|
 | 
						|
  // Parse '='.
 | 
						|
  if (!TryConsumeToken(tok::equal))
 | 
						|
    Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)
 | 
						|
        << "="
 | 
						|
        << ("context set name \"" + getOpenMPContextTraitSetName(TISet.Kind) +
 | 
						|
            "\"")
 | 
						|
               .str();
 | 
						|
 | 
						|
  // Parse '{'.
 | 
						|
  if (Tok.is(tok::l_brace)) {
 | 
						|
    (void)ConsumeBrace();
 | 
						|
  } else {
 | 
						|
    Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)
 | 
						|
        << "{"
 | 
						|
        << ("'=' that follows the context set name \"" +
 | 
						|
            getOpenMPContextTraitSetName(TISet.Kind) + "\"")
 | 
						|
               .str();
 | 
						|
  }
 | 
						|
 | 
						|
  llvm::StringMap<SourceLocation> SeenSelectors;
 | 
						|
  do {
 | 
						|
    OMPTraitSelector TISelector;
 | 
						|
    parseOMPContextSelector(TISelector, TISet.Kind, SeenSelectors);
 | 
						|
    if (TISelector.Kind != TraitSelector::invalid &&
 | 
						|
        !TISelector.Properties.empty())
 | 
						|
      TISet.Selectors.push_back(TISelector);
 | 
						|
  } while (TryConsumeToken(tok::comma));
 | 
						|
 | 
						|
  // Parse '}'.
 | 
						|
  if (Tok.is(tok::r_brace)) {
 | 
						|
    (void)ConsumeBrace();
 | 
						|
  } else {
 | 
						|
    Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)
 | 
						|
        << "}"
 | 
						|
        << ("context selectors for the context set \"" +
 | 
						|
            getOpenMPContextTraitSetName(TISet.Kind) + "\"")
 | 
						|
               .str();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// Parse OpenMP context selectors:
 | 
						|
///
 | 
						|
/// <trait-set-selector> [, <trait-set-selector>]*
 | 
						|
bool Parser::parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo& TI) {
 | 
						|
  llvm::StringMap<SourceLocation> SeenSets;
 | 
						|
  do {
 | 
						|
    OMPTraitSet TISet;
 | 
						|
    parseOMPContextSelectorSet(TISet, SeenSets);
 | 
						|
    if (TISet.Kind != TraitSet::invalid && !TISet.Selectors.empty())
 | 
						|
      TI.Sets.push_back(TISet);
 | 
						|
  } while (TryConsumeToken(tok::comma));
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
/// Parse clauses for '#pragma omp declare variant ( variant-func-id ) clause'.
 | 
						|
void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
 | 
						|
                                           CachedTokens &Toks,
 | 
						|
                                           SourceLocation Loc) {
 | 
						|
  PP.EnterToken(Tok, /*IsReinject*/ true);
 | 
						|
  PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
 | 
						|
                      /*IsReinject*/ true);
 | 
						|
  // Consume the previously pushed token.
 | 
						|
  ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
 | 
						|
  ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
 | 
						|
 | 
						|
  FNContextRAII FnContext(*this, Ptr);
 | 
						|
  // Parse function declaration id.
 | 
						|
  SourceLocation RLoc;
 | 
						|
  // Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs
 | 
						|
  // instead of MemberExprs.
 | 
						|
  ExprResult AssociatedFunction;
 | 
						|
  {
 | 
						|
    // Do not mark function as is used to prevent its emission if this is the
 | 
						|
    // only place where it is used.
 | 
						|
    EnterExpressionEvaluationContext Unevaluated(
 | 
						|
        Actions, Sema::ExpressionEvaluationContext::Unevaluated);
 | 
						|
    AssociatedFunction = ParseOpenMPParensExpr(
 | 
						|
        getOpenMPDirectiveName(OMPD_declare_variant), RLoc,
 | 
						|
        /*IsAddressOfOperand=*/true);
 | 
						|
  }
 | 
						|
  if (!AssociatedFunction.isUsable()) {
 | 
						|
    if (!Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
      while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))
 | 
						|
        ;
 | 
						|
    // Skip the last annot_pragma_openmp_end.
 | 
						|
    (void)ConsumeAnnotationToken();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
 | 
						|
  if (parseOMPDeclareVariantMatchClause(Loc, TI))
 | 
						|
    return;
 | 
						|
 | 
						|
  Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
 | 
						|
      Actions.checkOpenMPDeclareVariantFunction(
 | 
						|
          Ptr, AssociatedFunction.get(), TI,
 | 
						|
          SourceRange(Loc, Tok.getLocation()));
 | 
						|
 | 
						|
  // Skip last tokens.
 | 
						|
  while (Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
    ConsumeAnyToken();
 | 
						|
  if (DeclVarData && !TI.Sets.empty())
 | 
						|
    Actions.ActOnOpenMPDeclareVariantDirective(
 | 
						|
        DeclVarData->first, DeclVarData->second, TI,
 | 
						|
        SourceRange(Loc, Tok.getLocation()));
 | 
						|
 | 
						|
  // Skip the last annot_pragma_openmp_end.
 | 
						|
  (void)ConsumeAnnotationToken();
 | 
						|
}
 | 
						|
 | 
						|
bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc,
 | 
						|
                                               OMPTraitInfo &TI) {
 | 
						|
  // Parse 'match'.
 | 
						|
  OpenMPClauseKind CKind = Tok.isAnnotation()
 | 
						|
                               ? OMPC_unknown
 | 
						|
                               : getOpenMPClauseKind(PP.getSpelling(Tok));
 | 
						|
  if (CKind != OMPC_match) {
 | 
						|
    Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause)
 | 
						|
        << getOpenMPClauseName(OMPC_match);
 | 
						|
    while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))
 | 
						|
      ;
 | 
						|
    // Skip the last annot_pragma_openmp_end.
 | 
						|
    (void)ConsumeAnnotationToken();
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  (void)ConsumeToken();
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPClauseName(OMPC_match).data())) {
 | 
						|
    while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))
 | 
						|
      ;
 | 
						|
    // Skip the last annot_pragma_openmp_end.
 | 
						|
    (void)ConsumeAnnotationToken();
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse inner context selectors.
 | 
						|
  parseOMPContextSelectors(Loc, TI);
 | 
						|
 | 
						|
  // Parse ')'
 | 
						|
  (void)T.consumeClose();
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
 | 
						|
///
 | 
						|
///    default-clause:
 | 
						|
///         'default' '(' 'none' | 'shared'  | 'firstprivate' ')
 | 
						|
///
 | 
						|
///    proc_bind-clause:
 | 
						|
///         'proc_bind' '(' 'master' | 'close' | 'spread' ')
 | 
						|
///
 | 
						|
///    device_type-clause:
 | 
						|
///         'device_type' '(' 'host' | 'nohost' | 'any' )'
 | 
						|
namespace {
 | 
						|
  struct SimpleClauseData {
 | 
						|
    unsigned Type;
 | 
						|
    SourceLocation Loc;
 | 
						|
    SourceLocation LOpen;
 | 
						|
    SourceLocation TypeLoc;
 | 
						|
    SourceLocation RLoc;
 | 
						|
    SimpleClauseData(unsigned Type, SourceLocation Loc, SourceLocation LOpen,
 | 
						|
                     SourceLocation TypeLoc, SourceLocation RLoc)
 | 
						|
        : Type(Type), Loc(Loc), LOpen(LOpen), TypeLoc(TypeLoc), RLoc(RLoc) {}
 | 
						|
  };
 | 
						|
} // anonymous namespace
 | 
						|
 | 
						|
static Optional<SimpleClauseData>
 | 
						|
parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) {
 | 
						|
  const Token &Tok = P.getCurToken();
 | 
						|
  SourceLocation Loc = Tok.getLocation();
 | 
						|
  SourceLocation LOpen = P.ConsumeToken();
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPClauseName(Kind).data()))
 | 
						|
    return llvm::None;
 | 
						|
 | 
						|
  unsigned Type = getOpenMPSimpleClauseType(
 | 
						|
      Kind, Tok.isAnnotation() ? "" : P.getPreprocessor().getSpelling(Tok));
 | 
						|
  SourceLocation TypeLoc = Tok.getLocation();
 | 
						|
  if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
 | 
						|
      Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
    P.ConsumeAnyToken();
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  SourceLocation RLoc = Tok.getLocation();
 | 
						|
  if (!T.consumeClose())
 | 
						|
    RLoc = T.getCloseLocation();
 | 
						|
 | 
						|
  return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc);
 | 
						|
}
 | 
						|
 | 
						|
Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() {
 | 
						|
  // OpenMP 4.5 syntax with list of entities.
 | 
						|
  Sema::NamedDeclSetType SameDirectiveDecls;
 | 
						|
  SmallVector<std::tuple<OMPDeclareTargetDeclAttr::MapTypeTy, SourceLocation,
 | 
						|
                         NamedDecl *>,
 | 
						|
              4>
 | 
						|
      DeclareTargetDecls;
 | 
						|
  OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any;
 | 
						|
  SourceLocation DeviceTypeLoc;
 | 
						|
  while (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
    OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To;
 | 
						|
    if (Tok.is(tok::identifier)) {
 | 
						|
      IdentifierInfo *II = Tok.getIdentifierInfo();
 | 
						|
      StringRef ClauseName = II->getName();
 | 
						|
      bool IsDeviceTypeClause =
 | 
						|
          getLangOpts().OpenMP >= 50 &&
 | 
						|
          getOpenMPClauseKind(ClauseName) == OMPC_device_type;
 | 
						|
      // Parse 'to|link|device_type' clauses.
 | 
						|
      if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT) &&
 | 
						|
          !IsDeviceTypeClause) {
 | 
						|
        Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
 | 
						|
            << ClauseName << (getLangOpts().OpenMP >= 50 ? 1 : 0);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      // Parse 'device_type' clause and go to next clause if any.
 | 
						|
      if (IsDeviceTypeClause) {
 | 
						|
        Optional<SimpleClauseData> DevTypeData =
 | 
						|
            parseOpenMPSimpleClause(*this, OMPC_device_type);
 | 
						|
        if (DevTypeData.hasValue()) {
 | 
						|
          if (DeviceTypeLoc.isValid()) {
 | 
						|
            // We already saw another device_type clause, diagnose it.
 | 
						|
            Diag(DevTypeData.getValue().Loc,
 | 
						|
                 diag::warn_omp_more_one_device_type_clause);
 | 
						|
          }
 | 
						|
          switch(static_cast<OpenMPDeviceType>(DevTypeData.getValue().Type)) {
 | 
						|
          case OMPC_DEVICE_TYPE_any:
 | 
						|
            DT = OMPDeclareTargetDeclAttr::DT_Any;
 | 
						|
            break;
 | 
						|
          case OMPC_DEVICE_TYPE_host:
 | 
						|
            DT = OMPDeclareTargetDeclAttr::DT_Host;
 | 
						|
            break;
 | 
						|
          case OMPC_DEVICE_TYPE_nohost:
 | 
						|
            DT = OMPDeclareTargetDeclAttr::DT_NoHost;
 | 
						|
            break;
 | 
						|
          case OMPC_DEVICE_TYPE_unknown:
 | 
						|
            llvm_unreachable("Unexpected device_type");
 | 
						|
          }
 | 
						|
          DeviceTypeLoc = DevTypeData.getValue().Loc;
 | 
						|
        }
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      ConsumeToken();
 | 
						|
    }
 | 
						|
    auto &&Callback = [this, MT, &DeclareTargetDecls, &SameDirectiveDecls](
 | 
						|
                          CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {
 | 
						|
      NamedDecl *ND = Actions.lookupOpenMPDeclareTargetName(
 | 
						|
          getCurScope(), SS, NameInfo, SameDirectiveDecls);
 | 
						|
      if (ND)
 | 
						|
        DeclareTargetDecls.emplace_back(MT, NameInfo.getLoc(), ND);
 | 
						|
    };
 | 
						|
    if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback,
 | 
						|
                                 /*AllowScopeSpecifier=*/true))
 | 
						|
      break;
 | 
						|
 | 
						|
    // Consume optional ','.
 | 
						|
    if (Tok.is(tok::comma))
 | 
						|
      ConsumeToken();
 | 
						|
  }
 | 
						|
  SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
  ConsumeAnyToken();
 | 
						|
  for (auto &MTLocDecl : DeclareTargetDecls) {
 | 
						|
    OMPDeclareTargetDeclAttr::MapTypeTy MT;
 | 
						|
    SourceLocation Loc;
 | 
						|
    NamedDecl *ND;
 | 
						|
    std::tie(MT, Loc, ND) = MTLocDecl;
 | 
						|
    // device_type clause is applied only to functions.
 | 
						|
    Actions.ActOnOpenMPDeclareTargetName(
 | 
						|
        ND, Loc, MT, isa<VarDecl>(ND) ? OMPDeclareTargetDeclAttr::DT_Any : DT);
 | 
						|
  }
 | 
						|
  SmallVector<Decl *, 4> Decls(SameDirectiveDecls.begin(),
 | 
						|
                               SameDirectiveDecls.end());
 | 
						|
  if (Decls.empty())
 | 
						|
    return DeclGroupPtrTy();
 | 
						|
  return Actions.BuildDeclaratorGroup(Decls);
 | 
						|
}
 | 
						|
 | 
						|
void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) {
 | 
						|
  // The last seen token is annot_pragma_openmp_end - need to check for
 | 
						|
  // extra tokens.
 | 
						|
  if (Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
    return;
 | 
						|
 | 
						|
  Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
 | 
						|
      << getOpenMPDirectiveName(DKind);
 | 
						|
  while (Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
    ConsumeAnyToken();
 | 
						|
}
 | 
						|
 | 
						|
void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind,
 | 
						|
                                  OpenMPDirectiveKind ExpectedKind,
 | 
						|
                                  OpenMPDirectiveKind FoundKind,
 | 
						|
                                  SourceLocation BeginLoc,
 | 
						|
                                  SourceLocation FoundLoc,
 | 
						|
                                  bool SkipUntilOpenMPEnd) {
 | 
						|
  int DiagSelection = ExpectedKind == OMPD_end_declare_target ? 0 : 1;
 | 
						|
 | 
						|
  if (FoundKind == ExpectedKind) {
 | 
						|
    ConsumeAnyToken();
 | 
						|
    skipUntilPragmaOpenMPEnd(ExpectedKind);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Diag(FoundLoc, diag::err_expected_end_declare_target_or_variant)
 | 
						|
      << DiagSelection;
 | 
						|
  Diag(BeginLoc, diag::note_matching)
 | 
						|
      << ("'#pragma omp " + getOpenMPDirectiveName(BeginKind) + "'").str();
 | 
						|
  if (SkipUntilOpenMPEnd)
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
}
 | 
						|
 | 
						|
void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
 | 
						|
                                               SourceLocation DKLoc) {
 | 
						|
  parseOMPEndDirective(OMPD_declare_target, OMPD_end_declare_target, DKind,
 | 
						|
                       DKLoc, Tok.getLocation(),
 | 
						|
                       /* SkipUntilOpenMPEnd */ false);
 | 
						|
  // Skip the last annot_pragma_openmp_end.
 | 
						|
  if (Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
    ConsumeAnnotationToken();
 | 
						|
}
 | 
						|
 | 
						|
/// Parsing of declarative OpenMP directives.
 | 
						|
///
 | 
						|
///       threadprivate-directive:
 | 
						|
///         annot_pragma_openmp 'threadprivate' simple-variable-list
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
///       allocate-directive:
 | 
						|
///         annot_pragma_openmp 'allocate' simple-variable-list [<clause>]
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
///       declare-reduction-directive:
 | 
						|
///        annot_pragma_openmp 'declare' 'reduction' [...]
 | 
						|
///        annot_pragma_openmp_end
 | 
						|
///
 | 
						|
///       declare-mapper-directive:
 | 
						|
///         annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':']
 | 
						|
///         <type> <var> ')' [<clause>[[,] <clause>] ... ]
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
///       declare-simd-directive:
 | 
						|
///         annot_pragma_openmp 'declare simd' {<clause> [,]}
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///         <function declaration/definition>
 | 
						|
///
 | 
						|
///       requires directive:
 | 
						|
///         annot_pragma_openmp 'requires' <clause> [[[,] <clause>] ... ]
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
 | 
						|
    AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed,
 | 
						|
    DeclSpec::TST TagType, Decl *Tag) {
 | 
						|
  assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
 | 
						|
  ParsingOpenMPDirectiveRAII DirScope(*this);
 | 
						|
  ParenBraceBracketBalancer BalancerRAIIObj(*this);
 | 
						|
 | 
						|
  SourceLocation Loc;
 | 
						|
  OpenMPDirectiveKind DKind;
 | 
						|
  if (Delayed) {
 | 
						|
    TentativeParsingAction TPA(*this);
 | 
						|
    Loc = ConsumeAnnotationToken();
 | 
						|
    DKind = parseOpenMPDirectiveKind(*this);
 | 
						|
    if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) {
 | 
						|
      // Need to delay parsing until completion of the parent class.
 | 
						|
      TPA.Revert();
 | 
						|
      CachedTokens Toks;
 | 
						|
      unsigned Cnt = 1;
 | 
						|
      Toks.push_back(Tok);
 | 
						|
      while (Cnt && Tok.isNot(tok::eof)) {
 | 
						|
        (void)ConsumeAnyToken();
 | 
						|
        if (Tok.is(tok::annot_pragma_openmp))
 | 
						|
          ++Cnt;
 | 
						|
        else if (Tok.is(tok::annot_pragma_openmp_end))
 | 
						|
          --Cnt;
 | 
						|
        Toks.push_back(Tok);
 | 
						|
      }
 | 
						|
      // Skip last annot_pragma_openmp_end.
 | 
						|
      if (Cnt == 0)
 | 
						|
        (void)ConsumeAnyToken();
 | 
						|
      auto *LP = new LateParsedPragma(this, AS);
 | 
						|
      LP->takeToks(Toks);
 | 
						|
      getCurrentClass().LateParsedDeclarations.push_back(LP);
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
    TPA.Commit();
 | 
						|
  } else {
 | 
						|
    Loc = ConsumeAnnotationToken();
 | 
						|
    DKind = parseOpenMPDirectiveKind(*this);
 | 
						|
  }
 | 
						|
 | 
						|
  switch (DKind) {
 | 
						|
  case OMPD_threadprivate: {
 | 
						|
    ConsumeToken();
 | 
						|
    DeclDirectiveListParserHelper Helper(this, DKind);
 | 
						|
    if (!ParseOpenMPSimpleVarList(DKind, Helper,
 | 
						|
                                  /*AllowScopeSpecifier=*/true)) {
 | 
						|
      skipUntilPragmaOpenMPEnd(DKind);
 | 
						|
      // Skip the last annot_pragma_openmp_end.
 | 
						|
      ConsumeAnnotationToken();
 | 
						|
      return Actions.ActOnOpenMPThreadprivateDirective(Loc,
 | 
						|
                                                       Helper.getIdentifiers());
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_allocate: {
 | 
						|
    ConsumeToken();
 | 
						|
    DeclDirectiveListParserHelper Helper(this, DKind);
 | 
						|
    if (!ParseOpenMPSimpleVarList(DKind, Helper,
 | 
						|
                                  /*AllowScopeSpecifier=*/true)) {
 | 
						|
      SmallVector<OMPClause *, 1> Clauses;
 | 
						|
      if (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
        SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
 | 
						|
                    llvm::omp::Clause_enumSize + 1>
 | 
						|
            FirstClauses(llvm::omp::Clause_enumSize + 1);
 | 
						|
        while (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
          OpenMPClauseKind CKind =
 | 
						|
              Tok.isAnnotation() ? OMPC_unknown
 | 
						|
                                 : getOpenMPClauseKind(PP.getSpelling(Tok));
 | 
						|
          Actions.StartOpenMPClause(CKind);
 | 
						|
          OMPClause *Clause = ParseOpenMPClause(
 | 
						|
              OMPD_allocate, CKind, !FirstClauses[unsigned(CKind)].getInt());
 | 
						|
          SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
 | 
						|
                    StopBeforeMatch);
 | 
						|
          FirstClauses[unsigned(CKind)].setInt(true);
 | 
						|
          if (Clause != nullptr)
 | 
						|
            Clauses.push_back(Clause);
 | 
						|
          if (Tok.is(tok::annot_pragma_openmp_end)) {
 | 
						|
            Actions.EndOpenMPClause();
 | 
						|
            break;
 | 
						|
          }
 | 
						|
          // Skip ',' if any.
 | 
						|
          if (Tok.is(tok::comma))
 | 
						|
            ConsumeToken();
 | 
						|
          Actions.EndOpenMPClause();
 | 
						|
        }
 | 
						|
        skipUntilPragmaOpenMPEnd(DKind);
 | 
						|
      }
 | 
						|
      // Skip the last annot_pragma_openmp_end.
 | 
						|
      ConsumeAnnotationToken();
 | 
						|
      return Actions.ActOnOpenMPAllocateDirective(Loc, Helper.getIdentifiers(),
 | 
						|
                                                  Clauses);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_requires: {
 | 
						|
    SourceLocation StartLoc = ConsumeToken();
 | 
						|
    SmallVector<OMPClause *, 5> Clauses;
 | 
						|
    SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
 | 
						|
                llvm::omp::Clause_enumSize + 1>
 | 
						|
        FirstClauses(llvm::omp::Clause_enumSize + 1);
 | 
						|
    if (Tok.is(tok::annot_pragma_openmp_end)) {
 | 
						|
      Diag(Tok, diag::err_omp_expected_clause)
 | 
						|
          << getOpenMPDirectiveName(OMPD_requires);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
      OpenMPClauseKind CKind = Tok.isAnnotation()
 | 
						|
                                   ? OMPC_unknown
 | 
						|
                                   : getOpenMPClauseKind(PP.getSpelling(Tok));
 | 
						|
      Actions.StartOpenMPClause(CKind);
 | 
						|
      OMPClause *Clause = ParseOpenMPClause(
 | 
						|
          OMPD_requires, CKind, !FirstClauses[unsigned(CKind)].getInt());
 | 
						|
      SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
      FirstClauses[unsigned(CKind)].setInt(true);
 | 
						|
      if (Clause != nullptr)
 | 
						|
        Clauses.push_back(Clause);
 | 
						|
      if (Tok.is(tok::annot_pragma_openmp_end)) {
 | 
						|
        Actions.EndOpenMPClause();
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      // Skip ',' if any.
 | 
						|
      if (Tok.is(tok::comma))
 | 
						|
        ConsumeToken();
 | 
						|
      Actions.EndOpenMPClause();
 | 
						|
    }
 | 
						|
    // Consume final annot_pragma_openmp_end
 | 
						|
    if (Clauses.empty()) {
 | 
						|
      Diag(Tok, diag::err_omp_expected_clause)
 | 
						|
          << getOpenMPDirectiveName(OMPD_requires);
 | 
						|
      ConsumeAnnotationToken();
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
    ConsumeAnnotationToken();
 | 
						|
    return Actions.ActOnOpenMPRequiresDirective(StartLoc, Clauses);
 | 
						|
  }
 | 
						|
  case OMPD_declare_reduction:
 | 
						|
    ConsumeToken();
 | 
						|
    if (DeclGroupPtrTy Res = ParseOpenMPDeclareReductionDirective(AS)) {
 | 
						|
      skipUntilPragmaOpenMPEnd(OMPD_declare_reduction);
 | 
						|
      // Skip the last annot_pragma_openmp_end.
 | 
						|
      ConsumeAnnotationToken();
 | 
						|
      return Res;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case OMPD_declare_mapper: {
 | 
						|
    ConsumeToken();
 | 
						|
    if (DeclGroupPtrTy Res = ParseOpenMPDeclareMapperDirective(AS)) {
 | 
						|
      // Skip the last annot_pragma_openmp_end.
 | 
						|
      ConsumeAnnotationToken();
 | 
						|
      return Res;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_begin_declare_variant: {
 | 
						|
    // The syntax is:
 | 
						|
    // { #pragma omp begin declare variant clause }
 | 
						|
    // <function-declaration-or-definition-sequence>
 | 
						|
    // { #pragma omp end declare variant }
 | 
						|
    //
 | 
						|
    ConsumeToken();
 | 
						|
    OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
 | 
						|
    if (parseOMPDeclareVariantMatchClause(Loc, TI))
 | 
						|
      break;
 | 
						|
 | 
						|
    // Skip last tokens.
 | 
						|
    skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant);
 | 
						|
 | 
						|
    ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
 | 
						|
 | 
						|
    VariantMatchInfo VMI;
 | 
						|
    ASTContext &ASTCtx = Actions.getASTContext();
 | 
						|
    TI.getAsVariantMatchInfo(ASTCtx, VMI);
 | 
						|
    OMPContext OMPCtx(ASTCtx.getLangOpts().OpenMPIsDevice,
 | 
						|
                      ASTCtx.getTargetInfo().getTriple());
 | 
						|
 | 
						|
    if (isVariantApplicableInContext(VMI, OMPCtx, /* DeviceSetOnly */ true)) {
 | 
						|
      Actions.ActOnOpenMPBeginDeclareVariant(Loc, TI);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    // Elide all the code till the matching end declare variant was found.
 | 
						|
    unsigned Nesting = 1;
 | 
						|
    SourceLocation DKLoc;
 | 
						|
    OpenMPDirectiveKind DK = OMPD_unknown;
 | 
						|
    do {
 | 
						|
      DKLoc = Tok.getLocation();
 | 
						|
      DK = parseOpenMPDirectiveKind(*this);
 | 
						|
      if (DK == OMPD_end_declare_variant)
 | 
						|
        --Nesting;
 | 
						|
      else if (DK == OMPD_begin_declare_variant)
 | 
						|
        ++Nesting;
 | 
						|
      if (!Nesting || isEofOrEom())
 | 
						|
        break;
 | 
						|
      ConsumeAnyToken();
 | 
						|
    } while (true);
 | 
						|
 | 
						|
    parseOMPEndDirective(OMPD_begin_declare_variant, OMPD_end_declare_variant,
 | 
						|
                         DK, Loc, DKLoc, /* SkipUntilOpenMPEnd */ true);
 | 
						|
    if (isEofOrEom())
 | 
						|
      return nullptr;
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_end_declare_variant: {
 | 
						|
    if (Actions.isInOpenMPDeclareVariantScope())
 | 
						|
      Actions.ActOnOpenMPEndDeclareVariant();
 | 
						|
    else
 | 
						|
      Diag(Loc, diag::err_expected_begin_declare_variant);
 | 
						|
    ConsumeToken();
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_declare_variant:
 | 
						|
  case OMPD_declare_simd: {
 | 
						|
    // The syntax is:
 | 
						|
    // { #pragma omp declare {simd|variant} }
 | 
						|
    // <function-declaration-or-definition>
 | 
						|
    //
 | 
						|
    CachedTokens Toks;
 | 
						|
    Toks.push_back(Tok);
 | 
						|
    ConsumeToken();
 | 
						|
    while(Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
      Toks.push_back(Tok);
 | 
						|
      ConsumeAnyToken();
 | 
						|
    }
 | 
						|
    Toks.push_back(Tok);
 | 
						|
    ConsumeAnyToken();
 | 
						|
 | 
						|
    DeclGroupPtrTy Ptr;
 | 
						|
    if (Tok.is(tok::annot_pragma_openmp)) {
 | 
						|
      Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed,
 | 
						|
                                                       TagType, Tag);
 | 
						|
    } else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
 | 
						|
      // Here we expect to see some function declaration.
 | 
						|
      if (AS == AS_none) {
 | 
						|
        assert(TagType == DeclSpec::TST_unspecified);
 | 
						|
        MaybeParseCXX11Attributes(Attrs);
 | 
						|
        ParsingDeclSpec PDS(*this);
 | 
						|
        Ptr = ParseExternalDeclaration(Attrs, &PDS);
 | 
						|
      } else {
 | 
						|
        Ptr =
 | 
						|
            ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (!Ptr) {
 | 
						|
      Diag(Loc, diag::err_omp_decl_in_declare_simd_variant)
 | 
						|
          << (DKind == OMPD_declare_simd ? 0 : 1);
 | 
						|
      return DeclGroupPtrTy();
 | 
						|
    }
 | 
						|
    if (DKind == OMPD_declare_simd)
 | 
						|
      return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc);
 | 
						|
    assert(DKind == OMPD_declare_variant &&
 | 
						|
           "Expected declare variant directive only");
 | 
						|
    ParseOMPDeclareVariantClauses(Ptr, Toks, Loc);
 | 
						|
    return Ptr;
 | 
						|
  }
 | 
						|
  case OMPD_declare_target: {
 | 
						|
    SourceLocation DTLoc = ConsumeAnyToken();
 | 
						|
    if (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
      return ParseOMPDeclareTargetClauses();
 | 
						|
    }
 | 
						|
 | 
						|
    // Skip the last annot_pragma_openmp_end.
 | 
						|
    ConsumeAnyToken();
 | 
						|
 | 
						|
    if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc))
 | 
						|
      return DeclGroupPtrTy();
 | 
						|
 | 
						|
    ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
 | 
						|
    llvm::SmallVector<Decl *, 4>  Decls;
 | 
						|
    DKind = parseOpenMPDirectiveKind(*this);
 | 
						|
    while (DKind != OMPD_end_declare_target && Tok.isNot(tok::eof) &&
 | 
						|
           Tok.isNot(tok::r_brace)) {
 | 
						|
      DeclGroupPtrTy Ptr;
 | 
						|
      // Here we expect to see some function declaration.
 | 
						|
      if (AS == AS_none) {
 | 
						|
        assert(TagType == DeclSpec::TST_unspecified);
 | 
						|
        MaybeParseCXX11Attributes(Attrs);
 | 
						|
        ParsingDeclSpec PDS(*this);
 | 
						|
        Ptr = ParseExternalDeclaration(Attrs, &PDS);
 | 
						|
      } else {
 | 
						|
        Ptr =
 | 
						|
            ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);
 | 
						|
      }
 | 
						|
      if (Ptr) {
 | 
						|
        DeclGroupRef Ref = Ptr.get();
 | 
						|
        Decls.append(Ref.begin(), Ref.end());
 | 
						|
      }
 | 
						|
      if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) {
 | 
						|
        TentativeParsingAction TPA(*this);
 | 
						|
        ConsumeAnnotationToken();
 | 
						|
        DKind = parseOpenMPDirectiveKind(*this);
 | 
						|
        if (DKind != OMPD_end_declare_target)
 | 
						|
          TPA.Revert();
 | 
						|
        else
 | 
						|
          TPA.Commit();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    ParseOMPEndDeclareTargetDirective(DKind, DTLoc);
 | 
						|
    Actions.ActOnFinishOpenMPDeclareTargetDirective();
 | 
						|
    return Actions.BuildDeclaratorGroup(Decls);
 | 
						|
  }
 | 
						|
  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_taskgroup:
 | 
						|
  case OMPD_flush:
 | 
						|
  case OMPD_depobj:
 | 
						|
  case OMPD_scan:
 | 
						|
  case OMPD_for:
 | 
						|
  case OMPD_for_simd:
 | 
						|
  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_for_simd:
 | 
						|
  case OMPD_parallel_sections:
 | 
						|
  case OMPD_parallel_master:
 | 
						|
  case OMPD_atomic:
 | 
						|
  case OMPD_target:
 | 
						|
  case OMPD_teams:
 | 
						|
  case OMPD_cancellation_point:
 | 
						|
  case OMPD_cancel:
 | 
						|
  case OMPD_target_data:
 | 
						|
  case OMPD_target_enter_data:
 | 
						|
  case OMPD_target_exit_data:
 | 
						|
  case OMPD_target_parallel:
 | 
						|
  case OMPD_target_parallel_for:
 | 
						|
  case OMPD_taskloop:
 | 
						|
  case OMPD_taskloop_simd:
 | 
						|
  case OMPD_master_taskloop:
 | 
						|
  case OMPD_master_taskloop_simd:
 | 
						|
  case OMPD_parallel_master_taskloop:
 | 
						|
  case OMPD_parallel_master_taskloop_simd:
 | 
						|
  case OMPD_distribute:
 | 
						|
  case OMPD_end_declare_target:
 | 
						|
  case OMPD_target_update:
 | 
						|
  case OMPD_distribute_parallel_for:
 | 
						|
  case OMPD_distribute_parallel_for_simd:
 | 
						|
  case OMPD_distribute_simd:
 | 
						|
  case OMPD_target_parallel_for_simd:
 | 
						|
  case OMPD_target_simd:
 | 
						|
  case OMPD_teams_distribute:
 | 
						|
  case OMPD_teams_distribute_simd:
 | 
						|
  case OMPD_teams_distribute_parallel_for_simd:
 | 
						|
  case OMPD_teams_distribute_parallel_for:
 | 
						|
  case OMPD_target_teams:
 | 
						|
  case OMPD_target_teams_distribute:
 | 
						|
  case OMPD_target_teams_distribute_parallel_for:
 | 
						|
  case OMPD_target_teams_distribute_parallel_for_simd:
 | 
						|
  case OMPD_target_teams_distribute_simd:
 | 
						|
    Diag(Tok, diag::err_omp_unexpected_directive)
 | 
						|
        << 1 << getOpenMPDirectiveName(DKind);
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  while (Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
    ConsumeAnyToken();
 | 
						|
  ConsumeAnyToken();
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
/// Parsing of declarative or executable OpenMP directives.
 | 
						|
///
 | 
						|
///       threadprivate-directive:
 | 
						|
///         annot_pragma_openmp 'threadprivate' simple-variable-list
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
///       allocate-directive:
 | 
						|
///         annot_pragma_openmp 'allocate' simple-variable-list
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
///       declare-reduction-directive:
 | 
						|
///         annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':'
 | 
						|
///         <type> {',' <type>} ':' <expression> ')' ['initializer' '('
 | 
						|
///         ('omp_priv' '=' <expression>|<function_call>) ')']
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
///       declare-mapper-directive:
 | 
						|
///         annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':']
 | 
						|
///         <type> <var> ')' [<clause>[[,] <clause>] ... ]
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
///       executable-directive:
 | 
						|
///         annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
 | 
						|
///         'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
 | 
						|
///         'parallel for' | 'parallel sections' | 'parallel master' | 'task' |
 | 
						|
///         'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' |
 | 
						|
///         'atomic' | 'for simd' | 'parallel for simd' | 'target' | 'target
 | 
						|
///         data' | 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' |
 | 
						|
///         'master taskloop' | 'master taskloop simd' | 'parallel master
 | 
						|
///         taskloop' | 'parallel master taskloop simd' | 'distribute' | 'target
 | 
						|
///         enter data' | 'target exit data' | 'target parallel' | 'target
 | 
						|
///         parallel for' | 'target update' | 'distribute parallel for' |
 | 
						|
///         'distribute paralle for simd' | 'distribute simd' | 'target parallel
 | 
						|
///         for simd' | 'target simd' | 'teams distribute' | 'teams distribute
 | 
						|
///         simd' | 'teams distribute parallel for simd' | 'teams distribute
 | 
						|
///         parallel for' | 'target teams' | 'target teams distribute' | 'target
 | 
						|
///         teams distribute parallel for' | 'target teams distribute parallel
 | 
						|
///         for simd' | 'target teams distribute simd' {clause}
 | 
						|
///         annot_pragma_openmp_end
 | 
						|
///
 | 
						|
StmtResult
 | 
						|
Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
 | 
						|
  assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
 | 
						|
  ParsingOpenMPDirectiveRAII DirScope(*this);
 | 
						|
  ParenBraceBracketBalancer BalancerRAIIObj(*this);
 | 
						|
  SmallVector<OMPClause *, 5> Clauses;
 | 
						|
  SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
 | 
						|
              llvm::omp::Clause_enumSize + 1>
 | 
						|
      FirstClauses(llvm::omp::Clause_enumSize + 1);
 | 
						|
  unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
 | 
						|
                        Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
 | 
						|
  SourceLocation Loc = ConsumeAnnotationToken(), EndLoc;
 | 
						|
  OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this);
 | 
						|
  OpenMPDirectiveKind CancelRegion = OMPD_unknown;
 | 
						|
  // Name of critical directive.
 | 
						|
  DeclarationNameInfo DirName;
 | 
						|
  StmtResult Directive = StmtError();
 | 
						|
  bool HasAssociatedStatement = true;
 | 
						|
 | 
						|
  switch (DKind) {
 | 
						|
  case OMPD_threadprivate: {
 | 
						|
    // FIXME: Should this be permitted in C++?
 | 
						|
    if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) ==
 | 
						|
        ParsedStmtContext()) {
 | 
						|
      Diag(Tok, diag::err_omp_immediate_directive)
 | 
						|
          << getOpenMPDirectiveName(DKind) << 0;
 | 
						|
    }
 | 
						|
    ConsumeToken();
 | 
						|
    DeclDirectiveListParserHelper Helper(this, DKind);
 | 
						|
    if (!ParseOpenMPSimpleVarList(DKind, Helper,
 | 
						|
                                  /*AllowScopeSpecifier=*/false)) {
 | 
						|
      skipUntilPragmaOpenMPEnd(DKind);
 | 
						|
      DeclGroupPtrTy Res = Actions.ActOnOpenMPThreadprivateDirective(
 | 
						|
          Loc, Helper.getIdentifiers());
 | 
						|
      Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
 | 
						|
    }
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_allocate: {
 | 
						|
    // FIXME: Should this be permitted in C++?
 | 
						|
    if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) ==
 | 
						|
        ParsedStmtContext()) {
 | 
						|
      Diag(Tok, diag::err_omp_immediate_directive)
 | 
						|
          << getOpenMPDirectiveName(DKind) << 0;
 | 
						|
    }
 | 
						|
    ConsumeToken();
 | 
						|
    DeclDirectiveListParserHelper Helper(this, DKind);
 | 
						|
    if (!ParseOpenMPSimpleVarList(DKind, Helper,
 | 
						|
                                  /*AllowScopeSpecifier=*/false)) {
 | 
						|
      SmallVector<OMPClause *, 1> Clauses;
 | 
						|
      if (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
        SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
 | 
						|
                    llvm::omp::Clause_enumSize + 1>
 | 
						|
            FirstClauses(llvm::omp::Clause_enumSize + 1);
 | 
						|
        while (Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
          OpenMPClauseKind CKind =
 | 
						|
              Tok.isAnnotation() ? OMPC_unknown
 | 
						|
                                 : getOpenMPClauseKind(PP.getSpelling(Tok));
 | 
						|
          Actions.StartOpenMPClause(CKind);
 | 
						|
          OMPClause *Clause = ParseOpenMPClause(
 | 
						|
              OMPD_allocate, CKind, !FirstClauses[unsigned(CKind)].getInt());
 | 
						|
          SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
 | 
						|
                    StopBeforeMatch);
 | 
						|
          FirstClauses[unsigned(CKind)].setInt(true);
 | 
						|
          if (Clause != nullptr)
 | 
						|
            Clauses.push_back(Clause);
 | 
						|
          if (Tok.is(tok::annot_pragma_openmp_end)) {
 | 
						|
            Actions.EndOpenMPClause();
 | 
						|
            break;
 | 
						|
          }
 | 
						|
          // Skip ',' if any.
 | 
						|
          if (Tok.is(tok::comma))
 | 
						|
            ConsumeToken();
 | 
						|
          Actions.EndOpenMPClause();
 | 
						|
        }
 | 
						|
        skipUntilPragmaOpenMPEnd(DKind);
 | 
						|
      }
 | 
						|
      DeclGroupPtrTy Res = Actions.ActOnOpenMPAllocateDirective(
 | 
						|
          Loc, Helper.getIdentifiers(), Clauses);
 | 
						|
      Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
 | 
						|
    }
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_declare_reduction:
 | 
						|
    ConsumeToken();
 | 
						|
    if (DeclGroupPtrTy Res =
 | 
						|
            ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) {
 | 
						|
      skipUntilPragmaOpenMPEnd(OMPD_declare_reduction);
 | 
						|
      ConsumeAnyToken();
 | 
						|
      Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
 | 
						|
    } else {
 | 
						|
      SkipUntil(tok::annot_pragma_openmp_end);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case OMPD_declare_mapper: {
 | 
						|
    ConsumeToken();
 | 
						|
    if (DeclGroupPtrTy Res =
 | 
						|
            ParseOpenMPDeclareMapperDirective(/*AS=*/AS_none)) {
 | 
						|
      // Skip the last annot_pragma_openmp_end.
 | 
						|
      ConsumeAnnotationToken();
 | 
						|
      Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
 | 
						|
    } else {
 | 
						|
      SkipUntil(tok::annot_pragma_openmp_end);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_flush:
 | 
						|
  case OMPD_depobj:
 | 
						|
  case OMPD_scan:
 | 
						|
  case OMPD_taskyield:
 | 
						|
  case OMPD_barrier:
 | 
						|
  case OMPD_taskwait:
 | 
						|
  case OMPD_cancellation_point:
 | 
						|
  case OMPD_cancel:
 | 
						|
  case OMPD_target_enter_data:
 | 
						|
  case OMPD_target_exit_data:
 | 
						|
  case OMPD_target_update:
 | 
						|
    if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
 | 
						|
        ParsedStmtContext()) {
 | 
						|
      Diag(Tok, diag::err_omp_immediate_directive)
 | 
						|
          << getOpenMPDirectiveName(DKind) << 0;
 | 
						|
    }
 | 
						|
    HasAssociatedStatement = false;
 | 
						|
    // Fall through for further analysis.
 | 
						|
    LLVM_FALLTHROUGH;
 | 
						|
  case OMPD_parallel:
 | 
						|
  case OMPD_simd:
 | 
						|
  case OMPD_for:
 | 
						|
  case OMPD_for_simd:
 | 
						|
  case OMPD_sections:
 | 
						|
  case OMPD_single:
 | 
						|
  case OMPD_section:
 | 
						|
  case OMPD_master:
 | 
						|
  case OMPD_critical:
 | 
						|
  case OMPD_parallel_for:
 | 
						|
  case OMPD_parallel_for_simd:
 | 
						|
  case OMPD_parallel_sections:
 | 
						|
  case OMPD_parallel_master:
 | 
						|
  case OMPD_task:
 | 
						|
  case OMPD_ordered:
 | 
						|
  case OMPD_atomic:
 | 
						|
  case OMPD_target:
 | 
						|
  case OMPD_teams:
 | 
						|
  case OMPD_taskgroup:
 | 
						|
  case OMPD_target_data:
 | 
						|
  case OMPD_target_parallel:
 | 
						|
  case OMPD_target_parallel_for:
 | 
						|
  case OMPD_taskloop:
 | 
						|
  case OMPD_taskloop_simd:
 | 
						|
  case OMPD_master_taskloop:
 | 
						|
  case OMPD_master_taskloop_simd:
 | 
						|
  case OMPD_parallel_master_taskloop:
 | 
						|
  case OMPD_parallel_master_taskloop_simd:
 | 
						|
  case OMPD_distribute:
 | 
						|
  case OMPD_distribute_parallel_for:
 | 
						|
  case OMPD_distribute_parallel_for_simd:
 | 
						|
  case OMPD_distribute_simd:
 | 
						|
  case OMPD_target_parallel_for_simd:
 | 
						|
  case OMPD_target_simd:
 | 
						|
  case OMPD_teams_distribute:
 | 
						|
  case OMPD_teams_distribute_simd:
 | 
						|
  case OMPD_teams_distribute_parallel_for_simd:
 | 
						|
  case OMPD_teams_distribute_parallel_for:
 | 
						|
  case OMPD_target_teams:
 | 
						|
  case OMPD_target_teams_distribute:
 | 
						|
  case OMPD_target_teams_distribute_parallel_for:
 | 
						|
  case OMPD_target_teams_distribute_parallel_for_simd:
 | 
						|
  case OMPD_target_teams_distribute_simd: {
 | 
						|
    // Special processing for flush and depobj clauses.
 | 
						|
    Token ImplicitTok;
 | 
						|
    bool ImplicitClauseAllowed = false;
 | 
						|
    if (DKind == OMPD_flush || DKind == OMPD_depobj) {
 | 
						|
      ImplicitTok = Tok;
 | 
						|
      ImplicitClauseAllowed = true;
 | 
						|
    }
 | 
						|
    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();
 | 
						|
      }
 | 
						|
    } else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) {
 | 
						|
      CancelRegion = parseOpenMPDirectiveKind(*this);
 | 
						|
      if (Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
        ConsumeToken();
 | 
						|
    }
 | 
						|
 | 
						|
    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)) {
 | 
						|
      bool HasImplicitClause = false;
 | 
						|
      if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) {
 | 
						|
        HasImplicitClause = true;
 | 
						|
        // Push copy of the current token back to stream to properly parse
 | 
						|
        // pseudo-clause OMPFlushClause or OMPDepobjClause.
 | 
						|
        PP.EnterToken(Tok, /*IsReinject*/ true);
 | 
						|
        PP.EnterToken(ImplicitTok, /*IsReinject*/ true);
 | 
						|
        ConsumeAnyToken();
 | 
						|
      }
 | 
						|
      OpenMPClauseKind CKind = Tok.isAnnotation()
 | 
						|
                                   ? OMPC_unknown
 | 
						|
                                   : getOpenMPClauseKind(PP.getSpelling(Tok));
 | 
						|
      if (HasImplicitClause) {
 | 
						|
        assert(CKind == OMPC_unknown && "Must be unknown implicit clause.");
 | 
						|
        if (DKind == OMPD_flush) {
 | 
						|
          CKind = OMPC_flush;
 | 
						|
        } else {
 | 
						|
          assert(DKind == OMPD_depobj &&
 | 
						|
                 "Expected flush or depobj directives.");
 | 
						|
          CKind = OMPC_depobj;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      // No more implicit clauses allowed.
 | 
						|
      ImplicitClauseAllowed = false;
 | 
						|
      Actions.StartOpenMPClause(CKind);
 | 
						|
      HasImplicitClause = false;
 | 
						|
      OMPClause *Clause = ParseOpenMPClause(
 | 
						|
          DKind, CKind, !FirstClauses[unsigned(CKind)].getInt());
 | 
						|
      FirstClauses[unsigned(CKind)].setInt(true);
 | 
						|
      if (Clause) {
 | 
						|
        FirstClauses[unsigned(CKind)].setPointer(Clause);
 | 
						|
        Clauses.push_back(Clause);
 | 
						|
      }
 | 
						|
 | 
						|
      // Skip ',' if any.
 | 
						|
      if (Tok.is(tok::comma))
 | 
						|
        ConsumeToken();
 | 
						|
      Actions.EndOpenMPClause();
 | 
						|
    }
 | 
						|
    // End location of the directive.
 | 
						|
    EndLoc = Tok.getLocation();
 | 
						|
    // Consume final annot_pragma_openmp_end.
 | 
						|
    ConsumeAnnotationToken();
 | 
						|
 | 
						|
    // OpenMP [2.13.8, ordered Construct, Syntax]
 | 
						|
    // If the depend clause is specified, the ordered construct is a stand-alone
 | 
						|
    // directive.
 | 
						|
    if (DKind == OMPD_ordered && FirstClauses[unsigned(OMPC_depend)].getInt()) {
 | 
						|
      if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
 | 
						|
          ParsedStmtContext()) {
 | 
						|
        Diag(Loc, diag::err_omp_immediate_directive)
 | 
						|
            << getOpenMPDirectiveName(DKind) << 1
 | 
						|
            << getOpenMPClauseName(OMPC_depend);
 | 
						|
      }
 | 
						|
      HasAssociatedStatement = false;
 | 
						|
    }
 | 
						|
 | 
						|
    StmtResult AssociatedStmt;
 | 
						|
    if (HasAssociatedStatement) {
 | 
						|
      // The body is a block scope like in Lambdas and Blocks.
 | 
						|
      Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
 | 
						|
      // FIXME: We create a bogus CompoundStmt scope to hold the contents of
 | 
						|
      // the captured region. Code elsewhere assumes that any FunctionScopeInfo
 | 
						|
      // should have at least one compound statement scope within it.
 | 
						|
      ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
 | 
						|
      AssociatedStmt = (Sema::CompoundScopeRAII(Actions), ParseStatement());
 | 
						|
      AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
 | 
						|
    } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data ||
 | 
						|
               DKind == OMPD_target_exit_data) {
 | 
						|
      Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
 | 
						|
      AssociatedStmt = (Sema::CompoundScopeRAII(Actions),
 | 
						|
                        Actions.ActOnCompoundStmt(Loc, Loc, llvm::None,
 | 
						|
                                                  /*isStmtExpr=*/false));
 | 
						|
      AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
 | 
						|
    }
 | 
						|
    Directive = Actions.ActOnOpenMPExecutableDirective(
 | 
						|
        DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc,
 | 
						|
        EndLoc);
 | 
						|
 | 
						|
    // Exit scope.
 | 
						|
    Actions.EndOpenMPDSABlock(Directive.get());
 | 
						|
    OMPDirectiveScope.Exit();
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case OMPD_declare_simd:
 | 
						|
  case OMPD_declare_target:
 | 
						|
  case OMPD_end_declare_target:
 | 
						|
  case OMPD_requires:
 | 
						|
  case OMPD_begin_declare_variant:
 | 
						|
  case OMPD_end_declare_variant:
 | 
						|
  case OMPD_declare_variant:
 | 
						|
    Diag(Tok, diag::err_omp_unexpected_directive)
 | 
						|
        << 1 << getOpenMPDirectiveName(DKind);
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end);
 | 
						|
    break;
 | 
						|
  case OMPD_unknown:
 | 
						|
  default:
 | 
						|
    Diag(Tok, diag::err_omp_unknown_directive);
 | 
						|
    SkipUntil(tok::annot_pragma_openmp_end);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  return Directive;
 | 
						|
}
 | 
						|
 | 
						|
// Parses simple list:
 | 
						|
//   simple-variable-list:
 | 
						|
//         '(' id-expression {, id-expression} ')'
 | 
						|
//
 | 
						|
bool Parser::ParseOpenMPSimpleVarList(
 | 
						|
    OpenMPDirectiveKind Kind,
 | 
						|
    const llvm::function_ref<void(CXXScopeSpec &, DeclarationNameInfo)> &
 | 
						|
        Callback,
 | 
						|
    bool AllowScopeSpecifier) {
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPDirectiveName(Kind).data()))
 | 
						|
    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;
 | 
						|
    UnqualifiedId Name;
 | 
						|
    // Read var name.
 | 
						|
    Token PrevTok = Tok;
 | 
						|
    NoIdentIsFound = false;
 | 
						|
 | 
						|
    if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
 | 
						|
        ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
 | 
						|
                                       /*ObjectHadErrors=*/false, false)) {
 | 
						|
      IsCorrect = false;
 | 
						|
      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
    } else if (ParseUnqualifiedId(SS, /*ObjectType=*/nullptr,
 | 
						|
                                  /*ObjectHadErrors=*/false, false, false,
 | 
						|
                                  false, false, nullptr, 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 {
 | 
						|
      Callback(SS, Actions.GetNameFromUnqualifiedId(Name));
 | 
						|
    }
 | 
						|
    // 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;
 | 
						|
}
 | 
						|
 | 
						|
OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {
 | 
						|
  SourceLocation Loc = Tok.getLocation();
 | 
						|
  ConsumeAnyToken();
 | 
						|
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after, "uses_allocator"))
 | 
						|
    return nullptr;
 | 
						|
  SmallVector<Sema::UsesAllocatorsData, 4> Data;
 | 
						|
  do {
 | 
						|
    ExprResult Allocator = ParseCXXIdExpression();
 | 
						|
    if (Allocator.isInvalid()) {
 | 
						|
      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    Sema::UsesAllocatorsData &D = Data.emplace_back();
 | 
						|
    D.Allocator = Allocator.get();
 | 
						|
    if (Tok.is(tok::l_paren)) {
 | 
						|
      BalancedDelimiterTracker T(*this, tok::l_paren,
 | 
						|
                                 tok::annot_pragma_openmp_end);
 | 
						|
      T.consumeOpen();
 | 
						|
      ExprResult AllocatorTraits = ParseCXXIdExpression();
 | 
						|
      T.consumeClose();
 | 
						|
      if (AllocatorTraits.isInvalid()) {
 | 
						|
        SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                  StopBeforeMatch);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      D.AllocatorTraits = AllocatorTraits.get();
 | 
						|
      D.LParenLoc = T.getOpenLocation();
 | 
						|
      D.RParenLoc = T.getCloseLocation();
 | 
						|
    }
 | 
						|
    if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren))
 | 
						|
      Diag(Tok, diag::err_omp_expected_punc) << "uses_allocators" << 0;
 | 
						|
    // Parse ','
 | 
						|
    if (Tok.is(tok::comma))
 | 
						|
      ConsumeAnyToken();
 | 
						|
  } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
 | 
						|
  T.consumeClose();
 | 
						|
  return Actions.ActOnOpenMPUsesAllocatorClause(Loc, T.getOpenLocation(),
 | 
						|
                                                T.getCloseLocation(), Data);
 | 
						|
}
 | 
						|
 | 
						|
/// 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 | device-clause |
 | 
						|
///       simdlen-clause | threads-clause | simd-clause | num_teams-clause |
 | 
						|
///       thread_limit-clause | priority-clause | grainsize-clause |
 | 
						|
///       nogroup-clause | num_tasks-clause | hint-clause | to-clause |
 | 
						|
///       from-clause | is_device_ptr-clause | task_reduction-clause |
 | 
						|
///       in_reduction-clause | allocator-clause | allocate-clause |
 | 
						|
///       acq_rel-clause | acquire-clause | release-clause | relaxed-clause |
 | 
						|
///       depobj-clause | destroy-clause | detach-clause | inclusive-clause |
 | 
						|
///       exclusive-clause | uses_allocators-clause | use_device_addr-clause
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
 | 
						|
                                     OpenMPClauseKind CKind, bool FirstClause) {
 | 
						|
  OMPClauseKind = CKind;
 | 
						|
  OMPClause *Clause = nullptr;
 | 
						|
  bool ErrorFound = false;
 | 
						|
  bool WrongDirective = false;
 | 
						|
  // Check if clause is allowed for the given directive.
 | 
						|
  if (CKind != OMPC_unknown &&
 | 
						|
      !isAllowedClauseForDirective(DKind, CKind, getLangOpts().OpenMP)) {
 | 
						|
    Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
 | 
						|
                                               << getOpenMPDirectiveName(DKind);
 | 
						|
    ErrorFound = true;
 | 
						|
    WrongDirective = true;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (CKind) {
 | 
						|
  case OMPC_final:
 | 
						|
  case OMPC_num_threads:
 | 
						|
  case OMPC_safelen:
 | 
						|
  case OMPC_simdlen:
 | 
						|
  case OMPC_collapse:
 | 
						|
  case OMPC_ordered:
 | 
						|
  case OMPC_num_teams:
 | 
						|
  case OMPC_thread_limit:
 | 
						|
  case OMPC_priority:
 | 
						|
  case OMPC_grainsize:
 | 
						|
  case OMPC_num_tasks:
 | 
						|
  case OMPC_hint:
 | 
						|
  case OMPC_allocator:
 | 
						|
  case OMPC_depobj:
 | 
						|
  case OMPC_detach:
 | 
						|
    // OpenMP [2.5, Restrictions]
 | 
						|
    //  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 simdlen  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.
 | 
						|
    // OpenMP [teams Construct, Restrictions]
 | 
						|
    //  At most one num_teams clause can appear on the directive.
 | 
						|
    //  At most one thread_limit clause can appear on the directive.
 | 
						|
    // OpenMP [2.9.1, task Construct, Restrictions]
 | 
						|
    // At most one priority clause can appear on the directive.
 | 
						|
    // OpenMP [2.9.2, taskloop Construct, Restrictions]
 | 
						|
    // At most one grainsize clause can appear on the directive.
 | 
						|
    // OpenMP [2.9.2, taskloop Construct, Restrictions]
 | 
						|
    // At most one num_tasks clause can appear on the directive.
 | 
						|
    // OpenMP [2.11.3, allocate Directive, Restrictions]
 | 
						|
    // At most one allocator clause can appear on the directive.
 | 
						|
    // OpenMP 5.0, 2.10.1 task Construct, Restrictions.
 | 
						|
    // At most one detach clause can appear on the directive.
 | 
						|
    if (!FirstClause) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause)
 | 
						|
          << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
 | 
						|
    if (CKind == OMPC_ordered && PP.LookAhead(/*N=*/0).isNot(tok::l_paren))
 | 
						|
      Clause = ParseOpenMPClause(CKind, WrongDirective);
 | 
						|
    else
 | 
						|
      Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);
 | 
						|
    break;
 | 
						|
  case OMPC_default:
 | 
						|
  case OMPC_proc_bind:
 | 
						|
  case OMPC_atomic_default_mem_order:
 | 
						|
  case OMPC_order:
 | 
						|
    // 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.
 | 
						|
    // OpenMP [5.0, Requires directive, Restrictions]
 | 
						|
    //  At most one atomic_default_mem_order clause can appear
 | 
						|
    //  on the directive
 | 
						|
    if (!FirstClause && CKind != OMPC_order) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause)
 | 
						|
          << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
 | 
						|
    Clause = ParseOpenMPSimpleClause(CKind, WrongDirective);
 | 
						|
    break;
 | 
						|
  case OMPC_device:
 | 
						|
  case OMPC_schedule:
 | 
						|
  case OMPC_dist_schedule:
 | 
						|
  case OMPC_defaultmap:
 | 
						|
    // OpenMP [2.7.1, Restrictions, p. 3]
 | 
						|
    //  Only one schedule clause can appear on a loop directive.
 | 
						|
    // OpenMP 4.5 [2.10.4, Restrictions, p. 106]
 | 
						|
    //  At most one defaultmap clause can appear on the directive.
 | 
						|
    // OpenMP 5.0 [2.12.5, target construct, Restrictions]
 | 
						|
    //  At most one device clause can appear on the directive.
 | 
						|
    if ((getLangOpts().OpenMP < 50 || CKind != OMPC_defaultmap) &&
 | 
						|
        !FirstClause) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause)
 | 
						|
          << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
    LLVM_FALLTHROUGH;
 | 
						|
  case OMPC_if:
 | 
						|
    Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);
 | 
						|
    break;
 | 
						|
  case OMPC_nowait:
 | 
						|
  case OMPC_untied:
 | 
						|
  case OMPC_mergeable:
 | 
						|
  case OMPC_read:
 | 
						|
  case OMPC_write:
 | 
						|
  case OMPC_capture:
 | 
						|
  case OMPC_seq_cst:
 | 
						|
  case OMPC_acq_rel:
 | 
						|
  case OMPC_acquire:
 | 
						|
  case OMPC_release:
 | 
						|
  case OMPC_relaxed:
 | 
						|
  case OMPC_threads:
 | 
						|
  case OMPC_simd:
 | 
						|
  case OMPC_nogroup:
 | 
						|
  case OMPC_unified_address:
 | 
						|
  case OMPC_unified_shared_memory:
 | 
						|
  case OMPC_reverse_offload:
 | 
						|
  case OMPC_dynamic_allocators:
 | 
						|
  case OMPC_destroy:
 | 
						|
    // 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.
 | 
						|
    // OpenMP [5.0, Requires directive, Restrictions]
 | 
						|
    //   Each of the requires clauses can appear at most once on the directive.
 | 
						|
    if (!FirstClause) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause)
 | 
						|
          << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
 | 
						|
    Clause = ParseOpenMPClause(CKind, WrongDirective);
 | 
						|
    break;
 | 
						|
  case OMPC_update:
 | 
						|
    if (!FirstClause) {
 | 
						|
      Diag(Tok, diag::err_omp_more_one_clause)
 | 
						|
          << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
 | 
						|
      ErrorFound = true;
 | 
						|
    }
 | 
						|
 | 
						|
    Clause = (DKind == OMPD_depobj)
 | 
						|
                 ? ParseOpenMPSimpleClause(CKind, WrongDirective)
 | 
						|
                 : ParseOpenMPClause(CKind, WrongDirective);
 | 
						|
    break;
 | 
						|
  case OMPC_private:
 | 
						|
  case OMPC_firstprivate:
 | 
						|
  case OMPC_lastprivate:
 | 
						|
  case OMPC_shared:
 | 
						|
  case OMPC_reduction:
 | 
						|
  case OMPC_task_reduction:
 | 
						|
  case OMPC_in_reduction:
 | 
						|
  case OMPC_linear:
 | 
						|
  case OMPC_aligned:
 | 
						|
  case OMPC_copyin:
 | 
						|
  case OMPC_copyprivate:
 | 
						|
  case OMPC_flush:
 | 
						|
  case OMPC_depend:
 | 
						|
  case OMPC_map:
 | 
						|
  case OMPC_to:
 | 
						|
  case OMPC_from:
 | 
						|
  case OMPC_use_device_ptr:
 | 
						|
  case OMPC_use_device_addr:
 | 
						|
  case OMPC_is_device_ptr:
 | 
						|
  case OMPC_allocate:
 | 
						|
  case OMPC_nontemporal:
 | 
						|
  case OMPC_inclusive:
 | 
						|
  case OMPC_exclusive:
 | 
						|
  case OMPC_affinity:
 | 
						|
    Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);
 | 
						|
    break;
 | 
						|
  case OMPC_uses_allocators:
 | 
						|
    Clause = ParseOpenMPUsesAllocatorClause(DKind);
 | 
						|
    break;
 | 
						|
  case OMPC_device_type:
 | 
						|
  case OMPC_unknown:
 | 
						|
    skipUntilPragmaOpenMPEnd(DKind);
 | 
						|
    break;
 | 
						|
  case OMPC_threadprivate:
 | 
						|
  case OMPC_uniform:
 | 
						|
  case OMPC_match:
 | 
						|
    if (!WrongDirective)
 | 
						|
      Diag(Tok, diag::err_omp_unexpected_clause)
 | 
						|
          << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
 | 
						|
    SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  return ErrorFound ? nullptr : Clause;
 | 
						|
}
 | 
						|
 | 
						|
/// Parses simple expression in parens for single-expression clauses of OpenMP
 | 
						|
/// constructs.
 | 
						|
/// \param RLoc Returned location of right paren.
 | 
						|
ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
 | 
						|
                                         SourceLocation &RLoc,
 | 
						|
                                         bool IsAddressOfOperand) {
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data()))
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  SourceLocation ELoc = Tok.getLocation();
 | 
						|
  ExprResult LHS(ParseCastExpression(AnyCastExpr, IsAddressOfOperand,
 | 
						|
                                     NotTypeCast));
 | 
						|
  ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
 | 
						|
  Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  RLoc = Tok.getLocation();
 | 
						|
  if (!T.consumeClose())
 | 
						|
    RLoc = T.getCloseLocation();
 | 
						|
 | 
						|
  return Val;
 | 
						|
}
 | 
						|
 | 
						|
/// Parsing of OpenMP clauses with single expressions like 'final',
 | 
						|
/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams',
 | 
						|
/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks', 'hint' or
 | 
						|
/// 'detach'.
 | 
						|
///
 | 
						|
///    final-clause:
 | 
						|
///      'final' '(' expression ')'
 | 
						|
///
 | 
						|
///    num_threads-clause:
 | 
						|
///      'num_threads' '(' expression ')'
 | 
						|
///
 | 
						|
///    safelen-clause:
 | 
						|
///      'safelen' '(' expression ')'
 | 
						|
///
 | 
						|
///    simdlen-clause:
 | 
						|
///      'simdlen' '(' expression ')'
 | 
						|
///
 | 
						|
///    collapse-clause:
 | 
						|
///      'collapse' '(' expression ')'
 | 
						|
///
 | 
						|
///    priority-clause:
 | 
						|
///      'priority' '(' expression ')'
 | 
						|
///
 | 
						|
///    grainsize-clause:
 | 
						|
///      'grainsize' '(' expression ')'
 | 
						|
///
 | 
						|
///    num_tasks-clause:
 | 
						|
///      'num_tasks' '(' expression ')'
 | 
						|
///
 | 
						|
///    hint-clause:
 | 
						|
///      'hint' '(' expression ')'
 | 
						|
///
 | 
						|
///    allocator-clause:
 | 
						|
///      'allocator' '(' expression ')'
 | 
						|
///
 | 
						|
///    detach-clause:
 | 
						|
///      'detach' '(' event-handler-expression ')'
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,
 | 
						|
                                               bool ParseOnly) {
 | 
						|
  SourceLocation Loc = ConsumeToken();
 | 
						|
  SourceLocation LLoc = Tok.getLocation();
 | 
						|
  SourceLocation RLoc;
 | 
						|
 | 
						|
  ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc);
 | 
						|
 | 
						|
  if (Val.isInvalid())
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  if (ParseOnly)
 | 
						|
    return nullptr;
 | 
						|
  return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc);
 | 
						|
}
 | 
						|
 | 
						|
/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
 | 
						|
///
 | 
						|
///    default-clause:
 | 
						|
///         'default' '(' 'none' | 'shared' | 'firstprivate' ')'
 | 
						|
///
 | 
						|
///    proc_bind-clause:
 | 
						|
///         'proc_bind' '(' 'master' | 'close' | 'spread' ')'
 | 
						|
///
 | 
						|
///    update-clause:
 | 
						|
///         'update' '(' 'in' | 'out' | 'inout' | 'mutexinoutset' ')'
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind,
 | 
						|
                                           bool ParseOnly) {
 | 
						|
  llvm::Optional<SimpleClauseData> Val = parseOpenMPSimpleClause(*this, Kind);
 | 
						|
  if (!Val || ParseOnly)
 | 
						|
    return nullptr;
 | 
						|
  if (getLangOpts().OpenMP < 51 && Kind == OMPC_default &&
 | 
						|
      static_cast<DefaultKind>(Val.getValue().Type) ==
 | 
						|
          OMP_DEFAULT_firstprivate) {
 | 
						|
    Diag(Val.getValue().LOpen, diag::err_omp_invalid_dsa)
 | 
						|
        << getOpenMPClauseName(OMPC_firstprivate)
 | 
						|
        << getOpenMPClauseName(OMPC_default) << "5.1";
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  return Actions.ActOnOpenMPSimpleClause(
 | 
						|
      Kind, Val.getValue().Type, Val.getValue().TypeLoc, Val.getValue().LOpen,
 | 
						|
      Val.getValue().Loc, Val.getValue().RLoc);
 | 
						|
}
 | 
						|
 | 
						|
/// Parsing of OpenMP clauses like 'ordered'.
 | 
						|
///
 | 
						|
///    ordered-clause:
 | 
						|
///         'ordered'
 | 
						|
///
 | 
						|
///    nowait-clause:
 | 
						|
///         'nowait'
 | 
						|
///
 | 
						|
///    untied-clause:
 | 
						|
///         'untied'
 | 
						|
///
 | 
						|
///    mergeable-clause:
 | 
						|
///         'mergeable'
 | 
						|
///
 | 
						|
///    read-clause:
 | 
						|
///         'read'
 | 
						|
///
 | 
						|
///    threads-clause:
 | 
						|
///         'threads'
 | 
						|
///
 | 
						|
///    simd-clause:
 | 
						|
///         'simd'
 | 
						|
///
 | 
						|
///    nogroup-clause:
 | 
						|
///         'nogroup'
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind, bool ParseOnly) {
 | 
						|
  SourceLocation Loc = Tok.getLocation();
 | 
						|
  ConsumeAnyToken();
 | 
						|
 | 
						|
  if (ParseOnly)
 | 
						|
    return nullptr;
 | 
						|
  return Actions.ActOnOpenMPClause(Kind, Loc, Tok.getLocation());
 | 
						|
}
 | 
						|
 | 
						|
/// Parsing of OpenMP clauses with single expressions and some additional
 | 
						|
/// argument like 'schedule' or 'dist_schedule'.
 | 
						|
///
 | 
						|
///    schedule-clause:
 | 
						|
///      'schedule' '(' [ modifier [ ',' modifier ] ':' ] kind [',' expression ]
 | 
						|
///      ')'
 | 
						|
///
 | 
						|
///    if-clause:
 | 
						|
///      'if' '(' [ directive-name-modifier ':' ] expression ')'
 | 
						|
///
 | 
						|
///    defaultmap:
 | 
						|
///      'defaultmap' '(' modifier [ ':' kind ] ')'
 | 
						|
///
 | 
						|
///    device-clause:
 | 
						|
///      'device' '(' [ device-modifier ':' ] expression ')'
 | 
						|
///
 | 
						|
OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,
 | 
						|
                                                      OpenMPClauseKind Kind,
 | 
						|
                                                      bool ParseOnly) {
 | 
						|
  SourceLocation Loc = ConsumeToken();
 | 
						|
  SourceLocation DelimLoc;
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPClauseName(Kind).data()))
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  ExprResult Val;
 | 
						|
  SmallVector<unsigned, 4> Arg;
 | 
						|
  SmallVector<SourceLocation, 4> KLoc;
 | 
						|
  if (Kind == OMPC_schedule) {
 | 
						|
    enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements };
 | 
						|
    Arg.resize(NumberOfElements);
 | 
						|
    KLoc.resize(NumberOfElements);
 | 
						|
    Arg[Modifier1] = OMPC_SCHEDULE_MODIFIER_unknown;
 | 
						|
    Arg[Modifier2] = OMPC_SCHEDULE_MODIFIER_unknown;
 | 
						|
    Arg[ScheduleKind] = OMPC_SCHEDULE_unknown;
 | 
						|
    unsigned KindModifier = getOpenMPSimpleClauseType(
 | 
						|
        Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
 | 
						|
    if (KindModifier > OMPC_SCHEDULE_unknown) {
 | 
						|
      // Parse 'modifier'
 | 
						|
      Arg[Modifier1] = KindModifier;
 | 
						|
      KLoc[Modifier1] = Tok.getLocation();
 | 
						|
      if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
 | 
						|
          Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
        ConsumeAnyToken();
 | 
						|
      if (Tok.is(tok::comma)) {
 | 
						|
        // Parse ',' 'modifier'
 | 
						|
        ConsumeAnyToken();
 | 
						|
        KindModifier = getOpenMPSimpleClauseType(
 | 
						|
            Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
 | 
						|
        Arg[Modifier2] = KindModifier > OMPC_SCHEDULE_unknown
 | 
						|
                             ? KindModifier
 | 
						|
                             : (unsigned)OMPC_SCHEDULE_unknown;
 | 
						|
        KLoc[Modifier2] = Tok.getLocation();
 | 
						|
        if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
 | 
						|
            Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
          ConsumeAnyToken();
 | 
						|
      }
 | 
						|
      // Parse ':'
 | 
						|
      if (Tok.is(tok::colon))
 | 
						|
        ConsumeAnyToken();
 | 
						|
      else
 | 
						|
        Diag(Tok, diag::warn_pragma_expected_colon) << "schedule modifier";
 | 
						|
      KindModifier = getOpenMPSimpleClauseType(
 | 
						|
          Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
 | 
						|
    }
 | 
						|
    Arg[ScheduleKind] = KindModifier;
 | 
						|
    KLoc[ScheduleKind] = Tok.getLocation();
 | 
						|
    if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
 | 
						|
        Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
      ConsumeAnyToken();
 | 
						|
    if ((Arg[ScheduleKind] == OMPC_SCHEDULE_static ||
 | 
						|
         Arg[ScheduleKind] == OMPC_SCHEDULE_dynamic ||
 | 
						|
         Arg[ScheduleKind] == OMPC_SCHEDULE_guided) &&
 | 
						|
        Tok.is(tok::comma))
 | 
						|
      DelimLoc = ConsumeAnyToken();
 | 
						|
  } else if (Kind == OMPC_dist_schedule) {
 | 
						|
    Arg.push_back(getOpenMPSimpleClauseType(
 | 
						|
        Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)));
 | 
						|
    KLoc.push_back(Tok.getLocation());
 | 
						|
    if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
 | 
						|
        Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
      ConsumeAnyToken();
 | 
						|
    if (Arg.back() == OMPC_DIST_SCHEDULE_static && Tok.is(tok::comma))
 | 
						|
      DelimLoc = ConsumeAnyToken();
 | 
						|
  } else if (Kind == OMPC_defaultmap) {
 | 
						|
    // Get a defaultmap modifier
 | 
						|
    unsigned Modifier = getOpenMPSimpleClauseType(
 | 
						|
        Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
 | 
						|
    // Set defaultmap modifier to unknown if it is either scalar, aggregate, or
 | 
						|
    // pointer
 | 
						|
    if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown)
 | 
						|
      Modifier = OMPC_DEFAULTMAP_MODIFIER_unknown;
 | 
						|
    Arg.push_back(Modifier);
 | 
						|
    KLoc.push_back(Tok.getLocation());
 | 
						|
    if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
 | 
						|
        Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
      ConsumeAnyToken();
 | 
						|
    // Parse ':'
 | 
						|
    if (Tok.is(tok::colon) || getLangOpts().OpenMP < 50) {
 | 
						|
      if (Tok.is(tok::colon))
 | 
						|
        ConsumeAnyToken();
 | 
						|
      else if (Arg.back() != OMPC_DEFAULTMAP_MODIFIER_unknown)
 | 
						|
        Diag(Tok, diag::warn_pragma_expected_colon) << "defaultmap modifier";
 | 
						|
      // Get a defaultmap kind
 | 
						|
      Arg.push_back(getOpenMPSimpleClauseType(
 | 
						|
          Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)));
 | 
						|
      KLoc.push_back(Tok.getLocation());
 | 
						|
      if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
 | 
						|
          Tok.isNot(tok::annot_pragma_openmp_end))
 | 
						|
        ConsumeAnyToken();
 | 
						|
    } else {
 | 
						|
      Arg.push_back(OMPC_DEFAULTMAP_unknown);
 | 
						|
      KLoc.push_back(SourceLocation());
 | 
						|
    }
 | 
						|
  } else if (Kind == OMPC_device) {
 | 
						|
    // Only target executable directives support extended device construct.
 | 
						|
    if (isOpenMPTargetExecutionDirective(DKind) && getLangOpts().OpenMP >= 50 &&
 | 
						|
        NextToken().is(tok::colon)) {
 | 
						|
      // Parse optional <device modifier> ':'
 | 
						|
      Arg.push_back(getOpenMPSimpleClauseType(
 | 
						|
          Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)));
 | 
						|
      KLoc.push_back(Tok.getLocation());
 | 
						|
      ConsumeAnyToken();
 | 
						|
      // Parse ':'
 | 
						|
      ConsumeAnyToken();
 | 
						|
    } else {
 | 
						|
      Arg.push_back(OMPC_DEVICE_unknown);
 | 
						|
      KLoc.emplace_back();
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    assert(Kind == OMPC_if);
 | 
						|
    KLoc.push_back(Tok.getLocation());
 | 
						|
    TentativeParsingAction TPA(*this);
 | 
						|
    auto DK = parseOpenMPDirectiveKind(*this);
 | 
						|
    Arg.push_back(DK);
 | 
						|
    if (DK != OMPD_unknown) {
 | 
						|
      ConsumeToken();
 | 
						|
      if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) {
 | 
						|
        TPA.Commit();
 | 
						|
        DelimLoc = ConsumeToken();
 | 
						|
      } else {
 | 
						|
        TPA.Revert();
 | 
						|
        Arg.back() = unsigned(OMPD_unknown);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      TPA.Revert();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) ||
 | 
						|
                          (Kind == OMPC_dist_schedule && DelimLoc.isValid()) ||
 | 
						|
                          Kind == OMPC_if || Kind == OMPC_device;
 | 
						|
  if (NeedAnExpression) {
 | 
						|
    SourceLocation ELoc = Tok.getLocation();
 | 
						|
    ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast));
 | 
						|
    Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
 | 
						|
    Val =
 | 
						|
        Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  SourceLocation RLoc = Tok.getLocation();
 | 
						|
  if (!T.consumeClose())
 | 
						|
    RLoc = T.getCloseLocation();
 | 
						|
 | 
						|
  if (NeedAnExpression && Val.isInvalid())
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  if (ParseOnly)
 | 
						|
    return nullptr;
 | 
						|
  return Actions.ActOnOpenMPSingleExprWithArgClause(
 | 
						|
      Kind, Arg, Val.get(), Loc, T.getOpenLocation(), KLoc, DelimLoc, RLoc);
 | 
						|
}
 | 
						|
 | 
						|
static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
 | 
						|
                             UnqualifiedId &ReductionId) {
 | 
						|
  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, /*ObjectType=*/nullptr,
 | 
						|
      /*ObjectHadErrors=*/false, /*EnteringContext*/ false,
 | 
						|
      /*AllowDestructorName*/ false,
 | 
						|
      /*AllowConstructorName*/ false,
 | 
						|
      /*AllowDeductionGuide*/ false, nullptr, ReductionId);
 | 
						|
}
 | 
						|
 | 
						|
/// Checks if the token is a valid map-type-modifier.
 | 
						|
static OpenMPMapModifierKind isMapModifier(Parser &P) {
 | 
						|
  Token Tok = P.getCurToken();
 | 
						|
  if (!Tok.is(tok::identifier))
 | 
						|
    return OMPC_MAP_MODIFIER_unknown;
 | 
						|
 | 
						|
  Preprocessor &PP = P.getPreprocessor();
 | 
						|
  OpenMPMapModifierKind TypeModifier = static_cast<OpenMPMapModifierKind>(
 | 
						|
      getOpenMPSimpleClauseType(OMPC_map, PP.getSpelling(Tok)));
 | 
						|
  return TypeModifier;
 | 
						|
}
 | 
						|
 | 
						|
/// Parse the mapper modifier in map, to, and from clauses.
 | 
						|
bool Parser::parseMapperModifier(OpenMPVarListDataTy &Data) {
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::colon);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after, "mapper")) {
 | 
						|
    SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
              StopBeforeMatch);
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  // Parse mapper-identifier
 | 
						|
  if (getLangOpts().CPlusPlus)
 | 
						|
    ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec,
 | 
						|
                                   /*ObjectType=*/nullptr,
 | 
						|
                                   /*ObjectHadErrors=*/false,
 | 
						|
                                   /*EnteringContext=*/false);
 | 
						|
  if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) {
 | 
						|
    Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier);
 | 
						|
    SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
              StopBeforeMatch);
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  auto &DeclNames = Actions.getASTContext().DeclarationNames;
 | 
						|
  Data.ReductionOrMapperId = DeclarationNameInfo(
 | 
						|
      DeclNames.getIdentifier(Tok.getIdentifierInfo()), Tok.getLocation());
 | 
						|
  ConsumeToken();
 | 
						|
  // Parse ')'.
 | 
						|
  return T.consumeClose();
 | 
						|
}
 | 
						|
 | 
						|
/// Parse map-type-modifiers in map clause.
 | 
						|
/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list)
 | 
						|
/// where, map-type-modifier ::= always | close | mapper(mapper-identifier)
 | 
						|
bool Parser::parseMapTypeModifiers(OpenMPVarListDataTy &Data) {
 | 
						|
  while (getCurToken().isNot(tok::colon)) {
 | 
						|
    OpenMPMapModifierKind TypeModifier = isMapModifier(*this);
 | 
						|
    if (TypeModifier == OMPC_MAP_MODIFIER_always ||
 | 
						|
        TypeModifier == OMPC_MAP_MODIFIER_close) {
 | 
						|
      Data.MapTypeModifiers.push_back(TypeModifier);
 | 
						|
      Data.MapTypeModifiersLoc.push_back(Tok.getLocation());
 | 
						|
      ConsumeToken();
 | 
						|
    } else if (TypeModifier == OMPC_MAP_MODIFIER_mapper) {
 | 
						|
      Data.MapTypeModifiers.push_back(TypeModifier);
 | 
						|
      Data.MapTypeModifiersLoc.push_back(Tok.getLocation());
 | 
						|
      ConsumeToken();
 | 
						|
      if (parseMapperModifier(Data))
 | 
						|
        return true;
 | 
						|
    } else {
 | 
						|
      // For the case of unknown map-type-modifier or a map-type.
 | 
						|
      // Map-type is followed by a colon; the function returns when it
 | 
						|
      // encounters a token followed by a colon.
 | 
						|
      if (Tok.is(tok::comma)) {
 | 
						|
        Diag(Tok, diag::err_omp_map_type_modifier_missing);
 | 
						|
        ConsumeToken();
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      // Potential map-type token as it is followed by a colon.
 | 
						|
      if (PP.LookAhead(0).is(tok::colon))
 | 
						|
        return false;
 | 
						|
      Diag(Tok, diag::err_omp_unknown_map_type_modifier);
 | 
						|
      ConsumeToken();
 | 
						|
    }
 | 
						|
    if (getCurToken().is(tok::comma))
 | 
						|
      ConsumeToken();
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
/// Checks if the token is a valid map-type.
 | 
						|
static OpenMPMapClauseKind isMapType(Parser &P) {
 | 
						|
  Token Tok = P.getCurToken();
 | 
						|
  // The map-type token can be either an identifier or the C++ delete keyword.
 | 
						|
  if (!Tok.isOneOf(tok::identifier, tok::kw_delete))
 | 
						|
    return OMPC_MAP_unknown;
 | 
						|
  Preprocessor &PP = P.getPreprocessor();
 | 
						|
  OpenMPMapClauseKind MapType = static_cast<OpenMPMapClauseKind>(
 | 
						|
      getOpenMPSimpleClauseType(OMPC_map, PP.getSpelling(Tok)));
 | 
						|
  return MapType;
 | 
						|
}
 | 
						|
 | 
						|
/// Parse map-type in map clause.
 | 
						|
/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list)
 | 
						|
/// where, map-type ::= to | from | tofrom | alloc | release | delete
 | 
						|
static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) {
 | 
						|
  Token Tok = P.getCurToken();
 | 
						|
  if (Tok.is(tok::colon)) {
 | 
						|
    P.Diag(Tok, diag::err_omp_map_type_missing);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  Data.ExtraModifier = isMapType(P);
 | 
						|
  if (Data.ExtraModifier == OMPC_MAP_unknown)
 | 
						|
    P.Diag(Tok, diag::err_omp_unknown_map_type);
 | 
						|
  P.ConsumeToken();
 | 
						|
}
 | 
						|
 | 
						|
/// Parses simple expression in parens for single-expression clauses of OpenMP
 | 
						|
/// constructs.
 | 
						|
/// \param RLoc Returned location of right paren.
 | 
						|
ExprResult Parser::ParseOpenMPIteratorsExpr() {
 | 
						|
  assert(Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator" &&
 | 
						|
         "Expected 'iterator' token.");
 | 
						|
  SourceLocation IteratorKwLoc = ConsumeToken();
 | 
						|
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after, "iterator"))
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  SourceLocation LLoc = T.getOpenLocation();
 | 
						|
  SmallVector<Sema::OMPIteratorData, 4> Data;
 | 
						|
  while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
 | 
						|
    // Check if the type parsing is required.
 | 
						|
    ParsedType IteratorType;
 | 
						|
    if (Tok.isNot(tok::identifier) || NextToken().isNot(tok::equal)) {
 | 
						|
      // identifier '=' is not found - parse type.
 | 
						|
      TypeResult TR = ParseTypeName();
 | 
						|
      if (TR.isInvalid()) {
 | 
						|
        T.skipToEnd();
 | 
						|
        return ExprError();
 | 
						|
      }
 | 
						|
      IteratorType = TR.get();
 | 
						|
    }
 | 
						|
 | 
						|
    // Parse identifier.
 | 
						|
    IdentifierInfo *II = nullptr;
 | 
						|
    SourceLocation IdLoc;
 | 
						|
    if (Tok.is(tok::identifier)) {
 | 
						|
      II = Tok.getIdentifierInfo();
 | 
						|
      IdLoc = ConsumeToken();
 | 
						|
    } else {
 | 
						|
      Diag(Tok, diag::err_expected_unqualified_id) << 0;
 | 
						|
    }
 | 
						|
 | 
						|
    // Parse '='.
 | 
						|
    SourceLocation AssignLoc;
 | 
						|
    if (Tok.is(tok::equal))
 | 
						|
      AssignLoc = ConsumeToken();
 | 
						|
    else
 | 
						|
      Diag(Tok, diag::err_omp_expected_equal_in_iterator);
 | 
						|
 | 
						|
    // Parse range-specification - <begin> ':' <end> [ ':' <step> ]
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this);
 | 
						|
    // Parse <begin>
 | 
						|
    SourceLocation Loc = Tok.getLocation();
 | 
						|
    ExprResult LHS = ParseCastExpression(AnyCastExpr);
 | 
						|
    ExprResult Begin = Actions.CorrectDelayedTyposInExpr(
 | 
						|
        ParseRHSOfBinaryExpression(LHS, prec::Conditional));
 | 
						|
    Begin = Actions.ActOnFinishFullExpr(Begin.get(), Loc,
 | 
						|
                                        /*DiscardedValue=*/false);
 | 
						|
    // Parse ':'.
 | 
						|
    SourceLocation ColonLoc;
 | 
						|
    if (Tok.is(tok::colon))
 | 
						|
      ColonLoc = ConsumeToken();
 | 
						|
 | 
						|
    // Parse <end>
 | 
						|
    Loc = Tok.getLocation();
 | 
						|
    LHS = ParseCastExpression(AnyCastExpr);
 | 
						|
    ExprResult End = Actions.CorrectDelayedTyposInExpr(
 | 
						|
        ParseRHSOfBinaryExpression(LHS, prec::Conditional));
 | 
						|
    End = Actions.ActOnFinishFullExpr(End.get(), Loc,
 | 
						|
                                      /*DiscardedValue=*/false);
 | 
						|
 | 
						|
    SourceLocation SecColonLoc;
 | 
						|
    ExprResult Step;
 | 
						|
    // Parse optional step.
 | 
						|
    if (Tok.is(tok::colon)) {
 | 
						|
      // Parse ':'
 | 
						|
      SecColonLoc = ConsumeToken();
 | 
						|
      // Parse <step>
 | 
						|
      Loc = Tok.getLocation();
 | 
						|
      LHS = ParseCastExpression(AnyCastExpr);
 | 
						|
      Step = Actions.CorrectDelayedTyposInExpr(
 | 
						|
          ParseRHSOfBinaryExpression(LHS, prec::Conditional));
 | 
						|
      Step = Actions.ActOnFinishFullExpr(Step.get(), Loc,
 | 
						|
                                         /*DiscardedValue=*/false);
 | 
						|
    }
 | 
						|
 | 
						|
    // Parse ',' or ')'
 | 
						|
    if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren))
 | 
						|
      Diag(Tok, diag::err_omp_expected_punc_after_iterator);
 | 
						|
    if (Tok.is(tok::comma))
 | 
						|
      ConsumeToken();
 | 
						|
 | 
						|
    Sema::OMPIteratorData &D = Data.emplace_back();
 | 
						|
    D.DeclIdent = II;
 | 
						|
    D.DeclIdentLoc = IdLoc;
 | 
						|
    D.Type = IteratorType;
 | 
						|
    D.AssignLoc = AssignLoc;
 | 
						|
    D.ColonLoc = ColonLoc;
 | 
						|
    D.SecColonLoc = SecColonLoc;
 | 
						|
    D.Range.Begin = Begin.get();
 | 
						|
    D.Range.End = End.get();
 | 
						|
    D.Range.Step = Step.get();
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  SourceLocation RLoc = Tok.getLocation();
 | 
						|
  if (!T.consumeClose())
 | 
						|
    RLoc = T.getCloseLocation();
 | 
						|
 | 
						|
  return Actions.ActOnOMPIteratorExpr(getCurScope(), IteratorKwLoc, LLoc, RLoc,
 | 
						|
                                      Data);
 | 
						|
}
 | 
						|
 | 
						|
/// Parses clauses with list.
 | 
						|
bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
 | 
						|
                                OpenMPClauseKind Kind,
 | 
						|
                                SmallVectorImpl<Expr *> &Vars,
 | 
						|
                                OpenMPVarListDataTy &Data) {
 | 
						|
  UnqualifiedId UnqualifiedReductionId;
 | 
						|
  bool InvalidReductionId = false;
 | 
						|
  bool IsInvalidMapperModifier = false;
 | 
						|
 | 
						|
  // Parse '('.
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after,
 | 
						|
                         getOpenMPClauseName(Kind).data()))
 | 
						|
    return true;
 | 
						|
 | 
						|
  bool HasIterator = false;
 | 
						|
  bool NeedRParenForLinear = false;
 | 
						|
  BalancedDelimiterTracker LinearT(*this, tok::l_paren,
 | 
						|
                                  tok::annot_pragma_openmp_end);
 | 
						|
  // Handle reduction-identifier for reduction clause.
 | 
						|
  if (Kind == OMPC_reduction || Kind == OMPC_task_reduction ||
 | 
						|
      Kind == OMPC_in_reduction) {
 | 
						|
    Data.ExtraModifier = OMPC_REDUCTION_unknown;
 | 
						|
    if (Kind == OMPC_reduction && getLangOpts().OpenMP >= 50 &&
 | 
						|
        (Tok.is(tok::identifier) || Tok.is(tok::kw_default)) &&
 | 
						|
        NextToken().is(tok::comma)) {
 | 
						|
      // Parse optional reduction modifier.
 | 
						|
      Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
 | 
						|
      Data.ExtraModifierLoc = Tok.getLocation();
 | 
						|
      ConsumeToken();
 | 
						|
      assert(Tok.is(tok::comma) && "Expected comma.");
 | 
						|
      (void)ConsumeToken();
 | 
						|
    }
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this);
 | 
						|
    if (getLangOpts().CPlusPlus)
 | 
						|
      ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec,
 | 
						|
                                     /*ObjectType=*/nullptr,
 | 
						|
                                     /*ObjectHadErrors=*/false,
 | 
						|
                                     /*EnteringContext=*/false);
 | 
						|
    InvalidReductionId = ParseReductionId(
 | 
						|
        *this, Data.ReductionOrMapperIdScopeSpec, UnqualifiedReductionId);
 | 
						|
    if (InvalidReductionId) {
 | 
						|
      SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
    }
 | 
						|
    if (Tok.is(tok::colon))
 | 
						|
      Data.ColonLoc = ConsumeToken();
 | 
						|
    else
 | 
						|
      Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
 | 
						|
    if (!InvalidReductionId)
 | 
						|
      Data.ReductionOrMapperId =
 | 
						|
          Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId);
 | 
						|
  } else if (Kind == OMPC_depend) {
 | 
						|
    if (getLangOpts().OpenMP >= 50) {
 | 
						|
      if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {
 | 
						|
        // Handle optional dependence modifier.
 | 
						|
        // iterator(iterators-definition)
 | 
						|
        // where iterators-definition is iterator-specifier [,
 | 
						|
        // iterators-definition ]
 | 
						|
        // where iterator-specifier is [ iterator-type ] identifier =
 | 
						|
        // range-specification
 | 
						|
        HasIterator = true;
 | 
						|
        EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
 | 
						|
        ExprResult IteratorRes = ParseOpenMPIteratorsExpr();
 | 
						|
        Data.DepModOrTailExpr = IteratorRes.get();
 | 
						|
        // Parse ','
 | 
						|
        ExpectAndConsume(tok::comma);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    // Handle dependency type for depend clause.
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this);
 | 
						|
    Data.ExtraModifier = getOpenMPSimpleClauseType(
 | 
						|
        Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "");
 | 
						|
    Data.ExtraModifierLoc = Tok.getLocation();
 | 
						|
    if (Data.ExtraModifier == OMPC_DEPEND_unknown) {
 | 
						|
      SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
    } else {
 | 
						|
      ConsumeToken();
 | 
						|
      // Special processing for depend(source) clause.
 | 
						|
      if (DKind == OMPD_ordered && Data.ExtraModifier == OMPC_DEPEND_source) {
 | 
						|
        // Parse ')'.
 | 
						|
        T.consumeClose();
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (Tok.is(tok::colon)) {
 | 
						|
      Data.ColonLoc = ConsumeToken();
 | 
						|
    } else {
 | 
						|
      Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren
 | 
						|
                                      : diag::warn_pragma_expected_colon)
 | 
						|
          << "dependency type";
 | 
						|
    }
 | 
						|
  } else if (Kind == OMPC_linear) {
 | 
						|
    // Try to parse modifier if any.
 | 
						|
    Data.ExtraModifier = OMPC_LINEAR_val;
 | 
						|
    if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) {
 | 
						|
      Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
 | 
						|
      Data.ExtraModifierLoc = ConsumeToken();
 | 
						|
      LinearT.consumeOpen();
 | 
						|
      NeedRParenForLinear = true;
 | 
						|
    }
 | 
						|
  } else if (Kind == OMPC_lastprivate) {
 | 
						|
    // Try to parse modifier if any.
 | 
						|
    Data.ExtraModifier = OMPC_LASTPRIVATE_unknown;
 | 
						|
    // Conditional modifier allowed only in OpenMP 5.0 and not supported in
 | 
						|
    // distribute and taskloop based directives.
 | 
						|
    if ((getLangOpts().OpenMP >= 50 && !isOpenMPDistributeDirective(DKind) &&
 | 
						|
         !isOpenMPTaskLoopDirective(DKind)) &&
 | 
						|
        Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) {
 | 
						|
      Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
 | 
						|
      Data.ExtraModifierLoc = Tok.getLocation();
 | 
						|
      ConsumeToken();
 | 
						|
      assert(Tok.is(tok::colon) && "Expected colon.");
 | 
						|
      Data.ColonLoc = ConsumeToken();
 | 
						|
    }
 | 
						|
  } else if (Kind == OMPC_map) {
 | 
						|
    // Handle map type for map clause.
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this);
 | 
						|
 | 
						|
    // The first identifier may be a list item, a map-type or a
 | 
						|
    // map-type-modifier. The map-type can also be delete which has the same
 | 
						|
    // spelling of the C++ delete keyword.
 | 
						|
    Data.ExtraModifier = OMPC_MAP_unknown;
 | 
						|
    Data.ExtraModifierLoc = Tok.getLocation();
 | 
						|
 | 
						|
    // Check for presence of a colon in the map clause.
 | 
						|
    TentativeParsingAction TPA(*this);
 | 
						|
    bool ColonPresent = false;
 | 
						|
    if (SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
        StopBeforeMatch)) {
 | 
						|
      if (Tok.is(tok::colon))
 | 
						|
        ColonPresent = true;
 | 
						|
    }
 | 
						|
    TPA.Revert();
 | 
						|
    // Only parse map-type-modifier[s] and map-type if a colon is present in
 | 
						|
    // the map clause.
 | 
						|
    if (ColonPresent) {
 | 
						|
      IsInvalidMapperModifier = parseMapTypeModifiers(Data);
 | 
						|
      if (!IsInvalidMapperModifier)
 | 
						|
        parseMapType(*this, Data);
 | 
						|
      else
 | 
						|
        SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch);
 | 
						|
    }
 | 
						|
    if (Data.ExtraModifier == OMPC_MAP_unknown) {
 | 
						|
      Data.ExtraModifier = OMPC_MAP_tofrom;
 | 
						|
      Data.IsMapTypeImplicit = true;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Tok.is(tok::colon))
 | 
						|
      Data.ColonLoc = ConsumeToken();
 | 
						|
  } else if (Kind == OMPC_to || Kind == OMPC_from) {
 | 
						|
    if (Tok.is(tok::identifier)) {
 | 
						|
      bool IsMapperModifier = false;
 | 
						|
      if (Kind == OMPC_to) {
 | 
						|
        auto Modifier = static_cast<OpenMPToModifierKind>(
 | 
						|
            getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)));
 | 
						|
        if (Modifier == OMPC_TO_MODIFIER_mapper)
 | 
						|
          IsMapperModifier = true;
 | 
						|
      } else {
 | 
						|
        auto Modifier = static_cast<OpenMPFromModifierKind>(
 | 
						|
            getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)));
 | 
						|
        if (Modifier == OMPC_FROM_MODIFIER_mapper)
 | 
						|
          IsMapperModifier = true;
 | 
						|
      }
 | 
						|
      if (IsMapperModifier) {
 | 
						|
        // Parse the mapper modifier.
 | 
						|
        ConsumeToken();
 | 
						|
        IsInvalidMapperModifier = parseMapperModifier(Data);
 | 
						|
        if (Tok.isNot(tok::colon)) {
 | 
						|
          if (!IsInvalidMapperModifier)
 | 
						|
            Diag(Tok, diag::warn_pragma_expected_colon) << ")";
 | 
						|
          SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                    StopBeforeMatch);
 | 
						|
        }
 | 
						|
        // Consume ':'.
 | 
						|
        if (Tok.is(tok::colon))
 | 
						|
          ConsumeToken();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if (Kind == OMPC_allocate ||
 | 
						|
             (Kind == OMPC_affinity && Tok.is(tok::identifier) &&
 | 
						|
              PP.getSpelling(Tok) == "iterator")) {
 | 
						|
    // Handle optional allocator expression followed by colon delimiter.
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this);
 | 
						|
    TentativeParsingAction TPA(*this);
 | 
						|
    // OpenMP 5.0, 2.10.1, task Construct.
 | 
						|
    // where aff-modifier is one of the following:
 | 
						|
    // iterator(iterators-definition)
 | 
						|
    ExprResult Tail;
 | 
						|
    if (Kind == OMPC_allocate) {
 | 
						|
      Tail = ParseAssignmentExpression();
 | 
						|
    } else {
 | 
						|
      HasIterator = true;
 | 
						|
      EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
 | 
						|
      Tail = ParseOpenMPIteratorsExpr();
 | 
						|
    }
 | 
						|
    Tail = Actions.CorrectDelayedTyposInExpr(Tail);
 | 
						|
    Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(),
 | 
						|
                                       /*DiscardedValue=*/false);
 | 
						|
    if (Tail.isUsable()) {
 | 
						|
      if (Tok.is(tok::colon)) {
 | 
						|
        Data.DepModOrTailExpr = Tail.get();
 | 
						|
        Data.ColonLoc = ConsumeToken();
 | 
						|
        TPA.Commit();
 | 
						|
      } else {
 | 
						|
        // Colon not found, parse only list of variables.
 | 
						|
        TPA.Revert();
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      // Parsing was unsuccessfull, revert and skip to the end of clause or
 | 
						|
      // directive.
 | 
						|
      TPA.Revert();
 | 
						|
      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsComma =
 | 
						|
      (Kind != OMPC_reduction && Kind != OMPC_task_reduction &&
 | 
						|
       Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) ||
 | 
						|
      (Kind == OMPC_reduction && !InvalidReductionId) ||
 | 
						|
      (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) ||
 | 
						|
      (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown);
 | 
						|
  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))) {
 | 
						|
    ParseScope OMPListScope(this, Scope::OpenMPDirectiveScope);
 | 
						|
    ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
 | 
						|
    // Parse variable
 | 
						|
    ExprResult VarExpr =
 | 
						|
        Actions.CorrectDelayedTyposInExpr(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 ')' for linear clause with modifier.
 | 
						|
  if (NeedRParenForLinear)
 | 
						|
    LinearT.consumeClose();
 | 
						|
 | 
						|
  // Parse ':' linear-step (or ':' alignment).
 | 
						|
  const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
 | 
						|
  if (MustHaveTail) {
 | 
						|
    Data.ColonLoc = Tok.getLocation();
 | 
						|
    SourceLocation ELoc = ConsumeToken();
 | 
						|
    ExprResult Tail = ParseAssignmentExpression();
 | 
						|
    Tail =
 | 
						|
        Actions.ActOnFinishFullExpr(Tail.get(), ELoc, /*DiscardedValue*/ false);
 | 
						|
    if (Tail.isUsable())
 | 
						|
      Data.DepModOrTailExpr = Tail.get();
 | 
						|
    else
 | 
						|
      SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
 | 
						|
                StopBeforeMatch);
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse ')'.
 | 
						|
  Data.RLoc = Tok.getLocation();
 | 
						|
  if (!T.consumeClose())
 | 
						|
    Data.RLoc = T.getCloseLocation();
 | 
						|
  // Exit from scope when the iterator is used in depend clause.
 | 
						|
  if (HasIterator)
 | 
						|
    ExitScope();
 | 
						|
  return (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) ||
 | 
						|
         (MustHaveTail && !Data.DepModOrTailExpr) || InvalidReductionId ||
 | 
						|
         IsInvalidMapperModifier;
 | 
						|
}
 | 
						|
 | 
						|
/// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
 | 
						|
/// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction',
 | 
						|
/// 'in_reduction', 'nontemporal', 'exclusive' or 'inclusive'.
 | 
						|
///
 | 
						|
///    private-clause:
 | 
						|
///       'private' '(' list ')'
 | 
						|
///    firstprivate-clause:
 | 
						|
///       'firstprivate' '(' list ')'
 | 
						|
///    lastprivate-clause:
 | 
						|
///       'lastprivate' '(' list ')'
 | 
						|
///    shared-clause:
 | 
						|
///       'shared' '(' list ')'
 | 
						|
///    linear-clause:
 | 
						|
///       'linear' '(' linear-list [ ':' linear-step ] ')'
 | 
						|
///    aligned-clause:
 | 
						|
///       'aligned' '(' list [ ':' alignment ] ')'
 | 
						|
///    reduction-clause:
 | 
						|
///       'reduction' '(' [ modifier ',' ] reduction-identifier ':' list ')'
 | 
						|
///    task_reduction-clause:
 | 
						|
///       'task_reduction' '(' reduction-identifier ':' list ')'
 | 
						|
///    in_reduction-clause:
 | 
						|
///       'in_reduction' '(' reduction-identifier ':' list ')'
 | 
						|
///    copyprivate-clause:
 | 
						|
///       'copyprivate' '(' list ')'
 | 
						|
///    flush-clause:
 | 
						|
///       'flush' '(' list ')'
 | 
						|
///    depend-clause:
 | 
						|
///       'depend' '(' in | out | inout : list | source ')'
 | 
						|
///    map-clause:
 | 
						|
///       'map' '(' [ [ always [,] ] [ close [,] ]
 | 
						|
///          [ mapper '(' mapper-identifier ')' [,] ]
 | 
						|
///          to | from | tofrom | alloc | release | delete ':' ] list ')';
 | 
						|
///    to-clause:
 | 
						|
///       'to' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')'
 | 
						|
///    from-clause:
 | 
						|
///       'from' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')'
 | 
						|
///    use_device_ptr-clause:
 | 
						|
///       'use_device_ptr' '(' list ')'
 | 
						|
///    use_device_addr-clause:
 | 
						|
///       'use_device_addr' '(' list ')'
 | 
						|
///    is_device_ptr-clause:
 | 
						|
///       'is_device_ptr' '(' list ')'
 | 
						|
///    allocate-clause:
 | 
						|
///       'allocate' '(' [ allocator ':' ] list ')'
 | 
						|
///    nontemporal-clause:
 | 
						|
///       'nontemporal' '(' list ')'
 | 
						|
///    inclusive-clause:
 | 
						|
///       'inclusive' '(' list ')'
 | 
						|
///    exclusive-clause:
 | 
						|
///       'exclusive' '(' list ')'
 | 
						|
///
 | 
						|
/// For 'linear' clause linear-list may have the following forms:
 | 
						|
///  list
 | 
						|
///  modifier(list)
 | 
						|
/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++).
 | 
						|
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
 | 
						|
                                            OpenMPClauseKind Kind,
 | 
						|
                                            bool ParseOnly) {
 | 
						|
  SourceLocation Loc = Tok.getLocation();
 | 
						|
  SourceLocation LOpen = ConsumeToken();
 | 
						|
  SmallVector<Expr *, 4> Vars;
 | 
						|
  OpenMPVarListDataTy Data;
 | 
						|
 | 
						|
  if (ParseOpenMPVarList(DKind, Kind, Vars, Data))
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  if (ParseOnly)
 | 
						|
    return nullptr;
 | 
						|
  OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc);
 | 
						|
  return Actions.ActOnOpenMPVarListClause(
 | 
						|
      Kind, Vars, Data.DepModOrTailExpr, Locs, Data.ColonLoc,
 | 
						|
      Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId,
 | 
						|
      Data.ExtraModifier, Data.MapTypeModifiers, Data.MapTypeModifiersLoc,
 | 
						|
      Data.IsMapTypeImplicit, Data.ExtraModifierLoc);
 | 
						|
}
 | 
						|
 |