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
setFlags(Scope * parent,unsigned flags)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
Init(Scope * parent,unsigned flags)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
containedInPrototypeScope() const1050b57cec5SDimitry 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
AddFlags(unsigned FlagsToSet)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.
updateNRVOCandidate(VarDecl * VD)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
applyNRVO()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
dump() const1960b57cec5SDimitry Andric LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
1970b57cec5SDimitry Andric
dumpImpl(raw_ostream & OS) const1980b57cec5SDimitry 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