Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Sema/Scope.cpp
35234 views
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
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
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
95
void Scope::Init(Scope *parent, unsigned flags) {
96
setFlags(parent, flags);
97
98
DeclsInScope.clear();
99
UsingDirectives.clear();
100
Entity = nullptr;
101
ErrorTrap.reset();
102
NRVO = std::nullopt;
103
}
104
105
bool Scope::containedInPrototypeScope() const {
106
const Scope *S = this;
107
while (S) {
108
if (S->isFunctionPrototypeScope())
109
return true;
110
S = S->getParent();
111
}
112
return false;
113
}
114
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");
120
BreakParent = this;
121
}
122
if (FlagsToSet & ContinueScope) {
123
assert((Flags & ContinueScope) == 0 && "Already set");
124
ContinueParent = this;
125
}
126
Flags |= FlagsToSet;
127
}
128
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);
139
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();
144
145
if (IsReturnSlotFound)
146
S->ReturnSlots.insert(VD);
147
148
return IsReturnSlotFound;
149
};
150
151
bool CanBePutInReturnSlot = false;
152
153
for (auto *S = this; S; S = S->getParent()) {
154
CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
155
156
if (S->getEntity())
157
break;
158
}
159
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;
163
}
164
165
void Scope::applyNRVO() {
166
// There is no NRVO candidate in the current scope.
167
if (!NRVO.has_value())
168
return;
169
170
if (*NRVO && isDeclScope(*NRVO))
171
(*NRVO)->setNRVOVariable(true);
172
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.
175
// For example:
176
// X foo(bool b) {
177
// X x;
178
// if (b)
179
// return x;
180
// exit(0);
181
// }
182
// Also, we need to propagate nullptr value that means NRVO is not
183
// allowed in this scope.
184
// For example:
185
// X foo(bool b) {
186
// X x;
187
// if (b)
188
// return x;
189
// else
190
// return X(); // NRVO is not allowed
191
// }
192
if (!getEntity())
193
getParent()->NRVO = *NRVO;
194
}
195
196
LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
197
198
void Scope::dumpImpl(raw_ostream &OS) const {
199
unsigned Flags = getFlags();
200
bool HasFlags = Flags != 0;
201
202
if (HasFlags)
203
OS << "Flags: ";
204
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"},
237
};
238
239
for (auto Info : FlagInfo) {
240
if (Flags & Info.first) {
241
OS << Info.second;
242
Flags &= ~Info.first;
243
if (Flags)
244
OS << " | ";
245
}
246
}
247
248
assert(Flags == 0 && "Unknown scope flags");
249
250
if (HasFlags)
251
OS << '\n';
252
253
if (const Scope *Parent = getParent())
254
OS << "Parent: (clang::Scope*)" << Parent << '\n';
255
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';
261
262
if (!NRVO)
263
OS << "there is no NRVO candidate\n";
264
else if (*NRVO)
265
OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
266
else
267
OS << "NRVO is not allowed\n";
268
}
269
270