r233785 - [OPENMP] Sema analysis for 'atomic capture' construct.

Alexey Bataev a.bataev at hotmail.com
Tue Mar 31 20:33:18 PDT 2015


Author: abataev
Date: Tue Mar 31 22:33:17 2015
New Revision: 233785

URL: http://llvm.org/viewvc/llvm-project?rev=233785&view=rev
Log:
[OPENMP] Sema analysis for 'atomic capture' construct.

Added sema checks for forms of expressions/statements allowed under control of 'atomic capture' directive + generation of helper objects for future codegen.

Modified:
    cfe/trunk/include/clang/AST/StmtOpenMP.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/Stmt.cpp
    cfe/trunk/lib/Sema/SemaOpenMP.cpp
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/test/OpenMP/atomic_messages.c
    cfe/trunk/test/OpenMP/atomic_messages.cpp

Modified: cfe/trunk/include/clang/AST/StmtOpenMP.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtOpenMP.h?rev=233785&r1=233784&r2=233785&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtOpenMP.h (original)
+++ cfe/trunk/include/clang/AST/StmtOpenMP.h Tue Mar 31 22:33:17 2015
@@ -1592,6 +1592,15 @@ class OMPAtomicDirective : public OMPExe
   /// second. Required for correct codegen of non-associative operations (like
   /// << or >>).
   bool IsXLHSInRHSPart;
+  /// \brief Used for 'atomic update' or 'atomic capture' constructs. They may
+  /// have atomic expressions of forms
+  /// \code
+  /// v = x; <update x>;
+  /// <update x>; v = x;
+  /// \endcode
+  /// This field is true for the first(postfix) form of the expression and false
+  /// otherwise.
+  bool IsPostfixUpdate;
 
   /// \brief Build directive with the given start and end location.
   ///
@@ -1603,7 +1612,7 @@ class OMPAtomicDirective : public OMPExe
                      unsigned NumClauses)
       : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic,
                                StartLoc, EndLoc, NumClauses, 5),
-        IsXLHSInRHSPart(false) {}
+        IsXLHSInRHSPart(false), IsPostfixUpdate(false) {}
 
   /// \brief Build an empty directive.
   ///
@@ -1613,7 +1622,7 @@ class OMPAtomicDirective : public OMPExe
       : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic,
                                SourceLocation(), SourceLocation(), NumClauses,
                                5),
-        IsXLHSInRHSPart(false) {}
+        IsXLHSInRHSPart(false), IsPostfixUpdate(false) {}
 
   /// \brief Set 'x' part of the associated expression/statement.
   void setX(Expr *X) { *std::next(child_begin()) = X; }
@@ -1644,10 +1653,12 @@ public:
   /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
   /// \param IsXLHSInRHSPart true if \a UE has the first form and false if the
   /// second.
+  /// \param IsPostfixUpdate true if original value of 'x' must be stored in
+  /// 'v', not an updated one.
   static OMPAtomicDirective *
   Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
          ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V,
-         Expr *E, Expr *UE, bool IsXLHSInRHSPart);
+         Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate);
 
   /// \brief Creates an empty directive with the place for \a NumClauses
   /// clauses.
@@ -1676,6 +1687,9 @@ public:
   /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' and false if it has form
   /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
   bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; }
+  /// \brief Return true if 'v' expression must be updated to original value of
+  /// 'x', false if 'v' must be updated to the new value of 'x'.
+  bool isPostfixUpdate() const { return IsPostfixUpdate; }
   /// \brief Get 'v' part of the associated expression/statement.
   Expr *getV() { return cast_or_null<Expr>(*std::next(child_begin(), 3)); }
   const Expr *getV() const {

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=233785&r1=233784&r2=233785&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Mar 31 22:33:17 2015
@@ -7495,6 +7495,8 @@ def err_omp_atomic_capture_not_compound_
   " '{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 note_omp_atomic_capture: Note<
+  "%select{expected assignment expression|expected compound statement|expected exactly two expression statements|expected in right hand side of the first expression}0">;
 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<

Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=233785&r1=233784&r2=233785&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Tue Mar 31 22:33:17 2015
@@ -2007,11 +2007,10 @@ OMPOrderedDirective *OMPOrderedDirective
   return new (Mem) OMPOrderedDirective();
 }
 
