diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index a2f683ffc9e7a..d0369de09aafb 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -1396,6 +1396,15 @@ BridgedSpecializeAttr BridgedSpecializeAttr_createParsed( BridgedDeclNameRef cTargetFunction, BridgedArrayRef cSPIGroups, BridgedArrayRef cAvailableAttrs); +SWIFT_NAME("BridgedSpecializedAttr.createParsed(_:atLoc:range:whereClause:" + "exported:kind:taretFunction:spiGroups:availableAttrs:)") +BridgedSpecializedAttr BridgedSpecializedAttr_createParsed( + BridgedASTContext cContext, BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, BridgedNullableTrailingWhereClause cWhereClause, + bool exported, BridgedSpecializationKind cKind, + BridgedDeclNameRef cTargetFunction, BridgedArrayRef cSPIGroups, + BridgedArrayRef cAvailableAttrs); + SWIFT_NAME( "BridgedSPIAccessControlAttr.createParsed(_:atLoc:range:spiGroupName:)") BridgedSPIAccessControlAttr BridgedSPIAccessControlAttr_createParsed( diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 9881ff2407d1a..746e40ea13164 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -75,7 +75,7 @@ class GenericParamList; class TrailingWhereClause; class ParameterList; class PatternBindingEntry; -class SpecializeAttr; +class AbstractSpecializeAttr; class GenericContext; class DeclName; class StmtConditionElement; @@ -1241,10 +1241,10 @@ class TopLevelCodeScope final : public ASTScopeImpl { /// The \c _@specialize attribute. class SpecializeAttributeScope final : public ASTScopeImpl { public: - SpecializeAttr *const specializeAttr; + AbstractSpecializeAttr *const specializeAttr; AbstractFunctionDecl *const whatWasSpecialized; - SpecializeAttributeScope(SpecializeAttr *specializeAttr, + SpecializeAttributeScope(AbstractSpecializeAttr *specializeAttr, AbstractFunctionDecl *whatWasSpecialized) : ASTScopeImpl(ScopeKind::SpecializeAttribute), specializeAttr(specializeAttr), whatWasSpecialized(whatWasSpecialized) { diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 9cf98597514c6..9f7b04e17d5d4 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -16,7 +16,6 @@ #ifndef SWIFT_ATTR_H #define SWIFT_ATTR_H - #include "swift/AST/ASTAllocated.h" #include "swift/AST/AttrKind.h" #include "swift/AST/AutoDiff.h" @@ -203,7 +202,7 @@ class DeclAttribute : public AttributeBase { ownership : NumReferenceOwnershipBits ); - SWIFT_INLINE_BITFIELD(SpecializeAttr, DeclAttribute, 1+1, + SWIFT_INLINE_BITFIELD(AbstractSpecializeAttr, DeclAttribute, 1+1, exported : 1, kind : 1 ); @@ -1730,15 +1729,17 @@ class SynthesizedProtocolAttr : public DeclAttribute { } }; -/// The @_specialize attribute, which forces specialization on the specified -/// type list. -class SpecializeAttr final +/// The @_specialize/@specialize attribute, which forces specialization on the +/// specified type list. +template +using SpecializeAttrTrailingObjects = llvm::TrailingObjects; + +class AbstractSpecializeAttr : public DeclAttribute, - private llvm::TrailingObjects { + private llvm::trailing_objects_internal::TrailingObjectsBase { friend class SpecializeAttrTargetDeclRequest; friend class SerializeAttrGenericSignatureRequest; - friend TrailingObjects; public: // NOTE: When adding new kinds, you must update the inline bitfield macro. @@ -1759,37 +1760,16 @@ class SpecializeAttr final size_t numTypeErasedParams; bool typeErasedParamsInitialized; - SpecializeAttr(SourceLoc atLoc, SourceRange Range, - TrailingWhereClause *clause, bool exported, +protected: + AbstractSpecializeAttr(DeclAttrKind DK, SourceLoc atLoc, SourceRange Range, + TrailingWhereClause *clause, + bool exported, SpecializationKind kind, GenericSignature specializedSignature, DeclNameRef targetFunctionName, ArrayRef spiGroups, ArrayRef availabilityAttrs, size_t typeErasedParamsCount); public: - static SpecializeAttr * - create(ASTContext &Ctx, SourceLoc atLoc, SourceRange Range, - TrailingWhereClause *clause, bool exported, SpecializationKind kind, - DeclNameRef targetFunctionName, ArrayRef spiGroups, - ArrayRef availabilityAttrs, - GenericSignature specializedSignature = nullptr); - - static SpecializeAttr *create(ASTContext &ctx, bool exported, - SpecializationKind kind, - ArrayRef spiGroups, - ArrayRef availabilityAttrs, - GenericSignature specializedSignature, - DeclNameRef replacedFunction); - - static SpecializeAttr *create(ASTContext &ctx, bool exported, - SpecializationKind kind, - ArrayRef spiGroups, - ArrayRef availabilityAttrs, - ArrayRef typeErasedParams, - GenericSignature specializedSignature, - DeclNameRef replacedFunction, - LazyMemberLoader *resolver, uint64_t data); - size_t numTrailingObjects(OverloadToken) const { return numSPIGroups; } @@ -1797,17 +1777,27 @@ class SpecializeAttr final size_t numTrailingObjects(OverloadToken) const { return numAvailableAttrs; } + // Helper to get the trailing objects of one of the subclasses. + template + const Type *getSubclassTrailingObjects() const; + + template + Type *getSubclassTrailingObjects() { + const auto *constThis = this; + return const_cast(constThis->getSubclassTrailingObjects()); + } + /// Name of SPIs declared by the attribute. /// /// Note: A single SPI name per attribute is currently supported but this /// may change with the syntax change. ArrayRef getSPIGroups() const { - return { this->template getTrailingObjects(), + return { getSubclassTrailingObjects(), numSPIGroups }; } ArrayRef getAvailableAttrs() const { - return {this->template getTrailingObjects(), + return {getSubclassTrailingObjects(), numAvailableAttrs}; } @@ -1815,26 +1805,36 @@ class SpecializeAttr final if (!typeErasedParamsInitialized) return {}; - return {this->template getTrailingObjects(), + return {getSubclassTrailingObjects(), numTypeErasedParams}; } void setTypeErasedParams(const ArrayRef typeErasedParams) { assert(typeErasedParams.size() == numTypeErasedParams); if (!typeErasedParamsInitialized) { - std::uninitialized_copy(typeErasedParams.begin(), typeErasedParams.end(), getTrailingObjects()); + std::uninitialized_copy(typeErasedParams.begin(), typeErasedParams.end(), + getSubclassTrailingObjects()); typeErasedParamsInitialized = true; } } + void setResolver(LazyMemberLoader *resolver, uint64_t resolverContextData) { + this->resolver = resolver; + this->resolverContextData = resolverContextData; + } + TrailingWhereClause *getTrailingWhereClause() const; + bool isPublic() const { + return getKind() == DeclAttrKind::Specialized; + } + bool isExported() const { - return Bits.SpecializeAttr.exported; + return Bits.AbstractSpecializeAttr.exported; } SpecializationKind getSpecializationKind() const { - return SpecializationKind(Bits.SpecializeAttr.kind); + return SpecializationKind(Bits.AbstractSpecializeAttr.kind); } bool isFullSpecialization() const { @@ -1856,15 +1856,140 @@ class SpecializeAttr final GenericSignature getSpecializedSignature(const AbstractFunctionDecl *forDecl) const; + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DeclAttrKind::Specialize || + DA->getKind() == DeclAttrKind::Specialized; + } + + UNIMPLEMENTED_CLONE(AbstractSpecializeAttr) + + bool isEquivalent(const AbstractSpecializeAttr *other, Decl *attachedTo) const; +}; + +/// The @_specialize attribute. +class SpecializeAttr final : public AbstractSpecializeAttr, + private SpecializeAttrTrailingObjects { + friend TrailingObjects; + friend AbstractSpecializeAttr; + + // WARNING: Do not add storage here. The base class uses TrailingObjects. +private: + SpecializeAttr(SourceLoc atLoc, SourceRange Range, + TrailingWhereClause *clause, + bool exported, + SpecializationKind kind, GenericSignature specializedSignature, + DeclNameRef targetFunctionName, ArrayRef spiGroups, + ArrayRef availabilityAttrs, + size_t typeErasedParamsCount) : + AbstractSpecializeAttr(DeclAttrKind::Specialize, atLoc, Range, clause, + exported, kind, specializedSignature, targetFunctionName, + spiGroups, availabilityAttrs, typeErasedParamsCount) {} + +public: + static SpecializeAttr * + create(ASTContext &Ctx, SourceLoc atLoc, SourceRange Range, + TrailingWhereClause *clause, bool exported, + SpecializationKind kind, + DeclNameRef targetFunctionName, ArrayRef spiGroups, + ArrayRef availabilityAttrs, + GenericSignature specializedSignature = nullptr); + + static SpecializeAttr *create(ASTContext &ctx, bool exported, + SpecializationKind kind, + ArrayRef spiGroups, + ArrayRef availabilityAttrs, + GenericSignature specializedSignature, + DeclNameRef replacedFunction); + + static SpecializeAttr *create(ASTContext &ctx, bool exported, + SpecializationKind kind, + ArrayRef spiGroups, + ArrayRef availabilityAttrs, + ArrayRef typeErasedParams, + GenericSignature specializedSignature, + DeclNameRef replacedFunction, + LazyMemberLoader *resolver, uint64_t data); + static bool classof(const DeclAttribute *DA) { return DA->getKind() == DeclAttrKind::Specialize; } UNIMPLEMENTED_CLONE(SpecializeAttr) - bool isEquivalent(const SpecializeAttr *other, Decl *attachedTo) const; + bool isEquivalent(const SpecializeAttr *other, Decl *attachedTo) const { + return AbstractSpecializeAttr::isEquivalent(other, attachedTo); + } }; +/// The @specialized attribute. +class SpecializedAttr final : public AbstractSpecializeAttr , + private SpecializeAttrTrailingObjects { + friend TrailingObjects; + friend AbstractSpecializeAttr; + + // WARNING: Do not add storage here. The base class uses TrailingObjects. +private: + + SpecializedAttr(SourceLoc atLoc, SourceRange Range, + TrailingWhereClause *clause, + bool exported, + SpecializationKind kind, GenericSignature specializedSignature, + DeclNameRef targetFunctionName, ArrayRef spiGroups, + ArrayRef availabilityAttrs, + size_t typeErasedParamsCount) : + AbstractSpecializeAttr(DeclAttrKind::Specialized, atLoc, Range, clause, + exported, kind, specializedSignature, targetFunctionName, + spiGroups, availabilityAttrs, typeErasedParamsCount) {} + +public: + static SpecializedAttr * + create(ASTContext &Ctx, SourceLoc atLoc, SourceRange Range, + TrailingWhereClause *clause, bool exported, + SpecializationKind kind, + DeclNameRef targetFunctionName, ArrayRef spiGroups, + ArrayRef availabilityAttrs, + GenericSignature specializedSignature = nullptr); + + static SpecializedAttr *create(ASTContext &ctx, bool exported, + SpecializationKind kind, + ArrayRef spiGroups, + ArrayRef availabilityAttrs, + GenericSignature specializedSignature, + DeclNameRef replacedFunction); + + static SpecializedAttr *create(ASTContext &ctx, bool exported, + SpecializationKind kind, + ArrayRef spiGroups, + ArrayRef availabilityAttrs, + ArrayRef typeErasedParams, + GenericSignature specializedSignature, + DeclNameRef replacedFunction, + LazyMemberLoader *resolver, uint64_t data); + + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DeclAttrKind::Specialized; + } + + UNIMPLEMENTED_CLONE(SpecializedAttr) + + bool isEquivalent(const SpecializedAttr *other, Decl *attachedTo) const { + return AbstractSpecializeAttr::isEquivalent(other, attachedTo); + } +}; + +template +const Type *AbstractSpecializeAttr::getSubclassTrailingObjects() const { + if (auto attr = dyn_cast(this)) { + return attr->getTrailingObjects(); + } + if (auto attr = dyn_cast(this)) { + return attr->getTrailingObjects(); + } + llvm_unreachable("unhandled AbstractSpecializeAttr subclass?"); +} + + + class StorageRestrictionsAttr final : public DeclAttribute, private llvm::TrailingObjects { diff --git a/include/swift/AST/AvailabilityInference.h b/include/swift/AST/AvailabilityInference.h index cfc9d871476c4..86dd46657c672 100644 --- a/include/swift/AST/AvailabilityInference.h +++ b/include/swift/AST/AvailabilityInference.h @@ -57,7 +57,7 @@ class AvailabilityInference { annotatedAvailableRange(const Decl *D); static AvailabilityRange - annotatedAvailableRangeForAttr(const Decl *D, const SpecializeAttr *attr, + annotatedAvailableRangeForAttr(const Decl *D, const AbstractSpecializeAttr *attr, ASTContext &ctx); /// For the attribute's introduction version, update the platform and version diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 28560878799c4..8e99902ae96e6 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -892,8 +892,13 @@ SIMPLE_DECL_ATTR(preEnumExtensibility, PreEnumExtensibility, ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove | UnconstrainedInABIAttr, 171) DECL_ATTR_FEATURE_REQUIREMENT(PreEnumExtensibility, ExtensibleAttribute) - -LAST_DECL_ATTR(PreEnumExtensibility) + +DECL_ATTR(specialized, Specialized, + OnConstructor | OnFunc | OnAccessor, + AllowMultipleAttributes | LongAttribute | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, + 172) + +LAST_DECL_ATTR(Specialized) #undef DECL_ATTR_ALIAS #undef CONTEXTUAL_DECL_ATTR_ALIAS diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 8d484ae855150..0d7b038a0ca8c 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1746,22 +1746,26 @@ ERROR(attr_warn_unused_result_expected_rparen,none, // _specialize ERROR(attr_specialize_missing_colon,none, - "missing ':' after %0 in '_specialize' attribute", (StringRef)) + "missing ':' after %0 in %select{'_specialize'|'specialized'}1 attribute", (StringRef, bool)) ERROR(attr_specialize_missing_comma,none, - "missing ',' in '_specialize' attribute", ()) + "missing ',' in %select{'_specialize'|'specialized'}0 attribute", (bool)) ERROR(attr_specialize_unknown_parameter_name,none, - "unknown parameter %0 in '_specialize attribute'", (StringRef)) + "unknown parameter %0 in %select{'_specialize'|'specialized'}1 attribute", (StringRef, bool)) +ERROR(attr_specialize_unsupported_parameter_name,none, + "unsupported parameter %0 in 'specialized attribute'", (StringRef)) ERROR(attr_specialize_expected_bool_value,none, - "expected a boolean true or false value in '_specialize' attribute", ()) + "expected a boolean true or false value in %select{'_specialize'|'specialized'}0 attribute", (bool)) ERROR(attr_specialize_missing_parameter_label_or_where_clause,none, "expected a parameter label or a where clause in '_specialize' attribute", ()) +ERROR(attr_specialized_missing_where_clause,none, + "expected a where clause in 'specialized' attribute", ()) ERROR(attr_specialize_parameter_already_defined,none, - "parameter '%0' was already defined in '_specialize' attribute", (StringRef)) + "parameter '%0' was already defined in %select{'_specialize'|'specialized'}1 attribute", (StringRef, bool)) ERROR(attr_specialize_expected_partial_or_full,none, "expected 'partial' or 'full' as values of the 'kind' parameter in '_specialize' attribute", ()) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 8d95abf58a47a..cd5c8736efc4d 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7276,23 +7276,25 @@ ERROR(resilient_associated_type_less_available_requires_default,none, //------------------------------------------------------------------------------ ERROR(specialize_attr_nongeneric_trailing_where,none, - "trailing 'where' clause in '_specialize' attribute of non-generic function %0", (DeclName)) + "trailing 'where' clause in %select{'_specialize'|'specialized'}1 attribute of non-generic function %0", (DeclName, bool)) ERROR(specialize_missing_where_clause,none, - "missing 'where' clause in '_specialize' attribute", ()) + "missing 'where' clause in %select{'_specialize'|'specialized'}0 attribute", (bool)) ERROR(specialize_empty_where_clause,none, - "empty 'where' clause in '_specialize' attribute", ()) + "empty 'where' clause in %select{'_specialize'|'specialized'}0 attribute", (bool)) ERROR(specialize_attr_non_concrete_same_type_req,none, - "only concrete type same-type requirements are supported by '_specialize' attribute", ()) + "only concrete type same-type requirements are supported by %select{'_specialize'|'specialized'}0 attribute", (bool)) ERROR(specialize_attr_only_generic_param_req,none, - "only requirements on generic parameters are supported by '_specialize' attribute", ()) + "only requirements on generic parameters are supported by %select{'_specialize'|'specialized'}0 attribute", (bool)) ERROR(specialize_attr_type_parameter_count_mismatch,none, "too few generic parameters are specified " - "in '_specialize' attribute (got %0, but expected %1)", - (unsigned, unsigned)) + "in %select{'_specialize'|'specialized'}2 attribute (got %0, but expected %1)", + (unsigned, unsigned, bool)) NOTE(specialize_attr_missing_constraint,none, - "missing constraint for %0 in '_specialize' attribute", (DeclName)) + "missing constraint for %0 in %select{'_specialize'|'specialized'}1 attribute", (DeclName, bool)) ERROR(specialize_attr_unsupported_kind_of_req,none, "only same-type and layout requirements are supported by '_specialize' attribute", ()) +ERROR(specialized_attr_unsupported_kind_of_req,none, + "only same-type are supported by 'specialized' attribute", ()) ERROR(specialize_target_function_not_found, none, "target function %0 could not be found", (DeclNameRef)) ERROR(specialize_target_function_of_type_not_found, none, diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h index 074ed8cc74665..1db9f2fd947b9 100644 --- a/include/swift/AST/LazyResolver.h +++ b/include/swift/AST/LazyResolver.h @@ -136,7 +136,7 @@ class alignas(void*) LazyMemberLoader { uint64_t contextData) = 0; // Returns the target parameter of the `@_specialize` attribute or null. - virtual ValueDecl *loadTargetFunctionDecl(const SpecializeAttr *attr, + virtual ValueDecl *loadTargetFunctionDecl(const AbstractSpecializeAttr *attr, uint64_t contextData) = 0; }; diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index c2909a0174a08..652dc3c8a970f 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -969,7 +969,7 @@ class ModuleDecl SmallVectorImpl &results) const; // Is \p attr accessible as an explicitly imported SPI from this module? - bool isImportedAsSPI(const SpecializeAttr *attr, + bool isImportedAsSPI(const AbstractSpecializeAttr *attr, const ValueDecl *targetDecl) const; // Is \p spiGroup accessible as an explicitly imported SPI from this module? diff --git a/include/swift/AST/TypeAlignments.h b/include/swift/AST/TypeAlignments.h index 827e9ba1313d6..b4eb926d6a1e9 100644 --- a/include/swift/AST/TypeAlignments.h +++ b/include/swift/AST/TypeAlignments.h @@ -26,6 +26,7 @@ namespace swift { class AbstractClosureExpr; + class AbstractSpecializeAttr; class AbstractStorageDecl; class ArchetypeType; class AssociatedTypeDecl; @@ -54,6 +55,7 @@ namespace swift { class SILFunction; class SILFunctionType; class SpecializeAttr; + class SpecializedAttr; class Stmt; class TrailingWhereClause; class TypeVariableType; @@ -149,6 +151,8 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::RequirementRepr, LLVM_DECLARE_TYPE_ALIGNMENT(swift::SILFunction, swift::SILFunctionAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::SpecializeAttr, swift::PointerAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::SpecializedAttr, swift::PointerAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::AbstractSpecializeAttr, swift::PointerAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::TrailingWhereClause, swift::PointerAlignInBits) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 526fecfe2125d..3bd68e74fa17f 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -64,7 +64,7 @@ struct PropertyWrapperLValueness; struct PropertyWrapperMutability; class RequirementRepr; class ReturnStmt; -class SpecializeAttr; +class AbstractSpecializeAttr; class TrailingWhereClause; class TypeAliasDecl; class TypeLoc; @@ -648,7 +648,7 @@ struct WhereClauseOwner { /// The source of the where clause, which can be a generic parameter list /// or a declaration that can have a where clause. llvm::PointerUnion + AbstractSpecializeAttr *, DifferentiableAttr *> source; WhereClauseOwner() : dc(nullptr) {} @@ -662,7 +662,7 @@ struct WhereClauseOwner { WhereClauseOwner(DeclContext *dc, TrailingWhereClause *where) : dc(dc), source(where) {} - WhereClauseOwner(DeclContext *dc, SpecializeAttr *attr) + WhereClauseOwner(DeclContext *dc, AbstractSpecializeAttr *attr) : dc(dc), source(attr) {} WhereClauseOwner(DeclContext *dc, DifferentiableAttr *attr) @@ -3311,7 +3311,7 @@ class DynamicallyReplacedDeclRequest class SpecializeAttrTargetDeclRequest : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -3321,7 +3321,7 @@ class SpecializeAttrTargetDeclRequest // Evaluation. ValueDecl *evaluate(Evaluator &evaluator, const ValueDecl *vd, - SpecializeAttr *attr) const; + AbstractSpecializeAttr *attr) const; public: // Caching. @@ -4956,7 +4956,7 @@ class ExpandChildAvailabilityScopesRequest class SerializeAttrGenericSignatureRequest : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -4966,7 +4966,7 @@ class SerializeAttrGenericSignatureRequest GenericSignature evaluate(Evaluator &evaluator, const AbstractFunctionDecl *decl, - SpecializeAttr *attr) const; + AbstractSpecializeAttr *attr) const; public: // Separate caching. diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index ff50e811953d5..adccb8ace5927 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -96,7 +96,7 @@ SWIFT_REQUEST(TypeChecker, ABIMembersRequest, SWIFT_REQUEST(TypeChecker, AllMembersRequest, ArrayRef(IterableDeclContext *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, SpecializeAttrTargetDeclRequest, - ValueDecl *(const ValueDecl *, SpecializeAttr *), + ValueDecl *(const ValueDecl *, AbstractSpecializeAttr *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest, evaluator::SideEffect (EnumDecl *, TypeResolutionStage), @@ -564,7 +564,7 @@ SWIFT_REQUEST(TypeChecker, ExpandChildAvailabilityScopesRequest, std::vector(AvailabilityScope *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, SerializeAttrGenericSignatureRequest, - GenericSignature(Decl *, SpecializeAttr *), + GenericSignature(Decl *, AbstractSpecializeAttr *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, IsFunctionBodySkippedRequest, bool(const AbstractFunctionDecl *), diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 6da0b8a8788b0..18a1e0b13c0dd 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1038,20 +1038,20 @@ class Parser { bool isAttrModifier, SourceRange &parensRange, llvm::function_ref parseAttr); - /// Parse the @_specialize attribute. + /// Parse the @_specialize/@specialized attribute. /// \p closingBrace is the expected closing brace, which can be either ) or ] /// \p Attr is where to store the parsed attribute bool parseSpecializeAttribute( - swift::tok ClosingBrace, SourceLoc AtLoc, SourceLoc Loc, - SpecializeAttr *&Attr, AvailabilityRange *SILAvailability, + swift::tok ClosingBrace, SourceLoc AtLoc, SourceLoc Loc, bool isPublic, + AbstractSpecializeAttr *&Attr, AvailabilityRange *SILAvailability, llvm::function_ref parseSILTargetName = [](Parser &) { return false; }, llvm::function_ref parseSILSIPModule = [](Parser &) { return false; }); - /// Parse the arguments inside the @_specialize attribute + /// Parse the arguments inside the @_specialize/@specialized attribute bool parseSpecializeAttributeArguments( - swift::tok ClosingBrace, bool &DiscardAttribute, + swift::tok ClosingBrace, bool isPublic, bool &DiscardAttribute, std::optional &Exported, std::optional &Kind, TrailingWhereClause *&TrailingWhereClause, DeclNameRef &targetFunction, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 1bd7d6d6f9f55..508a978caa516 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -5430,7 +5430,16 @@ class PrintAttribute : public AttributeVisitor, printFoot(); } void visitSpecializeAttr(SpecializeAttr *Attr, Label label) { - printCommon(Attr, "specialize_attr", label); + visitAbstractSpecializeAttr(Attr, label); + } + + void visitSpecializedAttr(SpecializedAttr *Attr, Label label) { + visitAbstractSpecializeAttr(Attr, label); + } + + void visitAbstractSpecializeAttr(AbstractSpecializeAttr *Attr, Label label) { + printCommon(Attr, Attr->isPublic() ? "specialized_attr" : + "specialize_attr", label); printFlag(Attr->isExported(), "exported"); printFlag(Attr->isFullSpecialization(), "full"); printFlag(Attr->isPartialSpecialization(), "partial"); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index cde493033b558..7277b4fb648af 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -148,7 +148,7 @@ static bool isPackage(Type ty) { static bool isPrespecilizationDeclWithTarget(const ValueDecl *vd) { // Add exported prespecialized symbols. - for (auto *attr : vd->getAttrs().getAttributes()) { + for (auto *attr : vd->getAttrs().getAttributes()) { if (!attr->isExported()) continue; if (attr->getTargetFunctionDecl(vd)) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 40d0bc8b60b9d..baac19d2d0aa3 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -661,7 +661,7 @@ void ScopeCreator::addChildrenForKnownAttributes(Decl *decl, if (isa(attr)) relevantAttrs.push_back(attr); - if (isa(attr)) + if (isa(attr)) relevantAttrs.push_back(attr); if (isa(attr)) @@ -679,7 +679,7 @@ void ScopeCreator::addChildrenForKnownAttributes(Decl *decl, if (auto *diffAttr = dyn_cast(attr)) { constructExpandAndInsert( parent, diffAttr, decl); - } else if (auto *specAttr = dyn_cast(attr)) { + } else if (auto *specAttr = dyn_cast(attr)) { if (auto *afd = dyn_cast(decl)) { constructExpandAndInsert( parent, specAttr, afd); diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 003b7ccb446da..00b4443824834 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -1310,39 +1310,45 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, break; } + case DeclAttrKind::Specialized: case DeclAttrKind::Specialize: { - auto *attr = cast(this); + auto *attr = cast(this); // Don't print the _specialize attribute if it is marked spi and we are // asked to skip SPI. if (Options.printPublicInterface() && !attr->getSPIGroups().empty()) return false; Printer << "@" << getAttrName() << "("; - auto exported = attr->isExported() ? "true" : "false"; - auto kind = attr->isPartialSpecialization() ? "partial" : "full"; - auto target = attr->getTargetFunctionName(); - Printer << "exported: "<< exported << ", "; - for (auto id : attr->getSPIGroups()) { - Printer << "spi: " << id << ", "; - } - Printer << "kind: " << kind << ", "; - if (target) - Printer << "target: " << target << ", "; - SmallVector semanticAvailAttrs; - for (auto availAttr : attr->getAvailableAttrs()) { - if (auto semanticAttr = D->getSemanticAvailableAttr(availAttr)) - semanticAvailAttrs.push_back(*semanticAttr); - } - if (!semanticAvailAttrs.empty()) { - Printer << "availability: "; - if (semanticAvailAttrs.size() == 1) { - printAvailableAttr(D, semanticAvailAttrs[0], Printer, Options); - Printer << "; "; - } else { - printShortFormAvailable(D, semanticAvailAttrs, Printer, Options, - true /*forAtSpecialize*/); - Printer << "; "; + // The non-underscored @specialize attribute currently does not support + // parameters so lets not print them. + if (!attr->isPublic()) { + auto exported = attr->isExported() ? "true" : "false"; + auto kind = attr->isPartialSpecialization() ? "partial" : "full"; + auto target = attr->getTargetFunctionName(); + Printer << "exported: "<< exported << ", "; + for (auto id : attr->getSPIGroups()) { + Printer << "spi: " << id << ", "; + } + Printer << "kind: " << kind << ", "; + if (target) + Printer << "target: " << target << ", "; + SmallVector semanticAvailAttrs; + for (auto availAttr : attr->getAvailableAttrs()) { + if (auto semanticAttr = D->getSemanticAvailableAttr(availAttr)) + semanticAvailAttrs.push_back(*semanticAttr); + } + + if (!semanticAvailAttrs.empty()) { + Printer << "availability: "; + if (semanticAvailAttrs.size() == 1) { + printAvailableAttr(D, semanticAvailAttrs[0], Printer, Options); + Printer << "; "; + } else { + printShortFormAvailable(D, semanticAvailAttrs, Printer, Options, + true /*forAtSpecialize*/); + Printer << "; "; + } } } SmallVector requirementsScratch; @@ -1888,6 +1894,8 @@ StringRef DeclAttribute::getAttrName() const { return "<>"; case DeclAttrKind::SynthesizedProtocol: return "<>"; + case DeclAttrKind::Specialized: + return "specialized"; case DeclAttrKind::Specialize: return "_specialize"; case DeclAttrKind::StorageRestrictions: @@ -2441,31 +2449,32 @@ bool AvailableAttr::isNoAsync() const { llvm_unreachable("Unhandled AvailableAttr::Kind in switch."); } -SpecializeAttr::SpecializeAttr(SourceLoc atLoc, SourceRange range, - TrailingWhereClause *clause, bool exported, +AbstractSpecializeAttr::AbstractSpecializeAttr(DeclAttrKind DK, + SourceLoc atLoc, SourceRange range, + TrailingWhereClause *clause, + bool exported, SpecializationKind kind, GenericSignature specializedSignature, DeclNameRef targetFunctionName, ArrayRef spiGroups, ArrayRef availableAttrs, size_t typeErasedParamsCount) - : DeclAttribute(DeclAttrKind::Specialize, atLoc, range, - /*Implicit=*/clause == nullptr), + : DeclAttribute(DK, atLoc, range, /*Implicit=*/clause == nullptr), trailingWhereClause(clause), specializedSignature(specializedSignature), targetFunctionName(targetFunctionName), numSPIGroups(spiGroups.size()), numAvailableAttrs(availableAttrs.size()), numTypeErasedParams(typeErasedParamsCount), typeErasedParamsInitialized(false) { std::uninitialized_copy(spiGroups.begin(), spiGroups.end(), - getTrailingObjects()); + getSubclassTrailingObjects()); std::uninitialized_copy(availableAttrs.begin(), availableAttrs.end(), - getTrailingObjects()); + getSubclassTrailingObjects()); - Bits.SpecializeAttr.exported = exported; - Bits.SpecializeAttr.kind = unsigned(kind); + Bits.AbstractSpecializeAttr.exported = exported; + Bits.AbstractSpecializeAttr.kind = unsigned(kind); } -TrailingWhereClause *SpecializeAttr::getTrailingWhereClause() const { +TrailingWhereClause *AbstractSpecializeAttr::getTrailingWhereClause() const { return trailingWhereClause; } @@ -2512,8 +2521,8 @@ SpecializeAttr *SpecializeAttr::create(ASTContext &ctx, bool exported, spiGroups.size(), availableAttrs.size(), 0); void *mem = ctx.Allocate(size, alignof(SpecializeAttr)); return new (mem) SpecializeAttr( - SourceLoc(), SourceRange(), nullptr, exported, kind, specializedSignature, - targetFunctionName, spiGroups, availableAttrs, 0); + SourceLoc(), SourceRange(), nullptr, exported, kind, + specializedSignature, targetFunctionName, spiGroups, availableAttrs, 0); } SpecializeAttr *SpecializeAttr::create( @@ -2529,23 +2538,88 @@ SpecializeAttr *SpecializeAttr::create( SourceLoc(), SourceRange(), nullptr, exported, kind, specializedSignature, targetFunctionName, spiGroups, availableAttrs, typeErasedParams.size()); attr->setTypeErasedParams(typeErasedParams); - attr->resolver = resolver; - attr->resolverContextData = data; + attr->setResolver(resolver, data); + return attr; +} + +// @specialize +// +SpecializedAttr *SpecializedAttr::create(ASTContext &Ctx, SourceLoc atLoc, + SourceRange range, + TrailingWhereClause *clause, + bool exported, SpecializationKind kind, + DeclNameRef targetFunctionName, + ArrayRef spiGroups, + ArrayRef availableAttrs, + GenericSignature specializedSignature) { + size_t typeErasedParamsCount = 0; + if (Ctx.LangOpts.hasFeature(Feature::LayoutPrespecialization)) { + if (clause != nullptr) { + for (auto &req : clause->getRequirements()) { + if (req.getKind() == RequirementReprKind::LayoutConstraint) { + if (auto *attributedTy = + dyn_cast(req.getSubjectRepr())) { + if (attributedTy->has(TypeAttrKind::NoMetadata)) { + typeErasedParamsCount += 1; + } + } + } + } + } + } + + unsigned size = totalSizeToAlloc( + spiGroups.size(), availableAttrs.size(), typeErasedParamsCount); + void *mem = Ctx.Allocate(size, alignof(SpecializedAttr)); + + return new (mem) + SpecializedAttr(atLoc, range, clause, exported, kind, specializedSignature, + targetFunctionName, spiGroups, availableAttrs, typeErasedParamsCount); +} + +SpecializedAttr *SpecializedAttr::create(ASTContext &ctx, bool exported, + SpecializationKind kind, + ArrayRef spiGroups, + ArrayRef availableAttrs, + GenericSignature specializedSignature, + DeclNameRef targetFunctionName) { + unsigned size = totalSizeToAlloc( + spiGroups.size(), availableAttrs.size(), 0); + void *mem = ctx.Allocate(size, alignof(SpecializedAttr)); + return new (mem) SpecializedAttr( + SourceLoc(), SourceRange(), nullptr, exported, kind, + specializedSignature, targetFunctionName, spiGroups, availableAttrs, 0); +} + +SpecializedAttr *SpecializedAttr::create( + ASTContext &ctx, bool exported, SpecializationKind kind, + ArrayRef spiGroups, ArrayRef availableAttrs, + ArrayRef typeErasedParams, GenericSignature specializedSignature, + DeclNameRef targetFunctionName, LazyMemberLoader *resolver, + uint64_t data) { + unsigned size = totalSizeToAlloc( + spiGroups.size(), availableAttrs.size(), typeErasedParams.size()); + void *mem = ctx.Allocate(size, alignof(SpecializedAttr)); + auto *attr = new (mem) SpecializedAttr( + SourceLoc(), SourceRange(), nullptr, exported, kind, specializedSignature, + targetFunctionName, spiGroups, availableAttrs, typeErasedParams.size()); + attr->setTypeErasedParams(typeErasedParams); + attr->setResolver(resolver, data); return attr; } -ValueDecl * SpecializeAttr::getTargetFunctionDecl(const ValueDecl *onDecl) const { +ValueDecl * AbstractSpecializeAttr::getTargetFunctionDecl(const ValueDecl *onDecl) const { return evaluateOrDefault(onDecl->getASTContext().evaluator, SpecializeAttrTargetDeclRequest{ - onDecl, const_cast(this)}, + onDecl, const_cast(this)}, nullptr); } -GenericSignature SpecializeAttr::getSpecializedSignature( +GenericSignature AbstractSpecializeAttr::getSpecializedSignature( const AbstractFunctionDecl *onDecl) const { return evaluateOrDefault(onDecl->getASTContext().evaluator, SerializeAttrGenericSignatureRequest{ - onDecl, const_cast(this)}, + onDecl, const_cast(this)}, nullptr); } @@ -2584,7 +2658,7 @@ bool sameElements(ArrayRef first, ArrayRef second) { return sameElements(first, second, std::equal_to()); } -bool SpecializeAttr::isEquivalent(const SpecializeAttr *other, +bool AbstractSpecializeAttr::isEquivalent(const AbstractSpecializeAttr *other, Decl *attachedTo) const { if (isExported() != other->isExported() || getSpecializationKind() != other->getSpecializationKind() || diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 3f506a20f52d0..1098553821fa4 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -744,7 +744,7 @@ bool Decl::requiresUnavailableDeclABICompatibilityStubs() const { } AvailabilityRange AvailabilityInference::annotatedAvailableRangeForAttr( - const Decl *D, const SpecializeAttr *attr, ASTContext &ctx) { + const Decl *D, const AbstractSpecializeAttr *attr, ASTContext &ctx) { std::optional bestAvailAttr; for (auto *availAttr : attr->getAvailableAttrs()) { diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index 6c67b7174bdc0..4325fd293370e 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -842,9 +842,9 @@ static SpecializeAttr::SpecializationKind unbridge(BridgedSpecializationKind kind) { switch (kind) { case BridgedSpecializationKindFull: - return SpecializeAttr::SpecializationKind::Full; + return AbstractSpecializeAttr::SpecializationKind::Full; case BridgedSpecializationKindPartial: - return SpecializeAttr::SpecializationKind::Partial; + return AbstractSpecializeAttr::SpecializationKind::Partial; } llvm_unreachable("unhandled kind"); } @@ -868,6 +868,25 @@ BridgedSpecializeAttr BridgedSpecializeAttr_createParsed( cTargetFunction.unbridged(), spiGroups, availableAttrs); } +BridgedSpecializedAttr BridgedSpecializedAttr_createParsed( + BridgedASTContext cContext, BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, BridgedNullableTrailingWhereClause cWhereClause, + bool exported, BridgedSpecializationKind cKind, + BridgedDeclNameRef cTargetFunction, BridgedArrayRef cSPIGroups, + BridgedArrayRef cAvailableAttrs) { + SmallVector spiGroups; + for (auto bridging : cSPIGroups.unbridged()) + spiGroups.push_back(bridging.unbridged()); + SmallVector availableAttrs; + for (auto bridging : cAvailableAttrs.unbridged()) + availableAttrs.push_back(bridging.unbridged()); + + return SpecializedAttr::create( + cContext.unbridged(), cAtLoc.unbridged(), cRange.unbridged(), + cWhereClause.unbridged(), exported, unbridge(cKind), + cTargetFunction.unbridged(), spiGroups, availableAttrs); +} + BridgedSPIAccessControlAttr BridgedSPIAccessControlAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedSourceRange cRange, BridgedIdentifier cSPIGroupName) { @@ -918,4 +937,4 @@ BridgedUnavailableFromAsyncAttr BridgedUnavailableFromAsyncAttr_createParsed( return new (cContext.unbridged()) UnavailableFromAsyncAttr(cMessage.unbridged(), cAtLoc.unbridged(), cRange.unbridged(), /*implicit=*/false); -} \ No newline at end of file +} diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 03a100512445d..2897d3b55b69e 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -3109,7 +3109,7 @@ bool SourceFile::isImportedAsSPI(const ValueDecl *targetDecl) const { return false; } -bool ModuleDecl::isImportedAsSPI(const SpecializeAttr *attr, +bool ModuleDecl::isImportedAsSPI(const AbstractSpecializeAttr *attr, const ValueDecl *targetDecl) const { auto declSPIGroups = attr->getSPIGroups(); if (shouldImplicitImportAsSPI(declSPIGroups)) diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 11bd7187d880d..f56d66ff55f6a 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -468,7 +468,7 @@ WhereClauseOwner::WhereClauseOwner(AssociatedTypeDecl *atd) SourceLoc WhereClauseOwner::getLoc() const { if (auto genericParams = source.dyn_cast()) { return genericParams->getWhereLoc(); - } else if (auto attr = source.dyn_cast()) { + } else if (auto attr = source.dyn_cast()) { return attr->getLocation(); } else if (auto attr = source.dyn_cast()) { return attr->getLocation(); @@ -483,8 +483,11 @@ void swift::simple_display(llvm::raw_ostream &out, const WhereClauseOwner &owner) { if (owner.source.is()) { simple_display(out, owner.dc->getAsDecl()); - } else if (owner.source.is()) { - out << "@_specialize"; + } else if (auto attr = owner.source.dyn_cast()) { + if (attr->isPublic()) + out << "@specialized"; + else + out << "@_specialize"; } else if (owner.source.is()) { out << "@_differentiable"; } else { @@ -508,7 +511,7 @@ void RequirementRequest::noteCycleStep(DiagnosticEngine &diags) const { MutableArrayRef WhereClauseOwner::getRequirements() const { if (const auto genericParams = source.dyn_cast()) { return genericParams->getRequirements(); - } else if (const auto attr = source.dyn_cast()) { + } else if (const auto attr = source.dyn_cast()) { if (auto whereClause = attr->getTrailingWhereClause()) return whereClause->getRequirements(); } else if (const auto attr = source.dyn_cast()) { diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 1e8192ef7d22b..a27b622ed6d04 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -179,6 +179,8 @@ extension ASTGenVisitor { return handle(self.generateSILGenNameAttr(attribute: node)?.asDeclAttribute) case .specialize: return handle(self.generateSpecializeAttr(attribute: node, attrName: attrName)?.asDeclAttribute) + case .specialized: + return handle(self.generateSpecializedAttr(attribute: node, attrName: attrName)?.asDeclAttribute) case .spiAccessControl: return handle(self.generateSPIAccessControlAttr(attribute: node)?.asDeclAttribute) case .storageRestrictions: @@ -1871,7 +1873,40 @@ extension ASTGenVisitor { /// E.g.: /// ``` - /// @_specialize(exporeted: true, T == Int) + /// @specialized(T == Int) + /// ``` + func generateSpecializedAttr(attribute node: AttributeSyntax, attrName: SyntaxText) -> BridgedSpecializedAttr? { + guard + var arg = node.arguments?.as(SpecializedAttributeArgumentSyntax.self) + else { + // TODO: Diagnose + return nil + } + var exported: Bool? + var kind: BridgedSpecializationKind? = nil + var whereClause: BridgedTrailingWhereClause? = nil + var targetFunction: BridgedDeclNameRef? = nil + var spiGroups: [BridgedIdentifier] = [] + var availableAttrs: [BridgedAvailableAttr] = [] + + whereClause = self.generate(genericWhereClause: arg.genericWhereClause) + + return .createParsed( + self.ctx, + atLoc: self.generateSourceLoc(node.atSign), + range: self.generateAttrSourceRange(node), + whereClause: whereClause.asNullable, + exported: exported ?? false, + kind: kind ?? .full, + taretFunction: targetFunction ?? BridgedDeclNameRef(), + spiGroups: spiGroups.lazy.bridgedArray(in: self), + availableAttrs: availableAttrs.lazy.bridgedArray(in: self) + ) + } + + /// E.g.: + /// ``` + /// @_specialize(exported: true, T == Int) /// ``` func generateSpecializeAttr(attribute node: AttributeSyntax, attrName: SyntaxText) -> BridgedSpecializeAttr? { guard @@ -1880,7 +1915,6 @@ extension ASTGenVisitor { // TODO: Diagnose return nil } - var exported: Bool? var kind: BridgedSpecializationKind? = nil var whereClause: BridgedTrailingWhereClause? = nil diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 897061c3fc31b..b64b2c882f86a 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1687,7 +1687,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation llvm_unreachable("unimplemented for ClangImporter"); } - ValueDecl *loadTargetFunctionDecl(const SpecializeAttr *attr, + ValueDecl *loadTargetFunctionDecl(const AbstractSpecializeAttr *attr, uint64_t contextData) override { llvm_unreachable("unimplemented for ClangImporter"); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6f18c4f6429a0..6989b8229d165 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -560,7 +560,7 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( } bool Parser::parseSpecializeAttributeArguments( - swift::tok ClosingBrace, bool &DiscardAttribute, + swift::tok ClosingBrace, bool isPublic, bool &DiscardAttribute, std::optional &Exported, std::optional &Kind, swift::TrailingWhereClause *&TrailingWhereClause, @@ -580,11 +580,22 @@ bool Parser::parseSpecializeAttributeArguments( ParamLabel != "spiModule" && ParamLabel != "availability" && (!isSIL || ParamLabel != "available")) { diagnose(Tok.getLoc(), diag::attr_specialize_unknown_parameter_name, + ParamLabel, isPublic); + } + + // The non-underscored '@specialize' mode currently does not support any + // parameters. + if (isPublic) { + diagnose(Tok.getLoc(), diag::attr_specialize_unsupported_parameter_name, ParamLabel); + DiscardAttribute = true; + return false; } + auto AtLoc = consumeToken(); if (!consumeIf(tok::colon)) { - diagnose(Tok.getLoc(), diag::attr_specialize_missing_colon, ParamLabel); + diagnose(Tok.getLoc(), diag::attr_specialize_missing_colon, ParamLabel, + isPublic); skipUntil(tok::comma, tok::kw_where); if (Tok.is(ClosingBrace)) break; @@ -602,7 +613,7 @@ bool Parser::parseSpecializeAttributeArguments( (ParamLabel == "kind" && Kind.has_value()) || (ParamLabel == "spi" && !spiGroups.empty())) { diagnose(Tok.getLoc(), diag::attr_specialize_parameter_already_defined, - ParamLabel); + ParamLabel, isPublic); } if (ParamLabel == "available") { SourceRange range; @@ -628,7 +639,7 @@ bool Parser::parseSpecializeAttributeArguments( bool isTrue = consumeIf(tok::kw_true); bool isFalse = consumeIf(tok::kw_false); if (!isTrue && !isFalse) { - diagnose(Tok.getLoc(), diag::attr_specialize_expected_bool_value); + diagnose(Tok.getLoc(), diag::attr_specialize_expected_bool_value, isPublic); skipUntil(tok::comma, tok::kw_where); if (Tok.is(ClosingBrace)) break; @@ -678,7 +689,7 @@ bool Parser::parseSpecializeAttributeArguments( if (ParamLabel == "spiModule") { if (!parseSILSIPModule(*this)) { diagnose(Tok.getLoc(), diag::attr_specialize_unknown_parameter_name, - ParamLabel); + ParamLabel, isPublic); return false; } } @@ -693,7 +704,7 @@ bool Parser::parseSpecializeAttributeArguments( consumeToken(); } if (!isAvailability && !consumeIf(tok::comma)) { - diagnose(Tok.getLoc(), diag::attr_specialize_missing_comma); + diagnose(Tok.getLoc(), diag::attr_specialize_missing_comma, isPublic); skipUntil(tok::comma, tok::kw_where); if (Tok.is(ClosingBrace)) break; @@ -710,6 +721,7 @@ bool Parser::parseSpecializeAttributeArguments( continue; } diagnose(Tok.getLoc(), + isPublic ? diag::attr_specialized_missing_where_clause : diag::attr_specialize_missing_parameter_label_or_where_clause); DiscardAttribute = true; return false; @@ -719,8 +731,8 @@ bool Parser::parseSpecializeAttributeArguments( if (Tok.is(tok::kw_where)) { SourceLoc whereLoc, endLoc; SmallVector requirements; - parseGenericWhereClause(whereLoc, endLoc, requirements, - /* AllowLayoutConstraints */ true); + auto status = parseGenericWhereClause(whereLoc, endLoc, requirements, + /* AllowLayoutConstraints */ !isPublic); TrailingWhereClause = TrailingWhereClause::create(Context, whereLoc, endLoc, requirements); } @@ -858,8 +870,8 @@ bool Parser::parseAvailability( } bool Parser::parseSpecializeAttribute( - swift::tok ClosingBrace, SourceLoc AtLoc, SourceLoc Loc, - SpecializeAttr *&Attr, AvailabilityRange *SILAvailability, + swift::tok ClosingBrace, SourceLoc AtLoc, SourceLoc Loc, bool isPublic, + AbstractSpecializeAttr *&Attr, AvailabilityRange *SILAvailability, llvm::function_ref parseSILTargetName, llvm::function_ref parseSILSIPModule) { assert(ClosingBrace == tok::r_paren || ClosingBrace == tok::r_square); @@ -873,7 +885,7 @@ bool Parser::parseSpecializeAttribute( lParenLoc = consumeToken(); } bool DiscardAttribute = false; - StringRef AttrName = "_specialize"; + StringRef AttrName = isPublic ? "specialized" : "_specialize"; std::optional exported; std::optional kind; @@ -884,7 +896,8 @@ bool Parser::parseSpecializeAttribute( SmallVector spiGroups; SmallVector availableAttrs; if (!parseSpecializeAttributeArguments( - ClosingBrace, DiscardAttribute, exported, kind, trailingWhereClause, + ClosingBrace, isPublic, DiscardAttribute, exported, kind, + trailingWhereClause, targetFunction, SILAvailability, spiGroups, availableAttrs, parseSILTargetName, parseSILSIPModule)) { return false; @@ -914,10 +927,17 @@ bool Parser::parseSpecializeAttribute( } // Store the attribute. - Attr = SpecializeAttr::create(Context, AtLoc, SourceRange(Loc, rParenLoc), - trailingWhereClause, exported.value(), - kind.value(), targetFunction, spiGroups, - availableAttrs); + if (isPublic) + Attr = SpecializedAttr::create(Context, AtLoc, + SourceRange(Loc, rParenLoc), + trailingWhereClause, exported.value(), + kind.value(), targetFunction, spiGroups, + availableAttrs); + else + Attr = SpecializeAttr::create(Context, AtLoc, SourceRange(Loc, rParenLoc), + trailingWhereClause, exported.value(), + kind.value(), targetFunction, spiGroups, + availableAttrs); return true; } @@ -3586,14 +3606,17 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, break; } - case DeclAttrKind::Specialize: { + case DeclAttrKind::Specialize: + case DeclAttrKind::Specialized: { if (Tok.isNot(tok::l_paren)) { diagnose(Loc, diag::attr_expected_lparen, AttrName, DeclAttribute::isDeclModifier(DK)); return makeParserSuccess(); } - SpecializeAttr *Attr; - if (!parseSpecializeAttribute(tok::r_paren, AtLoc, Loc, Attr, nullptr)) + AbstractSpecializeAttr *Attr; + if (!parseSpecializeAttribute(tok::r_paren, AtLoc, Loc, + DK == DeclAttrKind::Specialized, Attr, + nullptr)) return makeParserSuccess(); Attributes.add(Attr); diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index 265ba7cec0c82..ea0cfa8d9e9f5 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -351,6 +351,8 @@ ParserStatus Parser::parseGenericWhereClause( if (!AllowLayoutConstraints && !isInSILMode()) { diagnose(LayoutLoc, diag::layout_constraints_only_inside_specialize_attr); + Status.setIsParseError(); + break; } else { // Add the layout requirement. Requirements.push_back(RequirementRepr::getLayoutConstraint( diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index b15f75b4645c8..e99d351f65888 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -65,8 +65,8 @@ void SILFunctionBuilder::addFunctionAttributes( F->addSemanticsAttr(semantics::FORCE_EMIT_OPT_REMARK_PREFIX); // Propagate @_specialize. - for (auto *A : Attrs.getAttributes()) { - auto *SA = cast(A); + for (auto *A : Attrs.getAttributes()) { + auto *SA = cast(A); auto kind = SA->getSpecializationKind() == SpecializeAttr::SpecializationKind::Full ? SILSpecializeAttr::SpecializationKind::Full diff --git a/lib/SIL/IR/SILSymbolVisitor.cpp b/lib/SIL/IR/SILSymbolVisitor.cpp index 3da9722583e55..fac8a1ba32c35 100644 --- a/lib/SIL/IR/SILSymbolVisitor.cpp +++ b/lib/SIL/IR/SILSymbolVisitor.cpp @@ -472,7 +472,7 @@ class SILSymbolVisitorImpl : public ASTVisitor { void visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) { // Add exported prespecialized symbols. - for (auto *attr : AFD->getAttrs().getAttributes()) { + for (auto *attr : AFD->getAttrs().getAttributes()) { if (!attr->isExported()) continue; diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 741dfe45b4836..0cce858d985a2 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -891,12 +891,15 @@ static bool parseDeclSILOptional( SpecAttr.requirements = {}; SpecAttr.exported = false; SpecAttr.kind = SILSpecializeAttr::SpecializationKind::Full; - SpecializeAttr *Attr; + AbstractSpecializeAttr *Attr; StringRef targetFunctionName; ModuleDecl *module = nullptr; + bool isPublic = false; // In SIL we don't care to disambiguate @specialize + // and @_specialize. We use the "more permissive" + // non-public version when parsing SIL. AvailabilityRange availability = AvailabilityRange::alwaysAvailable(); if (!SP.P.parseSpecializeAttribute( - tok::r_square, AtLoc, Loc, Attr, &availability, + tok::r_square, AtLoc, Loc, isPublic, Attr, &availability, [&targetFunctionName](Parser &P) -> bool { if (P.Tok.getKind() != tok::string_literal) { P.diagnose(P.Tok, diag::expected_in_attribute_list); diff --git a/lib/SILOptimizer/Transforms/GenericSpecializer.cpp b/lib/SILOptimizer/Transforms/GenericSpecializer.cpp index 93dd7cdd99dcb..5592408db8bc0 100644 --- a/lib/SILOptimizer/Transforms/GenericSpecializer.cpp +++ b/lib/SILOptimizer/Transforms/GenericSpecializer.cpp @@ -40,8 +40,8 @@ static void transferSpecializeAttributeTargets(SILModule &M, SILOptFunctionBuilder &builder, Decl *d) { auto *vd = cast(d); - for (auto *A : vd->getAttrs().getAttributes()) { - auto *SA = cast(A); + for (auto *A : vd->getAttrs().getAttributes()) { + auto *SA = cast(A); // Filter _spi. auto spiGroups = SA->getSPIGroups(); auto hasSPIGroup = !spiGroups.empty(); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 2edcc31fb553b..d83b28738e7e2 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -401,7 +401,9 @@ class AttributeChecker : public AttributeVisitor { void visitPostfixAttr(PostfixAttr *attr) { checkOperatorAttribute(attr); } void visitPrefixAttr(PrefixAttr *attr) { checkOperatorAttribute(attr); } + void visitSpecializedAttr(SpecializedAttr *attr); void visitSpecializeAttr(SpecializeAttr *attr); + void visitAbstractSpecializeAttr(AbstractSpecializeAttr *attr); void visitFixedLayoutAttr(FixedLayoutAttr *attr); void visitUsableFromInlineAttr(UsableFromInlineAttr *attr); @@ -3324,7 +3326,7 @@ void AttributeChecker::visitRethrowsAttr(RethrowsAttr *attr) { /// Ensure that the requirements provided by the @_specialize attribute /// can be supported by the SIL EagerSpecializer pass. -static void checkSpecializeAttrRequirements(SpecializeAttr *attr, +static void checkSpecializeAttrRequirements(AbstractSpecializeAttr *attr, GenericSignature originalSig, GenericSignature specializedSig, ASTContext &ctx) { @@ -3334,7 +3336,8 @@ static void checkSpecializeAttrRequirements(SpecializeAttr *attr, for (auto specializedReq : specializedReqs) { if (!specializedReq.getFirstType()->is()) { ctx.Diags.diagnose(attr->getLocation(), - diag::specialize_attr_only_generic_param_req); + diag::specialize_attr_only_generic_param_req, + attr->isPublic()); hadError = true; continue; } @@ -3346,14 +3349,17 @@ static void checkSpecializeAttrRequirements(SpecializeAttr *attr, case RequirementKind::Conformance: case RequirementKind::Superclass: ctx.Diags.diagnose(attr->getLocation(), - diag::specialize_attr_unsupported_kind_of_req); + attr->isPublic() ? + diag::specialized_attr_unsupported_kind_of_req : + diag::specialize_attr_unsupported_kind_of_req); hadError = true; break; case RequirementKind::SameType: if (specializedReq.getSecondType()->isTypeParameter()) { ctx.Diags.diagnose(attr->getLocation(), - diag::specialize_attr_non_concrete_same_type_req); + diag::specialize_attr_non_concrete_same_type_req, + attr->isPublic()); hadError = true; } break; @@ -3391,38 +3397,48 @@ static void checkSpecializeAttrRequirements(SpecializeAttr *attr, ctx.Diags.diagnose( attr->getLocation(), diag::specialize_attr_type_parameter_count_mismatch, - gotCount, expectedCount); + gotCount, expectedCount, attr->isPublic()); for (auto paramTy : unspecializedParams) { ctx.Diags.diagnose(attr->getLocation(), diag::specialize_attr_missing_constraint, - paramTy->getName()); + paramTy->getName(), + attr->isPublic()); } } -/// Type check that a set of requirements provided by @_specialize. +/// Type check that a set of requirements provided by @_specialize/@specialize. /// Store the set of requirements in the attribute. +void AttributeChecker::visitSpecializedAttr(SpecializedAttr *attr) { + visitAbstractSpecializeAttr(attr); +} void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { + visitAbstractSpecializeAttr(attr); +} +void AttributeChecker::visitAbstractSpecializeAttr(AbstractSpecializeAttr *attr) { auto *FD = cast(D); auto genericSig = FD->getGenericSignature(); auto *trailingWhereClause = attr->getTrailingWhereClause(); if (!trailingWhereClause) { // Report a missing "where" clause. - diagnose(attr->getLocation(), diag::specialize_missing_where_clause); + diagnose(attr->getLocation(), diag::specialize_missing_where_clause, + attr->isPublic()); return; } if (trailingWhereClause->getRequirements().empty()) { // Report an empty "where" clause. - diagnose(attr->getLocation(), diag::specialize_empty_where_clause); + diagnose(attr->getLocation(), diag::specialize_empty_where_clause, + attr->isPublic()); return; } if (!genericSig) { // Only generic functions are permitted to have trailing where clauses. diagnose(attr->getLocation(), - diag::specialize_attr_nongeneric_trailing_where, FD->getName()) + diag::specialize_attr_nongeneric_trailing_where, FD->getName(), + attr->isPublic()) .highlight(trailingWhereClause->getSourceRange()); return; } @@ -3433,7 +3449,7 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { GenericSignature SerializeAttrGenericSignatureRequest::evaluate(Evaluator &evaluator, const AbstractFunctionDecl *FD, - SpecializeAttr *attr) const { + AbstractSpecializeAttr *attr) const { if (attr->specializedSignature) return attr->specializedSignature; @@ -3489,7 +3505,7 @@ SerializeAttrGenericSignatureRequest::evaluate(Evaluator &evaluator, std::optional SerializeAttrGenericSignatureRequest::getCachedResult() const { const auto &storage = getStorage(); - SpecializeAttr *attr = std::get<1>(storage); + AbstractSpecializeAttr *attr = std::get<1>(storage); if (auto signature = attr->specializedSignature) return signature; return std::nullopt; @@ -3498,7 +3514,7 @@ SerializeAttrGenericSignatureRequest::getCachedResult() const { void SerializeAttrGenericSignatureRequest::cacheResult( GenericSignature signature) const { const auto &storage = getStorage(); - SpecializeAttr *attr = std::get<1>(storage); + AbstractSpecializeAttr *attr = std::get<1>(storage); attr->specializedSignature = signature; } @@ -3932,7 +3948,7 @@ findReplacedFunction(DeclNameRef replacedFunctionName, static AbstractFunctionDecl * findTargetFunction(DeclNameRef targetFunctionName, const AbstractFunctionDecl *base, - SpecializeAttr * attr, DiagnosticEngine *diags) { + AbstractSpecializeAttr * attr, DiagnosticEngine *diags) { return findSimilarFunction(targetFunctionName, base, attr, diags, false /*forDynamicReplacement*/); } @@ -5607,7 +5623,7 @@ DynamicallyReplacedDeclRequest::evaluate(Evaluator &evaluator, ValueDecl * SpecializeAttrTargetDeclRequest::evaluate(Evaluator &evaluator, const ValueDecl *vd, - SpecializeAttr *attr) const { + AbstractSpecializeAttr *attr) const { if (auto *lazyResolver = attr->resolver) { auto *decl = lazyResolver->loadTargetFunctionDecl(attr, attr->resolverContextData); diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 3e46cb956d5d6..aaee6b6bac20e 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1657,6 +1657,7 @@ namespace { UNINTERESTING_ATTR(SwiftNativeObjCRuntimeBase) UNINTERESTING_ATTR(ShowInInterface) UNINTERESTING_ATTR(Specialize) + UNINTERESTING_ATTR(Specialized) UNINTERESTING_ATTR(SpecializeExtension) UNINTERESTING_ATTR(DynamicReplacement) UNINTERESTING_ATTR(PrivateImport) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 24018bf5a1425..a17d0c5968268 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -6188,6 +6188,7 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { } case decls_block::Specialize_DECL_ATTR: { + unsigned isPublic; unsigned exported; SpecializeAttr::SpecializationKind specializationKind; unsigned specializationKindVal; @@ -6199,7 +6200,7 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { DeclID targetFunID; serialization::decls_block::SpecializeDeclAttrLayout::readRecord( - scratch, exported, specializationKindVal, specializedSigID, + scratch, isPublic, exported, specializationKindVal, specializedSigID, targetFunID, numSPIGroups, numAvailabilityAttrs, rawTrailingIDs); specializationKind = specializationKindVal @@ -6250,8 +6251,13 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { // Read target function DeclNameRef, if present. DeclNameRef targetFunName = deserializeDeclNameRefIfPresent(); - - Attr = SpecializeAttr::create(ctx, exported != 0, specializationKind, + if (isPublic) + Attr = SpecializedAttr::create(ctx, exported != 0, specializationKind, + spis, availabilityAttrs, typeErasedParams, + specializedSig, targetFunName, &MF, + targetFunID); + else + Attr = SpecializeAttr::create(ctx, exported != 0, specializationKind, spis, availabilityAttrs, typeErasedParams, specializedSig, targetFunName, &MF, targetFunID); @@ -8817,8 +8823,9 @@ ModuleFile::loadReferencedFunctionDecl(const DerivativeAttr *DA, return cast(getDecl(contextData)); } -ValueDecl *ModuleFile::loadTargetFunctionDecl(const SpecializeAttr *attr, - uint64_t contextData) { +ValueDecl *ModuleFile::loadTargetFunctionDecl( + const AbstractSpecializeAttr *attr, + uint64_t contextData) { if (contextData == 0) return nullptr; return cast(getDecl(contextData)); diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index 2226b88d8036b..f8b53a4621201 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -940,7 +940,7 @@ class ModuleFile loadDynamicallyReplacedFunctionDecl(const DynamicReplacementAttr *DRA, uint64_t contextData) override; - virtual ValueDecl *loadTargetFunctionDecl(const SpecializeAttr *attr, + virtual ValueDecl *loadTargetFunctionDecl(const AbstractSpecializeAttr *attr, uint64_t contextData) override; virtual AbstractFunctionDecl * loadReferencedFunctionDecl(const DerivativeAttr *DA, diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index fe4b2a33216ef..37d9371b924f7 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 951; // add modifier to @_inheritActorContext +const uint16_t SWIFTMODULE_VERSION_MINOR = 952; // Add @specialized /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2449,6 +2449,7 @@ namespace decls_block { using SpecializeDeclAttrLayout = BCRecordLayout< Specialize_DECL_ATTR, + BCFixed<1>, // isPublic flag (@specialized vs @_specialize) BCFixed<1>, // exported flag BCFixed<1>, // specialization kind GenericSignatureIDField, // specialized signature @@ -2457,6 +2458,9 @@ namespace decls_block { BCVBR<4>, // # of availability attributes BCArray // spi groups, type erased params >; + // Unused. We use the layout above. + using SpecializedDeclAttrLayout = BCRecordLayout< + Specialized_DECL_ATTR>; using StorageRestrictionsDeclAttrLayout = BCRecordLayout< StorageRestrictions_DECL_ATTR, diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 8d7782e519305..602bace3e9dcc 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3201,9 +3201,10 @@ class Serializer::DeclSerializer : public DeclVisitor { return; } + case DeclAttrKind::Specialized: case DeclAttrKind::Specialize: { auto abbrCode = S.DeclTypeAbbrCodes[SpecializeDeclAttrLayout::Code]; - auto attr = cast(DA); + auto attr = cast(DA); auto *afd = cast(D); auto *targetFunDecl = attr->getTargetFunctionDecl(afd); @@ -3223,7 +3224,8 @@ class Serializer::DeclSerializer : public DeclVisitor { auto numAvailabilityAttrs = attr->getAvailableAttrs().size(); SpecializeDeclAttrLayout::emitRecord( - S.Out, S.ScratchRecord, abbrCode, (unsigned)attr->isExported(), + S.Out, S.ScratchRecord, abbrCode, (unsigned)attr->isPublic(), + (unsigned)attr->isExported(), (unsigned)attr->getSpecializationKind(), S.addGenericSignatureRef(attr->getSpecializedSignature(afd)), S.addDeclRef(targetFunDecl), numSPIGroups, numAvailabilityAttrs, @@ -4140,8 +4142,8 @@ class Serializer::DeclSerializer : public DeclVisitor { void noteUseOfExportedPrespecialization(const AbstractFunctionDecl *afd) { bool hasNoted = false; - for (auto *A : afd->getAttrs().getAttributes()) { - auto *SA = cast(A); + for (auto *A : afd->getAttrs().getAttributes()) { + auto *SA = cast(A); if (!SA->isExported()) continue; if (SA->getTargetFunctionDecl(afd)) { diff --git a/test/ASTGen/attrs.swift b/test/ASTGen/attrs.swift index a223977aa26f2..6606ca054f08f 100644 --- a/test/ASTGen/attrs.swift +++ b/test/ASTGen/attrs.swift @@ -170,6 +170,9 @@ struct ProjectedValueStruct { @_specialize(where X: _TrivialStride(16), Y: _Trivial(32, 4), Z: _Class) func testSpecialize(x: X, y: Y, z: Z) {} +@specialized(where X == Int, Y == Float, Z == Double) +func testSpecializePublic(x: X, y: Y, z: Z) {} + @_spi(SPIName) public func spiFn() {} struct StorageRestrctionTest { diff --git a/test/SILGen/specialize_attr.swift b/test/SILGen/specialize_attr.swift index 3fb19f220c708..98c27788b4de7 100644 --- a/test/SILGen/specialize_attr.swift +++ b/test/SILGen/specialize_attr.swift @@ -3,6 +3,7 @@ // RUN: %target-swift-frontend -module-name A -emit-module-path %t/A.swiftmodule -enable-library-evolution -swift-version 5 %S/Inputs/specialize_attr_module.swift // RUN: %target-swift-frontend -I %t -module-name B -emit-module-path %t/B.swiftmodule -enable-library-evolution -swift-version 5 %S/Inputs/specialize_attr_module2.swift // RUN: %target-swift-emit-silgen -I %t -module-name specialize_attr -emit-verbose-sil %s -swift-version 5 | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-os +// RUN: %target-swift-emit-silgen -I %t -module-name specialize_attr -emit-verbose-sil %s -swift-version 5 | %FileCheck %s -check-prefix=CHECK2 // RUN: %target-swift-emit-sil -I %t -sil-verify-all -O -module-name specialize_attr -emit-verbose-sil %s | %FileCheck -check-prefix=CHECK-OPT -check-prefix=CHECK-OPT-EVO -check-prefix=CHECK-OPT-%target-os %s // Test .swiftinterface @@ -342,3 +343,24 @@ extension InternalThing2 { } } } + + +// Tests for the "public" @specialized attribute. +// CHECK2: @specialized(where T == Int, U == Float) +// CHECK2-NEXT: @specialized(where T == Klass1, U == FakeString) +// CHECK2-NEXT: func publicSpecializeThis(_ t: T, u: U) +@specialized(where T == Int, U == Float) +@specialized(where T == Klass1, U == FakeString) +public func publicSpecializeThis(_ t: T, u: U) {} +// CHECK2: extension TestPrespecialized { +// CHECK2-NEXT: @specialized(where T == Int) +// CHECK2-NEXT: public func testExtension() + +extension TestPrespecialized { + @specialized(where T == Int) + public func testExtension() { + } +} + +// CHECK2: sil [_specialize exported: false, kind: full, where T == Klass1, U == FakeString] [_specialize exported: false, kind: full, where T == Int, U == Float] [ossa] @$s15specialize_attr20publicSpecializeThis_1uyx_q_tr0_lF +// CHECK2: sil [_specialize exported: false, kind: full, where T == Int] [ossa] @$s15specialize_attr18TestPrespecializedV13testExtensionyyF diff --git a/test/SILOptimizer/prespecialize_public.swift b/test/SILOptimizer/prespecialize_public.swift new file mode 100644 index 0000000000000..2243dca0ee5ec --- /dev/null +++ b/test/SILOptimizer/prespecialize_public.swift @@ -0,0 +1,30 @@ +// RUN: %target-swift-frontend %s -O -emit-sil | %FileCheck %s + +// REQUIRES: optimized_stdlib + +extension Sequence where Element: BinaryInteger { + + @specialized(where Self == [Int]) + public func sum() -> Double { + reduce(0) { $0 + Double($1) } + } +// CHECK: sil @$sST20prespecialize_publicSz7ElementRpzrlE3sumSdyF : $@convention(method) (@in_guaranteed Self) -> Double { +// CHECK: bb0(%0 : $*Self): +// CHECK: [[T1:%.*]] = metatype $@thick Self.Type +// CHECK: [[T2:%.*]] = metatype $@thick Array.Type +// CHECK: [[T3:%.*]] = unchecked_trivial_bit_cast [[T1]] to $Builtin.Word +// CHECK: [[T4:%.*]] = unchecked_trivial_bit_cast [[T2]] to $Builtin.Word +// CHECK: [[T5:%.*]] = builtin "cmp_eq_Word"([[T3]], [[T4]]) : $Builtin.Int1 +// CHECK: cond_br [[T5]], bb3, bb1 + +// CHECK: bb1: +// CHECK: [[T6:%.*]] = function_ref @$sSTsE6reduceyqd__qd___qd__qd___7ElementQztKXEtKlF +// CHECK: apply {{.*}} [[T6]]( +// CHECK: br bb2( + +// CHECK: bb2({{.*}} : $Double): +// CHECK: return + +// CHECK: bb3: +// CHECK: %25 = unchecked_addr_cast %0 to $*Array +} diff --git a/test/attr/attr_specialize.swift b/test/attr/attr_specialize.swift index 2971406bbbaf7..679b8d6f275db 100644 --- a/test/attr/attr_specialize.swift +++ b/test/attr/attr_specialize.swift @@ -29,6 +29,7 @@ class NonSub {} @_specialize(where T == S) @_specialize(where T == Int, U == Int) // expected-error{{cannot find type 'U' in scope}}, @_specialize(where T == T1) // expected-error{{cannot find type 'T1' in scope}} +@specialized(where T == T1) // expected-error{{cannot find type 'T1' in scope}} public func oneGenericParam(_ t: T) -> T { return t } @@ -60,6 +61,11 @@ class G { func noGenericParams() {} + @specialized(where T == Int) + @specialized(where T == T) // expected-error{{too few generic parameters are specified in 'specialized' attribute (got 0, but expected 1)}} + // expected-note@-1 {{missing constraint for 'T' in 'specialized' attribute}} + func noGenericParamsPublic() {} + // CHECK: @_specialize(exported: false, kind: full, where T == Int, U == Float) @_specialize(where T == Int, U == Float) // CHECK: @_specialize(exported: false, kind: full, where T == Int, U == S) @@ -68,7 +74,10 @@ class G { func oneGenericParam(_ t: T, u: U) -> (U, T) { return (u, t) } -} + @specialized(where T == Int) // expected-error{{too few generic parameters are specified in 'specialized' attribute (got 1, but expected 2)}} expected-note {{missing constraint for 'U' in 'specialized' attribute}} + func oneGenericParamPublic(_ t: T, u: U) -> (U, T) { + return (u, t) + }} // Specialize with requirements. // ----------------------------- @@ -96,8 +105,14 @@ struct FloatElement : HasElt { @_specialize(where T == IntElement) // expected-error{{generic signature requires types 'IntElement.Element' (aka 'Int') and 'Float' to be the same}} func sameTypeRequirement(_ t: T) where T.Element == Float {} +@specialized(where T == FloatElement) +@specialized(where T == IntElement) // expected-error{{generic signature requires types 'IntElement.Element' (aka 'Int') and 'Float' to be the same}} +func sameTypeRequirementPublic(_ t: T) where T.Element == Float {} + @_specialize(where T == Sub) @_specialize(where T == NonSub) // expected-error{{no type for 'T' can satisfy both 'T : NonSub' and 'T : Base'}} +@specialized(where T == Sub) +@specialized(where T == NonSub) // expected-error{{no type for 'T' can satisfy both 'T : NonSub' and 'T : Base'}} func superTypeRequirement(_ t: T) {} @_specialize(where X:_Trivial(8), Y == Int) // expected-error{{trailing 'where' clause in '_specialize' attribute of non-generic function 'requirementOnNonGenericFunction(x:y:)'}} @@ -105,11 +120,13 @@ public func requirementOnNonGenericFunction(x: Int, y: Int) { } @_specialize(where Y == Int) // expected-error{{too few generic parameters are specified in '_specialize' attribute (got 1, but expected 2)}} expected-note{{missing constraint for 'X' in '_specialize' attribute}} +@specialized(where Y == Int) // expected-error{{too few generic parameters are specified in 'specialized' attribute (got 1, but expected 2)}} expected-note{{missing constraint for 'X' in 'specialized' attribute}} public func missingRequirement(x: X, y: Y) { } @_specialize(where) // expected-error{{expected type}} @_specialize() // expected-error{{expected a parameter label or a where clause in '_specialize' attribute}} expected-error{{expected declaration}} +@specialized() // expected-error{{expected a where clause in 'specialized' attribute}} expected-error{{expected declaration}} public func funcWithEmptySpecializeAttr(x: X, y: Y) { } @@ -149,11 +166,12 @@ public func funcWithTwoGenericParameters(x: X, y: Y) { @_specialize(kind: partial, exported: true, where X == Int, Y == Int) @_specialize(kind: partial, kind: partial, where X == Int, Y == Int) // expected-error{{parameter 'kind' was already defined in '_specialize' attribute}} -@_specialize(where X == Int, Y == Int, exported: true, kind: partial) // expected-error{{cannot find type 'exported' in scope}} expected-error{{cannot find type 'kind' in scope}} expected-error{{cannot find type 'partial' in scope}} expected-error{{expected type}} +@_specialize(where X == Int, Y == Int, exported: true, kind: partial) // expected-error{{expected type}} expected-error{{cannot find type 'exported' in scope}} expected-error{{cannot find type 'kind' in scope}} expected-error{{cannot find type 'partial' in scope}} public func anotherFuncWithTwoGenericParameters(x: X, y: Y) { } @_specialize(where T: P) // expected-error{{only same-type and layout requirements are supported by '_specialize' attribute}} +@specialized(where T: P) // expected-error{{only same-type are supported by 'specialized' attribute}} @_specialize(where T: Int) // expected-error{{type 'T' constrained to non-protocol, non-class type 'Int'}} expected-note {{use 'T == Int' to require 'T' to be 'Int'}} // expected-error@-1 {{too few generic parameters are specified in '_specialize' attribute (got 0, but expected 1)}} // expected-note@-2 {{missing constraint for 'T' in '_specialize' attribute}} @@ -163,6 +181,9 @@ public func anotherFuncWithTwoGenericParameters(x: X, y: Y) { // expected-note@-2 {{missing constraint for 'T' in '_specialize' attribute}} @_specialize(where T: C1) // expected-error{{only same-type and layout requirements are supported by '_specialize' attribute}} @_specialize(where Int: P) // expected-error{{too few generic parameters are specified in '_specialize' attribute (got 0, but expected 1)}} expected-note{{missing constraint for 'T' in '_specialize' attribute}} +@specialized(where T: Int) // expected-error{{type 'T' constrained to non-protocol, non-class type 'Int'}} expected-note {{use 'T == Int' to require 'T' to be 'Int'}} +// expected-error@-1 {{too few generic parameters are specified in 'specialized' attribute (got 0, but expected 1)}} +// expected-note@-2 {{missing constraint for 'T' in 'specialized' attribute}} func funcWithForbiddenSpecializeRequirement(_ t: T) { } @@ -230,10 +251,12 @@ public func copyValueAndReturn(_ t: S, s: inout S) -> S where S: P{ struct OuterStruct { struct MyStruct { @_specialize(where T == Int, U == Float) // expected-error{{too few generic parameters are specified in '_specialize' attribute (got 2, but expected 3)}} expected-note{{missing constraint for 'S' in '_specialize' attribute}} + @specialized(where T == Int, U == Float) // expected-error{{too few generic parameters are specified in 'specialized' attribute (got 2, but expected 3)}} expected-note{{missing constraint for 'S' in 'specialized' attribute}} public func foo(u : U) { } @_specialize(where T == Int, U == Float, S == Int) + @specialized(where T == Int, U == Float, S == Int) public func bar(u : U) { } } @@ -308,6 +331,7 @@ extension Container { // E becomes concrete via the combination of 'S == Set' and // 'E == S.Element'. @_specialize(where S == Set) +@specialized(where S == Set) public func takesSequenceAndElement(_: S, _: E) where S : Sequence, E == S.Element {} @@ -350,6 +374,36 @@ public func foo(_ t: T) where T.Element == ExpectedElement } @_specialize(where T == Conformer) // expected-error{{generic signature requires types 'Conformer.Element' (aka 'ConformerElement') and 'ExpectedElement' to be the same}} +@specialized(where T == Conformer) // expected-error{{generic signature requires types 'Conformer.Element' (aka 'ConformerElement') and 'ExpectedElement' to be the same}} public func bar(_ t: T) where T.Element == ExpectedElement { foo(t) } + +// CHECK: @specialized(where T == Int) +@specialized(where T == Int) +// CHECK: @specialized(where T == S) +@specialized(where T == S) +public func oneGenericParam2Good(_ t: T) -> T { + return t +} + +@specialized(where T == Int, U == Int) // expected-error{{cannot find type 'U' in scope}}, +@specialized(where T == T1) // expected-error{{cannot find type 'T1' in scope}}, +@specialized(where T : _Trivial) // expected-error{{layout constraints are only allowed inside '_specialize' attributes}} expected-error{{empty 'where' clause in 'specialized' attribute}} +public func oneGenericParam2(_ t: T) -> T { + return t +} + +// CHECK: @specialized(where T == Int, U == Int) +@specialized(where T == Int, U == Int) +@specialized(where T == Int) // expected-error{{too few generic parameters are specified in 'specialized' attribute (got 1, but expected 2)}} expected-note{{missing constraint for 'U' in 'specialized' attribute}} +public func twoGenericParams2(_ t: T, u: U) -> (T, U) { + return (t, u) +} + +@specialized(where T == Int) // expected-error{{trailing 'where' clause in 'specialized' attribute of non-generic function 'nonGenericParam2(x:)'}} +func nonGenericParam2(x: Int) {} + +@_specialize(where T == Int) +@_specialize(where T == Int) +func genericParamDuplicate(t: T) {}