r210184 - [OPENMP] Parsing/Sema for OMPLasprivateClause.

Alexander Musman alexander.musman at gmail.com
Wed Jun 4 06:06:40 PDT 2014


Author: amusman
Date: Wed Jun  4 08:06:39 2014
New Revision: 210184

URL: http://llvm.org/viewvc/llvm-project?rev=210184&view=rev
Log:
[OPENMP] Parsing/Sema for OMPLasprivateClause.
Parsing this clause, allowing it on directive ‘omp simd’ and semantic checks.

Added:
    cfe/trunk/test/OpenMP/simd_lastprivate_messages.cpp
Modified:
    cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/OpenMPClause.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/OpenMPKinds.def
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Stmt.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Basic/OpenMPKinds.cpp
    cfe/trunk/lib/Parse/ParseOpenMP.cpp
    cfe/trunk/lib/Sema/SemaOpenMP.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/test/OpenMP/simd_ast_print.cpp
    cfe/trunk/test/OpenMP/simd_loop_messages.cpp
    cfe/trunk/test/OpenMP/simd_misc_messages.c
    cfe/trunk/tools/libclang/CIndex.cpp

Modified: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h Wed Jun  4 08:06:39 2014
@@ -2354,6 +2354,13 @@ bool RecursiveASTVisitor<Derived>::Visit
 }
 
 template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
+    OMPLastprivateClause *C) {
+  VisitOMPClauseList(C);
+  return true;
+}
+
+template <typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
   VisitOMPClauseList(C);
   return true;

Modified: cfe/trunk/include/clang/AST/OpenMPClause.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OpenMPClause.h?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/OpenMPClause.h (original)
+++ cfe/trunk/include/clang/AST/OpenMPClause.h Wed Jun  4 08:06:39 2014
@@ -620,6 +620,66 @@ public:
   }
 };
 
+/// \brief This represents clause 'lastprivate' in the '#pragma omp ...'
+/// directives.
+///
+/// \code
+/// #pragma omp simd lastprivate(a,b)
+/// \endcode
+/// In this example directive '#pragma omp simd' has clause 'lastprivate'
+/// with the variables 'a' and 'b'.
+///
+class OMPLastprivateClause : public OMPVarListClause<OMPLastprivateClause> {
+  /// \brief Build clause with number of variables \a N.
+  ///
+  /// \param StartLoc Starting location of the clause.
+  /// \param LParenLoc Location of '('.
+  /// \param EndLoc Ending location of the clause.
+  /// \param N Number of the variables in the clause.
+  ///
+  OMPLastprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+                       SourceLocation EndLoc, unsigned N)
+      : OMPVarListClause<OMPLastprivateClause>(OMPC_lastprivate, StartLoc,
+                                               LParenLoc, EndLoc, N) {}
+
+  /// \brief Build an empty clause.
+  ///
+  /// \param N Number of variables.
+  ///
+  explicit OMPLastprivateClause(unsigned N)
+      : OMPVarListClause<OMPLastprivateClause>(
+            OMPC_lastprivate, SourceLocation(), SourceLocation(),
+            SourceLocation(), N) {}
+
+public:
+  /// \brief Creates clause with a list of variables \a VL.
+  ///
+  /// \param C AST context.
+  /// \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.
+  ///
+  static OMPLastprivateClause *
+  Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+         SourceLocation EndLoc, ArrayRef<Expr *> VL);
+  /// \brief Creates an empty clause with the place for \a N variables.
+  ///
+  /// \param C AST context.
+  /// \param N The number of variables.
+  ///
+  static OMPLastprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+  StmtRange children() {
+    return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
+                     reinterpret_cast<Stmt **>(varlist_end()));
+  }
+
+  static bool classof(const OMPClause *T) {
+    return T->getClauseKind() == OMPC_lastprivate;
+  }
+};
+
 /// \brief This represents clause 'shared' in the '#pragma omp ...' directives.
 ///
 /// \code

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Wed Jun  4 08:06:39 2014
@@ -2375,6 +2375,13 @@ bool RecursiveASTVisitor<Derived>::Visit
 }
 
 template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
+    OMPLastprivateClause *C) {
+  VisitOMPClauseList(C);
+  return true;
+}
+
+template <typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
   VisitOMPClauseList(C);
   return true;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jun  4 08:06:39 2014
@@ -6923,6 +6923,8 @@ def err_omp_private_incomplete_type : Er
   "a private variable with incomplete type %0">;
 def err_omp_firstprivate_incomplete_type : Error<
   "a firstprivate variable with incomplete type %0">;
+def err_omp_lastprivate_incomplete_type : Error<
+  "a lastprivate variable with incomplete type %0">;
 def err_omp_unexpected_clause_value : Error<
   "expected %0 in OpenMP clause '%1'">;
 def err_omp_expected_var_name : Error<

Modified: cfe/trunk/include/clang/Basic/OpenMPKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OpenMPKinds.def?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/OpenMPKinds.def (original)
+++ cfe/trunk/include/clang/Basic/OpenMPKinds.def Wed Jun  4 08:06:39 2014
@@ -45,6 +45,7 @@ OPENMP_CLAUSE(collapse, OMPCollapseClaus
 OPENMP_CLAUSE(default, OMPDefaultClause)
 OPENMP_CLAUSE(private, OMPPrivateClause)
 OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
+OPENMP_CLAUSE(lastprivate, OMPLastprivateClause)
 OPENMP_CLAUSE(shared,  OMPSharedClause)
 OPENMP_CLAUSE(linear,  OMPLinearClause)
 OPENMP_CLAUSE(aligned, OMPAlignedClause)
@@ -63,6 +64,7 @@ OPENMP_PARALLEL_CLAUSE(copyin)
 
 // FIXME: more clauses allowed for directive 'omp simd'.
 OPENMP_SIMD_CLAUSE(private)
+OPENMP_SIMD_CLAUSE(lastprivate)
 OPENMP_SIMD_CLAUSE(linear)
 OPENMP_SIMD_CLAUSE(aligned)
 OPENMP_SIMD_CLAUSE(safelen)

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jun  4 08:06:39 2014
@@ -7367,6 +7367,11 @@ public:
                                            SourceLocation StartLoc,
                                            SourceLocation LParenLoc,
                                            SourceLocation EndLoc);
+  /// \brief Called on well-formed 'lastprivate' clause.
+  OMPClause *ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
+                                          SourceLocation StartLoc,
+                                          SourceLocation LParenLoc,
+                                          SourceLocation EndLoc);
   /// \brief Called on well-formed 'shared' clause.
   OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
                                      SourceLocation StartLoc,

Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Wed Jun  4 08:06:39 2014
@@ -1168,6 +1168,28 @@ OMPFirstprivateClause *OMPFirstprivateCl
   return new (Mem) OMPFirstprivateClause(N);
 }
 
+OMPLastprivateClause *OMPLastprivateClause::Create(const ASTContext &C,
+                                                   SourceLocation StartLoc,
+                                                   SourceLocation LParenLoc,
+                                                   SourceLocation EndLoc,
+                                                   ArrayRef<Expr *> VL) {
+  void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
+                                                  llvm::alignOf<Expr *>()) +
+                         sizeof(Expr *) * VL.size());
+  OMPLastprivateClause *Clause =
+      new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
+  Clause->setVarRefs(VL);
+  return Clause;
+}
+
+OMPLastprivateClause *OMPLastprivateClause::CreateEmpty(const ASTContext &C,
+                                                        unsigned N) {
+  void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
+                                                  llvm::alignOf<Expr *>()) +
+                         sizeof(Expr *) * N);
+  return new (Mem) OMPLastprivateClause(N);
+}
+
 OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
                                          SourceLocation StartLoc,
                                          SourceLocation LParenLoc,

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Wed Jun  4 08:06:39 2014
@@ -657,6 +657,14 @@ void OMPClausePrinter::VisitOMPFirstpriv
   }
 }
 