-OMPAtomicDirective *
-OMPAtomicDirective::Create(const ASTContext &C, SourceLocation StartLoc,
-                           SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
-                           Stmt *AssociatedStmt, Expr *X, Expr *V, Expr *E,
-                           Expr *UE, bool IsXLHSInRHSPart) {
+OMPAtomicDirective *OMPAtomicDirective::Create(
+    const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+    ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V,
+    Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate) {
   unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective),
                                            llvm::alignOf<OMPClause *>());
   void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
@@ -2025,6 +2024,7 @@ OMPAtomicDirective::Create(const ASTCont
   Dir->setExpr(E);
   Dir->setUpdateExpr(UE);
   Dir->IsXLHSInRHSPart = IsXLHSInRHSPart;
+  Dir->IsPostfixUpdate = IsPostfixUpdate;
   return Dir;
 }
 

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=233785&r1=233784&r2=233785&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Tue Mar 31 22:33:17 2015
@@ -3295,18 +3295,22 @@ class OpenMPAtomicUpdateChecker {
   bool IsXLHSInRHSPart;
   BinaryOperatorKind Op;
   SourceLocation OpLoc;
+  /// \brief true if the source expression is a postfix unary operation, false
+  /// if it is a prefix unary operation.
+  bool IsPostfixUpdate;
 
 public:
   OpenMPAtomicUpdateChecker(Sema &SemaRef)
       : SemaRef(SemaRef), X(nullptr), E(nullptr), UpdateExpr(nullptr),
-        IsXLHSInRHSPart(false), Op(BO_PtrMemD) {}
+        IsXLHSInRHSPart(false), Op(BO_PtrMemD), IsPostfixUpdate(false) {}
   /// \brief Check specified statement that it is suitable for 'atomic update'
   /// constructs and extract 'x', 'expr' and Operation from the original
-  /// expression.
+  /// expression. If DiagId and NoteId == 0, then only check is performed
+  /// without error notification.
   /// \param DiagId Diagnostic which should be emitted if error is found.
   /// \param NoteId Diagnostic note for the main error message.
   /// \return true if statement is not an update expression, false otherwise.
-  bool checkStatement(Stmt *S, unsigned DiagId, unsigned NoteId);
+  bool checkStatement(Stmt *S, unsigned DiagId = 0, unsigned NoteId = 0);
   /// \brief Return the 'x' lvalue part of the source atomic expression.
   Expr *getX() const { return X; }
   /// \brief Return the 'expr' rvalue part of the source atomic expression.
@@ -3319,9 +3323,13 @@ public:
   /// false otherwise.
   bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; }
 
+  /// \brief true if the source expression is a postfix unary operation, false
+  /// if it is a prefix unary operation.
+  bool isPostfixUpdate() const { return IsPostfixUpdate; }
+
 private:
-  bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId,
-                            unsigned NoteId);
+  bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId = 0,
+                            unsigned NoteId = 0);
 };
 } // namespace
 
@@ -3383,7 +3391,7 @@ bool OpenMPAtomicUpdateChecker::checkBin
     NoteRange = SourceRange(NoteLoc, NoteLoc);
     ErrorFound = NotAnAssignmentOp;
   }
