Skip to content

[5.9🍒] prevent reinitialization of self after discard #66352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,10 @@ final public class MoveValueInst : SingleValueInstruction, UnaryInstruction {
public var fromValue: Value { operand.value }
}

final public class DropDeinitInst : SingleValueInstruction, UnaryInstruction {
public var fromValue: Value { operand.value }
}

final public class StrongCopyUnownedValueInst : SingleValueInstruction, UnaryInstruction {}

final public class StrongCopyUnmanagedValueInst : SingleValueInstruction, UnaryInstruction {}
Expand Down
1 change: 1 addition & 0 deletions SwiftCompilerSources/Sources/SIL/Registration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public func registerSILClasses() {
register(ProjectBoxInst.self)
register(CopyValueInst.self)
register(MoveValueInst.self)
register(DropDeinitInst.self)
register(EndCOWMutationInst.self)
register(ClassifyBridgeObjectInst.self)
register(PartialApplyInst.self)
Expand Down
23 changes: 23 additions & 0 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6148,6 +6148,29 @@ a type `T` into the move only value space.
The ``lexical`` attribute specifies that the value corresponds to a local
variable in the Swift source.


drop_deinit
```````````

::

sil-instruction ::= 'drop_deinit' sil-operand

%1 = drop_deinit %0 : $T
// T must be a move-only type
// %1 is an @owned T
%3 = drop_deinit %2 : $*T
// T must be a move-only type
// %2 has type *T

This instruction is a marker for a following destroy instruction to suppress
the call of the move-only type's deinitializer.
The instruction accepts an object or address type.
If its argument is an object type it takes in an `@owned T` and produces a new
`@owned T`. If its argument is an address type, it's an identity projection.

The instruction is only valid in ownership SIL.

release_value
`````````````

Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/DiagnosticsSIL.def
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,13 @@ ERROR(sil_movechecking_notconsumable_but_assignable_was_consumed, none,
ERROR(sil_movechecking_cannot_destructure_has_deinit, none,
"cannot partially consume '%0' when it has a deinitializer",
(StringRef))
ERROR(sil_movechecking_discard_missing_consume_self, none,
"must consume 'self' before exiting method that discards self", ())
ERROR(sil_movechecking_reinit_after_discard, none,
"cannot reinitialize 'self' after 'discard self'", ())

NOTE(sil_movechecking_discard_self_here, none,
"discarded self here", ())
NOTE(sil_movechecking_partial_consume_here, none,
"partially consumed here", ())
NOTE(sil_movechecking_consuming_use_here, none,
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/MemAccessUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -1632,6 +1632,7 @@ inline bool isAccessStorageIdentityCast(SingleValueInstruction *svi) {
// Simply pass-thru the incoming address.
case SILInstructionKind::MarkUninitializedInst:
case SILInstructionKind::MarkMustCheckInst:
case SILInstructionKind::DropDeinitInst:
case SILInstructionKind::MarkUnresolvedReferenceBindingInst:
case SILInstructionKind::MarkDependenceInst:
case SILInstructionKind::CopyValueInst:
Expand Down
8 changes: 8 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,14 @@ class SILBuilder {
operand, isLexical));
}

DropDeinitInst *createDropDeinit(SILLocation loc, SILValue operand) {
assert(getFunction().hasOwnership());
assert(!operand->getType().isTrivial(getFunction()) &&
"Should not be passing trivial values to this api.");
return insert(new (getModule()) DropDeinitInst(getSILDebugLocation(loc),
operand));
}

MarkUnresolvedMoveAddrInst *createMarkUnresolvedMoveAddr(SILLocation loc,
SILValue srcAddr,
SILValue takeAddr) {
Expand Down
11 changes: 11 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1896,6 +1896,17 @@ void SILCloner<ImplClass>::visitMoveValueInst(MoveValueInst *Inst) {
recordClonedInstruction(Inst, MVI);
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitDropDeinitInst(DropDeinitInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
if (!getBuilder().hasOwnership()) {
return recordFoldedValue(Inst, getOpValue(Inst->getOperand()));
}
auto *MVI = getBuilder().createDropDeinit(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand()));
recordClonedInstruction(Inst, MVI);
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitMarkMustCheckInst(MarkMustCheckInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
Expand Down
9 changes: 9 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -8301,6 +8301,15 @@ class MoveValueInst
void removeIsLexical() { lexical = false; }
};

class DropDeinitInst
: public UnaryInstructionBase<SILInstructionKind::DropDeinitInst,
SingleValueInstruction> {
friend class SILBuilder;

DropDeinitInst(SILDebugLocation DebugLoc, SILValue operand)
: UnaryInstructionBase(DebugLoc, operand, operand->getType()) {}
};

/// Equivalent to a copy_addr to [init] except that it is used for diagnostics
/// and should not be pattern matched. During the diagnostic passes, the "move
/// function" checker for addresses always converts this to a copy_addr [init]
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
// effects relative to other OSSA values like copy_value.
SINGLE_VALUE_INST(MoveValueInst, move_value, SingleValueInstruction, None,
DoesNotRelease)
SINGLE_VALUE_INST(DropDeinitInst, drop_deinit, SingleValueInstruction, None,
DoesNotRelease)
// A canary value inserted by a SIL generating frontend to signal to the move
// checker to check a specific value. Valid only in Raw SIL. The relevant
// checkers should remove the mark_must_check instruction after successfully
Expand Down
4 changes: 4 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,10 @@ class IRGenSILFunction :
auto e = getLoweredExplosion(i->getOperand());
setLoweredExplosion(i, e);
}
void visitDropDeinitInst(DropDeinitInst *i) {
auto e = getLoweredExplosion(i->getOperand());
setLoweredExplosion(i, e);
}
void visitMarkMustCheckInst(MarkMustCheckInst *i) {
llvm_unreachable("Invalid in Lowered SIL");
}
Expand Down
6 changes: 6 additions & 0 deletions lib/SIL/IR/OperandOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,12 @@ OperandOwnershipClassifier::visitStoreBorrowInst(StoreBorrowInst *i) {
return OperandOwnership::TrivialUse;
}

OperandOwnership
OperandOwnershipClassifier::visitDropDeinitInst(DropDeinitInst *i) {
return i->getType().isAddress() ? OperandOwnership::TrivialUse
: OperandOwnership::ForwardingConsume;
}

// Get the OperandOwnership for instantaneous apply, yield, and return uses.
// This does not apply to uses that begin an explicit borrow scope in the
// caller, such as begin_apply.
Expand Down
4 changes: 4 additions & 0 deletions lib/SIL/IR/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1999,6 +1999,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
*this << getIDAndType(I->getOperand());
}

void visitDropDeinitInst(DropDeinitInst *I) {
*this << getIDAndType(I->getOperand());
}

void visitMarkMustCheckInst(MarkMustCheckInst *I) {
using CheckKind = MarkMustCheckInst::CheckKind;
switch (I->getCheckKind()) {
Expand Down
4 changes: 4 additions & 0 deletions lib/SIL/IR/ValueOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,10 @@ ValueOwnershipKind ValueOwnershipKindClassifier::visitLoadInst(LoadInst *LI) {
llvm_unreachable("Unhandled LoadOwnershipQualifier in switch.");
}

ValueOwnershipKind ValueOwnershipKindClassifier::visitDropDeinitInst(DropDeinitInst *ddi) {
return ddi->getType().isAddress() ? OwnershipKind::None : OwnershipKind::Owned;
}

ValueOwnershipKind
ValueOwnershipKindClassifier::visitPartialApplyInst(PartialApplyInst *PA) {
// partial_apply instructions are modeled as creating an owned value during
Expand Down
9 changes: 9 additions & 0 deletions lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3702,6 +3702,15 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
break;
}

case SILInstructionKind::DropDeinitInst: {
if (parseTypedValueRef(Val, B))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDropDeinit(InstLoc, Val);
break;
}

case SILInstructionKind::MarkMustCheckInst: {
StringRef AttrName;
if (!parseSILOptional(AttrName, *this)) {
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/Utils/AddressWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ AddressUseKind TransitiveAddressWalker::walk(SILValue projectedAddress) && {
isa<BeginAccessInst>(user) || isa<TailAddrInst>(user) ||
isa<IndexAddrInst>(user) || isa<StoreBorrowInst>(user) ||
isa<UncheckedAddrCastInst>(user) || isa<MarkMustCheckInst>(user) ||
isa<MarkUninitializedInst>(user) ||
isa<MarkUninitializedInst>(user) || isa<DropDeinitInst>(user) ||
isa<ProjectBlockStorageInst>(user) || isa<UpcastInst>(user) ||
isa<TuplePackElementAddrInst>(user)) {
transitiveResultUses(op);
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/Utils/InstructionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
case SILInstructionKind::ValueToBridgeObjectInst:
case SILInstructionKind::MarkDependenceInst:
case SILInstructionKind::MoveValueInst:
case SILInstructionKind::DropDeinitInst:
case SILInstructionKind::MarkMustCheckInst:
case SILInstructionKind::MarkUnresolvedReferenceBindingInst:
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/Utils/MemAccessUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1866,6 +1866,7 @@ AccessPathDefUseTraversal::visitSingleValueUser(SingleValueInstruction *svi,
return IgnoredUse;
}

case SILInstructionKind::DropDeinitInst:
case SILInstructionKind::MarkMustCheckInst: {
// Mark must check goes on the project_box, so it isn't a ref.
assert(!dfs.isRef());
Expand Down
8 changes: 8 additions & 0 deletions lib/SIL/Verifier/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5968,6 +5968,14 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
"Result and operand must have the same type, today.");
}

void checkDropDeinitInst(DropDeinitInst *ddi) {
require(ddi->getType() == ddi->getOperand()->getType(),
"Result and operand must have the same type.");
require(ddi->getType().isMoveOnlyNominalType(),
"drop_deinit only allowed for move-only types");
require(F.hasOwnership(), "drop_deinit only allowed in OSSA");
}

void checkMarkMustCheckInst(MarkMustCheckInst *i) {
require(i->getModule().getStage() == SILStage::Raw,
"Only valid in Raw SIL! Should have been eliminated by /some/ "
Expand Down
1 change: 1 addition & 0 deletions lib/SILGen/SILGenDestructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ void SILGenFunction::emitMoveOnlyMemberDestruction(SILValue selfValue,
NominalTypeDecl *nom,
CleanupLocation cleanupLoc,
SILBasicBlock *finishBB) {
selfValue = B.createDropDeinit(cleanupLoc, selfValue);
if (selfValue->getType().isAddress()) {
if (auto *structDecl = dyn_cast<StructDecl>(nom)) {
for (VarDecl *vd : nom->getStoredProperties()) {
Expand Down
Loading