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; 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 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 1050b57cec5SDimitry 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 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. 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 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 1960b57cec5SDimitry Andric LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry 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