text: //=- LiveVariables.cpp - Live Variable Analysis for Source CFGs ----------*-==//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  //
  // This file implements Live Variables analysis for source-level CFGs.
  //
  //===----------------------------------------------------------------------===//
  
  #include "clang/Analysis/Analyses/LiveVariables.h"
  #include "clang/AST/Stmt.h"
  #include "clang/AST/StmtVisitor.h"
  #include "clang/Analysis/AnalysisDeclContext.h"
  #include "clang/Analysis/CFG.h"
  #include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
  #include "llvm/ADT/DenseMap.h"
  #include "llvm/Support/raw_ostream.h"
  #include <algorithm>
  #include <vector>
  
  using namespace clang;
  
  namespace {
  class LiveVariablesImpl {
  public:
    AnalysisDeclContext &analysisContext;
    llvm::ImmutableSet<const Stmt *>::Factory SSetFact;
    llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
    llvm::ImmutableSet<const BindingDecl *>::Factory BSetFact;
    llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
    llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness;
    llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness;
    llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment;
    const bool killAtAssign;
  
    LiveVariables::LivenessValues
    merge(LiveVariables::LivenessValues valsA,
          LiveVariables::LivenessValues valsB);
  
    LiveVariables::LivenessValues
    runOnBlock(const CFGBlock *block, LiveVariables::LivenessValues val,
               LiveVariables::Observer *obs = nullptr);
  
    void dumpBlockLiveness(const SourceManager& M);
    void dumpStmtLiveness(const SourceManager& M);
  
    LiveVariablesImpl(AnalysisDeclContext &ac, bool KillAtAssign)
      : analysisContext(ac),
        SSetFact(false), // Do not canonicalize ImmutableSets by default.
        DSetFact(false), // This is a *major* performance win.
        BSetFact(false),
        killAtAssign(KillAtAssign) {}
  };
  }
  
  static LiveVariablesImpl &getImpl(void *x) {
    return *((LiveVariablesImpl *) x);
  }
  
  //===----------------------------------------------------------------------===//
  // Operations and queries on LivenessValues.
  //===----------------------------------------------------------------------===//
  
  bool LiveVariables::LivenessValues::isLive(const Stmt *S) const {
    return liveStmts.contains(S);
  }
  
  bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const {
    if (const auto *DD = dyn_cast<DecompositionDecl>(D)) {
      bool alive = false;
      for (const BindingDecl *BD : DD->bindings())
        alive |= liveBindings.contains(BD);
      return alive;
    }
    return liveDecls.contains(D);
  }
  
  namespace {
    template <typename SET>
    SET mergeSets(SET A, SET B) {
      if (A.isEmpty())
        return B;
  
      for (typename SET::iterator it = B.begin(), ei = B.end(); it != ei; ++it) {
        A = A.add(*it);
      }
      return A;
    }
  } // namespace
  
  void LiveVariables::Observer::anchor() { }
  
  LiveVariables::LivenessValues
  LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA,
                           LiveVariables::LivenessValues valsB) {
  
    llvm::ImmutableSetRef<const Stmt *>
      SSetRefA(valsA.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()),
      SSetRefB(valsB.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory());
  
  
    llvm::ImmutableSetRef<const VarDecl *>
      DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()),
      DSetRefB(valsB.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory());
  
    llvm::ImmutableSetRef<const BindingDecl *>
      BSetRefA(valsA.liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory()),
      BSetRefB(valsB.liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory());
  
    SSetRefA = mergeSets(SSetRefA, SSetRefB);
    DSetRefA = mergeSets(DSetRefA, DSetRefB);
    BSetRefA = mergeSets(BSetRefA, BSetRefB);
  
    // asImmutableSet() canonicalizes the tree, allowing us to do an easy
    // comparison afterwards.
    return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(),
                                         DSetRefA.asImmutableSet(),
                                         BSetRefA.asImmutableSet());
  }
  
  bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const {
    return liveStmts == V.liveStmts && liveDecls == V.liveDecls;
  }
  
  //===----------------------------------------------------------------------===//
  // Query methods.
  //===----------------------------------------------------------------------===//
  
  static bool isAlwaysAlive(const VarDecl *D) {
    return D->hasGlobalStorage();
  }
  
  bool LiveVariables::isLive(const CFGBlock *B, const VarDecl *D) {
    return isAlwaysAlive(D) || getImpl(impl).blocksEndToLiveness[B].isLive(D);
  }
  
  bool LiveVariables::isLive(const Stmt *S, const VarDecl *D) {
    return isAlwaysAlive(D) || getImpl(impl).stmtsToLiveness[S].isLive(D);
  }
  
  bool LiveVariables::isLive(const Stmt *Loc, const Stmt *S) {
    return getImpl(impl).stmtsToLiveness[Loc].isLive(S);
  }
  
  //===----------------------------------------------------------------------===//
  // Dataflow computation.
  //===----------------------------------------------------------------------===//
  
  namespace {
  class TransferFunctions : public StmtVisitor<TransferFunctions> {
    LiveVariablesImpl &LV;
    LiveVariables::LivenessValues &val;
    LiveVariables::Observer *observer;
    const CFGBlock *currentBlock;
  public:
    TransferFunctions(LiveVariablesImpl &im,
                      LiveVariables::LivenessValues &Val,
                      LiveVariables::Observer *Observer,
                      const CFGBlock *CurrentBlock)
    : LV(im), val(Val), observer(Observer), currentBlock(CurrentBlock) {}
  
    void VisitBinaryOperator(BinaryOperator *BO);
    void VisitBlockExpr(BlockExpr *BE);
    void VisitDeclRefExpr(DeclRefExpr *DR);
    void VisitDeclStmt(DeclStmt *DS);
    void VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS);
    void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE);
    void VisitUnaryOperator(UnaryOperator *UO);
    void Visit(Stmt *S);
  };
  } // namespace
  
  static const VariableArrayType *FindVA(QualType Ty) {
    const Type *ty = Ty.getTypePtr();
    while (const ArrayType *VT = dyn_cast<ArrayType>(ty)) {
      if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(VT))
        if (VAT->getSizeExpr())
          return VAT;
  
      ty = VT->getElementType().getTypePtr();
    }
  
    return nullptr;
  }
  
  static const Stmt *LookThroughStmt(const Stmt *S) {
    while (S) {
      if (const Expr *Ex = dyn_cast<Expr>(S))
        S = Ex->IgnoreParens();
      if (const FullExpr *FE = dyn_cast<FullExpr>(S)) {
        S = FE->getSubExpr();
        continue;
      }
      if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) {
        S = OVE->getSourceExpr();
        continue;
      }
      break;
    }
    return S;
  }
  
  static void AddLiveStmt(llvm::ImmutableSet<const Stmt *> &Set,
                          llvm::ImmutableSet<const Stmt *>::Factory &F,
                          const Stmt *S) {
    Set = F.add(Set, LookThroughStmt(S));
  }
  
  void TransferFunctions::Visit(Stmt *S) {
    if (observer)
      observer->observeStmt(S, currentBlock, val);
  
    StmtVisitor<TransferFunctions>::Visit(S);
  
    if (isa<Expr>(S)) {
      val.liveStmts = LV.SSetFact.remove(val.liveStmts, S);
    }
  
    // Mark all children expressions live.
  
    switch (S->getStmtClass()) {
      default:
        break;
      case Stmt::StmtExprClass: {
        // For statement expressions, look through the compound statement.
        S = cast<StmtExpr>(S)->getSubStmt();
        break;
      }
      case Stmt::CXXMemberCallExprClass: {
        // Include the implicit "this" pointer as being live.
        CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S);
        if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) {
          AddLiveStmt(val.liveStmts, LV.SSetFact, ImplicitObj);
        }
        break;
      }
      case Stmt::ObjCMessageExprClass: {
        // In calls to super, include the implicit "self" pointer as being live.
        ObjCMessageExpr *CE = cast<ObjCMessageExpr>(S);
        if (CE->getReceiverKind() == ObjCMessageExpr::SuperInstance)
          val.liveDecls = LV.DSetFact.add(val.liveDecls,
                                          LV.analysisContext.getSelfDecl());
        break;
      }
      case Stmt::DeclStmtClass: {
        const DeclStmt *DS = cast<DeclStmt>(S);
        if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) {
          for (const VariableArrayType* VA = FindVA(VD->getType());
               VA != nullptr; VA = FindVA(VA->getElementType())) {
            AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr());
          }
        }
        break;
      }
      case Stmt::PseudoObjectExprClass: {
        // A pseudo-object operation only directly consumes its result
        // expression.
        Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr();
        if (!child) return;
        if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
          child = OV->getSourceExpr();
        child = child->IgnoreParens();
        val.liveStmts = LV.SSetFact.add(val.liveStmts, child);
        return;
      }
  
      // FIXME: These cases eventually shouldn't be needed.
      case Stmt::ExprWithCleanupsClass: {
        S = cast<ExprWithCleanups>(S)->getSubExpr();
        break;
      }
      case Stmt::CXXBindTemporaryExprClass: {
        S = cast<CXXBindTemporaryExpr>(S)->getSubExpr();
        break;
      }
      case Stmt::UnaryExprOrTypeTraitExprClass: {
        // No need to unconditionally visit subexpressions.
        return;
      }
      case Stmt::IfStmtClass: {
        // If one of the branches is an expression rather than a compound
        // statement, it will be bad if we mark it as live at the terminator
        // of the if-statement (i.e., immediately after the condition expression).
        AddLiveStmt(val.liveStmts, LV.SSetFact, cast<IfStmt>(S)->getCond());
        return;
      }
      case Stmt::WhileStmtClass: {
        // If the loop body is an expression rather than a compound statement,
        // it will be bad if we mark it as live at the terminator of the loop
        // (i.e., immediately after the condition expression).
        AddLiveStmt(val.liveStmts, LV.SSetFact, cast<WhileStmt>(S)->getCond());
        return;
      }
      case Stmt::DoStmtClass: {
        // If the loop body is an expression rather than a compound statement,
        // it will be bad if we mark it as live at the terminator of the loop
        // (i.e., immediately after the condition expression).
        AddLiveStmt(val.liveStmts, LV.SSetFact, cast<DoStmt>(S)->getCond());
        return;
      }
      case Stmt::ForStmtClass: {
        // If the loop body is an expression rather than a compound statement,
        // it will be bad if we mark it as live at the terminator of the loop
        // (i.e., immediately after the condition expression).
        AddLiveStmt(val.liveStmts, LV.SSetFact, cast<ForStmt>(S)->getCond());
        return;
      }
  
    }
  
    for (Stmt *Child : S->children()) {
      if (Child)
        AddLiveStmt(val.liveStmts, LV.SSetFact, Child);
    }
  }
  
  static bool writeShouldKill(const VarDecl *VD) {
    return VD && !VD->getType()->isReferenceType() &&
      !isAlwaysAlive(VD);
  }
  
  void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
    if (B->isAssignmentOp()) {
      if (!LV.killAtAssign)
        return;
  
      // Assigning to a variable?
      Expr *LHS = B->getLHS()->IgnoreParens();
  
      if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
        const Decl* D = DR->getDecl();
        bool Killed = false;
  
        if (const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
          Killed = !BD->getType()->isReferenceType();
          if (Killed)
            val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
        } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
          Killed = writeShouldKill(VD);
          if (Killed)
            val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
  
        }
  
        if (Killed && observer)
          observer->observerKill(DR);
      }
    }
  }
  
  void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
    for (const VarDecl *VD :
         LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl())) {
      if (isAlwaysAlive(VD))
        continue;
      val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
    }
  }
  
  void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
    const Decl* D = DR->getDecl();
    bool InAssignment = LV.inAssignment[DR];
    if (const auto *BD = dyn_cast<BindingDecl>(D)) {
      if (!InAssignment)
        val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
    } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
      if (!InAssignment && !isAlwaysAlive(VD))
        val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
    }
  }
  
  void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
    for (const auto *DI : DS->decls()) {
      if (const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
        for (const auto *BD : DD->bindings())
          val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
      } else if (const auto *VD = dyn_cast<VarDecl>(DI)) {
        if (!isAlwaysAlive(VD))
          val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
      }
    }
  }
  
  void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
    // Kill the iteration variable.
    DeclRefExpr *DR = nullptr;
    const VarDecl *VD = nullptr;
  
    Stmt *element = OS->getElement();
    if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
      VD = cast<VarDecl>(DS->getSingleDecl());
    }
    else if ((DR = dyn_cast<DeclRefExpr>(cast<Expr>(element)->IgnoreParens()))) {
      VD = cast<VarDecl>(DR->getDecl());
    }
  
    if (VD) {
      val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
      if (observer && DR)
        observer->observerKill(DR);
    }
  }
  
  void TransferFunctions::
  VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE)
  {
    // While sizeof(var) doesn't technically extend the liveness of 'var', it
    // does extent the liveness of metadata if 'var' is a VariableArrayType.
    // We handle that special case here.
    if (UE->getKind() != UETT_SizeOf || UE->isArgumentType())
      return;
  
    const Expr *subEx = UE->getArgumentExpr();
    if (subEx->getType()->isVariableArrayType()) {
      assert(subEx->isLValue());
      val.liveStmts = LV.SSetFact.add(val.liveStmts, subEx->IgnoreParens());
    }
  }
  
  void TransferFunctions::VisitUnaryOperator(UnaryOperator *UO) {
    // Treat ++/-- as a kill.
    // Note we don't actually have to do anything if we don't have an observer,
    // since a ++/-- acts as both a kill and a "use".
    if (!observer)
      return;
  
    switch (UO->getOpcode()) {
    default:
      return;
    case UO_PostInc:
    case UO_PostDec:
    case UO_PreInc:
    case UO_PreDec:
      break;
    }
  
    if (auto *DR = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens())) {
      const Decl *D = DR->getDecl();
      if (isa<VarDecl>(D) || isa<BindingDecl>(D)) {
        // Treat ++/-- as a kill.
        observer->observerKill(DR);
      }
    }
  }
  
  LiveVariables::LivenessValues
  LiveVariablesImpl::runOnBlock(const CFGBlock *block,
                                LiveVariables::LivenessValues val,
                                LiveVariables::Observer *obs) {
  
    TransferFunctions TF(*this, val, obs, block);
  
    // Visit the terminator (if any).
    if (const Stmt *term = block->getTerminatorStmt())
      TF.Visit(const_cast<Stmt*>(term));
  
    // Apply the transfer function for all Stmts in the block.
    for (CFGBlock::const_reverse_iterator it = block->rbegin(),
         ei = block->rend(); it != ei; ++it) {
      const CFGElement &elem = *it;
  
      if (Optional<CFGAutomaticObjDtor> Dtor =
              elem.getAs<CFGAutomaticObjDtor>()) {
        val.liveDecls = DSetFact.add(val.liveDecls, Dtor->getVarDecl());
        continue;
      }
  
      if (!elem.getAs<CFGStmt>())
        continue;
  
      const Stmt *S = elem.castAs<CFGStmt>().getStmt();
      TF.Visit(const_cast<Stmt*>(S));
      stmtsToLiveness[S] = val;
    }
    return val;
  }
  
  void LiveVariables::runOnAllBlocks(LiveVariables::Observer &obs) {
    const CFG *cfg = getImpl(impl).analysisContext.getCFG();
    for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it)
      getImpl(impl).runOnBlock(*it, getImpl(impl).blocksEndToLiveness[*it], &obs);
  }
  
  LiveVariables::LiveVariables(void *im) : impl(im) {}
  
  LiveVariables::~LiveVariables() {
    delete (LiveVariablesImpl*) impl;
  }
  
  std::unique_ptr<LiveVariables>
  LiveVariables::computeLiveness(AnalysisDeclContext &AC, bool killAtAssign) {
  
    // No CFG?  Bail out.
    CFG *cfg = AC.getCFG();
    if (!cfg)
      return nullptr;
  
    // The analysis currently has scalability issues for very large CFGs.
    // Bail out if it looks too large.
    if (cfg->getNumBlockIDs() > 300000)
      return nullptr;
  
    LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign);
  
    // Construct the dataflow worklist.  Enqueue the exit block as the
    // start of the analysis.
    BackwardDataflowWorklist worklist(*cfg, AC);
    llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs());
  
    // FIXME: we should enqueue using post order.
    for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) {
      const CFGBlock *block = *it;
      worklist.enqueueBlock(block);
  
      // FIXME: Scan for DeclRefExprs using in the LHS of an assignment.
      // We need to do this because we lack context in the reverse analysis
      // to determine if a DeclRefExpr appears in such a context, and thus
      // doesn't constitute a "use".
      if (killAtAssign)
        for (CFGBlock::const_iterator bi = block->begin(), be = block->end();
             bi != be; ++bi) {
          if (Optional<CFGStmt> cs = bi->getAs<CFGStmt>()) {
            const Stmt* stmt = cs->getStmt();
            if (const auto *BO = dyn_cast<BinaryOperator>(stmt)) {
              if (BO->getOpcode() == BO_Assign) {
                if (const auto *DR =
                      dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) {
                  LV->inAssignment[DR] = 1;
                }
              }
            }
          }
        }
    }
  
    while (const CFGBlock *block = worklist.dequeue()) {
      // Determine if the block's end value has changed.  If not, we
      // have nothing left to do for this block.
      LivenessValues &prevVal = LV->blocksEndToLiveness[block];
  
      // Merge the values of all successor blocks.
      LivenessValues val;
      for (CFGBlock::const_succ_iterator it = block->succ_begin(),
                                         ei = block->succ_end(); it != ei; ++it) {
        if (const CFGBlock *succ = *it) {
          val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
        }
      }
  
      if (!everAnalyzedBlock[block->getBlockID()])
        everAnalyzedBlock[block->getBlockID()] = true;
      else if (prevVal.equals(val))
        continue;
  
      prevVal = val;
  
      // Update the dataflow value for the start of this block.
      LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
  
      // Enqueue the value to the predecessors.
      worklist.enqueuePredecessors(block);
    }
  
    return std::unique_ptr<LiveVariables>(new LiveVariables(LV));
  }
  
  void LiveVariables::dumpBlockLiveness(const SourceManager &M) {
    getImpl(impl).dumpBlockLiveness(M);
  }
  
  void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) {
    std::vector<const CFGBlock *> vec;
    for (llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues>::iterator
         it = blocksEndToLiveness.begin(), ei = blocksEndToLiveness.end();
         it != ei; ++it) {
      vec.push_back(it->first);
    }
    llvm::sort(vec, [](const CFGBlock *A, const CFGBlock *B) {
      return A->getBlockID() < B->getBlockID();
    });
  
    std::vector<const VarDecl*> declVec;
  
    for (std::vector<const CFGBlock *>::iterator
          it = vec.begin(), ei = vec.end(); it != ei; ++it) {
      llvm::errs() << "\n[ B" << (*it)->getBlockID()
                   << " (live variables at block exit) ]\n";
  
      LiveVariables::LivenessValues vals = blocksEndToLiveness[*it];
      declVec.clear();
  
      for (llvm::ImmutableSet<const VarDecl *>::iterator si =
            vals.liveDecls.begin(),
            se = vals.liveDecls.end(); si != se; ++si) {
        declVec.push_back(*si);
      }
  
      llvm::sort(declVec, [](const Decl *A, const Decl *B) {
        return A->getBeginLoc() < B->getBeginLoc();
      });
  
      for (std::vector<const VarDecl*>::iterator di = declVec.begin(),
           de = declVec.end(); di != de; ++di) {
        llvm::errs() << " " << (*di)->getDeclName().getAsString()
                     << " <";
        (*di)->getLocation().print(llvm::errs(), M);
        llvm::errs() << ">\n";
      }
    }
    llvm::errs() << "\n";
  }
  
  void LiveVariables::dumpStmtLiveness(const SourceManager &M) {
    getImpl(impl).dumpStmtLiveness(M);
  }
  
  void LiveVariablesImpl::dumpStmtLiveness(const SourceManager &M) {
    // Don't iterate over blockEndsToLiveness directly because it's not sorted.
    for (auto I : *analysisContext.getCFG()) {
  
      llvm::errs() << "\n[ B" << I->getBlockID()
                   << " (live statements at block exit) ]\n";
      for (auto S : blocksEndToLiveness[I].liveStmts) {
        llvm::errs() << "\n";
        S->dump();
      }
      llvm::errs() << "\n";
    }
  }
  
  const void *LiveVariables::getTag() { static int x; return &x; }
  const void *RelaxedLiveVariables::getTag() { static int x; return &x; }
  