From 7bda3ec414cd8edaaa06f8f89e89c49adf57baea Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev@hotmail.com>
Date: Thu, 30 Jul 2015 11:36:16 +0000
Subject: [PATCH] [OPENMP 4.1] Initial support for extended 'ordered' clause.

OpenMP 4.1 introduces optional argument '(n)' for 'ordered' clause, where 'n' is a number of loops that immediately follow the directive.
'n' must be constant positive integer expressions and it must be less or equal than the number of the loops in the resulting loop nest.
Patch adds parsing and semantic analysis for this optional argument.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@243635 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/AST/DataRecursiveASTVisitor.h   |   3 +-
 include/clang/AST/OpenMPClause.h              |  39 +++--
 include/clang/AST/RecursiveASTVisitor.h       |   3 +-
 include/clang/Basic/DiagnosticSemaKinds.td    |   4 +-
 include/clang/Sema/Sema.h                     |   8 +-
 lib/AST/StmtPrinter.cpp                       |   7 +-
 lib/AST/StmtProfile.cpp                       |   5 +-
 lib/Parse/ParseOpenMP.cpp                     |   7 +-
 lib/Sema/SemaOpenMP.cpp                       | 153 ++++++++++++------
 lib/Sema/TreeTransform.h                      |  20 ++-
 lib/Serialization/ASTReaderStmt.cpp           |   5 +-
 lib/Serialization/ASTWriterStmt.cpp           |   5 +-
 test/OpenMP/for_ast_print.cpp                 |  14 +-
 test/OpenMP/for_ordered_clause.cpp            | 104 ++++++++++++
 test/OpenMP/parallel_for_ast_print.cpp        |  14 +-
 test/OpenMP/parallel_for_ordered_messages.cpp | 104 ++++++++++++
 tools/libclang/CIndex.cpp                     |   4 +-
 17 files changed, 424 insertions(+), 75 deletions(-)
 create mode 100644 test/OpenMP/for_ordered_clause.cpp
 create mode 100644 test/OpenMP/parallel_for_ordered_messages.cpp

diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index c776603c6b4..c1e98e757e1 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -2480,7 +2480,8 @@ RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
 }
 
 template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *) {
+bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *C) {
+  TRY_TO(TraverseStmt(C->getNumForLoops()));
   return true;
 }
 
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 7d3fcf04236..03104be1837 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -694,32 +694,53 @@ public:
 /// \brief This represents 'ordered' clause in the '#pragma omp ...' directive.
 ///
 /// \code
-/// #pragma omp for ordered
+/// #pragma omp for ordered (2)
 /// \endcode
-/// In this example directive '#pragma omp for' has 'ordered' clause.
+/// In this example directive '#pragma omp for' has 'ordered' clause with
+/// parameter 2.
 ///
 class OMPOrderedClause : public OMPClause {
+  friend class OMPClauseReader;
+  /// \brief Location of '('.
+  SourceLocation LParenLoc;
+  /// \brief Number of for-loops.
+  Stmt *NumForLoops;
+
+  /// \brief Set the number of associated for-loops.
+  void setNumForLoops(Expr *Num) { NumForLoops = Num; }
+
 public:
   /// \brief Build 'ordered' clause.
   ///
+  /// \param Num Expression, possibly associated with this clause.
   /// \param StartLoc Starting location of the clause.
+  /// \param LParenLoc Location of '('.
   /// \param EndLoc Ending location of the clause.
   ///
-  OMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc)
-      : OMPClause(OMPC_ordered, StartLoc, EndLoc) {}
+  OMPOrderedClause(Expr *Num, SourceLocation StartLoc,
+                    SourceLocation LParenLoc, SourceLocation EndLoc)
+      : OMPClause(OMPC_ordered, StartLoc, EndLoc), LParenLoc(LParenLoc),
+        NumForLoops(Num) {}
 
   /// \brief Build an empty clause.
   ///
