brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · e66cce2 Raw
271 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the Scope class, which is used for recording10// 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 18using namespace clang;19 20void 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 for29    // 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 |44                  FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==45        0)46      Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;47    // transmit the parent's 'order' flag, if exists48    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 as64  // 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 prototype76  // 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    else91      incrementMSManglingNumber();92  }93}94 95void Scope::Init(Scope *parent, unsigned flags) {96  setFlags(parent, flags);97 98  DeclsInScope.clear();99  UsingDirectives.clear();100  Entity = nullptr;101  ErrorTrap.reset();102  PrecedingLabel = nullptr;103  NRVO = std::nullopt;104}105 106bool Scope::containedInPrototypeScope() const {107  const Scope *S = this;108  while (S) {109    if (S->isFunctionPrototypeScope())110      return true;111    S = S->getParent();112  }113  return false;114}115 116void Scope::AddFlags(unsigned FlagsToSet) {117  assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&118         "Unsupported scope flags");119  if (FlagsToSet & BreakScope) {120    assert((Flags & BreakScope) == 0 && "Already set");121    BreakParent = this;122  }123  if (FlagsToSet & ContinueScope) {124    assert((Flags & ContinueScope) == 0 && "Already set");125    ContinueParent = this;126  }127  Flags |= FlagsToSet;128}129 130// The algorithm for updating NRVO candidate is as follows:131//   1. All previous candidates become invalid because a new NRVO candidate is132//      obtained. Therefore, we need to clear return slots for other133//      variables defined before the current return statement in the current134//      scope and in outer scopes.135//   2. Store the new candidate if its return slot is available. Otherwise,136//      there is no NRVO candidate so far.137void Scope::updateNRVOCandidate(VarDecl *VD) {138  auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {139    bool IsReturnSlotFound = S->ReturnSlots.contains(VD);140 141    // We found a candidate variable that can be put into a return slot.142    // Clear the set, because other variables cannot occupy a return143    // slot in the same scope.144    S->ReturnSlots.clear();145 146    if (IsReturnSlotFound)147      S->ReturnSlots.insert(VD);148 149    return IsReturnSlotFound;150  };151 152  bool CanBePutInReturnSlot = false;153 154  for (auto *S = this; S; S = S->getParent()) {155    CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);156 157    if (S->getEntity())158      break;159  }160 161  // Consider the variable as NRVO candidate if the return slot is available162  // for it in the current scope, or if it can be available in outer scopes.163  NRVO = CanBePutInReturnSlot ? VD : nullptr;164}165 166void Scope::applyNRVO() {167  // There is no NRVO candidate in the current scope.168  if (!NRVO.has_value())169    return;170 171  if (*NRVO && isDeclScope(*NRVO))172    (*NRVO)->setNRVOVariable(true);173 174  // It's necessary to propagate NRVO candidate to the parent scope for cases175  // when the parent scope doesn't contain a return statement.176  // For example:177  //    X foo(bool b) {178  //      X x;179  //      if (b)180  //        return x;181  //      exit(0);182  //    }183  // Also, we need to propagate nullptr value that means NRVO is not184  // allowed in this scope.185  // For example:186  //    X foo(bool b) {187  //      X x;188  //      if (b)189  //        return x;190  //      else191  //        return X(); // NRVO is not allowed192  //    }193  if (!getEntity())194    getParent()->NRVO = *NRVO;195}196 197LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }198 199void Scope::dumpImpl(raw_ostream &OS) const {200  unsigned Flags = getFlags();201  bool HasFlags = Flags != 0;202 203  if (HasFlags)204    OS << "Flags: ";205 206  std::pair<unsigned, const char *> FlagInfo[] = {207      {FnScope, "FnScope"},208      {BreakScope, "BreakScope"},209      {ContinueScope, "ContinueScope"},210      {DeclScope, "DeclScope"},211      {ControlScope, "ControlScope"},212      {ClassScope, "ClassScope"},213      {BlockScope, "BlockScope"},214      {TemplateParamScope, "TemplateParamScope"},215      {FunctionPrototypeScope, "FunctionPrototypeScope"},216      {FunctionDeclarationScope, "FunctionDeclarationScope"},217      {AtCatchScope, "AtCatchScope"},218      {ObjCMethodScope, "ObjCMethodScope"},219      {SwitchScope, "SwitchScope"},220      {TryScope, "TryScope"},221      {FnTryCatchScope, "FnTryCatchScope"},222      {OpenMPDirectiveScope, "OpenMPDirectiveScope"},223      {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},224      {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},225      {EnumScope, "EnumScope"},226      {SEHTryScope, "SEHTryScope"},227      {SEHExceptScope, "SEHExceptScope"},228      {SEHFilterScope, "SEHFilterScope"},229      {CompoundStmtScope, "CompoundStmtScope"},230      {ClassInheritanceScope, "ClassInheritanceScope"},231      {CatchScope, "CatchScope"},232      {ConditionVarScope, "ConditionVarScope"},233      {OpenMPOrderClauseScope, "OpenMPOrderClauseScope"},234      {LambdaScope, "LambdaScope"},235      {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},236      {TypeAliasScope, "TypeAliasScope"},237      {FriendScope, "FriendScope"},238      {OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},239      {OpenACCLoopConstructScope, "OpenACCLoopConstructScope"}};240 241  for (auto Info : FlagInfo) {242    if (Flags & Info.first) {243      OS << Info.second;244      Flags &= ~Info.first;245      if (Flags)246        OS << " | ";247    }248  }249 250  assert(Flags == 0 && "Unknown scope flags");251 252  if (HasFlags)253    OS << '\n';254 255  if (const Scope *Parent = getParent())256    OS << "Parent: (clang::Scope*)" << Parent << '\n';257 258  OS << "Depth: " << Depth << '\n';259  OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';260  OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';261  if (const DeclContext *DC = getEntity())262    OS << "Entity : (clang::DeclContext*)" << DC << '\n';263 264  if (!NRVO)265    OS << "there is no NRVO candidate\n";266  else if (*NRVO)267    OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';268  else269    OS << "NRVO is not allowed\n";270}271