From 011b5bf10caabec9bd34916c5477821bf1519d9f Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Tue, 1 Oct 2024 11:55:08 -0700 Subject: [PATCH 01/11] Delete dependsOn support Lifetime dependencies will now be represented with @lifetime attribute in the language. dependsOn is a type modifier and was represented as a LifetimeDependentTypeRepr in the AST. I am deleting dependsOn syntax parsing support and retaining LifetimeDependentTypeRepr support. We may want to represent lifetime dependencies in a function type with a type attribute in the future. If we use a decl attribute instead, then support for LifetimeDependentTypeRepr can be deleted. --- include/swift/AST/Decl.h | 2 - include/swift/AST/LifetimeDependence.h | 5 -- include/swift/Parse/Parser.h | 7 +-- lib/AST/ASTPrinter.cpp | 22 -------- lib/AST/ASTVerifier.cpp | 10 ---- lib/AST/Decl.cpp | 4 -- lib/AST/LifetimeDependence.cpp | 76 ++------------------------ lib/Parse/ParseDecl.cpp | 21 +------ lib/Sema/TypeCheckStmt.cpp | 17 ------ 9 files changed, 7 insertions(+), 157 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index cb41fc6018c48..1e76c4c79179f 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -8805,8 +8805,6 @@ class ConstructorDecl : public AbstractFunctionDecl { Bits.ConstructorDecl.HasStubImplementation = stub; } - bool hasLifetimeDependentReturn() const; - ConstructorDecl *getOverriddenDecl() const { return cast_or_null( AbstractFunctionDecl::getOverriddenDecl()); diff --git a/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index d1601f2cda4a8..81309180cbd8a 100644 --- a/include/swift/AST/LifetimeDependence.h +++ b/include/swift/AST/LifetimeDependence.h @@ -157,11 +157,6 @@ class LifetimeDependenceInfo { static std::optional> fromLifetimeAttribute(AbstractFunctionDecl *afd); - /// Builds LifetimeDependenceInfo from dependsOn type modifier - static std::optional - fromDependsOn(AbstractFunctionDecl *afd, TypeRepr *targetRepr, - Type targetType, unsigned targetIndex); - /// Infer LifetimeDependenceInfo on result static std::optional infer(AbstractFunctionDecl *afd); diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 8abc64409a5aa..5e6e5297c9e1f 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1222,11 +1222,8 @@ class Parser { } bool isLifetimeDependenceToken() { - if (!isInSILMode()) { - return Tok.isContextualKeyword("dependsOn"); - } - return Tok.isContextualKeyword("_inherit") || - Tok.isContextualKeyword("_scope"); + return isInSILMode() && (Tok.isContextualKeyword("_inherit") || + Tok.isContextualKeyword("_scope")); } bool canHaveParameterSpecifierContextualKeyword() { diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index ba3b6ee150a6f..6aeb6ccea3002 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4246,16 +4246,6 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { Printer.printDeclResultTypePre(decl, ResultTyLoc); Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); - { - if (!Options.SuppressNonEscapableTypes) { - if (auto *typeRepr = dyn_cast_or_null( - decl->getResultTypeRepr())) { - for (auto &dep : typeRepr->getLifetimeDependencies()) { - Printer << " " << dep.getDependsOnString() << " "; - } - } - } - } if (!Options.SuppressSendingArgsAndResults) { if (decl->hasSendingResult()) { @@ -4499,18 +4489,6 @@ void PrintAST::visitConstructorDecl(ConstructorDecl *decl) { printGenericDeclGenericParams(decl); printFunctionParameters(decl); - if (!Options.SuppressNonEscapableTypes) { - if (decl->hasLifetimeDependentReturn()) { - Printer << " -> "; - auto *typeRepr = - cast(decl->getResultTypeRepr()); - for (auto &dep : typeRepr->getLifetimeDependencies()) { - Printer << dep.getDependsOnString() << " "; - } - // TODO: Handle failable initializers with lifetime dependent returns - Printer << "Self"; - } - } }); printDeclGenericRequirements(decl); diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 96c641aeb77dd..3b6f6fd1b44cb 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -1109,16 +1109,6 @@ class Verifier : public ASTWalker { } if (S->hasResult()) { - if (auto *CD = dyn_cast(func)) { - if (!CD->hasLifetimeDependentReturn()) { - Out << "Expected ReturnStmt not to have a result. A constructor " - "should not return a result. Returned expression: "; - S->getResult()->dump(Out); - Out << "\n"; - abort(); - } - } - auto result = S->getResult(); auto returnType = result->getType(); // Make sure that the return has the same type as the function. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e72799559376f..698bf79231ead 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -10611,10 +10611,6 @@ bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const { return params->get(0)->getInterfaceType()->isVoid(); } -bool ConstructorDecl::hasLifetimeDependentReturn() const { - return isa_and_nonnull(getResultTypeRepr()); -} - DestructorDecl::DestructorDecl(SourceLoc DestructorLoc, DeclContext *Parent) : AbstractFunctionDecl(DeclKind::Destructor, Parent, DeclBaseName::createDestructor(), DestructorLoc, diff --git a/lib/AST/LifetimeDependence.cpp b/lib/AST/LifetimeDependence.cpp index d3f7e475f1738..3fbac4515e06a 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -414,48 +414,6 @@ LifetimeDependenceInfo::fromLifetimeAttribute(AbstractFunctionDecl *afd) { } std::optional -LifetimeDependenceInfo::fromDependsOn(AbstractFunctionDecl *afd, - TypeRepr *targetTypeRepr, Type targetType, - unsigned targetIndex) { - auto *dc = afd->getDeclContext(); - auto &ctx = dc->getASTContext(); - auto &diags = ctx.Diags; - - auto *lifetimeDependentRepr = - dyn_cast_or_null(targetTypeRepr); - if (!lifetimeDependentRepr) { - return std::nullopt; - } - - if (targetType->isEscapable()) { - diags.diagnose(targetTypeRepr->getLoc(), - diag::lifetime_dependence_invalid_type); - return std::nullopt; - } - - auto capacity = afd->hasImplicitSelfDecl() - ? (afd->getParameters()->size() + 1) - : afd->getParameters()->size(); - - SmallBitVector inheritIndices(capacity); - SmallBitVector scopeIndices(capacity); - bool isImmortal = false; - bool hasError = false; - - for (auto entry : lifetimeDependentRepr->getLifetimeDependencies()) { - hasError |= populateLifetimeDependence(afd, entry, inheritIndices, - scopeIndices, isImmortal); - } - - if (hasError) { - return std::nullopt; - } - return LifetimeDependenceInfo( - inheritIndices.any() ? IndexSubset::get(ctx, inheritIndices) : nullptr, - scopeIndices.any() ? IndexSubset::get(ctx, scopeIndices) : nullptr, - targetIndex, isImmortal); -} - // This utility is similar to its overloaded version that builds the // LifetimeDependenceInfo from the swift decl. Reason for duplicated code is // the apis on type and ownership is different in SIL compared to Sema. @@ -735,38 +693,12 @@ LifetimeDependenceInfo::get(AbstractFunctionDecl *afd) { return LifetimeDependenceInfo::fromLifetimeAttribute(afd); } - SmallVector lifetimeDependencies; - - for (unsigned targetIndex : indices(*afd->getParameters())) { - auto *param = (*afd->getParameters())[targetIndex]; - auto paramType = - afd->mapTypeIntoContext(param->toFunctionParam().getParameterType()); - if (auto result = LifetimeDependenceInfo::fromDependsOn( - afd, param->getTypeRepr(), paramType, targetIndex)) { - lifetimeDependencies.push_back(*result); - } - } - - std::optional resultDependence; - - if (auto *lifetimeTypeRepr = dyn_cast_or_null( - afd->getResultTypeRepr())) { - resultDependence = LifetimeDependenceInfo::fromDependsOn( - afd, lifetimeTypeRepr, getResultOrYield(afd), - afd->hasImplicitSelfDecl() ? afd->getParameters()->size() + 1 - : afd->getParameters()->size()); - } else { - resultDependence = LifetimeDependenceInfo::infer(afd); - } - - if (resultDependence.has_value()) { - lifetimeDependencies.push_back(*resultDependence); - } - - if (lifetimeDependencies.empty()) { + SmallVector lifetimeDependencies; + auto resultDependence = LifetimeDependenceInfo::infer(afd); + if (!resultDependence.has_value()) { return std::nullopt; } - + lifetimeDependencies.push_back(*resultDependence); return afd->getASTContext().AllocateCopy(lifetimeDependencies); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index ec68db1000d0e..a11e96c6f3063 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -10074,26 +10074,7 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) { isAsync = true; } - if (auto *lifetimeTyR = - dyn_cast_or_null(FuncRetTy)) { - auto *base = lifetimeTyR->getBase(); - - auto isOptionalSimpleUnqualifiedIdentifier = [](TypeRepr *typeRepr, - Identifier str) { - if (auto *optionalTR = dyn_cast(typeRepr)) { - return optionalTR->getBase()->isSimpleUnqualifiedIdentifier(str); - } - return false; - }; - - // Diagnose if return type is not Self or Self? - if (!base->isSimpleUnqualifiedIdentifier(Context.Id_Self) && - !isOptionalSimpleUnqualifiedIdentifier(base, Context.Id_Self)) { - diagnose(FuncRetTy->getStartLoc(), - diag::lifetime_dependence_invalid_init_return); - return nullptr; - } - } else if (FuncRetTy) { + if (FuncRetTy) { diagnose(FuncRetTy->getStartLoc(), diag::initializer_result_type) .fixItRemove(FuncRetTy->getSourceRange()); } diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 602a6a1e62617..d587c6587052c 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1726,23 +1726,6 @@ Stmt *PreCheckReturnStmtRequest::evaluate(Evaluator &evaluator, ReturnStmt *RS, // 'nil'. auto *nilExpr = dyn_cast(E->getSemanticsProvidingExpr()); if (!nilExpr) { - if (ctor->hasLifetimeDependentReturn()) { - bool isSelf = false; - if (auto *UDRE = dyn_cast(E)) { - isSelf = UDRE->getName().isSimpleName(ctx.Id_self); - // Result the result expression so that rest of the compilation - // pipeline handles initializers with lifetime dependence specifiers - // in the same way as other initializers. - RS->setResult(nullptr); - } - if (!isSelf) { - ctx.Diags.diagnose( - RS->getStartLoc(), - diag::lifetime_dependence_ctor_non_self_or_nil_return); - RS->setResult(nullptr); - } - return RS; - } ctx.Diags.diagnose(RS->getReturnLoc(), diag::return_init_non_nil) .highlight(E->getSourceRange()); RS->setResult(nullptr); From 31c1dc7eb55a55b0d284206f3e1d9c00cc403c9d Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Wed, 2 Oct 2024 13:24:53 -0700 Subject: [PATCH 02/11] Add support for specifying target in @lifetime @lifetime(target: source1, source2...) where target can be any parameter or 'self'. We cannot have @lifetime attributes with duplicate targets. Also, update the internal data structures. Previously LifetimeEntry stored pairwise (target, source) dependencies. Now, LifetimeEntry will store an optional target descriptor and an array of source descriptors. --- include/swift/AST/Attr.h | 21 +- include/swift/AST/DeclAttr.def | 2 +- include/swift/AST/DiagnosticsSema.def | 4 +- include/swift/AST/LifetimeDependence.h | 175 ++++++++------ include/swift/AST/TypeRepr.h | 32 +-- include/swift/Parse/Parser.h | 9 +- lib/AST/ASTDumper.cpp | 13 +- lib/AST/Attr.cpp | 24 +- lib/AST/LifetimeDependence.cpp | 303 ++++++++++++------------- lib/AST/TypeRepr.cpp | 15 +- lib/Parse/ParseDecl.cpp | 262 ++++++++------------- lib/Parse/ParseType.cpp | 4 +- 12 files changed, 385 insertions(+), 479 deletions(-) diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 30c853fa4746a..27029a7777778 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -2640,25 +2640,20 @@ class RawLayoutAttr final : public DeclAttribute { } }; -class LifetimeAttr final - : public DeclAttribute, - private llvm::TrailingObjects { - - friend TrailingObjects; +class LifetimeAttr final : public DeclAttribute { + LifetimeEntry *entry; - unsigned NumEntries = 0; - - explicit LifetimeAttr(SourceLoc atLoc, SourceRange baseRange, bool implicit, - ArrayRef entries); + LifetimeAttr(SourceLoc atLoc, SourceRange baseRange, bool implicit, + LifetimeEntry *entry) + : DeclAttribute(DeclAttrKind::Lifetime, atLoc, baseRange, implicit), + entry(entry) {} public: static LifetimeAttr *create(ASTContext &context, SourceLoc atLoc, SourceRange baseRange, bool implicit, - ArrayRef entries); + LifetimeEntry *entry); - ArrayRef getLifetimeEntries() const { - return {getTrailingObjects(), NumEntries}; - } + LifetimeEntry *getLifetimeEntry() const { return entry; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DeclAttrKind::Lifetime; diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 253495584af87..e7e004b70f799 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -510,7 +510,7 @@ SIMPLE_DECL_ATTR(unsafe, Unsafe, 160) DECL_ATTR(lifetime, Lifetime, - OnAccessor | OnConstructor | OnFunc | OnSubscript | LongAttribute | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove, + OnAccessor | OnConstructor | OnFunc | OnSubscript | LongAttribute | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | AllowMultipleAttributes, 161) LAST_DECL_ATTR(Lifetime) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 20576e0db3ba9..a09e6ff340993 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7948,9 +7948,9 @@ ERROR(pack_iteration_where_clause_not_supported, none, //------------------------------------------------------------------------------ ERROR(lifetime_dependence_invalid_param_name, none, - "invalid parameter name specified %0", (Identifier)) + "invalid parameter name specified '%0'", (StringRef)) ERROR(lifetime_dependence_invalid_param_index, none, - "invalid parameter index specified %0", (unsigned)) + "invalid parameter index specified '%0'", (unsigned)) ERROR(lifetime_dependence_invalid_self_in_static, none, "invalid lifetime dependence specifier on non-existent self", ()) ERROR(lifetime_dependence_invalid_self_in_init, none, diff --git a/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index 81309180cbd8a..b366099a9688d 100644 --- a/include/swift/AST/LifetimeDependence.h +++ b/include/swift/AST/LifetimeDependence.h @@ -43,102 +43,149 @@ enum class ParsedLifetimeDependenceKind : uint8_t { enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope }; -enum class LifetimeEntryKind { Named, Ordered, Self, Immortal }; - -class LifetimeEntry { -private: - SourceLoc loc; - LifetimeEntryKind lifetimeEntryKind; - ParsedLifetimeDependenceKind parsedLifetimeDependenceKind; +struct LifetimeDescriptor { union Value { struct { - Identifier name; + StringRef name; } Named; struct { unsigned index; } Ordered; struct { - } self; - Value(Identifier name) : Named({name}) {} + } Self; + Value(StringRef name) : Named({name}) {} Value(unsigned index) : Ordered({index}) {} - Value() {} + Value() : Self() {} } value; - LifetimeEntry(SourceLoc loc, LifetimeEntryKind lifetimeEntryKind, - ParsedLifetimeDependenceKind parsedLifetimeDependenceKind, - Value value) - : loc(loc), lifetimeEntryKind(lifetimeEntryKind), - parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), - value(value) {} + enum class DescriptorKind { Named, Ordered, Self } kind; -public: - static LifetimeEntry - getNamedLifetimeEntry(SourceLoc loc, Identifier name, - ParsedLifetimeDependenceKind kind = - ParsedLifetimeDependenceKind::Default) { - return {loc, LifetimeEntryKind::Named, kind, name}; - } + ParsedLifetimeDependenceKind parsedLifetimeDependenceKind; - static LifetimeEntry getImmortalLifetimeEntry(SourceLoc loc) { - return {loc, LifetimeEntryKind::Immortal, {}, {}}; - } + SourceLoc loc; - static LifetimeEntry - getOrderedLifetimeEntry(SourceLoc loc, unsigned index, - ParsedLifetimeDependenceKind kind = - ParsedLifetimeDependenceKind::Default) { - return {loc, LifetimeEntryKind::Ordered, kind, index}; - } +private: + LifetimeDescriptor(StringRef name, + ParsedLifetimeDependenceKind parsedLifetimeDependenceKind, + SourceLoc loc) + : value{name}, kind(DescriptorKind::Named), + parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {} + LifetimeDescriptor(unsigned index, + ParsedLifetimeDependenceKind parsedLifetimeDependenceKind, + SourceLoc loc) + : value{index}, kind(DescriptorKind::Ordered), + parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {} + LifetimeDescriptor(ParsedLifetimeDependenceKind parsedLifetimeDependenceKind, + SourceLoc loc) + : value{}, kind(DescriptorKind::Self), + parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {} - static LifetimeEntry - getSelfLifetimeEntry(SourceLoc loc, - ParsedLifetimeDependenceKind kind = - ParsedLifetimeDependenceKind::Default) { - return {loc, LifetimeEntryKind::Self, kind, {}}; +public: + static LifetimeDescriptor + forNamed(StringRef name, + ParsedLifetimeDependenceKind parsedLifetimeDependenceKind, + SourceLoc loc) { + return {name, parsedLifetimeDependenceKind, loc}; + } + static LifetimeDescriptor + forOrdered(unsigned index, + ParsedLifetimeDependenceKind parsedLifetimeDependenceKind, + SourceLoc loc) { + return {index, parsedLifetimeDependenceKind, loc}; + } + static LifetimeDescriptor + forSelf(ParsedLifetimeDependenceKind parsedLifetimeDependenceKind, + SourceLoc loc) { + return {parsedLifetimeDependenceKind, loc}; } - - SourceLoc getLoc() const { return loc; } - - LifetimeEntryKind getLifetimeEntryKind() const { return lifetimeEntryKind; } ParsedLifetimeDependenceKind getParsedLifetimeDependenceKind() const { return parsedLifetimeDependenceKind; } - Identifier getName() const { - assert(lifetimeEntryKind == LifetimeEntryKind::Named); + StringRef getName() const { + assert(kind == DescriptorKind::Named); return value.Named.name; } unsigned getIndex() const { - assert(lifetimeEntryKind == LifetimeEntryKind::Ordered); + assert(kind == DescriptorKind::Ordered); return value.Ordered.index; } - std::string getParamString() const { - switch (lifetimeEntryKind) { - case LifetimeEntryKind::Named: - return value.Named.name.str().str(); - case LifetimeEntryKind::Self: + DescriptorKind getDescriptorKind() const { return kind; } + + SourceLoc getLoc() const { return loc; } + + bool isImmortal() const { + if (getDescriptorKind() != LifetimeDescriptor::DescriptorKind::Named) { + return false; + } + return getName() == "immortal"; + } + + std::string getString() const { + switch (kind) { + case DescriptorKind::Named: + return getName().str(); + case DescriptorKind::Ordered: + return std::to_string(getIndex()); + case DescriptorKind::Self: return "self"; - case LifetimeEntryKind::Ordered: - return std::to_string(value.Ordered.index); - case LifetimeEntryKind::Immortal: - return "immortal"; } - llvm_unreachable("Invalid LifetimeEntryKind"); + llvm_unreachable("Invalid DescriptorKind"); } +}; + +// TODO: Use TrailingObjects to tail allocate sources +class LifetimeEntry { +private: + SourceLoc startLoc, endLoc; + ArrayRef sources; + std::optional targetDescriptor; + + LifetimeEntry( + SourceLoc startLoc, SourceLoc endLoc, + ArrayRef sources, + std::optional targetDescriptor = std::nullopt) + : startLoc(startLoc), endLoc(endLoc), sources(sources), + targetDescriptor(targetDescriptor) {} + +public: + /// \p sources should be allocated on the ASTContext + static LifetimeEntry * + create(const ASTContext &ctx, SourceLoc startLoc, SourceLoc endLoc, + ArrayRef sources, + std::optional targetDescriptor = std::nullopt); + + SourceLoc getLoc() const { return startLoc; } + SourceLoc getStartLoc() const { return startLoc; } + SourceLoc getEndLoc() const { return endLoc; } + + ArrayRef getSources() const { return sources; } + + std::optional getTargetDescriptor() const { + return targetDescriptor; + } + + bool empty() const { return !sources.empty(); } + + std::string getString() const { + std::string result = "@lifetime("; + if (targetDescriptor.has_value()) { + result += targetDescriptor->getString(); + result += ": "; + } - std::string getDependsOnString() const { - switch (parsedLifetimeDependenceKind) { - case ParsedLifetimeDependenceKind::Default: - return "dependsOn(" + getParamString() + ")"; - case ParsedLifetimeDependenceKind::Scope: - return "dependsOn(scoped " + getParamString() + ")"; - case ParsedLifetimeDependenceKind::Inherit: - return "dependsOn(inherited " + getParamString() + ")"; + for (auto source : sources) { + if (source.getParsedLifetimeDependenceKind() == + ParsedLifetimeDependenceKind::Scope) { + result += "borrow "; + } + result += source.getString(); } - llvm_unreachable("Invalid LifetimeEntry::ParsedLifetimeDependenceKind"); + result += ")"; + return result; } }; diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 14eb2c7dc7cb7..e6082dc295d2c 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -111,11 +111,6 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr /// The number of elements contained. NumElements : 32 ); - - SWIFT_INLINE_BITFIELD_FULL(LifetimeDependentTypeRepr, TypeRepr, 32, - : NumPadBits, - NumDependencies : 32 - ); } Bits; // clang-format on @@ -1531,32 +1526,19 @@ class SILBoxTypeRepr final : public TypeRepr, friend TypeRepr; }; -class LifetimeDependentTypeRepr final - : public SpecifierTypeRepr, - private llvm::TrailingObjects { - friend TrailingObjects; - - size_t numTrailingObjects(OverloadToken) const { - return Bits.LifetimeDependentTypeRepr.NumDependencies; - } +class LifetimeDependentTypeRepr final : public SpecifierTypeRepr { + LifetimeEntry *entry; public: - LifetimeDependentTypeRepr(TypeRepr *base, ArrayRef specifiers) + LifetimeDependentTypeRepr(TypeRepr *base, LifetimeEntry *entry) : SpecifierTypeRepr(TypeReprKind::LifetimeDependent, base, - specifiers.front().getLoc()) { - assert(base); - Bits.LifetimeDependentTypeRepr.NumDependencies = specifiers.size(); - std::uninitialized_copy(specifiers.begin(), specifiers.end(), - getTrailingObjects()); - } + entry->getLoc()), + entry(entry) {} static LifetimeDependentTypeRepr *create(ASTContext &C, TypeRepr *base, - ArrayRef specifiers); + LifetimeEntry *entry); - ArrayRef getLifetimeDependencies() const { - return {getTrailingObjects(), - Bits.LifetimeDependentTypeRepr.NumDependencies}; - } + LifetimeEntry *getLifetimeEntry() const { return entry; } static bool classof(const TypeRepr *T) { return T->getKind() == TypeReprKind::LifetimeDependent; diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 5e6e5297c9e1f..aacd94450f054 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1166,6 +1166,10 @@ class Parser { ParserResult parseLifetimeAttribute(SourceLoc AtLoc, SourceLoc Loc); + /// Common utility to parse swift @lifetime decl attribute and SIL @lifetime + /// type modifier. + ParserResult parseLifetimeEntry(SourceLoc loc); + /// Parse a specific attribute. ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc, SourceLoc AtEndLoc, @@ -1251,9 +1255,6 @@ class Parser { ConventionTypeAttr *&result, bool justChecking); - ParserStatus - parseLifetimeEntries(SmallVectorImpl &specifierList); - ParserResult parseDeclImport(ParseDeclOptions Flags, DeclAttributes &Attributes); @@ -1455,7 +1456,7 @@ class Parser { SourceLoc ConstLoc; SourceLoc SendingLoc; SmallVector Attributes; - SmallVector lifetimeEntries; + LifetimeEntry *lifetimeEntry = nullptr; ParsedTypeAttributeList(ParseTypeReason reason) : ParseReason(reason) {} diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 305bb52fb8f5c..42f00c9a1d5c7 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3576,13 +3576,12 @@ class PrintTypeRepr : public TypeReprVisitor, void visitLifetimeDependentTypeRepr(LifetimeDependentTypeRepr *T, StringRef label) { printCommon("type_lifetime_dependent_return", label); - for (auto &dep : T->getLifetimeDependencies()) { - printFieldRaw( - [&](raw_ostream &out) { - out << " " << dep.getDependsOnString() << " "; - }, - ""); - } + + printFieldRaw( + [&](raw_ostream &out) { + out << " " << T->getLifetimeEntry()->getString() << " "; + }, + ""); printRec(T->getBase()); printFoot(); } diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index bb17758de8b60..e57fbfd85f457 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -1814,15 +1814,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, case DeclAttrKind::Lifetime: { auto *attr = cast(this); - bool firstElem = true; - Printer << "@lifetime("; - for (auto entry : attr->getLifetimeEntries()) { - if (!firstElem) { - Printer << ", "; - } - Printer << entry.getParamString(); - } - Printer << ")"; + Printer << attr->getLifetimeEntry()->getString(); break; } @@ -3055,20 +3047,10 @@ AllowFeatureSuppressionAttr *AllowFeatureSuppressionAttr::create( AllowFeatureSuppressionAttr(atLoc, range, implicit, inverted, features); } -LifetimeAttr::LifetimeAttr(SourceLoc atLoc, SourceRange baseRange, - bool implicit, ArrayRef entries) - : DeclAttribute(DeclAttrKind::Lifetime, atLoc, baseRange, implicit), - NumEntries(entries.size()) { - std::copy(entries.begin(), entries.end(), - getTrailingObjects()); -} - LifetimeAttr *LifetimeAttr::create(ASTContext &context, SourceLoc atLoc, SourceRange baseRange, bool implicit, - ArrayRef entries) { - unsigned size = totalSizeToAlloc(entries.size()); - void *mem = context.Allocate(size, alignof(LifetimeEntry)); - return new (mem) LifetimeAttr(atLoc, baseRange, implicit, entries); + LifetimeEntry *entry) { + return new (context) LifetimeAttr(atLoc, baseRange, implicit, entry); } void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) { diff --git a/lib/AST/LifetimeDependence.cpp b/lib/AST/LifetimeDependence.cpp index 3fbac4515e06a..8908aa97f90ee 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -25,6 +25,14 @@ namespace swift { +LifetimeEntry * +LifetimeEntry::create(const ASTContext &ctx, SourceLoc startLoc, + SourceLoc endLoc, ArrayRef sources, + std::optional targetDescriptor) { + void *mem = ctx.Allocate(sizeof(LifetimeEntry), alignof(LifetimeEntry)); + return new (mem) LifetimeEntry(startLoc, endLoc, sources, targetDescriptor); +} + std::optional getLifetimeDependenceFor(ArrayRef lifetimeDependencies, unsigned index) { @@ -82,14 +90,6 @@ getLifetimeDependenceKindFromType(Type sourceType) { return LifetimeDependenceKind::Inherit; } -static LifetimeDependenceKind getLifetimeDependenceKindFromDecl( - ParsedLifetimeDependenceKind parsedLifetimeKind) { - assert(parsedLifetimeKind != ParsedLifetimeDependenceKind::Default); - return parsedLifetimeKind == ParsedLifetimeDependenceKind::Scope - ? LifetimeDependenceKind::Scope - : 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) { @@ -209,211 +209,187 @@ static bool hasEscapableResultOrYield(AbstractFunctionDecl *afd) { } static std::optional -getLifetimeDependenceKind(LifetimeEntry specifier, AbstractFunctionDecl *afd, - ParamDecl *decl) { +getLifetimeDependenceKind(LifetimeDescriptor descriptor, + AbstractFunctionDecl *afd, ParamDecl *decl) { auto &ctx = afd->getASTContext(); auto &diags = ctx.Diags; - auto loc = specifier.getLoc(); + auto loc = descriptor.getLoc(); auto ownership = decl->getValueOwnership(); auto type = decl->getTypeInContext(); // For @lifetime attribute, we check if we had a "borrow" modifier, if not // we infer inherit dependence. - if (afd->getAttrs().hasAttribute()) { - auto parsedLifetimeKind = specifier.getParsedLifetimeDependenceKind(); - if (parsedLifetimeKind == ParsedLifetimeDependenceKind::Scope) { - bool isCompatible = isLifetimeDependenceCompatibleWithOwnership( - LifetimeDependenceKind::Scope, type, ownership, afd); - if (!isCompatible) { - diags.diagnose( - loc, diag::lifetime_dependence_cannot_use_parsed_borrow_consuming); - return std::nullopt; - } - return LifetimeDependenceKind::Scope; - } - if (type->isEscapable()) { - diags.diagnose(loc, - diag::lifetime_dependence_invalid_inherit_escapable_type); - return std::nullopt; - } - return LifetimeDependenceKind::Inherit; - } - - // For dependsOn type modifier, we check if we had a "scoped" modifier, if not - // we determine lifetime dependence kind based on type. - auto parsedLifetimeKind = specifier.getParsedLifetimeDependenceKind(); - auto lifetimeKind = - parsedLifetimeKind == ParsedLifetimeDependenceKind::Default - ? getLifetimeDependenceKindFromType(type) - : getLifetimeDependenceKindFromDecl(parsedLifetimeKind); - - bool isCompatible = isLifetimeDependenceCompatibleWithOwnership( - lifetimeKind, type, ownership, afd); - if (!isCompatible) { - assert(lifetimeKind == LifetimeDependenceKind::Scope); - if (parsedLifetimeKind == ParsedLifetimeDependenceKind::Scope) { + auto parsedLifetimeKind = descriptor.getParsedLifetimeDependenceKind(); + if (parsedLifetimeKind == ParsedLifetimeDependenceKind::Scope) { + bool isCompatible = isLifetimeDependenceCompatibleWithOwnership( + LifetimeDependenceKind::Scope, type, ownership, afd); + if (!isCompatible) { diags.diagnose( - loc, diag::lifetime_dependence_cannot_use_parsed_scoped_consuming); + loc, diag::lifetime_dependence_cannot_use_parsed_borrow_consuming); return std::nullopt; } - diags.diagnose( - loc, diag::lifetime_dependence_cannot_use_inferred_scoped_consuming); + return LifetimeDependenceKind::Scope; + } + if (type->isEscapable()) { + diags.diagnose(loc, + diag::lifetime_dependence_invalid_inherit_escapable_type); return std::nullopt; } - return lifetimeKind; + return LifetimeDependenceKind::Inherit; } -static bool populateLifetimeDependence(AbstractFunctionDecl *afd, - LifetimeEntry entry, - SmallBitVector &inheritIndices, - SmallBitVector &scopeIndices, - bool &isImmortal) { +// Finds the ParamDecl* and its index from a LifetimeDescriptor +static std::optional> +getParamDeclFromDescriptor(AbstractFunctionDecl *afd, + LifetimeDescriptor descriptor) { auto *dc = afd->getDeclContext(); auto &ctx = dc->getASTContext(); auto &diags = ctx.Diags; - - auto updateLifetimeIndices = - [&](LifetimeEntry entry, unsigned paramIndexToSet, - std::optional lifetimeKind) { - auto loc = entry.getLoc(); - if (!lifetimeKind.has_value()) { - return true; - } - if (inheritIndices.test(paramIndexToSet) || - scopeIndices.test(paramIndexToSet)) { - diags.diagnose(loc, diag::lifetime_dependence_duplicate_param_id); - return true; - } - if (lifetimeKind == LifetimeDependenceKind::Inherit) { - inheritIndices.set(paramIndexToSet); - } else { - assert(lifetimeKind == LifetimeDependenceKind::Scope); - scopeIndices.set(paramIndexToSet); - } - return false; - }; - - switch (entry.getLifetimeEntryKind()) { - case LifetimeEntryKind::Immortal: { - auto immortalParam = - std::find_if(afd->getParameters()->begin(), afd->getParameters()->end(), - [](ParamDecl *param) { - return strcmp(param->getName().get(), "immortal") == 0; - }); - if (immortalParam != afd->getParameters()->end()) { - diags.diagnose(*immortalParam, - diag::lifetime_dependence_immortal_conflict_name); - return true; - } - if (inheritIndices.any() || scopeIndices.any()) { - diags.diagnose(entry.getLoc(), diag::lifetime_dependence_immortal_alone); - return true; - } - isImmortal = true; - return false; - } - case LifetimeEntryKind::Named: { + switch (descriptor.getDescriptorKind()) { + case LifetimeDescriptor::DescriptorKind::Named: { unsigned paramIndex = 0; ParamDecl *candidateParam = nullptr; for (auto *param : *afd->getParameters()) { - if (param->getParameterName() == entry.getName()) { + if (param->getParameterName().str() == descriptor.getName()) { candidateParam = param; break; } paramIndex++; } if (!candidateParam) { - diags.diagnose(entry.getLoc(), + diags.diagnose(descriptor.getLoc(), diag::lifetime_dependence_invalid_param_name, - entry.getName()); - return true; - } - if (isImmortal) { - diags.diagnose(entry.getLoc(), diag::lifetime_dependence_immortal_alone); - return true; + descriptor.getName()); + return std::nullopt; } - auto lifetimeKind = getLifetimeDependenceKind(entry, afd, candidateParam); - return updateLifetimeIndices(entry, paramIndex, lifetimeKind); + return std::make_pair(candidateParam, paramIndex); } - case LifetimeEntryKind::Ordered: { - auto index = entry.getIndex(); - if (index >= afd->getParameters()->size()) { - diags.diagnose(entry.getLoc(), - diag::lifetime_dependence_invalid_param_index, index); - return true; - } - if (isImmortal) { - diags.diagnose(entry.getLoc(), diag::lifetime_dependence_immortal_alone); - return true; + case LifetimeDescriptor::DescriptorKind::Ordered: { + auto paramIndex = descriptor.getIndex(); + if (paramIndex >= afd->getParameters()->size()) { + diags.diagnose(descriptor.getLoc(), + diag::lifetime_dependence_invalid_param_index, paramIndex); + return std::nullopt; } - auto candidateParam = afd->getParameters()->get(index); - auto lifetimeKind = getLifetimeDependenceKind(entry, afd, candidateParam); - return updateLifetimeIndices(entry, index, lifetimeKind); + auto candidateParam = afd->getParameters()->get(paramIndex); + return std::make_pair(candidateParam, paramIndex); } - case LifetimeEntryKind::Self: { + case LifetimeDescriptor::DescriptorKind::Self: { if (!afd->hasImplicitSelfDecl()) { - diags.diagnose(entry.getLoc(), + diags.diagnose(descriptor.getLoc(), diag::lifetime_dependence_invalid_self_in_static); - return true; + return std::nullopt; } if (isa(afd)) { - diags.diagnose(entry.getLoc(), + diags.diagnose(descriptor.getLoc(), diag::lifetime_dependence_invalid_self_in_init); - return true; - } - if (isImmortal) { - diags.diagnose(entry.getLoc(), diag::lifetime_dependence_immortal_alone); - return true; + return std::nullopt; } auto *selfDecl = afd->getImplicitSelfDecl(); - auto lifetimeKind = getLifetimeDependenceKind(entry, afd, selfDecl); - return updateLifetimeIndices( - entry, /* selfIndex */ afd->getParameters()->size(), lifetimeKind); + return std::make_pair(selfDecl, afd->getParameters()->size()); } } } -std::optional> -LifetimeDependenceInfo::fromLifetimeAttribute(AbstractFunctionDecl *afd) { +static std::optional +populateLifetimeDependence(AbstractFunctionDecl *afd, LifetimeEntry *entry) { auto *dc = afd->getDeclContext(); auto &ctx = dc->getASTContext(); - - auto lifetimeAttrs = afd->getAttrs().getAttributes(); - + auto &diags = ctx.Diags; auto capacity = afd->hasImplicitSelfDecl() ? (afd->getParameters()->size() + 1) : afd->getParameters()->size(); SmallBitVector inheritIndices(capacity); SmallBitVector scopeIndices(capacity); - bool isImmortal = false; - bool hasError = false; - for (auto attr : lifetimeAttrs) { - for (auto entry : attr->getLifetimeEntries()) { - hasError |= populateLifetimeDependence(afd, entry, inheritIndices, - scopeIndices, isImmortal); + auto updateLifetimeIndices = [&](LifetimeDescriptor descriptor, + unsigned paramIndexToSet, + LifetimeDependenceKind lifetimeKind) { + if (inheritIndices.test(paramIndexToSet) || + scopeIndices.test(paramIndexToSet)) { + diags.diagnose(descriptor.getLoc(), + diag::lifetime_dependence_duplicate_param_id); + return true; } - } + if (lifetimeKind == LifetimeDependenceKind::Inherit) { + inheritIndices.set(paramIndexToSet); + } else { + assert(lifetimeKind == LifetimeDependenceKind::Scope); + scopeIndices.set(paramIndexToSet); + } + return false; + }; - if (hasError) { - return std::nullopt; + auto targetDescriptor = entry->getTargetDescriptor(); + unsigned targetIndex; + if (targetDescriptor.has_value()) { + auto targetDeclAndIndex = + getParamDeclFromDescriptor(afd, *targetDescriptor); + if (!targetDeclAndIndex.has_value()) { + return std::nullopt; + } + targetIndex = targetDeclAndIndex->second; + } else { + targetIndex = afd->hasImplicitSelfDecl() ? afd->getParameters()->size() + 1 + : afd->getParameters()->size(); + } + + for (auto source : entry->getSources()) { + if (source.isImmortal()) { + auto immortalParam = + std::find_if(afd->getParameters()->begin(), + afd->getParameters()->end(), [](ParamDecl *param) { + return strcmp(param->getName().get(), "immortal") == 0; + }); + if (immortalParam != afd->getParameters()->end()) { + diags.diagnose(*immortalParam, + diag::lifetime_dependence_immortal_conflict_name); + return std::nullopt; + } + return LifetimeDependenceInfo(nullptr, nullptr, targetIndex, + /*isImmortal*/ true); + } + + auto paramDeclAndIndex = getParamDeclFromDescriptor(afd, source); + if (!paramDeclAndIndex.has_value()) { + return std::nullopt; + } + auto lifetimeKind = + getLifetimeDependenceKind(source, afd, paramDeclAndIndex->first); + if (!lifetimeKind.has_value()) { + return std::nullopt; + } + bool hasError = + updateLifetimeIndices(source, paramDeclAndIndex->second, *lifetimeKind); + if (hasError) { + return std::nullopt; + } } - // TODO: Handle lifetime dependencies for targets other than function result. - SmallVector lifetimeDependencies; - auto resultIndex = afd->hasImplicitSelfDecl() - ? afd->getParameters()->size() + 1 - : afd->getParameters()->size(); - auto resultDependence = LifetimeDependenceInfo( + + return LifetimeDependenceInfo( inheritIndices.any() ? IndexSubset::get(ctx, inheritIndices) : nullptr, scopeIndices.any() ? IndexSubset::get(ctx, scopeIndices) : nullptr, - resultIndex, isImmortal); - lifetimeDependencies.push_back(resultDependence); + targetIndex, /*isImmortal*/ false); +} + +std::optional> +LifetimeDependenceInfo::fromLifetimeAttribute(AbstractFunctionDecl *afd) { + SmallVector lifetimeDependencies; + auto lifetimeAttrs = afd->getAttrs().getAttributes(); + for (auto attr : lifetimeAttrs) { + auto lifetimeDependenceInfo = + populateLifetimeDependence(afd, attr->getLifetimeEntry()); + if (!lifetimeDependenceInfo.has_value()) { + return std::nullopt; + } + lifetimeDependencies.push_back(*lifetimeDependenceInfo); + } + return afd->getASTContext().AllocateCopy(lifetimeDependencies); } -std::optional // This utility is similar to its overloaded version that builds the // LifetimeDependenceInfo from the swift decl. Reason for duplicated code is // the apis on type and ownership is different in SIL compared to Sema. @@ -427,11 +403,11 @@ std::optional LifetimeDependenceInfo::fromDependsOn( SmallBitVector inheritLifetimeParamIndices(capacity); SmallBitVector scopeLifetimeParamIndices(capacity); - auto updateLifetimeDependenceInfo = [&](LifetimeEntry specifier, + auto updateLifetimeDependenceInfo = [&](LifetimeDescriptor descriptor, unsigned paramIndexToSet, ParameterConvention paramConvention) { - auto loc = specifier.getLoc(); - auto kind = specifier.getParsedLifetimeDependenceKind(); + auto loc = descriptor.getLoc(); + auto kind = descriptor.getParsedLifetimeDependenceKind(); if (kind == ParsedLifetimeDependenceKind::Scope && (!isGuaranteedParameterInCallee(paramConvention) && @@ -455,23 +431,24 @@ std::optional LifetimeDependenceInfo::fromDependsOn( return false; }; - for (auto specifier : lifetimeDependentRepr->getLifetimeDependencies()) { - switch (specifier.getLifetimeEntryKind()) { - case LifetimeEntryKind::Ordered: { - auto index = specifier.getIndex(); + for (auto source : lifetimeDependentRepr->getLifetimeEntry()->getSources()) { + switch (source.getDescriptorKind()) { + case LifetimeDescriptor::DescriptorKind::Ordered: { + auto index = source.getIndex(); if (index > capacity) { - diags.diagnose(specifier.getLoc(), + diags.diagnose(source.getLoc(), diag::lifetime_dependence_invalid_param_index, index); return std::nullopt; } auto param = params[index]; auto paramConvention = param.getConvention(); - if (updateLifetimeDependenceInfo(specifier, index, paramConvention)) { + if (updateLifetimeDependenceInfo(source, index, paramConvention)) { return std::nullopt; } break; } - case LifetimeEntryKind::Immortal: { + case LifetimeDescriptor::DescriptorKind::Named: { + assert(source.isImmortal()); return LifetimeDependenceInfo(/*inheritLifetimeParamIndices*/ nullptr, /*scopeLifetimeParamIndices*/ nullptr, targetIndex, diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index ff989cecfbc43..9c0f6f1487a33 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -691,18 +691,16 @@ SourceLoc SILBoxTypeRepr::getLocImpl() const { LifetimeDependentTypeRepr * LifetimeDependentTypeRepr::create(ASTContext &C, TypeRepr *base, - ArrayRef specifiers) { - auto size = totalSizeToAlloc(specifiers.size()); - auto mem = C.Allocate(size, alignof(LifetimeEntry)); - return new (mem) LifetimeDependentTypeRepr(base, specifiers); + LifetimeEntry *entry) { + return new (C) LifetimeDependentTypeRepr(base, entry); } SourceLoc LifetimeDependentTypeRepr::getStartLocImpl() const { - return getLifetimeDependencies().front().getLoc(); + return getLifetimeEntry()->getStartLoc(); } SourceLoc LifetimeDependentTypeRepr::getEndLocImpl() const { - return getLifetimeDependencies().back().getLoc(); + return getLifetimeEntry()->getEndLoc(); } SourceLoc LifetimeDependentTypeRepr::getLocImpl() const { @@ -712,10 +710,7 @@ SourceLoc LifetimeDependentTypeRepr::getLocImpl() const { void LifetimeDependentTypeRepr::printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const { Printer << " "; - for (auto &dep : getLifetimeDependencies()) { - Printer << dep.getDependsOnString() << " "; - } - + Printer << getLifetimeEntry()->getString(); printTypeRepr(getBase(), Printer, Opts); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index a11e96c6f3063..ede68d53ccd9b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2796,11 +2796,43 @@ static std::optional parseSingleAttrOptionImpl( return P.Context.getIdentifier(parsedName); } +static std::optional +parseLifetimeDescriptor(Parser &P, + ParsedLifetimeDependenceKind lifetimeDependenceKind = + ParsedLifetimeDependenceKind::Default) { + auto token = P.Tok; + switch (token.getKind()) { + case tok::identifier: { + Identifier name; + auto loc = P.consumeIdentifier(name, /*diagnoseDollarPrefix=*/false); + return LifetimeDescriptor::forNamed(name.str(), lifetimeDependenceKind, + loc); + } + case tok::integer_literal: { + SourceLoc loc; + unsigned index; + if (P.parseUnsignedInteger( + index, loc, diag::expected_param_index_lifetime_dependence)) { + return std::nullopt; + } + return LifetimeDescriptor::forOrdered(index, lifetimeDependenceKind, loc); + } + case tok::kw_self: { + auto loc = P.consumeToken(tok::kw_self); + return LifetimeDescriptor::forSelf(lifetimeDependenceKind, loc); + } + default: { + P.diagnose( + token, + diag::expected_identifier_or_index_or_self_after_lifetime_dependence); + return std::nullopt; + } + } +} + ParserResult Parser::parseLifetimeAttribute(SourceLoc atLoc, SourceLoc loc) { ParserStatus status; - SmallVector lifetimeEntries; - if (!Context.LangOpts.hasFeature(Feature::NonescapableTypes)) { diagnose(loc, diag::requires_experimental_feature, "lifetime attribute", false, getFeatureName(Feature::NonescapableTypes)); @@ -2808,87 +2840,14 @@ ParserResult Parser::parseLifetimeAttribute(SourceLoc atLoc, return status; } - if (!Tok.isFollowingLParen()) { - diagnose(loc, diag::expected_lparen_after_lifetime_dependence); - status.setIsParseError(); - return status; - } - // consume the l_paren - auto lParenLoc = consumeToken(); - - SourceLoc rParenLoc; - bool foundParamId = false; - status = parseList( - tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast*/ false, - diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus { - ParserStatus listStatus; - foundParamId = true; - - auto lifetimeDependenceKind = ParsedLifetimeDependenceKind::Default; - if (Tok.isContextualKeyword("borrow") && - peekToken().isAny(tok::identifier, tok::integer_literal, - tok::kw_self)) { - lifetimeDependenceKind = ParsedLifetimeDependenceKind::Scope; - consumeToken(); - } - - switch (Tok.getKind()) { - case tok::identifier: { - Identifier paramName; - auto paramLoc = - consumeIdentifier(paramName, /*diagnoseDollarPrefix=*/false); - if (paramName.is("immortal")) { - lifetimeEntries.push_back( - LifetimeEntry::getImmortalLifetimeEntry(paramLoc)); - } else { - lifetimeEntries.push_back(LifetimeEntry::getNamedLifetimeEntry( - paramLoc, paramName, lifetimeDependenceKind)); - } - break; - } - case tok::integer_literal: { - SourceLoc paramLoc; - unsigned paramNum; - if (parseUnsignedInteger( - paramNum, paramLoc, - diag::expected_param_index_lifetime_dependence)) { - listStatus.setIsParseError(); - return listStatus; - } - lifetimeEntries.push_back(LifetimeEntry::getOrderedLifetimeEntry( - paramLoc, paramNum, lifetimeDependenceKind)); - break; - } - case tok::kw_self: { - auto paramLoc = consumeToken(tok::kw_self); - lifetimeEntries.push_back(LifetimeEntry::getSelfLifetimeEntry( - paramLoc, lifetimeDependenceKind)); - break; - } - default: - diagnose( - Tok, - diag:: - expected_identifier_or_index_or_self_after_lifetime_dependence); - listStatus.setIsParseError(); - return listStatus; - } - return listStatus; - }); - - if (!foundParamId) { - diagnose( - Tok, - diag::expected_identifier_or_index_or_self_after_lifetime_dependence); + auto lifetimeEntry = parseLifetimeEntry(loc); + if (lifetimeEntry.isNull()) { status.setIsParseError(); return status; } - - assert(!lifetimeEntries.empty()); - SourceRange range(loc, rParenLoc); - return ParserResult( - LifetimeAttr::create(Context, atLoc, SourceRange(loc, rParenLoc), - /* implicit */ false, lifetimeEntries)); + return ParserResult(LifetimeAttr::create( + Context, atLoc, SourceRange(loc, lifetimeEntry.get()->getEndLoc()), + /* implicit */ false, lifetimeEntry.get())); } /// Parses a (possibly optional) argument for an attribute containing a single, arbitrary identifier. @@ -5187,101 +5146,64 @@ static ParsedLifetimeDependenceKind getSILLifetimeDependenceKind(const Token &T) return ParsedLifetimeDependenceKind::Scope; } -ParserStatus -Parser::parseLifetimeEntries(SmallVectorImpl &specifierList) { +ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { ParserStatus status; - // TODO: Add fixits for diagnostics in this function. - do { - if (!isLifetimeDependenceToken()) { - break; - } - - auto lifetimeDependenceKind = ParsedLifetimeDependenceKind::Default; - if (!isInSILMode()) { - // consume dependsOn - consumeToken(); - } else { - lifetimeDependenceKind = getSILLifetimeDependenceKind(Tok); - // consume _inherit or _scope - consumeToken(); - } + if (!Tok.isFollowingLParen()) { + diagnose(loc, diag::expected_lparen_after_lifetime_dependence); + status.setIsParseError(); + return status; + } + // consume the l_paren + auto lParenLoc = consumeToken(); - if (!Tok.isFollowingLParen()) { - diagnose(Tok, diag::expected_lparen_after_lifetime_dependence); + std::optional targetDescriptor; + if (Tok.isAny(tok::identifier, tok::integer_literal, tok::kw_self) && + peekToken().is(tok::colon)) { + targetDescriptor = parseLifetimeDescriptor(*this); + if (!targetDescriptor) { status.setIsParseError(); - continue; - } - // consume the l_paren - auto lParenLoc = consumeToken(); - - if (!isInSILMode()) { - // look for optional "scoped" - if (Tok.isContextualKeyword("scoped")) { - lifetimeDependenceKind = ParsedLifetimeDependenceKind::Scope; - // consume scoped - consumeToken(); - } + return status; } + consumeToken(); // consume ':' + } - SourceLoc rParenLoc; - bool foundParamId = false; - status = parseList( - tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast*/ false, - diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus { - ParserStatus listStatus; - foundParamId = true; - switch (Tok.getKind()) { - case tok::identifier: { - Identifier paramName; - auto paramLoc = - consumeIdentifier(paramName, /*diagnoseDollarPrefix=*/false); - if (paramName.is("immortal")) { - specifierList.push_back( - LifetimeEntry::getImmortalLifetimeEntry(paramLoc)); - } else { - specifierList.push_back(LifetimeEntry::getNamedLifetimeEntry( - paramLoc, paramName, lifetimeDependenceKind)); - } - break; - } - case tok::integer_literal: { - SourceLoc paramLoc; - unsigned paramNum; - if (parseUnsignedInteger( - paramNum, paramLoc, - diag::expected_param_index_lifetime_dependence)) { - listStatus.setIsParseError(); - return listStatus; - } - specifierList.push_back(LifetimeEntry::getOrderedLifetimeEntry( - paramLoc, paramNum, lifetimeDependenceKind)); - break; - } - case tok::kw_self: { - auto paramLoc = consumeToken(tok::kw_self); - specifierList.push_back(LifetimeEntry::getSelfLifetimeEntry( - paramLoc, lifetimeDependenceKind)); - break; - } - default: - diagnose( - Tok, - diag:: - expected_identifier_or_index_or_self_after_lifetime_dependence); - listStatus.setIsParseError(); - return listStatus; - } + SmallVector sources; + SourceLoc rParenLoc; + bool foundParamId = false; + status = parseList( + tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast*/ false, + diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus { + ParserStatus listStatus; + foundParamId = true; + auto lifetimeDependenceKind = ParsedLifetimeDependenceKind::Default; + if (Tok.isContextualKeyword("borrow") && + peekToken().isAny(tok::identifier, tok::integer_literal, + tok::kw_self)) { + lifetimeDependenceKind = ParsedLifetimeDependenceKind::Scope; + consumeToken(); + } + auto sourceDescriptor = + parseLifetimeDescriptor(*this, lifetimeDependenceKind); + if (!sourceDescriptor) { + listStatus.setIsParseError(); return listStatus; - }); + } + sources.push_back(*sourceDescriptor); + return listStatus; + }); - if (!foundParamId) { - diagnose(Tok, diag::expected_identifier_or_index_or_self_after_lifetime_dependence); - status.setIsParseError(); - } - } while (true); + if (!foundParamId) { + diagnose( + Tok, + diag::expected_identifier_or_index_or_self_after_lifetime_dependence); + status.setIsParseError(); + return status; + } - return status; + auto *lifetimeEntry = LifetimeEntry::create( + Context, loc, rParenLoc, Context.AllocateCopy(sources), targetDescriptor); + return ParserResult(lifetimeEntry); } ParserStatus Parser::parseDeclAttributeList( @@ -5590,7 +5512,13 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) { "lifetime dependence specifier", false, getFeatureName(Feature::NonescapableTypes)); } - status |= P.parseLifetimeEntries(lifetimeEntries); + auto loc = P.consumeToken(); + auto result = P.parseLifetimeEntry(loc); + if (result.isNull()) { + status |= result; + continue; + } + lifetimeEntry = result.get(); continue; } diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index ae9bfd6043aa6..df4bd5f4a996a 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -58,8 +58,8 @@ Parser::ParsedTypeAttributeList::applyAttributesToType(Parser &p, ty = new (p.Context) SendingTypeRepr(ty, SendingLoc); } - if (!lifetimeEntries.empty()) { - ty = LifetimeDependentTypeRepr::create(p.Context, ty, lifetimeEntries); + if (lifetimeEntry) { + ty = LifetimeDependentTypeRepr::create(p.Context, ty, lifetimeEntry); } return ty; } From 4ac90a3e11169e8635a8bcd7d8fb15c84be8ff34 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Wed, 2 Oct 2024 14:52:22 -0700 Subject: [PATCH 03/11] Diagnose multiple @lifetime attributes with same target --- include/swift/AST/DiagnosticsSema.def | 2 ++ lib/AST/LifetimeDependence.cpp | 12 ++++++++++++ test/Sema/lifetime_attr.swift | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index a09e6ff340993..6eacfc22eddc6 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8005,6 +8005,8 @@ ERROR(lifetime_dependence_invalid_inherit_escapable_type, none, ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none, "invalid use of borrow dependence with consuming ownership", ()) +ERROR(lifetime_dependence_duplicate_target, none, + "invalid duplicate target lifetime dependencies on function", ()) //===----------------------------------------------------------------------===// // MARK: Sending diff --git a/lib/AST/LifetimeDependence.cpp b/lib/AST/LifetimeDependence.cpp index 8908aa97f90ee..5f611e81fa530 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -376,7 +376,12 @@ populateLifetimeDependence(AbstractFunctionDecl *afd, LifetimeEntry *entry) { std::optional> LifetimeDependenceInfo::fromLifetimeAttribute(AbstractFunctionDecl *afd) { + auto *dc = afd->getDeclContext(); + auto &ctx = dc->getASTContext(); + auto &diags = ctx.Diags; + SmallVector lifetimeDependencies; + llvm::SmallSet lifetimeDependentTargets; auto lifetimeAttrs = afd->getAttrs().getAttributes(); for (auto attr : lifetimeAttrs) { auto lifetimeDependenceInfo = @@ -384,6 +389,13 @@ LifetimeDependenceInfo::fromLifetimeAttribute(AbstractFunctionDecl *afd) { if (!lifetimeDependenceInfo.has_value()) { return std::nullopt; } + auto targetIndex = lifetimeDependenceInfo->getTargetIndex(); + if (lifetimeDependentTargets.contains(targetIndex)) { + // TODO: Diagnose at the source location of the @lifetime attribute with + // duplicate target. + diags.diagnose(afd->getLoc(), diag::lifetime_dependence_duplicate_target); + } + lifetimeDependentTargets.insert(targetIndex); lifetimeDependencies.push_back(*lifetimeDependenceInfo); } diff --git a/test/Sema/lifetime_attr.swift b/test/Sema/lifetime_attr.swift index 2aa9da0d1f2fb..6375c124837a5 100644 --- a/test/Sema/lifetime_attr.swift +++ b/test/Sema/lifetime_attr.swift @@ -34,3 +34,8 @@ func invalidDependence(_ x: consuming Klass) -> NE { NE() } +@lifetime(result: source) +@lifetime(result: source) // TODO: display error here +func invalidTarget(_ result: inout NE, _ source: consuming NE) { // expected-error{{invalid duplicate target lifetime dependencies on function}} + result = source +} From 8e8b21e25eb6b9fcdd6c358aa3eb59f76fac5552 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Tue, 1 Oct 2024 17:05:38 -0700 Subject: [PATCH 04/11] Fix AST printing of @lifetime --- include/swift/AST/LifetimeDependence.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index b366099a9688d..5b67e60969160 100644 --- a/include/swift/AST/LifetimeDependence.h +++ b/include/swift/AST/LifetimeDependence.h @@ -177,12 +177,17 @@ class LifetimeEntry { result += ": "; } + bool firstElem = true; for (auto source : sources) { + if (!firstElem) { + result += ", "; + } if (source.getParsedLifetimeDependenceKind() == ParsedLifetimeDependenceKind::Scope) { result += "borrow "; } result += source.getString(); + firstElem = false; } result += ")"; return result; From f591680c2ace84e8343478b8513e9f80350fc04c Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Wed, 2 Oct 2024 13:34:35 -0700 Subject: [PATCH 05/11] Update SIL printing of @lifetime Lifetime dependencies in SIL tests continue to be represented as a type modifier on the target. As before, they are represented as a LifetimeDependentTypeRepr in the AST. --- include/swift/Parse/Parser.h | 14 +++---- lib/AST/LifetimeDependence.cpp | 24 ++++++++---- lib/Parse/ParseDecl.cpp | 38 +++++++++++-------- .../class/nonescapable-lifetimebound.swift | 14 +++---- 4 files changed, 54 insertions(+), 36 deletions(-) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index aacd94450f054..3b3d7f8f74252 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1201,6 +1201,9 @@ class Parser { bool isParameterSpecifier() { if (Tok.is(tok::kw_inout)) return true; + if (Context.LangOpts.hasFeature(Feature::NonescapableTypes) && + isSILLifetimeDependenceToken()) + return true; if (!canHaveParameterSpecifierContextualKeyword()) return false; if (Tok.isContextualKeyword("__shared") || Tok.isContextualKeyword("__owned") || @@ -1212,9 +1215,6 @@ class Parser { if (Context.LangOpts.hasFeature(Feature::SendingArgsAndResults) && Tok.isContextualKeyword("sending")) return true; - if (Context.LangOpts.hasFeature(Feature::NonescapableTypes) && - isLifetimeDependenceToken()) - return true; return false; } @@ -1225,9 +1225,9 @@ class Parser { consumeToken(); } - bool isLifetimeDependenceToken() { - return isInSILMode() && (Tok.isContextualKeyword("_inherit") || - Tok.isContextualKeyword("_scope")); + bool isSILLifetimeDependenceToken() { + return isInSILMode() && Tok.is(tok::at_sign) && + (peekToken().isContextualKeyword("lifetime")); } bool canHaveParameterSpecifierContextualKeyword() { @@ -1248,7 +1248,7 @@ class Parser { return true; } - return isLifetimeDependenceToken(); + return false; } bool parseConventionAttributeInternal(SourceLoc atLoc, SourceLoc attrLoc, diff --git a/lib/AST/LifetimeDependence.cpp b/lib/AST/LifetimeDependence.cpp index 5f611e81fa530..a68cd4547a871 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -45,8 +45,8 @@ getLifetimeDependenceFor(ArrayRef lifetimeDependencies, } std::string LifetimeDependenceInfo::getString() const { - std::string lifetimeDependenceString; - auto getOnIndices = [](IndexSubset *bitvector) { + std::string lifetimeDependenceString = "@lifetime("; + auto getSourceString = [](IndexSubset *bitvector, StringRef kind) { std::string result; bool isFirstSetBit = true; for (unsigned i = 0; i < bitvector->getCapacity(); i++) { @@ -54,20 +54,30 @@ std::string LifetimeDependenceInfo::getString() const { if (!isFirstSetBit) { result += ", "; } + result += kind; result += std::to_string(i); isFirstSetBit = false; } } return result; }; - if (inheritLifetimeParamIndices && !inheritLifetimeParamIndices->isEmpty()) { - lifetimeDependenceString = - "_inherit(" + getOnIndices(inheritLifetimeParamIndices) + ") "; + if (inheritLifetimeParamIndices) { + assert(!inheritLifetimeParamIndices->isEmpty()); + lifetimeDependenceString += + getSourceString(inheritLifetimeParamIndices, "copy "); } - if (scopeLifetimeParamIndices && !scopeLifetimeParamIndices->isEmpty()) { + if (scopeLifetimeParamIndices) { + assert(!scopeLifetimeParamIndices->isEmpty()); + if (inheritLifetimeParamIndices) { + lifetimeDependenceString += ", "; + } lifetimeDependenceString += - "_scope(" + getOnIndices(scopeLifetimeParamIndices) + ") "; + getSourceString(scopeLifetimeParamIndices, "borrow "); + } + if (isImmortal()) { + lifetimeDependenceString += "immortal"; } + lifetimeDependenceString += ") "; return lifetimeDependenceString; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index ede68d53ccd9b..2bc2a204a2d84 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5138,17 +5138,24 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result, llvm_unreachable("bad attribute kind"); } -static ParsedLifetimeDependenceKind getSILLifetimeDependenceKind(const Token &T) { - if (T.isContextualKeyword("_inherit")) { - return ParsedLifetimeDependenceKind::Inherit; - } - assert(T.isContextualKeyword("_scope")); - return ParsedLifetimeDependenceKind::Scope; -} - ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { ParserStatus status; + auto getLifetimeDependenceKind = + [&](Token Tok) -> std::optional { + if (Tok.isContextualKeyword("copy") && + peekToken().isAny(tok::identifier, tok::integer_literal, + tok::kw_self)) { + return ParsedLifetimeDependenceKind::Inherit; + } + if (Tok.isContextualKeyword("borrow") && + peekToken().isAny(tok::identifier, tok::integer_literal, + tok::kw_self)) { + return ParsedLifetimeDependenceKind::Scope; + } + return std::nullopt; + }; + if (!Tok.isFollowingLParen()) { diagnose(loc, diag::expected_lparen_after_lifetime_dependence); status.setIsParseError(); @@ -5176,13 +5183,14 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus { ParserStatus listStatus; foundParamId = true; + auto lifetimeDependenceKind = ParsedLifetimeDependenceKind::Default; - if (Tok.isContextualKeyword("borrow") && - peekToken().isAny(tok::identifier, tok::integer_literal, - tok::kw_self)) { - lifetimeDependenceKind = ParsedLifetimeDependenceKind::Scope; + auto result = getLifetimeDependenceKind(Tok); + if (result.has_value()) { + lifetimeDependenceKind = *result; consumeToken(); } + auto sourceDescriptor = parseLifetimeDescriptor(*this, lifetimeDependenceKind); if (!sourceDescriptor) { @@ -5462,7 +5470,6 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) { PatternBindingInitializer *initContext = nullptr; auto &Tok = P.Tok; while (P.isParameterSpecifier()) { - if (Tok.isContextualKeyword("isolated")) { Tok.setKind(tok::contextual_keyword); auto kwLoc = P.consumeToken(); @@ -5506,13 +5513,14 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) { continue; } - if (P.isLifetimeDependenceToken()) { + if (P.isSILLifetimeDependenceToken()) { if (!P.Context.LangOpts.hasFeature(Feature::NonescapableTypes)) { P.diagnose(Tok, diag::requires_experimental_feature, "lifetime dependence specifier", false, getFeatureName(Feature::NonescapableTypes)); } - auto loc = P.consumeToken(); + P.consumeToken(); // consume '@' + auto loc = P.consumeToken(); // consume 'lifetime' auto result = P.parseLifetimeEntry(loc); if (result.isNull()) { status |= result; diff --git a/test/Interop/Cxx/class/nonescapable-lifetimebound.swift b/test/Interop/Cxx/class/nonescapable-lifetimebound.swift index 4afb28b7c5927..e41f7f6ee6d29 100644 --- a/test/Interop/Cxx/class/nonescapable-lifetimebound.swift +++ b/test/Interop/Cxx/class/nonescapable-lifetimebound.swift @@ -69,12 +69,12 @@ private: }; // CHECK: sil [clang makeOwner] {{.*}}: $@convention(c) () -> Owner -// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> _scope(0) @autoreleased View -// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> _scope(0) @autoreleased View -// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> _scope(0, 1) @autoreleased View -// CHECK: sil [clang Owner.handOutView] {{.*}} : $@convention(cxx_method) (@in_guaranteed Owner) -> _scope(0) @autoreleased View -// CHECK: sil [clang Owner.handOutView2] {{.*}} : $@convention(cxx_method) (View, @in_guaranteed Owner) -> _scope(1) @autoreleased View -// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@guaranteed View, @guaranteed View) -> _inherit(0, 1) @autoreleased View +// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> _lifetime(_borrow 0) @autoreleased View +// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> _lifetime(_borrow 0) @autoreleased View +// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> _lifetime(_borrow 0, _borrow 1) @autoreleased View +// CHECK: sil [clang Owner.handOutView] {{.*}} : $@convention(cxx_method) (@in_guaranteed Owner) -> _lifetime(_borrow 0) @autoreleased View +// CHECK: sil [clang Owner.handOutView2] {{.*}} : $@convention(cxx_method) (View, @in_guaranteed Owner) -> _lifetime(_borrow 1) @autoreleased View +// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@guaranteed View, @guaranteed View) -> _lifetime(_copy 0, _copy 1) @autoreleased View // CHECK: sil [clang View.init] {{.*}} : $@convention(c) () -> @out View //--- test.swift @@ -91,4 +91,4 @@ public func test() { let _ = o.handOutView2(v1) let _ = getViewFromEither(v1, v2) let defaultView = View() -} \ No newline at end of file +} From ea420e07805b23c2a8fe4d9f47cb9221b63db3ca Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Thu, 3 Oct 2024 10:46:10 -0700 Subject: [PATCH 06/11] Add a test for @lifetime(immortal) --- include/swift/AST/DiagnosticsSema.def | 2 +- test/Sema/lifetime_attr.swift | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 6eacfc22eddc6..67210759eea90 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7992,7 +7992,7 @@ ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none, "Escapable", ()) ERROR(lifetime_dependence_immortal_conflict_name, none, - "conflict between the parameter name and immortal keyword", ()) + "conflict between the parameter name and 'immortal' contextual keyword", ()) ERROR(lifetime_dependence_function_type, none, "lifetime dependencies on function types are not supported", ()) diff --git a/test/Sema/lifetime_attr.swift b/test/Sema/lifetime_attr.swift index 6375c124837a5..6db5a90489b2c 100644 --- a/test/Sema/lifetime_attr.swift +++ b/test/Sema/lifetime_attr.swift @@ -39,3 +39,8 @@ func invalidDependence(_ x: consuming Klass) -> NE { func invalidTarget(_ result: inout NE, _ source: consuming NE) { // expected-error{{invalid duplicate target lifetime dependencies on function}} result = source } + +@lifetime(immortal) +func immortalConflict(_ immortal: Int) -> NE { // expected-error{{conflict between the parameter name and 'immortal' contextual keyword}} + NE() +} From 6710d501b157f89a20dbf4f1e2f1124c3c9179fd Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Thu, 3 Oct 2024 14:58:50 -0700 Subject: [PATCH 07/11] Fix SIL parsing of lifetime dependence in parameter position --- lib/Sema/TypeCheckType.cpp | 4 ++++ .../lifetime_dependence/lifetime_dependence.sil | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 8546f44ab4dd1..6a6d6d342340d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4561,6 +4561,10 @@ SILParameterInfo TypeResolver::resolveSILParameter( std::optional attrsBuffer; TypeAttrSet *attrs = nullptr; + + if (auto *lifetimeRepr = dyn_cast(repr)) { + repr = lifetimeRepr->getBase(); + } if (yieldAttrs) { attrs = yieldAttrs; assert(!isa(repr)); diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil b/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil index 46cdbef3ca8c2..22be9ed6ee995 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil @@ -13,8 +13,6 @@ sil_stage raw class C {} -@_marker public protocol Escapable { } - struct Nonescapable: ~Escapable {} sil @c_dependence : $@convention(thin) (@guaranteed C) -> _scope(0) @owned Nonescapable @@ -52,3 +50,7 @@ bb0: %t = tuple () return %t : $() } + +public struct Container : ~Copyable, ~Escapable where Element : ~Copyable {} + +sil [ossa] @parseInoutDep : $@convention(method) (_lifetime(_copy 0) @inout Container) -> () From b443ff76e4ab2e4f9b7fea63fff691c5c084f21b Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Tue, 8 Oct 2024 14:42:56 -0700 Subject: [PATCH 08/11] [NFC] Use llvm::TrailingObjects to represent variable list of lifetime sources --- include/swift/AST/LifetimeDependence.h | 29 +++++++++++++++++--------- lib/AST/LifetimeDependence.cpp | 3 ++- lib/Parse/ParseDecl.cpp | 2 +- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index 5b67e60969160..7c3e414c43ba2 100644 --- a/include/swift/AST/LifetimeDependence.h +++ b/include/swift/AST/LifetimeDependence.h @@ -26,6 +26,7 @@ #include "swift/Basic/SourceLoc.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/TrailingObjects.h" namespace swift { @@ -137,22 +138,30 @@ struct LifetimeDescriptor { } }; -// TODO: Use TrailingObjects to tail allocate sources -class LifetimeEntry { +class LifetimeEntry final + : private llvm::TrailingObjects { + friend TrailingObjects; + private: SourceLoc startLoc, endLoc; - ArrayRef sources; + unsigned numSources; std::optional targetDescriptor; LifetimeEntry( SourceLoc startLoc, SourceLoc endLoc, ArrayRef sources, std::optional targetDescriptor = std::nullopt) - : startLoc(startLoc), endLoc(endLoc), sources(sources), - targetDescriptor(targetDescriptor) {} + : startLoc(startLoc), endLoc(endLoc), numSources(sources.size()), + targetDescriptor(targetDescriptor) { + std::uninitialized_copy(sources.begin(), sources.end(), + getTrailingObjects()); + } + + size_t numTrailingObjects(OverloadToken) const { + return numSources; + } public: - /// \p sources should be allocated on the ASTContext static LifetimeEntry * create(const ASTContext &ctx, SourceLoc startLoc, SourceLoc endLoc, ArrayRef sources, @@ -162,14 +171,14 @@ class LifetimeEntry { SourceLoc getStartLoc() const { return startLoc; } SourceLoc getEndLoc() const { return endLoc; } - ArrayRef getSources() const { return sources; } + ArrayRef getSources() const { + return {getTrailingObjects(), numSources}; + } std::optional getTargetDescriptor() const { return targetDescriptor; } - bool empty() const { return !sources.empty(); } - std::string getString() const { std::string result = "@lifetime("; if (targetDescriptor.has_value()) { @@ -178,7 +187,7 @@ class LifetimeEntry { } bool firstElem = true; - for (auto source : sources) { + for (auto source : getSources()) { if (!firstElem) { result += ", "; } diff --git a/lib/AST/LifetimeDependence.cpp b/lib/AST/LifetimeDependence.cpp index a68cd4547a871..5689fd06cea5d 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -29,7 +29,8 @@ LifetimeEntry * LifetimeEntry::create(const ASTContext &ctx, SourceLoc startLoc, SourceLoc endLoc, ArrayRef sources, std::optional targetDescriptor) { - void *mem = ctx.Allocate(sizeof(LifetimeEntry), alignof(LifetimeEntry)); + unsigned size = totalSizeToAlloc(sources.size()); + void *mem = ctx.Allocate(size, alignof(LifetimeEntry)); return new (mem) LifetimeEntry(startLoc, endLoc, sources, targetDescriptor); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2bc2a204a2d84..343510b3c70d5 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5210,7 +5210,7 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { } auto *lifetimeEntry = LifetimeEntry::create( - Context, loc, rParenLoc, Context.AllocateCopy(sources), targetDescriptor); + Context, loc, rParenLoc, sources, targetDescriptor); return ParserResult(lifetimeEntry); } From 008431c3b478bf3185c429ca993927552c999684 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Wed, 2 Oct 2024 00:12:36 -0700 Subject: [PATCH 09/11] Update some dependsOn tests to @lifetime --- .../class/nonescapable-lifetimebound.swift | 14 +- .../Inputs/lifetime_dependence.swift | 23 +- .../lifetime_dependence_test.swift | 16 +- test/ModuleInterface/nonescapable_types.swift | 6 +- ...licit_lifetime_dependence_specifiers.swift | 167 ------------ test/SIL/Parser/lifetime_dependence.sil | 22 +- ...licit_lifetime_dependence_specifiers.swift | 70 ++--- test/SIL/implicit_lifetime_dependence.swift | 49 ++-- ...lifetime_dependence_buffer_view_test.swift | 169 ------------ test/SIL/lifetime_dependence_generics.swift | 18 +- ...etime_dependence_param_position_test.swift | 10 +- ...fetime_dependence_span_lifetime_attr.swift | 15 +- .../capture_promotion_ownership.sil | 6 +- .../lifetime_dependence/initializer.swift | 3 +- .../lifetime_dependence/inout.swift | 49 ++-- .../lifetime_dependence.sil | 14 +- .../lifetime_dependence_borrow.swift | 21 +- .../lifetime_dependence_borrow_fail.swift | 19 +- .../lifetime_dependence_closure.swift | 4 +- .../lifetime_dependence_diagnostics.swift | 27 +- .../lifetime_dependence_generic.swift | 23 +- .../lifetime_dependence_inherit.swift | 26 +- .../lifetime_dependence_inherit_fail.swift | 16 +- .../lifetime_dependence_insertion.swift | 8 +- .../lifetime_dependence_mutate.swift | 9 +- .../lifetime_dependence_optional.swift | 6 +- .../lifetime_dependence_param.swift | 15 +- .../lifetime_dependence_param_fail.swift | 7 +- .../lifetime_dependence_scope.swift | 13 +- .../lifetime_dependence_scope_fixup.swift | 54 ++-- .../lifetime_dependence/semantics.swift | 23 +- ...icit_lifetime_dependence_specifiers1.swift | 245 ------------------ ...icit_lifetime_dependence_specifiers2.swift | 23 -- test/Sema/implicit_lifetime_dependence.swift | 3 +- test/Sema/lifetime_attr.swift | 2 +- test/Sema/lifetime_dependence_functype.swift | 90 +++---- .../def_explicit_lifetime_dependence.swift | 36 ++- .../def_implicit_lifetime_dependence.swift | 6 +- .../explicit_lifetime_dependence.swift | 10 +- .../implicit_lifetime_dependence.swift | 14 +- test/attr/attr_nonEscapable.swift | 29 --- 41 files changed, 411 insertions(+), 969 deletions(-) delete mode 100644 test/Parse/explicit_lifetime_dependence_specifiers.swift delete mode 100644 test/SIL/lifetime_dependence_buffer_view_test.swift delete mode 100644 test/Sema/explicit_lifetime_dependence_specifiers1.swift delete mode 100644 test/Sema/explicit_lifetime_dependence_specifiers2.swift delete mode 100644 test/attr/attr_nonEscapable.swift diff --git a/test/Interop/Cxx/class/nonescapable-lifetimebound.swift b/test/Interop/Cxx/class/nonescapable-lifetimebound.swift index e41f7f6ee6d29..7c0acf6f4d33f 100644 --- a/test/Interop/Cxx/class/nonescapable-lifetimebound.swift +++ b/test/Interop/Cxx/class/nonescapable-lifetimebound.swift @@ -69,13 +69,13 @@ private: }; // CHECK: sil [clang makeOwner] {{.*}}: $@convention(c) () -> Owner -// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> _lifetime(_borrow 0) @autoreleased View -// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> _lifetime(_borrow 0) @autoreleased View -// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> _lifetime(_borrow 0, _borrow 1) @autoreleased View -// CHECK: sil [clang Owner.handOutView] {{.*}} : $@convention(cxx_method) (@in_guaranteed Owner) -> _lifetime(_borrow 0) @autoreleased View -// CHECK: sil [clang Owner.handOutView2] {{.*}} : $@convention(cxx_method) (View, @in_guaranteed Owner) -> _lifetime(_borrow 1) @autoreleased View -// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@guaranteed View, @guaranteed View) -> _lifetime(_copy 0, _copy 1) @autoreleased View -// CHECK: sil [clang View.init] {{.*}} : $@convention(c) () -> @out View +// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @autoreleased View +// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0) @autoreleased View +// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0, borrow 1) @autoreleased View +// CHECK: sil [clang Owner.handOutView] {{.*}} : $@convention(cxx_method) (@in_guaranteed Owner) -> @lifetime(borrow 0) @autoreleased View +// CHECK: sil [clang Owner.handOutView2] {{.*}} : $@convention(cxx_method) (View, @in_guaranteed Owner) -> @lifetime(borrow 1) @autoreleased View +// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@guaranteed View, @guaranteed View) -> @lifetime(copy 0, copy 1) @autoreleased View +// CHECK: sil [clang View.init] {{.*}} : $@convention(c) () -> @lifetime(immortal) @out View //--- test.swift diff --git a/test/ModuleInterface/Inputs/lifetime_dependence.swift b/test/ModuleInterface/Inputs/lifetime_dependence.swift index 4f4113ff8355b..9214b151695eb 100644 --- a/test/ModuleInterface/Inputs/lifetime_dependence.swift +++ b/test/ModuleInterface/Inputs/lifetime_dependence.swift @@ -1,7 +1,8 @@ public struct AnotherView : ~Escapable { @usableFromInline let _ptr: UnsafeRawBufferPointer @usableFromInline let _count: Int - internal init(_ ptr: UnsafeRawBufferPointer, _ count: Int) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + internal init(_ ptr: UnsafeRawBufferPointer, _ count: Int) { self._ptr = ptr self._count = count } @@ -11,25 +12,27 @@ public struct BufferView : ~Escapable { @usableFromInline let _ptr: UnsafeRawBufferPointer @usableFromInline let _count: Int @usableFromInline - internal init(_ ptr: UnsafeRawBufferPointer, _ count: Int) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + internal init(_ ptr: UnsafeRawBufferPointer, _ count: Int) { self._ptr = ptr self._count = count } @inlinable - internal init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) -> dependsOn(a) Self { + @lifetime(borrow a) + internal init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) { self.init(ptr, a.count) - return self } @inlinable - internal init(_ ptr: UnsafeRawBufferPointer, _ a: consuming AnotherView) -> dependsOn(a) Self { + @lifetime(a) + internal init(_ ptr: UnsafeRawBufferPointer, _ a: consuming AnotherView) { self.init(ptr, a._count) - return self } } @inlinable -public func derive(_ x: consuming BufferView) -> dependsOn(x) BufferView { +@lifetime(x) +public func derive(_ x: consuming BufferView) -> BufferView { return BufferView(x._ptr, x._count) } @@ -37,12 +40,14 @@ public func derive(_ x: consuming BufferView) -> dependsOn(x) BufferView { public func use(_ x: consuming BufferView) {} @inlinable -public func consumeAndCreate(_ view: consuming BufferView) -> dependsOn(view) BufferView { +@lifetime(view) +public func consumeAndCreate(_ view: consuming BufferView) -> BufferView { return BufferView(view._ptr, view._count) } @inlinable -public func deriveThisOrThat(_ this: consuming BufferView, _ that: consuming BufferView) -> dependsOn(this, that) BufferView { +@lifetime(this, that) +public func deriveThisOrThat(_ this: consuming BufferView, _ that: consuming BufferView) -> BufferView { if (Int.random(in: 1..<100) == 0) { return BufferView(this._ptr, this._count) } diff --git a/test/ModuleInterface/lifetime_dependence_test.swift b/test/ModuleInterface/lifetime_dependence_test.swift index f1198012c4584..4dc4c889f1059 100644 --- a/test/ModuleInterface/lifetime_dependence_test.swift +++ b/test/ModuleInterface/lifetime_dependence_test.swift @@ -21,12 +21,16 @@ // RUN: -enable-experimental-feature NonescapableTypes import lifetime_dependence +// CHECK: @lifetime(borrow a) +// CHECK-NEXT: @inlinable internal init(_ ptr: Swift.UnsafeRawBufferPointer, _ a: borrowing Swift.Array) { +// CHECK: @lifetime(a) +// CHECK-NEXT: @inlinable internal init(_ ptr: Swift.UnsafeRawBufferPointer, _ a: consuming lifetime_dependence.AnotherView) { -// CHECK: @inlinable internal init(_ ptr: Swift.UnsafeRawBufferPointer, _ a: borrowing Swift.Array) -> dependsOn(a) Self { -// CHECK: @inlinable internal init(_ ptr: Swift.UnsafeRawBufferPointer, _ a: consuming lifetime_dependence.AnotherView) -> dependsOn(a) Self { +// CHECK: @lifetime(x) +// CHECK-NEXT: @inlinable public func derive(_ x: consuming lifetime_dependence.BufferView) -> lifetime_dependence.BufferView { -// CHECK: @inlinable public func derive(_ x: consuming lifetime_dependence.BufferView) -> dependsOn(x) lifetime_dependence.BufferView { +// CHECK: @lifetime(view) +// CHECK-NEXT: @inlinable public func consumeAndCreate(_ view: consuming lifetime_dependence.BufferView) -> lifetime_dependence.BufferView { -// CHECK: @inlinable public func consumeAndCreate(_ view: consuming lifetime_dependence.BufferView) -> dependsOn(view) lifetime_dependence.BufferView { - -// CHECK: @inlinable public func deriveThisOrThat(_ this: consuming lifetime_dependence.BufferView, _ that: consuming lifetime_dependence.BufferView) -> dependsOn(this) dependsOn(that) lifetime_dependence.BufferView { +// CHECK: @lifetime(this, that) +// CHECK-NEXT: @inlinable public func deriveThisOrThat(_ this: consuming lifetime_dependence.BufferView, _ that: consuming lifetime_dependence.BufferView) -> lifetime_dependence.BufferView { diff --git a/test/ModuleInterface/nonescapable_types.swift b/test/ModuleInterface/nonescapable_types.swift index d42943cd5bf51..869e1929f484a 100644 --- a/test/ModuleInterface/nonescapable_types.swift +++ b/test/ModuleInterface/nonescapable_types.swift @@ -79,10 +79,12 @@ public func derive(_ y: Y) -> Y { } // CHECK: #if compiler(>=5.3) && $NonescapableTypes -// CHECK: public func derive(_ x: Test.X) -> dependsOn(x) Test.X where T : ~Escapable +// CHECK: @lifetime(x) +// CHECK: public func derive(_ x: Test.X) -> Test.X where T : ~Escapable // CHECK: #else // CHECK: public func derive(_ x: Test.X) -> Test.X // CHECK: #endif -public func derive(_ x: X) -> dependsOn(x) X { +@lifetime(x) +public func derive(_ x: X) -> X { x } diff --git a/test/Parse/explicit_lifetime_dependence_specifiers.swift b/test/Parse/explicit_lifetime_dependence_specifiers.swift deleted file mode 100644 index 0f9561aeda470..0000000000000 --- a/test/Parse/explicit_lifetime_dependence_specifiers.swift +++ /dev/null @@ -1,167 +0,0 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -enable-builtin-module -// REQUIRES: asserts - -import Builtin - -struct BufferView : ~Escapable { - let ptr: UnsafeRawBufferPointer - init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self { - self.ptr = ptr - } - // TODO: -> dependsOn(ptr) Self - @_unsafeNonescapableResult - init?(_ ptr: UnsafeRawBufferPointer, _ i: Int) { - if (i % 2 == 0) { - return nil - } - self.ptr = ptr - } - init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) -> dependsOn(a) Self { - self.ptr = ptr - return self - } - init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper) -> dependsOn(a) Self { - self.ptr = ptr - return self - } - init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper, b: borrowing Array) -> dependsOn(a) dependsOn(scoped b) Self { - self.ptr = ptr - return self - } - init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array, b: borrowing Array, c: Double) -> dependsOn(scoped a) dependsOn(b) Int { // expected-error{{expected Self return type for initializers with lifetime dependence specifiers}} - self.ptr = ptr - return 0 - } - /* TODO: Enable this test once Optional is ~Escapable - init?(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array, _ i: Int) -> dependsOn(a) Self? { - if (i % 2 == 0) { - self.ptr = ptr - return self - } - return nil - } - */ -} - -struct MutableBufferView : ~Escapable, ~Copyable { - let ptr: UnsafeMutableRawBufferPointer - init(_ ptr: UnsafeMutableRawBufferPointer) -> dependsOn(ptr) Self { - self.ptr = ptr - } -} - -func testBasic() { - let capacity = 4 - let a = Array(0.. dependsOn(x) BufferView { - return BufferView(x.ptr) -} - -func consumeAndCreate(_ x: consuming BufferView) -> dependsOn(x) BufferView { - return BufferView(x.ptr) -} - -func use(_ x: borrowing BufferView) {} - -func deriveMultiView1(_ x: borrowing BufferView, _ y: borrowing BufferView) -> dependsOn(x, y) BufferView { - if (Int.random(in: 1..<100) % 2 == 0) { - return BufferView(x.ptr) - } - return BufferView(y.ptr) -} - -func deriveMultiView2(_ x: borrowing BufferView, _ y: borrowing BufferView) -> dependsOn(x) dependsOn(y) BufferView { - if (Int.random(in: 1..<100) % 2 == 0) { - return BufferView(x.ptr) - } - return BufferView(y.ptr) -} - -func consumeAndCreateMultiView1(_ x: consuming BufferView, _ y: consuming BufferView) -> dependsOn(x, y) BufferView { - if (Int.random(in: 1..<100) % 2 == 0) { - return BufferView(x.ptr) - } - return BufferView(y.ptr) -} - -func consumeAndCreateMultiView2(_ x: consuming BufferView, _ y: consuming BufferView) -> dependsOn(x) dependsOn(y) BufferView { - if (Int.random(in: 1..<100) % 2 == 0) { - return BufferView(x.ptr) - } - return BufferView(y.ptr) -} - -func mixedMultiView(_ x: consuming BufferView, _ y: borrowing BufferView) -> dependsOn(x) dependsOn(y) BufferView { - if (Int.random(in: 1..<100) % 2 == 0) { - return BufferView(x.ptr) - } - return BufferView(y.ptr) -} - -func modifiedViewDependsOnInput(_ x: inout MutableBufferView) -> dependsOn(x) MutableBufferView { - return MutableBufferView(x.ptr) -} - -func modifiedViewDependsOnParent(_ x: inout MutableBufferView) -> dependsOn(x) MutableBufferView { - return MutableBufferView(x.ptr) -} - -func invalidSpecifier1(_ x: borrowing BufferView) -> dependsOn BufferView { // expected-error{{expected '(' after lifetime dependence specifier}} - return BufferView(x.ptr) -} - -func invalidSpecifier2(_ x: borrowing BufferView) -> dependsOn() BufferView {// expected-error{{expected identifier, index or self in lifetime dependence specifier}} - return BufferView(x.ptr) -} - -func invalidSpecifier3(_ x: borrowing BufferView) -> dependsOn(*) BufferView { // expected-error{{expected identifier, index or self in lifetime dependence specifier}} - return BufferView(x.ptr) -} - -// TODO: Diagnose using param indices on func decls in sema -func invalidSpecifier4(_ x: borrowing BufferView) -> dependsOn(self) BufferView { // expected-error{{invalid lifetime dependence specifier on non-existent self}} - return BufferView(x.ptr) -} - -struct Wrapper : ~Escapable { - let view: BufferView - init(_ view: consuming BufferView) -> dependsOn(view) Self { - self.view = view - return self - } - borrowing func getView1() -> dependsOn(self) BufferView { - return view - } - - consuming func getView2() -> dependsOn(self) BufferView { - return view - } - - mutating func getView3() -> dependsOn(self) BufferView { - return view - } - - borrowing func getView4() -> dependsOn(self) BufferView { - return view - } -} - -enum FakeOptional: ~Escapable { - case none, some(Wrapped) -} - -extension FakeOptional: Escapable where Wrapped: Escapable {} - -extension FakeOptional where Wrapped: ~Escapable { - init(nilLiteral: ()) -> dependsOn(immortal) Self { - self = .none - } -} diff --git a/test/SIL/Parser/lifetime_dependence.sil b/test/SIL/Parser/lifetime_dependence.sil index 60be8083ea3ee..11247d9a1f1a2 100644 --- a/test/SIL/Parser/lifetime_dependence.sil +++ b/test/SIL/Parser/lifetime_dependence.sil @@ -8,13 +8,15 @@ import Swift struct BufferView : ~Escapable { @_hasStorage let ptr: UnsafeRawBufferPointer { get } - @inlinable init(_ ptr: UnsafeRawBufferPointer) -> _scope(ptr) Self - init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) -> _scope(a) Self + @lifetime(borrow ptr) @inlinable init(_ ptr: UnsafeRawBufferPointer) + @lifetime(borrow a) init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) } -func derive(_ x: borrowing BufferView) -> _scope(x) BufferView +@lifetime(borrow x) +func derive(_ x: borrowing BufferView) -> BufferView -func consumeAndCreate(_ x: consuming BufferView) -> _inherit(x) BufferView +@lifetime(x) +func consumeAndCreate(_ x: consuming BufferView) -> BufferView sil hidden [unsafe_nonescapable_result] @bufferviewinit1 : $@convention(method) (UnsafeRawBufferPointer, @thin BufferView.Type) -> @owned BufferView { bb0(%0 : $UnsafeRawBufferPointer, %1 : $@thin BufferView.Type): @@ -30,8 +32,8 @@ bb0(%0 : $UnsafeRawBufferPointer, %1 : $@thin BufferView.Type): return %8 : $BufferView } -// CHECK-LABEL: sil hidden @bufferviewtest2 : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> _scope(1) @owned BufferView { -sil hidden @bufferviewtest2 : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> _scope(1) @owned BufferView { +// CHECK-LABEL: sil hidden @bufferviewtest2 : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> @lifetime(borrow 1) @owned BufferView { +sil hidden @bufferviewtest2 : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> @lifetime(borrow 1) @owned BufferView { bb0(%0 : $UnsafeRawBufferPointer, %1 : @noImplicitCopy $Array, %2 : $@thin BufferView.Type): %3 = alloc_stack [var_decl] $BufferView, var, name "self" %6 = begin_access [modify] [static] %3 : $*BufferView @@ -44,8 +46,8 @@ bb0(%0 : $UnsafeRawBufferPointer, %1 : @noImplicitCopy $Array, %2 : $@thin return %10 : $BufferView } -// CHECK-LABEL: sil hidden @derive : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView { -sil hidden @derive : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView { +// CHECK-LABEL: sil hidden @derive : $@convention(thin) (@guaranteed BufferView) -> @lifetime(borrow 0) @owned BufferView { +sil hidden @derive : $@convention(thin) (@guaranteed BufferView) -> @lifetime(borrow 0) @owned BufferView { bb0(%0 : @noImplicitCopy $BufferView): %2 = metatype $@thin BufferView.Type %3 = struct_extract %0 : $BufferView, #BufferView.ptr @@ -54,8 +56,8 @@ bb0(%0 : @noImplicitCopy $BufferView): return %5 : $BufferView } -// CHECK-LABEL: sil hidden @consumeAndCreate : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView { -sil hidden @consumeAndCreate : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView { +// CHECK-LABEL: sil hidden @consumeAndCreate : $@convention(thin) (@owned BufferView) -> @lifetime(copy 0) @owned BufferView { +sil hidden @consumeAndCreate : $@convention(thin) (@owned BufferView) -> @lifetime(copy 0) @owned BufferView { bb0(%0 : @noImplicitCopy @_eagerMove $BufferView): %1 = alloc_stack [var_decl] [moveable_value_debuginfo] $BufferView, var, name "x" %2 = struct_extract %0 : $BufferView, #BufferView.ptr diff --git a/test/SIL/explicit_lifetime_dependence_specifiers.swift b/test/SIL/explicit_lifetime_dependence_specifiers.swift index 06f814a91678d..ebddc2abf271f 100644 --- a/test/SIL/explicit_lifetime_dependence_specifiers.swift +++ b/test/SIL/explicit_lifetime_dependence_specifiers.swift @@ -7,11 +7,11 @@ import Builtin struct BufferView : ~Escapable { let ptr: UnsafeRawBufferPointer -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSWcfC : $@convention(method) (UnsafeRawBufferPointer, @thin BufferView.Type) -> _scope(0) @owned BufferView { - init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSWcfC : $@convention(method) (UnsafeRawBufferPointer, @thin BufferView.Type) -> @lifetime(borrow 0) @owned BufferView { + @lifetime(borrow ptr) + init(_ ptr: UnsafeRawBufferPointer) { self.ptr = ptr } - // TODO: -> dependsOn(ptr) Self @_unsafeNonescapableResult init?(_ ptr: UnsafeRawBufferPointer, _ i: Int) { if (i % 2 == 0) { @@ -23,26 +23,27 @@ struct BufferView : ~Escapable { init(independent ptr: UnsafeRawBufferPointer) { self.ptr = ptr } - // CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> _scope(1) @owned BufferView { - init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) -> dependsOn(a) Self { + // CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> @lifetime(borrow 1) @owned BufferView { + @lifetime(borrow a) + init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) { self.ptr = ptr - return self } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_AA7WrapperVtcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Wrapper, @thin BufferView.Type) -> _inherit(1) @owned BufferView { - init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper) -> dependsOn(a) Self { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_AA7WrapperVtcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Wrapper, @thin BufferView.Type) -> @lifetime(copy 1) @owned BufferView { + @lifetime(a) + init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper) { self.ptr = ptr - return self } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_AA7WrapperVSaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Wrapper, @guaranteed Array, @thin BufferView.Type) -> _inherit(1) _scope(2) @owned BufferView { - init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper, _ b: borrowing Array) -> dependsOn(a) dependsOn(b) Self { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_AA7WrapperVSaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Wrapper, @guaranteed Array, @thin BufferView.Type) -> @lifetime(copy 1, borrow 2) @owned BufferView { + @lifetime(a, borrow b) + init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper, _ b: borrowing Array) { self.ptr = ptr - return self } } struct MutableBufferView : ~Escapable, ~Copyable { let ptr: UnsafeMutableRawBufferPointer - init(_ ptr: UnsafeMutableRawBufferPointer) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + init(_ ptr: UnsafeMutableRawBufferPointer) { self.ptr = ptr } } @@ -58,26 +59,30 @@ func testBasic() { } } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView { -func derive(_ x: borrowing BufferView) -> dependsOn(scoped x) BufferView { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(borrow 0) @owned BufferView { +@lifetime(borrow x) +func derive(_ x: borrowing BufferView) -> BufferView { return BufferView(independent: x.ptr) } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView { -func consumeAndCreate(_ x: consuming BufferView) -> dependsOn(x) BufferView { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> @lifetime(copy 0) @owned BufferView { +@lifetime(x) +func consumeAndCreate(_ x: consuming BufferView) -> BufferView { return BufferView(independent: x.ptr) } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers17deriveThisOrThat1yAA10BufferViewVAD_ADtF : $@convention(thin) (@guaranteed BufferView, @guaranteed BufferView) -> _scope(0, 1) @owned BufferView { -func deriveThisOrThat1(_ this: borrowing BufferView, _ that: borrowing BufferView) -> dependsOn(scoped this, that) BufferView { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers17deriveThisOrThat1yAA10BufferViewVAD_ADtF : $@convention(thin) (@guaranteed BufferView, @guaranteed BufferView) -> @lifetime(copy 1, borrow 0) @owned BufferView { +@lifetime(borrow this, that) +func deriveThisOrThat1(_ this: borrowing BufferView, _ that: borrowing BufferView) -> BufferView { if (Int.random(in: 1..<100) == 0) { return BufferView(independent: this.ptr) } return BufferView(independent: that.ptr) } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers17deriveThisOrThat2yAA10BufferViewVAD_ADntF : $@convention(thin) (@guaranteed BufferView, @owned BufferView) -> _inherit(1) _scope(0) @owned BufferView { -func deriveThisOrThat2(_ this: borrowing BufferView, _ that: consuming BufferView) -> dependsOn(scoped this) dependsOn(that) BufferView { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers17deriveThisOrThat2yAA10BufferViewVAD_ADntF : $@convention(thin) (@guaranteed BufferView, @owned BufferView) -> @lifetime(copy 1, borrow 0) @owned BufferView { +@lifetime(borrow this, that) +func deriveThisOrThat2(_ this: borrowing BufferView, _ that: consuming BufferView) -> BufferView { if (Int.random(in: 1..<100) == 0) { return BufferView(independent: this.ptr) } @@ -91,31 +96,36 @@ struct Wrapper : ~Escapable { init(_ view: consuming BufferView) { self.view = view } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers7WrapperV8getView1AA10BufferViewVyF : $@convention(method) (@guaranteed Wrapper) -> _scope(0) @owned BufferView { - borrowing func getView1() -> dependsOn(scoped self) BufferView { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers7WrapperV8getView1AA10BufferViewVyF : $@convention(method) (@guaranteed Wrapper) -> @lifetime(borrow 0) @owned BufferView { + @lifetime(borrow self) + borrowing func getView1() -> BufferView { return view } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers7WrapperV8getView2AA10BufferViewVyF : $@convention(method) (@owned Wrapper) -> _inherit(0) @owned BufferView { - consuming func getView2() -> dependsOn(self) BufferView { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers7WrapperV8getView2AA10BufferViewVyF : $@convention(method) (@owned Wrapper) -> @lifetime(copy 0) @owned BufferView { + @lifetime(self) + consuming func getView2() -> BufferView { return view } } struct Container : ~Escapable { let ptr: UnsafeRawBufferPointer - init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + init(_ ptr: UnsafeRawBufferPointer) { self.ptr = ptr } } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getConsumingViewyAA06BufferG0VAA9ContainerVnF : $@convention(thin) (@owned Container) -> _inherit(0) @owned BufferView { -func getConsumingView(_ x: consuming Container) -> dependsOn(x) BufferView { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getConsumingViewyAA06BufferG0VAA9ContainerVnF : $@convention(thin) (@owned Container) -> @lifetime(copy 0) @owned BufferView { +@lifetime(x) +func getConsumingView(_ x: consuming Container) -> BufferView { return BufferView(independent: x.ptr) } -// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getBorrowingViewyAA06BufferG0VAA9ContainerVF : $@convention(thin) (@guaranteed Container) -> _scope(0) @owned BufferView { -func getBorrowingView(_ x: borrowing Container) -> dependsOn(scoped x) BufferView { +// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getBorrowingViewyAA06BufferG0VAA9ContainerVF : $@convention(thin) (@guaranteed Container) -> @lifetime(borrow 0) @owned BufferView { +@lifetime(borrow x) +func getBorrowingView(_ x: borrowing Container) -> BufferView { return BufferView(independent: x.ptr) } diff --git a/test/SIL/implicit_lifetime_dependence.swift b/test/SIL/implicit_lifetime_dependence.swift index 71fa9e294bf83..70444e42c2adf 100644 --- a/test/SIL/implicit_lifetime_dependence.swift +++ b/test/SIL/implicit_lifetime_dependence.swift @@ -6,7 +6,8 @@ struct BufferView : ~Escapable { let ptr: UnsafeRawBufferPointer let c: Int - init(_ ptr: UnsafeRawBufferPointer, _ c: Int) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + init(_ ptr: UnsafeRawBufferPointer, _ c: Int) { self.ptr = ptr self.c = c } @@ -15,17 +16,17 @@ struct BufferView : ~Escapable { self.ptr = ptr self.c = c } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyA2ChcfC : $@convention(method) (@guaranteed BufferView, @thin BufferView.Type) -> _inherit(0) @owned BufferView { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyA2ChcfC : $@convention(method) (@guaranteed BufferView, @thin BufferView.Type) -> @lifetime(copy 0) @owned BufferView { init(_ otherBV: borrowing BufferView) { self.ptr = otherBV.ptr self.c = otherBV.c } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyA2CcfC : $@convention(method) (@owned BufferView, @thin BufferView.Type) -> _inherit(0) @owned BufferView { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyA2CcfC : $@convention(method) (@owned BufferView, @thin BufferView.Type) -> @lifetime(copy 0) @owned BufferView { init(_ otherBV: consuming BufferView) { self.ptr = otherBV.ptr self.c = otherBV.c } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> _scope(1) @owned BufferView { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> @lifetime(borrow 1) @owned BufferView { init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) { self.ptr = ptr self.c = a.count @@ -35,7 +36,8 @@ struct BufferView : ~Escapable { struct MutableBufferView : ~Escapable, ~Copyable { let ptr: UnsafeMutableRawBufferPointer let c: Int - init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) { self.ptr = ptr self.c = c } @@ -51,7 +53,7 @@ func testBasic() { } } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _inherit(0) @owned BufferView { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(copy 0) @owned BufferView { func derive(_ x: borrowing BufferView) -> BufferView { return BufferView(x.ptr, x.c) } @@ -60,7 +62,7 @@ func derive(_ unused: Int, _ x: borrowing BufferView) -> BufferView { return BufferView(independent: x.ptr, x.c) } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> @lifetime(copy 0) @owned BufferView { func consumeAndCreate(_ x: consuming BufferView) -> BufferView { return BufferView(independent: x.ptr, x.c) } @@ -70,25 +72,25 @@ func use(_ x: borrowing BufferView) {} struct Wrapper : ~Escapable { var _view: BufferView var view: BufferView { -// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvr : $@yield_once @convention(method) (@guaranteed Wrapper) -> _inherit(0) @yields @guaranteed BufferView { +// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvr : $@yield_once @convention(method) (@guaranteed Wrapper) -> @lifetime(copy 0) @yields @guaranteed BufferView { _read { yield _view } -// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvM : $@yield_once @convention(method) (@inout Wrapper) -> _inherit(0) @yields @inout BufferView { +// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvM : $@yield_once @convention(method) (@inout Wrapper) -> @lifetime(copy 0) @yields @inout BufferView { _modify { yield &_view } } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperVyAcA10BufferViewVcfC : $@convention(method) (@owned BufferView, @thin Wrapper.Type) -> _inherit(0) @owned Wrapper { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperVyAcA10BufferViewVcfC : $@convention(method) (@owned BufferView, @thin Wrapper.Type) -> @lifetime(copy 0) @owned Wrapper { init(_ view: consuming BufferView) { self._view = view } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView1AA10BufferViewVyKF : $@convention(method) (@guaranteed Wrapper) -> _inherit(0) (@owned BufferView, @error any Error) { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView1AA10BufferViewVyKF : $@convention(method) (@guaranteed Wrapper) -> @lifetime(copy 0) (@owned BufferView, @error any Error) { borrowing func getView1() throws -> BufferView { return _view } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView2AA10BufferViewVyYaKF : $@convention(method) @async (@owned Wrapper) -> _inherit(0) (@owned BufferView, @error any Error) { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView2AA10BufferViewVyYaKF : $@convention(method) @async (@owned Wrapper) -> @lifetime(copy 0) (@owned BufferView, @error any Error) { consuming func getView2() async throws -> BufferView { return _view } @@ -97,7 +99,7 @@ struct Wrapper : ~Escapable { struct Container1 : ~Copyable { let ptr: UnsafeRawBufferPointer let c: Int -// CHECK: sil hidden @$s28implicit_lifetime_dependence10Container1V4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container1) -> _scope(0) @owned BufferView { +// CHECK: sil hidden @$s28implicit_lifetime_dependence10Container1V4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container1) -> @lifetime(borrow 0) @owned BufferView { var view: BufferView { get { return BufferView(ptr, c) @@ -108,7 +110,7 @@ struct Container1 : ~Copyable { struct Container2 : ~Copyable { let ptr: UnsafeMutableRawBufferPointer let c: Int -// CHECK: sil hidden @$s28implicit_lifetime_dependence10Container2V11mutableViewAA013MutableBufferF0Vvr : $@yield_once @convention(method) (@guaranteed Container2) -> _scope(0) @yields @guaranteed MutableBufferView { +// CHECK: sil hidden @$s28implicit_lifetime_dependence10Container2V11mutableViewAA013MutableBufferF0Vvr : $@yield_once @convention(method) (@guaranteed Container2) -> @lifetime(borrow 0) @yields @guaranteed MutableBufferView { var mutableView: MutableBufferView { _read { yield MutableBufferView(ptr, c) @@ -129,7 +131,7 @@ struct GenericBufferView : ~Escapable { let baseAddress: Pointer let count: Int -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence17GenericBufferViewV11baseAddress5countACyxGSV_SitcfC : $@convention(method) (UnsafeRawPointer, Int, @thin GenericBufferView.Type) -> _scope(0) @owned GenericBufferView { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence17GenericBufferViewV11baseAddress5countACyxGSV_SitcfC : $@convention(method) (UnsafeRawPointer, Int, @thin GenericBufferView.Type) -> @lifetime(borrow 0) @owned GenericBufferView { init(baseAddress: Pointer, count: Int, dependsOn: borrowing Storage) { @@ -137,7 +139,8 @@ struct GenericBufferView : ~Escapable { count: count) } // unsafe private API - init(baseAddress: Pointer, count: Int) -> dependsOn(baseAddress) Self { + @lifetime(borrow baseAddress) + init(baseAddress: Pointer, count: Int) { precondition(count >= 0, "Count must not be negative") self.baseAddress = baseAddress self.count = count @@ -152,7 +155,7 @@ struct GenericBufferView : ~Escapable { } } } -// CHECK: sil hidden @$s28implicit_lifetime_dependence17GenericBufferViewVyACyxGAA9FakeRangeVySVGcig : $@convention(method) (FakeRange, @guaranteed GenericBufferView) -> _inherit(1) @owned GenericBufferView { +// CHECK: sil hidden @$s28implicit_lifetime_dependence17GenericBufferViewVyACyxGAA9FakeRangeVySVGcig : $@convention(method) (FakeRange, @guaranteed GenericBufferView) -> @lifetime(copy 1) @owned GenericBufferView { subscript(bounds: FakeRange) -> Self { get { GenericBufferView( @@ -163,7 +166,7 @@ struct GenericBufferView : ~Escapable { } } -// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence23tupleLifetimeDependenceyAA10BufferViewV_ADtADF : $@convention(thin) (@guaranteed BufferView) -> _inherit(0) (@owned BufferView, @owned BufferView) { +// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence23tupleLifetimeDependenceyAA10BufferViewV_ADtADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(copy 0) (@owned BufferView, @owned BufferView) { func tupleLifetimeDependence(_ x: borrowing BufferView) -> (BufferView, BufferView) { return (BufferView(x.ptr, x.c), BufferView(x.ptr, x.c)) } @@ -172,7 +175,7 @@ public struct OuterNE: ~Escapable { // A public property generates an implicit setter with an infered dependence on 'newValue'. // // [inner1.setter] - // CHECK-LABEL: sil [transparent] @$s28implicit_lifetime_dependence7OuterNEV6inner1AC05InnerE0Vvs : $@convention(method) (@owned OuterNE.InnerNE, _inherit(0) @inout OuterNE) -> () { + // CHECK-LABEL: sil [transparent] @$s28implicit_lifetime_dependence7OuterNEV6inner1AC05InnerE0Vvs : $@convention(method) (@owned OuterNE.InnerNE, @lifetime(copy 0) @inout OuterNE) -> () { public var inner1: InnerNE // Explicit setter with an infered dependence on 'newValue'. @@ -184,16 +187,16 @@ public struct OuterNE: ~Escapable { public struct InnerNE: ~Escapable { init( owner: borrowing Owner - ) -> dependsOn(owner) Self {} + ) {} } - init(owner: borrowing Owner) -> dependsOn(owner) Self { + init(owner: borrowing Owner) { self.inner1 = InnerNE(owner: owner) } - // Infer a dependence from 'self' on 'value'. We might revoke this rule once we have dependsOn(self:) syntax. + // Infer a dependence from 'self' on 'value'. We might revoke this rule once we have syntax. // - // CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7OuterNEV8setInner5valueyAC0gE0V_tF : $@convention(method) (@guaranteed OuterNE.InnerNE, _inherit(0) @inout OuterNE) -> () { + // CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7OuterNEV8setInner5valueyAC0gE0V_tF : $@convention(method) (@guaranteed OuterNE.InnerNE, @lifetime(copy 0) @inout OuterNE) -> () { mutating func setInner(value: InnerNE) { self.inner1 = value } diff --git a/test/SIL/lifetime_dependence_buffer_view_test.swift b/test/SIL/lifetime_dependence_buffer_view_test.swift deleted file mode 100644 index 05e87c9d5b476..0000000000000 --- a/test/SIL/lifetime_dependence_buffer_view_test.swift +++ /dev/null @@ -1,169 +0,0 @@ -// RUN: %target-swift-frontend %s -emit-sil \ -// RUN: -enable-experimental-feature NonescapableTypes | %FileCheck %s - -// REQUIRES: asserts -// REQUIRES: swift_in_compiler - -// TODO: Use real Range -public struct FakeRange { - public let lowerBound: Bound - public let upperBound: Bound -} - -// TODO: Use real Optional -public enum FakeOptional { - case none - case some(T) -} - -public struct BufferViewIndex { - let _rawValue: UnsafeRawPointer - - internal init(rawValue: UnsafeRawPointer) { - _rawValue = rawValue - } - - var isAligned: Bool { - (Int(bitPattern: _rawValue) & (MemoryLayout.alignment-1)) == 0 - } -} - -extension BufferViewIndex: Equatable {} - -extension BufferViewIndex: Hashable {} - -extension BufferViewIndex: Strideable { - public typealias Stride = Int - - public func distance(to other: BufferViewIndex) -> Int { - let bytes = _rawValue.distance(to: other._rawValue) - let (q, r) = bytes.quotientAndRemainder(dividingBy: MemoryLayout.stride) - precondition(r == 0) - return q - } - - public func advanced(by n: Int) -> BufferViewIndex { - .init(rawValue: _rawValue.advanced(by: n &* MemoryLayout.stride)) - } -} - -extension BufferViewIndex: Comparable { - public static func <(lhs: BufferViewIndex, rhs: BufferViewIndex) -> Bool { - lhs._rawValue < rhs._rawValue - } -} - -public struct BufferView : ~Escapable { - let start: BufferViewIndex - public let count: Int - private var baseAddress: UnsafeRawPointer { start._rawValue } -// CHECK: sil @$s36lifetime_dependence_buffer_view_test10BufferViewV11baseAddress5count9dependsOnACyxGSV_Siqd__htcRi_d__Ri0_d__lufC : $@convention(method) (UnsafeRawPointer, Int, @in_guaranteed Owner, @thin BufferView.Type) -> _inherit(2) @owned BufferView { - public init( - baseAddress: UnsafeRawPointer, - count: Int, - dependsOn owner: borrowing Owner - ) { - self.init( - start: .init(rawValue: baseAddress), count: count, dependsOn: owner - ) - } -// CHECK: sil hidden @$s36lifetime_dependence_buffer_view_test10BufferViewV5start5count9dependsOnACyxGAA0fG5IndexVyxG_Siqd__htcRi_d__Ri0_d__lufC : $@convention(method) (BufferViewIndex, Int, @in_guaranteed Owner, @thin BufferView.Type) -> _inherit(2) @owned BufferView { - init( - start index: BufferViewIndex, - count: Int, - dependsOn owner: borrowing Owner - ) { - precondition(count >= 0, "Count must not be negative") - if !_isPOD(Element.self) { - precondition( - index.isAligned, - "baseAddress must be properly aligned for \(Element.self)" - ) - } - self.start = index - self.count = count - } - @_unsafeNonescapableResult - init(start index: BufferViewIndex, - count: Int) { - precondition(count >= 0, "Count must not be negative") - if !_isPOD(Element.self) { - precondition( - index.isAligned, - "baseAddress must be properly aligned for \(Element.self)" - ) - } - self.start = index - self.count = count - } -} -// TODO: extend Collection, BidirectionalCollection, RandomAccessCollection { -extension BufferView { - public typealias Index = BufferViewIndex - public typealias SubSequence = Self - - public var startIndex: Index { start } - public var endIndex: Index { start.advanced(by: count) } - - @inlinable @inline(__always) - public func distance(from start: Index, to end: Index) -> Int { - start.distance(to: end) - } - - public subscript(position: Index) -> Element { - get { - if _isPOD(Element.self) { - return position._rawValue.loadUnaligned(as: Element.self) - } - else { - return position._rawValue.load(as: Element.self) - } - } - } - - // CHECK: sil @$s36lifetime_dependence_buffer_view_test10BufferViewVyACyxGAA9FakeRangeVyAA0fG5IndexVyxGGcig : $@convention(method) (FakeRange>, @guaranteed BufferView) -> _inherit(1) @owned BufferView { - public subscript(bounds: FakeRange>) -> Self { - get { - BufferView( - start: bounds.lowerBound, - count: bounds.upperBound.distance(to:bounds.lowerBound) / MemoryLayout.stride - ) - } - } - - borrowing public func prefix(upTo index: BufferViewIndex) -> dependsOn(self) Self { - index == startIndex - ? Self(start: start, count: 0, dependsOn: copy self) - : prefix(through: index.advanced(by: -1)) - } - - borrowing public func prefix(through index: Index) -> dependsOn(self) Self { - let nc = distance(from: startIndex, to: index) &+ 1 - return Self(start: start, count: nc, dependsOn: copy self) - } - - consuming public func prefix(_ maxLength: Int) -> dependsOn(self) Self { - precondition(maxLength >= 0, "Can't have a prefix of negative length.") - let nc = maxLength < count ? maxLength : count - return Self(start: start, count: nc, dependsOn: self) - } -} - -extension ContiguousArray { - public var view: BufferView { - borrowing _read { - yield BufferView( - baseAddress: _baseAddressIfContiguous!, count: count, dependsOn: self - ) - } - } -} - -public func array_view_element(a: ContiguousArray , i: BufferViewIndex) -> Int { - a.view[i] -} - -public func array_view_slice_element(a: ContiguousArray , sliceIdx: FakeRange>, Idx: BufferViewIndex) -> Int { - a.view[sliceIdx][Idx] -} - diff --git a/test/SIL/lifetime_dependence_generics.swift b/test/SIL/lifetime_dependence_generics.swift index e5f476bf146bd..debc4c732a1b5 100644 --- a/test/SIL/lifetime_dependence_generics.swift +++ b/test/SIL/lifetime_dependence_generics.swift @@ -7,11 +7,13 @@ protocol P { associatedtype E: ~Escapable - borrowing func getE() -> dependsOn(self) E + @lifetime(borrow self) + borrowing func getE() -> E } extension P { - borrowing func getDefault() -> dependsOn(self) E { + @lifetime(borrow self) + borrowing func getDefault() -> E { return getE() } } @@ -23,17 +25,17 @@ public struct View: ~Escapable { } public struct PView: P { - borrowing func getE() -> dependsOn(self) View { return View() } + borrowing func getE() -> View { return View() } } -public func test(pview: borrowing PView) -> dependsOn(pview) View { +public func test(pview: borrowing PView) -> View { return pview.getDefault() } -// CHECK-LABEL: sil hidden @$s28lifetime_dependence_generics1PPAAE10getDefault1EQzyF : $@convention(method) (@in_guaranteed Self) -> _scope(0) @out Self.E { +// CHECK-LABEL: sil hidden @$s28lifetime_dependence_generics1PPAAE10getDefault1EQzyF : $@convention(method) (@in_guaranteed Self) -> @lifetime(borrow 0) @out Self.E { -// CHECK-LABEL: sil hidden @$s28lifetime_dependence_generics5PViewV4getEAA4ViewVyF : $@convention(method) (PView) -> _scope(0) @owned View { +// CHECK-LABEL: sil hidden @$s28lifetime_dependence_generics5PViewV4getEAA4ViewVyF : $@convention(method) (PView) -> @lifetime(borrow 0) @owned View { -// CHECK-LABEL: sil private [transparent] [thunk] @$s28lifetime_dependence_generics5PViewVAA1PA2aDP4getE1EQzyFTW : $@convention(witness_method: P) (@in_guaranteed PView) -> _scope(0) @out View { +// CHECK-LABEL: sil private [transparent] [thunk] @$s28lifetime_dependence_generics5PViewVAA1PA2aDP4getE1EQzyFTW : $@convention(witness_method: P) (@in_guaranteed PView) -> @lifetime(borrow 0) @out View { -// CHECK-LABEL: sil @$s28lifetime_dependence_generics4test5pviewAA4ViewVAA5PViewV_tF : $@convention(thin) (PView) -> _scope(0) @owned View { +// CHECK-LABEL: sil @$s28lifetime_dependence_generics4test5pviewAA4ViewVAA5PViewV_tF : $@convention(thin) (PView) -> @lifetime(borrow 0) @owned View { diff --git a/test/SIL/lifetime_dependence_param_position_test.swift b/test/SIL/lifetime_dependence_param_position_test.swift index 1965da5086c30..af2b543fb1e8a 100644 --- a/test/SIL/lifetime_dependence_param_position_test.swift +++ b/test/SIL/lifetime_dependence_param_position_test.swift @@ -13,9 +13,8 @@ public struct Span : ~Escapable { count: Int, dependsOn owner: borrowing Owner ) { - self.init( - baseAddress: baseAddress, count: count, dependsOn: owner - ) + self.baseAddress = baseAddress + self.count = count } } @@ -29,8 +28,9 @@ extension ContiguousArray { } } -// CHECK-LABEL: sil hidden [ossa] @$s39lifetime_dependence_param_position_test11mayReassign4span2toyAA4SpanVySiGzYlsUS__s15ContiguousArrayVySiGtF : $@convention(thin) (@inout Span, @guaranteed ContiguousArray) -> _scope(1) () { -func mayReassign(span: dependsOn(to) inout Span, to: ContiguousArray) { +// CHECK-LABEL: sil hidden @$s39lifetime_dependence_param_position_test11mayReassign4span2toyAA4SpanVySiGz_s15ContiguousArrayVySiGtF : $@convention(thin) (_lifetime(_borrow 1) @inout Span, @guaranteed ContiguousArray) -> () { +@lifetime(span: borrow to) +func mayReassign(span: inout Span, to: ContiguousArray) { span = to.span } diff --git a/test/SIL/lifetime_dependence_span_lifetime_attr.swift b/test/SIL/lifetime_dependence_span_lifetime_attr.swift index fd2d6a8134052..1889d2d01f427 100644 --- a/test/SIL/lifetime_dependence_span_lifetime_attr.swift +++ b/test/SIL/lifetime_dependence_span_lifetime_attr.swift @@ -1,7 +1,6 @@ // RUN: %target-swift-frontend %s -emit-sil \ // RUN: -enable-experimental-feature NonescapableTypes \ -// RUN: -disable-experimental-parser-round-trip -// FIXME: Remove '-disable-experimental-parser-round-trip'. +// RUN: -disable-experimental-parser-round-trip | %FileCheck %s // REQUIRES: asserts // REQUIRES: swift_in_compiler @@ -59,7 +58,7 @@ public struct Span : ~Escapable { let start: SpanIndex public let count: Int private var baseAddress: UnsafeRawPointer { start._rawValue } -// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanV11baseAddress5count9dependsOnACyxGSV_Siqd__htcRi_d__Ri0_d__lufC : $@convention(method) (UnsafeRawPointer, Int, @in_guaranteed Owner, @thin Span.Type) -> _inherit(2) @owned Span { +// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanV11baseAddress5count9dependsOnACyxGSV_Siqd__htcRi_d__Ri0_d__lufC : $@convention(method) (UnsafeRawPointer, Int, @in_guaranteed Owner, @thin Span.Type) -> @lifetime(copy 2) @owned Span { @lifetime(owner) public init( baseAddress: UnsafeRawPointer, @@ -70,7 +69,7 @@ public struct Span : ~Escapable { start: .init(rawValue: baseAddress), count: count, dependsOn: owner ) } -// CHECK-LABEL: sil hidden @$s025lifetime_dependence_span_A5_attr4SpanV5start5count9dependsOnACyxGAA0E5IndexVyxG_Siqd__htcRi_d__Ri0_d__lufC : $@convention(method) (SpanIndex, Int, @in_guaranteed Owner, @thin Span.Type) -> _inherit(2) @owned Span { +// CHECK-LABEL: sil hidden @$s025lifetime_dependence_span_A5_attr4SpanV5start5count9dependsOnACyxGAA0E5IndexVyxG_Siqd__htcRi_d__Ri0_d__lufC : $@convention(method) (SpanIndex, Int, @in_guaranteed Owner, @thin Span.Type) -> @lifetime(copy 2) @owned Span { @lifetime(owner) init( start index: SpanIndex, @@ -125,7 +124,7 @@ extension Span { } } -// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanVyACyxGAA9FakeRangeVyAA0E5IndexVyxGGcig : $@convention(method) (FakeRange>, @guaranteed Span) -> _inherit(1) @owned Span { +// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanVyACyxGAA9FakeRangeVyAA0E5IndexVyxGGcig : $@convention(method) (FakeRange>, @guaranteed Span) -> @lifetime(copy 1) @owned Span { public subscript(bounds: FakeRange>) -> Self { @lifetime(self) get { @@ -136,7 +135,7 @@ extension Span { } } -// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanV6prefix4upToACyxGAA0E5IndexVyxG_tF : $@convention(method) (SpanIndex, @guaranteed Span) -> _inherit(1) @owned Span { +// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanV6prefix4upToACyxGAA0E5IndexVyxG_tF : $@convention(method) (SpanIndex, @guaranteed Span) -> @lifetime(copy 1) @owned Span { @lifetime(self) borrowing public func prefix(upTo index: SpanIndex) -> Self { index == startIndex @@ -144,14 +143,14 @@ extension Span { : prefix(through: index.advanced(by: -1)) } -// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanV6prefix7throughACyxGAA0E5IndexVyxG_tF : $@convention(method) (SpanIndex, @guaranteed Span) -> _inherit(1) @owned Span { +// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanV6prefix7throughACyxGAA0E5IndexVyxG_tF : $@convention(method) (SpanIndex, @guaranteed Span) -> @lifetime(copy 1) @owned Span { @lifetime(self) borrowing public func prefix(through index: Index) -> Self { let nc = distance(from: startIndex, to: index) &+ 1 return Self(start: start, count: nc, dependsOn: copy self) } -// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanV6prefixyACyxGSiF : $@convention(method) (Int, @owned Span) -> _inherit(1) @owned Span { +// CHECK-LABEL: sil @$s025lifetime_dependence_span_A5_attr4SpanV6prefixyACyxGSiF : $@convention(method) (Int, @owned Span) -> @lifetime(copy 1) @owned Span { @lifetime(self) consuming public func prefix(_ maxLength: Int) -> Self { precondition(maxLength >= 0, "Can't have a prefix of negative length.") diff --git a/test/SILOptimizer/capture_promotion_ownership.sil b/test/SILOptimizer/capture_promotion_ownership.sil index cb614a440e4f7..051e100541ad8 100644 --- a/test/SILOptimizer/capture_promotion_ownership.sil +++ b/test/SILOptimizer/capture_promotion_ownership.sil @@ -521,7 +521,7 @@ bb0(%0 : @owned $Builtin.NativeObject): return %pai : $@callee_owned () -> () } -sil @foo_dependence : $@convention(thin) (@guaranteed Foo) -> _scope(0) @owned Nonescapable +sil @foo_dependence : $@convention(thin) (@guaranteed Foo) -> @lifetime(borrow 0) @owned Nonescapable sil @use_nonescapable : $@convention(thin) (@guaranteed Nonescapable) -> () // Test that the pass does not crash when it sees a mark_dependence on an alloc_box base that does not have a partial_apply value. @@ -537,8 +537,8 @@ bb0: store %13 to [init] %8 : $*Foo %16 = load_borrow %8 : $*Foo - %17 = function_ref @foo_dependence : $@convention(thin) (@guaranteed Foo) -> _scope(0) @owned Nonescapable - %18 = apply %17(%16) : $@convention(thin) (@guaranteed Foo) -> _scope(0) @owned Nonescapable + %17 = function_ref @foo_dependence : $@convention(thin) (@guaranteed Foo) -> @lifetime(borrow 0) @owned Nonescapable + %18 = apply %17(%16) : $@convention(thin) (@guaranteed Foo) -> @lifetime(borrow 0) @owned Nonescapable %19 = mark_dependence [unresolved] %18 : $Nonescapable on %6 : ${ let Foo } %20 = move_value [var_decl] %19 : $Nonescapable diff --git a/test/SILOptimizer/lifetime_dependence/initializer.swift b/test/SILOptimizer/lifetime_dependence/initializer.swift index f58ade99aa39b..19a8bd2c19d1e 100644 --- a/test/SILOptimizer/lifetime_dependence/initializer.swift +++ b/test/SILOptimizer/lifetime_dependence/initializer.swift @@ -18,7 +18,8 @@ struct Span: ~Escapable { self.count = count } - init(base: UnsafePointer, count: Int, generic: borrowing S) -> dependsOn(generic) Self { + @lifetime(borrow generic) + init(base: UnsafePointer, count: Int, generic: borrowing S) { self.base = base self.count = count } diff --git a/test/SILOptimizer/lifetime_dependence/inout.swift b/test/SILOptimizer/lifetime_dependence/inout.swift index 4fa30a047eeb0..19a8bd2c19d1e 100644 --- a/test/SILOptimizer/lifetime_dependence/inout.swift +++ b/test/SILOptimizer/lifetime_dependence/inout.swift @@ -18,49 +18,30 @@ struct Span: ~Escapable { self.count = count } - init(base: UnsafePointer, count: Int, generic: borrowing S) -> dependsOn(generic) Self { + @lifetime(borrow generic) + init(base: UnsafePointer, count: Int, generic: borrowing S) { self.base = base self.count = count } } -extension Array { - // TODO: comment out dependsOn(scoped) - borrowing func span() -> /* dependsOn(scoped self) */ Span { - /* not the real implementation */ - let p = self.withUnsafeBufferPointer { $0.baseAddress! } - return Span(base: p, count: 1) - } -} - -// Reassign an inout argument to a value that depends on the lifetime of another argument. -func mayReassign(span: dependsOn(a) inout Span, to a: Array) { - span = a.span() -} +struct Wrapper: ~Escapable { + private let span: Span -public struct OuterNE: ~Escapable { - // Generates a setter with an inferred dependence on the new value. - public var inner1: InnerNE - - // Explicit setter with an infered dependence on 'newValue'. - public var inner2: InnerNE { - get { inner1 } - set { inner1 = newValue } + init(span: borrowing Span) { + self.span = copy span } +} - // Modify yields inout self. - public var inner3: InnerNE { - _read { yield inner1 } - _modify { yield &inner1 } - } +struct SuperWrapper: ~Escapable { + private let wrapper: Wrapper - public struct InnerNE: ~Escapable { - init( - owner: borrowing Owner - ) -> dependsOn(owner) Self {} - } + // An extra field forces a projection on 'self' within the initializer without any access scope. + var depth: Int = 0 - init(owner: borrowing Owner) -> dependsOn(owner) Self { - self.inner1 = InnerNE(owner: owner) + // Make sure that LocalVariableUtils can successfully analyze 'self'. That's required to determine that the assignment + // of `wrapper` is returned without escaping + init(span: borrowing Span) { + self.wrapper = Wrapper(span: span) } } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil b/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil index 22be9ed6ee995..535e08fa55b70 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil @@ -15,8 +15,8 @@ class C {} struct Nonescapable: ~Escapable {} -sil @c_dependence : $@convention(thin) (@guaranteed C) -> _scope(0) @owned Nonescapable -sil @immortal_dependence : $@convention(thin) () -> _scope(immortal) @owned Nonescapable +sil @c_dependence : $@convention(thin) (@guaranteed C) -> @lifetime(borrow 0) @owned Nonescapable +sil @immortal_dependence : $@convention(thin) () -> @lifetime(borrow immortal) @owned Nonescapable // Test that SILType.isEscpable does not crash on a generic box when NoncopyableGenerics is enabled. sil shared [serialized] [ossa] @testLocalFunc : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () { @@ -29,8 +29,8 @@ bb0(%1 : @closureCapture @guaranteed $<τ_0_0> { var τ_0_0 } ): sil [ossa] @test_mark_dependence_store : $@convention(thin) (@owned C) -> () { bb0(%0 : @owned $C): %stk = alloc_stack [var_decl] $Nonescapable - %f = function_ref @c_dependence : $@convention(thin) (@guaranteed C) -> _scope(0) @owned Nonescapable - %c = apply %f(%0) : $@convention(thin) (@guaranteed C) -> _scope(0) @owned Nonescapable + %f = function_ref @c_dependence : $@convention(thin) (@guaranteed C) -> @lifetime(borrow 0) @owned Nonescapable + %c = apply %f(%0) : $@convention(thin) (@guaranteed C) -> @lifetime(borrow 0) @owned Nonescapable %md = mark_dependence [nonescaping] %c : $Nonescapable on %0 : $C store %md to [init] %stk : $*Nonescapable @@ -44,8 +44,8 @@ bb0(%0 : @owned $C): sil [ossa] @test_immortal_dependence : $@convention(thin) () -> () { bb0: - %f = function_ref @immortal_dependence : $@convention(thin) () -> _scope(immortal) @owned Nonescapable - %c = apply %f() : $@convention(thin) () -> _scope(immortal) @owned Nonescapable + %f = function_ref @immortal_dependence : $@convention(thin) () -> @lifetime(borrow immortal) @owned Nonescapable + %c = apply %f() : $@convention(thin) () -> @lifetime(borrow immortal) @owned Nonescapable destroy_value %c : $Nonescapable %t = tuple () return %t : $() @@ -53,4 +53,4 @@ bb0: public struct Container : ~Copyable, ~Escapable where Element : ~Copyable {} -sil [ossa] @parseInoutDep : $@convention(method) (_lifetime(_copy 0) @inout Container) -> () +sil [ossa] @parseInoutDep : $@convention(method) (@lifetime(copy 0) @inout Container) -> () diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_borrow.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_borrow.swift index d103d2a3800fa..e1f58726a9efd 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_borrow.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_borrow.swift @@ -21,7 +21,8 @@ struct BV : ~Escapable { public var isEmpty: Bool { i == 0 } - init(_ p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } @@ -37,13 +38,15 @@ struct MBV : ~Escapable, ~Copyable { let p: UnsafeRawPointer let i: Int - init(_ p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } // Requires a borrow. - borrowing func getBV() -> dependsOn(self) BV { + @lifetime(self) + borrowing func getBV() -> BV { BV(p, i) } } @@ -58,22 +61,26 @@ struct NEBV : ~Escapable { } // Propagate a borrow. -func bv_get_borrow(container: borrowing MBV) -> dependsOn(container) BV { +@lifetime(container) +func bv_get_borrow(container: borrowing MBV) -> BV { container.getBV() } // Copy a borrow. -func bv_get_copy(container: borrowing MBV) -> dependsOn(container) BV { +@lifetime(container) +func bv_get_copy(container: borrowing MBV) -> BV { return container.getBV() } // Recognize nested accesses as part of the same dependence scope. -func bv_get_mutate(container: inout MBV) -> dependsOn(container) BV { +@lifetime(container) +func bv_get_mutate(container: inout MBV) -> BV { container.getBV() } // Create and decompose a nonescapable aggregate. -func ne_wrap_and_extract_member(cn: borrowing CN) -> dependsOn(scoped cn) BV { +@lifetime(borrow cn) +func ne_wrap_and_extract_member(cn: borrowing CN) -> BV { let bv = BV(cn) let ne = NEBV(bv) return ne.bv diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_borrow_fail.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_borrow_fail.swift index 8e03e2955b2af..9c288c9621c8b 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_borrow_fail.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_borrow_fail.swift @@ -11,8 +11,8 @@ struct BV : ~Escapable { let p: UnsafeRawPointer let i: Int - - init(_ p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } @@ -26,7 +26,8 @@ struct NC : ~Copyable { self.p = p self.i = i } - borrowing func getBV() -> dependsOn(self) BV { + @lifetime(borrow self) + borrowing func getBV() -> BV { BV(p, i) } @@ -44,11 +45,13 @@ struct NE : ~Escapable { let p: UnsafeRawPointer let i: Int - init(_ p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } - borrowing func getBV() -> dependsOn(scoped self) BV { + @lifetime(borrow self) + borrowing func getBV() -> BV { BV(p, i) } } @@ -63,11 +66,13 @@ struct Wrapper : ~Escapable { let bv: BV } -func bv_incorrect_annotation1(_ bv1: borrowing BV, _ bv2: borrowing BV) -> dependsOn(bv2) BV { // expected-error {{lifetime-dependent variable 'bv1' escapes its scope}} +@lifetime(bv2) +func bv_incorrect_annotation1(_ bv1: borrowing BV, _ bv2: borrowing BV) -> BV { // expected-error {{lifetime-dependent variable 'bv1' escapes its scope}} return copy bv1 // expected-note @-1{{it depends on the lifetime of argument 'bv1'}} } // expected-note @-1{{this use causes the lifetime-dependent value to escape}} -func bv_incorrect_annotation2(_ w1: borrowing Wrapper, _ w2: borrowing Wrapper) -> dependsOn(w2) BV { // expected-error {{lifetime-dependent variable 'w1' escapes its scope}} +@lifetime(w2) +func bv_incorrect_annotation2(_ w1: borrowing Wrapper, _ w2: borrowing Wrapper) -> BV { // expected-error {{lifetime-dependent variable 'w1' escapes its scope}} return w1.bv // expected-note @-1{{it depends on the lifetime of argument 'w1'}} } // expected-note @-1{{this use causes the lifetime-dependent value to escape}} diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_closure.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_closure.swift index 26f8462e6a78f..39a48a141946c 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_closure.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_closure.swift @@ -17,9 +17,9 @@ struct NCInt: ~Copyable { struct NEInt : ~Escapable { let value: Int - init(borrowed: borrowing NCInt) -> dependsOn(borrowed) Self { + @lifetime(borrow borrowed) + init(borrowed: borrowing NCInt) { self.value = borrowed.value - return self } } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_diagnostics.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_diagnostics.swift index 8ebe0eca087c0..2e000bf7e5a53 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_diagnostics.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_diagnostics.swift @@ -10,13 +10,15 @@ struct BV : ~Escapable { let p: UnsafeRawPointer let c: Int - init(_ p: UnsafeRawPointer, _ c: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ c: Int) { self.p = p self.c = c } } -func bv_copy(_ bv: borrowing BV) -> dependsOn(bv) BV { +@lifetime(bv) +func bv_copy(_ bv: borrowing BV) -> BV { copy bv } @@ -41,7 +43,8 @@ public struct NEInt: ~Escapable { _modify { yield &i } } - init(owner: borrowing NCInt) -> dependsOn(owner) Self { + @lifetime(borrow owner) + init(owner: borrowing NCInt) { self.i = owner.i } } @@ -60,25 +63,27 @@ func takeClosure(_: () -> ()) {} // No mark_dependence is needed for a inherited scope. // -// CHECK-LABEL: sil hidden @$s4test14bv_borrow_copyyAA2BVVADF : $@convention(thin) (@guaranteed BV) -> _scope(0) @owned BV { +// CHECK-LABEL: sil hidden @$s4test14bv_borrow_copyyAA2BVVADF : $@convention(thin) (@guaranteed BV) -> @lifetime(borrow 0) @owned BV { // CHECK: bb0(%0 : @noImplicitCopy $BV): -// CHECK: apply %{{.*}}(%0) : $@convention(thin) (@guaranteed BV) -> _inherit(0) @owned BV +// CHECK: apply %{{.*}}(%0) : $@convention(thin) (@guaranteed BV) -> @lifetime(copy 0) @owned BV // CHECK-NEXT: return %3 : $BV // CHECK-LABEL: } // end sil function '$s4test14bv_borrow_copyyAA2BVVADF' -func bv_borrow_copy(_ bv: borrowing BV) -> dependsOn(scoped bv) BV { +@lifetime(borrow bv) +func bv_borrow_copy(_ bv: borrowing BV) -> BV { bv_copy(bv) } // The mark_dependence for the borrow scope should be marked // [nonescaping] after diagnostics. // -// CHECK-LABEL: sil hidden @$s4test010bv_borrow_C00B0AA2BVVAE_tF : $@convention(thin) (@guaranteed BV) -> _scope(0) @owned BV { +// CHECK-LABEL: sil hidden @$s4test010bv_borrow_C00B0AA2BVVAE_tF : $@convention(thin) (@guaranteed BV) -> @lifetime(borrow 0) @owned BV { // CHECK: bb0(%0 : @noImplicitCopy $BV): -// CHECK: [[R:%.*]] = apply %{{.*}}(%0) : $@convention(thin) (@guaranteed BV) -> _scope(0) @owned BV +// CHECK: [[R:%.*]] = apply %{{.*}}(%0) : $@convention(thin) (@guaranteed BV) -> @lifetime(borrow 0) @owned BV // CHECK: %{{.*}} = mark_dependence [nonescaping] [[R]] : $BV on %0 : $BV // CHECK-NEXT: return %{{.*}} : $BV // CHECK-LABEL: } // end sil function '$s4test010bv_borrow_C00B0AA2BVVAE_tF' -func bv_borrow_borrow(bv: borrowing BV) -> dependsOn(scoped bv) BV { +@lifetime(borrow bv) +func bv_borrow_borrow(bv: borrowing BV) -> BV { bv_borrow_copy(bv) } @@ -93,8 +98,8 @@ func neint_throws(ncInt: borrowing NCInt) throws -> NEInt { return NEInt(owner: ncInt) } -// CHECK-LABEL: sil hidden @$s4test9neint_try5ncIntAA5NEIntVAA5NCIntV_tKF : $@convention(thin) (@guaranteed NCInt) -> _scope(0) (@owned NEInt, @error any Error) { -// CHECK: try_apply %{{.*}}(%0) : $@convention(thin) (@guaranteed NCInt) -> _scope(0) (@owned NEInt, @error any Error), normal bb1, error bb2 +// CHECK-LABEL: sil hidden @$s4test9neint_try5ncIntAA5NEIntVAA5NCIntV_tKF : $@convention(thin) (@guaranteed NCInt) -> @lifetime(borrow 0) (@owned NEInt, @error any Error) { +// CHECK: try_apply %{{.*}}(%0) : $@convention(thin) (@guaranteed NCInt) -> @lifetime(borrow 0) (@owned NEInt, @error any Error), normal bb1, error bb2 // CHECK: bb1([[R:%.*]] : $NEInt): // CHECK: [[MD:%.*]] = mark_dependence [nonescaping] %5 : $NEInt on %0 : $NCInt // CHECK: return [[MD]] : $NEInt diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_generic.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_generic.swift index b339c749ad239..bba65d6160f7c 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_generic.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_generic.swift @@ -18,11 +18,13 @@ precedencegroup AssignmentPrecedence { assignment: true } protocol P { associatedtype E: ~Escapable - borrowing func getE() -> dependsOn(self) E + @lifetime(borrow self) + borrowing func getE() -> E } extension P { - borrowing func getDefault() -> dependsOn(self) E { + @lifetime(borrow self) + borrowing func getDefault() -> E { return getE() } } @@ -49,26 +51,29 @@ struct NCInt: ~Copyable { struct NEInt: ~Escapable { let value: Builtin.Int64 - init(v: Builtin.Int64, o: borrowing O) -> dependsOn(o) Self { + @lifetime(o) + init(v: Builtin.Int64, o: borrowing O) { self.value = v - return self } // Test a generic storage owner. - init(borrowed: borrowing NCInt) -> dependsOn(borrowed) Self { + @lifetime(borrow borrowed) + init(borrowed: borrowing NCInt) { self.init(v: borrowed.value, o: borrowed) - return self } } -public func consume_indirect(ne: consuming NE) -> dependsOn(ne) NE { +@lifetime(ne) +public func consume_indirect(ne: consuming NE) -> NE { return ne } -public func copy_indirect(ne: borrowing NE) -> dependsOn(ne) NE { +@lifetime(ne) +public func copy_indirect(ne: borrowing NE) -> NE { return copy ne } -public func copy_inout(ne: inout NE) -> dependsOn(ne) NE { +@lifetime(ne) +public func copy_inout(ne: inout NE) -> NE { return copy ne } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit.swift index 5125cad706bc2..c68ad4ece5a63 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit.swift @@ -11,27 +11,31 @@ // TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence should be expressed by a builtin that is // hidden within the function body. @_unsafeNonescapableResult +@lifetime(source) func unsafeLifetime( dependent: consuming T, dependsOn source: borrowing U) - -> dependsOn(source) T { + -> T { dependent } struct BV : ~Escapable { let p: UnsafeRawPointer let i: Int - - init(_ p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } - init(independent p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(independent p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } - consuming func derive() -> dependsOn(self) BV { + @lifetime(self) + consuming func derive() -> BV { // Technically, this "new" view does not depend on the 'view' argument. // This unsafely creates a new view with no dependence. let bv = BV(independent: self.p, self.i) @@ -57,22 +61,26 @@ struct NEBV : ~Escapable { } } - func borrowedView() -> dependsOn(scoped self) BV { + @lifetime(borrow self) + func borrowedView() -> BV { bv } } // Test lifetime inheritance through chained consumes. -func bv_derive(bv: consuming BV) -> dependsOn(bv) BV { +@lifetime(bv) +func bv_derive(bv: consuming BV) -> BV { bv.derive() } // Test lifetime inheritance through stored properties. -func ne_extract_member(nebv: consuming NEBV) -> dependsOn(nebv) BV { +@lifetime(nebv) +func ne_extract_member(nebv: consuming NEBV) -> BV { return nebv.bv } -func ne_yield_member(nebv: consuming NEBV) -> dependsOn(nebv) BV { +@lifetime(nebv) +func ne_yield_member(nebv: consuming NEBV) -> BV { return nebv.view } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit_fail.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit_fail.swift index 7cd6f646da666..df76c44dcb379 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit_fail.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit_fail.swift @@ -11,9 +11,10 @@ // TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence should be expressed by a builtin that is // hidden within the function body. @_unsafeNonescapableResult +@lifetime(source) func unsafeLifetime( dependent: consuming T, dependsOn source: borrowing U) - -> dependsOn(source) T { + -> T { dependent } @@ -21,17 +22,20 @@ struct BV : ~Escapable { let p: UnsafeRawPointer let i: Int - init(_ p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } - init(independent p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(independent p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } - consuming func derive() -> dependsOn(self) BV { + @lifetime(borrow self) + consuming func derive() -> BV { // Technically, this "new" view does not depend on the 'view' argument. // This unsafely creates a new view with no dependence. let bv = BV(independent: self.p, self.i) @@ -42,8 +46,8 @@ struct BV : ~Escapable { struct NE : ~Escapable { var bv: BV - init(_ bv: consuming BV) -> dependsOn(bv) Self { + @lifetime(bv) + init(_ bv: consuming BV) { self.bv = bv - return self } } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_insertion.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_insertion.swift index 9d77629678320..c399fed54e424 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_insertion.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_insertion.swift @@ -12,7 +12,8 @@ struct BV : ~Escapable { let p: UnsafeRawPointer let i: Int - init(_ p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } @@ -23,7 +24,8 @@ struct NC : ~Copyable { let i: Int // Requires a borrow. - borrowing func getBV() -> dependsOn(self) BV { + @lifetime(borrow self) + borrowing func getBV() -> BV { BV(p, i) } } @@ -35,7 +37,7 @@ func use(_ o : borrowing BV) // CHECK: [[A:%.*]] = begin_access [read] [unknown] %{{.*}} : $*NC // CHECK: [[U:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[A]] : $*NC // CHECK: [[L:%.*]] = load [copy] [[U]] : $*NC -// CHECK: [[R:%.*]] = apply %{{.*}}([[L]]) : $@convention(method) (@guaranteed NC) -> _scope(0) @owned BV +// CHECK: [[R:%.*]] = apply %{{.*}}([[L]]) : $@convention(method) (@guaranteed NC) -> @lifetime(borrow 0) @owned BV // CHECK: [[M:%.*]] = mark_dependence [unresolved] [[R]] : $BV on [[A]] : $*NC // CHECK: end_access [[A]] : $*NC // CHECK: [[MV:%.*]] = move_value [var_decl] [[M]] : $BV diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_mutate.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_mutate.swift index 32e83fe792429..8941ceac287bf 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_mutate.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_mutate.swift @@ -12,7 +12,8 @@ struct MutableSpan : ~Escapable, ~Copyable { let base: UnsafeMutableRawPointer let count: Int - init(_ p: UnsafeMutableRawPointer, _ c: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeMutableRawPointer, _ c: Int) { self.base = p self.count = c } @@ -33,7 +34,8 @@ struct MutableSpan : ~Escapable, ~Copyable { var base: UnsafeMutableRawPointer var count: Int - init(base: UnsafeMutableRawPointer, count: Int) -> dependsOn(base) Self { + @lifetime(borrow base) + init(base: UnsafeMutableRawPointer, count: Int) { self.base = base self.count = count } @@ -64,7 +66,8 @@ struct NC : ~Copyable { let c: Int // Requires a mutable borrow. - mutating func getMutableSpan() -> dependsOn(self) MutableSpan { + @lifetime(borrow self) + mutating func getMutableSpan() -> MutableSpan { MutableSpan(p, c) } } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_optional.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_optional.swift index d730982e69713..a005299cbc485 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_optional.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_optional.swift @@ -10,7 +10,8 @@ // Simply test that it is possible for a module to define a pseudo-Optional type without triggering any compiler errors. public protocol ExpressibleByNilLiteral: ~Copyable & ~Escapable { - init(nilLiteral: ()) -> dependsOn(immortal) Self + @lifetime(immortal) + init(nilLiteral: ()) } @frozen @@ -29,7 +30,8 @@ extension Nillable: BitwiseCopyable where Wrapped: BitwiseCopyable { } extension Nillable: ExpressibleByNilLiteral where Wrapped: ~Copyable & ~Escapable { @_transparent - public init(nilLiteral: ()) -> dependsOn(immortal) Self { + @lifetime(immortal) + public init(nilLiteral: ()) { self = .none } } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_param.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_param.swift index 2354675ec88e1..892db9c53d19f 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_param.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_param.swift @@ -11,9 +11,10 @@ // TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence should be expressed by a builtin that is // hidden within the function body. @_unsafeNonescapableResult +@lifetime(source) func unsafeLifetime( dependent: consuming T, dependsOn source: borrowing U) - -> dependsOn(source) T { + -> T { dependent } @@ -21,12 +22,14 @@ struct BV : ~Escapable { let p: UnsafeRawPointer let i: Int - init(_ p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } - init(independent p: UnsafeRawPointer, _ i: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(independent p: UnsafeRawPointer, _ i: Int) { self.p = p self.i = i } @@ -35,7 +38,8 @@ struct BV : ~Escapable { public var isEmpty: Bool { i == 0 } // Test consuming `self` - consuming func derive() -> dependsOn(self) BV { + @lifetime(self) + consuming func derive() -> BV { // Technically, this "new" view does not depend on the 'view' argument. // This unsafely creates a new view with no dependence. let bv = BV(independent: self.p, self.i) @@ -47,7 +51,8 @@ struct BV : ~Escapable { struct NE { var bv: BV - init(_ bv: BV) -> dependsOn(bv) Self { + @lifetime(bv) + init(_ bv: BV) { self.bv = bv } } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_param_fail.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_param_fail.swift index 9325b878cfa37..33db8980b6085 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_param_fail.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_param_fail.swift @@ -12,7 +12,8 @@ struct BV : ~Escapable { let p: UnsafeRawPointer let c: Int - init(_ p: UnsafeRawPointer, _ c: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ c: Int) { self.p = p self.c = c } @@ -32,9 +33,9 @@ struct NC : ~Copyable { struct NE { var bv: BV - init(_ bv: consuming BV) -> dependsOn(bv) Self { + @lifetime(bv) + init(_ bv: consuming BV) { self.bv = bv - return self } } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope.swift index 3a349d595717c..5048b4d4b6108 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope.swift @@ -15,7 +15,8 @@ struct BV : ~Escapable { public var isEmpty: Bool { c == 0 } - init(_ p: UnsafeRawPointer, _ c: Int) -> dependsOn(p) Self { + @lifetime(borrow p) + init(_ p: UnsafeRawPointer, _ c: Int) { self.p = p self.c = c } @@ -26,20 +27,22 @@ struct NC : ~Copyable { let c: Int // Requires a borrow. - borrowing func getBV() -> dependsOn(self) BV { + @lifetime(borrow self) + borrowing func getBV() -> BV { BV(p, c) } } // Rewrite the mark_dependence to depend on the incoming argument rather than the nested access. // -// CHECK-LABEL: sil hidden @$s4test13bv_get_mutate9containerAA2BVVAA2NCVz_tF : $@convention(thin) (@inout NC) -> _scope(0) @owned BV { +// CHECK-LABEL: sil hidden @$s4test13bv_get_mutate9containerAA2BVVAA2NCVz_tF : $@convention(thin) (@inout NC) -> @lifetime(borrow 0) @owned BV { // CHECK: bb0(%0 : $*NC): // CHECK: [[A:%.*]] = begin_access [read] [static] %0 : $*NC // CHECK: [[L:%.*]] = load [[A]] : $*NC -// CHECK: [[R:%.*]] = apply %{{.*}}([[L]]) : $@convention(method) (@guaranteed NC) -> _scope(0) @owned BV +// CHECK: [[R:%.*]] = apply %{{.*}}([[L]]) : $@convention(method) (@guaranteed NC) -> @lifetime(borrow 0) @owned BV // CHECK: [[M:%.*]] = mark_dependence [nonescaping] [[R]] : $BV on %0 : $*NC // CHECK-LABEL: } // end sil function '$s4test13bv_get_mutate9containerAA2BVVAA2NCVz_tF' -func bv_get_mutate(container: inout NC) -> dependsOn(container) BV { +@lifetime(borrow container) +func bv_get_mutate(container: inout NC) -> BV { container.getBV() } diff --git a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope_fixup.swift b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope_fixup.swift index 7996fd2e9bc5e..b4ff8740f3bc2 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope_fixup.swift +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope_fixup.swift @@ -1,8 +1,7 @@ -// RUN: %target-swift-frontend %s -emit-sil -o /dev/null -verify \ -// RUN: -enable-experimental-feature NonescapableTypes +// RUN: %target-swift-frontend %s -emit-sil \ +// RUN: -enable-experimental-feature NonescapableTypes | %FileCheck %s // REQUIRES: asserts - // REQUIRES: swift_in_compiler struct NCContainer : ~Copyable { @@ -17,7 +16,8 @@ struct NCContainer : ~Copyable { struct View : ~Escapable { let ptr: UnsafeRawBufferPointer let c: Int - init(_ ptr: UnsafeRawBufferPointer, _ c: Int) -> dependsOn(p) Self { + @lifetime(borrow ptr) + init(_ ptr: UnsafeRawBufferPointer, _ c: Int) { self.ptr = ptr self.c = c } @@ -38,7 +38,8 @@ struct View : ~Escapable { struct MutableView : ~Copyable, ~Escapable { let ptr: UnsafeRawBufferPointer let c: Int - init(_ ptr: UnsafeRawBufferPointer, _ c: Int) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + init(_ ptr: UnsafeRawBufferPointer, _ c: Int) { self.ptr = ptr self.c = c } @@ -59,15 +60,18 @@ func consume(_ o : consuming View) {} func use(_ o : borrowing MutableView) {} func consume(_ o : consuming MutableView) {} -func getConsumingView(_ x: consuming View) -> dependsOn(x) View { - return View(x.ptr, x.c) +@lifetime(x) +func getConsumingView(_ x: consuming View) -> View { + return View(x) } -func getBorrowingView(_ x: borrowing View) -> dependsOn(x) View { +@lifetime(borrow x) +func getBorrowingView(_ x: borrowing View) -> View { return View(x.ptr, x.c) } -func getBorrowingView(_ x: borrowing NCContainer) -> dependsOn(x) View { +@lifetime(borrow x) +func getBorrowingView(_ x: borrowing NCContainer) -> View { return View(x.ptr, x.c) } @@ -82,17 +86,17 @@ func test1(_ a: Array) { } } -// CHECK-LABEL: sil private @$s31lifetime_dependence_scope_fixup5test2yySaySiGFySWXEfU_ : $@convention(thin) @substituted <τ_0_0> (UnsafeRawBufferPointer) -> (@out τ_0_0, @error any Error) for <()> { -// CHECK: [[CONT:%.*]] = alloc_stack [lexical] $NCContainer, var, name "x" +// CHECK-LABEL: sil private @$s31lifetime_dependence_scope_fixup5test2yySaySiGFySWXEfU_ : $@convention(thin) @substituted <τ_0_0> (UnsafeRawBufferPointer, @guaranteed Array) -> (@out τ_0_0, @error any Error) for <()> { +// CHECK: [[CONT:%.*]] = alloc_stack [lexical] [var_decl] $NCContainer, var, name "x" // CHECK: [[BA:%.*]] = begin_access [read] [static] [[CONT]] : $*NCContainer -// CHECK: [[LD:%.*]] = load [[CONT]] : $*NCContainer -// CHECK: [[FUNC:%.*]] = function_ref @$s31lifetime_dependence_scope_fixup16getBorrowingViewyAA0G0VAA11NCContainerVYlsF : $@convention(thin) (@guaranteed NCContainer) -> _scope(1) @owned View -// CHECK: [[VIEW:%.*]] = apply [[FUNC]]([[LD]]) : $@convention(thin) (@guaranteed NCContainer) -> _scope(1) @owned View +// CHECK: [[LD:%.*]] = load [[BA]] : $*NCContainer +// CHECK: [[FUNC:%.*]] = function_ref @$s31lifetime_dependence_scope_fixup16getBorrowingViewyAA0G0VAA11NCContainerVF : $@convention(thin) (@guaranteed NCContainer) -> @lifetime(borrow 0) @owned View +// CHECK: [[VIEW:%.*]] = apply [[FUNC]]([[LD]]) : $@convention(thin) (@guaranteed NCContainer) -> @lifetime(borrow 0) @owned View // CHECK: [[MDI:%.*]] = mark_dependence [nonescaping] [[VIEW]] : $View on [[BA]] : $*NCContainer // CHECK: [[USE:%.*]] = function_ref @$s31lifetime_dependence_scope_fixup3useyyAA4ViewVF : $@convention(thin) (@guaranteed View) -> () // CHECK: apply [[USE]]([[MDI]]) : $@convention(thin) (@guaranteed View) -> () // CHECK: [[CONSUME:%.*]] = function_ref @$s31lifetime_dependence_scope_fixup7consumeyyAA4ViewVnF : $@convention(thin) (@owned View) -> () -// CHECK: apply [[CONSUME]]([[VIEW]]) : $@convention(thin) (@owned View) -> () +// CHECK: apply [[CONSUME]]([[MDI]]) : $@convention(thin) (@owned View) -> () // CHECK: end_access [[BA]] : $*NCContainer // CHECK-LABEL: } // end sil function '$s31lifetime_dependence_scope_fixup5test2yySaySiGFySWXEfU_' func test2(_ a: Array) { @@ -134,8 +138,7 @@ func test5(_ a: Array) { } } -// rdar://124651399 -// XFAIL: * +/* Enable once Optional is ~Escapable func test6(_ a: Array) { var p : View? // error: type 'View' does not conform to protocol 'Escapable' a.withUnsafeBytes { @@ -146,18 +149,19 @@ func test6(_ a: Array) { } use(p!) } +*/ // CHECK-LABEL: sil hidden @$s31lifetime_dependence_scope_fixup5test7yySWF : $@convention(thin) (UnsafeRawBufferPointer) -> () { -// CHECK: [[CONT:%.*]] = alloc_stack $NEContainer, var, name "x" -// CHECK: [[BA:%.*]] = begin_access [read] [static] [[CONT]] : $*NEContainer -// CHECK: [[LD:%.*]] = load [[BA]] : $*NEContainer -// CHECK: [[FUNC:%.*]] = function_ref @$s31lifetime_dependence_scope_fixup16getBorrowingViewyAA0G0VAA11NEContainerVYlsF : $@convention(thin) (@guaranteed NEContainer) -> _scope(1) @owned View -// CHECK: [[VIEW:%.*]] = apply [[FUNC]]([[LD]]) : $@convention(thin) (@guaranteed NEContainer) -> _scope(1) @owned View -// CHECK: [[MDI:%.*]] = mark_dependence [nonescaping] [[VIEW]] : $View on [[BA]] : $*NEContainer +// CHECK: [[CONT:%.*]] = alloc_stack [var_decl] $View +// CHECK: [[BA:%.*]] = begin_access [read] [static] [[CONT]] : $*View +// CHECK: [[LD:%.*]] = load [[BA]] : $*View +// CHECK: [[FUNC:%.*]] = function_ref @$s31lifetime_dependence_scope_fixup16getBorrowingViewyAA0G0VADF : $@convention(thin) (@guaranteed View) -> @lifetime(borrow 0) @owned View +// CHECK: [[VIEW:%.*]] = apply [[FUNC]]([[LD]]) : $@convention(thin) (@guaranteed View) -> @lifetime(borrow 0) @owned View +// CHECK: [[MDI:%.*]] = mark_dependence [nonescaping] [[VIEW]] : $View on [[BA]] : $*View // CHECK: [[USE:%.*]] = function_ref @$s31lifetime_dependence_scope_fixup3useyyAA4ViewVF : $@convention(thin) (@guaranteed View) -> () // CHECK: apply [[USE]]([[MDI]]) : $@convention(thin) (@guaranteed View) -> () // CHECK: release_value [[MDI]] : $View -// CHECK: end_access [[BA]] : $*NEContainer +// CHECK: end_access [[BA]] : $*View // CHECK-LABEL: } // end sil function '$s31lifetime_dependence_scope_fixup5test7yySWF' func test7(_ a: UnsafeRawBufferPointer) { var x = View(a, a.count) @@ -168,8 +172,6 @@ func test7(_ a: UnsafeRawBufferPointer) { mutate(&x) } -// Currently fails because the lifetime dependence util isn't analyzing a -// def-use chain involving a stack temporary func test8(_ a: Array) { a.withUnsafeBytes { var x = View($0, a.count) diff --git a/test/SILOptimizer/lifetime_dependence/semantics.swift b/test/SILOptimizer/lifetime_dependence/semantics.swift index 25c8bfb7dad0e..caa3836abad18 100644 --- a/test/SILOptimizer/lifetime_dependence/semantics.swift +++ b/test/SILOptimizer/lifetime_dependence/semantics.swift @@ -14,12 +14,14 @@ struct Span: ~Escapable { private var base: UnsafePointer private var count: Int - init(base: UnsafePointer, count: Int) -> dependsOn(base) Self { + @lifetime(borrow base) + init(base: UnsafePointer, count: Int) { self.base = base self.count = count } - init(base: UnsafePointer, count: Int, generic: borrowing S) -> dependsOn(generic) Self { + @lifetime(borrow generic) + init(base: UnsafePointer, count: Int, generic: borrowing S) { self.base = base self.count = count } @@ -35,23 +37,25 @@ extension Span { // TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence should be expressed by a builtin that is // hidden within the function body. @_unsafeNonescapableResult +@lifetime(source) func unsafeLifetime( dependent: consuming T, dependsOn source: borrowing U) - -> dependsOn(source) T { + -> T { dependent } // TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence should be expressed by a builtin that is // hidden within the function body. @_unsafeNonescapableResult +@lifetime(borrow source) func unsafeLifetime( dependent: consuming T, scope source: borrowing U) - -> dependsOn(scoped source) T { + -> T { dependent } extension Span { - mutating func droppingPrefix(length: Int) -> /* dependsOn(self) */ Span { + mutating func droppingPrefix(length: Int) -> /* */ Span { let oldBase = base let result = Span(base: oldBase, count: length) self.base += length @@ -61,8 +65,8 @@ extension Span { } extension Array { - // TODO: comment out dependsOn(scoped) - borrowing func span() -> /* dependsOn(scoped self) */ Span { + // TODO: comment out + borrowing func span() -> /* */ Span { /* not the real implementation */ let p = self.withUnsafeBufferPointer { $0.baseAddress! } return Span(base: p, count: 1) @@ -100,7 +104,7 @@ func testScopedCopy(_ arg: [Int] ) { // Inherited dependence on values // ============================================================================= -func copySpan(_ arg: Span) -> /* dependsOn(arg) */ Span { arg } +func copySpan(_ arg: Span) -> /* */ Span { arg } func testInheritedCopy(_ arg: [Int] ) { let a: Array = arg @@ -132,7 +136,8 @@ func testInheritedCopyVar(_ arg: [Int] ) { // Scoped dependence on inherited dependence // ============================================================================= -func reborrowSpan(_ arg: Span) -> dependsOn(scoped arg) Span { arg } +@lifetime(borrow arg) +func reborrowSpan(_ arg: Span) -> Span { arg } func testScopedOfInheritedWithCall(_ arg: [Int] ) { let a: Array = arg diff --git a/test/Sema/explicit_lifetime_dependence_specifiers1.swift b/test/Sema/explicit_lifetime_dependence_specifiers1.swift deleted file mode 100644 index d256476c756a2..0000000000000 --- a/test/Sema/explicit_lifetime_dependence_specifiers1.swift +++ /dev/null @@ -1,245 +0,0 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -// REQUIRES: asserts - -struct Container { - let ptr: UnsafeRawBufferPointer -} - -struct AnotherBufferView : ~Escapable { - let ptr: UnsafeRawBufferPointer - init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self { - self.ptr = ptr - } -} - -struct BufferView : ~Escapable { - let ptr: UnsafeRawBufferPointer - init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self { - self.ptr = ptr - } - @_unsafeNonescapableResult - init(independent ptr: UnsafeRawBufferPointer) { - self.ptr = ptr - } - init(_ ptr: UnsafeRawBufferPointer, _ arr: borrowing Array) -> dependsOn(arr) Self { - self.ptr = ptr - return self - } - init(_ ptr: UnsafeRawBufferPointer, _ arr: borrowing Array) -> dependsOn(arr) Self { - self.ptr = ptr - } - // TODO: Once Optional is ~Escapable, the error will go away - init?(_ ptr: UnsafeRawBufferPointer, _ arr: borrowing Array) -> dependsOn(arr) Self? { // expected-error{{lifetime dependence can only be specified on ~Escapable types}} - if (Int.random(in: 1..<100) == 0) { - return nil - } - self.ptr = ptr - } - init?(_ ptr: UnsafeRawBufferPointer, _ arr: borrowing Array) -> dependsOn(arr) Self? { // expected-error{{lifetime dependence can only be specified on ~Escapable types}} - if (Int.random(in: 1..<100) == 0) { - return nil - } - self.ptr = ptr - return self - } - init(_ ptr: UnsafeRawBufferPointer, _ arr: borrowing Array) -> dependsOn(self) Self { // expected-error{{invalid lifetime dependence on self in an initializer}} - self.ptr = ptr - } - init(_ ptr: UnsafeRawBufferPointer, _ arr: Array) -> dependsOn(scoped arr) Self { // expected-error{{invalid use of scoped lifetime dependence with consuming ownership}} - self.ptr = ptr - } - init(_ ptr: UnsafeRawBufferPointer, _ arr: Array) -> dependsOn(arr) Self { // expected-error{{invalid use of lifetime dependence on an Escapable parameter with consuming ownership}} - self.ptr = ptr - } - init(_ ptr: UnsafeRawBufferPointer, _ abv: AnotherBufferView) -> dependsOn(abv) Self { - self.ptr = ptr - } - - consuming func consume() -> dependsOn(scoped self) BufferView { - return BufferView(independent: self.ptr) - } - - func get() -> dependsOn(self) Self { // expected-note{{'get()' previously declared here}} - return self - } - - func get() -> dependsOn(scoped self) Self { // expected-error{{invalid redeclaration of 'get()'}} - return self - } -} - -struct MutableBufferView : ~Escapable, ~Copyable { - let ptr: UnsafeMutableRawBufferPointer - init(_ ptr: UnsafeMutableRawBufferPointer) -> dependsOn(ptr) Self { - self.ptr = ptr - } -} - -class Klass {} - -struct WrapperStruct { - let k: Klass -} - -func invalidLifetimeDependenceOnEscapableResult(_ w: borrowing WrapperStruct) -> dependsOn(w) Klass { // expected-error{{lifetime dependence can only be specified on ~Escapable types}} - return w.k -} - -func incorrectSelfInvalidLifetimeDependence(_ x: borrowing BufferView) -> dependsOn(self) BufferView { // expected-error{{invalid lifetime dependence specifier on non-existent self}} - return BufferView(x.ptr) -} - -func incorrectParamNameInvalidLifetimeDependence(_ x: borrowing BufferView) -> dependsOn(y) BufferView { // expected-error{{invalid parameter name specified 'y'}} - return BufferView(x.ptr) -} - -func duplicateParamInvalidLifetimeDependence1(_ x: borrowing BufferView) -> dependsOn(x, x) BufferView { // expected-error{{duplicate lifetime dependence specifier}} - return BufferView(x.ptr) -} - -func duplicateParamInvalidLifetimeDependence2(_ x: borrowing BufferView) -> dependsOn(x) dependsOn(x) BufferView { // expected-error{{duplicate lifetime dependence specifier}} - return BufferView(x.ptr) -} - -func duplicateParamInvalidLifetimeDependence3(_ x: borrowing BufferView) -> dependsOn(x) dependsOn(x) BufferView { // expected-error{{duplicate lifetime dependence specifier}} - return BufferView(x.ptr) -} - -func consumingParamInvalidLifetimeDependence1(_ x: consuming BufferView) -> dependsOn(scoped x) BufferView { - return BufferView(x.ptr) -} - -func borrowingParamInvalidLifetimeDependence1(_ x: borrowing BufferView) -> dependsOn(x) BufferView { - return BufferView(x.ptr) -} - -func implicitBorrowingParamLifetimeDependence1(_ x: BufferView) -> dependsOn(x) BufferView { - return BufferView(x.ptr) -} - -func implicitBorrowingParamLifetimeDependence2(_ x: BufferView) -> dependsOn(scoped x) BufferView { - return BufferView(x.ptr) -} - -func inoutParamLifetimeDependence1(_ x: inout BufferView) -> dependsOn(x) BufferView { - return BufferView(x.ptr) -} - -func inoutParamLifetimeDependence2(_ x: inout BufferView) -> dependsOn(scoped x) BufferView { - return BufferView(x.ptr) -} - -func invalidSpecifierPosition1(_ x: borrowing dependsOn(x) BufferView) -> BufferView { - return BufferView(x.ptr) -} - -func invalidSpecifierPosition2(_ x: borrowing BufferView) -> BufferView { - let y: dependsOn(x) x // expected-error{{lifetime dependence specifiers may only be used on result of functions, methods, initializers}} - return BufferView(y.ptr) -} - -func invalidTupleLifetimeDependence(_ x: inout BufferView) -> (dependsOn(x) BufferView, BufferView) { // expected-error{{lifetime dependence specifiers cannot be applied to tuple elements}} - return (BufferView(x.ptr), BufferView(x.ptr)) -} - -// TODO: Is this legal ? If not, diagnose in Sema. -func incorrectLifetimeDependenceInParamPosition1(bv: dependsOn(bv) inout BufferView, to: ContiguousArray) { -} - -func incorrectLifetimeDependenceInParamPosition1(bv: dependsOn(to) inout ContiguousArray, to: ContiguousArray) { // expected-error{{lifetime dependence can only be specified on ~Escapable types}} -} - -struct Wrapper : ~Escapable { - let view: BufferView - init(_ view: consuming BufferView) { - self.view = view - } - borrowing func getView1() -> dependsOn(self) BufferView { - return view - } - - consuming func getView2() -> dependsOn(self) BufferView { - return view - } - - mutating func getView3() -> dependsOn(self) BufferView { - return view - } - - borrowing func getView4() -> dependsOn(self) BufferView { - return view - } - - borrowing func borrowingMethodLifetimeDependence1() -> dependsOn(self) BufferView { - return view - } - - borrowing func borrowingMethodLifetimeDependence2() -> dependsOn(scoped self) BufferView { - return view - } - - consuming func consumingMethodLifetimeDependence1() -> dependsOn(self) BufferView { - return view - } - - consuming func consumingMethodInvalidLifetimeDependence1() -> dependsOn(scoped self) BufferView { - return view - } - - mutating func mutatingMethodLifetimeDependence1() -> dependsOn(self) BufferView { - return view - } - - mutating func mutatingMethodLifetimeDependence2() -> dependsOn(scoped self) BufferView { - return view - } -} - -public struct GenericBufferView : ~Escapable { - public typealias Index = Int - public typealias Pointer = UnsafePointer - - public let baseAddress: Pointer - public let count: Int - - public init(unsafeBuffer: UnsafeBufferPointer, - storage: borrowing Storage) - -> dependsOn(storage) Self { - let baseAddress = unsafeBuffer.baseAddress! - self = GenericBufferView(baseAddress: baseAddress, - count: unsafeBuffer.count) - return self - } - // unsafe private API - init(baseAddress: Pointer, count: Int) -> dependsOn(baseAddress) Self { - precondition(count >= 0, "Count must not be negative") - self.baseAddress = baseAddress - self.count = count - } -} - -func derive(_ x: BufferView) -> dependsOn(x) BufferView { // expected-note{{'derive' previously declared here}} - return BufferView(x.ptr) -} - -func derive(_ x: BufferView) -> dependsOn(scoped x) BufferView { // expected-error{{invalid redeclaration of 'derive'}} - return BufferView(x.ptr) -} - -struct RawBufferView { - let ptr: UnsafeRawBufferPointer - init(_ ptr: UnsafeRawBufferPointer) { - self.ptr = ptr - } -} - -extension RawBufferView { - mutating func zeroBufferView() throws -> BufferView { // expected-error{{cannot infer lifetime dependence on a self which is BitwiseCopyable & Escapable}} - return BufferView(ptr) - } -} - -func immortalConflict(immortal: UnsafeRawBufferPointer ) -> dependsOn(immortal) BufferView { // expected-error{{conflict between the parameter name and immortal keyword}} - return BufferView(immortal) -} - diff --git a/test/Sema/explicit_lifetime_dependence_specifiers2.swift b/test/Sema/explicit_lifetime_dependence_specifiers2.swift deleted file mode 100644 index 63eb1edbdb0d8..0000000000000 --- a/test/Sema/explicit_lifetime_dependence_specifiers2.swift +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -// REQUIRES: asserts - -struct AnotherBufferView : ~Escapable, BitwiseCopyable { - let ptr: UnsafeRawBufferPointer - init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self { - self.ptr = ptr - } -} - -struct BufferView : ~Escapable { - let ptr: UnsafeRawBufferPointer - init(_ bv: borrowing AnotherBufferView) -> dependsOn(bv) Self { - self.ptr = bv.ptr - return self - } -} - -struct NonescapableType: ~Escapable {} - -func f(arg: T) -> NonescapableType { - NonescapableType() -} diff --git a/test/Sema/implicit_lifetime_dependence.swift b/test/Sema/implicit_lifetime_dependence.swift index 574a8ffbf62e2..4923e0d472000 100644 --- a/test/Sema/implicit_lifetime_dependence.swift +++ b/test/Sema/implicit_lifetime_dependence.swift @@ -4,7 +4,8 @@ struct BufferView : ~Escapable, ~Copyable { let ptr: UnsafeRawBufferPointer? let c: Int - init(_ ptr: UnsafeRawBufferPointer?, _ c: Int) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + init(_ ptr: UnsafeRawBufferPointer?, _ c: Int) { self.ptr = ptr self.c = c } diff --git a/test/Sema/lifetime_attr.swift b/test/Sema/lifetime_attr.swift index 6db5a90489b2c..4762e7a7601eb 100644 --- a/test/Sema/lifetime_attr.swift +++ b/test/Sema/lifetime_attr.swift @@ -17,7 +17,7 @@ func invalidAttrOnNonExistingSelf(_ ne: NE) -> NE { ne } -@lifetime(2) // expected-error{{invalid parameter index specified 2}} +@lifetime(2) // expected-error{{invalid parameter index specified '2'}} func invalidAttrOnNonExistingParamIndex(_ ne: NE) -> NE { ne } diff --git a/test/Sema/lifetime_dependence_functype.swift b/test/Sema/lifetime_dependence_functype.swift index e3bab33087468..b44a117d0dc81 100644 --- a/test/Sema/lifetime_dependence_functype.swift +++ b/test/Sema/lifetime_dependence_functype.swift @@ -1,47 +1,47 @@ // RUN: %target-typecheck-verify-swift -enable-experimental-feature NonescapableTypes - // REQUIRES: asserts - - struct NC: ~Copyable { - var ne: NE { - NE() - } - } - - struct NE: ~Escapable { - @_unsafeNonescapableResult - init() {} - } - - func transfer(_ ne: NE) -> NE { - ne - } - - func applyAnnotatedTransfer(ne: NE, transfer: (NE) -> dependsOn(0) NE) -> NE { // expected-error{{lifetime dependencies on function types are not supported}} - transfer(ne) - } - - func applyTransfer(ne: NE, transfer: (NE) -> NE) -> NE { - transfer(ne) - } - - func testTransfer(nc: consuming NC) { - let transferred = applyTransfer(ne: nc.ne, transfer: transfer) // expected-error{{cannot convert value of type '(NE) -> _inherit(0) NE' to expected argument type '(NE) -> NE'}} - - _ = consume nc - _ = transfer(transferred) - } - - func borrow(_ nc: borrowing NC) -> NE { - nc.ne - } - - func applyBorrow(nc: borrowing NC, borrow: (borrowing NC) -> NE) -> NE { - borrow(nc) - } - - func testBorrow(nc: consuming NC) { - let borrowed = applyBorrow(nc: nc, borrow: borrow) // expected-error{{cannot convert value of type '(borrowing NC) -> _scope(0) NE' to expected argument type '(borrowing NC) -> NE}} - _ = consume nc - _ = transfer(borrowed) - } +// REQUIRES: asserts + +struct NC: ~Copyable { + var ne: NE { + NE() + } +} + +struct NE: ~Escapable { + @_unsafeNonescapableResult + init() {} +} + +func transfer(_ ne: NE) -> NE { + ne +} + +func applyAnnotatedTransfer(ne: NE, @lifetime(0) transfer: (NE) -> NE) -> NE { // expected-error{{'@lifetime' attribute cannot be applied to this declaration}} + transfer(ne) +} + +func applyTransfer(ne: NE, transfer: (NE) -> NE) -> NE { + transfer(ne) +} + +func testTransfer(nc: consuming NC) { + let transferred = applyTransfer(ne: nc.ne, transfer: transfer) // expected-error{{cannot convert value of type '(NE) -> @lifetime(copy 0) NE' to expected argument type '(NE) -> NE'}} + + _ = consume nc + _ = transfer(transferred) +} + +func borrow(_ nc: borrowing NC) -> NE { + nc.ne +} + +func applyBorrow(nc: borrowing NC, borrow: (borrowing NC) -> NE) -> NE { + borrow(nc) +} + +func testBorrow(nc: consuming NC) { + let borrowed = applyBorrow(nc: nc, borrow: borrow) // expected-error{{cannot convert value of type '(borrowing NC) -> @lifetime(borrow 0) NE' to expected argument type '(borrowing NC) -> NE}} + _ = consume nc + _ = transfer(borrowed) +} diff --git a/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift b/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift index a8eb2ac7ee4ab..e62b67c403d84 100644 --- a/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift +++ b/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift @@ -1,6 +1,7 @@ public struct AnotherView : ~Escapable { let ptr: UnsafeRawBufferPointer - public init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + public init(_ ptr: UnsafeRawBufferPointer) { self.ptr = ptr } } @@ -8,46 +9,52 @@ public struct AnotherView : ~Escapable { public struct BufferView : ~Escapable { public let ptr: UnsafeRawBufferPointer @inlinable - public init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + public init(_ ptr: UnsafeRawBufferPointer) { self.ptr = ptr } - public init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) -> dependsOn(a) Self { + @lifetime(borrow a) + public init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) { self.ptr = ptr - return self } - public init(_ ptr: UnsafeRawBufferPointer, _ a: consuming AnotherView) -> dependsOn(a) Self { + @lifetime(a) + public init(_ ptr: UnsafeRawBufferPointer, _ a: consuming AnotherView) { self.ptr = ptr - return self } - public init(_ ptr: UnsafeRawBufferPointer, _ a: consuming AnotherView, _ b: borrowing Array) -> dependsOn(a) dependsOn(b) Self { + @lifetime(a, borrow b) + public init(_ ptr: UnsafeRawBufferPointer, _ a: consuming AnotherView, _ b: borrowing Array) { self.ptr = ptr - return self } } public struct MutableBufferView : ~Escapable, ~Copyable { let ptr: UnsafeMutableRawBufferPointer - public init(_ ptr: UnsafeMutableRawBufferPointer) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + public init(_ ptr: UnsafeMutableRawBufferPointer) { self.ptr = ptr } } @inlinable -public func derive(_ x: borrowing BufferView) -> dependsOn(scoped x) BufferView { +@lifetime(borrow x) +public func derive(_ x: borrowing BufferView) -> BufferView { return BufferView(x.ptr) } public func use(_ x: borrowing BufferView) {} -public func borrowAndCreate(_ view: borrowing BufferView) -> dependsOn(scoped view) BufferView { +@lifetime(borrow view) +public func borrowAndCreate(_ view: borrowing BufferView) -> BufferView { return BufferView(view.ptr) } -public func consumeAndCreate(_ view: consuming BufferView) -> dependsOn(view) BufferView { +@lifetime(view) +public func consumeAndCreate(_ view: consuming BufferView) -> BufferView { return BufferView(view.ptr) } -public func deriveThisOrThat(_ this: borrowing BufferView, _ that: borrowing BufferView) -> dependsOn(scoped this, that) BufferView { +@lifetime(borrow this, that) +public func deriveThisOrThat(_ this: borrowing BufferView, _ that: borrowing BufferView) -> BufferView { if (Int.random(in: 1..<100) == 0) { return BufferView(this.ptr) } @@ -76,7 +83,8 @@ public enum FakeOptional: ~Escapable { extension FakeOptional: Escapable where Wrapped: Escapable {} extension FakeOptional where Wrapped: ~Escapable { - public init(_ nilLiteral: ()) -> dependsOn(immortal) Self { + @lifetime(immortal) + public init(_ nilLiteral: ()) { self = .none } } diff --git a/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift b/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift index 4de9d9ec604b6..a726bf10ea393 100644 --- a/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift +++ b/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift @@ -1,7 +1,8 @@ public struct BufferView : ~Escapable { public let ptr: UnsafeRawBufferPointer public let c: Int - public init(_ ptr: UnsafeRawBufferPointer, _ c: Int) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + public init(_ ptr: UnsafeRawBufferPointer, _ c: Int) { self.ptr = ptr self.c = c } @@ -15,7 +16,8 @@ public struct BufferView : ~Escapable { public struct MutableBufferView : ~Escapable, ~Copyable { let ptr: UnsafeMutableRawBufferPointer let c: Int - public init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) -> dependsOn(ptr) Self { + @lifetime(borrow ptr) + public init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) { self.ptr = ptr self.c = c } diff --git a/test/Serialization/explicit_lifetime_dependence.swift b/test/Serialization/explicit_lifetime_dependence.swift index 08dd1f3bcc99d..525b38da77f02 100644 --- a/test/Serialization/explicit_lifetime_dependence.swift +++ b/test/Serialization/explicit_lifetime_dependence.swift @@ -48,8 +48,8 @@ func testFakeOptional() { _ = FakeOptional(()) } -// CHECK-LABEL: sil @$s32def_explicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView -// CHECK-LABEL: sil @$s32def_explicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView -// CHECK-LABEL: sil @$s32def_explicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView -// CHECK-LABEL: sil @$s32def_explicit_lifetime_dependence16deriveThisOrThatyAA10BufferViewVAD_ADtF : $@convention(thin) (@guaranteed BufferView, @guaranteed BufferView) -> _scope(0, 1) @owned BufferView -// CHECK-LABEL: sil @$s32def_explicit_lifetime_dependence10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> _scope(1) @owned BufferView +// CHECK: sil @$s32def_explicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(borrow 0) @owned BufferView +// CHECK: sil @$s32def_explicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> @lifetime(copy 0) @owned BufferView +// CHECK: sil @$s32def_explicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(borrow 0) @owned BufferView +// CHECK: sil @$s32def_explicit_lifetime_dependence16deriveThisOrThatyAA10BufferViewVAD_ADtF : $@convention(thin) (@guaranteed BufferView, @guaranteed BufferView) -> @lifetime(copy 1, borrow 0) @owned BufferView +// CHECK: sil @$s32def_explicit_lifetime_dependence10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> @lifetime(borrow 1) @owned BufferView diff --git a/test/Serialization/implicit_lifetime_dependence.swift b/test/Serialization/implicit_lifetime_dependence.swift index 38ffbbd7b8499..7cbf082e8fb7f 100644 --- a/test/Serialization/implicit_lifetime_dependence.swift +++ b/test/Serialization/implicit_lifetime_dependence.swift @@ -60,11 +60,9 @@ func testReadMutateAccessors() { } } -// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence10BufferViewVyACSW_SitcfC : $@convention(method) (UnsafeRawBufferPointer, Int, @thin BufferView.Type) -> _scope(0) @owned BufferView -// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _inherit(0) @owned BufferView -// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView -// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _inherit(0) @owned BufferView -// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence9ContainerV4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container) -> _scope(0) @owned BufferView -// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvr : $@yield_once @convention(method) (@guaranteed Wrapper) -> _inherit(0) @yields @guaranteed BufferView -// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvM : $@yield_once @convention(method) (@inout Wrapper) -> _inherit(0) @yields @inout BufferView - +// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence10BufferViewVyACSW_SitcfC : $@convention(method) (UnsafeRawBufferPointer, Int, @thin BufferView.Type) -> @lifetime(borrow 0) @owned BufferView +// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(copy 0) @owned BufferView +// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> @lifetime(copy 0) @owned BufferView +// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(copy 0) @owned BufferView +// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence9ContainerV4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container) -> @lifetime(borrow 0) @owned BufferView +// CHECK-LABEL: sil @$s32def_implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvr : $@yield_once @convention(method) (@guaranteed Wrapper) -> @lifetime(copy 0) @yields @guaranteed BufferView diff --git a/test/attr/attr_nonEscapable.swift b/test/attr/attr_nonEscapable.swift deleted file mode 100644 index 20fd2400e35cd..0000000000000 --- a/test/attr/attr_nonEscapable.swift +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: %target-typecheck-verify-swift -enable-experimental-feature NonescapableTypes - -// REQUIRES: asserts - -public struct NES : ~Escapable { - let x: Int - - // TODO: dependsOn(immortal) - @_unsafeNonescapableResult - init() { - x = 0 - } - - // TODO: dependsOn(immortal) - @_unsafeNonescapableResult - static func makeS() -> NES { - return NES() - } -} - -struct BC { - public var nes: NES { - // TODO: dependsOn(immortal) - @_unsafeNonescapableResult - get { - NES() - } - } -} From 271143405b5476d38c49ec5d8532434c433a2edf Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Tue, 8 Oct 2024 15:21:39 -0700 Subject: [PATCH 10/11] Don't allow space between @lifetime and '(' --- lib/Parse/ParseDecl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 343510b3c70d5..2ccd59424db46 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5161,8 +5161,8 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { status.setIsParseError(); return status; } - // consume the l_paren - auto lParenLoc = consumeToken(); + + auto lParenLoc = consumeAttributeLParen(); // consume the l_paren std::optional targetDescriptor; if (Tok.isAny(tok::identifier, tok::integer_literal, tok::kw_self) && From a3740ae55795470a7b57892b1608e0adfcec54b0 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Tue, 8 Oct 2024 15:37:50 -0700 Subject: [PATCH 11/11] Disallow target specification in SIL's @lifetime SIL's @lifetime continues to be positional. Don't parse 'target:' in this case. --- lib/Parse/ParseDecl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2ccd59424db46..75d36133c60b2 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5165,7 +5165,8 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { auto lParenLoc = consumeAttributeLParen(); // consume the l_paren std::optional targetDescriptor; - if (Tok.isAny(tok::identifier, tok::integer_literal, tok::kw_self) && + if (!isInSILMode() && + Tok.isAny(tok::identifier, tok::integer_literal, tok::kw_self) && peekToken().is(tok::colon)) { targetDescriptor = parseLifetimeDescriptor(*this); if (!targetDescriptor) {