Merge pull request #19038 from jckarter/mutating-opened-existential-covariant-return-4.2

[4.2] Fix order of operations when a mutating method invoked on an existential returns Self.
diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h
index c4ba230..fb21df8 100644
--- a/include/swift/SIL/SILType.h
+++ b/include/swift/SIL/SILType.h
@@ -492,6 +492,9 @@
   /// Returns the underlying referent SILType of an @sil_unowned or @sil_weak
   /// Type.
   SILType getReferentType(SILModule &M) const;
+  
+  /// Returns a SILType with any archetypes mapped out of context.
+  SILType mapTypeOutOfContext() const;
 
   /// Given two SIL types which are representations of the same type,
   /// check whether they have an abstraction difference.
diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp
index 7e5861d..6655705 100644
--- a/lib/IRGen/GenHeap.cpp
+++ b/lib/IRGen/GenHeap.cpp
@@ -1558,10 +1558,7 @@
     // Allocate a new object using the layout.
     auto boxedInterfaceType = boxedType;
     if (env) {
-      boxedInterfaceType = SILType::getPrimitiveType(
-        boxedType.getSwiftRValueType()->mapTypeOutOfContext()
-           ->getCanonicalType(),
-         boxedType.getCategory());
+      boxedInterfaceType = boxedType.mapTypeOutOfContext();
     }
 
     auto boxDescriptor = IGF.IGM.getAddrOfBoxDescriptor(
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index a219de5..5b2bc9f 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -390,6 +390,12 @@
   return M.Types.getLoweredType(Ty->getReferentType()->getCanonicalType());
 }
 
+SILType SILType::mapTypeOutOfContext() const {
+  return SILType::getPrimitiveType(getSwiftRValueType()->mapTypeOutOfContext()
+                                                       ->getCanonicalType(),
+                                   getCategory());
+}
+
 CanType
 SILBoxType::getFieldLoweredType(SILModule &M, unsigned index) const {
   auto fieldTy = getLayout()->getFields()[index].getLoweredType();
diff --git a/lib/SILGen/Cleanup.h b/lib/SILGen/Cleanup.h
index 28dc213..2b9ccad 100644
--- a/lib/SILGen/Cleanup.h
+++ b/lib/SILGen/Cleanup.h
@@ -142,6 +142,10 @@
     assert(!stack.empty());
     return stack.stable_begin();
   }
+  
+  Cleanup &getCleanup(CleanupHandle iter) {
+    return *stack.find(iter);
+  }
 
   /// \brief Emit a branch to the given jump destination,
   /// threading out through any cleanups we need to run. This does not pop the
diff --git a/lib/SILGen/ResultPlan.cpp b/lib/SILGen/ResultPlan.cpp
index 861cb9c..70bae80 100644
--- a/lib/SILGen/ResultPlan.cpp
+++ b/lib/SILGen/ResultPlan.cpp
@@ -17,6 +17,7 @@
 #include "LValue.h"
 #include "RValue.h"
 #include "SILGenFunction.h"
+#include "swift/AST/GenericEnvironment.h"
 
 using namespace swift;
 using namespace Lowering;
@@ -29,7 +30,7 @@
 
 /// A result plan for evaluating an indirect result into the address
 /// associated with an initialization.
-class InPlaceInitializationResultPlan : public ResultPlan {
+class InPlaceInitializationResultPlan final : public ResultPlan {
   Initialization *init;
 
 public:
@@ -47,10 +48,150 @@
   }
 };
 
+/// A cleanup that handles the delayed emission of an indirect buffer for opened
+/// Self arguments.
+class IndirectOpenedSelfCleanup final : public Cleanup {
+  SILValue box;
+public:
+  IndirectOpenedSelfCleanup()
+    : box()
+  {}
+  
+  void setBox(SILValue b) {
+    assert(!box && "buffer already set?!");
+    box = b;
+  }
+  
+  void emit(SILGenFunction &SGF, CleanupLocation loc) override {
+    assert(box && "buffer never emitted before activating cleanup?!");
+    SGF.B.createDeallocBox(loc, box);
+  }
+  
+  void dump(SILGenFunction &SGF) const override {
+    llvm::errs() << "IndirectOpenedSelfCleanup\n";
+    if (box)
+      box->dump();
+  }
+};
+
+/// Map a type expressed in terms of opened archetypes into a context-free
+/// dependent type, returning the type, a generic signature with parameters
+/// corresponding to each opened type,
+static std::pair<CanType, CanGenericSignature>
+mapTypeOutOfOpenedExistentialContext(CanType t,
+                                   SmallVectorImpl<Substitution> &mappedSubs) {
+  SmallVector<ArchetypeType *, 4> openedTypes;
+  t->getOpenedExistentials(openedTypes);
+
+  SmallVector<GenericTypeParamType *, 4> params;
+  for (unsigned i : indices(openedTypes)) {
+    params.push_back(GenericTypeParamType::get(0, i, t->getASTContext()));
+    mappedSubs.push_back(Substitution(openedTypes[i], {}));
+  }
+  
+  auto mappedSig = GenericSignature::get(params, {});
+
+  auto mappedTy = t.subst(
+    [&](SubstitutableType *t) -> Type {
+      auto index = std::find(openedTypes.begin(), openedTypes.end(), t)
+        - openedTypes.begin();
+      assert(index != openedTypes.end() - openedTypes.begin());
+      return params[index];
+    },
+    MakeAbstractConformanceForGenericType());
+
+  return std::make_pair(mappedTy->getCanonicalType(mappedSig),
+                        mappedSig->getCanonicalSignature());
+}
+
+/// A result plan for an indirectly-returned opened existential value.
+///
+/// This defers allocating the temporary for the result to a later point so that
+/// it happens after the arguments are evaluated.
+class IndirectOpenedSelfResultPlan final : public ResultPlan {
+  AbstractionPattern origType;
+  CanType substType;
+  CleanupHandle handle = CleanupHandle::invalid();
+  mutable SILValue resultBox, resultBuf;
+
+public:
+  IndirectOpenedSelfResultPlan(SILGenFunction &SGF,
+                               AbstractionPattern origType,
+                               CanType substType)
+    : origType(origType), substType(substType)
+  {
+    // Create a cleanup to deallocate the stack buffer at the proper scope.
+    // We won't emit the buffer till later, after arguments have been opened,
+    // though.
+    SGF.Cleanups.pushCleanupInState<IndirectOpenedSelfCleanup>(
+                                                         CleanupState::Dormant);
+    handle = SGF.Cleanups.getCleanupsDepth();
+  }
+  
+  void
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const override {
+    assert(!resultBox && "already created temporary?!");
+    
+    // We allocate the buffer as a box because the scope nesting won't clean
+    // this up with good stack discipline relative to any stack allocations that
+    // occur during argument emission. Escape analysis during mandatory passes
+    // ought to clean this up.
+
+    auto resultTy = SGF.getLoweredType(origType, substType).getSwiftRValueType();
+    CanType layoutTy;
+    CanGenericSignature layoutSig;
+    SmallVector<Substitution, 4> layoutSubs;
+    std::tie(layoutTy, layoutSig)
+      = mapTypeOutOfOpenedExistentialContext(resultTy, layoutSubs);
+    
+    auto boxLayout = SILLayout::get(SGF.getASTContext(),
+      layoutSig->getCanonicalSignature(),
+      SILField(layoutTy->getCanonicalType(layoutSig), true));
+    
+    resultBox = SGF.B.createAllocBox(loc,
+      SILBoxType::get(SGF.getASTContext(),
+                      boxLayout,
+                      layoutSubs));
+    
+    // Complete the cleanup to deallocate this buffer later, after we're
+    // finished with the argument.
+    static_cast<IndirectOpenedSelfCleanup&>(SGF.Cleanups.getCleanup(handle))
+      .setBox(resultBox);
+    SGF.Cleanups.setCleanupState(handle, CleanupState::Active);
+
+    resultBuf = SGF.B.createProjectBox(loc, resultBox, 0);
+    outList.emplace_back(resultBuf);
+  }
+
+  RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
+                ArrayRef<ManagedValue> &directResults) override {
+    assert(resultBox && "never emitted temporary?!");
+    
+    // Lower the unabstracted result type.
+    auto &substTL = SGF.getTypeLowering(substType);
+
+    ManagedValue value;
+    // If the value isn't address-only, go ahead and load.
+    if (!substTL.isAddressOnly()) {
+      auto load = substTL.emitLoad(SGF.B, loc, resultBuf,
+                                   LoadOwnershipQualifier::Take);
+      value = SGF.emitManagedRValueWithCleanup(load);
+    } else {
+      value = SGF.emitManagedRValueWithCleanup(resultBuf);
+    }
+
+    // A Self return should never be further abstracted. It's also never emitted
+    // into context; we disable that optimization because Self may not even
+    // be available to pre-allocate a stack buffer before we prepare a call.
+    return RValue(SGF, loc, substType, value);
+  }
+};
+
 /// A result plan for working with a single value and potentially
 /// reabstracting it.  The value can actually be a tuple if the
 /// abstraction is opaque.
