cor3ntin created this revision.
Herald added subscribers: carlosgalvezp, martong, arphaman, zzheng.
Herald added a reviewer: shafik.
Herald added a project: All.
cor3ntin requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: cfe-commits, sstefan1.
Herald added projects: clang, clang-tools-extra.

This completes the implementation of P1091R3 and P1381R1.

This patch allow the capture of structured bindings
both for C++20+ and C++17, with extension/compat warning.

In addition, capturing an anonymous union member,
a bitfield, or a structured binding thereof now has a
better diagnostic.

Fixes https://github.com/llvm/llvm-project/issues/54300
Fixes https://github.com/llvm/llvm-project/issues/54300
Fixes https://github.com/llvm/llvm-project/issues/52720


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122768

Files:
  clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/DeclCXX.h
  clang/include/clang/AST/LambdaCapture.h
  clang/include/clang/AST/Stmt.h
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/ScopeInfo.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/DeclCXX.cpp
  clang/lib/AST/ExprCXX.cpp
  clang/lib/AST/ExprConstant.cpp
  clang/lib/AST/Stmt.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/Analysis/AnalysisDeclContext.cpp
  clang/lib/CodeGen/CGDebugInfo.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CGOpenMPRuntime.cpp
  clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Sema/ScopeInfo.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaLambda.cpp
  clang/lib/Sema/SemaOpenMP.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTWriter.cpp
  clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  clang/test/SemaCXX/cxx1z-decomposition.cpp
  clang/test/SemaCXX/decomposition-blocks.cpp
  clang/tools/libclang/CIndex.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1144,7 +1144,7 @@
     <tr>
       <td rowspan="2">Structured binding extensions</td>
       <td><a href="https://wg21.link/p1091r3";>P1091R3</a></td>
-      <td rowspan="2" class="partial" align="center">Partial</td>
+      <td rowspan="2" class="unreleased" align="center">Clang 15</td>
     </tr>
       <tr>
         <td><a href="https://wg21.link/p1381r1";>P1381R1</a></td>
Index: clang/tools/libclang/CIndex.cpp
===================================================================
--- clang/tools/libclang/CIndex.cpp
+++ clang/tools/libclang/CIndex.cpp
@@ -3350,9 +3350,10 @@
            C != CEnd; ++C) {
         if (!C->capturesVariable())
           continue;
-
-        if (Visit(MakeCursorVariableRef(C->getCapturedVar(), C->getLocation(),
-                                        TU)))
+        // TODO: hamdle structured bindings here ?
+        if (!isa<VarDecl>(C->getCapturedVar()))
+            continue;
+        if(Visit(MakeCursorVariableRef(cast<VarDecl>(C->getCapturedVar()), C->getLocation(), TU)))
           return true;
       }
       // Visit init captures
Index: clang/test/SemaCXX/decomposition-blocks.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/decomposition-blocks.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s -fblocks
+
+struct S {
+    int i : 1;
+    int j;
+};
+
+void run(void (^)());
+void test() {
+auto [i, j] = S{1, 42}; // expected-note {{'i' declared here}}
+run(^{ (void) i; }); // expected-error {{reference to local binding 'i' declared in enclosing function 'test'}}
+}
Index: clang/test/SemaCXX/cxx1z-decomposition.cpp
===================================================================
--- clang/test/SemaCXX/cxx1z-decomposition.cpp
+++ clang/test/SemaCXX/cxx1z-decomposition.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++17 -Wc++20-extensions -verify=expected %s
+// RUN: %clang_cc1 -std=c++20 -Wpre-c++20-compat -verify=expected %s
 
 void use_from_own_init() {
   auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}}
@@ -46,27 +47,60 @@
 }
 static_assert(f({1, 2}) == 12);
 
