https://github.com/akash-manna-sky created
https://github.com/llvm/llvm-project/pull/228914
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--;`.
>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] [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 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);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits