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

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 30 06:13:51 PDT 2026


================
@@ -3771,6 +3771,99 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
   // an enclosing scope.
   if (const auto *BD = dyn_cast<BindingDecl>(ND)) {
     if (E->refersToEnclosingVariableOrCapture()) {
+      // OpenMP case: binding was captured via its decomposed decl.
+      if (auto *DD = dyn_cast<VarDecl>(BD->getDecomposedDecl())) {
+        if (CapturedStmtInfo &&
+            CapturedStmtInfo->getKind() == CapturedRegionKind::CR_OpenMP &&
+            CGM.getLangOpts().OpenMP) {
+          auto I = LocalDeclMap.find(DD);
+          if (I != LocalDeclMap.end()) {
+            Address DDAddr = I->second;
+            llvm::Type *ExpectedTy = CGM.getTypes().ConvertTypeForMem(
+                DD->getType().getCanonicalType());
+            if (DDAddr.getElementType() != ExpectedTy)
+              DDAddr = DDAddr.withElementType(ExpectedTy);
+            LValue CapLVal;
+            if (DD->getType()->isReferenceType())
+              CapLVal = EmitLoadOfReferenceLValue(DDAddr, DD->getType(),
+                                                  AlignmentSource::Decl);
+            else
+              CapLVal =
+                  MakeAddrLValue(DDAddr, DD->getType().getCanonicalType());
+            if (getLangOpts().OpenMP &&
+                CGM.getOpenMPRuntime().isNontemporalDecl(DD))
+              CapLVal.setNontemporal(/*Value=*/true);
+            // Extract the specific binding from the decomposed object.
+            Expr *BindingExpr = BD->getBinding()->IgnoreImplicit();
+            if (auto *ME = dyn_cast<MemberExpr>(BindingExpr)) {
+              // Struct/union: access field.
+              return EmitLValueForField(CapLVal,
+                                        cast<FieldDecl>(ME->getMemberDecl()));
+            }
+            if (auto *ASE = dyn_cast<ArraySubscriptExpr>(BindingExpr)) {
+              Address Base = CapLVal.getAddress();
+              llvm::Value *Idx = EmitScalarExpr(ASE->getIdx());
+              llvm::Value *Indices[] = {llvm::ConstantInt::get(Int32Ty, 0),
+                                        Idx};
+              llvm::Type *ElemTy =
+                  CGM.getTypes().ConvertTypeForMem(ASE->getType());
+              llvm::Value *EltPtr = Builder.CreateInBoundsGEP(
+                  Base.getElementType(), Base.emitRawPointer(*this), Indices,
+                  "arrayidx");
+              CharUnits Align = Base.getAlignment().alignmentOfArrayElement(
+                  getContext().getTypeSizeInChars(ASE->getType()));
+              Address EltAddr(EltPtr, ElemTy, Align);
+              return MakeAddrLValue(EltAddr, ASE->getType());
+            }
+            // Fallback for complex binding types.
+            // TODO: Tuple bindings (std::tuple, std::pair via tuple protocol)
+            // use hidden temporary variables that aren't captured in OpenMP
+            // regions. Need to re-emit the get<N>() call on the captured tuple
+            // base object. For now, this will fail.
+            if (isa<DeclRefExpr>(BindingExpr))
+              llvm_unreachable(
+                  "tuple-like structured bindings not yet supported in OpenMP");
+            return EmitLValue(BindingExpr);
+          }
+          // DD not in LocalDeclMap, check capture struct
+          if (auto *FD = CapturedStmtInfo->lookup(DD)) {
----------------
erichkeane wrote:

Ah, I see the 'else'  here.  We should be checking whether it is captured first and do the work for that, THEN we can use the emit-lvalue type stuff.

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


More information about the cfe-commits mailing list