Skip to content
Merged
7 changes: 3 additions & 4 deletions include/swift/AST/DiagnosticsSIL.def
Original file line number Diff line number Diff line change
Expand Up @@ -760,12 +760,11 @@ ERROR(sil_moveonlychecker_notconsumable_but_assignable_was_consumed_global_var,
ERROR(sil_moveonlychecker_notconsumable_but_assignable_was_consumed_global_let, none,
"'%0' was consumed but it is illegal to consume a noncopyable global let. One can only read from it",
(StringRef))
ERROR(sil_moveonlychecker_notconsumable_but_assignable_was_consumed_escaping_let, none,
"'%0' was consumed but it is illegal to consume a noncopyable escaping immutable capture. One can only read from it",
(StringRef))
ERROR(sil_moveonlychecker_notconsumable_but_assignable_was_consumed_escaping_var, none,
"'%0' was consumed but it is illegal to consume a noncopyable escaping mutable capture. One can only read from it or assign over it",
"'%0' was consumed but it is illegal to consume a noncopyable mutable capture of an escaping closure. One can only read from it or assign over it",
(StringRef))
ERROR(sil_moveonlychecker_let_capture_consumed, none,
"'%0' was consumed but it is illegal to consume a noncopyable immutable capture of an escaping closure. One can only read from it", (StringRef))

NOTE(sil_moveonlychecker_moveonly_field_consumed_here, none,
"move only field consumed here", ())
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/SemanticAttrs.def
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,9 @@ SEMANTICS_ATTR(LIFETIMEMANAGEMENT_COPY, "lifetimemanagement.copy")

SEMANTICS_ATTR(NO_PERFORMANCE_ANALYSIS, "no_performance_analysis")

// A flag used to turn off moveonly diagnostics on functions that allocbox to
// stack specialized.
SEMANTICS_ATTR(NO_MOVEONLY_DIAGNOSTICS, "sil.optimizer.moveonly.diagnostic.ignore")

#undef SEMANTICS_ATTR

23 changes: 17 additions & 6 deletions lib/SIL/IR/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,26 @@ CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture,
assert(var->hasStorage() &&
"should not have attempted to directly capture this variable");

auto &lowering = getTypeLowering(
var->getType(), TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
expansion.getResilienceExpansion()));

// If this is a noncopyable 'let' constant that is not a shared paramdecl or
// used by a noescape capture, then we know it is boxed and want to pass it in
// its boxed form so we can obey Swift's capture reference semantics.
if (!var->supportsMutation() && lowering.getLoweredType().isPureMoveOnly() &&
!capture.isNoEscape()) {
auto *param = dyn_cast<ParamDecl>(var);
if (!param || param->getValueOwnership() != ValueOwnership::Shared) {
return CaptureKind::ImmutableBox;
}
}

// If this is a non-address-only stored 'let' constant, we can capture it
// by value. If it is address-only, then we can't load it, so capture it
// by its address (like a var) instead.
if (!var->supportsMutation() &&
!getTypeLowering(var->getType(),
TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
expansion.getResilienceExpansion()))
.isAddressOnly())
return CaptureKind::Constant;
if (!var->supportsMutation() && !lowering.isAddressOnly())
return CaptureKind::Constant;