-constexpr bool g(S &&s) { 
+constexpr bool g(S &&s) {
   auto &[a, b] = s;
   return &a == &s.a && &b == &s.b && &a != &b;
 }
 static_assert(g({1, 2}));
 
-auto [outer1, outer2] = S{1, 2};
+struct S1 {
+  int a, b;
+};
+struct S2 {
+  int a : 1; // expected-note 2{{bit-field is declared here}}
+  int b;
+};
+
+
+auto [outer1, outer2] = S1{1, 2};
+auto [outerbit1, outerbit2] = S1{1, 2}; // expected-note {{declared here}}
+
 void enclosing() {
   struct S { int a = outer1; };
-  auto [n] = S(); // expected-note 2{{'n' declared here}}
+  auto [n] = S(); // expected-note 3{{'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}}
 
-  struct Q { int f() { return n; } }; // expected-error {{reference to local binding 'n' declared in enclosing function}}
-  (void) [&] { return n; }; // expected-error {{reference to local binding 'n' declared in enclosing function}}
-  (void) [n] {}; // expected-error {{'n' in capture list does not name a variable}}
+  static auto [m] = S(); // expected-note {{'m' declared here}} \
+                         // expected-warning {{C++20}}
 
-  static auto [m] = S(); // expected-warning {{extension}}
   struct R { int f() { return m; } };
   (void) [&] { return m; };
-  (void) [m] {}; // expected-error {{'m' in capture list does not name a variable}}
+  (void) [m] {}; // expected-error {{'m' cannot be captured because it does not have automatic storage duration}}
+
+  (void) [outerbit1] {};  // expected-error {{'outerbit1' cannot be captured because it does not have automatic storage duration}}
+
+  auto [bit, var] = S2{1, 1}; // expected-note 4{{'bit' declared here}}
+
+  (void) [&bit] {   // expected-error {{cannot capture a bit-field by reference}} \
+                    // expected-warning {{C++20}}
+      return bit;
+  };
+
+  union { // expected-note {{declared here}}
+    int u;
+  };
+
+  (void)[&] { return bit + u; } // expected-error {{unnamed variable cannot be implicitly captured in a lambda expression}} \
+                                // expected-error {{cannot capture a bit-field by reference}} \
+                                // expected-warning {{C++20}}
+  ();
 }
 
+
 void bitfield() {
   struct { int a : 3, : 4, b : 5; } a;
   auto &[x, y] = a;
@@ -98,7 +132,7 @@
 
 struct PR37352 {
   int n;
-  void f() { static auto [a] = *this; } // expected-warning {{C++20 extension}}
+  void f() { static auto [a] = *this; } // expected-warning {{C++20}}
 };
 
 namespace instantiate_template {
Index: clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -175,7 +175,7 @@
   const CXXRecordDecl *LambdaCXXRec = MD->getParent();
 
   // Lookup the fields of the lambda
-  llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+  llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
   FieldDecl *LambdaThisCaptureField;
   LambdaCXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
 
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -2553,7 +2553,7 @@
         MD->getParent()->isLambda()) {
       // Lookup the field of the lambda.
       const CXXRecordDecl *CXXRec = MD->getParent();
-      llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+      llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
       FieldDecl *LambdaThisCaptureField;
       CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
 
Index: clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
@@ -57,7 +57,7 @@
   void visitLambdaExpr(LambdaExpr *L) const {
     for (const LambdaCapture &C : L->captures()) {
       if (C.capturesVariable()) {
-        VarDecl *CapturedVar = C.getCapturedVar();
+        ValueDecl *CapturedVar = C.getCapturedVar();
         if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) {
           Optional<bool> IsUncountedPtr = isUncountedPtr(CapturedVarType);
           if (IsUncountedPtr && *IsUncountedPtr) {
@@ -68,7 +68,7 @@
     }
   }
 
-  void reportBug(const LambdaCapture &Capture, VarDecl *CapturedVar,
+  void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
                  const Type *T) const {
     assert(CapturedVar);
 
Index: clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -504,7 +504,7 @@
   // Treat local variables captured by reference in C++ lambdas as escaped.
   void findLambdaReferenceCaptures(const LambdaExpr *LE)  {
     const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
-    llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
+    llvm::DenseMap<const ValueDecl *, FieldDecl *> CaptureFields;
     FieldDecl *ThisCaptureField;
     LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
 
@@ -512,14 +512,14 @@
       if (!C.capturesVariable())
         continue;
 
-      VarDecl *VD = C.getCapturedVar();
+      ValueDecl *VD = C.getCapturedVar();
       const FieldDecl *FD = CaptureFields[VD];
-      if (!FD)
+      if (!FD || !isa<VarDecl>(VD))
         continue;
 
       // If the capture field is a reference type, it is capture-by-reference.
       if (FD->getType()->isReferenceType())
-        Escaped.insert(VD);
+        Escaped.insert(cast<VarDecl>(VD));
     }
   }
 };
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -5780,7 +5780,7 @@
         break;
       case LCK_ByCopy:
       case LCK_ByRef:
-        VarDecl *Var =
+        ValueDecl *Var =
             Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr;
         AddDeclRef(Var);
         AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc()
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -12881,7 +12881,7 @@
       continue;
 
     TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()];
-    VarDecl *OldVD = C->getCapturedVar();
+    VarDecl *OldVD = cast<VarDecl>(C->getCapturedVar());
 
     auto SubstInitCapture = [&](SourceLocation EllipsisLoc,
                                 Optional<unsigned> NumExpansions) {
@@ -12898,7 +12898,7 @@
           getSema().buildLambdaInitCaptureInitialization(
               C->getLocation(), OldVD->getType()->isReferenceType(),
               EllipsisLoc, NumExpansions, OldVD->getIdentifier(),
-              C->getCapturedVar()->getInitStyle() != VarDecl::CInit,
+              cast<VarDecl>(C->getCapturedVar())->getInitStyle() != VarDecl::CInit,
               NewExprInit);
       Result.Expansions.push_back(
           InitCaptureInfoTy(NewExprInit, NewInitCaptureType));
@@ -13065,7 +13065,7 @@
     if (E->isInitCapture(C)) {
       TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()];
 
-      VarDecl *OldVD = C->getCapturedVar();
+      VarDecl *OldVD = cast<VarDecl>(C->getCapturedVar());
       llvm::SmallVector<Decl*, 4> NewVDs;
 
       for (InitCaptureInfoTy &Info : NewC.Expansions) {
@@ -13120,7 +13120,7 @@
         // The transform has determined that we should perform an expansion;
         // transform and capture each of the arguments.
         // expansion of the pattern. Do so.
-        VarDecl *Pack = C->getCapturedVar();
+        VarDecl *Pack = cast<VarDecl>(C->getCapturedVar());
         for (unsigned I = 0; I != *NumExpansions; ++I) {
           Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
           VarDecl *CapturedVar
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -4693,7 +4693,7 @@
                                                Cap.isReferenceCapture()
                                                    ? CapturedStmt::VCK_ByRef
                                                    : CapturedStmt::VCK_ByCopy,
-                                               Cap.getVariable()));
+                                               cast<VarDecl>(Cap.getVariable())));
     }
     CaptureInits.push_back(Init.get());
   }
