@@ -526,29 +526,46 @@ static LValueTypeData getValueTypeData(SILGenFunction &SGF,
526526
527527// / Given the address of an optional value, unsafely project out the
528528// / address of the value.
529- static ManagedValue getAddressOfOptionalValue (SILGenFunction &SGF,
529+ static ManagedValue getPayloadOfOptionalValue (SILGenFunction &SGF,
530530 SILLocation loc,
531- ManagedValue optAddr,
532- const LValueTypeData &valueTypeData) {
531+ ManagedValue optBase,
532+ const LValueTypeData &valueTypeData,
533+ SGFAccessKind accessKind) {
533534 // Project out the 'Some' payload.
534535 EnumElementDecl *someDecl = SGF.getASTContext ().getOptionalSomeDecl ();
535536
536537 // If the base is +1, we want to forward the cleanup.
537- bool hadCleanup = optAddr.hasCleanup ();
538+ SILValue value;
539+ bool isOwned;
540+ if (optBase.isPlusOne (SGF)) {
541+ value = optBase.forward (SGF);
542+ isOwned = true ;
543+ } else {
544+ value = optBase.getValue ();
545+ isOwned = false ;
546+ }
538547
539548 // UncheckedTakeEnumDataAddr is safe to apply to Optional, because it is
540549 // a single-payload enum. There will (currently) never be spare bits
541550 // embedded in the payload.
542- SILValue valueAddr =
543- SGF.B .createUncheckedTakeEnumDataAddr (loc, optAddr.forward (SGF), someDecl,
551+ SILValue payload;
552+ if (optBase.getType ().isAddress ()) {
553+ payload = SGF.B .createUncheckedTakeEnumDataAddr (loc, value, someDecl,
544554 SILType::getPrimitiveAddressType (
545- valueTypeData.TypeOfRValue ));
555+ valueTypeData.TypeOfRValue ));
556+ } else {
557+ payload = SGF.B .createUncheckedEnumData (loc, value, someDecl,
558+ SILType::getPrimitiveObjectType (
559+ valueTypeData.TypeOfRValue ));
560+ }
546561
547562 // Return the value as +1 if the optional was +1.
548- if (hadCleanup) {
549- return SGF.emitManagedBufferWithCleanup (valueAddr);
563+ if (isOwned) {
564+ return SGF.emitManagedBufferWithCleanup (payload);
565+ } else if (payload->getType ().isAddress ()) {
566+ return ManagedValue::forLValue (payload);
550567 } else {
551- return ManagedValue::forLValue (valueAddr );
568+ return ManagedValue::forBorrowedRValue (payload );
552569 }
553570}
554571
@@ -4348,10 +4365,12 @@ LValue SILGenLValue::visitBindOptionalExpr(BindOptionalExpr *e,
43484365 // Binding reads the base even if we then only write to the result.
43494366 auto baseAccessKind = getBaseAccessKindForStorage (accessKind);
43504367
4351- // We're going to take the address of the base.
4352- // TODO: deal more efficiently with an object-preferring access.
4353- baseAccessKind = getAddressAccessKind (baseAccessKind);
4354-
4368+ if (!isBorrowAccess (accessKind)) {
4369+ // We're going to take the address of the base.
4370+ // TODO: deal more efficiently with an object-preferring access.
4371+ baseAccessKind = getAddressAccessKind (baseAccessKind);
4372+ }
4373+
43554374 // Do formal evaluation of the base l-value.
43564375 LValue optLV = visitRec (e->getSubExpr (), baseAccessKind,
43574376 options.forComputedBaseLValue ());
@@ -4360,21 +4379,65 @@ LValue SILGenLValue::visitBindOptionalExpr(BindOptionalExpr *e,
43604379 LValueTypeData valueTypeData =
43614380 getOptionalObjectTypeData (SGF, accessKind, optTypeData);
43624381
4363- // The chaining operator immediately begins a formal access to the
4364- // base l-value. In concrete terms, this means we can immediately
4365- // evaluate the base down to an address.
4366- ManagedValue optAddr = SGF.emitAddressOfLValue (e, std::move (optLV));
4367-
4382+ // The chaining operator immediately evaluates the base.
4383+ // For move-checking purposes, the binding is also treated as an opaque use
4384+ // of the entire value, since we can't leave the value partially initialized
4385+ // across multiple optional binding expressions.
4386+ ManagedValue optBase;
4387+ if (isBorrowAccess (baseAccessKind)) {
4388+ optBase = SGF.emitBorrowedLValue (e, std::move (optLV));
4389+
4390+ if (optBase.getType ().isMoveOnly ()) {
4391+ if (optBase.getType ().isAddress ()) {
4392+ optBase = SGF.B .createFormalAccessOpaqueBorrowBeginAccess (e, optBase);
4393+ if (optBase.getType ().isLoadable (SGF.F )) {
4394+ optBase = SGF.B .createFormalAccessLoadBorrow (e, optBase);
4395+ }
4396+ } else {
4397+ optBase = SGF.B .createFormalAccessBeginBorrow (e, optBase,
4398+ false ,
4399+ /* fixed*/ true );
4400+ }
4401+ }
4402+ } else {
4403+ optBase = SGF.emitAddressOfLValue (e, std::move (optLV));
4404+
4405+ if (isConsumeAccess (accessKind)) {
4406+ if (optBase.getType ().isMoveOnly ()) {
4407+ optBase = SGF.B .createFormalAccessOpaqueConsumeBeginAccess (e, optBase);
4408+ } else {
4409+ // Take ownership of the base.
4410+ optBase = SGF.emitFormalAccessManagedRValueWithCleanup (e,
4411+ optBase.getValue ());
4412+ }
4413+ }
4414+ }
43684415 // Bind the value, branching to the destination address if there's no
43694416 // value there.
4370- SGF.emitBindOptionalAddress (e, optAddr, e->getDepth ());
4417+ assert (e->getDepth () < SGF.BindOptionalFailureDests .size ());
4418+ auto failureDepth = SGF.BindOptionalFailureDests .size () - e->getDepth () - 1 ;
4419+ auto failureDest = SGF.BindOptionalFailureDests [failureDepth];
4420+ assert (failureDest.isValid () && " too big to fail" );
4421+
4422+ // Since we know that we have an address, we do not need to worry about
4423+ // ownership invariants. Instead just use a select_enum_addr.
4424+ SILBasicBlock *someBB = SGF.createBasicBlock ();
4425+ SILValue hasValue = SGF.emitDoesOptionalHaveValue (e, optBase.getValue ());
4426+
4427+ auto noneBB = SGF.Cleanups .emitBlockForCleanups (failureDest, e);
4428+ SGF.B .createCondBranch (e, hasValue, someBB, noneBB);
4429+
4430+ // Reset the insertion point at the end of hasValueBB so we can
4431+ // continue to emit code there.
4432+ SGF.B .setInsertionPoint (someBB);
43714433
43724434 // Project out the payload on the success branch. We can just use a
43734435 // naked ValueComponent here; this is effectively a separate l-value.
4374- ManagedValue valueAddr =
4375- getAddressOfOptionalValue (SGF, e, optAddr , valueTypeData);
4436+ ManagedValue optPayload =
4437+ getPayloadOfOptionalValue (SGF, e, optBase , valueTypeData, accessKind );
43764438 LValue valueLV;
4377- valueLV.add <ValueComponent>(valueAddr, std::nullopt , valueTypeData);
4439+ valueLV.add <ValueComponent>(optPayload, std::nullopt , valueTypeData,
4440+ /* is rvalue*/ optBase.getType ().isObject ());
43784441 return valueLV;
43794442}
43804443
@@ -5324,13 +5387,11 @@ RValue SILGenFunction::emitRValueForStorageLoad(
53245387ManagedValue SILGenFunction::emitAddressOfLValue (SILLocation loc,
53255388 LValue &&src,
53265389 TSanKind tsanKind) {
5327- // Write is only included in this list because of property behaviors.
5328- // It's obviously unreasonable, though.
53295390 assert (src.getAccessKind () == SGFAccessKind::IgnoredRead ||
53305391 src.getAccessKind () == SGFAccessKind::BorrowedAddressRead ||
53315392 src.getAccessKind () == SGFAccessKind::OwnedAddressRead ||
5332- src.getAccessKind () == SGFAccessKind::ReadWrite ||
5333- src.getAccessKind () == SGFAccessKind::Write );
5393+ src.getAccessKind () == SGFAccessKind::OwnedAddressConsume ||
5394+ src.getAccessKind () == SGFAccessKind::ReadWrite );
53345395
53355396 ManagedValue addr;
53365397 PathComponent &&component =
0 commit comments