[clang] [Clang][OpenMP] Fix crash on `atomic` with an erroneous statement (PR #228914)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 4 10:26:53 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Akash Manna (akash-manna-sky)

<details>
<summary>Changes</summary>

Fixes #<!-- -->107979

A statement under `#pragma omp atomic` that already has an error, such as `0--;` or an assignment to a `const` variable, reaches `OpenMPAtomicUpdateChecker` as a `RecoveryExpr`. Since #<!-- -->71480 the checker rejects it with a `NotAValidExpression` code, but that code is also used as the `%select` index of `note_omp_atomic_update`, which only has eight options. So for `atomic`, `atomic update` and the `v = expr` form of `atomic capture` the note was emitted with index 8 and we hit the assertion in `HandleSelectModifier`.

`checkStatement` now returns early, without a diagnostic, when the expression contains errors, since the statement has already been diagnosed and its form can't be checked reliably. `NotAValidExpression` is removed, so the error codes match the note again. The check runs before the form analysis, which also gets rid of the bogus `invalid operands to binary expression ('int' and '<dependent type>')` for an erroneous operand in an otherwise valid form such as `x += 0--;`.


---
Full diff: https://github.com/llvm/llvm-project/pull/228914.diff


4 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+2) 
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+2-7) 
- (modified) clang/test/OpenMP/atomic_messages.c (+26-6) 
- (modified) clang/test/OpenMP/atomic_messages.cpp (+26-6) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bf194e87f76a6..4d08c8c390c46 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1077,6 +1077,8 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was renamed to `alpha.core.Use
 - Added the OpenMP 6.1 `#pragma omp flatten` loop transformation and the
   `depth` clause. Flatten combines perfectly nested canonical loops into one
   loop. `depth(k)` selects how many outermost loops to combine (default 2).
+- Fixed a crash when the statement of an OpenMP `atomic` directive contains an
+  invalid expression, such as `0--;`. (#GH107979)
 - Canonicalize intra-tiles in loop tiling. `#pragma omp tile` still emits a
   min-bounded inner loop, which vectorizes well. When a parent directive such as
   `for collapse(n)` needs a constant per-tile trip count, Clang rereads a
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index efc570a8933f1..9b7b9b36e42c1 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -12467,9 +12467,6 @@ class OpenMPAtomicUpdateChecker {
     /// RHS binary operation does not have reference to the updated LHS
     /// part.
     NotAnUpdateExpression,
-    /// An expression contains semantical error not related to
-    /// 'omp atomic [update]'
-    NotAValidExpression,
     /// No errors is found.
     NoError
   };
@@ -12610,6 +12607,8 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId,
   //  x = expr binop x;
   if (auto *AtomicBody = dyn_cast<Expr>(S)) {
     AtomicBody = AtomicBody->IgnoreParenImpCasts();
+    if (AtomicBody->containsErrors())
+      return true;
     if (AtomicBody->getType()->isScalarType() ||
         AtomicBody->isInstantiationDependent()) {
       if (const auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>(
@@ -12647,10 +12646,6 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId,
         ErrorFound = NotABinaryOrUnaryExpression;
         NoteLoc = ErrorLoc = AtomicBody->getExprLoc();
         NoteRange = ErrorRange = AtomicBody->getSourceRange();
-      } else if (AtomicBody->containsErrors()) {
-        ErrorFound = NotAValidExpression;
-        NoteLoc = ErrorLoc = AtomicBody->getExprLoc();
-        NoteRange = ErrorRange = AtomicBody->getSourceRange();
       }
     } else {
       ErrorFound = NotAScalarType;
diff --git a/clang/test/OpenMP/atomic_messages.c b/clang/test/OpenMP/atomic_messages.c
index f4e7db52494af..991dc916f2d2b 100644
--- a/clang/test/OpenMP/atomic_messages.c
+++ b/clang/test/OpenMP/atomic_messages.c
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 100 %s -Wuninitialized
-// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -ferror-limit 100 %s -Wuninitialized
-// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 150 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -ferror-limit 150 %s -Wuninitialized
+// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp -ferror-limit 150 %s -Wuninitialized
 
-// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 100 %s -Wuninitialized
-// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -ferror-limit 100 %s -Wuninitialized
-// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp-simd -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 150 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -ferror-limit 150 %s -Wuninitialized
+// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp-simd -ferror-limit 150 %s -Wuninitialized
 
 void xxx(int argc) {
   int x; // expected-note {{initialize the variable 'x' to silence this warning}}
@@ -397,6 +397,26 @@ void hint(void) {
   a += 1;
 }
 
+void gh107979(void) {
+  int x = 0, v = 0;
+#pragma omp atomic
+  0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  --0; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  0++; // expected-error {{expression is not assignable}}
+#pragma omp atomic update
+  0 += 1; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  x += 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  v = 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  { v = x; x += 0--; } // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  x--;
+}
+
 #ifdef OMP51
 extern void bbar(void);
 extern int ffoo(void);
diff --git a/clang/test/OpenMP/atomic_messages.cpp b/clang/test/OpenMP/atomic_messages.cpp
index c4e240a0ebb4e..188f4faa3b873 100644
--- a/clang/test/OpenMP/atomic_messages.cpp
+++ b/clang/test/OpenMP/atomic_messages.cpp
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 150 %s -Wuninitialized
-// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -ferror-limit 150 %s -Wuninitialized
-// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp -ferror-limit 150 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 200 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -ferror-limit 200 %s -Wuninitialized
+// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp -ferror-limit 200 %s -Wuninitialized
 
-// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 150 %s -Wuninitialized
-// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -ferror-limit 150 %s -Wuninitialized
-// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp-simd -ferror-limit 150 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 200 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -ferror-limit 200 %s -Wuninitialized
+// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp-simd -ferror-limit 200 %s -Wuninitialized
 
 int foo() {
 L1:
@@ -992,6 +992,26 @@ int mixed() {
   return mixed<int>();
 }
 
+void gh107979() {
+  int x = 0, v = 0;
+#pragma omp atomic
+  0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  --0; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  0++; // expected-error {{expression is not assignable}}
+#pragma omp atomic update
+  0 += 1; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  x += 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  v = 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  { v = x; x += 0--; } // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  x--;
+}
+
 #ifdef OMP51
 struct U {};
 struct U operator<(U, U);

``````````

</details>


https://github.com/llvm/llvm-project/pull/228914


More information about the cfe-commits mailing list