diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 637d4fc9564dd365bc746366fbabd3c87e8e5bd4..8569591d55a3f307754ac95e10ff8b84c98511ef 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -678,6 +678,7 @@ def ASM : DiagGroup<"asm", [
 // OpenMP warnings.
 def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
 def OpenMPClauses : DiagGroup<"openmp-clauses">;
+def OpenMPLoopForm : DiagGroup<"openmp-loop-form">;
 
 // Backend warnings.
 def BackendInlineAsm : DiagGroup<"inline-asm">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index b6f36d49db2a3cbc5471b4c8f7ae5470be006bf5..9c648e88a93b6a4cf5f6400ae8f71d862044a04f 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6937,6 +6937,8 @@ def note_omp_explicit_dsa : Note<
   "defined as %0">;
 def note_omp_predetermined_dsa : Note<
   "predetermined as %0">;
+def err_omp_loop_var_dsa : Error<
+  "loop iteration variable may not be %0">;
 def err_omp_not_for : Error<
   "statement after '#pragma omp %0' must be a for loop">;
 def err_omp_negative_expression_in_clause : Error<
@@ -6973,6 +6975,29 @@ def err_omp_aligned_twice : Error<
   "a variable cannot appear in more than one aligned clause">;
 def err_omp_local_var_in_threadprivate_init : Error<
   "variable with local storage in initial value of threadprivate variable">;
+def err_omp_loop_not_canonical_init : Error<
+  "initialization clause of OpenMP for loop must be of the form "
+  "'var = init' or 'T var = init'">;
+def ext_omp_loop_not_canonical_init : ExtWarn<
+  "initialization clause of OpenMP for loop is not in canonical form "
+  "('var = init' or 'T var = init')">, InGroup<OpenMPLoopForm>;
+def err_omp_loop_not_canonical_cond : Error<
+  "condition of OpenMP for loop must be a relational comparison "
+  "('<', '<=', '>', or '>=') of loop variable %0">;
+def err_omp_loop_not_canonical_incr : Error<
+  "increment clause of OpenMP for loop must perform simple addition "
+  "or subtraction on loop variable %0">;
+def err_omp_loop_variable_type : Error<
+  "variable must be of integer or %select{pointer|random access iterator}0 type">;
+def err_omp_loop_incr_not_compatible : Error<
+  "increment expression must cause %0 to %select{decrease|increase}1 "
+  "on each iteration of OpenMP for loop">;
+def note_omp_loop_cond_requres_compatible_incr : Note<
+  "loop step is expected to be %select{negative|positive}0 due to this condition">;
+def err_omp_loop_cannot_use_stmt : Error<
+  "'%0' statement cannot be used in OpenMP for loop">;
+def err_omp_simd_region_cannot_use_stmt : Error<
+  "'%0' statement cannot be used in OpenMP simd region">;
 } // end of OpenMP category
 
 let CategoryName = "Related Result Type Issue" in {
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index d1867b379eea80a31f8923d06da851b3f7853b1f..35488450ac346b68dcbc3b46294fdf8f785631d7 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -101,22 +101,30 @@ public:
     /// \brief This is the scope for a function-level C++ try or catch scope.
     FnTryCatchScope = 0x4000,
 
-    /// \brief This is the scope of OpenMP executable directive
-    OpenMPDirectiveScope = 0x8000
+    /// \brief This is the scope of OpenMP executable directive.
+    OpenMPDirectiveScope = 0x8000,
+
+    /// \brief This is the scope of some OpenMP loop directive.
+    OpenMPLoopDirectiveScope = 0x10000,
+
+    /// \brief This is the scope of some OpenMP simd directive.
+    /// For example, it is used for 'omp simd', 'omp for simd'.
+    /// This flag is propagated to children scopes.
+    OpenMPSimdDirectiveScope = 0x20000
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit
   /// scope.
   Scope *AnyParent;
 
+  /// Flags - This contains a set of ScopeFlags, which indicates how the scope
+  /// interrelates with other control flow statements.
+  unsigned Flags;
+
   /// Depth - This is the depth of this scope.  The translation-unit scope has
   /// depth 0.
   unsigned short Depth;
 
-  /// Flags - This contains a set of ScopeFlags, which indicates how the scope
-  /// interrelates with other control flow statements.
-  unsigned short Flags;
-
   /// \brief Declarations with static linkage are mangled with the number of
   /// scopes seen as a component.
   unsigned short MSLocalManglingNumber;
@@ -360,6 +368,30 @@ public:
     return (getFlags() & Scope::OpenMPDirectiveScope);
   }
 
+  /// \brief Determine whether this scope is some OpenMP loop directive scope
+  /// (for example, 'omp for', 'omp simd').
+  bool isOpenMPLoopDirectiveScope() const {
+    if (getFlags() & Scope::OpenMPLoopDirectiveScope) {
+      assert(isOpenMPDirectiveScope() &&
+             "OpenMP loop directive scope is not a directive scope");
+      return true;
+    }
+    return false;
+  }
+
+  /// \brief Determine whether this scope is (or is nested into) some OpenMP
+  /// loop simd directive scope (for example, 'omp simd', 'omp for simd').
+  bool isOpenMPSimdDirectiveScope() const {
+    return getFlags() & Scope::OpenMPSimdDirectiveScope;
+  }
+
+  /// \brief Determine whether this scope is a loop having OpenMP loop
+  /// directive attached.
+  bool isOpenMPLoopScope() const {
+    const Scope *P = getParent();
+    return P && P->isOpenMPLoopDirectiveScope();
+  }
+
   /// \brief Determine whether this scope is a C++ 'try' block.
   bool isTryScope() const { return getFlags() & Scope::TryScope; }
 
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 6818353f7012bc1f096661be0762389686a075ae..7b1be83e7e433ecd0b94066f60d15ad34078eb6b 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -7258,10 +7258,11 @@ private:
   /// \brief Initialization of data-sharing attributes stack.
   void InitDataSharingAttributesStack();
   void DestroyDataSharingAttributesStack();
