@@ -526,29 +526,46 @@ static LValueTypeData getValueTypeData(SILGenFunction &SGF,
526
526
527
527
// / Given the address of an optional value, unsafely project out the
528
528
// / address of the value.
529
- static ManagedValue getAddressOfOptionalValue (SILGenFunction &SGF,
529
+ static ManagedValue getPayloadOfOptionalValue (SILGenFunction &SGF,
530
530
SILLocation loc,
531
- ManagedValue optAddr,
532
- const LValueTypeData &valueTypeData) {
531
+ ManagedValue optBase,
532
+ const LValueTypeData &valueTypeData,
533
+ SGFAccessKind accessKind) {
533
534
// Project out the 'Some' payload.
534
535
EnumElementDecl *someDecl = SGF.getASTContext ().getOptionalSomeDecl ();
535
536
536
537
// 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
+ }
538
547
539
548
// UncheckedTakeEnumDataAddr is safe to apply to Optional, because it is
540
549
// a single-payload enum. There will (currently) never be spare bits
541
550
// 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,
544
554
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
+ }
546
561
547
562
// 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);
550
567
} else {
551
- return ManagedValue::forLValue (valueAddr );
568
+ return ManagedValue::forBorrowedRValue (payload );
552
569
}
553
570
}
554
571
@@ -4348,10 +4365,12 @@ LValue SILGenLValue::visitBindOptionalExpr(BindOptionalExpr *e,
4348
4365
// Binding reads the base even if we then only write to the result.
4349
4366
auto baseAccessKind = getBaseAccessKindForStorage (accessKind);
4350
4367
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
+
4355
4374
// Do formal evaluation of the base l-value.
4356
4375
LValue optLV = visitRec (e->getSubExpr (), baseAccessKind,
4357
4376
options.forComputedBaseLValue ());
@@ -4360,21 +4379,65 @@ LValue SILGenLValue::visitBindOptionalExpr(BindOptionalExpr *e,
4360
4379
LValueTypeData valueTypeData =
4361
4380
getOptionalObjectTypeData (SGF, accessKind, optTypeData);
4362
4381
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
+ }
4368
4415
// Bind the value, branching to the destination address if there's no
4369
4416
// 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);
4371
4433
4372
4434
// Project out the payload on the success branch. We can just use a
4373
4435
// 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 );
4376
4438
LValue valueLV;
4377
- valueLV.add <ValueComponent>(valueAddr, std::nullopt, valueTypeData);
4439
+ valueLV.add <ValueComponent>(optPayload, std::nullopt, valueTypeData,
4440
+ /* is rvalue*/ optBase.getType ().isObject ());
4378
4441
return valueLV;
4379
4442
}
4380
4443
@@ -5324,13 +5387,11 @@ RValue SILGenFunction::emitRValueForStorageLoad(
5324
5387
ManagedValue SILGenFunction::emitAddressOfLValue (SILLocation loc,
5325
5388
LValue &&src,
5326
5389
TSanKind tsanKind) {
5327
- // Write is only included in this list because of property behaviors.
5328
- // It's obviously unreasonable, though.
5329
5390
assert (src.getAccessKind () == SGFAccessKind::IgnoredRead ||
5330
5391
src.getAccessKind () == SGFAccessKind::BorrowedAddressRead ||
5331
5392
src.getAccessKind () == SGFAccessKind::OwnedAddressRead ||
5332
- src.getAccessKind () == SGFAccessKind::ReadWrite ||
5333
- src.getAccessKind () == SGFAccessKind::Write );
5393
+ src.getAccessKind () == SGFAccessKind::OwnedAddressConsume ||
5394
+ src.getAccessKind () == SGFAccessKind::ReadWrite );
5334
5395
5335
5396
ManagedValue addr;
5336
5397
PathComponent &&component =
0 commit comments