[OPENMP] Initial parsing and sema analysis for clause 'capture' in 'atomic' directive.
authorAlexey Bataev <a.bataev@hotmail.com>
Thu, 24 Jul 2014 06:46:57 +0000 (06:46 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Thu, 24 Jul 2014 06:46:57 +0000 (06:46 +0000)
llvm-svn: 213842

17 files changed:
clang/include/clang/AST/DataRecursiveASTVisitor.h
clang/include/clang/AST/OpenMPClause.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/OpenMPKinds.def
clang/include/clang/Sema/Sema.h
clang/lib/AST/StmtPrinter.cpp
clang/lib/AST/StmtProfile.cpp
clang/lib/Basic/OpenMPKinds.cpp
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/OpenMP/atomic_ast_print.cpp
clang/test/OpenMP/atomic_messages.cpp
clang/tools/libclang/CIndex.cpp

index 685f88f..388d57e 100644 (file)
@@ -2436,6 +2436,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) {
 }
 
 template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) {
+  return true;
+}
+
+template <typename Derived>
 template <typename T>
 bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
   for (auto *E : Node->varlists()) {
index c4816e0..c6c2022 100644 (file)
@@ -857,6 +857,36 @@ public:
   StmtRange children() { return StmtRange(); }
 };
 
+/// \brief This represents 'capture' clause in the '#pragma omp atomic'
+/// directive.
+///
+/// \code
+/// #pragma omp atomic capture
+/// \endcode
+/// In this example directive '#pragma omp atomic' has 'capture' clause.
+///
+class OMPCaptureClause : public OMPClause {
+public:
+  /// \brief Build 'capture' clause.
+  ///
+  /// \param StartLoc Starting location of the clause.
+  /// \param EndLoc Ending location of the clause.
+  ///
+  OMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc)
+      : OMPClause(OMPC_capture, StartLoc, EndLoc) {}
+
+  /// \brief Build an empty clause.
+  ///
+  OMPCaptureClause()
+      : OMPClause(OMPC_capture, SourceLocation(), SourceLocation()) {}
+
+  static bool classof(const OMPClause *T) {
+    return T->getClauseKind() == OMPC_capture;
+  }
+
+  StmtRange children() { return StmtRange(); }
+};
+
 /// \brief This represents clause 'private' in the '#pragma omp ...' directives.
 ///
 /// \code
index d6d1599..8de3101 100644 (file)
@@ -2458,6 +2458,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) {
 }
 
 template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) {
+  return true;
+}
+
+template <typename Derived>
 template <typename T>
 bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
   for (auto *E : Node->varlists()) {
index 9c6ffc0..c8c4e27 100644 (file)
@@ -7157,6 +7157,14 @@ def err_omp_atomic_write_not_expression_statement : Error<
 def err_omp_atomic_update_not_expression_statement : Error<
   "the statement for 'atomic%select{| update}0' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x',"
   " where x is an l-value expression with scalar type">;
+def err_omp_atomic_capture_not_expression_statement : Error<
+  "the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x',"
+  " where x and v are both l-value expressions with scalar type">;
+def err_omp_atomic_capture_not_compound_statement : Error<
+  "the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}',"
+  " '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}',"
+  " '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}'"
+  " where x is an l-value expression with scalar type">;
 def err_omp_atomic_several_clauses : Error<
   "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">;
 def note_omp_atomic_previous_clause : Note<
index fa0622d..dd1621e 100644 (file)
@@ -104,6 +104,7 @@ OPENMP_CLAUSE(flush, OMPFlushClause)
 OPENMP_CLAUSE(read, OMPReadClause)
 OPENMP_CLAUSE(write, OMPWriteClause)
 OPENMP_CLAUSE(update, OMPUpdateClause)
+OPENMP_CLAUSE(capture, OMPCaptureClause)
 
 // Clauses allowed for OpenMP directive 'parallel'.
 OPENMP_PARALLEL_CLAUSE(if)
@@ -205,6 +206,7 @@ OPENMP_TASK_CLAUSE(mergeable)
 OPENMP_ATOMIC_CLAUSE(read)
 OPENMP_ATOMIC_CLAUSE(write)
 OPENMP_ATOMIC_CLAUSE(update)
+OPENMP_ATOMIC_CLAUSE(capture)
 
 #undef OPENMP_SCHEDULE_KIND
 #undef OPENMP_PROC_BIND_KIND
index b61eec0..1fb42d1 100644 (file)
@@ -7491,6 +7491,9 @@ public:
   /// \brief Called on well-formed 'update' clause.
   OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc,
                                      SourceLocation EndLoc);
