[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