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/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/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..67210759eea90 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, @@ -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", ()) @@ -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/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index d1601f2cda4a8..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 { @@ -43,102 +44,162 @@ 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"); + } +}; + +class LifetimeEntry final + : private llvm::TrailingObjects { + friend TrailingObjects; + +private: + SourceLoc startLoc, endLoc; + unsigned numSources; + std::optional targetDescriptor; + + LifetimeEntry( + SourceLoc startLoc, SourceLoc endLoc, + ArrayRef sources, + std::optional targetDescriptor = std::nullopt) + : 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: + 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 {getTrailingObjects(), numSources}; + } + + std::optional getTargetDescriptor() const { + return targetDescriptor; } - 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() + ")"; + std::string getString() const { + std::string result = "@lifetime("; + if (targetDescriptor.has_value()) { + result += targetDescriptor->getString(); + result += ": "; + } + + bool firstElem = true; + for (auto source : getSources()) { + if (!firstElem) { + result += ", "; + } + if (source.getParsedLifetimeDependenceKind() == + ParsedLifetimeDependenceKind::Scope) { + result += "borrow "; + } + result += source.getString(); + firstElem = false; } - llvm_unreachable("Invalid LifetimeEntry::ParsedLifetimeDependenceKind"); + result += ")"; + return result; } }; @@ -157,11 +218,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/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 8abc64409a5aa..3b3d7f8f74252 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, @@ -1197,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") || @@ -1208,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; } @@ -1221,12 +1225,9 @@ class Parser { consumeToken(); } - bool isLifetimeDependenceToken() { - if (!isInSILMode()) { - return Tok.isContextualKeyword("dependsOn"); - } - return Tok.isContextualKeyword("_inherit") || - Tok.isContextualKeyword("_scope"); + bool isSILLifetimeDependenceToken() { + return isInSILMode() && Tok.is(tok::at_sign) && + (peekToken().isContextualKeyword("lifetime")); } bool canHaveParameterSpecifierContextualKeyword() { @@ -1247,16 +1248,13 @@ class Parser { return true; } - return isLifetimeDependenceToken(); + return false; } bool parseConventionAttributeInternal(SourceLoc atLoc, SourceLoc attrLoc, ConventionTypeAttr *&result, bool justChecking); - ParserStatus - parseLifetimeEntries(SmallVectorImpl &specifierList); - ParserResult parseDeclImport(ParseDeclOptions Flags, DeclAttributes &Attributes); @@ -1458,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/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/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/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..5689fd06cea5d 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -25,6 +25,15 @@ namespace swift { +LifetimeEntry * +LifetimeEntry::create(const ASTContext &ctx, SourceLoc startLoc, + SourceLoc endLoc, ArrayRef sources, + std::optional targetDescriptor) { + unsigned size = totalSizeToAlloc(sources.size()); + void *mem = ctx.Allocate(size, alignof(LifetimeEntry)); + return new (mem) LifetimeEntry(startLoc, endLoc, sources, targetDescriptor); +} + std::optional getLifetimeDependenceFor(ArrayRef lifetimeDependencies, unsigned index) { @@ -37,8 +46,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++) { @@ -46,20 +55,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; } @@ -82,14 +101,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,251 +220,197 @@ 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); - return afd->getASTContext().AllocateCopy(lifetimeDependencies); + targetIndex, /*isImmortal*/ false); } -std::optional -LifetimeDependenceInfo::fromDependsOn(AbstractFunctionDecl *afd, - TypeRepr *targetTypeRepr, Type targetType, - unsigned targetIndex) { +std::optional> +LifetimeDependenceInfo::fromLifetimeAttribute(AbstractFunctionDecl *afd) { 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); + + SmallVector lifetimeDependencies; + llvm::SmallSet lifetimeDependentTargets; + auto lifetimeAttrs = afd->getAttrs().getAttributes(); + for (auto attr : lifetimeAttrs) { + auto lifetimeDependenceInfo = + populateLifetimeDependence(afd, attr->getLifetimeEntry()); + 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); } - if (hasError) { - return std::nullopt; - } - return LifetimeDependenceInfo( - inheritIndices.any() ? IndexSubset::get(ctx, inheritIndices) : nullptr, - scopeIndices.any() ? IndexSubset::get(ctx, scopeIndices) : nullptr, - targetIndex, isImmortal); + return afd->getASTContext().AllocateCopy(lifetimeDependencies); } // This utility is similar to its overloaded version that builds the @@ -469,11 +426,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) && @@ -497,23 +454,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, @@ -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/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 ec68db1000d0e..75d36133c60b2 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); + auto lifetimeEntry = parseLifetimeEntry(loc); + if (lifetimeEntry.isNull()) { 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); - 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. @@ -5179,109 +5138,81 @@ 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; -} - -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 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; + }; - auto lifetimeDependenceKind = ParsedLifetimeDependenceKind::Default; + if (!Tok.isFollowingLParen()) { + diagnose(loc, diag::expected_lparen_after_lifetime_dependence); + status.setIsParseError(); + return status; + } - if (!isInSILMode()) { - // consume dependsOn - consumeToken(); - } else { - lifetimeDependenceKind = getSILLifetimeDependenceKind(Tok); - // consume _inherit or _scope - consumeToken(); - } + auto lParenLoc = consumeAttributeLParen(); // consume the l_paren - if (!Tok.isFollowingLParen()) { - diagnose(Tok, diag::expected_lparen_after_lifetime_dependence); + std::optional targetDescriptor; + if (!isInSILMode() && + Tok.isAny(tok::identifier, tok::integer_literal, tok::kw_self) && + peekToken().is(tok::colon)) { + targetDescriptor = parseLifetimeDescriptor(*this); + if (!targetDescriptor) { status.setIsParseError(); - continue; + return status; } - // consume the l_paren - auto lParenLoc = consumeToken(); + consumeToken(); // consume ':' + } - if (!isInSILMode()) { - // look for optional "scoped" - if (Tok.isContextualKeyword("scoped")) { - lifetimeDependenceKind = ParsedLifetimeDependenceKind::Scope; - // consume scoped - consumeToken(); - } - } + 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; - 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; - } + auto lifetimeDependenceKind = ParsedLifetimeDependenceKind::Default; + auto result = getLifetimeDependenceKind(Tok); + if (result.has_value()) { + lifetimeDependenceKind = *result; + 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, sources, targetDescriptor); + return ParserResult(lifetimeEntry); } ParserStatus Parser::parseDeclAttributeList( @@ -5540,7 +5471,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(); @@ -5584,13 +5514,20 @@ 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)); } - status |= P.parseLifetimeEntries(lifetimeEntries); + P.consumeToken(); // consume '@' + auto loc = P.consumeToken(); // consume 'lifetime' + auto result = P.parseLifetimeEntry(loc); + if (result.isNull()) { + status |= result; + continue; + } + lifetimeEntry = result.get(); continue; } @@ -10074,26 +10011,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/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; } 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); 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/Interop/Cxx/class/nonescapable-lifetimebound.swift b/test/Interop/Cxx/class/nonescapable-lifetimebound.swift index 4afb28b7c5927..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) -> _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 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 @@ -91,4 +91,4 @@ public func test() { let _ = o.handOutView2(v1) let _ = getViewFromEither(v1, v2) let defaultView = View() -} \ No newline at end of file +} 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 46cdbef3ca8c2..535e08fa55b70 100644 --- a/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil +++ b/test/SILOptimizer/lifetime_dependence/lifetime_dependence.sil @@ -13,12 +13,10 @@ sil_stage raw class C {} -@_marker public protocol Escapable { } - 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 } ) -> () { @@ -31,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 @@ -46,9 +44,13 @@ 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 : $() } + +public struct Container : ~Copyable, ~Escapable where Element : ~Copyable {} + +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 2aa9da0d1f2fb..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 } @@ -34,3 +34,13 @@ 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 +} + +@lifetime(immortal) +func immortalConflict(_ immortal: Int) -> NE { // expected-error{{conflict between the parameter name and 'immortal' contextual keyword}} + 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() - } - } -}