diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 45c954f3f98..bd72feaac7c 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -632,14 +632,16 @@ public: const llvm::VersionTuple &Obsoleted, SourceRange ObsoletedRange, PlatformAgnosticAvailabilityKind PlatformAgnostic, - bool Implicit) + bool Implicit, + bool IsSPI) : DeclAttribute(DAK_Available, AtLoc, Range, Implicit), Message(Message), Rename(Rename), RenameDecl(RenameDecl), INIT_VER_TUPLE(Introduced), IntroducedRange(IntroducedRange), INIT_VER_TUPLE(Deprecated), DeprecatedRange(DeprecatedRange), INIT_VER_TUPLE(Obsoleted), ObsoletedRange(ObsoletedRange), PlatformAgnostic(PlatformAgnostic), - Platform(Platform) + Platform(Platform), + IsSPI(IsSPI) {} #undef INIT_VER_TUPLE @@ -685,6 +687,9 @@ public: /// The platform of the availability. const PlatformKind Platform; + /// Whether this is available as SPI. + const bool IsSPI; + /// Whether this is a language-version-specific entity. bool isLanguageVersionSpecific() const; diff --git a/include/swift/AST/Availability.h b/include/swift/AST/Availability.h index 3b670adba29..57429e6ea6e 100644 --- a/include/swift/AST/Availability.h +++ b/include/swift/AST/Availability.h @@ -209,9 +209,12 @@ public: /// [lattice]: http://mathworld.wolfram.com/Lattice.html class AvailabilityContext { VersionRange OSVersion; + llvm::Optional SPI; public: /// Creates a context that requires certain versions of the target OS. - explicit AvailabilityContext(VersionRange OSVersion) : OSVersion(OSVersion) {} + explicit AvailabilityContext(VersionRange OSVersion, + llvm::Optional SPI = llvm::None) + : OSVersion(OSVersion), SPI(SPI) {} /// Creates a context that imposes the constraints of the ASTContext's /// deployment target. @@ -291,6 +294,10 @@ public: void unionWith(AvailabilityContext other) { OSVersion.unionWith(other.getOSVersion()); } + + bool isAvailableAsSPI() const { + return SPI && *SPI; + } }; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 4cc7dc63649..8586025ecde 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1030,6 +1030,8 @@ public: // an @_spi context. bool isSPI() const; + bool isAvailableAsSPI() const; + // List the SPI groups declared with @_spi or inherited by this decl. // // SPI groups are inherited from the parent contexts only if the local decl diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index cd67247aec9..ff6f3de94de 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -126,6 +126,7 @@ DeclAttrKind DeclAttribute::getAttrKindFromString(StringRef Str) { #define DECL_ATTR(X, CLASS, ...) .Case(#X, DAK_##CLASS) #define DECL_ATTR_ALIAS(X, CLASS) .Case(#X, DAK_##CLASS) #include "swift/AST/Attr.def" + .Case("_spi_available", DAK_Available) .Default(DAK_Count); } @@ -1599,7 +1600,7 @@ AvailableAttr::createPlatformAgnostic(ASTContext &C, NoVersion, SourceRange(), NoVersion, SourceRange(), Obsoleted, SourceRange(), - Kind, /* isImplicit */ false); + Kind, /* isImplicit */ false, /*SPI*/false); } AvailableAttr *AvailableAttr::createForAlternative( @@ -1610,7 +1611,7 @@ AvailableAttr *AvailableAttr::createForAlternative( NoVersion, SourceRange(), NoVersion, SourceRange(), NoVersion, SourceRange(), - PlatformAgnosticAvailabilityKind::None, /*Implicit=*/true); + PlatformAgnosticAvailabilityKind::None, /*Implicit=*/true, /*SPI*/false); } bool AvailableAttr::isActivePlatform(const ASTContext &ctx) const { @@ -1628,7 +1629,8 @@ AvailableAttr *AvailableAttr::clone(ASTContext &C, bool implicit) const { Obsoleted ? *Obsoleted : llvm::VersionTuple(), implicit ? SourceRange() : ObsoletedRange, PlatformAgnostic, - implicit); + implicit, + IsSPI); } Optional diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 82fe4d7a7c0..df2deee6a2d 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -41,6 +41,7 @@ struct InferredAvailability { Optional Introduced; Optional Deprecated; Optional Obsoleted; + bool IsSPI = false; }; /// The type of a function that merges two version tuples. @@ -51,17 +52,20 @@ typedef const llvm::VersionTuple &(*MergeFunction)( /// Apply a merge function to two optional versions, returning the result /// in Inferred. -static void +static bool mergeIntoInferredVersion(const Optional &Version, Optional &Inferred, MergeFunction Merge) { if (Version.hasValue()) { if (Inferred.hasValue()) { Inferred = Merge(Inferred.getValue(), Version.getValue()); + return *Inferred == *Version; } else { Inferred = Version; + return true; } } + return false; } /// Merge an attribute's availability with an existing inferred availability @@ -75,7 +79,9 @@ static void mergeWithInferredAvailability(const AvailableAttr *Attr, static_cast(Attr->getPlatformAgnosticAvailability()))); // The merge of two introduction versions is the maximum of the two versions. - mergeIntoInferredVersion(Attr->Introduced, Inferred.Introduced, std::max); + if (mergeIntoInferredVersion(Attr->Introduced, Inferred.Introduced, std::max)) { + Inferred.IsSPI = Attr->IsSPI; + } // The merge of deprecated and obsoleted versions takes the minimum. mergeIntoInferredVersion(Attr->Deprecated, Inferred.Deprecated, std::min); @@ -103,7 +109,8 @@ createAvailableAttr(PlatformKind Platform, Introduced, /*IntroducedRange=*/SourceRange(), Deprecated, /*DeprecatedRange=*/SourceRange(), Obsoleted, /*ObsoletedRange=*/SourceRange(), - Inferred.PlatformAgnostic, /*Implicit=*/true); + Inferred.PlatformAgnostic, /*Implicit=*/true, + Inferred.IsSPI); } void AvailabilityInference::applyInferredAvailableAttrs( @@ -173,7 +180,13 @@ AvailabilityInference::annotatedAvailableRange(const Decl *D, ASTContext &Ctx) { return None; return AvailabilityContext{ - VersionRange::allGTE(bestAvailAttr->Introduced.getValue())}; + VersionRange::allGTE(bestAvailAttr->Introduced.getValue()), + bestAvailAttr->IsSPI}; +} + +bool Decl::isAvailableAsSPI() const { + return AvailabilityInference::availableRange(this, getASTContext()) + .isAvailableAsSPI(); } AvailabilityContext diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 9308eaa5ed2..c522744fd9c 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1936,7 +1936,8 @@ static void applyAvailableAttribute(Decl *decl, AvailabilityContext &info, /*Obsoleted=*/noVersion, /*ObsoletedRange*/SourceRange(), PlatformAgnosticAvailabilityKind::None, - /*Implicit=*/false); + /*Implicit=*/false, + /*SPI*/false); decl->getAttrs().add(AvAttr); } @@ -2681,7 +2682,8 @@ namespace { /*Deprecated*/llvm::VersionTuple(), SourceRange(), /*Obsoleted*/llvm::VersionTuple(), SourceRange(), PlatformAgnosticAvailabilityKind::SwiftVersionSpecific, - /*Implicit*/false); + /*Implicit*/false, + /*SPI*/false); } } @@ -9013,18 +9015,10 @@ void ClangImporter::Implementation::importAttributes( AnyUnavailable = true; } - if (EnableClangSPI) { - if (isUsingMacroName(getClangASTContext().getSourceManager(), + auto IsSPI = isUsingMacroName(getClangASTContext().getSourceManager(), avail->getLoc(), "SPI_AVAILABLE") || - isUsingMacroName(getClangASTContext().getSourceManager(), - avail->getLoc(), "__SPI_AVAILABLE")) { - // The decl has been marked as SPI in the header by using the SPI macro, - // thus we add the SPI attribute to it with a default group name. - MappedDecl->getAttrs().add(SPIAccessControlAttr::create(SwiftContext, - SourceLoc(), SourceRange(), - SwiftContext.getIdentifier(CLANG_MODULE_DEFUALT_SPI_GROUP_NAME))); - } - } + isUsingMacroName(getClangASTContext().getSourceManager(), + avail->getLoc(), "__SPI_AVAILABLE"); StringRef message = avail->getMessage(); @@ -9065,7 +9059,8 @@ void ClangImporter::Implementation::importAttributes( /*DeprecatedRange=*/SourceRange(), obsoleted, /*ObsoletedRange=*/SourceRange(), - PlatformAgnostic, /*Implicit=*/false); + PlatformAgnostic, /*Implicit=*/false, + IsSPI); MappedDecl->getAttrs().add(AvAttr); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 894d21a29e4..f970a8ca26d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -573,7 +573,8 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( Deprecated.Version, Deprecated.Range, Obsoleted.Version, Obsoleted.Range, PlatformAgnostic, - /*Implicit=*/false); + /*Implicit=*/false, + AttrName == "_spi_available"); return makeParserResult(Attr); } @@ -858,7 +859,8 @@ bool Parser::parseAvailability( /*DeprecatedRange=*/SourceRange(), /*Obsoleted=*/llvm::VersionTuple(), /*ObsoletedRange=*/SourceRange(), PlatformAgnostic, - /*Implicit=*/false)); + /*Implicit=*/false, + AttrName == "_spi_available")); } return true; diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index e1b1d6813f5..94ab7daee4e 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -1545,7 +1545,7 @@ swift::getDisallowedOriginKind(const Decl *decl, } // Implementation-only imported, cannot be reexported. return DisallowedOriginKind::ImplementationOnly; - } else if (decl->isSPI() && !where.isSPI()) { + } else if ((decl->isSPI() || decl->isAvailableAsSPI()) && !where.isSPI()) { // SPI can only be exported in SPI. return where.getDeclContext()->getParentModule() == M ? DisallowedOriginKind::SPILocal : diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index e7971574ba0..67054ddd2c3 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4344,6 +4344,7 @@ ProtocolConformance *GetImplicitSendableRequest::evaluate( NoVersion, SourceRange(), NoVersion, SourceRange(), PlatformAgnosticAvailabilityKind::Unavailable, + false, false); // Conformance availability is currently tied to the declaring extension. diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 2dc1fda1bb2..ee570ed8f96 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -4362,6 +4362,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl &scratch, bool isUnavailable; bool isDeprecated; bool isPackageDescriptionVersionSpecific; + bool isSPI; DEF_VER_TUPLE_PIECES(Introduced); DEF_VER_TUPLE_PIECES(Deprecated); DEF_VER_TUPLE_PIECES(Obsoleted); @@ -4371,7 +4372,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl &scratch, // Decode the record, pulling the version tuple information. serialization::decls_block::AvailableDeclAttrLayout::readRecord( scratch, isImplicit, isUnavailable, isDeprecated, - isPackageDescriptionVersionSpecific, LIST_VER_TUPLE_PIECES(Introduced), + isPackageDescriptionVersionSpecific, isSPI, LIST_VER_TUPLE_PIECES(Introduced), LIST_VER_TUPLE_PIECES(Deprecated), LIST_VER_TUPLE_PIECES(Obsoleted), platform, renameDeclID, messageSize, renameSize); @@ -4406,7 +4407,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl &scratch, auto attr = new (ctx) AvailableAttr( SourceLoc(), SourceRange(), (PlatformKind)platform, message, rename, renameDecl, Introduced, SourceRange(), Deprecated, SourceRange(), - Obsoleted, SourceRange(), platformAgnostic, isImplicit); + Obsoleted, SourceRange(), platformAgnostic, isImplicit, isSPI); return attr; } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index dae9212a378..ab9ec929825 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 675; // primary associated types +const uint16_t SWIFTMODULE_VERSION_MINOR = 676; // Add IsSPI to @available /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1916,6 +1916,7 @@ namespace decls_block { BCFixed<1>, // is unconditionally unavailable? BCFixed<1>, // is unconditionally deprecated? BCFixed<1>, // is this PackageDescription version-specific kind? + BCFixed<1>, // is SPI? BC_AVAIL_TUPLE, // Introduced BC_AVAIL_TUPLE, // Deprecated BC_AVAIL_TUPLE, // Obsoleted diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index fe8e447bbee..9b07358f787 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2581,6 +2581,7 @@ class Serializer::DeclSerializer : public DeclVisitor { theAttr->isUnconditionallyUnavailable(), theAttr->isUnconditionallyDeprecated(), theAttr->isPackageDescriptionVersionSpecific(), + theAttr->IsSPI, LIST_VER_TUPLE_PIECES(Introduced), LIST_VER_TUPLE_PIECES(Deprecated), LIST_VER_TUPLE_PIECES(Obsoleted),