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
18 using namespace clang;
19
setFlags(Scope * parent,unsigned flags)20 void 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 MSLastManglingParent = parent->MSLastManglingParent;
41 MSCurManglingNumber = getMSLastManglingNumber();
42 if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
43 FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
44 0)
45 Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
46 } else {
47 Depth = 0;
48 PrototypeDepth = 0;
49 PrototypeIndex = 0;
50 MSLastManglingParent = FnParent = BlockParent = nullptr;
51 TemplateParamParent = nullptr;
52 MSLastManglingNumber = 1;
53 MSCurManglingNumber = 1;
54 }
55
56 // If this scope is a function or contains breaks/continues, remember it.
57 if (flags & FnScope) FnParent = this;
58 // The MS mangler uses the number of scopes that can hold declarations as
59 // part of an external name.
60 if (Flags & (ClassScope | FnScope)) {
61 MSLastManglingNumber = getMSLastManglingNumber();
62 MSLastManglingParent = this;
63 MSCurManglingNumber = 1;
64 }
65 if (flags & BreakScope) BreakParent = this;
66 if (flags & ContinueScope) ContinueParent = this;
67 if (flags & BlockScope) BlockParent = this;
68 if (flags & TemplateParamScope) TemplateParamParent = this;
69
70 // If this is a prototype scope, record that.
71 if (flags & FunctionPrototypeScope) PrototypeDepth++;
72
73 if (flags & DeclScope) {
74 if (flags & FunctionPrototypeScope)
75 ; // Prototype scopes are uninteresting.
76 else if ((flags & ClassScope) && getParent()->isClassScope())
77 ; // Nested class scopes aren't ambiguous.
78 else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)
79 ; // Classes inside of namespaces aren't ambiguous.
80 else if ((flags & EnumScope))
81 ; // Don't increment for enum scopes.
82 else
83 incrementMSManglingNumber();
84 }
85 }
86
Init(Scope * parent,unsigned flags)87 void Scope::Init(Scope *parent, unsigned flags) {
88 setFlags(parent, flags);
89
90 DeclsInScope.clear();
91 UsingDirectives.clear();
92 Entity = nullptr;
93 ErrorTrap.reset();
94 NRVO = None;
95 }
96
containedInPrototypeScope() const97 bool Scope::containedInPrototypeScope() const {
98 const Scope *S = this;
99 while (S) {
100 if (S->isFunctionPrototypeScope())
101 return true;
102 S = S->getParent();
103 }
104 return false;
105 }
106
AddFlags(unsigned FlagsToSet)107 void Scope::AddFlags(unsigned FlagsToSet) {
108 assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
109 "Unsupported scope flags");
110 if (FlagsToSet & BreakScope) {
111 assert((Flags & BreakScope) == 0 && "Already set");
112 BreakParent = this;
113 }
114 if (FlagsToSet & ContinueScope) {
115 assert((Flags & ContinueScope) == 0 && "Already set");
116 ContinueParent = this;
117 }
118 Flags |= FlagsToSet;
119 }
120
121 // The algorithm for updating NRVO candidate is as follows:
122 // 1. All previous candidates become invalid because a new NRVO candidate is
123 // obtained. Therefore, we need to clear return slots for other
124 // variables defined before the current return statement in the current
125 // scope and in outer scopes.
126 // 2. Store the new candidate if its return slot is available. Otherwise,
127 // there is no NRVO candidate so far.
updateNRVOCandidate(VarDecl * VD)128 void Scope::updateNRVOCandidate(VarDecl *VD) {
129 auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
130 bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
131
132 // We found a candidate variable that can be put into a return slot.
133 // Clear the set, because other variables cannot occupy a return
134 // slot in the same scope.
135 S->ReturnSlots.clear();
136
137 if (IsReturnSlotFound)
138 S->ReturnSlots.insert(VD);
139
140 return IsReturnSlotFound;
141 };
142
143 bool CanBePutInReturnSlot = false;
144
145 for (auto *S = this; S; S = S->getParent()) {
146 CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
147
148 if (S->getEntity())
149 break;
150 }
151
152 // Consider the variable as NRVO candidate if the return slot is available
153 // for it in the current scope, or if it can be available in outer scopes.
154 NRVO = CanBePutInReturnSlot ? VD : nullptr;
155 }
156
applyNRVO()157 void Scope::applyNRVO() {
158 // There is no NRVO candidate in the current scope.
159 if (!NRVO.hasValue())
160 return;
161
162 if (*NRVO && isDeclScope(*NRVO))
163 NRVO.getValue()->setNRVOVariable(true);
164
165 // It's necessary to propagate NRVO candidate to the parent scope for cases
166 // when the parent scope doesn't contain a return statement.
167 // For example:
168 // X foo(bool b) {
169 // X x;
170 // if (b)
171 // return x;
172 // exit(0);
173 // }
174 // Also, we need to propagate nullptr value that means NRVO is not
175 // allowed in this scope.
176 // For example:
177 // X foo(bool b) {
178 // X x;
179 // if (b)
180 // return x;
181 // else
182 // return X(); // NRVO is not allowed
183 // }
184 if (!getEntity())
185 getParent()->NRVO = *NRVO;
186 }
187
dump() const188 LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
189
dumpImpl(raw_ostream & OS) const190 void Scope::dumpImpl(raw_ostream &OS) const {
191 unsigned Flags = getFlags();
192 bool HasFlags = Flags != 0;
193
194 if (HasFlags)
195 OS << "Flags: ";
196
197 std::pair<unsigned, const char *> FlagInfo[] = {
198 {FnScope, "FnScope"},
199 {BreakScope, "BreakScope"},
200 {ContinueScope, "ContinueScope"},
201 {DeclScope, "DeclScope"},
202 {ControlScope, "ControlScope"},
203 {ClassScope, "ClassScope"},
204 {BlockScope, "BlockScope"},
205 {TemplateParamScope, "TemplateParamScope"},
206 {FunctionPrototypeScope, "FunctionPrototypeScope"},
207 {FunctionDeclarationScope, "FunctionDeclarationScope"},
208 {AtCatchScope, "AtCatchScope"},
209 {ObjCMethodScope, "ObjCMethodScope"},
210 {SwitchScope, "SwitchScope"},
211 {TryScope, "TryScope"},
212 {FnTryCatchScope, "FnTryCatchScope"},
213 {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
214 {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
215 {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
216 {EnumScope, "EnumScope"},
217 {SEHTryScope, "SEHTryScope"},
218 {SEHExceptScope, "SEHExceptScope"},
219 {SEHFilterScope, "SEHFilterScope"},
220 {CompoundStmtScope, "CompoundStmtScope"},
221 {ClassInheritanceScope, "ClassInheritanceScope"},
222 {CatchScope, "CatchScope"},
223 };
224
225 for (auto Info : FlagInfo) {
226 if (Flags & Info.first) {
227 OS << Info.second;
228 Flags &= ~Info.first;
229 if (Flags)
230 OS << " | ";
231 }
232 }
233
234 assert(Flags == 0 && "Unknown scope flags");
235
236 if (HasFlags)
237 OS << '\n';
238
239 if (const Scope *Parent = getParent())
240 OS << "Parent: (clang::Scope*)" << Parent << '\n';
241
242 OS << "Depth: " << Depth << '\n';
243 OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
244 OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
245 if (const DeclContext *DC = getEntity())
246 OS << "Entity : (clang::DeclContext*)" << DC << '\n';
247
248 if (!NRVO)
249 OS << "there is no NRVO candidate\n";
250 else if (*NRVO)
251 OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
252 else
253 OS << "NRVO is not allowed\n";
254 }
255