https://github.com/akash-manna-sky updated 
https://github.com/llvm/llvm-project/pull/228914

>From aa2addf995c8bdfea74305fe4f1ed657cd87eb3c Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Sun, 4 Oct 2026 21:40:48 +0530
Subject: [PATCH 1/4] [Clang][OpenMP] Fix crash on `atomic` with an erroneous
 statement

A statement under `#pragma omp atomic` that already has an error, such
as `0--;`, reaches OpenMPAtomicUpdateChecker as a RecoveryExpr. The
checker reported it with the NotAValidExpression code, which has no
matching option in note_omp_atomic_update, so formatting the note hit
an assertion.

Return early without a diagnostic when the expression contains errors,
and remove NotAValidExpression so the error codes match the note again.

Fixes #107979
---
 clang/docs/ReleaseNotes.md            |  2 ++
 clang/lib/Sema/SemaOpenMP.cpp         |  9 ++------
 clang/test/OpenMP/atomic_messages.c   | 32 ++++++++++++++++++++++-----
 clang/test/OpenMP/atomic_messages.cpp | 32 ++++++++++++++++++++++-----
 4 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bf194e87f76a6d..4d08c8c390c46e 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 efc570a8933f1d..9b7b9b36e42c1a 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 f4e7db52494afe..991dc916f2d2bd 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 c4e240a0ebb4ea..188f4faa3b873c 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);

>From e2431eb2a373938af6475c7ba53e6921b6f13eec Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Mon, 5 Oct 2026 10:28:12 +0530
Subject: [PATCH 2/4] Add the missing %select option instead of removing the
 error code

Keep NotAValidExpression and give note_omp_atomic_update a matching
option. The early return on containsErrors() also rejected valid
statements that only refer to a variable with an erroneous initializer.
---
 clang/include/clang/Basic/DiagnosticSemaKinds.td |  3 ++-
 clang/lib/Sema/SemaOpenMP.cpp                    |  9 +++++++--
 clang/test/OpenMP/atomic_messages.c              | 15 ++++++++++++---
 clang/test/OpenMP/atomic_messages.cpp            | 15 ++++++++++++---
 4 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9208aba1445d7e..d1ace2592e703d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12398,7 +12398,8 @@ def err_omp_atomic_not_expression_statement : Error<
 def note_omp_atomic_update: Note<
   "%select{expected an expression statement|expected built-in binary or unary 
operator|expected unary decrement/increment operation|"
   "expected expression of scalar type|expected assignment expression|expected 
built-in binary operator|"
-  "expected one of '+', '*', '-', '/', '&', '^', '%|', '<<', or '>>' built-in 
operations|expected in right hand side of expression}0">;
+  "expected one of '+', '*', '-', '/', '&', '^', '%|', '<<', or '>>' built-in 
operations|expected in right hand side of expression|"
+  "expected a valid expression}0">;
 def err_omp_atomic_capture_not_expression_statement : Error<
   "the statement for 'atomic capture' must be an expression statement of form 
'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = 
x binop expr' or 'v = x = expr binop x',"
   " where x and v are both lvalue expressions with scalar type">;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 9b7b9b36e42c1a..efc570a8933f1d 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -12467,6 +12467,9 @@ 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
   };
@@ -12607,8 +12610,6 @@ 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>(
@@ -12646,6 +12647,10 @@ 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 991dc916f2d2bd..48203c5fbbc154 100644
--- a/clang/test/OpenMP/atomic_messages.c
+++ b/clang/test/OpenMP/atomic_messages.c
@@ -400,19 +400,28 @@ void hint(void) {
 void gh107979(void) {
   int x = 0, v = 0;
 #pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
   0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
   --0; // expected-error {{expression is not assignable}}
 #pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
   0++; // expected-error {{expression is not assignable}}
 #pragma omp atomic update
+  // expected-error@+2 {{the statement for 'atomic update' must be an 
expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 
'x = x binop expr' or 'x = expr binop x', where x is an lvalue expression with 
scalar type}}
+  // expected-note@+1 {{expected a valid expression}}
   0 += 1; // expected-error {{expression is not assignable}}
-#pragma omp atomic
-  x += 0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic capture
+  // expected-error@+2 {{the statement for 'atomic capture' must be an 
expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v 
= x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x 
and v are both lvalue expressions with scalar type}}
+  // expected-note@+1 {{expected a valid expression}}
   v = 0--; // expected-error {{expression is not assignable}}
+  int w = 0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic capture
-  { v = x; x += 0--; } // expected-error {{expression is not assignable}}
+  { v = w; w++; }
 #pragma omp atomic
   x--;
 }