+void OMPClausePrinter::VisitOMPLastprivateClause(OMPLastprivateClause *Node) {
+  if (!Node->varlist_empty()) {
+    OS << "lastprivate";
+    VisitOMPClauseList(Node, '(');
+    OS << ")";
+  }
+}
+
 void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
   if (!Node->varlist_empty()) {
     OS << "shared";

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Wed Jun  4 08:06:39 2014
@@ -301,6 +301,10 @@ void OMPClauseProfiler::VisitOMPFirstpri
                                          const OMPFirstprivateClause *C) {
   VisitOMPClauseList(C);
 }
+void
+OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
+  VisitOMPClauseList(C);
+}
 void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
   VisitOMPClauseList(C);
 }

Modified: cfe/trunk/lib/Basic/OpenMPKinds.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/OpenMPKinds.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/OpenMPKinds.cpp (original)
+++ cfe/trunk/lib/Basic/OpenMPKinds.cpp Wed Jun  4 08:06:39 2014
@@ -86,6 +86,7 @@ unsigned clang::getOpenMPSimpleClauseTyp
   case OMPC_collapse:
   case OMPC_private:
   case OMPC_firstprivate:
+  case OMPC_lastprivate:
   case OMPC_shared:
   case OMPC_linear:
   case OMPC_aligned:
@@ -124,6 +125,7 @@ const char *clang::getOpenMPSimpleClause
   case OMPC_collapse:
   case OMPC_private:
   case OMPC_firstprivate:
+  case OMPC_lastprivate:
   case OMPC_shared:
   case OMPC_linear:
   case OMPC_aligned:

Modified: cfe/trunk/lib/Parse/ParseOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseOpenMP.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseOpenMP.cpp (original)
+++ cfe/trunk/lib/Parse/ParseOpenMP.cpp Wed Jun  4 08:06:39 2014
@@ -258,7 +258,7 @@ bool Parser::ParseOpenMPSimpleVarList(Op
 ///    clause:
 ///       if-clause | num_threads-clause | safelen-clause | default-clause |
 ///       private-clause | firstprivate-clause | shared-clause | linear-clause |
-///       aligned-clause | collapse-clause
+///       aligned-clause | collapse-clause | lastprivate-clause
 ///
 OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
                                      OpenMPClauseKind CKind, bool FirstClause) {
@@ -305,6 +305,7 @@ OMPClause *Parser::ParseOpenMPClause(Ope
     break;
   case OMPC_private:
   case OMPC_firstprivate:
+  case OMPC_lastprivate:
   case OMPC_shared:
   case OMPC_linear:
   case OMPC_aligned:
@@ -393,13 +394,15 @@ OMPClause *Parser::ParseOpenMPSimpleClau
                                          Tok.getLocation());
 }
 
-/// \brief Parsing of OpenMP clause 'private', 'firstprivate',
+/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
 /// 'shared', 'copyin', or 'reduction'.
 ///
 ///    private-clause:
 ///       'private' '(' list ')'
 ///    firstprivate-clause:
 ///       'firstprivate' '(' list ')'
+///    lastprivate-clause:
+///       'lastprivate' '(' list ')'
 ///    shared-clause:
 ///       'shared' '(' list ')'
 ///    linear-clause:

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Wed Jun  4 08:06:39 2014
@@ -832,6 +832,10 @@ StmtResult Sema::ActOnOpenMPParallelDire
                                       AStmt);
 }
 
