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

Zahira Ammarguellat via cfe-commits cfe-commits at lists.llvm.org
Mon May 4 10:08:26 PDT 2026


================
@@ -3589,6 +3589,51 @@ static bool canEmitSpuriousReferenceToVariable(CodeGenFunction &CGF,
   }
 }
 
+/// Emit an LValue for a structured binding captured in an OpenMP region.
+/// Handles extracting individual bindings from the captured decomposed
+/// declaration (struct fields, array elements, etc.).
+LValue CodeGenFunction::EmitOMPCapturedBindingLValue(const BindingDecl *BD) {
+  assert(CapturedStmtInfo &&
+         CapturedStmtInfo->getKind() == CapturedRegionKind::CR_OpenMP &&
+         CGM.getLangOpts().OpenMP);
+  auto *DD = cast<VarDecl>(BD->getDecomposedDecl());
+  QualType AggregType = DD->getType();
+  if (AggregType->isReferenceType())
+    AggregType = AggregType->getPointeeType();
+  DeclarationNameInfo NameInfo(DD->getDeclName(), SourceLocation());
+  DeclRefExpr *DRE = DeclRefExpr::Create(
+      getContext(), NestedNameSpecifierLoc(), SourceLocation(), DD,
+      /*RefersToEnclosingVariableOrCapture=*/false, NameInfo, AggregType,
+      VK_LValue);
+  LValue CapLVal = EmitLValue(DRE);
+
+  // Extract the specific binding from the decomposed object.
+  Expr *BindingExpr = BD->getBinding()->IgnoreImplicit();
+  if (auto *ME = dyn_cast<MemberExpr>(BindingExpr)) {
+    // Struct/union: access field.
+    FieldDecl *Field = cast<FieldDecl>(ME->getMemberDecl());
+    return EmitLValueForField(CapLVal, Field);
+  } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(BindingExpr)) {
----------------
zahiraam wrote:

I understand you want the decay operation in the AST rather than manual GEP in codegen. 
I rebuilt the binding expression in `BuildCaptureInit` with the correct pointer type for arrays, but that expression is only used for capture initialization. When  `EmitOMPCapturedBindingLValue` later calls `EmitLValue(BD->getBinding())`, it uses the original binding expression from the `BindingDecl`, which still has the array type and decay cast.
```
Binding expression class: ArraySubscriptExpr
Binding expression:
ArraySubscriptExpr 0x13efbbfab48 'int' lvalue
|-ImplicitCastExpr 0x13efbbfab30 'int *' <ArrayToPointerDecay>
| `-DeclRefExpr 0x13efbbfaae8 'int[2]' lvalue Decomposition 0x13efbbfa960 first_binding 'x' 'int[2]'
`-IntegerLiteral 0x13efbbfab08 'int' 0
```

```
Binding expression class: ArraySubscriptExpr
Binding expression:
ArraySubscriptExpr 0x13efbbfabc8 'int' lvalue
|-ImplicitCastExpr 0x13efbbfabb0 'int *' <ArrayToPointerDecay>
| `-DeclRefExpr 0x13efbbfab68 'int[2]' lvalue Decomposition 0x13efbbfa960 first_binding 'x' 'int[2]'
`-IntegerLiteral 0x13efbbfab88 'int' 1
```
Should we:                                                                                                                                                                                                    
 1. Store the rebuilt expression somewhere accessible to codegen (where?)
 2. Modify the BindingDecl's binding expression itself for OpenMP contexts (seems risky since it's shared across contexts).
 3. A different solution I am not seeing?

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


More information about the cfe-commits mailing list