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

Code before:
                 param->getName());
      }
    }
    if (functionKind != EscapingAutoClosure) {
      emittedError = true;
      diagnoseCaptureLoc(Context, DC, PAI, inoutCapture);
      continue;
    }
    // For an autoclosure capture, present a way to fix the problem.
    if (paramName) {
      emittedError = true;
      diagnose(Context, PAI->getLoc(), diag::copy_inout_captured_by_autoclosure,
               paramName.value());
    } else {
      emittedError = true;
      diagnose(Context, PAI->getLoc(), diag::copy_self_captured_by_autoclosure);
    }
  }

  // Finally, diagnose captures of values with noescape type.
  for (auto noEscapeCapture : noEscapeCaptures) {
    if (auto *param = getParamDeclFromOperand(noEscapeCapture->get())) {
      emittedError = true;
      diagnose(Context, PAI->getLoc(), diag::escaping_noescape_param_capture,
               functionKind, param->getName());
      diagnose(Context, param->getLoc(), diag::noescape_param_defined_here,
               param->getName());
    } else {
      emittedError = true;
      diagnose(Context, PAI->getLoc(), diag::escaping_noescape_var_capture,
               functionKind);
    }

    diagnoseCaptureLoc(Context, DC, PAI, noEscapeCapture);
  }

  // If we emitted an error, mark the closure function as not being suitable for
  // noncopyable diagnostics. The user can fix the issue and then recompile.
  if (emittedError) {
    if (auto *f = apply.getCalleeFunction()) {
      auto s = semantics::NO_MOVEONLY_DIAGNOSTICS;
      f->addSemanticsAttr(s);
    }
  }
}

// Enforce exclusivity restrictions on recursive uses of non-escaping closures.
// Exclusivity requires a Non-Escaping Recursion Restriction rule (SE-0176):
// A non-escaping closure A may not be recursively invoked during the
// execution of a non-escaping closure B which captures the same local
// variable or inout parameter unless:

Review comment (suggestion):
Can you add a small SIL example showing this. It will add clarity. Something like:

E.x.:

```
%param = ...
%address = pack_element_get %param
pack_element_set ...
... *snip * ...
$REST_OF_PATTERN_MATCH
```

this is especially important in your patch since you do not have any SIL test cases (I know why since the pass is not that amenable in its current form due to the way it uses the AST). Putting the examples in code will make it easier to maintain in the future.

Code after:
        uselistInsert(use);
      continue;
    }

    // Look through copies, borrows, and conversions.
    if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
      // Only follow the copied operand. Other operands are incidental,
      // as in the second operand of mark_dependence.
      if (oper->getOperandNumber() == 0) {
        for (auto *use : copy->getUses())
          uselistInsert(use);
        continue;
      }
    }

    // If the usage is a capture of the value by another closure, look inside
    // the body of that closure.
    if (auto site = ApplySite::isa(user)) {
      if (lookInsideClosure(site, oper)) {
        diagnose(Context, site.getLoc(), diag::value_captured_transitively);
        continue;
      }
    }

    // Look through indirect pack references. A function with a pack parameter
    // will get the address, set the pack, and later get and load the pack. We
    // want to follow this indirection until the load, so we can diagnose where
    // the pack is used, like `repeat each x`.
    //
    // %12 = tuple_pack_element_addr %10 of %1 // user: %13
    // pack_element_set %12 into %10 of %2 // id: %13
    // ^ find the users of that pack
    // %26 = pack_element_get %24 of %2 // user: %27
    // %27 = load [copy] %26 // users: %29, %28
    // ^ diagnose at this instruction
    if (auto *svi = dyn_cast<SingleValueInstruction>(user)) {
      if (isa<TuplePackElementAddrInst>(user) ||
          isa<PackElementGetInst>(user)) {
        for (auto *use : svi->getUses())
          uselistInsert(use);
        continue;
      }
    }

    // Follow the uses of the pack that is set, to discover get/load
    // instructions
    if (auto *packElemSetInst = dyn_cast<PackElementSetInst>(user)) {
      for (auto *use : packElemSetInst->getPack()->getUses()) {
        uselistInsert(use);
      }
      continue;