https://github.com/zahiraam updated 
https://github.com/llvm/llvm-project/pull/190832

>From ca43027b4156c15d34c7b6b75ed8420ccc0c1f2e Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Tue, 7 Apr 2026 12:10:39 -0700
Subject: [PATCH 1/3] [OpenMP] Support capturing structured bindings in OpenMP
 regions.

---
 clang/lib/CodeGen/CGExpr.cpp                  |  18 ++-
 clang/lib/Sema/SemaExpr.cpp                   |  16 +-
 clang/lib/Sema/SemaStmt.cpp                   |   5 +-
 .../OpenMP/structured-binding-capture.cpp     | 141 ++++++++++++++++++
 4 files changed, 169 insertions(+), 11 deletions(-)
 create mode 100644 clang/test/OpenMP/structured-binding-capture.cpp

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 23802cdeb4811..b2feb5d339a8e 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3737,8 +3737,22 @@ LValue CodeGenFunction::EmitDeclRefLValue(const 
DeclRefExpr *E) {
   // an enclosing scope.
   if (const auto *BD = dyn_cast<BindingDecl>(ND)) {
     if (E->refersToEnclosingVariableOrCapture()) {
-      auto *FD = LambdaCaptureFields.lookup(BD);
-      return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
+      if (auto *DD = dyn_cast<VarDecl>(BD->getDecomposedDecl())) {
+        auto I = LocalDeclMap.find(DD);
+        if (I != LocalDeclMap.end()) {
+          Address DDAddr = I->second;
+          llvm::Type *StructTy = CGM.getTypes().ConvertTypeForMem(
+              DD->getType().getCanonicalType());
+          if (DDAddr.getElementType() != StructTy)
+            DDAddr = DDAddr.withElementType(StructTy);
+          LValue BaseLV =
+              MakeAddrLValue(DDAddr, DD->getType().getCanonicalType());
+          return EmitLValueForField(
+              BaseLV, cast<FieldDecl>(
+                          cast<MemberExpr>(BD->getBinding()->IgnoreImplicit())
+                              ->getMemberDecl()));
+        }
+      }
     }
     // Suppress debug location updates when visiting the binding, since the
     // binding may emit instructions that would otherwise be associated with 
the
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index c9642ed298bf3..46a93b8e53d3e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19374,6 +19374,8 @@ static bool isVariableCapturable(CapturingScopeInfo 
*CSI, ValueDecl *Var,
   }
 
   if (isa<BindingDecl>(Var)) {
+      if (Var->getDeclName() && !Var->isImplicit())
+          return true;
     if (!IsLambda || !S.getLangOpts().CPlusPlus) {
       if (Diagnose)
         diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var);
@@ -19514,6 +19516,12 @@ static bool captureInLambda(LambdaScopeInfo *LSI, 
ValueDecl *Var,
     ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
   }
 
+  if (auto* BD = dyn_cast<BindingDecl>(Var)) {
+    // For structured bindings, capture the individual element type,
+    // not the full decomposed type.
+    CaptureType = BD->getType();
+    DeclRefType = BD->getType();
+  }
   if (BuildAndDiagnose && S.Context.getTargetInfo().getTriple().isWasm() &&
       CaptureType.getNonReferenceType().isWebAssemblyReferenceType()) {
     S.Diag(Loc, diag::err_wasm_ca_reference) << 0;
@@ -19880,14 +19888,6 @@ bool Sema::tryCaptureVariable(
         // just break here. Similarly, global variables that are captured in a
         // target region should not be captured outside the scope of the 
region.
         if (RSI->CapRegionKind == CR_OpenMP) {
-          // FIXME: We should support capturing structured bindings in OpenMP.
-          if (isa<BindingDecl>(Var)) {
-            if (BuildAndDiagnose) {
-              Diag(ExprLoc, diag::err_capture_binding_openmp) << Var;
-              Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
-            }
-            return true;
-          }
           OpenMPClauseKind IsOpenMPPrivateDecl = OpenMP().isOpenMPPrivateDecl(
               Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel);
           // If the variable is private (i.e. not captured) and has variably
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 531147ef35b08..21c799b89a64a 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4700,11 +4700,14 @@ buildCapturedStmtCaptureList(Sema &S, 
CapturedRegionScopeInfo *RSI,
         S.OpenMP().setOpenMPCaptureKind(Field, Cap.getVariable(),
                                         RSI->OpenMPLevel);
 
+      ValueDecl* CapVar = Cap.getVariable();
+      if (auto* BD = dyn_cast<BindingDecl>(CapVar))
+        CapVar = cast<VarDecl>(BD->getDecomposedDecl());
       Captures.push_back(CapturedStmt::Capture(
           Cap.getLocation(),
           Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef
                                    : CapturedStmt::VCK_ByCopy,
-          cast<VarDecl>(Cap.getVariable())));
+          cast<VarDecl>(CapVar)));
     }
     CaptureInits.push_back(Init.get());
   }
diff --git a/clang/test/OpenMP/structured-binding-capture.cpp 
b/clang/test/OpenMP/structured-binding-capture.cpp
new file mode 100644
index 0000000000000..5d3fae741958b
--- /dev/null
+++ b/clang/test/OpenMP/structured-binding-capture.cpp
@@ -0,0 +1,141 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --include-generated-funcs --replace-value-regex 
"__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" 
"pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ --version 4
+// RUN: %clang_cc1 -verify -std=c++20 -triple x86_64-pc-linux-gnu -fopenmp \
+// RUN: -emit-llvm %s -o - | FileCheck %s
+
+// expected-no-diagnostics
+
+struct Point {
+  int first, second;
+};
+
+Point twoints() {
+  return {37, 24};
+}
+
+int main() {
+  auto [m, n] = twoints();
+#pragma omp parallel for collapse(2)
+  for (int i = 0; i < 10; i++)
+    for (int j = 0; j < 10; j++)
+      [m, n](int i, int j) -> void { return; }(i, j);
+  return 0;
+}
+
+// CHECK-LABEL: define dso_local i64 @_Z7twointsv(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[RETVAL:%.*]] = alloca [[STRUCT_POINT:%.*]], align 4
+// CHECK-NEXT:    [[FIRST:%.*]] = getelementptr inbounds nuw [[STRUCT_POINT]], 
ptr [[RETVAL]], i32 0, i32 0
+// CHECK-NEXT:    store i32 37, ptr [[FIRST]], align 4
+// CHECK-NEXT:    [[SECOND:%.*]] = getelementptr inbounds nuw 
[[STRUCT_POINT]], ptr [[RETVAL]], i32 0, i32 1
+// CHECK-NEXT:    store i32 24, ptr [[SECOND]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    ret i64 [[TMP0]]
+//
+//
+// CHECK-LABEL: define dso_local noundef i32 @main(
+// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = alloca [[STRUCT_POINT:%.*]], align 4
+// CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    [[CALL:%.*]] = call i64 @_Z7twointsv()
+// CHECK-NEXT:    store i64 [[CALL]], ptr [[TMP0]], align 4
+// CHECK-NEXT:    [[FIRST:%.*]] = getelementptr inbounds nuw [[STRUCT_POINT]], 
ptr [[TMP0]], i32 0, i32 0
+// CHECK-NEXT:    [[SECOND:%.*]] = getelementptr inbounds nuw 
[[STRUCT_POINT]], ptr [[TMP0]], i32 0, i32 1
+// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr 
@[[GLOB2:[0-9]+]], i32 2, ptr @main.omp_outlined, ptr [[FIRST]], ptr [[SECOND]])
+// CHECK-NEXT:    ret i32 0
+//
+//
+// CHECK-LABEL: define internal void @main.omp_outlined(
+// CHECK-SAME: ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef 
[[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) 
[[TMP0:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[TMP1:%.*]]) 
#[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTADDR1:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[TMP:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[_TMP2:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[J:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[CLASS_ANON:%.*]], align 4
+// CHECK-NEXT:    store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], 
align 8
+// CHECK-NEXT:    store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], 
align 8
+// CHECK-NEXT:    store ptr [[TMP0]], ptr [[DOTADDR]], align 8
+// CHECK-NEXT:    store ptr [[TMP1]], ptr [[DOTADDR1]], align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8, !nonnull 
[[META2:![0-9]+]], !align [[META3:![0-9]+]]
+// CHECK-NEXT:    [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8, !nonnull 
[[META2]], !align [[META3]]
+// CHECK-NEXT:    store i32 0, ptr [[DOTOMP_LB]], align 4
+// CHECK-NEXT:    store i32 99, ptr [[DOTOMP_UB]], align 4
+// CHECK-NEXT:    store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// CHECK-NEXT:    store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
+// CHECK-NEXT:    call void @__kmpc_for_static_init_4(ptr @[[GLOB1:[0-9]+]], 
i32 [[TMP5]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr 
[[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// CHECK-NEXT:    [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[TMP6]], 99
+// CHECK-NEXT:    br i1 [[CMP]], label [[COND_TRUE:%.*]], label 
[[COND_FALSE:%.*]]
+// CHECK:       cond.true:
+// CHECK-NEXT:    br label [[COND_END:%.*]]
+// CHECK:       cond.false:
+// CHECK-NEXT:    [[TMP7:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// CHECK-NEXT:    br label [[COND_END]]
+// CHECK:       cond.end:
+// CHECK-NEXT:    [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP7]], 
[[COND_FALSE]] ]
+// CHECK-NEXT:    store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
+// CHECK-NEXT:    [[TMP8:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
+// CHECK-NEXT:    store i32 [[TMP8]], ptr [[DOTOMP_IV]], align 4
+// CHECK-NEXT:    br label [[OMP_INNER_FOR_COND:%.*]]
+// CHECK:       omp.inner.for.cond:
+// CHECK-NEXT:    [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK-NEXT:    [[TMP10:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// CHECK-NEXT:    [[CMP3:%.*]] = icmp sle i32 [[TMP9]], [[TMP10]]
+// CHECK-NEXT:    br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label 
[[OMP_INNER_FOR_END:%.*]]
+// CHECK:       omp.inner.for.body:
+// CHECK-NEXT:    [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[TMP11]], 10
+// CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
+// CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// CHECK-NEXT:    store i32 [[ADD]], ptr [[I]], align 4
+// CHECK-NEXT:    [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK-NEXT:    [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK-NEXT:    [[DIV4:%.*]] = sdiv i32 [[TMP13]], 10
+// CHECK-NEXT:    [[MUL5:%.*]] = mul nsw i32 [[DIV4]], 10
+// CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[TMP12]], [[MUL5]]
+// CHECK-NEXT:    [[MUL6:%.*]] = mul nsw i32 [[SUB]], 1
+// CHECK-NEXT:    [[ADD7:%.*]] = add nsw i32 0, [[MUL6]]
+// CHECK-NEXT:    store i32 [[ADD7]], ptr [[J]], align 4
+// CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds nuw [[CLASS_ANON]], 
ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[FIRST:%.*]] = getelementptr inbounds nuw 
[[STRUCT_POINT:%.*]], ptr [[TMP2]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP15:%.*]] = load i32, ptr [[FIRST]], align 4
+// CHECK-NEXT:    store i32 [[TMP15]], ptr [[TMP14]], align 4
+// CHECK-NEXT:    [[TMP16:%.*]] = getelementptr inbounds nuw [[CLASS_ANON]], 
ptr [[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT:    [[SECOND:%.*]] = getelementptr inbounds nuw 
[[STRUCT_POINT]], ptr [[TMP2]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP17:%.*]] = load i32, ptr [[SECOND]], align 4
+// CHECK-NEXT:    store i32 [[TMP17]], ptr [[TMP16]], align 4
+// CHECK-NEXT:    [[TMP18:%.*]] = load i32, ptr [[I]], align 4
+// CHECK-NEXT:    [[TMP19:%.*]] = load i32, ptr [[J]], align 4
+// CHECK-NEXT:    call void @"_ZZ4mainENK3$_0clEii"(ptr noundef nonnull align 
4 dereferenceable(8) [[REF_TMP]], i32 noundef [[TMP18]], i32 noundef [[TMP19]])
+// CHECK-NEXT:    br label [[OMP_BODY_CONTINUE:%.*]]
+// CHECK:       omp.body.continue:
+// CHECK-NEXT:    br label [[OMP_INNER_FOR_INC:%.*]]
+// CHECK:       omp.inner.for.inc:
+// CHECK-NEXT:    [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK-NEXT:    [[ADD8:%.*]] = add nsw i32 [[TMP20]], 1
+// CHECK-NEXT:    store i32 [[ADD8]], ptr [[DOTOMP_IV]], align 4
+// CHECK-NEXT:    br label [[OMP_INNER_FOR_COND]]
+// CHECK:       omp.inner.for.end:
+// CHECK-NEXT:    br label [[OMP_LOOP_EXIT:%.*]]
+// CHECK:       omp.loop.exit:
+// CHECK-NEXT:    call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 
[[TMP5]])
+// CHECK-NEXT:    ret void
+//
+//.
+// CHECK: [[META2]] = !{}
+// CHECK: [[META3]] = !{i64 4}
+//.

>From cc2b511f39d5f96318960733aa92cecdeacd7b62 Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Tue, 7 Apr 2026 12:31:59 -0700
Subject: [PATCH 2/3] Fix format

---
 clang/lib/Sema/SemaExpr.cpp |  6 +++---
 clang/lib/Sema/SemaStmt.cpp | 14 +++++++-------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 46a93b8e53d3e..2fb31c3a8c861 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19374,8 +19374,8 @@ static bool isVariableCapturable(CapturingScopeInfo 
*CSI, ValueDecl *Var,
   }
 
   if (isa<BindingDecl>(Var)) {
-      if (Var->getDeclName() && !Var->isImplicit())
-          return true;
+    if (Var->getDeclName() && !Var->isImplicit())
+      return true;
     if (!IsLambda || !S.getLangOpts().CPlusPlus) {
       if (Diagnose)
         diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var);
@@ -19516,7 +19516,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI, 
ValueDecl *Var,
     ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
   }
 
-  if (auto* BD = dyn_cast<BindingDecl>(Var)) {
+  if (auto *BD = dyn_cast<BindingDecl>(Var)) {
     // For structured bindings, capture the individual element type,
     // not the full decomposed type.
     CaptureType = BD->getType();
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 21c799b89a64a..b3521741ddebc 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4700,14 +4700,14 @@ buildCapturedStmtCaptureList(Sema &S, 
CapturedRegionScopeInfo *RSI,
         S.OpenMP().setOpenMPCaptureKind(Field, Cap.getVariable(),
                                         RSI->OpenMPLevel);
 
-      ValueDecl* CapVar = Cap.getVariable();
-      if (auto* BD = dyn_cast<BindingDecl>(CapVar))
+      ValueDecl *CapVar = Cap.getVariable();
+      if (auto *BD = dyn_cast<BindingDecl>(CapVar))
         CapVar = cast<VarDecl>(BD->getDecomposedDecl());
-      Captures.push_back(CapturedStmt::Capture(
-          Cap.getLocation(),
-          Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef
-                                   : CapturedStmt::VCK_ByCopy,
-          cast<VarDecl>(CapVar)));
+      Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
+                                               Cap.isReferenceCapture()
+                                                   ? CapturedStmt::VCK_ByRef
+                                                   : CapturedStmt::VCK_ByCopy,
+                                              cast<VarDecl>(CapVar)));
     }
     CaptureInits.push_back(Init.get());
   }

>From 9a6568a6f6797f8011d3a1d67ab873deaa7c7bde Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Wed, 8 Apr 2026 06:11:38 -0700
Subject: [PATCH 3/3] Fix the failures

---
 clang/lib/CodeGen/CGExpr.cpp                   |  2 ++
 clang/lib/Sema/SemaExpr.cpp                    |  2 +-
 clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp |  8 --------
 clang/test/SemaCXX/cxx1z-decomposition.cpp     | 14 ++++++--------
 clang/test/SemaCXX/decomposition-openmp.cpp    |  7 ++++---
 5 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index b2feb5d339a8e..1e74e49702932 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3752,6 +3752,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const 
DeclRefExpr *E) {
                           cast<MemberExpr>(BD->getBinding()->IgnoreImplicit())
                               ->getMemberDecl()));
         }
