xref: /freebsd/contrib/llvm-project/clang/lib/Sema/Scope.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
setFlags(Scope * parent,unsigned flags)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     DeclParent = parent->DeclParent;
41     MSLastManglingParent = parent->MSLastManglingParent;
42     MSCurManglingNumber = getMSLastManglingNumber();
43     if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
44                   FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
45         0)
46       Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
47     // transmit the parent's 'order' flag, if exists
48     if (parent->getFlags() & OpenMPOrderClauseScope)
49       Flags |= 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
91       incrementMSManglingNumber();
92   }
93 }
94 
Init(Scope * parent,unsigned flags)95 void Scope::Init(Scope *parent, unsigned flags) {
96   setFlags(parent, flags);
97 
98   DeclsInScope.clear();
99   UsingDirectives.clear();
100   Entity = nullptr;
101   ErrorTrap.reset();
102   NRVO = std::nullopt;
103 }
104 
containedInPrototypeScope() const105 bool Scope::containedInPrototypeScope() const {
106   const Scope *S = this;
107   while (S) {
108     if (S->isFunctionPrototypeScope())
109       return true;
110     S = S->getParent();
111   }
112   return false;
113 }
114 
AddFlags(unsigned FlagsToSet)115 void Scope::AddFlags(unsigned FlagsToSet) {
116   assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
117          "Unsupported scope flags");
118   if (FlagsToSet & BreakScope) {
119     assert((Flags & BreakScope) == 0 && "Already set");
120     BreakParent = this;
121   }
122   if (FlagsToSet & ContinueScope) {
123     assert((Flags & ContinueScope) == 0 && "Already set");
124     ContinueParent = this;
125   }
126   Flags |= FlagsToSet;
127 }
128 
129 // The algorithm for updating NRVO candidate is as follows:
130 //   1. All previous candidates become invalid because a new NRVO candidate is
131 //      obtained. Therefore, we need to clear return slots for other
132 //      variables defined before the current return statement in the current
133 //      scope and in outer scopes.
134 //   2. Store the new candidate if its return slot is available. Otherwise,
135 //      there is no NRVO candidate so far.
updateNRVOCandidate(VarDecl * VD)136 void Scope::updateNRVOCandidate(VarDecl *VD) {
137   auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
138     bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
139 
140     // We found a candidate variable that can be put into a return slot.
141     // Clear the set, because other variables cannot occupy a return
142     // slot in the same scope.
143     S->ReturnSlots.clear();
144 
145     if (IsReturnSlotFound)
146       S->ReturnSlots.insert(VD);
147 
148     return IsReturnSlotFound;
149   };
150 
151   bool CanBePutInReturnSlot = false;
152 
153   for (auto *S = this; S; S = S->getParent()) {
154     CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
155 
156     if (S->getEntity())
157       break;
158   }
159 
160   // Consider the variable as NRVO candidate if the return slot is available
161   // for it in the current scope, or if it can be available in outer scopes.
162   NRVO = CanBePutInReturnSlot ? VD : nullptr;
163 }
164 
applyNRVO()165 void Scope::applyNRVO() {
166   // There is no NRVO candidate in the current scope.
167   if (!NRVO.has_value())
168     return;
169 
170   if (*NRVO && isDeclScope(*NRVO))
171     (*NRVO)->setNRVOVariable(true);
172 
173   // It's necessary to propagate NRVO candidate to the parent scope for cases
174   // when the parent scope doesn't contain a return statement.
175   // For example:
176   //    X foo(bool b) {
177   //      X x;
178   //      if (b)
179   //        return x;
180   //      exit(0);
181   //    }
182   // Also, we need to propagate nullptr value that means NRVO is not
183   // allowed in this scope.
184   // For example:
185   //    X foo(bool b) {
186   //      X x;
187   //      if (b)
188   //        return x;
189   //      else
190   //        return X(); // NRVO is not allowed
191   //    }
192   if (!getEntity())
193     getParent()->NRVO = *NRVO;
194 }
195 
dump() const196 LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
197 
dumpImpl(raw_ostream & OS) const198 void Scope::dumpImpl(raw_ostream &OS) const {
199   unsigned Flags = getFlags();
200   bool HasFlags = Flags != 0;
201 
202   if (HasFlags)
203     OS << "Flags: ";
204 
205   std::pair<unsigned, const char *> FlagInfo[] = {
206       {FnScope, "FnScope"},
207       {BreakScope, "BreakScope"},
208       {ContinueScope, "ContinueScope"},
209       {DeclScope, "DeclScope"},
210       {ControlScope, "ControlScope"},
211       {ClassScope, "ClassScope"},
212       {BlockScope, "BlockScope"},
213       {TemplateParamScope, "TemplateParamScope"},
214       {FunctionPrototypeScope, "FunctionPrototypeScope"},
215       {FunctionDeclarationScope, "FunctionDeclarationScope"},
216       {AtCatchScope, "AtCatchScope"},
217       {ObjCMethodScope, "ObjCMethodScope"},
218       {SwitchScope, "SwitchScope"},
219       {TryScope, "TryScope"},
220       {FnTryCatchScope, "FnTryCatchScope"},
221       {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
222       {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
223       {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
224       {EnumScope, "EnumScope"},
225       {SEHTryScope, "SEHTryScope"},
226       {SEHExceptScope, "SEHExceptScope"},
227       {SEHFilterScope, "SEHFilterScope"},
228       {CompoundStmtScope, "CompoundStmtScope"},
229       {ClassInheritanceScope, "ClassInheritanceScope"},
230       {CatchScope, "CatchScope"},
231       {ConditionVarScope, "ConditionVarScope"},
232       {OpenMPOrderClauseScope, "OpenMPOrderClauseScope"},
233       {LambdaScope, "LambdaScope"},
234       {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
235       {TypeAliasScope, "TypeAliasScope"},
236       {FriendScope, "FriendScope"},
237   };
238 
239   for (auto Info : FlagInfo) {
240     if (Flags & Info.first) {
241       OS << Info.second;
242       Flags &= ~Info.first;
243       if (Flags)
244         OS << " | ";
245     }
246   }
247 
248   assert(Flags == 0 && "Unknown scope flags");
249 
250   if (HasFlags)
251     OS << '\n';
252 
253   if (const Scope *Parent = getParent())
254     OS << "Parent: (clang::Scope*)" << Parent << '\n';
255 
256   OS << "Depth: " << Depth << '\n';
257   OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
258   OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
259   if (const DeclContext *DC = getEntity())
260     OS << "Entity : (clang::DeclContext*)" << DC << '\n';
261 
262   if (!NRVO)
263     OS << "there is no NRVO candidate\n";
264   else if (*NRVO)
265     OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
266   else
267     OS << "NRVO is not allowed\n";
268 }
269