-class ScalarResultPlan : public ResultPlan {
+class ScalarResultPlan final : public ResultPlan {
   std::unique_ptr<TemporaryInitialization> temporary;
   AbstractionPattern origType;
   Initialization *init;
@@ -150,7 +291,7 @@
 
 /// A result plan which calls copyOrInitValueInto on an Initialization
 /// using a temporary buffer initialized by a sub-plan.
-class InitValueFromTemporaryResultPlan : public ResultPlan {
+class InitValueFromTemporaryResultPlan final : public ResultPlan {
   Initialization *init;
   ResultPlanPtr subPlan;
   std::unique_ptr<TemporaryInitialization> temporary;
@@ -184,7 +325,7 @@
 
 /// A result plan which calls copyOrInitValueInto using the result of
 /// a sub-plan.
-class InitValueFromRValueResultPlan : public ResultPlan {
+class InitValueFromRValueResultPlan final : public ResultPlan {
   Initialization *init;
   ResultPlanPtr subPlan;
 
@@ -212,7 +353,7 @@
 
 /// A result plan which produces a larger RValue from a bunch of
 /// components.
-class TupleRValueResultPlan : public ResultPlan {
+class TupleRValueResultPlan final : public ResultPlan {
   SmallVector<ResultPlanPtr, 4> eltPlans;
 
 public:
@@ -254,7 +395,7 @@
 
 /// A result plan which evaluates into the sub-components
 /// of a splittable tuple initialization.
-class TupleInitializationResultPlan : public ResultPlan {
+class TupleInitializationResultPlan final : public ResultPlan {
   Initialization *tupleInit;
   SmallVector<InitializationPtr, 4> eltInitsBuffer;
   MutableArrayRef<InitializationPtr> eltInits;
@@ -305,7 +446,7 @@
   }
 };
 
-class ForeignErrorInitializationPlan : public ResultPlan {
+class ForeignErrorInitializationPlan final : public ResultPlan {
   SILLocation loc;
   LValue lvalue;
   ResultPlanPtr subPlan;
@@ -466,6 +607,16 @@
   //   - store it to the destination
   // We could break this down into different ResultPlan implementations,
   // but it's easier not to.
+  
+  // If the result type involves an indirectly-returned opened existential,
+  // then we need to evaluate the arguments first in order to have access to
+  // the opened Self type. A special result plan defers allocating the stack
+  // slot to the point the call is emitted.
+  if (result.getType()->hasOpenedExistential()
+      && SGF.silConv.isSILIndirect(result)) {
+    return ResultPlanPtr(
+      new IndirectOpenedSelfResultPlan(SGF, origType, substType));
+  }
 
   // Create a temporary if the result is indirect.
   std::unique_ptr<TemporaryInitialization> temporary;
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 82f55a4..ab7b248 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -4409,7 +4409,7 @@
 
   auto directResultsArray = makeArrayRef(directResults);
   RValue result =
-      resultPlan->finish(*this, loc, substResultType, directResultsArray);
+    resultPlan->finish(*this, loc, substResultType, directResultsArray);
   assert(directResultsArray.empty() && "didn't claim all direct results");
 
   return result;
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index 6c7d43e..205c83a 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -505,28 +505,94 @@
 namespace {
 
 /// This is an initialization for an address-only existential in memory.
-class ExistentialInitialization : public KnownAddressInitialization {
-  CleanupHandle Cleanup;
+class ExistentialInitialization final : public SingleBufferInitialization {
+  SILValue existential;
+  CanType concreteFormalType;
+  ArrayRef<ProtocolConformanceRef> conformances;
+  ExistentialRepresentation repr;
+  
+  // Initialized lazily when the address for initialization is demanded.
+  SILValue concreteBuffer;
+  CleanupHandle deinitExistentialCleanup;
 public:
   /// \param existential The existential container
-  /// \param address Address of value in existential container
   /// \param concreteFormalType Unlowered AST type of value
-  /// \param repr Representation of container
-  ExistentialInitialization(SILValue existential, SILValue address,
+  /// \param conformances Conformances for concrete type to existential's
+  ///        protocols
+  ExistentialInitialization(SILGenFunction &SGF,
+                            SILValue existential,
                             CanType concreteFormalType,
-                            ExistentialRepresentation repr,
-                            SILGenFunction &SGF)
-      : KnownAddressInitialization(address) {
-    // Any early exit before we store a value into the existential must
-    // clean up the existential container.
-    Cleanup = SGF.enterDeinitExistentialCleanup(existential,
-                                                concreteFormalType,
-                                                repr);
+                            ArrayRef<ProtocolConformanceRef> conformances,
+                            ExistentialRepresentation repr)
+    : existential(existential),
+      concreteFormalType(concreteFormalType),
+      conformances(conformances),
+      repr(repr)
+  {
+    assert(existential->getType().isAddress());
+    
+    // Create a cleanup to deallocate an allocated but uninitialized concrete
+    // type buffer.
+    // It won't be activated until that buffer is formed later, though.
+    deinitExistentialCleanup =
+      SGF.enterDeinitExistentialCleanup(CleanupState::Dormant,
+                                        existential, concreteFormalType, repr);
+
+  }
+  
+  SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+                                              SILLocation loc) override {
+    // Create the buffer when needed, because in some cases the type may
+    // be the opened type from another existential that hasn't been opened
+    // at the point the existential destination was formed.
+    assert(!concreteBuffer && "concrete buffer already formed?!");
+    
+    auto concreteLoweredType =
+        SGF.getLoweredType(AbstractionPattern::getOpaque(), concreteFormalType);
+    
+    switch (repr) {
+    case ExistentialRepresentation::Opaque: {
+      concreteBuffer = SGF.B.createInitExistentialAddr(loc, existential,
+                                           concreteFormalType,
+                                           concreteLoweredType.getAddressType(),
+                                           conformances);
+      break;
+    }
+    case ExistentialRepresentation::Boxed: {
+      auto box = SGF.B.createAllocExistentialBox(loc,
+                       existential->getType().getObjectType(),
+                       concreteFormalType,
+                       conformances);
+      concreteBuffer = SGF.B.createProjectExistentialBox(loc,
+                                           concreteLoweredType.getAddressType(),
+                                           box);
+      SGF.B.createStore(loc, box, existential,
+                        StoreOwnershipQualifier::Init);
+      break;
+    }
+    case ExistentialRepresentation::Class:
+    case ExistentialRepresentation::Metatype:
+    case ExistentialRepresentation::None:
+      llvm_unreachable("not supported");
+    }
+    
+    // Activate the cleanup to deallocate the buffer we just allocated, should
+    SGF.Cleanups.setCleanupState(deinitExistentialCleanup,
+                                 CleanupState::Active);
+
+    return concreteBuffer;
+  }
+
+  bool isInPlaceInitializationOfGlobal() const override {
+    return existential && isa<GlobalAddrInst>(existential);
   }
 
   void finishInitialization(SILGenFunction &SGF) override {
     SingleBufferInitialization::finishInitialization(SGF);
-    SGF.Cleanups.setCleanupState(Cleanup, CleanupState::Dead);
+    // We've fully initialized the existential by this point, so we can
+    // retire the partial cleanup.
+    SGF.Cleanups.setCleanupState(deinitExistentialCleanup,
+                                 CleanupState::Dead);
   }
 };
 
@@ -713,24 +779,32 @@
                                       concreteFormalType, sub, conformances);
   }
   case ExistentialRepresentation::Boxed: {
-    // Allocate the existential.
-    auto *existential = B.createAllocExistentialBox(loc,
-                                           existentialTL.getLoweredType(),
-                                           concreteFormalType,
-                                           conformances);
-    auto *valueAddr = B.createProjectExistentialBox(loc,
-                                           concreteTL.getLoweredType(),
-                                           existential);
-    // Initialize the concrete value in-place.
-    ExistentialInitialization init(existential, valueAddr, concreteFormalType,
-                                   ExistentialRepresentation::Boxed, *this);
-    ManagedValue mv = F(SGFContext(&init));
-    if (!mv.isInContext()) {
-      mv.ensurePlusOne(*this, loc).forwardInto(*this, loc, init.getAddress());
-      init.finishInitialization(*this);
+    // We defer allocation of the box to when the address is demanded.
+    // Create a stack slot to hold the box once it's allocated.
+    SILValue boxValue;
+    auto buf = B.bufferForExpr(
+      loc, existentialTL.getLoweredType(), existentialTL, C,
+      [&](SILValue existential) {
+        // Initialize the existential in-place.
+        ExistentialInitialization init(*this, existential,
+                                       concreteFormalType,
+                                       conformances,
+                                       ExistentialRepresentation::Boxed);
+        ManagedValue mv = F(SGFContext(&init));
+        if (!mv.isInContext()) {
+          init.copyOrInitValueInto(*this, loc, mv.ensurePlusOne(*this, loc),
+                                    /*init*/ true);
+          init.finishInitialization(*this);
+        }
+      });
+
+    if (buf.isInContext()) {
+      return buf;
     }
-    
-    return emitManagedRValueWithCleanup(existential);
+
+    auto value = B.createLoad(loc, buf.forward(*this),
+                              LoadOwnershipQualifier::Take);
+    return emitManagedRValueWithCleanup(value);
   }
   case ExistentialRepresentation::Opaque: {
   
@@ -769,22 +843,16 @@
     return B.bufferForExpr(
         loc, existentialTL.getLoweredType(), existentialTL, C,
         [&](SILValue existential) {
-          // Allocate the concrete value inside the container.
-          SILValue valueAddr = B.createInitExistentialAddr(
-              loc, existential,
-              concreteFormalType,
-              concreteTLPtr->getLoweredType(),
-              conformances);
-          // Initialize the concrete value in-place.
-          InitializationPtr init(
-              new ExistentialInitialization(existential, valueAddr, concreteFormalType,
-                                            ExistentialRepresentation::Opaque,
-                                            *this));
-          ManagedValue mv = F(SGFContext(init.get()));
+          // Initialize the existential in-place.
+          ExistentialInitialization init(*this, existential,
+                                         concreteFormalType,
+                                         conformances,
+                                         ExistentialRepresentation::Opaque);
+          ManagedValue mv = F(SGFContext(&init));
           if (!mv.isInContext()) {
-            init->copyOrInitValueInto(*this, loc, mv.ensurePlusOne(*this, loc),
+            init.copyOrInitValueInto(*this, loc, mv.ensurePlusOne(*this, loc),
                                       /*init*/ true);
-            init->finishInitialization(*this);
+            init.finishInitialization(*this);
           }
         });
   }
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index bb22247..16f5644 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -1363,8 +1363,9 @@
         }
         break;
       case ExistentialRepresentation::Boxed:
-        SGF.B.createDeallocExistentialBox(l, concreteFormalType,
-                                          existentialAddr);
+        auto box = SGF.B.createLoad(l, existentialAddr,
+                                    LoadOwnershipQualifier::Take);
+        SGF.B.createDeallocExistentialBox(l, concreteFormalType, box);
         break;
       }
     }
@@ -1382,12 +1383,13 @@
 /// Enter a cleanup to emit a DeinitExistentialAddr or DeinitExistentialBox
 /// of the specified value.
 CleanupHandle SILGenFunction::enterDeinitExistentialCleanup(
-                                               SILValue valueOrAddr,
+                                               CleanupState state,
+                                               SILValue addr,
                                                CanType concreteFormalType,
                                                ExistentialRepresentation repr) {
-  Cleanups.pushCleanup<DeinitExistentialCleanup>(valueOrAddr,
-                                                 concreteFormalType,
-                                                 repr);
+  assert(addr->getType().isAddress());
+  Cleanups.pushCleanupInState<DeinitExistentialCleanup>(state, addr,
+                                                      concreteFormalType, repr);
   return Cleanups.getTopCleanup();
 }
 
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 453ea74..475077d 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -3764,10 +3764,7 @@
     auto indexLoweredTy = SGM.Types.getLoweredType(
                                                 AbstractionPattern::getOpaque(),
                                                 indexTy);
-    indexLoweredTy = SILType::getPrimitiveType(
-                     indexLoweredTy.getSwiftRValueType()->mapTypeOutOfContext()
-                                                        ->getCanonicalType(),
-                     indexLoweredTy.getCategory());
+    indexLoweredTy = indexLoweredTy.mapTypeOutOfContext();
     indexPatterns.push_back({indexTy->mapTypeOutOfContext()
                                     ->getCanonicalType(),
                              indexLoweredTy});
@@ -4983,7 +4980,8 @@
   auto &optTL = SGF.getTypeLowering(E->getSubExpr()->getType());
   
   ManagedValue optValue;
-  if (!SGF.silConv.useLoweredAddresses() || optTL.isLoadable()) {
+  if (!SGF.silConv.useLoweredAddresses() || optTL.isLoadable()
+      || E->getType()->hasOpenedExistential()) {
     optValue = SGF.emitRValueAsSingleValue(E->getSubExpr());
   } else {
     auto temp = SGF.emitTemporary(E, optTL);
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index 5fbad2b..5859fbc 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -1752,7 +1752,8 @@
   
   /// Enter a cleanup to emit a DeinitExistentialAddr or DeinitExistentialBox
   /// of the specified value.
-  CleanupHandle enterDeinitExistentialCleanup(SILValue valueOrAddr,
+  CleanupHandle enterDeinitExistentialCleanup(CleanupState state,
+                                              SILValue addr,
                                               CanType concreteFormalType,
                                               ExistentialRepresentation repr);
 
diff --git a/lib/SILGen/Scope.h b/lib/SILGen/Scope.h
index 89ce3c8..ae8e634 100644
--- a/lib/SILGen/Scope.h
+++ b/lib/SILGen/Scope.h
@@ -41,6 +41,18 @@
     cleanups.innermostScope = depth;
   }
 
+  Scope(const Scope &other) = delete;
+  Scope &operator=(const Scope &other) = delete;
+
+  Scope(Scope &&other)
+      : cleanups(other.cleanups), depth(other.depth),
+        savedInnermostScope(other.savedInnermostScope),
+        loc(other.loc) {
+    other.depth = CleanupsDepth::invalid();
+    assert(!other.isValid());
+  }
+  Scope &operator=(Scope &&other) = delete; // implementable if needed
+
   explicit Scope(SILGenFunction &SGF, SILLocation loc)
       : Scope(SGF.Cleanups, CleanupLocation::get(loc)) {}
 
diff --git a/test/SILGen/boxed_existentials.swift b/test/SILGen/boxed_existentials.swift
index a67d599..065e62e 100644
--- a/test/SILGen/boxed_existentials.swift
+++ b/test/SILGen/boxed_existentials.swift
@@ -20,12 +20,14 @@
 }
 // CHECK-LABEL: sil hidden @$S18boxed_existentials21test_concrete_erasureys5Error_pAA08ClericalF0OF
 // CHECK:       bb0([[ARG:%.*]] : @guaranteed $ClericalError):
+// CHECK:         [[ARG_COPY:%.*]] = copy_value [[ARG]]
 // CHECK:         [[EXISTENTIAL:%.*]] = alloc_existential_box $Error, $ClericalError
 // CHECK:         [[ADDR:%.*]] = project_existential_box $ClericalError in [[EXISTENTIAL]] : $Error
-// CHECK:         [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:         store [[EXISTENTIAL]] to [init] [[EXISTENTIAL_BUF:%.*]] :
 // CHECK:         store [[ARG_COPY]] to [init] [[ADDR]] : $*ClericalError
 // CHECK-NOT:         destroy_value [[ARG]]
-// CHECK:         return [[EXISTENTIAL]] : $Error
+// CHECK:         [[EXISTENTIAL2:%.*]] = load [take] [[EXISTENTIAL_BUF]]
+// CHECK:         return [[EXISTENTIAL2]] : $Error
 
 protocol HairType {}
 
@@ -36,9 +38,11 @@
 // CHECK:         [[VALUE_ADDR:%.*]] = open_existential_addr immutable_access [[OLD_EXISTENTIAL:%.*]] : $*Error & HairType to $*[[VALUE_TYPE:@opened\(.*\) Error & HairType]]
 // CHECK:         [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]]
 // CHECK:         [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error
+// CHECK:         store [[NEW_EXISTENTIAL]] to [init] [[NEW_EXISTENTIALBUF:%.*]] :
 // CHECK:         copy_addr [[VALUE_ADDR]] to [initialization] [[ADDR]]
 // CHECK-NOT:         destroy_addr [[OLD_EXISTENTIAL]]
-// CHECK:         return [[NEW_EXISTENTIAL]]
+// CHECK:         [[NEW_EXISTENTIAL2:%.*]] = load [take] [[NEW_EXISTENTIALBUF]]
+// CHECK:         return [[NEW_EXISTENTIAL2]]
 
 protocol HairClass: class {}
 
@@ -49,9 +53,11 @@
 // CHECK:         [[VALUE:%.*]] = open_existential_ref [[OLD_EXISTENTIAL:%.*]] : $Error & HairClass to $[[VALUE_TYPE:@opened\(.*\) Error & HairClass]]
 // CHECK:         [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]]
 // CHECK:         [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error
+// CHECK:         store [[NEW_EXISTENTIAL]] to [init] [[NEW_EXISTENTIALBUF:%.*]] :
 // CHECK:         [[COPIED_VALUE:%.*]] = copy_value [[VALUE]]
 // CHECK:         store [[COPIED_VALUE]] to [init] [[ADDR]]
-// CHECK:         return [[NEW_EXISTENTIAL]]
+// CHECK:         [[NEW_EXISTENTIAL2:%.*]] = load [take] [[NEW_EXISTENTIALBUF]]
+// CHECK:         return [[NEW_EXISTENTIAL2]]
 
 func test_property(_ x: Error) -> String {
   return x._domain
diff --git a/test/SILGen/dynamic_self.swift b/test/SILGen/dynamic_self.swift
index 03be0d0..6d5eb10 100644
--- a/test/SILGen/dynamic_self.swift
+++ b/test/SILGen/dynamic_self.swift
@@ -74,8 +74,8 @@
 // CHECK: bb0([[P:%[0-9]+]] : @trivial $*P):
 // CHECK:   [[PCOPY_ADDR:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P to $*@opened([[N:".*"]]) P
 // CHECK:   [[P_RESULT:%[0-9]+]] = alloc_stack $P
-// CHECK:   [[P_RESULT_ADDR:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*P, $@opened([[N]]) P
 // CHECK:   [[P_F_METHOD:%[0-9]+]] = witness_method $@opened([[N]]) P, #P.f!1 : {{.*}}, [[PCOPY_ADDR]]{{.*}} : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+// CHECK:   [[P_RESULT_ADDR:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*P, $@opened([[N]]) P
 // CHECK:   apply [[P_F_METHOD]]<@opened([[N]]) P>([[P_RESULT_ADDR]], [[PCOPY_ADDR]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
 // CHECK:   destroy_addr [[P_RESULT]] : $*P
 // CHECK:   dealloc_stack [[P_RESULT]] : $*P
diff --git a/test/SILGen/erasure_reabstraction.swift b/test/SILGen/erasure_reabstraction.swift
index 816e3f7..a59ae6d 100644
--- a/test/SILGen/erasure_reabstraction.swift
+++ b/test/SILGen/erasure_reabstraction.swift
@@ -4,17 +4,17 @@
 struct Foo {}
 class Bar {}
 
-// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $Foo.Type
 // CHECK: [[METATYPE:%.*]] = metatype $@thick Foo.Type
+// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $Foo.Type
 // CHECK: store [[METATYPE]] to [trivial] [[CONCRETE]] : $*@thick Foo.Type
 let x: Any = Foo.self
 
 
-// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $() -> ()
 // CHECK: [[CLOSURE:%.*]] = function_ref
 // CHECK: [[CLOSURE_THICK:%.*]] = thin_to_thick_function [[CLOSURE]]
 // CHECK: [[REABSTRACTION_THUNK:%.*]] = function_ref @$SIeg_ytytIegnr_TR
 // CHECK: [[CLOSURE_REABSTRACTED:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTION_THUNK]]([[CLOSURE_THICK]])
+// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $() -> ()
 // CHECK: store [[CLOSURE_REABSTRACTED]] to [init] [[CONCRETE]]
 let y: Any = {() -> () in ()}
 
diff --git a/test/SILGen/errors.swift b/test/SILGen/errors.swift
index 8ed2c70..b7e247c 100644
--- a/test/SILGen/errors.swift
+++ b/test/SILGen/errors.swift
@@ -35,26 +35,31 @@
 }
 
 // CHECK: sil hidden @$S6errors15dont_make_a_cat{{.*}}F : $@convention(thin) () -> (@owned Cat, @error Error) {
-// CHECK:      [[BOX:%.*]] = alloc_existential_box $Error, $HomeworkError
-// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $Error
-// CHECK-NEXT: [[T0:%.*]] = metatype $@thin HomeworkError.Type
+// CHECK:      [[T0:%.*]] = metatype $@thin HomeworkError.Type
 // CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooHard!enumelt
+// CHECK-NEXT: [[BOX:%.*]] = alloc_existential_box $Error, $HomeworkError
+// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $Error
+// CHECK-NEXT: store [[BOX]] to [init] [[BOXBUF:%.*]] :
 // CHECK-NEXT: store [[T1]] to [init] [[ADDR]]
+// CHECK-NEXT: [[BOX2:%.*]] = load [take] [[BOXBUF]]
 // CHECK-NEXT: builtin "willThrow"
-// CHECK-NEXT: throw [[BOX]]
+// CHECK-NEXT: dealloc_stack [[BOXBUF]]
+// CHECK-NEXT: throw [[BOX2]]
 func dont_make_a_cat() throws -> Cat {
   throw HomeworkError.TooHard
 }
 
 // CHECK: sil hidden @$S6errors11dont_return{{.*}}F : $@convention(thin) <T> (@in_guaranteed T) -> (@out T, @error Error) {
-// CHECK:      [[BOX:%.*]] = alloc_existential_box $Error, $HomeworkError
-// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $Error
-// CHECK-NEXT: [[T0:%.*]] = metatype $@thin HomeworkError.Type
+// CHECK:      [[T0:%.*]] = metatype $@thin HomeworkError.Type
 // CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooMuch!enumelt
+// CHECK-NEXT: [[BOX:%.*]] = alloc_existential_box $Error, $HomeworkError
+// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $Error
+// CHECK-NEXT: store [[BOX]] to [init] [[BOXBUF:%.*]] :
 // CHECK-NEXT: store [[T1]] to [init] [[ADDR]]
+// CHECK-NEXT: [[BOX2:%.*]] = load [take] [[BOXBUF]]
 // CHECK-NEXT: builtin "willThrow"
-// CHECK-NOT: destroy_addr %1 : $*T
-// CHECK-NEXT: throw [[BOX]]
+// CHECK-NEXT: dealloc_stack [[BOXBUF]]
+// CHECK-NEXT: throw [[BOX2]]
 func dont_return<T>(_ argument: T) throws -> T {
   throw HomeworkError.TooMuch
 }
@@ -224,6 +229,7 @@
 
 //CHECK-LABEL: sil hidden @$S6errors6IThrows5Int32VyKF
 //CHECK: builtin "willThrow"
+//CHECK-NEXT: dealloc_stack
 //CHECK-NEXT: throw
 func IThrow() throws -> Int32 {
   throw ColorError.Red
diff --git a/test/SILGen/existential_erasure.swift b/test/SILGen/existential_erasure.swift
index f262a82..b905502 100644
--- a/test/SILGen/existential_erasure.swift
+++ b/test/SILGen/existential_erasure.swift
@@ -44,18 +44,17 @@
 // CHECK: bb0(%0 : @trivial $*P):
 // CHECK:   [[OPEN:%.*]] = open_existential_addr immutable_access %0 : $*P to $*[[OPEN_TYPE:@opened\(.*\) P]]
 // CHECK:   [[RESULT:%.*]] = alloc_stack $P
-// CHECK:   [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
 // CHECK:   [[FUNC:%.*]] = function_ref @$S19existential_erasure12throwingFuncSbyKF
 // CHECK:   try_apply [[FUNC]]()
 //
 // CHECK: bb1([[SUCCESS:%.*]] : @trivial $Bool):
 // CHECK:   [[METHOD:%.*]] = witness_method $[[OPEN_TYPE]], #P.downgrade!1 : {{.*}}, [[OPEN]]
+// CHECK:   [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
 // CHECK:   apply [[METHOD]]<[[OPEN_TYPE]]>([[RESULT_ADDR]], [[SUCCESS]], [[OPEN]])
 // CHECK:   dealloc_stack [[RESULT]]
 // CHECK:   return
 //
 // CHECK: bb2([[FAILURE:%.*]] : @owned $Error):
-// CHECK:   deinit_existential_addr [[RESULT]]
 // CHECK:   dealloc_stack [[RESULT]]
 // CHECK:   throw [[FAILURE]]
 //
@@ -67,8 +66,8 @@
 // CHECK: bb0(%0 : @trivial $*P):
 // CHECK:   [[OPEN:%.*]] = open_existential_addr immutable_access %0 : $*P to $*[[OPEN_TYPE:@opened\(.*\) P]]
 // CHECK:   [[RESULT:%.*]] = alloc_stack $P
-// CHECK:   [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
 // CHECK:   [[METHOD:%.*]] = witness_method $[[OPEN_TYPE]], #P.upgrade!1 : {{.*}}, [[OPEN]]
+// CHECK:   [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
 // CHECK:   try_apply [[METHOD]]<[[OPEN_TYPE]]>([[RESULT_ADDR]], [[OPEN]])
 //
 // CHECK: bb1
@@ -96,16 +95,19 @@
 // CHECK: bb0([[ARG:%.*]] : @guaranteed $Error):
 // CHECK:  debug_value [[ARG]] : $Error
 // CHECK:  [[OPEN:%.*]] = open_existential_box [[ARG]] : $Error to $*[[OPEN_TYPE:@opened\(.*\) Error]]
+// CHECK:  [[FUNC:%.*]] = function_ref @$Ss5ErrorP19existential_erasureE17returnOrThrowSelf{{[_0-9a-zA-Z]*}}F
 // CHECK:  [[RESULT:%.*]] = alloc_existential_box $Error, $[[OPEN_TYPE]]
 // CHECK:  [[ADDR:%.*]] = project_existential_box $[[OPEN_TYPE]] in [[RESULT]] : $Error
-// CHECK:  [[FUNC:%.*]] = function_ref @$Ss5ErrorP19existential_erasureE17returnOrThrowSelf{{[_0-9a-zA-Z]*}}F
+// CHECK:  store [[RESULT]] to [init] [[RESULT_BUF:%.*]] :
 // CHECK:  try_apply [[FUNC]]<[[OPEN_TYPE]]>([[ADDR]], [[OPEN]])
 //
 // CHECK: bb1
-// CHECK:  return [[RESULT]] : $Error
+// CHECK:  [[RESULT2:%.*]] = load [take] [[RESULT_BUF]]
+// CHECK:  return [[RESULT2]] : $Error
 //
 // CHECK: bb2([[FAILURE:%.*]] : @owned $Error):
-// CHECK:  dealloc_existential_box [[RESULT]]
+// CHECK:  [[RESULT3:%.*]] = load [take] [[RESULT_BUF]]
+// CHECK:  dealloc_existential_box [[RESULT3]]
 // CHECK:  throw [[FAILURE]] : $Error
 //
   return try e.returnOrThrowSelf()
diff --git a/test/SILGen/existential_erasure_mutating_covariant_self.swift b/test/SILGen/existential_erasure_mutating_covariant_self.swift
new file mode 100644
index 0000000..68aa566
--- /dev/null
+++ b/test/SILGen/existential_erasure_mutating_covariant_self.swift
@@ -0,0 +1,73 @@
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -verify %s
+// RUN: %target-swift-frontend -emit-sil -enable-sil-ownership %s | %FileCheck --check-prefix=AFTER-MANDATORY-PASSES %s
+
+// ensure escape analysis killed the box allocations used for delayed Self
+// return buffers
+// AFTER-MANDATORY-PASSES-NOT: alloc_box
+
+extension Error {
+  mutating func covariantReturn(_: Int) -> Self { return self }
+  mutating func covariantOptionalReturn(_: Int) -> Self? { return self }
+  mutating func covariantReturnOrThrow(_: Int) throws -> Self { return self }
+  mutating func covariantClosureArgAndReturn(_: (Self) -> Int) -> Self { return self }
+}
+
+protocol MutatingWithCovariantReturn {
+  mutating func covariantReturn(_: Int) -> Self
+  mutating func covariantOptionalReturn(_: Int) -> Self?
+  mutating func covariantReturnOrThrow(_: Int) throws -> Self
+  mutating func covariantClosureArgAndReturn(_: (Self) -> Int) -> Self
+}
+
+protocol ClassConstrainedRefinement: MutatingWithCovariantReturn, AnyObject {}
+
+func int() -> Int { return 0 }
+func intThrows() throws -> Int { return 0 }
+
+func foo(x: inout MutatingWithCovariantReturn, y: inout ClassConstrainedRefinement, z: inout Error) throws {
+  _ = x.covariantReturn(int())
+  _ = x.covariantReturn(try intThrows())
+  _ = x.covariantReturn(try! intThrows())
+
+  _ = x.covariantOptionalReturn(int())
+  _ = x.covariantOptionalReturn(try intThrows())
+  _ = x.covariantOptionalReturn(try! intThrows())
+
+  _ = try x.covariantReturnOrThrow(int())
+  _ = try x.covariantReturnOrThrow(try intThrows())
+  _ = try x.covariantReturnOrThrow(try! intThrows())
+
+  _ = x.covariantClosureArgAndReturn({ _ in 0 })
+
+
+  _ = y.covariantReturn(int())
+  _ = y.covariantReturn(try intThrows())
+  _ = y.covariantReturn(try! intThrows())
+
+  _ = y.covariantOptionalReturn(int())
+  _ = y.covariantOptionalReturn(try intThrows())
+  _ = y.covariantOptionalReturn(try! intThrows())
+
+  _ = try y.covariantReturnOrThrow(int())
+  _ = try y.covariantReturnOrThrow(try intThrows())
+  _ = try y.covariantReturnOrThrow(try! intThrows())
+
+  // FIXME: the dynamic self capture here has to happen after existential
+  // opening as well.
+  //_ = y.covariantClosureArgAndReturn({ _ in 0 })
+
+
+  _ = z.covariantReturn(int())
+  _ = z.covariantReturn(try intThrows())
+  _ = z.covariantReturn(try! intThrows())
+
+  _ = z.covariantOptionalReturn(int())
+  _ = z.covariantOptionalReturn(try intThrows())
+  _ = z.covariantOptionalReturn(try! intThrows())
+
+  _ = try z.covariantReturnOrThrow(int())
+  _ = try z.covariantReturnOrThrow(try intThrows())
+  _ = try z.covariantReturnOrThrow(try! intThrows())
+
+  _ = z.covariantClosureArgAndReturn({ _ in 0 })
+}
diff --git a/test/SILGen/existential_metatypes.swift b/test/SILGen/existential_metatypes.swift
index ceec037..d58045c 100644
--- a/test/SILGen/existential_metatypes.swift
+++ b/test/SILGen/existential_metatypes.swift
@@ -21,8 +21,8 @@
   let type1 = type(of: x)
   // CHECK: [[INSTANCE1:%.*]] = alloc_stack $P
   // CHECK: [[OPEN_TYPE1:%.*]] = open_existential_metatype [[TYPE1]]
-  // CHECK: [[INSTANCE1_VALUE:%.*]] = init_existential_addr [[INSTANCE1]] : $*P
   // CHECK: [[INIT:%.*]] = witness_method {{.*}} #P.init!allocator
+  // CHECK: [[INSTANCE1_VALUE:%.*]] = init_existential_addr [[INSTANCE1]] : $*P
   // CHECK: apply [[INIT]]<{{.*}}>([[INSTANCE1_VALUE]], [[OPEN_TYPE1]])
   let instance1 = type1.init()
 
@@ -31,8 +31,8 @@
   let type2: P.Type = S.self
   // CHECK: [[INSTANCE2:%.*]] = alloc_stack $P
   // CHECK: [[OPEN_TYPE2:%.*]] = open_existential_metatype [[TYPE2]]
-  // CHECK: [[INSTANCE2_VALUE:%.*]] = init_existential_addr [[INSTANCE2]] : $*P
   // CHECK: [[STATIC_METHOD:%.*]] = witness_method {{.*}} #P.staticMethod
+  // CHECK: [[INSTANCE2_VALUE:%.*]] = init_existential_addr [[INSTANCE2]] : $*P
   // CHECK: apply [[STATIC_METHOD]]<{{.*}}>([[INSTANCE2_VALUE]], [[OPEN_TYPE2]])
   let instance2 = type2.staticMethod()
 }
diff --git a/test/SILGen/objc_bridging_any.swift b/test/SILGen/objc_bridging_any.swift
index 53c9a88..c1601c6 100644
--- a/test/SILGen/objc_bridging_any.swift
+++ b/test/SILGen/objc_bridging_any.swift
@@ -643,9 +643,9 @@
   // CHECK-LABEL: sil hidden @$SSo12GenericClassC17objc_bridging_anyE23pseudogenericAnyErasure1xypx_tF :
   func pseudogenericAnyErasure(x: T) -> Any {
     // CHECK: bb0([[ANY_OUT:%.*]] : @trivial $*Any, [[ARG:%.*]] : @guaranteed $T, [[SELF:%.*]] : @guaranteed $GenericClass<T>
-    // CHECK:   [[ANY_BUF:%.*]] = init_existential_addr [[ANY_OUT]] : $*Any, $AnyObject
     // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
     // CHECK:   [[ANYOBJECT:%.*]] = init_existential_ref [[ARG_COPY]] : $T : $T, $AnyObject
+    // CHECK:   [[ANY_BUF:%.*]] = init_existential_addr [[ANY_OUT]] : $*Any, $AnyObject
     // CHECK:   store [[ANYOBJECT]] to [init] [[ANY_BUF]]
     return x
   }
diff --git a/test/SILGen/objc_error.swift b/test/SILGen/objc_error.swift
index 8e90cea..d44060d 100644
--- a/test/SILGen/objc_error.swift
+++ b/test/SILGen/objc_error.swift
@@ -159,8 +159,10 @@
     // CHECK: [[FAILURE]]:
     // CHECK: [[ERROR_BOX:%[0-9]+]] = alloc_existential_box $Error, $Self
     // CHECK: [[ERROR_PROJECTED:%[0-9]+]] = project_existential_box $Self in [[ERROR_BOX]] : $Error
+    // CHECK: store [[ERROR_BOX]] to [init] [[ERROR_BUF:%.*]] :
     // CHECK: copy_addr [take] [[COPY]] to [initialization] [[ERROR_PROJECTED]] : $*Self
-    // CHECK: br [[CONTINUATION]]([[ERROR_BOX]] : $Error)
+    // CHECK: [[ERROR_BOX2:%.*]] = load [take] [[ERROR_BUF]]
+    // CHECK: br [[CONTINUATION]]([[ERROR_BOX2]] : $Error)
 
     // CHECK: [[CONTINUATION]]([[ERROR_ARG:%[0-9]+]] : @owned $Error):
 		return self as NSError
diff --git a/test/SILGen/protocol_extensions.swift b/test/SILGen/protocol_extensions.swift
index ca26608..654855a 100644
--- a/test/SILGen/protocol_extensions.swift
+++ b/test/SILGen/protocol_extensions.swift
@@ -528,8 +528,8 @@
   // CHECK: [[P1A:%[0-9]+]] = alloc_box ${ var P1 }
   // CHECK: [[PB:%.*]] = project_box [[P1A]]
   // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
-  // CHECK: [[P1AINIT:%[0-9]+]] = init_existential_addr [[PB]] : $*P1, $@opened([[UUID2:".*"]]) P1
   // CHECK: [[FN:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE11returnsSelf{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[P1AINIT:%[0-9]+]] = init_existential_addr [[PB]] : $*P1, $@opened([[UUID2:".*"]]) P1
   // CHECK: apply [[FN]]<@opened([[UUID]]) P1>([[P1AINIT]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> @out τ_0_0
   var p1a: P1 = p1.returnsSelf()
 }
diff --git a/test/SILGen/protocols.swift b/test/SILGen/protocols.swift
index 55bb387..9fa6f89 100644
--- a/test/SILGen/protocols.swift
+++ b/test/SILGen/protocols.swift
@@ -230,8 +230,8 @@
 // CHECK: bb0([[IM:%[0-9]+]] : @trivial $@thick Initializable.Type, [[I:%[0-9]+]] : @trivial $Int):
 // CHECK:   [[ARCHETYPE_META:%[0-9]+]] = open_existential_metatype [[IM]] : $@thick Initializable.Type to $@thick (@opened([[N:".*"]]) Initializable).Type
 // CHECK:   [[TEMP_VALUE:%[0-9]+]] = alloc_stack $Initializable
-// CHECK:   [[TEMP_ADDR:%[0-9]+]] = init_existential_addr [[TEMP_VALUE]] : $*Initializable, $@opened([[N]]) Initializable
 // CHECK:   [[INIT_WITNESS:%[0-9]+]] = witness_method $@opened([[N]]) Initializable, #Initializable.init!allocator.1 : {{.*}}, [[ARCHETYPE_META]]{{.*}} : $@convention(witness_method: Initializable) <τ_0_0 where τ_0_0 : Initializable> (Int, @thick τ_0_0.Type) -> @out τ_0_0
+// CHECK:   [[TEMP_ADDR:%[0-9]+]] = init_existential_addr [[TEMP_VALUE]] : $*Initializable, $@opened([[N]]) Initializable
 // CHECK:   [[INIT_RESULT:%[0-9]+]] = apply [[INIT_WITNESS]]<@opened([[N]]) Initializable>([[TEMP_ADDR]], [[I]], [[ARCHETYPE_META]]) : $@convention(witness_method: Initializable) <τ_0_0 where τ_0_0 : Initializable> (Int, @thick τ_0_0.Type) -> @out τ_0_0
 // CHECK:   destroy_addr [[TEMP_VALUE]] : $*Initializable
 // CHECK:   dealloc_stack [[TEMP_VALUE]] : $*Initializable
diff --git a/test/SILGen/subclass_existentials.swift b/test/SILGen/subclass_existentials.swift
index dbbfcbf..55c5a8b 100644
--- a/test/SILGen/subclass_existentials.swift
+++ b/test/SILGen/subclass_existentials.swift
@@ -128,16 +128,17 @@
   let _: Base<Int> & P = baseAndP.classSelfReturn()
 
   // CHECK: [[PAYLOAD:%.*]] = open_existential_ref [[ARG0]] : $Base<Int> & P to $@opened("{{.*}}") Base<Int> & P
-  // CHECK: [[RESULT_BOX:%.*]] = alloc_stack $@opened("{{.*}}") Base<Int> & P
   // CHECK: [[SELF_BOX:%.*]] = alloc_stack $@opened("{{.*}}") Base<Int> & P
   // CHECK: store_borrow [[PAYLOAD]] to [[SELF_BOX]] : $*@opened("{{.*}}") Base<Int> & P
   // CHECK: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") Base<Int> & P, #P.protocolSelfReturn!1 : <Self where Self : P> (Self) -> () -> @dynamic_self Self, [[PAYLOAD]] : $@opened("{{.*}}") Base<Int> & P : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
-  // CHECK: apply [[METHOD]]<@opened("{{.*}}") Base<Int> & P>([[RESULT_BOX]], [[SELF_BOX]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK: [[RESULT_BOX:%.*]] = alloc_box
+  // CHECK: [[RESULT_BUF:%.*]] = project_box [[RESULT_BOX]]
+  // CHECK: apply [[METHOD]]<@opened("{{.*}}") Base<Int> & P>([[RESULT_BUF]], [[SELF_BOX]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
   // CHECK: dealloc_stack [[SELF_BOX]] : $*@opened("{{.*}}") Base<Int> & P
-  // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BOX]] : $*@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BUF]] : $*@opened("{{.*}}") Base<Int> & P
   // CHECK: [[RESULT:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") Base<Int> & P : $@opened("{{.*}}") Base<Int> & P, $Base<Int> & P
   // CHECK: destroy_value [[RESULT]] : $Base<Int> & P
-  // CHECK: dealloc_stack [[RESULT_BOX]] : $*@opened("{{.*}}") Base<Int> & P
+  // CHECK: dealloc_box [[RESULT_BOX]]
   let _: Base<Int> & P = baseAndP.protocolSelfReturn()
 
   // CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
@@ -150,13 +151,14 @@
   let _: Base<Int> & P = baseAndPType.classSelfReturn()
 
   // CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
-  // CHECK: [[RESULT:%.*]] = alloc_stack $@opened("{{.*}}") (Base<Int> & P)
   // CHECK: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") (Base<Int> & P), #P.protocolSelfReturn!1 : <Self where Self : P> (Self.Type) -> () -> @dynamic_self Self, [[METATYPE]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
-  // CHECK: apply [[METHOD]]<@opened("{{.*}}") (Base<Int> & P)>([[RESULT]], [[METATYPE]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
-  // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT]] : $*@opened("{{.*}}") (Base<Int> & P)
+  // CHECK: [[RESULT_BOX:%.*]] = alloc_box
+  // CHECK: [[RESULT_BUF:%.*]] = project_box
+  // CHECK: apply [[METHOD]]<@opened("{{.*}}") (Base<Int> & P)>([[RESULT_BUF]], [[METATYPE]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
+  // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BUF]] : $*@opened("{{.*}}") (Base<Int> & P)
   // CHECK: [[RESULT_VALUE:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") (Base<Int> & P) : $@opened("{{.*}}") (Base<Int> & P), $Base<Int> & P
   // CHECK: destroy_value [[RESULT_VALUE]]
-  // CHECK: dealloc_stack [[RESULT]]
+  // CHECK: dealloc_box [[RESULT_BOX]]
   let _: Base<Int> & P = baseAndPType.protocolSelfReturn()
 
   // Partial applications
diff --git a/test/SILGen/toplevel_errors.swift b/test/SILGen/toplevel_errors.swift
index f037df0..04b3970 100644
--- a/test/SILGen/toplevel_errors.swift
+++ b/test/SILGen/toplevel_errors.swift
@@ -7,12 +7,14 @@
 throw MyError.A
 
 // CHECK: sil @main
+// CHECK: [[T0:%.*]] = enum $MyError, #MyError.A!enumelt
 // CHECK: [[ERR:%.*]] = alloc_existential_box $Error, $MyError
 // CHECK: [[ADDR:%.*]] = project_existential_box $MyError in [[ERR]] : $Error
-// CHECK: [[T0:%.*]] = enum $MyError, #MyError.A!enumelt
+// CHECK: store [[ERR]] to [init] [[ERRBUF:%.*]] :
 // CHECK: store [[T0]] to [trivial] [[ADDR]] : $*MyError
-// CHECK: builtin "willThrow"([[ERR]] : $Error)
-// CHECK: br bb2([[ERR]] : $Error)
+// CHECK: [[ERR2:%.*]] = load [take] [[ERRBUF]]
+// CHECK: builtin "willThrow"([[ERR2]] : $Error)
+// CHECK: br bb2([[ERR2]] : $Error)
 
 // CHECK: bb1([[T0:%.*]] : $Int32):
 // CHECK: return [[T0]] : $Int32
diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift
index 58a7198..2998f66 100644
--- a/test/SILOptimizer/access_marker_verify.swift
+++ b/test/SILOptimizer/access_marker_verify.swift
@@ -826,13 +826,13 @@
 // CHECK: copy_addr [[P1]] to [initialization] [[TEMP1]] : $*@opened
 // CHECK-NOT: begin_access
 // CHECK: [[OUTC:%.*]] = apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass
-// CHECK: [[OUTANY:%.*]] = init_existential_addr %0 : $*Any, $BaseClass
 // CHECK: [[P2:%.*]] = open_existential_addr immutable_access %1 : $*HasClassGetter to $*@opened
 // CHECK: [[TEMP2:%.*]] = alloc_stack $@opened
 // CHECK-NOT: begin_access
 // CHECK: copy_addr [[P2]] to [initialization] [[TEMP2]] : $*@opened
 // CHECK-NOT: begin_access
 // CHECK: apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass
+// CHECK: [[OUTANY:%.*]] = init_existential_addr %0 : $*Any, $BaseClass
 // CHECK: store %{{.*}} to [init] [[OUTANY]] : $*BaseClass
 // CHECK: return [[OUTC]] : $BaseClass
 // CHECK-LABEL: } // end sil function '$S20access_marker_verify14testMixedTuple1pAA9BaseClassC_yptAA03HasH6Getter_p_tF'
@@ -1003,8 +1003,8 @@
 // CHECK-LABEL: sil private @globalinit{{.*}} : $@convention(c) () -> () {
 // CHECK:   alloc_global @$S20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ
 // CHECK:   [[GADR:%.*]] = global_addr @$S20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ : $*P
-// CHECK:   [[EADR:%.*]] = init_existential_addr [[GADR]] : $*P, $StructP
 // CHECK:   %{{.*}} = apply %{{.*}}({{.*}}) : $@convention(method) (@thin StructP.Type) -> StructP
+// CHECK:   [[EADR:%.*]] = init_existential_addr [[GADR]] : $*P, $StructP
 // CHECK:   store %{{.*}} to [trivial] [[EADR]] : $*StructP
 // CHECK-LABEL: } // end sil function 'globalinit
 
@@ -1019,6 +1019,8 @@
 // CHECK-LABEL: sil @$S20access_marker_verify11testInitBoxyyKF : $@convention(thin) () -> @error Error {
 // CHECK: [[BOXALLOC:%.*]] = alloc_existential_box $Error, $SomeError
 // CHECK: [[PROJ:%.*]] = project_existential_box $SomeError in [[BOXALLOC]] : $Error
+// CHECK: store [[BOXALLOC]] to [init] [[BOXBUF:%.*]] :
 // CHECK: store %{{.*}} to [trivial] [[PROJ]] : $*SomeError
-// CHECK: throw [[BOXALLOC]] : $Error
+// CHECK: [[BOXALLOC2:%.*]] = load [take] [[BOXBUF]]
+// CHECK: throw [[BOXALLOC2]] : $Error
 // CHECK-LABEL: } // end sil function '$S20access_marker_verify11testInitBoxyyKF'