@@ -3178,6 +3178,9 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
31783178 llvm::dbgs () << ' \n ' );
31793179
31803180 auto subjectTy = S->getSubjectExpr ()->getType ();
3181+ auto subjectLoweredTy = getLoweredType (subjectTy);
3182+ auto subjectLoweredAddress =
3183+ silConv.useLoweredAddresses () && subjectLoweredTy.isAddressOnly (F);
31813184
31823185 // If the subject expression is uninhabited, we're already dead.
31833186 // Emit an unreachable in place of the switch statement.
@@ -3254,27 +3257,88 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
32543257 emission.emitAddressOnlyAllocations ();
32553258
32563259 SILBasicBlock *contBB = createBasicBlock ();
3257- JumpDest contDest (contBB, Cleanups.getCleanupsDepth (), CleanupLocation (S));
3258-
3260+ // Depending on the switch ownership behavior, we want to either:
3261+ //
3262+ // - allow the subject to (potentially or explicitly) be forwarded into the
3263+ // case blocks. In this case we want to include the cleanups for the subject
3264+ // in the case blocks so that the subject and its components can be
3265+ // consumed by each case block.
3266+ //
3267+ // or:
3268+ //
3269+ // - evaluate the subject under a formal access scope (a borrow or inout).
3270+ // In this case the lifetime of the access should cover all the way to the
3271+ // exits out of the switch.
3272+ //
3273+ // When we break out of a case block, we take the subject's remnants with us
3274+ // in the former case, but not the latter.q
3275+ CleanupsDepth subjectDepth = Cleanups.getCleanupsDepth ();
32593276 LexicalScope switchScope (*this , CleanupLocation (S));
3277+ llvm::Optional<FormalEvaluationScope> switchFormalAccess;
3278+
3279+ bool subjectUndergoesFormalAccess;
3280+ switch (ownership) {
3281+ // For normal copyable subjects, we allow the value to be forwarded into
3282+ // the cases, since we can copy it as needed to evaluate the pattern match.
3283+ case ValueOwnership::Default:
3284+ // Similarly, if the subject is an explicitly consumed noncopyable value,
3285+ // we can forward ownership of the subject's parts into matching case blocks.
3286+ case ValueOwnership::Owned:
3287+ subjectUndergoesFormalAccess = false ;
3288+ break ;
32603289
3261- // Enter a break/continue scope. If we wanted a continue
3262- // destination, it would probably be out here.
3263- BreakContinueDestStack.push_back ({S, contDest, JumpDest (S)});
3290+ // Borrowed and inout pattern matches both undergo a formal access.
3291+ case ValueOwnership::Shared:
3292+ case ValueOwnership::InOut:
3293+ subjectUndergoesFormalAccess = true ;
3294+ break ;
3295+ }
32643296
32653297 PatternMatchContext switchContext = { emission };
32663298 SwitchStack.push_back (&switchContext);
32673299
3268- // Emit the subject value. If at +1, dispatching will consume it. If it is at
3269- // +0, we just forward down borrows.
3270- //
3271- // TODO: For an inout switch, we'd start a formal access to an lvalue here.
3272- ManagedValue subjectMV = emitRValueAsSingleValue (
3273- S->getSubjectExpr (),
3274- ownership <= ValueOwnership::Shared
3275- ? SGFContext::AllowGuaranteedPlusZero
3276- : SGFContext ());
3277-
3300+ // Emit the subject value.
3301+ ManagedValue subjectMV;
3302+ switch (ownership) {
3303+ case ValueOwnership::Default: {
3304+ // A regular copyable pattern match. Emit as a regular rvalue.
3305+ // If at +1, dispatching will consume it. If it is at +0, we just forward
3306+ // down borrows.
3307+ subjectMV = emitRValueAsSingleValue (
3308+ S->getSubjectExpr (),
3309+ SGFContext::AllowGuaranteedPlusZero);
3310+ break ;
3311+ }
3312+ case ValueOwnership::Shared: {
3313+ // A borrowing pattern match. See if we can emit the subject under a read
3314+ // formal access.
3315+ switchFormalAccess.emplace (*this );
3316+ auto subjectExpr = S->getSubjectExpr ();
3317+ if (auto subjectLVExpr = findStorageReferenceExprForMoveOnly (subjectExpr,
3318+ StorageReferenceOperationKind::Borrow)) {
3319+ LValue sharedLV = emitLValue (subjectLVExpr,
3320+ subjectLoweredAddress ? SGFAccessKind::BorrowedAddressRead
3321+ : SGFAccessKind::BorrowedObjectRead);
3322+ subjectMV = emitBorrowedLValue (S->getSubjectExpr (), std::move (sharedLV));
3323+ } else {
3324+ // Emit the value as an allowed-+0 rvalue if it doesn't have special
3325+ // lvalue treatment.
3326+ subjectMV = emitRValueAsSingleValue (S->getSubjectExpr (),
3327+ SGFContext::AllowGuaranteedPlusZero);
3328+ }
3329+ break ;
3330+ }
3331+ case ValueOwnership::InOut: {
3332+ // A mutating pattern match. Emit the subject under a modify access.
3333+ llvm_unreachable (" not yet implemented" );
3334+ }
3335+ case ValueOwnership::Owned: {
3336+ // A consuming pattern match. Emit as a +1 rvalue.
3337+ subjectMV = emitRValueAsSingleValue (S->getSubjectExpr ());
3338+ break ;
3339+ }
3340+ }
3341+
32783342 // Inline constructor for subject.
32793343 auto subject = ([&]() -> ConsumableManagedValue {
32803344 if (subjectMV.getType ().isMoveOnly ()) {
@@ -3292,12 +3356,15 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
32923356
32933357 case ValueOwnership::Shared:
32943358 emission.setNoncopyableBorrowingOwnership ();
3359+ if (!subjectMV.isPlusZero ()) {
3360+ subjectMV = subjectMV.borrow (*this , S);
3361+ }
32953362 if (subjectMV.getType ().isAddress () &&
32963363 subjectMV.getType ().isLoadable (F)) {
32973364 // Load a borrow if the type is loadable.
3298- subjectMV = B. createLoadBorrow (S, subjectMV);
3299- } else if (!subjectMV. isPlusZero ()) {
3300- subjectMV = subjectMV. borrow (* this , S );
3365+ subjectMV = subjectUndergoesFormalAccess
3366+ ? B. createFormalAccessLoadBorrow (S, subjectMV)
3367+ : B. createLoadBorrow (S, subjectMV );
33013368 }
33023369 return {subjectMV, CastConsumptionKind::BorrowAlways};
33033370
@@ -3385,6 +3452,20 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
33853452 return {subjectMV.copy (*this , S), CastConsumptionKind::TakeAlways};
33863453 }());
33873454
3455+ CleanupsDepth caseBodyDepth = Cleanups.getCleanupsDepth ();
3456+ llvm::Optional<LexicalScope> caseBodyScope;
3457+ if (subjectUndergoesFormalAccess) {
3458+ caseBodyScope.emplace (*this , CleanupLocation (S));
3459+ }
3460+
3461+ // Enter a break/continue scope. As discussed above, the depth we jump to
3462+ // depends on whether the subject is under a formal access.
3463+ JumpDest contDest (contBB,
3464+ subjectUndergoesFormalAccess ? caseBodyDepth
3465+ : subjectDepth,
3466+ CleanupLocation (S));
3467+ BreakContinueDestStack.push_back ({S, contDest, JumpDest (S)});
3468+
33883469 // If we need to diagnose an unexpected enum case or unexpected enum case
33893470 // value, we need access to a value metatype for the subject. Emit this state
33903471 // now before we emit the actual switch to ensure that the subject has not
@@ -3446,7 +3527,14 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
34463527 }
34473528
34483529 assert (!B.hasValidInsertionPoint ());
3449- switchScope.pop ();
3530+ // Disable the cleanups for values that should be consumed by the case
3531+ // bodies.
3532+ caseBodyScope.reset ();
3533+ // If the subject isn't under a formal access, that includes the subject
3534+ // itself.
3535+ if (!subjectUndergoesFormalAccess) {
3536+ switchScope.pop ();
3537+ }
34503538
34513539 // Then emit the case blocks shared by multiple pattern cases.
34523540 emission.emitSharedCaseBlocks (
@@ -3463,6 +3551,12 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
34633551 } else {
34643552 B.emitBlock (contBB);
34653553 }
3554+
3555+ // End the formal access to the subject now (if there was one).
3556+ if (subjectUndergoesFormalAccess) {
3557+ switchFormalAccess.reset ();
3558+ switchScope.pop ();
3559+ }
34663560
34673561 // Now that we have emitted everything, see if our unexpected enum case info
34683562 // metatypes were actually used. If not, delete them.
0 commit comments