Repository: apple/swift
File: lib/SILOptimizer/Mandatory/DiagnoseInvalidEscapingCaptures.cpp (C++)

Code before:
         "Invalid capture in function with no source location information");

  SmallVector<Operand *, 8> uses;
  llvm::SmallDenseSet<Operand *, 8> visited;
  auto uselistInsert = [&](Operand *operand) {
    if (visited.insert(operand).second)
      uses.push_back(operand);
  };

  auto lookInsideClosure = [&](ApplySite site, Operand *oper) -> bool {
    auto *F = site.getCalleeFunction();
    if (F == nullptr || F->empty())
      return false;

    auto *otherDC = F->getDeclContext();
    if (otherDC == nullptr || DC == nullptr ||
        !otherDC->isChildContextOf(DC))
      return false;

    // Map an operand of an apply instruction to an argument inside
    // the callee.
    auto args = F->getArguments();
    auto argIndex = site.getCalleeArgIndex(*oper);
    auto arg = args[argIndex];

    // Look for a usage of the callee argument.
    for (Operand *use : arg->getUses())
      uselistInsert(use);

    return true;
  };

  lookInsideClosure(PAI, oper);

  while (!uses.empty()) {
    Operand *oper = uses.pop_back_val();
    SILInstruction *user = oper->getUser();

    // Look through copy_value.
    if (auto *ci = dyn_cast<CopyValueInst>(user)) {
      for (auto *use : ci->getUses()) {
        uselistInsert(use);
      }
      continue;
    }

    if (isIncidentalUse(user) || onlyAffectsRefCount(user) ||
        isa<DeallocationInst>(user) || isa<DestroyAddrInst>(user))
      continue;

    // Look through mark must check inst.

Review comment (suggestion):
I think that you need additional comments here explaining the arg part of this. The reason why is that this is walking from def->use. But here you are going from a use (the tuple pack element adds) to a def (the operand).

I would explain what pattern you are matching and perhaps that this is one of the patterns that you are searching for. I would even include some examples of this pattern and other patterns in the top level comment to provide extra clarity. It will make it clearer for future readers of the code.

Code after:
    // Follow the source of copy addr.
    if (auto *copyAddr = dyn_cast<CopyAddrInst>(inst)) {
      if (auto *src = copyAddr->getSrc()->getDefiningInstruction())
        worklist.pushIfNotVisited(src);
      continue;
    }

    // Follow the source of load inst.
    if (auto *load = dyn_cast<LoadInst>(inst)) {
      if (auto *src = load->getOperand()->getDefiningInstruction())
        worklist.pushIfNotVisited(src);
      continue;
    }

    // Follow the value of a pack set, ideally to a tuple pack element addr
    // inst.
    if (auto *packElemSet = dyn_cast<PackElementSetInst>(inst)) {
      if (auto *valueDef = packElemSet->getValue()->getDefiningInstruction())
        worklist.pushIfNotVisited(valueDef);
      continue;
    }

    // TuplePackElementAddrInst may have a function argument as its tuple
    // operand's definition. Otherwise, follow the users of the address.
    if (auto *tuplePackElemAddr = dyn_cast<TuplePackElementAddrInst>(inst)) {
      if (auto *arg = dyn_cast<SILArgument>(tuplePackElemAddr->getTuple())) {
        return arg;
      }
      worklist.pushInstructionsIfNotVisited(tuplePackElemAddr->getUsers());
      continue;
    }

    // PackElementGetInst may have a function argument as its pack operand's
    // definition. Otherwise, follow to the definition of the pack.
    if (auto *packElemGet = dyn_cast<PackElementGetInst>(inst)) {
      if (auto *arg = dyn_cast<SILArgument>(packElemGet->getPack())) {
        return arg;
      }
      if (auto *packDef = packElemGet->getPack()->getDefiningInstruction())
        worklist.pushIfNotVisited(packDef);
      continue;
    }
  }

  return SILValue();
}

const ParamDecl *getParamDeclFromOperand(SILValue value) {
  while (true) {
    // Look through mark must check.
    if (auto *mmci = dyn_cast<MarkUnresolvedNonCopyableValueInst>(value)) {