[clang] [OpenACC] Better handle error overloaded ops in ForStmtChecker (PR #211005)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 21 07:01:37 PDT 2026


https://github.com/erichkeane created https://github.com/llvm/llvm-project/pull/211005

The OpenACC 'loop' constructs do a bunch of checking on the contents of a ForStmt.  However, in cases of overloaded operators, some of the checking we assumed happened (like operators having a certain number of
    args) doesn't hold in the case of errors.  This patch adds some
guards to make sure we error-out if the number of args doesn't match what we're expecting everywhere I could find it.

Fixes: #210958

>From c8ee94d470a4af34f565773c20b18f4e0ba54a0d Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Tue, 21 Jul 2026 06:56:48 -0700
Subject: [PATCH] [OpenACC] Better handle error overloaded ops in
 ForStmtChecker

The OpenACC 'loop' constructs do a bunch of checking on the contents of
a ForStmt.  However, in cases of overloaded operators, some of the
checking we assumed happened (like operators having a certain number of
    args) doesn't hold in the case of errors.  This patch adds some
guards to make sure we error-out if the number of args doesn't match
what we're expecting everywhere I could find it.

Fixes: #210958
---
 clang/lib/Sema/SemaOpenACC.cpp            | 16 +++++++++++++++-
 clang/test/SemaOpenACC/loop-construct.cpp | 15 +++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 79edb8093c368..362bae5eebef6 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -1345,6 +1345,8 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInit(const Stmt *InitStmt,
     // Allow assignment operator call.
     if (CE->getOperator() != OO_Equal)
       return DiagLoopVar();
+    if (CE->getNumArgs() < 1)
+      return DiagLoopVar();
 
     const Expr *LHS = CE->getArg(0)->IgnoreParenImpCasts();
     if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
@@ -1437,6 +1439,9 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
     if (!CE->isComparisonOp() || CE->getOperator() == OO_Spaceship)
       return DiagCondVar();
 
+    if (CE->getNumArgs() < 1)
+      DiagCondVar();
+
     // Same logic here: Assign it to the LHS, unless the LHS comes back null or
     // not equal to the init var.
     CondVar = getDeclFromExpr(CE->getArg(0));
@@ -1506,6 +1511,11 @@ bool isValidForIncRHSAssign(const ValueDecl *InitVar, const Expr *RHS) {
     OverloadedOperatorKind Op = CE->getOperator();
     if (Op != OO_Plus && Op != OO_Minus)
       return false;
+    // Despite Plus/Minus otherwise only being possible with 2 arguments, error
+    // recovery will sometimes leave us with only 1 here, so fail out if we
+    // don't have the correct number of args.
+    if (CE->getNumArgs() != 2)
+      return false;
     return isValid(InitVar, CE->getArg(0), CE->getArg(1), Op == OO_Plus);
   }
 
@@ -1565,6 +1575,9 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
     }
     IncVar = getDeclFromExpr(BO->getLHS());
   } else if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(IncStmt)) {
+    if (CE->getNumArgs() < 1)
+      return DiagIncVar();
+
     switch (CE->getOperator()) {
     default:
       return DiagIncVar();
@@ -1576,7 +1589,8 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
     case OO_Equal:
       // For assignment we also allow InitVar = InitVar + N, InitVar = N +
       // InitVar, and InitVar = InitVar - N;  BUT only if 'N' is integral.
-      if (!isValidForIncRHSAssign(InitVar, CE->getArg(1)))
+      if (CE->getNumArgs() != 2 ||
+          !isValidForIncRHSAssign(InitVar, CE->getArg(1)))
         return DiagIncVar();
       break;
     }
diff --git a/clang/test/SemaOpenACC/loop-construct.cpp b/clang/test/SemaOpenACC/loop-construct.cpp
index 0282258023baf..a64376b31e390 100644
--- a/clang/test/SemaOpenACC/loop-construct.cpp
+++ b/clang/test/SemaOpenACC/loop-construct.cpp
@@ -439,3 +439,18 @@ void allowTrivialAssignStep(int N) {
   for (auto Itr = Col.begin(); Itr != Col.end(); Itr = N - Itr);
 }
 
+namespace gh210958 {
+// expected-error at +1{{overloaded 'operator-' must have at least one parameter of class or enumeration type}}
+void operator-();
+
+void foo() {
+#pragma acc loop
+  // expected-error at +5{{unknown type name 'I'}}
+  // expected-error at +4{{OpenACC 'loop' construct must have a terminating condition}}
+  // expected-note at -3{{'loop' construct is here}}
+  // expected-error at +2{{OpenACC 'loop' variable must monotonically increase or decrease ('++', '--', or compound assignment)}}
+  // expected-note at -5{{'loop' construct is here}}
+  for (I i = 0; i <= 2; i = -i);
+};
+
+}



More information about the cfe-commits mailing list