-  OMPOrderedClause()
-      : OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()) {}
+  explicit OMPOrderedClause()
+      : OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()),
+        LParenLoc(SourceLocation()), NumForLoops(nullptr) {}
+
+  /// \brief Sets the location of '('.
+  void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+  /// \brief Returns the location of '('.
+  SourceLocation getLParenLoc() const { return LParenLoc; }
+
+  /// \brief Return the number of associated for-loops.
+  Expr *getNumForLoops() const { return cast_or_null<Expr>(NumForLoops); }
 
   static bool classof(const OMPClause *T) {
     return T->getClauseKind() == OMPC_ordered;
   }
 
-  child_range children() {
-    return child_range(child_iterator(), child_iterator());
-  }
+  child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); }
 };
 
 /// \brief This represents 'nowait' clause in the '#pragma omp ...' directive.
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 99f5e56cf40..e0a48e86b85 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2512,7 +2512,8 @@ RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
 }
 
 template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *) {
+bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *C) {
+  TRY_TO(TraverseStmt(C->getNumForLoops()));
   return true;
 }
 
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 51e069a9ae1..44508d59024 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7501,8 +7501,8 @@ def err_omp_loop_var_dsa : Error<
 def err_omp_not_for : Error<
   "%select{statement after '#pragma omp %1' must be a for loop|"
   "expected %2 for loops after '#pragma omp %1'%select{|, but found only %4}3}0">;
-def note_omp_collapse_expr : Note<
-  "as specified in 'collapse' clause">;
+def note_omp_collapse_ordered_expr : Note<
+  "as specified in %select{'collapse'|'ordered'|'collapse' and 'ordered'}0 clause%select{||s}0">;
 def err_omp_negative_expression_in_clause : Error<
   "argument to '%0' clause must be a positive integer value">;
 def err_omp_not_integral : Error<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 575f7055421..edd7b2576fa 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -7903,6 +7903,11 @@ public:
                                        SourceLocation StartLoc,
                                        SourceLocation LParenLoc,
                                        SourceLocation EndLoc);
+  /// \brief Called on well-formed 'ordered' clause.
+  OMPClause *
+  ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc,
+                           SourceLocation LParenLoc = SourceLocation(),
+                           Expr *NumForLoops = nullptr);
 
   OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
                                      unsigned Argument,
@@ -7940,9 +7945,6 @@ public:
 
   OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc,
                                SourceLocation EndLoc);
-  /// \brief Called on well-formed 'ordered' clause.
-  OMPClause *ActOnOpenMPOrderedClause(SourceLocation StartLoc,
-                                      SourceLocation EndLoc);
   /// \brief Called on well-formed 'nowait' clause.
   OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc,
                                      SourceLocation EndLoc);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 30f15e037ba..57187ca8620 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -651,8 +651,13 @@ void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
   OS << ")";
 }
 
-void OMPClausePrinter::VisitOMPOrderedClause(OMPOrderedClause *) {
+void OMPClausePrinter::VisitOMPOrderedClause(OMPOrderedClause *Node) {
   OS << "ordered";
+  if (auto *Num = Node->getNumForLoops()) {
+    OS << "(";
+    Num->printPretty(OS, nullptr, Policy, 0);
+    OS << ")";
+  }
 }
 
 void OMPClausePrinter::VisitOMPNowaitClause(OMPNowaitClause *) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index f2fa53d25cd..091682ad7ff 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -306,7 +306,10 @@ void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) {
   }
 }
 
-void OMPClauseProfiler::VisitOMPOrderedClause(const OMPOrderedClause *) {}
+void OMPClauseProfiler::VisitOMPOrderedClause(const OMPOrderedClause *C) {
+  if (auto *Num = C->getNumForLoops())
+    Profiler->VisitStmt(Num);
+}
 
 void OMPClauseProfiler::VisitOMPNowaitClause(const OMPNowaitClause *) {}
 
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 2234f1396d5..1266e447fca 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -415,6 +415,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
   case OMPC_num_threads:
   case OMPC_safelen:
   case OMPC_collapse:
+  case OMPC_ordered:
     // OpenMP [2.5, Restrictions]
     //  At most one if clause can appear on the directive.
     //  At most one num_threads clause can appear on the directive.