+static bool isSimdDirective(OpenMPDirectiveKind DKind) {
+  return DKind == OMPD_simd; // FIXME: || DKind == OMPD_for_simd || ...
+}
+
 namespace {
 /// \brief Helper class for checking canonical form of the OpenMP loops and
 /// extracting iteration space of each loop in the loop nest, that will be used
@@ -1238,14 +1242,13 @@ static bool CheckOpenMPIterationSpace(Op
   // The loop iteration variable(s) in the associated for-loop(s) of a for or
   // parallel for construct may be listed in a private or lastprivate clause.
   DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var);
-  if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_linear &&
-      DVar.CKind != OMPC_threadprivate) {
+  if (isSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+      DVar.CKind != OMPC_linear && DVar.CKind != OMPC_lastprivate &&
+      (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
     // The loop iteration variable in the associated for-loop of a simd
     // construct with just one associated for-loop may be listed in a linear
     // clause with a constant-linear-step that is the increment of the
     // associated for-loop.
-    // FIXME: allow OMPC_lastprivate when it is ready.
-    assert(DKind == OMPD_simd && "DSA for non-simd loop vars");
     SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
         << getOpenMPClauseName(DVar.CKind);
     if (DVar.RefExpr)
@@ -1260,6 +1263,8 @@ static bool CheckOpenMPIterationSpace(Op
     DSA.addDSA(Var, nullptr, OMPC_private);
   }
 
+  assert(isSimdDirective(DKind) && "DSA for non-simd loop vars");
+
   // Check test-expr.
   HasErrors |= ISC.CheckCond(For->getCond());
 
@@ -1350,6 +1355,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprCl
   case OMPC_proc_bind:
   case OMPC_private:
   case OMPC_firstprivate:
+  case OMPC_lastprivate:
   case OMPC_shared:
   case OMPC_linear:
   case OMPC_aligned:
@@ -1524,6 +1530,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause
   case OMPC_collapse:
   case OMPC_private:
   case OMPC_firstprivate:
+  case OMPC_lastprivate:
   case OMPC_shared:
   case OMPC_linear:
   case OMPC_aligned:
@@ -1623,6 +1630,9 @@ Sema::ActOnOpenMPVarListClause(OpenMPCla
   case OMPC_firstprivate:
     Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
     break;
+  case OMPC_lastprivate:
+    Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+    break;
   case OMPC_shared:
     Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
     break;
@@ -1957,6 +1967,171 @@ OMPClause *Sema::ActOnOpenMPFirstprivate
                                        Vars);
 }
 
+OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
+                                              SourceLocation StartLoc,
+                                              SourceLocation LParenLoc,
+                                              SourceLocation EndLoc) {
+  SmallVector<Expr *, 8> Vars;
+  for (auto &RefExpr : VarList) {
+    assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
+    if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+      // It will be analyzed later.
+      Vars.push_back(RefExpr);
+      continue;
+    }
+
+    SourceLocation ELoc = RefExpr->getExprLoc();
+    // OpenMP [2.1, C/C++]
+    //  A list item is a variable name.
+    // OpenMP  [2.14.3.5, Restrictions, p.1]
+    //  A variable that is part of another variable (as an array or structure
+    //  element) cannot appear in a lastprivate clause.
+    DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
+    if (!DE || !isa<VarDecl>(DE->getDecl())) {
+      Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+      continue;
+    }
+    Decl *D = DE->getDecl();
+    VarDecl *VD = cast<VarDecl>(D);
+
+    QualType Type = VD->getType();
+    if (Type->isDependentType() || Type->isInstantiationDependentType()) {
+      // It will be analyzed later.
+      Vars.push_back(DE);
+      continue;
+    }
+
+    // OpenMP [2.14.3.5, Restrictions, C/C++, p.2]
+    //  A variable that appears in a lastprivate clause must not have an
+    //  incomplete type or a reference type.
+    if (RequireCompleteType(ELoc, Type,
+                            diag::err_omp_lastprivate_incomplete_type)) {
+      continue;
+    }
+    if (Type->isReferenceType()) {
+      Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+          << getOpenMPClauseName(OMPC_lastprivate) << Type;
+      bool IsDecl =
+          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+      Diag(VD->getLocation(),
+           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+          << VD;
+      continue;
+    }
+
+    // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
+    // in a Construct]
+    //  Variables with the predetermined data-sharing attributes may not be
+    //  listed in data-sharing attributes clauses, except for the cases
+    //  listed below.
+    //  A list item that is private within a parallel region, or that appears in
+    //  the reduction clause of a parallel construct, must not appear in a
+    //  lastprivate clause on a worksharing construct if any of the
+    //  corresponding worksharing regions ever binds to any of the corresponding
+    //  parallel regions.
+    //  TODO: Check implicit DSA for worksharing directives.
+    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+    if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
+        DVar.CKind != OMPC_firstprivate &&
+        (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
+      Diag(ELoc, diag::err_omp_wrong_dsa)
+          << getOpenMPClauseName(DVar.CKind)
+          << getOpenMPClauseName(OMPC_lastprivate);
+      if (DVar.RefExpr)
+        Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+            << getOpenMPClauseName(DVar.CKind);
+      else
+        Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
+            << getOpenMPClauseName(DVar.CKind);
+      continue;
+    }
+
+    // OpenMP [2.14.3.5, Restrictions, C++, p.1,2]
+    //  A variable of class type (or array thereof) that appears in a lastprivate
+    //  clause requires an accessible, unambiguous default constructor for the
+    //  class type, unless the list item is also specified in a firstprivate
+    //  clause.
+    //  A variable of class type (or array thereof) that appears in a
+    //  lastprivate clause requires an accessible, unambiguous copy assignment
+    //  operator for the class type.
+    while (Type.getNonReferenceType()->isArrayType())
+      Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr())
+                 ->getElementType();
+    CXXRecordDecl *RD = getLangOpts().CPlusPlus
+                            ? Type.getNonReferenceType()->getAsCXXRecordDecl()
+                            : nullptr;
+    if (RD) {
+      // FIXME: If a variable is also specified in a firstprivate clause, we may
+      // not require default constructor. This can be fixed after adding some
+      // directive allowing both firstprivate and lastprivate clauses (and this
+      // should be probably checked after all clauses are processed).
+      CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
+      PartialDiagnostic PD =
+          PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+      if (!CD || CheckConstructorAccess(
+                     ELoc, CD, InitializedEntity::InitializeTemporary(Type),
+                     CD->getAccess(), PD) == AR_inaccessible ||
+          CD->isDeleted()) {
+        Diag(ELoc, diag::err_omp_required_method)
+            << getOpenMPClauseName(OMPC_lastprivate) << 0;
+        bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+                      VarDecl::DeclarationOnly;
+        Diag(VD->getLocation(),
+             IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+            << VD;
+        Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+        continue;
+      }
+      MarkFunctionReferenced(ELoc, CD);
+      DiagnoseUseOfDecl(CD, ELoc);
+
+      CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
+      DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
+      if (!MD || CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
+          MD->isDeleted()) {
+        Diag(ELoc, diag::err_omp_required_method)
+            << getOpenMPClauseName(OMPC_lastprivate) << 2;
+        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, MD);
+      DiagnoseUseOfDecl(MD, ELoc);
+
+      CXXDestructorDecl *DD = RD->getDestructor();
+      if (DD) {
+        if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
+            DD->isDeleted()) {
+          Diag(ELoc, diag::err_omp_required_method)
+              << getOpenMPClauseName(OMPC_lastprivate) << 4;
+          bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+                        VarDecl::DeclarationOnly;
+          Diag(VD->getLocation(),
+               IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+              << VD;
+          Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+          continue;
+        }
+        MarkFunctionReferenced(ELoc, DD);
+        DiagnoseUseOfDecl(DD, ELoc);
+      }
+    }
+
+    DSAStack->addDSA(VD, DE, OMPC_lastprivate);
+    Vars.push_back(DE);
+  }
+
+  if (Vars.empty())
+    return nullptr;
+
+  return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+                                      Vars);
+}
+
 OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
                                          SourceLocation StartLoc,
                                          SourceLocation LParenLoc,

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Jun  4 08:06:39 2014
@@ -1394,6 +1394,18 @@ public:
                                                    EndLoc);
   }
 