+        auto *FD = LambdaCaptureFields.lookup(BD);
+        return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
       }
     }
     // Suppress debug location updates when visiting the binding, since the
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2fb31c3a8c861..d7a4f00fd36d7 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19374,7 +19374,7 @@ static bool isVariableCapturable(CapturingScopeInfo 
*CSI, ValueDecl *Var,
   }
 
   if (isa<BindingDecl>(Var)) {
-    if (Var->getDeclName() && !Var->isImplicit())
+    if (Var->getDeclName() && !Var->isImplicit() && !IsBlock)
       return true;
     if (!IsLambda || !S.getLangOpts().CPlusPlus) {
       if (Diagnose)
diff --git a/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp 
b/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
index aa8d055e44971..6d54ae5dc4a30 100644
--- a/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ b/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -385,10 +385,6 @@ namespace GH145956 {
     Pair p = {1, 2};
     auto const& [key, value] = p;
     return [&] { return key; }();
-#if __cpp_constexpr < 202002L
-    // expected-warning@-2 {{captured structured bindings are a C++20 
extension}}
-    // expected-note@-4 {{'key' declared here}}
-#endif
   }
   static_assert(f() == 1);
   constexpr auto retlambda() {
@@ -396,10 +392,6 @@ namespace GH145956 {
     Pair p = {1, 2};
     auto const& [key, value] = p;
     return [=] { return key; };
-#if __cpp_constexpr < 202002L
-    // expected-warning@-2 {{captured structured bindings are a C++20 
extension}}
-    // expected-note@-4 {{'key' declared here}}
-#endif
   }
   constexpr auto lambda = retlambda();
   static_assert(lambda() == 1);
diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp 
b/clang/test/SemaCXX/cxx1z-decomposition.cpp
index 6425f1ee7796e..b022fc9222417 100644
--- a/clang/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp
@@ -67,14 +67,14 @@ auto [outerbit1, outerbit2] = S1{1, 2}; // expected-note 
{{declared here}}
 
 void enclosing() {
   struct S { int a = outer1; };
-  auto [n] = S(); // expected-note 3{{'n' declared here}}
+  auto [n] = S(); // expected-note {{'n' declared here}}
 
   struct Q {
     int f() { return n; } // expected-error {{reference to local binding 'n' 
declared in enclosing function 'enclosing'}}
   };
 
-  (void)[&] { return n; }; // expected-warning {{C++20}}
-  (void)[n] { return n; }; // expected-warning {{C++20}}
+  (void)[&] { return n; };
+  (void)[n] { return n; };
 
   static auto [m] = S(); // expected-note {{'m' declared here}} \
                          // expected-warning {{C++20}}
@@ -85,10 +85,9 @@ void enclosing() {
 
   (void)[outerbit1]{}; // expected-error {{'outerbit1' cannot be captured 
because it does not have automatic storage duration}}
 
-  auto [bit, var] = S2{-1, 1}; // expected-note 2{{'bit' declared here}}
+  auto [bit, var] = S2{-1, 1};
 