Index: clang/lib/Sema/SemaOpenMP.cpp
===================================================================
--- clang/lib/Sema/SemaOpenMP.cpp
+++ clang/lib/Sema/SemaOpenMP.cpp
@@ -4485,12 +4485,12 @@
       DSAStack->setForceCaptureByReferenceInTargetExecutable(
           /*V=*/true);
       if (RD->isLambda()) {
-        llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+        llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
         FieldDecl *ThisCapture;
         RD->getCaptureFields(Captures, ThisCapture);
         for (const LambdaCapture &LC : RD->captures()) {
           if (LC.getCaptureKind() == LCK_ByRef) {
-            VarDecl *VD = LC.getCapturedVar();
+            VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
             DeclContext *VDC = VD->getDeclContext();
             if (!VDC->Encloses(CurContext))
               continue;
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -1088,7 +1088,7 @@
     if (C->Init.isInvalid())
       continue;
 
-    VarDecl *Var = nullptr;
+    ValueDecl *Var = nullptr;
     if (C->Init.isUsable()) {
       Diag(C->Loc, getLangOpts().CPlusPlus14
                        ? diag::warn_cxx11_compat_init_capture
@@ -1166,7 +1166,10 @@
           continue;
       }
 
-      Var = R.getAsSingle<VarDecl>();
+      if(auto BD = R.getAsSingle<BindingDecl>())
+          Var = BD;
+      else
+          Var = R.getAsSingle<VarDecl>();
       if (Var && DiagnoseUseOfDecl(Var, C->Loc))
         continue;
     }
@@ -1200,7 +1203,14 @@
     if (Var->isInvalidDecl())
       continue;
 
-    if (!Var->hasLocalStorage()) {
+    VarDecl* Underlying;
+    if(isa<BindingDecl>(Var)) {
+        Underlying = dyn_cast_or_null<VarDecl>(cast<BindingDecl>(Var)->getDecomposedDecl());
+    }
+    else
+        Underlying = cast<VarDecl>(Var);
+
+    if (!Underlying->hasLocalStorage()) {
       Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
       Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
       continue;
@@ -1224,7 +1234,7 @@
     }
 
     if (C->Init.isUsable()) {
-      addInitCapture(LSI, Var);
+      addInitCapture(LSI, cast<VarDecl>(Var));
     } else {
       TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
                                                    TryCapture_ExplicitByVal;
@@ -1574,7 +1584,7 @@
 
   // An init-capture is initialized directly from its stored initializer.
   if (Cap.isInitCapture())
-    return Cap.getVariable()->getInit();
+    return cast<VarDecl>(Cap.getVariable())->getInit();
 
   // For anything else, build an initialization expression. For an implicit
   // capture, the capture notionally happens at the capture-default, so use
@@ -1605,7 +1615,7 @@
       Init = This;
   } else {
     assert(Cap.isVariableCapture() && "unknown kind of capture");
-    VarDecl *Var = Cap.getVariable();
+    ValueDecl *Var = Cap.getVariable();
     Name = Var->getIdentifier();
     Init = BuildDeclarationNameExpr(
       CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
@@ -1654,7 +1664,7 @@
 
 bool Sema::CaptureHasSideEffects(const Capture &From) {
   if (From.isInitCapture()) {
-    Expr *Init = From.getVariable()->getInit();
+    Expr *Init = cast<VarDecl>(From.getVariable())->getInit();
     if (Init && Init->HasSideEffects(Context))
       return true;
   }
@@ -1703,10 +1713,8 @@
   QualType FieldType = Capture.getCaptureType();
 
   TypeSourceInfo *TSI = nullptr;
-  if (Capture.isVariableCapture()) {
-    auto *Var = Capture.getVariable();
-    if (Var->isInitCapture())
-      TSI = Capture.getVariable()->getTypeSourceInfo();
+  if (Capture.isInitCapture()) {
+    TSI = cast<VarDecl>(Capture.getVariable())->getTypeSourceInfo();
   }
 
   // FIXME: Should we really be doing this? A null TypeSourceInfo seems more
@@ -1854,7 +1862,7 @@
           return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
         } else {
           assert(From.isVariableCapture() && "unknown kind of capture");
-          VarDecl *Var = From.getVariable();
+          ValueDecl *Var = From.getVariable();
           LambdaCaptureKind Kind =
               From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
           return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -7787,9 +7787,10 @@
           break;
         // FIXME: We can't easily tell apart an init-capture from a nested
         // capture of an init-capture.
-        const VarDecl *VD = Elem.Capture->getCapturedVar();
+        const ValueDecl *VD = Elem.Capture->getCapturedVar();
+        bool InitCapture = isa<VarDecl>(VD) && cast<VarDecl>(VD)->isInitCapture();
         Diag(Elem.Capture->getLocation(), diag::note_lambda_capture_initializer)
-            << VD << VD->isInitCapture() << Elem.Capture->isExplicit()
+            << VD << InitCapture << Elem.Capture->isExplicit()
             << (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD
             << nextPathEntryRange(Path, I + 1, L);
         break;
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -2047,8 +2047,8 @@
                        SourceLocation TemplateKWLoc,
                        const TemplateArgumentListInfo *TemplateArgs) {
   bool RefersToCapturedVariable =
-      isa<VarDecl>(D) &&
-      NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
+      isa<VarDecl, BindingDecl>(D) &&
+      NeedToCaptureVariable(D, NameInfo.getLoc());
 
   DeclRefExpr *E = DeclRefExpr::Create(
       Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
@@ -3378,13 +3378,12 @@
     // These are always lvalues.
     valueKind = VK_LValue;
     type = type.getNonReferenceType();
-    // FIXME: Support lambda-capture of BindingDecls, once CWG actually
-    // decides how that's supposed to work.
     auto *BD = cast<BindingDecl>(VD);
-    if (BD->getDeclContext() != CurContext) {
-      auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
-      if (DD && DD->hasLocalStorage())
-        diagnoseUncapturableValueReference(*this, Loc, BD);
+    auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
+    if (DD && DD->hasLocalStorage()) {
+        if ((!LangOpts.CPlusPlus  || !isLambdaCallOperator(CurContext)) && BD->getDeclContext() != CurContext) {
+            diagnoseUncapturableValueReference(*this, Loc, VD);
+        }
     }
     break;
   }
@@ -16042,7 +16041,7 @@
     if (Cap.isInvalid() || Cap.isThisCapture())
       continue;
 
-    VarDecl *Var = Cap.getVariable();
+    VarDecl *Var = cast<VarDecl>(Cap.getVariable());
     Expr *CopyExpr = nullptr;
     if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) {
       if (const RecordType *Record =
@@ -17776,7 +17775,7 @@
   MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex);
 }
 
-static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
+void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
                                                ValueDecl *var) {
   DeclContext *VarDC = var->getDeclContext();
 
@@ -17818,7 +17817,7 @@
 }
 
 
-static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var,
+static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, ValueDecl *Var,
                                       bool &SubCapturesAreNested,
                                       QualType &CaptureType,
                                       QualType &DeclRefType) {
@@ -17849,14 +17848,14 @@
 
 // Only block literals, captured statements, and lambda expressions can
 // capture; other scopes don't work.
-static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var,
+static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, ValueDecl *Var,
                                  SourceLocation Loc,
                                  const bool Diagnose, Sema &S) {
   if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))
     return getLambdaAwareParentOfDeclContext(DC);
-  else if (Var->hasLocalStorage()) {
-    if (Diagnose)
-       diagnoseUncapturableValueReference(S, Loc, Var);
+  else if (VarDecl* VD = dyn_cast<VarDecl>(Var)){
+    if (VD->hasLocalStorage() && Diagnose)
+      diagnoseUncapturableValueReference(S, Loc, VD);
   }
   return nullptr;
 }
@@ -17864,10 +17863,12 @@
 // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
 // certain types of variables (unnamed, variably modified types etc.)
 // so check for eligibility.
-static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
+static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var,
                                  SourceLocation Loc,
                                  const bool Diagnose, Sema &S) {
 
+  assert((isa<VarDecl>(Var) || isa<BindingDecl>(Var)) && "Only variables and structured bindings can be captured");
+
   bool IsBlock = isa<BlockScopeInfo>(CSI);
   bool IsLambda = isa<LambdaScopeInfo>(CSI);
 
@@ -17923,11 +17924,31 @@
     return false;
   }
 
+  if (isa<BindingDecl>(Var)) {
+      if(!IsLambda || !S.getLangOpts().CPlusPlus) {
+          //if(Diagnose) {
+          //    S.Diag(Loc, diag::err_reference_to_local_in_enclosing_context)
+          //            << Var << /*binding << /*block|context(IsBlock ? 1 : 3);
+          //    S.Diag(Var->getLocation(), diag::note_entity_declared_at)
+          //            << Var;
+          //}
+          return false;
+      }
+      else if(Diagnose && S.getLangOpts().CPlusPlus) {
+          S.Diag(Loc, S.LangOpts.CPlusPlus20?
+                                   diag::warn_cxx17_compat_capture_binding:
+                                   diag::ext_capture_binding)
+                  << Var;
+          S.Diag(Var->getLocation(), diag::note_entity_declared_at)
+                  << Var;
+      }
+  }
+
   return true;
 }
 
 // Returns true if the capture by block was successful.
-static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
+static bool captureInBlock(BlockScopeInfo *BSI, ValueDecl *Var,
                                  SourceLocation Loc,
                                  const bool BuildAndDiagnose,
                                  QualType &CaptureType,
@@ -18000,7 +18021,7 @@
 
 /// Capture the given variable in the captured region.
 static bool captureInCapturedRegion(
-    CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc,
+    CapturedRegionScopeInfo *RSI, ValueDecl *Var, SourceLocation Loc,
     const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType,
     const bool RefersToCapturedVariable, Sema::TryCaptureKind Kind,
     bool IsTopScope, Sema &S, bool Invalid) {
@@ -18040,7 +18061,7 @@
 
 /// Capture the given variable in the lambda.
 static bool captureInLambda(LambdaScopeInfo *LSI,
-                            VarDecl *Var,
+                            ValueDecl *Var,
                             SourceLocation Loc,
                             const bool BuildAndDiagnose,
                             QualType &CaptureType,
@@ -18058,8 +18079,33 @@
     ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
   }
 
-  // Compute the type of the field that will capture this variable.
-  if (ByRef) {
+  if (ByRef && BuildAndDiagnose && (!S.LangOpts.OpenMP || !S.isOpenMPCapturedDecl(Var))) {
+      // C++20 : [expr.prim.lambda.capture]p12
+      // A bit-field or a member of an anonymous union shall
+      // not be captured by reference.
+      MemberExpr* ME = nullptr;
+      if(VarDecl* V = dyn_cast_or_null<VarDecl>(Var)) {
+          ME = dyn_cast_or_null<MemberExpr>(V->getInit()->IgnoreImplicit());
+      }
+      else if(BindingDecl* BD = dyn_cast<BindingDecl>(Var)) {
+          ME = llvm::dyn_cast_or_null<MemberExpr>(BD->getBinding());
+      }
+      if(ME) {
+          FieldDecl* FD = dyn_cast_or_null<FieldDecl>(ME->getMemberDecl());
+          if(FD && (FD->isBitField() || (FD->getParent()->isAnonymousStructOrUnion() && FD->getParent()->isUnion()))) {
+                  S.Diag(Loc, diag::err_bitfield_capture_by_ref)
+                   << Var;
+                  S.Diag(Var->getLocation(), diag::note_entity_declared_at)
+                   << Var;
+                  S.Diag(FD->getLocation(), diag::note_bitfield_decl)
+                   << FD;
+                  Invalid = true;
+              }
+          }
+      }
+
+    // Compute the type of the field that will capture this variable.
+    if(ByRef) {
     // C++11 [expr.prim.lambda]p15:
     //   An entity is captured by reference if it is implicitly or
     //   explicitly captured but not captured by copy. It is
@@ -18138,7 +18184,7 @@
   return !Invalid;
 }
 
-static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) {
+static bool canCaptureVariableByCopy(ValueDecl *Var, const ASTContext &Context) {
   // Offer a Copy fix even if the type is dependent.
   if (Var->getType()->isDependentType())
     return true;
@@ -18164,7 +18210,7 @@
 /// standard, for example we can't emit a default copy capture fix-it if we
 /// already explicitly copy capture capture another variable.
 static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
-                                    VarDecl *Var) {
+                                    ValueDecl *Var) {
   assert(LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None);
   // Don't offer Capture by copy of default capture by copy fixes if Var is
   // known not to be copy constructible.
@@ -18240,14 +18286,21 @@
 }
 
 bool Sema::tryCaptureVariable(
-    VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
+    ValueDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
     SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
     QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) {
   // An init-capture is notionally from the context surrounding its
   // declaration, but its parent DC is the lambda class.
   DeclContext *VarDC = Var->getDeclContext();
-  if (Var->isInitCapture())
-    VarDC = VarDC->getParent();
+  VarDecl* VD = dyn_cast<VarDecl>(Var);
+  if(VD) {
+      if (VD && VD->isInitCapture())
+          VarDC = VarDC->getParent();
+  }
+  else {
+    VD = dyn_cast<DecompositionDecl>(cast<BindingDecl>(Var)->getDecomposedDecl());
+  }
+  assert(VD && "Cannot capture a null variable");
 
   DeclContext *DC = CurContext;
   const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
@@ -18269,12 +18322,14 @@
 
   // Capture global variables if it is required to use private copy of this
   // variable.
-  bool IsGlobal = !Var->hasLocalStorage();
+  bool IsGlobal = !VD->hasLocalStorage();
   if (IsGlobal &&
       !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true,
                                                 MaxFunctionScopesIndex)))
     return true;
-  Var = Var->getCanonicalDecl();
+
+  if (isa<VarDecl>(Var))
+      Var = cast<VarDecl>(Var->getCanonicalDecl());
 
   // Walk up the stack to determine whether we can capture the variable,
   // performing the "simple" checks that don't depend on type. We stop when
@@ -18478,7 +18533,7 @@
   return Invalid;
 }
 
-bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
+bool Sema::tryCaptureVariable(ValueDecl *Var, SourceLocation Loc,
                               TryCaptureKind Kind, SourceLocation EllipsisLoc) {
   QualType CaptureType;
   QualType DeclRefType;
@@ -18487,7 +18542,7 @@
                             DeclRefType, nullptr);
 }
 
-bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
+bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) {
   QualType CaptureType;
   QualType DeclRefType;
   return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
@@ -18495,7 +18550,7 @@
                              DeclRefType, nullptr);
 }
 
-QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
+QualType Sema::getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc) {
   QualType CaptureType;
   QualType DeclRefType;
 
@@ -19091,6 +19146,25 @@
   }
 }
 
