diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0d301e76c92d7..1854c8e522b82 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10523,10 +10523,16 @@ def err_omp_atomic_compare : Error< " '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}'," " 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type," " and 'ordop' is one of '<' or '>'.">; +def err_omp_atomic_compare_capture : Error< + "the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}'," + " '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}'," + " 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x', 'r', and 'v' are lvalue expressions with scalar type, 'expr', 'e', and 'd' are expressions with scalar type," + " and 'ordop' is one of '<' or '>'.">; def note_omp_atomic_compare: Note< "%select{expected compound statement|expected exactly one expression statement|expected assignment statement|expected conditional operator|expect result value to be at false expression|" "expect binary operator in conditional expression|expect '<', '>' or '==' as order operator|expect comparison in a form of 'x == e', 'e == x', 'x ordop expr', or 'expr ordop x'|" - "expect lvalue for result value|expect scalar value|expect integer value|unexpected 'else' statement}0">; + "expect lvalue for result value|expect scalar value|expect integer value|unexpected 'else' statement|expect '==' operator|expect an assignment statement 'v = x'|" + "expect a 'if' statement|expect no more than two statements|expect a compound statement|expect 'else' statement|expect a form 'r = x == e; if (r) ...'}0">; def err_omp_atomic_several_clauses : Error< "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause">; def err_omp_several_mem_order_clauses : Error< diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c32609e4e32e3..43386c1ef8edb 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -10976,6 +10976,20 @@ class OpenMPAtomicCompareChecker { NotInteger, /// 'else' statement is not expected. UnexpectedElse, + /// Not an equality operator. + NotEQ, + /// Invalid assignment (not v == x). + InvalidAssignment, + /// Not if statement + NotIfStmt, + /// More than two statements in a compund statement. + MoreThanTwoStmts, + /// Not a compound statement. + NotCompoundStmt, + /// No else statement. + NoElse, + /// Not 'if (r)'. + InvalidCondition, /// No error. NoError, }; @@ -10999,7 +11013,7 @@ class OpenMPAtomicCompareChecker { Expr *getCond() const { return C; } bool isXBinopExpr() const { return IsXBinopExpr; } -private: +protected: /// Reference to ASTContext ASTContext &ContextRef; /// 'x' lvalue part of the source atomic expression. @@ -11026,6 +11040,35 @@ class OpenMPAtomicCompareChecker { /// Check if all captured values have right type. bool checkType(ErrorInfoTy &ErrorInfo) const; + + static bool CheckValue(const Expr *E, ErrorInfoTy &ErrorInfo, + bool ShouldBeLValue) { + if (ShouldBeLValue && !E->isLValue()) { + ErrorInfo.Error = ErrorTy::XNotLValue; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); + return false; + } + + if (!E->isInstantiationDependent()) { + QualType QTy = E->getType(); + if (!QTy->isScalarType()) { + ErrorInfo.Error = ErrorTy::NotScalar; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); + return false; + } + + if (!QTy->isIntegerType()) { + ErrorInfo.Error = ErrorTy::NotInteger; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); + return false; + } + } + + return true; + } }; bool OpenMPAtomicCompareChecker::checkCondUpdateStmt(IfStmt *S, @@ -11215,41 +11258,13 @@ bool OpenMPAtomicCompareChecker::checkType(ErrorInfoTy &ErrorInfo) const { // 'x' and 'e' cannot be nullptr assert(X && E && "X and E cannot be nullptr"); - auto CheckValue = [&ErrorInfo](const Expr *E, bool ShouldBeLValue) { - if (ShouldBeLValue && !E->isLValue()) { - ErrorInfo.Error = ErrorTy::XNotLValue; - ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); - ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); - return false; - } - - if (!E->isInstantiationDependent()) { - QualType QTy = E->getType(); - if (!QTy->isScalarType()) { - ErrorInfo.Error = ErrorTy::NotScalar; - ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); - ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); - return false; - } - - if (!QTy->isIntegerType()) { - ErrorInfo.Error = ErrorTy::NotInteger; - ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); - ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); - return false; - } - } - - return true; - }; - - if (!CheckValue(X, true)) + if (!CheckValue(X, ErrorInfo, true)) return false; - if (!CheckValue(E, false)) + if (!CheckValue(E, ErrorInfo, false)) return false; - if (D && !CheckValue(D, false)) + if (D && !CheckValue(D, ErrorInfo, false)) return false; return true; @@ -11297,6 +11312,413 @@ bool OpenMPAtomicCompareChecker::checkStmt( return checkType(ErrorInfo); } + +class OpenMPAtomicCompareCaptureChecker final + : public OpenMPAtomicCompareChecker { +public: + OpenMPAtomicCompareCaptureChecker(Sema &S) : OpenMPAtomicCompareChecker(S) {} + + Expr *getV() const { return V; } + Expr *getR() const { return R; } + bool isFailOnly() const { return IsFailOnly; } + + /// Check if statement \a S is valid for atomic compare capture. + bool checkStmt(Stmt *S, ErrorInfoTy &ErrorInfo); + +private: + bool checkType(ErrorInfoTy &ErrorInfo); + + // NOTE: Form 3, 4, 5 in the following comments mean the 3rd, 4th, and 5th + // form of 'conditional-update-capture-atomic' structured block on the v5.2 + // spec p.p. 82: + // (1) { v = x; cond-update-stmt } + // (2) { cond-update-stmt v = x; } + // (3) if(x == e) { x = d; } else { v = x; } + // (4) { r = x == e; if(r) { x = d; } } + // (5) { r = x == e; if(r) { x = d; } else { v = x; } } + + /// Check if it is valid 'if(x == e) { x = d; } else { v = x; }' (form 3) + bool checkForm3(IfStmt *S, ErrorInfoTy &ErrorInfo); + + /// Check if it is valid '{ r = x == e; if(r) { x = d; } }', + /// or '{ r = x == e; if(r) { x = d; } else { v = x; } }' (form 4 and 5) + bool checkForm45(Stmt *S, ErrorInfoTy &ErrorInfo); + + /// 'v' lvalue part of the source atomic expression. + Expr *V = nullptr; + /// 'r' lvalue part of the source atomic expression. + Expr *R = nullptr; + /// If 'v' is only updated when the comparison fails. + bool IsFailOnly = false; +}; + +bool OpenMPAtomicCompareCaptureChecker::checkType(ErrorInfoTy &ErrorInfo) { + if (!OpenMPAtomicCompareChecker::checkType(ErrorInfo)) + return false; + + if (V && !CheckValue(V, ErrorInfo, true)) + return false; + + if (R && !CheckValue(R, ErrorInfo, true)) + return false; + + return true; +} + +bool OpenMPAtomicCompareCaptureChecker::checkForm3(IfStmt *S, + ErrorInfoTy &ErrorInfo) { + IsFailOnly = true; + + auto *Then = S->getThen(); + if (auto *CS = dyn_cast(Then)) { + if (CS->body_empty()) { + ErrorInfo.Error = ErrorTy::NoStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange(); + return false; + } + if (CS->size() > 1) { + ErrorInfo.Error = ErrorTy::MoreThanOneStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange(); + return false; + } + Then = CS->body_front(); + } + + auto *BO = dyn_cast(Then); + if (!BO) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Then->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Then->getSourceRange(); + return false; + } + if (BO->getOpcode() != BO_Assign) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = BO->getExprLoc(); + ErrorInfo.NoteLoc = BO->getOperatorLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange(); + return false; + } + + X = BO->getLHS(); + D = BO->getRHS(); + + auto *Cond = dyn_cast(S->getCond()); + if (!Cond) { + ErrorInfo.Error = ErrorTy::NotABinaryOp; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange(); + return false; + } + if (Cond->getOpcode() != BO_EQ) { + ErrorInfo.Error = ErrorTy::NotEQ; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange(); + return false; + } + + if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS())) { + E = Cond->getRHS(); + } else if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) { + E = Cond->getLHS(); + } else { + ErrorInfo.Error = ErrorTy::InvalidComparison; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange(); + return false; + } + + C = Cond; + + if (!S->getElse()) { + ErrorInfo.Error = ErrorTy::NoElse; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange(); + return false; + } + + auto *Else = S->getElse(); + if (auto *CS = dyn_cast(Else)) { + if (CS->body_empty()) { + ErrorInfo.Error = ErrorTy::NoStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange(); + return false; + } + if (CS->size() > 1) { + ErrorInfo.Error = ErrorTy::MoreThanOneStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange(); + return false; + } + Else = CS->body_front(); + } + + auto *ElseBO = dyn_cast(Else); + if (!ElseBO) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Else->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Else->getSourceRange(); + return false; + } + if (ElseBO->getOpcode() != BO_Assign) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ElseBO->getExprLoc(); + ErrorInfo.NoteLoc = ElseBO->getOperatorLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseBO->getSourceRange(); + return false; + } + + if (!checkIfTwoExprsAreSame(ContextRef, X, ElseBO->getRHS())) { + ErrorInfo.Error = ErrorTy::InvalidAssignment; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseBO->getRHS()->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = + ElseBO->getRHS()->getSourceRange(); + return false; + } + + V = ElseBO->getLHS(); + + return checkType(ErrorInfo); +} + +bool OpenMPAtomicCompareCaptureChecker::checkForm45(Stmt *S, + ErrorInfoTy &ErrorInfo) { + // We don't check here as they should be already done before call this + // function. + auto *CS = cast(S); + assert(CS->size() == 2 && "CompoundStmt size is not expected"); + auto *S1 = cast(CS->body_front()); + auto *S2 = cast(CS->body_back()); + assert(S1->getOpcode() == BO_Assign && "unexpected binary operator"); + + if (!checkIfTwoExprsAreSame(ContextRef, S1->getLHS(), S2->getCond())) { + ErrorInfo.Error = ErrorTy::InvalidCondition; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S2->getCond()->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S1->getLHS()->getSourceRange(); + return false; + } + + R = S1->getLHS(); + + auto *Then = S2->getThen(); + if (auto *ThenCS = dyn_cast(Then)) { + if (ThenCS->body_empty()) { + ErrorInfo.Error = ErrorTy::NoStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ThenCS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenCS->getSourceRange(); + return false; + } + if (ThenCS->size() > 1) { + ErrorInfo.Error = ErrorTy::MoreThanOneStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ThenCS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenCS->getSourceRange(); + return false; + } + Then = ThenCS->body_front(); + } + + auto *ThenBO = dyn_cast(Then); + if (!ThenBO) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S2->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S2->getSourceRange(); + return false; + } + if (ThenBO->getOpcode() != BO_Assign) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ThenBO->getExprLoc(); + ErrorInfo.NoteLoc = ThenBO->getOperatorLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenBO->getSourceRange(); + return false; + } + + X = ThenBO->getLHS(); + D = ThenBO->getRHS(); + + auto *BO = cast(S1->getRHS()->IgnoreImpCasts()); + if (BO->getOpcode() != BO_EQ) { + ErrorInfo.Error = ErrorTy::NotEQ; + ErrorInfo.ErrorLoc = BO->getExprLoc(); + ErrorInfo.NoteLoc = BO->getOperatorLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange(); + return false; + } + + C = BO; + + if (checkIfTwoExprsAreSame(ContextRef, X, BO->getLHS())) { + E = BO->getRHS(); + } else if (checkIfTwoExprsAreSame(ContextRef, X, BO->getRHS())) { + E = BO->getLHS(); + } else { + ErrorInfo.Error = ErrorTy::InvalidComparison; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = BO->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange(); + return false; + } + + if (S2->getElse()) { + IsFailOnly = true; + + auto *Else = S2->getElse(); + if (auto *ElseCS = dyn_cast(Else)) { + if (ElseCS->body_empty()) { + ErrorInfo.Error = ErrorTy::NoStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseCS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseCS->getSourceRange(); + return false; + } + if (ElseCS->size() > 1) { + ErrorInfo.Error = ErrorTy::MoreThanOneStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseCS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseCS->getSourceRange(); + return false; + } + Else = ElseCS->body_front(); + } + + auto *ElseBO = dyn_cast(Else); + if (!ElseBO) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Else->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Else->getSourceRange(); + return false; + } + if (ElseBO->getOpcode() != BO_Assign) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ElseBO->getExprLoc(); + ErrorInfo.NoteLoc = ElseBO->getOperatorLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseBO->getSourceRange(); + return false; + } + if (!checkIfTwoExprsAreSame(ContextRef, X, ElseBO->getRHS())) { + ErrorInfo.Error = ErrorTy::InvalidAssignment; + ErrorInfo.ErrorLoc = ElseBO->getRHS()->getExprLoc(); + ErrorInfo.NoteLoc = X->getExprLoc(); + ErrorInfo.ErrorRange = ElseBO->getRHS()->getSourceRange(); + ErrorInfo.NoteRange = X->getSourceRange(); + return false; + } + + V = ElseBO->getLHS(); + } + + return checkType(ErrorInfo); +} + +bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S, + ErrorInfoTy &ErrorInfo) { + // if(x == e) { x = d; } else { v = x; } + if (auto *IS = dyn_cast(S)) + return checkForm3(IS, ErrorInfo); + + auto *CS = dyn_cast(S); + if (!CS) { + ErrorInfo.Error = ErrorTy::NotCompoundStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange(); + return false; + } + if (CS->body_empty()) { + ErrorInfo.Error = ErrorTy::NoStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange(); + return false; + } + + // { if(x == e) { x = d; } else { v = x; } } + if (CS->size() == 1) { + auto *IS = dyn_cast(CS->body_front()); + if (!IS) { + ErrorInfo.Error = ErrorTy::NotIfStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->body_front()->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = + CS->body_front()->getSourceRange(); + return false; + } + + return checkForm3(IS, ErrorInfo); + } else if (CS->size() == 2) { + auto *S1 = CS->body_front(); + auto *S2 = CS->body_back(); + + Stmt *UpdateStmt = nullptr; + Stmt *CondUpdateStmt = nullptr; + + if (auto *BO = dyn_cast(S1)) { + // { v = x; cond-update-stmt } or form 45. + UpdateStmt = S1; + CondUpdateStmt = S2; + // Check if form 45. + if (dyn_cast(BO->getRHS()->IgnoreImpCasts()) && + dyn_cast(S2)) + return checkForm45(CS, ErrorInfo); + } else { + // { cond-update-stmt v = x; } + UpdateStmt = S2; + CondUpdateStmt = S1; + } + + auto CheckCondUpdateStmt = [this, &ErrorInfo](Stmt *CUS) { + auto *IS = dyn_cast(CUS); + if (!IS) { + ErrorInfo.Error = ErrorTy::NotIfStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CUS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CUS->getSourceRange(); + return false; + } + + if (!checkCondUpdateStmt(IS, ErrorInfo)) + return false; + + return true; + }; + + // CheckUpdateStmt has to be called *after* CheckCondUpdateStmt. + auto CheckUpdateStmt = [this, &ErrorInfo](Stmt *US) { + auto *BO = dyn_cast(US); + if (!BO) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = US->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = US->getSourceRange(); + return false; + } + if (BO->getOpcode() != BO_Assign) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = BO->getExprLoc(); + ErrorInfo.NoteLoc = BO->getOperatorLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange(); + return false; + } + if (!checkIfTwoExprsAreSame(ContextRef, this->X, BO->getRHS())) { + ErrorInfo.Error = ErrorTy::InvalidAssignment; + ErrorInfo.ErrorLoc = BO->getRHS()->getExprLoc(); + ErrorInfo.NoteLoc = this->X->getExprLoc(); + ErrorInfo.ErrorRange = BO->getRHS()->getSourceRange(); + ErrorInfo.NoteRange = this->X->getSourceRange(); + return false; + } + + this->V = BO->getLHS(); + + return true; + }; + + if (!CheckCondUpdateStmt(CondUpdateStmt)) + return false; + if (!CheckUpdateStmt(UpdateStmt)) + return false; + } else { + ErrorInfo.Error = ErrorTy::MoreThanTwoStmts; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange(); + return false; + } + + return checkType(ErrorInfo); +} } // namespace StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef Clauses, @@ -11794,6 +12216,15 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef Clauses, UE = V = E = X = nullptr; } else if (AtomicKind == OMPC_compare) { if (IsCompareCapture) { + OpenMPAtomicCompareCaptureChecker::ErrorInfoTy ErrorInfo; + OpenMPAtomicCompareCaptureChecker Checker(*this); + if (!Checker.checkStmt(Body, ErrorInfo)) { + Diag(ErrorInfo.ErrorLoc, diag::err_omp_atomic_compare_capture) + << ErrorInfo.ErrorRange; + Diag(ErrorInfo.NoteLoc, diag::note_omp_atomic_compare) + << ErrorInfo.Error << ErrorInfo.NoteRange; + return StmtError(); + } // TODO: We don't set X, D, E, etc. here because in code gen we will emit // error directly. } else { diff --git a/clang/test/OpenMP/atomic_messages.c b/clang/test/OpenMP/atomic_messages.c index c66cd19b5aca3..4066d7518c628 100644 --- a/clang/test/OpenMP/atomic_messages.c +++ b/clang/test/OpenMP/atomic_messages.c @@ -500,4 +500,199 @@ void compare(void) { fx = fe; } } + +void compare_capture(void) { + int x = 0; + int d = 0; + int e = 0; + int v = 0; + int r = 0; +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected compound statement}} +#pragma omp atomic compare capture + if (x == e) {} +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected exactly one expression statement}} +#pragma omp atomic compare capture + if (x == e) { + x = d; + v = x; + } +// omp51-error@+4 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+3 {{expected assignment statement}} +#pragma omp atomic compare capture + if (x == e) { + bbar(); + } +// omp51-error@+4 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+3 {{expected assignment statement}} +#pragma omp atomic compare capture + if (x == e) { + x += d; + } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect binary operator in conditional expression}} +#pragma omp atomic compare capture + if (ffoo()) { + x = d; + } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect '==' operator}} +#pragma omp atomic compare capture + if (x > e) { + x = d; + } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect comparison in a form of 'x == e', 'e == x', 'x ordop expr', or 'expr ordop x'}} +#pragma omp atomic compare capture + if (d == e) { + x = d; + } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect 'else' statement}} +#pragma omp atomic compare capture + if (x == e) { + x = d; + } +// omp51-error@+5 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+4 {{expected compound statement}} +#pragma omp atomic compare capture + if (x == e) { + x = d; + } else { + } +// omp51-error@+5 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+4 {{expected exactly one expression statement}} +#pragma omp atomic compare capture + if (x == e) { + x = d; + } else { + v = x; + d = e; + } +// omp51-error@+6 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+5 {{expected assignment statement}} +#pragma omp atomic compare capture + if (x == e) { + x = d; + } else { + bbar(); + } +// omp51-error@+6 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+5 {{expected assignment statement}} +#pragma omp atomic compare capture + if (x == e) { + x = d; + } else { + v += x; + } +// omp51-error@+6 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+5 {{expect an assignment statement 'v = x'}} +#pragma omp atomic compare capture + if (x == e) { + x = d; + } else { + v = d; + } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected compound statement}} +#pragma omp atomic compare capture + {} +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect a compound statement}} +#pragma omp atomic compare capture + x = x > e ? e : x; +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect a 'if' statement}} +#pragma omp atomic compare capture + { x = x > e ? e : x; } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect a form 'r = x == e; if (r) ...'}} +#pragma omp atomic compare capture + { r = x == e; if (x == d) { x = e; } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected assignment statement}} +#pragma omp atomic compare capture + { r = x == e; if (r) { bbar(); } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected assignment statement}} +#pragma omp atomic compare capture + { r = x == e; if (r) { x += d; } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected compound statement}} +#pragma omp atomic compare capture + { r = x == e; if (r) {} } +// omp51-error@+5 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+4 {{expected exactly one expression statement}} +#pragma omp atomic compare capture + { + r = x == e; + if (r) { + x = d; + v = x; + } + } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect '==' operator}} +#pragma omp atomic compare capture + { r = x > e; if (r) { x = d; } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect comparison in a form of 'x == e', 'e == x', 'x ordop expr', or 'expr ordop x'}} +#pragma omp atomic compare capture + { r = d == e; if (r) { x = d; } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected compound statement}} +#pragma omp atomic compare capture + { r = x == e; if (r) { x = d; } else {} } +// omp51-error@+7 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+6 {{expected exactly one expression statement}} +#pragma omp atomic compare capture + { + r = x == e; + if (r) { + x = d; + } else { + v = x; + d = e; + } + } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected assignment statement}} +#pragma omp atomic compare capture + { r = x == e; if (r) { x = d; } else { bbar(); } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected assignment statement}} +#pragma omp atomic compare capture + { r = x == e; if (r) { x = d; } else { v += x; } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect an assignment statement 'v = x'}} +#pragma omp atomic compare capture + { r = x == e; if (r) { x = d; } else { v = d; } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected assignment statement}} +#pragma omp atomic compare capture + { v += x; if (x == e) { x = d; } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected assignment statement}} +#pragma omp atomic compare capture + { if (x == e) { x = d; } v += x; } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect an assignment statement 'v = x'}} +#pragma omp atomic compare capture + { v = d; if (x == e) { x = d; } } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect an assignment statement 'v = x'}} +#pragma omp atomic compare capture + { if (x == e) { x = d; } v = d; } +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect a 'if' statement}} +#pragma omp atomic compare capture + { v = x; bbar(); } + + float fv; +// omp51-error@+3 {{the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}', '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect integer value}} +#pragma omp atomic compare capture + { fv = x; if (x == e) { x = d; } } +} #endif diff --git a/clang/test/OpenMP/atomic_messages.cpp b/clang/test/OpenMP/atomic_messages.cpp index 700c86da1a588..23fd24bfcf118 100644 --- a/clang/test/OpenMP/atomic_messages.cpp +++ b/clang/test/OpenMP/atomic_messages.cpp @@ -928,7 +928,7 @@ T mixed() { } int mixed() { - int a, b = 0; + int a, v, b = 0; // expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}} // expected-note@+1 {{'read' clause used here}} #pragma omp atomic read write @@ -957,7 +957,7 @@ int mixed() { // expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'compare' clause}} // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}} #pragma omp atomic compare compare capture capture - a = b; + { v = a; if (a > b) a = b; } #endif // expected-note@+1 {{in instantiation of function template specialization 'mixed' requested here}} return mixed();