1 //===--- ScopeInfo.h - Information about a semantic context -----*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines FunctionScopeInfo and its subclasses, which contain
11 // information about a single function, block, lambda, or method body.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_CLANG_SEMA_SCOPE_INFO_H
16 #define LLVM_CLANG_SEMA_SCOPE_INFO_H
17
18 #include "clang/AST/Type.h"
19 #include "clang/Basic/PartialDiagnostic.h"
20 #include "llvm/ADT/DenseMap.h"
21 #include "llvm/ADT/SmallVector.h"
22
23 namespace clang {
24
25 class Decl;
26 class BlockDecl;
27 class CXXMethodDecl;
28 class ObjCPropertyDecl;
29 class IdentifierInfo;
30 class LabelDecl;
31 class ReturnStmt;
32 class Scope;
33 class SwitchStmt;
34 class VarDecl;
35 class DeclRefExpr;
36 class ObjCIvarRefExpr;
37 class ObjCPropertyRefExpr;
38 class ObjCMessageExpr;
39
40 namespace sema {
41
42 /// \brief Contains information about the compound statement currently being
43 /// parsed.
44 class CompoundScopeInfo {
45 public:
CompoundScopeInfo()46 CompoundScopeInfo()
47 : HasEmptyLoopBodies(false) { }
48
49 /// \brief Whether this compound stamement contains `for' or `while' loops
50 /// with empty bodies.
51 bool HasEmptyLoopBodies;
52
setHasEmptyLoopBodies()53 void setHasEmptyLoopBodies() {
54 HasEmptyLoopBodies = true;
55 }
56 };
57
58 class PossiblyUnreachableDiag {
59 public:
60 PartialDiagnostic PD;
61 SourceLocation Loc;
62 const Stmt *stmt;
63
PossiblyUnreachableDiag(const PartialDiagnostic & PD,SourceLocation Loc,const Stmt * stmt)64 PossiblyUnreachableDiag(const PartialDiagnostic &PD, SourceLocation Loc,
65 const Stmt *stmt)
66 : PD(PD), Loc(Loc), stmt(stmt) {}
67 };
68
69 /// \brief Retains information about a function, method, or block that is
70 /// currently being parsed.
71 class FunctionScopeInfo {
72 protected:
73 enum ScopeKind {
74 SK_Function,
75 SK_Block,
76 SK_Lambda
77 };
78
79 public:
80 /// \brief What kind of scope we are describing.
81 ///
82 ScopeKind Kind;
83
84 /// \brief Whether this function contains a VLA, \@try, try, C++
85 /// initializer, or anything else that can't be jumped past.
86 bool HasBranchProtectedScope;
87
88 /// \brief Whether this function contains any switches or direct gotos.
89 bool HasBranchIntoScope;
90
91 /// \brief Whether this function contains any indirect gotos.
92 bool HasIndirectGoto;
93
94 /// \brief Whether a statement was dropped because it was invalid.
95 bool HasDroppedStmt;
96
97 /// A flag that is set when parsing a method that must call super's
98 /// implementation, such as \c -dealloc, \c -finalize, or any method marked
99 /// with \c __attribute__((objc_requires_super)).
100 bool ObjCShouldCallSuper;
101
102 /// \brief Used to determine if errors occurred in this function or block.
103 DiagnosticErrorTrap ErrorTrap;
104
105 /// SwitchStack - This is the current set of active switch statements in the
106 /// block.
107 SmallVector<SwitchStmt*, 8> SwitchStack;
108
109 /// \brief The list of return statements that occur within the function or
110 /// block, if there is any chance of applying the named return value
111 /// optimization, or if we need to infer a return type.
112 SmallVector<ReturnStmt*, 4> Returns;
113
114 /// \brief The stack of currently active compound stamement scopes in the
115 /// function.
116 SmallVector<CompoundScopeInfo, 4> CompoundScopes;
117
118 /// \brief A list of PartialDiagnostics created but delayed within the
119 /// current function scope. These diagnostics are vetted for reachability
120 /// prior to being emitted.
121 SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags;
122
123 public:
124 /// Represents a simple identification of a weak object.
125 ///
126 /// Part of the implementation of -Wrepeated-use-of-weak.
127 ///
128 /// This is used to determine if two weak accesses refer to the same object.
129 /// Here are some examples of how various accesses are "profiled":
130 ///
131 /// Access Expression | "Base" Decl | "Property" Decl
132 /// :---------------: | :-----------------: | :------------------------------:
133 /// self.property | self (VarDecl) | property (ObjCPropertyDecl)
134 /// self.implicitProp | self (VarDecl) | -implicitProp (ObjCMethodDecl)
135 /// self->ivar.prop | ivar (ObjCIvarDecl) | prop (ObjCPropertyDecl)
136 /// cxxObj.obj.prop | obj (FieldDecl) | prop (ObjCPropertyDecl)
137 /// [self foo].prop | 0 (unknown) | prop (ObjCPropertyDecl)
138 /// self.prop1.prop2 | prop1 (ObjCPropertyDecl) | prop2 (ObjCPropertyDecl)
139 /// MyClass.prop | MyClass (ObjCInterfaceDecl) | -prop (ObjCMethodDecl)
140 /// weakVar | 0 (known) | weakVar (VarDecl)
141 /// self->weakIvar | self (VarDecl) | weakIvar (ObjCIvarDecl)
142 ///
143 /// Objects are identified with only two Decls to make it reasonably fast to
144 /// compare them.
145 class WeakObjectProfileTy {
146 /// The base object decl, as described in the class documentation.
147 ///
148 /// The extra flag is "true" if the Base and Property are enough to uniquely
149 /// identify the object in memory.
150 ///
151 /// \sa isExactProfile()
152 typedef llvm::PointerIntPair<const NamedDecl *, 1, bool> BaseInfoTy;
153 BaseInfoTy Base;
154
155 /// The "property" decl, as described in the class documentation.
156 ///
157 /// Note that this may not actually be an ObjCPropertyDecl, e.g. in the
158 /// case of "implicit" properties (regular methods accessed via dot syntax).
159 const NamedDecl *Property;
160
161 /// Used to find the proper base profile for a given base expression.
162 static BaseInfoTy getBaseInfo(const Expr *BaseE);
163
164 // For use in DenseMap.
165 friend class DenseMapInfo;
166 inline WeakObjectProfileTy();
167 static inline WeakObjectProfileTy getSentinel();
168
169 public:
170 WeakObjectProfileTy(const ObjCPropertyRefExpr *RE);
171 WeakObjectProfileTy(const Expr *Base, const ObjCPropertyDecl *Property);
172 WeakObjectProfileTy(const DeclRefExpr *RE);
173 WeakObjectProfileTy(const ObjCIvarRefExpr *RE);
174
getBase()175 const NamedDecl *getBase() const { return Base.getPointer(); }
getProperty()176 const NamedDecl *getProperty() const { return Property; }
177
178 /// Returns true if the object base specifies a known object in memory,
179 /// rather than, say, an instance variable or property of another object.
180 ///
181 /// Note that this ignores the effects of aliasing; that is, \c foo.bar is
182 /// considered an exact profile if \c foo is a local variable, even if
183 /// another variable \c foo2 refers to the same object as \c foo.
184 ///
185 /// For increased precision, accesses with base variables that are
186 /// properties or ivars of 'self' (e.g. self.prop1.prop2) are considered to
187 /// be exact, though this is not true for arbitrary variables
188 /// (foo.prop1.prop2).
isExactProfile()189 bool isExactProfile() const {
190 return Base.getInt();
191 }
192
193 bool operator==(const WeakObjectProfileTy &Other) const {
194 return Base == Other.Base && Property == Other.Property;
195 }
196
197 // For use in DenseMap.
198 // We can't specialize the usual llvm::DenseMapInfo at the end of the file
199 // because by that point the DenseMap in FunctionScopeInfo has already been
200 // instantiated.
201 class DenseMapInfo {
202 public:
getEmptyKey()203 static inline WeakObjectProfileTy getEmptyKey() {
204 return WeakObjectProfileTy();
205 }
getTombstoneKey()206 static inline WeakObjectProfileTy getTombstoneKey() {
207 return WeakObjectProfileTy::getSentinel();
208 }
209
getHashValue(const WeakObjectProfileTy & Val)210 static unsigned getHashValue(const WeakObjectProfileTy &Val) {
211 typedef std::pair<BaseInfoTy, const NamedDecl *> Pair;
212 return llvm::DenseMapInfo<Pair>::getHashValue(Pair(Val.Base,
213 Val.Property));
214 }
215
isEqual(const WeakObjectProfileTy & LHS,const WeakObjectProfileTy & RHS)216 static bool isEqual(const WeakObjectProfileTy &LHS,
217 const WeakObjectProfileTy &RHS) {
218 return LHS == RHS;
219 }
220 };
221 };
222
223 /// Represents a single use of a weak object.
224 ///
225 /// Stores both the expression and whether the access is potentially unsafe
226 /// (i.e. it could potentially be warned about).
227 ///
228 /// Part of the implementation of -Wrepeated-use-of-weak.
229 class WeakUseTy {
230 llvm::PointerIntPair<const Expr *, 1, bool> Rep;
231 public:
WeakUseTy(const Expr * Use,bool IsRead)232 WeakUseTy(const Expr *Use, bool IsRead) : Rep(Use, IsRead) {}
233
getUseExpr()234 const Expr *getUseExpr() const { return Rep.getPointer(); }
isUnsafe()235 bool isUnsafe() const { return Rep.getInt(); }
markSafe()236 void markSafe() { Rep.setInt(false); }
237
238 bool operator==(const WeakUseTy &Other) const {
239 return Rep == Other.Rep;
240 }
241 };
242
243 /// Used to collect uses of a particular weak object in a function body.
244 ///
245 /// Part of the implementation of -Wrepeated-use-of-weak.
246 typedef SmallVector<WeakUseTy, 4> WeakUseVector;
247
248 /// Used to collect all uses of weak objects in a function body.
249 ///
250 /// Part of the implementation of -Wrepeated-use-of-weak.
251 typedef llvm::SmallDenseMap<WeakObjectProfileTy, WeakUseVector, 8,
252 WeakObjectProfileTy::DenseMapInfo>
253 WeakObjectUseMap;
254
255 private:
256 /// Used to collect all uses of weak objects in this function body.
257 ///
258 /// Part of the implementation of -Wrepeated-use-of-weak.
259 WeakObjectUseMap WeakObjectUses;
260
261 public:
262 /// Record that a weak object was accessed.
263 ///
264 /// Part of the implementation of -Wrepeated-use-of-weak.
265 template <typename ExprT>
266 inline void recordUseOfWeak(const ExprT *E, bool IsRead = true);
267
268 void recordUseOfWeak(const ObjCMessageExpr *Msg,
269 const ObjCPropertyDecl *Prop);
270
271 /// Record that a given expression is a "safe" access of a weak object (e.g.
272 /// assigning it to a strong variable.)
273 ///
274 /// Part of the implementation of -Wrepeated-use-of-weak.
275 void markSafeWeakUse(const Expr *E);
276
getWeakObjectUses()277 const WeakObjectUseMap &getWeakObjectUses() const {
278 return WeakObjectUses;
279 }
280
setHasBranchIntoScope()281 void setHasBranchIntoScope() {
282 HasBranchIntoScope = true;
283 }
284
setHasBranchProtectedScope()285 void setHasBranchProtectedScope() {
286 HasBranchProtectedScope = true;
287 }
288
setHasIndirectGoto()289 void setHasIndirectGoto() {
290 HasIndirectGoto = true;
291 }
292
setHasDroppedStmt()293 void setHasDroppedStmt() {
294 HasDroppedStmt = true;
295 }
296
NeedsScopeChecking()297 bool NeedsScopeChecking() const {
298 return !HasDroppedStmt &&
299 (HasIndirectGoto ||
300 (HasBranchProtectedScope && HasBranchIntoScope));
301 }
302
FunctionScopeInfo(DiagnosticsEngine & Diag)303 FunctionScopeInfo(DiagnosticsEngine &Diag)
304 : Kind(SK_Function),
305 HasBranchProtectedScope(false),
306 HasBranchIntoScope(false),
307 HasIndirectGoto(false),
308 HasDroppedStmt(false),
309 ObjCShouldCallSuper(false),
310 ErrorTrap(Diag) { }
311
312 virtual ~FunctionScopeInfo();
313
314 /// \brief Clear out the information in this function scope, making it
315 /// suitable for reuse.
316 void Clear();
317 };
318
319 class CapturingScopeInfo : public FunctionScopeInfo {
320 public:
321 enum ImplicitCaptureStyle {
322 ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block
323 };
324
325 ImplicitCaptureStyle ImpCaptureStyle;
326
327 class Capture {
328 // There are two categories of capture: capturing 'this', and capturing
329 // local variables. There are three ways to capture a local variable:
330 // capture by copy in the C++11 sense, capture by reference
331 // in the C++11 sense, and __block capture. Lambdas explicitly specify
332 // capture by copy or capture by reference. For blocks, __block capture
333 // applies to variables with that annotation, variables of reference type
334 // are captured by reference, and other variables are captured by copy.
335 enum CaptureKind {
336 Cap_This, Cap_ByCopy, Cap_ByRef, Cap_Block
337 };
338
339 // The variable being captured (if we are not capturing 'this'),
340 // and misc bits descibing the capture.
341 llvm::PointerIntPair<VarDecl*, 2, CaptureKind> VarAndKind;
342
343 // Expression to initialize a field of the given type, and whether this
344 // is a nested capture; the expression is only required if we are
345 // capturing ByVal and the variable's type has a non-trivial
346 // copy constructor.
347 llvm::PointerIntPair<Expr*, 1, bool> CopyExprAndNested;
348
349 /// \brief The source location at which the first capture occurred..
350 SourceLocation Loc;
351
352 /// \brief The location of the ellipsis that expands a parameter pack.
353 SourceLocation EllipsisLoc;
354
355 /// \brief The type as it was captured, which is in effect the type of the
356 /// non-static data member that would hold the capture.
357 QualType CaptureType;
358
359 public:
Capture(VarDecl * Var,bool block,bool byRef,bool isNested,SourceLocation Loc,SourceLocation EllipsisLoc,QualType CaptureType,Expr * Cpy)360 Capture(VarDecl *Var, bool block, bool byRef, bool isNested,
361 SourceLocation Loc, SourceLocation EllipsisLoc,
362 QualType CaptureType, Expr *Cpy)
363 : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy),
364 CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc),
365 CaptureType(CaptureType){}
366
367 enum IsThisCapture { ThisCapture };
Capture(IsThisCapture,bool isNested,SourceLocation Loc,QualType CaptureType,Expr * Cpy)368 Capture(IsThisCapture, bool isNested, SourceLocation Loc,
369 QualType CaptureType, Expr *Cpy)
370 : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc),
371 EllipsisLoc(), CaptureType(CaptureType) { }
372
isThisCapture()373 bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; }
isVariableCapture()374 bool isVariableCapture() const { return !isThisCapture(); }
isCopyCapture()375 bool isCopyCapture() const { return VarAndKind.getInt() == Cap_ByCopy; }
isReferenceCapture()376 bool isReferenceCapture() const { return VarAndKind.getInt() == Cap_ByRef; }
isBlockCapture()377 bool isBlockCapture() const { return VarAndKind.getInt() == Cap_Block; }
isNested()378 bool isNested() { return CopyExprAndNested.getInt(); }
379
getVariable()380 VarDecl *getVariable() const {
381 return VarAndKind.getPointer();
382 }
383
384 /// \brief Retrieve the location at which this variable was captured.
getLocation()385 SourceLocation getLocation() const { return Loc; }
386
387 /// \brief Retrieve the source location of the ellipsis, whose presence
388 /// indicates that the capture is a pack expansion.
getEllipsisLoc()389 SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
390
391 /// \brief Retrieve the capture type for this capture, which is effectively
392 /// the type of the non-static data member in the lambda/block structure
393 /// that would store this capture.
getCaptureType()394 QualType getCaptureType() const { return CaptureType; }
395
getCopyExpr()396 Expr *getCopyExpr() const {
397 return CopyExprAndNested.getPointer();
398 }
399 };
400
CapturingScopeInfo(DiagnosticsEngine & Diag,ImplicitCaptureStyle Style)401 CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style)
402 : FunctionScopeInfo(Diag), ImpCaptureStyle(Style), CXXThisCaptureIndex(0),
403 HasImplicitReturnType(false)
404 {}
405
406 /// CaptureMap - A map of captured variables to (index+1) into Captures.
407 llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
408
409 /// CXXThisCaptureIndex - The (index+1) of the capture of 'this';
410 /// zero if 'this' is not captured.
411 unsigned CXXThisCaptureIndex;
412
413 /// Captures - The captures.
414 SmallVector<Capture, 4> Captures;
415
416 /// \brief - Whether the target type of return statements in this context
417 /// is deduced (e.g. a lambda or block with omitted return type).
418 bool HasImplicitReturnType;
419
420 /// ReturnType - The target type of return statements in this context,
421 /// or null if unknown.
422 QualType ReturnType;
423
addCapture(VarDecl * Var,bool isBlock,bool isByref,bool isNested,SourceLocation Loc,SourceLocation EllipsisLoc,QualType CaptureType,Expr * Cpy)424 void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
425 SourceLocation Loc, SourceLocation EllipsisLoc,
426 QualType CaptureType, Expr *Cpy) {
427 Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc,
428 EllipsisLoc, CaptureType, Cpy));
429 CaptureMap[Var] = Captures.size();
430 }
431
432 void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
433 Expr *Cpy);
434
435 /// \brief Determine whether the C++ 'this' is captured.
isCXXThisCaptured()436 bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; }
437
438 /// \brief Retrieve the capture of C++ 'this', if it has been captured.
getCXXThisCapture()439 Capture &getCXXThisCapture() {
440 assert(isCXXThisCaptured() && "this has not been captured");
441 return Captures[CXXThisCaptureIndex - 1];
442 }
443
444 /// \brief Determine whether the given variable has been captured.
isCaptured(VarDecl * Var)445 bool isCaptured(VarDecl *Var) const {
446 return CaptureMap.count(Var);
447 }
448
449 /// \brief Retrieve the capture of the given variable, if it has been
450 /// captured already.
getCapture(VarDecl * Var)451 Capture &getCapture(VarDecl *Var) {
452 assert(isCaptured(Var) && "Variable has not been captured");
453 return Captures[CaptureMap[Var] - 1];
454 }
455
getCapture(VarDecl * Var)456 const Capture &getCapture(VarDecl *Var) const {
457 llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known
458 = CaptureMap.find(Var);
459 assert(Known != CaptureMap.end() && "Variable has not been captured");
460 return Captures[Known->second - 1];
461 }
462
classof(const FunctionScopeInfo * FSI)463 static bool classof(const FunctionScopeInfo *FSI) {
464 return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda;
465 }
466 };
467
468 /// \brief Retains information about a block that is currently being parsed.
469 class BlockScopeInfo : public CapturingScopeInfo {
470 public:
471 BlockDecl *TheDecl;
472
473 /// TheScope - This is the scope for the block itself, which contains
474 /// arguments etc.
475 Scope *TheScope;
476
477 /// BlockType - The function type of the block, if one was given.
478 /// Its return type may be BuiltinType::Dependent.
479 QualType FunctionType;
480
BlockScopeInfo(DiagnosticsEngine & Diag,Scope * BlockScope,BlockDecl * Block)481 BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block)
482 : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block),
483 TheScope(BlockScope)
484 {
485 Kind = SK_Block;
486 }
487
488 virtual ~BlockScopeInfo();
489
classof(const FunctionScopeInfo * FSI)490 static bool classof(const FunctionScopeInfo *FSI) {
491 return FSI->Kind == SK_Block;
492 }
493 };
494
495 class LambdaScopeInfo : public CapturingScopeInfo {
496 public:
497 /// \brief The class that describes the lambda.
498 CXXRecordDecl *Lambda;
499
500 /// \brief The class that describes the lambda.
501 CXXMethodDecl *CallOperator;
502
503 /// \brief Source range covering the lambda introducer [...].
504 SourceRange IntroducerRange;
505
506 /// \brief The number of captures in the \c Captures list that are
507 /// explicit captures.
508 unsigned NumExplicitCaptures;
509
510 /// \brief Whether this is a mutable lambda.
511 bool Mutable;
512
513 /// \brief Whether the (empty) parameter list is explicit.
514 bool ExplicitParams;
515
516 /// \brief Whether any of the capture expressions requires cleanups.
517 bool ExprNeedsCleanups;
518
519 /// \brief Whether the lambda contains an unexpanded parameter pack.
520 bool ContainsUnexpandedParameterPack;
521
522 /// \brief Variables used to index into by-copy array captures.
523 SmallVector<VarDecl *, 4> ArrayIndexVars;
524
525 /// \brief Offsets into the ArrayIndexVars array at which each capture starts
526 /// its list of array index variables.
527 SmallVector<unsigned, 4> ArrayIndexStarts;
528
LambdaScopeInfo(DiagnosticsEngine & Diag,CXXRecordDecl * Lambda,CXXMethodDecl * CallOperator)529 LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
530 CXXMethodDecl *CallOperator)
531 : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
532 CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false),
533 ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false)
534 {
535 Kind = SK_Lambda;
536 }
537
538 virtual ~LambdaScopeInfo();
539
540 /// \brief Note when
finishedExplicitCaptures()541 void finishedExplicitCaptures() {
542 NumExplicitCaptures = Captures.size();
543 }
544
classof(const FunctionScopeInfo * FSI)545 static bool classof(const FunctionScopeInfo *FSI) {
546 return FSI->Kind == SK_Lambda;
547 }
548 };
549
550
WeakObjectProfileTy()551 FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy()
552 : Base(0, false), Property(0) {}
553
554 FunctionScopeInfo::WeakObjectProfileTy
getSentinel()555 FunctionScopeInfo::WeakObjectProfileTy::getSentinel() {
556 FunctionScopeInfo::WeakObjectProfileTy Result;
557 Result.Base.setInt(true);
558 return Result;
559 }
560
561 template <typename ExprT>
recordUseOfWeak(const ExprT * E,bool IsRead)562 void FunctionScopeInfo::recordUseOfWeak(const ExprT *E, bool IsRead) {
563 assert(E);
564 WeakUseVector &Uses = WeakObjectUses[WeakObjectProfileTy(E)];
565 Uses.push_back(WeakUseTy(E, IsRead));
566 }
567
568 inline void
addThisCapture(bool isNested,SourceLocation Loc,QualType CaptureType,Expr * Cpy)569 CapturingScopeInfo::addThisCapture(bool isNested, SourceLocation Loc,
570 QualType CaptureType, Expr *Cpy) {
571 Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType,
572 Cpy));
573 CXXThisCaptureIndex = Captures.size();
574
575 if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(this))
576 LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size());
577 }
578
579 } // end namespace sema
580 } // end namespace clang
581
582 #endif
583