xref: /freebsd/contrib/llvm-project/clang/lib/Sema/Scope.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 
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;
400b57cec5SDimitry Andric     MSLastManglingParent = parent->MSLastManglingParent;
410b57cec5SDimitry Andric     MSCurManglingNumber = getMSLastManglingNumber();
420b57cec5SDimitry Andric     if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
430b57cec5SDimitry Andric                   FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
440b57cec5SDimitry Andric         0)
450b57cec5SDimitry Andric       Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
46*bdd1243dSDimitry Andric     // transmit the parent's 'order' flag, if exists
47*bdd1243dSDimitry Andric     if (parent->getFlags() & OpenMPOrderClauseScope)
48*bdd1243dSDimitry Andric       Flags |= OpenMPOrderClauseScope;
490b57cec5SDimitry Andric   } else {
500b57cec5SDimitry Andric     Depth = 0;
510b57cec5SDimitry Andric     PrototypeDepth = 0;
520b57cec5SDimitry Andric     PrototypeIndex = 0;
530b57cec5SDimitry Andric     MSLastManglingParent = FnParent = BlockParent = nullptr;
540b57cec5SDimitry Andric     TemplateParamParent = nullptr;
550b57cec5SDimitry Andric     MSLastManglingNumber = 1;
560b57cec5SDimitry Andric     MSCurManglingNumber = 1;
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   // If this scope is a function or contains breaks/continues, remember it.
600b57cec5SDimitry Andric   if (flags & FnScope)            FnParent = this;
610b57cec5SDimitry Andric   // The MS mangler uses the number of scopes that can hold declarations as
620b57cec5SDimitry Andric   // part of an external name.
630b57cec5SDimitry Andric   if (Flags & (ClassScope | FnScope)) {
640b57cec5SDimitry Andric     MSLastManglingNumber = getMSLastManglingNumber();
650b57cec5SDimitry Andric     MSLastManglingParent = this;
660b57cec5SDimitry Andric     MSCurManglingNumber = 1;
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric   if (flags & BreakScope)         BreakParent = this;
690b57cec5SDimitry Andric   if (flags & ContinueScope)      ContinueParent = this;
700b57cec5SDimitry Andric   if (flags & BlockScope)         BlockParent = this;
710b57cec5SDimitry Andric   if (flags & TemplateParamScope) TemplateParamParent = this;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   // If this is a prototype scope, record that.
740b57cec5SDimitry Andric   if (flags & FunctionPrototypeScope) PrototypeDepth++;
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   if (flags & DeclScope) {
770b57cec5SDimitry Andric     if (flags & FunctionPrototypeScope)
780b57cec5SDimitry Andric       ; // Prototype scopes are uninteresting.
790b57cec5SDimitry Andric     else if ((flags & ClassScope) && getParent()->isClassScope())
800b57cec5SDimitry Andric       ; // Nested class scopes aren't ambiguous.
810b57cec5SDimitry Andric     else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)
820b57cec5SDimitry Andric       ; // Classes inside of namespaces aren't ambiguous.
830b57cec5SDimitry Andric     else if ((flags & EnumScope))
840b57cec5SDimitry Andric       ; // Don't increment for enum scopes.
850b57cec5SDimitry Andric     else
860b57cec5SDimitry Andric       incrementMSManglingNumber();
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric void Scope::Init(Scope *parent, unsigned flags) {
910b57cec5SDimitry Andric   setFlags(parent, flags);
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   DeclsInScope.clear();
940b57cec5SDimitry Andric   UsingDirectives.clear();
950b57cec5SDimitry Andric   Entity = nullptr;
960b57cec5SDimitry Andric   ErrorTrap.reset();
97*bdd1243dSDimitry Andric   NRVO = std::nullopt;
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric bool Scope::containedInPrototypeScope() const {
1010b57cec5SDimitry Andric   const Scope *S = this;
1020b57cec5SDimitry Andric   while (S) {
1030b57cec5SDimitry Andric     if (S->isFunctionPrototypeScope())
1040b57cec5SDimitry Andric       return true;
1050b57cec5SDimitry Andric     S = S->getParent();
1060b57cec5SDimitry Andric   }
1070b57cec5SDimitry Andric   return false;
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric void Scope::AddFlags(unsigned FlagsToSet) {
1110b57cec5SDimitry Andric   assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
1120b57cec5SDimitry Andric          "Unsupported scope flags");
1130b57cec5SDimitry Andric   if (FlagsToSet & BreakScope) {
1140b57cec5SDimitry Andric     assert((Flags & BreakScope) == 0 && "Already set");
1150b57cec5SDimitry Andric     BreakParent = this;
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric   if (FlagsToSet & ContinueScope) {
1180b57cec5SDimitry Andric     assert((Flags & ContinueScope) == 0 && "Already set");
1190b57cec5SDimitry Andric     ContinueParent = this;
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric   Flags |= FlagsToSet;
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric 
124972a253aSDimitry Andric // The algorithm for updating NRVO candidate is as follows:
125972a253aSDimitry Andric //   1. All previous candidates become invalid because a new NRVO candidate is
126972a253aSDimitry Andric //      obtained. Therefore, we need to clear return slots for other
127972a253aSDimitry Andric //      variables defined before the current return statement in the current
128972a253aSDimitry Andric //      scope and in outer scopes.
129972a253aSDimitry Andric //   2. Store the new candidate if its return slot is available. Otherwise,
130972a253aSDimitry Andric //      there is no NRVO candidate so far.
131972a253aSDimitry Andric void Scope::updateNRVOCandidate(VarDecl *VD) {
132972a253aSDimitry Andric   auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
133972a253aSDimitry Andric     bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
134972a253aSDimitry Andric 
135972a253aSDimitry Andric     // We found a candidate variable that can be put into a return slot.
136972a253aSDimitry Andric     // Clear the set, because other variables cannot occupy a return
137972a253aSDimitry Andric     // slot in the same scope.
138972a253aSDimitry Andric     S->ReturnSlots.clear();
139972a253aSDimitry Andric 
140972a253aSDimitry Andric     if (IsReturnSlotFound)
141972a253aSDimitry Andric       S->ReturnSlots.insert(VD);
142972a253aSDimitry Andric 
143972a253aSDimitry Andric     return IsReturnSlotFound;
144972a253aSDimitry Andric   };
145972a253aSDimitry Andric 
146972a253aSDimitry Andric   bool CanBePutInReturnSlot = false;
147972a253aSDimitry Andric 
148972a253aSDimitry Andric   for (auto *S = this; S; S = S->getParent()) {
149972a253aSDimitry Andric     CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
150972a253aSDimitry Andric 
151972a253aSDimitry Andric     if (S->getEntity())
152972a253aSDimitry Andric       break;
1530b57cec5SDimitry Andric   }
1540b57cec5SDimitry Andric 
155972a253aSDimitry Andric   // Consider the variable as NRVO candidate if the return slot is available
156972a253aSDimitry Andric   // for it in the current scope, or if it can be available in outer scopes.
157972a253aSDimitry Andric   NRVO = CanBePutInReturnSlot ? VD : nullptr;
158972a253aSDimitry Andric }
159972a253aSDimitry Andric 
160972a253aSDimitry Andric void Scope::applyNRVO() {
161972a253aSDimitry Andric   // There is no NRVO candidate in the current scope.
162*bdd1243dSDimitry Andric   if (!NRVO.has_value())
1630b57cec5SDimitry Andric     return;
1640b57cec5SDimitry Andric 
165972a253aSDimitry Andric   if (*NRVO && isDeclScope(*NRVO))
166*bdd1243dSDimitry Andric     (*NRVO)->setNRVOVariable(true);
167972a253aSDimitry Andric 
168972a253aSDimitry Andric   // It's necessary to propagate NRVO candidate to the parent scope for cases
169972a253aSDimitry Andric   // when the parent scope doesn't contain a return statement.
170972a253aSDimitry Andric   // For example:
171972a253aSDimitry Andric   //    X foo(bool b) {
172972a253aSDimitry Andric   //      X x;
173972a253aSDimitry Andric   //      if (b)
174972a253aSDimitry Andric   //        return x;
175972a253aSDimitry Andric   //      exit(0);
176972a253aSDimitry Andric   //    }
177972a253aSDimitry Andric   // Also, we need to propagate nullptr value that means NRVO is not
178972a253aSDimitry Andric   // allowed in this scope.
179972a253aSDimitry Andric   // For example:
180972a253aSDimitry Andric   //    X foo(bool b) {
181972a253aSDimitry Andric   //      X x;
182972a253aSDimitry Andric   //      if (b)
183972a253aSDimitry Andric   //        return x;
184972a253aSDimitry Andric   //      else
185972a253aSDimitry Andric   //        return X(); // NRVO is not allowed
186972a253aSDimitry Andric   //    }
187972a253aSDimitry Andric   if (!getEntity())
188972a253aSDimitry Andric     getParent()->NRVO = *NRVO;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric void Scope::dumpImpl(raw_ostream &OS) const {
1940b57cec5SDimitry Andric   unsigned Flags = getFlags();
1950b57cec5SDimitry Andric   bool HasFlags = Flags != 0;
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   if (HasFlags)
1980b57cec5SDimitry Andric     OS << "Flags: ";
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   std::pair<unsigned, const char *> FlagInfo[] = {
2010b57cec5SDimitry Andric       {FnScope, "FnScope"},
2020b57cec5SDimitry Andric       {BreakScope, "BreakScope"},
2030b57cec5SDimitry Andric       {ContinueScope, "ContinueScope"},
2040b57cec5SDimitry Andric       {DeclScope, "DeclScope"},
2050b57cec5SDimitry Andric       {ControlScope, "ControlScope"},
2060b57cec5SDimitry Andric       {ClassScope, "ClassScope"},
2070b57cec5SDimitry Andric       {BlockScope, "BlockScope"},
2080b57cec5SDimitry Andric       {TemplateParamScope, "TemplateParamScope"},
2090b57cec5SDimitry Andric       {FunctionPrototypeScope, "FunctionPrototypeScope"},
2100b57cec5SDimitry Andric       {FunctionDeclarationScope, "FunctionDeclarationScope"},
2110b57cec5SDimitry Andric       {AtCatchScope, "AtCatchScope"},
2120b57cec5SDimitry Andric       {ObjCMethodScope, "ObjCMethodScope"},
2130b57cec5SDimitry Andric       {SwitchScope, "SwitchScope"},
2140b57cec5SDimitry Andric       {TryScope, "TryScope"},
2150b57cec5SDimitry Andric       {FnTryCatchScope, "FnTryCatchScope"},
2160b57cec5SDimitry Andric       {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
2170b57cec5SDimitry Andric       {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
2180b57cec5SDimitry Andric       {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
2190b57cec5SDimitry Andric       {EnumScope, "EnumScope"},
2200b57cec5SDimitry Andric       {SEHTryScope, "SEHTryScope"},
2210b57cec5SDimitry Andric       {SEHExceptScope, "SEHExceptScope"},
2220b57cec5SDimitry Andric       {SEHFilterScope, "SEHFilterScope"},
2230b57cec5SDimitry Andric       {CompoundStmtScope, "CompoundStmtScope"},
2240b57cec5SDimitry Andric       {ClassInheritanceScope, "ClassInheritanceScope"},
2250b57cec5SDimitry Andric       {CatchScope, "CatchScope"},
2260b57cec5SDimitry Andric   };
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   for (auto Info : FlagInfo) {
2290b57cec5SDimitry Andric     if (Flags & Info.first) {
2300b57cec5SDimitry Andric       OS << Info.second;
2310b57cec5SDimitry Andric       Flags &= ~Info.first;
2320b57cec5SDimitry Andric       if (Flags)
2330b57cec5SDimitry Andric         OS << " | ";
2340b57cec5SDimitry Andric     }
2350b57cec5SDimitry Andric   }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   assert(Flags == 0 && "Unknown scope flags");
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   if (HasFlags)
2400b57cec5SDimitry Andric     OS << '\n';
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   if (const Scope *Parent = getParent())
2430b57cec5SDimitry Andric     OS << "Parent: (clang::Scope*)" << Parent << '\n';
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   OS << "Depth: " << Depth << '\n';
2460b57cec5SDimitry Andric   OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
2470b57cec5SDimitry Andric   OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
2480b57cec5SDimitry Andric   if (const DeclContext *DC = getEntity())
2490b57cec5SDimitry Andric     OS << "Entity : (clang::DeclContext*)" << DC << '\n';
2500b57cec5SDimitry Andric 
251972a253aSDimitry Andric   if (!NRVO)
252972a253aSDimitry Andric     OS << "there is no NRVO candidate\n";
253972a253aSDimitry Andric   else if (*NRVO)
254972a253aSDimitry Andric     OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
255972a253aSDimitry Andric   else
256972a253aSDimitry Andric     OS << "NRVO is not allowed\n";
2570b57cec5SDimitry Andric }
258