23class AtomicOperandChecker {
26 SourceLocation AtomicDirLoc;
30 bool DiagnoseInvalidAtomic(SourceLocation Loc, PartialDiagnostic NoteDiag) {
31 SemaRef.Diag(AtomicDirLoc, diag::err_acc_invalid_atomic)
32 << (AtKind != OpenACCAtomicKind::None) << AtKind;
33 SemaRef.Diag(Loc, NoteDiag);
41 if (!AssocStmt.isUsable())
44 if (!SemaRef.getASTContext().getLangOpts().RecoveryAST)
47 Expr *E = dyn_cast<Expr>(AssocStmt.get());
48 QualType
T = E ? E->
getType() : SemaRef.getASTContext().DependentTy;
51 AssocStmt.get()->getBeginLoc(),
52 AssocStmt.get()->getEndLoc(),
53 E ? ArrayRef<Expr *>{E} : ArrayRef<Expr *>{});
57 bool CheckOperandExpr(
const Expr *E, PartialDiagnostic PD) {
62 if (
ExprTy->isInstantiationDependentType() ||
ExprTy->isScalarType())
66 PD << diag::OACCLValScalar::Scalar << ExprTy);
71 bool CheckOperandVariable(
const Expr *E, PartialDiagnostic PD) {
72 if (CheckOperandExpr(E, PD))
79 PD << diag::OACCLValScalar::LVal);
82 Expr *RequireExpr(Stmt *Stmt, PartialDiagnostic ExpectedNote) {
83 if (Expr *E = dyn_cast<Expr>(Stmt))
86 DiagnoseInvalidAtomic(Stmt->
getBeginLoc(), ExpectedNote);
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))
112 return UnaryOpInfo{UO, UO->getSubExpr()->IgnoreImpCasts(),
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) {
371 PartialDiagnostic PD =
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) {
384 PartialDiagnostic PD =
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;
426 AssignInf.LHS->Profile(LHS_ID, SemaRef.getASTContext(),
428 BinInf->LHS->Profile(InnerLHS_ID, SemaRef.getASTContext(),
433 if (LHS_ID == InnerLHS_ID)
437 SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
438 << 1 << diag::OACCAtomicOpKind::CompoundAssign),
439 IDACInfo::AssignBinOp, AssignInf.LHS};
441 BinInf->RHS->Profile(InnerRHS_ID, SemaRef.getASTContext(),
445 if (LHS_ID == InnerRHS_ID)
449 SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
450 << 0 << diag::OACCAtomicOpKind::CompoundAssign),
451 IDACInfo::AssignBinOp, AssignInf.LHS};
454 DiagnoseInvalidAtomic(BinInf->FoundExpr->getExprLoc(),
455 SemaRef.PDiag(diag::note_acc_atomic_mismatch_operand)
456 << AssignInf.LHS << BinInf->LHS << BinInf->RHS);
457 return IDACInfo::Fail();
463 IDACInfo CheckIncDecAssignCompoundAssign(
const Expr *E,
464 SimpleAssignKind SAK) {
465 std::optional<UnaryOpInfo> UInf = GetUnaryOperatorInfo(E);
470 return CheckIncDec(*UInf);
472 std::optional<BinaryOpInfo> BinInf = GetBinaryOperatorInfo(E);
477 SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
478 << diag::OACCAtomicExpr::UnaryCompAssign);
479 return IDACInfo::Fail();
482 switch (BinInf->Operator) {
484 DiagnoseInvalidAtomic(
485 BinInf->FoundExpr->getExprLoc(),
487 diag::note_acc_atomic_unsupported_compound_binary_operator));
488 return IDACInfo::Fail();
490 return CheckAssignmentWithBinOpOnRHS(*BinInf, SAK);
500 PartialDiagnostic LPD =
501 SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
502 << 0 << diag::OACCAtomicOpKind::CompoundAssign;
503 PartialDiagnostic RPD =
504 SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
505 << 1 << diag::OACCAtomicOpKind::CompoundAssign;
508 bool Failed = CheckOperandVariable(BinInf->LHS, LPD) ||
509 CheckOperandExpr(BinInf->RHS, RPD);
511 return IDACInfo{Failed, IDACInfo::CompoundAssign, BinInf->LHS};
514 llvm_unreachable(
"all binary operator kinds should be checked above");
518 Expr *AssocExpr = RequireExpr(
519 AssocStmt.get(), SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
520 << diag::OACCAtomicExpr::Assign);
523 return getRecoveryExpr();
525 std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
527 return getRecoveryExpr();
529 PartialDiagnostic PD =
530 SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
531 << 1 << diag::OACCAtomicOpKind::Assign;
534 if (CheckOperandVariable(AssignRes->RHS, PD))
535 return getRecoveryExpr();
541 Expr *AssocExpr = RequireExpr(
542 AssocStmt.get(), SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
543 << diag::OACCAtomicExpr::Assign);
546 return getRecoveryExpr();
548 std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
550 return getRecoveryExpr();
552 PartialDiagnostic PD =
553 SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
554 << 1 << diag::OACCAtomicOpKind::Assign;
557 if (CheckOperandExpr(AssignRes->RHS, PD))
558 return getRecoveryExpr();
564 Expr *AssocExpr = RequireExpr(
565 AssocStmt.get(), SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
566 << diag::OACCAtomicExpr::UnaryCompAssign);
569 CheckIncDecAssignCompoundAssign(AssocExpr, SimpleAssignKind::None)
571 return getRecoveryExpr();
576 const Expr *IgnoreBeforeCompare(
const Expr *E) {
578 SemaRef.getASTContext());
581 bool CheckVarRefsSame(IDACInfo::ExprKindTy FirstKind,
const Expr *FirstX,
582 IDACInfo::ExprKindTy SecondKind,
const Expr *SecondX) {
583 llvm::FoldingSetNodeID First_ID, Second_ID;
584 FirstX->
Profile(First_ID, SemaRef.getASTContext(),
true);
585 SecondX->
Profile(Second_ID, SemaRef.getASTContext(),
true);
587 if (First_ID == Second_ID)
590 PartialDiagnostic PD =
591 SemaRef.PDiag(diag::note_acc_atomic_mismatch_compound_operand)
592 << FirstKind << FirstX << SecondKind << SecondX;
594 return DiagnoseInvalidAtomic(SecondX->getExprLoc(), PD);
598 if (
const auto *CmpdStmt = dyn_cast<CompoundStmt>(AssocStmt.get())) {
599 auto *
const *BodyItr = CmpdStmt->body().begin();
600 PartialDiagnostic PD = SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
601 << diag::OACCAtomicExpr::UnaryCompAssign;
603 if (BodyItr == CmpdStmt->body().end()) {
604 DiagnoseInvalidAtomic(CmpdStmt->getBeginLoc(), PD);
605 return getRecoveryExpr();
609 Expr *FirstExpr = RequireExpr(*BodyItr, PD);
611 return getRecoveryExpr();
613 IDACInfo FirstExprResults =
614 CheckIncDecAssignCompoundAssign(FirstExpr, SimpleAssignKind::Var);
615 if (FirstExprResults.Failed)
616 return getRecoveryExpr();
621 if (BodyItr == CmpdStmt->body().end()) {
622 DiagnoseInvalidAtomic(CmpdStmt->getEndLoc(), PD);
623 return getRecoveryExpr();
626 Expr *SecondExpr = RequireExpr(*BodyItr, PD);
628 return getRecoveryExpr();
630 assert(FirstExprResults.ExprKind != IDACInfo::Invalid);
632 switch (FirstExprResults.ExprKind) {
633 case IDACInfo::Invalid:
634 case IDACInfo::ExprAssign:
635 llvm_unreachable(
"Should have error'ed out by now");
636 case IDACInfo::Unary:
637 case IDACInfo::CompoundAssign:
638 case IDACInfo::AssignBinOp: {
641 std::optional<BinaryOpInfo> AssignRes = CheckAssignment(SecondExpr);
643 return getRecoveryExpr();
645 PartialDiagnostic PD =
646 SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
647 << 1 << diag::OACCAtomicOpKind::Assign;
649 if (CheckOperandVariable(AssignRes->RHS, PD))
650 return getRecoveryExpr();
652 if (CheckVarRefsSame(FirstExprResults.ExprKind,
653 IgnoreBeforeCompare(FirstExprResults.X_Var),
654 IDACInfo::SimpleAssign,
655 IgnoreBeforeCompare(AssignRes->RHS)))
656 return getRecoveryExpr();
659 case IDACInfo::SimpleAssign: {
661 IDACInfo SecondExprResults =
662 CheckIncDecAssignCompoundAssign(SecondExpr, SimpleAssignKind::Expr);
663 if (SecondExprResults.Failed)
664 return getRecoveryExpr();
666 if (CheckVarRefsSame(FirstExprResults.ExprKind,
667 IgnoreBeforeCompare(FirstExprResults.X_Var),
668 SecondExprResults.ExprKind,
669 IgnoreBeforeCompare(SecondExprResults.X_Var)))
670 return getRecoveryExpr();
675 if (BodyItr != CmpdStmt->body().end()) {
676 DiagnoseInvalidAtomic(
677 (*BodyItr)->getBeginLoc(),
678 SemaRef.PDiag(diag::note_acc_atomic_too_many_stmts));
679 return getRecoveryExpr();
683 Expr *AssocExpr = RequireExpr(
684 AssocStmt.get(), SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
685 << diag::OACCAtomicExpr::Assign);
687 return getRecoveryExpr();
690 std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
693 return getRecoveryExpr();
695 if (CheckIncDecAssignCompoundAssign(AssignRes->RHS,
696 SimpleAssignKind::None)
698 return getRecoveryExpr();
707 : SemaRef(S), AtKind(AtKind), AtomicDirLoc(DirLoc), AssocStmt(AssocStmt) {
713 case OpenACCAtomicKind::Read:
715 case OpenACCAtomicKind::Write:
717 case OpenACCAtomicKind::None:
718 case OpenACCAtomicKind::Update:
719 return CheckUpdate();
720 case OpenACCAtomicKind::Capture:
721 return CheckCapture();
723 llvm_unreachable(
"Unhandled atomic kind?");
737 AtomicOperandChecker Checker{*
this, AtKind, AtomicDirLoc, AssocStmt};
738 return Checker.Check();
Defines the clang::Expr interface and subclasses for C++ expressions.
This file declares semantic analysis for OpenACC constructs and clauses.
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...
static RecoveryExpr * Create(ASTContext &Ctx, QualType T, SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef< Expr * > SubExprs)
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.
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 isIncrementDecrementOp() const
const clang::Expr * ExprTy
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
@ None
The alignment was not explicit in code.
ActionResult< Stmt * > StmtResult