-  if (ErrorFound != NoError) {
+  if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) {
     SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange;
     SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
     return true;
@@ -3427,6 +3435,7 @@ bool OpenMPAtomicUpdateChecker::checkSta
                  dyn_cast<UnaryOperator>(AtomicBody->IgnoreParenImpCasts())) {
         // Check for Unary Operation
         if (AtomicUnaryOp->isIncrementDecrementOp()) {
+          IsPostfixUpdate = AtomicUnaryOp->isPostfix();
           Op = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub;
           OpLoc = AtomicUnaryOp->getOperatorLoc();
           X = AtomicUnaryOp->getSubExpr();
@@ -3454,7 +3463,7 @@ bool OpenMPAtomicUpdateChecker::checkSta
     NoteLoc = ErrorLoc = S->getLocStart();
     NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
   }
-  if (ErrorFound != NoError) {
+  if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) {
     SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange;
     SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
     return true;
@@ -3493,7 +3502,6 @@ StmtResult Sema::ActOnOpenMPAtomicDirect
   // top and a single exit at the bottom.
   // The point of exit cannot be a branch out of the structured block.
   // longjmp() and throw() must not violate the entry/exit criteria.
-  // TODO further analysis of associated statements and clauses.
   OpenMPClauseKind AtomicKind = OMPC_unknown;
   SourceLocation AtomicKindLoc;
   for (auto *C : Clauses) {
@@ -3521,6 +3529,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirect
   Expr *E = nullptr;
   Expr *UE = nullptr;
   bool IsXLHSInRHSPart = false;
+  bool IsPostfixUpdate = false;
   // OpenMP [2.12.6, atomic Construct]
   // In the next expressions:
   // * x and v (as applicable) are both l-value expressions with scalar type.
@@ -3543,14 +3552,14 @@ StmtResult Sema::ActOnOpenMPAtomicDirect
   // expr or subexpressions of expr.
   // * For forms that allow multiple occurrences of x, the number of times
   // that x is evaluated is unspecified.
-  enum {
-    NotAnExpression,
-    NotAnAssignmentOp,
-    NotAScalarType,
-    NotAnLValue,
-    NoError
-  } ErrorFound = NoError;
   if (AtomicKind == OMPC_read) {
+    enum {
+      NotAnExpression,
+      NotAnAssignmentOp,
+      NotAScalarType,
+      NotAnLValue,
+      NoError
+    } ErrorFound = NoError;
     SourceLocation ErrorLoc, NoteLoc;
     SourceRange ErrorRange, NoteRange;
     // If clause is read:
@@ -3606,6 +3615,13 @@ StmtResult Sema::ActOnOpenMPAtomicDirect
     } else if (CurContext->isDependentContext())
       V = X = nullptr;
   } else if (AtomicKind == OMPC_write) {
+    enum {
+      NotAnExpression,
+      NotAnAssignmentOp,
+      NotAScalarType,
+      NotAnLValue,
+      NoError
+    } ErrorFound = NoError;
     SourceLocation ErrorLoc, NoteLoc;
     SourceRange ErrorRange, NoteRange;
     // If clause is write:
@@ -3682,21 +3698,218 @@ StmtResult Sema::ActOnOpenMPAtomicDirect
       IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
     }
   } 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();
+    enum {
+      NotAnAssignmentOp,
+      NotACompoundStatement,
+      NotTwoSubstatements,
+      NotASpecificExpression,
+      NoError
+    } ErrorFound = NoError;
+    SourceLocation ErrorLoc, NoteLoc;
+    SourceRange ErrorRange, NoteRange;
+    if (auto *AtomicBody = dyn_cast<Expr>(Body)) {
+      // If clause is a capture:
+      //  v = x++;
+      //  v = x--;
+      //  v = ++x;
+      //  v = --x;
+      //  v = x binop= expr;
+      //  v = x = x binop expr;
+      //  v = x = expr binop x;
+      auto *AtomicBinOp =
+          dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts());
+      if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
+        V = AtomicBinOp->getLHS();
+        Body = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
+        OpenMPAtomicUpdateChecker Checker(*this);
+        if (Checker.checkStatement(
+                Body, diag::err_omp_atomic_capture_not_expression_statement,
+                diag::note_omp_atomic_update))
+          return StmtError();
+        E = Checker.getExpr();
+        X = Checker.getX();
+        UE = Checker.getUpdateExpr();
+        IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
+        IsPostfixUpdate = Checker.isPostfixUpdate();
+      } else {
+        ErrorLoc = AtomicBody->getExprLoc();
+        ErrorRange = AtomicBody->getSourceRange();
+        NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
+                              : AtomicBody->getExprLoc();
+        NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
+                                : AtomicBody->getSourceRange();
+        ErrorFound = NotAnAssignmentOp;
+      }
+      if (ErrorFound != NoError) {
+        Diag(ErrorLoc, diag::err_omp_atomic_capture_not_expression_statement)
+            << ErrorRange;
+        Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange;
+        return StmtError();
+      } else if (CurContext->isDependentContext()) {
+        UE = V = E = X = nullptr;
+      }
+    } else {
+      // If clause is a capture:
+      //  { v = x; x = expr; }
+      //  { v = x; x++; }
+      //  { v = x; x--; }
+      //  { v = x; ++x; }
+      //  { v = x; --x; }
+      //  { v = x; x binop= expr; }
+      //  { v = x; x = x binop expr; }
+      //  { v = x; x = expr binop x; }
+      //  { x++; v = x; }
+      //  { x--; v = x; }
+      //  { ++x; v = x; }
+      //  { --x; v = x; }
+      //  { x binop= expr; v = x; }
+      //  { x = x binop expr; v = x; }
+      //  { x = expr binop x; v = x; }
+      if (auto *CS = dyn_cast<CompoundStmt>(Body)) {
+        // Check that this is { expr1; expr2; }
+        if (CS->size() == 2) {
+          auto *First = CS->body_front();
+          auto *Second = CS->body_back();
+          if (auto *EWC = dyn_cast<ExprWithCleanups>(First))
+            First = EWC->getSubExpr()->IgnoreParenImpCasts();
+          if (auto *EWC = dyn_cast<ExprWithCleanups>(Second))
+            Second = EWC->getSubExpr()->IgnoreParenImpCasts();
+          // Need to find what subexpression is 'v' and what is 'x'.
+          OpenMPAtomicUpdateChecker Checker(*this);
+          bool IsUpdateExprFound = !Checker.checkStatement(Second);
+          BinaryOperator *BinOp = nullptr;
+          if (IsUpdateExprFound) {
+            BinOp = dyn_cast<BinaryOperator>(First);
+            IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign;
+          }
+          if (IsUpdateExprFound && !CurContext->isDependentContext()) {
+            //  { v = x; x++; }
+            //  { v = x; x--; }
+            //  { v = x; ++x; }
+            //  { v = x; --x; }
+            //  { v = x; x binop= expr; }
+            //  { v = x; x = x binop expr; }
+            //  { v = x; x = expr binop x; }
+            // Check that the first expression has form v = x.
+            auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
+            llvm::FoldingSetNodeID XId, PossibleXId;
+            Checker.getX()->Profile(XId, Context, /*Canonical=*/true);
+            PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true);
+            IsUpdateExprFound = XId == PossibleXId;
+            if (IsUpdateExprFound) {
+              V = BinOp->getLHS();
+              X = Checker.getX();
+              E = Checker.getExpr();
+              UE = Checker.getUpdateExpr();
+              IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
+              IsPostfixUpdate = Checker.isPostfixUpdate();
+            }
+          }
+          if (!IsUpdateExprFound) {
+            IsUpdateExprFound = !Checker.checkStatement(First);
+            BinOp = nullptr;
+            if (IsUpdateExprFound) {
+              BinOp = dyn_cast<BinaryOperator>(Second);
+              IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign;
+            }
+            if (IsUpdateExprFound && !CurContext->isDependentContext()) {
+              //  { x++; v = x; }
+              //  { x--; v = x; }
+              //  { ++x; v = x; }
+              //  { --x; v = x; }
+              //  { x binop= expr; v = x; }
+              //  { x = x binop expr; v = x; }
+              //  { x = expr binop x; v = x; }
+              // Check that the second expression has form v = x.
+              auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
+              llvm::FoldingSetNodeID XId, PossibleXId;
+              Checker.getX()->Profile(XId, Context, /*Canonical=*/true);
+              PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true);
+              IsUpdateExprFound = XId == PossibleXId;
+              if (IsUpdateExprFound) {
+                V = BinOp->getLHS();
+                X = Checker.getX();
+                E = Checker.getExpr();
+                UE = Checker.getUpdateExpr();
+                IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
+                IsPostfixUpdate = Checker.isPostfixUpdate();
+              }
+            }
+          }
+          if (!IsUpdateExprFound) {
+            //  { v = x; x = expr; }
+            auto *FirstBinOp = dyn_cast<BinaryOperator>(First);
+            if (!FirstBinOp || FirstBinOp->getOpcode() != BO_Assign) {
+              ErrorFound = NotAnAssignmentOp;
+              NoteLoc = ErrorLoc = FirstBinOp ? FirstBinOp->getOperatorLoc()
+                                              : First->getLocStart();
+              NoteRange = ErrorRange = FirstBinOp
+                                           ? FirstBinOp->getSourceRange()
+                                           : SourceRange(ErrorLoc, ErrorLoc);
+            } else {
+              auto *SecondBinOp = dyn_cast<BinaryOperator>(Second);
+              if (!SecondBinOp || SecondBinOp->getOpcode() != BO_Assign) {
+                ErrorFound = NotAnAssignmentOp;
+                NoteLoc = ErrorLoc = SecondBinOp ? SecondBinOp->getOperatorLoc()
+                                                 : Second->getLocStart();
+                NoteRange = ErrorRange = SecondBinOp
+                                             ? SecondBinOp->getSourceRange()
+                                             : SourceRange(ErrorLoc, ErrorLoc);
+              } else {
+                auto *PossibleXRHSInFirst =
+                    FirstBinOp->getRHS()->IgnoreParenImpCasts();
+                auto *PossibleXLHSInSecond =
+                    SecondBinOp->getLHS()->IgnoreParenImpCasts();
+                llvm::FoldingSetNodeID X1Id, X2Id;
+                PossibleXRHSInFirst->Profile(X1Id, Context, /*Canonical=*/true);
+                PossibleXLHSInSecond->Profile(X2Id, Context,
+                                              /*Canonical=*/true);
+                IsUpdateExprFound = X1Id == X2Id;
+                if (IsUpdateExprFound) {
+                  V = FirstBinOp->getLHS();
+                  X = SecondBinOp->getLHS();
+                  E = SecondBinOp->getRHS();
+                  UE = nullptr;
+                  IsXLHSInRHSPart = false;
+                  IsPostfixUpdate = true;
+                } else {
+                  ErrorFound = NotASpecificExpression;
+                  ErrorLoc = FirstBinOp->getExprLoc();
+                  ErrorRange = FirstBinOp->getSourceRange();
+                  NoteLoc = SecondBinOp->getLHS()->getExprLoc();
+                  NoteRange = SecondBinOp->getRHS()->getSourceRange();
+                }
+              }
+            }
+          }
+        } else {
+          NoteLoc = ErrorLoc = Body->getLocStart();
+          NoteRange = ErrorRange =
+              SourceRange(Body->getLocStart(), Body->getLocStart());
+          ErrorFound = NotTwoSubstatements;
+        }
+      } else {
+        NoteLoc = ErrorLoc = Body->getLocStart();
+        NoteRange = ErrorRange =
+            SourceRange(Body->getLocStart(), Body->getLocStart());
+        ErrorFound = NotACompoundStatement;
+      }
+      if (ErrorFound != NoError) {
+        Diag(ErrorLoc, diag::err_omp_atomic_capture_not_compound_statement)
+            << ErrorRange;
+        Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange;
+        return StmtError();
+      } else if (CurContext->isDependentContext()) {
+        UE = V = E = X = nullptr;
+      }
     }
   }
 
   getCurFunction()->setHasBranchProtectedScope();
 
   return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
