clang 22.0.0git
Scope.cpp
Go to the documentation of this file.
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();
45 0)
46 Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
47 // transmit the parent's 'order' flag, if exists
48 if (parent->getFlags() & 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
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
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::AddFlags(unsigned FlagsToSet) {
117 assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
118 "Unsupported scope flags");
119 if (FlagsToSet & BreakScope) {
120 assert((Flags & BreakScope) == 0 && "Already set");
121 BreakParent = this;
122 }
123 if (FlagsToSet & ContinueScope) {
124 assert((Flags & ContinueScope) == 0 && "Already set");
125 ContinueParent = this;
126 }
127 Flags |= FlagsToSet;
128}
129
130// The algorithm for updating NRVO candidate is as follows:
131// 1. All previous candidates become invalid because a new NRVO candidate is
132// obtained. Therefore, we need to clear return slots for other
133// variables defined before the current return statement in the current
134// scope and in outer scopes.
135// 2. Store the new candidate if its return slot is available. Otherwise,
136// there is no NRVO candidate so far.
138 auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
139 bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
140
141 // We found a candidate variable that can be put into a return slot.
142 // Clear the set, because other variables cannot occupy a return
143 // slot in the same scope.
144 S->ReturnSlots.clear();
145
146 if (IsReturnSlotFound)
147 S->ReturnSlots.insert(VD);
148
149 return IsReturnSlotFound;
150 };
151
152 bool CanBePutInReturnSlot = false;
153
154 for (auto *S = this; S; S = S->getParent()) {
155 CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
156
157 if (S->getEntity())
158 break;
159 }
160
161 // Consider the variable as NRVO candidate if the return slot is available
162 // for it in the current scope, or if it can be available in outer scopes.
163 NRVO = CanBePutInReturnSlot ? VD : nullptr;
164}
165
167 // There is no NRVO candidate in the current scope.
168 if (!NRVO.has_value())
169 return;
170
171 if (*NRVO && isDeclScope(*NRVO))
172 (*NRVO)->setNRVOVariable(true);
173
174 // It's necessary to propagate NRVO candidate to the parent scope for cases
175 // when the parent scope doesn't contain a return statement.
176 // For example:
177 // X foo(bool b) {
178 // X x;
179 // if (b)
180 // return x;
181 // exit(0);
182 // }
183 // Also, we need to propagate nullptr value that means NRVO is not
184 // allowed in this scope.
185 // For example:
186 // X foo(bool b) {
187 // X x;
188 // if (b)
189 // return x;
190 // else
191 // return X(); // NRVO is not allowed
192 // }
193 if (!getEntity())
194 getParent()->NRVO = *NRVO;
195}
196
197LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
198
199void Scope::dumpImpl(raw_ostream &OS) const {
200 unsigned Flags = getFlags();
201 bool HasFlags = Flags != 0;
202
203 if (HasFlags)
204 OS << "Flags: ";
205
206 std::pair<unsigned, const char *> FlagInfo[] = {
207 {FnScope, "FnScope"},
208 {BreakScope, "BreakScope"},
209 {ContinueScope, "ContinueScope"},
210 {DeclScope, "DeclScope"},
211 {ControlScope, "ControlScope"},
212 {ClassScope, "ClassScope"},
213 {BlockScope, "BlockScope"},
214 {TemplateParamScope, "TemplateParamScope"},
215 {FunctionPrototypeScope, "FunctionPrototypeScope"},
216 {FunctionDeclarationScope, "FunctionDeclarationScope"},
217 {AtCatchScope, "AtCatchScope"},
218 {ObjCMethodScope, "ObjCMethodScope"},
219 {SwitchScope, "SwitchScope"},
220 {TryScope, "TryScope"},
221 {FnTryCatchScope, "FnTryCatchScope"},
222 {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
223 {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
224 {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
225 {EnumScope, "EnumScope"},
226 {SEHTryScope, "SEHTryScope"},
227 {SEHExceptScope, "SEHExceptScope"},
228 {SEHFilterScope, "SEHFilterScope"},
229 {CompoundStmtScope, "CompoundStmtScope"},
230 {ClassInheritanceScope, "ClassInheritanceScope"},
231 {CatchScope, "CatchScope"},
232 {ConditionVarScope, "ConditionVarScope"},
233 {OpenMPOrderClauseScope, "OpenMPOrderClauseScope"},
234 {LambdaScope, "LambdaScope"},
235 {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
236 {TypeAliasScope, "TypeAliasScope"},
237 {FriendScope, "FriendScope"},
238 {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
239 {OpenACCLoopConstructScope, "OpenACCLoopConstructScope"}};
240
241 for (auto Info : FlagInfo) {
242 if (Flags & Info.first) {
243 OS << Info.second;
244 Flags &= ~Info.first;
245 if (Flags)
246 OS << " | ";
247 }
248 }
249
250 assert(Flags == 0 && "Unknown scope flags");
251
252 if (HasFlags)
253 OS << '\n';
254
255 if (const Scope *Parent = getParent())
256 OS << "Parent: (clang::Scope*)" << Parent << '\n';
257
258 OS << "Depth: " << Depth << '\n';
259 OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
260 OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
261 if (const DeclContext *DC = getEntity())
262 OS << "Entity : (clang::DeclContext*)" << DC << '\n';
263
264 if (!NRVO)
265 OS << "there is no NRVO candidate\n";
266 else if (*NRVO)
267 OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
268 else
269 OS << "NRVO is not allowed\n";
270}
NodeId Parent
Definition: ASTDiff.cpp:191
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1449
void reset()
Set to initial state of "no errors occurred".
Definition: Diagnostic.h:1099
Scope - A scope is a transient data structure that is used while parsing the program.
Definition: Scope.h:41
void Init(Scope *parent, unsigned flags)
Init - This is used by the parser to implement scope caching.
Definition: Scope.cpp:95
void AddFlags(unsigned Flags)
Sets up the specified scope flags and adjusts the scope state variables accordingly.
Definition: Scope.cpp:116
bool isClassScope() const
isClassScope - Return true if this scope is a class/struct/union scope.
Definition: Scope.h:428
void incrementMSManglingNumber()
Definition: Scope.h:372
unsigned getFlags() const
getFlags - Return the flags for this scope.
Definition: Scope.h:271
bool isDeclScope(const Decl *D) const
isDeclScope - Return true if this is the scope that the specified decl is declared in.
Definition: Scope.h:398
unsigned getMSLastManglingNumber() const
Definition: Scope.h:386
void dump() const
Definition: Scope.cpp:197
DeclContext * getEntity() const
Get the entity corresponding to this scope.
Definition: Scope.h:401
unsigned getMSCurManglingNumber() const
Definition: Scope.h:392
bool containedInPrototypeScope() const
containedInPrototypeScope - Return true if this or a parent scope is a FunctionPrototypeScope.
Definition: Scope.cpp:106
const Scope * getParent() const
getParent - Return the scope that this is nested in.
Definition: Scope.h:287
void updateNRVOCandidate(VarDecl *VD)
Definition: Scope.cpp:137
void dumpImpl(raw_ostream &OS) const
Definition: Scope.cpp:199
void applyNRVO()
Definition: Scope.cpp:166
@ OpenMPDirectiveScope
This is the scope of OpenMP executable directive.
Definition: Scope.h:111
@ FunctionPrototypeScope
This is a scope that corresponds to the parameters within a function prototype.
Definition: Scope.h:85
@ OpenMPOrderClauseScope
This is a scope of some OpenMP directive with order clause which specifies concurrent.
Definition: Scope.h:150
@ LambdaScope
This is the scope for a lambda, after the lambda introducer.
Definition: Scope.h:155
@ OpenACCLoopConstructScope
This is the scope of an OpenACC Loop/Combined construct, which is used to determine whether a 'cache'...
Definition: Scope.h:163
@ BlockScope
This is a scope that corresponds to a block/closure object.
Definition: Scope.h:75
@ SEHTryScope
This scope corresponds to an SEH try.
Definition: Scope.h:125
@ FriendScope
This is a scope of friend declaration.
Definition: Scope.h:169
@ ContinueScope
This is a while, do, for, which can have continue statements embedded into it.
Definition: Scope.h:59
@ OpenACCComputeConstructScope
This is the scope of an OpenACC Compute Construct, which restricts jumping into/out of it.
Definition: Scope.h:159
@ TypeAliasScope
This is a scope of type alias declaration.
Definition: Scope.h:166
@ ControlScope
The controlling scope in a if/switch/while/for statement.
Definition: Scope.h:66
@ ClassInheritanceScope
We are between inheritance colon and the real class/struct definition scope.
Definition: Scope.h:138
@ AtCatchScope
This is a scope that corresponds to the Objective-C @catch statement.
Definition: Scope.h:95
@ TemplateParamScope
This is a scope that corresponds to the template parameters of a C++ template.
Definition: Scope.h:81
@ SEHFilterScope
We are currently in the filter expression of an SEH except block.
Definition: Scope.h:131
@ SwitchScope
This is a scope that corresponds to a switch statement.
Definition: Scope.h:102
@ BreakScope
This is a while, do, switch, for, etc that can have break statements embedded into it.
Definition: Scope.h:55
@ CatchScope
This is the scope of a C++ catch statement.
Definition: Scope.h:141
@ CompoundStmtScope
This is a compound statement scope.
Definition: Scope.h:134
@ FnTryCatchScope
This is the scope for a function-level C++ try or catch scope.
Definition: Scope.h:108
@ SEHExceptScope
This scope corresponds to an SEH except.
Definition: Scope.h:128
@ ClassScope
The scope of a struct/union/class definition.
Definition: Scope.h:69
@ TryScope
This is the scope of a C++ try statement.
Definition: Scope.h:105
@ OpenMPSimdDirectiveScope
This is the scope of some OpenMP simd directive.
Definition: Scope.h:119
@ FunctionDeclarationScope
This is a scope that corresponds to the parameters within a function prototype for a function declara...
Definition: Scope.h:91
@ ConditionVarScope
This is a scope in which a condition variable is currently being parsed.
Definition: Scope.h:146
@ FnScope
This indicates that the scope corresponds to a function, which means that labels are set here.
Definition: Scope.h:51
@ ObjCMethodScope
This scope corresponds to an Objective-C method body.
Definition: Scope.h:99
@ EnumScope
This scope corresponds to an enum.
Definition: Scope.h:122
@ OpenMPLoopDirectiveScope
This is the scope of some OpenMP loop directive.
Definition: Scope.h:114
@ DeclScope
This is a scope that can contain a declaration.
Definition: Scope.h:63
Represents a variable declaration or definition.
Definition: Decl.h:925
The JSON file list parser is used to communicate input to InstallAPI.