diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index 0d470891fa7245568d5e7dadd3f4869bc06bdcb8..17f157aab27686722a543879b8da1476f64fb1f3 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -2482,6 +2482,12 @@ template <typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
     OMPFirstprivateClause *C) {
   TRY_TO(VisitOMPClauseList(C));
+  for (auto *E : C->private_copies()) {
+    TRY_TO(TraverseStmt(E));
+  }
+  for (auto *E : C->inits()) {
+    TRY_TO(TraverseStmt(E));
+  }
   return true;
 }
 
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index d598ea40a37ca11acaff932115376e12e9a129f3..7d0c7d2ab04671866ea7e8b14ecbedd14a721878 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -986,6 +986,8 @@ public:
 /// with the variables 'a' and 'b'.
 ///
 class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
+  friend class OMPClauseReader;
+
   /// \brief Build clause with number of variables \a N.
   ///
   /// \param StartLoc Starting location of the clause.
@@ -1006,6 +1008,33 @@ class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
       : OMPVarListClause<OMPFirstprivateClause>(
             OMPC_firstprivate, SourceLocation(), SourceLocation(),
             SourceLocation(), N) {}
+  /// \brief Sets the list of references to private copies with initializers for
+  /// new private variables.
+  /// \param VL List of references.
+  void setPrivateCopies(ArrayRef<Expr *> VL);
+
+  /// \brief Gets the list of references to private copies with initializers for
+  /// new private variables.
+  MutableArrayRef<Expr *> getPrivateCopies() {
+    return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+  }
+  ArrayRef<const Expr *> getPrivateCopies() const {
+    return llvm::makeArrayRef(varlist_end(), varlist_size());
+  }
+
+  /// \brief Sets the list of references to initializer variables for new
+  /// private variables.
+  /// \param VL List of references.
+  void setInits(ArrayRef<Expr *> VL);
+
+  /// \brief Gets the list of references to initializer variables for new
+  /// private variables.
+  MutableArrayRef<Expr *> getInits() {
+    return MutableArrayRef<Expr *>(getPrivateCopies().end(), varlist_size());
+  }
+  ArrayRef<const Expr *> getInits() const {
+    return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size());
+  }
 
 public:
   /// \brief Creates clause with a list of variables \a VL.
@@ -1014,11 +1043,16 @@ public:
   /// \param StartLoc Starting location of the clause.
   /// \param LParenLoc Location of '('.
   /// \param EndLoc Ending location of the clause.
-  /// \param VL List of references to the variables.
+  /// \param VL List of references to the original variables.
+  /// \param PrivateVL List of references to private copies with initializers.
+  /// \param InitVL List of references to auto generated variables used for
+  /// initialization of a single array element. Used if firstprivate variable is
+  /// of array type.
   ///
   static OMPFirstprivateClause *
   Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
-         SourceLocation EndLoc, ArrayRef<Expr *> VL);
+         SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
+         ArrayRef<Expr *> InitVL);
   /// \brief Creates an empty clause with the place for \a N variables.
   ///
   /// \param C AST context.
@@ -1026,6 +1060,33 @@ public:
   ///
   static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
 
+  typedef MutableArrayRef<Expr *>::iterator private_copies_iterator;
+  typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator;
+  typedef llvm::iterator_range<private_copies_iterator> private_copies_range;
+  typedef llvm::iterator_range<private_copies_const_iterator>
+      private_copies_const_range;
+
+  private_copies_range private_copies() {
+    return private_copies_range(getPrivateCopies().begin(),
+                                getPrivateCopies().end());
+  }
+  private_copies_const_range private_copies() const {
+    return private_copies_const_range(getPrivateCopies().begin(),
+                                      getPrivateCopies().end());
+  }
+
+  typedef MutableArrayRef<Expr *>::iterator inits_iterator;
+  typedef ArrayRef<const Expr *>::iterator inits_const_iterator;
+  typedef llvm::iterator_range<inits_iterator> inits_range;
+  typedef llvm::iterator_range<inits_const_iterator> inits_const_range;
+
+  inits_range inits() {
+    return inits_range(getInits().begin(), getInits().end());
+  }
+  inits_const_range inits() const {
+    return inits_const_range(getInits().begin(), getInits().end());
+  }
+
   StmtRange children() {
     return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
                      reinterpret_cast<Stmt **>(varlist_end()));
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 821eacb21f5a8373fda0f5de6af8424ee4832d76..65a148a1c42fa7c7378407dc558593dcccd5075a 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2504,6 +2504,12 @@ template <typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
     OMPFirstprivateClause *C) {
   TRY_TO(VisitOMPClauseList(C));
+  for (auto *E : C->private_copies()) {
+    TRY_TO(TraverseStmt(E));
+  }
+  for (auto *E : C->inits()) {
+    TRY_TO(TraverseStmt(E));
+  }
   return true;
 }
 
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index cb81078880d3084a8ea53e8d9e2af13ee93056dc..c6cdf909c4885a799a88824e5fc50fb0a83dc0f3 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7141,8 +7141,8 @@ def err_omp_expected_var_name : Error<
   "expected variable name">;
 def err_omp_required_method : Error<
   "%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">;
-def err_omp_task_predetermined_firstprivate_required_method : Error<
-  "predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous %select{copy constructor|destructor}0">;
+def note_omp_task_predetermined_firstprivate_here : Note<
+  "predetermined as a firstprivate in a task construct here">;
 def err_omp_clause_ref_type_arg : Error<
   "arguments of OpenMP clause '%0' cannot be of reference type %1">;
 def err_omp_task_predetermined_firstprivate_ref_type_arg : Error<
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index af19af4943a9d9f3f20f51a922b8522e552e2394..0d039939bc095c003d03d27051c6fddacb73d770 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -1198,19 +1198,31 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
   return new (Mem) OMPPrivateClause(N);
 }
 
-OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
-                                                     SourceLocation StartLoc,
-                                                     SourceLocation LParenLoc,
-                                                     SourceLocation EndLoc,
-                                                     ArrayRef<Expr *> VL) {
+void OMPFirstprivateClause::setPrivateCopies(ArrayRef<Expr *> VL) {
+  assert(VL.size() == varlist_size() &&
+         "Number of private copies is not the same as the preallocated buffer");
+  std::copy(VL.begin(), VL.end(), varlist_end());
+}
+
+void OMPFirstprivateClause::setInits(ArrayRef<Expr *> VL) {
+  assert(VL.size() == varlist_size() &&
+         "Number of inits is not the same as the preallocated buffer");
+  std::copy(VL.begin(), VL.end(), getPrivateCopies().end());
+}
+
+OMPFirstprivateClause *
+OMPFirstprivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
+                              SourceLocation LParenLoc, SourceLocation EndLoc,
+                              ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
+                              ArrayRef<Expr *> InitVL) {
   void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
                                                   llvm::alignOf<Expr *>()) +
-                         sizeof(Expr *) * VL.size());
-  OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
-                                                                  LParenLoc,
-                                                                  EndLoc,
-                                                                  VL.size());
+                         3 * sizeof(Expr *) * VL.size());
+  OMPFirstprivateClause *Clause =
+      new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
   Clause->setVarRefs(VL);
+  Clause->setPrivateCopies(PrivateVL);
+  Clause->setInits(InitVL);
   return Clause;
 }
 
@@ -1218,7 +1230,7 @@ OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
                                                           unsigned N) {
   void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
                                                   llvm::alignOf<Expr *>()) +
-                         sizeof(Expr *) * N);
+                         3 * sizeof(Expr *) * N);
   return new (Mem) OMPFirstprivateClause(N);
 }
 
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 9bcb5929ed0886f1f28a57b482dd1c6d1806d341..157e21d069b01e6df35a355e25ff4a8d1ab11e20 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -329,9 +329,15 @@ void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
 void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
   VisitOMPClauseList(C);
 }
-void OMPClauseProfiler::VisitOMPFirstprivateClause(
-                                         const OMPFirstprivateClause *C) {
+void
+OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) {
   VisitOMPClauseList(C);
+  for (auto *E : C->private_copies()) {
+    Profiler->VisitStmt(E);
+  }
+  for (auto *E : C->inits()) {
+    Profiler->VisitStmt(E);
+  }
 }
 void
 OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index d4a546dc11297c1f8304ffadbae12c48fc403dc0..24575ce6d41790018550071dbe1fb43f67459603 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -1073,7 +1073,7 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
 
 /// \brief Determine whether the given initializer is trivial in the sense
 /// that it requires no code to be generated.
-static bool isTrivialInitializer(const Expr *Init) {
+bool CodeGenFunction::isTrivialInitializer(const Expr *Init) {
   if (!Init)
     return true;
 
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index 9dfcd0753b224d32a3e0d4ac3c29b8c2adb4665d..c439833cfe73e67afdafa8647eb9b90e0d26b470 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -24,6 +24,29 @@
 using namespace clang;
 using namespace CodeGen;
 
+void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) {
+  CodeGenFunction::OuterDeclMapTy OuterDeclMap;
+  CGF.EmitOMPFirstprivateClause(Directive, OuterDeclMap);
+  if (!OuterDeclMap.empty()) {
+    // Emit implicit barrier to synchronize threads and avoid data races.
+    auto Flags = static_cast<CGOpenMPRuntime::OpenMPLocationFlags>(
+        CGOpenMPRuntime::OMP_IDENT_KMPC |
+        CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL);
+    CGF.CGM.getOpenMPRuntime().EmitOMPBarrierCall(CGF, Directive.getLocStart(),
+                                                  Flags);
+    // Remap captured variables to use their private copies in the outlined
+    // function.
+    for (auto I : OuterDeclMap) {
+      CGF.LocalDeclMap[I.first] = I.second;
+    }
+  }
+  CGCapturedStmtInfo::EmitBody(CGF, S);
+  // Clear mappings of captured private variables.
+  for (auto I : OuterDeclMap) {
+    CGF.LocalDeclMap.erase(I.first);
+  }
+}
+
 CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
     : CGM(CGM), DefaultOpenMPPSource(nullptr) {
   IdentTy = llvm::StructType::create(
@@ -51,11 +74,10 @@ CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
       DefaultOpenMPPSource =
           llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
     }
-    llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
-        CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
+    auto DefaultOpenMPLocation = new llvm::GlobalVariable(
+        CGM.getModule(), IdentTy, /*isConstant*/ true,
+        llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr);
     DefaultOpenMPLocation->setUnnamedAddr(true);
-    DefaultOpenMPLocation->setConstant(true);
-    DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
 
     llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
     llvm::Constant *Values[] = {Zero,
@@ -63,6 +85,7 @@ CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
                                 Zero, Zero, DefaultOpenMPPSource};
     llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
     DefaultOpenMPLocation->setInitializer(Init);
+    OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation;
     return DefaultOpenMPLocation;
   }
   return Entry;
@@ -120,14 +143,14 @@ llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
   return LocValue;
 }
 
-llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
-                                                       SourceLocation Loc) {
+llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF,
+                                                SourceLocation Loc) {
   assert(CGF.CurFn && "No function in current CodeGenFunction.");
 
-  llvm::Value *GTid = nullptr;
-  OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn);
-  if (I != OpenMPGtidMap.end()) {
-    GTid = I->second;
+  llvm::Value *ThreadID = nullptr;
+  OpenMPThreadIDMapTy::iterator I = OpenMPThreadIDMap.find(CGF.CurFn);
+  if (I != OpenMPThreadIDMap.end()) {
+    ThreadID = I->second;
   } else {
     // Check if current function is a function which has first parameter
     // with type int32 and name ".global_tid.".
@@ -145,24 +168,24 @@ llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
         CGF.CurFn->arg_begin()->getName() == ".global_tid.") {
       CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
       CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
-      GTid = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
+      ThreadID = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
     } else {
       // Generate "int32 .kmpc_global_thread_num.addr;"
       CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
       CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
       llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
-      GTid = CGF.EmitRuntimeCall(
+      ThreadID = CGF.EmitRuntimeCall(
           CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
     }
-    OpenMPGtidMap[CGF.CurFn] = GTid;
+    OpenMPThreadIDMap[CGF.CurFn] = ThreadID;
   }
-  return GTid;
+  return ThreadID;
 }
 
 void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) {
   assert(CGF.CurFn && "No function in current CodeGenFunction.");
-  if (OpenMPGtidMap.count(CGF.CurFn))
-    OpenMPGtidMap.erase(CGF.CurFn);
+  if (OpenMPThreadIDMap.count(CGF.CurFn))
+    OpenMPThreadIDMap.erase(CGF.CurFn);
   if (OpenMPLocMap.count(CGF.CurFn))
     OpenMPLocMap.erase(CGF.CurFn);
 }
@@ -219,10 +242,33 @@ CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical");
     break;
   }
+  case OMPRTL__kmpc_barrier: {
+    // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
+    llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+    llvm::FunctionType *FnTy =
+        llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+    RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier");
+    break;
+  }
   }
   return RTLFn;
 }
 
+void CGOpenMPRuntime::EmitOMPParallelCall(CodeGenFunction &CGF,
+                                          SourceLocation Loc,
+                                          llvm::Value *OutlinedFn,
+                                          llvm::Value *CapturedStruct) {
+  // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
+  llvm::Value *Args[] = {
+      EmitOpenMPUpdateLocation(CGF, Loc),
+      CGF.Builder.getInt32(1), // Number of arguments after 'microtask' argument
+      // (there is only one additional argument - 'context')
+      CGF.Builder.CreateBitCast(OutlinedFn, getKmpc_MicroPointerTy()),
+      CGF.EmitCastToVoidPtr(CapturedStruct)};
+  auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_fork_call);
+  CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
 llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) {
   SmallString<256> Buffer;
   llvm::raw_svector_ostream Out(Buffer);
@@ -245,7 +291,7 @@ void CGOpenMPRuntime::EmitOMPCriticalRegionStart(CodeGenFunction &CGF,
                                                  SourceLocation Loc) {
   // Prepare other arguments and build a call to __kmpc_critical
   llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
-                         GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
+                         GetOpenMPThreadID(CGF, Loc), RegionLock};
   auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical);
   CGF.EmitRuntimeCall(RTLFn, Args);
 }
@@ -255,8 +301,19 @@ void CGOpenMPRuntime::EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
                                                SourceLocation Loc) {
   // Prepare other arguments and build a call to __kmpc_end_critical
   llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
-                         GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
+                         GetOpenMPThreadID(CGF, Loc), RegionLock};
   auto RTLFn =
       CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical);
   CGF.EmitRuntimeCall(RTLFn, Args);
 }
+
+void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF,
+                                         SourceLocation Loc,
+                                         OpenMPLocationFlags Flags) {
+  // Build call __kmpc_barrier(loc, thread_id)
+  llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc, Flags),
+                         GetOpenMPThreadID(CGF, Loc)};
+  auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_barrier);
+  CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index bba2c8c4d78ad385bc249be5fff541da93c89350..ec6115fb0948c97533fab98a868310953f3360b3 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -14,33 +14,49 @@
 #ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
 #define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
 
+#include "CodeGenFunction.h"
+#include "clang/AST/StmtOpenMP.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/IR/Type.h"
 #include "llvm/IR/Value.h"
 
-namespace llvm {
-class AllocaInst;
-class CallInst;
-class GlobalVariable;
-class Constant;
-class Function;
-class Module;
-class StructLayout;
-class ArrayType;
-class FunctionType;
-class StructType;
-class Type;
-class Value;
-} // namespace llvm
-
 namespace clang {
 
 namespace CodeGen {
 
-class CodeGenFunction;
-class CodeGenModule;
+/// \brief API for captured statement code generation in OpenMP constructs.
+class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
+public:
+  CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &S,
+                     const VarDecl *ThreadIDVar)
+      : CGCapturedStmtInfo(S, CR_OpenMP), ThreadIDVar(ThreadIDVar),
+        Directive(D) {}
+
+  virtual ~CGOpenMPRegionInfo() override{};
+
+  /// \brief Gets a variable or parameter for storing global thread id
+  /// inside OpenMP construct.
+  const VarDecl *getThreadIDVariable() const { return ThreadIDVar; }
+
+  static bool classof(const CGCapturedStmtInfo *Info) {
+    return Info->getKind() == CR_OpenMP;
+  }
+
+  /// \brief Emit the captured statement body.
+  virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) override;
+
+  /// \brief Get the name of the capture helper.
+  virtual StringRef getHelperName() const override { return ".omp_outlined."; }
+
+private:
+  /// \brief A variable or parameter storing global thread id for OpenMP
+  /// constructs.
+  const VarDecl *ThreadIDVar;
+  /// \brief OpenMP executable directive associated with the region.
+  const OMPExecutableDirective &Directive;
+};
 
 class CGOpenMPRuntime {
 public:
@@ -76,7 +92,9 @@ public:
     OMPRTL__kmpc_critical,
     // Call to void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
     // kmp_critical_name *crit);
-    OMPRTL__kmpc_end_critical
+    OMPRTL__kmpc_end_critical,
+    // Call to void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
+    OMPRTL__kmpc_barrier
   };
 
 private:
@@ -139,24 +157,15 @@ private:
   /// \brief Map of local debug location and functions.
   typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPLocMapTy;
   OpenMPLocMapTy OpenMPLocMap;
