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     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 
92 void 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 
102 bool 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 
112 void 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.
133 void Scope::updateNRVOCandidate(VarDecl *VD) {
134   auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
135     bool IsReturnSlotFound = S->ReturnSlots.contains(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(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 
162 void 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 
193 LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
194 
195 void 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