+  /// \brief Build a new OpenMP 'lastprivate' clause.
+  ///
+  /// By default, performs semantic analysis to build the new OpenMP clause.
+  /// Subclasses may override this routine to provide different behavior.
+  OMPClause *RebuildOMPLastprivateClause(ArrayRef<Expr *> VarList,
+                                         SourceLocation StartLoc,
+                                         SourceLocation LParenLoc,
+                                         SourceLocation EndLoc) {
+    return getSema().ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc,
+                                                  EndLoc);
+  }
+
   /// \brief Build a new OpenMP 'shared' clause.
   ///
   /// By default, performs semantic analysis to build the new OpenMP clause.
@@ -6439,6 +6451,21 @@ OMPClause *TreeTransform<Derived>::Trans
       Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
 }
 
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPLastprivateClause(OMPLastprivateClause *C) {
+  llvm::SmallVector<Expr *, 16> Vars;
+  Vars.reserve(C->varlist_size());
+  for (auto *VE : C->varlists()) {
+    ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+    if (EVar.isInvalid())
+      return nullptr;
+    Vars.push_back(EVar.get());
+  }
+  return getDerived().RebuildOMPLastprivateClause(
+      Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
 template <typename Derived>
 OMPClause *
 TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Wed Jun  4 08:06:39 2014
@@ -1697,6 +1697,9 @@ OMPClause *OMPClauseReader::readClause()
   case OMPC_firstprivate:
     C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]);
     break;