-  /// \brief Map of local gtid and functions.
-  typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPGtidMapTy;
-  OpenMPGtidMapTy OpenMPGtidMap;
+  /// \brief Map of local ThreadID and functions.
+  typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPThreadIDMapTy;
+  OpenMPThreadIDMapTy OpenMPThreadIDMap;
   /// \brief Type kmp_critical_name, originally defined as typedef kmp_int32
   /// kmp_critical_name[8];
   llvm::ArrayType *KmpCriticalNameTy;
   /// \brief Map of critical regions names and the corresponding lock objects.
   llvm::StringMap<llvm::Value *, llvm::BumpPtrAllocator> CriticalRegionVarNames;
 
-public:
-  explicit CGOpenMPRuntime(CodeGenModule &CGM);
-  virtual ~CGOpenMPRuntime() {}
-
-  /// \brief Cleans up references to the objects in finished function.
-  /// \param CGF Reference to finished CodeGenFunction.
-  ///
-  void FunctionFinished(CodeGenFunction &CGF);
-
   /// \brief Emits object of ident_t type with info for source location.
   /// \param CGF Reference to current CodeGenFunction.
   /// \param Loc Clang source location.
@@ -166,13 +175,6 @@ public:
   EmitOpenMPUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
                            OpenMPLocationFlags Flags = OMP_IDENT_KMPC);
 
-  /// \brief Generates global thread number value.
-  /// \param CGF Reference to current CodeGenFunction.
-  /// \param Loc Clang source location.
-  ///
-  llvm::Value *GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
-                                        SourceLocation Loc);
-
   /// \brief Returns pointer to ident_t type;
   llvm::Type *getIdentTyPointerTy();
 
@@ -184,6 +186,33 @@ public:
   /// \return Specified function.
   llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);
 
+  /// \brief Gets thread id value for the current thread.
+  /// \param CGF Reference to current CodeGenFunction.
+  /// \param Loc Clang source location.
+  ///
+  llvm::Value *GetOpenMPThreadID(CodeGenFunction &CGF, SourceLocation Loc);
+
+public:
+  explicit CGOpenMPRuntime(CodeGenModule &CGM);
+  virtual ~CGOpenMPRuntime() {}
+
+  /// \brief Cleans up references to the objects in finished function.
+  /// \param CGF Reference to finished CodeGenFunction.
+  ///
+  void FunctionFinished(CodeGenFunction &CGF);
+
+  /// \brief Emits code for parallel call of the \a OutlinedFn with variables
+  /// captured in a record which address is stored in \a CapturedStruct.
+  /// \param CGF Reference to current CodeGenFunction.
+  /// \param Loc Clang source location.
+  /// \param OutlinedFn Outlined function to be run in parallel threads.
+  /// \param CapturedStruct A pointer to the record with the references to
+  /// variables used in \a OutlinedFn function.
+  ///
+  virtual void EmitOMPParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
+                                   llvm::Value *OutlinedFn,
+                                   llvm::Value *CapturedStruct);
+
   /// \brief Returns corresponding lock object for the specified critical region
   /// name. If the lock object does not exist it is created, otherwise the
   /// reference to the existing copy is returned.
@@ -208,6 +237,14 @@ public:
   virtual void EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
                                         llvm::Value *RegionLock,
                                         SourceLocation Loc);
+
+  /// \brief Emits a barrier for OpenMP threads.
+  /// \param CGF Reference to current CodeGenFunction.
+  /// \param Loc Clang source location.
+  /// \param Flags Flags for the barrier.
+  ///
+  virtual void EmitOMPBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
+                                  OpenMPLocationFlags Flags);
 };
 } // namespace CodeGen
 } // namespace clang
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index 985cc0e62aeb12001b7ebff97ad0f8ae932315ef..5efff2ccbde0e3191b0eaf354bc892f612bd3ec9 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -24,6 +24,110 @@ using namespace CodeGen;
 //                              OpenMP Directive Emission
 //===----------------------------------------------------------------------===//
 
+void CodeGenFunction::EmitOMPAggregateAssign(LValue OriginalAddr,
+                                             llvm::Value *PrivateAddr,
+                                             const Expr *AssignExpr,
+                                             QualType OriginalType,
+                                             const VarDecl *VDInit) {
+  EmitBlock(createBasicBlock(".omp.assign.begin."));
+  if (!isa<CXXConstructExpr>(AssignExpr) || isTrivialInitializer(AssignExpr)) {
+    // Perform simple memcpy.
+    EmitAggregateAssign(PrivateAddr, OriginalAddr.getAddress(),
+                        AssignExpr->getType());
+  } else {
+    // Perform element-by-element initialization.
+    QualType ElementTy;
+    auto SrcBegin = OriginalAddr.getAddress();
+    auto DestBegin = PrivateAddr;
+    auto ArrayTy = OriginalType->getAsArrayTypeUnsafe();
+    auto SrcNumElements = emitArrayLength(ArrayTy, ElementTy, SrcBegin);
+    auto DestNumElements = emitArrayLength(ArrayTy, ElementTy, DestBegin);
+    auto SrcEnd = Builder.CreateGEP(SrcBegin, SrcNumElements);
+    auto DestEnd = Builder.CreateGEP(DestBegin, DestNumElements);
+    // The basic structure here is a do-while loop, because we don't
+    // need to check for the zero-element case.
+    auto BodyBB = createBasicBlock("omp.arraycpy.body");
+    auto DoneBB = createBasicBlock("omp.arraycpy.done");
+    auto IsEmpty =
+        Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
+    Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
+
+    // Enter the loop body, making that address the current address.
+    auto EntryBB = Builder.GetInsertBlock();
+    EmitBlock(BodyBB);
+    auto SrcElementPast = Builder.CreatePHI(SrcBegin->getType(), 2,
+                                            "omp.arraycpy.srcElementPast");
+    SrcElementPast->addIncoming(SrcEnd, EntryBB);
+    auto DestElementPast = Builder.CreatePHI(DestBegin->getType(), 2,
+                                             "omp.arraycpy.destElementPast");
+    DestElementPast->addIncoming(DestEnd, EntryBB);
+
+    // Shift the address back by one element.
+    auto NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
+    auto DestElement = Builder.CreateGEP(DestElementPast, NegativeOne,
+                                         "omp.arraycpy.dest.element");
+    auto SrcElement = Builder.CreateGEP(SrcElementPast, NegativeOne,
+                                        "omp.arraycpy.src.element");
+    {
+      // Create RunCleanScope to cleanup possible temps.
+      CodeGenFunction::RunCleanupsScope Init(*this);
+      // Emit initialization for single element.
+      LocalDeclMap[VDInit] = SrcElement;
+      EmitAnyExprToMem(AssignExpr, DestElement,
+                       AssignExpr->getType().getQualifiers(),
+                       /*IsInitializer*/ false);
+      LocalDeclMap.erase(VDInit);
+    }
+
+    // Check whether we've reached the end.
+    auto Done =
+        Builder.CreateICmpEQ(DestElement, DestBegin, "omp.arraycpy.done");
+    Builder.CreateCondBr(Done, DoneBB, BodyBB);
+    DestElementPast->addIncoming(DestElement, Builder.GetInsertBlock());
+    SrcElementPast->addIncoming(SrcElement, Builder.GetInsertBlock());
+
+    // Done.
+    EmitBlock(DoneBB, true);
+  }
+  EmitBlock(createBasicBlock(".omp.assign.end."));
+}
+
+void CodeGenFunction::EmitOMPFirstprivateClause(
+    const OMPExecutableDirective &D,
+    CodeGenFunction::OuterDeclMapTy &OuterDeclMap) {
+  auto PrivateFilter = [](const OMPClause *C) -> bool {
+    return C->getClauseKind() == OMPC_firstprivate;
+  };
+  for (OMPExecutableDirective::filtered_clause_iterator<decltype(PrivateFilter)>
+           I(D.clauses(), PrivateFilter); I; ++I) {
+    auto *C = cast<OMPFirstprivateClause>(*I);
+    auto IRef = C->varlist_begin();
+    auto InitsRef = C->inits().begin();
+    for (auto IInit : C->private_copies()) {
+      auto VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
+      if (*InitsRef != nullptr) {
+        // Emit VarDecl with copy init for arrays.
+        auto *FD = CapturedStmtInfo->lookup(
+            cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl()));
+        LValue Base = MakeNaturalAlignAddrLValue(
+            CapturedStmtInfo->getContextValue(),
+            getContext().getTagDeclType(FD->getParent()));
+        auto OriginalAddr = EmitLValueForField(Base, FD);
+        auto VDInit = cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
+        auto Emission = EmitAutoVarAlloca(*VD);
+        // Emit initialization of aggregate firstprivate vars.
+        EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(),
+                               VD->getInit(), (*IRef)->getType(), VDInit);
+        EmitAutoVarCleanups(Emission);
+      } else
+        // Emit VarDecl with copy init.
+        EmitDecl(*VD);
+      OuterDeclMap[cast<DeclRefExpr>(*IRef)->getDecl()] = GetAddrOfLocalVar(VD);
+      ++IRef, ++InitsRef;
+    }
+  }
+}
+
 void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
   const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
   llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS);
