@@ -1275,11 +1275,8 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
1275
1275
CondVar->getCanonicalDecl () != InitVar->getCanonicalDecl () &&
1276
1276
CE->getNumArgs () > 1 ))
1277
1277
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 ();
1283
1280
}
1284
1281
1285
1282
if (!CondVar)
@@ -1293,6 +1290,59 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
1293
1290
return false ;
1294
1291
}
1295
1292
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
+
1296
1346
bool SemaOpenACC::ForStmtBeginChecker::checkForInc (const Stmt *IncStmt,
1297
1347
const ValueDecl *InitVar,
1298
1348
bool Diag) {
@@ -1335,14 +1385,12 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
1335
1385
return DiagIncVar ();
1336
1386
case BO_AddAssign:
1337
1387
case BO_SubAssign:
1338
- case BO_MulAssign:
1339
- case BO_DivAssign:
1388
+ break ;
1340
1389
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 ();
1346
1394
break ;
1347
1395
}
1348
1396
IncVar = getDeclFromExpr (BO->getLHS ());
@@ -1354,23 +1402,18 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
1354
1402
case OO_MinusMinus:
1355
1403
case OO_PlusEqual:
1356
1404
case OO_MinusEqual:
1357
- case OO_StarEqual:
1358
- case OO_SlashEqual:
1405
+ break ;
1359
1406
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 ();
1365
1411
break ;
1366
1412
}
1367
1413
1368
1414
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 ();
1374
1417
}
1375
1418
1376
1419
if (!IncVar)
0 commit comments