+  case OMPC_lastprivate:
+    C = OMPLastprivateClause::CreateEmpty(Context, Record[Idx++]);
+    break;
   case OMPC_shared:
     C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
     break;
@@ -1765,6 +1768,16 @@ void OMPClauseReader::VisitOMPFirstpriva
   C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
   unsigned NumVars = C->varlist_size();
   SmallVector<Expr *, 16> Vars;
+  Vars.reserve(NumVars);
+  for (unsigned i = 0; i != NumVars; ++i)
+    Vars.push_back(Reader->Reader.ReadSubExpr());
+  C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
+  C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+  unsigned NumVars = C->varlist_size();
+  SmallVector<Expr *, 16> Vars;
   Vars.reserve(NumVars);
   for (unsigned i = 0; i != NumVars; ++i)
     Vars.push_back(Reader->Reader.ReadSubExpr());

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Wed Jun  4 08:06:39 2014
@@ -1721,6 +1721,13 @@ void OMPClauseWriter::VisitOMPFirstpriva
     Writer->Writer.AddStmt(VE);
 }
 
+void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
+  Record.push_back(C->varlist_size());
+  Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+  for (auto *VE : C->varlists())
+    Writer->Writer.AddStmt(VE);
+}
+
 void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
   Record.push_back(C->varlist_size());
   Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);