@@ -31,22 +135,13 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
   llvm::Value *OutlinedFn;
   {
     CodeGenFunction CGF(CGM, true);
-    CGCapturedStmtInfo CGInfo(*CS, CS->getCapturedRegionKind());
+    CGOpenMPRegionInfo CGInfo(S, *CS, *CS->getCapturedDecl()->param_begin());
     CGF.CapturedStmtInfo = &CGInfo;
     OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS);
   }
 
-  // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
-  llvm::Value *Args[] = {
-      CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation(*this, S.getLocStart()),
-      Builder.getInt32(1), // Number of arguments after 'microtask' argument
-      // (there is only one additional argument - 'context')
-      Builder.CreateBitCast(OutlinedFn,
-                            CGM.getOpenMPRuntime().getKmpc_MicroPointerTy()),
-      EmitCastToVoidPtr(CapturedStruct)};
-  llvm::Constant *RTLFn = CGM.getOpenMPRuntime().CreateRuntimeFunction(
-      CGOpenMPRuntime::OMPRTL__kmpc_fork_call);
-  EmitRuntimeCall(RTLFn, Args);
+  CGM.getOpenMPRuntime().EmitOMPParallelCall(*this, S.getLocStart(), OutlinedFn,
+                                             CapturedStruct);
 }
 
 void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S,
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index a4b231ddf4b610b14f9b371e7a218a2c552d29e9..e471f1573812f2ebf299af0b8f5532872cd8db21 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -113,6 +113,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   void operator=(const CodeGenFunction &) LLVM_DELETED_FUNCTION;
 
   friend class CGCXXABI;
+  friend class CGOpenMPRegionInfo;
 public:
   /// A jump destination is an abstract label, branching to which may
   /// require a jump out through normal cleanups.
@@ -1826,6 +1827,10 @@ public:
   typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
                              llvm::Value *Address);
 
+  /// \brief Determine whether the given initializer is trivial in the sense
+  /// that it requires no code to be generated.
+  bool isTrivialInitializer(const Expr *Init);
+
   /// EmitAutoVarDecl - Emit an auto variable declaration.
   ///
   /// This function can be called with a null (unreachable) insert point.
@@ -1991,8 +1996,16 @@ public:
                            ArrayRef<const Attr *> Attrs = None);
 
   llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
+  void GenerateCapturedStmtFunctionProlog(const CapturedStmt &S);
+  llvm::Function *GenerateCapturedStmtFunctionEpilog(const CapturedStmt &S);
   llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
   llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
+  typedef llvm::DenseMap<const Decl *, llvm::Value *> OuterDeclMapTy;
+  void EmitOMPAggregateAssign(LValue OriginalAddr, llvm::Value *PrivateAddr,
+                              const Expr *AssignExpr, QualType Type,
+                              const VarDecl *VDInit);
+  void EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
+                                 OuterDeclMapTy &OuterDeclMap);
 
   void EmitOMPParallelDirective(const OMPParallelDirective &S);
   void EmitOMPSimdDirective(const OMPSimdDirective &S);
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index ff2b2826092f29ca6d069b3509ec7a841dc3aee6..159f1bb08edb0fb2bb1cb2337a5b0c9808ee4408 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -3902,11 +3902,36 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
   return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
 }
 
+namespace {
+class DiagsUninitializedSeveretyRAII {
+private:
+  DiagnosticsEngine &Diags;
+  SourceLocation SavedLoc;
+  bool IsIgnored;
+
+public:
+  DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc,
+                                 bool IsIgnored)
+      : Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) {
+    if (!IsIgnored) {
+      Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init,
+                        /*Map*/ diag::Severity::Ignored, Loc);
+    }
+  }
+  ~DiagsUninitializedSeveretyRAII() {
+    if (!IsIgnored)
+      Diags.popMappings(SavedLoc);
+  }
+};
+}
+
 OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
                                                SourceLocation StartLoc,
                                                SourceLocation LParenLoc,
                                                SourceLocation EndLoc) {
   SmallVector<Expr *, 8> Vars;
+  SmallVector<Expr *, 8> PrivateCopies;
+  SmallVector<Expr *, 8> Inits;
   bool IsImplicitClause =
       StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
   auto ImplicitClauseLoc = DSAStack->getConstructLoc();
@@ -3916,11 +3941,13 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
     if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
       // It will be analyzed later.
       Vars.push_back(RefExpr);
+      PrivateCopies.push_back(nullptr);
+      Inits.push_back(nullptr);
       continue;
     }
 
-    SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc
-                                           : RefExpr->getExprLoc();
+    SourceLocation ELoc =
+        IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc();
     // OpenMP [2.1, C/C++]
     //  A list item is a variable name.
     // OpenMP  [2.9.3.3, Restrictions, p.1]
@@ -3938,6 +3965,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
     if (Type->isDependentType() || Type->isInstantiationDependentType()) {
       // It will be analyzed later.
       Vars.push_back(DE);
+      PrivateCopies.push_back(nullptr);
+      Inits.push_back(nullptr);
       continue;
     }
 
@@ -3971,65 +4000,6 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
     //  clause requires an accessible, unambiguous copy constructor for the
     //  class type.
     Type = Context.getBaseElementType(Type);
-    CXXRecordDecl *RD = getLangOpts().CPlusPlus
-                            ? Type.getNonReferenceType()->getAsCXXRecordDecl()
-                            : nullptr;
-    // FIXME This code must be replaced by actual constructing/destructing of
-    // the firstprivate variable.
-    if (RD) {
-      CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);
-      PartialDiagnostic PD =
-          PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
-      if (!CD ||
-          CheckConstructorAccess(ELoc, CD,
-                                 InitializedEntity::InitializeTemporary(Type),
-                                 CD->getAccess(), PD) == AR_inaccessible ||
-          CD->isDeleted()) {
-        if (IsImplicitClause) {
-          Diag(ImplicitClauseLoc,
-               diag::err_omp_task_predetermined_firstprivate_required_method)
-              << 0;
-          Diag(RefExpr->getExprLoc(), diag::note_used_here);
-        } else {
-          Diag(ELoc, diag::err_omp_required_method)
-              << getOpenMPClauseName(OMPC_firstprivate) << 1;
-        }
-        bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
-                      VarDecl::DeclarationOnly;
-        Diag(VD->getLocation(),
-             IsDecl ? diag::note_previous_decl : diag::note_defined_here)
-            << VD;
-        Diag(RD->getLocation(), diag::note_previous_decl) << RD;
-        continue;
-      }
-      MarkFunctionReferenced(ELoc, CD);
-      DiagnoseUseOfDecl(CD, ELoc);
-
-      CXXDestructorDecl *DD = RD->getDestructor();
-      if (DD) {
-        if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
-            DD->isDeleted()) {
-          if (IsImplicitClause) {
-            Diag(ImplicitClauseLoc,
-                 diag::err_omp_task_predetermined_firstprivate_required_method)
-                << 1;
-            Diag(RefExpr->getExprLoc(), diag::note_used_here);
-          } else {
-            Diag(ELoc, diag::err_omp_required_method)
-                << getOpenMPClauseName(OMPC_firstprivate) << 4;
-          }
-          bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
-                        VarDecl::DeclarationOnly;
-          Diag(VD->getLocation(),
-               IsDecl ? diag::note_previous_decl : diag::note_defined_here)
-              << VD;
-          Diag(RD->getLocation(), diag::note_previous_decl) << RD;
-          continue;
-        }
-        MarkFunctionReferenced(ELoc, DD);
-        DiagnoseUseOfDecl(DD, ELoc);
-      }
-    }
 
     // If an implicit firstprivate variable found it was checked already.
     if (!IsImplicitClause) {
@@ -4119,15 +4089,67 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
       }
     }
 
