Scope.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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. #include "clang/Sema/Scope.h"
  14. #include "clang/AST/Decl.h"
  15. #include "llvm/Support/raw_ostream.h"
  16. using namespace clang;
  17. void Scope::setFlags(Scope *parent, unsigned flags) {
  18. AnyParent = parent;
  19. Flags = flags;
  20. if (parent && !(flags & FnScope)) {
  21. BreakParent = parent->BreakParent;
  22. ContinueParent = parent->ContinueParent;
  23. } else {
  24. // Control scopes do not contain the contents of nested function scopes for
  25. // control flow purposes.
  26. BreakParent = ContinueParent = nullptr;
  27. }
  28. if (parent) {
  29. Depth = parent->Depth + 1;
  30. PrototypeDepth = parent->PrototypeDepth;
  31. PrototypeIndex = 0;
  32. FnParent = parent->FnParent;
  33. BlockParent = parent->BlockParent;
  34. TemplateParamParent = parent->TemplateParamParent;
  35. MSLastManglingParent = parent->MSLastManglingParent;
  36. MSCurManglingNumber = getMSLastManglingNumber();
  37. if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
  38. FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
  39. 0)
  40. Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
  41. // transmit the parent's 'order' flag, if exists
  42. if (parent->getFlags() & OpenMPOrderClauseScope)
  43. Flags |= OpenMPOrderClauseScope;
  44. } else {
  45. Depth = 0;
  46. PrototypeDepth = 0;
  47. PrototypeIndex = 0;
  48. MSLastManglingParent = FnParent = BlockParent = nullptr;
  49. TemplateParamParent = nullptr;
  50. MSLastManglingNumber = 1;
  51. MSCurManglingNumber = 1;
  52. }
  53. // If this scope is a function or contains breaks/continues, remember it.
  54. if (flags & FnScope) FnParent = this;
  55. // The MS mangler uses the number of scopes that can hold declarations as
  56. // part of an external name.
  57. if (Flags & (ClassScope | FnScope)) {
  58. MSLastManglingNumber = getMSLastManglingNumber();
  59. MSLastManglingParent = this;
  60. MSCurManglingNumber = 1;
  61. }
  62. if (flags & BreakScope) BreakParent = this;
  63. if (flags & ContinueScope) ContinueParent = this;
  64. if (flags & BlockScope) BlockParent = this;
  65. if (flags & TemplateParamScope) TemplateParamParent = this;
  66. // If this is a prototype scope, record that.
  67. if (flags & FunctionPrototypeScope) PrototypeDepth++;
  68. if (flags & DeclScope) {
  69. if (flags & FunctionPrototypeScope)
  70. ; // Prototype scopes are uninteresting.
  71. else if ((flags & ClassScope) && getParent()->isClassScope())
  72. ; // Nested class scopes aren't ambiguous.
  73. else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)
  74. ; // Classes inside of namespaces aren't ambiguous.
  75. else if ((flags & EnumScope))
  76. ; // Don't increment for enum scopes.
  77. else
  78. incrementMSManglingNumber();
  79. }
  80. }
  81. void Scope::Init(Scope *parent, unsigned flags) {
  82. setFlags(parent, flags);
  83. DeclsInScope.clear();
  84. UsingDirectives.clear();
  85. Entity = nullptr;
  86. ErrorTrap.reset();
  87. NRVO = std::nullopt;
  88. }
  89. bool Scope::containedInPrototypeScope() const {
  90. const Scope *S = this;
  91. while (S) {
  92. if (S->isFunctionPrototypeScope())
  93. return true;
  94. S = S->getParent();
  95. }
  96. return false;
  97. }
  98. void Scope::AddFlags(unsigned FlagsToSet) {
  99. assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
  100. "Unsupported scope flags");
  101. if (FlagsToSet & BreakScope) {
  102. assert((Flags & BreakScope) == 0 && "Already set");
  103. BreakParent = this;
  104. }
  105. if (FlagsToSet & ContinueScope) {
  106. assert((Flags & ContinueScope) == 0 && "Already set");
  107. ContinueParent = this;
  108. }
  109. Flags |= FlagsToSet;
  110. }
  111. // The algorithm for updating NRVO candidate is as follows:
  112. // 1. All previous candidates become invalid because a new NRVO candidate is
  113. // obtained. Therefore, we need to clear return slots for other
  114. // variables defined before the current return statement in the current
  115. // scope and in outer scopes.
  116. // 2. Store the new candidate if its return slot is available. Otherwise,
  117. // there is no NRVO candidate so far.
  118. void Scope::updateNRVOCandidate(VarDecl *VD) {
  119. auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
  120. bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
  121. // We found a candidate variable that can be put into a return slot.
  122. // Clear the set, because other variables cannot occupy a return
  123. // slot in the same scope.
  124. S->ReturnSlots.clear();
  125. if (IsReturnSlotFound)
  126. S->ReturnSlots.insert(VD);
  127. return IsReturnSlotFound;
  128. };
  129. bool CanBePutInReturnSlot = false;
  130. for (auto *S = this; S; S = S->getParent()) {
  131. CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
  132. if (S->getEntity())
  133. break;
  134. }
  135. // Consider the variable as NRVO candidate if the return slot is available
  136. // for it in the current scope, or if it can be available in outer scopes.
  137. NRVO = CanBePutInReturnSlot ? VD : nullptr;
  138. }
  139. void Scope::applyNRVO() {
  140. // There is no NRVO candidate in the current scope.
  141. if (!NRVO.has_value())
  142. return;
  143. if (*NRVO && isDeclScope(*NRVO))
  144. (*NRVO)->setNRVOVariable(true);
  145. // It's necessary to propagate NRVO candidate to the parent scope for cases
  146. // when the parent scope doesn't contain a return statement.
  147. // For example:
  148. // X foo(bool b) {
  149. // X x;
  150. // if (b)
  151. // return x;
  152. // exit(0);
  153. // }
  154. // Also, we need to propagate nullptr value that means NRVO is not
  155. // allowed in this scope.
  156. // For example:
  157. // X foo(bool b) {
  158. // X x;
  159. // if (b)
  160. // return x;
  161. // else
  162. // return X(); // NRVO is not allowed
  163. // }
  164. if (!getEntity())
  165. getParent()->NRVO = *NRVO;
  166. }
  167. LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
  168. void Scope::dumpImpl(raw_ostream &OS) const {
  169. unsigned Flags = getFlags();
  170. bool HasFlags = Flags != 0;
  171. if (HasFlags)
  172. OS << "Flags: ";
  173. std::pair<unsigned, const char *> FlagInfo[] = {
  174. {FnScope, "FnScope"},
  175. {BreakScope, "BreakScope"},
  176. {ContinueScope, "ContinueScope"},
  177. {DeclScope, "DeclScope"},
  178. {ControlScope, "ControlScope"},
  179. {ClassScope, "ClassScope"},
  180. {BlockScope, "BlockScope"},
  181. {TemplateParamScope, "TemplateParamScope"},
  182. {FunctionPrototypeScope, "FunctionPrototypeScope"},
  183. {FunctionDeclarationScope, "FunctionDeclarationScope"},
  184. {AtCatchScope, "AtCatchScope"},
  185. {ObjCMethodScope, "ObjCMethodScope"},
  186. {SwitchScope, "SwitchScope"},
  187. {TryScope, "TryScope"},
  188. {FnTryCatchScope, "FnTryCatchScope"},
  189. {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
  190. {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
  191. {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
  192. {EnumScope, "EnumScope"},
  193. {SEHTryScope, "SEHTryScope"},
  194. {SEHExceptScope, "SEHExceptScope"},
  195. {SEHFilterScope, "SEHFilterScope"},
  196. {CompoundStmtScope, "CompoundStmtScope"},
  197. {ClassInheritanceScope, "ClassInheritanceScope"},
  198. {CatchScope, "CatchScope"},
  199. };
  200. for (auto Info : FlagInfo) {
  201. if (Flags & Info.first) {
  202. OS << Info.second;
  203. Flags &= ~Info.first;
  204. if (Flags)
  205. OS << " | ";
  206. }
  207. }
  208. assert(Flags == 0 && "Unknown scope flags");
  209. if (HasFlags)
  210. OS << '\n';
  211. if (const Scope *Parent = getParent())
  212. OS << "Parent: (clang::Scope*)" << Parent << '\n';
  213. OS << "Depth: " << Depth << '\n';
  214. OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
  215. OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
  216. if (const DeclContext *DC = getEntity())
  217. OS << "Entity : (clang::DeclContext*)" << DC << '\n';
  218. if (!NRVO)
  219. OS << "there is no NRVO candidate\n";
  220. else if (*NRVO)
  221. OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
  222. else
  223. OS << "NRVO is not allowed\n";
  224. }