-                                    X, V, E, UE, IsXLHSInRHSPart);
+                                    X, V, E, UE, IsXLHSInRHSPart,
+                                    IsPostfixUpdate);
 }
 
 StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=233785&r1=233784&r2=233785&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Mar 31 22:33:17 2015
@@ -2162,6 +2162,7 @@ void ASTStmtReader::VisitOMPAtomicDirect
   D->setExpr(Reader.ReadSubExpr());
   D->setUpdateExpr(Reader.ReadSubExpr());
   D->IsXLHSInRHSPart = Record[Idx++] != 0;
+  D->IsPostfixUpdate = Record[Idx++] != 0;
 }
 
 void ASTStmtReader::VisitOMPTargetDirective(OMPTargetDirective *D) {

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=233785&r1=233784&r2=233785&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Mar 31 22:33:17 2015
@@ -2010,6 +2010,7 @@ void ASTStmtWriter::VisitOMPAtomicDirect
   Writer.AddStmt(D->getExpr());
   Writer.AddStmt(D->getUpdateExpr());
   Record.push_back(D->isXLHSInRHSPart() ? 1 : 0);
+  Record.push_back(D->isPostfixUpdate() ? 1 : 0);
   Code = serialization::STMT_OMP_ATOMIC_DIRECTIVE;
 }
 

