//===--- Attr.h - Swift Language Attribute ASTs -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines classes related to declaration attributes. // //===----------------------------------------------------------------------===// #ifndef SWIFT_ATTR_H #define SWIFT_ATTR_H #include "swift/Basic/Debug.h" #include "swift/Basic/InlineBitfield.h" #include "swift/Basic/SourceLoc.h" #include "swift/Basic/UUID.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/Range.h" #include "swift/Basic/OptimizationMode.h" #include "swift/Basic/Version.h" #include "swift/Basic/Located.h" #include "swift/AST/Identifier.h" #include "swift/AST/AttrKind.h" #include "swift/AST/AutoDiff.h" #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/DeclNameLoc.h" #include "swift/AST/KnownProtocols.h" #include "swift/AST/Ownership.h" #include "swift/AST/PlatformKind.h" #include "swift/AST/Requirement.h" #include "swift/AST/TrailingCallArguments.h" #include "swift/AST/TypeLoc.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TrailingObjects.h" #include "llvm/Support/VersionTuple.h" namespace swift { class ASTPrinter; class ASTContext; struct PrintOptions; class Decl; class AbstractFunctionDecl; class FuncDecl; class ClassDecl; class GenericFunctionType; class LazyConformanceLoader; class LazyMemberLoader; class PatternBindingInitializer; class TrailingWhereClause; /// TypeAttributes - These are attributes that may be applied to types. class TypeAttributes { // Get a SourceLoc for every possible attribute that can be parsed in source. // the presence of the attribute is indicated by its location being set. SourceLoc AttrLocs[TAK_Count]; public: /// AtLoc - This is the location of the first '@' in the attribute specifier. /// If this is an empty attribute specifier, then this will be an invalid loc. SourceLoc AtLoc; struct Convention { StringRef Name = {}; DeclNameRef WitnessMethodProtocol = {}; Located ClangType = Located(StringRef(), {}); /// Convenience factory function to create a Swift convention. /// /// Don't use this function if you are creating a C convention as you /// probably need a ClangType field as well. static Convention makeSwiftConvention(StringRef name) { return {name, DeclNameRef(), Located("", {})}; } }; Optional ConventionArguments; // Indicates whether the type's '@differentiable' attribute has a 'linear' // argument. bool linear = false; // For an opened existential type, the known ID. Optional OpenedID; // For a reference to an opaque return type, the mangled name and argument // index into the generic signature. struct OpaqueReturnTypeRef { StringRef mangledName; unsigned index; }; Optional OpaqueReturnTypeOf; TypeAttributes() {} bool isValid() const { return AtLoc.isValid(); } bool isLinear() const { assert( !linear || (linear && has(TAK_differentiable)) && "Linear shouldn't have been true if there's no `@differentiable`"); return linear; } void clearAttribute(TypeAttrKind A) { AttrLocs[A] = SourceLoc(); } bool has(TypeAttrKind A) const { return getLoc(A).isValid(); } SourceLoc getLoc(TypeAttrKind A) const { return AttrLocs[A]; } void setOpaqueReturnTypeOf(StringRef mangling, unsigned index) { OpaqueReturnTypeOf = OpaqueReturnTypeRef{mangling, index}; } void setAttr(TypeAttrKind A, SourceLoc L) { assert(!L.isInvalid() && "Cannot clear attribute with this method"); AttrLocs[A] = L; } void getAttrLocs(SmallVectorImpl &Locs) const { for (auto Loc : AttrLocs) { if (Loc.isValid()) Locs.push_back(Loc); } } // This attribute list is empty if no attributes are specified. Note that // the presence of the leading @ is not enough to tell, because we want // clients to be able to remove attributes they process until they get to // an empty list. bool empty() const { for (SourceLoc elt : AttrLocs) if (elt.isValid()) return false; return true; } bool hasConvention() const { return ConventionArguments.hasValue(); } /// Returns the primary calling convention string. /// /// Note: For C conventions, this may not represent the full convention. StringRef getConventionName() const { return ConventionArguments.getValue().Name; } /// Show the string enclosed between @convention(..)'s parentheses. /// /// For example, @convention(foo, bar) will give the string "foo, bar". void getConventionArguments(SmallVectorImpl &buffer) const; bool hasOwnership() const { return getOwnership() != ReferenceOwnership::Strong; } ReferenceOwnership getOwnership() const { #define REF_STORAGE(Name, name, ...) \ if (has(TAK_sil_##name)) return ReferenceOwnership::Name; #include "swift/AST/ReferenceStorage.def" return ReferenceOwnership::Strong; } void clearOwnership() { #define REF_STORAGE(Name, name, ...) \ clearAttribute(TAK_sil_##name); #include "swift/AST/ReferenceStorage.def" } bool hasOpenedID() const { return OpenedID.hasValue(); } UUID getOpenedID() const { return *OpenedID; } /// Given a name like "autoclosure", return the type attribute ID that /// corresponds to it. This returns TAK_Count on failure. /// static TypeAttrKind getAttrKindFromString(StringRef Str); /// Return the name (like "autoclosure") for an attribute ID. static const char *getAttrName(TypeAttrKind kind); }; class alignas(1 << AttrAlignInBits) AttributeBase { public: /// The location of the '@'. const SourceLoc AtLoc; /// The source range of the attribute. const SourceRange Range; /// The location of the attribute. SourceLoc getLocation() const { return Range.Start; } /// Return the source range of the attribute. SourceRange getRange() const { return Range; } SourceRange getRangeWithAt() const { if (AtLoc.isValid()) return {AtLoc, Range.End}; return Range; } // Only allow allocation of attributes using the allocator in ASTContext // or by doing a placement new. void *operator new(size_t Bytes, ASTContext &C, unsigned Alignment = alignof(AttributeBase)); void operator delete(void *Data) throw() { } void *operator new(size_t Bytes, void *Mem) throw() { return Mem; } // Make vanilla new/delete illegal for attributes. void *operator new(size_t Bytes) throw() = delete; AttributeBase(const AttributeBase &) = delete; protected: AttributeBase(SourceLoc AtLoc, SourceRange Range) : AtLoc(AtLoc), Range(Range) {} }; class DeclAttributes; enum class DeclKind : uint8_t; /// Represents one declaration attribute. class DeclAttribute : public AttributeBase { friend class DeclAttributes; protected: union { uint64_t OpaqueBits; SWIFT_INLINE_BITFIELD_BASE(DeclAttribute, bitmax(NumDeclAttrKindBits,8)+1+1, Kind : bitmax(NumDeclAttrKindBits,8), // Whether this attribute was implicitly added. Implicit : 1, Invalid : 1 ); SWIFT_INLINE_BITFIELD(ObjCAttr, DeclAttribute, 1+1+1, /// Whether this attribute has location information that trails the main /// record, which contains the locations of the parentheses and any names. HasTrailingLocationInfo : 1, /// Whether the name is implicit, produced as the result of caching. ImplicitName : 1, /// Whether the @objc was inferred using Swift 3's deprecated inference /// rules. Swift3Inferred : 1 ); SWIFT_INLINE_BITFIELD(DynamicReplacementAttr, DeclAttribute, 1, /// Whether this attribute has location information that trails the main /// record, which contains the locations of the parentheses and any names. HasTrailingLocationInfo : 1 ); SWIFT_INLINE_BITFIELD(AbstractAccessControlAttr, DeclAttribute, 3, AccessLevel : 3 ); SWIFT_INLINE_BITFIELD_FULL(AlignmentAttr, DeclAttribute, 32, : NumPadBits, // The alignment value. Value : 32 ); SWIFT_INLINE_BITFIELD(ClangImporterSynthesizedTypeAttr, DeclAttribute, 1, kind : 1 ); SWIFT_INLINE_BITFIELD(EffectsAttr, DeclAttribute, NumEffectsKindBits, kind : NumEffectsKindBits ); SWIFT_INLINE_BITFIELD(InlineAttr, DeclAttribute, NumInlineKindBits, kind : NumInlineKindBits ); SWIFT_INLINE_BITFIELD(OptimizeAttr, DeclAttribute, NumOptimizationModeBits, mode : NumOptimizationModeBits ); SWIFT_INLINE_BITFIELD(ReferenceOwnershipAttr, DeclAttribute, NumReferenceOwnershipBits, ownership : NumReferenceOwnershipBits ); SWIFT_INLINE_BITFIELD(SpecializeAttr, DeclAttribute, 1+1, exported : 1, kind : 1 ); SWIFT_INLINE_BITFIELD(SynthesizedProtocolAttr, DeclAttribute, NumKnownProtocolKindBits, kind : NumKnownProtocolKindBits ); } Bits; DeclAttribute *Next = nullptr; DeclAttribute(DeclAttrKind DK, SourceLoc AtLoc, SourceRange Range, bool Implicit) : AttributeBase(AtLoc, Range) { Bits.OpaqueBits = 0; Bits.DeclAttribute.Kind = static_cast(DK); Bits.DeclAttribute.Implicit = Implicit; Bits.DeclAttribute.Invalid = false; } private: // NOTE: We cannot use DeclKind due to layering. Even if we could, there is no // guarantee that the first DeclKind starts at zero. This is only used to // build "OnXYZ" flags. enum class DeclKindIndex : unsigned { #define DECL(Name, _) Name, #define LAST_DECL(Name) Last_Decl = Name #include "swift/AST/DeclNodes.def" }; public: enum DeclAttrOptions : uint64_t { // There is one entry for each DeclKind, and some higher level buckets // below. These are used in Attr.def to control which kinds of declarations // an attribute can be attached to. #define DECL(Name, _) On##Name = 1ull << unsigned(DeclKindIndex::Name), #include "swift/AST/DeclNodes.def" // Abstract class aggregations for use in Attr.def. OnValue = 0 #define DECL(Name, _) #define VALUE_DECL(Name, _) |On##Name #include "swift/AST/DeclNodes.def" , OnNominalType = 0 #define DECL(Name, _) #define NOMINAL_TYPE_DECL(Name, _) |On##Name #include "swift/AST/DeclNodes.def" , OnConcreteNominalType = OnNominalType & ~OnProtocol, OnGenericType = OnNominalType | OnTypeAlias, OnAbstractFunction = 0 #define DECL(Name, _) #define ABSTRACT_FUNCTION_DECL(Name, _) |On##Name #include "swift/AST/DeclNodes.def" , OnOperator = 0 #define DECL(Name, _) #define OPERATOR_DECL(Name, _) |On##Name #include "swift/AST/DeclNodes.def" , OnAnyDecl = 0 #define DECL(Name, _) |On##Name #include "swift/AST/DeclNodes.def" , /// True if multiple instances of this attribute are allowed on a single /// declaration. AllowMultipleAttributes = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 1), /// True if this is a decl modifier - i.e., that it should not be spelled /// with an @. DeclModifier = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 2), /// True if this is a long attribute that should be printed on its own line. /// /// Currently has no effect on DeclModifier attributes. LongAttribute = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 3), /// True if this shouldn't be serialized. NotSerialized = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 4), /// True if this attribute is only valid when parsing a .sil file. SILOnly = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 5), /// The attribute should be reported by parser as unknown. RejectByParser = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 6), /// Whether client code cannot use the attribute. UserInaccessible = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 7), /// Whether adding this attribute can break API APIBreakingToAdd = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 8), /// Whether removing this attribute can break API APIBreakingToRemove = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 9), /// Whether adding this attribute can break ABI ABIBreakingToAdd = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 10), /// Whether removing this attribute can break ABI ABIBreakingToRemove = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 11), /// The opposite of APIBreakingToAdd APIStableToAdd = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 12), /// The opposite of APIBreakingToRemove APIStableToRemove = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 13), /// The opposite of ABIBreakingToAdd ABIStableToAdd = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 14), /// The opposite of ABIBreakingToRemove ABIStableToRemove = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 15), }; LLVM_READNONE static uint64_t getOptions(DeclAttrKind DK); uint64_t getOptions() const { return getOptions(getKind()); } /// Prints this attribute (if applicable), returning `true` if anything was /// printed. bool printImpl(ASTPrinter &Printer, const PrintOptions &Options, const Decl *D = nullptr) const; public: DeclAttrKind getKind() const { return static_cast(Bits.DeclAttribute.Kind); } /// Whether this attribute was implicitly added. bool isImplicit() const { return Bits.DeclAttribute.Implicit; } /// Set whether this attribute was implicitly added. void setImplicit(bool Implicit = true) { Bits.DeclAttribute.Implicit = Implicit; } /// Returns true if this attribute was find to be invalid in some way by /// semantic analysis. In that case, the attribute should not be considered, /// the attribute node should be only used to retrieve source information. bool isInvalid() const { return Bits.DeclAttribute.Invalid; } void setInvalid() { Bits.DeclAttribute.Invalid = true; } bool isValid() const { return !isInvalid(); } /// Returns the address of the next pointer field. /// Used for object deserialization. DeclAttribute **getMutableNext() { return &Next; } /// Print the attribute to the provided ASTPrinter. void print(ASTPrinter &Printer, const PrintOptions &Options, const Decl *D = nullptr) const; /// Print the attribute to the provided stream. void print(llvm::raw_ostream &OS, const Decl *D = nullptr) const; /// Returns true if this attribute can appear on the specified decl. This is /// controlled by the flags in Attr.def. bool canAppearOnDecl(const Decl *D) const { return canAttributeAppearOnDecl(getKind(), D); } LLVM_READONLY static bool canAttributeAppearOnDecl(DeclAttrKind DK, const Decl *D); /// Returns true if multiple instances of an attribute kind /// can appear on a declaration. static bool allowMultipleAttributes(DeclAttrKind DK) { return getOptions(DK) & AllowMultipleAttributes; } bool isLongAttribute() const { return isLongAttribute(getKind()); } static bool isLongAttribute(DeclAttrKind DK) { return getOptions(DK) & LongAttribute; } static bool shouldBeRejectedByParser(DeclAttrKind DK) { return getOptions(DK) & RejectByParser; } static bool isSilOnly(DeclAttrKind DK) { return getOptions(DK) & SILOnly; } static bool isUserInaccessible(DeclAttrKind DK) { return getOptions(DK) & UserInaccessible; } static bool isAddingBreakingABI(DeclAttrKind DK) { return getOptions(DK) & ABIBreakingToAdd; } #define DECL_ATTR(_, CLASS, OPTIONS, ...) \ static constexpr bool isOptionSetFor##CLASS(DeclAttrOptions Bit) { \ return (OPTIONS) & Bit; \ } #include "swift/AST/Attr.def" static bool isAddingBreakingAPI(DeclAttrKind DK) { return getOptions(DK) & APIBreakingToAdd; } static bool isRemovingBreakingABI(DeclAttrKind DK) { return getOptions(DK) & ABIBreakingToRemove; } static bool isRemovingBreakingAPI(DeclAttrKind DK) { return getOptions(DK) & APIBreakingToRemove; } bool isDeclModifier() const { return isDeclModifier(getKind()); } static bool isDeclModifier(DeclAttrKind DK) { return getOptions(DK) & DeclModifier; } static bool isOnParam(DeclAttrKind DK) { return getOptions(DK) & OnParam; } static bool isOnFunc(DeclAttrKind DK) { return getOptions(DK) & OnFunc; } static bool isOnClass(DeclAttrKind DK) { return getOptions(DK) & OnClass; } static bool isNotSerialized(DeclAttrKind DK) { return getOptions(DK) & NotSerialized; } bool isNotSerialized() const { return isNotSerialized(getKind()); } LLVM_READNONE static bool canAttributeAppearOnDeclKind(DeclAttrKind DAK, DeclKind DK); /// Returns the source name of the attribute, without the @ or any arguments. StringRef getAttrName() const; /// Given a name like "inline", return the decl attribute ID that corresponds /// to it. Note that this is a many-to-one mapping, and that the identifier /// passed in may only be the first portion of the attribute (e.g. in the case /// of the 'unowned(unsafe)' attribute, the string passed in is 'unowned'. /// /// Also note that this recognizes both attributes like '@inline' (with no @) /// and decl modifiers like 'final'. This returns DAK_Count on failure. /// static DeclAttrKind getAttrKindFromString(StringRef Str); }; /// Describes a "simple" declaration attribute that carries no data. template class SimpleDeclAttr : public DeclAttribute { public: SimpleDeclAttr(bool IsImplicit) : DeclAttribute(Kind, SourceLoc(), SourceLoc(), IsImplicit) {} SimpleDeclAttr(SourceLoc AtLoc, SourceLoc NameLoc) : DeclAttribute(Kind, AtLoc, SourceRange(AtLoc.isValid() ? AtLoc : NameLoc, NameLoc), /*Implicit=*/false) { } SimpleDeclAttr(SourceLoc NameLoc) : DeclAttribute(Kind, SourceLoc(), SourceRange(NameLoc, NameLoc), /*Implicit=*/false) { } static bool classof(const DeclAttribute *DA) { return DA->getKind() == Kind; } }; // Declare typedefs for all of the simple declaration attributes. #define SIMPLE_DECL_ATTR(_, CLASS, ...) \ typedef SimpleDeclAttr CLASS##Attr; #include "swift/AST/Attr.def" /// Defines the @_silgen_name attribute. class SILGenNameAttr : public DeclAttribute { public: SILGenNameAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit) : DeclAttribute(DAK_SILGenName, AtLoc, Range, Implicit), Name(Name) {} SILGenNameAttr(StringRef Name, bool Implicit) : SILGenNameAttr(Name, SourceLoc(), SourceRange(), /*Implicit=*/true) {} /// The symbol name. const StringRef Name; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_SILGenName; } }; /// Defines the @_cdecl attribute. class CDeclAttr : public DeclAttribute { public: CDeclAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit) : DeclAttribute(DAK_CDecl, AtLoc, Range, Implicit), Name(Name) {} CDeclAttr(StringRef Name, bool Implicit) : CDeclAttr(Name, SourceLoc(), SourceRange(), /*Implicit=*/true) {} /// The symbol name. const StringRef Name; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_CDecl; } }; /// Defines the @_semantics attribute. class SemanticsAttr : public DeclAttribute { public: SemanticsAttr(StringRef Value, SourceLoc AtLoc, SourceRange Range, bool Implicit) : DeclAttribute(DAK_Semantics, AtLoc, Range, Implicit), Value(Value) {} SemanticsAttr(StringRef Value, bool Implicit) : SemanticsAttr(Value, SourceLoc(), SourceRange(), /*Implicit=*/true) {} /// The semantics tag value. const StringRef Value; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Semantics; } }; /// Defines the @_alignment attribute. class AlignmentAttr : public DeclAttribute { public: AlignmentAttr(unsigned Value, SourceLoc AtLoc, SourceRange Range, bool Implicit) : DeclAttribute(DAK_Alignment, AtLoc, Range, Implicit) { Bits.AlignmentAttr.Value = Value; } unsigned getValue() const { return Bits.AlignmentAttr.Value; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Alignment; } }; /// Defines the @_swift_native_objc_runtime_base attribute. /// /// This attribute indicates a class that should be treated semantically /// as a native Swift root class, but which inherits a specific Objective-C /// class at runtime. For most classes this is the runtime's "SwiftObject" /// root class. The compiler does not need to know about the class; it's the /// build system's responsibility to link against the ObjC code that implements /// the root class, and the ObjC implementation's responsibility to ensure /// instances begin with a Swift-refcounting-compatible object header and /// override all the necessary NSObject refcounting methods. class SwiftNativeObjCRuntimeBaseAttr : public DeclAttribute { public: SwiftNativeObjCRuntimeBaseAttr(Identifier BaseClassName, SourceLoc AtLoc, SourceRange Range, bool Implicit) : DeclAttribute(DAK_SwiftNativeObjCRuntimeBase, AtLoc, Range, Implicit), BaseClassName(BaseClassName) {} // The base class's name. const Identifier BaseClassName; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_SwiftNativeObjCRuntimeBase; } }; /// Determine the result of comparing an availability attribute to a specific /// platform or language version. enum class AvailableVersionComparison { /// The entity is guaranteed to be available. Available, /// The entity is never available. Unavailable, /// The entity might be unavailable at runtime, because it was introduced /// after the requested minimum platform version. PotentiallyUnavailable, /// The entity has been obsoleted. Obsoleted, }; /// Describes the platform-agnostic availability of a declaration. enum class PlatformAgnosticAvailabilityKind { /// The associated availability attribute is not platform-agnostic. None, /// The declaration is deprecated, but can still be used. Deprecated, /// The declaration is unavailable in Swift, specifically UnavailableInSwift, /// The declaration is available in some but not all versions /// of Swift, as specified by the VersionTuple members. SwiftVersionSpecific, /// The declaration is available in some but not all versions /// of SwiftPM's PackageDescription library, as specified by /// the VersionTuple members. PackageDescriptionVersionSpecific, /// The declaration is unavailable for other reasons. Unavailable, }; /// Defines the @available attribute. class AvailableAttr : public DeclAttribute { public: #define INIT_VER_TUPLE(X)\ X(X.empty() ? Optional() : X) AvailableAttr(SourceLoc AtLoc, SourceRange Range, PlatformKind Platform, StringRef Message, StringRef Rename, const llvm::VersionTuple &Introduced, SourceRange IntroducedRange, const llvm::VersionTuple &Deprecated, SourceRange DeprecatedRange, const llvm::VersionTuple &Obsoleted, SourceRange ObsoletedRange, PlatformAgnosticAvailabilityKind PlatformAgnostic, bool Implicit) : DeclAttribute(DAK_Available, AtLoc, Range, Implicit), Message(Message), Rename(Rename), INIT_VER_TUPLE(Introduced), IntroducedRange(IntroducedRange), INIT_VER_TUPLE(Deprecated), DeprecatedRange(DeprecatedRange), INIT_VER_TUPLE(Obsoleted), ObsoletedRange(ObsoletedRange), PlatformAgnostic(PlatformAgnostic), Platform(Platform) {} #undef INIT_VER_TUPLE /// The optional message. const StringRef Message; /// An optional replacement string to emit in a fixit. This allows simple /// declaration renames to be applied by Xcode. /// /// This should take the form of an operator, identifier, or full function /// name, optionally with a prefixed type, similar to the syntax used for /// the `NS_SWIFT_NAME` annotation in Objective-C. const StringRef Rename; /// Indicates when the symbol was introduced. const Optional Introduced; /// Indicates where the Introduced version was specified. const SourceRange IntroducedRange; /// Indicates when the symbol was deprecated. const Optional Deprecated; /// Indicates where the Deprecated version was specified. const SourceRange DeprecatedRange; /// Indicates when the symbol was obsoleted. const Optional Obsoleted; /// Indicates where the Obsoleted version was specified. const SourceRange ObsoletedRange; /// Indicates if the declaration has platform-agnostic availability. const PlatformAgnosticAvailabilityKind PlatformAgnostic; /// The platform of the availability. const PlatformKind Platform; /// Whether this is a language-version-specific entity. bool isLanguageVersionSpecific() const; /// Whether this is a PackageDescription version specific entity. bool isPackageDescriptionVersionSpecific() const; /// Whether this is an unconditionally unavailable entity. bool isUnconditionallyUnavailable() const; /// Whether this is an unconditionally deprecated entity. bool isUnconditionallyDeprecated() const; /// Returns the platform-agnostic availability. PlatformAgnosticAvailabilityKind getPlatformAgnosticAvailability() const { return PlatformAgnostic; } /// Determine if a given declaration should be considered unavailable given /// the current settings. /// /// \returns The attribute responsible for making the declaration unavailable. static const AvailableAttr *isUnavailable(const Decl *D); /// Returns true if the availability applies to a specific /// platform. bool hasPlatform() const { return Platform != PlatformKind::none; } /// Returns the string for the platform of the attribute. StringRef platformString() const { return swift::platformString(Platform); } /// Returns the human-readable string for the platform of the attribute. StringRef prettyPlatformString() const { return swift::prettyPlatformString(Platform); } /// Returns true if this attribute is active given the current platform. bool isActivePlatform(const ASTContext &ctx) const; /// Returns the active version from the AST context corresponding to /// the available kind. For example, this will return the effective language /// version for swift version-specific availability kind, PackageDescription /// version for PackageDescription version-specific availability. llvm::VersionTuple getActiveVersion(const ASTContext &ctx) const; /// Compare this attribute's version information against the platform or /// language version (assuming the this attribute pertains to the active /// platform). AvailableVersionComparison getVersionAvailability(const ASTContext &ctx) const; /// Create an AvailableAttr that indicates specific availability /// for all platforms. static AvailableAttr * createPlatformAgnostic(ASTContext &C, StringRef Message, StringRef Rename = "", PlatformAgnosticAvailabilityKind Reason = PlatformAgnosticAvailabilityKind::Unavailable, llvm::VersionTuple Obsoleted = llvm::VersionTuple()); static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Available; } }; /// Indicates that the given declaration is visible to Objective-C. class ObjCAttr final : public DeclAttribute, private llvm::TrailingObjects { friend TrailingObjects; /// The Objective-C name associated with this entity, stored in its opaque /// representation so that we can use null as an indicator for "no name". void *NameData; /// Create an implicit @objc attribute with the given (optional) name. explicit ObjCAttr(Optional name, bool implicitName) : DeclAttribute(DAK_ObjC, SourceLoc(), SourceRange(), /*Implicit=*/true), NameData(nullptr) { Bits.ObjCAttr.HasTrailingLocationInfo = false; Bits.ObjCAttr.ImplicitName = implicitName; Bits.ObjCAttr.Swift3Inferred = false; if (name) { NameData = name->getOpaqueValue(); } } /// Create an @objc attribute written in the source. ObjCAttr(SourceLoc atLoc, SourceRange baseRange, Optional name, SourceRange parenRange, ArrayRef nameLocs); /// Determine whether this attribute has trailing location information. bool hasTrailingLocationInfo() const { return Bits.ObjCAttr.HasTrailingLocationInfo; } /// Retrieve the trailing location information. MutableArrayRef getTrailingLocations() { assert(hasTrailingLocationInfo() && "No trailing location information"); unsigned length = 2; if (auto name = getName()) length += name->getNumSelectorPieces(); return {getTrailingObjects(), length}; } /// Retrieve the trailing location information. ArrayRef getTrailingLocations() const { assert(hasTrailingLocationInfo() && "No trailing location information"); unsigned length = 2; if (auto name = getName()) length += name->getNumSelectorPieces(); return {getTrailingObjects(), length}; } public: /// Create implicit ObjC attribute with a given (optional) name. static ObjCAttr *create(ASTContext &Ctx, Optional name, bool implicitName); /// Create an unnamed Objective-C attribute, i.e., @objc. static ObjCAttr *createUnnamed(ASTContext &Ctx, SourceLoc AtLoc, SourceLoc ObjCLoc); static ObjCAttr *createUnnamedImplicit(ASTContext &Ctx); /// Create a nullary Objective-C attribute, which has a single name /// with no colon following it. /// /// Note that a nullary Objective-C attribute may represent either a /// selector for a zero-parameter function or some other Objective-C /// entity, such as a class or protocol. static ObjCAttr *createNullary(ASTContext &Ctx, SourceLoc AtLoc, SourceLoc ObjCLoc, SourceLoc LParenLoc, SourceLoc NameLoc, Identifier Name, SourceLoc RParenLoc); /// Create an implicit nullary Objective-C attribute, which has a /// single name with no colon following it. /// /// Note that a nullary Objective-C attribute may represent either a /// selector for a zero-parameter function or some other Objective-C /// entity, such as a class or protocol. static ObjCAttr *createNullary(ASTContext &Ctx, Identifier Name, bool isNameImplicit); /// Create a "selector" Objective-C attribute, which has some number /// of identifiers followed by colons. static ObjCAttr *createSelector(ASTContext &Ctx, SourceLoc AtLoc, SourceLoc ObjCLoc, SourceLoc LParenLoc, ArrayRef NameLocs, ArrayRef Names, SourceLoc RParenLoc); /// Create an implicit "selector" Objective-C attribute, which has /// some number of identifiers followed by colons. static ObjCAttr *createSelector(ASTContext &Ctx, ArrayRef Names, bool isNameImplicit); /// Determine whether this attribute has a name associated with it. bool hasName() const { return NameData != nullptr; } /// Retrieve the name of this entity, if specified. Optional getName() const { if (!hasName()) return None; return ObjCSelector::getFromOpaqueValue(NameData); } /// Determine whether the name associated with this attribute was /// implicit. bool isNameImplicit() const { return Bits.ObjCAttr.ImplicitName; } /// Set the name of this entity. void setName(ObjCSelector name, bool implicit) { // If we already have a name and we have location information, make sure // drop the location information rather than allowing it to corrupt our // state if (hasTrailingLocationInfo() && (!hasName() || getName()->getNumSelectorPieces() < name.getNumSelectorPieces())) { Bits.ObjCAttr.HasTrailingLocationInfo = false; } NameData = name.getOpaqueValue(); Bits.ObjCAttr.ImplicitName = implicit; } /// Determine whether this attribute was inferred based on Swift 3's /// deprecated @objc inference rules. bool isSwift3Inferred() const { return Bits.ObjCAttr.Swift3Inferred; } /// Set whether this attribute was inferred based on Swift 3's deprecated /// @objc inference rules. void setSwift3Inferred(bool inferred = true) { Bits.ObjCAttr.Swift3Inferred = inferred; } /// Clear the name of this entity. void clearName() { NameData = nullptr; } /// Retrieve the source locations for the names in a non-implicit /// nullary or selector attribute. ArrayRef getNameLocs() const; /// Retrieve the location of the opening parentheses, if there is one. SourceLoc getLParenLoc() const; /// Retrieve the location of the closing parentheses, if there is one. SourceLoc getRParenLoc() const; /// Clone the given attribute, producing an implicit copy of the /// original without source location information. ObjCAttr *clone(ASTContext &context) const; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_ObjC; } }; class PrivateImportAttr final : public DeclAttribute { StringRef SourceFile; PrivateImportAttr(SourceLoc atLoc, SourceRange baseRange, StringRef sourceFile, SourceRange parentRange); public: static PrivateImportAttr *create(ASTContext &Ctxt, SourceLoc AtLoc, SourceLoc PrivateLoc, SourceLoc LParenLoc, StringRef sourceFile, SourceLoc RParenLoc); StringRef getSourceFile() const { return SourceFile; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_PrivateImport; } }; /// The @_dynamicReplacement(for:) attribute. class DynamicReplacementAttr final : public DeclAttribute, private llvm::TrailingObjects { friend TrailingObjects; friend class DynamicallyReplacedDeclRequest; DeclNameRef ReplacedFunctionName; LazyMemberLoader *Resolver = nullptr; uint64_t ResolverContextData; /// Create an @_dynamicReplacement(for:) attribute written in the source. DynamicReplacementAttr(SourceLoc atLoc, SourceRange baseRange, DeclNameRef replacedFunctionName, SourceRange parenRange); DynamicReplacementAttr(DeclNameRef name, AbstractFunctionDecl *f) : DeclAttribute(DAK_DynamicReplacement, SourceLoc(), SourceRange(), /*Implicit=*/false), ReplacedFunctionName(name), Resolver(nullptr), ResolverContextData(0) { Bits.DynamicReplacementAttr.HasTrailingLocationInfo = false; } DynamicReplacementAttr(DeclNameRef name, LazyMemberLoader *Resolver = nullptr, uint64_t Data = 0) : DeclAttribute(DAK_DynamicReplacement, SourceLoc(), SourceRange(), /*Implicit=*/false), ReplacedFunctionName(name), Resolver(Resolver), ResolverContextData(Data) { Bits.DynamicReplacementAttr.HasTrailingLocationInfo = false; } /// Retrieve the trailing location information. MutableArrayRef getTrailingLocations() { assert(Bits.DynamicReplacementAttr.HasTrailingLocationInfo); unsigned length = 2; return {getTrailingObjects(), length}; } /// Retrieve the trailing location information. ArrayRef getTrailingLocations() const { assert(Bits.DynamicReplacementAttr.HasTrailingLocationInfo); unsigned length = 2; // lParens, rParens return {getTrailingObjects(), length}; } public: static DynamicReplacementAttr * create(ASTContext &Context, SourceLoc AtLoc, SourceLoc DynReplLoc, SourceLoc LParenLoc, DeclNameRef replacedFunction, SourceLoc RParenLoc); static DynamicReplacementAttr *create(ASTContext &ctx, DeclNameRef replacedFunction, AbstractFunctionDecl *replacedFuncDecl); static DynamicReplacementAttr *create(ASTContext &ctx, DeclNameRef replacedFunction, LazyMemberLoader *Resolver, uint64_t Data); DeclNameRef getReplacedFunctionName() const { return ReplacedFunctionName; } /// Retrieve the location of the opening parentheses, if there is one. SourceLoc getLParenLoc() const; /// Retrieve the location of the closing parentheses, if there is one. SourceLoc getRParenLoc() const; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_DynamicReplacement; } }; /// The \c @_typeEraser(TypeEraserType) attribute. class TypeEraserAttr final : public DeclAttribute { TypeLoc TypeEraserLoc; LazyMemberLoader *Resolver; uint64_t ResolverContextData; friend class ResolveTypeEraserTypeRequest; TypeEraserAttr(SourceLoc atLoc, SourceRange range, TypeLoc typeEraserLoc, LazyMemberLoader *Resolver, uint64_t Data) : DeclAttribute(DAK_TypeEraser, atLoc, range, /*Implicit=*/false), TypeEraserLoc(typeEraserLoc), Resolver(Resolver), ResolverContextData(Data) {} public: static TypeEraserAttr *create(ASTContext &ctx, SourceLoc atLoc, SourceRange range, TypeLoc typeEraserLoc); static TypeEraserAttr *create(ASTContext &ctx, LazyMemberLoader *Resolver, uint64_t Data); /// Retrieve the parsed type repr for this attribute, if it /// was parsed. Else returns \c nullptr. TypeRepr *getParsedTypeEraserTypeRepr() const { return TypeEraserLoc.getTypeRepr(); } /// Retrieve the parsed location for this attribute, if it was parsed. SourceLoc getLoc() const { return TypeEraserLoc.getLoc(); } /// Retrieve the resolved type of this attribute if it has been resolved by a /// successful call to \c getResolvedType(). Otherwise, /// returns \c Type() /// /// This entrypoint is only suitable for syntactic clients like the /// AST printer. Semantic clients should use \c getResolvedType() instead. Type getTypeWithoutResolving() const { return TypeEraserLoc.getType(); } /// Returns \c true if the type eraser type has a valid implementation of the /// erasing initializer for the given protocol. bool hasViableTypeEraserInit(ProtocolDecl *protocol) const; /// Resolves the type of this attribute. /// /// This entrypoint is suitable for semantic clients like the /// expression checker. Syntactic clients should use /// \c getTypeWithoutResolving() instead. Type getResolvedType(const ProtocolDecl *PD) const; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_TypeEraser; } }; /// Represents any sort of access control modifier. class AbstractAccessControlAttr : public DeclAttribute { protected: AbstractAccessControlAttr(DeclAttrKind DK, SourceLoc atLoc, SourceRange range, AccessLevel access, bool implicit) : DeclAttribute(DK, atLoc, range, implicit) { Bits.AbstractAccessControlAttr.AccessLevel = static_cast(access); assert(getAccess() == access && "not enough bits for access control"); } public: AccessLevel getAccess() const { return static_cast(Bits.AbstractAccessControlAttr.AccessLevel); } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_AccessControl || DA->getKind() == DAK_SetterAccess; } }; /// Represents a 'private', 'internal', or 'public' marker on a declaration. class AccessControlAttr : public AbstractAccessControlAttr { public: AccessControlAttr(SourceLoc atLoc, SourceRange range, AccessLevel access, bool implicit = false) : AbstractAccessControlAttr(DAK_AccessControl, atLoc, range, access, implicit) {} static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_AccessControl; } }; /// Represents a 'private', 'internal', or 'public' marker for a setter on a /// declaration. class SetterAccessAttr : public AbstractAccessControlAttr { public: SetterAccessAttr(SourceLoc atLoc, SourceRange range, AccessLevel access, bool implicit = false) : AbstractAccessControlAttr(DAK_SetterAccess, atLoc, range, access, implicit) {} static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_SetterAccess; } }; /// SPI attribute applied to both decls and imports. class SPIAccessControlAttr final : public DeclAttribute, private llvm::TrailingObjects { friend TrailingObjects; SPIAccessControlAttr(SourceLoc atLoc, SourceRange range, ArrayRef spiGroups); // Number of trailing SPI group identifiers. size_t numSPIGroups; public: static SPIAccessControlAttr *create(ASTContext &context, SourceLoc atLoc, SourceRange range, ArrayRef spiGroups); /// 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(), numSPIGroups }; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_SPIAccessControl; } }; /// Represents an inline attribute. class InlineAttr : public DeclAttribute { public: InlineAttr(SourceLoc atLoc, SourceRange range, InlineKind kind) : DeclAttribute(DAK_Inline, atLoc, range, /*Implicit=*/false) { Bits.InlineAttr.kind = unsigned(kind); } InlineAttr(InlineKind kind) : InlineAttr(SourceLoc(), SourceRange(), kind) {} InlineKind getKind() const { return InlineKind(Bits.InlineAttr.kind); } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Inline; } }; /// Represents the optimize attribute. class OptimizeAttr : public DeclAttribute { public: OptimizeAttr(SourceLoc atLoc, SourceRange range, OptimizationMode mode) : DeclAttribute(DAK_Optimize, atLoc, range, /*Implicit=*/false) { Bits.OptimizeAttr.mode = unsigned(mode); } OptimizeAttr(OptimizationMode mode) : OptimizeAttr(SourceLoc(), SourceRange(), mode) {} OptimizationMode getMode() const { return OptimizationMode(Bits.OptimizeAttr.mode); } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Optimize; } }; /// Represents the side effects attribute. class EffectsAttr : public DeclAttribute { public: EffectsAttr(SourceLoc atLoc, SourceRange range, EffectsKind kind) : DeclAttribute(DAK_Effects, atLoc, range, /*Implicit=*/false) { Bits.EffectsAttr.kind = unsigned(kind); } EffectsAttr(EffectsKind kind) : EffectsAttr(SourceLoc(), SourceRange(), kind) {} EffectsKind getKind() const { return EffectsKind(Bits.EffectsAttr.kind); } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Effects; } }; /// Represents weak/unowned/unowned(unsafe) decl modifiers. class ReferenceOwnershipAttr : public DeclAttribute { public: ReferenceOwnershipAttr(SourceRange range, ReferenceOwnership kind) : DeclAttribute(DAK_ReferenceOwnership, range.Start, range, /*Implicit=*/false) { Bits.ReferenceOwnershipAttr.ownership = unsigned(kind); } ReferenceOwnershipAttr(ReferenceOwnership kind) : ReferenceOwnershipAttr(SourceRange(), kind) {} ReferenceOwnership get() const { return ReferenceOwnership(Bits.ReferenceOwnershipAttr.ownership); } /// Returns a copy of this attribute without any source information. ReferenceOwnershipAttr *clone(ASTContext &context) const { return new (context) ReferenceOwnershipAttr(get()); } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_ReferenceOwnership; } }; /// Defines the attribute that we use to model documentation comments. class RawDocCommentAttr : public DeclAttribute { /// Source range of the attached comment. This comment is located before /// the declaration. CharSourceRange CommentRange; public: RawDocCommentAttr(CharSourceRange CommentRange) : DeclAttribute(DAK_RawDocComment, SourceLoc(), SourceRange(), /*Implicit=*/false), CommentRange(CommentRange) {} CharSourceRange getCommentRange() const { return CommentRange; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_RawDocComment; } }; /// An attribute applied to a CoreFoundation class that is toll-free bridged to /// an Objective-C class. /// /// This attribute is introduced by the Clang importer, and is therefore always /// implicit. class ObjCBridgedAttr : public DeclAttribute { ClassDecl *ObjCClass; public: ObjCBridgedAttr(ClassDecl *ObjCClass) : DeclAttribute(DAK_ObjCBridged, SourceLoc(), SourceRange(), /*Implicit=*/true), ObjCClass(ObjCClass) { } /// Retrieve the Objective-C class to which this foreign class is toll-free /// bridged. ClassDecl *getObjCClass() const { return ObjCClass; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_ObjCBridged; } }; /// An attribute that specifies a synthesized conformance of a known /// protocol for the declaration to which it appertains. /// /// There is no spelling for this particular attribute in source code; /// rather, it is introduced by the Clang importer to indicate /// synthesized conformances. class SynthesizedProtocolAttr : public DeclAttribute { LazyConformanceLoader *Loader; public: SynthesizedProtocolAttr(KnownProtocolKind protocolKind, LazyConformanceLoader *Loader) : DeclAttribute(DAK_SynthesizedProtocol, SourceLoc(), SourceRange(), /*Implicit=*/true), Loader(Loader) { Bits.SynthesizedProtocolAttr.kind = unsigned(protocolKind); } /// Retrieve the known protocol kind naming the protocol to be /// synthesized. KnownProtocolKind getProtocolKind() const { return KnownProtocolKind(Bits.SynthesizedProtocolAttr.kind); } /// Retrieve the lazy loader that will be used to populate the /// synthesized conformance. LazyConformanceLoader *getLazyLoader() const { return Loader; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_SynthesizedProtocol; } }; /// The @_specialize attribute, which forces specialization on the specified /// type list. class SpecializeAttr : public DeclAttribute { public: // NOTE: When adding new kinds, you must update the inline bitfield macro. enum class SpecializationKind { Full, Partial }; private: TrailingWhereClause *trailingWhereClause; GenericSignature specializedSignature; SpecializeAttr(SourceLoc atLoc, SourceRange Range, TrailingWhereClause *clause, bool exported, SpecializationKind kind, GenericSignature specializedSignature); public: static SpecializeAttr *create(ASTContext &Ctx, SourceLoc atLoc, SourceRange Range, TrailingWhereClause *clause, bool exported, SpecializationKind kind, GenericSignature specializedSignature = nullptr); TrailingWhereClause *getTrailingWhereClause() const; GenericSignature getSpecializedSgnature() const { return specializedSignature; } void setSpecializedSignature(GenericSignature newSig) { specializedSignature = newSig; } bool isExported() const { return Bits.SpecializeAttr.exported; } SpecializationKind getSpecializationKind() const { return SpecializationKind(Bits.SpecializeAttr.kind); } bool isFullSpecialization() const { return getSpecializationKind() == SpecializationKind::Full; } bool isPartialSpecialization() const { return getSpecializationKind() == SpecializationKind::Partial; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Specialize; } }; /// The @_implements attribute, which treats a decl as the implementation for /// some named protocol requirement (but otherwise not-visible by that name). class ImplementsAttr : public DeclAttribute { TypeLoc ProtocolType; DeclName MemberName; DeclNameLoc MemberNameLoc; public: ImplementsAttr(SourceLoc atLoc, SourceRange Range, TypeLoc ProtocolType, DeclName MemberName, DeclNameLoc MemberNameLoc); static ImplementsAttr *create(ASTContext &Ctx, SourceLoc atLoc, SourceRange Range, TypeLoc ProtocolType, DeclName MemberName, DeclNameLoc MemberNameLoc); TypeLoc getProtocolType() const; TypeLoc &getProtocolType(); DeclName getMemberName() const { return MemberName; } DeclNameLoc getMemberNameLoc() const { return MemberNameLoc; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Implements; } }; /// A limited variant of \c \@objc that's used for classes with generic ancestry. class ObjCRuntimeNameAttr : public DeclAttribute { static StringRef getSimpleName(const ObjCAttr &Original) { assert(Original.hasName()); return Original.getName()->getSimpleName().str(); } public: ObjCRuntimeNameAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit) : DeclAttribute(DAK_ObjCRuntimeName, AtLoc, Range, Implicit), Name(Name) {} explicit ObjCRuntimeNameAttr(const ObjCAttr &Original) : ObjCRuntimeNameAttr(getSimpleName(Original), Original.AtLoc, Original.Range, Original.isImplicit()) {} const StringRef Name; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_ObjCRuntimeName; } }; /// Attribute that specifies a protocol conformance that has been restated /// (i.e., is redundant) but should still be emitted in Objective-C metadata. class RestatedObjCConformanceAttr : public DeclAttribute { public: explicit RestatedObjCConformanceAttr(ProtocolDecl *proto) : DeclAttribute(DAK_RestatedObjCConformance, SourceLoc(), SourceRange(), /*Implicit=*/true), Proto(proto) {} /// The protocol to which this type conforms. ProtocolDecl * const Proto; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_RestatedObjCConformance; } }; /// Attached to type declarations synthesized by the Clang importer. /// /// Used to control manglings. class ClangImporterSynthesizedTypeAttr : public DeclAttribute { public: // NOTE: When adding new kinds, you must update the inline bitfield macro. enum class Kind : char { /// A struct synthesized by the importer to represent an NSError with a /// particular domain, as specified by an enum with the \c ns_error_domain /// Clang attribute. /// /// This one is for enums with names. NSErrorWrapper, /// A struct synthesized by the importer to represent an NSError with a /// particular domain, as specified by an enum with the \c ns_error_domain /// Clang attribute. /// /// This one is for anonymous enums that are immediately typedef'd, giving /// them a unique name for linkage purposes according to the C++ standard. NSErrorWrapperAnon, }; /// The (Clang) name of the declaration that caused this type declaration to /// be synthesized. /// /// Must be a valid Swift identifier as well, for mangling purposes. const StringRef originalTypeName; explicit ClangImporterSynthesizedTypeAttr(StringRef originalTypeName, Kind kind) : DeclAttribute(DAK_ClangImporterSynthesizedType, SourceLoc(), SourceRange(), /*Implicit=*/true), originalTypeName(originalTypeName) { assert(!originalTypeName.empty()); Bits.ClangImporterSynthesizedTypeAttr.kind = unsigned(kind); } Kind getKind() const { return Kind(Bits.ClangImporterSynthesizedTypeAttr.kind); } StringRef getManglingName() const { return manglingNameForKind(getKind()); } static StringRef manglingNameForKind(Kind kind) { switch (kind) { case Kind::NSErrorWrapper: return "e"; case Kind::NSErrorWrapperAnon: return "E"; } llvm_unreachable("unhandled kind"); } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_ClangImporterSynthesizedType; } }; /// Defines a custom attribute. class CustomAttr final : public DeclAttribute, public TrailingCallArguments { TypeLoc type; Expr *arg; PatternBindingInitializer *initContext; Expr *semanticInit = nullptr; unsigned hasArgLabelLocs : 1; unsigned numArgLabels : 16; CustomAttr(SourceLoc atLoc, SourceRange range, TypeLoc type, PatternBindingInitializer *initContext, Expr *arg, ArrayRef argLabels, ArrayRef argLabelLocs, bool implicit); public: static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type, bool implicit = false) { return create(ctx, atLoc, type, false, nullptr, SourceLoc(), { }, { }, { }, SourceLoc(), implicit); } static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type, bool hasInitializer, PatternBindingInitializer *initContext, SourceLoc lParenLoc, ArrayRef args, ArrayRef argLabels, ArrayRef argLabelLocs, SourceLoc rParenLoc, bool implicit = false); unsigned getNumArguments() const { return numArgLabels; } bool hasArgumentLabelLocs() const { return hasArgLabelLocs; } TypeLoc &getTypeLoc() { return type; } const TypeLoc &getTypeLoc() const { return type; } Expr *getArg() const { return arg; } void setArg(Expr *newArg) { arg = newArg; } Expr *getSemanticInit() const { return semanticInit; } void setSemanticInit(Expr *expr) { semanticInit = expr; } PatternBindingInitializer *getInitContext() const { return initContext; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Custom; } }; /// Relates a property to its projection value property, as described by a property wrapper. For /// example, given /// \code /// @A var foo: Int /// \endcode /// /// Where \c A is a property wrapper that has a \c projectedValue property, the compiler /// synthesizes a declaration $foo an attaches the attribute /// \c _projectedValuePropertyAttr($foo) to \c foo to record the link. class ProjectedValuePropertyAttr : public DeclAttribute { public: ProjectedValuePropertyAttr(Identifier PropertyName, SourceLoc AtLoc, SourceRange Range, bool Implicit) : DeclAttribute(DAK_ProjectedValueProperty, AtLoc, Range, Implicit), ProjectionPropertyName(PropertyName) {} // The projection property name. const Identifier ProjectionPropertyName; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_ProjectedValueProperty; } }; /// Describe a symbol was originally defined in another module. For example, given /// \code /// @_originallyDefinedIn(module: "Original", OSX 10.15) var foo: Int /// \endcode /// /// Where variable Foo has originally defined in another module called Original prior to OSX 10.15 class OriginallyDefinedInAttr: public DeclAttribute { public: OriginallyDefinedInAttr(SourceLoc AtLoc, SourceRange Range, StringRef OriginalModuleName, PlatformKind Platform, const llvm::VersionTuple MovedVersion, bool Implicit) : DeclAttribute(DAK_OriginallyDefinedIn, AtLoc, Range, Implicit), OriginalModuleName(OriginalModuleName), Platform(Platform), MovedVersion(MovedVersion) {} // The original module name. const StringRef OriginalModuleName; /// The platform of the symbol. const PlatformKind Platform; /// Indicates when the symbol was moved here. const llvm::VersionTuple MovedVersion; struct ActiveVersion { StringRef ModuleName; PlatformKind Platform; bool IsSimulator; llvm::VersionTuple Version; }; /// Returns non-optional if this attribute is active given the current platform. /// The value provides more details about the active platform. Optional isActivePlatform(const ASTContext &ctx) const; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_OriginallyDefinedIn; } }; /// A declaration name with location. struct DeclNameRefWithLoc { DeclNameRef Name; DeclNameLoc Loc; }; /// Attribute that marks a function as differentiable. /// /// Examples: /// @differentiable(where T : FloatingPoint) /// @differentiable(wrt: (self, x, y)) class DifferentiableAttr final : public DeclAttribute, private llvm::TrailingObjects { friend TrailingObjects; friend class DifferentiableAttributeTypeCheckRequest; /// The declaration on which the `@differentiable` attribute is declared. /// May not be a valid declaration for `@differentiable` attributes. /// Resolved during parsing and deserialization. Decl *OriginalDeclaration = nullptr; /// Whether this function is linear (optional). bool Linear; /// The number of parsed differentiability parameters specified in 'wrt:'. unsigned NumParsedParameters = 0; /// The differentiability parameter indices, resolved by the type checker. /// The bit stores whether the parameter indices have been computed. /// /// Note: it is necessary to use a bit instead of `nullptr` parameter indices /// to represent "parameter indices not yet type-checked" because invalid /// attributes have `nullptr` parameter indices but have been type-checked. llvm::PointerIntPair ParameterIndicesAndBit; /// The trailing where clause (optional). TrailingWhereClause *WhereClause = nullptr; /// The generic signature for autodiff associated functions. Resolved by the /// type checker based on the original function's generic signature and the /// attribute's where clause requirements. This is set only if the attribute /// has a where clause. GenericSignature DerivativeGenericSignature; /// The source location of the implicitly inherited protocol requirement /// `@differentiable` attribute. Used for diagnostics, not serialized. /// /// This is set during conformance type-checking, only for implicit /// `@differentiable` attributes created for non-public protocol witnesses of /// protocol requirements with `@differentiable` attributes. SourceLoc ImplicitlyInheritedDifferentiableAttrLocation; explicit DifferentiableAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, bool linear, ArrayRef parameters, TrailingWhereClause *clause); explicit DifferentiableAttr(Decl *original, bool implicit, SourceLoc atLoc, SourceRange baseRange, bool linear, IndexSubset *parameterIndices, GenericSignature derivativeGenericSignature); public: static DifferentiableAttr *create(ASTContext &context, bool implicit, SourceLoc atLoc, SourceRange baseRange, bool linear, ArrayRef params, TrailingWhereClause *clause); static DifferentiableAttr *create(AbstractFunctionDecl *original, bool implicit, SourceLoc atLoc, SourceRange baseRange, bool linear, IndexSubset *parameterIndices, GenericSignature derivativeGenSig); Decl *getOriginalDeclaration() const { return OriginalDeclaration; } /// Sets the original declaration on which this attribute is declared. /// Should only be used by parsing and deserialization. void setOriginalDeclaration(Decl *originalDeclaration); private: /// Returns true if the given `@differentiable` attribute has been /// type-checked. bool hasBeenTypeChecked() const; public: IndexSubset *getParameterIndices() const; void setParameterIndices(IndexSubset *parameterIndices); /// The parsed differentiability parameters, i.e. the list of parameters /// specified in 'wrt:'. ArrayRef getParsedParameters() const { return {getTrailingObjects(), NumParsedParameters}; } MutableArrayRef getParsedParameters() { return {getTrailingObjects(), NumParsedParameters}; } size_t numTrailingObjects(OverloadToken) const { return NumParsedParameters; } bool isLinear() const { return Linear; } TrailingWhereClause *getWhereClause() const { return WhereClause; } GenericSignature getDerivativeGenericSignature() const { return DerivativeGenericSignature; } void setDerivativeGenericSignature(GenericSignature derivativeGenSig) { DerivativeGenericSignature = derivativeGenSig; } SourceLoc getImplicitlyInheritedDifferentiableAttrLocation() const { return ImplicitlyInheritedDifferentiableAttrLocation; } void getImplicitlyInheritedDifferentiableAttrLocation(SourceLoc loc) { assert(isImplicit()); ImplicitlyInheritedDifferentiableAttrLocation = loc; } /// Get the derivative generic environment for the given `@differentiable` /// attribute and original function. GenericEnvironment * getDerivativeGenericEnvironment(AbstractFunctionDecl *original) const; // Print the attribute to the given stream. // If `omitWrtClause` is true, omit printing the `wrt:` clause. void print(llvm::raw_ostream &OS, const Decl *D, bool omitWrtClause = false) const; static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Differentiable; } }; /// The `@derivative(of:)` attribute registers a function as a derivative of /// another function-like declaration: a 'func', 'init', 'subscript', or 'var' /// computed property declaration. /// /// The `@derivative(of:)` attribute also has an optional `wrt:` clause /// specifying the parameters that are differentiated "with respect to", i.e. /// the differentiability parameters. The differentiability parameters must /// conform to the `Differentiable` protocol. /// /// If the `wrt:` clause is unspecified, the differentiability parameters are /// inferred to be all parameters that conform to `Differentiable`. /// /// `@derivative(of:)` attribute type-checking verifies that the type of the /// derivative function declaration is consistent with the type of the /// referenced original declaration and the differentiability parameters. /// /// Examples: /// @derivative(of: sin(_:)) /// @derivative(of: +, wrt: (lhs, rhs)) class DerivativeAttr final : public DeclAttribute, private llvm::TrailingObjects { friend TrailingObjects; friend class DerivativeAttrOriginalDeclRequest; /// The base type for the referenced original declaration. This field is /// non-null only for parsed attributes that reference a qualified original /// declaration. This field is not serialized; type-checking uses it to /// resolve the original declaration, which is serialized. TypeRepr *BaseTypeRepr; /// The original function name. DeclNameRefWithLoc OriginalFunctionName; /// The original function. /// /// The states are: /// - nullptr: /// The original function is unknown. The typechecker is responsible for /// eventually resolving it. /// - AbstractFunctionDecl: /// The original function is known to be this `AbstractFunctionDecl`. /// - LazyMemberLoader: /// This `LazyMemberLoader` knows how to resolve the original function. /// `ResolverContextData` is an additional piece of data that the /// `LazyMemberLoader` needs. // TODO(TF-1235): Making `DerivativeAttr` immutable will simplify this by // removing the `AbstractFunctionDecl` state. llvm::PointerUnion OriginalFunction; /// Data representing the original function declaration. See doc comment for /// `OriginalFunction`. uint64_t ResolverContextData = 0; /// The number of parsed differentiability parameters specified in 'wrt:'. unsigned NumParsedParameters = 0; /// The differentiability parameter indices, resolved by the type checker. IndexSubset *ParameterIndices = nullptr; /// The derivative function kind (JVP or VJP), resolved by the type checker. Optional Kind = None; explicit DerivativeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, TypeRepr *baseTypeRepr, DeclNameRefWithLoc original, ArrayRef params); explicit DerivativeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, TypeRepr *baseTypeRepr, DeclNameRefWithLoc original, IndexSubset *parameterIndices); public: static DerivativeAttr *create(ASTContext &context, bool implicit, SourceLoc atLoc, SourceRange baseRange, TypeRepr *baseTypeRepr, DeclNameRefWithLoc original, ArrayRef params); static DerivativeAttr *create(ASTContext &context, bool implicit, SourceLoc atLoc, SourceRange baseRange, TypeRepr *baseTypeRepr, DeclNameRefWithLoc original, IndexSubset *parameterIndices); TypeRepr *getBaseTypeRepr() const { return BaseTypeRepr; } DeclNameRefWithLoc getOriginalFunctionName() const { return OriginalFunctionName; } AbstractFunctionDecl *getOriginalFunction(ASTContext &context) const; void setOriginalFunction(AbstractFunctionDecl *decl); void setOriginalFunctionResolver(LazyMemberLoader *resolver, uint64_t resolverContextData); AutoDiffDerivativeFunctionKind getDerivativeKind() const { assert(Kind && "Derivative function kind has not yet been resolved"); return *Kind; } void setDerivativeKind(AutoDiffDerivativeFunctionKind kind) { Kind = kind; } /// The parsed differentiability parameters, i.e. the list of parameters /// specified in 'wrt:'. ArrayRef getParsedParameters() const { return {getTrailingObjects(), NumParsedParameters}; } MutableArrayRef getParsedParameters() { return {getTrailingObjects(), NumParsedParameters}; } size_t numTrailingObjects(OverloadToken) const { return NumParsedParameters; } IndexSubset *getParameterIndices() const { return ParameterIndices; } void setParameterIndices(IndexSubset *parameterIndices) { ParameterIndices = parameterIndices; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Derivative; } }; /// The `@transpose(of:)` attribute registers a function as a transpose of /// another function-like declaration: a 'func', 'init', 'subscript', or 'var' /// computed property declaration. /// /// The `@transpose(of:)` attribute also has a `wrt:` clause specifying the /// parameters that are transposed "with respect to", i.e. the linearity /// parameters. /// /// Examples: /// @transpose(of: foo) /// @transpose(of: +, wrt: (0, 1)) class TransposeAttr final : public DeclAttribute, private llvm::TrailingObjects { friend TrailingObjects; /// The base type for the referenced original declaration. This field is /// non-null only for parsed attributes that reference a qualified original /// declaration. This field is not serialized; type-checking uses it to /// resolve the original declaration, which is serialized. TypeRepr *BaseTypeRepr; /// The original function name. DeclNameRefWithLoc OriginalFunctionName; /// The original function declaration, resolved by the type checker. AbstractFunctionDecl *OriginalFunction = nullptr; /// The number of parsed linearity parameters specified in 'wrt:'. unsigned NumParsedParameters = 0; /// The linearity parameter indices, resolved by the type checker. IndexSubset *ParameterIndices = nullptr; explicit TransposeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, TypeRepr *baseType, DeclNameRefWithLoc original, ArrayRef params); explicit TransposeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, TypeRepr *baseType, DeclNameRefWithLoc original, IndexSubset *parameterIndices); public: static TransposeAttr *create(ASTContext &context, bool implicit, SourceLoc atLoc, SourceRange baseRange, TypeRepr *baseType, DeclNameRefWithLoc original, ArrayRef params); static TransposeAttr *create(ASTContext &context, bool implicit, SourceLoc atLoc, SourceRange baseRange, TypeRepr *baseType, DeclNameRefWithLoc original, IndexSubset *parameterIndices); TypeRepr *getBaseTypeRepr() const { return BaseTypeRepr; } DeclNameRefWithLoc getOriginalFunctionName() const { return OriginalFunctionName; } AbstractFunctionDecl *getOriginalFunction() const { return OriginalFunction; } void setOriginalFunction(AbstractFunctionDecl *decl) { OriginalFunction = decl; } /// The parsed linearity parameters, i.e. the list of parameters specified in /// 'wrt:'. ArrayRef getParsedParameters() const { return {getTrailingObjects(), NumParsedParameters}; } MutableArrayRef getParsedParameters() { return {getTrailingObjects(), NumParsedParameters}; } size_t numTrailingObjects(OverloadToken) const { return NumParsedParameters; } IndexSubset *getParameterIndices() const { return ParameterIndices; } void setParameterIndices(IndexSubset *parameterIndices) { ParameterIndices = parameterIndices; } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DAK_Transpose; } }; /// Attributes that may be applied to declarations. class DeclAttributes { /// Linked list of declaration attributes. DeclAttribute *DeclAttrs; public: DeclAttributes() : DeclAttrs(nullptr) {} bool isEmpty() const { return DeclAttrs == nullptr; } void getAttrRanges(SmallVectorImpl &Ranges) const { for (auto Attr : *this) { auto R = Attr->getRangeWithAt(); if (R.isValid()) Ranges.push_back(R); } } /// If this attribute set has a prefix/postfix attribute on it, return this. UnaryOperatorKind getUnaryOperatorKind() const { if (hasAttribute()) return UnaryOperatorKind::Prefix; if (hasAttribute()) return UnaryOperatorKind::Postfix; return UnaryOperatorKind::None; } bool isUnavailable(const ASTContext &ctx) const { return getUnavailable(ctx) != nullptr; } /// Determine whether there is a swiftVersionSpecific attribute that's /// unavailable relative to the provided language version. bool isUnavailableInSwiftVersion(const version::Version &effectiveVersion) const; /// Finds the most-specific platform-specific attribute that is /// active for the current platform. const AvailableAttr * findMostSpecificActivePlatform(const ASTContext &ctx) const; /// Returns the first @available attribute that indicates /// a declaration is unavailable, or the first one that indicates it's /// potentially unavailable, or null otherwise. const AvailableAttr *getPotentiallyUnavailable(const ASTContext &ctx) const; /// Returns the first @available attribute that indicates /// a declaration is unavailable, or null otherwise. const AvailableAttr *getUnavailable(const ASTContext &ctx) const; /// Returns the first @available attribute that indicates /// a declaration is deprecated on all deployment targets, or null otherwise. const AvailableAttr *getDeprecated(const ASTContext &ctx) const; SWIFT_DEBUG_DUMPER(dump(const Decl *D = nullptr)); void print(ASTPrinter &Printer, const PrintOptions &Options, const Decl *D = nullptr) const; static void print(ASTPrinter &Printer, const PrintOptions &Options, ArrayRef FlattenedAttrs, const Decl *D = nullptr); template class iterator_base : public std::iterator { T *Impl; public: explicit iterator_base(T *Impl) : Impl(Impl) {} DERIVED &operator++() { Impl = Impl->Next; return (DERIVED&)*this; } bool operator==(const iterator_base &X) const { return X.Impl == Impl; } bool operator!=(const iterator_base &X) const { return X.Impl != Impl; } T *operator*() const { return Impl; } T &operator->() const { return *Impl; } }; /// Add a constructed DeclAttribute to this list. void add(DeclAttribute *Attr) { Attr->Next = DeclAttrs; DeclAttrs = Attr; } // Iterator interface over DeclAttribute objects. class iterator : public iterator_base { public: explicit iterator(DeclAttribute *Impl) : iterator_base(Impl) {} }; class const_iterator : public iterator_base { public: explicit const_iterator(const DeclAttribute *Impl) : iterator_base(Impl) {} }; iterator begin() { return iterator(DeclAttrs); } iterator end() { return iterator(nullptr); } const_iterator begin() const { return const_iterator(DeclAttrs); } const_iterator end() const { return const_iterator(nullptr); } /// Retrieve the first attribute of the given attribute class. template const ATTR *getAttribute(bool AllowInvalid = false) const { return const_cast(this)->getAttribute(AllowInvalid); } template ATTR *getAttribute(bool AllowInvalid = false) { for (auto Attr : *this) if (auto *SpecificAttr = dyn_cast(Attr)) if (SpecificAttr->isValid() || AllowInvalid) return SpecificAttr; return nullptr; } /// Determine whether there is an attribute with the given attribute class. template bool hasAttribute(bool AllowInvalid = false) const { return getAttribute(AllowInvalid) != nullptr; } /// Retrieve the first attribute with the given kind. const DeclAttribute *getAttribute(DeclAttrKind DK, bool AllowInvalid = false) const { for (auto Attr : *this) if (Attr->getKind() == DK && (Attr->isValid() || AllowInvalid)) return Attr; return nullptr; } /// Retrieve the first attribute with the given kind. DeclAttribute *getAttribute(DeclAttrKind DK, bool AllowInvalid = false) { for (auto Attr : *this) if (Attr->getKind() == DK && (Attr->isValid() || AllowInvalid)) return Attr; return nullptr; } private: /// Predicate used to filter MatchingAttributeRange. template struct ToAttributeKind { ToAttributeKind() {} Optional operator()(const DeclAttribute *Attr) const { if (isa(Attr) && (Attr->isValid() || AllowInvalid)) return cast(Attr); return None; } }; public: template using AttributeKindRange = OptionalTransformRange, ToAttributeKind, const_iterator>; /// Return a range with all attributes in DeclAttributes with AttrKind /// ATTR. template AttributeKindRange getAttributes() const { return AttributeKindRange( make_range(begin(), end()), ToAttributeKind()); } // Remove the given attribute from the list of attributes. Used when // the attribute was semantically invalid. void removeAttribute(const DeclAttribute *attr) { // If it's the first attribute, remove it. if (DeclAttrs == attr) { DeclAttrs = attr->Next; return; } // Otherwise, find it in the list. This is inefficient, but rare. for (auto **prev = &DeclAttrs; *prev; prev = &(*prev)->Next) { if ((*prev)->Next == attr) { (*prev)->Next = attr->Next; return; } } llvm_unreachable("Attribute not found for removal"); } /// Set the raw chain of attributes. Used for deserialization. void setRawAttributeChain(DeclAttribute *Chain) { DeclAttrs = Chain; } SourceLoc getStartLoc(bool forModifiers = false) const; }; void simple_display(llvm::raw_ostream &out, const DeclAttribute *attr); inline SourceLoc extractNearestSourceLoc(const DeclAttribute *attr) { return attr->getLocation(); } } // end namespace swift #endif