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