+    Type = Type.getUnqualifiedType();
+    auto VDPrivate = VarDecl::Create(Context, CurContext, DE->getLocStart(),
+                                     ELoc, VD->getIdentifier(), VD->getType(),
+                                     VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+    // Generate helper private variable and initialize it with the value of the
+    // original variable. The address of the original variable is replaced by
+    // the address of the new private variable in the CodeGen. This new variable
+    // is not added to IdResolver, so the code in the OpenMP region uses
+    // original variable for proper diagnostics and variable capturing.
+    Expr *VDInitRefExpr = nullptr;
+    // For arrays generate initializer for single element and replace it by the
+    // original array element in CodeGen.
+    if (DE->getType()->isArrayType()) {
+      auto VDInit = VarDecl::Create(Context, CurContext, DE->getLocStart(),
+                                    ELoc, VD->getIdentifier(), Type,
+                                    VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+      CurContext->addHiddenDecl(VDInit);
+      VDInitRefExpr = DeclRefExpr::Create(
+          Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+          /*TemplateKWLoc*/ SourceLocation(), VDInit,
+          /*isEnclosingLocal*/ false, ELoc, Type,
+          /*VK*/ VK_LValue);
+      VDInit->setIsUsed();
+      auto Init = DefaultLvalueConversion(VDInitRefExpr).get();
+      InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit);
+      InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc);
+
+      InitializationSequence InitSeq(*this, Entity, Kind, Init);
+      ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Init);
+      if (Result.isInvalid())
+        VDPrivate->setInvalidDecl();
+      else
+        VDPrivate->setInit(Result.getAs<Expr>());
+    } else {
+      AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(DE).get(),
+                           /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
+    }
+    if (VDPrivate->isInvalidDecl()) {
+      if (IsImplicitClause) {
+        Diag(DE->getExprLoc(),
+             diag::note_omp_task_predetermined_firstprivate_here);
+      }
+      continue;
+    }
+    CurContext->addDecl(VDPrivate);
+    auto VDPrivateRefExpr = DeclRefExpr::Create(
+        Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+        /*TemplateKWLoc*/ SourceLocation(), VDPrivate,
+        /*isEnclosingLocal*/ false, DE->getLocStart(), DE->getType(),
+        /*VK*/ VK_LValue);
     DSAStack->addDSA(VD, DE, OMPC_firstprivate);
     Vars.push_back(DE);
+    PrivateCopies.push_back(VDPrivateRefExpr);
+    Inits.push_back(VDInitRefExpr);
   }
 
   if (Vars.empty())
     return nullptr;
 
   return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
-                                       Vars);
+                                       Vars, PrivateCopies, Inits);
 }
 
 OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index c8343373ad6f667d613ecf22105438aa95e1210f..0b8efb514019c268e2b2fa17cf0edcae892f5057 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1854,6 +1854,14 @@ void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
   for (unsigned i = 0; i != NumVars; ++i)
     Vars.push_back(Reader->Reader.ReadSubExpr());
   C->setVarRefs(Vars);
+  Vars.clear();
+  for (unsigned i = 0; i != NumVars; ++i)
+    Vars.push_back(Reader->Reader.ReadSubExpr());
+  C->setPrivateCopies(Vars);
+  Vars.clear();
+  for (unsigned i = 0; i != NumVars; ++i)
+    Vars.push_back(Reader->Reader.ReadSubExpr());
+  C->setInits(Vars);
 }
 
 void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 80d42b8ae5ffbd1018ea4695db145d2336ad3709..a963d6b875a7162e1f32a8a8182014765dc092fa 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1761,8 +1761,15 @@ void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
 void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
   Record.push_back(C->varlist_size());
   Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
-  for (auto *VE : C->varlists())
+  for (auto *VE : C->varlists()) {
+    Writer->Writer.AddStmt(VE);
+  }
+  for (auto *VE : C->private_copies()) {
     Writer->Writer.AddStmt(VE);
+  }
+  for (auto *VE : C->inits()) {
+    Writer->Writer.AddStmt(VE);
+  }
 }
 
 void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
diff --git a/test/OpenMP/for_firstprivate_messages.cpp b/test/OpenMP/for_firstprivate_messages.cpp
index f1d21b8ce5af7e3bd989255cbb9eec38ba6662b9..6aa977b65d9284efa705b186fcbdf8da3dc92c25 100644
--- a/test/OpenMP/for_firstprivate_messages.cpp
+++ b/test/OpenMP/for_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
 
 public:
   S2() : a(0) {}
-  S2(S2 &s2) : a(s2.a) {}
+  S2(const S2 &s2) : a(s2.a) {}
   static float S2s;
   static const float S2sc;
 };
@@ -26,23 +26,23 @@ class S3 {
   S3 &operator=(const S3 &s3);
 
 public:
-  S3() : a(0) {}
-  S3(S3 &s3) : a(s3.a) {}
+  S3() : a(0) {} // expected-note {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
+  S3(S3 &s3) : a(s3.a) {} // expected-note {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}}
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
 
 public:
   S4(int v) : a(v) {}
 };
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
   int a;