@@ -430,7 +431,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
       ErrorFound = true;
     }
 
-    Clause = ParseOpenMPSingleExprClause(CKind);
+    if (CKind == OMPC_ordered && PP.LookAhead(/*N=*/0).isNot(tok::l_paren))
+      Clause = ParseOpenMPClause(CKind);
+    else
+      Clause = ParseOpenMPSingleExprClause(CKind);
     break;
   case OMPC_default:
   case OMPC_proc_bind:
@@ -458,7 +462,6 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
 
     Clause = ParseOpenMPSingleExprWithArgClause(CKind);
     break;
-  case OMPC_ordered:
   case OMPC_nowait:
   case OMPC_untied:
   case OMPC_mergeable:
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 88a705056a2..422e0e4ca33 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -2751,7 +2751,7 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
 static bool CheckOpenMPIterationSpace(
     OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA,
     unsigned CurrentNestedLoopCount, unsigned NestedLoopCount,
-    Expr *NestedLoopCountExpr,
+    Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr,
     llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA,
     LoopIterationSpace &ResultIterSpace) {
   // OpenMP [2.6, Canonical Loop Form]
@@ -2759,13 +2759,24 @@ static bool CheckOpenMPIterationSpace(
   auto For = dyn_cast_or_null<ForStmt>(S);
   if (!For) {
     SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for)
-        << (NestedLoopCountExpr != nullptr) << getOpenMPDirectiveName(DKind)
-        << NestedLoopCount << (CurrentNestedLoopCount > 0)
-        << CurrentNestedLoopCount;
-    if (NestedLoopCount > 1)
-      SemaRef.Diag(NestedLoopCountExpr->getExprLoc(),
-                   diag::note_omp_collapse_expr)
-          << NestedLoopCountExpr->getSourceRange();
+        << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
+        << getOpenMPDirectiveName(DKind) << NestedLoopCount
+        << (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount;
+    if (NestedLoopCount > 1) {
+      if (CollapseLoopCountExpr && OrderedLoopCountExpr)
+        SemaRef.Diag(DSA.getConstructLoc(),
+                     diag::note_omp_collapse_ordered_expr)
+            << 2 << CollapseLoopCountExpr->getSourceRange()
+            << OrderedLoopCountExpr->getSourceRange();
+      else if (CollapseLoopCountExpr)
+        SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(),
+                     diag::note_omp_collapse_ordered_expr)
+            << 0 << CollapseLoopCountExpr->getSourceRange();
+      else
+        SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(),
+                     diag::note_omp_collapse_ordered_expr)
+            << 1 << OrderedLoopCountExpr->getSourceRange();
+    }
     return true;
   }
   assert(For->getBody());
@@ -2840,7 +2851,8 @@ static bool CheckOpenMPIterationSpace(
   } else if (LoopVarRefExpr != nullptr) {
     // Make the loop iteration variable private (for worksharing constructs),
     // linear (for simd directives with the only one associated loop) or
-    // lastprivate (for simd directives with several collapsed loops).
+    // lastprivate (for simd directives with several collapsed or ordered
+    // loops).
     if (DVar.CKind == OMPC_unknown)
       DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(),
                         /*FromParent=*/false);
@@ -2942,16 +2954,23 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) {
 /// \return Returns 0 if one of the collapsed stmts is not canonical for loop,
 /// number of collapsed loops otherwise.
 static unsigned
-CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
-                Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA,
+CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
+                Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef,
+                DSAStackTy &DSA,
                 llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA,
                 OMPLoopDirective::HelperExprs &Built) {
   unsigned NestedLoopCount = 1;
-  if (NestedLoopCountExpr) {
+  if (CollapseLoopCountExpr) {
     // Found 'collapse' clause - calculate collapse number.
     llvm::APSInt Result;
-    if (NestedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
-      NestedLoopCount = Result.getLimitedValue();
+    if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
+      NestedLoopCount += Result.getLimitedValue() - 1;
+  }
+  if (OrderedLoopCountExpr) {
+    // Found 'ordered' clause - calculate collapse number.
+    llvm::APSInt Result;
+    if (OrderedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
+      NestedLoopCount += Result.getLimitedValue() - 1;
   }
   // This is helper routine for loop directives (e.g., 'for', 'simd',
   // 'for simd', etc.).
@@ -2960,8 +2979,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
   Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true);
   for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
     if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt,
-                                  NestedLoopCount, NestedLoopCountExpr,
-                                  VarsWithImplicitDSA, IterSpaces[Cnt]))
+                                  NestedLoopCount, CollapseLoopCountExpr,
+                                  OrderedLoopCountExpr, VarsWithImplicitDSA,
+                                  IterSpaces[Cnt]))
       return 0;
     // Move on to the next nested for loop, or to the loop body.
     // OpenMP [2.8.1, simd construct, Restrictions]