// In-out parameters are captured by address.
if (auto *param = dyn_cast<ParamDecl>(var)) {
Expand Down
34 changes: 24 additions & 10 deletions lib/SILGen/SILGenConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,11 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
// Allocate the local variable for 'self'.
emitLocalVariableWithCleanup(selfDecl, MUIKind)->finishInitialization(*this);

SILValue selfLV = VarLocs[selfDecl].value;
ManagedValue selfLV =
maybeEmitValueOfLocalVarDecl(selfDecl, AccessKind::ReadWrite);
if (!selfLV)
selfLV = maybeEmitAddressForBoxOfLocalVarDecl(selfDecl, selfDecl);
assert(selfLV);

// Emit the prolog.
emitBasicProlog(ctor->getParameters(),
Expand Down Expand Up @@ -491,7 +495,13 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {

if (!F.getConventions().hasIndirectSILResults()) {
// Otherwise, load and return the final 'self' value.
selfValue = lowering.emitLoad(B, cleanupLoc, selfLV,
if (selfLV.getType().isMoveOnly()) {
selfLV = B.createMarkMustCheckInst(
cleanupLoc, selfLV,
MarkMustCheckInst::CheckKind::AssignableButNotConsumable);
}

selfValue = lowering.emitLoad(B, cleanupLoc, selfLV.getValue(),
LoadOwnershipQualifier::Copy);

// Inject the self value into an optional if the constructor is failable.
Expand All @@ -513,17 +523,16 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
returnAddress = completeReturnAddress;
} else {
// If this is a failable initializer, project out the payload.
returnAddress = B.createInitEnumDataAddr(cleanupLoc,
completeReturnAddress,
getASTContext().getOptionalSomeDecl(),
selfLV->getType());
returnAddress = B.createInitEnumDataAddr(
cleanupLoc, completeReturnAddress,
getASTContext().getOptionalSomeDecl(), selfLV.getType());
}

// We have to do a non-take copy because someone else may be using the
// box (e.g. someone could have closed over it).
B.createCopyAddr(cleanupLoc, selfLV, returnAddress,
B.createCopyAddr(cleanupLoc, selfLV.getLValueAddress(), returnAddress,
IsNotTake, IsInitialization);

// Inject the enum tag if the result is optional because of failability.
if (ctor->isFailable()) {
// Inject the 'Some' tag.
Expand Down Expand Up @@ -1022,14 +1031,19 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
static ManagedValue emitSelfForMemberInit(SILGenFunction &SGF, SILLocation loc,
VarDecl *selfDecl) {
CanType selfFormalType = selfDecl->getType()->getCanonicalType();
if (selfFormalType->hasReferenceSemantics())
if (selfFormalType->hasReferenceSemantics()) {
return SGF.emitRValueForDecl(loc, selfDecl, selfFormalType,
AccessSemantics::DirectToStorage,
SGFContext::AllowImmediatePlusZero)
.getAsSingleValue(SGF, loc);
else
} else {
// First see if we have a variable that is boxed without a value.
if (auto value = SGF.maybeEmitAddressForBoxOfLocalVarDecl(loc, selfDecl))
return value;
// Otherwise, emit the address directly.
return SGF.emitAddressOfLocalVarDecl(loc, selfDecl, selfFormalType,
SGFAccessKind::Write);
}
}

// FIXME: Can emitMemberInit() share code with InitializationForPattern in
Expand Down
51 changes: 31 additions & 20 deletions lib/SILGen/SILGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,13 +351,13 @@ class LocalVariableInitialization : public SingleBufferInitialization {
"can't emit a local var for a non-local var decl");
assert(decl->hasStorage() && "can't emit storage for a computed variable");
assert(!SGF.VarLocs.count(decl) && "Already have an entry for this decl?");

// The box type's context is lowered in the minimal resilience domain.
auto instanceType = SGF.SGM.Types.getLoweredRValueType(
TypeExpansionContext::minimal(), decl->getType());
auto boxType = SGF.SGM.Types.getContextBoxTypeForCapture(
decl,
SGF.SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(),
decl->getType()),
SGF.F.getGenericEnvironment(),
/*mutable*/ true);
decl, instanceType, SGF.F.getGenericEnvironment(),
/*mutable*/ !instanceType->isPureMoveOnly() || !decl->isLet());

// The variable may have its lifetime extended by a closure, heap-allocate
// it using a box.
Expand All @@ -376,12 +376,8 @@ class LocalVariableInitialization : public SingleBufferInitialization {
}
}

Addr = SGF.B.createProjectBox(decl, Box, 0);
if (Addr->getType().isMoveOnly()) {
// TODO: Handle no implicit copy here.
Addr = SGF.B.createMarkMustCheckInst(
decl, Addr, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
}
if (!Box->getType().isBoxedNonCopyableType(Box->getFunction()))
Addr = SGF.B.createProjectBox(decl, Box, 0);

// Push a cleanup to destroy the local variable. This has to be
// inactive until the variable is initialized.
Expand All @@ -401,16 +397,24 @@ class LocalVariableInitialization : public SingleBufferInitialization {
}

SILValue getAddress() const {
assert(Addr);
return Addr;
}

/// If we have an address, returns the address. Otherwise, if we only have a
/// box, lazily projects it out and returns it.
SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
SILLocation loc) override {
if (!Addr && Box) {
auto pbi = SGF.B.createProjectBox(loc, Box, 0);
return pbi;
}

return getAddress();
}

bool isInPlaceInitializationOfGlobal() const override {
return isa<GlobalAddrInst>(getAddress());
return dyn_cast_or_null<GlobalAddrInst>(Addr);
}

void finishUninitialized(SILGenFunction &SGF) override {
Expand All @@ -421,7 +425,11 @@ class LocalVariableInitialization : public SingleBufferInitialization {
/// Remember that this is the memory location that we've emitted the
/// decl to.
assert(SGF.VarLocs.count(decl) == 0 && "Already emitted the local?");
SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(Addr, Box);

if (Addr)
SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(Addr, Box);
else
SGF.VarLocs[decl] = SILGenFunction::VarLoc::getForBox(Box);

SingleBufferInitialization::finishInitialization(SGF);
assert(!DidFinish &&
Expand Down Expand Up @@ -485,9 +493,13 @@ class LetValueInitialization : public Initialization {
isUninitialized = true;
} else {
// If this is a let with an initializer or bound value, we only need a
// buffer if the type is address only.
// buffer if the type is address only or is noncopyable.
//
// For noncopyable types, we always need to box them and eagerly
// reproject.
needsTemporaryBuffer =
lowering->isAddressOnly() && SGF.silConv.useLoweredAddresses();
(lowering->isAddressOnly() && SGF.silConv.useLoweredAddresses()) ||
lowering->getLoweredType().isPureMoveOnly();
}

// Make sure that we have a non-address only type when binding a
Expand Down Expand Up @@ -634,8 +646,7 @@ class LetValueInitialization : public Initialization {
// We do this before the begin_borrow "normal" path below since move only
// types do not have no implicit copy attr on them.
if (value->getOwnershipKind() == OwnershipKind::Owned &&
value->getType().isMoveOnly() &&
!value->getType().isMoveOnlyWrapped()) {
value->getType().isPureMoveOnly()) {
value = SGF.B.createMoveValue(PrologueLoc, value, true /*isLexical*/);
return SGF.B.createMarkMustCheckInst(
PrologueLoc, value,
Expand Down Expand Up @@ -1253,10 +1264,10 @@ SILGenFunction::emitInitializationForVarDecl(VarDecl *vd, bool forceImmutable) {

assert(!isa<InOutType>(varType) && "local variables should never be inout");

// If this is a 'let' initialization for a non-global, set up a
// let binding, which stores the initialization value into VarLocs directly.
// If this is a 'let' initialization for a copyable non-global, set up a let
// binding, which stores the initialization value into VarLocs directly.
if (forceImmutable && vd->getDeclContext()->isLocalContext() &&
!isa<ReferenceStorageType>(varType))
!isa<ReferenceStorageType>(varType) && !varType->isPureMoveOnly())
return InitializationPtr(new LetValueInitialization(vd, *this));

// If the variable has no initial value, emit a mark_uninitialized instruction
Expand Down
20 changes: 13 additions & 7 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@ void SILGenFunction::emitCaptures(SILLocation loc,

// Get an address value for a SILValue if it is address only in an type
// expansion context without opaque archetype substitution.
auto getAddressValue = [&](SILValue entryValue) -> SILValue {
auto getAddressValue = [&](VarLoc entryVarLoc) -> SILValue {
SILValue entryValue = entryVarLoc.getValueOrBoxedValue(*this, vd);
if (SGM.M.useLoweredAddresses()
&& SGM.Types
.getTypeLowering(
Expand All @@ -382,7 +383,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
case CaptureKind::Constant: {
// let declarations.
auto &tl = getTypeLowering(valueType);
SILValue Val = Entry.value;
SILValue Val = Entry.getValueOrBoxedValue(*this);
bool eliminateMoveOnlyWrapper =
Val->getType().isMoveOnlyWrapped() &&
!vd->getInterfaceType()->is<SILMoveOnlyWrappedType>();
Expand All @@ -409,6 +410,11 @@ void SILGenFunction::emitCaptures(SILLocation loc,
} else {
// If we have a mutable binding for a 'let', such as 'self' in an
// 'init' method, load it.
if (Val->getType().isMoveOnly()) {
Val = B.createMarkMustCheckInst(
loc, Val,
MarkMustCheckInst::CheckKind::AssignableButNotConsumable);
}
Val = emitLoad(loc, Val, tl, SGFContext(), IsNotTake).forward(*this);
}

Expand All @@ -425,14 +431,14 @@ void SILGenFunction::emitCaptures(SILLocation loc,
if (canGuarantee) {
// No-escaping stored declarations are captured as the
// address of the value.
auto entryValue = getAddressValue(Entry.value);
auto entryValue = getAddressValue(Entry);
capturedArgs.push_back(ManagedValue::forBorrowedRValue(entryValue));
}
else if (!silConv.useLoweredAddresses()) {
capturedArgs.push_back(
B.createCopyValue(loc, ManagedValue::forUnmanaged(Entry.value)));
} else {
auto entryValue = getAddressValue(Entry.value);
auto entryValue = getAddressValue(Entry);
// We cannot pass a valid SILDebugVariable while creating the temp here
// See rdar://60425582
auto addr = B.createAllocStack(loc, entryValue->getType().getObjectType());
Expand All @@ -443,7 +449,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
break;
}
case CaptureKind::StorageAddress: {
auto entryValue = getAddressValue(Entry.value);
auto entryValue = getAddressValue(Entry);
// No-escaping stored declarations are captured as the
// address of the value.
assert(entryValue->getType().isAddress() && "no address for captured var!");
Expand All @@ -452,7 +458,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
}

case CaptureKind::Box: {
auto entryValue = getAddressValue(Entry.value);
auto entryValue = getAddressValue(Entry);
// LValues are captured as both the box owning the value and the
// address of the value.
assert(entryValue->getType().isAddress() && "no address for captured var!");
Expand Down Expand Up @@ -501,7 +507,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
break;
}
case CaptureKind::ImmutableBox: {
auto entryValue = getAddressValue(Entry.value);
auto entryValue = getAddressValue(Entry);
// LValues are captured as both the box owning the value and the
// address of the value.
assert(entryValue->getType().isAddress() &&
Expand Down
Loading