-  ExprResult PerformImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op);
   ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op,
                                                    OpenMPClauseKind CKind);
 public:
+  ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc,
+                                                    Expr *Op);
   /// \brief Called on start of new data sharing attribute block.
   void StartOpenMPDSABlock(OpenMPDirectiveKind K,
                            const DeclarationNameInfo &DirName,
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index e293148b0afe61ddb13b7412e93776ea472f6e4d..a8b73de06d908839c9cb7b6bb7c8dfdbcba02166 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -86,7 +86,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
   SmallVector<OMPClause *, 5> Clauses;
   SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
   FirstClauses(OMPC_unknown + 1);
-  const unsigned ScopeFlags =
+  unsigned ScopeFlags =
       Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
   SourceLocation Loc = ConsumeToken(), EndLoc;
   OpenMPDirectiveKind DKind = Tok.isAnnotation()
@@ -142,6 +142,9 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
 
     StmtResult AssociatedStmt;
     bool CreateDirective = true;
+    if (DKind == OMPD_simd)
+      ScopeFlags |=
+          Scope::OpenMPLoopDirectiveScope | Scope::OpenMPSimdDirectiveScope;
     ParseScope OMPDirectiveScope(this, ScopeFlags);
     {
       // The body is a block scope like in Lambdas and Blocks.
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
index 278b087fad25bc391854f1a64ccabc1de2505e5b..860b7c66ec60838997c05cd21a50053ff3e25921 100644
--- a/lib/Sema/Scope.cpp
+++ b/lib/Sema/Scope.cpp
@@ -39,6 +39,10 @@ void Scope::Init(Scope *parent, unsigned flags) {
     BlockParent    = parent->BlockParent;
     TemplateParamParent = parent->TemplateParamParent;
     MSLocalManglingParent = parent->MSLocalManglingParent;
+    if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
+                  FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
+        0)
+      Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
   } else {
     Depth = 0;
     PrototypeDepth = 0;
@@ -178,6 +182,12 @@ void Scope::dumpImpl(raw_ostream &OS) const {
     } else if (Flags & OpenMPDirectiveScope) {
       OS << "OpenMPDirectiveScope";
       Flags &= ~OpenMPDirectiveScope;
+    } else if (Flags & OpenMPLoopDirectiveScope) {
+      OS << "OpenMPLoopDirectiveScope";
+      Flags &= ~OpenMPLoopDirectiveScope;
+    } else if (Flags & OpenMPSimdDirectiveScope) {
+      OS << "OpenMPSimdDirectiveScope";
+      Flags &= ~OpenMPSimdDirectiveScope;
     }
 
     if (Flags)
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 41eceb156079bcd976ed98e8e7ab4eb4cc3e0109..1e9f0fa6d064046233dca09cdee7e76740512835 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -618,7 +618,10 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
   if (!getLangOpts().CXXExceptions &&
       !getSourceManager().isInSystemHeader(OpLoc))
     Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
-  
+
+  if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
+    Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
+
   if (Ex && !Ex->isTypeDependent()) {
     ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope);
     if (ExRes.isInvalid())
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index c78c42952cadfdefcf8420dad51c7b1076381270..32b956b81ea361926e8beb56d07f631dfc1e7b91 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -832,22 +832,497 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
                                       AStmt);
 }
 
+namespace {
+/// \brief Helper class for checking canonical form of the OpenMP loops and
+/// extracting iteration space of each loop in the loop nest, that will be used
+/// for IR generation.
+class OpenMPIterationSpaceChecker {
+  /// \brief Reference to Sema.
+  Sema &SemaRef;
+  /// \brief A location for diagnostics (when there is no some better location).
+  SourceLocation DefaultLoc;
+  /// \brief A location for diagnostics (when increment is not compatible).
+  SourceLocation ConditionLoc;
+  /// \brief A source location for referring to condition later.
+  SourceRange ConditionSrcRange;
+  /// \brief Loop variable.
+  VarDecl *Var;
+  /// \brief Lower bound (initializer for the var).
+  Expr *LB;
+  /// \brief Upper bound.
+  Expr *UB;
+  /// \brief Loop step (increment).
+  Expr *Step;
+  /// \brief This flag is true when condition is one of:
+  ///   Var <  UB
+  ///   Var <= UB
+  ///   UB  >  Var
+  ///   UB  >= Var
+  bool TestIsLessOp;
+  /// \brief This flag is true when condition is strict ( < or > ).
+  bool TestIsStrictOp;
+  /// \brief This flag is true when step is subtracted on each iteration.
+  bool SubtractStep;
+
+public:
+  OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
+      : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc),
+        ConditionSrcRange(SourceRange()), Var(nullptr), LB(nullptr),
+        UB(nullptr), Step(nullptr), TestIsLessOp(false), TestIsStrictOp(false),
+        SubtractStep(false) {}
+  /// \brief Check init-expr for canonical loop form and save loop counter
+  /// variable - #Var and its initialization value - #LB.
+  bool CheckInit(Stmt *S);
+  /// \brief Check test-expr for canonical form, save upper-bound (#UB), flags
+  /// for less/greater and for strict/non-strict comparison.
+  bool CheckCond(Expr *S);
+  /// \brief Check incr-expr for canonical loop form and return true if it
+  /// does not conform, otherwise save loop step (#Step).
+  bool CheckInc(Expr *S);
+  /// \brief Return the loop counter variable.
+  VarDecl *GetLoopVar() const { return Var; }
+  /// \brief Return true if any expression is dependent.
+  bool Dependent() const;
+
+private:
+  /// \brief Check the right-hand side of an assignment in the increment
+  /// expression.
+  bool CheckIncRHS(Expr *RHS);
+  /// \brief Helper to set loop counter variable and its initializer.
+  bool SetVarAndLB(VarDecl *NewVar, Expr *NewLB);
+  /// \brief Helper to set upper bound.
+  bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, const SourceRange &SR,
+             const SourceLocation &SL);
+  /// \brief Helper to set loop increment.
+  bool SetStep(Expr *NewStep, bool Subtract);
+};
+
+bool OpenMPIterationSpaceChecker::Dependent() const {
+  if (!Var) {
+    assert(!LB && !UB && !Step);
+    return false;
+  }
+  return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) ||
+         (UB && UB->isValueDependent()) || (Step && Step->isValueDependent());
+}
+
+bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, Expr *NewLB) {
+  // State consistency checking to ensure correct usage.
+  assert(Var == nullptr && LB == nullptr && UB == nullptr && Step == nullptr &&
+         !TestIsLessOp && !TestIsStrictOp);
+  if (!NewVar || !NewLB)
+    return true;
+  Var = NewVar;
+  LB = NewLB;
+  return false;
+}
+
+bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp,
+                                        const SourceRange &SR,
+                                        const SourceLocation &SL) {
+  // State consistency checking to ensure correct usage.
+  assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr &&
+         !TestIsLessOp && !TestIsStrictOp);
+  if (!NewUB)
+    return true;
+  UB = NewUB;
+  TestIsLessOp = LessOp;
+  TestIsStrictOp = StrictOp;
+  ConditionSrcRange = SR;
+  ConditionLoc = SL;
+  return false;
+}
+
+bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) {
+  // State consistency checking to ensure correct usage.
+  assert(Var != nullptr && LB != nullptr && Step == nullptr);
+  if (!NewStep)
+    return true;
+  if (!NewStep->isValueDependent()) {
+    // Check that the step is integer expression.
+    SourceLocation StepLoc = NewStep->getLocStart();
+    ExprResult Val =
+        SemaRef.PerformOpenMPImplicitIntegerConversion(StepLoc, NewStep);
+    if (Val.isInvalid())
+      return true;
+    NewStep = Val.get();
+
+    // OpenMP [2.6, Canonical Loop Form, Restrictions]
+    //  If test-expr is of form var relational-op b and relational-op is < or
+    //  <= then incr-expr must cause var to increase on each iteration of the
+    //  loop. If test-expr is of form var relational-op b and relational-op is
+    //  > or >= then incr-expr must cause var to decrease on each iteration of
+    //  the loop.
+    //  If test-expr is of form b relational-op var and relational-op is < or
+    //  <= then incr-expr must cause var to decrease on each iteration of the
+    //  loop. If test-expr is of form b relational-op var and relational-op is
+    //  > or >= then incr-expr must cause var to increase on each iteration of
+    //  the loop.
+    llvm::APSInt Result;
+    bool IsConstant = NewStep->isIntegerConstantExpr(Result, SemaRef.Context);
+    bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation();
+    bool IsConstNeg =
+        IsConstant && Result.isSigned() && (Subtract != Result.isNegative());
+    bool IsConstZero = IsConstant && !Result.getBoolValue();
+    if (UB && (IsConstZero ||
+               (TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract))
+                             : (!IsConstNeg || (IsUnsigned && !Subtract))))) {
+      SemaRef.Diag(NewStep->getExprLoc(),
+                   diag::err_omp_loop_incr_not_compatible)
+          << Var << TestIsLessOp << NewStep->getSourceRange();
+      SemaRef.Diag(ConditionLoc,
+                   diag::note_omp_loop_cond_requres_compatible_incr)
+          << TestIsLessOp << ConditionSrcRange;
+      return true;
+    }
+  }
+
+  Step = NewStep;
+  SubtractStep = Subtract;
+  return false;
+}
+
+bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) {
+  // Check init-expr for canonical loop form and save loop counter
+  // variable - #Var and its initialization value - #LB.
+  // OpenMP [2.6] Canonical loop form. init-expr may be one of the following:
+  //   var = lb
+  //   integer-type var = lb
+  //   random-access-iterator-type var = lb
+  //   pointer-type var = lb
+  //
+  if (!S) {
+    SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init);
+    return true;
+  }
+  if (Expr *E = dyn_cast<Expr>(S))
+    S = E->IgnoreParens();
+  if (auto BO = dyn_cast<BinaryOperator>(S)) {
+    if (BO->getOpcode() == BO_Assign)
+      if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens()))
+        return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), BO->getLHS());
+  } else if (auto DS = dyn_cast<DeclStmt>(S)) {
+    if (DS->isSingleDecl()) {
+      if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) {
+        if (Var->hasInit()) {
+          // Accept non-canonical init form here but emit ext. warning.
+          if (Var->getInitStyle() != VarDecl::CInit)
+            SemaRef.Diag(S->getLocStart(),
+                         diag::ext_omp_loop_not_canonical_init)
+                << S->getSourceRange();
+          return SetVarAndLB(Var, Var->getInit());
+        }
+      }
+    }
+  } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S))
+    if (CE->getOperator() == OO_Equal)
+      if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0)))
+        return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), CE->getArg(1));
+
+  SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init)
+      << S->getSourceRange();
+  return true;
+}
+
+/// \brief Ignore parenthesises, implicit casts, copy constructor and return the
+/// variable (which may be the loop variable) if possible.
+static const VarDecl *GetInitVarDecl(const Expr *E) {
+  if (!E)
+    return 0;
+  E = E->IgnoreParenImpCasts();
+  if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(E))
+    if (const CXXConstructorDecl *Ctor = CE->getConstructor())
+      if (Ctor->isCopyConstructor() && CE->getNumArgs() == 1 &&
+          CE->getArg(0) != nullptr)
+        E = CE->getArg(0)->IgnoreParenImpCasts();
+  auto DRE = dyn_cast_or_null<DeclRefExpr>(E);
+  if (!DRE)
+    return nullptr;
+  return dyn_cast<VarDecl>(DRE->getDecl());
+}
+
+bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) {
+  // Check test-expr for canonical form, save upper-bound UB, flags for
+  // less/greater and for strict/non-strict comparison.
+  // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+  //   var relational-op b
+  //   b relational-op var
+  //
+  if (!S) {
+    SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var;
+    return true;
+  }
+  S = S->IgnoreParenImpCasts();
+  SourceLocation CondLoc = S->getLocStart();
+  if (auto BO = dyn_cast<BinaryOperator>(S)) {
+    if (BO->isRelationalOp()) {
+      if (GetInitVarDecl(BO->getLHS()) == Var)
+        return SetUB(BO->getRHS(),
+                     (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE),
+                     (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
+                     BO->getSourceRange(), BO->getOperatorLoc());
+      if (GetInitVarDecl(BO->getRHS()) == Var)
+        return SetUB(BO->getLHS(),
+                     (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
+                     (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
+                     BO->getSourceRange(), BO->getOperatorLoc());
+    }
+  } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) {
+    if (CE->getNumArgs() == 2) {
+      auto Op = CE->getOperator();
+      switch (Op) {
+      case OO_Greater:
+      case OO_GreaterEqual:
+      case OO_Less:
+      case OO_LessEqual:
+        if (GetInitVarDecl(CE->getArg(0)) == Var)
+          return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual,
+                       Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
+                       CE->getOperatorLoc());
+        if (GetInitVarDecl(CE->getArg(1)) == Var)
+          return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual,
+                       Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
+                       CE->getOperatorLoc());
+        break;
+      default:
+        break;
+      }
+    }
+  }
+  SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)
+      << S->getSourceRange() << Var;
+  return true;
+}
+
+bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) {
+  // RHS of canonical loop form increment can be:
+  //   var + incr
+  //   incr + var
+  //   var - incr
+  //
+  RHS = RHS->IgnoreParenImpCasts();
+  if (auto BO = dyn_cast<BinaryOperator>(RHS)) {
+    if (BO->isAdditiveOp()) {
+      bool IsAdd = BO->getOpcode() == BO_Add;
+      if (GetInitVarDecl(BO->getLHS()) == Var)
+        return SetStep(BO->getRHS(), !IsAdd);
+      if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var)
+        return SetStep(BO->getLHS(), false);
+    }
+  } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(RHS)) {
+    bool IsAdd = CE->getOperator() == OO_Plus;
+    if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) {
+      if (GetInitVarDecl(CE->getArg(0)) == Var)
+        return SetStep(CE->getArg(1), !IsAdd);
+      if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var)
+        return SetStep(CE->getArg(0), false);
+    }
+  }
+  SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr)
+      << RHS->getSourceRange() << Var;
+  return true;
+}
+
+bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
+  // Check incr-expr for canonical loop form and return true if it
+  // does not conform.
+  // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+  //   ++var
+  //   var++
+  //   --var
+  //   var--
+  //   var += incr
+  //   var -= incr
+  //   var = var + incr
+  //   var = incr + var
+  //   var = var - incr
+  //
+  if (!S) {
+    SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var;
+    return true;
+  }
+  S = S->IgnoreParens();
+  if (auto UO = dyn_cast<UnaryOperator>(S)) {
+    if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var)
+      return SetStep(
+          SemaRef.ActOnIntegerConstant(UO->getLocStart(),
+                                       (UO->isDecrementOp() ? -1 : 1)).get(),
+          false);
+  } else if (auto BO = dyn_cast<BinaryOperator>(S)) {
+    switch (BO->getOpcode()) {
+    case BO_AddAssign:
+    case BO_SubAssign:
+      if (GetInitVarDecl(BO->getLHS()) == Var)
+        return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign);
+      break;
+    case BO_Assign:
+      if (GetInitVarDecl(BO->getLHS()) == Var)
+        return CheckIncRHS(BO->getRHS());
+      break;
+    default:
+      break;
+    }
+  } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) {
+    switch (CE->getOperator()) {
+    case OO_PlusPlus:
+    case OO_MinusMinus:
+      if (GetInitVarDecl(CE->getArg(0)) == Var)
+        return SetStep(
+            SemaRef.ActOnIntegerConstant(
+                        CE->getLocStart(),
+                        ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)).get(),
+            false);
+      break;
+    case OO_PlusEqual:
+    case OO_MinusEqual:
+      if (GetInitVarDecl(CE->getArg(0)) == Var)
+        return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual);
+      break;
+    case OO_Equal:
+      if (GetInitVarDecl(CE->getArg(0)) == Var)
+        return CheckIncRHS(CE->getArg(1));
+      break;
+    default:
+      break;
+    }
+  }
+  SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr)
+      << S->getSourceRange() << Var;
+  return true;
+}
+}
+
+/// \brief Called on a for stmt to check and extract its iteration space
+/// for further processing (such as collapsing).
+static bool CheckOpenMPIterationSpace(OpenMPDirectiveKind DKind, Stmt *S,
+                                      Sema &SemaRef, DSAStackTy &DSA) {
+  // OpenMP [2.6, Canonical Loop Form]
+  //   for (init-expr; test-expr; incr-expr) structured-block
+  auto For = dyn_cast_or_null<ForStmt>(S);
+  if (!For) {
+    SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for)
+        << getOpenMPDirectiveName(DKind);
+    return true;
+  }
+  assert(For->getBody());
+
+  OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc());
+
+  // Check init.
+  Stmt *Init = For->getInit();
+  if (ISC.CheckInit(Init)) {
+    return true;
+  }
+
+  bool HasErrors = false;
+
+  // Check loop variable's type.
+  VarDecl *Var = ISC.GetLoopVar();
+
+  // OpenMP [2.6, Canonical Loop Form]
+  // Var is one of the following:
+  //   A variable of signed or unsigned integer type.
+  //   For C++, a variable of a random access iterator type.
+  //   For C, a variable of a pointer type.
+  QualType VarType = Var->getType();
+  if (!VarType->isDependentType() && !VarType->isIntegerType() &&
+      !VarType->isPointerType() &&
+      !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) {
+    SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type)
+        << SemaRef.getLangOpts().CPlusPlus;
+    HasErrors = true;
+  }
+
+  // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in
+  // a Construct, C/C++].
+  // The loop iteration variable(s) in the associated for-loop(s) of a for or
+  // parallel for construct may be listed in a private or lastprivate clause.
+  DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var);
+  if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_linear &&
+      DVar.CKind != OMPC_threadprivate) {
+    // The loop iteration variable in the associated for-loop of a simd
+    // construct with just one associated for-loop may be listed in a linear
+    // clause with a constant-linear-step that is the increment of the
+    // associated for-loop.
+    // FIXME: allow OMPC_lastprivate when it is ready.
+    assert(DKind == OMPD_simd && "DSA for non-simd loop vars");
+    SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
+        << getOpenMPClauseName(DVar.CKind);
+    if (DVar.RefExpr)
+      SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+          << getOpenMPClauseName(DVar.CKind);
+    else
+      SemaRef.Diag(Var->getLocation(), diag::note_omp_predetermined_dsa)
+          << getOpenMPClauseName(DVar.CKind);
+    HasErrors = true;
+  } else {
+    // Make the loop iteration variable private by default.
+    DSA.addDSA(Var, nullptr, OMPC_private);
+  }
+
+  // Check test-expr.
+  HasErrors |= ISC.CheckCond(For->getCond());
+
+  // Check incr-expr.
+  HasErrors |= ISC.CheckInc(For->getInc());
+
+  if (ISC.Dependent())
+    return HasErrors;
+
+  // FIXME: Build loop's iteration space representation.
+  return HasErrors;
+}
+
+/// \brief A helper routine to skip no-op (attributed, compound) stmts get the
+/// next nested for loop. If \a IgnoreCaptured is true, it skips captured stmt
+/// to get the first for loop.
+static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) {
+  if (IgnoreCaptured)
+    if (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
+      S = CapS->getCapturedStmt();
+  // OpenMP [2.8.1, simd construct, Restrictions]
+  // All loops associated with the construct must be perfectly nested; that is,
+  // there must be no intervening code nor any OpenMP directive between any two
+  // loops.
+  while (true) {
+    if (auto AS = dyn_cast_or_null<AttributedStmt>(S))
+      S = AS->getSubStmt();
+    else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) {
+      if (CS->size() != 1)
+        break;
+      S = CS->body_back();
+    } else
+      break;
+  }
+  return S;
+}
+
+/// \brief Called on a for stmt to check itself and nested loops (if any).
+static bool CheckOpenMPLoop(OpenMPDirectiveKind DKind, unsigned NestedLoopCount,
+                            Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA) {
+  // This is helper routine for loop directives (e.g., 'for', 'simd',
+  // 'for simd', etc.).
+  assert(NestedLoopCount == 1);
+  Stmt *CurStmt = IgnoreContainerStmts(AStmt, true);
+  for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
+    if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA))
+      return true;
+    // Move on to the next nested for loop, or to the loop body.
+    CurStmt = IgnoreContainerStmts(cast<ForStmt>(CurStmt)->getBody(), false);
+  }
+
+  // FIXME: Build resulting iteration space for IR generation (collapsing
+  // iteration spaces when loop count > 1 ('collapse' clause)).
+  return false;
+}
+
 StmtResult Sema::ActOnOpenMPSimdDirective(ArrayRef<OMPClause *> Clauses,
                                           Stmt *AStmt, SourceLocation StartLoc,
                                           SourceLocation EndLoc) {
-  Stmt *CStmt = AStmt;
-  while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(CStmt))
-    CStmt = CS->getCapturedStmt();
-  while (AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(CStmt))
-    CStmt = AS->getSubStmt();
-  ForStmt *For = dyn_cast<ForStmt>(CStmt);
-  if (!For) {
-    Diag(CStmt->getLocStart(), diag::err_omp_not_for)
-        << getOpenMPDirectiveName(OMPD_simd);
+  // In presence of clause 'collapse', it will define the nested loops number.
+  // For now, pass default value of 1.
+  if (CheckOpenMPLoop(OMPD_simd, 1, AStmt, *this, *DSAStack))
     return StmtError();
-  }
-
-  // FIXME: Checking loop canonical form, collapsing etc.
 
   getCurFunction()->setHasBranchProtectedScope();
   return OMPSimdDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
