diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 31cce3d1ff0c2..f3b7220761f56 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -1086,8 +1086,9 @@ BridgedInlineAttr BridgedInlineAttr_createParsed(BridgedASTContext cContext, enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedParsedLifetimeDependenceKind { BridgedParsedLifetimeDependenceKindDefault, - BridgedParsedLifetimeDependenceKindScope, + BridgedParsedLifetimeDependenceKindBorrow, BridgedParsedLifetimeDependenceKindInherit, + BridgedParsedLifetimeDependenceKindInout }; class BridgedLifetimeDescriptor { diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ca975820763c1..ccf07e88ad35a 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8169,8 +8169,11 @@ ERROR(lifetime_dependence_invalid_inherit_escapable_type, none, "'@lifetime(borrow %0)' instead", (StringRef)) ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none, - "invalid use of borrow dependence with consuming ownership", - ()) + "invalid use of %0 dependence with %1 ownership", + (StringRef, StringRef)) +ERROR(lifetime_dependence_cannot_use_default_escapable_consuming, none, + "invalid lifetime dependence on an Escapable value with %0 ownership", + (StringRef)) ERROR(lifetime_dependence_cannot_use_parsed_borrow_inout, none, "invalid use of borrow dependence on the same inout parameter", ()) diff --git a/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index 0d8cd14029bbb..56681d4fc087d 100644 --- a/include/swift/AST/LifetimeDependence.h +++ b/include/swift/AST/LifetimeDependence.h @@ -38,8 +38,9 @@ class SILResultInfo; enum class ParsedLifetimeDependenceKind : uint8_t { Default = 0, - Scope, - Inherit // Only used with deserialized decls + Borrow, + Inherit, // Only used with deserialized decls + Inout }; enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope }; @@ -182,6 +183,7 @@ class LifetimeEntry final ArrayRef sources, std::optional targetDescriptor = std::nullopt); + std::string getString() const; SourceLoc getLoc() const { return startLoc; } SourceLoc getStartLoc() const { return startLoc; } SourceLoc getEndLoc() const { return endLoc; } @@ -193,35 +195,6 @@ class LifetimeEntry final std::optional getTargetDescriptor() const { return targetDescriptor; } - - std::string getString() const { - std::string result = "@lifetime("; - if (targetDescriptor.has_value()) { - result += targetDescriptor->getString(); - result += ": "; - } - - bool firstElem = true; - for (auto source : getSources()) { - if (!firstElem) { - result += ", "; - } - switch (source.getParsedLifetimeDependenceKind()) { - case ParsedLifetimeDependenceKind::Scope: - result += "borrow "; - break; - case ParsedLifetimeDependenceKind::Inherit: - result += "copy "; - break; - default: - break; - } - result += source.getString(); - firstElem = false; - } - result += ")"; - return result; - } }; class LifetimeDependenceInfo { @@ -366,6 +339,9 @@ filterEscapableLifetimeDependencies(GenericSignature sig, SmallVectorImpl &outputs, llvm::function_ref getSubstTargetType); +StringRef +getNameForParsedLifetimeDependenceKind(ParsedLifetimeDependenceKind kind); + } // namespace swift #endif diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 2f889e2fefc7b..42aee05e6109a 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -416,6 +416,9 @@ EXPERIMENTAL_FEATURE(StructLetDestructuring, true) /// Enable returning non-escapable types from functions. EXPERIMENTAL_FEATURE(LifetimeDependence, true) +/// Enable inout lifetime dependence - @lifetime(&arg) +EXPERIMENTAL_FEATURE(InoutLifetimeDependence, true) + /// Enable the `@_staticExclusiveOnly` attribute. EXPERIMENTAL_FEATURE(StaticExclusiveOnly, true) diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index 774879aad0bda..1cb1165bf470b 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -470,10 +470,12 @@ unbridged(BridgedParsedLifetimeDependenceKind kind) { switch (kind) { case BridgedParsedLifetimeDependenceKindDefault: return swift::ParsedLifetimeDependenceKind::Default; - case BridgedParsedLifetimeDependenceKindScope: - return swift::ParsedLifetimeDependenceKind::Scope; + case BridgedParsedLifetimeDependenceKindBorrow: + return swift::ParsedLifetimeDependenceKind::Borrow; case BridgedParsedLifetimeDependenceKindInherit: return swift::ParsedLifetimeDependenceKind::Inherit; + case BridgedParsedLifetimeDependenceKindInout: + return swift::ParsedLifetimeDependenceKind::Inout; } llvm_unreachable("unhandled enum value"); } diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 2197edead58e8..f876293661a9d 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -271,6 +271,18 @@ static bool usesFeatureLifetimeDependence(Decl *decl) { return false; } +static bool usesFeatureInoutLifetimeDependence(Decl *decl) { + for (auto attr : decl->getAttrs().getAttributes()) { + for (auto source : attr->getLifetimeEntry()->getSources()) { + if (source.getParsedLifetimeDependenceKind() == + ParsedLifetimeDependenceKind::Inout) { + return true; + } + } + } + return false; +} + UNINTERESTING_FEATURE(DynamicActorIsolation) UNINTERESTING_FEATURE(NonfrozenEnumExhaustivity) UNINTERESTING_FEATURE(ClosureIsolation) diff --git a/lib/AST/LifetimeDependence.cpp b/lib/AST/LifetimeDependence.cpp index 8bdef9dc4b73d..d64e3d2576046 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -37,6 +37,35 @@ LifetimeEntry::create(const ASTContext &ctx, SourceLoc startLoc, return new (mem) LifetimeEntry(startLoc, endLoc, sources, targetDescriptor); } +std::string LifetimeEntry::getString() const { + std::string result = "@lifetime("; + if (targetDescriptor.has_value()) { + result += targetDescriptor->getString(); + result += ": "; + } + + bool firstElem = true; + for (auto source : getSources()) { + if (!firstElem) { + result += ", "; + } + auto lifetimeKind = source.getParsedLifetimeDependenceKind(); + auto kindString = getNameForParsedLifetimeDependenceKind(lifetimeKind); + bool printSpace = (lifetimeKind == ParsedLifetimeDependenceKind::Borrow || + lifetimeKind == ParsedLifetimeDependenceKind::Inherit); + if (!kindString.empty()) { + result += kindString; + } + if (printSpace) { + result += " "; + } + result += source.getString(); + firstElem = false; + } + result += ")"; + return result; +} + std::optional getLifetimeDependenceFor(ArrayRef lifetimeDependencies, unsigned index) { @@ -74,6 +103,20 @@ filterEscapableLifetimeDependencies(GenericSignature sig, return didRemoveLifetimeDependencies; } +StringRef +getNameForParsedLifetimeDependenceKind(ParsedLifetimeDependenceKind kind) { + switch (kind) { + case ParsedLifetimeDependenceKind::Borrow: + return "borrow"; + case ParsedLifetimeDependenceKind::Inherit: + return "copy"; + case ParsedLifetimeDependenceKind::Inout: + return "&"; + default: + return ""; + } +} + std::string LifetimeDependenceInfo::getString() const { std::string lifetimeDependenceString = "@lifetime("; auto addressable = getAddressableIndices(); @@ -138,16 +181,6 @@ void LifetimeDependenceInfo::Profile(llvm::FoldingSetNodeID &ID) const { } } -// Infer the kind of dependence that would be implied by assigning into a stored -// property of 'sourceType'. -static LifetimeDependenceKind -inferLifetimeDependenceKindFromType(Type sourceType) { - if (sourceType->isEscapable()) { - return LifetimeDependenceKind::Scope; - } - return LifetimeDependenceKind::Inherit; -} - // Warning: this is incorrect for Setter 'newValue' parameters. It should only // be called for a Setter's 'self'. static ValueOwnership getLoweredOwnership(AbstractFunctionDecl *afd) { @@ -456,9 +489,9 @@ class LifetimeDependenceChecker { } } - bool isCompatibleWithOwnership(LifetimeDependenceKind kind, Type type, + bool isCompatibleWithOwnership(ParsedLifetimeDependenceKind kind, Type type, ValueOwnership ownership) const { - if (kind == LifetimeDependenceKind::Inherit) { + if (kind == ParsedLifetimeDependenceKind::Inherit) { return true; } // Lifetime dependence always propagates through temporary BitwiseCopyable @@ -466,16 +499,33 @@ class LifetimeDependenceChecker { if (isBitwiseCopyable(type, ctx)) { return true; } - assert(kind == LifetimeDependenceKind::Scope); auto loweredOwnership = ownership != ValueOwnership::Default ? ownership : getLoweredOwnership(afd); - if (loweredOwnership == ValueOwnership::InOut || - loweredOwnership == ValueOwnership::Shared) { + if (kind == ParsedLifetimeDependenceKind::Borrow) { + return loweredOwnership == ValueOwnership::Shared; + } + assert(kind == ParsedLifetimeDependenceKind::Inout); + return loweredOwnership == ValueOwnership::InOut; + } + + bool isCompatibleWithOwnership(LifetimeDependenceKind kind, Type type, + ValueOwnership ownership) const { + if (kind == LifetimeDependenceKind::Inherit) { return true; } - assert(loweredOwnership == ValueOwnership::Owned); - return false; + // Lifetime dependence always propagates through temporary BitwiseCopyable + // values, even if the dependence is scoped. + if (isBitwiseCopyable(type, ctx)) { + return true; + } + auto loweredOwnership = ownership != ValueOwnership::Default + ? ownership + : getLoweredOwnership(afd); + + assert(kind == LifetimeDependenceKind::Scope); + return loweredOwnership == ValueOwnership::Shared || + loweredOwnership == ValueOwnership::InOut; } struct TargetDeps { @@ -552,43 +602,57 @@ class LifetimeDependenceChecker { getDependenceKindFromDescriptor(LifetimeDescriptor descriptor, ParamDecl *decl) { auto loc = descriptor.getLoc(); - - auto ownership = decl->getValueOwnership(); auto type = decl->getTypeInContext(); + auto parsedLifetimeKind = descriptor.getParsedLifetimeDependenceKind(); + auto ownership = decl->getValueOwnership(); + auto loweredOwnership = ownership != ValueOwnership::Default + ? ownership + : getLoweredOwnership(afd); - LifetimeDependenceKind kind; - switch (descriptor.getParsedLifetimeDependenceKind()) { - case ParsedLifetimeDependenceKind::Default: + switch (parsedLifetimeKind) { + case ParsedLifetimeDependenceKind::Default: { if (type->isEscapable()) { - kind = LifetimeDependenceKind::Scope; - } else if (useLazyInference()) { - kind = LifetimeDependenceKind::Inherit; - } else { - diagnose(loc, diag::lifetime_dependence_cannot_infer_kind, - diagnosticQualifier(), descriptor.getString()); + if (loweredOwnership == ValueOwnership::Shared || + loweredOwnership == ValueOwnership::InOut) { + return LifetimeDependenceKind::Scope; + } + diagnose( + loc, + diag::lifetime_dependence_cannot_use_default_escapable_consuming, + getOwnershipSpelling(loweredOwnership)); return std::nullopt; } - break; - case ParsedLifetimeDependenceKind::Scope: - kind = LifetimeDependenceKind::Scope; - break; - case ParsedLifetimeDependenceKind::Inherit: - kind = LifetimeDependenceKind::Inherit; - break; + if (useLazyInference()) { + return LifetimeDependenceKind::Inherit; + } + diagnose(loc, diag::lifetime_dependence_cannot_infer_kind, + diagnosticQualifier(), descriptor.getString()); + return std::nullopt; } - // @lifetime(borrow x) is invalid for consuming parameters. - if (!isCompatibleWithOwnership(kind, type, ownership)) { + + case ParsedLifetimeDependenceKind::Borrow: LLVM_FALLTHROUGH; + case ParsedLifetimeDependenceKind::Inout: { + // @lifetime(borrow x) is valid only for borrowing parameters. + // @lifetime(inout x) is valid only for inout parameters. + if (!isCompatibleWithOwnership(parsedLifetimeKind, type, + loweredOwnership)) { diagnose(loc, - diag::lifetime_dependence_cannot_use_parsed_borrow_consuming); + diag::lifetime_dependence_cannot_use_parsed_borrow_consuming, + getNameForParsedLifetimeDependenceKind(parsedLifetimeKind), + getOwnershipSpelling(loweredOwnership)); return std::nullopt; } + return LifetimeDependenceKind::Scope; + } + case ParsedLifetimeDependenceKind::Inherit: // @lifetime(copy x) is only invalid for Escapable types. - if (kind == LifetimeDependenceKind::Inherit && type->isEscapable()) { + if (type->isEscapable()) { diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type, descriptor.getString()); return std::nullopt; } - return kind; + return LifetimeDependenceKind::Inherit; + } } // Finds the ParamDecl* and its index from a LifetimeDescriptor @@ -829,15 +893,35 @@ class LifetimeDependenceChecker { return; } } - auto kind = inferLifetimeDependenceKindFromType(selfTypeInContext); - auto selfOwnership = afd->getImplicitSelfDecl()->getValueOwnership(); - if (!isCompatibleWithOwnership(kind, selfTypeInContext, selfOwnership)) { + auto kind = inferLifetimeDependenceKind( + selfTypeInContext, afd->getImplicitSelfDecl()->getValueOwnership()); + if (!kind) { diagnose(returnLoc, diag::lifetime_dependence_cannot_infer_scope_ownership, "self", diagnosticQualifier()); return; } - pushDeps(createDeps(resultIndex).add(selfIndex, kind)); + pushDeps(createDeps(resultIndex).add(selfIndex, *kind)); + } + + std::optional + inferLifetimeDependenceKind(Type sourceType, ValueOwnership ownership) { + if (!sourceType->isEscapable()) { + return LifetimeDependenceKind::Inherit; + } + // Lifetime dependence always propagates through temporary BitwiseCopyable + // values, even if the dependence is scoped. + if (isBitwiseCopyable(sourceType, ctx)) { + return LifetimeDependenceKind::Scope; + } + auto loweredOwnership = ownership != ValueOwnership::Default + ? ownership + : getLoweredOwnership(afd); + if (loweredOwnership != ValueOwnership::Shared && + loweredOwnership != ValueOwnership::InOut) { + return std::nullopt; + } + return LifetimeDependenceKind::Scope; } // Infer implicit initialization. The dependence kind can be inferred, similar @@ -861,16 +945,15 @@ class LifetimeDependenceChecker { if (paramTypeInContext->hasError()) { continue; } - auto kind = inferLifetimeDependenceKindFromType(paramTypeInContext); - auto paramOwnership = param->getValueOwnership(); - if (!isCompatibleWithOwnership(kind, paramTypeInContext, paramOwnership)) - { + auto kind = inferLifetimeDependenceKind(paramTypeInContext, + param->getValueOwnership()); + if (!kind) { diagnose(returnLoc, diag::lifetime_dependence_cannot_infer_scope_ownership, param->getParameterName().str(), diagnosticQualifier()); continue; } - targetDeps = std::move(targetDeps).add(paramIndex, kind); + targetDeps = std::move(targetDeps).add(paramIndex, *kind); } pushDeps(std::move(targetDeps)); } @@ -954,9 +1037,8 @@ class LifetimeDependenceChecker { } candidateLifetimeKind = - inferLifetimeDependenceKindFromType(paramTypeInContext); - if (!isCompatibleWithOwnership( - *candidateLifetimeKind, paramTypeInContext, paramOwnership)) { + inferLifetimeDependenceKind(paramTypeInContext, paramOwnership); + if (!candidateLifetimeKind) { continue; } if (candidateParamIndex) { @@ -1025,11 +1107,12 @@ class LifetimeDependenceChecker { if (paramTypeInContext->hasError()) { return; } - auto kind = inferLifetimeDependenceKindFromType(paramTypeInContext); + auto kind = inferLifetimeDependenceKind(paramTypeInContext, + param->getValueOwnership()); pushDeps(createDeps(selfIndex) - .add(selfIndex, LifetimeDependenceKind::Inherit) - .add(newValIdx, kind)); + .add(selfIndex, LifetimeDependenceKind::Inherit) + .add(newValIdx, *kind)); break; } default: @@ -1119,7 +1202,7 @@ static std::optional checkSILTypeModifiers( auto loc = descriptor.getLoc(); auto kind = descriptor.getParsedLifetimeDependenceKind(); - if (kind == ParsedLifetimeDependenceKind::Scope && + if (kind == ParsedLifetimeDependenceKind::Borrow && isConsumedParameterInCallee(paramConvention)) { diags.diagnose(loc, diag::lifetime_dependence_cannot_use_kind, "_scope", getStringForParameterConvention(paramConvention)); @@ -1134,7 +1217,7 @@ static std::optional checkSILTypeModifiers( if (kind == ParsedLifetimeDependenceKind::Inherit) { inheritLifetimeParamIndices.set(paramIndexToSet); } else { - assert(kind == ParsedLifetimeDependenceKind::Scope); + assert(kind == ParsedLifetimeDependenceKind::Borrow); scopeLifetimeParamIndices.set(paramIndexToSet); } return false; diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 7d80b663340f0..bc91febfee879 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -1104,8 +1104,11 @@ extension ASTGenVisitor { lifetimeDependenceKind = .inherit descriptorExpr = copyExpr.expression } else if let borrowExpr = node.as(BorrowExprSyntax.self) { - lifetimeDependenceKind = .scope + lifetimeDependenceKind = .borrow descriptorExpr = borrowExpr.expression + } else if let inoutExpr = node.as(InOutExprSyntax.self) { + lifetimeDependenceKind = .inout + descriptorExpr = inoutExpr.expression } else { lifetimeDependenceKind = .default descriptorExpr = node diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b3a4319d904ba..4429477f708ee 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5019,7 +5019,12 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { if (Tok.isContextualKeyword("borrow") && peekToken().isAny(tok::identifier, tok::integer_literal, tok::kw_self)) { - return ParsedLifetimeDependenceKind::Scope; + return ParsedLifetimeDependenceKind::Borrow; + } + if (Tok.is(tok::amp_prefix) && + peekToken().isAny(tok::identifier, tok::integer_literal, + tok::kw_self)) { + return ParsedLifetimeDependenceKind::Inout; } return std::nullopt; }; diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index 6f85621f62a91..a67ce5d14d200 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -631,6 +631,7 @@ function(_compile_swift_files list(APPEND swift_flags "-enable-experimental-feature" "NonescapableTypes") list(APPEND swift_flags "-enable-experimental-feature" "LifetimeDependence") + list(APPEND swift_flags "-enable-experimental-feature" "InoutLifetimeDependence") list(APPEND swift_flags "-enable-upcoming-feature" "MemberImportVisibility") diff --git a/stdlib/public/core/Array.swift b/stdlib/public/core/Array.swift index ccec5d1c45a10..e0798e8597782 100644 --- a/stdlib/public/core/Array.swift +++ b/stdlib/public/core/Array.swift @@ -1732,7 +1732,7 @@ extension Array { @available(SwiftStdlib 6.2, *) public var mutableSpan: MutableSpan { - @lifetime(/*inout*/borrow self) + @lifetime(&self) @_alwaysEmitIntoClient mutating get { _makeMutableAndUnique() diff --git a/stdlib/public/core/ArraySlice.swift b/stdlib/public/core/ArraySlice.swift index 886869b1ec796..282830234f997 100644 --- a/stdlib/public/core/ArraySlice.swift +++ b/stdlib/public/core/ArraySlice.swift @@ -1302,7 +1302,7 @@ extension ArraySlice { @available(SwiftStdlib 6.2, *) public var mutableSpan: MutableSpan { - @lifetime(/*inout*/borrow self) + @lifetime(/*inout*/&self) @_alwaysEmitIntoClient mutating get { _makeMutableAndUnique() diff --git a/stdlib/public/core/ContiguousArray.swift b/stdlib/public/core/ContiguousArray.swift index 13b50082e7556..6537d818ab188 100644 --- a/stdlib/public/core/ContiguousArray.swift +++ b/stdlib/public/core/ContiguousArray.swift @@ -1244,7 +1244,7 @@ extension ContiguousArray { @available(SwiftStdlib 6.2, *) public var mutableSpan: MutableSpan { - @lifetime(/*inout*/borrow self) + @lifetime(&self) @_alwaysEmitIntoClient mutating get { _makeMutableAndUnique() diff --git a/stdlib/public/core/LifetimeManager.swift b/stdlib/public/core/LifetimeManager.swift index 34c8aefbb7712..eeaeba32b2484 100644 --- a/stdlib/public/core/LifetimeManager.swift +++ b/stdlib/public/core/LifetimeManager.swift @@ -325,7 +325,7 @@ internal func _overrideLifetime< @_unsafeNonescapableResult @_alwaysEmitIntoClient @_transparent -@lifetime(borrow source) +@lifetime(&source) internal func _overrideLifetime< T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable >( diff --git a/stdlib/public/core/Span/MutableRawSpan.swift b/stdlib/public/core/Span/MutableRawSpan.swift index 056a5f9f912e8..2d1aa6776064d 100644 --- a/stdlib/public/core/Span/MutableRawSpan.swift +++ b/stdlib/public/core/Span/MutableRawSpan.swift @@ -190,7 +190,7 @@ extension MutableRawSpan { @unsafe @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) public mutating func _unsafeMutableView( as type: T.Type ) -> MutableSpan { @@ -448,7 +448,7 @@ extension MutableRawSpan { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(_ bounds: Range) -> Self { _precondition( UInt(bitPattern: bounds.lowerBound) <= UInt(bitPattern: _count) && @@ -475,7 +475,7 @@ extension MutableRawSpan { /// - Complexity: O(1) @unsafe @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(unchecked bounds: Range) -> Self { let newStart = unsafe _pointer?.advanced(by: bounds.lowerBound) let newSpan = unsafe Self(_unchecked: newStart, byteCount: bounds.count) @@ -496,7 +496,7 @@ extension MutableRawSpan { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting( _ bounds: some RangeExpression ) -> Self { @@ -520,7 +520,7 @@ extension MutableRawSpan { /// - Complexity: O(1) @unsafe @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(unchecked bounds: ClosedRange) -> Self { let range = unsafe Range( _uncheckedBounds: (bounds.lowerBound, bounds.upperBound+1) @@ -538,7 +538,7 @@ extension MutableRawSpan { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(_: UnboundedRange) -> Self { let newSpan = unsafe Self(_unchecked: _start(), byteCount: _count) return unsafe _overrideLifetime(newSpan, mutating: &self) @@ -565,7 +565,7 @@ extension MutableRawSpan { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(first maxLength: Int) -> Self { _precondition(maxLength >= 0, "Can't have a prefix of negative length") let newCount = min(maxLength, byteCount) @@ -588,7 +588,7 @@ extension MutableRawSpan { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(droppingLast k: Int) -> Self { _precondition(k >= 0, "Can't drop a negative number of elements") let droppedCount = min(k, byteCount) @@ -613,7 +613,7 @@ extension MutableRawSpan { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(last maxLength: Int) -> Self { _precondition(maxLength >= 0, "Can't have a suffix of negative length") let newCount = min(maxLength, byteCount) @@ -637,7 +637,7 @@ extension MutableRawSpan { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(droppingFirst k: Int) -> Self { _precondition(k >= 0, "Can't drop a negative number of bytes") let droppedCount = min(k, byteCount) diff --git a/stdlib/public/core/Span/MutableSpan.swift b/stdlib/public/core/Span/MutableSpan.swift index c9f444c434f1f..b778a9b6fe2e0 100644 --- a/stdlib/public/core/Span/MutableSpan.swift +++ b/stdlib/public/core/Span/MutableSpan.swift @@ -666,7 +666,7 @@ extension MutableSpan where Element: ~Copyable { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(_ bounds: Range) -> Self { _precondition( UInt(bitPattern: bounds.lowerBound) <= UInt(bitPattern: _count) && @@ -693,7 +693,7 @@ extension MutableSpan where Element: ~Copyable { /// - Complexity: O(1) @unsafe @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(unchecked bounds: Range) -> Self { let delta = bounds.lowerBound &* MemoryLayout.stride let newStart = unsafe _pointer?.advanced(by: delta) @@ -715,7 +715,7 @@ extension MutableSpan where Element: ~Copyable { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting( _ bounds: some RangeExpression ) -> Self { @@ -739,7 +739,7 @@ extension MutableSpan where Element: ~Copyable { /// - Complexity: O(1) @unsafe @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting( unchecked bounds: ClosedRange ) -> Self { @@ -759,7 +759,7 @@ extension MutableSpan where Element: ~Copyable { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(_: UnboundedRange) -> Self { let newSpan = unsafe Self(_unchecked: _start(), count: _count) return unsafe _overrideLifetime(newSpan, mutating: &self) @@ -786,7 +786,7 @@ extension MutableSpan where Element: ~Copyable { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(first maxLength: Int) -> Self { _precondition(maxLength >= 0, "Can't have a prefix of negative length") let newCount = min(maxLength, count) @@ -809,7 +809,7 @@ extension MutableSpan where Element: ~Copyable { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(droppingLast k: Int) -> Self { _precondition(k >= 0, "Can't drop a negative number of elements") let droppedCount = min(k, count) @@ -834,7 +834,7 @@ extension MutableSpan where Element: ~Copyable { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(last maxLength: Int) -> Self { _precondition(maxLength >= 0, "Can't have a suffix of negative length") let newCount = min(maxLength, count) @@ -859,7 +859,7 @@ extension MutableSpan where Element: ~Copyable { /// /// - Complexity: O(1) @_alwaysEmitIntoClient - @lifetime(borrow self) + @lifetime(&self) mutating public func extracting(droppingFirst k: Int) -> Self { _precondition(k >= 0, "Can't drop a negative number of elements") let droppedCount = min(k, count) diff --git a/test/SILOptimizer/Inputs/SpanExtras.swift b/test/SILOptimizer/Inputs/SpanExtras.swift index 5775ccce3417d..881ac3d998b26 100644 --- a/test/SILOptimizer/Inputs/SpanExtras.swift +++ b/test/SILOptimizer/Inputs/SpanExtras.swift @@ -40,7 +40,7 @@ internal func _overrideLifetime< @_unsafeNonescapableResult @_alwaysEmitIntoClient @_transparent -@lifetime(borrow source) +@lifetime(&source) internal func _overrideLifetime< T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable >( @@ -310,7 +310,7 @@ extension MutableSpan where Element: ~Copyable { precondition(indices.contains(position), "index out of bounds") yield self[unchecked: position] } - @lifetime(borrow self) + @lifetime(&self) _modify { precondition(indices.contains(position), "index out of bounds") yield &self[unchecked: position] diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_diagnostics.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_diagnostics.swift index e161fa38707c7..eb8e31e76284c 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_diagnostics.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_diagnostics.swift @@ -39,7 +39,7 @@ public struct NEInt: ~Escapable { var iprop: NEInt { @lifetime(copy self) _read { yield self } - @lifetime(borrow self) + @lifetime(&self) _modify { yield &self } } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_mutate.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_mutate.swift index b1b28f35b416a..e880a0dac7d07 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_mutate.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_mutate.swift @@ -41,7 +41,7 @@ internal func _overrideLifetime< /// the `source` argument. @_unsafeNonescapableResult @_transparent -@lifetime(borrow source) +@lifetime(&source) internal func _overrideLifetime< T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable >( @@ -112,7 +112,7 @@ struct NC : ~Copyable { let c: Int // Requires a mutable borrow. - @lifetime(borrow self) + @lifetime(&self) mutating func getMutableSpan() -> MutableSpan { MutableSpan(p, c) } diff --git a/test/SILOptimizer/lifetime_dependence/semantics.swift b/test/SILOptimizer/lifetime_dependence/semantics.swift index 4dfcec2565417..7a2e012532932 100644 --- a/test/SILOptimizer/lifetime_dependence/semantics.swift +++ b/test/SILOptimizer/lifetime_dependence/semantics.swift @@ -49,7 +49,7 @@ internal func _overrideLifetime< /// the `source` argument. @_unsafeNonescapableResult @_transparent -@lifetime(borrow source) +@lifetime(&source) internal func _overrideLifetime< T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable >( @@ -110,7 +110,7 @@ struct MutableSpan: ~Escapable, ~Copyable { let base: UnsafeMutablePointer let count: Int - @lifetime(borrow base) + @lifetime(&base) init(base: UnsafeMutablePointer, count: Int) { self.base = base self.count = count @@ -128,7 +128,7 @@ extension Array { } extension Array { - @lifetime(borrow self) + @lifetime(&self) mutating func mutableSpan() -> MutableSpan { /* not the real implementation */ let p = self.withUnsafeMutableBufferPointer { $0.baseAddress! } @@ -263,7 +263,7 @@ struct MutableView: ~Escapable, ~Copyable { self.owner = copy owner // OK } - @lifetime(borrow mutableOwner) + @lifetime(&mutableOwner) init(mutableOwner: inout AnyObject) { // Initialization of a ~Escapable value is unenforced. So we can initialize // the `owner` property without locally borrowing `mutableOwner`. @@ -432,13 +432,13 @@ func testGlobal(local: InnerTrivial) -> Span { // Scoped dependence on mutable values // ============================================================================= -@lifetime(borrow a) +@lifetime(&a) func testInoutBorrow(a: inout [Int]) -> Span { a.span() // expected-error {{lifetime-dependent value escapes its scope}} // expected-note @-1{{it depends on this scoped access to variable 'a'}} } // expected-note {{this use causes the lifetime-dependent value to escape}} -@lifetime(borrow a) +@lifetime(&a) func testInoutMutableBorrow(a: inout [Int]) -> MutableSpan { a.mutableSpan() } @@ -460,7 +460,7 @@ extension Container { View(owner: self.owner) // OK } - @lifetime(borrow self) + @lifetime(&self) mutating func mutableView() -> MutableView { // Reading 'self.owner' creates a local borrow scope. This new MutableView // depends on a the local borrow scope for 'self.owner', so it cannot be @@ -469,7 +469,7 @@ extension Container { // expected-note @-1{{it depends on this scoped access to variable 'self'}} } // expected-note {{this use causes the lifetime-dependent value to escape}} - @lifetime(borrow self) + @lifetime(&self) mutating func mutableViewModifiesOwner() -> MutableView { // Passing '&self.owner' inout creates a nested exclusive access that must extend to all uses of the new // MutableView. This is allowed because the nested access is logically extended to the end of the function (without @@ -477,7 +477,7 @@ extension Container { MutableView(mutableOwner: &self.owner) } - @lifetime(borrow self) + @lifetime(&self) mutating func mutableSpan() -> MutableSpan { // Reading 'self.pointer' creates a local borrow scope. The local borrow // scope is ignored because 'pointer' is a trivial value. Instead, the new diff --git a/test/Sema/Inputs/lifetime_depend_infer.swiftinterface b/test/Sema/Inputs/lifetime_depend_infer.swiftinterface index d4776fcf1106e..f7982508c5773 100644 --- a/test/Sema/Inputs/lifetime_depend_infer.swiftinterface +++ b/test/Sema/Inputs/lifetime_depend_infer.swiftinterface @@ -40,7 +40,7 @@ public struct NonEscapableSelf : ~Swift.Escapable { public mutating func mutatingMethodNoParamCopy() -> lifetime_depend_infer.NonEscapableSelf #endif #if $LifetimeDependence - @lifetime(borrow self) + @lifetime(&self) public mutating func mutatingMethodNoParamBorrow() -> lifetime_depend_infer.NonEscapableSelf #endif #if $LifetimeDependence @@ -67,7 +67,7 @@ public struct NonEscapableSelf : ~Swift.Escapable { public mutating func mutatingMethodOneParamCopy(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf #endif #if $LifetimeDependence - @lifetime(borrow self) + @lifetime(&self) public mutating func mutatingMethodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf #endif } @@ -85,7 +85,7 @@ public struct EscapableTrivialSelf { public mutating func mutatingMethodNoParamLifetime() -> lifetime_depend_infer.NEImmortal #endif #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence - @lifetime(borrow self) + @lifetime(&self) public mutating func mutatingMethodNoParamBorrow() -> lifetime_depend_infer.NEImmortal #endif #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence @@ -101,7 +101,7 @@ public struct EscapableTrivialSelf { public mutating func mutatingMethodOneParamLifetime(_: Swift.Int) -> lifetime_depend_infer.NEImmortal #endif #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence - @lifetime(borrow self) + @lifetime(&self) public mutating func mutatingMethodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NEImmortal #endif } @@ -126,7 +126,7 @@ public struct EscapableNonTrivialSelf { public mutating func mutatingMethodNoParamLifetime() -> lifetime_depend_infer.NEImmortal #endif #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence - @lifetime(borrow self) + @lifetime(&self) public mutating func mutatingMethodNoParamBorrow() -> lifetime_depend_infer.NEImmortal #endif #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence @@ -148,7 +148,7 @@ public struct EscapableNonTrivialSelf { public mutating func mutatingMethodOneParamLifetime(_: Swift.Int) -> lifetime_depend_infer.NEImmortal #endif #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence - @lifetime(borrow self) + @lifetime(&self) public mutating func mutatingMethodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NEImmortal #endif } @@ -256,7 +256,7 @@ public struct NonescapableSelfAccessors : ~Swift.Escapable { #if $LifetimeDependence public var neYielded: lifetime_depend_infer.NE { _read - @lifetime(borrow self) + @lifetime(&self) _modify } #endif @@ -272,7 +272,7 @@ public struct NoncopyableSelfAccessors : ~Copyable & ~Escapable { #if $LifetimeDependence public var neYielded: lifetime_depend_infer.NE { _read - @lifetime(borrow self) + @lifetime(&self) _modify } #endif @@ -312,7 +312,7 @@ public struct NoncopyableSelfAccessors : ~Copyable & ~Escapable { public var neComputedBorrow: lifetime_depend_infer.NE { @lifetime(borrow self) get - @lifetime(borrow self) + @lifetime(&self) set } #endif @@ -320,7 +320,7 @@ public struct NoncopyableSelfAccessors : ~Copyable & ~Escapable { public var neYieldedBorrow: lifetime_depend_infer.NE { @lifetime(borrow self) _read - @lifetime(borrow self) + @lifetime(&self) _modify } #endif @@ -346,7 +346,7 @@ public struct NonEscapableMutableSelf : ~Swift.Escapable { public mutating func mutatingMethodOneParamCopy(_: lifetime_depend_infer.NE) #endif #if $LifetimeDependence - @lifetime(borrow self) + @lifetime(&self) public mutating func mutatingMethodOneParamBorrow(_: lifetime_depend_infer.NE) #endif } diff --git a/test/Sema/lifetime_attr.swift b/test/Sema/lifetime_attr.swift index 4c31c7f6ec784..51bb6e59f30ad 100644 --- a/test/Sema/lifetime_attr.swift +++ b/test/Sema/lifetime_attr.swift @@ -63,3 +63,9 @@ do { // rdar://146401190 ([nonescapable] implement non-inout parameter dependencies) @lifetime(span: borrow holder) func testParameterDep(holder: AnyObject, span: Span) {} // expected-error{{lifetime-dependent parameter must be 'inout'}} + +@lifetime(&ne) +func inoutLifetimeDependence(_ ne: inout NE) -> NE { + ne +} + diff --git a/test/Sema/lifetime_depend_infer.swift b/test/Sema/lifetime_depend_infer.swift index 631242a0685e7..ede6a1a2ca0a9 100644 --- a/test/Sema/lifetime_depend_infer.swift +++ b/test/Sema/lifetime_depend_infer.swift @@ -137,7 +137,7 @@ struct EscapableNonTrivialSelf { @lifetime(copy self) // expected-error{{cannot copy the lifetime of an Escapable type, use '@lifetime(borrow self)' instead}} mutating func mutatingMethodNoParamCopy() -> NEImmortal { NEImmortal() } - @lifetime(borrow self) + @lifetime(&self) mutating func mutatingMethodNoParamBorrow() -> NEImmortal { NEImmortal() } func methodOneParam(_: Int) -> NEImmortal { NEImmortal() } // expected-error{{a method with a ~Escapable result requires '@lifetime(...)'}} @@ -159,7 +159,7 @@ struct EscapableNonTrivialSelf { @lifetime(copy self) // expected-error{{cannot copy the lifetime of an Escapable type, use '@lifetime(borrow self)' instead}} mutating func mutatingMethodOneParamCopy(_: Int) -> NEImmortal { NEImmortal() } - @lifetime(borrow self) + @lifetime(&self) mutating func mutatingMethodOneParamBorrow(_: Int) -> NEImmortal { NEImmortal() } } @@ -224,7 +224,7 @@ func oneParamLifetime(c: C) -> NEImmortal { NEImmortal() } func oneParamConsume(c: consuming C) -> NEImmortal { NEImmortal() } // expected-error{{cannot borrow the lifetime of 'c', which has consuming ownership on a function}} -@lifetime(c) // expected-error{{invalid use of borrow dependence with consuming ownership}} +@lifetime(c) // expected-error{{invalid lifetime dependence on an Escapable value with consuming ownership}} func oneParamConsumeLifetime(c: consuming C) -> NEImmortal { NEImmortal() } func oneParamBorrow(c: borrowing C) -> NEImmortal { NEImmortal() } // OK @@ -424,7 +424,7 @@ struct NoncopyableSelfAccessors: ~Copyable & ~Escapable { yield ne } - @lifetime(borrow self) + @lifetime(&self) _modify { yield &ne } @@ -484,7 +484,7 @@ struct NoncopyableSelfAccessors: ~Copyable & ~Escapable { ne } - @lifetime(borrow self) + @lifetime(&self) set { ne = newValue } @@ -496,7 +496,7 @@ struct NoncopyableSelfAccessors: ~Copyable & ~Escapable { yield ne } - @lifetime(borrow self) + @lifetime(&self) _modify { yield &ne } diff --git a/test/Sema/lifetime_depend_infer_lazy.swift b/test/Sema/lifetime_depend_infer_lazy.swift index 12b92d69f19c2..d717e754515ec 100644 --- a/test/Sema/lifetime_depend_infer_lazy.swift +++ b/test/Sema/lifetime_depend_infer_lazy.swift @@ -106,7 +106,7 @@ struct EscapableNonTrivialSelf { @lifetime(self) mutating func mutatingMethodNoParamLifetime() -> NEImmortal { NEImmortal() } - @lifetime(borrow self) + @lifetime(&self) mutating func mutatingMethodNoParamBorrow() -> NEImmortal { NEImmortal() } func methodOneParam(_: Int) -> NEImmortal { NEImmortal() } // OK @@ -122,7 +122,7 @@ struct EscapableNonTrivialSelf { @lifetime(self) // OK mutating func mutatingMethodOneParamLifetime(_: Int) -> NEImmortal { NEImmortal() } - @lifetime(borrow self) // OK + @lifetime(&self) // OK mutating func mutatingMethodOneParamBorrow(_: Int) -> NEImmortal { NEImmortal() } } @@ -351,7 +351,7 @@ struct NoncopyableSelfAccessors: ~Copyable & ~Escapable { yield ne } - @lifetime(borrow self) + @lifetime(&self) _modify { yield &ne } @@ -411,7 +411,7 @@ struct NoncopyableSelfAccessors: ~Copyable & ~Escapable { ne } - @lifetime(borrow self) + @lifetime(&self) set { ne = newValue } @@ -423,7 +423,7 @@ struct NoncopyableSelfAccessors: ~Copyable & ~Escapable { yield ne } - @lifetime(borrow self) + @lifetime(&self) _modify { yield &ne } diff --git a/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift b/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift index 05094ef6e9689..7987999b93b53 100644 --- a/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift +++ b/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift @@ -72,7 +72,7 @@ public struct Wrapper : ~Escapable { _read { yield _view } - @lifetime(borrow self) + @lifetime(&self) _modify { yield &_view } diff --git a/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift b/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift index 8a327ce4fdbdf..fe8577c255d07 100644 --- a/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift +++ b/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift @@ -62,7 +62,7 @@ public struct Wrapper : ~Escapable { _read { yield _view } - @lifetime(borrow self) + @lifetime(&self) _modify { yield &_view }