diff --git a/CMakeLists.txt b/CMakeLists.txt index baeb525d1f737..d699d69d04a50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,24 +147,20 @@ set(SWIFT_COMPILER_VERSION "" CACHE STRING set(CLANG_COMPILER_VERSION "" CACHE STRING "The internal version of the Clang compiler") -# Indicate whether Swift should attempt to use the lld linker. -if(CMAKE_SYSTEM_NAME STREQUAL Windows AND NOT CMAKE_HOST_SYSTEM_NAME STREQUAL Windows) - set(SWIFT_ENABLE_LLD_LINKER_default TRUE) +# Which default linker to use. Prefer LLVM_USE_LINKER if it set, otherwise use +# our own defaults. This should only be possible in a unified (not stand alone) +# build environment. +if(LLVM_USE_LINKER) + set(SWIFT_USE_LINKER_default "${LLVM_USE_LINKER}") +elseif(CMAKE_SYSTEM_NAME STREQUAL Windows AND NOT CMAKE_HOST_SYSTEM_NAME STREQUAL Windows) + set(SWIFT_USE_LINKER_default "lld") +elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set(SWIFT_USE_LINKER_default "") else() - set(SWIFT_ENABLE_LLD_LINKER_default FALSE) + set(SWIFT_USE_LINKER_default "gold") endif() -set(SWIFT_ENABLE_LLD_LINKER ${SWIFT_ENABLE_LLD_LINKER_default} CACHE BOOL - "Enable using the lld linker when available") - -# Indicate whether Swift should attempt to use the gold linker. -# This is not used on Darwin. -if(CMAKE_SYSTEM_NAME STREQUAL Darwin OR CMAKE_SYSTEM_NAME STREQUAL Windows) - set(SWIFT_ENABLE_GOLD_LINKER_default FALSE) -else() - set(SWIFT_ENABLE_GOLD_LINKER_default TRUE) -endif() -set(SWIFT_ENABLE_GOLD_LINKER ${SWIFT_ENABLE_GOLD_LINKER_default} CACHE BOOL - "Enable using the gold linker when available") +set(SWIFT_USE_LINKER ${SWIFT_USE_LINKER_default} CACHE STRING + "Build Swift with a non-default linker") set(SWIFT_TOOLS_ENABLE_LTO OFF CACHE STRING "Build Swift tools with LTO. One must specify the form of LTO by setting this to one of: 'full', 'thin'. This diff --git a/README.md b/README.md index cf2df214ddb99..033d95fac68e2 100644 --- a/README.md +++ b/README.md @@ -154,8 +154,6 @@ with version 2 shipped with Ubuntu. **Note:** For Ubuntu 20.04, use `libpython2-dev` in place of the libpython-dev package above. -Build instructions for Ubuntu 14.04 LTS can be found [here](docs/Ubuntu14.md). - ### Getting Sources for Swift and Related Projects First create a directory for all of the Swift sources: diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index ae109498abce4..ff24b14198b4a 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -116,7 +116,7 @@ function(_add_host_variant_c_compile_link_flags name) if(SWIFT_HOST_VARIANT_SDK STREQUAL ANDROID) # lld can handle targeting the android build. However, if lld is not # enabled, then fallback to the linker included in the android NDK. - if(NOT SWIFT_ENABLE_LLD_LINKER) + if(NOT SWIFT_USE_LINKER STREQUAL "lld") swift_android_tools_path(${SWIFT_HOST_VARIANT_ARCH} tools_path) target_compile_options(${name} PRIVATE -B${tools_path}) endif() @@ -368,12 +368,9 @@ function(_add_host_variant_link_flags target) endif() if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - if(SWIFT_ENABLE_LLD_LINKER) + if(SWIFT_USE_LINKER) target_link_options(${target} PRIVATE - -fuse-ld=lld$<$:.exe>) - elseif(SWIFT_ENABLE_GOLD_LINKER) - target_link_options(${target} PRIVATE - -fuse-ld=gold$<$:.exe>) + -fuse-ld=${SWIFT_USE_LINKER}$<$:.exe>) endif() endif() diff --git a/cmake/modules/AddSwiftUnittests.cmake b/cmake/modules/AddSwiftUnittests.cmake index e088997741eb1..811b455bd3ed2 100644 --- a/cmake/modules/AddSwiftUnittests.cmake +++ b/cmake/modules/AddSwiftUnittests.cmake @@ -57,15 +57,9 @@ function(add_swift_unittest test_dirname) _ENABLE_EXTENDED_ALIGNED_STORAGE) endif() - find_program(LDLLD_PATH "ld.lld") - # Strangely, macOS finds lld and then can't find it when using -fuse-ld= - if(SWIFT_ENABLE_LLD_LINKER AND LDLLD_PATH AND NOT APPLE) + if(SWIFT_USE_LINKER) set_property(TARGET "${test_dirname}" APPEND_STRING PROPERTY - LINK_FLAGS " -fuse-ld=lld") - elseif(SWIFT_ENABLE_GOLD_LINKER AND - "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_OBJECT_FORMAT}" STREQUAL "ELF") - set_property(TARGET "${test_dirname}" APPEND_STRING PROPERTY - LINK_FLAGS " -fuse-ld=gold") + LINK_FLAGS " -fuse-ld=${SWIFT_USE_LINKER}") endif() if(SWIFT_ANALYZE_CODE_COVERAGE) diff --git a/docs/DifferentiableProgramming.md b/docs/DifferentiableProgramming.md index c40dd3da310ff..0cec90aa47712 100644 --- a/docs/DifferentiableProgramming.md +++ b/docs/DifferentiableProgramming.md @@ -1079,11 +1079,6 @@ public extension Differentiable where Self == TangentVector { mutating func move(along direction: TangentVector) { self += direction } - - @noDerivative - var zeroTangentVectorInitializer: () -> TangentVector { - { .zero } - } } ``` @@ -1144,8 +1139,8 @@ extension Array: Differentiable where Element: Differentiable { @noDerivative public var zeroTangentVectorInitializer: () -> TangentVector { - { [count = self.count] in - TangentVector(Array(repeating: .zero, count: count)) + { [zeroInits = map(\.zeroTangentVectorInitializer)] in + TangentVector(zeroInits.map { $0() }) } } } @@ -1238,8 +1233,15 @@ the same effective access level as their corresponding original properties. A `move(along:)` method is synthesized with a body that calls `move(along:)` for each pair of the original property and its corresponding property in -`TangentVector`. Similarly, `zeroTangentVector` is synthesized to return a -tangent vector that consists of each stored property's `zeroTangentVector`. +`TangentVector`. + +Similarly, when memberwise derivation is possible, +`zeroTangentVectorInitializer` is synthesized to return a closure that captures +and calls each stored property's `zeroTangentVectorInitializer` closure. +When memberwise derivation is not possible (e.g. for custom user-defined +`TangentVector` types), `zeroTangentVectorInitializer` is synthesized as a +`{ TangentVector.zero }` closure. + Here's an example: ```swift @@ -1251,14 +1253,17 @@ struct Foo: @memberwise Differentiable { @noDerivative let helperVariable: T // The compiler synthesizes: + // // struct TangentVector: Differentiable, AdditiveArithmetic { // var x: T.TangentVector // var y: U.TangentVector // } + // // mutating func move(along direction: TangentVector) { // x.move(along: direction.x) // y.move(along: direction.y) // } + // // @noDerivative // var zeroTangentVectorInitializer: () -> TangentVector { // { [xTanInit = x.zeroTangentVectorInitializer, @@ -1278,8 +1283,8 @@ properties are declared to conform to `AdditiveArithmetic`. There are no `@noDerivative` stored properties. In these cases, the compiler will make `TangentVector` be a type alias for Self. -Method `move(along:)` and property `zeroTangentVector` will not be synthesized -because a default implementation already exists. +Method `move(along:)` will not be synthesized because a default implementation +already exists. ```swift struct Point: @memberwise Differentiable, @memberwise AdditiveArithmetic { @@ -1287,7 +1292,16 @@ struct Point: @memberwise Differentiable, @memberwise AdditiveArithmeti var x, y: T // The compiler synthesizes: + // // typealias TangentVector = Self + // + // @noDerivative + // var zeroTangentVectorInitializer: () -> TangentVector { + // { [xTanInit = x.zeroTangentVectorInitializer, + // yTanInit = y.zeroTangentVectorInitializer] in + // TangentVector(x: xTanInit(), y: yTanInit()) + // } + // } } ``` diff --git a/docs/Ubuntu14.md b/docs/Ubuntu14.md deleted file mode 100644 index 78e2982e4ef53..0000000000000 --- a/docs/Ubuntu14.md +++ /dev/null @@ -1,24 +0,0 @@ -# Getting Started with Swift on Ubuntu 14.04 - -## Upgrade Clang -You'll need to upgrade your clang compiler for C++14 support and create a symlink. The minimum required version of clang may change, and may not be available on Ubuntu 14.04 in the future. -```bash -sudo apt-get install clang-3.9 -sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.9 100 -sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.9 100 -sudo update-alternatives --set clang /usr/bin/clang-3.9 -sudo update-alternatives --set clang++ /usr/bin/clang++-3.9 -``` - -## Upgrade CMake -You'll need to upgrade your CMake toolchain to a supported version by building a local copy. The minimum required version of CMake may change, and may not be available on Ubuntu 14.04 in the future. -```bash -wget https://cmake.org/files/v3.5/cmake-3.5.2.tar.gz -tar xf cmake-3.5.2.tar.gz -cd cmake-3.5.2 -./configure -make -sudo make install -sudo update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 1 --force -cmake --version # This should print 3.5.2 -``` diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md index 367f965600401..28c4e28040420 100644 --- a/docs/WindowsBuild.md +++ b/docs/WindowsBuild.md @@ -1,6 +1,6 @@ # Building Swift on Windows -Visual Studio 2017 or newer is needed to build Swift on Windows. +Visual Studio 2017 or newer is needed to build Swift on Windows. The free Community edition is sufficient to build Swift. The commands below (with the exception of installing Visual Studio) must be entered in the "**x64 Native** Tools Command Prompt for VS2017" (or VS2019, VS2019 Preview depending on the Visual Studio that you are using) in the Start Menu. This sets environment variables to select the correct target platform. @@ -32,7 +32,7 @@ The command above already installs Python 2 and 3. Alternatively, in the Visual 1. Install *Python 2*, either the 32-bit version (C:\Python27\\) or the 64-bit version (C:\Python27amd64\\) -> If you install the 64-bit version only, you will need to adjust `PYTHON_EXECUTABLE` below to `C:\Python27amd64\python.exe` + **Note:** If you install the 64-bit version only, you will need to adjust `PYTHON_EXECUTABLE` below to `C:\Python27amd64\python.exe` 2. Install *Python 3 64 bits (3.7.x)* @@ -150,6 +150,9 @@ cmake -B "S:\b\toolchain" ^ ninja -C S:\b\toolchain ``` +**Note:** If you installed only the 64-bit version of Python, you will need to adjust `PYTHON_EXECUTABLE` argument to `C:\Python27amd64\python.exe` + + ## Running Swift tests on Windows ```cmd diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 8409c8dcd724e..8049387c4e191 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -1025,7 +1025,7 @@ struct TargetAnyClassMetadata : public TargetHeapMetadata { using TargetMetadata::setClassISA; #endif - // Note that ObjC classes does not have a metadata header. + // Note that ObjC classes do not have a metadata header. /// The metadata for the superclass. This is null for the root class. ConstTargetMetadataPointer Superclass; diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 8054500c3b772..95504c3477426 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -126,7 +126,7 @@ DECL_ATTR(available, Available, CONTEXTUAL_SIMPLE_DECL_ATTR(final, Final, OnClass | OnFunc | OnAccessor | OnVar | OnSubscript | DeclModifier | - ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIStableToRemove, + ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove, 2) DECL_ATTR(objc, ObjC, OnAbstractFunction | OnClass | OnProtocol | OnExtension | OnVar | diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 7dd491d870d22..24c9f9c3d979c 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -223,6 +223,7 @@ IDENTIFIER(move) IDENTIFIER(pullback) IDENTIFIER(TangentVector) IDENTIFIER(zero) +IDENTIFIER(zeroTangentVectorInitializer) #undef IDENTIFIER #undef IDENTIFIER_ diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 0bf41995878ab..6e8c2cd1b0330 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -852,7 +852,17 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// \returns The superclass of this type, or a null type if it has no /// superclass. Type getSuperclass(bool useArchetypes = true); - + + /// Retrieve the root class of this type by repeatedly retrieving the + /// superclass. + /// + /// \param useArchetypes Whether to use context archetypes for outer generic + /// parameters if the class is nested inside a generic function. + /// + /// \returns The base class of this type, or this type itself if it has no + /// superclasses. + Type getRootClass(bool useArchetypes = true); + /// True if this type is the exact superclass of another type. /// /// \param ty The potential subclass. diff --git a/include/swift/Basic/LLVM.h b/include/swift/Basic/LLVM.h index c88b322b0ecd7..df5db366409dd 100644 --- a/include/swift/Basic/LLVM.h +++ b/include/swift/Basic/LLVM.h @@ -36,8 +36,8 @@ namespace llvm { template class SmallPtrSet; #if !defined(swiftCore_EXPORTS) template class SmallVectorImpl; -#endif template class SmallVector; +#endif template class SmallString; template class SmallSetVector; #if !defined(swiftCore_EXPORTS) @@ -86,8 +86,8 @@ namespace swift { using llvm::SmallPtrSetImpl; using llvm::SmallSetVector; using llvm::SmallString; - using llvm::SmallVector; #if !defined(swiftCore_EXPORTS) + using llvm::SmallVector; using llvm::SmallVectorImpl; #endif using llvm::StringLiteral; diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 8321255140d40..5e534c3e901fe 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -287,5 +287,9 @@ NODE(OpaqueTypeDescriptorAccessorVar) NODE(OpaqueReturnType) CONTEXT_NODE(OpaqueReturnTypeOf) +// Added in Swift 5.3 +NODE(CanonicalSpecializedGenericMetaclass) +NODE(CanonicalSpecializedGenericTypeMetadataAccessFunction) + #undef CONTEXT_NODE #undef NODE diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index 8bfc73f4e932d..017fd096e0f74 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -361,7 +361,7 @@ class TypeDecoder { if (Node->getNumChildren() < 2) return BuiltType(); - SmallVector args; + llvm::SmallVector args; const auto &genericArgs = Node->getChild(1); if (genericArgs->getKind() != NodeKind::TypeList) @@ -474,7 +474,7 @@ class TypeDecoder { return BuiltType(); // Find the protocol list. - SmallVector Protocols; + llvm::SmallVector Protocols; auto TypeList = Node->getChild(0); if (TypeList->getKind() == NodeKind::ProtocolList && TypeList->getNumChildren() >= 1) { @@ -576,7 +576,7 @@ class TypeDecoder { return BuiltType(); bool hasParamFlags = false; - SmallVector, 8> parameters; + llvm::SmallVector, 8> parameters; if (!decodeMangledFunctionInputType(Node->getChild(isThrow ? 1 : 0), parameters, hasParamFlags)) return BuiltType(); @@ -598,9 +598,9 @@ class TypeDecoder { } case NodeKind::ImplFunctionType: { auto calleeConvention = ImplParameterConvention::Direct_Unowned; - SmallVector, 8> parameters; - SmallVector, 8> results; - SmallVector, 8> errorResults; + llvm::SmallVector, 8> parameters; + llvm::SmallVector, 8> results; + llvm::SmallVector, 8> errorResults; ImplFunctionTypeFlags flags; for (unsigned i = 0; i < Node->getNumChildren(); i++) { @@ -684,7 +684,7 @@ class TypeDecoder { return decodeMangledType(Node->getChild(0)); case NodeKind::Tuple: { - SmallVector elements; + llvm::SmallVector elements; std::string labels; bool variadic = false; for (auto &element : *Node) { diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index acfa09b4b9cf7..fac7f4510c30a 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -193,7 +193,7 @@ class LinkEntity { /// The nominal type descriptor for a nominal type. /// The pointer is a NominalTypeDecl*. NominalTypeDescriptor, - + /// The descriptor for an opaque type. /// The pointer is an OpaqueTypeDecl*. OpaqueTypeDescriptor, @@ -295,12 +295,12 @@ class LinkEntity { /// The descriptor for an extension. /// The pointer is an ExtensionDecl*. ExtensionDescriptor, - + /// The descriptor for a runtime-anonymous context. /// The pointer is the DeclContext* of a child of the context that should /// be considered private. AnonymousDescriptor, - + /// A SIL global variable. The pointer is a SILGlobalVariable*. SILGlobalVariable, @@ -384,6 +384,15 @@ class LinkEntity { /// A global function pointer for dynamically replaceable functions. DynamicallyReplaceableFunctionVariable, + + /// A reference to a metaclass-stub for a statically specialized generic + /// class. + /// The pointer is a canonical TypeBase*. + CanonicalSpecializedGenericSwiftMetaclassStub, + + /// An access function for prespecialized type metadata. + /// The pointer is a canonical TypeBase*. + CanonicalSpecializedGenericTypeMetadataAccessFunction, }; friend struct llvm::DenseMapInfo; @@ -1020,6 +1029,22 @@ class LinkEntity { return entity; } + static LinkEntity + forSpecializedGenericSwiftMetaclassStub(CanType concreteType) { + LinkEntity entity; + entity.setForType(Kind::CanonicalSpecializedGenericSwiftMetaclassStub, + concreteType); + return entity; + } + + static LinkEntity + forPrespecializedTypeMetadataAccessFunction(CanType theType) { + LinkEntity entity; + entity.setForType( + Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction, theType); + return entity; + } + void mangle(llvm::raw_ostream &out) const; void mangle(SmallVectorImpl &buffer) const; std::string mangleAsString() const; diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 474961ebaf76d..010aefc58805f 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -802,9 +802,9 @@ SILCloner::visitAllocStackInst(AllocStackInst *Inst) { Loc = MandatoryInlinedLocation::getAutoGeneratedLocation(); VarInfo = None; } - recordClonedInstruction(Inst, - getBuilder().createAllocStack( - Loc, getOpType(Inst->getElementType()), VarInfo)); + recordClonedInstruction(Inst, getBuilder().createAllocStack( + Loc, getOpType(Inst->getElementType()), + VarInfo, Inst->hasDynamicLifetime())); } template diff --git a/include/swift/SILOptimizer/Differentiation/VJPEmitter.h b/include/swift/SILOptimizer/Differentiation/VJPEmitter.h index d2f8f7fabb996..db196e7374b89 100644 --- a/include/swift/SILOptimizer/Differentiation/VJPEmitter.h +++ b/include/swift/SILOptimizer/Differentiation/VJPEmitter.h @@ -117,8 +117,21 @@ class VJPEmitter final /// Get the lowered SIL type of the given nominal type declaration. SILType getNominalDeclLoweredType(NominalTypeDecl *nominal); - /// Build a pullback struct value for the original block corresponding to the - /// given terminator. + // Creates a trampoline block for given original terminator instruction, the + // pullback struct value for its parent block, and a successor basic block. + // + // The trampoline block has the same arguments as and branches to the remapped + // successor block, but drops the last predecessor enum argument. + // + // Used for cloning branching terminator instructions with specific + // requirements on successor block arguments, where an additional predecessor + // enum argument is not acceptable. + SILBasicBlock *createTrampolineBasicBlock(TermInst *termInst, + StructInst *pbStructVal, + SILBasicBlock *succBB); + + /// Build a pullback struct value for the given original terminator + /// instruction. StructInst *buildPullbackValueStructValue(TermInst *termInst); /// Build a predecessor enum instance using the given builder for the given @@ -141,6 +154,12 @@ class VJPEmitter final void visitSwitchEnumAddrInst(SwitchEnumAddrInst *seai); + void visitCheckedCastBranchInst(CheckedCastBranchInst *ccbi); + + void visitCheckedCastValueBranchInst(CheckedCastValueBranchInst *ccvbi); + + void visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *ccabi); + // If an `apply` has active results or active inout arguments, replace it // with an `apply` of its VJP. void visitApplyInst(ApplyInst *ai); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 108bceaf6656e..4ad4df3636fc2 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2810,7 +2810,7 @@ CanType ValueDecl::getOverloadSignatureType() const { // implementation of the swift::conflicting overload that deals with // overload types, in order to account for cases where the overload types // don't match, but the decls differ and therefore always conflict. - + assert(isa(this)); return CanType(); } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 5afc70b7d9bce..c6f36c1522a67 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -244,12 +244,13 @@ static ConstructorComparison compareConstructors(ConstructorDecl *ctor1, return ConstructorComparison::Same; } -/// Given a set of declarations whose names and signatures have matched, +/// Given a set of declarations whose names and interface types have matched, /// figure out which of these declarations have been shadowed by others. template -static void -recordShadowedDeclsAfterSignatureMatch(ArrayRef decls, const DeclContext *dc, - llvm::SmallPtrSetImpl &shadowed) { +static void recordShadowedDeclsAfterTypeMatch( + ArrayRef decls, + const DeclContext *dc, + llvm::SmallPtrSetImpl &shadowed) { assert(decls.size() > 1 && "Nothing collided"); // Compare each declaration to every other declaration. This is @@ -491,6 +492,48 @@ recordShadowedDeclsAfterSignatureMatch(ArrayRef decls, const DeclContext *dc, } } +/// Given a set of declarations whose names and generic signatures have matched, +/// figure out which of these declarations have been shadowed by others. +static void recordShadowedDeclsAfterSignatureMatch( + ArrayRef decls, + const DeclContext *dc, + llvm::SmallPtrSetImpl &shadowed) { + assert(decls.size() > 1 && "Nothing collided"); + + // Categorize all of the declarations based on their overload types. + llvm::SmallDenseMap> collisions; + llvm::SmallVector collisionTypes; + + for (auto decl : decls) { + assert(!isa(decl)); + + CanType type; + + // FIXME: The type of a variable or subscript doesn't include + // enough context to distinguish entities from different + // constrained extensions, so use the overload signature's + // type. This is layering a partial fix upon a total hack. + if (auto asd = dyn_cast(decl)) + type = asd->getOverloadSignatureType(); + else + type = decl->getInterfaceType()->getCanonicalType(); + + // Record this declaration based on its signature. + auto &known = collisions[type]; + if (known.size() == 1) { + collisionTypes.push_back(type); + } + known.push_back(decl); + } + + // Check whether we have shadowing for signature collisions. + for (auto type : collisionTypes) { + ArrayRef collidingDecls = collisions[type]; + recordShadowedDeclsAfterTypeMatch(collidingDecls, dc, + shadowed); + } +} + /// Look through the given set of declarations (that all have the same name), /// recording those that are shadowed by another declaration in the /// \c shadowed set. @@ -526,14 +569,23 @@ static void recordShadowedDecls(ArrayRef decls, if (decls.size() < 2) return; + llvm::TinyPtrVector typeDecls; + // Categorize all of the declarations based on their overload signatures. - llvm::SmallDenseMap> collisions; - llvm::SmallVector collisionTypes; - llvm::SmallDenseMap> + llvm::SmallDenseMap> collisions; + llvm::SmallVector collisionSignatures; + llvm::SmallDenseMap> importedInitializerCollisions; - llvm::TinyPtrVector importedInitializerCollectionTypes; + llvm::TinyPtrVector importedInitializerCollisionTypes; for (auto decl : decls) { + if (auto *typeDecl = dyn_cast(decl)) { + typeDecls.push_back(typeDecl); + continue; + } + // Specifically keep track of imported initializers, which can come from // Objective-C init methods, Objective-C factory methods, renamed C // functions, or be synthesized by the importer. @@ -544,50 +596,47 @@ static void recordShadowedDecls(ArrayRef decls, auto nominal = ctor->getDeclContext()->getSelfNominalTypeDecl(); auto &knownInits = importedInitializerCollisions[nominal]; if (knownInits.size() == 1) { - importedInitializerCollectionTypes.push_back(nominal); + importedInitializerCollisionTypes.push_back(nominal); } knownInits.push_back(ctor); } } - CanType signature; + // If the decl is currently being validated, this is likely a recursive + // reference and we'll want to skip ahead so as to avoid having its type + // attempt to desugar itself. + if (decl->isRecursiveValidation()) + continue; - if (!isa(decl)) { - // If the decl is currently being validated, this is likely a recursive - // reference and we'll want to skip ahead so as to avoid having its type - // attempt to desugar itself. - if (decl->isRecursiveValidation()) - continue; - auto ifaceType = decl->getInterfaceType(); - - // FIXME: the canonical type makes a poor signature, because we don't - // canonicalize away default arguments. - signature = ifaceType->getCanonicalType(); - - // FIXME: The type of a variable or subscript doesn't include - // enough context to distinguish entities from different - // constrained extensions, so use the overload signature's - // type. This is layering a partial fix upon a total hack. - if (auto asd = dyn_cast(decl)) - signature = asd->getOverloadSignatureType(); - } + CanGenericSignature signature; + + auto *dc = decl->getInnermostDeclContext(); + if (auto genericSig = dc->getGenericSignatureOfContext()) + signature = genericSig->getCanonicalSignature(); // Record this declaration based on its signature. - auto &known = collisions[signature]; + auto &known = collisions[signature.getPointer()]; if (known.size() == 1) { - collisionTypes.push_back(signature); + collisionSignatures.push_back(signature.getPointer()); } + known.push_back(decl); } + // Check whether we have shadowing for type declarations. + if (typeDecls.size() > 1) { + ArrayRef collidingDecls = typeDecls; + recordShadowedDeclsAfterTypeMatch(collidingDecls, dc, shadowed); + } + // Check whether we have shadowing for signature collisions. - for (auto signature : collisionTypes) { + for (auto signature : collisionSignatures) { ArrayRef collidingDecls = collisions[signature]; recordShadowedDeclsAfterSignatureMatch(collidingDecls, dc, shadowed); } // Check whether we have shadowing for imported initializer collisions. - for (auto nominal : importedInitializerCollectionTypes) { + for (auto nominal : importedInitializerCollisionTypes) { recordShadowedDeclsForImportedInits(importedInitializerCollisions[nominal], shadowed); } @@ -597,15 +646,15 @@ static void recordShadowedDecls(ArrayRef decls, const DeclContext *dc, llvm::SmallPtrSetImpl &shadowed) { // Always considered to have the same signature. - recordShadowedDeclsAfterSignatureMatch(decls, dc, shadowed); + recordShadowedDeclsAfterTypeMatch(decls, dc, shadowed); } static void recordShadowedDecls(ArrayRef decls, const DeclContext *dc, llvm::SmallPtrSetImpl &shadowed) { - // Always considered to have the same signature. - recordShadowedDeclsAfterSignatureMatch(decls, dc, shadowed); + // Always considered to have the same type. + recordShadowedDeclsAfterTypeMatch(decls, dc, shadowed); } template diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 25e6178dc2ee0..cb44104a71dfe 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1552,6 +1552,17 @@ Type TypeBase::getSuperclass(bool useArchetypes) { return superclassTy.subst(subMap); } +Type TypeBase::getRootClass(bool useArchetypes) { + Type iterator = this; + assert(iterator); + + while (auto superclass = iterator->getSuperclass(useArchetypes)) { + iterator = superclass; + } + + return iterator; +} + bool TypeBase::isExactSuperclassOf(Type ty) { // For there to be a superclass relationship, we must be a class, and // the potential subtype must be a class, superclass-bounded archetype, diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 2ea37950dd96e..f447c2cef583b 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -1874,6 +1874,9 @@ NodePointer Demangler::demangleMetatype() { case 'A': return createWithChild(Node::Kind::ReflectionMetadataAssocTypeDescriptor, popProtocolConformance()); + case 'b': + return createWithPoppedType( + Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction); case 'B': return createWithChild(Node::Kind::ReflectionMetadataBuiltinDescriptor, popNode(Node::Kind::Type)); @@ -1917,6 +1920,9 @@ NodePointer Demangler::demangleMetatype() { return createWithPoppedType(Node::Kind::TypeMetadataLazyCache); case 'm': return createWithPoppedType(Node::Kind::Metaclass); + case 'M': + return createWithPoppedType( + Node::Kind::CanonicalSpecializedGenericMetaclass); case 'n': return createWithPoppedType(Node::Kind::NominalTypeDescriptor); case 'o': diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 655cbac01ea24..22d52337aae39 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -540,6 +540,8 @@ class NodePrinter { case Node::Kind::OpaqueTypeDescriptorSymbolicReference: case Node::Kind::OpaqueReturnType: case Node::Kind::OpaqueReturnTypeOf: + case Node::Kind::CanonicalSpecializedGenericMetaclass: + case Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction: return false; } printer_unreachable("bad node kind"); @@ -2418,6 +2420,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { case Node::Kind::AccessorFunctionReference: Printer << "accessor function at " << Node->getIndex(); return nullptr; + case Node::Kind::CanonicalSpecializedGenericMetaclass: + Printer << "specialized generic metaclass for "; + print(Node->getFirstChild()); + return nullptr; + case Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction: + Printer << "canonical specialized generic type metadata accessor for "; + print(Node->getChild(0)); + return nullptr; } printer_unreachable("bad node kind!"); } diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index 09b1896d9f9e1..02e974a926ee0 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -2133,6 +2133,17 @@ void Remangler::mangleAccessorFunctionReference(Node *node) { unreachable("can't remangle"); } +void Remangler::mangleCanonicalSpecializedGenericMetaclass(Node *node) { + Buffer << "MM"; + mangleSingleChildNode(node); // type +} + +void Remangler::mangleCanonicalSpecializedGenericTypeMetadataAccessFunction( + Node *node) { + mangleSingleChildNode(node); + Buffer << "Mb"; +} + /// The top-level interface to the remangler. std::string Demangle::mangleNodeOld(NodePointer node) { if (!node) return ""; diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 4e9907d7d9699..3c8832acac374 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -2533,6 +2533,17 @@ void Remangler::mangleAccessorFunctionReference(Node *node) { unreachable("can't remangle"); } +void Remangler::mangleCanonicalSpecializedGenericMetaclass(Node *node) { + mangleChildNodes(node); + Buffer << "MM"; +} + +void Remangler::mangleCanonicalSpecializedGenericTypeMetadataAccessFunction( + Node *node) { + mangleSingleChildNode(node); + Buffer << "Mb"; +} + } // anonymous namespace /// The top-level interface to the remangler. diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index 0778dcf3dc757..31ce01280bf81 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -130,7 +130,10 @@ static std::vector resolveDirectDependencies( for (const auto &clangDep : allClangModules) { if (auto found = ctx.getModuleDependencies( clangDep, /*onlyClangModule=*/false, cache, ASTDelegate)) { - if (found->getKind() == ModuleDependenciesKind::Swift) + // ASTContext::getModuleDependencies returns dependencies for a module with a given name. + // This Clang module may have the same name as the Swift module we are resolving, so we + // need to make sure we don't add a dependency from a Swift module to itself. + if (found->getKind() == ModuleDependenciesKind::Swift && clangDep != module.first) result.push_back({clangDep, found->getKind()}); } } diff --git a/lib/IRGen/ClassTypeInfo.h b/lib/IRGen/ClassTypeInfo.h new file mode 100644 index 0000000000000..0e47a01df8a43 --- /dev/null +++ b/lib/IRGen/ClassTypeInfo.h @@ -0,0 +1,66 @@ +//===--- ClassTypeInfo.h - The layout info for class types. -----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 contains layout information for class types. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IRGEN_CLASSTYPEINFO_H +#define SWIFT_IRGEN_CLASSTYPEINFO_H + +#include "ClassLayout.h" +#include "HeapTypeInfo.h" + +namespace swift { +namespace irgen { + +/// Layout information for class types. +class ClassTypeInfo : public HeapTypeInfo { + ClassDecl *TheClass; + + // The resilient layout of the class, without making any assumptions + // that violate resilience boundaries. This is used to allocate + // and deallocate instances of the class, and to access fields. + mutable Optional ResilientLayout; + + // A completely fragile layout, used for metadata emission. + mutable Optional FragileLayout; + + /// Can we use swift reference-counting, or do we have to use + /// objc_retain/release? + const ReferenceCounting Refcount; + + ClassLayout generateLayout(IRGenModule &IGM, SILType classType, + bool forBackwardDeployment) const; + +public: + ClassTypeInfo(llvm::PointerType *irType, Size size, SpareBitVector spareBits, + Alignment align, ClassDecl *theClass, + ReferenceCounting refcount) + : HeapTypeInfo(irType, size, std::move(spareBits), align), + TheClass(theClass), Refcount(refcount) {} + + ReferenceCounting getReferenceCounting() const { return Refcount; } + + ClassDecl *getClass() const { return TheClass; } + + const ClassLayout &getClassLayout(IRGenModule &IGM, SILType type, + bool forBackwardDeployment) const; + + StructLayout *createLayoutWithTailElems(IRGenModule &IGM, SILType classType, + ArrayRef tailTypes) const; +}; + +} // namespace irgen +} // namespace swift + +#endif diff --git a/lib/IRGen/GenClangDecl.cpp b/lib/IRGen/GenClangDecl.cpp index 304ddf5bf2b92..577307ce502d9 100644 --- a/lib/IRGen/GenClangDecl.cpp +++ b/lib/IRGen/GenClangDecl.cpp @@ -113,6 +113,17 @@ IRGenModule::getAddrOfClangGlobalDecl(clang::GlobalDecl global, } void IRGenModule::finalizeClangCodeGen() { + // Ensure that code is emitted for any `PragmaCommentDecl`s. (These are + // always guaranteed to be directly below the TranslationUnitDecl.) + // In Clang, this happens automatically during the Sema phase, but here we + // need to take care of it manually because our Clang CodeGenerator is not + // attached to Clang Sema as an ASTConsumer. + for (const auto *D : ClangASTContext->getTranslationUnitDecl()->decls()) { + if (const auto *PCD = dyn_cast(D)) { + emitClangDecl(PCD); + } + } + ClangCodeGen->HandleTranslationUnit( *const_cast(ClangASTContext)); } diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 5c1d736fb99e4..f613828649ee9 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -32,6 +32,7 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILVTableVisitor.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/SmallString.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" @@ -40,72 +41,29 @@ #include "Callee.h" #include "ClassLayout.h" +#include "ClassTypeInfo.h" #include "ConstantBuilder.h" #include "Explosion.h" #include "GenFunc.h" +#include "GenHeap.h" #include "GenMeta.h" #include "GenObjC.h" #include "GenPointerAuth.h" #include "GenProto.h" #include "GenType.h" +#include "HeapTypeInfo.h" #include "IRGenDebugInfo.h" #include "IRGenFunction.h" #include "IRGenModule.h" -#include "GenHeap.h" -#include "HeapTypeInfo.h" #include "MemberAccessStrategy.h" #include "MetadataLayout.h" #include "MetadataRequest.h" - using namespace swift; using namespace irgen; -namespace { - /// Layout information for class types. - class ClassTypeInfo : public HeapTypeInfo { - ClassDecl *TheClass; - - // The resilient layout of the class, without making any assumptions - // that violate resilience boundaries. This is used to allocate - // and deallocate instances of the class, and to access fields. - mutable Optional ResilientLayout; - - // A completely fragile layout, used for metadata emission. - mutable Optional FragileLayout; - - /// Can we use swift reference-counting, or do we have to use - /// objc_retain/release? - const ReferenceCounting Refcount; - - ClassLayout generateLayout(IRGenModule &IGM, SILType classType, - bool forBackwardDeployment) const; - - public: - ClassTypeInfo(llvm::PointerType *irType, Size size, - SpareBitVector spareBits, Alignment align, - ClassDecl *theClass, ReferenceCounting refcount) - : HeapTypeInfo(irType, size, std::move(spareBits), align), - TheClass(theClass), Refcount(refcount) {} - - ReferenceCounting getReferenceCounting() const { - return Refcount; - } - - ClassDecl *getClass() const { return TheClass; } - - - const ClassLayout &getClassLayout(IRGenModule &IGM, SILType type, - bool forBackwardDeployment) const; - - StructLayout *createLayoutWithTailElems(IRGenModule &IGM, - SILType classType, - ArrayRef tailTypes) const; - }; -} // end anonymous namespace - /// Return the lowered type for the class's 'self' type within its context. -static SILType getSelfType(const ClassDecl *base) { +SILType irgen::getSelfType(const ClassDecl *base) { auto loweredTy = base->getDeclaredTypeInContext()->getCanonicalType(); return SILType::getPrimitiveObjectType(loweredTy); } @@ -328,12 +286,17 @@ namespace { auto element = ElementLayout::getIncomplete(*eltType); bool isKnownEmpty = !addField(element, LayoutStrategy::Universal); + bool isSpecializedGeneric = + (theClass->isGenericContext() && !classType.getASTType() + ->getRecursiveProperties() + .hasUnboundGeneric()); + // The 'Elements' list only contains superclass fields when we're // building a layout for tail allocation. - if (!superclass || TailTypes) + if (!superclass || TailTypes || isSpecializedGeneric) Elements.push_back(element); - if (!superclass) { + if (!superclass || isSpecializedGeneric) { AllStoredProperties.push_back(var); AllFieldAccesses.push_back(getFieldAccess(isKnownEmpty)); } @@ -813,17 +776,6 @@ llvm::Value *irgen::emitClassAllocation(IRGenFunction &IGF, SILType selfType, auto &classLayout = classTI.getClassLayout(IGF.IGM, selfType, /*forBackwardDeployment=*/false); - llvm::Value *size, *alignMask; - if (classLayout.isFixedSize()) { - size = IGF.IGM.getSize(classLayout.getSize()); - alignMask = IGF.IGM.getSize(classLayout.getAlignMask()); - } else { - std::tie(size, alignMask) - = emitClassResilientInstanceSizeAndAlignMask(IGF, - selfType.getClassOrBoundGenericClass(), - metadata); - } - llvm::Type *destType = classLayout.getType()->getPointerTo(); llvm::Value *val = nullptr; if (llvm::Value *Promoted = stackPromote(IGF, classLayout, StackAllocSize, @@ -831,6 +783,17 @@ llvm::Value *irgen::emitClassAllocation(IRGenFunction &IGF, SILType selfType, val = IGF.Builder.CreateBitCast(Promoted, IGF.IGM.RefCountedPtrTy); val = IGF.emitInitStackObjectCall(metadata, val, "reference.new"); } else { + llvm::Value *size, *alignMask; + if (classLayout.isFixedSize()) { + size = IGF.IGM.getSize(classLayout.getSize()); + alignMask = IGF.IGM.getSize(classLayout.getAlignMask()); + } else { + std::tie(size, alignMask) + = emitClassResilientInstanceSizeAndAlignMask(IGF, + selfType.getClassOrBoundGenericClass(), + metadata); + } + // Allocate the object on the heap. std::tie(size, alignMask) = appendSizeForTailAllocatedArrays(IGF, size, alignMask, TailArrays); @@ -964,26 +927,49 @@ namespace { /// category data (category_t), or protocol data (protocol_t). class ClassDataBuilder : public ClassMemberVisitor { IRGenModule &IGM; - PointerUnion TheEntity; + using ClassPair = std::pair; + using ClassUnion = TaggedUnion; + TaggedUnion TheEntity; ExtensionDecl *TheExtension; const ClassLayout *FieldLayout; ClassDecl *getClass() const { - return TheEntity.get(); + const ClassUnion *classUnion; + if (!(classUnion = TheEntity.dyn_cast())) { + return nullptr; + } + if (auto *const *theClass = classUnion->dyn_cast()) { + return *theClass; + } + auto pair = classUnion->get(); + return pair.first; } ProtocolDecl *getProtocol() const { - return TheEntity.get(); + if (auto *const *theProtocol = TheEntity.dyn_cast()) { + return *theProtocol; + } + return nullptr; } - + Optional getSpecializedGenericType() const { + const ClassUnion *classUnion; + if (!(classUnion = TheEntity.dyn_cast())) { + return llvm::None; + } + const ClassPair *classPair; + if (!(classPair = classUnion->dyn_cast())) { + return llvm::None; + } + auto &pair = *classPair; + return pair.second; + } + bool isBuildingClass() const { - return TheEntity.is() && !TheExtension; + return TheEntity.isa() && !TheExtension; } bool isBuildingCategory() const { - return TheEntity.is() && TheExtension; - } - bool isBuildingProtocol() const { - return TheEntity.is(); + return TheEntity.isa() && TheExtension; } + bool isBuildingProtocol() const { return TheEntity.isa(); } bool HasNonTrivialDestructor = false; bool HasNonTrivialConstructor = false; @@ -1063,23 +1049,27 @@ namespace { public: ClassDataBuilder(IRGenModule &IGM, ClassDecl *theClass, const ClassLayout &fieldLayout) - : IGM(IGM), TheEntity(theClass), TheExtension(nullptr), - FieldLayout(&fieldLayout) - { - visitConformances(theClass); - visitMembers(theClass); - - if (Lowering::usesObjCAllocator(theClass)) { - addIVarInitializer(); - addIVarDestroyer(); + : ClassDataBuilder(IGM, ClassUnion(theClass), fieldLayout) {} + + ClassDataBuilder( + IRGenModule &IGM, + TaggedUnion> theUnion, + const ClassLayout &fieldLayout) + : IGM(IGM), TheEntity(theUnion), TheExtension(nullptr), + FieldLayout(&fieldLayout) { + visitConformances(getClass()); + visitMembers(getClass()); + + if (Lowering::usesObjCAllocator(getClass())) { + addIVarInitializer(); + addIVarDestroyer(); } } - + ClassDataBuilder(IRGenModule &IGM, ClassDecl *theClass, ExtensionDecl *theExtension) - : IGM(IGM), TheEntity(theClass), TheExtension(theExtension), - FieldLayout(nullptr) - { + : IGM(IGM), TheEntity(ClassUnion(theClass)), TheExtension(theExtension), + FieldLayout(nullptr) { buildCategoryName(CategoryName); visitConformances(theExtension); @@ -1087,7 +1077,7 @@ namespace { for (Decl *member : TheExtension->getMembers()) visit(member); } - + ClassDataBuilder(IRGenModule &IGM, ProtocolDecl *theProtocol) : IGM(IGM), TheEntity(theProtocol), TheExtension(nullptr) { @@ -1143,7 +1133,12 @@ namespace { } } - llvm::Constant *getMetaclassRefOrNull(ClassDecl *theClass) { + llvm::Constant *getMetaclassRefOrNull(Type specializedGenericType, + ClassDecl *theClass) { + if (specializedGenericType) { + return IGM.getAddrOfCanonicalSpecializedGenericMetaclassObject( + specializedGenericType->getCanonicalType(), NotForDefinition); + } if (theClass->isGenericContext() && !theClass->hasClangNode()) { return llvm::ConstantPointerNull::get(IGM.ObjCClassPtrTy); } else { @@ -1153,9 +1148,20 @@ namespace { void buildMetaclassStub() { assert(FieldLayout && "can't build a metaclass from a category"); + + auto specializedGenericType = getSpecializedGenericType().map( + [](auto canType) { return (Type)canType; }); + // The isa is the metaclass pointer for the root class. - auto rootClass = getRootClassForMetaclass(IGM, TheEntity.get()); - auto rootPtr = getMetaclassRefOrNull(rootClass); + auto rootClass = getRootClassForMetaclass(IGM, getClass()); + Type rootType; + if (specializedGenericType && rootClass->isGenericContext()) { + rootType = + (*specializedGenericType)->getRootClass(/*useArchetypes=*/false); + } else { + rootType = Type(); + } + auto rootPtr = getMetaclassRefOrNull(rootType, rootClass); // The superclass of the metaclass is the metaclass of the // superclass. Note that for metaclass stubs, we can always @@ -1166,10 +1172,16 @@ namespace { llvm::Constant *superPtr; if (getClass()->hasSuperclass()) { auto base = getClass()->getSuperclassDecl(); - superPtr = getMetaclassRefOrNull(base); + if (specializedGenericType && base->isGenericContext()) { + superPtr = getMetaclassRefOrNull( + (*specializedGenericType)->getSuperclass(/*useArchetypes=*/false), + base); + } else { + superPtr = getMetaclassRefOrNull(Type(), base); + } } else { superPtr = getMetaclassRefOrNull( - IGM.getObjCRuntimeBaseForSwiftRootClass(getClass())); + Type(), IGM.getObjCRuntimeBaseForSwiftRootClass(getClass())); } auto dataPtr = emitROData(ForMetaClass, DoesNotHaveUpdateCallback); @@ -1184,9 +1196,16 @@ namespace { }; auto init = llvm::ConstantStruct::get(IGM.ObjCClassStructTy, makeArrayRef(fields)); - auto metaclass = - cast( - IGM.getAddrOfMetaclassObject(getClass(), ForDefinition)); + llvm::Constant *uncastMetaclass; + if (auto theType = getSpecializedGenericType()) { + uncastMetaclass = + IGM.getAddrOfCanonicalSpecializedGenericMetaclassObject( + *theType, ForDefinition); + } else { + uncastMetaclass = + IGM.getAddrOfMetaclassObject(getClass(), ForDefinition); + } + auto metaclass = cast(uncastMetaclass); metaclass->setInitializer(init); } @@ -1349,9 +1368,20 @@ namespace { b.addInt32(0); } - // const uint8_t *ivarLayout; - // GC/ARC layout. TODO. - b.addNullPointer(IGM.Int8PtrTy); + // union { + // const uint8_t *IvarLayout; + // ClassMetadata *NonMetaClass; + // }; + Optional specializedGenericType; + if ((specializedGenericType = getSpecializedGenericType()) && forMeta) { + // ClassMetadata *NonMetaClass; + b.addBitCast(IGM.getAddrOfTypeMetadata(*specializedGenericType), + IGM.Int8PtrTy); + } else { + // const uint8_t *IvarLayout; + // GC/ARC layout. TODO. + b.addNullPointer(IGM.Int8PtrTy); + } // const char *name; // It is correct to use the same name for both class and metaclass. @@ -1383,9 +1413,8 @@ namespace { if (hasUpdater) { // Class _Nullable (*metadataUpdateCallback)(Class _Nonnull cls, // void * _Nullable arg); - auto *impl = IGM.getAddrOfObjCMetadataUpdateFunction( - TheEntity.get(), - NotForDefinition); + auto *impl = IGM.getAddrOfObjCMetadataUpdateFunction(getClass(), + NotForDefinition); const auto &schema = IGM.getOptions().PointerAuth.ObjCMethodListFunctionPointers; b.addSignedPointer(impl, schema, PointerAuthEntity()); @@ -1995,14 +2024,14 @@ namespace { /// Get the name of the class or protocol to mangle into the ObjC symbol /// name. StringRef getEntityName(llvm::SmallVectorImpl &buffer) const { - if (auto theClass = TheEntity.dyn_cast()) { + if (auto theClass = getClass()) { return theClass->getObjCRuntimeName(buffer); } - - if (auto theProtocol = TheEntity.dyn_cast()) { + + if (auto theProtocol = getProtocol()) { return theProtocol->getObjCRuntimeName(buffer); } - + llvm_unreachable("not a class or protocol?!"); } @@ -2137,18 +2166,27 @@ void IRGenModule::emitObjCResilientClassStub(ClassDecl *D) { defineAlias(entity, objcStub); } -/// Emit the private data (RO-data) associated with a class. -llvm::Constant *irgen::emitClassPrivateData(IRGenModule &IGM, - ClassDecl *cls) { +static llvm::Constant *doEmitClassPrivateData( + IRGenModule &IGM, + TaggedUnion> classUnion) { assert(IGM.ObjCInterop && "emitting RO-data outside of interop mode"); - PrettyStackTraceDecl stackTraceRAII("emitting ObjC metadata for", cls); + + ClassDecl *cls; + + if (auto *theClass = classUnion.dyn_cast()) { + cls = *theClass; + } else { + auto pair = classUnion.get>(); + cls = pair.first; + } + SILType selfType = getSelfType(cls); auto &classTI = IGM.getTypeInfo(selfType).as(); // FIXME: For now, always use the fragile layout when emitting metadata. auto &fieldLayout = classTI.getClassLayout(IGM, selfType, /*forBackwardDeployment=*/true); - ClassDataBuilder builder(IGM, cls, fieldLayout); + ClassDataBuilder builder(IGM, classUnion, fieldLayout); // First, build the metaclass object. builder.buildMetaclassStub(); @@ -2171,6 +2209,25 @@ llvm::Constant *irgen::emitClassPrivateData(IRGenModule &IGM, return builder.emitROData(ForClass, hasUpdater); } +llvm::Constant *irgen::emitSpecializedGenericClassPrivateData( + IRGenModule &IGM, ClassDecl *theClass, CanType theType) { + assert(theType->getClassOrBoundGenericClass() == theClass); + assert(theClass->getGenericEnvironment()); + Type ty = theType; + PrettyStackTraceType stackTraceRAII(theClass->getASTContext(), + "emitting ObjC metadata for", ty); + return doEmitClassPrivateData( + IGM, TaggedUnion>( + std::make_pair(theClass, theType))); +} + +/// Emit the private data (RO-data) associated with a class. +llvm::Constant *irgen::emitClassPrivateData(IRGenModule &IGM, ClassDecl *cls) { + PrettyStackTraceDecl stackTraceRAII("emitting ObjC metadata for", cls); + return doEmitClassPrivateData( + IGM, TaggedUnion>(cls)); +} + std::pair irgen::emitClassPrivateDataFields(IRGenModule &IGM, ConstantStructBuilder &init, diff --git a/lib/IRGen/GenClass.h b/lib/IRGen/GenClass.h index 834b10d32ba72..549a4a502ec3c 100644 --- a/lib/IRGen/GenClass.h +++ b/lib/IRGen/GenClass.h @@ -51,6 +51,9 @@ namespace irgen { enum class ClassDeallocationKind : unsigned char; enum class FieldAccess : uint8_t; + /// Return the lowered type for the class's 'self' type within its context. + SILType getSelfType(const ClassDecl *base); + OwnedAddress projectPhysicalClassMemberAddress( IRGenFunction &IGF, llvm::Value *base, SILType baseType, SILType fieldType, VarDecl *field); @@ -118,6 +121,11 @@ namespace irgen { ClassDecl *cls); llvm::Constant *emitClassPrivateData(IRGenModule &IGM, ClassDecl *theClass); + + llvm::Constant *emitSpecializedGenericClassPrivateData(IRGenModule &IGM, + ClassDecl *theClass, + CanType theType); + void emitGenericClassPrivateDataTemplate(IRGenModule &IGM, ClassDecl *theClass, llvm::SmallVectorImpl &fields, diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 97ad57e20d1a6..290f1d24a3138 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -38,6 +38,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/GlobalDecl.h" #include "llvm/ADT/SmallString.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Module.h" @@ -1164,7 +1165,8 @@ void IRGenerator::emitLazyDefinitions() { !LazyOpaqueTypeDescriptors.empty() || !LazyFieldDescriptors.empty() || !LazyFunctionDefinitions.empty() || - !LazyWitnessTables.empty()) { + !LazyWitnessTables.empty() || + !LazyCanonicalSpecializedMetadataAccessors.empty()) { // Emit any lazy type metadata we require. while (!LazyTypeMetadata.empty()) { @@ -1220,6 +1222,15 @@ void IRGenerator::emitLazyDefinitions() { && "function with externally-visible linkage emitted lazily?"); IGM->emitSILFunction(f); } + + while (!LazyCanonicalSpecializedMetadataAccessors.empty()) { + CanType theType = + LazyCanonicalSpecializedMetadataAccessors.pop_back_val(); + auto *nominal = theType->getAnyNominal(); + assert(nominal); + CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext()); + emitLazyCanonicalSpecializedMetadataAccessor(*IGM.get(), theType); + } } while (!LazyMetadataAccessors.empty()) { @@ -1394,14 +1405,30 @@ void IRGenerator::noteUseOfFieldDescriptor(NominalTypeDecl *type) { LazyFieldDescriptors.push_back(type); } +void IRGenerator::noteUseOfCanonicalSpecializedMetadataAccessor( + CanType forType) { + auto key = forType->getAnyNominal(); + assert(key); + assert(key->isGenericContext()); + auto &enqueuedSpecializedAccessors = + CanonicalSpecializedAccessorsForGenericTypes[key]; + if (llvm::all_of(enqueuedSpecializedAccessors, + [&](CanType enqueued) { return enqueued != forType; })) { + assert(!FinishedEmittingLazyDefinitions); + LazyCanonicalSpecializedMetadataAccessors.insert(forType); + enqueuedSpecializedAccessors.push_back(forType); + } +} + void IRGenerator::noteUseOfSpecializedGenericTypeMetadata(CanType type) { auto key = type->getAnyNominal(); assert(key); - auto &enqueuedSpecializedTypes = this->SpecializationsForGenericTypes[key]; + assert(key->isGenericContext()); + auto &enqueuedSpecializedTypes = CanonicalSpecializationsForGenericTypes[key]; if (llvm::all_of(enqueuedSpecializedTypes, [&](CanType enqueued) { return enqueued != type; })) { assert(!FinishedEmittingLazyDefinitions); - this->LazySpecializedTypeMetadataRecords.push_back(type); + LazySpecializedTypeMetadataRecords.push_back(type); enqueuedSpecializedTypes.push_back(type); } } @@ -3516,6 +3543,22 @@ IRGenModule::getAddrOfMetaclassObject(ClassDecl *decl, return addr; } +llvm::Constant * +IRGenModule::getAddrOfCanonicalSpecializedGenericMetaclassObject( + CanType concreteType, ForDefinition_t forDefinition) { + auto *theClass = concreteType->getClassOrBoundGenericClass(); + assert(theClass && "only classes have metaclasses"); + assert(concreteType->getClassOrBoundGenericClass()->isGenericContext()); + + auto entity = + LinkEntity::forSpecializedGenericSwiftMetaclassStub(concreteType); + + auto DbgTy = DebugTypeInfo::getObjCClass( + theClass, ObjCClassPtrTy, getPointerSize(), getPointerAlignment()); + auto addr = getAddrOfLLVMVariable(entity, forDefinition, DbgTy); + return addr; +} + /// Fetch the declaration of an Objective-C metadata update callback. llvm::Function * IRGenModule::getAddrOfObjCMetadataUpdateFunction(ClassDecl *classDecl, @@ -3640,6 +3683,38 @@ IRGenModule::getAddrOfGenericTypeMetadataAccessFunction( return entry; } +llvm::Function * +IRGenModule::getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction( + CanType theType, ForDefinition_t forDefinition) { + assert(shouldPrespecializeGenericMetadata()); + assert(!theType->hasUnboundGenericType()); + auto *nominal = theType->getAnyNominal(); + assert(nominal); + assert(nominal->isGenericContext()); + + IRGen.noteUseOfCanonicalSpecializedMetadataAccessor(theType); + + LinkEntity entity = + LinkEntity::forPrespecializedTypeMetadataAccessFunction(theType); + llvm::Function *&entry = GlobalFuncs[entity]; + if (entry) { + if (forDefinition) + updateLinkageForDefinition(*this, entry, entity); + return entry; + } + + llvm::Type *paramTypesArray[1]; + paramTypesArray[0] = SizeTy; // MetadataRequest + + auto paramTypes = llvm::makeArrayRef(paramTypesArray, 1); + auto functionType = + llvm::FunctionType::get(TypeMetadataResponseTy, paramTypes, false); + Signature signature(functionType, llvm::AttributeList(), SwiftCC); + LinkInfo link = LinkInfo::get(*this, entity, forDefinition); + entry = createFunction(*this, link, signature); + return entry; +} + /// Get or create a type metadata cache variable. These are an /// implementation detail of type metadata access functions. llvm::Constant * @@ -3826,14 +3901,19 @@ ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType, llvm::Type *defaultVarTy; unsigned adjustmentIndex; - bool fullMetadata = (nominal && requiresForeignTypeMetadata(nominal)) || - (concreteType->getAnyGeneric() && - concreteType->getAnyGeneric()->isGenericContext()); + bool foreign = nominal && requiresForeignTypeMetadata(nominal); + bool fullMetadata = + foreign || (concreteType->getAnyGeneric() && + concreteType->getAnyGeneric()->isGenericContext()); // Foreign classes reference the full metadata with a GEP. if (fullMetadata) { defaultVarTy = FullTypeMetadataStructTy; - adjustmentIndex = MetadataAdjustmentIndex::ValueType; + if (concreteType->getClassOrBoundGenericClass() && !foreign) { + adjustmentIndex = MetadataAdjustmentIndex::Class; + } else { + adjustmentIndex = MetadataAdjustmentIndex::ValueType; + } // The symbol for other nominal type metadata is generated at the address // point. } else if (nominal) { @@ -3870,19 +3950,24 @@ ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType, if (fullMetadata) { entity = LinkEntity::forTypeMetadata(concreteType, TypeMetadataAddress::FullMetadata); - DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType), - defaultVarTy->getPointerTo(), Size(0), - Alignment(1));; } else { entity = LinkEntity::forTypeMetadata(concreteType, TypeMetadataAddress::AddressPoint); - DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType), - defaultVarTy->getPointerTo(), Size(0), - Alignment(1));; + } + DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType), + defaultVarTy->getPointerTo(), Size(0), + Alignment(1)); + + ConstantReference addr; + + if (fullMetadata && !foreign) { + addr = getAddrOfLLVMVariable(*entity, ConstantInit(), DbgTy, refKind, + /*overrideDeclType=*/nullptr); + } else { + addr = getAddrOfLLVMVariable(*entity, ConstantInit(), DbgTy, refKind, + /*overrideDeclType=*/defaultVarTy); } - auto addr = getAddrOfLLVMVariable(*entity, ConstantInit(), DbgTy, refKind, - defaultVarTy); if (auto *GV = dyn_cast(addr.getValue())) GV->setComdat(nullptr); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 7eca86628b80c..b3205dfe2c6b1 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -14,6 +14,8 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "type-metadata-layout" + #include "swift/ABI/MetadataValues.h" #include "swift/ABI/TypeIdentity.h" #include "swift/AST/ASTContext.h" @@ -44,6 +46,7 @@ #include "Callee.h" #include "ClassLayout.h" #include "ClassMetadataVisitor.h" +#include "ClassTypeInfo.h" #include "ConstantBuilder.h" #include "EnumMetadataVisitor.h" #include "FixedTypeInfo.h" @@ -1520,6 +1523,15 @@ namespace { void addVTable() { if (VTableEntries.empty()) return; + + LLVM_DEBUG( + llvm::dbgs() << "VTable entries for " << getType()->getName() << ":\n"; + for (auto entry : VTableEntries) { + llvm::dbgs() << " "; + entry.print(llvm::dbgs()); + llvm::dbgs() << '\n'; + } + ); // Only emit a method lookup function if the class is resilient // and has a non-empty vtable. @@ -1901,6 +1913,25 @@ void irgen::emitLazyMetadataAccessor(IRGenModule &IGM, isReadNone); } +void irgen::emitLazyCanonicalSpecializedMetadataAccessor(IRGenModule &IGM, + CanType theType) { + llvm::Function *accessor = + IGM.getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction( + theType, ForDefinition); + + if (IGM.getOptions().optimizeForSize()) { + accessor->addFnAttr(llvm::Attribute::NoInline); + } + + emitCacheAccessFunction( + IGM, accessor, /*cache=*/nullptr, CacheStrategy::None, + [&](IRGenFunction &IGF, Explosion ¶ms) { + return emitCanonicalSpecializedGenericTypeMetadataAccessFunction( + IGF, params, theType); + }, + /*isReadNone=*/true); +} + void irgen::emitLazySpecializedGenericTypeMetadata(IRGenModule &IGM, CanType type) { switch (type->getKind()) { @@ -1914,6 +1945,11 @@ void irgen::emitLazySpecializedGenericTypeMetadata(IRGenModule &IGM, emitSpecializedGenericEnumMetadata(IGM, type, *type.getEnumOrBoundGenericEnum()); break; + case TypeKind::Class: + case TypeKind::BoundGenericClass: + emitSpecializedGenericClassMetadata(IGM, type, + *type.getClassOrBoundGenericClass()); + break; default: llvm_unreachable("Cannot statically specialize types of kind other than " "struct and enum."); @@ -2662,6 +2698,8 @@ namespace { using super = ClassMetadataVisitor; protected: + using NominalDecl = ClassDecl; + using super::asImpl; using super::IGM; using super::Target; @@ -2683,26 +2721,34 @@ namespace { VTable(IGM.getSILModule().lookUpVTable(theClass)) {} public: + SILType getLoweredType() { + return IGM.getLoweredType(Target->getDeclaredTypeInContext()); + } + void noteAddressPoint() { ClassMetadataVisitor::noteAddressPoint(); AddressPoint = B.getNextOffsetFromGlobal(); } - void addClassFlags() { - B.addInt32((uint32_t) getClassFlags(Target)); - } + ClassFlags getClassFlags() { return ::getClassFlags(Target); } + + void addClassFlags() { B.addInt32((uint32_t)asImpl().getClassFlags()); } void noteResilientSuperclass() {} void noteStartOfImmediateMembers(ClassDecl *theClass) {} - void addValueWitnessTable() { + ConstantReference getValueWitnessTable(bool relativeReference) { + assert( + !relativeReference && + "Cannot get a relative reference to a class' value witness table."); switch (IGM.getClassMetadataStrategy(Target)) { case ClassMetadataStrategy::Resilient: case ClassMetadataStrategy::Singleton: // The runtime fills in the value witness table for us. - B.add(llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy)); - break; + return ConstantReference( + llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy), + swift::irgen::ConstantReference::Direct); case ClassMetadataStrategy::Update: case ClassMetadataStrategy::FixedOrUpdate: @@ -2712,12 +2758,20 @@ namespace { ? IGM.Context.getAnyObjectType() : IGM.Context.TheNativeObjectType); auto wtable = IGM.getAddrOfValueWitnessTable(type); - B.add(wtable); - break; + return ConstantReference(wtable, + swift::irgen::ConstantReference::Direct); } } } + void addValueWitnessTable() { + B.add(asImpl().getValueWitnessTable(false).getValue()); + } + + llvm::Constant *getAddrOfMetaclassObject(ForDefinition_t forDefinition) { + return IGM.getAddrOfMetaclassObject(Target, forDefinition); + } + /// The 'metadata flags' field in a class is actually a pointer to /// the metaclass object for the class. /// @@ -2730,8 +2784,7 @@ namespace { if (IGM.ObjCInterop) { // Get the metaclass pointer as an intptr_t. - auto metaclass = IGM.getAddrOfMetaclassObject(Target, - NotForDefinition); + auto metaclass = asImpl().getAddrOfMetaclassObject(NotForDefinition); auto flags = llvm::ConstantExpr::getPtrToInt(metaclass, IGM.MetadataKindTy); B.add(flags); @@ -2744,18 +2797,32 @@ namespace { } } - void addSuperclass() { + llvm::Constant *getSuperclassMetadata() { + Type type = Target->mapTypeIntoContext(Target->getSuperclass()); + auto *metadata = + tryEmitConstantHeapMetadataRef(IGM, type->getCanonicalType(), + /*allowUninit*/ false); + return metadata; + } + + bool shouldAddNullSuperclass() { // If we might have generic ancestry, leave a placeholder since - // swift_initClassMetdata() will fill in the superclass. + // swift_initClassMetadata() will fill in the superclass. switch (IGM.getClassMetadataStrategy(Target)) { case ClassMetadataStrategy::Resilient: case ClassMetadataStrategy::Singleton: - B.addNullPointer(IGM.TypeMetadataPtrTy); - return; + return true; case ClassMetadataStrategy::Update: case ClassMetadataStrategy::FixedOrUpdate: case ClassMetadataStrategy::Fixed: - break; + return false; + } + } + + void addSuperclass() { + if (asImpl().shouldAddNullSuperclass()) { + B.addNullPointer(IGM.TypeMetadataPtrTy); + return; } // If this is a root class, use SwiftObject as our formal parent. @@ -2775,10 +2842,7 @@ namespace { return; } - Type type = Target->mapTypeIntoContext(Target->getSuperclass()); - auto *metadata = tryEmitConstantHeapMetadataRef( - IGM, type->getCanonicalType(), - /*allowUninit*/ false); + auto *metadata = asImpl().getSuperclassMetadata(); assert(metadata != nullptr); B.add(metadata); } @@ -2813,8 +2877,12 @@ namespace { return ClassContextDescriptorBuilder(IGM, Target, RequireMetadata).emit(); } + llvm::Constant *getNominalTypeDescriptor() { + return emitNominalTypeDescriptor(); + } + void addNominalTypeDescriptor() { - B.addSignedPointer(emitNominalTypeDescriptor(), + B.addSignedPointer(asImpl().getNominalTypeDescriptor(), IGM.getOptions().PointerAuth.TypeDescriptors, PointerAuthEntity::Special::TypeDescriptor); } @@ -2832,9 +2900,13 @@ namespace { B.addInt32(0); } + bool hasFixedLayout() { return FieldLayout.isFixedLayout(); } + + const ClassLayout &getFieldLayout() { return FieldLayout; } + void addInstanceSize() { - if (FieldLayout.isFixedLayout()) { - B.addInt32(FieldLayout.getSize().getValue()); + if (asImpl().hasFixedLayout()) { + B.addInt32(asImpl().getFieldLayout().getSize().getValue()); } else { // Leave a zero placeholder to be filled at runtime B.addInt32(0); @@ -2842,8 +2914,8 @@ namespace { } void addInstanceAlignMask() { - if (FieldLayout.isFixedLayout()) { - B.addInt16(FieldLayout.getAlignMask().getValue()); + if (asImpl().hasFixedLayout()) { + B.addInt16(asImpl().getFieldLayout().getAlignMask().getValue()); } else { // Leave a zero placeholder to be filled at runtime B.addInt16(0); @@ -2873,6 +2945,12 @@ namespace { B.add(IGM.getObjCEmptyVTablePtr()); } + llvm::Constant *getROData() { return emitClassPrivateData(IGM, Target); } + + uint64_t getClassDataPointerHasSwiftMetadataBits() { + return IGM.UseDarwinPreStableABIBit ? 1 : 2; + } + void addClassDataPointer() { if (!IGM.ObjCInterop) { // with no Objective-C runtime, just give an empty pointer with the @@ -2883,11 +2961,11 @@ namespace { } // Derive the RO-data. - llvm::Constant *data = emitClassPrivateData(IGM, Target); + llvm::Constant *data = asImpl().getROData(); // Set a low bit to indicate this class has Swift metadata. - auto bit = llvm::ConstantInt::get(IGM.IntPtrTy, - IGM.UseDarwinPreStableABIBit ? 1 : 2); + auto bit = llvm::ConstantInt::get( + IGM.IntPtrTy, asImpl().getClassDataPointerHasSwiftMetadataBits()); // Emit data + bit. data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy); @@ -2941,6 +3019,14 @@ namespace { } }; + static void + addFixedFieldOffset(IRGenModule &IGM, ConstantStructBuilder &B, VarDecl *var, + std::function typeFromContext) { + SILType baseType = SILType::getPrimitiveObjectType( + typeFromContext(var->getDeclContext())->getCanonicalType()); + B.addInt(IGM.SizeTy, getClassFieldOffset(IGM, baseType, var).getValue()); + } + /// A builder for non-generic class metadata which does not require any /// runtime initialization, or that only requires runtime initialization /// on newer Objective-C runtimes. @@ -2957,10 +3043,9 @@ namespace { : super(IGM, theClass, builder, fieldLayout) {} void addFieldOffset(VarDecl *var) { - SILType baseType = SILType::getPrimitiveObjectType( - var->getDeclContext()->getDeclaredTypeInContext() - ->getCanonicalType()); - B.addInt(IGM.SizeTy, getClassFieldOffset(IGM, baseType, var).getValue()); + addFixedFieldOffset(IGM, B, var, [](DeclContext *dc) { + return dc->getDeclaredTypeInContext(); + }); } void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) { @@ -2982,6 +3067,7 @@ namespace { /// fields or generic ancestry. class SingletonClassMetadataBuilder : public ClassMetadataBuilderBase { + using NominalDecl = StructDecl; using super = ClassMetadataBuilderBase; using super::IGM; using super::B; @@ -3287,6 +3373,183 @@ namespace { metadata, collector); } }; + + template