23class AtomicOperandChecker {
31 SemaRef.
Diag(AtomicDirLoc, diag::err_acc_invalid_atomic)
32 << (AtKind != OpenACCAtomicKind::None) << AtKind;
47 Expr *
E = dyn_cast<Expr>(AssocStmt.
get());
66 PD << diag::OACCLValScalar::Scalar << ExprTy);
72 if (CheckOperandExpr(
E, PD))
79 PD << diag::OACCLValScalar::LVal);
93 const Expr *FoundExpr =
nullptr;
94 const Expr *LHS =
nullptr;
95 const Expr *RHS =
nullptr;
100 const Expr *FoundExpr =
nullptr;
101 const Expr *SubExpr =
nullptr;
104 bool IsIncrementOp() {
105 return Operator == UO_PostInc || Operator == UO_PreInc;
109 std::optional<UnaryOpInfo> GetUnaryOperatorInfo(
const Expr *
E) {
111 if (
const auto *UO = dyn_cast<UnaryOperator>(
E))
117 if (
const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(
E)) {
119 Inf.FoundExpr = OpCall;
121 switch (OpCall->getOperator()) {
125 Inf.Operator = OpCall->getNumArgs() == 1 ? UO_PreInc : UO_PostInc;
128 Inf.Operator = OpCall->getNumArgs() == 1 ? UO_PreDec : UO_PostDec;
131 Inf.Operator = UO_AddrOf;
134 Inf.Operator = UO_Deref;
137 Inf.Operator = UO_Plus;
140 Inf.Operator = UO_Minus;
143 Inf.Operator = UO_Not;
146 Inf.Operator = UO_LNot;
149 Inf.Operator = UO_Coawait;
155 if (
Inf.Operator != UO_PostInc &&
Inf.Operator != UO_PostDec &&
156 OpCall->getNumArgs() != 1)
159 Inf.SubExpr = OpCall->getArg(0);
166 std::optional<BinaryOpInfo> GetBinaryOperatorInfo(
const Expr *
E) {
167 if (
const auto *BO = dyn_cast<BinaryOperator>(
E))
168 return BinaryOpInfo{BO, BO->getLHS()->IgnoreImpCasts(),
169 BO->getRHS()->IgnoreImpCasts(), BO->getOpcode()};
173 if (
const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(
E)) {
175 Inf.FoundExpr = OpCall;
177 switch (OpCall->getOperator()) {
181 Inf.Operator = BO_Add;
184 Inf.Operator = BO_Sub;
187 Inf.Operator = BO_Mul;
190 Inf.Operator = BO_Div;
193 Inf.Operator = BO_Rem;
196 Inf.Operator = BO_Xor;
199 Inf.Operator = BO_And;
202 Inf.Operator = BO_Or;
205 Inf.Operator = BO_Assign;
208 Inf.Operator = BO_Cmp;
211 Inf.Operator = BO_LT;
214 Inf.Operator = BO_GT;
217 Inf.Operator = BO_AddAssign;
220 Inf.Operator = BO_SubAssign;
223 Inf.Operator = BO_MulAssign;
226 Inf.Operator = BO_DivAssign;
228 case OO_PercentEqual:
229 Inf.Operator = BO_RemAssign;
232 Inf.Operator = BO_XorAssign;
235 Inf.Operator = BO_AndAssign;
238 Inf.Operator = BO_OrAssign;
241 Inf.Operator = BO_Shl;
243 case OO_GreaterGreater:
244 Inf.Operator = BO_Shr;
246 case OO_LessLessEqual:
247 Inf.Operator = BO_ShlAssign;
249 case OO_GreaterGreaterEqual:
250 Inf.Operator = BO_ShrAssign;
253 Inf.Operator = BO_EQ;
255 case OO_ExclaimEqual:
256 Inf.Operator = BO_NE;
259 Inf.Operator = BO_LE;
261 case OO_GreaterEqual:
262 Inf.Operator = BO_GE;
265 Inf.Operator = BO_LAnd;
268 Inf.Operator = BO_LOr;
271 Inf.Operator = BO_Comma;
274 Inf.Operator = BO_PtrMemI;
279 if (OpCall->getNumArgs() != 2)
284 Inf.LHS = OpCall->getArg(0)->IgnoreImpCasts();
285 Inf.RHS = OpCall->getArg(1)->IgnoreImpCasts();
294 std::optional<BinaryOpInfo> CheckAssignment(
const Expr *
E) {
295 std::optional<BinaryOpInfo>
Inf = GetBinaryOperatorInfo(
E);
299 SemaRef.
PDiag(diag::note_acc_atomic_expr_must_be)
300 << diag::OACCAtomicExpr::Assign);
304 if (
Inf->Operator != BO_Assign) {
305 DiagnoseInvalidAtomic(
Inf->FoundExpr->getExprLoc(),
306 SemaRef.
PDiag(diag::note_acc_atomic_expr_must_be)
307 << diag::OACCAtomicExpr::Assign);
312 if (CheckOperandVariable(
313 Inf->LHS, SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
314 << 0 << diag::OACCAtomicOpKind::Assign))
340 const Expr *X_Var =
nullptr;
342 static IDACInfo Fail() {
return IDACInfo{
true,
Invalid,
nullptr}; };
346 IDACInfo CheckIncDec(UnaryOpInfo
Inf) {
349 DiagnoseInvalidAtomic(
350 Inf.FoundExpr->getExprLoc(),
351 SemaRef.
PDiag(diag::note_acc_atomic_unsupported_unary_operator));
352 return IDACInfo::Fail();
354 bool Failed = CheckOperandVariable(
356 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
358 << (
Inf.IsIncrementOp() ? diag::OACCAtomicOpKind::Inc
359 : diag::OACCAtomicOpKind::Dec));
361 return IDACInfo{Failed, IDACInfo::Unary,
Inf.SubExpr};
364 enum class SimpleAssignKind {
None, Var,
Expr };
369 IDACInfo CheckAssignmentWithBinOpOnRHS(BinaryOpInfo AssignInf,
370 SimpleAssignKind SAK) {
372 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
373 << 0 << diag::OACCAtomicOpKind::Assign;
374 if (CheckOperandVariable(AssignInf.LHS, PD))
375 return IDACInfo::Fail();
377 std::optional<BinaryOpInfo> BinInf = GetBinaryOperatorInfo(AssignInf.RHS);
383 if (SAK != SimpleAssignKind::None) {
385 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
386 << 1 << diag::OACCAtomicOpKind::Assign;
387 if (SAK == SimpleAssignKind::Var) {
389 return IDACInfo{CheckOperandVariable(AssignInf.RHS, PD),
390 IDACInfo::SimpleAssign, AssignInf.RHS};
392 assert(SAK == SimpleAssignKind::Expr);
395 return IDACInfo{CheckOperandExpr(AssignInf.RHS, PD),
396 IDACInfo::ExprAssign, AssignInf.LHS};
399 DiagnoseInvalidAtomic(
400 AssignInf.RHS->getExprLoc(),
401 SemaRef.
PDiag(diag::note_acc_atomic_expected_binop));
403 return IDACInfo::Fail();
405 switch (BinInf->Operator) {
407 DiagnoseInvalidAtomic(
408 BinInf->FoundExpr->getExprLoc(),
409 SemaRef.
PDiag(diag::note_acc_atomic_unsupported_binary_operator));
410 return IDACInfo::Fail();
425 llvm::FoldingSetNodeID LHS_ID, InnerLHS_ID, InnerRHS_ID;
433 if (LHS_ID == InnerLHS_ID)
437 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar
439 << diag::OACCAtomicOpKind::CompoundAssign)),
440 IDACInfo::AssignBinOp, AssignInf.LHS};
446 if (LHS_ID == InnerRHS_ID)
450 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
451 << 0 << diag::OACCAtomicOpKind::CompoundAssign),
452 IDACInfo::AssignBinOp, AssignInf.LHS};
455 DiagnoseInvalidAtomic(BinInf->FoundExpr->getExprLoc(),
456 SemaRef.
PDiag(diag::note_acc_atomic_mismatch_operand)
457 <<
const_cast<Expr *
>(AssignInf.LHS)
458 <<
const_cast<Expr *
>(BinInf->LHS)
459 <<
const_cast<Expr *
>(BinInf->RHS));
460 return IDACInfo::Fail();
466 IDACInfo CheckIncDecAssignCompoundAssign(
const Expr *
E,
467 SimpleAssignKind SAK) {
468 std::optional<UnaryOpInfo> UInf = GetUnaryOperatorInfo(
E);
473 return CheckIncDec(*UInf);
475 std::optional<BinaryOpInfo> BinInf = GetBinaryOperatorInfo(
E);
480 SemaRef.
PDiag(diag::note_acc_atomic_expr_must_be)
481 << diag::OACCAtomicExpr::UnaryCompAssign);
482 return IDACInfo::Fail();
485 switch (BinInf->Operator) {
487 DiagnoseInvalidAtomic(
488 BinInf->FoundExpr->getExprLoc(),
490 diag::note_acc_atomic_unsupported_compound_binary_operator));
491 return IDACInfo::Fail();
493 return CheckAssignmentWithBinOpOnRHS(*BinInf, SAK);
504 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
505 << 0 << diag::OACCAtomicOpKind::CompoundAssign;
507 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
508 << 1 << diag::OACCAtomicOpKind::CompoundAssign;
511 bool Failed = CheckOperandVariable(BinInf->LHS, LPD) ||
512 CheckOperandExpr(BinInf->RHS, RPD);
514 return IDACInfo{Failed, IDACInfo::CompoundAssign, BinInf->LHS};
517 llvm_unreachable(
"all binary operator kinds should be checked above");
521 Expr *AssocExpr = RequireExpr(
522 AssocStmt.
get(), SemaRef.
PDiag(diag::note_acc_atomic_expr_must_be)
523 << diag::OACCAtomicExpr::Assign);
526 return getRecoveryExpr();
528 std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
530 return getRecoveryExpr();
533 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
534 << 1 << diag::OACCAtomicOpKind::Assign;
537 if (CheckOperandVariable(AssignRes->RHS, PD))
538 return getRecoveryExpr();
544 Expr *AssocExpr = RequireExpr(
545 AssocStmt.
get(), SemaRef.
PDiag(diag::note_acc_atomic_expr_must_be)
546 << diag::OACCAtomicExpr::Assign);
549 return getRecoveryExpr();
551 std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
553 return getRecoveryExpr();
556 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
557 << 1 << diag::OACCAtomicOpKind::Assign;
560 if (CheckOperandExpr(AssignRes->RHS, PD))
561 return getRecoveryExpr();
567 Expr *AssocExpr = RequireExpr(
568 AssocStmt.
get(), SemaRef.
PDiag(diag::note_acc_atomic_expr_must_be)
569 << diag::OACCAtomicExpr::UnaryCompAssign);
572 CheckIncDecAssignCompoundAssign(AssocExpr, SimpleAssignKind::None)
574 return getRecoveryExpr();
579 const Expr *IgnoreBeforeCompare(
const Expr *
E) {
584 bool CheckVarRefsSame(IDACInfo::ExprKindTy FirstKind,
const Expr *FirstX,
585 IDACInfo::ExprKindTy SecondKind,
const Expr *SecondX) {
586 llvm::FoldingSetNodeID First_ID, Second_ID;
590 if (First_ID == Second_ID)
594 SemaRef.
PDiag(diag::note_acc_atomic_mismatch_compound_operand)
595 << FirstKind << const_cast<Expr *>(FirstX) << SecondKind
596 <<
const_cast<Expr *
>(SecondX);
598 return DiagnoseInvalidAtomic(SecondX->
getExprLoc(), PD);
602 if (
const auto *CmpdStmt = dyn_cast<CompoundStmt>(AssocStmt.
get())) {
603 auto *
const *BodyItr = CmpdStmt->body().begin();
605 << diag::OACCAtomicExpr::UnaryCompAssign;
607 if (BodyItr == CmpdStmt->body().end()) {
608 DiagnoseInvalidAtomic(CmpdStmt->getBeginLoc(), PD);
609 return getRecoveryExpr();
613 Expr *FirstExpr = RequireExpr(*BodyItr, PD);
615 return getRecoveryExpr();
617 IDACInfo FirstExprResults =
618 CheckIncDecAssignCompoundAssign(FirstExpr, SimpleAssignKind::Var);
619 if (FirstExprResults.Failed)
620 return getRecoveryExpr();
625 if (BodyItr == CmpdStmt->body().end()) {
626 DiagnoseInvalidAtomic(CmpdStmt->getEndLoc(), PD);
627 return getRecoveryExpr();
630 Expr *SecondExpr = RequireExpr(*BodyItr, PD);
632 return getRecoveryExpr();
634 assert(FirstExprResults.ExprKind != IDACInfo::Invalid);
636 switch (FirstExprResults.ExprKind) {
637 case IDACInfo::Invalid:
638 case IDACInfo::ExprAssign:
639 llvm_unreachable(
"Should have error'ed out by now");
640 case IDACInfo::Unary:
641 case IDACInfo::CompoundAssign:
642 case IDACInfo::AssignBinOp: {
645 std::optional<BinaryOpInfo> AssignRes = CheckAssignment(SecondExpr);
647 return getRecoveryExpr();
650 SemaRef.
PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
651 << 1 << diag::OACCAtomicOpKind::Assign;
653 if (CheckOperandVariable(AssignRes->RHS, PD))
654 return getRecoveryExpr();
656 if (CheckVarRefsSame(FirstExprResults.ExprKind,
657 IgnoreBeforeCompare(FirstExprResults.X_Var),
658 IDACInfo::SimpleAssign,
659 IgnoreBeforeCompare(AssignRes->RHS)))
660 return getRecoveryExpr();
663 case IDACInfo::SimpleAssign: {
665 IDACInfo SecondExprResults =
666 CheckIncDecAssignCompoundAssign(SecondExpr, SimpleAssignKind::Expr);
667 if (SecondExprResults.Failed)
668 return getRecoveryExpr();
670 if (CheckVarRefsSame(FirstExprResults.ExprKind,
671 IgnoreBeforeCompare(FirstExprResults.X_Var),
672 SecondExprResults.ExprKind,
673 IgnoreBeforeCompare(SecondExprResults.X_Var)))
674 return getRecoveryExpr();
679 if (BodyItr != CmpdStmt->body().end()) {
680 DiagnoseInvalidAtomic(
681 (*BodyItr)->getBeginLoc(),
682 SemaRef.
PDiag(diag::note_acc_atomic_too_many_stmts));
683 return getRecoveryExpr();
687 Expr *AssocExpr = RequireExpr(
688 AssocStmt.
get(), SemaRef.
PDiag(diag::note_acc_atomic_expr_must_be)
689 << diag::OACCAtomicExpr::Assign);
691 return getRecoveryExpr();
694 std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
697 return getRecoveryExpr();
699 if (CheckIncDecAssignCompoundAssign(AssignRes->RHS,
700 SimpleAssignKind::None)
702 return getRecoveryExpr();
711 : SemaRef(S), AtKind(AtKind), AtomicDirLoc(DirLoc), AssocStmt(AssocStmt) {
717 case OpenACCAtomicKind::Read:
719 case OpenACCAtomicKind::Write:
721 case OpenACCAtomicKind::None:
722 case OpenACCAtomicKind::Update:
723 return CheckUpdate();
724 case OpenACCAtomicKind::Capture:
725 return CheckCapture();
727 llvm_unreachable(
"Unhandled atomic kind?");
738 if (isa<RecoveryExpr>(AssocStmt.
get()))
741 AtomicOperandChecker Checker{*
this, AtKind, AtomicDirLoc, AssocStmt};
742 return Checker.Check();
Defines the clang::Expr interface and subclasses for C++ expressions.
This file declares semantic analysis for OpenACC constructs and clauses.
const LangOptions & getLangOpts() const
This represents one expression.
Expr * IgnoreParenNoopCasts(const ASTContext &Ctx) LLVM_READONLY
Skip past any parentheses and casts which do not change the value (including ptr->int casts of the sa...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
A (possibly-)qualified type.
static RecoveryExpr * Create(ASTContext &Ctx, QualType T, SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef< Expr * > SubExprs)
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
PartialDiagnostic PDiag(unsigned DiagID=0)
Build a partial diagnostic.
ASTContext & getASTContext() const
StmtResult CheckAtomicAssociatedStmt(SourceLocation AtomicDirLoc, OpenACCAtomicKind AtKind, StmtResult AssocStmt)
Called to check the form of the atomic construct which has some fairly sizable restrictions.
Encodes a location in the source.
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical, bool ProfileLambdaExpr=false) const
Produce a unique representation of the given statement.
SourceLocation getBeginLoc() const LLVM_READONLY
bool isScalarType() const
bool isInstantiationDependentType() const
Determine whether this type is an instantiation-dependent type, meaning that the type involves a temp...
bool isIncrementDecrementOp() const
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T