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) {
 
   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
 
  439                            << diag::OACCAtomicOpKind::CompoundAssign)),
 
  440          IDACInfo::AssignBinOp, AssignInf.LHS};
 
  442    BinInf->RHS->Profile(InnerRHS_ID, SemaRef.getASTContext(),
 
  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                              << AssignInf.LHS << BinInf->LHS << BinInf->RHS);
 
  458    return IDACInfo::Fail();
 
  464  IDACInfo CheckIncDecAssignCompoundAssign(
const Expr *E,
 
  465                                           SimpleAssignKind SAK) {
 
  466    std::optional<UnaryOpInfo> UInf = GetUnaryOperatorInfo(E);
 
  471      return CheckIncDec(*UInf);
 
  473    std::optional<BinaryOpInfo> BinInf = GetBinaryOperatorInfo(E);
 
  478                            SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
 
  479                                << diag::OACCAtomicExpr::UnaryCompAssign);
 
  480      return IDACInfo::Fail();
 
  483    switch (BinInf->Operator) {
 
  485      DiagnoseInvalidAtomic(
 
  486          BinInf->FoundExpr->getExprLoc(),
 
  488              diag::note_acc_atomic_unsupported_compound_binary_operator));
 
  489      return IDACInfo::Fail();
 
  491      return CheckAssignmentWithBinOpOnRHS(*BinInf, SAK);
 
  501      PartialDiagnostic LPD =
 
  502          SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
 
  503          << 0 << diag::OACCAtomicOpKind::CompoundAssign;
 
  504      PartialDiagnostic RPD =
 
  505          SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
 
  506          << 1 << diag::OACCAtomicOpKind::CompoundAssign;
 
  509      bool Failed = CheckOperandVariable(BinInf->LHS, LPD) ||
 
  510                    CheckOperandExpr(BinInf->RHS, RPD);
 
  512      return IDACInfo{Failed, IDACInfo::CompoundAssign, BinInf->LHS};
 
  515    llvm_unreachable(
"all binary operator kinds should be checked above");
 
  519    Expr *AssocExpr = RequireExpr(
 
  520        AssocStmt.get(), SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
 
  521                             << diag::OACCAtomicExpr::Assign);
 
  524      return getRecoveryExpr();
 
  526    std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
 
  528      return getRecoveryExpr();
 
  530    PartialDiagnostic PD =
 
  531        SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
 
  532        << 1 << diag::OACCAtomicOpKind::Assign;
 
  535    if (CheckOperandVariable(AssignRes->RHS, PD))
 
  536      return getRecoveryExpr();
 
  542    Expr *AssocExpr = RequireExpr(
 
  543        AssocStmt.get(), SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
 
  544                             << diag::OACCAtomicExpr::Assign);
 
  547      return getRecoveryExpr();
 
  549    std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
 
  551      return getRecoveryExpr();
 
  553    PartialDiagnostic PD =
 
  554        SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
 
  555        << 1 << diag::OACCAtomicOpKind::Assign;
 
  558    if (CheckOperandExpr(AssignRes->RHS, PD))
 
  559      return getRecoveryExpr();
 
  565    Expr *AssocExpr = RequireExpr(
 
  566        AssocStmt.get(), SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
 
  567                             << diag::OACCAtomicExpr::UnaryCompAssign);
 
  570        CheckIncDecAssignCompoundAssign(AssocExpr, SimpleAssignKind::None)
 
  572      return getRecoveryExpr();
 
  577  const Expr *IgnoreBeforeCompare(
const Expr *E) {
 
  579        SemaRef.getASTContext());
 
  582  bool CheckVarRefsSame(IDACInfo::ExprKindTy FirstKind, 
const Expr *FirstX,
 
  583                        IDACInfo::ExprKindTy SecondKind, 
const Expr *SecondX) {
 
  584    llvm::FoldingSetNodeID First_ID, Second_ID;
 
  585    FirstX->
Profile(First_ID, SemaRef.getASTContext(), 
true);
 
  586    SecondX->
Profile(Second_ID, SemaRef.getASTContext(), 
true);
 
  588    if (First_ID == Second_ID)
 
  591    PartialDiagnostic PD =
 
  592        SemaRef.PDiag(diag::note_acc_atomic_mismatch_compound_operand)
 
  593        << FirstKind << FirstX << SecondKind << SecondX;
 
  595    return DiagnoseInvalidAtomic(SecondX->getExprLoc(), PD);
 
  599    if (
const auto *CmpdStmt = dyn_cast<CompoundStmt>(AssocStmt.get())) {
 
  600      auto *
const *BodyItr = CmpdStmt->body().begin();
 
  601      PartialDiagnostic PD = SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
 
  602                             << diag::OACCAtomicExpr::UnaryCompAssign;
 
  604      if (BodyItr == CmpdStmt->body().end()) {
 
  605        DiagnoseInvalidAtomic(CmpdStmt->getBeginLoc(), PD);
 
  606        return getRecoveryExpr();
 
  610      Expr *FirstExpr = RequireExpr(*BodyItr, PD);
 
  612        return getRecoveryExpr();
 
  614      IDACInfo FirstExprResults =
 
  615          CheckIncDecAssignCompoundAssign(FirstExpr, SimpleAssignKind::Var);
 
  616      if (FirstExprResults.Failed)
 
  617        return getRecoveryExpr();
 
  622      if (BodyItr == CmpdStmt->body().end()) {
 
  623        DiagnoseInvalidAtomic(CmpdStmt->getEndLoc(), PD);
 
  624        return getRecoveryExpr();
 
  627      Expr *SecondExpr = RequireExpr(*BodyItr, PD);
 
  629        return getRecoveryExpr();
 
  631      assert(FirstExprResults.ExprKind != IDACInfo::Invalid);
 
  633      switch (FirstExprResults.ExprKind) {
 
  634      case IDACInfo::Invalid:
 
  635      case IDACInfo::ExprAssign:
 
  636        llvm_unreachable(
"Should have error'ed out by now");
 
  637      case IDACInfo::Unary:
 
  638      case IDACInfo::CompoundAssign:
 
  639      case IDACInfo::AssignBinOp: {
 
  642        std::optional<BinaryOpInfo> AssignRes = CheckAssignment(SecondExpr);
 
  644          return getRecoveryExpr();
 
  646        PartialDiagnostic PD =
 
  647            SemaRef.PDiag(diag::note_acc_atomic_operand_lvalue_scalar)
 
  648            << 1 << diag::OACCAtomicOpKind::Assign;
 
  650        if (CheckOperandVariable(AssignRes->RHS, PD))
 
  651          return getRecoveryExpr();
 
  653        if (CheckVarRefsSame(FirstExprResults.ExprKind,
 
  654                             IgnoreBeforeCompare(FirstExprResults.X_Var),
 
  655                             IDACInfo::SimpleAssign,
 
  656                             IgnoreBeforeCompare(AssignRes->RHS)))
 
  657          return getRecoveryExpr();
 
  660      case IDACInfo::SimpleAssign: {
 
  662        IDACInfo SecondExprResults =
 
  663            CheckIncDecAssignCompoundAssign(SecondExpr, SimpleAssignKind::Expr);
 
  664        if (SecondExprResults.Failed)
 
  665          return getRecoveryExpr();
 
  667        if (CheckVarRefsSame(FirstExprResults.ExprKind,
 
  668                             IgnoreBeforeCompare(FirstExprResults.X_Var),
 
  669                             SecondExprResults.ExprKind,
 
  670                             IgnoreBeforeCompare(SecondExprResults.X_Var)))
 
  671          return getRecoveryExpr();
 
  676      if (BodyItr != CmpdStmt->body().end()) {
 
  677        DiagnoseInvalidAtomic(
 
  678            (*BodyItr)->getBeginLoc(),
 
  679            SemaRef.PDiag(diag::note_acc_atomic_too_many_stmts));
 
  680        return getRecoveryExpr();
 
  684      Expr *AssocExpr = RequireExpr(
 
  685          AssocStmt.get(), SemaRef.PDiag(diag::note_acc_atomic_expr_must_be)
 
  686                               << diag::OACCAtomicExpr::Assign);
 
  688        return getRecoveryExpr();
 
  691      std::optional<BinaryOpInfo> AssignRes = CheckAssignment(AssocExpr);
 
  694        return getRecoveryExpr();
 
  696      if (CheckIncDecAssignCompoundAssign(AssignRes->RHS,
 
  697                                          SimpleAssignKind::None)
 
  699        return getRecoveryExpr();
 
  708      : SemaRef(S), AtKind(AtKind), AtomicDirLoc(DirLoc), AssocStmt(AssocStmt) {
 
  714    case OpenACCAtomicKind::Read:
 
  716    case OpenACCAtomicKind::Write:
 
  718    case OpenACCAtomicKind::None:
 
  719    case OpenACCAtomicKind::Update:
 
  720      return CheckUpdate();
 
  721    case OpenACCAtomicKind::Capture:
 
  722      return CheckCapture();
 
  724    llvm_unreachable(
"Unhandled atomic kind?");
 
  738  AtomicOperandChecker Checker{*
this, AtKind, AtomicDirLoc, AssocStmt};
 
  739  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 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.
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
@ None
The alignment was not explicit in code.
ActionResult< Stmt * > StmtResult