llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Akash Manna (akash-manna-sky)
<details>
<summary>Changes</summary>
Fixes #<!-- -->223397
`SemaOpenMP::isOpenMPCapturedDecl` figures out whether a global must be
captured for a `target` region by walking the function scope stack down to the
innermost OpenMP captured region, and it stops as soon as it meets an ordinary
function scope. When a directive is finished, the capture initializers of its
outermost region are built after every region has been popped, while the
directive is still on the DSA stack. Inside a function that walk simply ends at
the function's scope. A lambda or block at namespace scope has no scope
underneath it at all, so the walk ran off the end of the stack and tripped the
assertion. The self-referential declaration in the report is incidental: plain
`int &r = x; auto l = [] { #pragma omp target r = 1; };` crashes the same
way, and so do lambdas in default arguments and in variable template
instantiations.
Running out of scopes now means the same thing as reaching a function scope:
the variable is not captured from the current scope, so the walk returns null.
That is exactly what the same lambda already gets when it sits inside a
function, and it matches what the neighbouring walk for the `CheckScopeInfo`
case already does when it finds no OpenMP region.
---
Full diff: https://github.com/llvm/llvm-project/pull/226691.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+1)
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+5-1)
- (added) clang/test/OpenMP/target_global_ref_namespace_scope_lambda.cpp (+55)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index f4a34a37aff52..4164ab1da17f2 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -544,6 +544,7 @@ features cannot lower the translation-unit ABI level;
- Fixed a crash when declaring a member template within a local class inside
an OpenMP region. (#GH216052)
- Fixed a bug where repeated #imports of modular headers in non-modular
compilation were translated to #pragma clang module import. (#GH216924)
- Fixed an assertion when `#pragma omp declare simd` or `#pragma omp declare
variant` is followed by another OpenMP declarative directive containing a
qualified identifier. (#GH217204)
+- Fixed a crash when a reference variable with static storage duration, such
as a global reference, was used in an OpenMP `target` region inside a lambda or
block at namespace scope. (#GH223397)
- Fixed a crash when an `asm` label names the register for a global variable
of incomplete type. (#GH219746)
- Fixed an ICE hat occurred when using `__imag int/float` as lvalue in
assignment. (#GH119498)
- Fixed an assertion failure in `-Wsign-compare` when a negated or
complemented vector of unsigned integers was compared against a signed
constant. (#GH203575)
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 2e4d9f2f82f0b..6cbfe113902a3 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -2473,7 +2473,11 @@ VarDecl *SemaOpenMP::isOpenMPCapturedDecl(ValueDecl *D,
bool CheckScopeInfo,
break;
}
}
- assert(CSI && "Failed to find CapturedRegionScopeInfo");
+ // A lambda or block at namespace scope has no enclosing function scope,
+ // so the walk can run out of scopes once all captured regions of the
+ // directive have been left.
+ if (!CSI)
+ return nullptr;
SmallVector<OpenMPDirectiveKind, 4> Regions;
getOpenMPCaptureRegions(Regions,
DSAStack->getDirective(CSI->OpenMPLevel));
diff --git a/clang/test/OpenMP/target_global_ref_namespace_scope_lambda.cpp
b/clang/test/OpenMP/target_global_ref_namespace_scope_lambda.cpp
new file mode 100644
index 0000000000000..32a7e6dfd74e4
--- /dev/null
+++ b/clang/test/OpenMP/target_global_ref_namespace_scope_lambda.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -verify -fopenmp -fblocks -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fblocks -fsyntax-only %s
+
+// A reference without local storage used in a target region inside a lambda or
+// block at namespace scope used to assert in SemaOpenMP::isOpenMPCapturedDecl.
+
+int x;
+int &ref = x;
+
+auto lambda = []() {
+#pragma omp target
+ ref = 42;
+};
+
+auto nested_lambda = []() {
+ return []() {
+#pragma omp target
+ ref = 42;
+ };
+};
+
+auto combined_directive = []() {
+#pragma omp target teams
+ ref = 42;
+};
+
+auto static_local = []() {
+ static int &local_ref = x;
+#pragma omp target
+ local_ref = 42;
+};
+
+void (^block)() = ^{
+#pragma omp target
+ ref = 42;
+};
+
+void default_argument(int = []() {
+#pragma omp target
+ ref = 42;
+ return 0;
+}());
+
+template <int N> int variable_template = []() {
+#pragma omp target
+ ref = N;
+ return 0;
+}();
+int instantiation = variable_template<1>;
+
+// Reproducer from GH223397.
+int &foo = []() { // expected-error {{non-const lvalue reference to type 'int'
cannot bind to a temporary of type '(lambda at}}
+#pragma omp target
+ foo(42); // expected-error {{called object type 'int' is not a function or
function pointer}}
+};
``````````
</details>
https://github.com/llvm/llvm-project/pull/226691
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits