xref: /freebsd/contrib/llvm-project/clang/lib/Sema/Scope.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- Scope.cpp - Lexical scope information --------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the Scope class, which is used for recording
100b57cec5SDimitry Andric // information about a lexical scope.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/Sema/Scope.h"
150b57cec5SDimitry Andric #include "clang/AST/Decl.h"
160b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace clang;
190b57cec5SDimitry Andric 
setFlags(Scope * parent,unsigned flags)200b57cec5SDimitry Andric void Scope::setFlags(Scope *parent, unsigned flags) {
210b57cec5SDimitry Andric   AnyParent = parent;
220b57cec5SDimitry Andric   Flags = flags;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric   if (parent && !(flags & FnScope)) {
250b57cec5SDimitry Andric     BreakParent    = parent->BreakParent;
260b57cec5SDimitry Andric     ContinueParent = parent->ContinueParent;
270b57cec5SDimitry Andric   } else {
280b57cec5SDimitry Andric     // Control scopes do not contain the contents of nested function scopes for
290b57cec5SDimitry Andric     // control flow purposes.
300b57cec5SDimitry Andric     BreakParent = ContinueParent = nullptr;
310b57cec5SDimitry Andric   }
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   if (parent) {
340b57cec5SDimitry Andric     Depth = parent->Depth + 1;
350b57cec5SDimitry Andric     PrototypeDepth = parent->PrototypeDepth;
360b57cec5SDimitry Andric     PrototypeIndex = 0;
370b57cec5SDimitry Andric     FnParent       = parent->FnParent;
380b57cec5SDimitry Andric     BlockParent    = parent->BlockParent;
390b57cec5SDimitry Andric     TemplateParamParent = parent->TemplateParamParent;
40*0fca6ea1SDimitry Andric     DeclParent = parent->DeclParent;
410b57cec5SDimitry Andric     MSLastManglingParent = parent->MSLastManglingParent;
420b57cec5SDimitry Andric     MSCurManglingNumber = getMSLastManglingNumber();
430b57cec5SDimitry Andric     if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
440b57cec5SDimitry Andric                   FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
450b57cec5SDimitry Andric         0)
460b57cec5SDimitry Andric       Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
47bdd1243dSDimitry Andric     // transmit the parent's 'order' flag, if exists
48bdd1243dSDimitry Andric     if (parent->getFlags() & OpenMPOrderClauseScope)
49bdd1243dSDimitry Andric       Flags |= OpenMPOrderClauseScope;
500b57cec5SDimitry Andric   } else {
510b57cec5SDimitry Andric     Depth = 0;
520b57cec5SDimitry Andric     PrototypeDepth = 0;
530b57cec5SDimitry Andric     PrototypeIndex = 0;
540b57cec5SDimitry Andric     MSLastManglingParent = FnParent = BlockParent = nullptr;
550b57cec5SDimitry Andric     TemplateParamParent = nullptr;
56*0fca6ea1SDimitry Andric     DeclParent = nullptr;
570b57cec5SDimitry Andric     MSLastManglingNumber = 1;
580b57cec5SDimitry Andric     MSCurManglingNumber = 1;
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   // If this scope is a function or contains breaks/continues, remember it.
620b57cec5SDimitry Andric   if (flags & FnScope)            FnParent = this;
630b57cec5SDimitry Andric   // The MS mangler uses the number of scopes that can hold declarations as
640b57cec5SDimitry Andric   // part of an external name.
650b57cec5SDimitry Andric   if (Flags & (ClassScope | FnScope)) {
660b57cec5SDimitry Andric     MSLastManglingNumber = getMSLastManglingNumber();
670b57cec5SDimitry Andric     MSLastManglingParent = this;
680b57cec5SDimitry Andric     MSCurManglingNumber = 1;
690b57cec5SDimitry Andric   }
700b57cec5SDimitry Andric   if (flags & BreakScope)         BreakParent = this;
710b57cec5SDimitry Andric   if (flags & ContinueScope)      ContinueParent = this;
720b57cec5SDimitry Andric   if (flags & BlockScope)         BlockParent = this;
730b57cec5SDimitry Andric   if (flags & TemplateParamScope) TemplateParamParent = this;
740b57cec5SDimitry Andric 
7506c3fb27SDimitry Andric   // If this is a prototype scope, record that. Lambdas have an extra prototype
7606c3fb27SDimitry Andric   // scope that doesn't add any depth.
7706c3fb27SDimitry Andric   if (flags & FunctionPrototypeScope && !(flags & LambdaScope))
7806c3fb27SDimitry Andric     PrototypeDepth++;
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   if (flags & DeclScope) {
81*0fca6ea1SDimitry Andric     DeclParent = this;
820b57cec5SDimitry Andric     if (flags & FunctionPrototypeScope)
830b57cec5SDimitry Andric       ; // Prototype scopes are uninteresting.
840b57cec5SDimitry Andric     else if ((flags & ClassScope) && getParent()->isClassScope())
850b57cec5SDimitry Andric       ; // Nested class scopes aren't ambiguous.
860b57cec5SDimitry Andric     else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)
870b57cec5SDimitry Andric       ; // Classes inside of namespaces aren't ambiguous.
880b57cec5SDimitry Andric     else if ((flags & EnumScope))
890b57cec5SDimitry Andric       ; // Don't increment for enum scopes.
900b57cec5SDimitry Andric     else
910b57cec5SDimitry Andric       incrementMSManglingNumber();
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
Init(Scope * parent,unsigned flags)950b57cec5SDimitry Andric void Scope::Init(Scope *parent, unsigned flags) {
960b57cec5SDimitry Andric   setFlags(parent, flags);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   DeclsInScope.clear();
990b57cec5SDimitry Andric   UsingDirectives.clear();
1000b57cec5SDimitry Andric   Entity = nullptr;
1010b57cec5SDimitry Andric   ErrorTrap.reset();
102bdd1243dSDimitry Andric   NRVO = std::nullopt;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
containedInPrototypeScope() const1050b57cec5SDimitry Andric bool Scope::containedInPrototypeScope() const {
1060b57cec5SDimitry Andric   const Scope *S = this;
1070b57cec5SDimitry Andric   while (S) {
1080b57cec5SDimitry Andric     if (S->isFunctionPrototypeScope())
1090b57cec5SDimitry Andric       return true;
1100b57cec5SDimitry Andric     S = S->getParent();
1110b57cec5SDimitry Andric   }
1120b57cec5SDimitry Andric   return false;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
AddFlags(unsigned FlagsToSet)1150b57cec5SDimitry Andric void Scope::AddFlags(unsigned FlagsToSet) {
1160b57cec5SDimitry Andric   assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
1170b57cec5SDimitry Andric          "Unsupported scope flags");
1180b57cec5SDimitry Andric   if (FlagsToSet & BreakScope) {
1190b57cec5SDimitry Andric     assert((Flags & BreakScope) == 0 && "Already set");
1200b57cec5SDimitry Andric     BreakParent = this;
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric   if (FlagsToSet & ContinueScope) {
1230b57cec5SDimitry Andric     assert((Flags & ContinueScope) == 0 && "Already set");
1240b57cec5SDimitry Andric     ContinueParent = this;
1250b57cec5SDimitry Andric   }
1260b57cec5SDimitry Andric   Flags |= FlagsToSet;
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
129972a253aSDimitry Andric // The algorithm for updating NRVO candidate is as follows:
130972a253aSDimitry Andric //   1. All previous candidates become invalid because a new NRVO candidate is
131972a253aSDimitry Andric //      obtained. Therefore, we need to clear return slots for other
132972a253aSDimitry Andric //      variables defined before the current return statement in the current
133972a253aSDimitry Andric //      scope and in outer scopes.
134972a253aSDimitry Andric //   2. Store the new candidate if its return slot is available. Otherwise,
135972a253aSDimitry Andric //      there is no NRVO candidate so far.
updateNRVOCandidate(VarDecl * VD)136972a253aSDimitry Andric void Scope::updateNRVOCandidate(VarDecl *VD) {
137972a253aSDimitry Andric   auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
138972a253aSDimitry Andric     bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
139972a253aSDimitry Andric 
140972a253aSDimitry Andric     // We found a candidate variable that can be put into a return slot.
141972a253aSDimitry Andric     // Clear the set, because other variables cannot occupy a return
142972a253aSDimitry Andric     // slot in the same scope.
143972a253aSDimitry Andric     S->ReturnSlots.clear();
144972a253aSDimitry Andric 
145972a253aSDimitry Andric     if (IsReturnSlotFound)
146972a253aSDimitry Andric       S->ReturnSlots.insert(VD);
147972a253aSDimitry Andric 
148972a253aSDimitry Andric     return IsReturnSlotFound;
149972a253aSDimitry Andric   };
150972a253aSDimitry Andric 
151972a253aSDimitry Andric   bool CanBePutInReturnSlot = false;
152972a253aSDimitry Andric 
153972a253aSDimitry Andric   for (auto *S = this; S; S = S->getParent()) {
154972a253aSDimitry Andric     CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
155972a253aSDimitry Andric 
156972a253aSDimitry Andric     if (S->getEntity())
157972a253aSDimitry Andric       break;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
160972a253aSDimitry Andric   // Consider the variable as NRVO candidate if the return slot is available
161972a253aSDimitry Andric   // for it in the current scope, or if it can be available in outer scopes.
162972a253aSDimitry Andric   NRVO = CanBePutInReturnSlot ? VD : nullptr;
163972a253aSDimitry Andric }
164972a253aSDimitry Andric 
applyNRVO()165972a253aSDimitry Andric void Scope::applyNRVO() {
166972a253aSDimitry Andric   // There is no NRVO candidate in the current scope.
167bdd1243dSDimitry Andric   if (!NRVO.has_value())
1680b57cec5SDimitry Andric     return;
1690b57cec5SDimitry Andric 
170972a253aSDimitry Andric   if (*NRVO && isDeclScope(*NRVO))
171bdd1243dSDimitry Andric     (*NRVO)->setNRVOVariable(true);
172972a253aSDimitry Andric 
173972a253aSDimitry Andric   // It's necessary to propagate NRVO candidate to the parent scope for cases
174972a253aSDimitry Andric   // when the parent scope doesn't contain a return statement.
175972a253aSDimitry Andric   // For example:
176972a253aSDimitry Andric   //    X foo(bool b) {
177972a253aSDimitry Andric   //      X x;
178972a253aSDimitry Andric   //      if (b)
179972a253aSDimitry Andric   //        return x;
180972a253aSDimitry Andric   //      exit(0);
181972a253aSDimitry Andric   //    }
182972a253aSDimitry Andric   // Also, we need to propagate nullptr value that means NRVO is not
183972a253aSDimitry Andric   // allowed in this scope.
184972a253aSDimitry Andric   // For example:
185972a253aSDimitry Andric   //    X foo(bool b) {
186972a253aSDimitry Andric   //      X x;
187972a253aSDimitry Andric   //      if (b)
188972a253aSDimitry Andric   //        return x;
189972a253aSDimitry Andric   //      else
190972a253aSDimitry Andric   //        return X(); // NRVO is not allowed
191972a253aSDimitry Andric   //    }
192972a253aSDimitry Andric   if (!getEntity())
193972a253aSDimitry Andric     getParent()->NRVO = *NRVO;
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
dump() const1960b57cec5SDimitry Andric LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
1970b57cec5SDimitry Andric 
dumpImpl(raw_ostream & OS) const1980b57cec5SDimitry Andric void Scope::dumpImpl(raw_ostream &OS) const {
1990b57cec5SDimitry Andric   unsigned Flags = getFlags();
2000b57cec5SDimitry Andric   bool HasFlags = Flags != 0;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   if (HasFlags)
2030b57cec5SDimitry Andric     OS << "Flags: ";
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric   std::pair<unsigned, const char *> FlagInfo[] = {
2060b57cec5SDimitry Andric       {FnScope, "FnScope"},
2070b57cec5SDimitry Andric       {BreakScope, "BreakScope"},
2080b57cec5SDimitry Andric       {ContinueScope, "ContinueScope"},
2090b57cec5SDimitry Andric       {DeclScope, "DeclScope"},
2100b57cec5SDimitry Andric       {ControlScope, "ControlScope"},
2110b57cec5SDimitry Andric       {ClassScope, "ClassScope"},
2120b57cec5SDimitry Andric       {BlockScope, "BlockScope"},
2130b57cec5SDimitry Andric       {TemplateParamScope, "TemplateParamScope"},
2140b57cec5SDimitry Andric       {FunctionPrototypeScope, "FunctionPrototypeScope"},
2150b57cec5SDimitry Andric       {FunctionDeclarationScope, "FunctionDeclarationScope"},
2160b57cec5SDimitry Andric       {AtCatchScope, "AtCatchScope"},
2170b57cec5SDimitry Andric       {ObjCMethodScope, "ObjCMethodScope"},
2180b57cec5SDimitry Andric       {SwitchScope, "SwitchScope"},
2190b57cec5SDimitry Andric       {TryScope, "TryScope"},
2200b57cec5SDimitry Andric       {FnTryCatchScope, "FnTryCatchScope"},
2210b57cec5SDimitry Andric       {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
2220b57cec5SDimitry Andric       {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
2230b57cec5SDimitry Andric       {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
2240b57cec5SDimitry Andric       {EnumScope, "EnumScope"},
2250b57cec5SDimitry Andric       {SEHTryScope, "SEHTryScope"},
2260b57cec5SDimitry Andric       {SEHExceptScope, "SEHExceptScope"},
2270b57cec5SDimitry Andric       {SEHFilterScope, "SEHFilterScope"},
2280b57cec5SDimitry Andric       {CompoundStmtScope, "CompoundStmtScope"},
2290b57cec5SDimitry Andric       {ClassInheritanceScope, "ClassInheritanceScope"},
2300b57cec5SDimitry Andric       {CatchScope, "CatchScope"},
231*0fca6ea1SDimitry Andric       {ConditionVarScope, "ConditionVarScope"},
232*0fca6ea1SDimitry Andric       {OpenMPOrderClauseScope, "OpenMPOrderClauseScope"},
233*0fca6ea1SDimitry Andric       {LambdaScope, "LambdaScope"},
234*0fca6ea1SDimitry Andric       {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
235*0fca6ea1SDimitry Andric       {TypeAliasScope, "TypeAliasScope"},
236*0fca6ea1SDimitry Andric       {FriendScope, "FriendScope"},
2370b57cec5SDimitry Andric   };
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   for (auto Info : FlagInfo) {
2400b57cec5SDimitry Andric     if (Flags & Info.first) {
2410b57cec5SDimitry Andric       OS << Info.second;
2420b57cec5SDimitry Andric       Flags &= ~Info.first;
2430b57cec5SDimitry Andric       if (Flags)
2440b57cec5SDimitry Andric         OS << " | ";
2450b57cec5SDimitry Andric     }
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   assert(Flags == 0 && "Unknown scope flags");
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   if (HasFlags)
2510b57cec5SDimitry Andric     OS << '\n';
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   if (const Scope *Parent = getParent())
2540b57cec5SDimitry Andric     OS << "Parent: (clang::Scope*)" << Parent << '\n';
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   OS << "Depth: " << Depth << '\n';
2570b57cec5SDimitry Andric   OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
2580b57cec5SDimitry Andric   OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
2590b57cec5SDimitry Andric   if (const DeclContext *DC = getEntity())
2600b57cec5SDimitry Andric     OS << "Entity : (clang::DeclContext*)" << DC << '\n';
2610b57cec5SDimitry Andric 
262972a253aSDimitry Andric   if (!NRVO)
263972a253aSDimitry Andric     OS << "there is no NRVO candidate\n";
264972a253aSDimitry Andric   else if (*NRVO)
265972a253aSDimitry Andric     OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
266972a253aSDimitry Andric   else
267972a253aSDimitry Andric     OS << "NRVO is not allowed\n";
2680b57cec5SDimitry Andric }
269