@@ -904,8 +1379,8 @@ OMPClause *Sema::ActOnOpenMPIfClause(Expr *Condition, SourceLocation StartLoc,
   return new (Context) OMPIfClause(ValExpr, StartLoc, LParenLoc, EndLoc);
 }
 
-ExprResult Sema::PerformImplicitIntegerConversion(SourceLocation Loc,
-                                                  Expr *Op) {
+ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
+                                                        Expr *Op) {
   if (!Op)
     return ExprError();
 
@@ -958,7 +1433,7 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
       !NumThreads->containsUnexpandedParameterPack()) {
     SourceLocation NumThreadsLoc = NumThreads->getLocStart();
     ExprResult Val =
-        PerformImplicitIntegerConversion(NumThreadsLoc, NumThreads);
+        PerformOpenMPImplicitIntegerConversion(NumThreadsLoc, NumThreads);
     if (Val.isInvalid())
       return nullptr;
 
@@ -1651,7 +2126,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
       !Step->isInstantiationDependent() &&
       !Step->containsUnexpandedParameterPack()) {
     SourceLocation StepLoc = Step->getLocStart();
-    ExprResult Val = PerformImplicitIntegerConversion(StepLoc, Step);
+    ExprResult Val = PerformOpenMPImplicitIntegerConversion(StepLoc, Step);
     if (Val.isInvalid())
       return nullptr;
     StepExpr = Val.get();
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index ec11daddf84ed6dd8e77ec05c2462d36153298b9..cdcbaeae04dd0b9e90760f369daed0e7ef215071 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2417,6 +2417,9 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
     // C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
     return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
   }