+  /// \brief Called on well-formed 'capture' clause.
+  OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc,
+                                      SourceLocation EndLoc);
 
   OMPClause *
   ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> Vars,
index 8e5018d..887f201 100644 (file)
@@ -673,6 +673,10 @@ void OMPClausePrinter::VisitOMPUpdateClause(OMPUpdateClause *) {
   OS << "update";
 }
 
+void OMPClausePrinter::VisitOMPCaptureClause(OMPCaptureClause *) {
+  OS << "capture";
+}
+
 template<typename T>
 void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
   for (typename T::varlist_iterator I = Node->varlist_begin(),
index e4fcbef..6d6e319 100644 (file)
@@ -316,6 +316,8 @@ void OMPClauseProfiler::VisitOMPWriteClause(const OMPWriteClause *) {}
 
 void OMPClauseProfiler::VisitOMPUpdateClause(const OMPUpdateClause *) {}
 
+void OMPClauseProfiler::VisitOMPCaptureClause(const OMPCaptureClause *) {}
+
 template<typename T>
 void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
   for (auto *I : Node->varlists())
index 4520e62..b125586 100644 (file)
@@ -111,6 +111,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
   case OMPC_read:
   case OMPC_write:
   case OMPC_update:
+  case OMPC_capture:
     break;
   }
   llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -173,6 +174,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
   case OMPC_read:
   case OMPC_write:
   case OMPC_update:
+  case OMPC_capture:
     break;
   }
   llvm_unreachable("Invalid OpenMP simple clause kind");
index 024b1ab..6c8fd64 100644 (file)
@@ -343,7 +343,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
 ///       lastprivate-clause | reduction-clause | proc_bind-clause |
 ///       schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
 ///       mergeable-clause | flush-clause | read-clause | write-clause |
-///       update-clause
+///       update-clause | capture-clause
 ///
 OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
                                      OpenMPClauseKind CKind, bool FirstClause) {
@@ -412,6 +412,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
   case OMPC_read:
   case OMPC_write:
   case OMPC_update:
+  case OMPC_capture:
     // OpenMP [2.7.1, Restrictions, p. 9]
     //  Only one ordered clause can appear on a loop directive.
     // OpenMP [2.7.1, Restrictions, C/C++, p. 4]
index 9c05e92..5bbed68 100644 (file)
@@ -2392,7 +2392,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
   SourceLocation AtomicKindLoc;
   for (auto *C : Clauses) {
     if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write ||
-        C->getClauseKind() == OMPC_update) {
+        C->getClauseKind() == OMPC_update ||
+        C->getClauseKind() == OMPC_capture) {
       if (AtomicKind != OMPC_unknown) {
         Diag(C->getLocStart(), diag::err_omp_atomic_several_clauses)
             << SourceRange(C->getLocStart(), C->getLocEnd());
@@ -2404,25 +2405,36 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
       }
     }
   }