@@ -2978,11 +2998,12 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
 
   // An example of what is generated for the following code:
   //
-  //   #pragma omp simd collapse(2)
+  //   #pragma omp simd collapse(2) ordered(2)
   //   for (i = 0; i < NI; ++i)
-  //     for (j = J0; j < NJ; j+=2) {
-  //     <loop body>
-  //   }
+  //     for (k = 0; k < NK; ++k)
+  //       for (j = J0; j < NJ; j+=2) {
+  //         <loop body>
+  //       }
   //
   // We generate the code below.
   // Note: the loop body may be outlined in CodeGen.
@@ -3292,7 +3313,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
   return NestedLoopCount;
 }
 
-static Expr *GetCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
+static Expr *getCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
   auto &&CollapseFilter = [](const OMPClause *C) -> bool {
     return C->getClauseKind() == OMPC_collapse;
   };
@@ -3303,15 +3324,27 @@ static Expr *GetCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
   return nullptr;
 }
 
+static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) {
+  auto &&OrderedFilter = [](const OMPClause *C) -> bool {
+    return C->getClauseKind() == OMPC_ordered;
+  };
+  OMPExecutableDirective::filtered_clause_iterator<decltype(OrderedFilter)> I(
+      Clauses, std::move(OrderedFilter));
+  if (I)
+    return cast<OMPOrderedClause>(*I)->getNumForLoops();
+  return nullptr;
+}
+
 StmtResult Sema::ActOnOpenMPSimdDirective(
     ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
     SourceLocation EndLoc,
     llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
   OMPLoopDirective::HelperExprs B;
-  // In presence of clause 'collapse', it will define the nested loops number.
-  unsigned NestedLoopCount =
-      CheckOpenMPLoop(OMPD_simd, GetCollapseNumberExpr(Clauses), AStmt, *this,
-                      *DSAStack, VarsWithImplicitDSA, B);
+  // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+  // define the nested loops number.
+  unsigned NestedLoopCount = CheckOpenMPLoop(
+      OMPD_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses),
+      AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
   if (NestedLoopCount == 0)
     return StmtError();
 
@@ -3338,10 +3371,11 @@ StmtResult Sema::ActOnOpenMPForDirective(
     SourceLocation EndLoc,
     llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
   OMPLoopDirective::HelperExprs B;
-  // In presence of clause 'collapse', it will define the nested loops number.
-  unsigned NestedLoopCount =
-      CheckOpenMPLoop(OMPD_for, GetCollapseNumberExpr(Clauses), AStmt, *this,
-                      *DSAStack, VarsWithImplicitDSA, B);
+  // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+  // define the nested loops number.
+  unsigned NestedLoopCount = CheckOpenMPLoop(
+      OMPD_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses),
+      AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
   if (NestedLoopCount == 0)
     return StmtError();
 
@@ -3358,10 +3392,12 @@ StmtResult Sema::ActOnOpenMPForSimdDirective(
     SourceLocation EndLoc,
     llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
   OMPLoopDirective::HelperExprs B;
-  // In presence of clause 'collapse', it will define the nested loops number.
+  // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+  // define the nested loops number.
   unsigned NestedLoopCount =
-      CheckOpenMPLoop(OMPD_for_simd, GetCollapseNumberExpr(Clauses), AStmt,
-                      *this, *DSAStack, VarsWithImplicitDSA, B);
+      CheckOpenMPLoop(OMPD_for_simd, getCollapseNumberExpr(Clauses),
+                      getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
+                      VarsWithImplicitDSA, B);
   if (NestedLoopCount == 0)
     return StmtError();
 
@@ -3490,10 +3526,12 @@ StmtResult Sema::ActOnOpenMPParallelForDirective(
   CS->getCapturedDecl()->setNothrow();
 
   OMPLoopDirective::HelperExprs B;
-  // In presence of clause 'collapse', it will define the nested loops number.
+  // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+  // define the nested loops number.
   unsigned NestedLoopCount =
-      CheckOpenMPLoop(OMPD_parallel_for, GetCollapseNumberExpr(Clauses), AStmt,
-                      *this, *DSAStack, VarsWithImplicitDSA, B);
+      CheckOpenMPLoop(OMPD_parallel_for, getCollapseNumberExpr(Clauses),
+                      getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
+                      VarsWithImplicitDSA, B);
   if (NestedLoopCount == 0)
     return StmtError();
 
@@ -3519,10 +3557,12 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
   CS->getCapturedDecl()->setNothrow();
 
   OMPLoopDirective::HelperExprs B;
-  // In presence of clause 'collapse', it will define the nested loops number.
+  // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+  // define the nested loops number.
   unsigned NestedLoopCount =
-      CheckOpenMPLoop(OMPD_parallel_for_simd, GetCollapseNumberExpr(Clauses),
-                      AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
+      CheckOpenMPLoop(OMPD_parallel_for_simd, getCollapseNumberExpr(Clauses),
+                      getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
+                      VarsWithImplicitDSA, B);
   if (NestedLoopCount == 0)
     return StmtError();
 
@@ -4426,6 +4466,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
   case OMPC_collapse:
     Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc);
     break;
+  case OMPC_ordered:
+    Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr);
+    break;
   case OMPC_default:
   case OMPC_proc_bind:
   case OMPC_schedule:
@@ -4438,7 +4481,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
   case OMPC_aligned:
   case OMPC_copyin:
   case OMPC_copyprivate:
-  case OMPC_ordered:
   case OMPC_nowait:
   case OMPC_untied:
   case OMPC_mergeable:
@@ -4588,7 +4630,11 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E,
     return ExprError();
   }
   if (CKind == OMPC_collapse) {
-    DSAStack->setCollapseNumber(Result.getExtValue());
+    DSAStack->setCollapseNumber(DSAStack->getCollapseNumber() - 1 +
+                                Result.getExtValue());
+  } else if (CKind == OMPC_ordered) {
+    DSAStack->setCollapseNumber(DSAStack->getCollapseNumber() - 1 +
+                                Result.getExtValue());
   }
   return ICE;
 }
@@ -4623,6 +4669,27 @@ OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops,
       OMPCollapseClause(NumForLoopsResult.get(), StartLoc, LParenLoc, EndLoc);
 }
 
+OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
+                                          SourceLocation EndLoc,
+                                          SourceLocation LParenLoc,
+                                          Expr *NumForLoops) {
+  DSAStack->setOrderedRegion();
+  // OpenMP [2.7.1, loop construct, Description]
+  // OpenMP [2.8.1, simd construct, Description]
+  // OpenMP [2.9.6, distribute construct, Description]
+  // The parameter of the ordered clause must be a constant
+  // positive integer expression if any.
+  if (NumForLoops && LParenLoc.isValid()) {
+    ExprResult NumForLoopsResult =
+        VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_ordered);
+    if (NumForLoopsResult.isInvalid())
+      return nullptr;
+    NumForLoops = NumForLoopsResult.get();
+  }
+  return new (Context)
+      OMPOrderedClause(NumForLoops, StartLoc, LParenLoc, EndLoc);
+}
+
 OMPClause *Sema::ActOnOpenMPSimpleClause(
     OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc,
     SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
@@ -4915,12 +4982,6 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
   return Res;
 }
 
-OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
-                                          SourceLocation EndLoc) {
-  DSAStack->setOrderedRegion();
-  return new (Context) OMPOrderedClause(StartLoc, EndLoc);
-}
-
 OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc,
                                          SourceLocation EndLoc) {
   DSAStack->setNowaitRegion();
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 35408acdad3..885dba778f1 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1447,6 +1447,16 @@ public:
         Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc);
   }
 
