xref: /freebsd/contrib/llvm-project/clang/lib/Sema/Scope.cpp (revision cfd6422a5217410fbd66f7a7a8a64d9d85e61229)
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the Scope class, which is used for recording
10 // 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 
18 using namespace clang;
19 
20 void 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 for
29     // 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     MSLastManglingParent = parent->MSLastManglingParent;
41     MSCurManglingNumber = getMSLastManglingNumber();
42     if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
43                   FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
44         0)
45       Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
46   } else {
47     Depth = 0;
48     PrototypeDepth = 0;
49     PrototypeIndex = 0;
50     MSLastManglingParent = FnParent = BlockParent = nullptr;
51     TemplateParamParent = nullptr;
52     MSLastManglingNumber = 1;
53     MSCurManglingNumber = 1;
54   }
55 
56   // If this scope is a function or contains breaks/continues, remember it.
57   if (flags & FnScope)            FnParent = this;
58   // The MS mangler uses the number of scopes that can hold declarations as
59   // part of an external name.
60   if (Flags & (ClassScope | FnScope)) {
61     MSLastManglingNumber = getMSLastManglingNumber();
62     MSLastManglingParent = this;
63     MSCurManglingNumber = 1;
64   }
65   if (flags & BreakScope)         BreakParent = this;
66   if (flags & ContinueScope)      ContinueParent = this;
67   if (flags & BlockScope)         BlockParent = this;
68   if (flags & TemplateParamScope) TemplateParamParent = this;
69 
70   // If this is a prototype scope, record that.
71   if (flags & FunctionPrototypeScope) PrototypeDepth++;
72 
73   if (flags & DeclScope) {
74     if (flags & FunctionPrototypeScope)
75       ; // Prototype scopes are uninteresting.
76     else if ((flags & ClassScope) && getParent()->isClassScope())
77       ; // Nested class scopes aren't ambiguous.
78     else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)
79       ; // Classes inside of namespaces aren't ambiguous.
80     else if ((flags & EnumScope))
81       ; // Don't increment for enum scopes.
82     else
83       incrementMSManglingNumber();
84   }
85 }
86 
87 void Scope::Init(Scope *parent, unsigned flags) {
88   setFlags(parent, flags);
89 
90   DeclsInScope.clear();
91   UsingDirectives.clear();
92   Entity = nullptr;
93   ErrorTrap.reset();
94   NRVO.setPointerAndInt(nullptr, 0);
95 }
96 
97 bool Scope::containedInPrototypeScope() const {
98   const Scope *S = this;
99   while (S) {
100     if (S->isFunctionPrototypeScope())
101       return true;
102     S = S->getParent();
103   }
104   return false;
105 }
106 
107 void Scope::AddFlags(unsigned FlagsToSet) {
108   assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
109          "Unsupported scope flags");
110   if (FlagsToSet & BreakScope) {
111     assert((Flags & BreakScope) == 0 && "Already set");
112     BreakParent = this;
113   }
114   if (FlagsToSet & ContinueScope) {
115     assert((Flags & ContinueScope) == 0 && "Already set");
116     ContinueParent = this;
117   }
118   Flags |= FlagsToSet;
119 }
120 
121 void Scope::mergeNRVOIntoParent() {
122   if (VarDecl *Candidate = NRVO.getPointer()) {
123     if (isDeclScope(Candidate))
124       Candidate->setNRVOVariable(true);
125   }
126 
127   if (getEntity())
128     return;
129 
130   if (NRVO.getInt())
131     getParent()->setNoNRVO();
132   else if (NRVO.getPointer())
133     getParent()->addNRVOCandidate(NRVO.getPointer());
134 }
135 
136 LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
137 
138 void Scope::dumpImpl(raw_ostream &OS) const {
139   unsigned Flags = getFlags();
140   bool HasFlags = Flags != 0;
141 
142   if (HasFlags)
143     OS << "Flags: ";
144 
145   std::pair<unsigned, const char *> FlagInfo[] = {
146       {FnScope, "FnScope"},
147       {BreakScope, "BreakScope"},
148       {ContinueScope, "ContinueScope"},
149       {DeclScope, "DeclScope"},
150       {ControlScope, "ControlScope"},
151       {ClassScope, "ClassScope"},
152       {BlockScope, "BlockScope"},
153       {TemplateParamScope, "TemplateParamScope"},
154       {FunctionPrototypeScope, "FunctionPrototypeScope"},
155       {FunctionDeclarationScope, "FunctionDeclarationScope"},
156       {AtCatchScope, "AtCatchScope"},
157       {ObjCMethodScope, "ObjCMethodScope"},
158       {SwitchScope, "SwitchScope"},
159       {TryScope, "TryScope"},
160       {FnTryCatchScope, "FnTryCatchScope"},
161       {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
162       {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
163       {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
164       {EnumScope, "EnumScope"},
165       {SEHTryScope, "SEHTryScope"},
166       {SEHExceptScope, "SEHExceptScope"},
167       {SEHFilterScope, "SEHFilterScope"},
168       {CompoundStmtScope, "CompoundStmtScope"},
169       {ClassInheritanceScope, "ClassInheritanceScope"},
170       {CatchScope, "CatchScope"},
171   };
172 
173   for (auto Info : FlagInfo) {
174     if (Flags & Info.first) {
175       OS << Info.second;
176       Flags &= ~Info.first;
177       if (Flags)
178         OS << " | ";
179     }
180   }
181 
182   assert(Flags == 0 && "Unknown scope flags");
183 
184   if (HasFlags)
185     OS << '\n';
186 
187   if (const Scope *Parent = getParent())
188     OS << "Parent: (clang::Scope*)" << Parent << '\n';
189 
190   OS << "Depth: " << Depth << '\n';
191   OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
192   OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
193   if (const DeclContext *DC = getEntity())
194     OS << "Entity : (clang::DeclContext*)" << DC << '\n';
195 
196   if (NRVO.getInt())
197     OS << "NRVO not allowed\n";
198   else if (NRVO.getPointer())
199     OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n';
200 }
201