1//===- Scope.cpp - Lexical scope information --------------------*- 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 implements the Scope class, which is used for recording
10// information about a lexical scope.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Sema/Scope.h"
15#include "clang/AST/Decl.h"
16#include "llvm/Support/raw_ostream.h"
17
18using namespace clang;
19
20void Scope::setFlags(Scope *parent, unsigned flags) {
21 AnyParent = parent;
22 Flags = flags;
23
24 if (parent && !(flags & FnScope)) {
25 BreakParent = parent->BreakParent;
26 ContinueParent = parent->ContinueParent;
27 } else {
28 // Control scopes do not contain the contents of nested function scopes for
29 // control flow purposes.
30 BreakParent = ContinueParent = nullptr;
31 }
32
33 if (parent) {
34 Depth = parent->Depth + 1;
35 PrototypeDepth = parent->PrototypeDepth;
36 PrototypeIndex = 0;
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)) ==
45 0)
46 Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
47 // transmit the parent's 'order' flag, if exists
48 if (parent->getFlags() & OpenMPOrderClauseScope)
49 Flags |= OpenMPOrderClauseScope;
50 } else {
51 Depth = 0;
52 PrototypeDepth = 0;
53 PrototypeIndex = 0;
54 MSLastManglingParent = FnParent = BlockParent = nullptr;
55 TemplateParamParent = nullptr;
56 DeclParent = nullptr;
57 MSLastManglingNumber = 1;
58 MSCurManglingNumber = 1;
59 }
60
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;
69 }
70 if (flags & BreakScope) BreakParent = this;
71 if (flags & ContinueScope) ContinueParent = this;
72 if (flags & BlockScope) BlockParent = this;
73 if (flags & TemplateParamScope) TemplateParamParent = this;
74
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))
78 PrototypeDepth++;
79
80 if (flags & DeclScope) {
81 DeclParent = this;
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.
90 else
91 incrementMSManglingNumber();
92 }
93}
94
95void Scope::Init(Scope *parent, unsigned flags) {
96 setFlags(parent, flags);
97
98 DeclsInScope.clear();
99 UsingDirectives.clear();
100 Entity = nullptr;
101 ErrorTrap.reset();
102 PrecedingLabel = nullptr;
103 NRVO = std::nullopt;
104}
105
106bool Scope::containedInPrototypeScope() const {
107 const Scope *S = this;
108 while (S) {
109 if (S->isFunctionPrototypeScope())
110 return true;
111 S = S->getParent();
112 }
113 return false;
114}
115
116void Scope::EnterLoopBody(LabelDecl *LD) {
117 Flags |= BreakScope | ContinueScope;
118 BreakParent = ContinueParent = this;
119 PrecedingLabel = LD;
120}
121
122void Scope::EnterSwitchBody(LabelDecl *LD) {
123 Flags |= BreakScope;
124 BreakParent = this;
125 PrecedingLabel = LD;
126}
127
128void Scope::LeaveLoopBody() {
129 Flags &= ~(BreakScope | ContinueScope);
130 BreakParent = getParent()->BreakParent;
131 ContinueParent = getParent()->ContinueParent;
132 PrecedingLabel = nullptr;
133}
134
135// The algorithm for updating NRVO candidate is as follows:
136// 1. All previous candidates become invalid because a new NRVO candidate is
137// obtained. Therefore, we need to clear return slots for other
138// variables defined before the current return statement in the current
139// scope and in outer scopes.
140// 2. Store the new candidate if its return slot is available. Otherwise,
141// there is no NRVO candidate so far.
142void Scope::updateNRVOCandidate(VarDecl *VD) {
143 auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
144 bool IsReturnSlotFound = S->ReturnSlots.contains(Ptr: VD);
145
146 // We found a candidate variable that can be put into a return slot.
147 // Clear the set, because other variables cannot occupy a return
148 // slot in the same scope.
149 S->ReturnSlots.clear();
150
151 if (IsReturnSlotFound)
152 S->ReturnSlots.insert(Ptr: VD);
153
154 return IsReturnSlotFound;
155 };
156
157 bool CanBePutInReturnSlot = false;
158
159 for (auto *S = this; S; S = S->getParent()) {
160 CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
161
162 if (S->getEntity())
163 break;
164 }
165
166 // Consider the variable as NRVO candidate if the return slot is available
167 // for it in the current scope, or if it can be available in outer scopes.
168 NRVO = CanBePutInReturnSlot ? VD : nullptr;
169}
170
171void Scope::applyNRVO() {
172 // There is no NRVO candidate in the current scope.
173 if (!NRVO.has_value())
174 return;
175
176 if (*NRVO && isDeclScope(D: *NRVO))
177 (*NRVO)->setNRVOVariable(true);
178
179 // It's necessary to propagate NRVO candidate to the parent scope for cases
180 // when the parent scope doesn't contain a return statement.
181 // For example:
182 // X foo(bool b) {
183 // X x;
184 // if (b)
185 // return x;
186 // exit(0);
187 // }
188 // Also, we need to propagate nullptr value that means NRVO is not
189 // allowed in this scope.
190 // For example:
191 // X foo(bool b) {
192 // X x;
193 // if (b)
194 // return x;
195 // else
196 // return X(); // NRVO is not allowed
197 // }
198 if (!getEntity())
199 getParent()->NRVO = *NRVO;
200}
201
202LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(OS&: llvm::errs()); }
203
204void Scope::dumpImpl(raw_ostream &OS) const {
205 unsigned Flags = getFlags();
206 bool HasFlags = Flags != 0;
207
208 if (HasFlags)
209 OS << "Flags: ";
210
211 std::pair<unsigned, const char *> FlagInfo[] = {
212 {FnScope, "FnScope"},
213 {BreakScope, "BreakScope"},
214 {ContinueScope, "ContinueScope"},
215 {DeclScope, "DeclScope"},
216 {ControlScope, "ControlScope"},
217 {ClassScope, "ClassScope"},
218 {BlockScope, "BlockScope"},
219 {TemplateParamScope, "TemplateParamScope"},
220 {FunctionPrototypeScope, "FunctionPrototypeScope"},
221 {FunctionDeclarationScope, "FunctionDeclarationScope"},
222 {AtCatchScope, "AtCatchScope"},
223 {ObjCMethodScope, "ObjCMethodScope"},
224 {SwitchScope, "SwitchScope"},
225 {TryScope, "TryScope"},
226 {FnTryCatchScope, "FnTryCatchScope"},
227 {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
228 {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
229 {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
230 {EnumScope, "EnumScope"},
231 {SEHTryScope, "SEHTryScope"},
232 {SEHExceptScope, "SEHExceptScope"},
233 {SEHFilterScope, "SEHFilterScope"},
234 {CompoundStmtScope, "CompoundStmtScope"},
235 {ClassInheritanceScope, "ClassInheritanceScope"},
236 {CatchScope, "CatchScope"},
237 {Unused, "Unused"},
238 {OpenMPOrderClauseScope, "OpenMPOrderClauseScope"},
239 {LambdaScope, "LambdaScope"},
240 {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
241 {TypeAliasScope, "TypeAliasScope"},
242 {FriendScope, "FriendScope"},
243 {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
244 {OpenACCLoopConstructScope, "OpenACCLoopConstructScope"}};
245
246 for (auto Info : FlagInfo) {
247 if (Flags & Info.first) {
248 OS << Info.second;
249 Flags &= ~Info.first;
250 if (Flags)
251 OS << " | ";
252 }
253 }
254
255 assert(Flags == 0 && "Unknown scope flags");
256
257 if (HasFlags)
258 OS << '\n';
259
260 if (const Scope *Parent = getParent())
261 OS << "Parent: (clang::Scope*)" << Parent << '\n';
262
263 OS << "Depth: " << Depth << '\n';
264 OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
265 OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
266 if (const DeclContext *DC = getEntity())
267 OS << "Entity : (clang::DeclContext*)" << DC << '\n';
268
269 if (!NRVO)
270 OS << "there is no NRVO candidate\n";
271 else if (*NRVO)
272 OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
273 else
274 OS << "NRVO is not allowed\n";
275}
276