forked from OSchip/llvm-project
[Clang][OpenMP] Add Sema support for atomic compare capture
This patch adds Sema support for `atomic compare capture`. Reviewed By: ABataev Differential Revision: https://reviews.llvm.org/D120200
This commit is contained in:
parent
2d653b7e5b
commit
e2855e1760
|
@ -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<
|
||||
|
|
|
@ -10976,6 +10976,20 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ private:
|
|||
|
||||
/// 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 <tt>atomic compare capture</tt>.
|
||||
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<CompoundStmt>(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<BinaryOperator>(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<BinaryOperator>(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<CompoundStmt>(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<BinaryOperator>(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<CompoundStmt>(S);
|
||||
assert(CS->size() == 2 && "CompoundStmt size is not expected");
|
||||
auto *S1 = cast<BinaryOperator>(CS->body_front());
|
||||
auto *S2 = cast<IfStmt>(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<CompoundStmt>(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<BinaryOperator>(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<BinaryOperator>(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<CompoundStmt>(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<BinaryOperator>(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<IfStmt>(S))
|
||||
return checkForm3(IS, ErrorInfo);
|
||||
|
||||
auto *CS = dyn_cast<CompoundStmt>(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<IfStmt>(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<BinaryOperator>(S1)) {
|
||||
// { v = x; cond-update-stmt } or form 45.
|
||||
UpdateStmt = S1;
|
||||
CondUpdateStmt = S2;
|
||||
// Check if form 45.
|
||||
if (dyn_cast<BinaryOperator>(BO->getRHS()->IgnoreImpCasts()) &&
|
||||
dyn_cast<IfStmt>(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<IfStmt>(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<BinaryOperator>(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<OMPClause *> Clauses,
|
||||
|
@ -11794,6 +12216,15 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> 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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<int>' requested here}}
|
||||
return mixed<int>();
|
||||
|
|
Loading…
Reference in New Issue