Modified: cfe/trunk/test/OpenMP/atomic_messages.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/atomic_messages.c?rev=233785&r1=233784&r2=233785&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/atomic_messages.c (original)
+++ cfe/trunk/test/OpenMP/atomic_messages.c Tue Mar 31 22:33:17 2015
@@ -193,3 +193,175 @@ int updateint() {
   return 0;
 }
 
+int captureint() {
+  int a = 0, b = 0, c = 0;
+// Test for atomic capture
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected compound statement}}
+  ;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  foo();
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected built-in binary or unary operator}}
+  a = b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = b || a;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected one of '+', '*', '-', '/', '&', '^', '|', '<<', or '>>' built-in operations}}
+  b = a = a && b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = (float)a + b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = 2 * b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = b + *&a;
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected exactly two expression statements}}
+  { a = b; }
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected exactly two expression statements}}
+  {}
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected in right hand side of the first expression}}
+  {a = b;a = b;}
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected in right hand side of the first expression}}
+  {a = b; a = b || a;}
+#pragma omp atomic capture
+  {b = a; a = a && b;}
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = (float)a + b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = 2 * b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = b + *&a;
+#pragma omp atomic capture
+  c = *&a = *&a +  2;
+#pragma omp atomic capture
+  c = a++;
+#pragma omp atomic capture
+  c = ++a;
+#pragma omp atomic capture
+  c = a--;
+#pragma omp atomic capture
+  c = --a;
+#pragma omp atomic capture
+  c = a += b;
+#pragma omp atomic capture
+  c = a %= b;
+#pragma omp atomic capture
+  c = a *= b;
+#pragma omp atomic capture
+  c = a -= b;
+#pragma omp atomic capture
+  c = a /= b;
+#pragma omp atomic capture
+  c = a &= b;
+#pragma omp atomic capture
+  c = a ^= b;
+#pragma omp atomic capture
+  c = a |= b;
+#pragma omp atomic capture
+  c = a <<= b;
+#pragma omp atomic capture
+  c = a >>= b;
+#pragma omp atomic capture
+  c = a = b + a;
+#pragma omp atomic capture
+  c = a = a * b;
+#pragma omp atomic capture
+  c = a = b - a;
+#pragma omp atomic capture
+  c = a = a / b;
+#pragma omp atomic capture
+  c = a = b & a;
+#pragma omp atomic capture
+  c = a = a ^ b;
+#pragma omp atomic capture
+  c = a = b | a;
+#pragma omp atomic capture
+  c = a = a << b;
+#pragma omp atomic capture
+  c = a = b >> a;
+#pragma omp atomic capture
+  { c = *&a; *&a = *&a +  2;}
+#pragma omp atomic capture
+  { *&a = *&a +  2; c = *&a;}
+#pragma omp atomic capture
+  {c = a; a++;}
+#pragma omp atomic capture
+  {++a;c = a;}
+#pragma omp atomic capture
+  {c = a;a--;}
+#pragma omp atomic capture
+  {--a;c = a;}
+#pragma omp atomic capture
+  {c = a; a += b;}
+#pragma omp atomic capture
+  {a %= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a *= b;}
+#pragma omp atomic capture
+  {a -= b;c = a;}
+#pragma omp atomic capture
+  {c = a; a /= b;}
+#pragma omp atomic capture
+  {a &= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a ^= b;}
+#pragma omp atomic capture
+  {a |= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a <<= b;}
+#pragma omp atomic capture
+  {a >>= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b + a;}
+#pragma omp atomic capture
+  {a = a * b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b - a;}
+#pragma omp atomic capture
+  {a = a / b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b & a;}
+#pragma omp atomic capture
+  {a = a ^ b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b | a;}
+#pragma omp atomic capture
+  {a = a << b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b >> a;}
+#pragma omp atomic capture
+  {c = a; a = foo();}
+  // expected-error at +1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture capture
+  b = a /= b;
+
+  return 0;
+}
+

