Annotation of /trunk/llvm/patches/clang-15.0.7-structured-bindings-r1.patch
Parent Directory | Revision Log
Revision 3753 -
(hide annotations)
(download)
Fri Aug 4 08:32:09 2023 UTC (10 months ago) by niro
File size: 69760 byte(s)
Fri Aug 4 08:32:09 2023 UTC (10 months ago) by niro
File size: 69760 byte(s)
-llcm/clang patches for 15.0.7
1 | niro | 3753 | 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> |