Modified: cfe/trunk/test/OpenMP/simd_ast_print.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/simd_ast_print.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/simd_ast_print.cpp (original)
+++ cfe/trunk/test/OpenMP/simd_ast_print.cpp Wed Jun  4 08:06:39 2014
@@ -35,8 +35,8 @@ template<class T> struct S {
 // CHECK: T res;
 // CHECK: T val;
 // CHECK: T lin = 0;
-    #pragma omp simd private(val)  safelen(7) linear(lin : -5)
-// CHECK-NEXT: #pragma omp simd private(val) safelen(7) linear(lin: -5)
+    #pragma omp simd private(val)  safelen(7) linear(lin : -5) lastprivate(res)
+// CHECK-NEXT: #pragma omp simd private(val) safelen(7) linear(lin: -5) lastprivate(res)
     for (T i = 7; i < m_a; ++i) {
       val = v[i-7] + m_a;
       res = val;
@@ -97,10 +97,10 @@ int main (int argc, char **argv) {
   for (int i=0; i < 2; ++i)*a=2;
 // CHECK-NEXT: for (int i = 0; i < 2; ++i)
 // CHECK-NEXT: *a = 2;
-#pragma omp simd private(argc, b) collapse(2) aligned(a : 4)
+#pragma omp simd private(argc, b),lastprivate(d,f) collapse(2) aligned(a : 4)
   for (int i = 0; i < 10; ++i)
   for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;}
-// CHECK-NEXT: #pragma omp simd private(argc,b) collapse(2) aligned(a: 4)
+// CHECK-NEXT: #pragma omp simd private(argc,b) lastprivate(d,f) collapse(2) aligned(a: 4)
 // CHECK-NEXT: for (int i = 0; i < 10; ++i)
 // CHECK-NEXT: for (int j = 0; j < 10; ++j) {
 // CHECK-NEXT: foo();

Added: cfe/trunk/test/OpenMP/simd_lastprivate_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/simd_lastprivate_messages.cpp?rev=210184&view=auto
==============================================================================
--- cfe/trunk/test/OpenMP/simd_lastprivate_messages.cpp (added)
+++ cfe/trunk/test/OpenMP/simd_lastprivate_messages.cpp Wed Jun  4 08:06:39 2014
@@ -0,0 +1,160 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+  return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+  mutable int a;
+public:
+  S2():a(0) { }
+  S2(S2 &s2):a(s2.a) { }
+  static float S2s; // expected-note {{predetermined as shared}}
+  static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note {{predetermined as shared}}
+const S2 b;
+const S2 ba[5];
+class S3 { // expected-note {{'S3' declared here}}
+  int a;
+  S3& operator =(const S3& s3);
+public:
+  S3():a(0) { }
+  S3(S3 &s3):a(s3.a) { }
+};
+const S3 c; // expected-note {{predetermined as shared}}
+const S3 ca[5]; // expected-note {{predetermined as shared}}
+extern const int f; // expected-note {{predetermined as shared}}
+class S4 { // expected-note {{'S4' declared here}}
+  int a;
+  S4();
+  S4(const S4 &s4);
+public:
+  S4(int v):a(v) { }
+};
+class S5 { // expected-note {{'S5' declared here}}
+  int a;
+  S5():a(0) {}
+public:
+  S5(const S5 &s5):a(s5.a) { }
+  S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template<class I, class C> int foomain(I argc, C **argv) {
+  I e(4);
+  I g(5);
+  int i;
+  int &j = i; // expected-note {{'j' defined here}}
+  #pragma omp simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate () // expected-error {{expected expression}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate (argc)
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate (S1) // expected-error {{'S1' does not refer to a value}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate (a, b) // expected-error {{lastprivate variable with incomplete type 'S1'}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate (argv[1]) // expected-error {{expected variable name}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate(e, g)
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd firstprivate(i) // expected-error {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp parallel
+  {
+    int v = 0;
+    int i;
+    #pragma omp simd lastprivate(i)
+    for (int k = 0; k < argc; ++k) { i = k; v += i; }
+  }
+  #pragma omp parallel shared(i)
+  #pragma omp parallel private(i)
+  #pragma omp simd lastprivate (j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
+  for (int k = 0; k < argc; ++k) ++k;
+  #pragma omp simd lastprivate(i)
+  for (int k = 0; k < argc; ++k) ++k;
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  const int d = 5; // expected-note {{predetermined as shared}}
+  const int da[5] = { 0 }; // expected-note {{predetermined as shared}}
+  S4 e(4); // expected-note {{'e' defined here}}
+  S5 g(5); // expected-note {{'g' defined here}}
+  S3 m; // expected-note {{'m' defined here}}
+  int i;
+  int &j = i; // expected-note {{'j' defined here}}
+  #pragma omp simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate () // expected-error {{expected expression}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate (argc)
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate (S1) // expected-error {{'S1' does not refer to a value}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate (a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate (argv[1]) // expected-error {{expected variable name}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate (2*2) // expected-error {{expected variable name}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(ba)
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(da) // expected-error {{shared variable cannot be lastprivate}}
+  for (i = 0; i < argc; ++i) foo();
+  int xa;
+  #pragma omp simd lastprivate(xa) // OK
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd firstprivate (g) // expected-error {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp simd lastprivate(i)
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp parallel private(xa) 
+  #pragma omp simd lastprivate(xa) // OK: may be lastprivate
+  for (i = 0; i < argc; ++i) foo();
+  #pragma omp parallel
+  #pragma omp simd lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
+  for (i = 0; i < argc; ++i) foo();
+  return 0;
+}

Modified: cfe/trunk/test/OpenMP/simd_loop_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/simd_loop_messages.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/simd_loop_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/simd_loop_messages.cpp Wed Jun  4 08:06:39 2014
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
 
 static int sii;
-#pragma omp threadprivate(sii)
+#pragma omp threadprivate(sii) // expected-note {{defined as threadprivate or thread local}}
 
 int test_iteration_spaces() {
   const int N = 100;
@@ -247,6 +247,7 @@ int test_iteration_spaces() {
 
   #pragma omp parallel
   {
+    // expected-error at +2 {{loop iteration variable may not be threadprivate or thread local}}
     #pragma omp simd
     for (sii = 0; sii < 10; sii+=1)
       c[sii] = a[sii];

Modified: cfe/trunk/test/OpenMP/simd_misc_messages.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/simd_misc_messages.c?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/simd_misc_messages.c (original)
+++ cfe/trunk/test/OpenMP/simd_misc_messages.c Wed Jun  4 08:06:39 2014
@@ -290,6 +290,17 @@ void test_linear()
   // expected-warning at +1 {{zero linear step (x and other variables in clause should probably be const)}}
   #pragma omp simd linear(x,y:0)
   for (i = 0; i < 16; ++i) ;
+
+  // expected-note at +2 {{defined as linear}}
+  // expected-error at +1 {{linear variable cannot be lastprivate}}
+  #pragma omp simd linear(x) lastprivate(x)
+  for (i = 0; i < 16; ++i) ;
+
+  // expected-note at +2 {{defined as lastprivate}}
+  // expected-error at +1 {{lastprivate variable cannot be linear}}
+  #pragma omp simd lastprivate(x) linear(x) 
+  for (i = 0; i < 16; ++i) ;
+
 }
 
 void test_aligned()
@@ -414,6 +425,40 @@ void test_firstprivate()
   for (i = 0; i < 16; ++i) ;
 }
 
+void test_lastprivate()
+{
+  int i;
+  // expected-error at +2 {{expected ')'}} expected-note at +2 {{to match this '('}}
+  // expected-error at +1 {{expected expression}}
+  #pragma omp simd lastprivate(
+  for (i = 0; i < 16; ++i) ;
+
+  // expected-error at +2 {{expected ')'}} expected-note at +2 {{to match this '('}}
+  // expected-error at +1 2 {{expected expression}}
+  #pragma omp simd lastprivate(,
+  for (i = 0; i < 16; ++i) ;
+  // expected-error at +1 2 {{expected expression}}
+  #pragma omp simd lastprivate(,)
+  for (i = 0; i < 16; ++i) ;
+  // expected-error at +1 {{expected expression}}
+  #pragma omp simd lastprivate()
+  for (i = 0; i < 16; ++i) ;
+  // expected-error at +1 {{expected expression}}
+  #pragma omp simd lastprivate(int)
+  for (i = 0; i < 16; ++i) ;
+  // expected-error at +1 {{expected variable name}}
+  #pragma omp simd lastprivate(0)
+  for (i = 0; i < 16; ++i) ;
+
+  int x, y, z;
+  #pragma omp simd lastprivate(x)
+  for (i = 0; i < 16; ++i) ;
+  #pragma omp simd lastprivate(x, y)
+  for (i = 0; i < 16; ++i) ;
+  #pragma omp simd lastprivate(x, y, z)
+  for (i = 0; i < 16; ++i) ;
+}
+
 void test_loop_messages()
 {
   float a[100], b[100], c[100];

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=210184&r1=210183&r2=210184&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Wed Jun  4 08:06:39 2014
@@ -1956,6 +1956,10 @@ void OMPClauseEnqueue::VisitOMPFirstpriv
                                         const OMPFirstprivateClause *C) {
   VisitOMPClauseList(C);
 }
+void OMPClauseEnqueue::VisitOMPLastprivateClause(
+                                        const OMPLastprivateClause *C) {
+  VisitOMPClauseList(C);
+}
 void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
   VisitOMPClauseList(C);
 }





More information about the cfe-commits mailing list