Modified: cfe/trunk/test/OpenMP/atomic_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/atomic_messages.cpp?rev=233785&r1=233784&r2=233785&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/atomic_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/atomic_messages.cpp Tue Mar 31 22:33:17 2015
@@ -152,7 +152,7 @@ int write() {
 
 template <class T>
 T update() {
-  T a, b = 0;
+  T a = 0, b = 0, c = 0;
 // Test for atomic update
 #pragma omp atomic update
   // expected-error at +2 {{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}}
@@ -332,34 +332,347 @@ int update() {
 
 template <class T>
 T capture() {
-  T a, b = 0;
+  T a = 0, b = 0, c = 0;
 // Test for atomic capture
 #pragma omp atomic capture
-  // expected-error at +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 at +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 at +2 {{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-note at +1 {{expected compound statement}}
   ;
-// expected-error at +1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  foo();
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected built-in binary or unary operator}}
+  a = b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = b || a;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected one of '+', '*', '-', '/', '&', '^', '|', '<<', or '>>' built-in operations}}
+  b = a = a && b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = (float)a + b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = 2 * b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = b + *&a;
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected exactly two expression statements}}
+  { a = b; }
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected exactly two expression statements}}
+  {}
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected in right hand side of the first expression}}
+  {a = b;a = b;}
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected in right hand side of the first expression}}
+  {a = b; a = b || a;}
+#pragma omp atomic capture
+  {b = a; a = a && b;}
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = (float)a + b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = 2 * b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = b + *&a;
+#pragma omp atomic capture
+  c = *&a = *&a +  2;
+#pragma omp atomic capture
+  c = a++;
+#pragma omp atomic capture
+  c = ++a;
+#pragma omp atomic capture
+  c = a--;
+#pragma omp atomic capture
+  c = --a;
+#pragma omp atomic capture
+  c = a += b;
+#pragma omp atomic capture
+  c = a %= b;
+#pragma omp atomic capture
+  c = a *= b;
+#pragma omp atomic capture
+  c = a -= b;
+#pragma omp atomic capture
+  c = a /= b;
+#pragma omp atomic capture
+  c = a &= b;
+#pragma omp atomic capture
+  c = a ^= b;
+#pragma omp atomic capture
+  c = a |= b;
+#pragma omp atomic capture
+  c = a <<= b;
+#pragma omp atomic capture
+  c = a >>= b;
+#pragma omp atomic capture
+  c = a = b + a;
+#pragma omp atomic capture
+  c = a = a * b;
+#pragma omp atomic capture
+  c = a = b - a;
+#pragma omp atomic capture
+  c = a = a / b;
+#pragma omp atomic capture
+  c = a = b & a;
+#pragma omp atomic capture
+  c = a = a ^ b;
+#pragma omp atomic capture
+  c = a = b | a;
+#pragma omp atomic capture
+  c = a = a << b;
+#pragma omp atomic capture
+  c = a = b >> a;
+#pragma omp atomic capture
+  { c = *&a; *&a = *&a +  2;}
+#pragma omp atomic capture
+  { *&a = *&a +  2; c = *&a;}
+#pragma omp atomic capture
+  {c = a; a++;}
+#pragma omp atomic capture
+  {++a;c = a;}
+#pragma omp atomic capture
+  {c = a;a--;}
+#pragma omp atomic capture
+  {--a;c = a;}
+#pragma omp atomic capture
+  {c = a; a += b;}
+#pragma omp atomic capture
+  {a %= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a *= b;}
+#pragma omp atomic capture
+  {a -= b;c = a;}
+#pragma omp atomic capture
+  {c = a; a /= b;}
+#pragma omp atomic capture
+  {a &= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a ^= b;}
+#pragma omp atomic capture
+  {a |= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a <<= b;}
+#pragma omp atomic capture
+  {a >>= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b + a;}
+#pragma omp atomic capture
+  {a = a * b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b - a;}
+#pragma omp atomic capture
+  {a = a / b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b & a;}
+#pragma omp atomic capture
+  {a = a ^ b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b | a;}
+#pragma omp atomic capture
+  {a = a << b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b >> a;}
+#pragma omp atomic capture
+  {c = a; a = foo();}
+  // expected-error at +1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
 #pragma omp atomic capture capture
