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