@@ -157,9 +157,58 @@ class MoveOnlyCheckerPass : public SILFunctionTransform {
157157 assert (fn->getModule ().getStage () == SILStage::Raw &&
158158 " Should only run on Raw SIL" );
159159
160+ // If an earlier pass asked us to eliminate the function body if it's
161+ // unused, and the function is in fact unused, do that now.
162+ if (fn->hasSemanticsAttr (semantics::MOVEONLY_DELETE_IF_UNUSED)) {
163+ if (fn->getRefCount () == 0
164+ && !isPossiblyUsedExternally (fn->getLinkage (),
165+ fn->getModule ().isWholeModule ())) {
166+ LLVM_DEBUG (llvm::dbgs () << " ===> Deleting unused function " << fn->getName () << " 's body that was marked for deletion\n " );
167+ // Remove all non-entry blocks.
168+ auto entryBB = fn->begin ();
169+ auto nextBB = std::next (entryBB);
170+
171+ while (nextBB != fn->end ()) {
172+ auto thisBB = nextBB;
173+ ++nextBB;
174+ thisBB->eraseFromParent ();
175+ }
176+
177+ // Rewrite the entry block to only contain an unreachable.
178+ auto loc = entryBB->begin ()->getLoc ();
179+ entryBB->eraseAllInstructions (fn->getModule ());
180+ {
181+ SILBuilder b (&*entryBB);
182+ b.createUnreachable (loc);
183+ }
184+
185+ // If the function has shared linkage, reduce this version to private
186+ // linkage, because we don't want the deleted-body form to win in any
187+ // ODR shootouts.
188+ if (fn->getLinkage () == SILLinkage::Shared) {
189+ fn->setLinkage (SILLinkage::Private);
190+ }
191+
192+ invalidateAnalysis (SILAnalysis::InvalidationKind::FunctionBody);
193+ return ;
194+ }
195+ // If the function wasn't unused, let it continue into diagnostics.
196+ // This would come up if a closure function somehow was used in different
197+ // functions with different escape analysis results. This shouldn't really
198+ // be possible, and we should try harder to make it impossible, but if
199+ // it does happen now, the least bad thing to do is to proceed with
200+ // move checking. This will either succeed and make sure the original
201+ // function contains valid SIL, or raise errors relating to the use
202+ // of the captures in an escaping way, which is the right thing to do
203+ // if they are in fact escapable.
204+ LLVM_DEBUG (llvm::dbgs () << " ===> Function " << fn->getName ()
205+ << " was marked to be deleted, but has uses. Continuing with move checking\n " );
206+
207+ }
208+
160209 // If an earlier pass told use to not emit diagnostics for this function,
161210 // clean up any copies, invalidate the analysis, and return early.
162- if (getFunction () ->hasSemanticsAttr (semantics::NO_MOVEONLY_DIAGNOSTICS)) {
211+ if (fn ->hasSemanticsAttr (semantics::NO_MOVEONLY_DIAGNOSTICS)) {
163212 if (cleanupNonCopyableCopiesAfterEmittingDiagnostic (getFunction ()))
164213 invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
165214 return ;
@@ -169,7 +218,7 @@ class MoveOnlyCheckerPass : public SILFunctionTransform {
169218 << " ===> MoveOnly Checker. Visiting: " << fn->getName () << ' \n ' );
170219
171220 MoveOnlyChecker checker (
172- getFunction () , getAnalysis<DominanceAnalysis>()->get (getFunction () ),
221+ fn , getAnalysis<DominanceAnalysis>()->get (fn ),
173222 getAnalysis<PostOrderAnalysis>());
174223
175224 checker.checkObjects ();
@@ -180,12 +229,12 @@ class MoveOnlyCheckerPass : public SILFunctionTransform {
180229 // non-copyable copies into explicit variants below and let the user
181230 // recompile.
182231 if (!checker.diagnosticEmitter .emittedDiagnostic ()) {
183- emitCheckerMissedCopyOfNonCopyableTypeErrors (getFunction () ,
232+ emitCheckerMissedCopyOfNonCopyableTypeErrors (fn ,
184233 checker.diagnosticEmitter );
185234 }
186235
187236 checker.madeChange |=
188- cleanupNonCopyableCopiesAfterEmittingDiagnostic (getFunction () );
237+ cleanupNonCopyableCopiesAfterEmittingDiagnostic (fn );
189238
190239 if (checker.madeChange )
191240 invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
0 commit comments