+  auto Body = CS->getCapturedStmt();
   if (AtomicKind == OMPC_read) {
-    if (!isa<Expr>(CS->getCapturedStmt())) {
-      Diag(CS->getCapturedStmt()->getLocStart(),
+    if (!isa<Expr>(Body)) {
+      Diag(Body->getLocStart(),
            diag::err_omp_atomic_read_not_expression_statement);
       return StmtError();
     }
   } else if (AtomicKind == OMPC_write) {
-    if (!isa<Expr>(CS->getCapturedStmt())) {
-      Diag(CS->getCapturedStmt()->getLocStart(),
+    if (!isa<Expr>(Body)) {
+      Diag(Body->getLocStart(),
            diag::err_omp_atomic_write_not_expression_statement);
       return StmtError();
     }
   } else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) {
-    if (!isa<Expr>(CS->getCapturedStmt())) {
-      Diag(CS->getCapturedStmt()->getLocStart(),
+    if (!isa<Expr>(Body)) {
+      Diag(Body->getLocStart(),
            diag::err_omp_atomic_update_not_expression_statement)
           << (AtomicKind == OMPC_update);
       return StmtError();
     }
+  } else if (AtomicKind == OMPC_capture) {
+    if (isa<Expr>(Body) && !isa<BinaryOperator>(Body)) {
+      Diag(Body->getLocStart(),
+           diag::err_omp_atomic_capture_not_expression_statement);
+      return StmtError();
+    } else if (!isa<Expr>(Body) && !isa<CompoundStmt>(Body)) {
+      Diag(Body->getLocStart(),
+           diag::err_omp_atomic_capture_not_compound_statement);
+      return StmtError();
+    }
   }
 
   getCurFunction()->setHasBranchProtectedScope();
@@ -2472,6 +2484,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
   case OMPC_read:
   case OMPC_write:
   case OMPC_update:
+  case OMPC_capture:
   case OMPC_unknown:
     llvm_unreachable("Clause is not allowed.");
   }
@@ -2677,6 +2690,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
   case OMPC_read:
   case OMPC_write:
   case OMPC_update:
+  case OMPC_capture:
   case OMPC_unknown:
     llvm_unreachable("Clause is not allowed.");
   }
@@ -2795,6 +2809,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
   case OMPC_read:
   case OMPC_write:
   case OMPC_update:
+  case OMPC_capture:
   case OMPC_unknown:
     llvm_unreachable("Clause is not allowed.");
   }
@@ -2883,6 +2898,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
   case OMPC_update:
     Res = ActOnOpenMPUpdateClause(StartLoc, EndLoc);
     break;
+  case OMPC_capture:
+    Res = ActOnOpenMPCaptureClause(StartLoc, EndLoc);
+    break;
   case OMPC_if:
   case OMPC_final:
   case OMPC_num_threads:
@@ -2944,6 +2962,11 @@ OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc,
   return new (Context) OMPUpdateClause(StartLoc, EndLoc);
 }
 
+OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc,
+                                          SourceLocation EndLoc) {
+  return new (Context) OMPCaptureClause(StartLoc, EndLoc);
+}
+
 OMPClause *Sema::ActOnOpenMPVarListClause(
     OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
     SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
@@ -3000,6 +3023,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
   case OMPC_read:
   case OMPC_write:
   case OMPC_update:
+  case OMPC_capture:
   case OMPC_unknown:
     llvm_unreachable("Clause is not allowed.");
   }