+static void DoMarkBindingDeclReferenced(
+    Sema &SemaRef, SourceLocation Loc, BindingDecl *BD) {
+  BD->setReferenced();
+
+  if (BD->isInvalidDecl())
+    return;
+
+  OdrUseContext OdrUse = isOdrUseContext(SemaRef);
+  if(OdrUse == OdrUseContext::Used) {
+      QualType CaptureType, DeclRefType;
+      SemaRef.tryCaptureVariable(BD, Loc, Sema::TryCapture_Implicit,
+        /*EllipsisLoc*/ SourceLocation(),
+        /*BuildAndDiagnose*/ true,
+        CaptureType, DeclRefType,
+        /*FunctionScopeIndexToStopAt*/ nullptr);
+  }
+}
+
+
 /// Mark a variable referenced, and check whether it is odr-used
 /// (C++ [basic.def.odr]p2, C99 6.9p3).  Note that this should not be
 /// used directly for normal expressions referring to VarDecl.
@@ -19110,6 +19184,12 @@
     return;
   }
 
+  if(BindingDecl* Decl = dyn_cast<BindingDecl>(D)) {
+    DoMarkBindingDeclReferenced(SemaRef, Loc, Decl);
+    return;
+  }
+
+
   SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse);
 
   // If this is a call to a method via a cast, also mark the method in the
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -14334,9 +14334,11 @@
   auto I = LambdaClass->field_begin();
   for (const auto &C : LambdaClass->captures()) {
     if (C.capturesVariable()) {
-      VarDecl *VD = C.getCapturedVar();
-      if (VD->isInitCapture())
-        S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
+      ValueDecl *VD = C.getCapturedVar();
+      if (VarDecl* Var = dyn_cast<VarDecl>(VD)) {
+          if(Var->isInitCapture())
+              S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
+      }
       const bool ByRef = C.getCaptureKind() == LCK_ByRef;
       LSI->addCapture(VD, /*IsBlock*/false, ByRef,
           /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(),
Index: clang/lib/Sema/ScopeInfo.cpp
===================================================================
--- clang/lib/Sema/ScopeInfo.cpp
+++ clang/lib/Sema/ScopeInfo.cpp
@@ -220,7 +220,8 @@
 bool Capture::isInitCapture() const {
   // Note that a nested capture of an init-capture is not itself an
   // init-capture.
-  return !isNested() && isVariableCapture() && getVariable()->isInitCapture();
+  return !isNested() && isVariableCapture() && isa<VarDecl>(getVariable()) &&
+         cast<VarDecl>(getVariable())->isInitCapture();
 }
 
 bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -609,7 +609,7 @@
   const CodeGen::CGBlockInfo *BlockInfo = nullptr;
   llvm::Value *BlockPointer = nullptr;
 
-  llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+  llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
   FieldDecl *LambdaThisCaptureField = nullptr;
 
   /// A mapping from NRVO variables to the flags used to indicate
Index: clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
===================================================================
--- clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
+++ clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
@@ -3809,7 +3809,7 @@
     else
       VDLVal = CGF.MakeAddrLValue(
           VDAddr, VD->getType().getCanonicalType().getNonReferenceType());
-    llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+    llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
     FieldDecl *ThisCapture = nullptr;
     RD->getCaptureFields(Captures, ThisCapture);
     if (ThisCapture && CGF.CapturedStmtInfo->isCXXThisExprCaptured()) {
@@ -3821,7 +3821,7 @@
     for (const LambdaCapture &LC : RD->captures()) {
       if (LC.getCaptureKind() != LCK_ByRef)
         continue;
-      const VarDecl *VD = LC.getCapturedVar();
+      const VarDecl *VD = cast<VarDecl>(C.getCapturedVar());
       if (!CS->capturesVariable(VD))
         continue;
       auto It = Captures.find(VD);
Index: clang/lib/CodeGen/CGOpenMPRuntime.cpp
===================================================================
--- clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -409,7 +409,7 @@
 /// RAII for emitting code of OpenMP constructs.
 class InlinedOpenMPRegionRAII {
   CodeGenFunction &CGF;
-  llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+  llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
   FieldDecl *LambdaThisCaptureField = nullptr;
   const CodeGen::CGBlockInfo *BlockInfo = nullptr;
   bool NoInheritance = false;
@@ -9035,7 +9035,7 @@
     Address VDAddr(Arg, CGF.ConvertTypeForMem(VDType),
                    CGF.getContext().getDeclAlign(VD));
     LValue VDLVal = CGF.MakeAddrLValue(VDAddr, VDType);
-    llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+    llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
     FieldDecl *ThisCapture = nullptr;
     RD->getCaptureFields(Captures, ThisCapture);
     if (ThisCapture) {
@@ -9057,7 +9057,7 @@
     for (const LambdaCapture &LC : RD->captures()) {
       if (!LC.capturesVariable())
         continue;
-      const VarDecl *VD = LC.getCapturedVar();
+      const VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
       if (LC.getCaptureKind() != LCK_ByRef && !VD->getType()->isPointerType())
         continue;
       auto It = Captures.find(VD);
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -2904,8 +2904,14 @@
   // FIXME: While we're emitting a binding from an enclosing scope, all other
   // DeclRefExprs we see should be implicitly treated as if they also refer to
   // an enclosing scope.
-  if (const auto *BD = dyn_cast<BindingDecl>(ND))
-    return EmitLValue(BD->getBinding());
+  if (const auto *BD = dyn_cast<BindingDecl>(ND)) {
+      if (E->refersToEnclosingVariableOrCapture()) {
+          auto *FD = LambdaCaptureFields.lookup(BD);
+          assert(FD);
+          return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
+      }
+      return EmitLValue(BD->getBinding());
+  }
 
   // We can form DeclRefExprs naming GUID declarations when reconstituting
   // non-type template parameters into expressions.
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1491,7 +1491,7 @@
     if (C.capturesVariable()) {
       SourceLocation Loc = C.getLocation();
       assert(!Field->isBitField() && "lambdas don't have bitfield members!");
-      VarDecl *V = C.getCapturedVar();
+      ValueDecl *V = C.getCapturedVar();
       StringRef VName = V->getName();
       llvm::DIFile *VUnit = getOrCreateFile(Loc);
       auto Align = getDeclAlignIfRequired(V, CGM.getContext());
Index: clang/lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- clang/lib/Analysis/AnalysisDeclContext.cpp
+++ clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -169,8 +169,8 @@
     if (!LC.capturesVariable())
       continue;
 
-    VarDecl *VD = LC.getCapturedVar();
-    if (isSelfDecl(VD))
+    ValueDecl *VD = LC.getCapturedVar();
+    if (isSelfDecl(dyn_cast<VarDecl>(VD)))
       return dyn_cast<ImplicitParamDecl>(VD);
   }
 
Index: clang/lib/AST/StmtPrinter.cpp
===================================================================
--- clang/lib/AST/StmtPrinter.cpp
+++ clang/lib/AST/StmtPrinter.cpp
@@ -2072,7 +2072,7 @@
       OS << "...";
 
     if (Node->isInitCapture(C)) {
-      VarDecl *D = C->getCapturedVar();
+      VarDecl *D = cast<VarDecl>(C->getCapturedVar());
 
       llvm::StringRef Pre;
       llvm::StringRef Post;
Index: clang/lib/AST/Stmt.cpp
===================================================================
--- clang/lib/AST/Stmt.cpp
+++ clang/lib/AST/Stmt.cpp
@@ -1413,7 +1413,7 @@
   CapDeclAndKind.setInt(Kind);
 }
 
-bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
+bool CapturedStmt::capturesVariable(const ValueDecl *Var) const {
   for (const auto &I : captures()) {
     if (!I.capturesVariable() && !I.capturesVariableByCopy())
       continue;
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -578,7 +578,7 @@
 
     /// LambdaCaptureFields - Mapping from captured variables/this to
     /// corresponding data members in the closure class.
-    llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+    llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
     FieldDecl *LambdaThisCaptureField;
 
     CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
Index: clang/lib/AST/ExprCXX.cpp
===================================================================
--- clang/lib/AST/ExprCXX.cpp
+++ clang/lib/AST/ExprCXX.cpp
@@ -1083,7 +1083,7 @@
     : Expr(SC, Empty), NumArgs(NumArgs) {}
 
 LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
-                             LambdaCaptureKind Kind, VarDecl *Var,
+                             LambdaCaptureKind Kind, ValueDecl *Var,
                              SourceLocation EllipsisLoc)
     : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) {
   unsigned Bits = 0;
@@ -1207,7 +1207,8 @@
 }
 
 bool LambdaExpr::isInitCapture(const LambdaCapture *C) const {
-  return (C->capturesVariable() && C->getCapturedVar()->isInitCapture() &&
+  return (C->capturesVariable()
+          && isa<VarDecl>(C->getCapturedVar()) && cast<VarDecl>(C->getCapturedVar())->isInitCapture() &&
           (getCallOperator() == C->getCapturedVar()->getDeclContext()));
 }
 
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -1556,7 +1556,7 @@
 }
 
 void CXXRecordDecl::getCaptureFields(
-       llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
+       llvm::DenseMap<const ValueDecl *, FieldDecl *> &Captures,
        FieldDecl *&ThisCapture) const {
   Captures.clear();
   ThisCapture = nullptr;
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -965,7 +965,7 @@
 
 template <>
 Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
-  VarDecl *Var = nullptr;
+  ValueDecl *Var = nullptr;
   if (From.capturesVariable()) {
     if (auto VarOrErr = import(From.getCapturedVar()))
       Var = *VarOrErr;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5175,23 +5175,23 @@
   ///
   /// \returns true if an error occurred (i.e., the variable cannot be
   /// captured) and false if the capture succeeded.
-  bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind,
+  bool tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, TryCaptureKind Kind,
                           SourceLocation EllipsisLoc, bool BuildAndDiagnose,
                           QualType &CaptureType,
                           QualType &DeclRefType,
                           const unsigned *const FunctionScopeIndexToStopAt);
 
   /// Try to capture the given variable.
-  bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
+  bool tryCaptureVariable(ValueDecl *Var, SourceLocation Loc,
                           TryCaptureKind Kind = TryCapture_Implicit,
                           SourceLocation EllipsisLoc = SourceLocation());
 
   /// Checks if the variable must be captured.
-  bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc);
+  bool NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc);
 
   /// Given a variable, determine the type that a reference to that
   /// variable will have in the given scope.
-  QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc);
+  QualType getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc);
 
   /// Mark all of the declarations referenced within a particular AST node as
   /// referenced. Used when template instantiation instantiates a non-dependent
Index: clang/include/clang/Sema/ScopeInfo.h
===================================================================
--- clang/include/clang/Sema/ScopeInfo.h
+++ clang/include/clang/Sema/ScopeInfo.h
@@ -548,7 +548,7 @@
     const VariableArrayType *CapturedVLA;
 
     /// Otherwise, the captured variable (if any).
-    VarDecl *CapturedVar;
+    ValueDecl *CapturedVar;
   };
 
   /// The source location at which the first capture occurred.
@@ -584,7 +584,7 @@
   unsigned Invalid : 1;
 
 public:
-  Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
+  Capture(ValueDecl *Var, bool Block, bool ByRef, bool IsNested,
           SourceLocation Loc, SourceLocation EllipsisLoc, QualType CaptureType,
           bool Invalid)
       : CapturedVar(Var), Loc(Loc), EllipsisLoc(EllipsisLoc),
@@ -634,7 +634,7 @@
       NonODRUsed = true;
   }
 
-  VarDecl *getVariable() const {
+  ValueDecl *getVariable() const {
     assert(isVariableCapture());
     return CapturedVar;
   }
@@ -673,7 +673,7 @@
       : FunctionScopeInfo(Diag), ImpCaptureStyle(Style) {}
 
   /// CaptureMap - A map of captured variables to (index+1) into Captures.
-  llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
+  llvm::DenseMap<ValueDecl*, unsigned> CaptureMap;
 
   /// CXXThisCaptureIndex - The (index+1) of the capture of 'this';
   /// zero if 'this' is not captured.
@@ -690,7 +690,7 @@
   /// or null if unknown.
   QualType ReturnType;
 
-  void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
+  void addCapture(ValueDecl *Var, bool isBlock, bool isByref, bool isNested,
                   SourceLocation Loc, SourceLocation EllipsisLoc,
                   QualType CaptureType, bool Invalid) {
     Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc,
@@ -717,7 +717,7 @@
   }
 
   /// Determine whether the given variable has been captured.
-  bool isCaptured(VarDecl *Var) const {
+  bool isCaptured(ValueDecl *Var) const {
     return CaptureMap.count(Var);
   }
 
@@ -726,13 +726,13 @@
 
   /// Retrieve the capture of the given variable, if it has been
   /// captured already.
-  Capture &getCapture(VarDecl *Var) {
+  Capture &getCapture(ValueDecl *Var) {
     assert(isCaptured(Var) && "Variable has not been captured");
     return Captures[CaptureMap[Var] - 1];
   }
 
-  const Capture &getCapture(VarDecl *Var) const {
-    llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known
+  const Capture &getCapture(ValueDecl *Var) const {
+    llvm::DenseMap<ValueDecl*, unsigned>::const_iterator Known
       = CaptureMap.find(Var);
     assert(Known != CaptureMap.end() && "Variable has not been captured");
     return Captures[Known->second - 1];
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8954,6 +8954,14 @@
 def err_reference_to_local_in_enclosing_context : Error<
   "reference to local %select{variable|binding}1 %0 declared in enclosing "
   "%select{%3|block literal|lambda expression|context}2">;
+def err_bitfield_capture_by_ref : Error<
+  "cannot capture a bit-field by reference">;
+def ext_capture_binding : ExtWarn<
+  "captured structured bindings are a C++20 extension">, InGroup<CXX20>;
+def warn_cxx17_compat_capture_binding : Warning<
+  "captured structured bindings are incompatible with "
+  "C++ standards before C++20">,
+  InGroup<CXXPre20Compat>, DefaultIgnore;
 
 def err_static_data_member_not_allowed_in_local_class : Error<
   "static data member %0 not allowed in local %sub{select_tag_type_kind}2 %1">;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4690,7 +4690,7 @@
 /// In the matcher
 /// lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))),
 /// capturesVar(hasName("x")) matches `x` and `x = 1`.
-AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher<VarDecl>,
+AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher<ValueDecl>,
               InnerMatcher) {
   auto *capturedVar = Node.getCapturedVar();
   return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder);
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -59,6 +59,7 @@
 class StringLiteral;
 class Token;
 class VarDecl;
+class ValueDecl;
 
 //===----------------------------------------------------------------------===//
 // AST classes for statements.
@@ -3629,7 +3630,7 @@
   }
 
   /// True if this variable has been captured.
-  bool capturesVariable(const VarDecl *Var) const;
+  bool capturesVariable(const ValueDecl *Var) const;
 
   /// An iterator that walks over the captures.
   using capture_iterator = Capture *;
Index: clang/include/clang/AST/LambdaCapture.h
===================================================================
--- clang/include/clang/AST/LambdaCapture.h
+++ clang/include/clang/AST/LambdaCapture.h
@@ -71,7 +71,7 @@
   /// capture that is a pack expansion, or an invalid source
   /// location to indicate that this is not a pack expansion.
   LambdaCapture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind,
-                VarDecl *Var = nullptr,
+                ValueDecl *Var = nullptr,
                 SourceLocation EllipsisLoc = SourceLocation());
 
   /// Determine the kind of capture.
@@ -86,7 +86,7 @@
 
   /// Determine whether this capture handles a variable.
   bool capturesVariable() const {
-    return isa_and_nonnull<VarDecl>(DeclAndBits.getPointer());
+    return isa_and_nonnull<ValueDecl>(DeclAndBits.getPointer());
   }
 
   /// Determine whether this captures a variable length array bound
@@ -101,9 +101,9 @@
   ///
   /// This operation is only valid if this capture is a variable capture
   /// (other than a capture of \c this).
-  VarDecl *getCapturedVar() const {
+  ValueDecl *getCapturedVar() const {
     assert(capturesVariable() && "No variable available for capture");
-    return static_cast<VarDecl *>(DeclAndBits.getPointer());
+    return static_cast<ValueDecl *>(DeclAndBits.getPointer());
   }
 
   /// Determine whether this was an implicit capture (not
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -1057,7 +1057,7 @@
   ///
   /// \note No entries will be added for init-captures, as they do not capture
   /// variables.
-  void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
+  void getCaptureFields(llvm::DenseMap<const ValueDecl *, FieldDecl *> &Captures,
                         FieldDecl *&ThisCapture) const;
 
   using capture_const_iterator = const LambdaCapture *;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -189,6 +189,7 @@
 ^^^^^^^^^^^^^^^^^^^^^
 - Diagnose consteval and constexpr issues that happen at namespace scope. This
   partially addresses `Issue 51593 <https://github.com/llvm/llvm-project/issues/51593>`_.
+- Support capturing structured bindings in lambdas (`P1091R3 <https://wg21.link/p1091r3>`_ and `P1381R1 <https://wg21.link/P1381R1>`)
 
 C++2b Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
Index: clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
+++ clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
@@ -785,8 +785,8 @@
                                                    const LambdaCapture *C,
                                                    Expr *Init) {
   if (C->capturesVariable()) {
-    const VarDecl *VDecl = C->getCapturedVar();
-    if (areSameVariable(IndexVar, cast<ValueDecl>(VDecl))) {
+    const ValueDecl *VDecl = C->getCapturedVar();
+    if (areSameVariable(IndexVar, VDecl)) {
       // FIXME: if the index is captured, it will count as an usage and the
       // alias (if any) won't work, because it is only used in case of having
       // exactly one usage.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to