+  /// \brief Build a new OpenMP 'ordered' clause.
+  ///
+  /// By default, performs semantic analysis to build the new OpenMP clause.
+  /// Subclasses may override this routine to provide different behavior.
+  OMPClause *RebuildOMPOrderedClause(SourceLocation StartLoc,
+                                     SourceLocation EndLoc,
+                                     SourceLocation LParenLoc, Expr *Num) {
+    return getSema().ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Num);
+  }
+
   /// \brief Build a new OpenMP 'private' clause.
   ///
   /// By default, performs semantic analysis to build the new OpenMP clause.
@@ -7237,8 +7247,14 @@ TreeTransform<Derived>::TransformOMPScheduleClause(OMPScheduleClause *C) {
 template <typename Derived>
 OMPClause *
 TreeTransform<Derived>::TransformOMPOrderedClause(OMPOrderedClause *C) {
-  // No need to rebuild this clause, no template-dependent parameters.
-  return C;
+  ExprResult E;
+  if (auto *Num = C->getNumForLoops()) {
+    E = getDerived().TransformExpr(Num);
+    if (E.isInvalid())
+      return nullptr;
+  }
+  return getDerived().RebuildOMPOrderedClause(C->getLocStart(), C->getLocEnd(),
+                                              C->getLParenLoc(), E.get());
 }
 
 template <typename Derived>
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index f8aac551e1a..83c46253547 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1845,7 +1845,10 @@ void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) {
   C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx));
 }
 
-void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *) {}
+void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *C) {
+  C->setNumForLoops(Reader->Reader.ReadSubExpr());
+  C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
 
 void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *) {}
 
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 3cc0835448d..74a37fd4f9b 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1763,7 +1763,10 @@ void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) {
   Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record);
 }
 
-void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *) {}
+void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *C) {
+  Writer->Writer.AddStmt(C->getNumForLoops());
+  Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
 
 void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *) {}
 
