[PATCH] [OPENMP] Initial support of 'reduction' clause

Alexey Bataev a.bataev at hotmail.com
Thu May 15 20:15:53 PDT 2014


Hi Alp,
1. Ok, I'll fix it.
2. It is done to suppress all errors and possible warnings, which might 
confuse the programmers. Actually it is just a stub for future actual 
generation of helper expressions and statements for OpenMP constructs 
and it will be removed later.
Best regards,
Alexey Bataev
=============
Software Engineer
Intel Compiler Team
Intel Corp.

15 Май 2014 г. 17:34:40, Alp Toker писал:
> Couple of remarks inline...
>
>
> On 15/05/2014 11:30, Alexey Bataev wrote:
>> Hi doug.gregor, gribozavr, hfinkel, cbergstrom, fraggamuffin, rsmith,
>>
>> Parsing and sema analysis for OpenMP clause 'reduction'
>>
>> http://reviews.llvm.org/D3776
>>
>> Files:
>>    include/clang/AST/DataRecursiveASTVisitor.h
>>    include/clang/AST/OpenMPClause.h
>>    include/clang/AST/RecursiveASTVisitor.h
>>    include/clang/Basic/DiagnosticSemaKinds.td
>>    include/clang/Basic/OpenMPKinds.def
>>    include/clang/Sema/Sema.h
>>    lib/AST/Stmt.cpp
>>    lib/AST/StmtPrinter.cpp
>>    lib/AST/StmtProfile.cpp
>>    lib/Basic/OpenMPKinds.cpp
>>    lib/Parse/ParseOpenMP.cpp
>>    lib/Sema/SemaOpenMP.cpp
>>    lib/Sema/TreeTransform.h
>>    lib/Serialization/ASTReaderStmt.cpp
>>    lib/Serialization/ASTWriterStmt.cpp
>>    test/OpenMP/parallel_ast_print.cpp
>>    test/OpenMP/parallel_reduction_messages.cpp
>>    test/OpenMP/simd_linear_messages.cpp
>>    tools/libclang/CIndex.cpp
>>
>> D3776.9411.patch
>>
>>
>> Index: include/clang/AST/DataRecursiveASTVisitor.h
>> ===================================================================
>> --- include/clang/AST/DataRecursiveASTVisitor.h
>> +++ include/clang/AST/DataRecursiveASTVisitor.h
>> @@ -2412,6 +2412,15 @@
>>   }
>>   template<typename Derived>
>> +bool DataRecursiveASTVisitor<Derived>::VisitOMPReductionClause(
>> +
>> OMPReductionClause *C) {
>> +  TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
>> +  TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
>> +  VisitOMPClauseList(C);
>> +  return true;
>> +}
>> +
>> +template<typename Derived>
>>   bool
>>
>> DataRecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C)
>> {
>>     VisitOMPClauseList(C);
>> Index: include/clang/AST/OpenMPClause.h
>> ===================================================================
>> --- include/clang/AST/OpenMPClause.h
>> +++ include/clang/AST/OpenMPClause.h
>> @@ -623,6 +623,99 @@
>>     }
>>   };
>> +/// \brief This represents clause 'reduction' in the '#pragma omp ...'
>> +/// directives.
>> +///
>> +/// \code
>> +/// #pragma omp parallel reduction(+:a,b)
>> +/// \endcode
>> +/// In this example directive '#pragma omp parallel' has clause
>> 'reduction'
>> +/// with operator '+' and the variables 'a' and 'b'.
>> +///
>> +class OMPReductionClause : public
>> OMPVarListClause<OMPReductionClause> {
>> +  friend class OMPClauseReader;
>> +  /// \brief Location of ':'.
>> +  SourceLocation ColonLoc;
>> +  /// \brief Nested name specifier for C++.
>> +  NestedNameSpecifierLoc QualifierLoc;
>> +  /// \brief Name of custom operator.
>> +  DeclarationNameInfo NameInfo;
>> +
>> +  /// \brief Build clause with number of variables \a N.
>> +  ///
>> +  /// \param StartLoc Starting location of the clause.
>> +  /// \param LParenLoc Location of '('.
>> +  /// \param EndLoc Ending location of the clause.
>> +  /// \param ColonLoc Location of ':'.
>> +  /// \param N Number of the variables in the clause.
>> +  /// \param QualifierLoc The nested-name qualifier with location
>> information
>> +  /// \param NameInfo The full name info for reduction identifier.
>> +  ///
>> +  OMPReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc,
>> +                     SourceLocation ColonLoc, SourceLocation EndLoc,
>> unsigned N,
>> +                     NestedNameSpecifierLoc QualifierLoc,
>> +                     const DeclarationNameInfo &NameInfo)
>> +      : OMPVarListClause<OMPReductionClause>(OMPC_reduction, StartLoc,
>> +                                             LParenLoc, EndLoc, N),
>> +        ColonLoc(ColonLoc), QualifierLoc(QualifierLoc),
>> NameInfo(NameInfo) {}
>> +
>> +  /// \brief Build an empty clause.
>> +  ///
>> +  /// \param N Number of variables.
>> +  ///
>> +  explicit OMPReductionClause(unsigned N)
>> +      : OMPVarListClause<OMPReductionClause>(OMPC_reduction,
>> SourceLocation(),
>> +                                             SourceLocation(),
>> SourceLocation(),
>> +                                             N),
>> +        ColonLoc(), QualifierLoc(), NameInfo() {}
>> +
>> +  /// \brief Sets location of ':' symbol in clause.
>> +  void setColonLoc(SourceLocation CL) { ColonLoc = CL; }
>> +  /// \brief Sets the name info for specified reduction identifier.
>> +  void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; }
>> +  /// \brief Sets the nested name specifier.
>> +  void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc =
>> NSL; }
>> +
>> +public:
>> +  /// \brief Creates clause with a list of variables \a VL.
>> +  ///
>> +  /// \param StartLoc Starting location of the clause.
>> +  /// \param LParenLoc Location of '('.
>> +  /// \param ColonLoc Location of ':'.
>> +  /// \param EndLoc Ending location of the clause.
>> +  /// \param N Number of the variables in the clause.
>> +  /// \param QualifierLoc The nested-name qualifier with location
>> information
>> +  /// \param NameInfo The full name info for reduction identifier.
>> +  ///
>> +  static OMPReductionClause *
>> +  Create(const ASTContext &C, SourceLocation StartLoc,
>> SourceLocation LParenLoc,
>> +         SourceLocation ColonLoc, SourceLocation EndLoc,
>> ArrayRef<Expr *> VL,
>> +         NestedNameSpecifierLoc QualifierLoc,
>> +         const DeclarationNameInfo &NameInfo);
>> +  /// \brief Creates an empty clause with the place for \a N variables.
>> +  ///
>> +  /// \param C AST context.
>> +  /// \param N The number of variables.
>> +  ///
>> +  static OMPReductionClause *CreateEmpty(const ASTContext &C,
>> unsigned N);
>> +
>> +  /// \brief Gets location of ':' symbol in clause.
>> +  SourceLocation getColonLoc() const { return ColonLoc; }
>> +  /// \brief Gets the name info for specified reduction identifier.
>> +  const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
>> +  /// \brief Gets the nested name specifier.
>> +  NestedNameSpecifierLoc getQualifierLoc() const { return
>> QualifierLoc; }
>> +
>> +  StmtRange children() {
>> +    return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
>> +                     reinterpret_cast<Stmt **>(varlist_end()));
>> +  }
>> +
>> +  static bool classof(const OMPClause *T) {
>> +    return T->getClauseKind() == OMPC_reduction;
>> +  }
>> +};
>> +
>>   /// \brief This represents clause 'linear' in the '#pragma omp ...'
>>   /// directives.
>>   ///
>> Index: include/clang/AST/RecursiveASTVisitor.h
>> ===================================================================
>> --- include/clang/AST/RecursiveASTVisitor.h
>> +++ include/clang/AST/RecursiveASTVisitor.h
>> @@ -2448,6 +2448,15 @@
>>   }
>>   template<typename Derived>
>> +bool RecursiveASTVisitor<Derived>::VisitOMPReductionClause(
>> +
>> OMPReductionClause *C) {
>> +  TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
>> +  TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
>> +  VisitOMPClauseList(C);
>> +  return true;
>> +}
>> +
>> +template<typename Derived>
>>   bool
>> RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
>>     VisitOMPClauseList(C);
>>     TraverseStmt(C->getStep());
>> Index: include/clang/Basic/DiagnosticSemaKinds.td
>> ===================================================================
>> --- include/clang/Basic/DiagnosticSemaKinds.td
>> +++ include/clang/Basic/DiagnosticSemaKinds.td
>> @@ -6907,6 +6907,8 @@
>>     "a private variable with incomplete type %0">;
>>   def err_omp_firstprivate_incomplete_type : Error<
>>     "a firstprivate variable with incomplete type %0">;
>> +def err_omp_reduction_incomplete_type : Error<
>> +  "a reduction variable with incomplete type %0">;
>>   def err_omp_unexpected_clause_value : Error<
>>     "expected %0 in OpenMP clause '%1'">;
>>   def err_omp_expected_var_name : Error<
>> @@ -6953,6 +6955,24 @@
>>   def warn_omp_linear_step_zero : Warning<
>>     "zero linear step (%0 %select{|and other variables in clause
>> }1should probably be const)">,
>>     InGroup<OpenMPClauses>;
>> +def err_omp_unknown_reduction_identifier : Error<
>> +  "incorrect reduction identifier, expected one of '+', '-', '*',
>> '&', '|', '^', '&&', '||', 'min' or 'max'">;
>> +def err_omp_reduction_type_array : Error<
>> +  "a reduction variable with array type %0">;
>> +def err_omp_reduction_ref_type_arg : Error<
>> +  "argument of OpenMP clause 'reduction' must reference the same
>> object in all threads">;
>> +def err_omp_clause_not_arithmetic_type_arg : Error<
>> +  "arguments of OpenMP clause 'reduction' for 'min' or 'max' must be
>> of %select{scalar|arithmetic}0 type">;
>> +def err_omp_clause_floating_type_arg : Error<
>> +  "arguments of OpenMP clause 'reduction' with bitwise operators
>> cannot be of floating type">;
>> +def err_omp_once_referenced : Error<
>> +  "variable can appear only once in OpenMP '%0' clause">;
>> +def note_omp_referenced : Note<
>> +  "previously referenced here">;
>> +def err_omp_reduction_in_task : Error<
>> +  "reduction variables may not be accessed in an explicit task">;
>> +def err_omp_reduction_id_not_compatible : Error<
>> +  "variable of type %0 is not valid for specified reduction
>> operation">;
>>   } // end of OpenMP category
>>   let CategoryName = "Related Result Type Issue" in {
>> Index: include/clang/Basic/OpenMPKinds.def
>> ===================================================================
>> --- include/clang/Basic/OpenMPKinds.def
>> +++ include/clang/Basic/OpenMPKinds.def
>> @@ -45,6 +45,7 @@
>>   OPENMP_CLAUSE(private, OMPPrivateClause)
>>   OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
>>   OPENMP_CLAUSE(shared,  OMPSharedClause)
>> +OPENMP_CLAUSE(reduction,  OMPReductionClause)
>>   OPENMP_CLAUSE(linear,  OMPLinearClause)
>>   OPENMP_CLAUSE(copyin,  OMPCopyinClause)
>>   OPENMP_CLAUSE(proc_bind, OMPProcBindClause)
>> @@ -57,6 +58,7 @@
>>   OPENMP_PARALLEL_CLAUSE(private)
>>   OPENMP_PARALLEL_CLAUSE(firstprivate)
>>   OPENMP_PARALLEL_CLAUSE(shared)
>> +OPENMP_PARALLEL_CLAUSE(reduction)
>>   OPENMP_PARALLEL_CLAUSE(copyin)
>>   // FIXME: more clauses allowed for directive 'omp simd'.
>> Index: include/clang/Sema/Sema.h
>> ===================================================================
>> --- include/clang/Sema/Sema.h
>> +++ include/clang/Sema/Sema.h
>> @@ -7329,13 +7329,13 @@
>>                                          SourceLocation LParenLoc,
>>                                          SourceLocation EndLoc);
>> -  OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
>> -                                      ArrayRef<Expr *> Vars,
>> -                                      Expr *TailExpr,
>> -                                      SourceLocation StartLoc,
>> -                                      SourceLocation LParenLoc,
>> -                                      SourceLocation ColonLoc,
>> -                                      SourceLocation EndLoc);
>> +  OMPClause *
>> +  ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *>
>> Vars,
>> +                           Expr *TailExpr, SourceLocation StartLoc,
>> +                           SourceLocation LParenLoc, SourceLocation
>> ColonLoc,
>> +                           SourceLocation EndLoc,
>> +                           CXXScopeSpec &ReductionIdScopeSpec,
>> +                           const DeclarationNameInfo &ReductionId);
>>     /// \brief Called on well-formed 'private' clause.
>>     OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
>>                                         SourceLocation StartLoc,
>> @@ -7351,6 +7351,13 @@
>>                                        SourceLocation StartLoc,
>>                                        SourceLocation LParenLoc,
>>                                        SourceLocation EndLoc);
>> +  /// \brief Called on well-formed 'reduction' clause.
>> +  OMPClause *
>> +  ActOnOpenMPReductionClause(ArrayRef<Expr *> VarList,
>> SourceLocation StartLoc,
>> +                             SourceLocation LParenLoc,
>> SourceLocation ColonLoc,
>> +                             SourceLocation EndLoc,
>> +                             CXXScopeSpec &ReductionIdScopeSpec,
>> +                             const DeclarationNameInfo &ReductionId);
>>     /// \brief Called on well-formed 'linear' clause.
>>     OMPClause *ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList,
>>                                        Expr *Step,
>> Index: lib/AST/Stmt.cpp
>> ===================================================================
>> --- lib/AST/Stmt.cpp
>> +++ lib/AST/Stmt.cpp
>> @@ -1242,6 +1242,27 @@
>>     std::copy(Clauses.begin(), Clauses.end(), getClauses().begin());
>>   }
>> +OMPReductionClause *OMPReductionClause::Create(
>> +    const ASTContext &C, SourceLocation StartLoc, SourceLocation
>> LParenLoc,
>> +    SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *>
>> VL,
>> +    NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo
>> &NameInfo) {
>> +  void *Mem =
>> C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
>> +                                                  llvm::alignOf<Expr
>> *>()) +
>> +                         sizeof(Expr *) * VL.size());
>> +  OMPReductionClause *Clause = new (Mem) OMPReductionClause(
>> +      StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(),
>> QualifierLoc, NameInfo);
>> +  Clause->setVarRefs(VL);
>> +  return Clause;
>> +}
>> +
>> +OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext
>> &C,
>> +                                                    unsigned N) {
>> +  void *Mem =
>> C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
>> +                                                  llvm::alignOf<Expr
>> *>()) +
>> +                         sizeof(Expr *) * N);
>> +  return new (Mem) OMPReductionClause(N);
>> +}
>> +
>>   OMPParallelDirective *OMPParallelDirective::Create(
>>                                                 const ASTContext &C,
>>                                                 SourceLocation StartLoc,
>> Index: lib/AST/StmtPrinter.cpp
>> ===================================================================
>> --- lib/AST/StmtPrinter.cpp
>> +++ lib/AST/StmtPrinter.cpp
>> @@ -659,6 +659,28 @@
>>     }
>>   }
>> +void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause
>> *Node) {
>> +  if (!Node->varlist_empty()) {
>> +    OS << "reduction(";
>> +    NestedNameSpecifier *QualifierLoc =
>> +        Node->getQualifierLoc().getNestedNameSpecifier();
>> +    OverloadedOperatorKind OOK =
>> +        Node->getNameInfo().getName().getCXXOverloadedOperator();
>> +    if (QualifierLoc == nullptr && OOK != OO_None) {
>> +      // Print reduction identifier in C format
>> +      OS << getOperatorSpelling(OOK);
>> +    } else {
>> +      // Use C++ format
>> +      if (QualifierLoc != nullptr)
>> +        QualifierLoc->print(OS, Policy);
>> +      OS << Node->getNameInfo();
>> +    }
>> +    OS << ":";
>> +    VisitOMPClauseList(Node, ' ');
>> +    OS << ")";
>> +  }
>> +}
>> +
>>   void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) {
>>     if (!Node->varlist_empty()) {
>>       OS << "linear";
>> Index: lib/AST/StmtProfile.cpp
>> ===================================================================
>> --- lib/AST/StmtProfile.cpp
>> +++ lib/AST/StmtProfile.cpp
>> @@ -299,6 +299,13 @@
>>   void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause
>> *C) {
>>     VisitOMPClauseList(C);
>>   }
>> +void OMPClauseProfiler::VisitOMPReductionClause(
>> +                                         const OMPReductionClause *C) {
>> +  Profiler->VisitNestedNameSpecifier(
>> +      C->getQualifierLoc().getNestedNameSpecifier());
>> +  Profiler->VisitName(C->getNameInfo().getName());
>> +  VisitOMPClauseList(C);
>> +}
>>   void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause
>> *C) {
>>     VisitOMPClauseList(C);
>>     Profiler->VisitStmt(C->getStep());
>> Index: lib/Basic/OpenMPKinds.cpp
>> ===================================================================
>> --- lib/Basic/OpenMPKinds.cpp
>> +++ lib/Basic/OpenMPKinds.cpp
>> @@ -86,6 +86,7 @@
>>     case OMPC_private:
>>     case OMPC_firstprivate:
>>     case OMPC_shared:
>> +  case OMPC_reduction:
>>     case OMPC_linear:
>>     case OMPC_copyin:
>>       break;
>> @@ -122,6 +123,7 @@
>>     case OMPC_private:
>>     case OMPC_firstprivate:
>>     case OMPC_shared:
>> +  case OMPC_reduction:
>>     case OMPC_linear:
>>     case OMPC_copyin:
>>       break;
>> Index: lib/Parse/ParseOpenMP.cpp
>> ===================================================================
>> --- lib/Parse/ParseOpenMP.cpp
>> +++ lib/Parse/ParseOpenMP.cpp
>> @@ -257,7 +257,8 @@
>>   ///
>>   ///    clause:
>>   ///       if-clause | num_threads-clause | safelen-clause |
>> default-clause |
>> -///       private-clause | firstprivate-clause | shared-clause |
>> linear-clause
>> +///       private-clause | firstprivate-clause | shared-clause |
>> linear-clause |
>> +///       reduction-clause
>>   ///
>>   OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
>>                                        OpenMPClauseKind CKind, bool
>> FirstClause) {
>> @@ -303,6 +304,7 @@
>>     case OMPC_private:
>>     case OMPC_firstprivate:
>>     case OMPC_shared:
>> +  case OMPC_reduction:
>>     case OMPC_linear:
>>     case OMPC_copyin:
>>       Clause = ParseOpenMPVarListClause(CKind);
>> @@ -388,6 +390,52 @@
>>                                            Tok.getLocation());
>>   }
>> +static bool ParseReductionId(Parser &P, CXXScopeSpec
>> &ReductionIdScopeSpec,
>> +                             UnqualifiedId &ReductionId) {
>> +  SourceLocation TemplateKWLoc;
>> +  if (ReductionIdScopeSpec.isEmpty()) {
>> +    auto OOK = OO_None;
>
> Not convinced this 'auto' is clearer than writing out the type.
>
>> +    switch (P.getCurToken().getKind()) {
>> +    case tok::plus:
>> +      OOK = OO_Plus;
>> +      break;
>> +    case tok::minus:
>> +      OOK = OO_Minus;
>> +      break;
>> +    case tok::star:
>> +      OOK = OO_Star;
>> +      break;
>> +    case tok::amp:
>> +      OOK = OO_Amp;
>> +      break;
>> +    case tok::pipe:
>> +      OOK = OO_Pipe;
>> +      break;
>> +    case tok::caret:
>> +      OOK = OO_Caret;
>> +      break;
>> +    case tok::ampamp:
>> +      OOK = OO_AmpAmp;
>> +      break;
>> +    case tok::pipepipe:
>> +      OOK = OO_PipePipe;
>> +      break;
>> +    default:
>> +      break;
>> +    }
>> +    if (OOK != OO_None) {
>> +      SourceLocation OpLoc = P.ConsumeToken();
>> +      SourceLocation SymbolLocations[] = { OpLoc, OpLoc,
>> SourceLocation() };
>> +      ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);
>> +      return false;
>> +    }
>> +  }
>> +  return P.ParseUnqualifiedId(ReductionIdScopeSpec,
>> /*EnteringContext*/ false,
>> +                              /*AllowDestructorName*/ false,
>> +                              /*AllowConstructorName*/ false,
>> ParsedType(),
>> +                              TemplateKWLoc, ReductionId);
>> +}
>> +
>>   /// \brief Parsing of OpenMP clause 'private', 'firstprivate',
>>   /// 'shared', 'copyin', or 'reduction'.
>>   ///
>> @@ -399,19 +447,44 @@
>>   ///       'shared' '(' list ')'
>>   ///    linear-clause:
>>   ///       'linear' '(' list [ ':' linear-step ] ')'
>> +///    reduction-clause:
>> +///       'reduction' '(' reduction-identifier ':' list ')'
>>   ///
>>   OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
>>     SourceLocation Loc = Tok.getLocation();
>>     SourceLocation LOpen = ConsumeToken();
>>     SourceLocation ColonLoc = SourceLocation();
>> +  // Optional scope specifier and unqualified id for reduction
>> identifier.
>> +  CXXScopeSpec ReductionIdScopeSpec;
>> +  UnqualifiedId ReductionId;
>> +  bool InvalidReductionId = false;
>>     // Parse '('.
>>     BalancedDelimiterTracker T(*this, tok::l_paren,
>> tok::annot_pragma_openmp_end);
>>     if (T.expectAndConsume(diag::err_expected_lparen_after,
>>                            getOpenMPClauseName(Kind)))
>> -    return 0;
>> +    return nullptr;
>> +
>> +  // Handle reduction-identifier for reduction clause.
>> +  if (Kind == OMPC_reduction) {
>> +    ColonProtectionRAIIObject ColonRAII(*this);
>> +    if (getLangOpts().CPlusPlus) {
>> +      ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec,
>> ParsedType(), false);
>> +    }
>> +    InvalidReductionId =
>> +        ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
>> +    if (InvalidReductionId) {
>> +      SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
>> +                StopBeforeMatch);
>> +    }
>> +    if (Tok.is(tok::colon)) {
>> +      ColonLoc = ConsumeToken();
>> +    } else {
>> +      Diag(Tok, diag::warn_pragma_expected_colon) << "reduction
>> identifier";
>> +    }
>> +  }
>>     SmallVector<Expr *, 5> Vars;
>> -  bool IsComma = true;
>> +  bool IsComma = !InvalidReductionId;
>>     const bool MayHaveTail = (Kind == OMPC_linear);
>>     while (IsComma || (Tok.isNot(tok::r_paren) &&
>> Tok.isNot(tok::colon) &&
>>                        Tok.isNot(tok::annot_pragma_openmp_end))) {
>> @@ -435,7 +508,7 @@
>>     }
>>     // Parse ':' linear-step
>> -  Expr *TailExpr = 0;
>> +  Expr *TailExpr = nullptr;
>>     const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
>>     if (MustHaveTail) {
>>       ColonLoc = Tok.getLocation();
>> @@ -450,10 +523,13 @@
>>     // Parse ')'.
>>     T.consumeClose();
>> -  if (Vars.empty() || (MustHaveTail && !TailExpr))
>> -    return 0;
>> +  if (Vars.empty() || (MustHaveTail && !TailExpr) ||
>> InvalidReductionId)
>> +    return nullptr;
>> -  return Actions.ActOnOpenMPVarListClause(Kind, Vars, TailExpr, Loc,
>> LOpen,
>> -                                          ColonLoc, Tok.getLocation());
>> +  return Actions.ActOnOpenMPVarListClause(
>> +      Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
>> +      ReductionIdScopeSpec,
>> +      ReductionId.isValid() ?
>> Actions.GetNameFromUnqualifiedId(ReductionId)
>> +                            : DeclarationNameInfo());
>>   }
>> Index: lib/Sema/SemaOpenMP.cpp
>> ===================================================================
>> --- lib/Sema/SemaOpenMP.cpp
>> +++ lib/Sema/SemaOpenMP.cpp
>> @@ -111,6 +111,10 @@
>>     /// attribute in \a DKind directive.
>>     DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind,
>>                       OpenMPDirectiveKind DKind = OMPD_unknown);
>> +  /// \brief Checks if the specified variables has \a CKind
>> data-sharing
>> +  /// attribute in an innermost \a DKind directive.
>> +  DSAVarData hasInnermostDSA(VarDecl *D, OpenMPClauseKind CKind,
>> +                             OpenMPDirectiveKind DKind);
>>     /// \brief Returns currently analyzed directive.
>>     OpenMPDirectiveKind getCurrentDirective() const {
>> @@ -146,7 +150,6 @@
>>       //  File-scope or namespace-scope variables referenced in
>> called routines
>>       //  in the region are shared unless they appear in a threadprivate
>>       //  directive.
>> -    // TODO
>>       if (!D->isFunctionOrMethodVarDecl())
>>         DVar.CKind = OMPC_shared;
>> @@ -207,7 +210,6 @@
>>       //  In a task construct, if no default clause is present, a
>> variable that in
>>       //  the enclosing context is determined to be shared by all
>> implicit tasks
>>       //  bound to the current team is shared.
>> -    // TODO
>>       if (DVar.DKind == OMPD_task) {
>>         DSAVarData DVarTemp;
>>         for (StackTy::reverse_iterator I = std::next(Iter),
>> @@ -375,6 +377,21 @@
>>     return DSAVarData();
>>   }
>> +DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(VarDecl *D,
>> +                                                   OpenMPClauseKind
>> CKind,
>> +
>> OpenMPDirectiveKind DKind) {
>> +  assert(DKind != OMPD_unknown && "Directive must be specified
>> explicitly");
>> +  for (auto I = Stack.rbegin(), EE = std::prev(Stack.rend()); I !=
>> EE; ++I) {
>> +    if (DKind != I->Directive)
>> +      continue;
>> +    DSAVarData DVar = getDSA(I, D);
>> +    if (DVar.CKind == CKind)
>> +      return DVar;
>> +    return DSAVarData();
>> +  }
>> +  return DSAVarData();
>> +}
>> +
>>   void Sema::InitDataSharingAttributesStack() {
>>     VarDataSharingAttributesStack = new DSAStackTy(*this);
>>   }
>> @@ -638,7 +655,16 @@
>>         //  A list item that appears in a reduction clause of the
>> innermost
>>         //  enclosing worksharing or parallel construct may not be
>> accessed in an
>>         //  explicit task.
>> -      // TODO:
>> +      DVar = Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_parallel);
>> +      if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) {
>> +        ErrorFound = true;
>> +        Actions.Diag(ELoc, diag::err_omp_reduction_in_task);
>> +        if (DVar.RefExpr) {
>> +          Actions.Diag(DVar.RefExpr->getExprLoc(),
>> diag::note_omp_explicit_dsa)
>> +              << getOpenMPClauseName(OMPC_reduction);
>> +        }
>> +        return;
>> +      }
>>         // Define implicit data-sharing attributes for task.
>>         DVar = Stack->getImplicitDSA(VD);
>> @@ -814,6 +840,7 @@
>>     case OMPC_private:
>>     case OMPC_firstprivate:
>>     case OMPC_shared:
>> +  case OMPC_reduction:
>>     case OMPC_linear:
>>     case OMPC_copyin:
>>     case OMPC_threadprivate:
>> @@ -974,6 +1001,7 @@
>>     case OMPC_private:
>>     case OMPC_firstprivate:
>>     case OMPC_shared:
>> +  case OMPC_reduction:
>>     case OMPC_linear:
>>     case OMPC_copyin:
>>     case OMPC_threadprivate:
>> @@ -1058,13 +1086,11 @@
>>                                            EndLoc);
>>   }
>> -OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
>> -                                          ArrayRef<Expr *> VarList,
>> -                                          Expr *TailExpr,
>> -                                          SourceLocation StartLoc,
>> -                                          SourceLocation LParenLoc,
>> -                                          SourceLocation ColonLoc,
>> -                                          SourceLocation EndLoc) {
>> +OMPClause *Sema::ActOnOpenMPVarListClause(
>> +    OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
>> +    SourceLocation StartLoc, SourceLocation LParenLoc,
>> SourceLocation ColonLoc,
>> +    SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
>> +    const DeclarationNameInfo &ReductionId) {
>>     OMPClause *Res = 0;
>>     switch (Kind) {
>>     case OMPC_private:
>> @@ -1076,6 +1102,11 @@
>>     case OMPC_shared:
>>       Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc,
>> EndLoc);
>>       break;
>> +  case OMPC_reduction:
>> +    Res =
>> +        ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc,
>> ColonLoc,
>> +                                   EndLoc, ReductionIdScopeSpec,
>> ReductionId);
>> +    break;
>>     case OMPC_linear:
>>       Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc,
>> LParenLoc,
>>                                     ColonLoc, EndLoc);
>> @@ -1462,6 +1493,323 @@
>>     return OMPSharedClause::Create(Context, StartLoc, LParenLoc,
>> EndLoc, Vars);
>>   }
>> +namespace {
>> +class DSARefChecker : public StmtVisitor<DSARefChecker, bool> {
>> +  DSAStackTy *Stack;
>> +
>> +public:
>> +  bool VisitDeclRefExpr(DeclRefExpr *E) {
>> +    if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
>> +      DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
>> +      if (DVar.CKind == OMPC_shared && !DVar.RefExpr)
>> +        return false;
>> +      if (DVar.CKind != OMPC_unknown)
>> +        return true;
>> +      DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(VD,
>> OMPC_private);
>> +      DSAStackTy::DSAVarData DVarFirstprivate =
>> +          Stack->hasDSA(VD, OMPC_firstprivate);
>> +      DSAStackTy::DSAVarData DVarReduction = Stack->hasDSA(VD,
>> OMPC_reduction);
>> +      if (DVarPrivate.CKind != OMPC_unknown ||
>> +          DVarFirstprivate.CKind != OMPC_unknown ||
>> +          DVarReduction.CKind != OMPC_unknown)
>> +        return true;
>> +      return false;
>> +    }
>> +    return false;
>> +  }
>> +  bool VisitStmt(Stmt *S) {
>> +    for (auto Child : S->children()) {
>> +      if (Child && Visit(Child))
>> +        return true;
>> +    }
>> +    return false;
>> +  }
>> +  DSARefChecker(DSAStackTy *S) : Stack(S) {}
>> +};
>> +}
>> +
>> +OMPClause *Sema::ActOnOpenMPReductionClause(
>> +    ArrayRef<Expr *> VarList, SourceLocation StartLoc,
>> SourceLocation LParenLoc,
>> +    SourceLocation ColonLoc, SourceLocation EndLoc,
>> +    CXXScopeSpec &ReductionIdScopeSpec,
>> +    const DeclarationNameInfo &ReductionId) {
>> +  // TODO: Allow scope specification search when 'declare reduction' is
>> +  // supported.
>> +  assert(ReductionIdScopeSpec.isEmpty() &&
>> +         "No support for scoped reduction identifiers yet.");
>> +
>> +  auto DN = ReductionId.getName();
>> +  auto OOK = DN.getCXXOverloadedOperator();
>> +  auto BOK = BO_Comma;
>> +
>> +  // OpenMP [2.14.3.6, reduction clause]
>> +  // C
>> +  // reduction-identifier is either an identifier or one of the
>> following
>> +  // operators: +, -, *,  &, |, ^, && and ||
>> +  // C++
>> +  // reduction-identifier is either an id-expression or one of the
>> following
>> +  // operators: +, -, *, &, |, ^, && and ||
>> +  // FIXME: Only 'min' and 'max' identifiers are supported for now.
>> +  switch (OOK) {
>> +  case OO_Plus:
>> +  case OO_Minus:
>> +    BOK = BO_AddAssign;
>> +    break;
>> +  case OO_Star:
>> +    BOK = BO_MulAssign;
>> +    break;
>> +  case OO_Amp:
>> +    BOK = BO_AndAssign;
>> +    break;
>> +  case OO_Pipe:
>> +    BOK = BO_OrAssign;
>> +    break;
>> +  case OO_Caret:
>> +    BOK = BO_XorAssign;
>> +    break;
>> +  case OO_AmpAmp:
>> +    BOK = BO_LAnd;
>> +    break;
>> +  case OO_PipePipe:
>> +    BOK = BO_LOr;
>> +    break;
>> +  default:
>> +    if (auto II = DN.getAsIdentifierInfo()) {
>> +      if (II->isStr("max"))
>> +        BOK = BO_GT;
>> +      else if (II->isStr("min"))
>> +        BOK = BO_LT;
>> +    }
>> +    break;
>> +  }
>> +  SourceRange ReductionIdRange;
>> +  if (ReductionIdScopeSpec.isValid()) {
>> +    ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
>> +  }
>> +  ReductionIdRange.setEnd(ReductionId.getEndLoc());
>> +  if (BOK == BO_Comma) {
>> +    // Not allowed reduction identifier is found.
>> +    Diag(ReductionId.getLocStart(),
>> diag::err_omp_unknown_reduction_identifier)
>> +        << ReductionIdRange;
>> +    return nullptr;
>> +  }
>> +
>> +  SmallVector<Expr *, 8> Vars;
>> +  for (auto RefExpr : VarList) {
>> +    assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
>> +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
>> +      // It will be analyzed later.
>> +      Vars.push_back(RefExpr);
>> +      continue;
>> +    }
>> +
>> +    if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
>> +        RefExpr->isInstantiationDependent() ||
>> +        RefExpr->containsUnexpandedParameterPack()) {
>> +      // It will be analyzed later.
>> +      Vars.push_back(RefExpr);
>> +      continue;
>> +    }
>> +
>> +    auto ELoc = RefExpr->getExprLoc();
>> +    auto ERange = RefExpr->getSourceRange();
>> +    // OpenMP [2.1, C/C++]
>> +    //  A list item is a variable or array section, subject to the
>> restrictions
>> +    //  specified in Section 2.4 on page 42 and in each of the sections
>> +    // describing clauses and directives for which a list appears.
>> +    // OpenMP  [2.14.3.3, Restrictions, p.1]
>> +    //  A variable that is part of another variable (as an array or
>> +    //  structure element) cannot appear in a private clause.
>> +    auto DE = dyn_cast<DeclRefExpr>(RefExpr);
>> +    if (!DE || !isa<VarDecl>(DE->getDecl())) {
>> +      Diag(ELoc, diag::err_omp_expected_var_name) << ERange;
>> +      continue;
>> +    }
>> +    auto D = DE->getDecl();
>> +    auto VD = cast<VarDecl>(D);
>> +    auto Type = VD->getType();
>> +    // OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
>> +    //  A variable that appears in a private clause must not have an
>> incomplete
>> +    //  type or a reference type.
>> +    if (RequireCompleteType(ELoc, Type,
>> +                            diag::err_omp_reduction_incomplete_type))
>> +      continue;
>> +    // OpenMP [2.14.3.6, reduction clause, Restrictions]
>> +    // Arrays may not appear in a reduction clause.
>> +    if (Type.getNonReferenceType()->isArrayType()) {
>> +      Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange;
>> +      bool IsDecl =
>> +          VD->isThisDeclarationADefinition(Context) ==
>> VarDecl::DeclarationOnly;
>> +      Diag(VD->getLocation(),
>> +           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
>> +          << VD;
>> +      continue;
>> +    }
>> +    // OpenMP [2.14.3.6, reduction clause, Restrictions]
>> +    // A list item that appears in a reduction clause must not be
>> +    // const-qualified.
>> +    if (Type.getNonReferenceType().isConstant(Context)) {
>> +      Diag(ELoc, diag::err_omp_const_variable)
>> +          << getOpenMPClauseName(OMPC_reduction) << Type << ERange;
>> +      bool IsDecl =
>> +          VD->isThisDeclarationADefinition(Context) ==
>> VarDecl::DeclarationOnly;
>> +      Diag(VD->getLocation(),
>> +           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
>> +          << VD;
>> +      continue;
>> +    }
>> +    // OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
>> +    //  If a list-item is a reference type then it must bind to the
>> same object
>> +    //  for all threads of the team.
>> +    VarDecl *VDDef = VD->getDefinition();
>> +    if (Type->isReferenceType() && VDDef) {
>> +      DSARefChecker Check(DSAStack);
>> +      if (Check.Visit(VDDef->getInit())) {
>> +        Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange;
>> +        Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
>> +        continue;
>> +      }
>> +    }
>> +    // OpenMP [2.14.3.6, reduction clause, Restrictions]
>> +    // The type of a list item that appears in a reduction clause
>> must be valid
>> +    // for the reduction-identifier. For a max or min reduction in
>> C, the type
>> +    // of the list item must be an allowed arithmetic data type:
>> char, int,
>> +    // float, double, or _Bool, possibly modified with long, short,
>> signed, or
>> +    // unsigned. For a max or min reduction in C++, the type of the
>> list item
>> +    // must be an allowed arithmetic data type: char, wchar_t, int,
>> float,
>> +    // double, or bool, possibly modified with long, short, signed,
>> or unsigned.
>> +    if ((BOK == BO_GT || BOK == BO_LT) &&
>> +        !(Type->isScalarType() ||
>> +          (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
>> +      Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
>> +          << getLangOpts().CPlusPlus;
>> +      bool IsDecl =
>> +          VD->isThisDeclarationADefinition(Context) ==
>> VarDecl::DeclarationOnly;
>> +      Diag(VD->getLocation(),
>> +           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
>> +          << VD;
>> +      continue;
>> +    }
>> +    if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK ==
>> BO_XorAssign) &&
>> +        !getLangOpts().CPlusPlus && Type->isFloatingType()) {
>> +      Diag(ELoc, diag::err_omp_clause_floating_type_arg);
>> +      bool IsDecl =
>> +          VD->isThisDeclarationADefinition(Context) ==
>> VarDecl::DeclarationOnly;
>> +      Diag(VD->getLocation(),
>> +           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
>> +          << VD;
>> +      continue;
>> +    }
>> +    bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
>> +    getDiagnostics().setSuppressAllDiagnostics(true);
>
> Could you explain what the intention is here? An error trap might be
> more appropriate.
>
> Alp.
>
>> +    ExprResult ReductionOp =
>> +        BuildBinOp(DSAStack->getCurScope(),
>> ReductionId.getLocStart(), BOK,
>> +                   RefExpr, RefExpr);
>> +    getDiagnostics().setSuppressAllDiagnostics(Suppress);
>> +    if (ReductionOp.isInvalid()) {
>> +      Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
>> +          << ReductionIdRange;
>> +      bool IsDecl =
>> +          VD->isThisDeclarationADefinition(Context) ==
>> VarDecl::DeclarationOnly;
>> +      Diag(VD->getLocation(),
>> +           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
>> +          << VD;
>> +      continue;
>> +    }
>> +
>> +    // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables
>> Referenced
>> +    // in a Construct]
>> +    //  Variables with the predetermined data-sharing attributes may
>> not be
>> +    //  listed in data-sharing attributes clauses, except for the cases
>> +    //  listed below. For these exceptions only, listing a
>> predetermined
>> +    //  variable in a data-sharing attribute clause is allowed and
>> overrides
>> +    //  the variable's predetermined data-sharing attributes.
>> +    // OpenMP [2.14.3.6, Restrictions, p.3]
>> +    //  Any number of reduction clauses can be specified on the
>> directive,
>> +    //  but a list item can appear only once in the reduction
>> clauses for that
>> +    //  directive.
>> +    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
>> +    if (DVar.CKind == OMPC_reduction) {
>> +      Diag(ELoc, diag::err_omp_once_referenced)
>> +          << getOpenMPClauseName(OMPC_reduction);
>> +      if (DVar.RefExpr) {
>> +        Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
>> +      }
>> +    } else if (DVar.CKind != OMPC_unknown) {
>> +      Diag(ELoc, diag::err_omp_wrong_dsa)
>> +          << getOpenMPClauseName(DVar.CKind)
>> +          << getOpenMPClauseName(OMPC_reduction);
>> +      if (DVar.RefExpr) {
>> +        Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
>> +            << getOpenMPClauseName(DVar.CKind);
>> +      } else {
>> +        Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
>> +            << getOpenMPClauseName(DVar.CKind);
>> +      }
>> +      continue;
>> +    }
>> +
>> +    // OpenMP [2.14.3.6, Restrictions, p.1]
>> +    //  A list item that appears in a reduction clause of a worksharing
>> +    //  construct must be shared in the parallel regions to which
>> any of the
>> +    //  worksharing regions arising from the worksharing construct
>> bind.
>> +    // TODO Implement it later.
>> +
>> +    CXXRecordDecl *RD = getLangOpts().CPlusPlus
>> +                            ?
>> Type.getNonReferenceType()->getAsCXXRecordDecl()
>> +                            : nullptr;
>> +    if (RD) {
>> +      CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
>> +      PartialDiagnostic PD =
>> +          PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
>> +      if (!CD || CheckConstructorAccess(
>> +                     ELoc, CD,
>> InitializedEntity::InitializeTemporary(Type),
>> +                     CD->getAccess(), PD) == AR_inaccessible ||
>> +          CD->isDeleted()) {
>> +        Diag(ELoc, diag::err_omp_required_method)
>> +            << getOpenMPClauseName(OMPC_reduction) << 0;
>> +        bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
>> +                      VarDecl::DeclarationOnly;
>> +        Diag(VD->getLocation(),
>> +             IsDecl ? diag::note_previous_decl :
>> diag::note_defined_here)
>> +            << VD;
>> +        Diag(RD->getLocation(), diag::note_previous_decl) << RD;
>> +        continue;
>> +      }
>> +      MarkFunctionReferenced(ELoc, CD);
>> +      DiagnoseUseOfDecl(CD, ELoc);
>> +
>> +      CXXDestructorDecl *DD = RD->getDestructor();
>> +      if (DD) {
>> +        if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
>> +            DD->isDeleted()) {
>> +          Diag(ELoc, diag::err_omp_required_method)
>> +              << getOpenMPClauseName(OMPC_reduction) << 4;
>> +          bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
>> +                        VarDecl::DeclarationOnly;
>> +          Diag(VD->getLocation(),
>> +               IsDecl ? diag::note_previous_decl :
>> diag::note_defined_here)
>> +              << VD;
>> +          Diag(RD->getLocation(), diag::note_previous_decl) << RD;
>> +          continue;
>> +        }
>> +        MarkFunctionReferenced(ELoc, DD);
>> +        DiagnoseUseOfDecl(DD, ELoc);
>> +      }
>> +    }
>> +
>> +    DSAStack->addDSA(VD, DE, OMPC_reduction);
>> +    Vars.push_back(DE);
>> +  }
>> +
>> +  if (Vars.empty())
>> +    return nullptr;
>> +
>> +  return OMPReductionClause::Create(
>> +      Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
>> +      ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId);
>> +}
>> +
>>   OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList,
>> Expr *Step,
>>                                            SourceLocation StartLoc,
>>                                            SourceLocation LParenLoc,
>> Index: lib/Sema/TreeTransform.h
>> ===================================================================
>> --- lib/Sema/TreeTransform.h
>> +++ lib/Sema/TreeTransform.h
>> @@ -1394,6 +1394,22 @@
>>                                                EndLoc);
>>     }
>> +  /// \brief Build a new OpenMP 'reduction' clause.
>> +  ///
>> +  /// By default, performs semantic analysis to build the new
>> statement.
>> +  /// Subclasses may override this routine to provide different
>> behavior.
>> +  OMPClause *RebuildOMPReductionClause(ArrayRef<Expr *> VarList,
>> +                                       SourceLocation StartLoc,
>> +                                       SourceLocation LParenLoc,
>> +                                       SourceLocation ColonLoc,
>> +                                       SourceLocation EndLoc,
>> +                                       CXXScopeSpec
>> &ReductionIdScopeSpec,
>> +                                       const DeclarationNameInfo
>> &ReductionId) {
>> +    return getSema().ActOnOpenMPReductionClause(
>> +        VarList, StartLoc, LParenLoc, ColonLoc, EndLoc,
>> ReductionIdScopeSpec,
>> +        ReductionId);
>> +  }
>> +
>>     /// \brief Build a new OpenMP 'linear' clause.
>>     ///
>>     /// By default, performs semantic analysis to build the new
>> statement.
>> @@ -6320,21 +6336,16 @@
>>          I != E; ++I) {
>>       if (*I) {
>>         OMPClause *Clause = getDerived().TransformOMPClause(*I);
>> -      if (!Clause) {
>> -        return StmtError();
>> -      }
>> -      TClauses.push_back(Clause);
>> -    }
>> -    else {
>> -      TClauses.push_back(nullptr);
>> +      if (Clause)
>> +        TClauses.push_back(Clause);
>>       }
>>     }
>>     if (!D->getAssociatedStmt()) {
>>       return StmtError();
>>     }
>>     StmtResult AssociatedStmt =
>>       getDerived().TransformStmt(D->getAssociatedStmt());
>> -  if (AssociatedStmt.isInvalid()) {
>> +  if (AssociatedStmt.isInvalid() || TClauses.size() !=
>> Clauses.size()) {
>>       return StmtError();
>>     }
>> @@ -6469,6 +6480,31 @@
>>                                                C->getLocEnd());
>>   }
>> +template <typename Derived>
>> +OMPClause *
>> +TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause
>> *C) {
>> +  llvm::SmallVector<Expr *, 16> Vars;
>> +  Vars.reserve(C->varlist_size());
>> +  for (auto *VE : C->varlists()) {
>> +    ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
>> +    if (EVar.isInvalid())
>> +      return nullptr;
>> +    Vars.push_back(EVar.take());
>> +  }
>> +  CXXScopeSpec ReductionIdScopeSpec;
>> +  ReductionIdScopeSpec.Adopt(C->getQualifierLoc());
>> +
>> +  DeclarationNameInfo NameInfo = C->getNameInfo();
>> +  if (NameInfo.getName()) {
>> +    NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
>> +    if (!NameInfo.getName())
>> +      return nullptr;
>> +  }
>> +  return getDerived().RebuildOMPReductionClause(
>> +      Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
>> +      C->getLocEnd(), ReductionIdScopeSpec, NameInfo);
>> +}
>> +
>>   template<typename Derived>
>>   OMPClause *
>>   TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
>> Index: lib/Serialization/ASTReaderStmt.cpp
>> ===================================================================
>> --- lib/Serialization/ASTReaderStmt.cpp
>> +++ lib/Serialization/ASTReaderStmt.cpp
>> @@ -1697,6 +1697,9 @@
>>     case OMPC_shared:
>>       C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
>>       break;
>> +  case OMPC_reduction:
>> +    C = OMPReductionClause::CreateEmpty(Context, Record[Idx++]);
>> +    break;
>>     case OMPC_linear:
>>       C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]);
>>       break;
>> @@ -1770,6 +1773,24 @@
>>     C->setVarRefs(Vars);
>>   }
>> +void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
>> +  C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
>> +  C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
>> +  NestedNameSpecifierLoc NNSL =
>> +    Reader->Reader.ReadNestedNameSpecifierLoc(Reader->F, Record, Idx);
>> +  DeclarationNameInfo DNI;
>> +  Reader->ReadDeclarationNameInfo(DNI, Record, Idx);
>> +  C->setQualifierLoc(NNSL);
>> +  C->setNameInfo(DNI);
>> +
>> +  unsigned NumVars = C->varlist_size();
>> +  SmallVector<Expr *, 16> Vars;
>> +  Vars.reserve(NumVars);
>> +  for (unsigned i = 0; i != NumVars; ++i)
>> +    Vars.push_back(Reader->Reader.ReadSubExpr());
>> +  C->setVarRefs(Vars);
>> +}
>> +
>>   void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
>>     C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
>>     C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
>> Index: lib/Serialization/ASTWriterStmt.cpp
>> ===================================================================
>> --- lib/Serialization/ASTWriterStmt.cpp
>> +++ lib/Serialization/ASTWriterStmt.cpp
>> @@ -1723,6 +1723,16 @@
>>       Writer->Writer.AddStmt(VE);
>>   }
>> +void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
>> +  Record.push_back(C->varlist_size());
>> +  Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
>> +  Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
>> +  Writer->Writer.AddNestedNameSpecifierLoc(C->getQualifierLoc(),
>> Record);
>> +  Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record);
>> +  for (auto *VE : C->varlists())
>> +    Writer->Writer.AddStmt(VE);
>> +}
>> +
>>   void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
>>     Record.push_back(C->varlist_size());
>>     Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
>> Index: test/OpenMP/parallel_ast_print.cpp
>> ===================================================================
>> --- test/OpenMP/parallel_ast_print.cpp
>> +++ test/OpenMP/parallel_ast_print.cpp
>> @@ -35,9 +35,9 @@
>>     S<T> s;
>>   #pragma omp parallel
>>     a=2;
>> -#pragma omp parallel default(none), private(argc,b)
>> firstprivate(argv) shared (d) if (argc > 0) num_threads(C)
>> copyin(S<T>::TS) proc_bind(master)
>> +#pragma omp parallel default(none), private(argc,b)
>> firstprivate(argv) shared (d) if (argc > 0) num_threads(C)
>> copyin(S<T>::TS) proc_bind(master) reduction(+:c) reduction(max:e)
>>     foo();
>> -#pragma omp parallel if (C) num_threads(s) proc_bind(close)
>> +#pragma omp parallel if (C) num_threads(s) proc_bind(close)
>> reduction(^:e, f) reduction(&& : g)
>>     foo();
>>     return 0;
>>   }
>> @@ -48,29 +48,29 @@
>>   // CHECK-NEXT: S<int> s;
>>   // CHECK-NEXT: #pragma omp parallel
>>   // CHECK-NEXT: a = 2;
>> -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
>> firstprivate(argv) shared(d) if(argc > 0) num_threads(5)
>> copyin(S<int>::TS) proc_bind(master)
>> +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
>> firstprivate(argv) shared(d) if(argc > 0) num_threads(5)
>> copyin(S<int>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
>>   // CHECK-NEXT: foo()
>> -// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s)
>> proc_bind(close)
>> +// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s)
>> proc_bind(close) reduction(^: e,f) reduction(&&: g)
>>   // CHECK-NEXT: foo()
>>   // CHECK: template <typename T = long, int C = 1> long tmain(long
>> argc, long *argv) {
>>   // CHECK-NEXT: long b = argc, c, d, e, f, g;
>>   // CHECK-NEXT: static long a;
>>   // CHECK-NEXT: S<long> s;
>>   // CHECK-NEXT: #pragma omp parallel
>>   // CHECK-NEXT: a = 2;
>> -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
>> firstprivate(argv) shared(d) if(argc > 0) num_threads(1)
>> copyin(S<long>::TS) proc_bind(master)
>> +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
>> firstprivate(argv) shared(d) if(argc > 0) num_threads(1)
>> copyin(S<long>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
>>   // CHECK-NEXT: foo()
>> -// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s)
>> proc_bind(close)
>> +// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s)
>> proc_bind(close) reduction(^: e,f) reduction(&&: g)
>>   // CHECK-NEXT: foo()
>>   // CHECK: template <typename T, int C> T tmain(T argc, T *argv) {
>>   // CHECK-NEXT: T b = argc, c, d, e, f, g;
>>   // CHECK-NEXT: static T a;
>>   // CHECK-NEXT: S<T> s;
>>   // CHECK-NEXT: #pragma omp parallel
>>   // CHECK-NEXT: a = 2;
>> -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
>> firstprivate(argv) shared(d) if(argc > 0) num_threads(C)
>> copyin(S<T>::TS) proc_bind(master)
>> +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
>> firstprivate(argv) shared(d) if(argc > 0) num_threads(C)
>> copyin(S<T>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
>>   // CHECK-NEXT: foo()
>> -// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s)
>> proc_bind(close)
>> +// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s)
>> proc_bind(close) reduction(^: e,f) reduction(&&: g)
>>   // CHECK-NEXT: foo()
>>   enum Enum { };
>> @@ -86,8 +86,8 @@
>>   // CHECK-NEXT: #pragma omp parallel
>>     a=2;
>>   // CHECK-NEXT: a = 2;
>> -#pragma omp parallel default(none), private(argc,b)
>> firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a)
>> proc_bind(spread)
>> -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
>> firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a)
>> proc_bind(spread)
>> +#pragma omp parallel default(none), private(argc,b)
>> firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a)
>> proc_bind(spread) reduction(| : c, d) reduction(* : e)
>> +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
>> firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a)
>> proc_bind(spread) reduction(|: c,d) reduction(*: e)
>>     foo();
>>   // CHECK-NEXT: foo();
>>     return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
>> Index: test/OpenMP/parallel_reduction_messages.cpp
>> ===================================================================
>> --- test/OpenMP/parallel_reduction_messages.cpp
>> +++ test/OpenMP/parallel_reduction_messages.cpp
>> @@ -0,0 +1,215 @@
>> +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s
>> +
>> +void foo() {
>> +}
>> +
>> +bool foobool(int argc) {
>> +  return argc;
>> +}
>> +
>> +struct S1; // expected-note {{declared here}} expected-note 4
>> {{forward declaration of 'S1'}}
>> +extern S1 a;
>> +class S2 {
>> +  mutable int a;
>> +  S2 &operator +=(const S2 &arg) {return (*this);}
>> +public:
>> +  S2():a(0) { }
>> +  S2(S2 &s2):a(s2.a) { }
>> +  static float S2s; // expected-note 2 {{predetermined as shared}}
>> +  static const float S2sc;
>> +};
>> +const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
>> +S2 b; // expected-note 2 {{'b' defined here}}
>> +const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
>> +class S3 {
>> +  int a;
>> +public:
>> +  S3():a(0) { }
>> +  S3(const S3 &s3):a(s3.a) { }
>> +  S3 operator +=(const S3 &arg1) {return arg1;}
>> +};
>> +int operator +=(const S3 &arg1, const S3 &arg2) {return 5;}
>> +S3 c; // expected-note 2 {{'c' defined here}}
>> +const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
>> +extern const int f; // expected-note 4 {{'f' declared here}}
>> +class S4 { // expected-note {{'S4' declared here}}
>> +  int a;
>> +  S4();
>> +  S4(const S4 &s4);
>> +  S4 &operator +=(const S4 &arg) {return (*this);}
>> +public:
>> +  S4(int v):a(v) { }
>> +};
>> +S4 &operator &=(S4 &arg1, S4 &arg2) {return arg1;}
>> +class S5 {
>> +  int a;
>> +  S5():a(0) {}
>> +  S5(const S5 &s5):a(s5.a) { }
>> +  S5 &operator +=(const S5 &arg);
>> +public:
>> +  S5(int v):a(v) { }
>> +};
>> +class S6 {
>> +    int a;
>> +  public:
>> +    S6():a(6){ }
>> +    operator int() { return 6; }
>> +} o; // expected-note 2 {{'o' defined here}}
>> +
>> +S3 h, k;
>> +#pragma omp threadprivate(h) // expected-note 2 {{defined as
>> threadprivate or thread local}}
>> +
>> +template <class T> // expected-note {{declared here}}
>> +T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
>> +  const T d = T(); // expected-note 4 {{'d' defined here}}
>> +  const T da[5] = { T() }; // expected-note 2 {{'da' defined here}}
>> +  T qa[5] = { T() };
>> +  T i;
>> +  T &j = i; // expected-note 4 {{'j' defined here}}
>> +  S3 &p = k; // expected-note 2 {{'p' defined here}}
>> +  const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
>> +  T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
>> +  T fl; // expected-note {{'fl' defined here}}
>> +  #pragma omp parallel reduction // expected-error {{expected '('
>> after 'reduction'}}
>> +  foo();
>> +  #pragma omp parallel reduction + // expected-error {{expected '('
>> after 'reduction'}} expected-warning {{extra tokens at the end of
>> '#pragma omp parallel' are ignored}}
>> +  foo();
>> +  #pragma omp parallel reduction ( // expected-error {{expected
>> unqualified-id}} expected-warning {{missing ':' after reduction
>> identifier - ignoring}} expected-error {{expected ')'}} expected-note
>> {{to match this '('}}
>> +  foo();
>> +  #pragma omp parallel reduction (- // expected-warning {{missing
>> ':' after reduction identifier - ignoring}} expected-error {{expected
>> expression}} expected-error {{expected ')'}} expected-note {{to match
>> this '('}}
>> +  foo();
>> +  #pragma omp parallel reduction () // expected-error {{expected
>> unqualified-id}} expected-warning {{missing ':' after reduction
>> identifier - ignoring}}
>> +  foo();
>> +  #pragma omp parallel reduction (*) // expected-warning {{missing
>> ':' after reduction identifier - ignoring}} expected-error {{expected
>> expression}}
>> +  foo();
>> +  #pragma omp parallel reduction (\) // expected-error {{expected
>> unqualified-id}} expected-warning {{missing ':' after reduction
>> identifier - ignoring}}
>> +  foo();
>> +  #pragma omp parallel reduction (&: argc // expected-error
>> {{expected ')'}} expected-note {{to match this '('}} expected-error
>> {{variable of type 'float' is not valid for specified reduction
>> operation}}
>> +  foo();
>> +  #pragma omp parallel reduction (| :argc, // expected-error
>> {{expected expression}} expected-error {{expected ')'}} expected-note
>> {{to match this '('}} expected-error {{variable of type 'float' is
>> not valid for specified reduction operation}}
>> +  foo();
>> +  #pragma omp parallel reduction (|| :argc ? i : argc) //
>> expected-error 2 {{expected variable name}}
>> +  foo();
>> +  #pragma omp parallel reduction (foo:argc) //expected-error
>> {{incorrect reduction identifier, expected one of '+', '-', '*', '&',
>> '|', '^', '&&', '||', 'min' or 'max'}}
>> +  foo();
>> +  #pragma omp parallel reduction (&& :argc)
>> +  foo();
>> +  #pragma omp parallel reduction (^ : T) // expected-error {{'T'
>> does not refer to a value}}
>> +  foo();
>> +  #pragma omp parallel reduction (+ : a, b, c, d, f) //
>> expected-error {{reduction variable with incomplete type 'S1'}}
>> expected-error 3 {{const-qualified variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction (min : a, b, c, d, f) //
>> expected-error {{reduction variable with incomplete type 'S1'}}
>> expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min'
>> or 'max' must be of arithmetic type}} expected-error 3
>> {{const-qualified variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction (max : qa[1]) // expected-error 2
>> {{expected variable name}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : ba) // expected-error {{a
>> reduction variable with array type 'const S2 [5]'}}
>> +  foo();
>> +  #pragma omp parallel reduction(* : ca) // expected-error {{a
>> reduction variable with array type 'const S3 [5]'}}
>> +  foo();
>> +  #pragma omp parallel reduction(- : da) // expected-error {{a
>> reduction variable with array type 'const int [5]'}} expected-error
>> {{a reduction variable with array type 'const float [5]'}}
>> +  foo();
>> +  #pragma omp parallel reduction(^ : fl) // expected-error
>> {{variable of type 'float' is not valid for specified reduction
>> operation}}
>> +  foo();
>> +  #pragma omp parallel reduction(&& : S2::S2s) // expected-error
>> {{shared variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction(&& : S2::S2sc) // expected-error
>> {{const-qualified variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : h, k) // expected-error
>> {{threadprivate or thread local variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : o) // expected-error {{variable
>> of type 'class S6' is not valid for specified reduction operation}}
>> +  foo();
>> +  #pragma omp parallel private(i), reduction(+ : j), reduction(+:q)
>> // expected-error 4 {{argument of OpenMP clause 'reduction' must
>> reference the same object in all threads}}
>> +  foo();
>> +  #pragma omp parallel private(k)
>> +  #pragma omp parallel reduction(+ : p), reduction(+ : p) //
>> expected-error 2 {{argument of OpenMP clause 'reduction' must
>> reference the same object in all threads}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : p), reduction(+ : p) //
>> expected-error 3 {{variable can appear only once in OpenMP
>> 'reduction' clause}} expected-note 3 {{previously referenced here}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : r) // expected-error 2
>> {{const-qualified variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel shared(i)
>> +  #pragma omp parallel reduction(min : i)
>> +  #pragma omp parallel reduction(max : j) // expected-error 2
>> {{argument of OpenMP clause 'reduction' must reference the same
>> object in all threads}}
>> +  foo();
>> +
>> +  return T();
>> +}
>> +
>> +int main(int argc, char **argv) {
>> +  const int d = 5; // expected-note 2 {{'d' defined here}}
>> +  const int da[5] = { 0 }; // expected-note {{'da' defined here}}
>> +  int qa[5] = { 0 };
>> +  S4 e(4); // expected-note {{'e' defined here}}
>> +  S5 g(5); // expected-note {{'g' defined here}}
>> +  int i;
>> +  int &j = i; // expected-note 2 {{'j' defined here}}
>> +  S3 &p = k; // expected-note 2 {{'p' defined here}}
>> +  const int &r = da[i]; // expected-note {{'r' defined here}}
>> +  int &q = qa[i]; // expected-note {{'q' defined here}}
>> +  float fl; // expected-note {{'fl' defined here}}
>> +  #pragma omp parallel reduction // expected-error {{expected '('
>> after 'reduction'}}
>> +  foo();
>> +  #pragma omp parallel reduction + // expected-error {{expected '('
>> after 'reduction'}} expected-warning {{extra tokens at the end of
>> '#pragma omp parallel' are ignored}}
>> +  foo();
>> +  #pragma omp parallel reduction ( // expected-error {{expected
>> unqualified-id}} expected-warning {{missing ':' after reduction
>> identifier - ignoring}} expected-error {{expected ')'}} expected-note
>> {{to match this '('}}
>> +  foo();
>> +  #pragma omp parallel reduction (- // expected-warning {{missing
>> ':' after reduction identifier - ignoring}} expected-error {{expected
>> expression}} expected-error {{expected ')'}} expected-note {{to match
>> this '('}}
>> +  foo();
>> +  #pragma omp parallel reduction () // expected-error {{expected
>> unqualified-id}} expected-warning {{missing ':' after reduction
>> identifier - ignoring}}
>> +  foo();
>> +  #pragma omp parallel reduction (*) // expected-warning {{missing
>> ':' after reduction identifier - ignoring}} expected-error {{expected
>> expression}}
>> +  foo();
>> +  #pragma omp parallel reduction (\) // expected-error {{expected
>> unqualified-id}} expected-warning {{missing ':' after reduction
>> identifier - ignoring}}
>> +  foo();
>> +  #pragma omp parallel reduction (foo: argc // expected-error
>> {{expected ')'}} expected-note {{to match this '('}} expected-error
>> {{incorrect reduction identifier, expected one of '+', '-', '*', '&',
>> '|', '^', '&&', '||', 'min' or 'max'}}
>> +  foo();
>> +  #pragma omp parallel reduction (| :argc, // expected-error
>> {{expected expression}} expected-error {{expected ')'}} expected-note
>> {{to match this '('}}
>> +  foo();
>> +  #pragma omp parallel reduction (|| :argc > 0 ? argv[1] : argv[2])
>> // expected-error {{expected variable name}}
>> +  foo();
>> +  #pragma omp parallel reduction (~:argc) // expected-error
>> {{expected unqualified-id}}
>> +  foo();
>> +  #pragma omp parallel reduction (&& :argc)
>> +  foo();
>> +  #pragma omp parallel reduction (^ : S1) // expected-error {{'S1'
>> does not refer to a value}}
>> +  foo();
>> +  #pragma omp parallel reduction (+ : a, b, c, d, f) //
>> expected-error {{reduction variable with incomplete type 'S1'}}
>> expected-error 2 {{const-qualified variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction (min : a, b, c, d, f) //
>> expected-error {{reduction variable with incomplete type 'S1'}}
>> expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min'
>> or 'max' must be of arithmetic type}} expected-error 2
>> {{const-qualified variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction (max : argv[1]) // expected-error
>> {{expected variable name}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : ba) // expected-error {{a
>> reduction variable with array type 'const S2 [5]'}}
>> +  foo();
>> +  #pragma omp parallel reduction(* : ca) // expected-error {{a
>> reduction variable with array type 'const S3 [5]'}}
>> +  foo();
>> +  #pragma omp parallel reduction(- : da) // expected-error {{a
>> reduction variable with array type 'const int [5]'}}
>> +  foo();
>> +  #pragma omp parallel reduction(^ : fl) // expected-error
>> {{variable of type 'float' is not valid for specified reduction
>> operation}}
>> +  foo();
>> +  #pragma omp parallel reduction(&& : S2::S2s) // expected-error
>> {{shared variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction(&& : S2::S2sc) // expected-error
>> {{const-qualified variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction(& : e, g) // expected-error
>> {{reduction variable must have an accessible, unambiguous default
>> constructor}} expected-error {{variable of type 'S5' is not valid for
>> specified reduction operation}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : h, k) // expected-error
>> {{threadprivate or thread local variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : o) // expected-error {{variable
>> of type 'class S6' is not valid for specified reduction operation}}
>> +  foo();
>> +  #pragma omp parallel private(i), reduction(+ : j), reduction(+:q)
>> // expected-error 2 {{argument of OpenMP clause 'reduction' must
>> reference the same object in all threads}}
>> +  foo();
>> +  #pragma omp parallel private(k)
>> +  #pragma omp parallel reduction(+ : p), reduction(+ : p) //
>> expected-error 2 {{argument of OpenMP clause 'reduction' must
>> reference the same object in all threads}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : p), reduction(+ : p) //
>> expected-error {{variable can appear only once in OpenMP 'reduction'
>> clause}} expected-note {{previously referenced here}}
>> +  foo();
>> +  #pragma omp parallel reduction(+ : r) // expected-error
>> {{const-qualified variable cannot be reduction}}
>> +  foo();
>> +  #pragma omp parallel shared(i)
>> +  #pragma omp parallel reduction(min : i)
>> +  #pragma omp parallel reduction(max : j) // expected-error
>> {{argument of OpenMP clause 'reduction' must reference the same
>> object in all threads}}
>> +  foo();
>> +
>> +  return tmain(argc) + tmain(fl); // expected-note {{in
>> instantiation of function template specialization 'tmain<int>'
>> requested here}} expected-note {{in instantiation of function
>> template specialization 'tmain<float>' requested here}}
>> +}
>> Index: test/OpenMP/simd_linear_messages.cpp
>> ===================================================================
>> --- test/OpenMP/simd_linear_messages.cpp
>> +++ test/OpenMP/simd_linear_messages.cpp
>> @@ -50,10 +50,11 @@
>>     // expected-error at +1 {{argument of a linear clause should be of
>> integral or pointer type}}
>>   #pragma omp simd linear(ind2:L)
>>     for (i = 0; i < num; ++i) {
>> -    T cur = arr[ind2];
>> +    T cur = arr[(int)ind2];
>>       ind2 += L;
>>       sum += cur;
>>     }
>> +  return T();
>>   }
>>   template<int LEN> int test_warn() {
>> Index: tools/libclang/CIndex.cpp
>> ===================================================================
>> --- tools/libclang/CIndex.cpp
>> +++ tools/libclang/CIndex.cpp
>> @@ -1955,6 +1955,9 @@
>>   void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause
>> *C) {
>>     VisitOMPClauseList(C);
>>   }
>> +void OMPClauseEnqueue::VisitOMPReductionClause(const
>> OMPReductionClause *C) {
>> +  VisitOMPClauseList(C);
>> +}
>>   void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause
>> *C) {
>>     VisitOMPClauseList(C);
>>     Visitor->AddStmt(C->getStep());
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>




More information about the cfe-commits mailing list