+  if (S->isOpenMPLoopScope())
+    return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)
+                     << "break");
 
   return new (Context) BreakStmt(BreakLoc);
 }
@@ -3188,6 +3191,9 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
       !getSourceManager().isInSystemHeader(TryLoc))
       Diag(TryLoc, diag::err_exceptions_disabled) << "try";
 
+  if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
+    Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try";
+
   const unsigned NumHandlers = Handlers.size();
   assert(NumHandlers > 0 &&
          "The parser shouldn't call this if there are no handlers.");
diff --git a/test/OpenMP/simd_loop_messages.cpp b/test/OpenMP/simd_loop_messages.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c960e0651a0c21f55a70f31d1db3e4c6cbaf5f8f
--- /dev/null
+++ b/test/OpenMP/simd_loop_messages.cpp
@@ -0,0 +1,574 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
+
+static int sii;
+#pragma omp threadprivate(sii)
+
+int test_iteration_spaces() {
+  const int N = 100;
+  float a[N], b[N], c[N];
+  int ii, jj, kk;
+  float fii;
+  double dii;
+  #pragma omp simd
+  for (int i = 0; i < 10; i+=1) {
+    c[i] = a[i] + b[i];
+  }
+  #pragma omp simd
+  for (char i = 0; i < 10; i++) {
+    c[i] = a[i] + b[i];
+  }
+  #pragma omp simd
+  for (char i = 0; i < 10; i+='\1') {
+    c[i] = a[i] + b[i];
+  }
+  #pragma omp simd
+  for (long long i = 0; i < 10; i++) {
+    c[i] = a[i] + b[i];
+  }
+  // expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'double'}}
+  #pragma omp simd
+  for (long long i = 0; i < 10; i+=1.5) {
+    c[i] = a[i] + b[i];
+  }
+  #pragma omp simd
+  for (long long i = 0; i < 'z'; i+=1u) {
+    c[i] = a[i] + b[i];
+  }
+  // expected-error@+2 {{variable must be of integer or random access iterator type}}
+  #pragma omp simd
+  for (float fi = 0; fi < 10.0; fi++) {
+    c[(int)fi] = a[(int)fi] + b[(int)fi];
+  }
+  // expected-error@+2 {{variable must be of integer or random access iterator type}}
+  #pragma omp simd
+  for (double fi = 0; fi < 10.0; fi++) {
+    c[(int)fi] = a[(int)fi] + b[(int)fi];
+  }
+  // expected-error@+2 {{variable must be of integer or random access iterator type}}
+  #pragma omp simd
+  for (int &ref = ii; ref < 10; ref++) {
+  }
+  // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+  #pragma omp simd
+  for (int i; i < 10; i++)
+    c[i] = a[i];
+
+  // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+  #pragma omp simd
+  for (int i = 0, j = 0; i < 10; ++i)
+    c[i] = a[i];
+
+  // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+  #pragma omp simd
+  for (;ii < 10; ++ii)
+    c[ii] = a[ii];
+
+  // expected-warning@+3 {{expression result unused}}
+  // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+  #pragma omp simd
+  for (ii + 1;ii < 10; ++ii)
+    c[ii] = a[ii];
+
+  // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+  #pragma omp simd
+  for (c[ii] = 0;ii < 10; ++ii)
+    c[ii] = a[ii];
+
+  // Ok to skip parenthesises.
+  #pragma omp simd
+  for (((ii)) = 0;ii < 10; ++ii)
+    c[ii] = a[ii];
+
+  // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+  #pragma omp simd
+  for (int i = 0; i; i++)
+    c[i] = a[i];
+
+  // expected-error@+3 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'i'}}
+  #pragma omp simd
+  for (int i = 0; jj < kk; ii++)
+    c[i] = a[i];
+
+  // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+  #pragma omp simd
+  for (int i = 0; !!i; i++)
+    c[i] = a[i];
+
+  // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+  #pragma omp simd
+  for (int i = 0; i != 1; i++)
+    c[i] = a[i];
+
+  // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+  #pragma omp simd
+  for (int i = 0; ; i++)
+    c[i] = a[i];
+
+  // Ok.
+  #pragma omp simd
+  for (int i = 11; i > 10; i--)
+    c[i] = a[i];
+
+  // Ok.
+  #pragma omp simd
+  for (int i = 0; i < 10; ++i)
+    c[i] = a[i];
+
+    // Ok.
+  #pragma omp simd
+  for (ii = 0; ii < 10; ++ii)
+    c[ii] = a[ii];
+
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; ++jj)
+    c[ii] = a[jj];
+
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; ++ ++ ii)
+    c[ii] = a[ii];
+
+  // Ok but undefined behavior (in general, cannot check that incr
+  // is really loop-invariant).
+  #pragma omp simd
+  for (ii = 0; ii < 10; ii = ii + ii)
+    c[ii] = a[ii];
+
+  // expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'float'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; ii = ii + 1.0f)
+    c[ii] = a[ii];
+
+  // Ok - step was converted to integer type.
+  #pragma omp simd
+  for (ii = 0; ii < 10; ii = ii + (int)1.1f)
+    c[ii] = a[ii];
+
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; jj = ii + 2)
+    c[ii] = a[ii];
+
+  // expected-warning@+3 {{relational comparison result unused}}
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; jj > kk + 2)
+    c[ii] = a[ii];
+
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10;)
+    c[ii] = a[ii];
+
+  // expected-warning@+3 {{expression result unused}}
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; !ii)
+    c[ii] = a[ii];
+
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; ii ? ++ii : ++jj)
+    c[ii] = a[ii];
+
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; ii = ii < 10)
+    c[ii] = a[ii];
+
+  // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; ii = ii + 0)
+    c[ii] = a[ii];
+
+  // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; ii = ii + (int)(0.8 - 0.45))
+    c[ii] = a[ii];
+
+  // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (ii = 0; (ii) < 10; ii-=25)
+    c[ii] = a[ii];
+
+  // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (ii = 0; (ii < 10); ii-=0)
+    c[ii] = a[ii];
+
+  // expected-note@+3 {{loop step is expected to be negative due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (ii = 0; ii > 10; (ii+=0))
+    c[ii] = a[ii];
+
+  // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (ii = 0; ii < 10; (ii) = (1-1)+(ii))
+    c[ii] = a[ii];
+
+  // expected-note@+3 {{loop step is expected to be negative due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for ((ii = 0); ii > 10; (ii-=0))
+    c[ii] = a[ii];
+
+  // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (ii = 0; (ii < 10); (ii-=0))
+    c[ii] = a[ii];
+
+  // expected-note@+2  {{defined as private}}
+  // expected-error@+2 {{loop iteration variable may not be private}}
+  #pragma omp simd private(ii)
+  for (ii = 0; ii < 10; ii++)
+    c[ii] = a[ii];
+
+  // expected-error@+3 {{unexpected OpenMP clause 'shared' in directive '#pragma omp simd'}}
+  // expected-note@+2  {{defined as shared}}
+  // expected-error@+2 {{loop iteration variable may not be shared}}
+  #pragma omp simd shared(ii)
+  for (ii = 0; ii < 10; ii++)
+    c[ii] = a[ii];
+
+  #pragma omp simd linear(ii)
+  for (ii = 0; ii < 10; ii++)
+    c[ii] = a[ii];
+
+  // TODO: Add test for lastprivate.
+
+  #pragma omp parallel
+  {
+    #pragma omp simd
+    for (sii = 0; sii < 10; sii+=1)
+      c[sii] = a[sii];
+  }
+
+  // expected-error@+2 {{statement after '#pragma omp simd' must be a for loop}}
+  #pragma omp simd
+  for (auto &item : a) {
+    item = item + 1;
+  }
+
+  // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'i' to increase on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (unsigned i = 9; i < 10; i--) {
+    c[i] = a[i] + b[i];
+  }
+
+  int (*lb)[4] = nullptr;
+  #pragma omp simd
+  for (int (*p)[4] = lb; p < lb + 8; ++p) {
+  }
+
+  // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+  #pragma omp simd
+  for (int a{0}; a<10; ++a) {
+  }
+
+  return 0;
+}
+
+// Iterators allowed in openmp for-loops.
+namespace std {
+struct random_access_iterator_tag { };
+template <class Iter> struct iterator_traits {
+  typedef typename Iter::difference_type difference_type;
+  typedef typename Iter::iterator_category iterator_category;
+};
+template <class Iter>
+typename iterator_traits<Iter>::difference_type
+distance(Iter first, Iter last) { return first - last; }
+}
+class Iter0 {
+  public:
+    Iter0() { }
+    Iter0(const Iter0 &) { }
+    Iter0 operator ++() { return *this; }
+    Iter0 operator --() { return *this; }
+    bool operator <(Iter0 a) { return true; }
+};
+int operator -(Iter0 a, Iter0 b) { return 0; }
+class Iter1 {
+  public:
+    Iter1(float f=0.0f, double d=0.0) { }
+    Iter1(const Iter1 &) { }
+    Iter1 operator ++() { return *this; }
+    Iter1 operator --() { return *this; }
+    bool operator <(Iter1 a) { return true; }
+    bool operator >=(Iter1 a) { return false; }
+};
+class GoodIter {
+  public:
+    GoodIter() { }
+    GoodIter(const GoodIter &) { }
+    GoodIter(int fst, int snd) { }
+    GoodIter &operator =(const GoodIter &that) { return *this; }
+    GoodIter &operator =(const Iter0 &that) { return *this; }
+    GoodIter &operator +=(int x) { return *this; }
+    explicit GoodIter(void *) { }
+    GoodIter operator ++() { return *this; }
+    GoodIter operator --() { return *this; }
+    bool operator !() { return true; }
+    bool operator <(GoodIter a) { return true; }
+    bool operator <=(GoodIter a) { return true; }
+    bool operator >=(GoodIter a) { return false; }
+    typedef int difference_type;
+    typedef std::random_access_iterator_tag iterator_category;
+};
+int operator -(GoodIter a, GoodIter b) { return 0; }
+GoodIter operator -(GoodIter a) { return a; }
+GoodIter operator -(GoodIter a, int v) { return GoodIter(); }
+GoodIter operator +(GoodIter a, int v) { return GoodIter(); }
+GoodIter operator -(int v, GoodIter a) { return GoodIter(); }
+GoodIter operator +(int v, GoodIter a) { return GoodIter(); }
+
+int test_with_random_access_iterator() {
+  GoodIter begin, end;
+  Iter0 begin0, end0;
+  #pragma omp simd
+  for (GoodIter I = begin; I < end; ++I)
+    ++I;
+  // expected-error@+2 {{variable must be of integer or random access iterator type}}
+  #pragma omp simd
+  for (GoodIter &I = begin; I < end; ++I)
+    ++I;
+  #pragma omp simd
+  for (GoodIter I = begin; I >= end; --I)
+    ++I;
+  // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+  #pragma omp simd
+  for (GoodIter I(begin); I < end; ++I)
+    ++I;
+  // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+  #pragma omp simd
+  for (GoodIter I(nullptr); I < end; ++I)
+    ++I;
+  // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+  #pragma omp simd
+  for (GoodIter I(0); I < end; ++I)
+    ++I;
+  // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+  #pragma omp simd
+  for (GoodIter I(1,2); I < end; ++I)
+    ++I;
+  #pragma omp simd
+  for (begin = GoodIter(0); begin < end; ++begin)
+    ++begin;
+  #pragma omp simd
+  for (begin = begin0; begin < end; ++begin)
+    ++begin;
+  // expected-error@+2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+  #pragma omp simd
+  for (++begin; begin < end; ++begin)
+    ++begin;
+  #pragma omp simd
+  for (begin = end; begin < end; ++begin)
+    ++begin;
+  // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+  #pragma omp simd
+  for (GoodIter I = begin; I - I; ++I)
+    ++I;
+  // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+  #pragma omp simd
+  for (GoodIter I = begin; begin < end; ++I)
+    ++I;
+  // expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+  #pragma omp simd
+  for (GoodIter I = begin; !I; ++I)
+    ++I;
+  // expected-note@+3 {{loop step is expected to be negative due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (GoodIter I = begin; I >= end; I = I + 1)
+    ++I;
+  #pragma omp simd
+  for (GoodIter I = begin; I >= end; I = I - 1)
+    ++I;
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+  #pragma omp simd
+  for (GoodIter I = begin; I >= end; I = -I)
+    ++I;
+  // expected-note@+3 {{loop step is expected to be negative due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (GoodIter I = begin; I >= end; I = 2 + I)
+    ++I;
+  // expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+  #pragma omp simd
+  for (GoodIter I = begin; I >= end; I = 2 - I)
+    ++I;
+  #pragma omp simd
+  for (Iter0 I = begin0; I < end0; ++I)
+    ++I;
+  // Initializer is constructor without params.
+  // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+  #pragma omp simd
+  for (Iter0 I; I < end0; ++I)
+    ++I;
+  Iter1 begin1, end1;
+  #pragma omp simd
+  for (Iter1 I = begin1; I < end1; ++I)
+    ++I;
+  // expected-note@+3 {{loop step is expected to be negative due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (Iter1 I = begin1; I >= end1; ++I)
+    ++I;
+  // Initializer is constructor with all default params.
+  // expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+  #pragma omp simd
+  for (Iter1 I; I < end1; ++I) {
+  }
+  return 0;
+}
+
+template <typename IT, int ST> class TC {
+  public:
+    int dotest_lt(IT begin, IT end) {
+      // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+      // expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+      #pragma omp simd
+      for (IT I = begin; I < end; I = I + ST) {
+        ++I;
+      }
+      // expected-note@+3 {{loop step is expected to be positive due to this condition}}
+      // expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+      #pragma omp simd
+      for (IT I = begin; I <= end; I += ST) {
+        ++I;
+      }
+      #pragma omp simd
+      for (IT I = begin; I < end; ++I) {
+        ++I;
+      }
+    }
+
+    static IT step() {
+      return IT(ST);
+    }
+};
+template <typename IT, int ST=0> int dotest_gt(IT begin, IT end) {
+  // expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+  // expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (IT I = begin; I >= end; I = I + ST) {
+    ++I;
+  }
+  // expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+  // expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (IT I = begin; I >= end; I += ST) {
+    ++I;
+  }
+
+  // expected-note@+3 {{loop step is expected to be negative due to this condition}}
+  // expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+  #pragma omp simd
+  for (IT I = begin; I >= end; ++I) {
+    ++I;
+  }
+
+  #pragma omp simd
+  for (IT I = begin; I < end; I+=TC<int,ST>::step()) {
+    ++I;
+  }
+}
+
+void test_with_template() {
+  GoodIter begin, end;
+  TC<GoodIter, 100> t1;
+  TC<GoodIter, -100> t2;
+  t1.dotest_lt(begin, end);
+  t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
+  dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
+  dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+}
+
+void test_loop_break() {
+  const int N = 100;
+  float a[N], b[N], c[N];
+  #pragma omp simd
+  for (int i = 0; i < 10; i++) {
+    c[i] = a[i] + b[i];
+    for (int j = 0; j < 10; ++j) {
+      if (a[i] > b[j])
+        break; // OK in nested loop
+    }
+    switch(i) {
+      case 1:
+        b[i]++;
+        break;
+      default:
+        break;
+    }
+    if (c[i] > 10)
+      break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+
+    if (c[i] > 11)
+      break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+  }
+
+  #pragma omp simd
+  for (int i = 0; i < 10; i++) {
+    for (int j = 0; j < 10; j++) {
+      c[i] = a[i] + b[i];
+      if (c[i] > 10) {
+        if (c[i] < 20) {
+          break; // OK
+        }
+      }
+    }
+  }
+}
+
+void test_loop_eh() {
+  const int N = 100;
+  float a[N], b[N], c[N];
+  #pragma omp simd
+  for (int i = 0; i < 10; i++) {
+    c[i] = a[i] + b[i];
+    try { // expected-error {{'try' statement cannot be used in OpenMP simd region}}
+      for (int j = 0; j < 10; ++j) {
+        if (a[i] > b[j])
+          throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+      }
+      throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+    }
+    catch (float f) {
+      if (f > 0.1)
+        throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+      return; // expected-error {{cannot return from OpenMP region}}
+    }
+    switch(i) {
+      case 1:
+        b[i]++;
+        break;
+      default:
+        break;
+    }
+    for (int j = 0; j < 10; j++) {
+      if (c[i] > 10)
+        throw c[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+    }
+  }
+  if (c[9] > 10)
+    throw c[9]; // OK
+
+  #pragma omp simd
+  for (int i = 0; i < 10; ++i) {
+    struct S {
+      void g() { throw 0; }
+    };
+  }
+}
+
diff --git a/test/OpenMP/simd_misc_messages.c b/test/OpenMP/simd_misc_messages.c
index 9608c007b8d1c85b2e12b5cec3771d2531566705..648308e44dae1eae630d4dd59012760fa67fa8f6 100644
--- a/test/OpenMP/simd_misc_messages.c
+++ b/test/OpenMP/simd_misc_messages.c
@@ -414,3 +414,18 @@ void test_firstprivate()
   for (i = 0; i < 16; ++i) ;
 }
 
+void test_loop_messages()
+{
+  float a[100], b[100], c[100];
+  // expected-error@+2 {{variable must be of integer or pointer type}}
+  #pragma omp simd
+  for (float fi = 0; fi < 10.0; fi++) {
+    c[(int)fi] = a[(int)fi] + b[(int)fi];
+  }
+  // expected-error@+2 {{variable must be of integer or pointer type}}
+  #pragma omp simd
+  for (double fi = 0; fi < 10.0; fi++) {
+    c[(int)fi] = a[(int)fi] + b[(int)fi];
+  }
+}
+