xref: /openbsd-src/gnu/llvm/clang/lib/Sema/Scope.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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