@@ -1275,11 +1275,8 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
12751275 CondVar->getCanonicalDecl () != InitVar->getCanonicalDecl () &&
12761276 CE->getNumArgs () > 1 ))
12771277 CondVar = getDeclFromExpr (CE->getArg (1 ));
1278- } else if (const auto *ME = dyn_cast<CXXMemberCallExpr>(CondStmt)) {
1279- // Here there isn't much we can do besides hope it is the right variable.
1280- // Codegen might have to just give up on figuring out trip count in this
1281- // case?
1282- CondVar = getDeclFromExpr (ME->getImplicitObjectArgument ());
1278+ } else {
1279+ return DiagCondVar ();
12831280 }
12841281
12851282 if (!CondVar)
@@ -1293,6 +1290,59 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
12931290 return false ;
12941291}
12951292
1293+ namespace {
1294+ // Helper to check the RHS of an assignment during for's step. We can allow
1295+ // InitVar = InitVar + N, InitVar = N + InitVar, and Initvar = Initvar - N,
1296+ // where N is an integer.
1297+ bool isValidForIncRHSAssign (const ValueDecl *InitVar, const Expr *RHS) {
1298+
1299+ auto isValid = [](const ValueDecl *InitVar, const Expr *InnerLHS,
1300+ const Expr *InnerRHS, bool IsAddition) {
1301+ // ONE of the sides has to be an integer type.
1302+ if (!InnerLHS->getType ()->isIntegerType () &&
1303+ !InnerRHS->getType ()->isIntegerType ())
1304+ return false ;
1305+
1306+ // If the init var is already an error, don't bother trying to check for
1307+ // it.
1308+ if (!InitVar)
1309+ return true ;
1310+
1311+ const ValueDecl *LHSDecl = getDeclFromExpr (InnerLHS);
1312+ const ValueDecl *RHSDecl = getDeclFromExpr (InnerRHS);
1313+ // If we can't get a declaration, this is probably an error, so give up.
1314+ if (!LHSDecl || !RHSDecl)
1315+ return true ;
1316+
1317+ // If the LHS is the InitVar, the other must be int, so this is valid.
1318+ if (LHSDecl->getCanonicalDecl () ==
1319+ InitVar->getCanonicalDecl ())
1320+ return true ;
1321+
1322+ // Subtraction doesn't allow the RHS to be init var, so this is invalid.
1323+ if (!IsAddition)
1324+ return false ;
1325+
1326+ return RHSDecl->getCanonicalDecl () ==
1327+ InitVar->getCanonicalDecl ();
1328+ };
1329+
1330+ if (const auto *BO = dyn_cast<BinaryOperator>(RHS)) {
1331+ BinaryOperatorKind OpC = BO->getOpcode ();
1332+ if (OpC != BO_Add && OpC != BO_Sub)
1333+ return false ;
1334+ return isValid (InitVar, BO->getLHS (), BO->getRHS (), OpC == BO_Add);
1335+ } else if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(RHS)) {
1336+ OverloadedOperatorKind Op = CE->getOperator ();
1337+ if (Op != OO_Plus && Op != OO_Minus)
1338+ return false ;
1339+ return isValid (InitVar, CE->getArg (0 ), CE->getArg (1 ), Op == OO_Plus);
1340+ }
1341+
1342+ return false ;
1343+ }
1344+ } // namespace
1345+
12961346bool SemaOpenACC::ForStmtBeginChecker::checkForInc (const Stmt *IncStmt,
12971347 const ValueDecl *InitVar,
12981348 bool Diag) {
@@ -1335,14 +1385,12 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
13351385 return DiagIncVar ();
13361386 case BO_AddAssign:
13371387 case BO_SubAssign:
1338- case BO_MulAssign:
1339- case BO_DivAssign:
1388+ break ;
13401389 case BO_Assign:
1341- // += -= *= /= should all be fine here, this should be all of the
1342- // 'monotonical' compound-assign ops.
1343- // Assignment we just give up on, we could do better, and ensure that it
1344- // is a binary/operator expr doing more work, but that seems like a lot
1345- // of work for an error prone check.
1390+ // For assignment we also allow InitVar = InitVar + N, InitVar = N +
1391+ // InitVar, and InitVar = InitVar - N; BUT only if 'N' is integral.
1392+ if (!isValidForIncRHSAssign (InitVar, BO->getRHS ()))
1393+ return DiagIncVar ();
13461394 break ;
13471395 }
13481396 IncVar = getDeclFromExpr (BO->getLHS ());
@@ -1354,23 +1402,18 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
13541402 case OO_MinusMinus:
13551403 case OO_PlusEqual:
13561404 case OO_MinusEqual:
1357- case OO_StarEqual:
1358- case OO_SlashEqual:
1405+ break ;
13591406 case OO_Equal:
1360- // += -= *= /= should all be fine here, this should be all of the
1361- // 'monotonical' compound-assign ops.
1362- // Assignment we just give up on, we could do better, and ensure that it
1363- // is a binary/operator expr doing more work, but that seems like a
1364- // lot of work for an error prone check.
1407+ // For assignment we also allow InitVar = InitVar + N, InitVar = N +
1408+ // InitVar, and InitVar = InitVar - N; BUT only if 'N' is integral.
1409+ if (!isValidForIncRHSAssign (InitVar, CE->getArg (1 )))
1410+ return DiagIncVar ();
13651411 break ;
13661412 }
13671413
13681414 IncVar = getDeclFromExpr (CE->getArg (0 ));
1369-
1370- } else if (const auto *ME = dyn_cast<CXXMemberCallExpr>(IncStmt)) {
1371- IncVar = getDeclFromExpr (ME->getImplicitObjectArgument ());
1372- // We can't really do much for member expressions, other than hope they are
1373- // doing the right thing, so give up here.
1415+ } else {
1416+ return DiagIncVar ();
13741417 }
13751418
13761419 if (!IncVar)
0 commit comments