index 16a424e..95b027a 100644 (file)
@@ -6782,6 +6782,13 @@ TreeTransform<Derived>::TransformOMPUpdateClause(OMPUpdateClause *C) {
 
 template <typename Derived>
 OMPClause *
+TreeTransform<Derived>::TransformOMPCaptureClause(OMPCaptureClause *C) {
+  // No need to rebuild this clause, no template-dependent parameters.
+  return C;
+}
+
+template <typename Derived>
+OMPClause *
 TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
   llvm::SmallVector<Expr *, 16> Vars;
   Vars.reserve(C->varlist_size());
index 78a4441..90987fe 100644 (file)
@@ -1724,6 +1724,9 @@ OMPClause *OMPClauseReader::readClause() {
   case OMPC_update:
     C = new (Context) OMPUpdateClause();
     break;
+  case OMPC_capture:
+    C = new (Context) OMPCaptureClause();
+    break;
   case OMPC_private:
     C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
     break;
@@ -1824,6 +1827,8 @@ void OMPClauseReader::VisitOMPWriteClause(OMPWriteClause *) {}
 
 void OMPClauseReader::VisitOMPUpdateClause(OMPUpdateClause *) {}
 
+void OMPClauseReader::VisitOMPCaptureClause(OMPCaptureClause *) {}
+
 void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
   C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
   unsigned NumVars = C->varlist_size();
index 3b8dbea..0ce5dfd 100644 (file)
@@ -1741,6 +1741,8 @@ void OMPClauseWriter::VisitOMPWriteClause(OMPWriteClause *) {}
 
 void OMPClauseWriter::VisitOMPUpdateClause(OMPUpdateClause *) {}
 
+void OMPClauseWriter::VisitOMPCaptureClause(OMPCaptureClause *) {}
+
 void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
   Record.push_back(C->varlist_size());
   Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
index ce8ebd5..31c0892 100644 (file)
@@ -8,6 +8,7 @@
 
 template <class T>
 T foo(T argc) {
+  T b = T();
   T a = T();
 #pragma omp atomic
   a++;
@@ -17,6 +18,13 @@ T foo(T argc) {
   a = argc + argc;
 #pragma omp atomic update
   a = a + argc;
+#pragma omp atomic capture
+  a = b++;
+#pragma omp atomic capture
+  {
+    a = b;
+    b++;
+  }
   return T();
 }
 
@@ -29,6 +37,13 @@ T foo(T argc) {
 // CHECK-NEXT: a = argc + argc;
 // CHECK-NEXT: #pragma omp atomic update
 // CHECK-NEXT: a = a + argc;
+// CHECK-NEXT: #pragma omp atomic capture
+// CHECK-NEXT: a = b++;
+// CHECK-NEXT: #pragma omp atomic capture
+// CHECK-NEXT: {
+// CHECK-NEXT: a = b;
+// CHECK-NEXT: b++;
+// CHECK-NEXT: }
 // CHECK: T a = T();
 // CHECK-NEXT: #pragma omp atomic
 // CHECK-NEXT: a++;
@@ -38,8 +53,16 @@ T foo(T argc) {
 // CHECK-NEXT: a = argc + argc;
 // CHECK-NEXT: #pragma omp atomic update
 // CHECK-NEXT: a = a + argc;
+// CHECK-NEXT: #pragma omp atomic capture
+// CHECK-NEXT: a = b++;
+// CHECK-NEXT: #pragma omp atomic capture
+// CHECK-NEXT: {
+// CHECK-NEXT: a = b;
+// CHECK-NEXT: b++;
+// CHECK-NEXT: }
 
 int main(int argc, char **argv) {
+  int b = 0;
   int a = 0;
 // CHECK: int a = 0;
 #pragma omp atomic
@@ -50,6 +73,13 @@ int main(int argc, char **argv) {
   a = argc + argc;
 #pragma omp atomic update
   a = a + argc;
+#pragma omp atomic capture
+  a = b++;
+#pragma omp atomic capture
+  {
+    a = b;
+    b++;
+  }
   // CHECK-NEXT: #pragma omp atomic
   // CHECK-NEXT: a++;
   // CHECK-NEXT: #pragma omp atomic read
@@ -58,6 +88,13 @@ int main(int argc, char **argv) {
   // CHECK-NEXT: a = argc + argc;
   // CHECK-NEXT: #pragma omp atomic update
   // CHECK-NEXT: a = a + argc;
+  // CHECK-NEXT: #pragma omp atomic capture
+  // CHECK-NEXT: a = b++;
+  // CHECK-NEXT: #pragma omp atomic capture
+  // CHECK-NEXT: {
+  // CHECK-NEXT: a = b;
+  // CHECK-NEXT: b++;
+  // CHECK-NEXT: }
   return foo(a);
 }
 
index d7856cc..66f7c9d 100644 (file)
@@ -4,14 +4,14 @@ int foo() {
 L1:
   foo();
 #pragma omp atomic
-// expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
   {
     foo();
     goto L1; // expected-error {{use of undeclared label 'L1'}}
   }
   goto L2; // expected-error {{use of undeclared label 'L2'}}
 #pragma omp atomic
-// expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
   {
     foo();
   L2:
@@ -26,7 +26,7 @@ T read() {
   T a, b = 0;
 // Test for atomic read
 #pragma omp atomic read
-// expected-error@+1 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both l-value expressions with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both l-value expressions with scalar type}}
   ;
 // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'read' clause}}
 #pragma omp atomic read read
@@ -39,7 +39,7 @@ int read() {
   int a, b = 0;
 // Test for atomic read
 #pragma omp atomic read
-// expected-error@+1 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both l-value expressions with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both l-value expressions with scalar type}}
   ;
 // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'read' clause}}
 #pragma omp atomic read read
@@ -53,7 +53,7 @@ T write() {
   T a, b = 0;
 // Test for atomic write
 #pragma omp atomic write
-// expected-error@+1 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is an l-value expression with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is an l-value expression with scalar type}}
   ;
 // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}}
 #pragma omp atomic write write
@@ -66,7 +66,7 @@ int write() {
   int a, b = 0;
 // Test for atomic write
 #pragma omp atomic write
-// expected-error@+1 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is an l-value expression with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic write' must be an expression statement of form 'x = expr;', where x is an l-value expression with scalar type}}
   ;
 // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'write' clause}}
 #pragma omp atomic write write
@@ -80,14 +80,14 @@ T update() {
   T a, b = 0;
 // Test for atomic update
 #pragma omp atomic update
-// expected-error@+1 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
   ;
 // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'update' clause}}
 #pragma omp atomic update update
   a += b;
 
 #pragma omp atomic
-// expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
   ;
 
   return T();
@@ -97,20 +97,53 @@ int update() {
   int a, b = 0;
 // Test for atomic update
 #pragma omp atomic update
-// expected-error@+1 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
   ;
 // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'update' clause}}
 #pragma omp atomic update update
   a += b;
 
 #pragma omp atomic
-// expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+  // expected-error@+1 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
   ;
 
   return update<int>();
 }
 
 template <class T>
+T capture() {
+  T a, b = 0;
+// Test for atomic capture
+#pragma omp atomic capture
+  // expected-error@+1 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+  ++a;
+#pragma omp atomic capture
+  // expected-error@+1 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+  ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture capture
+  a = ++b;
+
+  return T();
+}
+
+int capture() {
+  int a, b = 0;
+// Test for atomic capture
+#pragma omp atomic capture
+  // expected-error@+1 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+  ++a;
+#pragma omp atomic capture
+  // expected-error@+1 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+  ;
+// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture capture
+  a = ++b;
+
+  return capture<int>();
+}
+
+template <class T>
 T mixed() {
   T a, b = T();
 // expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
@@ -125,6 +158,10 @@ T mixed() {
 // expected-note@+1 2 {{'update' clause used here}}
 #pragma omp atomic update read
   a += b;
+// expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 2 {{'capture' clause used here}}
+#pragma omp atomic capture read
+  a = ++b;
   return T();
 }
 
@@ -142,7 +179,11 @@ int mixed() {
 // expected-note@+1 {{'write' clause used here}}
 #pragma omp atomic write update
   a = b;
-// expected-note@+1 {{in instantiation of function template specialization 'mixed<int>' requested here}}
+// expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}}
+// expected-note@+1 {{'write' clause used here}}
+#pragma omp atomic write capture
+  a = b;
+  // expected-note@+1 {{in instantiation of function template specialization 'mixed<int>' requested here}}
   return mixed<int>();
 }
 
index e5e7d7e..e5a438b 100644 (file)
@@ -1987,6 +1987,8 @@ void OMPClauseEnqueue::VisitOMPWriteClause(const OMPWriteClause *) {}
 
 void OMPClauseEnqueue::VisitOMPUpdateClause(const OMPUpdateClause *) {}
 
+void OMPClauseEnqueue::VisitOMPCaptureClause(const OMPCaptureClause *) {}
+
 template<typename T>
 void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
   for (const auto *I : Node->varlists())