-  (void)[&bit] { // expected-error {{non-const reference cannot bind to 
bit-field 'a'}} \
-                    // expected-warning {{C++20}}
+  (void)[&bit] { // expected-error {{non-const reference cannot bind to 
bit-field 'a'}}
     return bit;
   };
 
@@ -97,8 +96,7 @@ void enclosing() {
   };
 
   (void)[&] { return bit + u; } // expected-error {{unnamed variable cannot be 
implicitly captured in a lambda expression}} \
-                                // expected-error {{non-const reference cannot 
bind to bit-field 'a'}} \
-                                // expected-warning {{C++20}}
+                                // expected-error {{non-const reference cannot 
bind to bit-field 'a'}}
   ();
 }
 
diff --git a/clang/test/SemaCXX/decomposition-openmp.cpp 
b/clang/test/SemaCXX/decomposition-openmp.cpp
index 2185f3db83d4e..7a379c2d3b1ce 100644
--- a/clang/test/SemaCXX/decomposition-openmp.cpp
+++ b/clang/test/SemaCXX/decomposition-openmp.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 -fopenmp %s
 
+// expected-no-diagnostics
+
 // Okay, not an OpenMP capture.
 auto f() {
   int i[2] = {};
@@ -20,13 +22,12 @@ void g() {
   }
 }
 
-// FIXME: OpenMP should support capturing structured bindings
+// Okay.
 void h() {
   int i[2] = {};
-  auto [a, b] = i; // expected-note 2{{declared here}}
+  auto [a, b] = i;
   #pragma omp parallel
   {
-    // expected-error@+1 2{{capturing a structured binding is not yet 
supported in OpenMP}}
     foo(a + b);
   }
 }

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

Reply via email to