1 //===- Scope.cpp - Lexical scope information --------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the Scope class, which is used for recording
10 // information about a lexical scope.
12 //===----------------------------------------------------------------------===//
14 #include "clang/Sema/Scope.h"
15 #include "clang/AST/Decl.h"
16 #include "llvm/Support/raw_ostream.h"
18 using namespace clang
;
20 void Scope::setFlags(Scope
*parent
, unsigned flags
) {
24 if (parent
&& !(flags
& FnScope
)) {
25 BreakParent
= parent
->BreakParent
;
26 ContinueParent
= parent
->ContinueParent
;
28 // Control scopes do not contain the contents of nested function scopes for
29 // control flow purposes.
30 BreakParent
= ContinueParent
= nullptr;
34 Depth
= parent
->Depth
+ 1;
35 PrototypeDepth
= parent
->PrototypeDepth
;
37 FnParent
= parent
->FnParent
;
38 BlockParent
= parent
->BlockParent
;
39 TemplateParamParent
= parent
->TemplateParamParent
;
40 DeclParent
= parent
->DeclParent
;
41 MSLastManglingParent
= parent
->MSLastManglingParent
;
42 MSCurManglingNumber
= getMSLastManglingNumber();
43 if ((Flags
& (FnScope
| ClassScope
| BlockScope
| TemplateParamScope
|
44 FunctionPrototypeScope
| AtCatchScope
| ObjCMethodScope
)) ==
46 Flags
|= parent
->getFlags() & OpenMPSimdDirectiveScope
;
47 // transmit the parent's 'order' flag, if exists
48 if (parent
->getFlags() & OpenMPOrderClauseScope
)
49 Flags
|= OpenMPOrderClauseScope
;
54 MSLastManglingParent
= FnParent
= BlockParent
= nullptr;
55 TemplateParamParent
= nullptr;
57 MSLastManglingNumber
= 1;
58 MSCurManglingNumber
= 1;
61 // If this scope is a function or contains breaks/continues, remember it.
62 if (flags
& FnScope
) FnParent
= this;
63 // The MS mangler uses the number of scopes that can hold declarations as
64 // part of an external name.
65 if (Flags
& (ClassScope
| FnScope
)) {
66 MSLastManglingNumber
= getMSLastManglingNumber();
67 MSLastManglingParent
= this;
68 MSCurManglingNumber
= 1;
70 if (flags
& BreakScope
) BreakParent
= this;
71 if (flags
& ContinueScope
) ContinueParent
= this;
72 if (flags
& BlockScope
) BlockParent
= this;
73 if (flags
& TemplateParamScope
) TemplateParamParent
= this;
75 // If this is a prototype scope, record that. Lambdas have an extra prototype
76 // scope that doesn't add any depth.
77 if (flags
& FunctionPrototypeScope
&& !(flags
& LambdaScope
))
80 if (flags
& DeclScope
) {
82 if (flags
& FunctionPrototypeScope
)
83 ; // Prototype scopes are uninteresting.
84 else if ((flags
& ClassScope
) && getParent()->isClassScope())
85 ; // Nested class scopes aren't ambiguous.
86 else if ((flags
& ClassScope
) && getParent()->getFlags() == DeclScope
)
87 ; // Classes inside of namespaces aren't ambiguous.
88 else if ((flags
& EnumScope
))
89 ; // Don't increment for enum scopes.
91 incrementMSManglingNumber();
95 void Scope::Init(Scope
*parent
, unsigned flags
) {
96 setFlags(parent
, flags
);
99 UsingDirectives
.clear();
105 bool Scope::containedInPrototypeScope() const {
106 const Scope
*S
= this;
108 if (S
->isFunctionPrototypeScope())
115 void Scope::AddFlags(unsigned FlagsToSet
) {
116 assert((FlagsToSet
& ~(BreakScope
| ContinueScope
)) == 0 &&
117 "Unsupported scope flags");
118 if (FlagsToSet
& BreakScope
) {
119 assert((Flags
& BreakScope
) == 0 && "Already set");
122 if (FlagsToSet
& ContinueScope
) {
123 assert((Flags
& ContinueScope
) == 0 && "Already set");
124 ContinueParent
= this;
129 // The algorithm for updating NRVO candidate is as follows:
130 // 1. All previous candidates become invalid because a new NRVO candidate is
131 // obtained. Therefore, we need to clear return slots for other
132 // variables defined before the current return statement in the current
133 // scope and in outer scopes.
134 // 2. Store the new candidate if its return slot is available. Otherwise,
135 // there is no NRVO candidate so far.
136 void Scope::updateNRVOCandidate(VarDecl
*VD
) {
137 auto UpdateReturnSlotsInScopeForVD
= [VD
](Scope
*S
) -> bool {
138 bool IsReturnSlotFound
= S
->ReturnSlots
.contains(VD
);
140 // We found a candidate variable that can be put into a return slot.
141 // Clear the set, because other variables cannot occupy a return
142 // slot in the same scope.
143 S
->ReturnSlots
.clear();
145 if (IsReturnSlotFound
)
146 S
->ReturnSlots
.insert(VD
);
148 return IsReturnSlotFound
;
151 bool CanBePutInReturnSlot
= false;
153 for (auto *S
= this; S
; S
= S
->getParent()) {
154 CanBePutInReturnSlot
|= UpdateReturnSlotsInScopeForVD(S
);
160 // Consider the variable as NRVO candidate if the return slot is available
161 // for it in the current scope, or if it can be available in outer scopes.
162 NRVO
= CanBePutInReturnSlot
? VD
: nullptr;
165 void Scope::applyNRVO() {
166 // There is no NRVO candidate in the current scope.
167 if (!NRVO
.has_value())
170 if (*NRVO
&& isDeclScope(*NRVO
))
171 (*NRVO
)->setNRVOVariable(true);
173 // It's necessary to propagate NRVO candidate to the parent scope for cases
174 // when the parent scope doesn't contain a return statement.
182 // Also, we need to propagate nullptr value that means NRVO is not
183 // allowed in this scope.
190 // return X(); // NRVO is not allowed
193 getParent()->NRVO
= *NRVO
;
196 LLVM_DUMP_METHOD
void Scope::dump() const { dumpImpl(llvm::errs()); }
198 void Scope::dumpImpl(raw_ostream
&OS
) const {
199 unsigned Flags
= getFlags();
200 bool HasFlags
= Flags
!= 0;
205 std::pair
<unsigned, const char *> FlagInfo
[] = {
206 {FnScope
, "FnScope"},
207 {BreakScope
, "BreakScope"},
208 {ContinueScope
, "ContinueScope"},
209 {DeclScope
, "DeclScope"},
210 {ControlScope
, "ControlScope"},
211 {ClassScope
, "ClassScope"},
212 {BlockScope
, "BlockScope"},
213 {TemplateParamScope
, "TemplateParamScope"},
214 {FunctionPrototypeScope
, "FunctionPrototypeScope"},
215 {FunctionDeclarationScope
, "FunctionDeclarationScope"},
216 {AtCatchScope
, "AtCatchScope"},
217 {ObjCMethodScope
, "ObjCMethodScope"},
218 {SwitchScope
, "SwitchScope"},
219 {TryScope
, "TryScope"},
220 {FnTryCatchScope
, "FnTryCatchScope"},
221 {OpenMPDirectiveScope
, "OpenMPDirectiveScope"},
222 {OpenMPLoopDirectiveScope
, "OpenMPLoopDirectiveScope"},
223 {OpenMPSimdDirectiveScope
, "OpenMPSimdDirectiveScope"},
224 {EnumScope
, "EnumScope"},
225 {SEHTryScope
, "SEHTryScope"},
226 {SEHExceptScope
, "SEHExceptScope"},
227 {SEHFilterScope
, "SEHFilterScope"},
228 {CompoundStmtScope
, "CompoundStmtScope"},
229 {ClassInheritanceScope
, "ClassInheritanceScope"},
230 {CatchScope
, "CatchScope"},
231 {ConditionVarScope
, "ConditionVarScope"},
232 {OpenMPOrderClauseScope
, "OpenMPOrderClauseScope"},
233 {LambdaScope
, "LambdaScope"},
234 {OpenACCComputeConstructScope
, "OpenACCComputeConstructScope"},
235 {TypeAliasScope
, "TypeAliasScope"},
236 {FriendScope
, "FriendScope"},
239 for (auto Info
: FlagInfo
) {
240 if (Flags
& Info
.first
) {
242 Flags
&= ~Info
.first
;
248 assert(Flags
== 0 && "Unknown scope flags");
253 if (const Scope
*Parent
= getParent())
254 OS
<< "Parent: (clang::Scope*)" << Parent
<< '\n';
256 OS
<< "Depth: " << Depth
<< '\n';
257 OS
<< "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
258 OS
<< "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
259 if (const DeclContext
*DC
= getEntity())
260 OS
<< "Entity : (clang::DeclContext*)" << DC
<< '\n';
263 OS
<< "there is no NRVO candidate\n";
265 OS
<< "NRVO candidate : (clang::VarDecl*)" << *NRVO
<< '\n';
267 OS
<< "NRVO is not allowed\n";