diff --git a/clang/test/OpenMP/atomic_messages.cpp 
b/clang/test/OpenMP/atomic_messages.cpp
index 188f4faa3b873c..05a51dc76c9cbe 100644
--- a/clang/test/OpenMP/atomic_messages.cpp
+++ b/clang/test/OpenMP/atomic_messages.cpp
@@ -995,19 +995,28 @@ int mixed() {
 void gh107979() {
   int x = 0, v = 0;
 #pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
   0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
   --0; // expected-error {{expression is not assignable}}
 #pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
   0++; // expected-error {{expression is not assignable}}
 #pragma omp atomic update
+  // expected-error@+2 {{the statement for 'atomic update' must be an 
expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 
'x = x binop expr' or 'x = expr binop x', where x is an lvalue expression with 
scalar type}}
+  // expected-note@+1 {{expected a valid expression}}
   0 += 1; // expected-error {{expression is not assignable}}
-#pragma omp atomic
-  x += 0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic capture
+  // expected-error@+2 {{the statement for 'atomic capture' must be an 
expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v 
= x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x 
and v are both lvalue expressions with scalar type}}
+  // expected-note@+1 {{expected a valid expression}}
   v = 0--; // expected-error {{expression is not assignable}}
+  int w = 0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic capture
-  { v = x; x += 0--; } // expected-error {{expression is not assignable}}
+  { v = w; w++; }
 #pragma omp atomic
   x--;
 }

>From 1d7ecaa88c9db05d428f9dca01ffe7c7292ebe44 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Wed, 7 Oct 2026 19:55:31 +0530
Subject: [PATCH 3/4] Add tests for the cases around the erroneous atomic
 statement

Cover other erroneous statement shapes, a const update, a function
template, every atomic form with the same broken statement, and every
atomic form with a variable whose initializer had an error.
---
 clang/test/OpenMP/atomic_messages.c   | 39 ++++++++++++++++++++++
 clang/test/OpenMP/atomic_messages.cpp | 48 +++++++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/clang/test/OpenMP/atomic_messages.c 
b/clang/test/OpenMP/atomic_messages.c
index 48203c5fbbc154..dc0a3ede703309 100644
--- a/clang/test/OpenMP/atomic_messages.c
+++ b/clang/test/OpenMP/atomic_messages.c
@@ -419,9 +419,48 @@ void gh107979(void) {
   // expected-error@+2 {{the statement for 'atomic capture' must be an 
expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v 
= x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x 
and v are both lvalue expressions with scalar type}}
   // expected-note@+1 {{expected a valid expression}}
   v = 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
+  (void)(0--); // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
+  x ? 0-- : 1; // expected-error {{expression is not assignable}}
+  const int c = 0; // expected-note {{variable 'c' declared const here}}
+#pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
+  c += 1; // expected-error {{cannot assign to variable 'c' with 
const-qualified type 'const int'}}
+#pragma omp atomic read
+  0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic write
+  0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  { v = x; 0--; } // expected-error {{expression is not assignable}}
+#ifdef OMP51
+#pragma omp atomic compare
+  // omp51-error@+2 {{the statement for 'atomic compare' must be a compound 
statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : 
x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x 
= expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) 
{x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 
'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'}}
+  // omp51-note@+1 {{expected assignment statement}}
+  0--; // expected-error {{expression is not assignable}}
+#endif
   int w = 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  w++;
+#pragma omp atomic
+  w += 1;
+#pragma omp atomic
+  w = w + 1;
+#pragma omp atomic read
+  v = w;
+#pragma omp atomic write
+  w = 1;
+#pragma omp atomic capture
+  v = w++;
 #pragma omp atomic capture
   { v = w; w++; }
+#pragma omp atomic capture
+  { w++; v = w; }
 #pragma omp atomic
   x--;
 }
diff --git a/clang/test/OpenMP/atomic_messages.cpp 
b/clang/test/OpenMP/atomic_messages.cpp
index 05a51dc76c9cbe..d20dd8bbd0b4a6 100644
--- a/clang/test/OpenMP/atomic_messages.cpp
+++ b/clang/test/OpenMP/atomic_messages.cpp
@@ -1014,9 +1014,57 @@ void gh107979() {
   // expected-error@+2 {{the statement for 'atomic capture' must be an 
expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v 
= x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x 
and v are both lvalue expressions with scalar type}}
   // expected-note@+1 {{expected a valid expression}}
   v = 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
