Magellan Linux

Contents of /trunk/llvm/patches/clang-15.0.7-structured-bindings-r1-v2.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3754 - (show annotations) (download)
Fri Aug 4 08:50:12 2023 UTC (9 months, 1 week ago) by niro
File size: 69760 byte(s)
-fixed clang-extra pathes
1 From 127bf44385424891eb04cff8e52d3f157fc2cb7c Mon Sep 17 00:00:00 2001
2 From: Corentin Jabot <corentinjabot@gmail.com>
3 Date: Wed, 30 Mar 2022 14:27:44 +0200
4 Subject: [PATCH] [Clang][C++20] Support capturing structured bindings in
5 lambdas
6
7 This completes the implementation of P1091R3 and P1381R1.
8
9 This patch allow the capture of structured bindings
10 both for C++20+ and C++17, with extension/compat warning.
11
12 In addition, capturing an anonymous union member,
13 a bitfield, or a structured binding thereof now has a
14 better diagnostic.
15
16 We only support structured bindings - as opposed to other kinds
17 of structured statements/blocks. We still emit an error for those.
18
19 In addition, support for structured bindings capture is entirely disabled in
20 OpenMP mode as this needs more investigation - a specific diagnostic indicate the feature is not yet supported there.
21
22 Note that the rest of P1091R3 (static/thread_local structured bindings) was already implemented.
23
24 at the request of @shafik, i can confirm the correct behavior of lldb wit this change.
25
26 Fixes https://github.com/llvm/llvm-project/issues/54300
27 Fixes https://github.com/llvm/llvm-project/issues/54300
28 Fixes https://github.com/llvm/llvm-project/issues/52720
29
30 Reviewed By: aaron.ballman
31
32 Differential Revision: https://reviews.llvm.org/D122768
33 ---
34 .../clang-tidy/modernize/LoopConvertUtils.cpp | 4 +-
35 clang/docs/ReleaseNotes.rst | 10 +
36 clang/include/clang/AST/Decl.h | 5 +
37 clang/include/clang/AST/DeclCXX.h | 5 +-
38 clang/include/clang/AST/LambdaCapture.h | 8 +-
39 clang/include/clang/AST/Stmt.h | 1 +
40 clang/include/clang/ASTMatchers/ASTMatchers.h | 2 +-
41 .../clang/Basic/DiagnosticSemaKinds.td | 10 +
42 clang/include/clang/Sema/ScopeInfo.h | 27 ++-
43 clang/include/clang/Sema/Sema.h | 12 +-
44 clang/lib/AST/ASTImporter.cpp | 2 +-
45 clang/lib/AST/Decl.cpp | 6 +
46 clang/lib/AST/DeclCXX.cpp | 4 +-
47 clang/lib/AST/ExprCXX.cpp | 6 +-
48 clang/lib/AST/ExprConstant.cpp | 2 +-
49 clang/lib/AST/StmtPrinter.cpp | 3 +-
50 clang/lib/Analysis/AnalysisDeclContext.cpp | 6 +-
51 clang/lib/CodeGen/CGDebugInfo.cpp | 2 +-
52 clang/lib/CodeGen/CGExpr.cpp | 7 +-
53 clang/lib/CodeGen/CGOpenMPRuntime.cpp | 6 +-
54 clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp | 15 +-
55 clang/lib/CodeGen/CodeGenFunction.h | 2 +-
56 clang/lib/Sema/SemaDecl.cpp | 2 +-
57 clang/lib/Sema/SemaExpr.cpp | 200 ++++++++++++------
58 clang/lib/Sema/SemaInit.cpp | 2 +-
59 clang/lib/Sema/SemaLambda.cpp | 31 ++-
60 clang/lib/Sema/SemaOpenMP.cpp | 4 +-
61 clang/lib/Sema/SemaStmt.cpp | 10 +-
62 clang/lib/Sema/TreeTransform.h | 9 +-
63 clang/lib/Serialization/ASTWriter.cpp | 2 +-
64 .../Checkers/DeadStoresChecker.cpp | 8 +-
65 .../WebKit/UncountedLambdaCapturesChecker.cpp | 4 +-
66 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 2 +-
67 .../lib/StaticAnalyzer/Core/LoopUnrolling.cpp | 2 +-
68 clang/test/CodeGenCXX/cxx20-decomposition.cpp | 48 +++++
69 clang/test/SemaCXX/cxx1z-decomposition.cpp | 54 ++++-
70 clang/test/SemaCXX/cxx20-decomposition.cpp | 141 ++++++++++++
71 clang/test/SemaCXX/decomposition-blocks.cpp | 14 ++
72 clang/test/SemaCXX/decomposition-openmp.cpp | 13 ++
73 clang/tools/libclang/CIndex.cpp | 8 +-
74 clang/www/cxx_status.html | 2 +-
75 41 files changed, 539 insertions(+), 162 deletions(-)
76 create mode 100644 clang/test/CodeGenCXX/cxx20-decomposition.cpp
77 create mode 100644 clang/test/SemaCXX/cxx20-decomposition.cpp
78 create mode 100644 clang/test/SemaCXX/decomposition-blocks.cpp
79 create mode 100644 clang/test/SemaCXX/decomposition-openmp.cpp
80
81 diff --git a/clang/tools/extra/clang-tidy/modernize/LoopConvertUtils.cpp b/clang/tools/extra/clang-tidy/modernize/LoopConvertUtils.cpp
82 index 5d4f3b82492499..fc3dfbdeac785f 100644
83 --- a/clang/tools/extra/clang-tidy/modernize/LoopConvertUtils.cpp
84 +++ b/clang/tools/extra/clang-tidy/modernize/LoopConvertUtils.cpp
85 @@ -785,8 +785,8 @@ bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
86 const LambdaCapture *C,
87 Expr *Init) {
88 if (C->capturesVariable()) {
89 - const VarDecl *VDecl = C->getCapturedVar();
90 - if (areSameVariable(IndexVar, cast<ValueDecl>(VDecl))) {
91 + const ValueDecl *VDecl = C->getCapturedVar();
92 + if (areSameVariable(IndexVar, VDecl)) {
93 // FIXME: if the index is captured, it will count as an usage and the
94 // alias (if any) won't work, because it is only used in case of having
95 // exactly one usage.
96 diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
97 index 7d90b08814baa3..878effe08294cb 100644
98 --- a/clang/docs/ReleaseNotes.rst
99 +++ b/clang/docs/ReleaseNotes.rst
100 @@ -108,6 +108,16 @@ C++ Language Changes in Clang
101 C++20 Feature Support
102 ^^^^^^^^^^^^^^^^^^^^^
103
104 +- Support capturing structured bindings in lambdas
105 + (`P1091R3 <https://wg21.link/p1091r3>`_ and `P1381R1 <https://wg21.link/P1381R1>`).
106 + This fixes issues `GH52720 <https://github.com/llvm/llvm-project/issues/52720>`_,
107 + `GH54300 <https://github.com/llvm/llvm-project/issues/54300>`_,
108 + `GH54301 <https://github.com/llvm/llvm-project/issues/54301>`_,
109 + and `GH49430 <https://github.com/llvm/llvm-project/issues/49430>`_.
110 +
111 +
112 +
113 +
114 C++2b Feature Support
115 ^^^^^^^^^^^^^^^^^^^^^
116
117 diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
118 index 6441cd339d917a..1b414b5c0c194a 100644
119 --- a/clang/include/clang/AST/Decl.h
120 +++ b/clang/include/clang/AST/Decl.h
121 @@ -689,6 +689,11 @@ class ValueDecl : public NamedDecl {
122 /// or declared with the weak or weak-ref attr.
123 bool isWeak() const;
124
125 + /// Whether this variable is the implicit variable for a lambda init-capture.
126 + /// Only VarDecl can be init captures, but both VarDecl and BindingDecl
127 + /// can be captured.
128 + bool isInitCapture() const;
129 +
130 // Implement isa/cast/dyncast/etc.
131 static bool classof(const Decl *D) { return classofKind(D->getKind()); }
132 static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; }
133 diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
134 index 9e4fc3fc1254fd..c97301957cb609 100644
135 --- a/clang/include/clang/AST/DeclCXX.h
136 +++ b/clang/include/clang/AST/DeclCXX.h
137 @@ -1057,8 +1057,9 @@ class CXXRecordDecl : public RecordDecl {
138 ///
139 /// \note No entries will be added for init-captures, as they do not capture
140 /// variables.
141 - void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
142 - FieldDecl *&ThisCapture) const;
143 + void
144 + getCaptureFields(llvm::DenseMap<const ValueDecl *, FieldDecl *> &Captures,
145 + FieldDecl *&ThisCapture) const;
146
147 using capture_const_iterator = const LambdaCapture *;
148 using capture_const_range = llvm::iterator_range<capture_const_iterator>;
149 diff --git a/clang/include/clang/AST/LambdaCapture.h b/clang/include/clang/AST/LambdaCapture.h
150 index 7ad1e2361e4273..62e7716ed3699d 100644
151 --- a/clang/include/clang/AST/LambdaCapture.h
152 +++ b/clang/include/clang/AST/LambdaCapture.h
153 @@ -71,7 +71,7 @@ class LambdaCapture {
154 /// capture that is a pack expansion, or an invalid source
155 /// location to indicate that this is not a pack expansion.
156 LambdaCapture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind,
157 - VarDecl *Var = nullptr,
158 + ValueDecl *Var = nullptr,
159 SourceLocation EllipsisLoc = SourceLocation());
160
161 /// Determine the kind of capture.
162 @@ -86,7 +86,7 @@ class LambdaCapture {
163
164 /// Determine whether this capture handles a variable.
165 bool capturesVariable() const {
166 - return isa_and_nonnull<VarDecl>(DeclAndBits.getPointer());
167 + return isa_and_nonnull<ValueDecl>(DeclAndBits.getPointer());
168 }
169
170 /// Determine whether this captures a variable length array bound
171 @@ -101,9 +101,9 @@ class LambdaCapture {
172 ///
173 /// This operation is only valid if this capture is a variable capture
174 /// (other than a capture of \c this).
175 - VarDecl *getCapturedVar() const {
176 + ValueDecl *getCapturedVar() const {
177 assert(capturesVariable() && "No variable available for capture");
178 - return static_cast<VarDecl *>(DeclAndBits.getPointer());
179 + return static_cast<ValueDecl *>(DeclAndBits.getPointer());
180 }
181
182 /// Determine whether this was an implicit capture (not
183 diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
184 index 49a66a1ea5b86a..52c0ca51ea8669 100644
185 --- a/clang/include/clang/AST/Stmt.h
186 +++ b/clang/include/clang/AST/Stmt.h
187 @@ -59,6 +59,7 @@ class RecordDecl;
188 class SourceManager;
189 class StringLiteral;
190 class Token;
191 +class ValueDecl;
192 class VarDecl;
193
194 //===----------------------------------------------------------------------===//
195 diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
196 index 9f4d807c232dcd..5bcf1d3896e89b 100644
197 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h
198 +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
199 @@ -4722,7 +4722,7 @@ AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher<LambdaCapture>,
200 /// In the matcher
201 /// lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))),
202 /// capturesVar(hasName("x")) matches `x` and `x = 1`.
203 -AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher<VarDecl>,
204 +AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher<ValueDecl>,
205 InnerMatcher) {
206 auto *capturedVar = Node.getCapturedVar();
207 return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder);
208 diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
209 index 6ff5b8de57fd02..550ad5ab73c642 100644
210 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
211 +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
212 @@ -9013,6 +9013,16 @@ def ext_ms_anonymous_record : ExtWarn<
213 def err_reference_to_local_in_enclosing_context : Error<
214 "reference to local %select{variable|binding}1 %0 declared in enclosing "
215 "%select{%3|block literal|lambda expression|context}2">;
216 +def err_bitfield_capture_by_ref : Error<
217 + "cannot capture a bit-field by reference">;
218 +def err_capture_binding_openmp : Error<
219 + "capturing a structured binding is not yet supported in OpenMP">;
220 +def ext_capture_binding : ExtWarn<
221 + "captured structured bindings are a C++20 extension">, InGroup<CXX20>;
222 +def warn_cxx17_compat_capture_binding : Warning<
223 + "captured structured bindings are incompatible with "
224 + "C++ standards before C++20">,
225 + InGroup<CXXPre20Compat>, DefaultIgnore;
226
227 def err_static_data_member_not_allowed_in_local_class : Error<
228 "static data member %0 not allowed in local %sub{select_tag_type_kind}2 %1">;
229 diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
230 index 18848c8d8a4564..c0dfcb89e86ffc 100644
231 --- a/clang/include/clang/Sema/ScopeInfo.h
232 +++ b/clang/include/clang/Sema/ScopeInfo.h
233 @@ -553,7 +553,7 @@ class Capture {
234 const VariableArrayType *CapturedVLA;
235
236 /// Otherwise, the captured variable (if any).
237 - VarDecl *CapturedVar;
238 + ValueDecl *CapturedVar;
239 };
240
241 /// The source location at which the first capture occurred.
242 @@ -589,12 +589,13 @@ class Capture {
243 unsigned Invalid : 1;
244
245 public:
246 - Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
247 + Capture(ValueDecl *Var, bool Block, bool ByRef, bool IsNested,
248 SourceLocation Loc, SourceLocation EllipsisLoc, QualType CaptureType,
249 bool Invalid)
250 : CapturedVar(Var), Loc(Loc), EllipsisLoc(EllipsisLoc),
251 - CaptureType(CaptureType),
252 - Kind(Block ? Cap_Block : ByRef ? Cap_ByRef : Cap_ByCopy),
253 + CaptureType(CaptureType), Kind(Block ? Cap_Block
254 + : ByRef ? Cap_ByRef
255 + : Cap_ByCopy),
256 Nested(IsNested), CapturesThis(false), ODRUsed(false),
257 NonODRUsed(false), Invalid(Invalid) {}
258
259 @@ -639,7 +640,7 @@ class Capture {
260 NonODRUsed = true;
261 }
262
263 - VarDecl *getVariable() const {
264 + ValueDecl *getVariable() const {
265 assert(isVariableCapture());
266 return CapturedVar;
267 }
268 @@ -678,7 +679,7 @@ class CapturingScopeInfo : public FunctionScopeInfo {
269 : FunctionScopeInfo(Diag), ImpCaptureStyle(Style) {}
270
271 /// CaptureMap - A map of captured variables to (index+1) into Captures.
272 - llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
273 + llvm::DenseMap<ValueDecl *, unsigned> CaptureMap;
274
275 /// CXXThisCaptureIndex - The (index+1) of the capture of 'this';
276 /// zero if 'this' is not captured.
277 @@ -695,7 +696,7 @@ class CapturingScopeInfo : public FunctionScopeInfo {
278 /// or null if unknown.
279 QualType ReturnType;
280
281 - void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
282 + void addCapture(ValueDecl *Var, bool isBlock, bool isByref, bool isNested,
283 SourceLocation Loc, SourceLocation EllipsisLoc,
284 QualType CaptureType, bool Invalid) {
285 Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc,
286 @@ -722,23 +723,21 @@ class CapturingScopeInfo : public FunctionScopeInfo {
287 }
288
289 /// Determine whether the given variable has been captured.
290 - bool isCaptured(VarDecl *Var) const {
291 - return CaptureMap.count(Var);
292 - }
293 + bool isCaptured(ValueDecl *Var) const { return CaptureMap.count(Var); }
294
295 /// Determine whether the given variable-array type has been captured.
296 bool isVLATypeCaptured(const VariableArrayType *VAT) const;
297
298 /// Retrieve the capture of the given variable, if it has been
299 /// captured already.
300 - Capture &getCapture(VarDecl *Var) {
301 + Capture &getCapture(ValueDecl *Var) {
302 assert(isCaptured(Var) && "Variable has not been captured");
303 return Captures[CaptureMap[Var] - 1];
304 }
305
306 - const Capture &getCapture(VarDecl *Var) const {
307 - llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known
308 - = CaptureMap.find(Var);
309 + const Capture &getCapture(ValueDecl *Var) const {
310 + llvm::DenseMap<ValueDecl *, unsigned>::const_iterator Known =
311 + CaptureMap.find(Var);
312 assert(Known != CaptureMap.end() && "Variable has not been captured");
313 return Captures[Known->second - 1];
314 }
315 diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
316 index ed50b9ef42ef49..706383e8943fcf 100644
317 --- a/clang/include/clang/Sema/Sema.h
318 +++ b/clang/include/clang/Sema/Sema.h
319 @@ -5325,23 +5325,23 @@ class Sema final {
320 ///
321 /// \returns true if an error occurred (i.e., the variable cannot be
322 /// captured) and false if the capture succeeded.
323 - bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind,
324 - SourceLocation EllipsisLoc, bool BuildAndDiagnose,
325 - QualType &CaptureType,
326 + bool tryCaptureVariable(ValueDecl *Var, SourceLocation Loc,
327 + TryCaptureKind Kind, SourceLocation EllipsisLoc,
328 + bool BuildAndDiagnose, QualType &CaptureType,
329 QualType &DeclRefType,
330 const unsigned *const FunctionScopeIndexToStopAt);
331
332 /// Try to capture the given variable.
333 - bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
334 + bool tryCaptureVariable(ValueDecl *Var, SourceLocation Loc,
335 TryCaptureKind Kind = TryCapture_Implicit,
336 SourceLocation EllipsisLoc = SourceLocation());
337
338 /// Checks if the variable must be captured.
339 - bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc);
340 + bool NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc);
341
342 /// Given a variable, determine the type that a reference to that
343 /// variable will have in the given scope.
344 - QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc);
345 + QualType getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc);
346
347 /// Mark all of the declarations referenced within a particular AST node as
348 /// referenced. Used when template instantiation instantiates a non-dependent
349 diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
350 index 159010713f4343..2e230921b938f7 100644
351 --- a/clang/lib/AST/ASTImporter.cpp
352 +++ b/clang/lib/AST/ASTImporter.cpp
353 @@ -1006,7 +1006,7 @@ ASTNodeImporter::import(const Designator &D) {
354
355 template <>
356 Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
357 - VarDecl *Var = nullptr;
358 + ValueDecl *Var = nullptr;
359 if (From.capturesVariable()) {
360 if (auto VarOrErr = import(From.getCapturedVar()))
361 Var = *VarOrErr;
362 diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
363 index 030792bfc7ca3b..61688688b0a73b 100644
364 --- a/clang/lib/AST/Decl.cpp
365 +++ b/clang/lib/AST/Decl.cpp
366 @@ -4983,6 +4983,12 @@ bool ValueDecl::isWeak() const {
367 MostRecent->hasAttr<WeakRefAttr>() || isWeakImported();
368 }
369
370 +bool ValueDecl::isInitCapture() const {
371 + if (auto *Var = llvm::dyn_cast<VarDecl>(this))
372 + return Var->isInitCapture();
373 + return false;
374 +}
375 +
376 void ImplicitParamDecl::anchor() {}
377
378 ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
379 diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
380 index a955b4f3aba00f..38c46b112b8030 100644
381 --- a/clang/lib/AST/DeclCXX.cpp
382 +++ b/clang/lib/AST/DeclCXX.cpp
383 @@ -1570,8 +1570,8 @@ CXXMethodDecl *CXXRecordDecl::getLambdaStaticInvoker(CallingConv CC) const {
384 }
385
386 void CXXRecordDecl::getCaptureFields(
387 - llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
388 - FieldDecl *&ThisCapture) const {
389 + llvm::DenseMap<const ValueDecl *, FieldDecl *> &Captures,
390 + FieldDecl *&ThisCapture) const {
391 Captures.clear();
392 ThisCapture = nullptr;
393
394 diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
395 index 6328fa4a7dd512..1f860a351866f2 100644
396 --- a/clang/lib/AST/ExprCXX.cpp
397 +++ b/clang/lib/AST/ExprCXX.cpp
398 @@ -1087,7 +1087,7 @@ CXXConstructExpr::CXXConstructExpr(StmtClass SC, EmptyShell Empty,
399 : Expr(SC, Empty), NumArgs(NumArgs) {}
400
401 LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
402 - LambdaCaptureKind Kind, VarDecl *Var,
403 + LambdaCaptureKind Kind, ValueDecl *Var,
404 SourceLocation EllipsisLoc)
405 : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) {
406 unsigned Bits = 0;
407 @@ -1211,8 +1211,8 @@ const CompoundStmt *LambdaExpr::getCompoundStmtBody() const {
408 }
409
410 bool LambdaExpr::isInitCapture(const LambdaCapture *C) const {
411 - return (C->capturesVariable() && C->getCapturedVar()->isInitCapture() &&
412 - (getCallOperator() == C->getCapturedVar()->getDeclContext()));
413 + return C->capturesVariable() && C->getCapturedVar()->isInitCapture() &&
414 + getCallOperator() == C->getCapturedVar()->getDeclContext();
415 }
416
417 LambdaExpr::capture_iterator LambdaExpr::capture_begin() const {
418 diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
419 index efaccf52132b34..6f3539a4b2c177 100644
420 --- a/clang/lib/AST/ExprConstant.cpp
421 +++ b/clang/lib/AST/ExprConstant.cpp
422 @@ -578,7 +578,7 @@ namespace {
423
424 /// LambdaCaptureFields - Mapping from captured variables/this to
425 /// corresponding data members in the closure class.
426 - llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
427 + llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
428 FieldDecl *LambdaThisCaptureField;
429
430 CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
431 diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
432 index 8d778500d10336..9cb72ee6b1964c 100644
433 --- a/clang/lib/AST/StmtPrinter.cpp
434 +++ b/clang/lib/AST/StmtPrinter.cpp
435 @@ -2164,7 +2164,8 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
436 OS << "...";
437
438 if (Node->isInitCapture(C)) {
439 - VarDecl *D = C->getCapturedVar();
440 + // Init captures are always VarDecl.
441 + auto *D = cast<VarDecl>(C->getCapturedVar());
442
443 llvm::StringRef Pre;
444 llvm::StringRef Post;
445 diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
446 index f20924604f6491..f72c75a12fec99 100644
447 --- a/clang/lib/Analysis/AnalysisDeclContext.cpp
448 +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
449 @@ -142,7 +142,7 @@ bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const {
450
451 /// Returns true if \param VD is an Objective-C implicit 'self' parameter.
452 static bool isSelfDecl(const VarDecl *VD) {
453 - return isa<ImplicitParamDecl>(VD) && VD->getName() == "self";
454 + return isa_and_nonnull<ImplicitParamDecl>(VD) && VD->getName() == "self";
455 }
456
457 const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
458 @@ -169,8 +169,8 @@ const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
459 if (!LC.capturesVariable())
460 continue;
461
462 - VarDecl *VD = LC.getCapturedVar();
463 - if (isSelfDecl(VD))
464 + ValueDecl *VD = LC.getCapturedVar();
465 + if (isSelfDecl(dyn_cast<VarDecl>(VD)))
466 return dyn_cast<ImplicitParamDecl>(VD);
467 }
468
469 diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
470 index 522ed7ae8b144f..6527d87399bef7 100644
471 --- a/clang/lib/CodeGen/CGDebugInfo.cpp
472 +++ b/clang/lib/CodeGen/CGDebugInfo.cpp
473 @@ -1497,7 +1497,7 @@ void CGDebugInfo::CollectRecordLambdaFields(
474 if (C.capturesVariable()) {
475 SourceLocation Loc = C.getLocation();
476 assert(!Field->isBitField() && "lambdas don't have bitfield members!");
477 - VarDecl *V = C.getCapturedVar();
478 + ValueDecl *V = C.getCapturedVar();
479 StringRef VName = V->getName();
480 llvm::DIFile *VUnit = getOrCreateFile(Loc);
481 auto Align = getDeclAlignIfRequired(V, CGM.getContext());
482 diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
483 index 91a6b4e5284728..e26822eaa601e6 100644
484 --- a/clang/lib/CodeGen/CGExpr.cpp
485 +++ b/clang/lib/CodeGen/CGExpr.cpp
486 @@ -2942,8 +2942,13 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
487 // FIXME: While we're emitting a binding from an enclosing scope, all other
488 // DeclRefExprs we see should be implicitly treated as if they also refer to
489 // an enclosing scope.
490 - if (const auto *BD = dyn_cast<BindingDecl>(ND))
491 + if (const auto *BD = dyn_cast<BindingDecl>(ND)) {
492 + if (E->refersToEnclosingVariableOrCapture()) {
493 + auto *FD = LambdaCaptureFields.lookup(BD);
494 + return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
495 + }
496 return EmitLValue(BD->getBinding());
497 + }
498
499 // We can form DeclRefExprs naming GUID declarations when reconstituting
500 // non-type template parameters into expressions.
501 diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
502 index 3a1ed38d491fc6..9fc7360e924723 100644
503 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
504 +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
505 @@ -409,7 +409,7 @@ class CGOpenMPInnerExprInfo final : public CGOpenMPInlinedRegionInfo {
506 /// RAII for emitting code of OpenMP constructs.
507 class InlinedOpenMPRegionRAII {
508 CodeGenFunction &CGF;
509 - llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
510 + llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
511 FieldDecl *LambdaThisCaptureField = nullptr;
512 const CodeGen::CGBlockInfo *BlockInfo = nullptr;
513 bool NoInheritance = false;
514 @@ -8948,7 +8948,7 @@ class MappableExprsHandler {
515 Address VDAddr(Arg, CGF.ConvertTypeForMem(VDType),
516 CGF.getContext().getDeclAlign(VD));
517 LValue VDLVal = CGF.MakeAddrLValue(VDAddr, VDType);
518 - llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
519 + llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
520 FieldDecl *ThisCapture = nullptr;
521 RD->getCaptureFields(Captures, ThisCapture);
522 if (ThisCapture) {
523 @@ -8970,7 +8970,7 @@ class MappableExprsHandler {
524 for (const LambdaCapture &LC : RD->captures()) {
525 if (!LC.capturesVariable())
526 continue;
527 - const VarDecl *VD = LC.getCapturedVar();
528 + const VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
529 if (LC.getCaptureKind() != LCK_ByRef && !VD->getType()->isPointerType())
530 continue;
531 auto It = Captures.find(VD);
532 diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
533 index 058b312c0ce68f..e8affaaecc980e 100644
534 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
535 +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
536 @@ -444,9 +444,8 @@ class CheckVarsEscapingDeclContext final
537 markAsEscaped(VD);
538 if (isa<OMPCapturedExprDecl>(VD))
539 VisitValueDecl(VD);
540 - else if (const auto *VarD = dyn_cast<VarDecl>(VD))
541 - if (VarD->isInitCapture())
542 - VisitValueDecl(VD);
543 + else if (VD->isInitCapture())
544 + VisitValueDecl(VD);
545 }
546 void VisitUnaryOperator(const UnaryOperator *E) {
547 if (!E)
548 @@ -3810,7 +3809,7 @@ void CGOpenMPRuntimeGPU::adjustTargetSpecificDataForLambdas(
549 else
550 VDLVal = CGF.MakeAddrLValue(
551 VDAddr, VD->getType().getCanonicalType().getNonReferenceType());
552 - llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
553 + llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
554 FieldDecl *ThisCapture = nullptr;
555 RD->getCaptureFields(Captures, ThisCapture);
556 if (ThisCapture && CGF.CapturedStmtInfo->isCXXThisExprCaptured()) {
557 @@ -3822,13 +3821,15 @@ void CGOpenMPRuntimeGPU::adjustTargetSpecificDataForLambdas(
558 for (const LambdaCapture &LC : RD->captures()) {
559 if (LC.getCaptureKind() != LCK_ByRef)
560 continue;
561 - const VarDecl *VD = LC.getCapturedVar();
562 - if (!CS->capturesVariable(VD))
563 + const ValueDecl *VD = LC.getCapturedVar();
564 + // FIXME: For now VD is always a VarDecl because OpenMP does not support
565 + // capturing structured bindings in lambdas yet.
566 + if (!CS->capturesVariable(cast<VarDecl>(VD)))
567 continue;
568 auto It = Captures.find(VD);
569 assert(It != Captures.end() && "Found lambda capture without field.");
570 LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
571 - Address VDAddr = CGF.GetAddrOfLocalVar(VD);
572 + Address VDAddr = CGF.GetAddrOfLocalVar(cast<VarDecl>(VD));
573 if (VD->getType().getCanonicalType()->isReferenceType())
574 VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr,
575 VD->getType().getCanonicalType())
576 diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
577 index fe0890f433e8c9..b61a2a68687d9f 100644
578 --- a/clang/lib/CodeGen/CodeGenFunction.h
579 +++ b/clang/lib/CodeGen/CodeGenFunction.h
580 @@ -609,7 +609,7 @@ class CodeGenFunction : public CodeGenTypeCache {
581 const CodeGen::CGBlockInfo *BlockInfo = nullptr;
582 llvm::Value *BlockPointer = nullptr;
583
584 - llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
585 + llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
586 FieldDecl *LambdaThisCaptureField = nullptr;
587
588 /// A mapping from NRVO variables to the flags used to indicate
589 diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
590 index eca20002b30dab..b110a07f4fcbad 100644
591 --- a/clang/lib/Sema/SemaDecl.cpp
592 +++ b/clang/lib/Sema/SemaDecl.cpp
593 @@ -14681,7 +14681,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
594 auto I = LambdaClass->field_begin();
595 for (const auto &C : LambdaClass->captures()) {
596 if (C.capturesVariable()) {
597 - VarDecl *VD = C.getCapturedVar();
598 + ValueDecl *VD = C.getCapturedVar();
599 if (VD->isInitCapture())
600 S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
601 const bool ByRef = C.getCaptureKind() == LCK_ByRef;
602 diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
603 index 6f758e437a9059..9497c4b5d53004 100644
604 --- a/clang/lib/Sema/SemaExpr.cpp
605 +++ b/clang/lib/Sema/SemaExpr.cpp
606 @@ -2082,9 +2082,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
607 NestedNameSpecifierLoc NNS, NamedDecl *FoundD,
608 SourceLocation TemplateKWLoc,
609 const TemplateArgumentListInfo *TemplateArgs) {
610 - bool RefersToCapturedVariable =
611 - isa<VarDecl>(D) &&
612 - NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
613 + bool RefersToCapturedVariable = isa<VarDecl, BindingDecl>(D) &&
614 + NeedToCaptureVariable(D, NameInfo.getLoc());
615
616 DeclRefExpr *E = DeclRefExpr::Create(
617 Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
618 @@ -3252,8 +3251,9 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
619 return ULE;
620 }
621
622 -static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
623 - ValueDecl *var);
624 +static void diagnoseUncapturableValueReferenceOrBinding(Sema &S,
625 + SourceLocation loc,
626 + ValueDecl *var);
627
628 /// Complete semantic analysis for a reference to the given declaration.
629 ExprResult Sema::BuildDeclarationNameExpr(
630 @@ -3411,20 +3411,11 @@ ExprResult Sema::BuildDeclarationNameExpr(
631 break;
632 }
633
634 - case Decl::Binding: {
635 + case Decl::Binding:
636 // These are always lvalues.
637 valueKind = VK_LValue;
638 type = type.getNonReferenceType();
639 - // FIXME: Support lambda-capture of BindingDecls, once CWG actually
640 - // decides how that's supposed to work.
641 - auto *BD = cast<BindingDecl>(VD);
642 - if (BD->getDeclContext() != CurContext) {
643 - auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
644 - if (DD && DD->hasLocalStorage())
645 - diagnoseUncapturableValueReference(*this, Loc, BD);
646 - }
647 break;
648 - }
649
650 case Decl::Function: {
651 if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
652 @@ -16411,8 +16402,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
653 for (Capture &Cap : BSI->Captures) {
654 if (Cap.isInvalid() || Cap.isThisCapture())
655 continue;
656 -
657 - VarDecl *Var = Cap.getVariable();
658 + // Cap.getVariable() is always a VarDecl because
659 + // blocks cannot capture structured bindings or other ValueDecl kinds.
660 + auto *Var = cast<VarDecl>(Cap.getVariable());
661 Expr *CopyExpr = nullptr;
662 if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) {
663 if (const RecordType *Record =
664 @@ -18243,8 +18235,8 @@ void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture,
665 MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex);
666 }
667
668 -static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
669 - ValueDecl *var) {
670 +void diagnoseUncapturableValueReferenceOrBinding(Sema &S, SourceLocation loc,
671 + ValueDecl *var) {
672 DeclContext *VarDC = var->getDeclContext();
673
674 // If the parameter still belongs to the translation unit, then
675 @@ -18284,12 +18276,12 @@ static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
676 // capture.
677 }
678
679 -
680 -static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var,
681 - bool &SubCapturesAreNested,
682 - QualType &CaptureType,
683 - QualType &DeclRefType) {
684 - // Check whether we've already captured it.
685 +static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI,
686 + ValueDecl *Var,
687 + bool &SubCapturesAreNested,
688 + QualType &CaptureType,
689 + QualType &DeclRefType) {
690 + // Check whether we've already captured it.
691 if (CSI->CaptureMap.count(Var)) {
692 // If we found a capture, any subcaptures are nested.
693 SubCapturesAreNested = true;
694 @@ -18316,14 +18308,22 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec
695
696 // Only block literals, captured statements, and lambda expressions can
697 // capture; other scopes don't work.
698 -static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var,
699 - SourceLocation Loc,
700 - const bool Diagnose, Sema &S) {
701 +static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC,
702 + ValueDecl *Var,
703 + SourceLocation Loc,
704 + const bool Diagnose,
705 + Sema &S) {
706 if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))
707 return getLambdaAwareParentOfDeclContext(DC);
708 - else if (Var->hasLocalStorage()) {
709 - if (Diagnose)
710 - diagnoseUncapturableValueReference(S, Loc, Var);
711 +
712 + ValueDecl *Underlying = Var;
713 + auto *BD = dyn_cast_or_null<BindingDecl>(Var);
714 + if (BD)
715 + Underlying = BD->getDecomposedDecl();
716 +
717 + if (auto *VD = dyn_cast<VarDecl>(Underlying)) {
718 + if (VD->hasLocalStorage() && Diagnose)
719 + diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var);
720 }
721 return nullptr;
722 }
723 @@ -18331,9 +18331,12 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *
724 // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
725 // certain types of variables (unnamed, variably modified types etc.)
726 // so check for eligibility.
727 -static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
728 - SourceLocation Loc,
729 - const bool Diagnose, Sema &S) {
730 +static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var,
731 + SourceLocation Loc, const bool Diagnose,
732 + Sema &S) {
733 +
734 + assert((isa<VarDecl, BindingDecl>(Var)) &&
735 + "Only variables and structured bindings can be captured");
736
737 bool IsBlock = isa<BlockScopeInfo>(CSI);
738 bool IsLambda = isa<LambdaScopeInfo>(CSI);
739 @@ -18390,17 +18393,28 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
740 return false;
741 }
742
743 + if (isa<BindingDecl>(Var)) {
744 + if (!IsLambda || !S.getLangOpts().CPlusPlus) {
745 + if (Diagnose)
746 + diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var);
747 + return false;
748 + } else if (Diagnose && S.getLangOpts().CPlusPlus) {
749 + S.Diag(Loc, S.LangOpts.CPlusPlus20
750 + ? diag::warn_cxx17_compat_capture_binding
751 + : diag::ext_capture_binding)
752 + << Var;
753 + S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
754 + }
755 + }
756 +
757 return true;
758 }
759
760 // Returns true if the capture by block was successful.
761 -static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
762 - SourceLocation Loc,
763 - const bool BuildAndDiagnose,
764 - QualType &CaptureType,
765 - QualType &DeclRefType,
766 - const bool Nested,
767 - Sema &S, bool Invalid) {
768 +static bool captureInBlock(BlockScopeInfo *BSI, ValueDecl *Var,
769 + SourceLocation Loc, const bool BuildAndDiagnose,
770 + QualType &CaptureType, QualType &DeclRefType,
771 + const bool Nested, Sema &S, bool Invalid) {
772 bool ByRef = false;
773
774 // Blocks are not allowed to capture arrays, excepting OpenCL.
775 @@ -18464,10 +18478,9 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
776 return !Invalid;
777 }
778
779 -
780 /// Capture the given variable in the captured region.
781 static bool captureInCapturedRegion(
782 - CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc,
783 + CapturedRegionScopeInfo *RSI, ValueDecl *Var, SourceLocation Loc,
784 const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType,
785 const bool RefersToCapturedVariable, Sema::TryCaptureKind Kind,
786 bool IsTopScope, Sema &S, bool Invalid) {
787 @@ -18506,16 +18519,12 @@ static bool captureInCapturedRegion(
788 }
789
790 /// Capture the given variable in the lambda.
791 -static bool captureInLambda(LambdaScopeInfo *LSI,
792 - VarDecl *Var,
793 - SourceLocation Loc,
794 - const bool BuildAndDiagnose,
795 - QualType &CaptureType,
796 - QualType &DeclRefType,
797 +static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var,
798 + SourceLocation Loc, const bool BuildAndDiagnose,
799 + QualType &CaptureType, QualType &DeclRefType,
800 const bool RefersToCapturedVariable,
801 const Sema::TryCaptureKind Kind,
802 - SourceLocation EllipsisLoc,
803 - const bool IsTopScope,
804 + SourceLocation EllipsisLoc, const bool IsTopScope,
805 Sema &S, bool Invalid) {
806 // Determine whether we are capturing by reference or by value.
807 bool ByRef = false;
808 @@ -18524,6 +18533,40 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
809 } else {
810 ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
811 }
812 + // C++20 : [expr.prim.lambda.capture]p12
813 + // A bit-field or a member of an anonymous union shall
814 + // not be captured by reference.
815 + MemberExpr *ME = nullptr;
816 + BindingDecl *BD = nullptr;
817 + if (auto *V = dyn_cast<VarDecl>(Var)) {
818 + if (V->getInit())
819 + ME = dyn_cast<MemberExpr>(V->getInit()->IgnoreImplicit());
820 + } else if ((BD = dyn_cast<BindingDecl>(Var))) {
821 + ME = dyn_cast_or_null<MemberExpr>(BD->getBinding());
822 + }
823 +
824 + // Capturing a bitfield by reference is not allowed except in OpenMP.
825 + if (ByRef && ME &&
826 + (isa<BindingDecl>(Var) || !S.LangOpts.OpenMP ||
827 + !S.isOpenMPCapturedDecl(Var))) {
828 + const auto *FD = dyn_cast_or_null<FieldDecl>(ME->getMemberDecl());
829 + if (FD && FD->isBitField()) {
830 + if (BuildAndDiagnose) {
831 + S.Diag(Loc, diag::err_bitfield_capture_by_ref) << Var;
832 + S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
833 + S.Diag(FD->getLocation(), diag::note_bitfield_decl) << FD;
834 + }
835 + Invalid = true;
836 + }
837 + }
838 + // FIXME: We should support capturing structured bindings in OpenMP.
839 + if (!Invalid && BD && S.LangOpts.OpenMP) {
840 + if (BuildAndDiagnose) {
841 + S.Diag(Loc, diag::err_capture_binding_openmp) << Var;
842 + S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
843 + }
844 + Invalid = true;
845 + }
846
847 // Compute the type of the field that will capture this variable.
848 if (ByRef) {
849 @@ -18605,7 +18648,8 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
850 return !Invalid;
851 }
852
853 -static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) {
854 +static bool canCaptureVariableByCopy(ValueDecl *Var,
855 + const ASTContext &Context) {
856 // Offer a Copy fix even if the type is dependent.
857 if (Var->getType()->isDependentType())
858 return true;
859 @@ -18631,7 +18675,7 @@ static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) {
860 /// standard, for example we can't emit a default copy capture fix-it if we
861 /// already explicitly copy capture capture another variable.
862 static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
863 - VarDecl *Var) {
864 + ValueDecl *Var) {
865 assert(LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None);
866 // Don't offer Capture by copy of default capture by copy fixes if Var is
867 // known not to be copy constructible.
868 @@ -18707,14 +18751,21 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
869 }
870
871 bool Sema::tryCaptureVariable(
872 - VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
873 + ValueDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
874 SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
875 QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) {
876 // An init-capture is notionally from the context surrounding its
877 // declaration, but its parent DC is the lambda class.
878 DeclContext *VarDC = Var->getDeclContext();
879 - if (Var->isInitCapture())
880 - VarDC = VarDC->getParent();
881 + const auto *VD = dyn_cast<VarDecl>(Var);
882 + if (VD) {
883 + if (VD->isInitCapture())
884 + VarDC = VarDC->getParent();
885 + } else {
886 + VD = dyn_cast<DecompositionDecl>(
887 + cast<BindingDecl>(Var)->getDecomposedDecl());
888 + }
889 + assert(VD && "Cannot capture a null variable");
890
891 DeclContext *DC = CurContext;
892 const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
893 @@ -18736,12 +18787,14 @@ bool Sema::tryCaptureVariable(
894
895 // Capture global variables if it is required to use private copy of this
896 // variable.
897 - bool IsGlobal = !Var->hasLocalStorage();
898 + bool IsGlobal = !VD->hasLocalStorage();
899 if (IsGlobal &&
900 !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true,
901 MaxFunctionScopesIndex)))
902 return true;
903 - Var = Var->getCanonicalDecl();
904 +
905 + if (isa<VarDecl>(Var))
906 + Var = cast<VarDecl>(Var->getCanonicalDecl());
907
908 // Walk up the stack to determine whether we can capture the variable,
909 // performing the "simple" checks that don't depend on type. We stop when
910 @@ -18797,7 +18850,7 @@ bool Sema::tryCaptureVariable(
911 Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl);
912 buildLambdaCaptureFixit(*this, LSI, Var);
913 } else
914 - diagnoseUncapturableValueReference(*this, ExprLoc, Var);
915 + diagnoseUncapturableValueReferenceOrBinding(*this, ExprLoc, Var);
916 }
917 return true;
918 }
919 @@ -18945,7 +18998,7 @@ bool Sema::tryCaptureVariable(
920 return Invalid;
921 }
922
923 -bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
924 +bool Sema::tryCaptureVariable(ValueDecl *Var, SourceLocation Loc,
925 TryCaptureKind Kind, SourceLocation EllipsisLoc) {
926 QualType CaptureType;
927 QualType DeclRefType;
928 @@ -18954,7 +19007,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
929 DeclRefType, nullptr);
930 }
931
932 -bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
933 +bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) {
934 QualType CaptureType;
935 QualType DeclRefType;
936 return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
937 @@ -18962,7 +19015,7 @@ bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
938 DeclRefType, nullptr);
939 }
940
941 -QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
942 +QualType Sema::getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc) {
943 QualType CaptureType;
944 QualType DeclRefType;
945
946 @@ -19558,6 +19611,24 @@ static void DoMarkVarDeclReferenced(
947 }
948 }
949
950 +static void DoMarkBindingDeclReferenced(Sema &SemaRef, SourceLocation Loc,
951 + BindingDecl *BD) {
952 + BD->setReferenced();
953 +
954 + if (BD->isInvalidDecl())
955 + return;
956 +
957 + OdrUseContext OdrUse = isOdrUseContext(SemaRef);
958 + if (OdrUse == OdrUseContext::Used) {
959 + QualType CaptureType, DeclRefType;
960 + SemaRef.tryCaptureVariable(BD, Loc, Sema::TryCapture_Implicit,
961 + /*EllipsisLoc*/ SourceLocation(),
962 + /*BuildAndDiagnose*/ true, CaptureType,
963 + DeclRefType,
964 + /*FunctionScopeIndexToStopAt*/ nullptr);
965 + }
966 +}
967 +
968 /// Mark a variable referenced, and check whether it is odr-used
969 /// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be
970 /// used directly for normal expressions referring to VarDecl.
971 @@ -19577,6 +19648,11 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E,
972 return;
973 }
974
975 + if (BindingDecl *Decl = dyn_cast<BindingDecl>(D)) {
976 + DoMarkBindingDeclReferenced(SemaRef, Loc, Decl);
977 + return;
978 + }
979 +
980 SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse);
981
982 // If this is a call to a method via a cast, also mark the method in the
983 diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
984 index d3b454843234b3..737952bdfe8106 100644
985 --- a/clang/lib/Sema/SemaInit.cpp
986 +++ b/clang/lib/Sema/SemaInit.cpp
987 @@ -7846,7 +7846,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
988 break;
989 // FIXME: We can't easily tell apart an init-capture from a nested
990 // capture of an init-capture.
991 - const VarDecl *VD = Elem.Capture->getCapturedVar();
992 + const ValueDecl *VD = Elem.Capture->getCapturedVar();
993 Diag(Elem.Capture->getLocation(), diag::note_lambda_capture_initializer)
994 << VD << VD->isInitCapture() << Elem.Capture->isExplicit()
995 << (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD
996 diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
997 index afc2f3ef4d76e6..3f271d6c53f17b 100644
998 --- a/clang/lib/Sema/SemaLambda.cpp
999 +++ b/clang/lib/Sema/SemaLambda.cpp
1000 @@ -1088,7 +1088,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
1001 if (C->Init.isInvalid())
1002 continue;
1003
1004 - VarDecl *Var = nullptr;
1005 + ValueDecl *Var = nullptr;
1006 if (C->Init.isUsable()) {
1007 Diag(C->Loc, getLangOpts().CPlusPlus14
1008 ? diag::warn_cxx11_compat_init_capture
1009 @@ -1166,7 +1166,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
1010 continue;
1011 }
1012
1013 - Var = R.getAsSingle<VarDecl>();
1014 + if (auto *BD = R.getAsSingle<BindingDecl>())
1015 + Var = BD;
1016 + else
1017 + Var = R.getAsSingle<VarDecl>();
1018 if (Var && DiagnoseUseOfDecl(Var, C->Loc))
1019 continue;
1020 }
1021 @@ -1200,7 +1203,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
1022 if (Var->isInvalidDecl())
1023 continue;
1024
1025 - if (!Var->hasLocalStorage()) {
1026 + VarDecl *Underlying;
1027 + if (auto *BD = dyn_cast<BindingDecl>(Var))
1028 + Underlying = dyn_cast<VarDecl>(BD->getDecomposedDecl());
1029 + else
1030 + Underlying = cast<VarDecl>(Var);
1031 +
1032 + if (!Underlying->hasLocalStorage()) {
1033 Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
1034 Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
1035 continue;
1036 @@ -1224,7 +1233,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
1037 }
1038
1039 if (C->Init.isUsable()) {
1040 - addInitCapture(LSI, Var);
1041 + addInitCapture(LSI, cast<VarDecl>(Var));
1042 } else {
1043 TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
1044 TryCapture_ExplicitByVal;
1045 @@ -1574,7 +1583,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
1046
1047 // An init-capture is initialized directly from its stored initializer.
1048 if (Cap.isInitCapture())
1049 - return Cap.getVariable()->getInit();
1050 + return cast<VarDecl>(Cap.getVariable())->getInit();
1051
1052 // For anything else, build an initialization expression. For an implicit
1053 // capture, the capture notionally happens at the capture-default, so use
1054 @@ -1605,7 +1614,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
1055 Init = This;
1056 } else {
1057 assert(Cap.isVariableCapture() && "unknown kind of capture");
1058 - VarDecl *Var = Cap.getVariable();
1059 + ValueDecl *Var = Cap.getVariable();
1060 Name = Var->getIdentifier();
1061 Init = BuildDeclarationNameExpr(
1062 CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
1063 @@ -1654,7 +1663,7 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) {
1064
1065 bool Sema::CaptureHasSideEffects(const Capture &From) {
1066 if (From.isInitCapture()) {
1067 - Expr *Init = From.getVariable()->getInit();
1068 + Expr *Init = cast<VarDecl>(From.getVariable())->getInit();
1069 if (Init && Init->HasSideEffects(Context))
1070 return true;
1071 }
1072 @@ -1704,9 +1713,9 @@ FieldDecl *Sema::BuildCaptureField(RecordDecl *RD,
1073
1074 TypeSourceInfo *TSI = nullptr;
1075 if (Capture.isVariableCapture()) {
1076 - auto *Var = Capture.getVariable();
1077 - if (Var->isInitCapture())
1078 - TSI = Capture.getVariable()->getTypeSourceInfo();
1079 + const auto *Var = dyn_cast_or_null<VarDecl>(Capture.getVariable());
1080 + if (Var && Var->isInitCapture())
1081 + TSI = Var->getTypeSourceInfo();
1082 }
1083
1084 // FIXME: Should we really be doing this? A null TypeSourceInfo seems more
1085 @@ -1854,7 +1863,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
1086 return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
1087 } else {
1088 assert(From.isVariableCapture() && "unknown kind of capture");
1089 - VarDecl *Var = From.getVariable();
1090 + ValueDecl *Var = From.getVariable();
1091 LambdaCaptureKind Kind =
1092 From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
1093 return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
1094 diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
1095 index a92fec6a02323f..4279a152db907d 100644
1096 --- a/clang/lib/Sema/SemaOpenMP.cpp
1097 +++ b/clang/lib/Sema/SemaOpenMP.cpp
1098 @@ -4677,12 +4677,12 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) {
1099 DSAStack->setForceCaptureByReferenceInTargetExecutable(
1100 /*V=*/true);
1101 if (RD->isLambda()) {
1102 - llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
1103 + llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
1104 FieldDecl *ThisCapture;
1105 RD->getCaptureFields(Captures, ThisCapture);
1106 for (const LambdaCapture &LC : RD->captures()) {
1107 if (LC.getCaptureKind() == LCK_ByRef) {
1108 - VarDecl *VD = LC.getCapturedVar();
1109 + VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
1110 DeclContext *VDC = VD->getDeclContext();
1111 if (!VDC->Encloses(CurContext))
1112 continue;
1113 diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
1114 index c6ca10c0342c57..73d243cda974e0 100644
1115 --- a/clang/lib/Sema/SemaStmt.cpp
1116 +++ b/clang/lib/Sema/SemaStmt.cpp
1117 @@ -4695,11 +4695,11 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI,
1118 if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
1119 S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
1120
1121 - Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
1122 - Cap.isReferenceCapture()
1123 - ? CapturedStmt::VCK_ByRef
1124 - : CapturedStmt::VCK_ByCopy,
1125 - Cap.getVariable()));
1126 + Captures.push_back(CapturedStmt::Capture(
1127 + Cap.getLocation(),
1128 + Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef
1129 + : CapturedStmt::VCK_ByCopy,
1130 + cast<VarDecl>(Cap.getVariable())));
1131 }
1132 CaptureInits.push_back(Init.get());
1133 }
1134 diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
1135 index 86d92158da8df6..14f652614730db 100644
1136 --- a/clang/lib/Sema/TreeTransform.h
1137 +++ b/clang/lib/Sema/TreeTransform.h
1138 @@ -12986,7 +12986,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1139 continue;
1140
1141 TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()];
1142 - VarDecl *OldVD = C->getCapturedVar();
1143 + auto *OldVD = cast<VarDecl>(C->getCapturedVar());
1144
1145 auto SubstInitCapture = [&](SourceLocation EllipsisLoc,
1146 Optional<unsigned> NumExpansions) {
1147 @@ -13003,7 +13003,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1148 getSema().buildLambdaInitCaptureInitialization(
1149 C->getLocation(), OldVD->getType()->isReferenceType(),
1150 EllipsisLoc, NumExpansions, OldVD->getIdentifier(),
1151 - C->getCapturedVar()->getInitStyle() != VarDecl::CInit,
1152 + cast<VarDecl>(C->getCapturedVar())->getInitStyle() !=
1153 + VarDecl::CInit,
1154 NewExprInit);
1155 Result.Expansions.push_back(
1156 InitCaptureInfoTy(NewExprInit, NewInitCaptureType));
1157 @@ -13170,7 +13171,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1158 if (E->isInitCapture(C)) {
1159 TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()];
1160
1161 - VarDecl *OldVD = C->getCapturedVar();
1162 + auto *OldVD = cast<VarDecl>(C->getCapturedVar());
1163 llvm::SmallVector<Decl*, 4> NewVDs;
1164
1165 for (InitCaptureInfoTy &Info : NewC.Expansions) {
1166 @@ -13225,7 +13226,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1167 // The transform has determined that we should perform an expansion;
1168 // transform and capture each of the arguments.
1169 // expansion of the pattern. Do so.
1170 - VarDecl *Pack = C->getCapturedVar();
1171 + auto *Pack = cast<VarDecl>(C->getCapturedVar());
1172 for (unsigned I = 0; I != *NumExpansions; ++I) {
1173 Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
1174 VarDecl *CapturedVar
1175 diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
1176 index 34af5d6600126c..7e0496fcf34d22 100644
1177 --- a/clang/lib/Serialization/ASTWriter.cpp
1178 +++ b/clang/lib/Serialization/ASTWriter.cpp
1179 @@ -5786,7 +5786,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
1180 break;
1181 case LCK_ByCopy:
1182 case LCK_ByRef:
1183 - VarDecl *Var =
1184 + ValueDecl *Var =
1185 Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr;
1186 AddDeclRef(Var);
1187 AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc()
1188 diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
1189 index 2102f9233bc109..8b6304f65dce5b 100644
1190 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
1191 +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
1192 @@ -504,7 +504,7 @@ class FindEscaped {
1193 // Treat local variables captured by reference in C++ lambdas as escaped.
1194 void findLambdaReferenceCaptures(const LambdaExpr *LE) {
1195 const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
1196 - llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
1197 + llvm::DenseMap<const ValueDecl *, FieldDecl *> CaptureFields;
1198 FieldDecl *ThisCaptureField;
1199 LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
1200
1201 @@ -512,14 +512,14 @@ class FindEscaped {
1202 if (!C.capturesVariable())
1203 continue;
1204
1205 - VarDecl *VD = C.getCapturedVar();
1206 + ValueDecl *VD = C.getCapturedVar();
1207 const FieldDecl *FD = CaptureFields[VD];
1208 - if (!FD)
1209 + if (!FD || !isa<VarDecl>(VD))
1210 continue;
1211
1212 // If the capture field is a reference type, it is capture-by-reference.
1213 if (FD->getType()->isReferenceType())
1214 - Escaped.insert(VD);
1215 + Escaped.insert(cast<VarDecl>(VD));
1216 }
1217 }
1218 };
1219 diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
1220 index deebbd603b2c1c..0c952b5ab9a546 100644
1221 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
1222 +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
1223 @@ -57,7 +57,7 @@ class UncountedLambdaCapturesChecker
1224 void visitLambdaExpr(LambdaExpr *L) const {
1225 for (const LambdaCapture &C : L->captures()) {
1226 if (C.capturesVariable()) {
1227 - VarDecl *CapturedVar = C.getCapturedVar();
1228 + ValueDecl *CapturedVar = C.getCapturedVar();
1229 if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) {
1230 Optional<bool> IsUncountedPtr = isUncountedPtr(CapturedVarType);
1231 if (IsUncountedPtr && *IsUncountedPtr) {
1232 @@ -68,7 +68,7 @@ class UncountedLambdaCapturesChecker
1233 }
1234 }
1235
1236 - void reportBug(const LambdaCapture &Capture, VarDecl *CapturedVar,
1237 + void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
1238 const Type *T) const {
1239 assert(CapturedVar);
1240
1241 diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
1242 index cdd566029ae0ca..049b7d4724353c 100644
1243 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
1244 +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
1245 @@ -2732,7 +2732,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
1246 MD->getParent()->isLambda()) {
1247 // Lookup the field of the lambda.
1248 const CXXRecordDecl *CXXRec = MD->getParent();
1249 - llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
1250 + llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
1251 FieldDecl *LambdaThisCaptureField;
1252 CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
1253
1254 diff --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
1255 index 506d61d94d5fe6..f6efde8c90d136 100644
1256 --- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
1257 +++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
1258 @@ -175,7 +175,7 @@ static bool isCapturedByReference(ExplodedNode *N, const DeclRefExpr *DR) {
1259 const CXXRecordDecl *LambdaCXXRec = MD->getParent();
1260
1261 // Lookup the fields of the lambda
1262 - llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
1263 + llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
1264 FieldDecl *LambdaThisCaptureField;
1265 LambdaCXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
1266
1267 diff --git a/clang/test/CodeGenCXX/cxx20-decomposition.cpp b/clang/test/CodeGenCXX/cxx20-decomposition.cpp
1268 new file mode 100644
1269 index 00000000000000..165450318a80ab
1270 --- /dev/null
1271 +++ b/clang/test/CodeGenCXX/cxx20-decomposition.cpp
1272 @@ -0,0 +1,48 @@
1273 +// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
1274 +
1275 +struct S {
1276 + int i;
1277 + int j;
1278 +};
1279 +
1280 +int f() {
1281 + auto [i, j] = S{1, 42};
1282 + return [&i, j] {
1283 + return i + j;
1284 + }();
1285 +}
1286 +
1287 +// Ensures the representation of the lambda, the order of the
1288 +// 1st 2nd don't matter except for ABI-esque things, but make sure
1289 +// that the ref-capture is a ptr, and 'j' is captured by value.
1290 +// CHECK: %[[LAMBDA_TY:.+]] = type <{ ptr, i32, [4 x i8] }>
1291 +
1292 +// Check the captures themselves.
1293 +// CHECK: define{{.*}} i32 @_Z1fv()
1294 +// CHECK: %[[BINDING:.+]] = alloca %struct.S
1295 +// CHECK: %[[LAMBDA:.+]] = alloca %[[LAMBDA_TY]]
1296 +
1297 +// Copy a pointer to the binding, for reference capture.
1298 +// CHECK: %[[LAMBDA_CAP_PTR:.+]] = getelementptr inbounds %[[LAMBDA_TY]], ptr %[[LAMBDA]], i32 0, i32 0
1299 +// CHECK: %[[BINDING_PTR:.+]] = getelementptr inbounds %struct.S, ptr %[[BINDING]], i32 0, i32 0
1300 +// CHECK: store ptr %[[BINDING_PTR]], ptr %[[LAMBDA_CAP_PTR]]
1301 +
1302 +// Copy the integer from the binding, for copy capture.
1303 +// CHECK: %[[LAMBDA_CAP_INT:.+]] = getelementptr inbounds %[[LAMBDA_TY]], ptr %[[LAMBDA]], i32 0, i32 1
1304 +// CHECK: %[[PTR_TO_J:.+]] = getelementptr inbounds %struct.S, ptr %[[BINDING]], i32 0, i32 1
1305 +// CHECK: %[[J_COPY:.+]] = load i32, ptr %[[PTR_TO_J]]
1306 +// CHECK: store i32 %[[J_COPY]], ptr %[[LAMBDA_CAP_INT]]
1307 +
1308 +// Ensure the captures are properly extracted in operator().
1309 +// CHECK: define{{.*}} i32 @"_ZZ1fvENK3$_0clEv"
1310 +// CHECK: %[[THIS_ADDR:.+]] = alloca ptr
1311 +// CHECK: %[[THIS_PTR:.+]] = load ptr, ptr %[[THIS_ADDR]]
1312 +
1313 +// Load 'i', passed by reference.
1314 +// CHECK: %[[LAMBDA_GEP_TO_PTR:.+]] = getelementptr inbounds %[[LAMBDA_TY]], ptr %[[THIS_PTR]], i32 0, i32 0
1315 +// CHECK: %[[I_PTR:.+]] = load ptr, ptr %[[LAMBDA_GEP_TO_PTR]]
1316 +// CHECK: %[[I_VALUE:.+]] = load i32, ptr %[[I_PTR]]
1317 +
1318 +// Load the 'j', passed by value.
1319 +// CHECK: %[[LAMBDA_GEP_TO_INT:.+]] = getelementptr inbounds %[[LAMBDA_TY]], ptr %[[THIS_PTR]], i32 0, i32 1
1320 +// CHECK: %[[J_VALUE:.+]] = load i32, ptr %[[LAMBDA_GEP_TO_INT]]
1321 diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp
1322 index 4c8c64177ed133..7165f30dc07030 100644
1323 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp
1324 +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp
1325 @@ -1,4 +1,5 @@
1326 -// RUN: %clang_cc1 -std=c++17 -verify %s
1327 +// RUN: %clang_cc1 -std=c++17 -Wc++20-extensions -verify=expected %s
1328 +// RUN: %clang_cc1 -std=c++20 -Wpre-c++20-compat -verify=expected %s
1329
1330 void use_from_own_init() {
1331 auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}}
1332 @@ -46,25 +47,58 @@ constexpr int f(S s) {
1333 }
1334 static_assert(f({1, 2}) == 12);
1335
1336 -constexpr bool g(S &&s) {
1337 +constexpr bool g(S &&s) {
1338 auto &[a, b] = s;
1339 return &a == &s.a && &b == &s.b && &a != &b;
1340 }
1341 static_assert(g({1, 2}));
1342
1343 -auto [outer1, outer2] = S{1, 2};
1344 +struct S1 {
1345 + int a, b;
1346 +};
1347 +struct S2 {
1348 + int a : 1; // expected-note 2{{bit-field is declared here}}
1349 + int b;
1350 +};
1351 +
1352 +auto [outer1, outer2] = S1{1, 2};
1353 +auto [outerbit1, outerbit2] = S1{1, 2}; // expected-note {{declared here}}
1354 +
1355 void enclosing() {
1356 struct S { int a = outer1; };
1357 - auto [n] = S(); // expected-note 2{{'n' declared here}}
1358 + auto [n] = S(); // expected-note 3{{'n' declared here}}
1359 +
1360 + struct Q {
1361 + int f() { return n; } // expected-error {{reference to local binding 'n' declared in enclosing function 'enclosing'}}
1362 + };
1363 +
1364 + (void)[&] { return n; }; // expected-warning {{C++20}}
1365 + (void)[n] { return n; }; // expected-warning {{C++20}}
1366
1367 - struct Q { int f() { return n; } }; // expected-error {{reference to local binding 'n' declared in enclosing function}}
1368 - (void) [&] { return n; }; // expected-error {{reference to local binding 'n' declared in enclosing function}}
1369 - (void) [n] {}; // expected-error {{'n' in capture list does not name a variable}}
1370 + static auto [m] = S(); // expected-note {{'m' declared here}} \
1371 + // expected-warning {{C++20}}
1372
1373 - static auto [m] = S(); // expected-warning {{extension}}
1374 struct R { int f() { return m; } };
1375 (void) [&] { return m; };
1376 - (void) [m] {}; // expected-error {{'m' in capture list does not name a variable}}
1377 + (void)[m]{}; // expected-error {{'m' cannot be captured because it does not have automatic storage duration}}
1378 +
1379 + (void)[outerbit1]{}; // expected-error {{'outerbit1' cannot be captured because it does not have automatic storage duration}}
1380 +
1381 + auto [bit, var] = S2{1, 1}; // expected-note 4{{'bit' declared here}}
1382 +
1383 + (void)[&bit] { // expected-error {{cannot capture a bit-field by reference}} \
1384 + // expected-warning {{C++20}}
1385 + return bit;
1386 + };
1387 +
1388 + union { // expected-note {{declared here}}
1389 + int u;
1390 + };
1391 +
1392 + (void)[&] { return bit + u; } // expected-error {{unnamed variable cannot be implicitly captured in a lambda expression}} \
1393 + // expected-error {{cannot capture a bit-field by reference}} \
1394 + // expected-warning {{C++20}}
1395 + ();
1396 }
1397
1398 void bitfield() {
1399 @@ -98,7 +132,7 @@ template <class T> void dependent_foreach(T t) {
1400
1401 struct PR37352 {
1402 int n;
1403 - void f() { static auto [a] = *this; } // expected-warning {{C++20 extension}}
1404 + void f() { static auto [a] = *this; } // expected-warning {{C++20}}
1405 };
1406
1407 namespace instantiate_template {
1408 diff --git a/clang/test/SemaCXX/cxx20-decomposition.cpp b/clang/test/SemaCXX/cxx20-decomposition.cpp
1409 new file mode 100644
1410 index 00000000000000..a99766f5775b22
1411 --- /dev/null
1412 +++ b/clang/test/SemaCXX/cxx20-decomposition.cpp
1413 @@ -0,0 +1,141 @@
1414 +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
1415 +// expected-no-diagnostics
1416 +
1417 +template <typename, typename>
1418 +constexpr bool is_same = false;
1419 +template <typename T>
1420 +constexpr bool is_same<T, T> = true;
1421 +
1422 +struct S {
1423 + int i;
1424 + int &j;
1425 +};
1426 +
1427 +void check_category() {
1428 + int a = 42;
1429 + {
1430 + auto [v, r] = S{1, a};
1431 + (void)[ v, r ] {
1432 + static_assert(is_same<decltype(v), int>);
1433 + static_assert(is_same<decltype(r), int &>);
1434 + };
1435 + }
1436 + {
1437 + auto [v, r] = S{1, a};
1438 + (void)[&v, &r ] {
1439 + static_assert(is_same<decltype(v), int>);
1440 + static_assert(is_same<decltype(r), int &>);
1441 + };
1442 + }
1443 + {
1444 + S s{1, a};
1445 + const auto &[v, r] = s;
1446 + (void)[ v, r ] {
1447 + static_assert(is_same<decltype(v), const int>);
1448 + static_assert(is_same<decltype(r), int &>);
1449 + };
1450 + }
1451 + {
1452 + S s{1, a};
1453 + const auto &[v, r] = s;
1454 + (void)[&v, &r ] {
1455 + static_assert(is_same<decltype(v), const int>);
1456 + static_assert(is_same<decltype(r), int &>);
1457 + };
1458 + }
1459 +}
1460 +
1461 +void check_array() {
1462 + int arr[2] = {42, 42};
1463 + auto &[a, b] = arr;
1464 + (void)[ a, &b ] {
1465 + static_assert(is_same<decltype(a), int>);
1466 + static_assert(is_same<decltype(b), int>);
1467 + };
1468 +}
1469 +
1470 +struct tuple {
1471 + template <unsigned long I>
1472 + decltype(auto) get() {
1473 + if constexpr (I == 0) {
1474 + return a;
1475 + } else {
1476 + return b;
1477 + }
1478 + }
1479 +
1480 + template <unsigned long I>
1481 + decltype(auto) get() const {
1482 + if constexpr (I == 0) {
1483 + return a;
1484 + } else {
1485 + return b;
1486 + }
1487 + }
1488 +
1489 + int a = 0;
1490 + int &b = a;
1491 +};
1492 +
1493 +namespace std {
1494 +
1495 +template <typename T>
1496 +struct tuple_size {
1497 + static constexpr unsigned long value = 2;
1498 +};
1499 +
1500 +template <unsigned long, typename T>
1501 +struct tuple_element;
1502 +
1503 +template <>
1504 +struct tuple_element<0, tuple> {
1505 + using type = int;
1506 +};
1507 +
1508 +template <>
1509 +struct tuple_element<1, tuple> {
1510 + using type = int &;
1511 +};
1512 +
1513 +template <>
1514 +struct tuple_element<0, const tuple> {
1515 + using type = int;
1516 +};
1517 +
1518 +template <>
1519 +struct tuple_element<1, const tuple> {
1520 + using type = const int &;
1521 +};
1522 +} // namespace std
1523 +
1524 +void check_tuple_like() {
1525 + tuple t;
1526 + {
1527 + auto [v, r] = t;
1528 + (void)[ v, r ] {
1529 + static_assert(is_same<decltype(v), int>);
1530 + static_assert(is_same<decltype(r), int &>);
1531 + };
1532 + }
1533 + {
1534 + auto &[v, r] = t;
1535 + (void)[&v, &r ] {
1536 + static_assert(is_same<decltype(v), int>);
1537 + static_assert(is_same<decltype(r), int &>);
1538 + };
1539 + }
1540 + {
1541 + const auto &[v, r] = t;
1542 + (void)[ v, r ] {
1543 + static_assert(is_same<decltype(v), int>);
1544 + static_assert(is_same<decltype(r), const int &>);
1545 + };
1546 + }
1547 + {
1548 + const auto &[v, r] = t;
1549 + (void)[&v, &r ] {
1550 + static_assert(is_same<decltype(v), int>);
1551 + static_assert(is_same<decltype(r), const int &>);
1552 + };
1553 + }
1554 +}
1555 diff --git a/clang/test/SemaCXX/decomposition-blocks.cpp b/clang/test/SemaCXX/decomposition-blocks.cpp
1556 new file mode 100644
1557 index 00000000000000..21f66f8c7c1b83
1558 --- /dev/null
1559 +++ b/clang/test/SemaCXX/decomposition-blocks.cpp
1560 @@ -0,0 +1,14 @@
1561 +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s -fblocks
1562 +
1563 +struct S {
1564 + int i : 1;
1565 + int j;
1566 +};
1567 +
1568 +void run(void (^)());
1569 +void test() {
1570 + auto [i, j] = S{1, 42}; // expected-note {{'i' declared here}}
1571 + run(^{
1572 + (void)i; // expected-error {{reference to local binding 'i' declared in enclosing function 'test'}}
1573 + });
1574 +}
1575 diff --git a/clang/test/SemaCXX/decomposition-openmp.cpp b/clang/test/SemaCXX/decomposition-openmp.cpp
1576 new file mode 100644
1577 index 00000000000000..28afc398003995
1578 --- /dev/null
1579 +++ b/clang/test/SemaCXX/decomposition-openmp.cpp
1580 @@ -0,0 +1,13 @@
1581 +
1582 +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 -fopenmp %s
1583 +
1584 +// FIXME: OpenMP should support capturing structured bindings
1585 +auto f() {
1586 + int i[2] = {};
1587 + auto [a, b] = i; // expected-note 2{{declared here}}
1588 + return [=, &a] {
1589 + // expected-error@-1 {{capturing a structured binding is not yet supported in OpenMP}}
1590 + return a + b;
1591 + // expected-error@-1 {{capturing a structured binding is not yet supported in OpenMP}}
1592 + };
1593 +}
1594 diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
1595 index 9356dd4a23774b..b3f91ef794ba22 100644
1596 --- a/clang/tools/libclang/CIndex.cpp
1597 +++ b/clang/tools/libclang/CIndex.cpp
1598 @@ -3482,9 +3482,11 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
1599 C != CEnd; ++C) {
1600 if (!C->capturesVariable())
1601 continue;
1602 -
1603 - if (Visit(MakeCursorVariableRef(C->getCapturedVar(), C->getLocation(),
1604 - TU)))
1605 + // TODO: handle structured bindings here ?
1606 + if (!isa<VarDecl>(C->getCapturedVar()))
1607 + continue;
1608 + if (Visit(MakeCursorVariableRef(cast<VarDecl>(C->getCapturedVar()),
1609 + C->getLocation(), TU)))
1610 return true;
1611 }
1612 // Visit init captures
1613 diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
1614 index 41b788e82d73de..5aae4ba8228261 100755
1615 --- a/clang/www/cxx_status.html
1616 +++ b/clang/www/cxx_status.html
1617 @@ -1140,7 +1140,7 @@ <h2 id="cxx20">C++20 implementation status</h2>
1618 <tr>
1619 <td rowspan="2">Structured binding extensions</td>
1620 <td><a href="https://wg21.link/p1091r3">P1091R3</a></td>
1621 - <td rowspan="2" class="partial" align="center">Partial</td>
1622 + <td rowspan="2" class="unreleased" align="center">Clang 16</td>
1623 </tr>
1624 <tr>
1625 <td><a href="https://wg21.link/p1381r1">P1381R1</a></td>