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

source code of clang/lib/Sema/Scope.cpp