1//===- Scope.h - Scope interface --------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the Scope interface.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_SEMA_SCOPE_H
14#define LLVM_CLANG_SEMA_SCOPE_H
15
16#include "clang/AST/Decl.h"
17#include "clang/Basic/Diagnostic.h"
18#include "llvm/ADT/PointerIntPair.h"
19#include "llvm/ADT/SmallPtrSet.h"
20#include "llvm/ADT/SmallVector.h"
21#include "llvm/ADT/iterator_range.h"
22#include <cassert>
23#include <optional>
24
25namespace llvm {
26
27class raw_ostream;
28
29} // namespace llvm
30
31namespace clang {
32
33class Decl;
34class DeclContext;
35class UsingDirectiveDecl;
36class VarDecl;
37
38/// Scope - A scope is a transient data structure that is used while parsing the
39/// program. It assists with resolving identifiers to the appropriate
40/// declaration.
41class Scope {
42public:
43 /// ScopeFlags - These are bitfields that are or'd together when creating a
44 /// scope, which defines the sorts of things the scope contains.
45 enum ScopeFlags {
46 // A bitfield value representing no scopes.
47 NoScope = 0,
48
49 /// This indicates that the scope corresponds to a function, which
50 /// means that labels are set here.
51 FnScope = 0x01,
52
53 /// This is a while, do, switch, for, etc that can have break
54 /// statements embedded into it.
55 BreakScope = 0x02,
56
57 /// This is a while, do, for, which can have continue statements
58 /// embedded into it.
59 ContinueScope = 0x04,
60
61 /// This is a scope that can contain a declaration. Some scopes
62 /// just contain loop constructs but don't contain decls.
63 DeclScope = 0x08,
64
65 /// The controlling scope in a if/switch/while/for statement.
66 ControlScope = 0x10,
67
68 /// The scope of a struct/union/class definition.
69 ClassScope = 0x20,
70
71 /// This is a scope that corresponds to a block/closure object.
72 /// Blocks serve as top-level scopes for some objects like labels, they
73 /// also prevent things like break and continue. BlockScopes always have
74 /// the FnScope and DeclScope flags set as well.
75 BlockScope = 0x40,
76
77 /// This is a scope that corresponds to the
78 /// template parameters of a C++ template. Template parameter
79 /// scope starts at the 'template' keyword and ends when the
80 /// template declaration ends.
81 TemplateParamScope = 0x80,
82
83 /// This is a scope that corresponds to the
84 /// parameters within a function prototype.
85 FunctionPrototypeScope = 0x100,
86
87 /// This is a scope that corresponds to the parameters within
88 /// a function prototype for a function declaration (as opposed to any
89 /// other kind of function declarator). Always has FunctionPrototypeScope
90 /// set as well.
91 FunctionDeclarationScope = 0x200,
92
93 /// This is a scope that corresponds to the Objective-C
94 /// \@catch statement.
95 AtCatchScope = 0x400,
96
97 /// This scope corresponds to an Objective-C method body.
98 /// It always has FnScope and DeclScope set as well.
99 ObjCMethodScope = 0x800,
100
101 /// This is a scope that corresponds to a switch statement.
102 SwitchScope = 0x1000,
103
104 /// This is the scope of a C++ try statement.
105 TryScope = 0x2000,
106
107 /// This is the scope for a function-level C++ try or catch scope.
108 FnTryCatchScope = 0x4000,
109
110 /// This is the scope of OpenMP executable directive.
111 OpenMPDirectiveScope = 0x8000,
112
113 /// This is the scope of some OpenMP loop directive.
114 OpenMPLoopDirectiveScope = 0x10000,
115
116 /// This is the scope of some OpenMP simd directive.
117 /// For example, it is used for 'omp simd', 'omp for simd'.
118 /// This flag is propagated to children scopes.
119 OpenMPSimdDirectiveScope = 0x20000,
120
121 /// This scope corresponds to an enum.
122 EnumScope = 0x40000,
123
124 /// This scope corresponds to an SEH try.
125 SEHTryScope = 0x80000,
126
127 /// This scope corresponds to an SEH except.
128 SEHExceptScope = 0x100000,
129
130 /// We are currently in the filter expression of an SEH except block.
131 SEHFilterScope = 0x200000,
132
133 /// This is a compound statement scope.
134 CompoundStmtScope = 0x400000,
135
136 /// We are between inheritance colon and the real class/struct definition
137 /// scope.
138 ClassInheritanceScope = 0x800000,
139
140 /// This is the scope of a C++ catch statement.
141 CatchScope = 0x1000000,
142
143 /// This is a scope in which a condition variable is currently being
144 /// parsed. If such a scope is a ContinueScope, it's invalid to jump to the
145 /// continue block from here.
146 ConditionVarScope = 0x2000000,
147
148 /// This is a scope of some OpenMP directive with
149 /// order clause which specifies concurrent
150 OpenMPOrderClauseScope = 0x4000000,
151 /// This is the scope for a lambda, after the lambda introducer.
152 /// Lambdas need two FunctionPrototypeScope scopes (because there is a
153 /// template scope in between), the outer scope does not increase the
154 /// depth of recursion.
155 LambdaScope = 0x8000000,
156 /// This is the scope of an OpenACC Compute Construct, which restricts
157 /// jumping into/out of it.
158 OpenACCComputeConstructScope = 0x10000000,
159
160 /// This is a scope of type alias declaration.
161 TypeAliasScope = 0x20000000,
162 };
163
164private:
165 /// The parent scope for this scope. This is null for the translation-unit
166 /// scope.
167 Scope *AnyParent;
168
169 /// Flags - This contains a set of ScopeFlags, which indicates how the scope
170 /// interrelates with other control flow statements.
171 unsigned Flags;
172
173 /// Depth - This is the depth of this scope. The translation-unit scope has
174 /// depth 0.
175 unsigned short Depth;
176
177 /// Declarations with static linkage are mangled with the number of
178 /// scopes seen as a component.
179 unsigned short MSLastManglingNumber;
180
181 unsigned short MSCurManglingNumber;
182
183 /// PrototypeDepth - This is the number of function prototype scopes
184 /// enclosing this scope, including this scope.
185 unsigned short PrototypeDepth;
186
187 /// PrototypeIndex - This is the number of parameters currently
188 /// declared in this scope.
189 unsigned short PrototypeIndex;
190
191 /// FnParent - If this scope has a parent scope that is a function body, this
192 /// pointer is non-null and points to it. This is used for label processing.
193 Scope *FnParent;
194 Scope *MSLastManglingParent;
195
196 /// BreakParent/ContinueParent - This is a direct link to the innermost
197 /// BreakScope/ContinueScope which contains the contents of this scope
198 /// for control flow purposes (and might be this scope itself), or null
199 /// if there is no such scope.
200 Scope *BreakParent, *ContinueParent;
201
202 /// BlockParent - This is a direct link to the immediately containing
203 /// BlockScope if this scope is not one, or null if there is none.
204 Scope *BlockParent;
205
206 /// TemplateParamParent - This is a direct link to the
207 /// immediately containing template parameter scope. In the
208 /// case of nested templates, template parameter scopes can have
209 /// other template parameter scopes as parents.
210 Scope *TemplateParamParent;
211
212 /// DeclScopeParent - This is a direct link to the immediately containing
213 /// DeclScope, i.e. scope which can contain declarations.
214 Scope *DeclParent;
215
216 /// DeclsInScope - This keeps track of all declarations in this scope. When
217 /// the declaration is added to the scope, it is set as the current
218 /// declaration for the identifier in the IdentifierTable. When the scope is
219 /// popped, these declarations are removed from the IdentifierTable's notion
220 /// of current declaration. It is up to the current Action implementation to
221 /// implement these semantics.
222 using DeclSetTy = llvm::SmallPtrSet<Decl *, 32>;
223 DeclSetTy DeclsInScope;
224
225 /// The DeclContext with which this scope is associated. For
226 /// example, the entity of a class scope is the class itself, the
227 /// entity of a function scope is a function, etc.
228 DeclContext *Entity;
229
230 using UsingDirectivesTy = SmallVector<UsingDirectiveDecl *, 2>;
231 UsingDirectivesTy UsingDirectives;
232
233 /// Used to determine if errors occurred in this scope.
234 DiagnosticErrorTrap ErrorTrap;
235
236 /// A single NRVO candidate variable in this scope.
237 /// There are three possible values:
238 /// 1) pointer to VarDecl that denotes NRVO candidate itself.
239 /// 2) nullptr value means that NRVO is not allowed in this scope
240 /// (e.g. return a function parameter).
241 /// 3) std::nullopt value means that there is no NRVO candidate in this scope
242 /// (i.e. there are no return statements in this scope).
243 std::optional<VarDecl *> NRVO;
244
245 /// Represents return slots for NRVO candidates in the current scope.
246 /// If a variable is present in this set, it means that a return slot is
247 /// available for this variable in the current scope.
248 llvm::SmallPtrSet<VarDecl *, 8> ReturnSlots;
249
250 void setFlags(Scope *Parent, unsigned F);
251
252public:
253 Scope(Scope *Parent, unsigned ScopeFlags, DiagnosticsEngine &Diag)
254 : ErrorTrap(Diag) {
255 Init(parent: Parent, flags: ScopeFlags);
256 }
257
258 /// getFlags - Return the flags for this scope.
259 unsigned getFlags() const { return Flags; }
260
261 void setFlags(unsigned F) { setFlags(Parent: getParent(), F); }
262
263 /// isBlockScope - Return true if this scope correspond to a closure.
264 bool isBlockScope() const { return Flags & BlockScope; }
265
266 /// getParent - Return the scope that this is nested in.
267 const Scope *getParent() const { return AnyParent; }
268 Scope *getParent() { return AnyParent; }
269
270 /// getFnParent - Return the closest scope that is a function body.
271 const Scope *getFnParent() const { return FnParent; }
272 Scope *getFnParent() { return FnParent; }
273
274 const Scope *getMSLastManglingParent() const {
275 return MSLastManglingParent;
276 }
277 Scope *getMSLastManglingParent() { return MSLastManglingParent; }
278
279 /// getContinueParent - Return the closest scope that a continue statement
280 /// would be affected by.
281 Scope *getContinueParent() {
282 return ContinueParent;
283 }
284
285 const Scope *getContinueParent() const {
286 return const_cast<Scope*>(this)->getContinueParent();
287 }
288
289 // Set whether we're in the scope of a condition variable, where 'continue'
290 // is disallowed despite being a continue scope.
291 void setIsConditionVarScope(bool InConditionVarScope) {
292 Flags = (Flags & ~ConditionVarScope) |
293 (InConditionVarScope ? ConditionVarScope : 0);
294 }
295
296 bool isConditionVarScope() const {
297 return Flags & ConditionVarScope;
298 }
299
300 /// getBreakParent - Return the closest scope that a break statement
301 /// would be affected by.
302 Scope *getBreakParent() {
303 return BreakParent;
304 }
305 const Scope *getBreakParent() const {
306 return const_cast<Scope*>(this)->getBreakParent();
307 }
308
309 Scope *getBlockParent() { return BlockParent; }
310 const Scope *getBlockParent() const { return BlockParent; }
311
312 Scope *getTemplateParamParent() { return TemplateParamParent; }
313 const Scope *getTemplateParamParent() const { return TemplateParamParent; }
314
315 Scope *getDeclParent() { return DeclParent; }
316 const Scope *getDeclParent() const { return DeclParent; }
317
318 /// Returns the depth of this scope. The translation-unit has scope depth 0.
319 unsigned getDepth() const { return Depth; }
320
321 /// Returns the number of function prototype scopes in this scope
322 /// chain.
323 unsigned getFunctionPrototypeDepth() const {
324 return PrototypeDepth;
325 }
326
327 /// Return the number of parameters declared in this function
328 /// prototype, increasing it by one for the next call.
329 unsigned getNextFunctionPrototypeIndex() {
330 assert(isFunctionPrototypeScope());
331 return PrototypeIndex++;
332 }
333
334 using decl_range = llvm::iterator_range<DeclSetTy::iterator>;
335
336 decl_range decls() const {
337 return decl_range(DeclsInScope.begin(), DeclsInScope.end());
338 }
339
340 bool decl_empty() const { return DeclsInScope.empty(); }
341
342 void AddDecl(Decl *D) {
343 if (auto *VD = dyn_cast<VarDecl>(Val: D))
344 if (!isa<ParmVarDecl>(Val: VD))
345 ReturnSlots.insert(Ptr: VD);
346
347 DeclsInScope.insert(Ptr: D);
348 }
349
350 void RemoveDecl(Decl *D) { DeclsInScope.erase(Ptr: D); }
351
352 void incrementMSManglingNumber() {
353 if (Scope *MSLMP = getMSLastManglingParent()) {
354 MSLMP->MSLastManglingNumber += 1;
355 MSCurManglingNumber += 1;
356 }
357 }
358
359 void decrementMSManglingNumber() {
360 if (Scope *MSLMP = getMSLastManglingParent()) {
361 MSLMP->MSLastManglingNumber -= 1;
362 MSCurManglingNumber -= 1;
363 }
364 }
365
366 unsigned getMSLastManglingNumber() const {
367 if (const Scope *MSLMP = getMSLastManglingParent())
368 return MSLMP->MSLastManglingNumber;
369 return 1;
370 }
371
372 unsigned getMSCurManglingNumber() const {
373 return MSCurManglingNumber;
374 }
375
376 /// isDeclScope - Return true if this is the scope that the specified decl is
377 /// declared in.
378 bool isDeclScope(const Decl *D) const { return DeclsInScope.contains(Ptr: D); }
379
380 /// Get the entity corresponding to this scope.
381 DeclContext *getEntity() const {
382 return isTemplateParamScope() ? nullptr : Entity;
383 }
384
385 /// Get the DeclContext in which to continue unqualified lookup after a
386 /// lookup in this scope.
387 DeclContext *getLookupEntity() const { return Entity; }
388
389 void setEntity(DeclContext *E) {
390 assert(!isTemplateParamScope() &&
391 "entity associated with template param scope");
392 Entity = E;
393 }
394 void setLookupEntity(DeclContext *E) { Entity = E; }
395
396 /// Determine whether any unrecoverable errors have occurred within this
397 /// scope. Note that this may return false even if the scope contains invalid
398 /// declarations or statements, if the errors for those invalid constructs
399 /// were suppressed because some prior invalid construct was referenced.
400 bool hasUnrecoverableErrorOccurred() const {
401 return ErrorTrap.hasUnrecoverableErrorOccurred();
402 }
403
404 /// isFunctionScope() - Return true if this scope is a function scope.
405 bool isFunctionScope() const { return getFlags() & Scope::FnScope; }
406
407 /// isClassScope - Return true if this scope is a class/struct/union scope.
408 bool isClassScope() const { return getFlags() & Scope::ClassScope; }
409
410 /// Determines whether this scope is between inheritance colon and the real
411 /// class/struct definition.
412 bool isClassInheritanceScope() const {
413 return getFlags() & Scope::ClassInheritanceScope;
414 }
415
416 /// isInCXXInlineMethodScope - Return true if this scope is a C++ inline
417 /// method scope or is inside one.
418 bool isInCXXInlineMethodScope() const {
419 if (const Scope *FnS = getFnParent()) {
420 assert(FnS->getParent() && "TUScope not created?");
421 return FnS->getParent()->isClassScope();
422 }
423 return false;
424 }
425
426 /// isInObjcMethodScope - Return true if this scope is, or is contained in, an
427 /// Objective-C method body. Note that this method is not constant time.
428 bool isInObjcMethodScope() const {
429 for (const Scope *S = this; S; S = S->getParent()) {
430 // If this scope is an objc method scope, then we succeed.
431 if (S->getFlags() & ObjCMethodScope)
432 return true;
433 }
434 return false;
435 }
436
437 /// isInObjcMethodOuterScope - Return true if this scope is an
438 /// Objective-C method outer most body.
439 bool isInObjcMethodOuterScope() const {
440 if (const Scope *S = this) {
441 // If this scope is an objc method scope, then we succeed.
442 if (S->getFlags() & ObjCMethodScope)
443 return true;
444 }
445 return false;
446 }
447
448 /// isTemplateParamScope - Return true if this scope is a C++
449 /// template parameter scope.
450 bool isTemplateParamScope() const {
451 return getFlags() & Scope::TemplateParamScope;
452 }
453
454 /// isFunctionPrototypeScope - Return true if this scope is a
455 /// function prototype scope.
456 bool isFunctionPrototypeScope() const {
457 return getFlags() & Scope::FunctionPrototypeScope;
458 }
459
460 /// isFunctionDeclarationScope - Return true if this scope is a
461 /// function prototype scope.
462 bool isFunctionDeclarationScope() const {
463 return getFlags() & Scope::FunctionDeclarationScope;
464 }
465
466 /// isAtCatchScope - Return true if this scope is \@catch.
467 bool isAtCatchScope() const {
468 return getFlags() & Scope::AtCatchScope;
469 }
470
471 /// isCatchScope - Return true if this scope is a C++ catch statement.
472 bool isCatchScope() const { return getFlags() & Scope::CatchScope; }
473
474 /// isSwitchScope - Return true if this scope is a switch scope.
475 bool isSwitchScope() const {
476 for (const Scope *S = this; S; S = S->getParent()) {
477 if (S->getFlags() & Scope::SwitchScope)
478 return true;
479 else if (S->getFlags() & (Scope::FnScope | Scope::ClassScope |
480 Scope::BlockScope | Scope::TemplateParamScope |
481 Scope::FunctionPrototypeScope |
482 Scope::AtCatchScope | Scope::ObjCMethodScope))
483 return false;
484 }
485 return false;
486 }
487
488 /// Return true if this scope is a loop.
489 bool isLoopScope() const {
490 // 'switch' is the only loop that is not a 'break' scope as well, so we can
491 // just check BreakScope and not SwitchScope.
492 return (getFlags() & Scope::BreakScope) &&
493 !(getFlags() & Scope::SwitchScope);
494 }
495
496 /// Determines whether this scope is the OpenMP directive scope
497 bool isOpenMPDirectiveScope() const {
498 return (getFlags() & Scope::OpenMPDirectiveScope);
499 }
500
501 /// Determine whether this scope is some OpenMP loop directive scope
502 /// (for example, 'omp for', 'omp simd').
503 bool isOpenMPLoopDirectiveScope() const {
504 if (getFlags() & Scope::OpenMPLoopDirectiveScope) {
505 assert(isOpenMPDirectiveScope() &&
506 "OpenMP loop directive scope is not a directive scope");
507 return true;
508 }
509 return false;
510 }
511
512 /// Determine whether this scope is (or is nested into) some OpenMP
513 /// loop simd directive scope (for example, 'omp simd', 'omp for simd').
514 bool isOpenMPSimdDirectiveScope() const {
515 return getFlags() & Scope::OpenMPSimdDirectiveScope;
516 }
517
518 /// Determine whether this scope is a loop having OpenMP loop
519 /// directive attached.
520 bool isOpenMPLoopScope() const {
521 const Scope *P = getParent();
522 return P && P->isOpenMPLoopDirectiveScope();
523 }
524
525 /// Determine whether this scope is some OpenMP directive with
526 /// order clause which specifies concurrent scope.
527 bool isOpenMPOrderClauseScope() const {
528 return getFlags() & Scope::OpenMPOrderClauseScope;
529 }
530
531 /// Determine whether this scope is the statement associated with an OpenACC
532 /// Compute construct directive.
533 bool isOpenACCComputeConstructScope() const {
534 return getFlags() & Scope::OpenACCComputeConstructScope;
535 }
536
537 /// Determine if this scope (or its parents) are a compute construct. If the
538 /// argument is provided, the search will stop at any of the specified scopes.
539 /// Otherwise, it will stop only at the normal 'no longer search' scopes.
540 bool isInOpenACCComputeConstructScope(ScopeFlags Flags = NoScope) const {
541 for (const Scope *S = this; S; S = S->getParent()) {
542 if (S->isOpenACCComputeConstructScope())
543 return true;
544
545 if (S->getFlags() & Flags)
546 return false;
547
548 else if (S->getFlags() &
549 (Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
550 Scope::TemplateParamScope | Scope::FunctionPrototypeScope |
551 Scope::AtCatchScope | Scope::ObjCMethodScope))
552 return false;
553 }
554 return false;
555 }
556
557 /// Determine whether this scope is a while/do/for statement, which can have
558 /// continue statements embedded into it.
559 bool isContinueScope() const {
560 return getFlags() & ScopeFlags::ContinueScope;
561 }
562
563 /// Determine whether this scope is a C++ 'try' block.
564 bool isTryScope() const { return getFlags() & Scope::TryScope; }
565
566 /// Determine whether this scope is a function-level C++ try or catch scope.
567 bool isFnTryCatchScope() const {
568 return getFlags() & ScopeFlags::FnTryCatchScope;
569 }
570
571 /// Determine whether this scope is a SEH '__try' block.
572 bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; }
573
574 /// Determine whether this scope is a SEH '__except' block.
575 bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; }
576
577 /// Determine whether this scope is a compound statement scope.
578 bool isCompoundStmtScope() const {
579 return getFlags() & Scope::CompoundStmtScope;
580 }
581
582 /// Determine whether this scope is a controlling scope in a
583 /// if/switch/while/for statement.
584 bool isControlScope() const { return getFlags() & Scope::ControlScope; }
585
586 /// Determine whether this scope is a type alias scope.
587 bool isTypeAliasScope() const { return getFlags() & Scope::TypeAliasScope; }
588
589 /// Returns if rhs has a higher scope depth than this.
590 ///
591 /// The caller is responsible for calling this only if one of the two scopes
592 /// is an ancestor of the other.
593 bool Contains(const Scope& rhs) const { return Depth < rhs.Depth; }
594
595 /// containedInPrototypeScope - Return true if this or a parent scope
596 /// is a FunctionPrototypeScope.
597 bool containedInPrototypeScope() const;
598
599 void PushUsingDirective(UsingDirectiveDecl *UDir) {
600 UsingDirectives.push_back(Elt: UDir);
601 }
602
603 using using_directives_range =
604 llvm::iterator_range<UsingDirectivesTy::iterator>;
605
606 using_directives_range using_directives() {
607 return using_directives_range(UsingDirectives.begin(),
608 UsingDirectives.end());
609 }
610
611 void updateNRVOCandidate(VarDecl *VD);
612
613 void applyNRVO();
614
615 /// Init - This is used by the parser to implement scope caching.
616 void Init(Scope *parent, unsigned flags);
617
618 /// Sets up the specified scope flags and adjusts the scope state
619 /// variables accordingly.
620 void AddFlags(unsigned Flags);
621
622 void dumpImpl(raw_ostream &OS) const;
623 void dump() const;
624};
625
626} // namespace clang
627
628#endif // LLVM_CLANG_SEMA_SCOPE_H
629

source code of clang/include/clang/Sema/Scope.h