diff --git a/docs/SIL.rst b/docs/SIL.rst index 4406173136df0..61ba52a31fa65 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -8460,6 +8460,33 @@ need for the guaranteed form in the future. @moveOnly trivial type, we convert from the non-trivial representation to the trivial representation. +copyable_to_moveonlywrapper_addr +```````````````````````````````` +:: + + sil-instruction ::= 'copyable_to_moveonlywrapper_addr' + +`copyable_to_moveonlywrapper_addr`_ takes in a '*T' and maps it to a move only +wrapped '*@moveOnly T'. This is semantically used by a code generator +initializing a new moveOnly binding from a copyable value. It semantically acts +as an address cast. If one thinks of '@moveOnly' as a monad, this is how one +injects a copyable value into the move only space. + +moveonlywrapper_to_copyable_addr +```````````````````````````````` +:: + + sil-instruction ::= 'moveonlywrapper_to_copyable_addr' + +`moveonlywrapper_to_copyable_addr`_ takes in a '*@moveOnly T' and produces a new +'*T' value. This instruction acts like an address cast that projects out the +underlying T from an @moveOnly T. + +NOTE: From the perspective of the address checker, a trivial `load`_ with a +`moveonlywrapper_to_copyable_addr`_ operand is considered to be a use of a +noncopyable type. + + Assertion configuration ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 2c86b5739aa8a..8cccc2212afb4 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -224,6 +224,26 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, StaticSpellingKind SSK); /// Diagnostic printing of \c ReferenceOwnership. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceOwnership RO); +enum class SelfAccessKind : uint8_t { + NonMutating, + Mutating, + LegacyConsuming, + Consuming, + Borrowing, + LastSelfAccessKind = Borrowing, +}; +enum : unsigned { + NumSelfAccessKindBits = + countBitsUsed(static_cast(SelfAccessKind::LastSelfAccessKind)) +}; +static_assert(uint8_t(SelfAccessKind::LastSelfAccessKind) < + (NumSelfAccessKindBits << 1), + "Self Access Kind is too small to fit in SelfAccess kind bits. " + "Please expand "); + +/// Diagnostic printing of \c SelfAccessKind. +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK); + /// Encapsulation of the overload signature of a given declaration, /// which is used to determine uniqueness of a declaration within a /// given context. @@ -315,6 +335,10 @@ enum class ArtificialMainKind : uint8_t { /// Decl - Base class for all declarations in Swift. class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { protected: + // clang-format off + // + // We format these different than clang-format wishes us to... so turn if off + // for the inline bitfields. union { uint64_t OpaqueBits; SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1, @@ -456,7 +480,8 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { DistributedThunk: 1 ); - SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1, + SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, + 1+1+2+1+1+NumSelfAccessKindBits+1, /// Whether we've computed the 'static' flag yet. IsStaticComputed : 1, @@ -473,7 +498,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { SelfAccessComputed : 1, /// Backing bits for 'self' access kind. - SelfAccess : 2, + SelfAccess : NumSelfAccessKindBits, /// Whether this is a top-level function which should be treated /// as if it were in local context for the purposes of capture @@ -735,6 +760,8 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { ); } Bits; + // Turn back on clang-format now that we have defined our inline bitfields. + // clang-format on // Storage for the declaration attributes. DeclAttributes Attrs; @@ -7234,17 +7261,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { class OperatorDecl; -enum class SelfAccessKind : uint8_t { - NonMutating, - Mutating, - LegacyConsuming, - Consuming, - Borrowing, -}; - -/// Diagnostic printing of \c SelfAccessKind. -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK); - /// FuncDecl - 'func' declaration. class FuncDecl : public AbstractFunctionDecl { friend class AbstractFunctionDecl; diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index e6836655f6ac4..16c6841f8a2fc 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -602,7 +602,11 @@ ERROR(sil_ref_inst_wrong_field,none, ERROR(sil_invalid_instr_operands,none, "invalid instruction operands", ()) ERROR(sil_operand_not_address,none, - "%0 operand of '%1' must have address type", (StringRef, StringRef)) + "%0 of '%1' must have address type", (StringRef, StringRef)) +ERROR(sil_operand_not_object,none, + "%0 of '%1' must have object type", (StringRef, StringRef)) +ERROR(sil_operand_has_incorrect_moveonlywrapped,none, + "%0 of '%1' %select{must|must not}2 be of moveonlywrapped type", (StringRef, StringRef, unsigned)) ERROR(sil_operand_not_ref_storage_address,none, "%0 operand of '%1' must have address of %2 type", (StringRef, StringRef, ReferenceOwnership)) @@ -910,6 +914,8 @@ ERROR(sil_box_expected_r_brace,none, "expected '}' to complete SIL box field type list", ()) ERROR(sil_box_expected_r_angle,none, "expected '>' to complete SIL box generic argument list", ()) +ERROR(sil_box_expected,none, + "%0 expects its operand to be of SIL box field type", (StringRef)) // SIL function types ERROR(sil_function_subst_expected_l_angle,none, diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 681b500b371d3..577462fbcd6f8 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -5291,7 +5291,9 @@ class SILMoveOnlyWrappedType final : public TypeBase, SILMoveOnlyWrappedType(CanType innerType) : TypeBase(TypeKind::SILMoveOnlyWrapped, &innerType->getASTContext(), innerType->getRecursiveProperties()), - innerType(innerType) {} + innerType(innerType) { + assert(!innerType->isPureMoveOnly() && "Inner type must be copyable"); + } public: CanType getInnerType() const { return innerType; } diff --git a/include/swift/SIL/MemAccessUtils.h b/include/swift/SIL/MemAccessUtils.h index d1446d38ec95e..11569c2c94920 100644 --- a/include/swift/SIL/MemAccessUtils.h +++ b/include/swift/SIL/MemAccessUtils.h @@ -1592,6 +1592,9 @@ inline bool isAccessStorageTypeCast(SingleValueInstruction *svi) { default: return false; // Simply pass-thru the incoming address. But change its type! + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: + // Simply pass-thru the incoming address. But change its type! case SILInstructionKind::UncheckedAddrCastInst: // Casting to RawPointer does not affect the AccessPath. When converting // between address types, they must be layout compatible (with truncation). diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 909443fe499ee..c1f2543e338fd 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -1410,6 +1410,24 @@ class SILBuilder { CopyableToMoveOnlyWrapperValueInst::Guaranteed)); } + MoveOnlyWrapperToCopyableBoxInst * + createMoveOnlyWrapperToCopyableBox(SILLocation loc, SILValue src) { + return insert(new (getModule()) MoveOnlyWrapperToCopyableBoxInst( + getSILDebugLocation(loc), src, src->getOwnershipKind())); + } + + MoveOnlyWrapperToCopyableAddrInst * + createMoveOnlyWrapperToCopyableAddr(SILLocation loc, SILValue src) { + return insert(new (getModule()) MoveOnlyWrapperToCopyableAddrInst( + getSILDebugLocation(loc), src)); + } + + CopyableToMoveOnlyWrapperAddrInst * + createCopyableToMoveOnlyWrapperAddr(SILLocation loc, SILValue src) { + return insert(new (getModule()) CopyableToMoveOnlyWrapperAddrInst( + getSILDebugLocation(loc), src)); + } + MoveOnlyWrapperToCopyableValueInst * createOwnedMoveOnlyWrapperToCopyableValue(SILLocation loc, SILValue src) { return insert(new (getModule()) MoveOnlyWrapperToCopyableValueInst( diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 5164ea053ab88..d8ac338a0d447 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -1942,6 +1942,33 @@ void SILCloner::visitMoveOnlyWrapperToCopyableValueInst( recordClonedInstruction(inst, cvt); } +template +void SILCloner::visitMoveOnlyWrapperToCopyableBoxInst( + MoveOnlyWrapperToCopyableBoxInst *inst) { + getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope())); + recordClonedInstruction( + inst, getBuilder().createMoveOnlyWrapperToCopyableBox( + getOpLocation(inst->getLoc()), getOpValue(inst->getOperand()))); +} + +template +void SILCloner::visitMoveOnlyWrapperToCopyableAddrInst( + MoveOnlyWrapperToCopyableAddrInst *inst) { + getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope())); + recordClonedInstruction( + inst, getBuilder().createMoveOnlyWrapperToCopyableAddr( + getOpLocation(inst->getLoc()), getOpValue(inst->getOperand()))); +} + +template +void SILCloner::visitCopyableToMoveOnlyWrapperAddrInst( + CopyableToMoveOnlyWrapperAddrInst *inst) { + getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope())); + recordClonedInstruction( + inst, getBuilder().createCopyableToMoveOnlyWrapperAddr( + getOpLocation(inst->getLoc()), getOpValue(inst->getOperand()))); +} + template void SILCloner::visitCopyableToMoveOnlyWrapperValueInst( CopyableToMoveOnlyWrapperValueInst *inst) { diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 2e807f7705bb2..e9dc76baa9149 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -1397,6 +1397,7 @@ FirstArgOwnershipForwardingSingleValueInst::classof(SILInstructionKind kind) { case SILInstructionKind::InitExistentialRefInst: case SILInstructionKind::MarkDependenceInst: case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst: + case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: return true; default: @@ -8482,10 +8483,21 @@ class CopyableToMoveOnlyWrapperValueInst DebugLoc, operand, operand->getType().addingMoveOnlyWrapper(), kind == InitialKind::Guaranteed ? OwnershipKind::Guaranteed : OwnershipKind::Owned), - initialKind(kind) {} + initialKind(kind) { + assert(!operand->getType().isMoveOnly() && + "Cannot be moveonly or moveonly wrapped"); + } public: InitialKind getInitialKind() const { return initialKind; } + + bool hasGuaranteedInitialKind() const { + return getInitialKind() == InitialKind::Guaranteed; + } + + bool hasOwnedInitialKind() const { + return getInitialKind() == InitialKind::Owned; + } }; /// Convert from an @moveOnly wrapper type to the underlying copyable type. Can @@ -8534,10 +8546,71 @@ class MoveOnlyWrapperToCopyableValueInst DebugLoc, operand, operand->getType().removingMoveOnlyWrapper(), kind == InitialKind::Guaranteed ? OwnershipKind::Guaranteed : OwnershipKind::Owned), - initialKind(kind) {} + initialKind(kind) { + assert(operand->getType().isMoveOnlyWrapped() && + "Expected moveonlywrapped argument!"); + } public: InitialKind getInitialKind() const { return initialKind; } + + bool hasGuaranteedInitialKind() const { + return getInitialKind() == InitialKind::Guaranteed; + } + + bool hasOwnedInitialKind() const { + return getInitialKind() == InitialKind::Owned; + } +}; + +/// Convert a ${ @moveOnly T } to $T. This is a forwarding instruction that acts +/// similarly to an object cast like upcast, unlike +/// MoveOnlyWrapperToCopyableValue which provides artificial semantics injected +/// by SILGen. +class MoveOnlyWrapperToCopyableBoxInst + : public UnaryInstructionBase< + SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst, + FirstArgOwnershipForwardingSingleValueInst> { + friend class SILBuilder; + + MoveOnlyWrapperToCopyableBoxInst(SILDebugLocation DebugLoc, SILValue operand, + ValueOwnershipKind forwardingOwnershipKind) + : UnaryInstructionBase( + DebugLoc, operand, + operand->getType().removingMoveOnlyWrapperToBoxedType( + operand->getFunction()), + forwardingOwnershipKind) { + assert( + operand->getType().isBoxedMoveOnlyWrappedType(operand->getFunction()) && + "Expected moveonlywrapped argument!"); + } +}; + +class CopyableToMoveOnlyWrapperAddrInst + : public UnaryInstructionBase< + SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst, + SingleValueInstruction> { + friend class SILBuilder; + + CopyableToMoveOnlyWrapperAddrInst(SILDebugLocation DebugLoc, SILValue operand) + : UnaryInstructionBase(DebugLoc, operand, + operand->getType().addingMoveOnlyWrapper()) { + assert(!operand->getType().isMoveOnly() && "Expected copyable argument"); + } +}; + +class MoveOnlyWrapperToCopyableAddrInst + : public UnaryInstructionBase< + SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst, + SingleValueInstruction> { + friend class SILBuilder; + + MoveOnlyWrapperToCopyableAddrInst(SILDebugLocation DebugLoc, SILValue operand) + : UnaryInstructionBase(DebugLoc, operand, + operand->getType().removingMoveOnlyWrapper()) { + assert(operand->getType().isMoveOnlyWrapped() && + "Expected moveonlywrapped argument"); + } }; /// Given an object reference, return true iff it is non-nil and refers diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index a6c570b8e9672..443bc06064e34 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -490,11 +490,25 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction) // and owned for assignment/owned function arguments. SINGLE_VALUE_INST(CopyableToMoveOnlyWrapperValueInst, copyable_to_moveonlywrapper, SingleValueInstruction, None, DoesNotRelease) - // Convert a $@moveOnly T to $T. Ownership is fixed at construction by + // Convert a $@moveOnly T object to $T. Ownership is fixed at construction by // frontend to express specific semantics: guaranteed for function arguments // and owned for assignment/return values. - SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableValueInst, moveonlywrapper_to_copyable, - SingleValueInstruction, None, DoesNotRelease) + SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableValueInst, + moveonlywrapper_to_copyable, SingleValueInstruction, None, + DoesNotRelease) + // Convert a ${ @moveOnly T } to $T. This is a forwarding instruction that + // acts similarly to an object cast, unlike MoveOnlyWrapperToCopyableValue. + SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableBoxInst, + moveonlywrapper_to_copyable_box, SingleValueInstruction, None, + DoesNotRelease) + // Convert a $*@moveOnly T to $*T. Acts just as a cast. + SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableAddrInst, + moveonlywrapper_to_copyable_addr, SingleValueInstruction, + None, DoesNotRelease) + // Convert a $*T to $*@moveOnly T. Acts just as a cast. + SINGLE_VALUE_INST(CopyableToMoveOnlyWrapperAddrInst, + copyable_to_moveonlywrapper_addr, SingleValueInstruction, + None, DoesNotRelease) // A move_addr is a Raw SIL only instruction that is equivalent to a copy_addr // [init]. It is lowered during the diagnostic passes to a copy_addr [init] if // the move checker found uses that prevented us from converting this to a diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 3dc865805ec1d..30d817d45e09c 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -721,8 +721,8 @@ class SILType { return getRawASTType()->is(); } - /// If this is already a move only wrapped type, return *this. Otherwise, wrap - /// the copyable type in the mov eonly wrapper. + /// If this is already a moveonlywrapped type, return *this. Otherwise, wrap + /// the copyable type in the moveonlywrapper. SILType addingMoveOnlyWrapper() const { if (isMoveOnlyWrapped()) return *this; @@ -749,6 +749,20 @@ class SILType { return *this; } + /// If this is a box type containing a moveonlywrapped type, return a new box + /// with the moveonlywrapped type unwrapped. + /// + /// DISCUSSION: This is separate from addingMoveOnlyWrapper since this API + /// requires a SILFunction * and is specialized. + SILType addingMoveOnlyWrapperToBoxedType(const SILFunction *fn); + + /// If this is a box type containing a copyable type, return a new box type + /// with the copyable type wrapped in a moveonly wrapped type. + /// + /// DISCUSSION: This is separate from removingMoveOnlyWrapper since this API + /// requires a SILFunction * and is specialized. + SILType removingMoveOnlyWrapperToBoxedType(const SILFunction *fn); + /// Returns a SILType with any archetypes mapped out of context. SILType mapTypeOutOfContext() const; @@ -799,6 +813,12 @@ class SILType { return isBoxedNonCopyableType(&fn); } + bool isBoxedMoveOnlyWrappedType(const SILFunction *fn) const { + if (!this->is()) + return false; + return getSILBoxFieldType(fn).isMoveOnlyWrapped(); + } + SILType getInstanceTypeOfMetatype(SILFunction *function) const; bool isOrContainsObjectiveCClass() const; diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index 21cb9c323fc3b..425136faa5b6f 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -576,10 +576,15 @@ class ValueBase : public SILNode, public SILAllocated { /// /// NOTE: Please do not use this directly! It is only meant to be used by the /// optimizer pass: SILMoveOnlyWrappedTypeEliminator. - bool unsafelyEliminateMoveOnlyWrapper() { - if (!Type.isMoveOnlyWrapped()) + bool unsafelyEliminateMoveOnlyWrapper(const SILFunction *fn) { + if (!Type.isMoveOnlyWrapped() && !Type.isBoxedMoveOnlyWrappedType(fn)) return false; - Type = Type.removingMoveOnlyWrapper(); + if (Type.isMoveOnlyWrapped()) { + Type = Type.removingMoveOnlyWrapper(); + } else { + assert(Type.isBoxedMoveOnlyWrappedType(fn)); + Type = Type.removingMoveOnlyWrapperToBoxedType(fn); + } return true; } diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 6f90c22b027bb..06b518960e880 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1268,6 +1268,20 @@ class IRGenSILFunction : auto e = getLoweredExplosion(i->getOperand()); setLoweredExplosion(i, e); } + void + visitMoveOnlyWrapperToCopyableBoxInst(MoveOnlyWrapperToCopyableBoxInst *i) { + llvm_unreachable("OSSA instruction"); + } + void + visitMoveOnlyWrapperToCopyableAddrInst(MoveOnlyWrapperToCopyableAddrInst *i) { + auto e = getLoweredExplosion(i->getOperand()); + setLoweredExplosion(i, e); + } + void + visitCopyableToMoveOnlyWrapperAddrInst(CopyableToMoveOnlyWrapperAddrInst *i) { + auto e = getLoweredExplosion(i->getOperand()); + setLoweredExplosion(i, e); + } void visitReleaseValueInst(ReleaseValueInst *i); void visitReleaseValueAddrInst(ReleaseValueAddrInst *i); void visitDestroyValueInst(DestroyValueInst *i); diff --git a/lib/SIL/IR/AbstractionPattern.cpp b/lib/SIL/IR/AbstractionPattern.cpp index 7e389f502ce23..6fa1285c98276 100644 --- a/lib/SIL/IR/AbstractionPattern.cpp +++ b/lib/SIL/IR/AbstractionPattern.cpp @@ -852,6 +852,8 @@ AbstractionPattern AbstractionPattern::removingMoveOnlyWrapper() const { case Kind::Tuple: llvm_unreachable("cannot apply move-only wrappers to open-coded patterns"); case Kind::Opaque: + // Opaque is opaque. We do not remove anything. + return *this; case Kind::Type: if (auto mvi = dyn_cast(getType())) { return AbstractionPattern(getGenericSubstitutions(), diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 1a7f5478ce52f..a2e4303ba4644 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -148,6 +148,8 @@ OPERAND_OWNERSHIP(TrivialUse, AddressToPointer) OPERAND_OWNERSHIP(TrivialUse, AllocRef) // with tail operand OPERAND_OWNERSHIP(TrivialUse, AllocRefDynamic) // with tail operand OPERAND_OWNERSHIP(TrivialUse, BeginAccess) +OPERAND_OWNERSHIP(TrivialUse, MoveOnlyWrapperToCopyableAddr) +OPERAND_OWNERSHIP(TrivialUse, CopyableToMoveOnlyWrapperAddr) OPERAND_OWNERSHIP(TrivialUse, BeginUnpairedAccess) OPERAND_OWNERSHIP(TrivialUse, BindMemory) OPERAND_OWNERSHIP(TrivialUse, RebindMemory) @@ -372,6 +374,7 @@ FORWARDING_OWNERSHIP(MarkMustCheck) FORWARDING_OWNERSHIP(MarkUnresolvedReferenceBinding) FORWARDING_OWNERSHIP(MoveOnlyWrapperToCopyableValue) FORWARDING_OWNERSHIP(CopyableToMoveOnlyWrapperValue) +FORWARDING_OWNERSHIP(MoveOnlyWrapperToCopyableBox) #undef FORWARDING_OWNERSHIP // Arbitrary value casts are forwarding instructions that are also allowed to diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 7322a6dc99396..42ca297171341 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2459,6 +2459,18 @@ class SILPrinter : public SILInstructionVisitor { << (BAI->isFromBuiltin() ? "[builtin] " : "") << getIDAndType(BAI->getOperand()); } + void visitMoveOnlyWrapperToCopyableAddrInst( + MoveOnlyWrapperToCopyableAddrInst *BAI) { + *this << getIDAndType(BAI->getOperand()); + } + void + visitMoveOnlyWrapperToCopyableBoxInst(MoveOnlyWrapperToCopyableBoxInst *BAI) { + *this << getIDAndType(BAI->getOperand()); + } + void visitCopyableToMoveOnlyWrapperAddrInst( + CopyableToMoveOnlyWrapperAddrInst *BAI) { + *this << getIDAndType(BAI->getOperand()); + } void visitEndAccessInst(EndAccessInst *EAI) { *this << (EAI->isAborting() ? "[abort] " : "") << getIDAndType(EAI->getOperand()); diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index a0cbcdb204453..4de275b78e621 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -329,6 +329,9 @@ SILType SILType::getFieldType(VarDecl *field, TypeConverter &TC, if (field->hasClangNode()) { substFieldTy = origFieldTy.getType(); } else { + // We want to specifically use getASTType() here instead of getRawASTType() + // to ensure that we can correctly get our substituted field type. If we + // need to rewrap the type layer, we do it below. substFieldTy = getASTType()->getTypeOfMember(&TC.M, field)->getCanonicalType(); } @@ -655,8 +658,8 @@ CanType swift::getSILBoxFieldLoweredType(TypeExpansionContext context, LookUpConformanceInSubstitutionMap(subMap), sig); } - - return fieldTy.getASTType(); + + return fieldTy.getRawASTType(); } ValueOwnershipKind @@ -1145,10 +1148,46 @@ intptr_t SILType::getCaseIdxOfEnumType(StringRef caseName) const { } std::string SILType::getDebugDescription() const { - std::string str; - llvm::raw_string_ostream os(str); - print(os); - str.pop_back(); // Remove trailing newline. - return str; - } - + std::string str; + llvm::raw_string_ostream os(str); + print(os); + str.pop_back(); // Remove trailing newline. + return str; +} + +SILType SILType::addingMoveOnlyWrapperToBoxedType(const SILFunction *fn) { + auto boxTy = castTo(); + auto *oldLayout = boxTy->getLayout(); + auto oldField = oldLayout->getFields()[0]; + if (oldField.getLoweredType()->is()) + return *this; + assert(!oldField.getLoweredType()->isPureMoveOnly() && + "Cannot moveonlywrapped in a moveonly type"); + auto newField = + SILField(SILMoveOnlyWrappedType::get(oldField.getLoweredType()), + oldField.isMutable()); + auto *newLayout = + SILLayout::get(fn->getASTContext(), oldLayout->getGenericSignature(), + {newField}, oldLayout->capturesGenericEnvironment()); + auto newBoxType = SILBoxType::get(fn->getASTContext(), newLayout, + boxTy->getSubstitutions()); + return SILType::getPrimitiveObjectType(newBoxType); +} + +SILType SILType::removingMoveOnlyWrapperToBoxedType(const SILFunction *fn) { + auto boxTy = castTo(); + auto *oldLayout = boxTy->getLayout(); + auto oldField = oldLayout->getFields()[0]; + auto *moveOnlyWrapped = + oldField.getLoweredType()->getAs(); + if (!moveOnlyWrapped) + return *this; + auto newField = + SILField(moveOnlyWrapped->getInnerType(), oldField.isMutable()); + auto *newLayout = + SILLayout::get(fn->getASTContext(), oldLayout->getGenericSignature(), + {newField}, oldLayout->capturesGenericEnvironment()); + auto newBoxType = SILBoxType::get(fn->getASTContext(), newLayout, + boxTy->getSubstitutions()); + return SILType::getPrimitiveObjectType(newBoxType); +} diff --git a/lib/SIL/IR/SILTypeSubstitution.cpp b/lib/SIL/IR/SILTypeSubstitution.cpp index 1481c0403423f..68f4e356569d8 100644 --- a/lib/SIL/IR/SILTypeSubstitution.cpp +++ b/lib/SIL/IR/SILTypeSubstitution.cpp @@ -292,7 +292,7 @@ class SILTypeSubstituter : } SILType subst(SILType type) { - return SILType::getPrimitiveType(visit(type.getASTType()), + return SILType::getPrimitiveType(visit(type.getRawASTType()), type.getCategory()); } diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 2194c7eaa8b6f..7f5ead67d4822 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -2524,7 +2524,7 @@ TypeConverter::~TypeConverter() { // Destroy only the unique entries. CanType srcType = ti.first.OrigType; if (!srcType) continue; - CanType mappedType = ti.second->getLoweredType().getASTType(); + CanType mappedType = ti.second->getLoweredType().getRawASTType(); if (srcType == mappedType) ti.second->~TypeLowering(); } @@ -4394,10 +4394,11 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured, env->mapTypeIntoContext(contextBoxTy) ->getCanonicalType()); } + + auto ty = getSILBoxFieldType(TypeExpansionContext::minimal(), contextBoxTy, + *this, 0); assert(contextBoxTy->getLayout()->getFields().size() == 1 && - getSILBoxFieldType(TypeExpansionContext::minimal(), contextBoxTy, - *this, 0) - .getASTType() == loweredContextType && + ty.getRawASTType() == loweredContextType && "box field type doesn't match capture!"); #endif return boxTy; @@ -4449,7 +4450,7 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement( } // Use the enum's signature for the box type. - auto boundEnum = enumType.getASTType(); + auto boundEnum = enumType.getRawASTType(); // Lower the enum element's argument in the box's context. auto eltIntfTy = elt->getArgumentInterfaceType(); diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp index 4d9732ecbd344..d19d1e970a4b0 100644 --- a/lib/SIL/IR/ValueOwnership.cpp +++ b/lib/SIL/IR/ValueOwnership.cpp @@ -97,6 +97,8 @@ CONSTANT_OWNERSHIP_INST(None, AllocPack) CONSTANT_OWNERSHIP_INST(None, AllocPackMetadata) CONSTANT_OWNERSHIP_INST(None, PackLength) CONSTANT_OWNERSHIP_INST(None, BeginAccess) +CONSTANT_OWNERSHIP_INST(None, MoveOnlyWrapperToCopyableAddr) +CONSTANT_OWNERSHIP_INST(None, CopyableToMoveOnlyWrapperAddr) CONSTANT_OWNERSHIP_INST(None, BindMemory) CONSTANT_OWNERSHIP_INST(None, RebindMemory) CONSTANT_OWNERSHIP_INST(None, BridgeObjectToWord) @@ -284,6 +286,7 @@ FORWARDING_OWNERSHIP_INST(MarkMustCheck) FORWARDING_OWNERSHIP_INST(MarkUnresolvedReferenceBinding) FORWARDING_OWNERSHIP_INST(MoveOnlyWrapperToCopyableValue) FORWARDING_OWNERSHIP_INST(CopyableToMoveOnlyWrapperValue) +FORWARDING_OWNERSHIP_INST(MoveOnlyWrapperToCopyableBox) #undef FORWARDING_OWNERSHIP_INST ValueOwnershipKind diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 85343661e506c..50cfa69faeed5 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -3800,6 +3800,20 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, return true; if (parseSILDebugLocation(InstLoc, B)) return true; + + if (!Val->getType().isObject()) { + P.diagnose(InstLoc.getSourceLoc(), + diag::sil_operand_not_object, "operand", OpcodeName); + return true; + } + + if (Val->getType().isMoveOnlyWrapped()) { + P.diagnose(InstLoc.getSourceLoc(), + diag::sil_operand_has_incorrect_moveonlywrapped, + "operand", OpcodeName, 1); + return true; + } + if (OwnershipKind == OwnershipKind::Owned) ResultVal = B.createOwnedCopyableToMoveOnlyWrapperValue(InstLoc, Val); else @@ -3832,6 +3846,20 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, return true; if (parseSILDebugLocation(InstLoc, B)) return true; + + if (!Val->getType().isObject()) { + P.diagnose(InstLoc.getSourceLoc(), + diag::sil_operand_not_object, "operand", OpcodeName); + return true; + } + + if (!Val->getType().isMoveOnlyWrapped()) { + P.diagnose(InstLoc.getSourceLoc(), + diag::sil_operand_has_incorrect_moveonlywrapped, + "operand", OpcodeName, 0); + return true; + } + if (OwnershipKind == OwnershipKind::Owned) ResultVal = B.createOwnedMoveOnlyWrapperToCopyableValue(InstLoc, Val); else @@ -4514,6 +4542,76 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, break; } + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: { + SILValue addrVal; + SourceLoc addrLoc; + if (parseTypedValueRef(addrVal, addrLoc, B)) + return true; + + if (parseSILDebugLocation(InstLoc, B)) + return true; + + if (!addrVal->getType().isAddress()) { + P.diagnose(addrLoc, diag::sil_operand_not_address, "operand", OpcodeName); + return true; + } + + if (!addrVal->getType().isMoveOnlyWrapped()) { + P.diagnose(addrLoc, diag::sil_operand_has_incorrect_moveonlywrapped, + "operand", OpcodeName, 0); + return true; + } + + ResultVal = B.createMoveOnlyWrapperToCopyableAddr(InstLoc, addrVal); + break; + } + case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: { + SILValue addrVal; + SourceLoc addrLoc; + if (parseTypedValueRef(addrVal, addrLoc, B)) + return true; + + if (parseSILDebugLocation(InstLoc, B)) + return true; + + if (!addrVal->getType().is()) { + P.diagnose(addrLoc, diag::sil_box_expected, OpcodeName); + return true; + } + + if (!addrVal->getType().isBoxedMoveOnlyWrappedType( + addrVal->getFunction())) { + P.diagnose(addrLoc, diag::sil_operand_has_incorrect_moveonlywrapped, + "operand", OpcodeName, 0); + return true; + } + + ResultVal = B.createMoveOnlyWrapperToCopyableBox(InstLoc, addrVal); + break; + } + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: { + SILValue addrVal; + SourceLoc addrLoc; + if (parseTypedValueRef(addrVal, addrLoc, B)) + return true; + + if (parseSILDebugLocation(InstLoc, B)) + return true; + + if (!addrVal->getType().isAddress()) { + P.diagnose(addrLoc, diag::sil_operand_not_address, "operand", OpcodeName); + return true; + } + + if (addrVal->getType().isMoveOnlyWrapped()) { + P.diagnose(addrLoc, diag::sil_operand_has_incorrect_moveonlywrapped, + "operand", OpcodeName, 1); + return true; + } + + ResultVal = B.createCopyableToMoveOnlyWrapperAddr(InstLoc, addrVal); + break; + } case SILInstructionKind::BeginAccessInst: case SILInstructionKind::BeginUnpairedAccessInst: case SILInstructionKind::EndAccessInst: diff --git a/lib/SIL/Utils/AddressWalker.cpp b/lib/SIL/Utils/AddressWalker.cpp index 8749cd8550db5..54b2c9d935ef4 100644 --- a/lib/SIL/Utils/AddressWalker.cpp +++ b/lib/SIL/Utils/AddressWalker.cpp @@ -159,7 +159,9 @@ AddressUseKind TransitiveAddressWalker::walk(SILValue projectedAddress) && { isa(user) || isa(user) || isa(user) || isa(user) || isa(user) || isa(user) || - isa(user)) { + isa(user) || + isa(user) || + isa(user)) { transitiveResultUses(op); continue; } diff --git a/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp b/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp index f056c53515be5..27cbaebc45098 100644 --- a/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp +++ b/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp @@ -123,6 +123,12 @@ SubElementOffset::computeForAddress(SILValue projectionDerivedFromRoot, continue; } + if (auto *m = dyn_cast( + projectionDerivedFromRoot)) { + projectionDerivedFromRoot = m->getOperand(); + continue; + } + if (auto *teai = dyn_cast(projectionDerivedFromRoot)) { SILType tupleType = teai->getOperand()->getType(); diff --git a/lib/SIL/Utils/InstructionUtils.cpp b/lib/SIL/Utils/InstructionUtils.cpp index 415adfdb16d2f..50131fdd14dd0 100644 --- a/lib/SIL/Utils/InstructionUtils.cpp +++ b/lib/SIL/Utils/InstructionUtils.cpp @@ -459,6 +459,9 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType) case SILInstructionKind::BridgeObjectToWordInst: case SILInstructionKind::ThinToThickFunctionInst: case SILInstructionKind::ThickToObjCMetatypeInst: + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: + case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: case SILInstructionKind::ObjCMetatypeToObjectInst: case SILInstructionKind::ObjCExistentialMetatypeToObjectInst: case SILInstructionKind::ClassifyBridgeObjectInst: diff --git a/lib/SIL/Utils/MemAccessUtils.cpp b/lib/SIL/Utils/MemAccessUtils.cpp index 2dbc61ed8e1d8..78706279f1e62 100644 --- a/lib/SIL/Utils/MemAccessUtils.cpp +++ b/lib/SIL/Utils/MemAccessUtils.cpp @@ -1349,7 +1349,12 @@ class AccessPathVisitor : public FindAccessVisitorImpl { // as such when it operates on unchecked_take_enum_data_addr. || isa(projectedAddr) // Ignore mark_must_check, we just look through it when we see it. - || isa(projectedAddr)); + || isa(projectedAddr) + // Ignore moveonlywrapper_to_copyable_addr and + // copyable_to_moveonlywrapper_addr, we just look through it when + // we see it + || isa(projectedAddr) || + isa(projectedAddr)); } return sourceAddr->get(); } @@ -1874,6 +1879,12 @@ AccessPathDefUseTraversal::visitSingleValueUser(SingleValueInstruction *svi, return IgnoredUse; } + // Look through both of these. + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: + pushUsers(svi, dfs); + return IgnoredUse; + // MARK: Access projections case SILInstructionKind::StructElementAddrInst: diff --git a/lib/SIL/Utils/OwnershipUtils.cpp b/lib/SIL/Utils/OwnershipUtils.cpp index acaa000b22842..b54166270ad3d 100644 --- a/lib/SIL/Utils/OwnershipUtils.cpp +++ b/lib/SIL/Utils/OwnershipUtils.cpp @@ -1340,6 +1340,9 @@ ValueOwnershipKind ForwardingOperand::getForwardingOwnershipKind() const { return move->getForwardingOwnershipKind(); } + if (auto *move = dyn_cast(user)) + return move->getForwardingOwnershipKind(); + llvm_unreachable("Unhandled forwarding inst?!"); } diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index e24326acd6bad..803809fcfb2b6 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -669,12 +669,15 @@ struct ImmutableAddressUseVerifier { OpenedExistentialAccess::Immutable) return true; LLVM_FALLTHROUGH; + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: case SILInstructionKind::StructElementAddrInst: case SILInstructionKind::TupleElementAddrInst: case SILInstructionKind::IndexAddrInst: case SILInstructionKind::TailAddrInst: case SILInstructionKind::IndexRawPointerInst: case SILInstructionKind::MarkMustCheckInst: + case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: case SILInstructionKind::PackElementGetInst: // Add these to our worklist. for (auto result : inst->getResults()) { @@ -4497,6 +4500,9 @@ class SILVerifier : public SILVerifierBase { void checkUpcastInst(UpcastInst *UI) { require(UI->getType() != UI->getOperand()->getType(), "can't upcast to same type"); + require(UI->getOperand()->getType().isMoveOnlyWrapped() == + UI->getType().isMoveOnlyWrapped(), + "cast cannot be used to remove move only wrapped?!"); checkNoTrivialToReferenceCast(UI); if (UI->getType().is()) { CanType instTy(UI->getType().castTo()->getInstanceType()); @@ -4590,6 +4596,9 @@ class SILVerifier : public SILVerifierBase { "unchecked_addr_cast operand must be an address"); require(AI->getType().isAddress(), "unchecked_addr_cast result must be an address"); + require(AI->getOperand()->getType().isMoveOnlyWrapped() == + AI->getType().isMoveOnlyWrapped(), + "Unchecked addr cast cannot be used to remove move only wrapped?!"); } void checkUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *BI) { @@ -4600,6 +4609,9 @@ class SILVerifier : public SILVerifierBase { "unchecked_trivial_bit_cast must produce a value"); require(BI->getType().isTrivial(F), "unchecked_trivial_bit_cast must produce a value of trivial type"); + require(BI->getOperand()->getType().isMoveOnlyWrapped() == + BI->getType().isMoveOnlyWrapped(), + "cast cannot be used to remove move only wrapped?!"); } void checkUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *BI) { @@ -4608,6 +4620,9 @@ class SILVerifier : public SILVerifierBase { "unchecked_bitwise_cast must operate on a value"); require(BI->getType().isObject(), "unchecked_bitwise_cast must produce a value"); + require(BI->getOperand()->getType().isMoveOnlyWrapped() == + BI->getType().isMoveOnlyWrapped(), + "cast cannot be used to remove move only wrapped?!"); } void checkRefToRawPointerInst(RefToRawPointerInst *AI) { @@ -6037,12 +6052,24 @@ class SILVerifier : public SILVerifierBase { MoveOnlyWrapperToCopyableValueInst *cvt) { require(cvt->getOperand()->getType().isObject(), "Operand value should be an object"); - require(!cvt->getType().isMoveOnlyWrapped(), "Output should not move only"); + require(cvt->getOperand()->getType().isMoveOnlyWrapped(), + "Operand should be move only wrapped"); require(cvt->getType() == cvt->getOperand()->getType().removingMoveOnlyWrapper(), "Result and operand must have the same type, today."); } + void checkMoveOnlyWrapperToCopyableBoxInst( + MoveOnlyWrapperToCopyableBoxInst *cvt) { + require(cvt->getOperand()->getType().isObject(), + "Operand value should be an object"); + require(cvt->getOperand()->getType().isBoxedMoveOnlyWrappedType(cvt->getFunction()), + "Operand should be move only wrapped"); + require(cvt->getType() == + cvt->getOperand()->getType().removingMoveOnlyWrapperToBoxedType(cvt->getFunction()), + "Result and operand must have the same type, today."); + } + void checkCopyableToMoveOnlyWrapperValueInst( CopyableToMoveOnlyWrapperValueInst *cvt) { require(cvt->getInitialKind() == @@ -6071,6 +6098,27 @@ class SILVerifier : public SILVerifierBase { "Must have alloc_pack_metadata operand"); } + void checkMoveOnlyWrapperToCopyableAddrInst( + MoveOnlyWrapperToCopyableAddrInst *cvt) { + require(cvt->getType().isAddress(), "Output should be an address"); + require(cvt->getOperand()->getType().isMoveOnlyWrapped(), + "Input should be move only"); + require(cvt->getType() == + cvt->getOperand()->getType().removingMoveOnlyWrapper(), + "Result and operand must have the same type."); + } + + void checkCopyableToMoveOnlyWrapperAddrInst( + CopyableToMoveOnlyWrapperAddrInst *cvt) { + require(cvt->getType().isAddress(), "Output should be an address"); + require(!cvt->getOperand()->getType().isMoveOnlyWrapped(), + "Input should not be move only wrapped"); + require(cvt->getType() == + cvt->getOperand()->getType().addingMoveOnlyWrapper(), + "Result and operand must have the same underlying type ignoring " + "move only wrappedness."); + } + void verifyEpilogBlocks(SILFunction *F) { bool FoundReturnBlock = false; bool FoundThrowBlock = false; diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index c391500da4406..55292c116cc6f 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -227,8 +227,26 @@ static ManagedValue borrowedCastToOriginalSelfType(SILGenFunction &SGF, } static ManagedValue convertOwnershipConventionGivenParamInfo( - SILGenFunction &SGF, SILParameterInfo param, ManagedValue value, + SILGenFunction &SGF, SILParameterInfo param, + Optional origParam, ManagedValue value, SILLocation loc, bool isForCoroutine) { + bool isOwned = false; + if (origParam) { + isOwned |= origParam->isOwned(); + } + + // If we have a moveonlywrapped type that is trivial when unwrapped, then we + // at an ABI level our parameter will be passed as direct_unowned. We want to + // consume this value though if we have an owned parameter. + auto valueType = value.getType(); + if (isOwned && valueType.isMoveOnlyWrapped() && + valueType.removingMoveOnlyWrapper().isTrivial(SGF.F)) { + if (value.getOwnershipKind() == OwnershipKind::Guaranteed) { + value = value.copyUnmanaged(SGF, loc); + return SGF.B.createOwnedMoveOnlyWrapperToCopyableValue(loc, value); + } + } + if (param.isConsumed() && value.getOwnershipKind() == OwnershipKind::Guaranteed) { return value.copyUnmanaged(SGF, loc); @@ -257,7 +275,8 @@ static void convertOwnershipConventionsGivenParamInfos( llvm::transform(indices(params), std::back_inserter(outVar), [&](unsigned i) -> ManagedValue { return convertOwnershipConventionGivenParamInfo( - SGF, params[i], values[i], loc, isForCoroutine); + SGF, params[i], None /*orig param*/, values[i], loc, + isForCoroutine); }); } @@ -1895,8 +1914,11 @@ static void emitRawApply(SILGenFunction &SGF, argValue = args[i].forward(SGF); if (argValue->getType().isMoveOnlyWrapped() && !inputTy.isMoveOnlyWrapped()) { - argValue = - SGF.B.createOwnedMoveOnlyWrapperToCopyableValue(loc, argValue); + if (argValue->getType().isObject()) + argValue = + SGF.B.createOwnedMoveOnlyWrapperToCopyableValue(loc, argValue); + else + argValue = SGF.B.createMoveOnlyWrapperToCopyableAddr(loc, argValue); } } else { ManagedValue arg = args[i]; @@ -1911,10 +1933,17 @@ static void emitRawApply(SILGenFunction &SGF, // We need to borrow so that we can convert from $@moveOnly T -> $T. // Use a formal access borrow to ensure that we have tight scopes like // we do when we borrow fn. - if (!arg.isPlusZero()) - arg = arg.formalAccessBorrow(SGF, loc); + if (arg.getType().isObject()) { + if (!arg.isPlusZero() || + arg.getOwnershipKind() != OwnershipKind::Guaranteed) + arg = arg.formalAccessBorrow(SGF, loc); - arg = SGF.B.createGuaranteedMoveOnlyWrapperToCopyableValue(loc, arg); + arg = + SGF.B.createGuaranteedMoveOnlyWrapperToCopyableValue(loc, arg); + } else { + arg = ManagedValue::forBorrowedAddressRValue( + SGF.B.createMoveOnlyWrapperToCopyableAddr(loc, arg.getValue())); + } } } @@ -3096,7 +3125,12 @@ Expr *ArgumentSource::findStorageReferenceExprForMoveOnly( SILType ty = SGF.getLoweredType(type->getWithoutSpecifierType()->getCanonicalType()); - if (!ty.isPureMoveOnly()) + bool isMoveOnly = ty.isPureMoveOnly(); + if (auto *pd = dyn_cast(storage)) { + isMoveOnly |= pd->getSpecifier() == ParamSpecifier::Borrowing; + isMoveOnly |= pd->getSpecifier() == ParamSpecifier::Consuming; + } + if (!isMoveOnly) return nullptr; // It makes sense to borrow any kind of storage we refer to at this stage, @@ -3205,7 +3239,8 @@ class ArgEmitter { DelayedArguments(delayedArgs) {} // origParamType is a parameter type. - void emitSingleArg(ArgumentSource &&arg, AbstractionPattern origParamType) { + void emitSingleArg(ArgumentSource &&arg, AbstractionPattern origParamType, + Optional param = None) { // If this is delayed default argument, prepare to emit the default argument // generator later. if (arg.isDelayedDefaultArg()) { @@ -3225,7 +3260,7 @@ class ArgEmitter { maybeEmitForeignArgument(); return; } - emit(std::move(arg), origParamType); + emit(std::move(arg), origParamType, param); maybeEmitForeignArgument(); } @@ -3233,6 +3268,7 @@ class ArgEmitter { void emitPreparedArgs(PreparedArguments &&args, AbstractionPattern origFormalType) { assert(args.isValid()); + auto params = args.getParams(); auto argSources = std::move(args).getSources(); maybeEmitForeignArgument(); @@ -3249,10 +3285,10 @@ class ArgEmitter { // If the next pattern is not a pack expansion, just emit it as a // single argument. if (!origFormalParamType.isPackExpansion()) { - emitSingleArg(std::move(argSources[nextArgSourceIndex++]), - origFormalParamType); - - // Otherwise we need to emit a pack argument. + emitSingleArg(std::move(argSources[nextArgSourceIndex]), + origFormalParamType, params[nextArgSourceIndex]); + ++nextArgSourceIndex; + // Otherwise we need to emit a pack argument. } else { auto numComponents = origFormalParamType.getNumPackExpandedComponents(); @@ -3268,7 +3304,8 @@ class ArgEmitter { } private: - void emit(ArgumentSource &&arg, AbstractionPattern origParamType) { + void emit(ArgumentSource &&arg, AbstractionPattern origParamType, + Optional origParam = None) { if (!arg.hasLValueType()) { // If the unsubstituted function type has a parameter of tuple type, // explode the tuple value. @@ -3309,6 +3346,12 @@ class ArgEmitter { SILType loweredSubstParamType = SILType::getPrimitiveType( param.getInterfaceType(), loweredSubstArgType.getCategory()); + bool isShared = false; + bool isOwned = false; + if (origParam) { + isOwned |= origParam->isOwned(); + isShared |= origParam->isShared(); + } // If the caller takes the argument indirectly, the argument has an // inout type. @@ -3319,7 +3362,7 @@ class ArgEmitter { } // If we have a guaranteed +0 parameter... - if (param.isGuaranteed()) { + if (param.isGuaranteed() || isShared) { // And this is a yield, emit a borrowed r-value. if (IsYield) { if (tryEmitBorrowed(std::move(arg), loweredSubstArgType, @@ -3341,7 +3384,7 @@ class ArgEmitter { return; } - if (param.isConsumed()) { + if (param.isConsumed() || isOwned) { if (tryEmitConsumedMoveOnly(std::move(arg), loweredSubstArgType, loweredSubstParamType, origParamType, paramSlice)) @@ -3355,7 +3398,8 @@ class ArgEmitter { // Okay, if the original parameter is passed directly, then we // just need to handle abstraction differences and bridging. - emitDirect(std::move(arg), loweredSubstArgType, origParamType, param); + emitDirect(std::move(arg), loweredSubstArgType, origParamType, param, + origParam); } ClaimedParamsRef claimNextParameters(unsigned count) { @@ -3669,14 +3713,14 @@ class ArgEmitter { } void emitDirect(ArgumentSource &&arg, SILType loweredSubstArgType, - AbstractionPattern origParamType, - SILParameterInfo param) { + AbstractionPattern origParamType, SILParameterInfo param, + Optional origParam = None) { ManagedValue value; auto loc = arg.getLocation(); auto convertOwnershipConvention = [&](ManagedValue value) { - return convertOwnershipConventionGivenParamInfo(SGF, param, value, loc, - IsForCoroutine); + return convertOwnershipConventionGivenParamInfo( + SGF, param, origParam, value, loc, IsForCoroutine); }; auto contexts = getRValueEmissionContexts(loweredSubstArgType, param); @@ -4261,7 +4305,6 @@ static void emitBorrowedLValueRecursive(SILGenFunction &SGF, params = params.slice(1); // Load if necessary. - assert(!param.isConsumed() && "emitting borrow into consumed parameter?"); if (value.getType().isAddress()) { if (!param.isIndirectInGuaranteed() || !SGF.silConv.useLoweredAddresses()) { if (value.getType().isMoveOnly()) { @@ -4350,10 +4393,15 @@ static void emitConsumedLValueRecursive(SILGenFunction &SGF, SILLocation loc, params = params.slice(1); // Load if necessary. - assert(param.isConsumed() && "Should have a consumed parameter?"); if (value.getType().isAddress()) { if (!param.isIndirectIn() || !SGF.silConv.useLoweredAddresses()) { value = SGF.B.createFormalAccessLoadTake(loc, value); + + // If our value is a moveonlywrapped type, unwrap it using owned so that + // we consume it. + if (value.getType().isMoveOnlyWrapped()) { + value = SGF.B.createOwnedMoveOnlyWrapperToCopyableValue(loc, value); + } } } @@ -4366,7 +4414,7 @@ void DelayedArgument::emitConsumedLValue(SILGenFunction &SGF, SmallVectorImpl &args, size_t &argIndex) { // Begin the access. - auto value = SGF.emitConsumedLValue(info.Loc, std::move(info.LV)); + ManagedValue value = SGF.emitConsumedLValue(info.Loc, std::move(info.LV)); ClaimedParamsRef params = info.ParamsToEmit; // We inserted exactly one space in the argument array, so fix that up @@ -5233,12 +5281,25 @@ CallEmission CallEmission::forApplyExpr(SILGenFunction &SGF, ApplyExpr *e) { // Apply 'self' if provided. if (apply.selfParam) { - AnyFunctionType::Param selfParam( - apply.selfParam.getSubstRValueType(), - Identifier(), - apply.selfParam.isLValue() - ? ParameterTypeFlags().withInOut(true) - : ParameterTypeFlags()); + auto substFormalType = apply.getCallee().getSubstFormalType(); + auto origSelfParam = substFormalType->getParams().back(); + auto origSelfParamFlags = origSelfParam.getParameterFlags(); + + auto newFlags = ParameterTypeFlags(); + if (apply.selfParam.isLValue()) { + newFlags = newFlags.withInOut(true); + } else { + // Transfer to new flags shared or owned if we do not have an lvalue. + // + // TODO: I wonder if we can reuse more of the orig self param flags here. + if (origSelfParamFlags.isOwned()) + newFlags = newFlags.withOwned(true); + else if (origSelfParamFlags.isShared()) + newFlags = newFlags.withShared(true); + } + + AnyFunctionType::Param selfParam(apply.selfParam.getSubstRValueType(), + Identifier(), newFlags); emission.addSelfParam(e, std::move(apply.selfParam), selfParam); } diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp index 4fd7137a7d638..59e4e4348575b 100644 --- a/lib/SILGen/SILGenBuilder.cpp +++ b/lib/SILGen/SILGenBuilder.cpp @@ -483,7 +483,14 @@ static ManagedValue createInputFunctionArgument( assert((F.isBare() || isFormalParameterPack || decl) && "Function arguments of non-bare functions must have a decl"); auto *arg = F.begin()->createFunctionArgument(type, decl); - arg->setNoImplicitCopy(isNoImplicitCopy); + if (auto *pd = dyn_cast_or_null(decl)) { + if (!arg->getType().isPureMoveOnly()) { + isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Borrowing; + isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Consuming; + } + } + if (isNoImplicitCopy) + arg->setNoImplicitCopy(isNoImplicitCopy); arg->setClosureCapture(isClosureCapture); arg->setLifetimeAnnotation(lifetimeAnnotation); arg->setFormalParameterPack(isFormalParameterPack); @@ -980,11 +987,12 @@ ManagedValue SILGenBuilder::createBeginBorrow(SILLocation loc, return ManagedValue::forUnmanaged(newValue); } -ManagedValue SILGenBuilder::createMoveValue(SILLocation loc, - ManagedValue value) { +ManagedValue SILGenBuilder::createMoveValue(SILLocation loc, ManagedValue value, + bool isLexical) { assert(value.isPlusOne(SGF) && "Must be +1 to be moved!"); CleanupCloner cloner(*this, value); - auto *mdi = createMoveValue(loc, value.forward(getSILGenFunction())); + auto *mdi = + createMoveValue(loc, value.forward(getSILGenFunction()), isLexical); return cloner.clone(mdi); } @@ -1027,8 +1035,9 @@ ManagedValue SILGenBuilder::createGuaranteedCopyableToMoveOnlyWrapperValue( ManagedValue SILGenBuilder::createMarkMustCheckInst(SILLocation loc, ManagedValue value, MarkMustCheckInst::CheckKind kind) { - assert((value.isPlusOne(SGF) || value.isLValue()) && - "Argument must be at +1 or be an inout!"); + assert((value.isPlusOne(SGF) || value.isLValue() || + value.getType().isAddress()) && + "Argument must be at +1 or be an address!"); CleanupCloner cloner(*this, value); auto *mdi = SILBuilder::createMarkMustCheckInst( loc, value.forward(getSILGenFunction()), kind); diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h index 8e89291a6b411..a7c7cc852d152 100644 --- a/lib/SILGen/SILGenBuilder.h +++ b/lib/SILGen/SILGenBuilder.h @@ -441,7 +441,8 @@ class SILGenBuilder : public SILBuilder { bool isLexical = false); using SILBuilder::createMoveValue; - ManagedValue createMoveValue(SILLocation loc, ManagedValue value); + ManagedValue createMoveValue(SILLocation loc, ManagedValue value, + bool isLexical = false); using SILBuilder::createOwnedMoveOnlyWrapperToCopyableValue; ManagedValue createOwnedMoveOnlyWrapperToCopyableValue(SILLocation loc, diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index b232f869b0ebc..2d2a7e9b97528 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -509,6 +509,25 @@ class LocalVariableInitialization : public SingleBufferInitialization { // The box type's context is lowered in the minimal resilience domain. auto instanceType = SGF.SGM.Types.getLoweredRValueType( TypeExpansionContext::minimal(), decl->getType()); + + // If we have a no implicit copy param decl, make our instance type + // @moveOnly. + if (!instanceType->isPureMoveOnly()) { + if (auto *pd = dyn_cast(decl)) { + bool isNoImplicitCopy = pd->isNoImplicitCopy(); + isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Consuming; + if (pd->isSelfParameter()) { + auto *dc = pd->getDeclContext(); + if (auto *fn = dyn_cast(dc)) { + auto accessKind = fn->getSelfAccessKind(); + isNoImplicitCopy |= accessKind == SelfAccessKind::Consuming; + } + } + if (isNoImplicitCopy) + instanceType = SILMoveOnlyWrappedType::get(instanceType); + } + } + auto boxType = SGF.SGM.Types.getContextBoxTypeForCapture( decl, instanceType, SGF.F.getGenericEnvironment(), /*mutable*/ !instanceType->isPureMoveOnly() || !decl->isLet()); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index e73942d626667..529ab0ad23ace 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -6131,11 +6131,18 @@ RValue RValueEmitter::visitConsumeExpr(ConsumeExpr *E, SGFContext C) { auto address = SGF.emitAddressOfLValue(subExpr, std::move(lv)); auto optTemp = SGF.emitTemporary(E, SGF.getTypeLowering(subType)); SILValue toAddr = optTemp->getAddressForInPlaceInitialization(SGF, E); - if (address.getType().isMoveOnly()) { - SGF.B.createCopyAddr(subExpr, address.getLValueAddress(), toAddr, IsNotTake, + SILValue fromAddr = address.getLValueAddress(); + bool isMoveOnly = fromAddr->getType().isMoveOnly() || + isa(fromAddr); + if (toAddr->getType().isMoveOnlyWrapped()) + toAddr = SGF.B.createMoveOnlyWrapperToCopyableAddr(subExpr, toAddr); + if (isMoveOnly) { + if (fromAddr->getType().isMoveOnlyWrapped()) + fromAddr = SGF.B.createMoveOnlyWrapperToCopyableAddr(subExpr, fromAddr); + SGF.B.createCopyAddr(subExpr, fromAddr, toAddr, IsNotTake, IsInitialization); } else { - SGF.B.createMarkUnresolvedMoveAddr(subExpr, address.getLValueAddress(), toAddr); + SGF.B.createMarkUnresolvedMoveAddr(subExpr, fromAddr, toAddr); } optTemp->finishInitialization(SGF); @@ -6176,8 +6183,15 @@ RValue RValueEmitter::visitConsumeExpr(ConsumeExpr *E, SGFContext C) { SGF.emitRValue(subExpr, SGFContext(SGFContext::AllowImmediatePlusZero)) .getAsSingleValue(SGF, subExpr); assert(mv.getType().isAddress()); - if (mv.getType().isMoveOnly()) { - SGF.B.createCopyAddr(subExpr, mv.getValue(), toAddr, IsNotTake, + bool isMoveOnly = mv.getType().isMoveOnly() || + isa(mv.getValue()); + SILValue fromAddr = mv.getValue(); + if (toAddr->getType().isMoveOnlyWrapped()) + toAddr = SGF.B.createMoveOnlyWrapperToCopyableAddr(subExpr, toAddr); + if (isMoveOnly) { + if (fromAddr->getType().isMoveOnlyWrapped()) + fromAddr = SGF.B.createMoveOnlyWrapperToCopyableAddr(subExpr, fromAddr); + SGF.B.createCopyAddr(subExpr, fromAddr, toAddr, IsNotTake, IsInitialization); } else { SGF.B.createMarkUnresolvedMoveAddr(subExpr, mv.getValue(), toAddr); @@ -6202,6 +6216,13 @@ RValue RValueEmitter::visitCopyExpr(CopyExpr *E, SGFContext C) { // above. ManagedValue value = SGF.B.createFormalAccessLoadBorrow(E, address); + if (value.getType().isMoveOnlyWrapped()) { + value = SGF.B.createGuaranteedMoveOnlyWrapperToCopyableValue(E, value); + // If we have a trivial value after unwrapping, just return that. + if (value.getType().isTrivial(SGF.F)) + return RValue(SGF, {value}, subType.getASTType()); + } + // We purposely, use a lexical cleanup here so that the cleanup lasts // through the formal evaluation scope. ManagedValue copy = SGF.B.createExplicitCopyValue(E, value); @@ -6211,8 +6232,13 @@ RValue RValueEmitter::visitCopyExpr(CopyExpr *E, SGFContext C) { auto optTemp = SGF.emitTemporary(E, SGF.getTypeLowering(subType)); SILValue toAddr = optTemp->getAddressForInPlaceInitialization(SGF, E); - SGF.B.createExplicitCopyAddr(subExpr, address.getLValueAddress(), toAddr, - IsNotTake, IsInitialization); + if (toAddr->getType().isMoveOnlyWrapped()) + toAddr = SGF.B.createMoveOnlyWrapperToCopyableAddr(E, toAddr); + SILValue fromAddr = address.getLValueAddress(); + if (fromAddr->getType().isMoveOnlyWrapped()) + fromAddr = SGF.B.createMoveOnlyWrapperToCopyableAddr(E, fromAddr); + SGF.B.createExplicitCopyAddr(subExpr, fromAddr, toAddr, IsNotTake, + IsInitialization); optTemp->finishInitialization(SGF); return RValue(SGF, {optTemp->getManagedAddress()}, subType.getASTType()); } @@ -6221,7 +6247,24 @@ RValue RValueEmitter::visitCopyExpr(CopyExpr *E, SGFContext C) { ManagedValue mv = SGF.emitRValue(subExpr).getAsSingleValue(SGF, subExpr); if (mv.getType().isTrivial(SGF.F)) return RValue(SGF, {mv}, subType.getASTType()); - mv = SGF.B.createExplicitCopyValue(E, mv); + { + // We use a formal evaluation scope so we tightly scope the formal access + // borrow below. + FormalEvaluationScope scope(SGF); + if (mv.getType().isMoveOnlyWrapped()) { + if (mv.getOwnershipKind() != OwnershipKind::Guaranteed) + mv = mv.formalAccessBorrow(SGF, E); + mv = SGF.B.createGuaranteedMoveOnlyWrapperToCopyableValue(E, mv); + } + + // Only perform the actual explicit_copy_value if we do not have a trivial + // type. + // + // DISCUSSION: We can only get a trivial type if we have a moveonlywrapped + // type of a trivial type. + if (!mv.getType().isTrivial(SGF.F)) + mv = SGF.B.createExplicitCopyValue(E, mv); + } return RValue(SGF, {mv}, subType.getASTType()); } @@ -6237,7 +6280,12 @@ RValue RValueEmitter::visitCopyExpr(CopyExpr *E, SGFContext C) { SGF.emitRValue(subExpr, SGFContext(SGFContext::AllowImmediatePlusZero)) .getAsSingleValue(SGF, subExpr); assert(mv.getType().isAddress()); - SGF.B.createExplicitCopyAddr(subExpr, mv.getValue(), toAddr, IsNotTake, + if (toAddr->getType().isMoveOnlyWrapped()) + toAddr = SGF.B.createMoveOnlyWrapperToCopyableAddr(E, toAddr); + SILValue fromAddr = mv.getValue(); + if (fromAddr->getType().isMoveOnlyWrapped()) + fromAddr = SGF.B.createMoveOnlyWrapperToCopyableAddr(E, fromAddr); + SGF.B.createExplicitCopyAddr(subExpr, fromAddr, toAddr, IsNotTake, IsInitialization); optTemp->finishInitialization(SGF); return RValue(SGF, {optTemp->getManagedAddress()}, subType.getASTType()); diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 45f5340b86dab..a749212a17846 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -752,6 +752,10 @@ void SILGenFunction::emitCaptures(SILLocation loc, B.createCopyValue(loc, ManagedValue::forUnmanaged(val))); } else { auto addr = getAddressValue(val, /*forceCopy=*/true); + // If our address is move only wrapped, unwrap it. + if (addr->getType().isMoveOnlyWrapped()) { + addr = B.createMoveOnlyWrapperToCopyableAddr(loc, addr); + } capturedArgs.push_back(ManagedValue::forLValue(addr)); } break; @@ -760,9 +764,15 @@ void SILGenFunction::emitCaptures(SILLocation loc, assert(!isPack); auto addr = getAddressValue(val, /*forceCopy=*/false); + // No-escaping stored declarations are captured as the // address of the value. assert(addr->getType().isAddress() && "no address for captured var!"); + + // If we have a moveonlywrapped address type, unwrap it. + if (addr->getType().isMoveOnlyWrapped()) + addr = B.createMoveOnlyWrapperToCopyableAddr(loc, addr); + capturedArgs.push_back(ManagedValue::forLValue(addr)); break; } @@ -780,13 +790,24 @@ void SILGenFunction::emitCaptures(SILLocation loc, // If this is a boxed variable, we can use it directly. if (Entry.box && entryValue->getType().getASTType() == minimalLoweredType) { + // If our captured value is a box with a moveonlywrapped type inside, + // unwrap it. + auto box = ManagedValue::forBorrowedObjectRValue(Entry.box); // We can guarantee our own box to the callee. if (canGuarantee) { - capturedArgs.push_back( - ManagedValue::forUnmanaged(Entry.box).borrow(*this, loc)); + box = box.borrow(*this, loc); } else { - capturedArgs.push_back(emitManagedRetain(loc, Entry.box)); + box = box.copy(*this, loc); + } + + if (box.getType().isBoxedMoveOnlyWrappedType(&F)) { + CleanupCloner cloner(*this, box); + box = cloner.clone( + B.createMoveOnlyWrapperToCopyableBox(loc, box.forward(*this))); } + + capturedArgs.push_back(box); + if (captureCanEscape) escapesToMark.push_back(entryValue); } else { diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 15e9bef484594..f3769c5b90c92 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -879,6 +879,12 @@ namespace { return SGF.B.createStructExtract(loc, base, Field); } + // If we have a moveonlywrapped type, unwrap it. The reason why is that + // any fields that we access we want to be treated as copyable. + if (base.getType().isMoveOnlyWrapped()) + base = ManagedValue::forLValue( + SGF.B.createMoveOnlyWrapperToCopyableAddr(loc, base.getValue())); + // TODO: if the base is +1, break apart its cleanup. auto Res = SGF.B.createStructElementAddr(loc, base.getValue(), Field, SubstFieldType); @@ -4174,8 +4180,17 @@ ManagedValue SILGenFunction::emitLoad(SILLocation loc, SILValue addr, // If the client is cool with a +0 rvalue, the decl has an address-only // type, and there are no conversions, then we can return this as a +0 // address RValue. - if (isPlusZeroOk && rvalueTL.getLoweredType() == addrTL.getLoweredType()) - return ManagedValue::forUnmanaged(addr); + if (isPlusZeroOk) { + SILType rvalueType = rvalueTL.getLoweredType(); + SILType addrType = addrTL.getLoweredType(); + if (!rvalueType.isMoveOnlyWrapped() && addrType.isMoveOnlyWrapped()) { + SILValue value = B.createMoveOnlyWrapperToCopyableAddr(loc, addr); + return ManagedValue::forUnmanaged(value); + } + if (rvalueTL.getLoweredType() == addrTL.getLoweredType()) { + return ManagedValue::forUnmanaged(addr); + } + } // Copy the address-only value. return B.bufferForExpr( @@ -4514,19 +4529,29 @@ void SILGenFunction::emitSemanticLoadInto(SILLocation loc, return; } - // Then see if our source address was a move only type and our dest was + // Then see if our source address was a moveonlywrapped type and our dest was // not. In such a case, just cast away the move only and perform a // copy_addr. We are going to error on this later after SILGen. if (srcTL.getLoweredType().removingMoveOnlyWrapper() == destTL.getLoweredType().removingMoveOnlyWrapper()) { // In such a case, for now emit B.createCopyAddr. In the future, insert the // address version of moveonly_to_copyable. - if (src->getType().isMoveOnlyWrapped()) - src = B.createUncheckedAddrCast( - loc, src, srcTL.getLoweredType().removingMoveOnlyWrapper()); - if (dest->getType().isMoveOnlyWrapped()) - dest = B.createUncheckedAddrCast( - loc, dest, destTL.getLoweredType().removingMoveOnlyWrapper()); + if (src->getType().isMoveOnlyWrapped()) { + // If we have a take, we are performing an owned usage of our src addr. If + // we aren't taking, then we can use guaranteed. + if (isTake) { + src = B.createMoveOnlyWrapperToCopyableAddr(loc, src); + } else { + src = B.createMoveOnlyWrapperToCopyableAddr(loc, src); + } + } + if (dest->getType().isMoveOnlyWrapped()) { + if (isInit) { + dest = B.createMoveOnlyWrapperToCopyableAddr(loc, dest); + } else { + dest = B.createMoveOnlyWrapperToCopyableAddr(loc, dest); + } + } B.createCopyAddr(loc, src, dest, isTake, isInit); return; } @@ -4543,24 +4568,27 @@ void SILGenFunction::emitSemanticStore(SILLocation loc, IsInitialization_t isInit) { assert(destTL.getLoweredType().getAddressType() == dest->getType()); - // If our rvalue is a move only value, insert a moveonly_to_copyable - // instruction. This type must have come from the usage of an @_noImplicitCopy - // or @_isNoEscape. We rely on the relevant checkers at the SIL level to - // validate that this is safe to do. SILGen is just leaving in crumbs to be - // checked. - // - // TODO: For now we are only supporting objects since we are setup to handle - // lets when opaque values are enabled. We may also in the future support - // vars. If we do that before opaque values are enabled, we will use it to - // also handle address only lets. - if (rvalue->getType().isMoveOnlyWrapped() && rvalue->getType().isObject()) { - rvalue = B.createOwnedMoveOnlyWrapperToCopyableValue(loc, rvalue); + if (rvalue->getType().isMoveOnlyWrapped()) { + + // If our rvalue is a moveonlywrapped value, insert a moveonly_to_copyable + // instruction. We rely on the relevant checkers at the SIL level to + // validate that this is safe to do. SILGen is just leaving in crumbs to be + // checked. + if (rvalue->getType().isObject()) + rvalue = B.createOwnedMoveOnlyWrapperToCopyableValue(loc, rvalue); + else + rvalue = B.createMoveOnlyWrapperToCopyableAddr(loc, rvalue); + } + + // If our dest is a moveonlywrapped address, unwrap it. + if (dest->getType().isMoveOnlyWrapped()) { + dest = B.createMoveOnlyWrapperToCopyableAddr(loc, dest); } // Easy case: the types match. - if (rvalue->getType() == destTL.getLoweredType()) { - assert(!silConv.useLoweredAddresses() - || (destTL.isAddressOnly() == rvalue->getType().isAddress())); + if (rvalue->getType().getObjectType() == dest->getType().getObjectType()) { + assert(!silConv.useLoweredAddresses() || + (dest->getType().isAddressOnly(F) == rvalue->getType().isAddress())); if (rvalue->getType().isAddress()) { B.createCopyAddr(loc, rvalue, dest, IsTake, isInit); } else { @@ -5102,6 +5130,12 @@ void SILGenFunction::emitCopyLValueInto(SILLocation loc, LValue &&src, UnenforcedAccess access; SILValue accessAddress = access.beginAccess(*this, loc, destAddr, SILAccessKind::Modify); + + if (srcAddr->getType().isMoveOnlyWrapped()) + srcAddr = B.createMoveOnlyWrapperToCopyableAddr(loc, srcAddr); + if (accessAddress->getType().isMoveOnlyWrapped()) + accessAddress = B.createMoveOnlyWrapperToCopyableAddr(loc, accessAddress); + B.createCopyAddr(loc, srcAddr, accessAddress, IsNotTake, IsInitialization); access.endAccess(*this); diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index aee5969afe9a9..7971435c54bda 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -631,43 +631,55 @@ class ArgumentInitHelper { } void updateArgumentValueForBinding(ManagedValue argrv, SILLocation loc, - ParamDecl *pd, SILValue value, + ParamDecl *pd, const SILDebugVariable &varinfo) { bool calledCompletedUpdate = false; SWIFT_DEFER { assert(calledCompletedUpdate && "Forgot to call completed update along " "all paths or manually turn it off"); }; - auto completeUpdate = [&](SILValue value) -> void { - SGF.B.createDebugValue(loc, value, varinfo); - SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value); + auto completeUpdate = [&](ManagedValue value) -> void { + SGF.B.createDebugValue(loc, value.getValue(), varinfo); + SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value.getValue()); calledCompletedUpdate = true; }; // If we do not need to support lexical lifetimes, just return value as the // updated value. if (!SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) - return completeUpdate(value); + return completeUpdate(argrv); // Look for the following annotations on the function argument: // - @noImplicitCopy // - @_eagerMove // - @_noEagerMove - auto isNoImplicitCopy = pd->isNoImplicitCopy(); + bool isNoImplicitCopy = pd->isNoImplicitCopy(); + if (!argrv.getType().isPureMoveOnly()) { + isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Borrowing; + isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Consuming; + if (pd->isSelfParameter()) { + auto *dc = pd->getDeclContext(); + if (auto *fn = dyn_cast(dc)) { + auto accessKind = fn->getSelfAccessKind(); + isNoImplicitCopy |= accessKind == SelfAccessKind::Borrowing; + isNoImplicitCopy |= accessKind == SelfAccessKind::Consuming; + } + } + } // If we have a no implicit copy argument and the argument is trivial, // we need to use copyable to move only to convert it to its move only // form. if (!isNoImplicitCopy) { - if (!value->getType().isMoveOnly()) { + if (!argrv.getType().isMoveOnly()) { // Follow the normal path. The value's lifetime will be enforced based // on its ownership. - return completeUpdate(value); + return completeUpdate(argrv); } // At this point, we have a noncopyable type. If it is owned, create an // alloc_box for it. - if (value->getOwnershipKind() == OwnershipKind::Owned) { + if (argrv.getOwnershipKind() == OwnershipKind::Owned) { // TODO: Once owned values are mutable, this needs to become mutable. auto boxType = SGF.SGM.Types.getContextBoxTypeForCapture( pd, @@ -696,17 +708,18 @@ class ArgumentInitHelper { // misleading consuming message. We still are able to pass it to // non-escaping closures though since the onstack partial_apply does not // consume the value. - assert(value->getOwnershipKind() == OwnershipKind::Guaranteed); - value = SGF.B.createCopyValue(loc, value); - value = SGF.B.createMarkMustCheckInst( - loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); - SGF.emitManagedRValueWithCleanup(value); - return completeUpdate(value); + assert(argrv.getOwnershipKind() == OwnershipKind::Guaranteed); + argrv = argrv.copy(SGF, loc); + argrv = SGF.B.createMarkMustCheckInst( + loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); + return completeUpdate(argrv); } - if (value->getType().isTrivial(SGF.F)) { - value = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(loc, value); - value = SGF.B.createMoveValue(loc, value, /*isLexical=*/true); + if (argrv.getType().isTrivial(SGF.F)) { + SILValue value = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue( + loc, argrv.getValue()); + argrv = SGF.emitManagedRValueWithCleanup(value); + argrv = SGF.B.createMoveValue(loc, argrv, /*isLexical=*/true); // If our argument was owned, we use no implicit copy. Otherwise, we // use no copy. @@ -723,40 +736,35 @@ class ArgumentInitHelper { break; } - value = SGF.B.createMarkMustCheckInst(loc, value, kind); - SGF.emitManagedRValueWithCleanup(value); - return completeUpdate(value); + argrv = SGF.B.createMarkMustCheckInst(loc, argrv, kind); + return completeUpdate(argrv); } - if (value->getOwnershipKind() == OwnershipKind::Guaranteed) { - value = SGF.B.createGuaranteedCopyableToMoveOnlyWrapperValue(loc, value); - value = SGF.B.createCopyValue(loc, value); - value = SGF.B.createMarkMustCheckInst( - loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); - SGF.emitManagedRValueWithCleanup(value); - return completeUpdate(value); + if (argrv.getOwnershipKind() == OwnershipKind::Guaranteed) { + argrv = SGF.B.createGuaranteedCopyableToMoveOnlyWrapperValue(loc, argrv); + argrv = argrv.copy(SGF, loc); + argrv = SGF.B.createMarkMustCheckInst( + loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); + return completeUpdate(argrv); } - if (value->getOwnershipKind() == OwnershipKind::Owned) { + if (argrv.getOwnershipKind() == OwnershipKind::Owned) { // If we have an owned value, forward it into the mark_must_check to // avoid an extra destroy_value. - value = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue( - loc, argrv.forward(SGF)); - value = SGF.B.createMoveValue(loc, value, true /*is lexical*/); - value = SGF.B.createMarkMustCheckInst( - loc, value, MarkMustCheckInst::CheckKind::ConsumableAndAssignable); - SGF.emitManagedRValueWithCleanup(value); - return completeUpdate(value); + argrv = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(loc, argrv); + argrv = SGF.B.createMoveValue(loc, argrv, true /*is lexical*/); + argrv = SGF.B.createMarkMustCheckInst( + loc, argrv, MarkMustCheckInst::CheckKind::ConsumableAndAssignable); + return completeUpdate(argrv); } - return completeUpdate(value); + return completeUpdate(argrv); } /// Create a SILArgument and store its value into the given Initialization, /// if not null. void makeArgumentIntoBinding(SILLocation loc, ParamDecl *pd) { ManagedValue argrv = makeArgument(loc, pd); - SILValue value = argrv.getValue(); if (pd->isInOut()) { assert(argrv.getType().isAddress() && "expected inout to be address"); } else if (!pd->isImmutableInFunctionBody()) { @@ -774,33 +782,53 @@ class ArgumentInitHelper { SILDebugVariable varinfo(pd->isImmutableInFunctionBody(), ArgNo); if (!argrv.getType().isAddress()) { // NOTE: We setup SGF.VarLocs[pd] in updateArgumentValueForBinding. - updateArgumentValueForBinding(argrv, loc, pd, value, varinfo); + updateArgumentValueForBinding(argrv, loc, pd, varinfo); return; } - if (auto *allocStack = dyn_cast(value)) { + if (auto *allocStack = dyn_cast(argrv.getValue())) { allocStack->setArgNo(ArgNo); if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes( SGF.getModule()) && - SGF.F.getLifetime(pd, value->getType()).isLexical()) + SGF.F.getLifetime(pd, allocStack->getType()).isLexical()) allocStack->setIsLexical(); - SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value); + SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(allocStack); return; } - SILValue debugOperand = value; - if (value->getType().isMoveOnly()) { + if (auto *arg = dyn_cast(argrv.getValue())) { + if (arg->isNoImplicitCopy()) { + switch (pd->getSpecifier()) { + case swift::ParamSpecifier::Borrowing: + // Shouldn't have any cleanups on this. + assert(!argrv.hasCleanup()); + argrv = ManagedValue::forBorrowedAddressRValue( + SGF.B.createCopyableToMoveOnlyWrapperAddr(pd, argrv.getValue())); + break; + case swift::ParamSpecifier::Consuming: + case swift::ParamSpecifier::Default: + case swift::ParamSpecifier::InOut: + case swift::ParamSpecifier::LegacyOwned: + case swift::ParamSpecifier::LegacyShared: + break; + } + } + } + + SILValue debugOperand = argrv.getValue(); + + if (argrv.getType().isMoveOnly()) { switch (pd->getValueOwnership()) { case ValueOwnership::Default: if (pd->isSelfParameter()) { - assert(!isa(value) && + assert(!isa(argrv.getValue()) && "Should not have inserted mark must check inst in EmitBBArgs"); if (!pd->isInOut()) { - value = SGF.B.createMarkMustCheckInst( - loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); + argrv = SGF.B.createMarkMustCheckInst( + loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); } } else { - if (auto *fArg = dyn_cast(value)) { + if (auto *fArg = dyn_cast(argrv.getValue())) { switch (fArg->getArgumentConvention()) { case SILArgumentConvention::Direct_Guaranteed: case SILArgumentConvention::Direct_Owned: @@ -814,51 +842,51 @@ class ArgumentInitHelper { case SILArgumentConvention::Pack_Out: llvm_unreachable("Should have been handled elsewhere"); case SILArgumentConvention::Indirect_In: - value = SGF.B.createMarkMustCheckInst( - loc, value, + argrv = SGF.B.createMarkMustCheckInst( + loc, argrv, MarkMustCheckInst::CheckKind::ConsumableAndAssignable); break; case SILArgumentConvention::Indirect_In_Guaranteed: - value = SGF.B.createMarkMustCheckInst( - loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); + argrv = SGF.B.createMarkMustCheckInst( + loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); } } else { - assert(isa(value) && + assert(isa(argrv.getValue()) && "Should have inserted mark must check inst in EmitBBArgs"); } } break; case ValueOwnership::InOut: { - assert(isa(value) - && "Expected mark must check inst with inout to be handled in " - "emitBBArgs earlier"); - auto mark = cast(value); + assert(isa(argrv.getValue()) && + "Expected mark must check inst with inout to be handled in " + "emitBBArgs earlier"); + auto mark = cast(argrv.getValue()); debugOperand = mark->getOperand(); break; } case ValueOwnership::Owned: - value = SGF.B.createMarkMustCheckInst( - loc, value, MarkMustCheckInst::CheckKind::ConsumableAndAssignable); + argrv = SGF.B.createMarkMustCheckInst( + loc, argrv, MarkMustCheckInst::CheckKind::ConsumableAndAssignable); break; case ValueOwnership::Shared: - value = SGF.B.createMarkMustCheckInst( - loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); + argrv = SGF.B.createMarkMustCheckInst( + loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign); break; } } DebugValueInst *debugInst = SGF.B.createDebugValueAddr(loc, debugOperand, varinfo); - - if (value != debugOperand) { - if (auto valueInst = dyn_cast(value)) { + + if (argrv.getValue() != debugOperand) { + if (auto valueInst = dyn_cast(argrv.getValue())) { // Move the debug instruction outside of any marker instruction that might // have been applied to the value, so that analysis doesn't move the // debug_value anywhere it shouldn't be. debugInst->moveBefore(valueInst); } } - SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value); + SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(argrv.getValue()); } void emitParam(ParamDecl *PD) { diff --git a/lib/SILGen/SwitchEnumBuilder.cpp b/lib/SILGen/SwitchEnumBuilder.cpp index d2e5f16f80104..d50db70c6081b 100644 --- a/lib/SILGen/SwitchEnumBuilder.cpp +++ b/lib/SILGen/SwitchEnumBuilder.cpp @@ -90,17 +90,35 @@ void SwitchEnumBuilder::emit() && { defaultBlockData ? defaultBlockData->count : ProfileCounter(); ArrayRef caseBlockCountsRef = caseBlockCounts; if (isAddressOnly) { + if (subjectExprOperand.getType().isMoveOnlyWrapped()) { + subjectExprOperand = ManagedValue::forUnmanaged( + builder.createMoveOnlyWrapperToCopyableAddr( + loc, subjectExprOperand.getValue())); + } builder.createSwitchEnumAddr(loc, subjectExprOperand.getValue(), defaultBlock, caseBlocks, caseBlockCountsRef, defaultBlockCount); } else { if (subjectExprOperand.getType().isAddress()) { - // TODO: Refactor this into a maybe load. - if (subjectExprOperand.hasCleanup()) { - subjectExprOperand = builder.createLoadTake(loc, subjectExprOperand); + bool hasCleanup = subjectExprOperand.hasCleanup(); + SILValue value = subjectExprOperand.forward(getSGF()); + if (value->getType().isMoveOnlyWrapped()) { + value = builder.createMoveOnlyWrapperToCopyableAddr( + loc, subjectExprOperand.getValue()); + } + if (hasCleanup) { + value = builder.emitLoadValueOperation(loc, value, + LoadOwnershipQualifier::Take); } else { - subjectExprOperand = builder.createLoadCopy(loc, subjectExprOperand); + value = builder.emitLoadValueOperation(loc, value, + LoadOwnershipQualifier::Copy); } + subjectExprOperand = getSGF().emitManagedRValueWithCleanup(value); + } else { + if (subjectExprOperand.getType().isMoveOnlyWrapped()) + subjectExprOperand = + builder.createOwnedMoveOnlyWrapperToCopyableValue( + loc, subjectExprOperand); } switchEnum = builder.createSwitchEnum( loc, subjectExprOperand.forward(getSGF()), defaultBlock, caseBlocks, diff --git a/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp b/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp index dea24876b0e02..73138ef18e785 100644 --- a/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp +++ b/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp @@ -616,7 +616,7 @@ class AccessEnforcementSelection : public SILModuleTransform { protected: void processFunction(SILFunction *F); - SourceAccess getAccessKindForBox(ProjectBoxInst *projection); + SourceAccess getAccessKindForBox(SILValue boxOperand); SourceAccess getSourceAccess(SILValue address); void handleApply(ApplySite apply); void handleAccess(BeginAccessInst *access); @@ -681,9 +681,7 @@ processFunction(SILFunction *F) { #endif } -SourceAccess -AccessEnforcementSelection::getAccessKindForBox(ProjectBoxInst *projection) { - SILValue source = projection->getOperand(); +SourceAccess AccessEnforcementSelection::getAccessKindForBox(SILValue source) { if (auto *BBI = dyn_cast(source)) source = BBI->getOperand(); if (auto *MUI = dyn_cast(source)) @@ -708,8 +706,16 @@ SourceAccess AccessEnforcementSelection::getSourceAccess(SILValue address) { if (auto *mmci = dyn_cast(address)) return getSourceAccess(mmci->getOperand()); + // Recurse through moveonlywrapper_to_copyable_addr. + if (auto *m = dyn_cast(address)) + return getSourceAccess(m->getOperand()); + + // Recurse through moveonlywrapper_to_copyable_box. + if (auto *m = dyn_cast(address)) + return getAccessKindForBox(m->getOperand()); + if (auto box = dyn_cast(address)) - return getAccessKindForBox(box); + return getAccessKindForBox(box->getOperand()); if (auto arg = dyn_cast(address)) { switch (arg->getArgumentConvention()) { diff --git a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp index 097b31298193d..0254a1cf067c7 100644 --- a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp +++ b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp @@ -396,6 +396,9 @@ static SILValue insertMarkDependenceForCapturedArguments(PartialApplyInst *pai, if (isa(arg.get()) || arg.get()->getType().isTrivial(*pai->getFunction())) continue; + if (auto *m = dyn_cast(arg.get())) + if (m->hasGuaranteedInitialKind()) + continue; curr = b.createMarkDependence(pai->getLoc(), curr, arg.get()); } @@ -434,19 +437,26 @@ static void insertAfterClosureUser(SILInstruction *closureUser, return; insertFn(builder); }; - - if (BeginBorrowInst *beginBorrow = dyn_cast(closureUser)) { - // Insert everywhere after the borrow is ended. - SmallVector endBorrows; - for (auto eb : beginBorrow->getEndBorrows()) { - endBorrows.push_back(eb); - } - - for (auto eb : endBorrows) { - SILBuilderWithScope builder(std::next(eb->getIterator())); - insertAtNonUnreachable(builder); + + { + SILInstruction *userForBorrow = closureUser; + if (auto *m = dyn_cast(userForBorrow)) + if (m->hasGuaranteedInitialKind()) + if (auto *svi = dyn_cast(m->getOperand())) + userForBorrow = svi; + if (auto *beginBorrow = dyn_cast(userForBorrow)) { + // Insert everywhere after the borrow is ended. + SmallVector endBorrows; + for (auto eb : beginBorrow->getEndBorrows()) { + endBorrows.push_back(eb); + } + + for (auto eb : endBorrows) { + SILBuilderWithScope builder(std::next(eb->getIterator())); + insertAtNonUnreachable(builder); + } + return; } - return; } if (auto *startAsyncLet = dyn_cast(closureUser)) { @@ -599,11 +609,25 @@ static SILValue tryRewriteToPartialApplyStack( } // Borrow the arguments that need borrowing. + SmallVector + noImplicitCopyWrapperToDelete; SmallVector args; for (Operand &arg : origPA->getArgumentOperands()) { auto argTy = arg.get()->getType(); if (!argTy.isAddress() && !argTy.isTrivial(*cvt->getFunction())) { - auto borrow = b.createBeginBorrow(origPA->getLoc(), arg.get()); + SILValue argValue = arg.get(); + bool foundNoImplicitCopy = false; + if (auto *mmci = dyn_cast(argValue)) { + if (mmci->hasOwnedInitialKind() && mmci->hasOneUse()) { + foundNoImplicitCopy = true; + argValue = mmci->getOperand(); + noImplicitCopyWrapperToDelete.push_back(mmci); + } + } + SILValue borrow = b.createBeginBorrow(origPA->getLoc(), argValue); + if (foundNoImplicitCopy) + borrow = b.createGuaranteedMoveOnlyWrapperToCopyableValue( + origPA->getLoc(), borrow); args.push_back(borrow); } else { args.push_back(arg.get()); @@ -653,6 +677,9 @@ static SILValue tryRewriteToPartialApplyStack( if (convertOrPartialApply != origPA) saveDeleteInst(convertOrPartialApply); saveDeleteInst(origPA); + // Delete the mmci of the origPA. + while (!noImplicitCopyWrapperToDelete.empty()) + saveDeleteInst(noImplicitCopyWrapperToDelete.pop_back_val()); ApplySite site(newPA); SILFunctionConventions calleeConv(site.getSubstCalleeType(), @@ -669,11 +696,15 @@ static SILValue tryRewriteToPartialApplyStack( assert(calleeArgumentIndex >= calleeConv.getSILArgIndexOfFirstParam()); auto paramInfo = calleeConv.getParamInfoForSILArg(calleeArgumentIndex); if (paramInfo.getConvention() == ParameterConvention::Indirect_In_Guaranteed) { + SILValue argValue = arg.get(); + if (auto *mmci = dyn_cast(argValue)) + argValue = mmci->getOperand(); // go over all the dealloc_stack, remove it - SmallVector Uses(arg.get()->getUses()); - for (auto use : Uses) + SmallVector Uses(argValue->getUses()); + for (auto use : Uses) { if (auto *deallocInst = dyn_cast(use->getUser())) deleter.forceDelete(deallocInst); + } } } diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index 7c6cb94b843f6..330931afa0507 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -441,7 +441,7 @@ static bool memInstMustConsume(Operand *memOper) { (CAI->getDest() == address && !CAI->isInitializationOfDest()); } case SILInstructionKind::ExplicitCopyAddrInst: { - auto *CAI = cast(memInst); + auto *CAI = cast(memInst); return (CAI->getSrc() == address && CAI->isTakeOfSrc()) || (CAI->getDest() == address && !CAI->isInitializationOfDest()); } @@ -518,6 +518,14 @@ static bool isInOutDefThatNeedsEndOfFunctionLiveness(MarkMustCheckInst *markedAd return false; } +static bool isCopyableValue(SILValue value) { + if (value->getType().isMoveOnly()) + return false; + if (auto *m = dyn_cast(value)) + return false; + return true; +} + //===----------------------------------------------------------------------===// // MARK: Partial Apply Utilities //===----------------------------------------------------------------------===// @@ -919,30 +927,36 @@ void UseState::initializeLiveness( // Then check if our markedValue is from an argument that is in, // in_guaranteed, inout, or inout_aliasable, consider the marked address to be // the initialization point. - if (auto *fArg = dyn_cast(address->getOperand())) { - switch (fArg->getArgumentConvention()) { - case swift::SILArgumentConvention::Indirect_In: - case swift::SILArgumentConvention::Indirect_In_Guaranteed: - case swift::SILArgumentConvention::Indirect_Inout: - case swift::SILArgumentConvention::Indirect_InoutAliasable: - // We need to add our address to the initInst array to make sure that - // later invariants that we assert upon remain true. - LLVM_DEBUG(llvm::dbgs() - << "Found in/in_guaranteed/inout/inout_aliasable argument as " - "an init... adding mark_must_check as init!\n"); - initInsts.insert({address, liveness.getTopLevelSpan()}); - liveness.initializeDef(address, liveness.getTopLevelSpan()); - break; - case swift::SILArgumentConvention::Indirect_Out: - llvm_unreachable("Should never have out addresses here"); - case swift::SILArgumentConvention::Direct_Owned: - case swift::SILArgumentConvention::Direct_Unowned: - case swift::SILArgumentConvention::Direct_Guaranteed: - case swift::SILArgumentConvention::Pack_Inout: - case swift::SILArgumentConvention::Pack_Guaranteed: - case swift::SILArgumentConvention::Pack_Owned: - case swift::SILArgumentConvention::Pack_Out: - llvm_unreachable("Working with addresses"); + { + SILValue operand = address->getOperand(); + if (auto *c = dyn_cast(operand)) + operand = c->getOperand(); + if (auto *fArg = dyn_cast(operand)) { + switch (fArg->getArgumentConvention()) { + case swift::SILArgumentConvention::Indirect_In: + case swift::SILArgumentConvention::Indirect_In_Guaranteed: + case swift::SILArgumentConvention::Indirect_Inout: + case swift::SILArgumentConvention::Indirect_InoutAliasable: + // We need to add our address to the initInst array to make sure that + // later invariants that we assert upon remain true. + LLVM_DEBUG( + llvm::dbgs() + << "Found in/in_guaranteed/inout/inout_aliasable argument as " + "an init... adding mark_must_check as init!\n"); + initInsts.insert({address, liveness.getTopLevelSpan()}); + liveness.initializeDef(address, liveness.getTopLevelSpan()); + break; + case swift::SILArgumentConvention::Indirect_Out: + llvm_unreachable("Should never have out addresses here"); + case swift::SILArgumentConvention::Direct_Owned: + case swift::SILArgumentConvention::Direct_Unowned: + case swift::SILArgumentConvention::Direct_Guaranteed: + case swift::SILArgumentConvention::Pack_Inout: + case swift::SILArgumentConvention::Pack_Guaranteed: + case swift::SILArgumentConvention::Pack_Owned: + case swift::SILArgumentConvention::Pack_Out: + llvm_unreachable("Working with addresses"); + } } } @@ -1357,7 +1371,7 @@ struct CopiedLoadBorrowEliminationVisitor final // Look through copy_value of a move only value. We treat copy_value of // copyable values as normal uses. if (auto *cvi = dyn_cast(nextUse->getUser())) { - if (cvi->getOperand()->getType().isMoveOnly()) { + if (!isCopyableValue(cvi->getOperand())) { shouldConvertToLoadCopy = true; break; } @@ -1462,6 +1476,12 @@ checkForDestructureThroughDeinit(MarkMustCheckInst *rootAddress, Operand *use, auto iterType = rootAddress->getType(); TypeOffsetSizePair iterPair(iterType, fn); + // If our rootAddress is moveonlywrapped, then we know that it must be + // copyable under the hood meanign that we copy its fields rather than + // destructure the fields. + if (iterType.isMoveOnlyWrapped()) + return; + while (iterType != targetType) { // If we have a nominal type as our parent type, see if it has a // deinit. We know that it must be non-copyable since copyable types @@ -1665,7 +1685,7 @@ bool GatherUsesVisitor::visitUse(Operand *op) { return false; // If we have a non-move only type, just treat this as a liveness use. - if (!copyAddr->getSrc()->getType().isMoveOnly()) { + if (isCopyableValue(copyAddr->getSrc())) { LLVM_DEBUG(llvm::dbgs() << "Found copy of copyable type. Treating as liveness use! " << *user); @@ -1682,6 +1702,7 @@ bool GatherUsesVisitor::visitUse(Operand *op) { markedValue); return true; } + LLVM_DEBUG(llvm::dbgs() << "Found mark must check [nocopy] error: " << *user); diagnosticEmitter.emitAddressDiagnosticNoCopy(markedValue, copyAddr); @@ -1716,7 +1737,7 @@ bool GatherUsesVisitor::visitUse(Operand *op) { // trivial load. If it is, then we just treat this as a liveness requiring // use. if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Trivial || - !li->getType().isMoveOnly()) { + isCopyableValue(li)) { auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress()); if (!leafRange) return false; @@ -2005,6 +2026,22 @@ bool GatherUsesVisitor::visitUse(Operand *op) { } } + if (auto *explicitCopy = dyn_cast(op->getUser())) { + assert(op->getOperandNumber() == ExplicitCopyAddrInst::Src && + "Dest should have been handled earlier"); + assert(!explicitCopy->isTakeOfSrc() && + "If we had a take of src, this should have already been identified " + "as a must consume"); + auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress()); + if (!leafRange) { + LLVM_DEBUG(llvm::dbgs() << "Failed to compute leaf range!\n"); + return false; + } + + useState.livenessUses.insert({user, *leafRange}); + return true; + } + // If we don't fit into any of those categories, just track as a liveness // use. We assume all such uses must only be reads to the memory. So we assert // to be careful. diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp index 09df8c4c39e6e..913c373a26fac 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp @@ -499,14 +499,15 @@ void DiagnosticEmitter::emitObjectDiagnosticsForGuaranteedUses( auto &astContext = fn->getASTContext(); for (auto *consumingUser : getCanonicalizer().consumingUsesNeedingCopy) { - if (ignorePartialApplyUses && isa(consumingUser)) + if (ignorePartialApplyUses && + OSSACanonicalizer::isPartialApplyUser(consumingUser)) continue; diagnose(astContext, consumingUser, diag::sil_movechecking_consuming_use_here); } for (auto *user : getCanonicalizer().consumingBoundaryUsers) { - if (ignorePartialApplyUses && isa(user)) + if (ignorePartialApplyUses && OSSACanonicalizer::isPartialApplyUser(user)) continue; diagnose(astContext, user, diag::sil_movechecking_consuming_use_here); @@ -518,7 +519,7 @@ void DiagnosticEmitter::emitObjectDiagnosticsForPartialApplyUses( auto &astContext = fn->getASTContext(); for (auto *user : getCanonicalizer().consumingUsesNeedingCopy) { - if (!isa(user)) + if (!OSSACanonicalizer::isPartialApplyUser(user)) continue; diagnose(astContext, user, @@ -527,7 +528,7 @@ void DiagnosticEmitter::emitObjectDiagnosticsForPartialApplyUses( } for (auto *user : getCanonicalizer().consumingBoundaryUsers) { - if (!isa(user)) + if (!OSSACanonicalizer::isPartialApplyUser(user)) continue; diagnose(astContext, diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyObjectCheckerUtils.h b/lib/SILOptimizer/Mandatory/MoveOnlyObjectCheckerUtils.h index f0359e5400eb0..8d03058f07442 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyObjectCheckerUtils.h +++ b/lib/SILOptimizer/Mandatory/MoveOnlyObjectCheckerUtils.h @@ -97,24 +97,44 @@ struct OSSACanonicalizer { bool foundFinalConsumingUses() const { return consumingBoundaryUsers.size(); } + /// Helper method for hasPartialApplyConsumingUse and + /// hasNonPartialApplyConsumingUse. + static bool isPartialApplyUser(SILInstruction *user) { + // If our user is an owned moveonlywrapper to copyable value inst, search + // through it for a partial_apply user. + if (auto *mtci = dyn_cast(user)) { + if (mtci->hasOwnedInitialKind()) { + return llvm::any_of(mtci->getUses(), [](Operand *use) { + return isa(use->getUser()); + }); + } + } + return isa(user); + } + + static bool isNotPartialApplyUser(SILInstruction *user) { + // If our user is an owned moveonlywrapper to copyable value inst, search + // through it for a partial_apply user. + if (auto *mtci = dyn_cast(user)) { + if (mtci->hasOwnedInitialKind()) { + return llvm::any_of(mtci->getUses(), [](Operand *use) { + return !isa(use->getUser()); + }); + } + } + return !isa(user); + } + bool hasPartialApplyConsumingUse() const { - return llvm::any_of(consumingUsesNeedingCopy, - [](SILInstruction *user) { - return isa(user); - }) || - llvm::any_of(consumingBoundaryUsers, [](SILInstruction *user) { - return isa(user); - }); + auto test = OSSACanonicalizer::isPartialApplyUser; + return llvm::any_of(consumingUsesNeedingCopy, test) || + llvm::any_of(consumingBoundaryUsers, test); } bool hasNonPartialApplyConsumingUse() const { - return llvm::any_of(consumingUsesNeedingCopy, - [](SILInstruction *user) { - return !isa(user); - }) || - llvm::any_of(consumingBoundaryUsers, [](SILInstruction *user) { - return !isa(user); - }); + auto test = OSSACanonicalizer::isNotPartialApplyUser; + return llvm::any_of(consumingUsesNeedingCopy, test) || + llvm::any_of(consumingBoundaryUsers, test); } struct DropDeinitFilter { diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp index b411791a49558..92b594f1bcf63 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp @@ -129,7 +129,10 @@ struct SILMoveOnlyWrappedTypeEliminatorVisitor return eraseFromParent(inst); \ } RAUW_ALWAYS(MoveOnlyWrapperToCopyableValue) + RAUW_ALWAYS(MoveOnlyWrapperToCopyableBox) + RAUW_ALWAYS(MoveOnlyWrapperToCopyableAddr) RAUW_ALWAYS(CopyableToMoveOnlyWrapperValue) + RAUW_ALWAYS(CopyableToMoveOnlyWrapperAddr) #undef RAUW_ALWAYS #define DELETE_IF_TRIVIAL_OP(CLS) \ @@ -171,6 +174,8 @@ struct SILMoveOnlyWrappedTypeEliminatorVisitor #define NO_UPDATE_NEEDED(CLS) \ bool visit##CLS##Inst(CLS##Inst *inst) { return false; } NO_UPDATE_NEEDED(AllocStack) + NO_UPDATE_NEEDED(AllocBox) + NO_UPDATE_NEEDED(ProjectBox) NO_UPDATE_NEEDED(DebugValue) NO_UPDATE_NEEDED(StructElementAddr) NO_UPDATE_NEEDED(TupleElementAddr) @@ -183,6 +188,8 @@ struct SILMoveOnlyWrappedTypeEliminatorVisitor NO_UPDATE_NEEDED(DestroyAddr) NO_UPDATE_NEEDED(DeallocStack) NO_UPDATE_NEEDED(Branch) + NO_UPDATE_NEEDED(ExplicitCopyAddr) + NO_UPDATE_NEEDED(CopyAddr) NO_UPDATE_NEEDED(RefElementAddr) NO_UPDATE_NEEDED(CheckedCastBranch) NO_UPDATE_NEEDED(Object) @@ -190,6 +197,8 @@ struct SILMoveOnlyWrappedTypeEliminatorVisitor NO_UPDATE_NEEDED(ConvertFunction) NO_UPDATE_NEEDED(RefToBridgeObject) NO_UPDATE_NEEDED(BridgeObjectToRef) + NO_UPDATE_NEEDED(BeginAccess) + NO_UPDATE_NEEDED(EndAccess) NO_UPDATE_NEEDED(ClassMethod) #undef NO_UPDATE_NEEDED @@ -270,6 +279,18 @@ struct SILMoveOnlyWrappedTypeEliminator { } // namespace +/// Returns true if this is a moveonlywrapped type whose underlying type is a +/// trivial type /or/ if this is a boxed type of that sort. +static bool isMoveOnlyWrappedTrivial(SILValue value) { + auto *fn = value->getFunction(); + SILType type = value->getType(); + if (type.removingMoveOnlyWrapper().isTrivial(fn)) + return true; + if (type.isBoxedMoveOnlyWrappedType(fn)) + return type.getSILBoxFieldType(fn).removingMoveOnlyWrapper().isTrivial(fn); + return false; +} + bool SILMoveOnlyWrappedTypeEliminator::process() { bool madeChange = true; @@ -278,7 +299,8 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { for (auto &bb : *fn) { for (auto *arg : bb.getArguments()) { - if (!arg->getType().isMoveOnlyWrapped()) + if (!arg->getType().isMoveOnlyWrapped() && + !arg->getType().isBoxedMoveOnlyWrappedType(fn)) continue; // If we are looking at trivial only, skip non-trivial function args. @@ -286,7 +308,7 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { !arg->getType().removingMoveOnlyWrapper().isTrivial(*fn)) continue; - arg->unsafelyEliminateMoveOnlyWrapper(); + arg->unsafelyEliminateMoveOnlyWrapper(fn); // If our new type is trivial, convert the arguments ownership to // None. Otherwise, preserve the ownership kind of the argument. @@ -299,14 +321,15 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { for (auto &ii : bb) { for (SILValue v : ii.getResults()) { - if (!v->getType().isMoveOnlyWrapped()) + if (!v->getType().isMoveOnlyWrapped() && + !v->getType().isBoxedMoveOnlyWrappedType(fn)) continue; if (trivialOnly && - !v->getType().removingMoveOnlyWrapper().isTrivial(*fn)) + !isMoveOnlyWrappedTrivial(v)) continue; - v->unsafelyEliminateMoveOnlyWrapper(); + v->unsafelyEliminateMoveOnlyWrapper(fn); touchedInsts.insert(&ii); // Add all users as well. This ensures we visit things like diff --git a/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp index 209db695f593b..b0fd930d00ffe 100644 --- a/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp @@ -199,6 +199,7 @@ struct OwnershipModelEliminatorVisitor } HANDLE_FORWARDING_INST(ConvertFunction) HANDLE_FORWARDING_INST(MoveOnlyWrapperToCopyableValue) + HANDLE_FORWARDING_INST(MoveOnlyWrapperToCopyableBox) HANDLE_FORWARDING_INST(Upcast) HANDLE_FORWARDING_INST(UncheckedRefCast) HANDLE_FORWARDING_INST(RefToBridgeObject) diff --git a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp index 9cf6f15c6738d..a02429ae68112 100644 --- a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp +++ b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp @@ -225,6 +225,9 @@ static bool hasOpaqueArchetype(TypeExpansionContext context, case SILInstructionKind::BeginBorrowInst: case SILInstructionKind::StoreBorrowInst: case SILInstructionKind::BeginAccessInst: + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: + case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: #define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ case SILInstructionKind::Load##Name##Inst: #include "swift/AST/ReferenceStorage.def" diff --git a/lib/SILOptimizer/Utils/InstOptUtils.cpp b/lib/SILOptimizer/Utils/InstOptUtils.cpp index 3a46b27d5ac3f..ca864041a1a25 100644 --- a/lib/SILOptimizer/Utils/InstOptUtils.cpp +++ b/lib/SILOptimizer/Utils/InstOptUtils.cpp @@ -1477,7 +1477,10 @@ void swift::insertDestroyOfCapturedArguments( auto loc = CleanupLocation(origLoc); for (auto &arg : pai->getArgumentOperands()) { SILValue argValue = arg.get(); - BeginBorrowInst *argBorrow = dyn_cast(argValue); + if (auto *m = dyn_cast(argValue)) + if (m->hasGuaranteedInitialKind()) + argValue = m->getOperand(); + auto *argBorrow = dyn_cast(argValue); if (argBorrow) { argValue = argBorrow->getOperand(); builder.createEndBorrow(loc, argBorrow); @@ -1499,18 +1502,19 @@ void swift::insertDeallocOfCapturedArguments(PartialApplyInst *pai, SILFunctionConventions calleeConv(site.getSubstCalleeType(), pai->getModule()); for (auto &arg : pai->getArgumentOperands()) { - SILValue argValue = arg.get(); - if (auto argBorrow = dyn_cast(argValue)) { - argValue = argBorrow->getOperand(); - } unsigned calleeArgumentIndex = site.getCalleeArgIndex(arg); assert(calleeArgumentIndex >= calleeConv.getSILArgIndexOfFirstParam()); auto paramInfo = calleeConv.getParamInfoForSILArg(calleeArgumentIndex); if (!paramInfo.isIndirectInGuaranteed()) continue; + SILValue argValue = arg.get(); + if (auto moveWrapper = + dyn_cast(argValue)) + argValue = moveWrapper->getOperand(); + SmallVector boundary; - auto *asi = cast(arg.get()); + auto *asi = cast(argValue); computeDominatedBoundaryBlocks(asi->getParent(), domInfo, boundary); SmallVector uses; diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index aa6901d7a2bb4..d2c5ca4e21c5b 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -882,6 +882,9 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst: case SILInstructionKind::TestSpecificationInst: + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: + case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: return InlineCost::Free; // Typed GEPs are free. diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 220c3a6d1c64f..b40cfa51c79c7 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -466,7 +466,7 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) { } auto DC = FD->getDeclContext(); - // self-ownership attributes may only appear in type context. + // mutation attributes may only appear in type context. if (auto contextTy = DC->getDeclaredInterfaceType()) { // 'mutating' and 'nonmutating' are not valid on types // with reference semantics. @@ -487,27 +487,6 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) { break; } } - - // Unless we have the experimental no-implicit-copy feature enabled, Copyable - // types can't use 'consuming' or 'borrowing' ownership specifiers. - if (!Ctx.LangOpts.hasFeature(Feature::NoImplicitCopy)) { - if (!contextTy->isPureMoveOnly()) { - switch (attrModifier) { // check the modifier for the Copyable type. - case SelfAccessKind::NonMutating: - case SelfAccessKind::Mutating: - case SelfAccessKind::LegacyConsuming: - // already checked - break; - - case SelfAccessKind::Consuming: - case SelfAccessKind::Borrowing: - diagnoseAndRemoveAttr(attr, diag::self_ownership_specifier_copyable, - attrModifier, FD->getDescriptiveKind()); - break; - } - } - } - } else { diagnoseAndRemoveAttr(attr, diag::mutating_invalid_global_scope, attrModifier); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index a3c6a815d3074..9e75d85f8b08b 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4297,30 +4297,18 @@ TypeResolver::resolveOwnershipTypeRepr(OwnershipTypeRepr *repr, case ParamSpecifier::InOut: case ParamSpecifier::LegacyShared: case ParamSpecifier::LegacyOwned: + case ParamSpecifier::Borrowing: break; - case ParamSpecifier::Consuming: if (auto *fnTy = result->getAs()) { if (fnTy->isNoEscape()) { - diagnoseInvalid(ownershipRepr, - ownershipRepr->getLoc(), + diagnoseInvalid(ownershipRepr, ownershipRepr->getLoc(), diag::ownership_specifier_nonescaping_closure, ownershipRepr->getSpecifierSpelling()); return ErrorType::get(getASTContext()); } } - SWIFT_FALLTHROUGH; - case ParamSpecifier::Borrowing: - // Unless we have the experimental no-implicit-copy feature enabled, Copyable - // types can't use 'consuming' or 'borrowing' ownership specifiers. - if (!getASTContext().LangOpts.hasFeature(Feature::NoImplicitCopy)) { - if (!result->isPureMoveOnly()) { - diagnoseInvalid(ownershipRepr, - ownershipRepr->getLoc(), - diag::ownership_specifier_copyable); - return ErrorType::get(getASTContext()); - } - } + break; } return result; diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 1ada5b44c2098..14bf3eee24e2e 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -2330,6 +2330,27 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, noNestedConflict, fromBuiltin); break; } + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: { + assert(RecordKind == SIL_ONE_OPERAND); + SILValue op = getLocalValue( + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); + ResultInst = Builder.createMoveOnlyWrapperToCopyableAddr(Loc, op); + break; + } + case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: { + assert(RecordKind == SIL_ONE_OPERAND); + SILValue op = getLocalValue( + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); + ResultInst = Builder.createMoveOnlyWrapperToCopyableBox(Loc, op); + break; + } + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: { + assert(RecordKind == SIL_ONE_OPERAND); + SILValue op = getLocalValue( + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); + ResultInst = Builder.createCopyableToMoveOnlyWrapperAddr(Loc, op); + break; + } case SILInstructionKind::EndAccessInst: { SILValue op = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 82e4491e3b3c9..bffaa9711caef 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 784; // pack element type +const uint16_t SWIFTMODULE_VERSION_MINOR = 785; // noimplicitcopy addr /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 7253bc94d876c..5a2a8b2d62022 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -5633,6 +5633,7 @@ void Serializer::writeAllDeclsAndTypes() { registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); + registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index d9af160191fb3..8d28a662c6eb9 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -433,7 +433,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { FuncTable[F.getName()] = NextFuncID++; Funcs.push_back(Out.GetCurrentBitNo()); unsigned abbrCode = SILAbbrCodes[SILFunctionLayout::Code]; - TypeID FnID = S.addTypeRef(F.getLoweredType().getASTType()); + TypeID FnID = S.addTypeRef(F.getLoweredType().getRawASTType()); LLVM_DEBUG(llvm::dbgs() << "SILFunction " << F.getName() << " @ BitNo " << Out.GetCurrentBitNo() << " abbrCode " << abbrCode << " FnID " << FnID << "\n"); @@ -620,7 +620,7 @@ void SILSerializer::writeSILBasicBlock(const SILBasicBlock &BB) { SmallVector Args; for (auto I = BB.args_begin(), E = BB.args_end(); I != E; ++I) { SILArgument *SA = *I; - DeclID tId = S.addTypeRef(SA->getType().getASTType()); + DeclID tId = S.addTypeRef(SA->getType().getRawASTType()); DeclID vId = addValueRef(static_cast(SA)); Args.push_back(tId); @@ -687,7 +687,7 @@ void SILSerializer::handleMethodInst(const MethodInst *MI, SmallVectorImpl &ListOfValues) { handleSILDeclRef(S, MI->getMember(), ListOfValues); ListOfValues.push_back( - S.addTypeRef(operand->getType().getASTType())); + S.addTypeRef(operand->getType().getRawASTType())); ListOfValues.push_back((unsigned)operand->getType().getCategory()); ListOfValues.push_back(addValueRef(operand)); } @@ -697,7 +697,7 @@ void SILSerializer::writeOneTypeLayout(SILInstructionKind valueKind, unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned) valueKind, attrs, - S.addTypeRef(type.getASTType()), + S.addTypeRef(type.getRawASTType()), (unsigned)type.getCategory()); } @@ -714,7 +714,7 @@ void SILSerializer::writeOneOperandLayout(SILInstructionKind valueKind, SILValue operand) { auto operandType = operand->getType(); - auto operandTypeRef = S.addTypeRef(operandType.getASTType()); + auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneOperandLayout::emitRecord(Out, ScratchRecord, @@ -730,7 +730,7 @@ writeOneOperandExtraAttributeLayout(SILInstructionKind valueKind, SILValue operand) { auto operandType = operand->getType(); - auto operandTypeRef = S.addTypeRef(operandType.getASTType()); + auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneOperandExtraAttributeLayout::emitRecord( @@ -743,9 +743,9 @@ void SILSerializer::writeOneTypeOneOperandLayout(SILInstructionKind valueKind, unsigned attrs, SILType type, SILValue operand) { - auto typeRef = S.addTypeRef(type.getASTType()); + auto typeRef = S.addTypeRef(type.getRawASTType()); auto operandType = operand->getType(); - auto operandTypeRef = S.addTypeRef(operandType.getASTType()); + auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, @@ -762,7 +762,7 @@ void SILSerializer::writeOneTypeOneOperandLayout(SILInstructionKind valueKind, SILValue operand) { auto typeRef = S.addTypeRef(type); auto operandType = operand->getType(); - auto operandTypeRef = S.addTypeRef(operandType.getASTType()); + auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, @@ -778,9 +778,9 @@ writeOneTypeOneOperandExtraAttributeLayout(SILInstructionKind valueKind, unsigned attrs, SILType type, SILValue operand) { - auto typeRef = S.addTypeRef(type.getASTType()); + auto typeRef = S.addTypeRef(type.getRawASTType()); auto operandType = operand->getType(); - auto operandTypeRef = S.addTypeRef(operandType.getASTType()); + auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneTypeOneOperandExtraAttributeLayout::emitRecord(Out, ScratchRecord, @@ -840,7 +840,7 @@ SILSerializer::writeKeyPathPatternComponent( ListOfValues.push_back(index.Operand); ListOfValues.push_back(S.addTypeRef(index.FormalType)); ListOfValues.push_back( - S.addTypeRef(index.LoweredType.getASTType())); + S.addTypeRef(index.LoweredType.getRawASTType())); ListOfValues.push_back((unsigned)index.LoweredType.getCategory()); ListOfValues.push_back(S.addConformanceRef(index.Hashable)); } @@ -903,12 +903,12 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { Args.push_back(addValueRef(OpVal)); SILType OpType = OpVal->getType(); assert(OpType.isObject()); - Args.push_back(S.addTypeRef(OpType.getASTType())); + Args.push_back(S.addTypeRef(OpType.getRawASTType())); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef( - OI->getType().getASTType()), + OI->getType().getRawASTType()), (unsigned)OI->getType().getCategory(), Args); break; @@ -990,7 +990,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILValueCategory operandCategory = SILValueCategory::Object; ValueID operandID = 0; if (operand) { - operandType = S.addTypeRef(operand->getType().getASTType()); + operandType = S.addTypeRef(operand->getType().getRawASTType()); operandCategory = operand->getType().getCategory(); operandID = addValueRef(operand); } @@ -1001,7 +1001,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILInitExistentialLayout::Code]; SILInitExistentialLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), - S.addTypeRef(Ty.getASTType()), + S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), operandType, (unsigned)operandCategory, @@ -1065,18 +1065,18 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { for (unsigned Idx = 0; Idx < NumOpsToWrite; ++Idx) { if (Idx < NumTailAllocs) { assert(TailTypes[Idx].isObject()); - Args.push_back(S.addTypeRef(TailTypes[Idx].getASTType())); + Args.push_back(S.addTypeRef(TailTypes[Idx].getRawASTType())); } SILValue OpVal = AllOps[Idx].get(); Args.push_back(addValueRef(OpVal)); SILType OpType = OpVal->getType(); assert(OpType.isObject()); - Args.push_back(S.addTypeRef(OpType.getASTType())); + Args.push_back(S.addTypeRef(OpType.getRawASTType())); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef( - ARI->getType().getASTType()), + ARI->getType().getRawASTType()), (unsigned)ARI->getType().getCategory(), Args); break; @@ -1107,7 +1107,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { auto boxOperand = PBI->getOperand(); auto boxRef = addValueRef(boxOperand); auto boxType = boxOperand->getType(); - auto boxTypeRef = S.addTypeRef(boxType.getASTType()); + auto boxTypeRef = S.addTypeRef(boxType.getRawASTType()); SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], @@ -1134,14 +1134,14 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SmallVector Args; for (auto Arg : BI->getArguments()) { Args.push_back(addValueRef(Arg)); - Args.push_back(S.addTypeRef(Arg->getType().getASTType())); + Args.push_back(S.addTypeRef(Arg->getType().getRawASTType())); Args.push_back((unsigned)Arg->getType().getCategory()); } SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_BUILTIN, 0, S.addSubstitutionMapRef(BI->getSubstitutions()), - S.addTypeRef(BI->getType().getASTType()), + S.addTypeRef(BI->getType().getRawASTType()), (unsigned)BI->getType().getCategory(), S.addDeclBaseNameRef(BI->getName()), Args); @@ -1163,7 +1163,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SIL_APPLY, unsigned(AI->getApplyOptions().toRaw()), S.addSubstitutionMapRef(AI->getSubstitutionMap()), - S.addTypeRef(AI->getCallee()->getType().getASTType()), + S.addTypeRef(AI->getCallee()->getType().getRawASTType()), S.addTypeRef(AI->getSubstCalleeType()), addValueRef(AI->getCallee()), Args); @@ -1184,7 +1184,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILAbbrCodes[SILInstApplyLayout::Code], SIL_BEGIN_APPLY, unsigned(AI->getApplyOptions().toRaw()), S.addSubstitutionMapRef(AI->getSubstitutionMap()), - S.addTypeRef(AI->getCallee()->getType().getASTType()), + S.addTypeRef(AI->getCallee()->getType().getRawASTType()), S.addTypeRef(AI->getSubstCalleeType()), addValueRef(AI->getCallee()), Args); @@ -1208,7 +1208,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILAbbrCodes[SILInstApplyLayout::Code], SIL_TRY_APPLY, unsigned(AI->getApplyOptions().toRaw()), S.addSubstitutionMapRef(AI->getSubstitutionMap()), - S.addTypeRef(AI->getCallee()->getType().getASTType()), + S.addTypeRef(AI->getCallee()->getType().getRawASTType()), S.addTypeRef(AI->getSubstCalleeType()), addValueRef(AI->getCallee()), Args); @@ -1224,8 +1224,8 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILAbbrCodes[SILInstApplyLayout::Code], SIL_PARTIAL_APPLY, 0, S.addSubstitutionMapRef(PAI->getSubstitutionMap()), - S.addTypeRef(PAI->getCallee()->getType().getASTType()), - S.addTypeRef(PAI->getType().getASTType()), + S.addTypeRef(PAI->getCallee()->getType().getRawASTType()), + S.addTypeRef(PAI->getType().getRawASTType()), addValueRef(PAI->getCallee()), Args); break; @@ -1250,7 +1250,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), 0, - S.addTypeRef(GI->getType().getASTType()), + S.addTypeRef(GI->getType().getRawASTType()), (unsigned)GI->getType().getCategory(), S.addUniquedStringRef(G->getName())); break; @@ -1267,7 +1267,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const BranchInst *BrI = cast(&SI); SmallVector ListOfValues; for (auto Elt : BrI->getArgs()) { - ListOfValues.push_back(S.addTypeRef(Elt->getType().getASTType())); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } @@ -1291,12 +1291,12 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { ListOfValues.push_back(BasicBlockMap[CBI->getFalseBB()]); ListOfValues.push_back(CBI->getTrueArgs().size()); for (auto Elt : CBI->getTrueArgs()) { - ListOfValues.push_back(S.addTypeRef(Elt->getType().getASTType())); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } for (auto Elt : CBI->getFalseArgs()) { - ListOfValues.push_back(S.addTypeRef(Elt->getType().getASTType())); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } @@ -1304,7 +1304,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CBI->getCondition()->getType().getASTType()), + S.addTypeRef(CBI->getCondition()->getType().getRawASTType()), (unsigned)CBI->getCondition()->getType().getCategory(), ListOfValues); break; @@ -1324,7 +1324,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(AACI->getOperand()->getType().getASTType()), + S.addTypeRef(AACI->getOperand()->getType().getRawASTType()), (unsigned)AACI->getOperand()->getType().getCategory(), ListOfValues); break; @@ -1360,13 +1360,13 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { Out, ScratchRecord, SILAbbrCodes[SILOneTypeOwnershipValuesLayout::Code], (unsigned)SI.getKind(), ownershipField, - S.addTypeRef(SOI.getOperand()->getType().getASTType()), + S.addTypeRef(SOI.getOperand()->getType().getRawASTType()), (unsigned)SOI.getOperand()->getType().getCategory(), ListOfValues); } else { SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(SOI.getOperand()->getType().getASTType()), + S.addTypeRef(SOI.getOperand()->getType().getRawASTType()), (unsigned)SOI.getOperand()->getType().getCategory(), ListOfValues); } break; @@ -1381,7 +1381,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const SelectEnumInstBase *SOI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SOI->getEnumOperand())); - ListOfValues.push_back(S.addTypeRef(SOI->getType().getASTType())); + ListOfValues.push_back(S.addTypeRef(SOI->getType().getRawASTType())); ListOfValues.push_back((unsigned)SOI->getType().getCategory()); ListOfValues.push_back((unsigned)SOI->hasDefault()); if (SOI->hasDefault()) { @@ -1399,7 +1399,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(SOI->getEnumOperand()->getType().getASTType()), + S.addTypeRef(SOI->getEnumOperand()->getType().getRawASTType()), (unsigned)SOI->getEnumOperand()->getType().getCategory(), ListOfValues); break; @@ -1428,7 +1428,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(SII->getOperand()->getType().getASTType()), + S.addTypeRef(SII->getOperand()->getType().getRawASTType()), (unsigned)SII->getOperand()->getType().getCategory(), ListOfValues); break; @@ -1442,7 +1442,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const SelectValueInst *SVI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SVI->getOperand())); - ListOfValues.push_back(S.addTypeRef(SVI->getType().getASTType())); + ListOfValues.push_back(S.addTypeRef(SVI->getType().getRawASTType())); ListOfValues.push_back((unsigned)SVI->getType().getCategory()); ListOfValues.push_back((unsigned)SVI->hasDefault()); if (SVI->hasDefault()) { @@ -1460,7 +1460,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(SVI->getOperand()->getType().getASTType()), + S.addTypeRef(SVI->getOperand()->getType().getRawASTType()), (unsigned)SVI->getOperand()->getType().getCategory(), ListOfValues); break; @@ -1581,7 +1581,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { auto YI = cast(&SI); SmallVector args; for (auto arg: YI->getYieldedValues()) { - args.push_back(S.addTypeRef(arg->getType().getASTType())); + args.push_back(S.addTypeRef(arg->getType().getRawASTType())); args.push_back((unsigned)arg->getType().getCategory()); args.push_back(addValueRef(arg)); } @@ -1600,7 +1600,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, - S.addTypeRef(FRI->getType().getASTType()), + S.addTypeRef(FRI->getType().getRawASTType()), (unsigned)FRI->getType().getCategory(), addSILFunctionRef(ReferencedFunction)); @@ -1614,7 +1614,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, - S.addTypeRef(FRI->getType().getASTType()), + S.addTypeRef(FRI->getType().getRawASTType()), (unsigned)FRI->getType().getCategory(), addSILFunctionRef(ReferencedFunction)); @@ -1628,7 +1628,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, - S.addTypeRef(FRI->getType().getASTType()), + S.addTypeRef(FRI->getType().getRawASTType()), (unsigned)FRI->getType().getCategory(), addSILFunctionRef(ReferencedFunction)); @@ -1666,10 +1666,10 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), Attr, - S.addTypeRef(operand->getType().getASTType()), + S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand), - S.addTypeRef(operand2->getType().getASTType()), + S.addTypeRef(operand2->getType().getRawASTType()), (unsigned)operand2->getType().getCategory(), addValueRef(operand2)); break; @@ -1677,10 +1677,10 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { case SILInstructionKind::PackElementGetInst: { auto PEGI = cast(&SI); auto elementType = PEGI->getElementType(); - auto elementTypeRef = S.addTypeRef(elementType.getASTType()); + auto elementTypeRef = S.addTypeRef(elementType.getRawASTType()); auto pack = PEGI->getPack(); auto packType = pack->getType(); - auto packTypeRef = S.addTypeRef(packType.getASTType()); + auto packTypeRef = S.addTypeRef(packType.getRawASTType()); auto packRef = addValueRef(pack); auto indexRef = addValueRef(PEGI->getIndex()); SILPackElementGetLayout::emitRecord(Out, ScratchRecord, @@ -1698,11 +1698,11 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { auto PESI = cast(&SI); auto value = PESI->getValue(); auto valueType = value->getType(); - auto valueTypeRef = S.addTypeRef(valueType.getASTType()); + auto valueTypeRef = S.addTypeRef(valueType.getRawASTType()); auto valueRef = addValueRef(value); auto pack = PESI->getPack(); auto packType = pack->getType(); - auto packTypeRef = S.addTypeRef(packType.getASTType()); + auto packTypeRef = S.addTypeRef(packType.getRawASTType()); auto packRef = addValueRef(pack); auto indexRef = addValueRef(PESI->getIndex()); SILPackElementSetLayout::emitRecord(Out, ScratchRecord, @@ -1719,10 +1719,10 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { case SILInstructionKind::TuplePackElementAddrInst: { auto TPEAI = cast(&SI); auto elementType = TPEAI->getElementType(); - auto elementTypeRef = S.addTypeRef(elementType.getASTType()); + auto elementTypeRef = S.addTypeRef(elementType.getRawASTType()); auto tuple = TPEAI->getTuple(); auto tupleType = tuple->getType(); - auto tupleTypeRef = S.addTypeRef(tupleType.getASTType()); + auto tupleTypeRef = S.addTypeRef(tupleType.getRawASTType()); auto tupleRef = addValueRef(tuple); auto indexRef = addValueRef(TPEAI->getIndex()); SILPackElementGetLayout::emitRecord(Out, ScratchRecord, @@ -1741,11 +1741,11 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILTailAddrLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTailAddrLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(TAI->getBase()->getType().getASTType()), + S.addTypeRef(TAI->getBase()->getType().getRawASTType()), addValueRef(TAI->getBase()), - S.addTypeRef(TAI->getIndex()->getType().getASTType()), + S.addTypeRef(TAI->getIndex()->getType().getRawASTType()), addValueRef(TAI->getIndex()), - S.addTypeRef(TAI->getTailType().getASTType())); + S.addTypeRef(TAI->getTailType().getRawASTType())); break; } case SILInstructionKind::CondFailInst: { @@ -1754,7 +1754,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), /*attributes*/ 0, - S.addTypeRef(operand->getType().getASTType()), + S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand), 0, 0, S.addUniquedStringRef(CFI->getMessage())); @@ -1804,7 +1804,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, - S.addTypeRef(Ty.getASTType()), (unsigned)Ty.getCategory(), + S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), S.addUniquedStringRef(Str.str())); break; } @@ -1814,7 +1814,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const MarkFunctionEscapeInst *MFE = cast(&SI); SmallVector ListOfValues; for (auto Elt : MFE->getElements()) { - ListOfValues.push_back(S.addTypeRef(Elt->getType().getASTType())); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } @@ -1834,7 +1834,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, - S.addTypeRef(PI->getType().getASTType()), + S.addTypeRef(PI->getType().getRawASTType()), (unsigned)PI->getType().getCategory(), S.addDeclRef(PI->getProtocol())); break; @@ -1877,7 +1877,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { auto operand = opei.getIndexOperand(); auto operandRef = addValueRef(operand); auto operandType = operand->getType(); - auto operandTypeRef = S.addTypeRef(operandType.getASTType()); + auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); SILOpenPackElementLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOpenPackElementLayout::Code], @@ -1961,10 +1961,10 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), /*attr*/ 0, - S.addTypeRef(RI->getConverted()->getType().getASTType()), + S.addTypeRef(RI->getConverted()->getType().getRawASTType()), (unsigned)RI->getConverted()->getType().getCategory(), addValueRef(RI->getConverted()), - S.addTypeRef(RI->getBitsOperand()->getType().getASTType()), + S.addTypeRef(RI->getBitsOperand()->getType().getRawASTType()), (unsigned)RI->getBitsOperand()->getType().getCategory(), addValueRef(RI->getBitsOperand())); break; @@ -1974,14 +1974,14 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { auto CI = cast(&SI); ValueID listOfValues[] = { addValueRef(CI->getOperand()), - S.addTypeRef(CI->getSourceLoweredType().getASTType()), + S.addTypeRef(CI->getSourceLoweredType().getRawASTType()), (unsigned)CI->getSourceLoweredType().getCategory(), S.addTypeRef(CI->getTargetFormalType()) }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CI->getTargetLoweredType().getASTType()), + S.addTypeRef(CI->getTargetLoweredType().getRawASTType()), (unsigned)CI->getTargetLoweredType().getCategory(), llvm::makeArrayRef(listOfValues)); break; @@ -1991,14 +1991,14 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { ValueID listOfValues[] = { S.addTypeRef(CI->getSourceFormalType()), addValueRef(CI->getSrc()), - S.addTypeRef(CI->getSourceLoweredType().getASTType()), + S.addTypeRef(CI->getSourceLoweredType().getRawASTType()), (unsigned)CI->getSourceLoweredType().getCategory(), S.addTypeRef(CI->getTargetFormalType()), addValueRef(CI->getDest()) }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CI->getTargetLoweredType().getASTType()), + S.addTypeRef(CI->getTargetLoweredType().getRawASTType()), (unsigned)CI->getTargetLoweredType().getCategory(), llvm::makeArrayRef(listOfValues)); break; @@ -2008,14 +2008,14 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { ValueID listOfValues[] = { S.addTypeRef(CI->getSourceFormalType()), addValueRef(CI->getSrc()), - S.addTypeRef(CI->getSourceLoweredType().getASTType()), + S.addTypeRef(CI->getSourceLoweredType().getRawASTType()), (unsigned)CI->getSourceLoweredType().getCategory(), S.addTypeRef(CI->getTargetFormalType()), addValueRef(CI->getDest()) }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CI->getTargetLoweredType().getASTType()), + S.addTypeRef(CI->getTargetLoweredType().getRawASTType()), (unsigned)CI->getTargetLoweredType().getCategory(), llvm::makeArrayRef(listOfValues)); break; @@ -2032,12 +2032,46 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneOperandExtraAttributeLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), attr, - S.addTypeRef(operand->getType().getASTType()), + S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } + case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: { + unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; + auto *BAI = cast(&SI); + SILValue operand = BAI->getOperand(); + + SILOneOperandLayout::emitRecord( + Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, + S.addTypeRef(operand->getType().getRawASTType()), + (unsigned)operand->getType().getCategory(), addValueRef(operand)); + break; + } + case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: { + unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; + auto *BAI = cast(&SI); + SILValue operand = BAI->getOperand(); + + SILOneOperandLayout::emitRecord( + Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, + S.addTypeRef(operand->getType().getRawASTType()), + (unsigned)operand->getType().getCategory(), addValueRef(operand)); + break; + } + case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: { + unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; + auto *BAI = cast(&SI); + SILValue operand = BAI->getOperand(); + + SILOneOperandLayout::emitRecord( + Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, + S.addTypeRef(operand->getType().getRawASTType()), + (unsigned)operand->getType().getCategory(), addValueRef(operand)); + break; + } + case SILInstructionKind::EndAccessInst: { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; auto *EAI = cast(&SI); @@ -2046,7 +2080,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), attr, - S.addTypeRef(operand->getType().getASTType()), + S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; @@ -2064,10 +2098,10 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILTwoOperandsExtraAttributeLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), attr, - S.addTypeRef(source->getType().getASTType()), + S.addTypeRef(source->getType().getRawASTType()), (unsigned)source->getType().getCategory(), addValueRef(source), - S.addTypeRef(buffer->getType().getASTType()), + S.addTypeRef(buffer->getType().getRawASTType()), (unsigned)buffer->getType().getCategory(), addValueRef(buffer)); break; @@ -2083,7 +2117,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneOperandExtraAttributeLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), attr, - S.addTypeRef(operand->getType().getASTType()), + S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; @@ -2138,7 +2172,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILOneValueOneOperandLayout::Code]; SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), Attr, addValueRef(value), - S.addTypeRef(operand->getType().getASTType()), + S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; @@ -2152,11 +2186,11 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILType boundType = BI->getBoundType(); SmallVector ListOfValues; ListOfValues.push_back(S.addTypeRef( - baseOperand->getType().getASTType())); + baseOperand->getType().getRawASTType())); ListOfValues.push_back((unsigned)baseOperand->getType().getCategory()); ListOfValues.push_back(addValueRef(baseOperand)); ListOfValues.push_back(S.addTypeRef( - indexOperand->getType().getASTType())); + indexOperand->getType().getRawASTType())); ListOfValues.push_back((unsigned)indexOperand->getType().getCategory()); ListOfValues.push_back(addValueRef(indexOperand)); @@ -2165,7 +2199,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(boundType.getASTType()), + S.addTypeRef(boundType.getRawASTType()), (unsigned)boundType.getCategory(), ListOfValues); break; @@ -2177,10 +2211,10 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), /*attr*/0, - S.addTypeRef(baseOperand->getType().getASTType()), + S.addTypeRef(baseOperand->getType().getRawASTType()), (unsigned)baseOperand->getType().getCategory(), addValueRef(baseOperand), - S.addTypeRef(inToken->getType().getASTType()), + S.addTypeRef(inToken->getType().getRawASTType()), (unsigned)inToken->getType().getCategory(), addValueRef(inToken)); break; @@ -2232,7 +2266,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneValueOneOperandLayout::Code], (unsigned)SI.getKind(), attr, S.addDeclRef(tDecl), - S.addTypeRef(operand->getType().getASTType()), + S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; @@ -2250,7 +2284,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const StructInst *StrI = cast(&SI); SmallVector ListOfValues; for (auto Elt : StrI->getElements()) { - ListOfValues.push_back(S.addTypeRef(Elt->getType().getASTType())); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } @@ -2258,7 +2292,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(StrI->getType().getASTType()), + S.addTypeRef(StrI->getType().getRawASTType()), (unsigned)StrI->getType().getCategory(), ListOfValues); break; } @@ -2283,7 +2317,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILAbbrCodes[SILOneTypeOneOperandLayout::Code], (unsigned)SI.getKind(), 0, FieldNo, 0, - S.addTypeRef(operand->getType().getASTType()), + S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; @@ -2300,7 +2334,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code]; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), - S.addTypeRef(TI->getType().getASTType()), + S.addTypeRef(TI->getType().getRawASTType()), (unsigned)TI->getType().getCategory(), ListOfValues); break; @@ -2310,13 +2344,13 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { // (DeclID + hasOperand), and an operand. const EnumInst *UI = cast(&SI); TypeID OperandTy = UI->hasOperand() ? - S.addTypeRef(UI->getOperand()->getType().getASTType()) : TypeID(); + S.addTypeRef(UI->getOperand()->getType().getRawASTType()) : TypeID(); unsigned OperandTyCategory = UI->hasOperand() ? (unsigned)UI->getOperand()->getType().getCategory() : 0; SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), UI->hasOperand(), - S.addTypeRef(UI->getType().getASTType()), + S.addTypeRef(UI->getType().getRawASTType()), (unsigned)UI->getType().getCategory(), S.addDeclRef(UI->getElement()), OperandTy, OperandTyCategory, @@ -2343,7 +2377,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILInstWitnessMethodLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstWitnessMethodLayout::Code], S.addTypeRef(Ty), 0, 0, - S.addTypeRef(Ty2.getASTType()), (unsigned)Ty2.getCategory(), + S.addTypeRef(Ty2.getRawASTType()), (unsigned)Ty2.getCategory(), OperandTy, OperandTyCategory, OperandValueId, ConformanceId, ListOfValues); break; @@ -2359,7 +2393,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(Ty.getASTType()), + S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), ListOfValues); break; } @@ -2374,7 +2408,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(Ty.getASTType()), + S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), ListOfValues); break; } @@ -2389,7 +2423,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(Ty.getASTType()), + S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), ListOfValues); break; } @@ -2404,7 +2438,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(Ty.getASTType()), + S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), ListOfValues); break; } @@ -2420,7 +2454,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(DMB->getOperand()->getType().getASTType()), + S.addTypeRef(DMB->getOperand()->getType().getRawASTType()), (unsigned)DMB->getOperand()->getType().getCategory(), ListOfValues); break; } @@ -2429,7 +2463,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { ValueID listOfValues[] = { CBI->isExact(), addValueRef(CBI->getOperand()), - S.addTypeRef(CBI->getSourceLoweredType().getASTType()), + S.addTypeRef(CBI->getSourceLoweredType().getRawASTType()), (unsigned)CBI->getSourceLoweredType().getCategory(), S.addTypeRef(CBI->getTargetFormalType()), BasicBlockMap[CBI->getSuccessBB()], @@ -2440,7 +2474,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeOwnershipValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeOwnershipValuesLayout::Code], (unsigned)SI.getKind(), ownershipField, - S.addTypeRef(CBI->getTargetLoweredType().getASTType()), + S.addTypeRef(CBI->getTargetLoweredType().getRawASTType()), (unsigned)CBI->getTargetLoweredType().getCategory(), llvm::makeArrayRef(listOfValues)); break; @@ -2451,7 +2485,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { toStableCastConsumptionKind(CBI->getConsumptionKind()), S.addTypeRef(CBI->getSourceFormalType()), addValueRef(CBI->getSrc()), - S.addTypeRef(CBI->getSourceLoweredType().getASTType()), + S.addTypeRef(CBI->getSourceLoweredType().getRawASTType()), (unsigned)CBI->getSourceLoweredType().getCategory(), S.addTypeRef(CBI->getTargetFormalType()), addValueRef(CBI->getDest()), @@ -2460,7 +2494,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CBI->getTargetLoweredType().getASTType()), + S.addTypeRef(CBI->getTargetLoweredType().getRawASTType()), (unsigned)CBI->getTargetLoweredType().getCategory(), llvm::makeArrayRef(listOfValues)); break; @@ -2470,18 +2504,18 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SmallVector ListOfValues; ListOfValues.push_back(addValueRef(IBSHI->getBlockStorage())); ListOfValues.push_back( - S.addTypeRef(IBSHI->getBlockStorage()->getType().getASTType())); + S.addTypeRef(IBSHI->getBlockStorage()->getType().getRawASTType())); // Always an address, don't need to save category ListOfValues.push_back(addValueRef(IBSHI->getInvokeFunction())); ListOfValues.push_back( - S.addTypeRef(IBSHI->getInvokeFunction()->getType().getASTType())); + S.addTypeRef(IBSHI->getInvokeFunction()->getType().getRawASTType())); // Always a value, don't need to save category ListOfValues.push_back(S.addSubstitutionMapRef(IBSHI->getSubstitutions())); SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(IBSHI->getType().getASTType()), + S.addTypeRef(IBSHI->getType().getRawASTType()), (unsigned)IBSHI->getType().getCategory(), ListOfValues); @@ -2518,13 +2552,13 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { for (auto &operand : KPI->getPatternOperands()) { auto value = operand.get(); ListOfValues.push_back(addValueRef(value)); - ListOfValues.push_back(S.addTypeRef(value->getType().getASTType())); + ListOfValues.push_back(S.addTypeRef(value->getType().getRawASTType())); ListOfValues.push_back((unsigned)value->getType().getCategory()); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(KPI->getType().getASTType()), + S.addTypeRef(KPI->getType().getRawASTType()), (unsigned)KPI->getType().getCategory(), ListOfValues); @@ -2541,7 +2575,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { trailingInfo.push_back(i); for (auto &op : dfi->getAllOperands()) { auto val = op.get(); - trailingInfo.push_back(S.addTypeRef(val->getType().getASTType())); + trailingInfo.push_back(S.addTypeRef(val->getType().getRawASTType())); trailingInfo.push_back((unsigned)val->getType().getCategory()); trailingInfo.push_back(addValueRef(val)); } @@ -2561,7 +2595,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { trailingInfo.push_back(idx); for (auto &op : lfi->getAllOperands()) { auto val = op.get(); - trailingInfo.push_back(S.addTypeRef(val->getType().getASTType())); + trailingInfo.push_back(S.addTypeRef(val->getType().getRawASTType())); trailingInfo.push_back((unsigned)val->getType().getCategory()); trailingInfo.push_back(addValueRef(val)); } @@ -2575,9 +2609,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { auto *dfei = cast(&SI); auto operandRef = addValueRef(dfei->getOperand()); auto operandType = dfei->getOperand()->getType(); - auto operandTypeRef = S.addTypeRef(operandType.getASTType()); + auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto rawExtractee = (unsigned)dfei->getExtractee(); - auto extracteeTypeRef = S.addTypeRef(dfei->getType().getASTType()); + auto extracteeTypeRef = S.addTypeRef(dfei->getType().getRawASTType()); SILInstDifferentiableFunctionExtractLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstDifferentiableFunctionExtractLayout::Code], @@ -2590,7 +2624,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { auto *lfei = cast(&SI); auto operandRef = addValueRef(lfei->getOperand()); auto operandType = lfei->getOperand()->getType(); - auto operandTypeRef = S.addTypeRef(operandType.getASTType()); + auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto rawExtractee = (unsigned)lfei->getExtractee(); SILInstLinearFunctionExtractLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstLinearFunctionExtractLayout::Code], @@ -2612,7 +2646,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneOperandLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)dwfi->getKind(), rawWitnessKind, - hasExplicitFnTy ? S.addTypeRef(dwfi->getType().getASTType()) : TypeID(), + hasExplicitFnTy ? S.addTypeRef(dwfi->getType().getRawASTType()) : TypeID(), hasExplicitFnTy ? (unsigned)dwfi->getType().getCategory() : 0, S.addUniquedStringRef(mangledKey)); break; @@ -2738,7 +2772,7 @@ void SILSerializer::writeIndexTables() { void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { GlobalVarList[g.getName()] = NextGlobalVarID++; GlobalVarOffset.push_back(Out.GetCurrentBitNo()); - TypeID TyID = S.addTypeRef(g.getLoweredType().getASTType()); + TypeID TyID = S.addTypeRef(g.getLoweredType().getRawASTType()); DeclID dID = S.addDeclRef(g.getDecl()); SILGlobalVarLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILGlobalVarLayout::Code], diff --git a/test/Distributed/distributed_actor_ban_owned_shared.swift b/test/Distributed/distributed_actor_ban_owned_shared.swift index 44f5b3bff42f3..64b0a480753ee 100644 --- a/test/Distributed/distributed_actor_ban_owned_shared.swift +++ b/test/Distributed/distributed_actor_ban_owned_shared.swift @@ -15,8 +15,7 @@ distributed actor First { distributed func owned(_: __owned Param) async throws {} // expected-error{{cannot declare '__owned' argument '_' in distributed instance method 'owned'}} distributed func shared(_: __shared Param) async throws {} // expected-error{{cannot declare '__shared' argument '_' in distributed instance method 'shared'}} distributed func consuming(_: consuming Param) async throws {} - // expected-error@-1{{copyable types cannot be 'consuming' or 'borrowing' yet}} - // expected-error@-2{{parameter '' of type '<>' in distributed instance method does not conform to serialization requirement 'Codable'}} + // expected-error @-1 {{cannot declare 'consuming' argument '_' in distributed instance method 'consuming'}} } func test(first: First) async throws { diff --git a/test/Interpreter/noimplicitcopy_parameters.swift b/test/Interpreter/noimplicitcopy_parameters.swift new file mode 100644 index 0000000000000..5118446fd966a --- /dev/null +++ b/test/Interpreter/noimplicitcopy_parameters.swift @@ -0,0 +1,41 @@ +// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all) | %FileCheck %s +// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all) | %FileCheck %s + +// REQUIRES: executable_test + +class Klass { + var name: String + + init(_ x: String) { + name = x + } + + func doSomething() { + print("Doing something \(name)") + } +} + +func simpleTest(_ x: consuming Klass) { + // CHECK: Doing something MyName + x.doSomething() + let f: () -> () = { + x.doSomething() + } + // CHECK: Doing something MyName + f() + x = Klass("MyOtherName") + // CHECK: Doing something MyOtherName + f() + var f2: () -> () = {} + f2 = { + x.doSomething() + } + // CHECK: Doing something MyOtherName + f2() +} + +func main() { + simpleTest(Klass("MyName")) +} + +main() diff --git a/test/Parse/ownership_modifiers.swift b/test/Parse/ownership_modifiers.swift index 2ee7a07712c5a..da77360d873ff 100644 --- a/test/Parse/ownership_modifiers.swift +++ b/test/Parse/ownership_modifiers.swift @@ -3,7 +3,7 @@ struct borrowing {} struct consuming {} -struct Foo: ~Copyable {} +struct Foo {} func foo(x: borrowing Foo) {} func bar(x: consuming Foo) {} @@ -18,13 +18,13 @@ func worst(x: (borrowing consuming Foo) -> ()) {} // expected-error{{at most one func zim(x: borrowing) {} func zang(x: consuming) {} -func zung(x: borrowing consuming) {} // expected-error{{copyable types cannot be 'consuming' or 'borrowing' yet}} -func zip(x: consuming borrowing) {} // expected-error{{copyable types cannot be 'consuming' or 'borrowing' yet}} +func zung(x: borrowing consuming) {} +func zip(x: consuming borrowing) {} func zap(x: (borrowing, consuming) -> ()) {} -func zoop(x: (borrowing consuming, consuming borrowing) -> ()) {} // expected-error 2{{copyable types cannot be 'consuming' or 'borrowing' yet}} +func zoop(x: (borrowing consuming, consuming borrowing) -> ()) {} -func worster(x: borrowing borrowing borrowing) {} // expected-error{{at most one}} // expected-error{{copyable types cannot be 'consuming' or 'borrowing' yet}} -func worstest(x: (borrowing borrowing borrowing) -> ()) {} // expected-error{{at most one}} // expected-error{{copyable types cannot be 'consuming' or 'borrowing' yet}} +func worster(x: borrowing borrowing borrowing) {} // expected-error{{at most one}} +func worstest(x: (borrowing borrowing borrowing) -> ()) {} // expected-error{{at most one}} // Parameter specifier names are regular identifiers in other positions, // including argument labels. @@ -47,7 +47,7 @@ func argumentLabel(anonConsumingInClosure: (_ consuming: Int) -> ()) {} func argumentLabel(anonSharedInClosure: (_ __shared: Int) -> ()) {} func argumentLabel(anonOwnedInClosure: (_ __owned: Int) -> ()) {} -struct MethodModifiers: ~Copyable { +struct MethodModifiers { mutating func mutating() {} borrowing func borrowing() {} consuming func consuming() {} @@ -60,16 +60,15 @@ struct MethodModifiers: ~Copyable { borrowing mutating consuming func tooManyD() {} // expected-error 2 {{method must not be declared both }} } - -func chalk(_ a: consuming String, // expected-error{{copyable types cannot be 'consuming' or 'borrowing' yet}} - _ b: borrowing [Int], // expected-error{{copyable types cannot be 'consuming' or 'borrowing' yet}} +func chalk(_ a: consuming String, + _ b: borrowing [Int], _ c: __shared [String], _ d: __owned Int?) {} struct Stepping { - consuming func perform() {} // expected-error {{'consuming' is not yet valid on instance methods of a copyable type}} - borrowing func doIt() {} // expected-error {{'borrowing' is not yet valid on instance methods of a copyable type}} + consuming func perform() {} + borrowing func doIt() {} mutating func change() {} var ex: Int { __consuming get { 0 } @@ -77,16 +76,16 @@ struct Stepping { } class Clapping { - consuming func perform() {} // expected-error {{'consuming' is not yet valid on instance methods of a copyable type}} - borrowing func doIt() {} // expected-error {{'borrowing' is not yet valid on instance methods of a copyable type}} + consuming func perform() {} + borrowing func doIt() {} var ex: Int { __consuming get { 0 } } } protocol Popping { - consuming func perform() // expected-error {{'consuming' is not yet valid on instance methods of a copyable type}} - borrowing func doIt() // expected-error {{'borrowing' is not yet valid on instance methods of a copyable type}} + consuming func perform() + borrowing func doIt() mutating func change() var ex: Int { __consuming get @@ -94,8 +93,8 @@ protocol Popping { } enum Exercising { - consuming func perform() {} // expected-error {{'consuming' is not yet valid on instance methods of a copyable type}} - borrowing func doIt() {} // expected-error {{'borrowing' is not yet valid on instance methods of a copyable type}} + consuming func perform() {} + borrowing func doIt() {} mutating func change() {} var ex: Int { __consuming get { 0 } @@ -103,7 +102,8 @@ enum Exercising { } func consumingClosure1(_ f: consuming () -> ()) { } // expected-error {{'consuming' cannot be applied to nonescaping closure}} -func consumingClosure2(_ f: consuming @escaping () -> ()) { } // expected-error {{copyable types cannot be 'consuming' or 'borrowing' yet}} +func consumingClosure2(_ f: consuming @escaping () -> ()) { } + +func borrowingClosure1(_ f: borrowing () -> ()) { } +func borrowingClosure2(_ f: borrowing @escaping () -> ()) { } -func borrowingClosure1(_ f: borrowing () -> ()) { } // expected-error {{copyable types cannot be 'consuming' or 'borrowing' yet}} -func borrowingClosure2(_ f: borrowing @escaping () -> ()) { } // expected-error {{copyable types cannot be 'consuming' or 'borrowing' yet}} diff --git a/test/Parse/ownership_modifiers_no_errors.swift b/test/Parse/ownership_modifiers_no_errors.swift index 6f9815e0c741c..f7bb3187a30ac 100644 --- a/test/Parse/ownership_modifiers_no_errors.swift +++ b/test/Parse/ownership_modifiers_no_errors.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -enable-experimental-feature NoImplicitCopy +// RUN: %target-typecheck-verify-swift // This is a variation of `ownership_modifiers.swift` with the expected error // lines removed, so that the file is parsed by the SwiftSyntax parser diff --git a/test/SIL/Parser/basic2.sil b/test/SIL/Parser/basic2.sil index 3c599b9afc6a2..023008dbb12df 100644 --- a/test/SIL/Parser/basic2.sil +++ b/test/SIL/Parser/basic2.sil @@ -140,4 +140,54 @@ bb0: dealloc_box %0 : ${ var Builtin.NativeObject } %9999 = tuple() return %9999 : $() -} \ No newline at end of file +} + +// CHECK-LABEL: sil [ossa] @test_copyable_to_moveonlywrapper : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK: copyable_to_moveonlywrapper +// CHECK: } // end sil function 'test_copyable_to_moveonlywrapper' +sil [ossa] @test_copyable_to_moveonlywrapper : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%0 : @owned $Builtin.NativeObject): + %0a = copyable_to_moveonlywrapper [owned] %0 : $Builtin.NativeObject + destroy_value %0a : $@moveOnly Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @test_moveonlywrapper_to_copyable_addr : $@convention(thin) (@in Builtin.NativeObject) -> () { +// CHECK: moveonlywrapper_to_copyable_addr +// CHECK: } // end sil function 'test_moveonlywrapper_to_copyable_addr' +sil [ossa] @test_moveonlywrapper_to_copyable_addr : $@convention(thin) (@in Builtin.NativeObject) -> () { +bb0(%0 : $*Builtin.NativeObject): + %1 = alloc_stack $@moveOnly Builtin.NativeObject + %1a = moveonlywrapper_to_copyable_addr %1 : $*@moveOnly Builtin.NativeObject + copy_addr [take] %0 to [init] %1a : $*Builtin.NativeObject + destroy_addr %1 : $*@moveOnly Builtin.NativeObject + dealloc_stack %1 : $*@moveOnly Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @test_copyable_to_moveonlywrapper_addr : $@convention(thin) (@in Builtin.NativeObject) -> () { +// CHECK: copyable_to_moveonlywrapper_addr +// CHECK: } // end sil function 'test_copyable_to_moveonlywrapper_addr' +sil [ossa] @test_copyable_to_moveonlywrapper_addr : $@convention(thin) (@in Builtin.NativeObject) -> () { +bb0(%0 : $*Builtin.NativeObject): + %0a = copyable_to_moveonlywrapper_addr %0 : $*Builtin.NativeObject + destroy_addr %0a : $*@moveOnly Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @test_moveonlywrapper_to_copyable_box : $@convention(thin) () -> () { +// CHECK: [[BOX:%.*]] = alloc_box ${ var @moveOnly Builtin.NativeObject } +// CHECK: [[CAST:%.*]] = moveonlywrapper_to_copyable_box [[BOX]] : ${ var @moveOnly Builtin.NativeObject } +// CHECK: dealloc_box [[CAST]] : ${ var Builtin.NativeObject } +// CHECK: } // end sil function 'test_moveonlywrapper_to_copyable_box' +sil [ossa] @test_moveonlywrapper_to_copyable_box : $@convention(thin) () -> () { +bb0: + %0 = alloc_box ${ var @moveOnly Builtin.NativeObject } + %1 = moveonlywrapper_to_copyable_box %0 : ${ var @moveOnly Builtin.NativeObject } + dealloc_box %1 : ${ var Builtin.NativeObject } + %9999 = tuple () + return %9999 : $() +} diff --git a/test/SIL/Parser/moveonlywrapped_diagnostics.sil b/test/SIL/Parser/moveonlywrapped_diagnostics.sil new file mode 100644 index 0000000000000..86dec1488efda --- /dev/null +++ b/test/SIL/Parser/moveonlywrapped_diagnostics.sil @@ -0,0 +1,79 @@ +// RUN: %target-sil-opt -verify %s + +sil_stage raw + +import Builtin + +class Klass {} + +struct S { + var k: Klass +} + +sil [ossa] @moveonlywrapper_to_copyable_addr_test_1 : $@convention(thin) (@in Klass) -> () { +bb0(%0 : $*Klass): + %0a = moveonlywrapper_to_copyable_addr %0 : $*Klass + // expected-error @-1 {{operand of 'moveonlywrapper_to_copyable_addr' must be of moveonlywrapped type}} + destroy_addr %0a : $*Klass + %9999 = tuple() +} + +sil [ossa] @moveonlywrapper_to_copyable_addr_test_2 : $@convention(thin) (@owned Klass) -> () { +bb0(%1 : @owned $Klass): + %2 = moveonlywrapper_to_copyable_addr %1 : $Klass + // expected-error @-1 {{operand of 'moveonlywrapper_to_copyable_addr' must have address type}} + destroy_value %2 : $Klass + %9999 = tuple() +} + +sil [ossa] @moveonlywrapper_to_copyable_value_test_1 : $@convention(thin) (@in Klass, @owned Klass) -> () { +bb0(%0 : $*Klass, %1 : @owned $Klass): + %2 = moveonlywrapper_to_copyable [guaranteed] %0 : $*Klass + // expected-error @-1 {{operand of 'moveonlywrapper_to_copyable' must have object type}} + destroy_addr %2 : $*Klass + %3 = moveonlywrapper_to_copyable [guaranteed] %1 : $Klass + destroy_value %3 : $Klass + %9999 = tuple() +} + +sil [ossa] @moveonlywrapper_to_copyable_value_test_2 : $@convention(thin) (@in Klass, @owned Klass) -> () { +bb0(%0 : $*Klass, %1 : @owned $Klass): + %3 = moveonlywrapper_to_copyable [guaranteed] %1 : $Klass + // expected-error @-1 {{operand of 'moveonlywrapper_to_copyable' must be of moveonlywrapped type}} + destroy_value %3 : $Klass + %9999 = tuple() +} + +sil [ossa] @copyable_to_moveonlywrapper_value_test : $@convention(thin) (@in Klass, @owned @moveOnly Klass) -> () { +bb0(%0 : $*Klass, %1 : @owned $@moveOnly Klass): + %2 = copyable_to_moveonlywrapper [owned] %0 : $*Klass + // expected-error @-1 {{operand of 'copyable_to_moveonlywrapper' must have object type}} + destroy_addr %2 : $*Klass + %3 = copyable_to_moveonlywrapper [owned] %1 : $Klass + destroy_value %3 : $Klass + %9999 = tuple() +} + +sil [ossa] @copyable_to_moveonlywrapper_value_test_2 : $@convention(thin) (@in Klass, @owned @moveOnly Klass) -> () { +bb0(%0 : $*Klass, %1 : @owned $@moveOnly Klass): + %3 = copyable_to_moveonlywrapper [owned] %1 : $@moveOnly Klass + // expected-error @-1 {{operand of 'copyable_to_moveonlywrapper' must not be of moveonlywrapped type}} + destroy_value %3 : $Klass + %9999 = tuple() +} + +sil [ossa] @copyable_to_moveonlywrapper_addr_test_1 : $@convention(thin) (@in @moveOnly Klass) -> () { +bb0(%0 : $*@moveOnly Klass): + %0a = copyable_to_moveonlywrapper_addr %0 : $*@moveOnly Klass + // expected-error @-1 {{operand of 'copyable_to_moveonlywrapper_addr' must not be of moveonlywrapped type}} + destroy_addr %0a : $*@moveOnly Klass + %9999 = tuple() +} + +sil [ossa] @copyable_to_moveonlywrapper_addr_test_2 : $@convention(thin) (@owned @moveOnly Klass) -> () { +bb0(%1 : @owned $@moveOnly Klass): + %2 = copyable_to_moveonlywrapper_addr %1 : $@moveOnly Klass + // expected-error @-1 {{operand of 'copyable_to_moveonlywrapper_addr' must have address type}} + destroy_value %2 : $@moveOnly Klass + %9999 = tuple() +} \ No newline at end of file diff --git a/test/SIL/Serialization/basic2.sil b/test/SIL/Serialization/basic2.sil index eeba9fee0b310..fbe6c08093d1e 100644 --- a/test/SIL/Serialization/basic2.sil +++ b/test/SIL/Serialization/basic2.sil @@ -17,6 +17,28 @@ bb0: return %9999 : $() } +// CHECK-LABEL: sil [ossa] @test_copyable_to_moveonlywrapper : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK: copyable_to_moveonlywrapper [owned] +// CHECK: } // end sil function 'test_copyable_to_moveonlywrapper' +sil [ossa] @test_copyable_to_moveonlywrapper : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%0 : @owned $Builtin.NativeObject): + %0a = copyable_to_moveonlywrapper [owned] %0 : $Builtin.NativeObject + destroy_value %0a : $@moveOnly Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @test_copyable_to_moveonlywrapper_addr : $@convention(thin) (@in Builtin.NativeObject) -> () { +// CHECK: copyable_to_moveonlywrapper_addr +// CHECK: } // end sil function 'test_copyable_to_moveonlywrapper_addr' +sil [ossa] @test_copyable_to_moveonlywrapper_addr : $@convention(thin) (@in Builtin.NativeObject) -> () { +bb0(%0 : $*Builtin.NativeObject): + %0a = copyable_to_moveonlywrapper_addr %0 : $*Builtin.NativeObject + destroy_addr %0a : $*@moveOnly Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + // We don't serialize debug_value today... but we should. // // CHECK-LABEL: sil [ossa] @test_debug_value_alloc_stack_moved : $@convention(thin) (@owned Builtin.NativeObject) -> () { @@ -66,3 +88,31 @@ bb0(%0 : @owned $Builtin.NativeObject): %9999 = tuple() return %9999 : $() } + +// CHECK-LABEL: sil [ossa] @test_moveonlywrapper_to_copyable_addr : $@convention(thin) (@in Builtin.NativeObject) -> () { +// CHECK: moveonlywrapper_to_copyable_addr +// CHECK: } // end sil function 'test_moveonlywrapper_to_copyable_addr' +sil [ossa] @test_moveonlywrapper_to_copyable_addr : $@convention(thin) (@in Builtin.NativeObject) -> () { +bb0(%0 : $*Builtin.NativeObject): + %1 = alloc_stack $@moveOnly Builtin.NativeObject + %1a = moveonlywrapper_to_copyable_addr %1 : $*@moveOnly Builtin.NativeObject + copy_addr [take] %0 to [init] %1a : $*Builtin.NativeObject + destroy_addr %1 : $*@moveOnly Builtin.NativeObject + dealloc_stack %1 : $*@moveOnly Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @test_moveonlywrapper_to_copyable_box : $@convention(thin) () -> () { +// CHECK: [[BOX:%.*]] = alloc_box ${ var @moveOnly Builtin.NativeObject } +// CHECK: [[CAST:%.*]] = moveonlywrapper_to_copyable_box [[BOX]] : ${ var @moveOnly Builtin.NativeObject } +// CHECK: dealloc_box [[CAST]] : ${ var Builtin.NativeObject } +// CHECK: } // end sil function 'test_moveonlywrapper_to_copyable_box' +sil [ossa] @test_moveonlywrapper_to_copyable_box : $@convention(thin) () -> () { +bb0: + %0 = alloc_box ${ var @moveOnly Builtin.NativeObject } + %1 = moveonlywrapper_to_copyable_box %0 : ${ var @moveOnly Builtin.NativeObject } + dealloc_box %1 : ${ var Builtin.NativeObject } + %9999 = tuple () + return %9999 : $() +} \ No newline at end of file diff --git a/test/SILGen/consuming_parameter.swift b/test/SILGen/consuming_parameter.swift index 5e6ae43d11a6a..2de697c52888c 100644 --- a/test/SILGen/consuming_parameter.swift +++ b/test/SILGen/consuming_parameter.swift @@ -1,26 +1,33 @@ -// RUN: %target-swift-emit-silgen -enable-experimental-feature NoImplicitCopy %s | %FileCheck %s +// RUN: %target-swift-emit-silgen %s | %FileCheck %s func bar(_: String) {} // CHECK-LABEL: sil {{.*}} @${{.*}}3foo func foo(y: consuming String, z: String) -> () -> String { - // CHECK: bb0(%0 : @_eagerMove @owned $String, %1 : @guaranteed $String): - // CHECK: [[BOX:%.*]] = alloc_box ${ var String } + // CHECK: bb0(%0 : @noImplicitCopy @_eagerMove @owned $String, %1 : @guaranteed $String): + // CHECK: [[BOX:%.*]] = alloc_box ${ var @moveOnly String } // CHECK: [[Y:%.*]] = project_box [[BOX]] - // CHECK: store %0 to [init] [[Y]] + // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[Y]] + // CHECK: store %0 to [init] [[UNWRAP]] // CHECK: [[YCAPTURE:%.*]] = copy_value [[BOX]] - // CHECK: partial_apply {{.*}} {{%.*}}([[YCAPTURE]]) + // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_box [[YCAPTURE]] + // CHECK: partial_apply {{.*}} {{%.*}}([[UNWRAP]]) let r = { y } // CHECK: [[ZCOPY:%.*]] = copy_value %1 // CHECK: [[YACCESS:%.*]] = begin_access [modify] [unknown] [[Y]] - // CHECK: assign [[ZCOPY]] to [[YACCESS]] + // CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[YACCESS]] + // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[MARK]] + // CHECK: assign [[ZCOPY]] to [[UNWRAP]] y = z // CHECK: [[YACCESS:%.*]] = begin_access [read] [unknown] [[Y]] - // CHECK: [[YVAL:%.*]] = load [copy] [[YACCESS]] - // CHECK: apply {{%.*}}([[YVAL]] + // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[YACCESS]] + // CHECK: [[YVAL:%.*]] = load [copy] [[MARK]] + // CHECK: [[BORROW:%.*]] = begin_borrow [[YVAL]] + // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [guaranteed] [[BORROW]] + // CHECK: apply {{%.*}}([[UNWRAP]] bar(y) return r @@ -33,23 +40,30 @@ struct Butt { // CHECK-LABEL: sil {{.*}} @${{.*}}4Butt{{.*}}6merged consuming func merged(with other: Butt) -> () -> Butt { - // CHECK: bb0(%0 : @guaranteed $Butt, %1 : @_eagerMove @owned $Butt): - // CHECK: [[BOX:%.*]] = alloc_box ${ var Butt } + // CHECK: bb0(%0 : @guaranteed $Butt, %1 : @noImplicitCopy @_eagerMove @owned $Butt): + // CHECK: [[BOX:%.*]] = alloc_box ${ var @moveOnly Butt } // CHECK: [[SELF:%.*]] = project_box [[BOX]] - // CHECK: store %1 to [init] [[SELF]] + // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[SELF]] + // CHECK: store %1 to [init] [[UNWRAP]] // CHECK: [[SELFCAPTURE:%.*]] = copy_value [[BOX]] - // CHECK: partial_apply {{.*}} {{%.*}}([[SELFCAPTURE]]) + // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_box [[SELFCAPTURE]] + // CHECK: partial_apply {{.*}} {{%.*}}([[UNWRAP]]) let r = { self } // CHECK: [[OCOPY:%.*]] = copy_value %0 // CHECK: [[SELFACCESS:%.*]] = begin_access [modify] [unknown] [[SELF]] - // CHECK: assign [[OCOPY]] to [[SELFACCESS]] + // CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[SELFACCESS]] + // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[MARK]] + // CHECK: assign [[OCOPY]] to [[UNWRAP]] self = other // CHECK: [[SELFACCESS:%.*]] = begin_access [read] [unknown] [[SELF]] - // CHECK: [[SELFVAL:%.*]] = load [copy] [[SELFACCESS]] - // CHECK: apply {{%.*}}([[SELFVAL]] + // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[SELFACCESS]] + // CHECK: [[SELFVAL:%.*]] = load [copy] [[MARK]] + // CHECK: [[BORROW:%.*]] = begin_borrow [[SELFVAL]] + // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [guaranteed] [[BORROW]] + // CHECK: apply {{%.*}}([[UNWRAP]] self.bar() diff --git a/test/SILGen/moveonly.swift b/test/SILGen/moveonly.swift index 641a313f9d79c..e25375482eb4e 100644 --- a/test/SILGen/moveonly.swift +++ b/test/SILGen/moveonly.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-silgen -enable-experimental-feature NoImplicitCopy %s | %FileCheck %s +// RUN: %target-swift-emit-silgen %s | %FileCheck %s ////////////////// // Declarations // @@ -988,9 +988,9 @@ func testConditionallyInitializedLet() { consumeVal(x) } -///////////////////////////// -// MARK: AddressOnlySetter // -///////////////////////////// +//////////////////////// +// MARK: Setter Tests // +//////////////////////// struct AddressOnlySetterTester : ~Copyable { var a: AddressOnlyProtocol { @@ -1005,6 +1005,24 @@ struct AddressOnlySetterTester : ~Copyable { } } +public class NonFinalClassTest { + // CHECK: sil hidden [transparent] [ossa] @$s8moveonly17NonFinalClassTestC1xAA19AddressOnlyProtocolVvs : $@convention(method) (@in AddressOnlyProtocol, @guaranteed NonFinalClassTest) -> () { + // CHECK: bb0([[INPUT:%.*]] : $*AddressOnlyProtocol, [[SELF:%.*]] : @guaranteed + // CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[INPUT]] + // CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol + // CHECK: copy_addr [[MARK]] to [init] [[TEMP]] + // CHECK: [[REF:%.*]] = ref_element_addr [[SELF]] + // CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[REF]] + // CHECK: [[MARK2:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]] + // CHECK: copy_addr [take] [[TEMP]] to [[MARK2]] + // CHECK: end_access [[ACCESS]] + // CHECK: dealloc_stack [[TEMP]] + // CHECK: destroy_addr [[MARK]] + // CHECK: } // end sil function '$s8moveonly17NonFinalClassTestC1xAA19AddressOnlyProtocolVvs' + var x: AddressOnlyProtocol + init(y: consuming AddressOnlyProtocol) { self.x = y } +} + ///////////////////// // MARK: Subscript // ///////////////////// @@ -3071,3 +3089,4 @@ public func testSubscriptGetModifyThroughParentClass_BaseLoadable_ResultAddressO m.computedTester2[0].nonMutatingFunc() m.computedTester2[0].mutatingFunc() } + diff --git a/test/SILGen/moveonly_escaping_closure.swift b/test/SILGen/moveonly_escaping_closure.swift index 09b1e72869fb9..623529b74470a 100644 --- a/test/SILGen/moveonly_escaping_closure.swift +++ b/test/SILGen/moveonly_escaping_closure.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-emit-silgen -enable-experimental-feature NoImplicitCopy -module-name moveonly_closure %s | %FileCheck %s -// RUN: %target-swift-emit-sil -enable-experimental-feature NoImplicitCopy -module-name moveonly_closure -verify %s +// RUN: %target-swift-emit-silgen -module-name moveonly_closure %s | %FileCheck %s +// RUN: %target-swift-emit-sil -module-name moveonly_closure -verify %s @_moveOnly struct Empty {} @@ -265,10 +265,11 @@ func testInOutVarClosureCaptureVar(_ f: inout () -> ()) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure36testConsumingEscapeClosureCaptureVaryyyycnF : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> () { -// CHECK: bb0([[ARG:%.*]] : @_eagerMove @owned -// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @callee_guaranteed () -> () } +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @_eagerMove @owned +// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @moveOnly @callee_guaranteed () -> () } // CHECK: [[FUNC_PROJECT:%.*]] = project_box [[FUNC_BOX]] -// CHECK: store [[ARG]] to [init] [[FUNC_PROJECT]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[FUNC_PROJECT]] +// CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } // CHECK: [[PROJECT:%.*]] = project_box [[BOX]] @@ -277,7 +278,9 @@ func testInOutVarClosureCaptureVar(_ f: inout () -> ()) { // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] -// CHECK: assign [[PAI]] to [[ACCESS]] +// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[MARK]] +// CHECK: assign [[PAI]] to [[UNWRAP]] // CHECK: end_access [[ACCESS]] // CHECK: } // end sil function '$s16moveonly_closure36testConsumingEscapeClosureCaptureVaryyyycnF' // @@ -522,10 +525,11 @@ func testInOutVarClosureCaptureLet(_ f: inout () -> ()) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure36testConsumingEscapeClosureCaptureLetyyyycnF : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> () { -// CHECK: bb0([[ARG:%.*]] : @_eagerMove @owned -// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @callee_guaranteed () -> () } +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @_eagerMove @owned +// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @moveOnly @callee_guaranteed () -> () } // CHECK: [[FUNC_PROJECT:%.*]] = project_box [[FUNC_BOX]] -// CHECK: store [[ARG]] to [init] [[FUNC_PROJECT]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[FUNC_PROJECT]] +// CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ let SingleElt } // CHECK: [[PROJECT:%.*]] = project_box [[BOX]] @@ -534,7 +538,9 @@ func testInOutVarClosureCaptureLet(_ f: inout () -> ()) { // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] -// CHECK: assign [[PAI]] to [[ACCESS]] +// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[MARK]] +// CHECK: assign [[PAI]] to [[UNWRAP]] // CHECK: end_access [[ACCESS]] // CHECK: } // end sil function '$s16moveonly_closure36testConsumingEscapeClosureCaptureLetyyyycnF' // @@ -771,16 +777,19 @@ func testInOutVarClosureCaptureInOut(_ f: inout () -> (), _ x: inout SingleElt) // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure38testConsumingEscapeClosureCaptureInOutyyyycn_AA9SingleEltVztF : $@convention(thin) (@owned @callee_guaranteed () -> (), @inout SingleElt) -> () { -// CHECK: bb0([[FUNC_ARG:%.*]] : @_eagerMove @owned $@callee_guaranteed () -> (), [[PROJECT:%.*]] : $*SingleElt): -// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @callee_guaranteed () -> () } +// CHECK: bb0([[FUNC_ARG:%.*]] : @noImplicitCopy @_eagerMove @owned $@callee_guaranteed () -> (), [[PROJECT:%.*]] : $*SingleElt): +// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @moveOnly @callee_guaranteed () -> () } // CHECK: [[FUNC_PROJECT:%.*]] = project_box [[FUNC_BOX]] -// CHECK: store [[FUNC_ARG]] to [init] [[FUNC_PROJECT]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[FUNC_PROJECT]] +// CHECK: store [[FUNC_ARG]] to [init] [[UNWRAP]] // // CHECK: [[CHECK:%.*]] = mark_must_check [consumable_and_assignable] [[PROJECT]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure38testConsumingEscapeClosureCaptureInOutyyyycn_AA9SingleEltVztFyycfU_ : $@convention(thin) (@inout_aliasable SingleElt) -> () // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[CHECK]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] -// CHECK: assign [[PAI]] to [[ACCESS]] +// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[MARK]] +// CHECK: assign [[PAI]] to [[UNWRAP]] // CHECK: end_access [[ACCESS]] // CHECK: } // end sil function '$s16moveonly_closure38testConsumingEscapeClosureCaptureInOutyyyycn_AA9SingleEltVztF' // @@ -1019,10 +1028,11 @@ func testLocalVarClosureCaptureConsuming(_ x: consuming SingleElt) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure033testConsumingEscapeClosureCaptureD0yyyycn_AA9SingleEltVntF : $@convention(thin) (@owned @callee_guaranteed () -> (), @owned SingleElt) -> () { -// CHECK: bb0([[ARG:%.*]] : @_eagerMove @owned $@callee_guaranteed () -> (), -// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @callee_guaranteed () -> () } +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @_eagerMove @owned $@callee_guaranteed () -> (), +// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @moveOnly @callee_guaranteed () -> () } // CHECK: [[FUNC_PROJECT:%.*]] = project_box [[FUNC_BOX]] -// CHECK: store [[ARG]] to [init] [[FUNC_PROJECT]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[FUNC_PROJECT]] +// CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } // CHECK: [[PROJECT:%.*]] = project_box [[BOX]] @@ -1031,7 +1041,9 @@ func testLocalVarClosureCaptureConsuming(_ x: consuming SingleElt) { // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] -// CHECK: assign [[PAI]] to [[ACCESS]] +// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[MARK]] +// CHECK: assign [[PAI]] to [[UNWRAP]] // CHECK: end_access [[ACCESS]] // CHECK: } // end sil function '$s16moveonly_closure033testConsumingEscapeClosureCaptureD0yyyycn_AA9SingleEltVntF' // @@ -1270,10 +1282,11 @@ func testInOutVarClosureCaptureOwned(_ f: inout () -> (), _ x: __owned SingleElt // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure38testConsumingEscapeClosureCaptureOwnedyyyycn_AA9SingleEltVntF : $@convention(thin) (@owned @callee_guaranteed () -> (), @owned SingleElt) -> () { -// CHECK: bb0([[ARG:%.*]] : @_eagerMove @owned $@callee_guaranteed () -> (), -// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @callee_guaranteed () -> () } +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @_eagerMove @owned $@callee_guaranteed () -> (), +// CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @moveOnly @callee_guaranteed () -> () } // CHECK: [[FUNC_PROJECT:%.*]] = project_box [[FUNC_BOX]] -// CHECK: store [[ARG]] to [init] [[FUNC_PROJECT]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[FUNC_PROJECT]] +// CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ let SingleElt } // CHECK: [[PROJECT:%.*]] = project_box [[BOX]] @@ -1282,7 +1295,9 @@ func testInOutVarClosureCaptureOwned(_ f: inout () -> (), _ x: __owned SingleElt // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] -// CHECK: assign [[PAI]] to [[ACCESS]] +// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[MARK]] +// CHECK: assign [[PAI]] to [[UNWRAP]] // CHECK: end_access [[ACCESS]] // CHECK: } // end sil function '$s16moveonly_closure38testConsumingEscapeClosureCaptureOwnedyyyycn_AA9SingleEltVntF' // diff --git a/test/SILGen/noimplicitcopy_borrowing_parameters.swift b/test/SILGen/noimplicitcopy_borrowing_parameters.swift new file mode 100644 index 0000000000000..82e83ecefe628 --- /dev/null +++ b/test/SILGen/noimplicitcopy_borrowing_parameters.swift @@ -0,0 +1,305 @@ +// RUN: %target-swift-emit-silgen -sil-verify-all %s | %FileCheck %s + +//////////////////////// +// MARK: Declarations // +//////////////////////// + +public class Klass {} + +public struct NonTrivialStruct { + var k = Klass() + + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + mutating func doSomethingMutating() {} + //consuming func doSomethingConsuming() {} +} + +public protocol P { + static var value: Self { get } +} + +public struct GenericNonTrivialStruct { + var t = T.value + + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} +} + +enum AddressOnlyEnum { + case x(NonTrivialStruct) + case y(T) +} + +enum LoadableEnum { + case x(NonTrivialStruct) + case y(Int) +} + +func borrowValDefault(_ x: NonTrivialStruct) {} +func borrowValBorrowing(_ x: borrowing NonTrivialStruct) {} +func borrowValDefault(_ x: GenericNonTrivialStruct) {} +func borrowValBorrowing(_ x: borrowing GenericNonTrivialStruct) {} +//func consumeValOwned(_ x: __owned NonTrivialStruct) {} +//func consumeValConsuming(_ x: consuming NonTrivialStruct) {} +//func consumeValOwned(_ x: __owned GenericNonTrivialStruct) {} +//func consumeValConsuming(_ x: consuming GenericNonTrivialStruct) {} + +//////////////////////// +// MARK: Simple Tests // +//////////////////////// + +// CHECK: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters11testConsumeyyAA16NonTrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @guaranteed $NonTrivialStruct): +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +// CHECK: [[COPY2:%.*]] = copy_value [[BORROW]] +// CHECK: [[MOVE:%.*]] = move_value [[COPY2]] +// CHECK: destroy_value [[MOVE]] +// CHECK: end_borrow [[BORROW]] +// +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +// CHECK: [[EXT:%.*]] = struct_extract [[BORROW]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [guaranteed] [[EXT]] +// CHECK: [[COPY:%.*]] = copy_value [[UNWRAP]] +// CHECK: destroy_value [[COPY]] +// CHECK: end_borrow [[BORROW]] +// +// CHECK: destroy_value [[CHECK]] +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters11testConsumeyyAA16NonTrivialStructVF' +func testConsume(_ x: borrowing NonTrivialStruct) { + let _ = x + let _ = x.k +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters7testUseyyAA16NonTrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @guaranteed $NonTrivialStruct): +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +// CHECK: end_borrow [[BORROW]] +// CHECK: destroy_value [[CHECK]] +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters7testUseyyAA16NonTrivialStructVF' +func testUse(_ x: borrowing NonTrivialStruct) { + _ = x +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters24testCallBorrowValDefaultyyAA16NonTrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @guaranteed $NonTrivialStruct): +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [guaranteed] [[BORROW]] +// CHECK: apply {{%.*}}([[UNWRAP]]) +// CHECK: end_borrow [[BORROW]] +// CHECK: destroy_value [[CHECK]] +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters24testCallBorrowValDefaultyyAA16NonTrivialStructVF' +func testCallBorrowValDefault(_ x: borrowing NonTrivialStruct) { + borrowValDefault(x) +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters26testCallBorrowValBorrowingyyAA16NonTrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @guaranteed $NonTrivialStruct): +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +func testCallBorrowValBorrowing(_ x: borrowing NonTrivialStruct) { + borrowValBorrowing(x) +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters25testCallMethodSelfDefaultyyAA16NonTrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @guaranteed $NonTrivialStruct): +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [guaranteed] [[BORROW]] +// CHECK: apply {{%.*}}([[UNWRAP]]) +// CHECK: end_borrow [[BORROW]] +// CHECK: destroy_value [[CHECK]] +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters25testCallMethodSelfDefaultyyAA16NonTrivialStructVF' +func testCallMethodSelfDefault(_ x: borrowing NonTrivialStruct) { + x.doSomethingDefault() +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters27testCallMethodSelfBorrowingyyAA16NonTrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [guaranteed] [[BORROW]] +// TODO: This should be passed directly without a conversion. +// CHECK: apply {{%.*}}([[UNWRAP]]) +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters27testCallMethodSelfBorrowingyyAA16NonTrivialStructVF' +func testCallMethodSelfBorrowing(_ x: borrowing NonTrivialStruct) { + x.doSomethingBorrowing() +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters19testEscapingClosureyyAA16NonTrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @guaranteed $NonTrivialStruct): +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[COPY2:%.*]] = copy_value [[CHECK]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [owned] [[COPY2]] +// CHECK: partial_apply [callee_guaranteed] {{%.*}}([[UNWRAP]]) +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters19testEscapingClosureyyAA16NonTrivialStructVF' +func testEscapingClosure(_ x: borrowing NonTrivialStruct) { + var f: () -> () = {} + f = { + _ = x + } + _ = f +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters22testNonEscapingClosureyyAA0E13TrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @guaranteed $NonTrivialStruct): +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[COPY2:%.*]] = copy_value [[CHECK]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [owned] [[COPY2]] +// CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[UNWRAP]]) +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters22testNonEscapingClosureyyAA0E13TrivialStructVF' +func testNonEscapingClosure(_ x: borrowing NonTrivialStruct) { + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { + _ = x + } +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters36testLoadableBorrowingConsumeOperatoryyAA16NonTrivialStructVF : $@convention(thin) (@guaranteed NonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +// CHECK: [[COPY2:%.*]] = copy_value [[BORROW]] +// CHECK: [[MOVE:%.*]] = move_value [allows_diagnostics] [[COPY2]] +// CHECK: destroy_value [[MOVE]] +// CHECK: end_borrow [[BORROW]] +// CHECK: destroy_value [[CHECK]] +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters36testLoadableBorrowingConsumeOperatoryyAA16NonTrivialStructVF' +func testLoadableBorrowingConsumeOperator(_ x: borrowing NonTrivialStruct) { + _ = consume x +} + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters25testLoadableBorrowingEnumyyAA0eG0OF : $@convention(thin) (@guaranteed LoadableEnum) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper [guaranteed] +// CHECK: [[COPY:%.*]] = copy_value [[WRAP]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[COPY]] +// CHECK: [[BORROW:%.*]] = begin_borrow [[CHECK]] +// CHECK: [[COPY2:%.*]] = copy_value [[BORROW]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable [owned] [[COPY2]] +// CHECK: switch_enum [[UNWRAP]] +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters25testLoadableBorrowingEnumyyAA0eG0OF' +func testLoadableBorrowingEnum(_ x: borrowing LoadableEnum) { + switch x { + case let .x(y): + _ = y + break + case .y: + break + } +} + +////////////////////////////////////////////// +// MARK: Simple AddressOnly Borrowing Tests // +////////////////////////////////////////////// + +// CHECK-LABEL: sil hidden [ossa] @$s35noimplicitcopy_borrowing_parameters31testAddressOnlyBorrowingConsumeyyAA23GenericNonTrivialStructVyxGAA1PRzlF : $@convention(thin) (@in_guaranteed GenericNonTrivialStruct) -> () { +// CHECK: bb0([[ARG:%.*]] : @noImplicitCopy +// CHECK: [[WRAP:%.*]] = copyable_to_moveonlywrapper_addr [[ARG]] +// CHECK: [[CHECK:%.*]] = mark_must_check [no_consume_or_assign] [[WRAP]] +// CHECK: [[STACK:%.*]] = alloc_stack +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[CHECK]] +// CHECK: copy_addr [[UNWRAP]] to [init] [[STACK]] +// CHECK: destroy_addr [[STACK]] +// CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[CHECK]] +// TODO: We probably want the unwrap to be on the struct_element_addr, not the other wya around. +// CHECK: [[GEP:%.*]] = struct_element_addr [[UNWRAP]] +// CHECK: [[STACK:%.*]] = alloc_stack +// CHECK: copy_addr [[GEP]] to [init] [[STACK]] +// CHECK: destroy_addr [[STACK]] +// CHECK: } // end sil function '$s35noimplicitcopy_borrowing_parameters31testAddressOnlyBorrowingConsumeyyAA23GenericNonTrivialStructVyxGAA1PRzlF' +func testAddressOnlyBorrowingConsume(_ x: borrowing GenericNonTrivialStruct) { + let _ = x + let _ = x.t +} + +func testAddressOnlyBorrowingConsume2(_ x: borrowing GenericNonTrivialStruct) { + var y = x + y = x + _ = y +} + +func testAddressOnlyBorrowingConsume3(_ x: borrowing GenericNonTrivialStruct) { + let y = x + _ = y +} + +func testAddressOnlyBorrowingUse(_ x: borrowing GenericNonTrivialStruct) { + _ = x +} + +func testAddressOnlyBorrowingUseAndConsume(_ x: borrowing GenericNonTrivialStruct) { + borrowValDefault(x) + let _ = x +} + +func testAddressOnlyBorrowingCallBorrowValDefault(_ x: borrowing GenericNonTrivialStruct) { + borrowValDefault(x) +} + +func testAddressOnlyBorrowingCallBorrowValBorrowing(_ x: borrowing GenericNonTrivialStruct) { + borrowValBorrowing(x) +} + +func testAddressOnlyBorrowingCallMethodSelfDefault(_ x: borrowing GenericNonTrivialStruct) { + x.doSomethingDefault() +} + +func testAddressOnlyBorrowingCallMethodSelfBorrowing(_ x: borrowing GenericNonTrivialStruct) { + x.doSomethingBorrowing() +} + +func testAddressOnlyBorrowingEscapingClosure(_ x: borrowing GenericNonTrivialStruct) { + var f: () -> () = {} + f = { + _ = x + } + _ = f +} + +func testAddressOnlyBorrowingNonEscapingClosure(_ x: borrowing GenericNonTrivialStruct) { + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { + _ = x + } +} + +func testAddressOnlyBorrowingCast(_ x: borrowing GenericNonTrivialStruct) { + let _ = x as Any +} + +func testAddressOnlyBorrowingCastCheck(_ x: borrowing GenericNonTrivialStruct) { + if x is Any { + } +} + +func testAddressOnlyBorrowingEnum(_ x: borrowing AddressOnlyEnum) { + switch x { + case let .x(y): + _ = y + break + case let .y(z): + _ = z + break + } +} diff --git a/test/SILGen/ownership_specifier_mangling.swift b/test/SILGen/ownership_specifier_mangling.swift index 6a6da68df18cf..ffaca6a31965d 100644 --- a/test/SILGen/ownership_specifier_mangling.swift +++ b/test/SILGen/ownership_specifier_mangling.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-silgen -enable-experimental-feature NoImplicitCopy %s | %FileCheck %s +// RUN: %target-swift-emit-silgen %s | %FileCheck %s // The internal `__shared` and `__owned` modifiers would always affect // symbol mangling, even if they don't have a concrete impact on ABI. The diff --git a/test/SILOptimizer/consuming_parameter.swift b/test/SILOptimizer/consuming_parameter.swift index acc1cee9c5f07..aee8a90063e25 100644 --- a/test/SILOptimizer/consuming_parameter.swift +++ b/test/SILOptimizer/consuming_parameter.swift @@ -1,9 +1,9 @@ -// RUN: %target-swift-frontend -c -enable-experimental-feature NoImplicitCopy -disable-availability-checking -Xllvm --sil-print-final-ossa-module -O -module-name=main -o /dev/null %s 2>&1 | %FileCheck %s +// RUN: %target-swift-frontend -c -disable-availability-checking -Xllvm --sil-print-final-ossa-module -O -module-name=main -o /dev/null %s 2>&1 | %FileCheck %s // REQUIRES: concurrency // CHECK-LABEL: sil [ossa] @async_dead_arg_call : {{.*}} { -// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @_eagerMove @owned +// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @noImplicitCopy @_eagerMove @owned // CHECK: destroy_value [[INSTANCE]] // CHECK: [[EXECUTOR:%[^,]+]] = enum $Optional, #Optional.none!enumelt // CHECK: [[CALLEE:%[^,]+]] = function_ref @async_callee @@ -17,7 +17,7 @@ public func async_dead_arg_call(o: consuming AnyObject) async { } // CHECK-LABEL: sil [ossa] @async_dead_arg_call_lexical : {{.*}} { -// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @_lexical @owned +// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @noImplicitCopy @_lexical @owned // CHECK: [[MOVE:%[^,]+]] = move_value [lexical] [[INSTANCE]] // CHECK: [[EXECUTOR:%[^,]+]] = enum $Optional, #Optional.none!enumelt // CHECK: [[CALLEE:%[^,]+]] = function_ref @async_callee @@ -33,7 +33,7 @@ public func async_dead_arg_call_lexical(@_noEagerMove o: consuming AnyObject) as extension C { // CHECK-LABEL: sil [ossa] @async_dead_arg_call_lexical_method : {{.*}} { - // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @_lexical @owned + // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @noImplicitCopy @_lexical @owned // CHECK-LABEL: } // end sil function 'async_dead_arg_call_lexical_method' @_silgen_name("async_dead_arg_call_lexical_method") @_noEagerMove @@ -46,7 +46,7 @@ extension C { public class C { // CHECK-LABEL: sil [ossa] @async_dead_arg_call_method : {{.*}} { - // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @_eagerMove @owned + // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @noImplicitCopy @_eagerMove @owned // CHECK: destroy_value [[INSTANCE]] // CHECK: [[EXECUTOR:%[^,]+]] = enum $Optional, #Optional.none!enumelt // CHECK: [[CALLEE:%[^,]+]] = function_ref @async_callee : $@convention(thin) @async () -> () @@ -66,7 +66,7 @@ public class C { func bar() async {} // CHECK-LABEL: sil [ossa] @write_to_pointer : {{.*}} { -// CHECK: {{bb[0-9]+}}([[CONSUMED_INSTANCE:%[^,]+]] : @_eagerMove @owned $AnyObject, [[UMP:%[^,]+]] : +// CHECK: {{bb[0-9]+}}([[CONSUMED_INSTANCE:%[^,]+]] : @noImplicitCopy @_eagerMove @owned $AnyObject, [[UMP:%[^,]+]] : // CHECK: [[PTR:%[^,]+]] = struct_extract [[UMP]] // CHECK: [[ADDR:%[^,]+]] = pointer_to_address [[PTR]] // CHECK: store [[CONSUMED_INSTANCE]] to [assign] [[ADDR]] @@ -84,7 +84,7 @@ public func write_to_pointer(o: consuming AnyObject, p: UnsafeMutablePointer, [[INSTANCE:%[^,]+]] : @_eagerMove @owned + // CHECK: {{bb[0-9]+}}([[UMP:%[^,]+]] : $UnsafeMutablePointer, [[INSTANCE:%[^,]+]] : @noImplicitCopy @_eagerMove @owned // CHECK: [[PTR:%[^,]+]] = struct_extract [[UMP]] // CHECK: [[ADDR:%[^,]+]] = pointer_to_address [[PTR]] // CHECK: store [[INSTANCE]] to [assign] [[ADDR]] diff --git a/test/SILOptimizer/move_only_checker_addressonly_fail.swift b/test/SILOptimizer/move_only_checker_addressonly_fail.swift index 20b638e0e00e6..f9f32a278debd 100644 --- a/test/SILOptimizer/move_only_checker_addressonly_fail.swift +++ b/test/SILOptimizer/move_only_checker_addressonly_fail.swift @@ -16,6 +16,8 @@ func test1(_ x: T) { // // An earlier change, I believe made it so that SILGen did not emit these // unchecked_addr_cast. - consumeValue(x2) // expected-error {{usage of no-implicit-copy value that the compiler can't verify.}} - consumeValue(x2) // expected-error {{usage of no-implicit-copy value that the compiler can't verify.}} + consumeValue(x2) // expected-error {{'x2' is borrowed and cannot be consumed}} + // expected-note @-1 {{consumed here}} + consumeValue(x2) // expected-error {{'x2' is borrowed and cannot be consumed}} + // expected-note @-1 {{consumed here}} } diff --git a/test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift b/test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift index f1797b37c64d6..bb16dcbe55fb8 100644 --- a/test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift +++ b/test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses -enable-experimental-feature MoveOnlyTuples %s +// RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature MoveOnlyClasses -enable-experimental-feature MoveOnlyTuples %s // This test validates that we properly emit errors if we partially invalidate // through a type with a deinit. diff --git a/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift b/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift index 423d0d25bea51..9a51e2624413d 100644 --- a/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift @@ -4486,3 +4486,14 @@ func testMyEnum() { _ = consume x // expected-note {{consumed again here}} } } + +//////////////////////// +// MARK: Setter Tests // +//////////////////////// + +public class NonFinalCopyableKlassWithMoveOnlyField { + var moveOnlyVarStruct = NonTrivialStruct() + let moveOnlyLetStruct = NonTrivialStruct() + var moveOnlyVarProt = AddressOnlyProtocol() + let moveOnlyLetProt = AddressOnlyProtocol() +} diff --git a/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift b/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift index a6a6bc1328f24..08a73a77e080f 100644 --- a/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s +// RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature MoveOnlyClasses %s ////////////////// // Declarations // diff --git a/test/SILOptimizer/moveonly_trivial_addresschecker_diagnostics.swift b/test/SILOptimizer/moveonly_trivial_addresschecker_diagnostics.swift index 9471901809a68..284745459fe04 100644 --- a/test/SILOptimizer/moveonly_trivial_addresschecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_trivial_addresschecker_diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-sil -enable-experimental-feature NoImplicitCopy -sil-verify-all -verify %s +// RUN: %target-swift-emit-sil -sil-verify-all -verify %s ////////////////// // Declarations // diff --git a/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift b/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift index c2aafa1d0a35f..720b5082725c9 100644 --- a/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-sil -enable-experimental-feature NoImplicitCopy -sil-verify-all -verify %s +// RUN: %target-swift-emit-sil -sil-verify-all -verify %s ////////////////// // Declarations // diff --git a/test/SILOptimizer/noimplicitcopy.swift b/test/SILOptimizer/noimplicitcopy.swift index 3a94069910bba..feee6511b00c0 100644 --- a/test/SILOptimizer/noimplicitcopy.swift +++ b/test/SILOptimizer/noimplicitcopy.swift @@ -2001,8 +2001,9 @@ public func closureCaptureClassUseAfterConsumeError(_ x: Klass) { let _ = x3 } -public func closureCaptureClassArgUseAfterConsume(@_noImplicitCopy _ x2: Klass) { // expected-error {{'x2' is borrowed and cannot be consumed}} - let f = { // expected-note {{consumed here}} +public func closureCaptureClassArgUseAfterConsume(@_noImplicitCopy _ x2: Klass) { + // expected-error @-1 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} + let f = { // expected-note {{closure capturing 'x2' here}} classUseMoveOnlyWithoutEscaping(x2) classConsume(x2) print(x2) @@ -2121,8 +2122,9 @@ public func closureAndDeferCaptureClassUseAfterConsume3(_ x: Klass) { classConsume(x2) // expected-note {{consumed again here}} } -public func closureAndDeferCaptureClassArgUseAfterConsume(@_noImplicitCopy _ x2: Klass) { // expected-error {{'x2' is borrowed and cannot be consumed}} - let f = { // expected-note {{consumed here}} +public func closureAndDeferCaptureClassArgUseAfterConsume(@_noImplicitCopy _ x2: Klass) { + // expected-error @-1 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} + let f = { // expected-note {{closure capturing 'x2' here}} defer { classUseMoveOnlyWithoutEscaping(x2) classConsume(x2) @@ -2186,8 +2188,9 @@ public func closureAndClosureCaptureClassUseAfterConsume2(_ x: Klass) { } -public func closureAndClosureCaptureClassArgUseAfterConsume(@_noImplicitCopy _ x2: Klass) { // expected-error {{'x2' is borrowed and cannot be consumed}} - let f = { // expected-note {{consumed here}} +public func closureAndClosureCaptureClassArgUseAfterConsume(@_noImplicitCopy _ x2: Klass) { + // expected-error @-1 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} + let f = { // expected-note {{closure capturing 'x2' here}} let g = { classUseMoveOnlyWithoutEscaping(x2) classConsume(x2) diff --git a/test/SILOptimizer/noimplicitcopy_borrowing_parameters.swift b/test/SILOptimizer/noimplicitcopy_borrowing_parameters.swift new file mode 100644 index 0000000000000..712f620f162fb --- /dev/null +++ b/test/SILOptimizer/noimplicitcopy_borrowing_parameters.swift @@ -0,0 +1,574 @@ +// RUN: %target-swift-frontend -emit-sil %s -verify -sil-verify-all + +//////////////////////// +// MARK: Declarations // +//////////////////////// + +public class Klass {} + +public struct NonTrivialStruct { + var k = Klass() + + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + mutating func doSomethingMutating() {} +} + +public protocol P { + static var value: Self { get } +} + +public struct GenericNonTrivialStruct { + var t = T.value + + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + mutating func doSomethingMutating() {} +} + +public struct TrivialStruct { + var k: Int + + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + mutating func doSomethingMutating() {} +} + +enum LoadableEnum { + case x(NonTrivialStruct) + case y(Int) +} + +enum TrivialEnum { + case x(Int64) + case y(Int) +} + +enum AddressOnlyEnum { + case x(NonTrivialStruct) + case y(T) +} + +func borrowValDefault(_ x: NonTrivialStruct) {} +func borrowValBorrowing(_ x: borrowing NonTrivialStruct) {} +func borrowValDefault(_ x: TrivialStruct) {} +func borrowValBorrowing(_ x: borrowing TrivialStruct) {} +func borrowValDefault(_ x: GenericNonTrivialStruct) {} +func borrowValBorrowing(_ x: borrowing GenericNonTrivialStruct) {} +func consumeVal(_ x: consuming NonTrivialStruct) {} +func consumeVal(_ x: consuming GenericNonTrivialStruct) {} + +/////////////////////////////////////////// +// MARK: Simple Loadable Borrowing Tests // +/////////////////////////////////////////// + +func testLoadableBorrowingConsume(_ x: borrowing NonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + let _ = x // expected-note {{consumed here}} + let _ = x.k +} + +func testLoadableBorrowingConsume2(_ x: borrowing NonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + var y = x // expected-note {{consumed here}} + y = x // expected-note {{consumed here}} + _ = y +} + +func testLoadableBorrowingConsume3(_ x: borrowing NonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + let y = x // expected-note {{consumed here}} + _ = y +} + +func testLoadableBorrowingUse(_ x: borrowing NonTrivialStruct) { + _ = x +} + +func testLoadableBorrowingUseAndConsume(_ x: borrowing NonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + _ = x + let _ = x // expected-note {{consumed here}} +} + +func testLoadableBorrowingCallBorrowValDefault(_ x: borrowing NonTrivialStruct) { + borrowValDefault(x) +} + +func testLoadableBorrowingCallBorrowValBorrowing(_ x: borrowing NonTrivialStruct) { + borrowValBorrowing(x) +} + +func testLoadableBorrowingCallMethodSelfDefault(_ x: borrowing NonTrivialStruct) { + x.doSomethingDefault() +} + +func testLoadableBorrowingCallMethodSelfBorrowing(_ x: borrowing NonTrivialStruct) { + x.doSomethingBorrowing() +} + +func testLoadableBorrowingEscapingClosure(_ x: borrowing NonTrivialStruct) { + // expected-error @-1 {{'x' cannot be captured by an escaping closure since it is a borrowed parameter}} + var f: () -> () = {} + f = { // expected-note {{closure capturing 'x' here}} + _ = x + } + _ = f +} + +func testLoadableBorrowingNonEscapingClosure(_ x: borrowing NonTrivialStruct) { + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { + _ = x + } +} + +func testLoadableBorrowingConsumeOperator(_ x: borrowing NonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + _ = consume x // expected-note {{consumed here}} +} + +func testLoadableBorrowingEnum(_ x: borrowing LoadableEnum) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + switch x { // expected-note {{consumed here}} + case let .x(y): + _ = y + break + case .y: + break + } +} + +func testLoadableBorrowingCopyOperator(_ x: borrowing NonTrivialStruct) { + _ = copy x + let _ = copy x + consumeVal(copy x) +} + +////////////////////////////////////////// +// MARK: Trivial Struct Borrowing Tests // +////////////////////////////////////////// + +func testTrivialBorrowingConsume(_ x: borrowing TrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + let _ = x // expected-note {{consumed here}} + let _ = x.k +} + +func testTrivialBorrowingConsume2(_ x: borrowing TrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + var y = x // expected-note {{consumed here}} + y = x // expected-note {{consumed here}} + _ = y +} + +func testTrivialBorrowingConsume3(_ x: borrowing TrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + let y = x // expected-note {{consumed here}} + _ = y +} + +func testTrivialBorrowingUse(_ x: borrowing TrivialStruct) { + _ = x +} + +func testTrivialBorrowingUseAndConsume(_ x: borrowing TrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + _ = x + let _ = x // expected-note {{consumed here}} +} + +func testTrivialBorrowingCallBorrowValDefault(_ x: borrowing TrivialStruct) { + borrowValDefault(x) +} + +func testTrivialBorrowingCallBorrowValBorrowing(_ x: borrowing TrivialStruct) { + borrowValBorrowing(x) +} + +func testTrivialBorrowingCallMethodSelfDefault(_ x: borrowing TrivialStruct) { + x.doSomethingDefault() +} + +func testTrivialBorrowingCallMethodSelfBorrowing(_ x: borrowing TrivialStruct) { + x.doSomethingBorrowing() +} + +func testTrivialBorrowingEscapingClosure(_ x: borrowing TrivialStruct) { + // expected-error @-1 {{'x' cannot be captured by an escaping closure since it is a borrowed parameter}} + var f: () -> () = {} + f = { // expected-note {{closure capturing 'x' here}} + _ = x + } + _ = f +} + +func testTrivialBorrowingNonEscapingClosure(_ x: borrowing TrivialStruct) { + // expected-error @-1 {{'x' cannot be captured by an escaping closure since it is a borrowed parameter}} + // TODO: Wrong + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { // expected-note {{closure capturing 'x' here}} + _ = x + } +} + +func testTrivialBorrowingConsumeOperator(_ x: borrowing TrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + _ = consume x // expected-note {{consumed here}} +} + +func testTrivialBorrowingEnum(_ x: borrowing TrivialEnum) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + switch x { // expected-note {{consumed here}} + case let .x(y): + _ = y + break + case .y: + break + } +} + +func testTrivialBorrowingCopyOperator(_ x: borrowing TrivialStruct) { + _ = copy x + let _ = copy x +} + +////////////////////////////////////////////// +// MARK: Simple AddressOnly Borrowing Tests // +////////////////////////////////////////////// + +func testAddressOnlyBorrowSimple(_ x: borrowing T) {} + +func testAddressOnlyBorrowingConsume(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + let _ = x // expected-note {{consumed here}} + let _ = x.t +} + +func testAddressOnlyBorrowingConsume2(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + // expected-error @-2 {{'x' is borrowed and cannot be consumed}} + var y = x // expected-note {{consumed here}} + y = x // expected-note {{consumed here}} + _ = y +} + +func testAddressOnlyBorrowingConsume3(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + let y = x // expected-note {{consumed here}} + _ = y +} + +func testAddressOnlyBorrowingUse(_ x: borrowing GenericNonTrivialStruct) { + _ = x +} + +func testAddressOnlyBorrowingUseAndConsume(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + borrowValDefault(x) + let _ = x // expected-note {{consumed here}} +} + +func testAddressOnlyBorrowingCallBorrowValDefault(_ x: borrowing GenericNonTrivialStruct) { + borrowValDefault(x) +} + +func testAddressOnlyBorrowingCallBorrowValBorrowing(_ x: borrowing GenericNonTrivialStruct) { + borrowValBorrowing(x) +} + +func testAddressOnlyBorrowingCallMethodSelfDefault(_ x: borrowing GenericNonTrivialStruct) { + x.doSomethingDefault() +} + +func testAddressOnlyBorrowingCallMethodSelfBorrowing(_ x: borrowing GenericNonTrivialStruct) { + x.doSomethingBorrowing() +} + +func testAddressOnlyBorrowingEscapingClosure(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + var f: () -> () = {} + f = { // expected-note {{consumed here}} + _ = x + } + _ = f +} + +func testAddressOnlyBorrowingNonEscapingClosure(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { // expected-note {{consumed here}} + _ = x + } +} + +func testAddressOnlyBorrowingCast(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + let _ = x as Any // expected-note {{consumed here}} +} + +func testAddressOnlyBorrowingCastCheck(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + if x is Any { // expected-note {{consumed here}} + // expected-warning @-1 {{'is' test is always true}} + + } +} + +func testAddressOnlyBorrowingEnum(_ x: borrowing AddressOnlyEnum) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + switch x { // expected-note {{consumed here}} + case let .x(y): + _ = y + break + case let .y(z): + _ = z + break + } +} + +func testAddressOnlyConsumeOperator(_ x: borrowing GenericNonTrivialStruct) { + // expected-error @-1 {{'x' is borrowed and cannot be consumed}} + _ = consume x // expected-note {{consumed here}} +} + +func testAddressOnlyCopyOperator(_ x: borrowing GenericNonTrivialStruct) { + _ = copy x + let _ = copy x + consumeVal(copy x) +} + + +/////////////////////////////// +// MARK: Loadable Self Tests // +/////////////////////////////// + +struct LoadableSelfTest { + var k = Klass() + + consuming func consumeSelf() {} + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + + borrowing func testUseSelf() { + _ = self + } + + borrowing func testLetUseSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + let _ = self // expected-note {{consumed here}} + } + + borrowing func callDoSomethingDefault() { + self.doSomethingDefault() + } + + borrowing func callDoSomethingBorrowing() { + self.doSomethingBorrowing() + } + + borrowing func testConsumeOperatorSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + _ = consume self // expected-note {{consumed here}} + } + + borrowing func testCopyOperatorSelf() { + _ = copy self + let _ = copy self + (copy self).consumeSelf() + } + + borrowing func testUseField() { + _ = self.k + } + + borrowing func testConsumeField() { + // No error, since our field is copyable. + let _ = self.k + } + + borrowing func testCallConsumeMethod() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + consumeSelf() // expected-note {{consumed here}} + } + + borrowing func testCallFreeFunctionConsumeSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + consumeLoadableSelfTest(self) // expected-note {{consumed here}} + } + + borrowing func testCallEscapingClosure() { + // expected-error @-1 {{'self' cannot be captured by an escaping closure since it is a borrowed parameter}} + var f: () -> () = {} + f = { // expected-note {{closure capturing 'self' here}} + let _ = self + } + f() + } + + borrowing func testCallNonEscapingClosure() { + func f(_ x: () -> ()) {} + f { + _ = self + } + } +} + +func consumeLoadableSelfTest(_ x: consuming LoadableSelfTest) {} + +/////////////////////////////////// +// MARK: Address Only Self Tests // +/////////////////////////////////// + +struct AddressOnlySelfTest { + var t: T + + consuming func consumeSelf() {} + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + + borrowing func testUseSelf() { + _ = self + } + + borrowing func testLetUseSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + let _ = self // expected-note {{consumed here}} + } + + borrowing func callDoSomethingDefault() { + self.doSomethingDefault() + } + + borrowing func callDoSomethingBorrowing() { + self.doSomethingBorrowing() + } + + borrowing func testConsumeOperatorSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + _ = consume self // expected-note {{consumed here}} + } + + borrowing func testCopyOperatorSelf() { + _ = copy self + let _ = copy self + (copy self).consumeSelf() + } + + borrowing func testUseField() { + _ = self.t + } + + borrowing func testConsumeField() { + // No error, since our field is copyable. + let _ = self.t + } + + borrowing func testCallConsumeMethod() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + consumeSelf() // expected-note {{consumed here}} + } + + borrowing func testCallFreeFunctionConsumeSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + consumeAddressOnlySelfTest(self) // expected-note {{consumed here}} + } + + borrowing func testCallEscapingClosure() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + // TODO: Capture. + var f: () -> () = {} + f = { // expected-note {{consumed here}} + let _ = self + } + f() + } + + borrowing func testCallNonEscapingClosure() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + // TODO: fix + func f(_ x: () -> ()) {} + f { // expected-note {{consumed here}} + _ = self + } + } +} + +func consumeAddressOnlySelfTest(_ x: consuming AddressOnlySelfTest) {} + +////////////////////////////// +// MARK: Trivial Self Tests // +////////////////////////////// + +struct TrivialSelfTest { + var t: Int + + consuming func consumeSelf() {} + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + + borrowing func testUseSelf() { + _ = self + } + + borrowing func testLetUseSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + let _ = self // expected-note {{consumed here}} + } + + borrowing func callDoSomethingDefault() { + self.doSomethingDefault() + } + + borrowing func callDoSomethingBorrowing() { + self.doSomethingBorrowing() + } + + borrowing func testConsumeOperatorSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + _ = consume self // expected-note {{consumed here}} + } + + borrowing func testCopyOperatorSelf() { + _ = copy self + } + + borrowing func testUseField() { + _ = self.t + } + + borrowing func testConsumeField() { + // No error, since our field is copyable. + let _ = self.t + } + + borrowing func testCallConsumeMethod() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + consumeSelf() // expected-note {{consumed here}} + } + + borrowing func testCallFreeFunctionConsumeSelf() { + // expected-error @-1 {{'self' is borrowed and cannot be consumed}} + consumeTrivialSelfTest(self) // expected-note {{consumed here}} + } + + borrowing func testCallEscapingClosure() { + // expected-error @-1 {{'self' cannot be captured by an escaping closure since it is a borrowed parameter}} + var f: () -> () = {} + f = { // expected-note {{closure capturing 'self' here}} + let _ = self + } + f() + } + + borrowing func testCallNonEscapingClosure() { + // expected-error @-1 {{'self' cannot be captured by an escaping closure since it is a borrowed parameter}} + // TODO: Error + func f(_ x: () -> ()) {} + f { // expected-note {{closure capturing 'self' here}} + _ = self + } + } +} + +func consumeTrivialSelfTest(_ x: consuming TrivialSelfTest) {} diff --git a/test/SILOptimizer/noimplicitcopy_consuming_parameters.swift b/test/SILOptimizer/noimplicitcopy_consuming_parameters.swift new file mode 100644 index 0000000000000..e9a3f21e340db --- /dev/null +++ b/test/SILOptimizer/noimplicitcopy_consuming_parameters.swift @@ -0,0 +1,993 @@ +// RUN: %target-swift-frontend -emit-sil %s -verify -sil-verify-all + +//////////////////////// +// MARK: Declarations // +//////////////////////// + +public class Klass { +} + +public struct NonTrivialStruct { + var k = Klass() + + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + consuming func doSomethingConsuming() {} + mutating func doSomethingMutating() {} +} + +public protocol P { + static var value: Self { get } +} + +public struct GenericNonTrivialStruct { + var t = T.value + + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + consuming func doSomethingConsuming() {} + mutating func doSomethingMutating() {} +} + +public struct TrivialStruct { + var k: Int = 5 + + func doSomethingDefault() {} + consuming func doSomethingConsuming() {} + borrowing func doSomethingBorrowing() {} + mutating func doSomethingMutating() {} +} + +enum LoadableEnum { + case x(NonTrivialStruct) + case y(Int) +} + +enum TrivialEnum { + case x(Int64) + case y(Int) +} + +enum AddressOnlyEnum { + case x(NonTrivialStruct) + case y(T) +} + +func borrowValDefault(_ x: NonTrivialStruct) {} +func borrowValBorrowing(_ x: borrowing NonTrivialStruct) {} +func consumeVal(_ x: consuming NonTrivialStruct) {} +func borrowValDefault(_ x: TrivialStruct) {} +func borrowValBorrowing(_ x: borrowing TrivialStruct) {} +func consumeVal(_ x: consuming TrivialStruct) {} +func borrowValDefault(_ x: GenericNonTrivialStruct) {} +func borrowValBorrowing(_ x: borrowing GenericNonTrivialStruct) {} +func consumeVal(_ x: consuming GenericNonTrivialStruct) {} + +/////////////////////////////////////////// +// MARK: Simple Loadable Borrowing Tests // +/////////////////////////////////////////// + +func testLoadableConsumingConsume(_ x: consuming NonTrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + let _ = x.k // expected-note {{used here}} +} + +func testLoadableConsumingConsume1a(_ x: consuming NonTrivialStruct) { + let _ = x + x = NonTrivialStruct() + let _ = x.k +} + +func testLoadableConsumingConsume2(_ x: consuming NonTrivialStruct) { + // expected-error @-1 {{'x' consumed more than once}} + var y = x // expected-note {{consumed here}} + y = x // expected-note {{consumed again here}} + _ = y +} + +func testLoadableConsumingConsume3(_ x: consuming NonTrivialStruct) { + let y = x + _ = y +} + +func testLoadableConsumingUse(_ x: consuming NonTrivialStruct) { + _ = x +} + +func testLoadableConsumingUseAndConsume(_ x: consuming NonTrivialStruct) { + borrowValBorrowing(x) + let _ = x +} + +func testLoadableConsumingConsumeAndUse(_ x: consuming NonTrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + borrowValBorrowing(x) // expected-note {{used here}} +} + +func testLoadableConsumingConsumeAndUseReinit(_ x: consuming NonTrivialStruct) { + let _ = x + x = NonTrivialStruct() + borrowValBorrowing(x) +} + +func testLoadableConsumingCallBorrowValDefault(_ x: consuming NonTrivialStruct) { + borrowValDefault(x) +} + +func testLoadableConsumingCallBorrowValBorrowing(_ x: consuming NonTrivialStruct) { + borrowValBorrowing(x) +} + +func testLoadableConsumingCallConsumeVal(_ x: consuming NonTrivialStruct) { + consumeVal(x) +} + +func testLoadableConsumingCallConsumeValMultiple(_ x: consuming NonTrivialStruct) { + // expected-error @-1 {{'x' consumed more than once}} + consumeVal(x) // expected-note {{consumed here}} + consumeVal(x) // expected-note {{consumed again here}} +} + +func testLoadableConsumingCallMethodSelfDefault(_ x: consuming NonTrivialStruct) { + x.doSomethingDefault() +} + +func testLoadableConsumingCallMethodSelfConsuming(_ x: consuming NonTrivialStruct) { + x.doSomethingConsuming() +} + +func testLoadableConsumingCallMethodSelfMutating(_ x: consuming NonTrivialStruct) { + x.doSomethingMutating() +} + +func testLoadableConsumingEscapingClosure(_ x: consuming NonTrivialStruct) { + var f: () -> () = {} + f = { + _ = x + } + _ = f +} + +func testLoadableConsumingEscapingClosure2(_ x: consuming NonTrivialStruct) { + _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + var f: () -> () = {} + f = { + _ = x + } + _ = f +} + +func testLoadableConsumingEscapingClosure3(_ x: consuming NonTrivialStruct) { + var f: () -> () = {} + f = { + _ = x + } + _ = f + _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} +} + +func testLoadableConsumingNonEscapingClosure(_ x: consuming NonTrivialStruct) { + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { + _ = x + } +} + +func testLoadableConsumingNonEscapingClosure2(_ x: consuming NonTrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { // expected-note {{used here}} + _ = x + } +} + +func testLoadableConsumingConsumeOperator(_ x: consuming NonTrivialStruct) { + _ = consume x +} + +func testLoadableConsumingConsumeOperator1(_ x: consuming NonTrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + _ = consume x // expected-note {{consumed here}} + borrowValDefault(x) // expected-note {{used here}} +} + +func testLoadableConsumingConsumeOperator2(_ x: consuming NonTrivialStruct) { + x = consume x +} + +func testLoadableConsumingConsumeOperator3(_ x: consuming NonTrivialStruct) { + _ = consume x + let y = NonTrivialStruct() + x = consume y +} + +func testLoadableConsumingEnum(_ x: consuming LoadableEnum) { + switch x { + case let .x(y): + _ = y + break + case .y: + break + } +} + +func testLoadableConsumingEnum2(_ x: consuming LoadableEnum) { + // expected-error @-1 {{'x' consumed more than once}} + switch x { // expected-note {{consumed here}} + case let .x(y): + _ = consume x // expected-note {{consumed again here}} + _ = y + break + case .y: + break + } +} + +func testLoadableConsumingCopyOperator(_ x: consuming NonTrivialStruct) { + _ = copy x +} + +////////////////////////////////////////// +// MARK: Trivial Struct Consuming Tests // +////////////////////////////////////////// + +func testTrivialConsumingConsume(_ x: consuming TrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + let _ = x.k // expected-note {{used here}} +} + +func testTrivialConsumingConsume2(_ x: consuming TrivialStruct) { + // expected-error @-1 {{'x' consumed more than once}} + var y = x // expected-note {{consumed here}} + y = x // expected-note {{consumed again here}} + _ = y +} + +func testTrivialConsumingConsume3(_ x: consuming TrivialStruct) { + let y = x + _ = y +} + +func testTrivialConsumingUse(_ x: consuming TrivialStruct) { + _ = x +} + +func testTrivialConsumingUseAndConsume(_ x: consuming TrivialStruct) { + borrowValBorrowing(x) + let _ = x +} + +func testTrivialConsumingConsumeAndUse(_ x: consuming TrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + borrowValBorrowing(x) // expected-note {{used here}} +} + +func testTrivialConsumingConsumeAndUseReinit(_ x: consuming TrivialStruct) { + let _ = x + x = TrivialStruct() + borrowValBorrowing(x) +} + +func testTrivialConsumingCallBorrowValDefault(_ x: consuming TrivialStruct) { + borrowValDefault(x) +} + +func testTrivialConsumingCallBorrowValBorrowing(_ x: consuming TrivialStruct) { + borrowValBorrowing(x) +} + +func testTrivialConsumingCallConsumeVal(_ x: consuming TrivialStruct) { + consumeVal(x) +} + +func testTrivialConsumingCallMethodSelfDefault(_ x: consuming TrivialStruct) { + x.doSomethingDefault() +} + +func testTrivialConsumingCallMethodSelfConsuming(_ x: consuming TrivialStruct) { + x.doSomethingConsuming() +} + +func testTrivialConsumingEscapingClosure(_ x: consuming TrivialStruct) { + var f: () -> () = {} + f = { + _ = x + } + _ = f +} + +func testTrivialConsumingEscapingClosure2(_ x: consuming TrivialStruct) { + let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + var f: () -> () = {} + f = { + _ = x + } + _ = f +} + +func testTrivialConsumingEscapingClosure3(_ x: consuming TrivialStruct) { + var f: () -> () = {} + f = { + _ = x + } + _ = f + let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} +} + +func testTrivialConsumingNonEscapingClosure(_ x: consuming TrivialStruct) { + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { + _ = x + } +} + +func testTrivialConsumingNonEscapingClosure2(_ x: consuming TrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { // expected-note {{used here}} + _ = x + } +} + +func testTrivialConsumingConsumeOperator(_ x: consuming TrivialStruct) { + _ = consume x +} + +func testTrivialConsumingEnum(_ x: consuming TrivialEnum) { + switch x { + case let .x(y): + _ = y + break + case .y: + break + } +} + +func testTrivialConsumingEnum2(_ x: consuming TrivialEnum) { + // expected-error @-1 {{'x' used after consume}} + switch x { // expected-note {{consumed here}} + case let .x(y): + _ = y + break + case .y: + _ = copy x // expected-note {{used here}} + break + } +} + + +func testTrivialConsumingCopyOperator(_ x: consuming TrivialStruct) { + _ = copy x +} + +////////////////////////////////////////////// +// MARK: Simple AddressOnly Consuming Tests // +////////////////////////////////////////////// + +func testAddressOnlyBorrowSimple(_ x: borrowing T) {} + +func testAddressOnlyConsumingConsume(_ x: consuming GenericNonTrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + let _ = x.t // expected-note {{used here}} +} + +func testAddressOnlyConsumingConsume2(_ x: consuming GenericNonTrivialStruct) { + // expected-error @-1 {{'x' consumed more than once}} + var y = x // expected-note {{consumed here}} + y = x // expected-note {{consumed again here}} + _ = y +} + +func testAddressOnlyConsumingConsume3(_ x: consuming GenericNonTrivialStruct) { + let y = x + _ = y +} + +func testAddressOnlyConsumingUse(_ x: consuming GenericNonTrivialStruct) { + _ = x +} + +func testAddressOnlyConsumingUseAndConsume(_ x: consuming GenericNonTrivialStruct) { + borrowValDefault(x) + let _ = x +} + +func testAddressOnlyConsumingConsumeAndUse(_ x: consuming GenericNonTrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + borrowValDefault(x) // expected-note {{used here}} +} + +func testAddressOnlyConsumingConsumeAndUseReinit(_ x: consuming GenericNonTrivialStruct) { + let _ = x + x = GenericNonTrivialStruct() + borrowValDefault(x) +} + +func testAddressOnlyConsumingCallBorrowValDefault(_ x: consuming GenericNonTrivialStruct) { + borrowValDefault(x) +} + +func testAddressOnlyConsumingCallBorrowValBorrowing(_ x: consuming GenericNonTrivialStruct) { + borrowValBorrowing(x) +} + +func testAddressOnlyConsumingCallConsumeVal(_ x: consuming GenericNonTrivialStruct) { + consumeVal(x) +} + +func testAddressOnlyConsumingCallMethodSelfDefault(_ x: consuming GenericNonTrivialStruct) { + x.doSomethingDefault() +} + +func testAddressOnlyConsumingCallMethodSelfConsuming(_ x: consuming GenericNonTrivialStruct) { + x.doSomethingConsuming() +} + +func testAddressOnlyConsumingEscapingClosure(_ x: consuming GenericNonTrivialStruct) { + var f: () -> () = {} + f = { + _ = x + } + _ = f +} + +func testAddressOnlyConsumingEscapingClosure2(_ x: consuming GenericNonTrivialStruct) { + let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + var f: () -> () = {} + f = { + _ = x + } + _ = f +} + +func testAddressOnlyConsumingEscapingClosure3(_ x: consuming GenericNonTrivialStruct) { + var f: () -> () = {} + f = { + _ = x + } + _ = f + let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} +} + +func testAddressOnlyConsumingNonEscapingClosure(_ x: consuming GenericNonTrivialStruct) { + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { + _ = x + } +} + +func testAddressOnlyConsumingNonEscapingClosure2(_ x: consuming GenericNonTrivialStruct) { + // expected-error @-1 {{'x' used after consume}} + let _ = x // expected-note {{consumed here}} + func useNonEscaping(_ f: () -> ()) {} + useNonEscaping { // expected-note {{used here}} + _ = x + } +} + +func testAddressOnlyConsumingCast(_ x: consuming GenericNonTrivialStruct) { + let _ = x as Any +} + +func testAddressOnlyConsumingCast2(_ x: consuming GenericNonTrivialStruct) { + // expected-error @-1 {{'x' consumed more than once}} + let _ = x as Any // expected-note {{consumed here}} + let _ = x as Any // expected-note {{consumed again here}} +} + +func testAddressOnlyConsumingCastCheck(_ x: consuming GenericNonTrivialStruct) { + if x is Any { // expected-warning {{'is' test is always true}} + } +} + +func testAddressOnlyConsumingCastCheck2(_ x: consuming GenericNonTrivialStruct) { + // expected-error @-1 {{'x' consumed more than once}} + if x is Any { // expected-note {{consumed here}} + // expected-warning @-1 {{'is' test is always true}} + + } + if x is Any { // expected-note {{consumed again here}} + // expected-warning @-1 {{'is' test is always true}} + } +} + +func testAddressOnlyConsumingEnum(_ x: consuming AddressOnlyEnum) { + switch x { + case let .x(y): + _ = y + break + case let .y(z): + _ = z + break + } +} + +func testAddressOnlyConsumingEnum2(_ x: consuming AddressOnlyEnum) { + // expected-error @-1 {{'x' used after consume}} + switch x { // expected-note {{consumed here}} + case let .x(y): + _ = y + break + case let .y(z): + _ = z + break + } + _ = copy x // expected-note {{used here}} +} + +func testAddressOnlyConsumeOperator(_ x: consuming GenericNonTrivialStruct) { + _ = consume x +} + +func testAddressOnlyCopyOperator(_ x: consuming GenericNonTrivialStruct) { + _ = copy x +} + +/////////////////////////////// +// MARK: Loadable Self Tests // +/////////////////////////////// + +struct LoadableSelfTest { + var k = Klass() + + consuming func consumeSelf() {} + func doSomethingDefault() {} + consuming func doSomethingConsuming() {} + borrowing func doSomethingBorrowing() {} + mutating func doSomethingMutating() {} + + consuming func testUseSelf() { + _ = self + } + + consuming func testUseSelf2() { + self.doSomethingDefault() + self.doSomethingDefault() + } + + consuming func testUseSelf3() { + self.doSomethingBorrowing() + self.doSomethingDefault() + } + + consuming func testUseSelf4() { + self.doSomethingBorrowing() + self.doSomethingBorrowing() + } + + consuming func testLetUseSelf() { + let _ = self + } + + consuming func callDoSomethingDefault() { + self.doSomethingDefault() + } + + consuming func callDoSomethingBorrowing() { + self.doSomethingBorrowing() + } + + consuming func callDoSomethingConsuming() { + self.doSomethingConsuming() + } + + consuming func callDoSomethingMutating() { + self.doSomethingMutating() + } + + consuming func callDoSomethingMutating2() { + self.doSomethingMutating() + _ = consume self + } + + consuming func callDoSomethingMutating3() { + // expected-error @-1 {{'self' used after consume}} + _ = consume self // expected-note {{consumed here}} + self.doSomethingMutating() // expected-note {{used here}} + } + + consuming func testConsumeOperatorSelf() { + _ = consume self + } + + consuming func testConsumeOperatorSelf2() { + // expected-error @-1 {{'self' consumed more than once}} + _ = consume self // expected-note {{consumed here}} + _ = consume self // expected-note {{consumed again here}} + } + + consuming func testCopyOperatorSelf() { + _ = copy self + } + + consuming func testUseField() { + _ = self.k + } + + consuming func testConsumeField() { + // No error, since our field is copyable. + let _ = self.k + } + + consuming func testCallConsumeMethod() { + consumeSelf() + } + + consuming func testCallConsumeMethod2() { + // expected-error @-1 {{'self' consumed more than once}} + consumeSelf() // expected-note {{consumed here}} + consumeSelf() // expected-note {{consumed again here}} + } + + consuming func testCallFreeFunctionConsumeSelf() { + consumeLoadableSelfTest(self) + } + + consuming func testCallFreeFunctionConsumeSelf2() { + // expected-error @-1 {{'self' consumed more than once}} + consumeLoadableSelfTest(self) // expected-note {{consumed here}} + consumeSelf() // expected-note {{consumed again here}} + } + + consuming func testCallEscapingClosure() { + var f: () -> () = {} + f = { + let _ = self + } + f() + } + + consuming func testCallEscapingClosure2() { + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + var f: () -> () = {} + f = { + let _ = self + } + f() + } + + consuming func testCallEscapingClosure3() { + var f: () -> () = {} + f = { + let _ = self + } + f() + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + } + + consuming func testCallNonEscapingClosure() { + func f(_ x: () -> ()) {} + f { + _ = self + } + } + + consuming func testCallNonEscapingClosure2() { + // expected-error @-1 {{'self' used after consume}} + let _ = self // expected-note {{consumed here}} + func f(_ x: () -> ()) {} + f { // expected-note {{used here}} + _ = self + } + } + + consuming func testCallNonEscapingClosure3() { + let _ = self + self = LoadableSelfTest() + func f(_ x: () -> ()) {} + f { + _ = self + } + } +} + +func consumeLoadableSelfTest(_ x: consuming LoadableSelfTest) {} + +/////////////////////////////////// +// MARK: Address Only Self Tests // +/////////////////////////////////// + +struct AddressOnlySelfTest { + var t: T + + consuming func consumeSelf() {} + func doSomethingDefault() {} + consuming func doSomethingConsuming() {} + mutating func doSomethingMutating() {} + borrowing func doSomethingBorrowing() {} + + consuming func testUseSelf() { + // expected-error @-1 {{'self' consumed more than once}} + _ = self // expected-note {{consumed here}} + _ = self // expected-note {{consumed again here}} + } + + consuming func testUseSelf2() { + self.doSomethingDefault() + self.doSomethingDefault() + } + + consuming func testUseSelf3() { + self.doSomethingBorrowing() + self.doSomethingDefault() + } + + consuming func testUseSelf4() { + self.doSomethingDefault() + self.doSomethingBorrowing() + } + + consuming func testLetUseSelf() { + // expected-error @-1 {{'self' consumed more than once}} + let _ = self // expected-note {{consumed here}} + let _ = self // expected-note {{consumed again here}} + } + + consuming func callDoSomethingDefault() { + self.doSomethingDefault() + self.doSomethingBorrowing() + } + + consuming func callDoSomethingConsuming() { + self.doSomethingConsuming() + } + + consuming func callDoSomethingConsuming2() { + // expected-error @-1 {{'self' used after consume}} + self.doSomethingConsuming() // expected-note {{consumed here}} + self.doSomethingDefault() // expected-note {{used here}} + } + + consuming func callDoSomethingConsuming3() { + // expected-error @-1 {{'self' used after consume}} + self.doSomethingConsuming() // expected-note {{consumed here}} + self.doSomethingDefault() // expected-note {{used here}} + } + + consuming func callDoSomethingConsuming4() { + // expected-error @-1 {{'self' used after consume}} + self.doSomethingConsuming() // expected-note {{consumed here}} + self.doSomethingMutating() // expected-note {{used here}} + } + + consuming func callDoSomethingConsuming4(_ x: AddressOnlySelfTest) { + self.doSomethingConsuming() + self = x + self.doSomethingDefault() + } + + consuming func testConsumeOperatorSelf() { + _ = consume self + } + + consuming func testCopyOperatorSelf() { + _ = copy self + } + + consuming func testUseField() { + _ = self.t + } + + consuming func testConsumeField() { + // No error, since our field is copyable. + let _ = self.t + } + + consuming func testCallConsumeMethod() { + consumeSelf() + } + + consuming func testCallFreeFunctionConsumeSelf() { + consumeAddressOnlySelfTest(self) + } + + consuming func testCallFreeFunctionConsumeSelf2() { + // expected-error @-1 {{'self' consumed more than once}} + consumeAddressOnlySelfTest(self) // expected-note {{consumed here}} + consumeSelf() // expected-note {{consumed again here}} + } + + consuming func testCallEscapingClosure() { + var f: () -> () = {} + f = { + let _ = self + } + f() + } + + consuming func testCallEscapingClosure2() { + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + var f: () -> () = {} + f = { + let _ = self + } + f() + } + + consuming func testCallEscapingClosure3() { + var f: () -> () = {} + f = { + let _ = self + } + f() + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + } + + consuming func testCallEscapingClosure4() { + var f: () -> () = {} + f = { + let _ = self + } + f() + f = { + let _ = self + } + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + } + + consuming func testCallNonEscapingClosure() { + func f(_ x: () -> ()) {} + f { + _ = self + } + } + + consuming func testCallNonEscapingClosure2() { + // expected-error @-1 {{'self' used after consume}} + let _ = self // expected-note {{consumed here}} + func f(_ x: () -> ()) {} + f { // expected-note {{used here}} + _ = self + } + f { + _ = self + } + } +} + +func consumeAddressOnlySelfTest(_ x: consuming AddressOnlySelfTest) {} + +////////////////////////////// +// MARK: Trivial Self Tests // +////////////////////////////// + +struct TrivialSelfTest { + var t = 5 + + consuming func consumeSelf() {} + func doSomethingDefault() {} + borrowing func doSomethingBorrowing() {} + consuming func doSomethingConsuming() {} + mutating func doSomethingMutating() {} + + consuming func testUseSelf() { + _ = self + } + + consuming func testUseSelf2() { + // expected-error @-1 {{'self' consumed more than once}} + _ = self // expected-note {{consumed here}} + _ = self // expected-note {{consumed again here}} + } + + consuming func testUseSelf3() { + // expected-error @-1 {{'self' consumed more than once}} + // + // TODO: This is why we need to change SILFunctionType to contain + // information about default conventions. + self.doSomethingDefault() // expected-note {{consumed here}} + self.doSomethingDefault() // expected-note {{consumed again here}} + } + + consuming func testUseSelf4() { + // expected-error @-1 {{'self' used after consume}} + self.doSomethingDefault() // expected-note {{consumed here}} + self.doSomethingBorrowing() // expected-note {{used here}} + } + + consuming func testUseSelf5() { + self.doSomethingBorrowing() + self.doSomethingBorrowing() + } + + consuming func testLetUseSelf() { + let _ = self + } + + consuming func callDoSomethingDefault() { + self.doSomethingDefault() + } + + consuming func callDoSomethingConsuming() { + self.doSomethingConsuming() + } + + consuming func testConsumeOperatorSelf() { + _ = consume self + } + + consuming func testConsumeOperatorSelf2() { + // expected-error @-1 {{'self' consumed more than once}} + _ = consume self // expected-note {{consumed here}} + _ = consume self // expected-note {{consumed again here}} + } + + consuming func testCopyOperatorSelf() { + _ = copy self + } + + consuming func testUseField() { + _ = self.t + } + + consuming func testConsumeField() { + // No error, since our field is copyable. + let _ = self.t + } + + consuming func testCallConsumeMethod() { + consumeSelf() + } + + consuming func testCallFreeFunctionConsumeSelf() { + consumeTrivialSelfTest(self) + } + + consuming func testCallFreeFunctionConsumeSelf2() { + // expected-error @-1 {{'self' consumed more than once}} + consumeTrivialSelfTest(self) // expected-note {{consumed here}} + consumeSelf() // expected-note {{consumed again here}} + } + + consuming func testCallEscapingClosure() { + var f: () -> () = {} + f = { + let _ = self + } + f() + } + + consuming func testCallEscapingClosure2() { + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + var f: () -> () = {} + f = { + let _ = self + } + f() + } + + consuming func testCallNonEscapingClosure() { + func f(_ x: () -> ()) {} + f { + _ = self + } + } + + consuming func testCallNonEscapingClosure2() { + // expected-error @-1 {{'self' used after consume}} + let _ = self // expected-note {{consumed here}} + func f(_ x: () -> ()) {} + f { // expected-note {{used here}} + _ = self + } + } + + consuming func testCallNonEscapingClosure3() { + let _ = self + self = TrivialSelfTest() + func f(_ x: () -> ()) {} + f { + _ = self + } + } +} + +func consumeTrivialSelfTest(_ x: consuming TrivialSelfTest) {} diff --git a/test/SILOptimizer/noimplicitcopy_trivial.swift b/test/SILOptimizer/noimplicitcopy_trivial.swift index bc8a977cb3748..6b44bc109e5d2 100644 --- a/test/SILOptimizer/noimplicitcopy_trivial.swift +++ b/test/SILOptimizer/noimplicitcopy_trivial.swift @@ -496,17 +496,23 @@ public func aggStructDiamondOwnedArg(@_noImplicitCopy _ x2: __owned AggStruct) { } public func aggStructDiamondInLoop(_ x: AggStruct) { - @_noImplicitCopy let x2 = x // expected-error {{'x2' used after consume}} - // expected-error @-1 {{'x2' used after consume}} + @_noImplicitCopy let x2 = x + // expected-error @-1 {{'x2' consumed in a loop}} + // expected-error @-2 {{'x2' consumed more than once}} + // expected-error @-3 {{'x2' consumed more than once}} + // expected-error @-4 {{'x2' consumed more than once}} for _ in 0..<1024 { if boolValue { let y = x2 // expected-note {{consumed here}} let _ = y - aggStructConsume(x2) // expected-note {{used here}} + aggStructConsume(x2) // expected-note {{consumed here}} + // expected-note @-1 {{consumed again here}} } else { let y = x2 // expected-note {{consumed here}} + // expected-note @-1 {{consumed again here}} let _ = y - aggStructConsume(x2) // expected-note {{used here}} + aggStructConsume(x2) // expected-note {{consumed again here}} + // expected-note @-1 {{consumed in loop here}} } } } @@ -517,26 +523,35 @@ public func aggStructDiamondInLoopArg(@_noImplicitCopy _ x2: AggStruct) { // exp let y = x2 // expected-note {{consumed here}} let _ = y - aggStructConsume(x2) + aggStructConsume(x2) // expected-note {{consumed here}} } else { let y = x2 // expected-note {{consumed here}} let _ = y - aggStructConsume(x2) + aggStructConsume(x2) // expected-note {{consumed here}} } } } -public func aggStructDiamondInLoopOwnedArg(@_noImplicitCopy _ x2: __owned AggStruct) { // expected-error {{'x2' used after consume}} - // expected-error @-1 {{'x2' used after consume}} +public func aggStructDiamondInLoopOwnedArg(@_noImplicitCopy _ x2: __owned AggStruct) { + // expected-error @-1 {{'x2' consumed more than once}} + // expected-error @-2 {{'x2' consumed more than once}} + // expected-error @-3 {{'x2' consumed more than once}} + // expected-error @-4 {{'x2' consumed in a loop}} for _ in 0..<1024 { if boolValue { let y = x2 // expected-note {{consumed here}} let _ = y - aggStructConsume(x2) // expected-note {{used here}} + aggStructConsume(x2) + // expected-note @-1 {{consumed here}} + // expected-note @-2 {{consumed again here}} } else { - let y = x2 // expected-note {{consumed here}} + let y = x2 + // expected-note @-1 {{consumed here}} + // expected-note @-2 {{consumed again here}} let _ = y - aggStructConsume(x2) // expected-note {{used here}} + aggStructConsume(x2) + // expected-note @-1 {{consumed in loop here}} + // expected-note @-2 {{consumed again here}} } } } @@ -629,28 +644,36 @@ public func aggGenericStructMultipleNonConsumingUseTestOwnedArg(@_noImplicitCopy } public func aggGenericStructUseAfterConsume(_ x: AggGenericStruct) { - @_noImplicitCopy let x2 = x // expected-error {{'x2' used after consume}} + @_noImplicitCopy let x2 = x + // expected-error @-1 {{'x2' consumed more than once}} + // expected-error @-2 {{'x2' consumed more than once}} aggGenericStructUseMoveOnlyWithoutEscaping(x2) let y = x2 // expected-note {{consumed here}} let _ = y - aggGenericStructConsume(x2) // expected-note {{used here}} + aggGenericStructConsume(x2) // expected-note {{consumed here}} + // expected-note @-1 {{consumed again here}} print(x2) + // expected-note @-1 {{consumed again here}} } public func aggGenericStructUseAfterConsumeArg(@_noImplicitCopy _ x2: AggGenericStruct) { // expected-error {{'x2' is borrowed and cannot be consumed}} aggGenericStructUseMoveOnlyWithoutEscaping(x2) let y = x2 // expected-note {{consumed here}} let _ = y - aggGenericStructConsume(x2) + aggGenericStructConsume(x2) // expected-note {{consumed here}} print(x2) // expected-note {{consumed here}} } -public func aggGenericStructUseAfterConsumeOwnedArg(@_noImplicitCopy _ x2: __owned AggGenericStruct) { // expected-error {{'x2' used after consume}} +public func aggGenericStructUseAfterConsumeOwnedArg(@_noImplicitCopy _ x2: __owned AggGenericStruct) { + // expected-error @-1 {{'x2' consumed more than once}} + // expected-error @-2 {{'x2' consumed more than once}} aggGenericStructUseMoveOnlyWithoutEscaping(x2) let y = x2 // expected-note {{consumed here}} let _ = y - aggGenericStructConsume(x2) // expected-note {{used here}} + aggGenericStructConsume(x2) // expected-note {{consumed here}} + // expected-note @-1 {{consumed again here}} print(x2) + // expected-note @-1 {{consumed again here}} } public func aggGenericStructDoubleConsume(_ x: AggGenericStruct) { @@ -698,11 +721,11 @@ public func aggGenericStructLoopConsumeOwnedArg(@_noImplicitCopy _ x2: __owned A } public func aggGenericStructDiamond(_ x: AggGenericStruct) { - @_noImplicitCopy let x2 = x // expected-error {{'x2' used after consume}} + @_noImplicitCopy let x2 = x // expected-error {{'x2' consumed more than once}} if boolValue { let y = x2 // expected-note {{consumed here}} let _ = y - aggGenericStructConsume(x2) // expected-note {{used here}} + aggGenericStructConsume(x2) // expected-note {{consumed again here}} } else { let z = x2 let _ = z @@ -713,18 +736,19 @@ public func aggGenericStructDiamondArg(@_noImplicitCopy _ x2: AggGenericStruct) { // expected-error {{'x2' used after consume}} +public func aggGenericStructDiamondOwnedArg(@_noImplicitCopy _ x2: __owned AggGenericStruct) { + // expected-error @-1 {{'x2' consumed more than once}} if boolValue { let y = x2 // expected-note {{consumed here}} let _ = y - aggGenericStructConsume(x2) // expected-note {{used here}} + aggGenericStructConsume(x2) // expected-note {{consumed again here}} } else { let z = x2 let _ = z @@ -856,28 +880,38 @@ public func aggGenericStructMultipleNonConsumingUseTestOwnedArg(@_noImplicitC } public func aggGenericStructUseAfterConsume(_ x: AggGenericStruct) { - @_noImplicitCopy let x2 = x // expected-error {{'x2' used after consume}} + @_noImplicitCopy let x2 = x + // expected-error @-1 {{'x2' used after consume}} + // expected-error @-2 {{'x2' consumed more than once}} + // expected-error @-3 {{'x2' consumed more than once}} aggGenericStructUseMoveOnlyWithoutEscaping(x2) let y = x2 // expected-note {{consumed here}} let _ = y - aggGenericStructConsume(x2) // expected-note {{used here}} - print(x2) + aggGenericStructConsume(x2) // expected-note {{consumed here}} + // expected-note @-1 {{consumed again here}} + print(x2) // expected-note {{consumed here}} + // expected-note @-1 {{consumed again here}} + aggGenericStructUseMoveOnlyWithoutEscaping(x2) + // expected-note @-1 {{used here}} } public func aggGenericStructUseAfterConsumeArg(@_noImplicitCopy _ x2: AggGenericStruct) { // expected-error {{'x2' is borrowed and cannot be consumed}} aggGenericStructUseMoveOnlyWithoutEscaping(x2) let y = x2 // expected-note {{consumed here}} let _ = y - aggGenericStructConsume(x2) + aggGenericStructConsume(x2) // expected-note {{consumed here}} print(x2) // expected-note {{consumed here}} } -public func aggGenericStructUseAfterConsumeOwnedArg(@_noImplicitCopy _ x2: __owned AggGenericStruct) { // expected-error {{'x2' used after consume}} +public func aggGenericStructUseAfterConsumeOwnedArg(@_noImplicitCopy _ x2: __owned AggGenericStruct) { + // expected-error @-1 {{'x2' consumed more than once}} + // expected-error @-2 {{'x2' consumed more than once}} aggGenericStructUseMoveOnlyWithoutEscaping(x2) let y = x2 // expected-note {{consumed here}} let _ = y - aggGenericStructConsume(x2) // expected-note {{used here}} - print(x2) + aggGenericStructConsume(x2) // expected-note {{consumed again here}} + // expected-note @-1 {{consumed here}} + print(x2) // expected-note {{consumed again here}} } public func aggGenericStructDoubleConsume(_ x: AggGenericStruct) { diff --git a/test/attr/lexical.swift b/test/attr/lexical.swift index 940df58d190dc..7794503984ec7 100644 --- a/test/attr/lexical.swift +++ b/test/attr/lexical.swift @@ -44,14 +44,13 @@ func foo() { _ = s3 } -struct MoveOnly: ~Copyable {} +struct MoveOnly : ~Copyable {} -@_eagerMove struct MoveOnlyEagerly: ~Copyable {} // expected-error {{@_eagerMove cannot be applied to NonCopyable types}} +@_eagerMove struct MoveOnlyEagerly : ~Copyable {} // expected-error {{@_eagerMove cannot be applied to NonCopyable types}} func zoo(@_eagerMove _ : consuming MoveOnly) {} // expected-error {{@_eagerMove cannot be applied to NonCopyable types}} -// TODO: Copyable types can't be consuming right now (rdar://108383660) -//func zooo(@_noEagerMove _ : consuming C) {} // ok, only way to spell this behavior +func zooo(@_noEagerMove _ : consuming C) {} // ok, only way to spell this behavior extension MoveOnly { @_eagerMove // expected-error {{@_eagerMove cannot be applied to NonCopyable types}} diff --git a/utils/sil-mode.el b/utils/sil-mode.el index 1795d3cb2c2e2..2961efed1f36a 100644 --- a/utils/sil-mode.el +++ b/utils/sil-mode.el @@ -186,6 +186,11 @@ ;; Debug Info `(,(regexp-opt '("loc" "scope" "parent" "inlined_at") 'words) . font-lock-keyword-face) + ;; noimplicit copy + `(,(regexp-opt '("moveonlywrapper_to_copyable" "moveonlywrapper_to_copyable_addr" + "copyable_to_moveonlywrapper" "copyable_to_moveonlywrapper_addr" + "moveonlywrapper_to_copyable_box") + 'words) . font-lock-keyword-face) ;; SIL Value '("\\b[%][A-Za-z_0-9]+\\([#][0-9]+\\)?\\b" . font-lock-variable-name-face) ;; Variables