271 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the Scope class, which is used for recording10// 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 18using namespace clang;19 20void 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 for29 // 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 DeclParent = parent->DeclParent;41 MSLastManglingParent = parent->MSLastManglingParent;42 MSCurManglingNumber = getMSLastManglingNumber();43 if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |44 FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==45 0)46 Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;47 // transmit the parent's 'order' flag, if exists48 if (parent->getFlags() & OpenMPOrderClauseScope)49 Flags |= OpenMPOrderClauseScope;50 } else {51 Depth = 0;52 PrototypeDepth = 0;53 PrototypeIndex = 0;54 MSLastManglingParent = FnParent = BlockParent = nullptr;55 TemplateParamParent = nullptr;56 DeclParent = nullptr;57 MSLastManglingNumber = 1;58 MSCurManglingNumber = 1;59 }60 61 // If this scope is a function or contains breaks/continues, remember it.62 if (flags & FnScope) FnParent = this;63 // The MS mangler uses the number of scopes that can hold declarations as64 // part of an external name.65 if (Flags & (ClassScope | FnScope)) {66 MSLastManglingNumber = getMSLastManglingNumber();67 MSLastManglingParent = this;68 MSCurManglingNumber = 1;69 }70 if (flags & BreakScope) BreakParent = this;71 if (flags & ContinueScope) ContinueParent = this;72 if (flags & BlockScope) BlockParent = this;73 if (flags & TemplateParamScope) TemplateParamParent = this;74 75 // If this is a prototype scope, record that. Lambdas have an extra prototype76 // scope that doesn't add any depth.77 if (flags & FunctionPrototypeScope && !(flags & LambdaScope))78 PrototypeDepth++;79 80 if (flags & DeclScope) {81 DeclParent = this;82 if (flags & FunctionPrototypeScope)83 ; // Prototype scopes are uninteresting.84 else if ((flags & ClassScope) && getParent()->isClassScope())85 ; // Nested class scopes aren't ambiguous.86 else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)87 ; // Classes inside of namespaces aren't ambiguous.88 else if ((flags & EnumScope))89 ; // Don't increment for enum scopes.90 else91 incrementMSManglingNumber();92 }93}94 95void Scope::Init(Scope *parent, unsigned flags) {96 setFlags(parent, flags);97 98 DeclsInScope.clear();99 UsingDirectives.clear();100 Entity = nullptr;101 ErrorTrap.reset();102 PrecedingLabel = nullptr;103 NRVO = std::nullopt;104}105 106bool Scope::containedInPrototypeScope() const {107 const Scope *S = this;108 while (S) {109 if (S->isFunctionPrototypeScope())110 return true;111 S = S->getParent();112 }113 return false;114}115 116void Scope::AddFlags(unsigned FlagsToSet) {117 assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&118 "Unsupported scope flags");119 if (FlagsToSet & BreakScope) {120 assert((Flags & BreakScope) == 0 && "Already set");121 BreakParent = this;122 }123 if (FlagsToSet & ContinueScope) {124 assert((Flags & ContinueScope) == 0 && "Already set");125 ContinueParent = this;126 }127 Flags |= FlagsToSet;128}129 130// The algorithm for updating NRVO candidate is as follows:131// 1. All previous candidates become invalid because a new NRVO candidate is132// obtained. Therefore, we need to clear return slots for other133// variables defined before the current return statement in the current134// scope and in outer scopes.135// 2. Store the new candidate if its return slot is available. Otherwise,136// there is no NRVO candidate so far.137void Scope::updateNRVOCandidate(VarDecl *VD) {138 auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {139 bool IsReturnSlotFound = S->ReturnSlots.contains(VD);140 141 // We found a candidate variable that can be put into a return slot.142 // Clear the set, because other variables cannot occupy a return143 // slot in the same scope.144 S->ReturnSlots.clear();145 146 if (IsReturnSlotFound)147 S->ReturnSlots.insert(VD);148 149 return IsReturnSlotFound;150 };151 152 bool CanBePutInReturnSlot = false;153 154 for (auto *S = this; S; S = S->getParent()) {155 CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);156 157 if (S->getEntity())158 break;159 }160 161 // Consider the variable as NRVO candidate if the return slot is available162 // for it in the current scope, or if it can be available in outer scopes.163 NRVO = CanBePutInReturnSlot ? VD : nullptr;164}165 166void Scope::applyNRVO() {167 // There is no NRVO candidate in the current scope.168 if (!NRVO.has_value())169 return;170 171 if (*NRVO && isDeclScope(*NRVO))172 (*NRVO)->setNRVOVariable(true);173 174 // It's necessary to propagate NRVO candidate to the parent scope for cases175 // when the parent scope doesn't contain a return statement.176 // For example:177 // X foo(bool b) {178 // X x;179 // if (b)180 // return x;181 // exit(0);182 // }183 // Also, we need to propagate nullptr value that means NRVO is not184 // allowed in this scope.185 // For example:186 // X foo(bool b) {187 // X x;188 // if (b)189 // return x;190 // else191 // return X(); // NRVO is not allowed192 // }193 if (!getEntity())194 getParent()->NRVO = *NRVO;195}196 197LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }198 199void Scope::dumpImpl(raw_ostream &OS) const {200 unsigned Flags = getFlags();201 bool HasFlags = Flags != 0;202 203 if (HasFlags)204 OS << "Flags: ";205 206 std::pair<unsigned, const char *> FlagInfo[] = {207 {FnScope, "FnScope"},208 {BreakScope, "BreakScope"},209 {ContinueScope, "ContinueScope"},210 {DeclScope, "DeclScope"},211 {ControlScope, "ControlScope"},212 {ClassScope, "ClassScope"},213 {BlockScope, "BlockScope"},214 {TemplateParamScope, "TemplateParamScope"},215 {FunctionPrototypeScope, "FunctionPrototypeScope"},216 {FunctionDeclarationScope, "FunctionDeclarationScope"},217 {AtCatchScope, "AtCatchScope"},218 {ObjCMethodScope, "ObjCMethodScope"},219 {SwitchScope, "SwitchScope"},220 {TryScope, "TryScope"},221 {FnTryCatchScope, "FnTryCatchScope"},222 {OpenMPDirectiveScope, "OpenMPDirectiveScope"},223 {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},224 {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},225 {EnumScope, "EnumScope"},226 {SEHTryScope, "SEHTryScope"},227 {SEHExceptScope, "SEHExceptScope"},228 {SEHFilterScope, "SEHFilterScope"},229 {CompoundStmtScope, "CompoundStmtScope"},230 {ClassInheritanceScope, "ClassInheritanceScope"},231 {CatchScope, "CatchScope"},232 {ConditionVarScope, "ConditionVarScope"},233 {OpenMPOrderClauseScope, "OpenMPOrderClauseScope"},234 {LambdaScope, "LambdaScope"},235 {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},236 {TypeAliasScope, "TypeAliasScope"},237 {FriendScope, "FriendScope"},238 {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},239 {OpenACCLoopConstructScope, "OpenACCLoopConstructScope"}};240 241 for (auto Info : FlagInfo) {242 if (Flags & Info.first) {243 OS << Info.second;244 Flags &= ~Info.first;245 if (Flags)246 OS << " | ";247 }248 }249 250 assert(Flags == 0 && "Unknown scope flags");251 252 if (HasFlags)253 OS << '\n';254 255 if (const Scope *Parent = getParent())256 OS << "Parent: (clang::Scope*)" << Parent << '\n';257 258 OS << "Depth: " << Depth << '\n';259 OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';260 OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';261 if (const DeclContext *DC = getEntity())262 OS << "Entity : (clang::DeclContext*)" << DC << '\n';263 264 if (!NRVO)265 OS << "there is no NRVO candidate\n";266 else if (*NRVO)267 OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';268 else269 OS << "NRVO is not allowed\n";270}271