diff --git a/test/OpenMP/for_ast_print.cpp b/test/OpenMP/for_ast_print.cpp
index c482ec56b9c..d87cece1762 100644
--- a/test/OpenMP/for_ast_print.cpp
+++ b/test/OpenMP/for_ast_print.cpp
@@ -20,7 +20,12 @@ T tmain(T argc) {
 // CHECK-NEXT: for (int i = 0; i < 2; ++i)
 // CHECK-NEXT: a = 2;
 #pragma omp parallel
-#pragma omp for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered nowait
+#pragma omp for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) nowait
+  for (int i = 0; i < 10; ++i)
+    for (int j = 0; j < 10; ++j)
+      for (int j = 0; j < 10; ++j)
+        for (int j = 0; j < 10; ++j)
+          for (int j = 0; j < 10; ++j)
   for (int i = 0; i < 10; ++i)
     for (int j = 0; j < 10; ++j)
       for (int j = 0; j < 10; ++j)
@@ -28,7 +33,12 @@ T tmain(T argc) {
           for (int j = 0; j < 10; ++j)
             foo();
   // CHECK-NEXT: #pragma omp parallel
-  // CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered nowait
+  // CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) nowait
+  // CHECK-NEXT: for (int i = 0; i < 10; ++i)
+  // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+  // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+  // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+  // CHECK-NEXT: for (int j = 0; j < 10; ++j)
   // CHECK-NEXT: for (int i = 0; i < 10; ++i)
   // CHECK-NEXT: for (int j = 0; j < 10; ++j)
   // CHECK-NEXT: for (int j = 0; j < 10; ++j)
diff --git a/test/OpenMP/for_ordered_clause.cpp b/test/OpenMP/for_ordered_clause.cpp
new file mode 100644
index 00000000000..5b080215873
--- /dev/null
+++ b/test/OpenMP/for_ordered_clause.cpp
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+  return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) {                   //expected-note 2 {{declared here}}
+#pragma omp for ordered
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered() // expected-error {{expected expression}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+// expected-error@+2 2 {{expression is not an integral constant expression}}
+// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+#pragma omp for ordered(argc
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
+#pragma omp for ordered(ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered(1)) // expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'ordered' clause}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp for', but found only 1}}
+// expected-error@+3 2 {{directive '#pragma omp for' cannot contain more than one 'ordered' clause}}
+// expected-error@+2 2 {{argument to 'ordered' clause must be a positive integer value}}
+// expected-error@+1 2 {{expression is not an integral constant expression}}
+#pragma omp for ordered(foobool(argc)), ordered(true), ordered(-5)
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered(S) // expected-error {{'S' does not refer to a value}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+// expected-error@+1 2 {{expression is not an integral constant expression}}
+#pragma omp for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered(1)
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered(N) // expected-error {{argument to 'ordered' clause must be a positive integer value}}
+  for (T i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}}
+  foo();                    // expected-error {{expected 2 for loops after '#pragma omp for'}}
+  return argc;
+}
+
+int main(int argc, char **argv) {
+#pragma omp for ordered
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp for ordered( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp for ordered() // expected-error {{expected expression}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp for ordered(4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'ordered' clause}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4]; // expected-error {{expected 4 for loops after '#pragma omp for', but found only 1}}
+#pragma omp for ordered(2 + 2))              // expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}}  expected-note {{as specified in 'ordered' clause}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];    // expected-error {{expected 4 for loops after '#pragma omp for', but found only 1}}
+#pragma omp for ordered(foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+// expected-error@+3 {{expression is not an integral constant expression}}
+// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'ordered' clause}}
+// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
+#pragma omp for ordered(foobool(argc)), ordered(true), ordered(-5)
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp for ordered(S1) // expected-error {{'S1' does not refer to a value}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+// expected-error@+1 {{expression is not an integral constant expression}}
+#pragma omp for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+// expected-error@+3 {{statement after '#pragma omp for' must be a for loop}}
+// expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+#pragma omp for ordered(ordered(tmain < int, char, -1, -2 > (argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+  foo();
+#pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}}
+  foo();                    // expected-error {{expected 2 for loops after '#pragma omp for'}}
+  // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+  return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/test/OpenMP/parallel_for_ast_print.cpp b/test/OpenMP/parallel_for_ast_print.cpp
index f2899ee16ef..f3025ced3b5 100644
--- a/test/OpenMP/parallel_for_ast_print.cpp
+++ b/test/OpenMP/parallel_for_ast_print.cpp
@@ -21,14 +21,24 @@ T tmain(T argc) {
     a = 2;
 // CHECK-NEXT: for (int i = 0; i < 2; ++i)
 // CHECK-NEXT: a = 2;
-#pragma omp parallel for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered if (argc) num_threads(N) default(shared) shared(e) reduction(+ : h)
+#pragma omp parallel for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) if (argc) num_threads(N) default(shared) shared(e) reduction(+ : h)
+  for (int i = 0; i < 10; ++i)
+    for (int j = 0; j < 10; ++j)
+      for (int j = 0; j < 10; ++j)
+        for (int j = 0; j < 10; ++j)
+          for (int j = 0; j < 10; ++j)
   for (int i = 0; i < 10; ++i)
     for (int j = 0; j < 10; ++j)
       for (int j = 0; j < 10; ++j)
         for (int j = 0; j < 10; ++j)
           for (int j = 0; j < 10; ++j)
             foo();
-  // CHECK-NEXT: #pragma omp parallel for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered if(argc) num_threads(N) default(shared) shared(e) reduction(+: h)
+  // CHECK-NEXT: #pragma omp parallel for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) if(argc) num_threads(N) default(shared) shared(e) reduction(+: h)
+  // CHECK-NEXT: for (int i = 0; i < 10; ++i)
+  // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+  // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+  // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+  // CHECK-NEXT: for (int j = 0; j < 10; ++j)
   // CHECK-NEXT: for (int i = 0; i < 10; ++i)
   // CHECK-NEXT: for (int j = 0; j < 10; ++j)
   // CHECK-NEXT: for (int j = 0; j < 10; ++j)
diff --git a/test/OpenMP/parallel_for_ordered_messages.cpp b/test/OpenMP/parallel_for_ordered_messages.cpp
new file mode 100644
index 00000000000..4a8d3788966
--- /dev/null
+++ b/test/OpenMP/parallel_for_ordered_messages.cpp
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+  return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) {                   //expected-note 2 {{declared here}}
+#pragma omp parallel for ordered
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp parallel for ordered( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp parallel for ordered() // expected-error {{expected expression}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+// expected-error@+2 2 {{expression is not an integral constant expression}}
+// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+#pragma omp parallel for ordered(argc
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
+#pragma omp parallel for ordered(ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp parallel for ordered(1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for' are ignored}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp parallel for ordered((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'ordered' clause}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp parallel for', but found only 1}}
+// expected-error@+3 2 {{directive '#pragma omp parallel for' cannot contain more than one 'ordered' clause}}
+// expected-error@+2 2 {{argument to 'ordered' clause must be a positive integer value}}
+// expected-error@+1 2 {{expression is not an integral constant expression}}
+#pragma omp parallel for ordered(foobool(argc)), ordered(true), ordered(-5)
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp parallel for ordered(S) // expected-error {{'S' does not refer to a value}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+// expected-error@+1 2 {{expression is not an integral constant expression}}
+#pragma omp parallel for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp parallel for ordered(1)
+  for (int i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp parallel for ordered(N) // expected-error {{argument to 'ordered' clause must be a positive integer value}}
+  for (T i = ST; i < N; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp parallel for ordered(2) // expected-note {{as specified in 'ordered' clause}}
+  foo();                            // expected-error {{expected 2 for loops after '#pragma omp parallel for'}}
+  return argc;
+}
+
+int main(int argc, char **argv) {
+#pragma omp parallel for ordered
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp parallel for ordered( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp parallel for ordered() // expected-error {{expected expression}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp parallel for ordered(4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'ordered' clause}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4]; // expected-error {{expected 4 for loops after '#pragma omp parallel for', but found only 1}}
+#pragma omp parallel for ordered(2 + 2))      // expected-warning {{extra tokens at the end of '#pragma omp parallel for' are ignored}}  expected-note {{as specified in 'ordered' clause}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];            // expected-error {{expected 4 for loops after '#pragma omp parallel for', but found only 1}}
+#pragma omp parallel for ordered(foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+// expected-error@+3 {{expression is not an integral constant expression}}
+// expected-error@+2 2 {{directive '#pragma omp parallel for' cannot contain more than one 'ordered' clause}}
+// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
+#pragma omp parallel for ordered(foobool(argc)), ordered(true), ordered(-5)
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp parallel for ordered(S1) // expected-error {{'S1' does not refer to a value}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+// expected-error@+1 {{expression is not an integral constant expression}}
+#pragma omp parallel for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int i = 4; i < 12; i++)
+    argv[0][i] = argv[0][i] - argv[0][i - 4];
+// expected-error@+3 {{statement after '#pragma omp parallel for' must be a for loop}}
+// expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+#pragma omp parallel for ordered(ordered(tmain < int, char, -1, -2 > (argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+  foo();
+#pragma omp parallel for ordered(2) // expected-note {{as specified in 'ordered' clause}}
+  foo();                            // expected-error {{expected 2 for loops after '#pragma omp parallel for'}}
+  // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+  return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index f6710a096e7..ed9a1ec6f01 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -2033,7 +2033,9 @@ void OMPClauseEnqueue::VisitOMPScheduleClause(const OMPScheduleClause *C) {
   Visitor->AddStmt(C->getHelperChunkSize());
 }
 
-void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *) {}
+void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *C) {
+  Visitor->AddStmt(C->getNumForLoops());
+}
 
 void OMPClauseEnqueue::VisitOMPNowaitClause(const OMPNowaitClause *) {}
 
-- 
GitLab