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