Path: blob/main/contrib/llvm-project/clang/lib/Sema/Scope.cpp
35234 views
//===- Scope.cpp - Lexical scope information --------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the Scope class, which is used for recording9// information about a lexical scope.10//11//===----------------------------------------------------------------------===//1213#include "clang/Sema/Scope.h"14#include "clang/AST/Decl.h"15#include "llvm/Support/raw_ostream.h"1617using namespace clang;1819void Scope::setFlags(Scope *parent, unsigned flags) {20AnyParent = parent;21Flags = flags;2223if (parent && !(flags & FnScope)) {24BreakParent = parent->BreakParent;25ContinueParent = parent->ContinueParent;26} else {27// Control scopes do not contain the contents of nested function scopes for28// control flow purposes.29BreakParent = ContinueParent = nullptr;30}3132if (parent) {33Depth = parent->Depth + 1;34PrototypeDepth = parent->PrototypeDepth;35PrototypeIndex = 0;36FnParent = parent->FnParent;37BlockParent = parent->BlockParent;38TemplateParamParent = parent->TemplateParamParent;39DeclParent = parent->DeclParent;40MSLastManglingParent = parent->MSLastManglingParent;41MSCurManglingNumber = getMSLastManglingNumber();42if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |43FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==440)45Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;46// transmit the parent's 'order' flag, if exists47if (parent->getFlags() & OpenMPOrderClauseScope)48Flags |= OpenMPOrderClauseScope;49} else {50Depth = 0;51PrototypeDepth = 0;52PrototypeIndex = 0;53MSLastManglingParent = FnParent = BlockParent = nullptr;54TemplateParamParent = nullptr;55DeclParent = nullptr;56MSLastManglingNumber = 1;57MSCurManglingNumber = 1;58}5960// If this scope is a function or contains breaks/continues, remember it.61if (flags & FnScope) FnParent = this;62// The MS mangler uses the number of scopes that can hold declarations as63// part of an external name.64if (Flags & (ClassScope | FnScope)) {65MSLastManglingNumber = getMSLastManglingNumber();66MSLastManglingParent = this;67MSCurManglingNumber = 1;68}69if (flags & BreakScope) BreakParent = this;70if (flags & ContinueScope) ContinueParent = this;71if (flags & BlockScope) BlockParent = this;72if (flags & TemplateParamScope) TemplateParamParent = this;7374// If this is a prototype scope, record that. Lambdas have an extra prototype75// scope that doesn't add any depth.76if (flags & FunctionPrototypeScope && !(flags & LambdaScope))77PrototypeDepth++;7879if (flags & DeclScope) {80DeclParent = this;81if (flags & FunctionPrototypeScope)82; // Prototype scopes are uninteresting.83else if ((flags & ClassScope) && getParent()->isClassScope())84; // Nested class scopes aren't ambiguous.85else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)86; // Classes inside of namespaces aren't ambiguous.87else if ((flags & EnumScope))88; // Don't increment for enum scopes.89else90incrementMSManglingNumber();91}92}9394void Scope::Init(Scope *parent, unsigned flags) {95setFlags(parent, flags);9697DeclsInScope.clear();98UsingDirectives.clear();99Entity = nullptr;100ErrorTrap.reset();101NRVO = std::nullopt;102}103104bool Scope::containedInPrototypeScope() const {105const Scope *S = this;106while (S) {107if (S->isFunctionPrototypeScope())108return true;109S = S->getParent();110}111return false;112}113114void Scope::AddFlags(unsigned FlagsToSet) {115assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&116"Unsupported scope flags");117if (FlagsToSet & BreakScope) {118assert((Flags & BreakScope) == 0 && "Already set");119BreakParent = this;120}121if (FlagsToSet & ContinueScope) {122assert((Flags & ContinueScope) == 0 && "Already set");123ContinueParent = this;124}125Flags |= FlagsToSet;126}127128// The algorithm for updating NRVO candidate is as follows:129// 1. All previous candidates become invalid because a new NRVO candidate is130// obtained. Therefore, we need to clear return slots for other131// variables defined before the current return statement in the current132// scope and in outer scopes.133// 2. Store the new candidate if its return slot is available. Otherwise,134// there is no NRVO candidate so far.135void Scope::updateNRVOCandidate(VarDecl *VD) {136auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {137bool IsReturnSlotFound = S->ReturnSlots.contains(VD);138139// We found a candidate variable that can be put into a return slot.140// Clear the set, because other variables cannot occupy a return141// slot in the same scope.142S->ReturnSlots.clear();143144if (IsReturnSlotFound)145S->ReturnSlots.insert(VD);146147return IsReturnSlotFound;148};149150bool CanBePutInReturnSlot = false;151152for (auto *S = this; S; S = S->getParent()) {153CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);154155if (S->getEntity())156break;157}158159// Consider the variable as NRVO candidate if the return slot is available160// for it in the current scope, or if it can be available in outer scopes.161NRVO = CanBePutInReturnSlot ? VD : nullptr;162}163164void Scope::applyNRVO() {165// There is no NRVO candidate in the current scope.166if (!NRVO.has_value())167return;168169if (*NRVO && isDeclScope(*NRVO))170(*NRVO)->setNRVOVariable(true);171172// It's necessary to propagate NRVO candidate to the parent scope for cases173// when the parent scope doesn't contain a return statement.174// For example:175// X foo(bool b) {176// X x;177// if (b)178// return x;179// exit(0);180// }181// Also, we need to propagate nullptr value that means NRVO is not182// allowed in this scope.183// For example:184// X foo(bool b) {185// X x;186// if (b)187// return x;188// else189// return X(); // NRVO is not allowed190// }191if (!getEntity())192getParent()->NRVO = *NRVO;193}194195LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }196197void Scope::dumpImpl(raw_ostream &OS) const {198unsigned Flags = getFlags();199bool HasFlags = Flags != 0;200201if (HasFlags)202OS << "Flags: ";203204std::pair<unsigned, const char *> FlagInfo[] = {205{FnScope, "FnScope"},206{BreakScope, "BreakScope"},207{ContinueScope, "ContinueScope"},208{DeclScope, "DeclScope"},209{ControlScope, "ControlScope"},210{ClassScope, "ClassScope"},211{BlockScope, "BlockScope"},212{TemplateParamScope, "TemplateParamScope"},213{FunctionPrototypeScope, "FunctionPrototypeScope"},214{FunctionDeclarationScope, "FunctionDeclarationScope"},215{AtCatchScope, "AtCatchScope"},216{ObjCMethodScope, "ObjCMethodScope"},217{SwitchScope, "SwitchScope"},218{TryScope, "TryScope"},219{FnTryCatchScope, "FnTryCatchScope"},220{OpenMPDirectiveScope, "OpenMPDirectiveScope"},221{OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},222{OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},223{EnumScope, "EnumScope"},224{SEHTryScope, "SEHTryScope"},225{SEHExceptScope, "SEHExceptScope"},226{SEHFilterScope, "SEHFilterScope"},227{CompoundStmtScope, "CompoundStmtScope"},228{ClassInheritanceScope, "ClassInheritanceScope"},229{CatchScope, "CatchScope"},230{ConditionVarScope, "ConditionVarScope"},231{OpenMPOrderClauseScope, "OpenMPOrderClauseScope"},232{LambdaScope, "LambdaScope"},233{OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},234{TypeAliasScope, "TypeAliasScope"},235{FriendScope, "FriendScope"},236};237238for (auto Info : FlagInfo) {239if (Flags & Info.first) {240OS << Info.second;241Flags &= ~Info.first;242if (Flags)243OS << " | ";244}245}246247assert(Flags == 0 && "Unknown scope flags");248249if (HasFlags)250OS << '\n';251252if (const Scope *Parent = getParent())253OS << "Parent: (clang::Scope*)" << Parent << '\n';254255OS << "Depth: " << Depth << '\n';256OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';257OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';258if (const DeclContext *DC = getEntity())259OS << "Entity : (clang::DeclContext*)" << DC << '\n';260261if (!NRVO)262OS << "there is no NRVO candidate\n";263else if (*NRVO)264OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';265else266OS << "NRVO is not allowed\n";267}268269270