-  a = ++b;
+  b = a /= b;
 
   return T();
 }
 
 int capture() {
-  int a, b = 0;
+  int a = 0, b = 0, c = 0;
 // Test for atomic capture
 #pragma omp atomic capture
-  // expected-error at +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 at +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 at +2 {{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-note at +1 {{expected compound statement}}
   ;
-// expected-error at +1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  foo();
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected built-in binary or unary operator}}
+  a = b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = b || a;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected one of '+', '*', '-', '/', '&', '^', '|', '<<', or '>>' built-in operations}}
+  b = a = a && b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = (float)a + b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = 2 * b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected assignment expression}}
+  a = b + *&a;
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected exactly two expression statements}}
+  { a = b; }
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected exactly two expression statements}}
+  {}
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected in right hand side of the first expression}}
+  {a = b;a = b;}
+#pragma omp atomic capture
+  // expected-error at +2 {{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-note at +1 {{expected in right hand side of the first expression}}
+  {a = b; a = b || a;}
+#pragma omp atomic capture
+  {b = a; a = a && b;}
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = (float)a + b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = 2 * b;
+#pragma omp atomic capture
+  // expected-error at +2 {{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}}
+  // expected-note at +1 {{expected in right hand side of expression}}
+  b = a = b + *&a;
+#pragma omp atomic capture
+  c = *&a = *&a +  2;
+#pragma omp atomic capture
+  c = a++;
+#pragma omp atomic capture
+  c = ++a;
+#pragma omp atomic capture
+  c = a--;
+#pragma omp atomic capture
+  c = --a;
+#pragma omp atomic capture
+  c = a += b;
+#pragma omp atomic capture
+  c = a %= b;
+#pragma omp atomic capture
+  c = a *= b;
+#pragma omp atomic capture
+  c = a -= b;
+#pragma omp atomic capture
+  c = a /= b;
+#pragma omp atomic capture
+  c = a &= b;
+#pragma omp atomic capture
+  c = a ^= b;
+#pragma omp atomic capture
+  c = a |= b;
+#pragma omp atomic capture
+  c = a <<= b;
+#pragma omp atomic capture
+  c = a >>= b;
+#pragma omp atomic capture
+  c = a = b + a;
+#pragma omp atomic capture
+  c = a = a * b;
+#pragma omp atomic capture
+  c = a = b - a;
+#pragma omp atomic capture
+  c = a = a / b;
+#pragma omp atomic capture
+  c = a = b & a;
+#pragma omp atomic capture
+  c = a = a ^ b;
+#pragma omp atomic capture
+  c = a = b | a;
+#pragma omp atomic capture
+  c = a = a << b;
+#pragma omp atomic capture
+  c = a = b >> a;
+#pragma omp atomic capture
+  { c = *&a; *&a = *&a +  2;}
+#pragma omp atomic capture
+  { *&a = *&a +  2; c = *&a;}
+#pragma omp atomic capture
+  {c = a; a++;}
+#pragma omp atomic capture
+  {++a;c = a;}
+#pragma omp atomic capture
+  {c = a;a--;}
+#pragma omp atomic capture
+  {--a;c = a;}
+#pragma omp atomic capture
+  {c = a; a += b;}
+#pragma omp atomic capture
+  {a %= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a *= b;}
+#pragma omp atomic capture
+  {a -= b;c = a;}
+#pragma omp atomic capture
+  {c = a; a /= b;}
+#pragma omp atomic capture
+  {a &= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a ^= b;}
+#pragma omp atomic capture
+  {a |= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a <<= b;}
+#pragma omp atomic capture
+  {a >>= b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b + a;}
+#pragma omp atomic capture
+  {a = a * b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b - a;}
+#pragma omp atomic capture
+  {a = a / b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b & a;}
+#pragma omp atomic capture
+  {a = a ^ b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b | a;}
+#pragma omp atomic capture
+  {a = a << b; c = a;}
+#pragma omp atomic capture
+  {c = a; a = b >> a;}
+#pragma omp atomic capture
+  {c = a; a = foo();}
+  // expected-error at +1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
 #pragma omp atomic capture capture
-  a = ++b;
+  b = a /= b;
 
+  // expected-note at +1 {{in instantiation of function template specialization 'capture<int>' requested here}}
   return capture<int>();
 }
 





More information about the cfe-commits mailing list