clang  19.0.0git
Scope.cpp
Go to the documentation of this file.
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  DeclParent = parent->DeclParent;
41  MSLastManglingParent = parent->MSLastManglingParent;
42  MSCurManglingNumber = getMSLastManglingNumber();
43  if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
45  0)
46  Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
47  // transmit the parent's 'order' flag, if exists
48  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 as
64  // 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 prototype
76  // 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  else
92  }
93 }
94 
95 void Scope::Init(Scope *parent, unsigned flags) {
96  setFlags(parent, flags);
97 
98  DeclsInScope.clear();
99  UsingDirectives.clear();
100  Entity = nullptr;
101  ErrorTrap.reset();
102  NRVO = std::nullopt;
103 }
104 
106  const Scope *S = this;
107  while (S) {
108  if (S->isFunctionPrototypeScope())
109  return true;
110  S = S->getParent();
111  }
112  return false;
113 }
114 
115 void Scope::AddFlags(unsigned FlagsToSet) {
116  assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
117  "Unsupported scope flags");
118  if (FlagsToSet & BreakScope) {
119  assert((Flags & BreakScope) == 0 && "Already set");
120  BreakParent = this;
121  }
122  if (FlagsToSet & ContinueScope) {
123  assert((Flags & ContinueScope) == 0 && "Already set");
124  ContinueParent = this;
125  }
126  Flags |= FlagsToSet;
127 }
128 
129 // The algorithm for updating NRVO candidate is as follows:
130 // 1. All previous candidates become invalid because a new NRVO candidate is
131 // obtained. Therefore, we need to clear return slots for other
132 // variables defined before the current return statement in the current
133 // scope and in outer scopes.
134 // 2. Store the new candidate if its return slot is available. Otherwise,
135 // there is no NRVO candidate so far.
137  auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
138  bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
139 
140  // We found a candidate variable that can be put into a return slot.
141  // Clear the set, because other variables cannot occupy a return
142  // slot in the same scope.
143  S->ReturnSlots.clear();
144 
145  if (IsReturnSlotFound)
146  S->ReturnSlots.insert(VD);
147 
148  return IsReturnSlotFound;
149  };
150 
151  bool CanBePutInReturnSlot = false;
152 
153  for (auto *S = this; S; S = S->getParent()) {
154  CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
155 
156  if (S->getEntity())
157  break;
158  }
159 
160  // Consider the variable as NRVO candidate if the return slot is available
161  // for it in the current scope, or if it can be available in outer scopes.
162  NRVO = CanBePutInReturnSlot ? VD : nullptr;
163 }
164 
166  // There is no NRVO candidate in the current scope.
167  if (!NRVO.has_value())
168  return;
169 
170  if (*NRVO && isDeclScope(*NRVO))
171  (*NRVO)->setNRVOVariable(true);
172 
173  // It's necessary to propagate NRVO candidate to the parent scope for cases
174  // when the parent scope doesn't contain a return statement.
175  // For example:
176  // X foo(bool b) {
177  // X x;
178  // if (b)
179  // return x;
180  // exit(0);
181  // }
182  // Also, we need to propagate nullptr value that means NRVO is not
183  // allowed in this scope.
184  // For example:
185  // X foo(bool b) {
186  // X x;
187  // if (b)
188  // return x;
189  // else
190  // return X(); // NRVO is not allowed
191  // }
192  if (!getEntity())
193  getParent()->NRVO = *NRVO;
194 }
195 
196 LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
197 
198 void Scope::dumpImpl(raw_ostream &OS) const {
199  unsigned Flags = getFlags();
200  bool HasFlags = Flags != 0;
201 
202  if (HasFlags)
203  OS << "Flags: ";
204 
205  std::pair<unsigned, const char *> FlagInfo[] = {
206  {FnScope, "FnScope"},
207  {BreakScope, "BreakScope"},
208  {ContinueScope, "ContinueScope"},
209  {DeclScope, "DeclScope"},
210  {ControlScope, "ControlScope"},
211  {ClassScope, "ClassScope"},
212  {BlockScope, "BlockScope"},
213  {TemplateParamScope, "TemplateParamScope"},
214  {FunctionPrototypeScope, "FunctionPrototypeScope"},
215  {FunctionDeclarationScope, "FunctionDeclarationScope"},
216  {AtCatchScope, "AtCatchScope"},
217  {ObjCMethodScope, "ObjCMethodScope"},
218  {SwitchScope, "SwitchScope"},
219  {TryScope, "TryScope"},
220  {FnTryCatchScope, "FnTryCatchScope"},
221  {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
222  {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
223  {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
224  {EnumScope, "EnumScope"},
225  {SEHTryScope, "SEHTryScope"},
226  {SEHExceptScope, "SEHExceptScope"},
227  {SEHFilterScope, "SEHFilterScope"},
228  {CompoundStmtScope, "CompoundStmtScope"},
229  {ClassInheritanceScope, "ClassInheritanceScope"},
230  {CatchScope, "CatchScope"},
231  {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
232  {FriendScope, "FriendScope"},
233  };
234 
235  for (auto Info : FlagInfo) {
236  if (Flags & Info.first) {
237  OS << Info.second;
238  Flags &= ~Info.first;
239  if (Flags)
240  OS << " | ";
241  }
242  }
243 
244  assert(Flags == 0 && "Unknown scope flags");
245 
246  if (HasFlags)
247  OS << '\n';
248 
249  if (const Scope *Parent = getParent())
250  OS << "Parent: (clang::Scope*)" << Parent << '\n';
251 
252  OS << "Depth: " << Depth << '\n';
253  OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
254  OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
255  if (const DeclContext *DC = getEntity())
256  OS << "Entity : (clang::DeclContext*)" << DC << '\n';
257 
258  if (!NRVO)
259  OS << "there is no NRVO candidate\n";
260  else if (*NRVO)
261  OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
262  else
263  OS << "NRVO is not allowed\n";
264 }
NodeId Parent
Definition: ASTDiff.cpp:191
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1436
void reset()
Set to initial state of "no errors occurred".
Definition: Diagnostic.h:1105
Scope - A scope is a transient data structure that is used while parsing the program.
Definition: Scope.h:41
void Init(Scope *parent, unsigned flags)
Init - This is used by the parser to implement scope caching.
Definition: Scope.cpp:95
void AddFlags(unsigned Flags)
Sets up the specified scope flags and adjusts the scope state variables accordingly.
Definition: Scope.cpp:115
bool isClassScope() const
isClassScope - Return true if this scope is a class/struct/union scope.
Definition: Scope.h:411
void incrementMSManglingNumber()
Definition: Scope.h:355
unsigned getFlags() const
getFlags - Return the flags for this scope.
Definition: Scope.h:262
bool isDeclScope(const Decl *D) const
isDeclScope - Return true if this is the scope that the specified decl is declared in.
Definition: Scope.h:381
unsigned getMSLastManglingNumber() const
Definition: Scope.h:369
void dump() const
Definition: Scope.cpp:196
unsigned getMSCurManglingNumber() const
Definition: Scope.h:375
DeclContext * getEntity() const
Get the entity corresponding to this scope.
Definition: Scope.h:384
bool containedInPrototypeScope() const
containedInPrototypeScope - Return true if this or a parent scope is a FunctionPrototypeScope.
Definition: Scope.cpp:105
const Scope * getParent() const
getParent - Return the scope that this is nested in.
Definition: Scope.h:270
void updateNRVOCandidate(VarDecl *VD)
Definition: Scope.cpp:136
void dumpImpl(raw_ostream &OS) const
Definition: Scope.cpp:198
void applyNRVO()
Definition: Scope.cpp:165
@ OpenMPDirectiveScope
This is the scope of OpenMP executable directive.
Definition: Scope.h:111
@ FunctionPrototypeScope
This is a scope that corresponds to the parameters within a function prototype.
Definition: Scope.h:85
@ OpenMPOrderClauseScope
This is a scope of some OpenMP directive with order clause which specifies concurrent.
Definition: Scope.h:150
@ LambdaScope
This is the scope for a lambda, after the lambda introducer.
Definition: Scope.h:155
@ BlockScope
This is a scope that corresponds to a block/closure object.
Definition: Scope.h:75
@ SEHTryScope
This scope corresponds to an SEH try.
Definition: Scope.h:125
@ FriendScope
This is a scope of friend declaration.
Definition: Scope.h:164
@ ContinueScope
This is a while, do, for, which can have continue statements embedded into it.
Definition: Scope.h:59
@ OpenACCComputeConstructScope
This is the scope of an OpenACC Compute Construct, which restricts jumping into/out of it.
Definition: Scope.h:158
@ ControlScope
The controlling scope in a if/switch/while/for statement.
Definition: Scope.h:66
@ ClassInheritanceScope
We are between inheritance colon and the real class/struct definition scope.
Definition: Scope.h:138
@ AtCatchScope
This is a scope that corresponds to the Objective-C @catch statement.
Definition: Scope.h:95
@ TemplateParamScope
This is a scope that corresponds to the template parameters of a C++ template.
Definition: Scope.h:81
@ SEHFilterScope
We are currently in the filter expression of an SEH except block.
Definition: Scope.h:131
@ SwitchScope
This is a scope that corresponds to a switch statement.
Definition: Scope.h:102
@ BreakScope
This is a while, do, switch, for, etc that can have break statements embedded into it.
Definition: Scope.h:55
@ CatchScope
This is the scope of a C++ catch statement.
Definition: Scope.h:141
@ CompoundStmtScope
This is a compound statement scope.
Definition: Scope.h:134
@ FnTryCatchScope
This is the scope for a function-level C++ try or catch scope.
Definition: Scope.h:108
@ SEHExceptScope
This scope corresponds to an SEH except.
Definition: Scope.h:128
@ ClassScope
The scope of a struct/union/class definition.
Definition: Scope.h:69
@ TryScope
This is the scope of a C++ try statement.
Definition: Scope.h:105
@ OpenMPSimdDirectiveScope
This is the scope of some OpenMP simd directive.
Definition: Scope.h:119
@ FunctionDeclarationScope
This is a scope that corresponds to the parameters within a function prototype for a function declara...
Definition: Scope.h:91
@ FnScope
This indicates that the scope corresponds to a function, which means that labels are set here.
Definition: Scope.h:51
@ ObjCMethodScope
This scope corresponds to an Objective-C method body.
Definition: Scope.h:99
@ EnumScope
This scope corresponds to an enum.
Definition: Scope.h:122
@ OpenMPLoopDirectiveScope
This is the scope of some OpenMP loop directive.
Definition: Scope.h:114
@ DeclScope
This is a scope that can contain a declaration.
Definition: Scope.h:63
Represents a variable declaration or definition.
Definition: Decl.h:919
The JSON file list parser is used to communicate input to InstallAPI.