-  S5(const S5 &s5) : a(s5.a) {}
+  S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
 
 public:
   S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
 
 template <class I, class C>
 int foomain(int argc, char **argv) {
-  I e(4); // expected-note {{'e' defined here}}
-  C g(5); // expected-note 2 {{'g' defined here}}
+  I e(4);
+  C g(5);
   int i;
   int &j = i; // expected-note {{'j' defined here}}
 #pragma omp parallel
@@ -107,7 +107,7 @@ int foomain(int argc, char **argv) {
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel
-#pragma omp for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel
@@ -138,7 +138,7 @@ int foomain(int argc, char **argv) {
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel
-#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel private(i) // expected-note {{defined as private}}
@@ -155,8 +155,8 @@ int foomain(int argc, char **argv) {
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = {0};
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note 2 {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   S3 m;
   S6 n(2);
   int i;
@@ -194,7 +194,7 @@ int main(int argc, char **argv) {
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
-#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} expected-error {{no matching constructor for initialization of 'const S3'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
@@ -235,7 +235,7 @@ int main(int argc, char **argv) {
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
-#pragma omp for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
@@ -263,7 +263,7 @@ int main(int argc, char **argv) {
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
-#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
@@ -291,3 +291,4 @@ int main(int argc, char **argv) {
 
   return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
 }
+
diff --git a/test/OpenMP/for_simd_firstprivate_messages.cpp b/test/OpenMP/for_simd_firstprivate_messages.cpp
index 629a5b852956cfff53e428594e67b731d7713ae0..1345bfc9886a8f18ba41fc0a966be8d300ad969f 100644
--- a/test/OpenMP/for_simd_firstprivate_messages.cpp
+++ b/test/OpenMP/for_simd_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
 
 public:
   S2() : a(0) {}
-  S2(S2 &s2) : a(s2.a) {}
+  S2(const S2 &s2) : a(s2.a) {}
   static float S2s;
   static const float S2sc;
 };
@@ -27,22 +27,22 @@ class S3 {
 
 public:
   S3() : a(0) {}
-  S3(S3 &s3) : a(s3.a) {}
+  S3(const S3 &s3) : a(s3.a) {}
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
 
 public:
   S4(int v) : a(v) {}
 };
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
   int a;
-  S5(const S5 &s5) : a(s5.a) {}
+  S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
 
 public:
   S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
 
 template <class I, class C>
 int foomain(int argc, char **argv) {
-  I e(4); // expected-note {{'e' defined here}}
-  C g(5); // expected-note 2 {{'g' defined here}}
+  I e(4);
+  C g(5);
   int i;
   int &j = i; // expected-note {{'j' defined here}}
 #pragma omp parallel
@@ -99,7 +99,7 @@ int foomain(int argc, char **argv) {
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel
-#pragma omp for simd firstprivate(a, b) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+#pragma omp for simd firstprivate(a, b) // expected-error {{a firstprivate variable with incomplete type 'S1'}}
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel
@@ -107,7 +107,7 @@ int foomain(int argc, char **argv) {
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel
-#pragma omp for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel
@@ -138,7 +138,7 @@ int foomain(int argc, char **argv) {
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel
-#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel private(i) // expected-note {{defined as private}}
@@ -155,8 +155,8 @@ int foomain(int argc, char **argv) {
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = {0};
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note 2 {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   S3 m;
   S6 n(2);
   int i;
@@ -235,7 +235,7 @@ int main(int argc, char **argv) {
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
-#pragma omp for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
@@ -263,7 +263,7 @@ int main(int argc, char **argv) {
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
-#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel
diff --git a/test/OpenMP/parallel_codegen.cpp b/test/OpenMP/parallel_codegen.cpp
index d9ff5ac0233326cec34b9f5cfaef03ecda0b656c..e50ab43c2808c8e852f735fc7089f878cbf378d3 100644
--- a/test/OpenMP/parallel_codegen.cpp
+++ b/test/OpenMP/parallel_codegen.cpp
@@ -39,7 +39,7 @@ int main (int argc, char **argv) {
 // CHECK:       [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0
 // CHECK-NEXT:  store i32* {{%[a-z0-9.]+}}, i32** [[ARGC_REF]]
 // CHECK-NEXT:  [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
-// CHECK-NEXT:  call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-NEXT:  call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
 // CHECK-NEXT:  [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
 // CHECK-NEXT:  [[RET:%.+]] = call {{[a-z]*[ ]?i32}} [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
 // CHECK-NEXT:  ret i32 [[RET]]
@@ -55,13 +55,13 @@ int main (int argc, char **argv) {
 // CHECK-DEBUG-NEXT:  [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
 // CHECK-DEBUG-NEXT:  store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC1]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
 // CHECK-DEBUG-NEXT:  [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
-// CHECK-DEBUG-NEXT:  call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-DEBUG-NEXT:  call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
 // CHECK-DEBUG-NEXT:  [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
 // CHECK-DEBUG-NEXT:  [[RET:%.+]] = call i32 [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
 // CHECK-DEBUG-NEXT:  ret i32 [[RET]]
 // CHECK-DEBUG-NEXT:  }
 
-// CHECK-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
+// CHECK-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
 // CHECK:       [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
 // CHECK:       store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
 // CHECK:       [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
@@ -73,7 +73,7 @@ int main (int argc, char **argv) {
 // CHECK:       call void @{{.+terminate.*}}(
 // CHECK-NEXT:  unreachable
 // CHECK-NEXT:  }
-// CHECK-DEBUG-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
+// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
 // CHECK-DEBUG:       [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
 // CHECK-DEBUG:       store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
 // CHECK-DEBUG:       [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
@@ -96,7 +96,7 @@ int main (int argc, char **argv) {
 // CHECK:       [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon.0* [[AGG_CAPTURED]], i32 0, i32 0
 // CHECK-NEXT:  store i8*** {{%[a-z0-9.]+}}, i8**** [[ARGC_REF]]
 // CHECK-NEXT:  [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
-// CHECK-NEXT:  call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-NEXT:  call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
 // CHECK-NEXT:  ret i32 0
 // CHECK-NEXT:  }
 // CHECK-DEBUG:       define linkonce_odr i32 [[TMAIN]](i8** %argc)
@@ -110,11 +110,11 @@ int main (int argc, char **argv) {
 // CHECK-DEBUG-NEXT:  [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
 // CHECK-DEBUG-NEXT:  store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC2]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
 // CHECK-DEBUG-NEXT:  [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
-// CHECK-DEBUG-NEXT:  call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-DEBUG-NEXT:  call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
 // CHECK-DEBUG-NEXT:  ret i32 0
 // CHECK-DEBUG-NEXT:  }
 
-// CHECK-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
+// CHECK-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
 // CHECK:       [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
 // CHECK:       store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
 // CHECK:       [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
@@ -126,7 +126,7 @@ int main (int argc, char **argv) {
 // CHECK:       call void @{{.+terminate.*}}(
 // CHECK-NEXT:  unreachable
 // CHECK-NEXT:  }
-// CHECK-DEBUG-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
+// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
 // CHECK-DEBUG:       [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
 // CHECK-DEBUG:       store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
 // CHECK-DEBUG:       [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
diff --git a/test/OpenMP/parallel_firstprivate_codegen.cpp b/test/OpenMP/parallel_firstprivate_codegen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4c128f4510af59225c62cd66b5a0e92cc02f48f0
--- /dev/null
+++ b/test/OpenMP/parallel_firstprivate_codegen.cpp
@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+struct St {
+  int a, b;
+  St() : a(0), b(0) {}
+  St(const St &st) : a(st.a + st.b), b(0) {}
+  ~St() {}
+};
+
+template <class T>
+struct S {
+  T f;
+  S(T a) : f(a) {}
+  S() : f() {}
+  S(const S &s, St t = St()) : f(s.f + t.a) {}
+  operator T() { return T(); }
+  ~S() {}
+};
+
+// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
+// CHECK-DAG: [[ST_TY:%.+]] = type { i{{[0-9]+}}, i{{[0-9]+}} }
+// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* }
+// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* }
+// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+
+template <typename T>
+T tmain() {
+  S<T> test;
+  T t_var = T();
+  T vec[] = {1, 2};
+  S<T> s_arr[] = {1, 2};
+  S<T> var(3);
+#pragma omp parallel firstprivate(t_var, vec, s_arr, var)
+  {
+    vec[0] = t_var;
+    s_arr[0] = var;
+  }
+  return T();
+}
+
+int main() {
+  S<float> test;
+  int t_var = 0;
+  int vec[] = {1, 2};
+  S<float> s_arr[] = {1, 2};
+  S<float> var(3);
+#pragma omp parallel firstprivate(t_var, vec, s_arr, var)
+  {
+    vec[0] = t_var;
+    s_arr[0] = var;
+  }
+  return tmain<int>();
+}
+
+// CHECK: define i{{[0-9]+}} @main()
+// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: = call i{{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call void [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]],
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
+// CHECK: br label %[[VEC_PRIV_INIT:.+]]
+// CHECK: [[VEC_PRIV_INIT]]
+// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
+// CHECK: br label %[[VEC_PRIV_INIT_END:.+]]
+// CHECK: [[VEC_PRIV_INIT_END]]
+// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]** [[S_ARR_REF_PTR]],
+// CHECK: br label %[[S_ARR_PRIV_INIT:.+]]
+// CHECK: [[S_ARR_PRIV_INIT]]
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call void [[ST_TY_DEFAULT_CONSTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call void [[S_FLOAT_TY_COPY_CONSTR:@.+]]([[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call void [[ST_TY_DESTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
+// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]]
+// CHECK: [[S_ARR_PRIV_INIT_END]]
+// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]** [[VAR_REF_PTR]],
+// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call void [[S_FLOAT_TY_COPY_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
+// CHECK: ret void
+
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call void [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}** [[T_VAR_PTR_REF]],
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}* [[T_VAR_REF]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
+// CHECK: br label %[[VEC_PRIV_INIT:.+]]
+// CHECK: [[VEC_PRIV_INIT]]
+// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
+// CHECK: br label %[[VEC_PRIV_INIT_END:.+]]
+// CHECK: [[VEC_PRIV_INIT_END]]
+// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_INT_TY]]]** [[S_ARR_REF_PTR]],
+// CHECK: br label %[[S_ARR_PRIV_INIT:.+]]
+// CHECK: [[S_ARR_PRIV_INIT]]
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call void [[S_INT_TY_COPY_CONSTR:@.+]]([[S_INT_TY]]* {{.+}}, [[S_INT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
+// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]]
+// CHECK: [[S_ARR_PRIV_INIT_END]]
+// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]** [[VAR_REF_PTR]],
+// CHECK: call void [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call void [[S_INT_TY_COPY_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call void [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]*
+// CHECK: ret void
+#endif
+
diff --git a/test/OpenMP/parallel_firstprivate_messages.cpp b/test/OpenMP/parallel_firstprivate_messages.cpp
index 9df45c60e708e709b54fe53f22f82039d968756a..7d1e3593500eec8cdbe4f68f3ee0734ccead1610 100644
--- a/test/OpenMP/parallel_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_firstprivate_messages.cpp
@@ -13,7 +13,7 @@ class S2 {
   mutable int a;
 public:
   S2():a(0) { }
-  S2(S2 &s2):a(s2.a) { }
+  S2(const S2 &s2):a(s2.a) { }
   static float S2s;
   static const float S2sc;
 };
@@ -24,22 +24,22 @@ class S3 {
   int a;
 public:
   S3():a(0) { }
-  S3(S3 &s3):a(s3.a) { }
+  S3(const S3 &s3):a(s3.a) { }
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note {{implicitly declared private here}}
 public:
   S4(int v):a(v) { }
 };
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
   int a;
   S5():a(0) {}
-  S5(const S5 &s5):a(s5.a) { }
+  S5(const S5 &s5):a(s5.a) { } // expected-note {{implicitly declared private here}}
 public:
   S5(int v):a(v) { }
 };
@@ -50,8 +50,8 @@ S3 h;
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = { 0 };
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   int i;
   int &j = i; // expected-note {{'j' defined here}}
   #pragma omp parallel firstprivate // expected-error {{expected '(' after 'firstprivate'}}
@@ -69,7 +69,7 @@ int main(int argc, char **argv) {
   #pragma omp parallel firstprivate(da)
   #pragma omp parallel firstprivate(S2::S2s)
   #pragma omp parallel firstprivate(S2::S2sc)
-  #pragma omp parallel firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+  #pragma omp parallel firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   #pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
   #pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
   foo();
diff --git a/test/OpenMP/parallel_for_firstprivate_messages.cpp b/test/OpenMP/parallel_for_firstprivate_messages.cpp
index 99dd68f3cbfab25ea810b7dbf68b3ba65027ed03..b4958733deca425edb1dbfb3f17b1e61ec9d9744 100644
--- a/test/OpenMP/parallel_for_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
 
 public:
   S2() : a(0) {}
-  S2(S2 &s2) : a(s2.a) {}
+  S2(const S2 &s2) : a(s2.a) {}
   static float S2s;
   static const float S2sc;
 };
@@ -27,22 +27,22 @@ class S3 {
 
 public:
   S3() : a(0) {}
-  S3(S3 &s3) : a(s3.a) {}
+  S3(const S3 &s3) : a(s3.a) {}
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
 
 public:
   S4(int v) : a(v) {}
 };
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
   int a;
-  S5(const S5 &s5) : a(s5.a) {}
+  S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
 
 public:
   S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
 
 template <class I, class C>
 int foomain(int argc, char **argv) {
-  I e(4); // expected-note {{'e' defined here}}
-  C g(5); // expected-note 2 {{'g' defined here}}
+  I e(4);
+  C g(5);
   int i;
   int &j = i; // expected-note {{'j' defined here}}
 #pragma omp parallel for firstprivate // expected-error {{expected '(' after 'firstprivate'}}
@@ -96,7 +96,7 @@ int foomain(int argc, char **argv) {
 #pragma omp parallel for firstprivate(argv[1]) // expected-error {{expected variable name}}
   for (int k = 0; k < argc; ++k)
     ++k;
-#pragma omp parallel for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel for firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
@@ -123,7 +123,7 @@ int foomain(int argc, char **argv) {
 #pragma omp parallel for firstprivate(i)
   for (int k = 0; k < argc; ++k)
     ++k;
-#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel private(i)
@@ -140,8 +140,8 @@ int foomain(int argc, char **argv) {
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = {0};
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note 2 {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   S3 m;
   S6 n(2);
   int i;
@@ -201,7 +201,7 @@ int main(int argc, char **argv) {
 #pragma omp parallel for safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp parallel for'}}
   for (i = 0; i < argc; ++i)
     foo();
-#pragma omp parallel for firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel for firstprivate(m) // OK
@@ -223,7 +223,7 @@ int main(int argc, char **argv) {
 #pragma omp parallel for firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
   for (i = 0; i < argc; ++i)
     foo();
-#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel for lastprivate(n) firstprivate(n) // OK
diff --git a/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp b/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp
index f76d1fc9496cf2e5ddc1213fc5643e879e79dcc1..876d422e634dae4fb9ed6015621e466ca94d42c5 100644
--- a/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
 
 public:
   S2() : a(0) {}
-  S2(S2 &s2) : a(s2.a) {}
+  S2(const S2 &s2) : a(s2.a) {}
   static float S2s;
   static const float S2sc;
 };
@@ -27,22 +27,22 @@ class S3 {
 
 public:
   S3() : a(0) {}
-  S3(S3 &s3) : a(s3.a) {}
+  S3(const S3 &s3) : a(s3.a) {}
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
 
 public:
   S4(int v) : a(v) {}
 };
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
   int a;
-  S5(const S5 &s5) : a(s5.a) {}
+  S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
 
 public:
   S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
 
 template <class I, class C>
 int foomain(int argc, char **argv) {
-  I e(4); // expected-note {{'e' defined here}}
-  C g(5); // expected-note 2 {{'g' defined here}}
+  I e(4);
+  C g(5);
   int i;
   int &j = i; // expected-note {{'j' defined here}}
 #pragma omp parallel for simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
@@ -96,7 +96,7 @@ int foomain(int argc, char **argv) {
 #pragma omp parallel for simd firstprivate(argv[1]) // expected-error {{expected variable name}}
   for (int k = 0; k < argc; ++k)
     ++k;
-#pragma omp parallel for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   for (int k = 0; k < argc; ++k)
     ++k;
 #pragma omp parallel for simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
@@ -122,7 +122,7 @@ int foomain(int argc, char **argv) {
 #pragma omp parallel for simd firstprivate(i)
   for (int k = 0; k < argc; ++k)
     ++k;
-#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel private(i)
@@ -139,8 +139,8 @@ int foomain(int argc, char **argv) {
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = {0};
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note 2 {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   S3 m;
   S6 n(2);
   int i;
@@ -200,7 +200,7 @@ int main(int argc, char **argv) {
 #pragma omp parallel for simd safelen(5)
   for (i = 0; i < argc; ++i)
     foo();
-#pragma omp parallel for simd firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel for simd firstprivate(m) // OK
@@ -221,7 +221,7 @@ int main(int argc, char **argv) {
 #pragma omp parallel for simd firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
   for (i = 0; i < argc; ++i)
     foo();
-#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel for simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   for (i = 0; i < argc; ++i)
     foo();
 #pragma omp parallel for simd lastprivate(n) firstprivate(n) // OK
diff --git a/test/OpenMP/parallel_sections_firstprivate_messages.cpp b/test/OpenMP/parallel_sections_firstprivate_messages.cpp
index ffd2b0cfd5e57af45d1d76fcfe17aade76272c37..2d27b1a600daf5bc4143bf8a5f665c453d09d863 100644
--- a/test/OpenMP/parallel_sections_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_sections_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
 
 public:
   S2() : a(0) {}
-  S2(S2 &s2) : a(s2.a) {}
+  S2(const S2 &s2) : a(s2.a) {}
   static float S2s;
   static const float S2sc;
 };
@@ -27,22 +27,22 @@ class S3 {
 
 public:
   S3() : a(0) {}
-  S3(S3 &s3) : a(s3.a) {}
+  S3(const S3 &s3) : a(s3.a) {}
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
 
 public:
   S4(int v) : a(v) {}
 };
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
   int a;
-  S5(const S5 &s5) : a(s5.a) {}
+  S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
 
 public:
   S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
 
 template <class I, class C>
 int foomain(int argc, char **argv) {
-  I e(4); // expected-note {{'e' defined here}}
-  C g(5); // expected-note 2 {{'g' defined here}}
+  I e(4);
+  C g(5);
   int i;
   int &j = i;                              // expected-note {{'j' defined here}}
 #pragma omp parallel sections firstprivate // expected-error {{expected '(' after 'firstprivate'}}
@@ -106,7 +106,7 @@ int foomain(int argc, char **argv) {
   {
     foo();
   }
-#pragma omp parallel sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   {
     foo();
   }
@@ -138,7 +138,7 @@ int foomain(int argc, char **argv) {
   {
     foo();
   }
-#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   {
     foo();
   }
@@ -158,8 +158,8 @@ int foomain(int argc, char **argv) {
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = {0};
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note 2 {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   S3 m;
   S6 n(2);
   int i;
@@ -237,7 +237,7 @@ int main(int argc, char **argv) {
   {
     foo();
   }
-#pragma omp parallel sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   {
     foo();
   }
@@ -262,7 +262,7 @@ int main(int argc, char **argv) {
   {
     foo();
   }
-#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp parallel sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   {
     foo();
   }
diff --git a/test/OpenMP/sections_firstprivate_messages.cpp b/test/OpenMP/sections_firstprivate_messages.cpp
index b030ce549d336359774932737caf5fceae38ba35..ecee45900feade001bafb4adfa7fd569f92ea9c6 100644
--- a/test/OpenMP/sections_firstprivate_messages.cpp
+++ b/test/OpenMP/sections_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
 
 public:
   S2() : a(0) {}
-  S2(S2 &s2) : a(s2.a) {}
+  S2(const S2 &s2) : a(s2.a) {}
   static float S2s;
   static const float S2sc;
 };
@@ -27,22 +27,22 @@ class S3 {
 
 public:
   S3() : a(0) {}
-  S3(S3 &s3) : a(s3.a) {}
+  S3(const S3 &s3) : a(s3.a) {}
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
 
 public:
   S4(int v) : a(v) {}
 };
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
   int a;
-  S5(const S5 &s5) : a(s5.a) {}
+  S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
 
 public:
   S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
 
 template <class I, class C>
 int foomain(int argc, char **argv) {
-  I e(4); // expected-note {{'e' defined here}}
-  C g(5); // expected-note 2 {{'g' defined here}}
+  I e(4);
+  C g(5);
   int i;
   int &j = i; // expected-note {{'j' defined here}}
 #pragma omp parallel
@@ -117,7 +117,7 @@ int foomain(int argc, char **argv) {
     foo();
   }
 #pragma omp parallel
-#pragma omp sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   {
     foo();
   }
@@ -153,7 +153,7 @@ int foomain(int argc, char **argv) {
     foo();
   }
 #pragma omp parallel
-#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   {
     foo();
   }
@@ -173,8 +173,8 @@ int foomain(int argc, char **argv) {
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = {0};
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note 2 {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   S3 m;
   S6 n(2);
   int i;
@@ -271,7 +271,7 @@ int main(int argc, char **argv) {
     foo();
   }
 #pragma omp parallel
-#pragma omp sections firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp sections firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   {
     foo();
   }
@@ -301,7 +301,7 @@ int main(int argc, char **argv) {
     foo();
   }
 #pragma omp parallel
-#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp sections lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   {
     foo();
   }
diff --git a/test/OpenMP/single_firstprivate_messages.cpp b/test/OpenMP/single_firstprivate_messages.cpp
index 6d4988254fb659cebae5ea43215bde3c4d9e1080..9f6f16083544436754b0ce38406667ab75c5d6de 100644
--- a/test/OpenMP/single_firstprivate_messages.cpp
+++ b/test/OpenMP/single_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
 
 public:
   S2() : a(0) {}
-  S2(S2 &s2) : a(s2.a) {}
+  S2(const S2 &s2) : a(s2.a) {}
   static float S2s;
   static const float S2sc;
 };
@@ -27,22 +27,22 @@ class S3 {
 
 public:
   S3() : a(0) {}
-  S3(S3 &s3) : a(s3.a) {}
+  S3(const S3 &s3) : a(s3.a) {}
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
 
 public:
   S4(int v) : a(v) {}
 };
-class S5 { // expected-note 4 {{'S5' declared here}}
+class S5 {
   int a;
-  S5(const S5 &s5) : a(s5.a) {}
+  S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
 
 public:
   S5() : a(0) {}
@@ -62,8 +62,8 @@ S3 h;
 
 template <class I, class C>
 int foomain(int argc, char **argv) {
-  I e(4); // expected-note {{'e' defined here}}
-  C g(5); // expected-note 2 {{'g' defined here}}
+  I e(4);
+  C g(5);
   int i;
   int &j = i; // expected-note {{'j' defined here}}
 #pragma omp parallel
@@ -97,7 +97,7 @@ int foomain(int argc, char **argv) {
 #pragma omp single firstprivate(argv[1]) // expected-error {{expected variable name}}
   foo();
 #pragma omp parallel
-#pragma omp single firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp single firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   foo();
 #pragma omp parallel
 #pragma omp single firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
@@ -121,7 +121,7 @@ int foomain(int argc, char **argv) {
 #pragma omp single firstprivate(i)
   foo();
 #pragma omp parallel
-#pragma omp single firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp single firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   foo();
 #pragma omp parallel private(i)    // expected-note {{defined as private}}
 #pragma omp single firstprivate(i) // expected-error {{firstprivate variable must be shared}}
@@ -135,8 +135,8 @@ int foomain(int argc, char **argv) {
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = {0};
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note 2 {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   S3 m;
   S6 n(2);
   int i;
@@ -197,7 +197,7 @@ int main(int argc, char **argv) {
 #pragma omp single safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp single'}}
   foo();
 #pragma omp parallel
-#pragma omp single firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp single firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
   foo();
 #pragma omp parallel
 #pragma omp single firstprivate(m) // OK
@@ -215,7 +215,7 @@ int main(int argc, char **argv) {
 #pragma omp single firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
   foo();
 #pragma omp parallel
-#pragma omp single firstprivate(g) // expected-error {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp single firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
   foo();
 #pragma omp parallel
 #pragma omp single firstprivate(n) // OK
diff --git a/test/OpenMP/task_firstprivate_messages.cpp b/test/OpenMP/task_firstprivate_messages.cpp
index 85d3f9f46144f39fe00b029285f0b22b49ee0888..6c5ccfca57bf7ddfecc3214e3def11b1a561be31 100644
--- a/test/OpenMP/task_firstprivate_messages.cpp
+++ b/test/OpenMP/task_firstprivate_messages.cpp
@@ -14,7 +14,7 @@ class S2 {
 
 public:
   S2() : a(0) {}
-  S2(S2 &s2) : a(s2.a) {}
+  S2(const S2 &s2) : a(s2.a) {}
   static float S2s;
   static const float S2sc;
 };
@@ -26,23 +26,23 @@ class S3 {
 
 public:
   S3() : a(0) {}
-  S3(S3 &s3) : a(s3.a) {}
+  S3(const S3 &s3) : a(s3.a) {}
 };
 const S3 c;
 const S3 ca[5];
 extern const int f;
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
   int a;
   S4();
-  S4(const S4 &s4);
+  S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
 
 public:
   S4(int v) : a(v) {}
 };
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
   int a;
   S5() : a(0) {}
-  S5(const S5 &s5) : a(s5.a) {}
+  S5(const S5 &s5) : a(s5.a) {} // expected-note 2 {{implicitly declared private here}}
 
 public:
   S5(int v) : a(v) {}
@@ -54,8 +54,8 @@ S3 h;
 int main(int argc, char **argv) {
   const int d = 5;
   const int da[5] = {0};
-  S4 e(4); // expected-note {{'e' defined here}}
-  S5 g(5); // expected-note {{'g' defined here}}
+  S4 e(4);
+  S5 g(5);
   int i;
   int &j = i;                                               // expected-note {{'j' defined here}}
 #pragma omp task firstprivate                               // expected-error {{expected '(' after 'firstprivate'}}
@@ -73,7 +73,7 @@ int main(int argc, char **argv) {
 #pragma omp task firstprivate(da)
 #pragma omp task firstprivate(S2::S2s)
 #pragma omp task firstprivate(S2::S2sc)
-#pragma omp task firstprivate(e, g)          // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
+#pragma omp task firstprivate(e, g)          // expected-error 2 {{calling a private constructor of class 'S4'}} expected-error 2 {{calling a private constructor of class 'S5'}}
 #pragma omp task firstprivate(h)             // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
 #pragma omp task private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
   foo();
diff --git a/test/OpenMP/task_messages.cpp b/test/OpenMP/task_messages.cpp
index 88c339afc1173e8f53138ac6f43688814ea50859..b02b43c2b3950c71829d121b9eb7daf79f2c126f 100644
--- a/test/OpenMP/task_messages.cpp
+++ b/test/OpenMP/task_messages.cpp
@@ -5,8 +5,8 @@ void foo() {
 
 #pragma omp task // expected-error {{unexpected OpenMP directive '#pragma omp task'}}
 
-class S { // expected-note 6 {{'S' declared here}}
-  S(const S &s) { a = s.a + 12; }
+class S {
+  S(const S &s) { a = s.a + 12; } // expected-note 6 {{implicitly declared private here}}
   int a;
 
 public:
@@ -17,23 +17,35 @@ public:
   S operator+(const S &) { return *this; }
 };
 
+class S1 {
+  int a;
+
+public:
+  S1() : a(0) {}
+  S1 &operator++() { return *this; }
+  S1(const S1 &) = delete; // expected-note 2 {{'S1' has been explicitly marked deleted here}}
+};
+
 template <class T>
 int foo() {
-  T a; // expected-note 3 {{'a' defined here}}
+  T a;
   T &b = a; // expected-note 4 {{'b' defined here}}
   int r;
+  S1 s1;
+// expected-error@+1 2 {{call to deleted constructor of 'S1'}}
+#pragma omp task
+// expected-note@+1 2 {{predetermined as a firstprivate in a task construct here}}
+  ++s1;
 #pragma omp task default(none)
 #pragma omp task default(shared)
   ++a;
-// expected-error@+2 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
 #pragma omp task default(none)
 #pragma omp task
-// expected-note@+1 {{used here}}
+  // expected-error@+1 {{calling a private constructor of class 'S'}}
   ++a;
 #pragma omp task
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
 #pragma omp task
-  // expected-note@+1 {{used here}}
+  // expected-error@+1 {{calling a private constructor of class 'S'}}
   ++a;
 #pragma omp task default(shared)
 #pragma omp task
@@ -46,11 +58,11 @@ int foo() {
 #pragma omp task
   // expected-note@+1 2 {{used here}}
   ++b;
-// expected-error@+3 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'int &'}}
-// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
+// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'int &'}}
+// expected-error@+1 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
 #pragma omp task
-// expected-note@+1 3 {{used here}}
+// expected-error@+2 {{calling a private constructor of class 'S'}}
+// expected-note@+1 2 {{used here}}
 #pragma omp parallel shared(a, b)
   ++a, ++b;
 // expected-note@+1 3 {{defined as reduction}}
@@ -109,7 +121,7 @@ int foo() {
 int main(int argc, char **argv) {
   int a;
   int &b = a; // expected-note 2 {{'b' defined here}}
-  S sa;       // expected-note 3 {{'sa' defined here}}
+  S sa;
   S &sb = sa; // expected-note 2 {{'sb' defined here}}
   int r;
 #pragma omp task { // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
@@ -193,14 +205,12 @@ L2:
 #pragma omp task default(shared)
   ++sa;
 #pragma omp task default(none)
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
 #pragma omp task
-// expected-note@+1 {{used here}}
+  // expected-error@+1 {{calling a private constructor of class 'S'}}
   ++sa;
 #pragma omp task
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
 #pragma omp task
-// expected-note@+1 {{used here}}
+  // expected-error@+1 {{calling a private constructor of class 'S'}}
   ++sa;
 #pragma omp task default(shared)
 #pragma omp task
@@ -212,10 +222,10 @@ L2:
 #pragma omp task
   // expected-note@+1 {{used here}}
   ++sb;
-// expected-error@+2 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
-// expected-error@+1 {{predetermined as a firstprivate in a task construct variable must have an accessible, unambiguous copy constructor}}
+// expected-error@+1 {{predetermined as a firstprivate in a task construct variable cannot be of reference type 'S &'}}
 #pragma omp task
-// expected-note@+1 2 {{used here}}
+// expected-error@+2 {{calling a private constructor of class 'S'}}
+// expected-note@+1 {{used here}}
 #pragma omp parallel shared(sa, sb)
   ++sa, ++sb;
 // expected-note@+1 2 {{defined as reduction}}