+  (void)(0--); // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
+  x ? 0-- : 1; // expected-error {{expression is not assignable}}
+  const int c = 0; // expected-note {{variable 'c' declared const here}}
+#pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
+  c += 1; // expected-error {{cannot assign to variable 'c' with 
const-qualified type 'const int'}}
+#pragma omp atomic read
+  0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic write
+  0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  { v = x; 0--; } // expected-error {{expression is not assignable}}
+#ifdef OMP51
+#pragma omp atomic compare
+  // omp51-error@+2 {{the statement for 'atomic compare' must be a compound 
statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : 
x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x 
= expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) 
{x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 
'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'}}
+  // omp51-note@+1 {{expected assignment statement}}
+  0--; // expected-error {{expression is not assignable}}
+#endif
   int w = 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  w++;
+#pragma omp atomic
+  w += 1;
+#pragma omp atomic
+  w = w + 1;
+#pragma omp atomic read
+  v = w;
+#pragma omp atomic write
+  w = 1;
+#pragma omp atomic capture
+  v = w++;
 #pragma omp atomic capture
   { v = w; w++; }
+#pragma omp atomic capture
+  { w++; v = w; }
+#pragma omp atomic
+  x--;
+}
+
+template <class T> void gh107979_template(T x) {
+#pragma omp atomic
+  // expected-error@+2 {{the statement for 'atomic' must be an expression 
statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x 
binop expr' or 'x = expr binop x', where x is an lvalue expression with scalar 
type}}
+  // expected-note@+1 {{expected a valid expression}}
+  0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic
   x--;
 }

>From 737cbb3d2d7018cf36673766bae015adbd436983 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Sun, 18 Oct 2026 19:30:15 +0530
Subject: [PATCH 4/4] Skip the update expression when its operands contain
 errors

Building it from a RecoveryExpr produced a
second error, "invalid operands to binary expression ('int' and
'<dependent type>')", for statements such as `x += 0--;`.
---
 clang/lib/Sema/SemaOpenMP.cpp         |  3 ++-
 clang/test/OpenMP/atomic_messages.c   | 10 ++++++++++
 clang/test/OpenMP/atomic_messages.cpp | 10 ++++++++++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index a3be416d2da24f..efe8c9338b5a9e 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -12669,7 +12669,8 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, 
unsigned DiagId,
   }
   if (SemaRef.CurContext->isDependentContext())
     E = X = UpdateExpr = nullptr;
-  if (ErrorFound == NoError && E && X) {
+  if (ErrorFound == NoError && E && X && !E->containsErrors() &&
+      !X->containsErrors()) {
     // Build an update expression of form 'OpaqueValueExpr(x) binop
     // OpaqueValueExpr(expr)' or 'OpaqueValueExpr(expr) binop
     // OpaqueValueExpr(x)' and then cast it to the type of the 'x' expression.
diff --git a/clang/test/OpenMP/atomic_messages.c 
b/clang/test/OpenMP/atomic_messages.c
index dc0a3ede703309..9d42e21984e772 100644
--- a/clang/test/OpenMP/atomic_messages.c
+++ b/clang/test/OpenMP/atomic_messages.c
@@ -438,6 +438,16 @@ void gh107979(void) {
   0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic capture
   { v = x; 0--; } // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  x += 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  x = x + 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  (0--)++; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  v = x += 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  { v = x; x += 0--; } // expected-error {{expression is not assignable}}
 #ifdef OMP51
 #pragma omp atomic compare
   // omp51-error@+2 {{the statement for 'atomic compare' must be a compound 
statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : 
x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x 
= expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) 
{x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 
'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'}}
diff --git a/clang/test/OpenMP/atomic_messages.cpp 
b/clang/test/OpenMP/atomic_messages.cpp
index d20dd8bbd0b4a6..4dd26967f0e3ad 100644
--- a/clang/test/OpenMP/atomic_messages.cpp
+++ b/clang/test/OpenMP/atomic_messages.cpp
@@ -1033,6 +1033,16 @@ void gh107979() {
   0--; // expected-error {{expression is not assignable}}
 #pragma omp atomic capture
   { v = x; 0--; } // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  x += 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  x = x + 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic
+  (0--)++; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  v = x += 0--; // expected-error {{expression is not assignable}}
+#pragma omp atomic capture
+  { v = x; x += 0--; } // expected-error {{expression is not assignable}}
 #ifdef OMP51
 #pragma omp atomic compare
   // omp51-error@+2 {{the statement for 'atomic compare' must be a compound 
statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : 
x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x 
= expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) 
{x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 
'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'}}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to