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