[clang] [OpenMP] Support capturing structured bindings in OpenMP regions. (PR #190832)

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 26 09:11:47 PDT 2026


================
@@ -4626,43 +4635,89 @@ static bool
 buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI,
                              SmallVectorImpl<CapturedStmt::Capture> &Captures,
                              SmallVectorImpl<Expr *> &CaptureInits) {
+  bool HasError = false; // Track if any errors occurred.
+  llvm::SmallPtrSet<VarDecl *, 4> CapturedDecomposed;
   for (const sema::Capture &Cap : RSI->Captures) {
     if (Cap.isInvalid())
       continue;
 
+    ValueDecl *CapVar = nullptr;
+    if (Cap.isVariableCapture()) {
+      CapVar = Cap.getVariable();
+      if (auto *BD = dyn_cast<BindingDecl>(CapVar)) {
+        // Detect structured bindings in OpenMP captured regions.
+        // When a BindingDecl (e.g., 'a' from 'auto [a, b] = p')
+        // is referenced inside an OpenMP region.
+        // This is reached during capture list construction when processing the
+        // OpenMP region, before expression evaluation in SemaExpr.cpp.
+        // Note: The reset to DecompositionDecl in SemaExpr.cpp happens during
+        // expression evaluation (a later phase). This code runs during capture
+        // list construction (earlier phase).
+        if (RSI->CapRegionKind == CR_OpenMP && BD->getHoldingVar()) {
+          S.Diag(Cap.getLocation(), diag::err_capture_tuple_binding_openmp)
+              << CapVar;
+          S.Diag(CapVar->getLocation(), diag::note_entity_declared_at)
+              << CapVar;
+          HasError = true; // Mark error but continue.
+          continue;        // Skip this capture, move to next.
+        }
+        CapVar = cast<VarDecl>(BD->getDecomposedDecl());
+      }
+      if (RSI->CapRegionKind == CR_OpenMP) {
+        if (auto *DD = dyn_cast<DecompositionDecl>(CapVar)) {
+          if (!CapturedDecomposed.insert(DD).second) {
+            continue; // Skip duplicate
----------------
alexey-bataev wrote:

apturedDecomposed keeps one CapturedStmt::Capture per DecompositionDecl. Cap.isReferenceCapture() comes from whichever binding is captured first. DSA conflicts on mixed clauses are caught (modulo item 1), but if two bindings from the same decomposition ever legitimately need different capture kinds (by-ref vs by-copy), the second is silently dropped. Need to diagnose and reject explicitly.

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


More information about the cfe-commits mailing list