diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b689fca09a72d..0b5f322eed1be 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,9 +20,12 @@ jobs: - uses: actions/cache@v1 with: path: ../build-cache - key: ${{ runner.os }}-sccache-v2 + key: ${{ runner.os }}-sccache-v3 - name: Build Linux installable archive - run: ./utils/webassembly/ci.sh + run: | + ./utils/webassembly/ci.sh + echo "Cleanup build directory to free disk space" + rm -rf ../build - name: Upload Linux installable archive uses: actions/upload-artifact@v1 with: @@ -47,7 +50,7 @@ jobs: - uses: actions/cache@v1 with: path: ../build-cache - key: ${{ runner.os }}-sccache-v2 + key: ${{ runner.os }}-sccache-v3 - name: Build macOS installable archive run: ./utils/webassembly/ci.sh - name: Upload macOS installable archive diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b4ac94897765..9ee3f1fba6f4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -477,7 +477,6 @@ endif() include(SwiftComponents) include(SwiftHandleGybSources) include(SwiftSetIfArchBitness) -include(SwiftSource) include(AddSwift) include(SwiftConfigureSDK) include(SwiftComponents) diff --git a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake index e21f9c87566cc..a63d18c794dc4 100644 --- a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake +++ b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake @@ -106,7 +106,7 @@ endmacro() macro(configure_sdks_darwin) set(macosx_arch "x86_64") - set(iphoneos_arch "arm64" "armv7") + set(iphoneos_arch "arm64" "arm64e" "armv7") set(appletvos_arch "arm64") set(watchos_arch "armv7k") diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index a85880399d28a..6d51c74c5f1b0 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -742,26 +742,18 @@ function(_add_swift_host_library_single target) # Include LLVM Bitcode slices for iOS, Watch OS, and Apple TV OS device libraries. if(SWIFT_EMBED_BITCODE_SECTION) if(${SWIFT_HOST_VARIANT_SDK} MATCHES "(I|TV|WATCH)OS") - # The two branches of this if statement accomplish the same end result - # We are simply accounting for the fact that on CMake < 3.16 - # using a generator expression to - # specify a LINKER: argument does not work, + target_link_options(${target} PRIVATE + "LINKER:-bitcode_bundle" + "LINKER:-lto_library,${LLVM_LIBRARY_DIR}/libLTO.dylib") + + # Please note that using a generator expression to fit + # this in a single target_link_options does not work + # (at least in CMake 3.15 and 3.16), # since that seems not to allow the LINKER: prefix to be # evaluated (i.e. it will be added as-is to the linker parameters) - if(CMAKE_VERSION VERSION_LESS 3.16) - target_link_options(${target} PRIVATE - "LINKER:-bitcode_bundle" - "LINKER:-lto_library,${LLVM_LIBRARY_DIR}/libLTO.dylib") - - if(SWIFT_EMBED_BITCODE_SECTION_HIDE_SYMBOLS) - target_link_options(${target} PRIVATE - "LINKER:-bitcode_hide_symbols") - endif() - else() + if(SWIFT_EMBED_BITCODE_SECTION_HIDE_SYMBOLS) target_link_options(${target} PRIVATE - "LINKER:-bitcode_bundle" - $<$:"LINKER:-bitcode_hide_symbols"> - "LINKER:-lto_library,${LLVM_LIBRARY_DIR}/libLTO.dylib") + "LINKER:-bitcode_hide_symbols") endif() endif() endif() diff --git a/cmake/modules/DarwinSDKs.cmake b/cmake/modules/DarwinSDKs.cmake index 387ff28f6aaa7..f10940b79b82b 100644 --- a/cmake/modules/DarwinSDKs.cmake +++ b/cmake/modules/DarwinSDKs.cmake @@ -3,10 +3,10 @@ option(SWIFT_ENABLE_IOS32 TRUE) if(SWIFT_ENABLE_IOS32) -set(SUPPORTED_IOS_ARCHS "armv7;armv7s;arm64") +set(SUPPORTED_IOS_ARCHS "armv7;armv7s;arm64;arm64e") set(SUPPORTED_IOS_SIMULATOR_ARCHS "i386;x86_64") else() -set(SUPPORTED_IOS_ARCHS "arm64") +set(SUPPORTED_IOS_ARCHS "arm64;arm64e") set(SUPPORTED_IOS_SIMULATOR_ARCHS "x86_64") endif() diff --git a/cmake/modules/StandaloneOverlay.cmake b/cmake/modules/StandaloneOverlay.cmake index ed089097b8d19..6ac7fab79c65b 100644 --- a/cmake/modules/StandaloneOverlay.cmake +++ b/cmake/modules/StandaloneOverlay.cmake @@ -112,7 +112,6 @@ include(SwiftSharedCMakeConfig) include(AddSwift) include(SwiftHandleGybSources) include(SwiftConfigureSDK) -include(SwiftSource) include(SwiftComponents) include(DarwinSDKs) diff --git a/cmake/modules/SwiftSetIfArchBitness.cmake b/cmake/modules/SwiftSetIfArchBitness.cmake index d38a9689150ba..b48a6388f01b3 100644 --- a/cmake/modules/SwiftSetIfArchBitness.cmake +++ b/cmake/modules/SwiftSetIfArchBitness.cmake @@ -17,6 +17,7 @@ function(set_if_arch_bitness var_name) set("${var_name}" "${SIA_CASE_32_BIT}" PARENT_SCOPE) elseif("${SIA_ARCH}" STREQUAL "x86_64" OR "${SIA_ARCH}" STREQUAL "arm64" OR + "${SIA_ARCH}" STREQUAL "arm64e" OR "${SIA_ARCH}" STREQUAL "aarch64" OR "${SIA_ARCH}" STREQUAL "powerpc64" OR "${SIA_ARCH}" STREQUAL "powerpc64le" OR diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 2594a3393e9f2..cfa67d6d80ab4 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -583,10 +583,12 @@ mangled in to disambiguate. :: impl-function-type ::= type* 'I' FUNC-ATTRIBUTES '_' - impl-function-type ::= type* generic-signature 'I' PSEUDO-GENERIC? FUNC-ATTRIBUTES '_' + impl-function-type ::= type* generic-signature 'I' FUNC-ATTRIBUTES '_' - FUNC-ATTRIBUTES ::= CALLEE-ESCAPE? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? PARAM-CONVENTION* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION)? + FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? PARAM-CONVENTION* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION)? + PATTERN-SUBS ::= 's' // has pattern substitutions + INVOCATION-SUB ::= 'I' // has invocation substitutions PSEUDO-GENERIC ::= 'P' CALLEE-ESCAPE ::= 'e' // @escaping (inverse of SIL @noescape) diff --git a/docs/SIL.rst b/docs/SIL.rst index bddf188c65c18..d6f9043cbdead 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -592,6 +592,46 @@ autorelease in the callee. importer only imports non-native methods and types as ``throws`` when it is possible to do this automatically. +- SIL function types may provide a pattern signature and substitutions + to express that values of the type use a particular generic abstraction + pattern. Both must be provided together. If a pattern signature is + present, the component types (parameters, yields, and results) must be + expressed in terms of the generic parameters of that signature. + The pattern substitutions should be expressed in terms of the generic + parameters of the overall generic signature, if any, or else + the enclosing generic context, if any. + + A pattern signature follows the ``@substituted`` attribute, which + must be the final attribute preceding the function type. Pattern + substitutions follow the function type, preceded by the ``for`` + keyword. For example:: + + @substituted (@in T) -> @out T.Element for Array + + The low-level representation of a value of this type may not match + the representation of a value of the substituted-through version of it:: + + (@in Array) -> @out Int + + Substitution differences at the outermost level of a function value + may be adjusted using the ``convert_function`` instruction. Note that + this only works at the outermost level and not in nested positions. + For example, a function which takes a parameter of the first type above + cannot be converted by ``convert_function`` to a function which takes + a parameter of the second type; such a conversion must be done with a + thunk. + + Type substitution on a function type with a pattern signature and + substitutions only substitutes into the substitutions; the component + types are preserved with their exact original structure. + +- In the implementation, a SIL function type may also carry substitutions + for its generic signature. This is a convenience for working with + applied generic types and is not generally a formal part of the SIL + language; in particular, values should not have such types. Such a + type behaves like a non-generic type, as if the substitutions were + actually applied to the underlying function type. + Coroutine Types ``````````````` @@ -815,7 +855,8 @@ Functions :: decl ::= sil-function - sil-function ::= 'sil' sil-linkage? sil-function-name ':' sil-type + sil-function ::= 'sil' sil-linkage? sil-function-attribute+ + sil-function-name ':' sil-type '{' sil-basic-block+ '}' sil-function-name ::= '@' [A-Za-z_0-9]+ @@ -827,6 +868,134 @@ The ``sil`` syntax declares the function's name and SIL type, and defines the body of the function inside braces. The declared type must be a function type, which may be generic. + +Function Attributes +``````````````````` +:: + + sil-function-attribute ::= '[canonical]' + +The function is in canonical SIL even if the module is still in raw SIL. +:: + + sil-function-attribute ::= '[ossa]' + +The function is in OSSA (ownership SSA) form. +:: + + sil-function-attribute ::= '[transparent]' + +Transparent functions are always inlined and don't keep their source +information when inlined. +:: + + sil-function-attribute ::= '[' sil-function-thunk ']' + sil-function-thunk ::= 'thunk' + sil-function-thunk ::= 'signature_optimized_thunk' + sil-function-thunk ::= 'reabstraction_thunk' + +The function is a compiler generated thunk. +:: + + sil-function-attribute ::= '[dynamically_replacable]' + +The function can be replaced at runtime with a different implementation. +Optimizations must not assume anything about such a function, even if the SIL +of the function body is available. +:: + + sil-function-attribute ::= '[dynamic_replacement_for' identifier ']' + sil-function-attribute ::= '[objc_replacement_for' identifier ']' + +Specifies for which function this function is a replacement. +:: + + sil-function-attribute ::= '[exact_self_class]' + +The function is a designated initializers, where it is known that the static +type being allocated is the type of the class that defines the designated +initializer. +:: + + sil-function-attribute ::= '[without_actually_escaping]' + +The function is a thunk for closures which are not actually escaping. +:: + + sil-function-attribute ::= '[' sil-function-purpose ']' + sil-function-purpose ::= 'global_init' + +The implied semantics are: + + - side-effects can occur any time before the first invocation. + - all calls to the same ``global_init`` function have the same side-effects. + - any operation that may observe the initializer's side-effects must be + preceded by a call to the initializer. + +This is currently true if the function is an addressor that was lazily +generated from a global variable access. Note that the initialization +function itself does not need this attribute. It is private and only +called within the addressor. +:: + + sil-function-attribute ::= '[weak_imported]' + +Cross-module references to this function should always use weak linking. +:: + + sil-function-attribute ::= '[available' sil-version-tuple ']' + sil-version-tuple ::= [0-9]+ ('.' [0-9]+)* + +The minimal OS-version where the function is available. +:: + + sil-function-attribute ::= '[' sil-function-inlining ']' + sil-function-inlining ::= 'never' + +The function is never inlined. +:: + + sil-function-inlining ::= 'always' + +The function is always inlined, even in a ``Onone`` build. +:: + + sil-function-attribute ::= '[' sil-function-optimization ']' + sil-function-inlining ::= 'Onone' + sil-function-inlining ::= 'Ospeed' + sil-function-inlining ::= 'Osize' + +The function is optimized according to this attribute, overriding the setting +from the command line. +:: + + sil-function-attribute ::= '[' sil-function-effects ']' + sil-function-effects ::= 'readonly' + sil-function-effects ::= 'readnone' + sil-function-effects ::= 'readwrite' + sil-function-effects ::= 'releasenone' + +The specified memory effects of the function. +:: + + sil-function-attribute ::= '[_semantics "' [A-Za-z._0-9]+ '"]' + +The specified high-level semantics of the function. The optimizer can use this +information to perform high-level optimizations before such functions are +inlined. For example, ``Array`` operations are annotated with semantic +attributes to let the optimizer perform redundant bounds check elimination and +similar optimizations. +:: + + sil-function-attribute ::= '[_specialize "' [A-Za-z._0-9]+ '"]' + +Specifies for which types specialized code should be generated. +:: + + sil-function-attribute ::= '[clang "' identifier '"]' + +The clang node owner. + Basic Blocks ~~~~~~~~~~~~ :: diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md index 2f988ca919783..d8774156367f4 100644 --- a/docs/WindowsBuild.md +++ b/docs/WindowsBuild.md @@ -13,7 +13,7 @@ The following must take place in the **developer command prompt** (provided by V 2. Microsoft.VisualStudio.Component.Windows10SDK.17763 3. Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -The following [link](https://docs.microsoft.com/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2019)) helps in finding the component name given its ID for Visual Studio 2019. +The following [link](https://docs.microsoft.com/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2019) helps in finding the component name given its ID for Visual Studio 2019. ## Clone the repositories @@ -92,7 +92,25 @@ Warning: Creating the above links usually requires administrator privileges. The ```cmd md "S:\b\toolchain" -cmake -B "S:\b\toolchain" -G Ninja -S S:\toolchain\llvm -C S:\windows-swift\cmake\caches\Windows-x86_64.cmake -C S:\windows-swift\cmake\caches\org.compnerd.dt.cmake -DLLVM_ENABLE_ASSERTIONS=YES -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;cmark;swift;lldb;lld" -DLLVM_EXTERNAL_PROJECTS="cmark;swift" -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE=S:\toolchain\swift-corelibs-libdispatch -DLLVM_ENABLE_PDB=YES -DLLDB_DISABLE_PYTHON=YES -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE="S:/Library/icu-64/usr/include" -DSWIFT_WINDOWS_x86_64_ICU_UC="S:/Library/icu-64/usr/lib/icuuc64.lib" -DSWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE="S:/Library/icu-64/usr/include" -DSWIFT_WINDOWS_x86_64_ICU_I18N="S:/Library/icu-64/usr/lib/icuin64.lib" -DCMAKE_INSTALL_PREFIX="C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr" -DPYTHON_EXECUTABLE=C:\Python27\python.exe -DSWIFT_BUILD_DYNAMIC_STDLIB=YES -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY=YES +cmake -B "S:\b\toolchain" -G Ninja -S S:\toolchain\llvm ^ + -C S:\windows-swift\cmake\caches\Windows-x86_64.cmake ^ + -C S:\windows-swift\cmake\caches\org.compnerd.dt.cmake ^ + -DLLVM_ENABLE_ASSERTIONS=YES ^ + -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;cmark;swift;lldb;lld" ^ + -DLLVM_EXTERNAL_PROJECTS="cmark;swift" ^ + -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE=S:\toolchain\swift-corelibs-libdispatch ^ + -DLLVM_ENABLE_PDB=YES ^ + -DLLVM_ENABLE_LIBEDIT=NO ^ + -DLLDB_DISABLE_PYTHON=YES ^ + -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE="S:/Library/icu-64/usr/include" ^ + -DSWIFT_WINDOWS_x86_64_ICU_UC="S:/Library/icu-64/usr/lib/icuuc64.lib" ^ + -DSWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE="S:/Library/icu-64/usr/include" ^ + -DSWIFT_WINDOWS_x86_64_ICU_I18N="S:/Library/icu-64/usr/lib/icuin64.lib" ^ + -DCMAKE_INSTALL_PREFIX="C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr" ^ + -DPYTHON_EXECUTABLE=C:\Python27\python.exe ^ + -DSWIFT_BUILD_DYNAMIC_STDLIB=YES ^ + -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY=YES + ninja -C S:\b\toolchain ``` diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 92ba02693beb7..5eed1606e02fb 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -53,6 +53,10 @@ struct RuntimeTarget; template <> struct RuntimeTarget<4> { using StoredPointer = uint32_t; + // To avoid implicit conversions from StoredSignedPointer to StoredPointer. + using StoredSignedPointer = struct { + uint32_t SignedValue; + }; using StoredSize = uint32_t; using StoredPointerDifference = int32_t; static constexpr size_t PointerSize = 4; @@ -61,6 +65,10 @@ struct RuntimeTarget<4> { template <> struct RuntimeTarget<8> { using StoredPointer = uint64_t; + // To avoid implicit conversions from StoredSignedPointer to StoredPointer. + using StoredSignedPointer = struct { + uint64_t SignedValue; + }; using StoredSize = uint64_t; using StoredPointerDifference = int64_t; static constexpr size_t PointerSize = 8; @@ -77,6 +85,7 @@ namespace reflection { struct InProcess { static constexpr size_t PointerSize = sizeof(uintptr_t); using StoredPointer = uintptr_t; + using StoredSignedPointer = uintptr_t; using StoredSize = size_t; using StoredPointerDifference = ptrdiff_t; @@ -85,6 +94,9 @@ struct InProcess { template using Pointer = T*; + + template + using SignedPointer = T; template using FarRelativeDirectPointer = FarRelativeDirectPointer; @@ -111,6 +123,7 @@ struct ExternalPointer { template struct External { using StoredPointer = typename Runtime::StoredPointer; + using StoredSignedPointer = typename Runtime::StoredSignedPointer; using StoredSize = typename Runtime::StoredSize; using StoredPointerDifference = typename Runtime::StoredPointerDifference; static constexpr size_t PointerSize = Runtime::PointerSize; @@ -118,6 +131,9 @@ struct External { template using Pointer = StoredPointer; + + template + using SignedPointer = StoredSignedPointer; template using FarRelativeDirectPointer = StoredPointer; @@ -141,9 +157,13 @@ using ConstTargetMetadataPointer template using TargetPointer = typename Runtime::template Pointer; +template +using TargetSignedPointer = typename Runtime::template SignedPointer; + template using ConstTargetPointer = typename Runtime::template Pointer; + template class Pointee, bool Nullable = true> using ConstTargetFarRelativeDirectPointer @@ -281,7 +301,10 @@ class TargetValueWitnessTypes { #define WANT_ALL_VALUE_WITNESSES #define DATA_VALUE_WITNESS(lowerId, upperId, type) #define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \ - typedef TargetPointer lowerId; + typedef returnType (*lowerId ## Unsigned) paramTypes; \ + typedef TargetSignedPointer lowerId; #define MUTABLE_VALUE_TYPE TargetPointer #define IMMUTABLE_VALUE_TYPE ConstTargetPointer #define MUTABLE_BUFFER_TYPE TargetPointer @@ -314,6 +337,9 @@ template struct TargetValueWitnessTable { #define WANT_ONLY_REQUIRED_VALUE_WITNESSES #define VALUE_WITNESS(LOWER_ID, UPPER_ID) \ typename TargetValueWitnessTypes::LOWER_ID LOWER_ID; +#define FUNCTION_VALUE_WITNESS(LOWER_ID, UPPER_ID, RET, PARAMS) \ + typename TargetValueWitnessTypes::LOWER_ID LOWER_ID; + #include "swift/ABI/ValueWitness.def" using StoredSize = typename Runtime::StoredSize; @@ -595,7 +621,7 @@ struct TargetMetadata { #define WANT_ONLY_REQUIRED_VALUE_WITNESSES #define FUNCTION_VALUE_WITNESS(WITNESS, UPPER, RET_TYPE, PARAM_TYPES) \ template \ - _ResultOf::type \ + _ResultOf::type \ vw_##WITNESS(A &&...args) const { \ return getValueWitnesses()->WITNESS(std::forward(args)..., this); \ } @@ -744,7 +770,7 @@ template struct TargetHeapMetadataHeaderPrefix { /// Destroy the object, returning the allocated size of the object /// or 0 if the object shouldn't be deallocated. - TargetPointer destroy; + TargetSignedPointer destroy; }; using HeapMetadataHeaderPrefix = TargetHeapMetadataHeaderPrefix; @@ -838,10 +864,17 @@ struct TargetVTableDescriptorHeader { template struct TargetContextDescriptor; -template +template class Context = TargetContextDescriptor> +using TargetSignedContextPointer = TargetSignedPointer * __ptrauth_swift_type_descriptor>; + +template class Context = TargetContextDescriptor> using TargetRelativeContextPointer = - RelativeIndirectablePointer, - /*nullable*/ true>; + RelativeIndirectablePointer, + /*nullable*/ true, int32_t, + TargetSignedContextPointer>; using RelativeContextPointer = TargetRelativeContextPointer; @@ -849,7 +882,8 @@ template class Context = TargetContextDescriptor> using RelativeContextPointerIntPair = RelativeIndirectablePointerIntPair, IntTy, - /*nullable*/ true, int32_t>; + /*nullable*/ true, int32_t, + TargetSignedContextPointer>; template struct TargetMethodDescriptor; @@ -1085,13 +1119,13 @@ struct TargetClassMetadata : public TargetAnyClassMetadata { /// if this is an artificial subclass. We currently provide no /// supported mechanism for making a non-artificial subclass /// dynamically. - ConstTargetMetadataPointer Description; + TargetSignedPointer * __ptrauth_swift_type_descriptor> Description; public: /// A function for destroying instance variables, used to clean up after an /// early return from a constructor. If null, no clean up will be performed /// and all ivars must be trivial. - TargetPointer IVarDestroyer; + TargetSignedPointer IVarDestroyer; // After this come the class members, laid out as follows: // - class members for the superclass (recursively) @@ -1108,6 +1142,12 @@ struct TargetClassMetadata : public TargetAnyClassMetadata { return Description; } + typename Runtime::StoredSignedPointer + getDescriptionAsSignedPointer() const { + assert(isTypeMetadata()); + return Description; + } + void setDescription(const TargetClassDescriptor *description) { Description = description; } @@ -1314,7 +1354,7 @@ struct TargetForeignClassMetadata : public TargetForeignTypeMetadata { using StoredPointer = typename Runtime::StoredPointer; /// An out-of-line description of the type. - ConstTargetMetadataPointer Description; + TargetSignedPointer * __ptrauth_swift_type_descriptor> Description; /// The superclass of the foreign class, if any. ConstTargetMetadataPointer @@ -1330,6 +1370,11 @@ struct TargetForeignClassMetadata : public TargetForeignTypeMetadata { return Description; } + typename Runtime::StoredSignedPointer + getDescriptionAsSignedPointer() const { + return Description; + } + static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::ForeignClass; } @@ -1345,8 +1390,7 @@ struct TargetValueMetadata : public TargetMetadata { : TargetMetadata(Kind), Description(description) {} /// An out-of-line description of the type. - ConstTargetMetadataPointer - Description; + TargetSignedPointer * __ptrauth_swift_type_descriptor> Description; static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Struct @@ -1358,6 +1402,11 @@ struct TargetValueMetadata : public TargetMetadata { getDescription() const { return Description; } + + typename Runtime::StoredSignedPointer + getDescriptionAsSignedPointer() const { + return Description; + } }; using ValueMetadata = TargetValueMetadata; @@ -1822,11 +1871,16 @@ using ProtocolDescriptor = TargetProtocolDescriptor; /// the layout of a witness table is dependent on the protocol being /// represented. template -struct TargetWitnessTable { +class TargetWitnessTable { /// The protocol conformance descriptor from which this witness table /// was generated. ConstTargetMetadataPointer Description; + +public: + const TargetProtocolConformanceDescriptor *getDescription() const { + return Description; + } }; using WitnessTable = TargetWitnessTable; @@ -2189,7 +2243,7 @@ struct TargetTypeMetadataRecord { DirectNominalTypeDescriptor; /// An indirect reference to a nominal type descriptor. - RelativeDirectPointerIntPair * const, + RelativeDirectPointerIntPair * __ptrauth_swift_type_descriptor>, TypeReferenceKind> IndirectNominalTypeDescriptor; @@ -2242,24 +2296,25 @@ template class TargetGenericRequirementDescriptor; /// pointer equivalent to \c TargetProtocolDescriptorRef. template class RelativeTargetProtocolDescriptorPointer { - union AnyProtocol { - TargetProtocolDescriptor descriptor; + union { + /// Relative pointer to a Swift protocol descriptor. + /// The \c bool value will be false to indicate that the protocol + /// is a Swift protocol, or true to indicate that this references + /// an Objective-C protocol. + RelativeContextPointerIntPair + swiftPointer; +#if SWIFT_OBJC_INTEROP + /// Relative pointer to an ObjC protocol descriptor. + /// The \c bool value will be false to indicate that the protocol + /// is a Swift protocol, or true to indicate that this references + /// an Objective-C protocol. + RelativeIndirectablePointerIntPair objcPointer; +#endif }; - /// The relative pointer itself. - /// - /// The \c AnyProtocol value type ensures that we can reference any - /// protocol descriptor; it will be reinterpret_cast to the appropriate - /// protocol descriptor type. - /// - /// The \c bool integer value will be false to indicate that the protocol - /// is a Swift protocol, or true to indicate that this references - /// an Objective-C protocol. - RelativeIndirectablePointerIntPair pointer; - #if SWIFT_OBJC_INTEROP bool isObjC() const { - return pointer.getInt(); + return objcPointer.getInt(); } #endif @@ -2269,13 +2324,13 @@ class RelativeTargetProtocolDescriptorPointer { #if SWIFT_OBJC_INTEROP if (isObjC()) { return TargetProtocolDescriptorRef::forObjC( - protocol_const_cast(pointer.getPointer())); + const_cast(objcPointer.getPointer())); } #endif return TargetProtocolDescriptorRef::forSwift( reinterpret_cast>(pointer.getPointer())); + Runtime, TargetProtocolDescriptor>>(swiftPointer.getPointer())); } operator TargetProtocolDescriptorRef() const { @@ -2293,7 +2348,7 @@ struct TargetTypeReference { /// An indirect reference to a TypeContextDescriptor or ProtocolDescriptor. RelativeDirectPointer< - ConstTargetMetadataPointer> + TargetSignedPointer * __ptrauth_swift_type_descriptor>> IndirectTypeDescriptor; /// An indirect reference to an Objective-C class. @@ -2391,7 +2446,7 @@ struct TargetProtocolConformanceDescriptor final private: /// The protocol being conformed to. - RelativeIndirectablePointer Protocol; + TargetRelativeContextPointer Protocol; // Some description of the type that conforms to the protocol. TargetTypeReference TypeRef; @@ -2424,7 +2479,8 @@ struct TargetProtocolConformanceDescriptor final return TypeRef.getTypeDescriptor(getTypeKind()); } - const TargetContextDescriptor **_getTypeDescriptorLocation() const { + TargetContextDescriptor * __ptrauth_swift_type_descriptor * + _getTypeDescriptorLocation() const { if (getTypeKind() != TypeReferenceKind::IndirectTypeDescriptor) return nullptr; return TypeRef.IndirectTypeDescriptor.get(); @@ -2669,7 +2725,7 @@ class TargetGenericRequirementDescriptor { /// The conformance the param is constrained to use. /// /// Only valid if the requirement has SameConformance kind. - RelativeIndirectablePointer, + RelativeIndirectablePointer, /*nullable*/ false> Conformance; /// The kind of layout constraint. @@ -2707,7 +2763,7 @@ class TargetGenericRequirementDescriptor { /// Retrieve the protocol conformance record for a SameConformance /// requirement. - const TargetProtocolConformanceRecord *getConformance() const { + const TargetProtocolConformanceDescriptor *getConformance() const { assert(getKind() == GenericRequirementKind::SameConformance); return Conformance; } @@ -4490,11 +4546,20 @@ struct DynamicReplacementChainEntry { struct DynamicReplacementKey { RelativeDirectPointer root; uint32_t flags; + + uint16_t getExtraDiscriminator() const { + return flags & 0x0000FFFF; + } }; /// A record describing a dynamic function replacement. class DynamicReplacementDescriptor { - RelativeIndirectablePointer replacedFunctionKey; + RelativeIndirectablePointer< + const DynamicReplacementKey, false, int32_t, + TargetSignedPointer> + replacedFunctionKey; RelativeDirectPointer replacementFunction; RelativeDirectPointer chainEntry; uint32_t flags; diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index 6e1cc0356f35e..606c1a007d150 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -19,6 +19,7 @@ #ifndef SWIFT_ABI_METADATAVALUES_H #define SWIFT_ABI_METADATAVALUES_H +#include "swift/ABI/KeyPath.h" #include "swift/AST/Ownership.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/FlagSet.h" @@ -294,6 +295,8 @@ class MethodDescriptorFlags { KindMask = 0x0F, // 16 kinds should be enough for anybody IsInstanceMask = 0x10, IsDynamicMask = 0x20, + ExtraDiscriminatorShift = 16, + ExtraDiscriminatorMask = 0xFFFF0000, }; int_type Value; @@ -320,6 +323,13 @@ class MethodDescriptorFlags { return copy; } + MethodDescriptorFlags withExtraDiscriminator(uint16_t value) const { + auto copy = *this; + copy.Value = (copy.Value & ~ExtraDiscriminatorMask) + | (int_type(value) << ExtraDiscriminatorShift); + return copy; + } + Kind getKind() const { return Kind(Value & KindMask); } /// Is the method marked 'dynamic'? @@ -330,6 +340,10 @@ class MethodDescriptorFlags { /// Note that 'init' is not considered an instance member. bool isInstance() const { return Value & IsInstanceMask; } + uint16_t getExtraDiscriminator() const { + return (Value >> ExtraDiscriminatorShift); + } + int_type getIntValue() const { return Value; } }; @@ -516,6 +530,8 @@ class ProtocolRequirementFlags { enum : int_type { KindMask = 0x0F, // 16 kinds should be enough for anybody IsInstanceMask = 0x10, + ExtraDiscriminatorShift = 16, + ExtraDiscriminatorMask = 0xFFFF0000, }; int_type Value; @@ -533,6 +549,13 @@ class ProtocolRequirementFlags { return copy; } + ProtocolRequirementFlags withExtraDiscriminator(uint16_t value) const { + auto copy = *this; + copy.Value = (copy.Value & ~ExtraDiscriminatorMask) + | (int_type(value) << ExtraDiscriminatorShift); + return copy; + } + Kind getKind() const { return Kind(Value & KindMask); } /// Is the method an instance member? @@ -540,6 +563,14 @@ class ProtocolRequirementFlags { /// Note that 'init' is not considered an instance member. bool isInstance() const { return Value & IsInstanceMask; } + bool isSignedWithAddress() const { + return getKind() != Kind::BaseProtocol; + } + + uint16_t getExtraDiscriminator() const { + return (Value >> ExtraDiscriminatorShift); + } + int_type getIntValue() const { return Value; } enum : uintptr_t { @@ -1029,6 +1060,68 @@ static inline bool isValueWitnessTableMutable(EnumLayoutFlags flags) { return uintptr_t(flags) & uintptr_t(EnumLayoutFlags::IsVWTMutable); } +namespace SpecialPointerAuthDiscriminators { + // All of these values are the stable string hash of the corresponding + // variable name: + // (computeStableStringHash % 65535 + 1) + + /// HeapMetadataHeader::destroy + const uint16_t HeapDestructor = 0xbbbf; + + /// Type descriptor data pointers. + const uint16_t TypeDescriptor = 0xae86; + + /// Runtime function variables exported by the runtime. + const uint16_t RuntimeFunctionEntry = 0x625b; + + /// Value witness functions. + const uint16_t InitializeBufferWithCopyOfBuffer = 0xda4a; + const uint16_t Destroy = 0x04f8; + const uint16_t InitializeWithCopy = 0xe3ba; + const uint16_t AssignWithCopy = 0x8751; + const uint16_t InitializeWithTake = 0x48d8; + const uint16_t AssignWithTake = 0xefda; + const uint16_t DestroyArray = 0x2398; + const uint16_t InitializeArrayWithCopy = 0xa05c; + const uint16_t InitializeArrayWithTakeFrontToBack = 0x1c3e; + const uint16_t InitializeArrayWithTakeBackToFront = 0x8dd3; + const uint16_t StoreExtraInhabitant = 0x79c5; + const uint16_t GetExtraInhabitantIndex = 0x2ca8; + const uint16_t GetEnumTag = 0xa3b5; + const uint16_t DestructiveProjectEnumData = 0x041d; + const uint16_t DestructiveInjectEnumTag = 0xb2e4; + const uint16_t GetEnumTagSinglePayload = 0x60f0; + const uint16_t StoreEnumTagSinglePayload = 0xa0d1; + + /// KeyPath metadata functions. + const uint16_t KeyPathDestroy = _SwiftKeyPath_ptrauth_ArgumentDestroy; + const uint16_t KeyPathCopy = _SwiftKeyPath_ptrauth_ArgumentCopy; + const uint16_t KeyPathEquals = _SwiftKeyPath_ptrauth_ArgumentEquals; + const uint16_t KeyPathHash = _SwiftKeyPath_ptrauth_ArgumentHash; + const uint16_t KeyPathGetter = _SwiftKeyPath_ptrauth_Getter; + const uint16_t KeyPathNonmutatingSetter = _SwiftKeyPath_ptrauth_NonmutatingSetter; + const uint16_t KeyPathMutatingSetter = _SwiftKeyPath_ptrauth_MutatingSetter; + const uint16_t KeyPathGetLayout = _SwiftKeyPath_ptrauth_ArgumentLayout; + const uint16_t KeyPathInitializer = _SwiftKeyPath_ptrauth_ArgumentInit; + const uint16_t KeyPathMetadataAccessor = _SwiftKeyPath_ptrauth_MetadataAccessor; + + /// ObjC bridging entry points. + const uint16_t ObjectiveCTypeDiscriminator = 0x31c3; // = 12739 + const uint16_t bridgeToObjectiveCDiscriminator = 0xbca0; // = 48288 + const uint16_t forceBridgeFromObjectiveCDiscriminator = 0x22fb; // = 8955 + const uint16_t conditionallyBridgeFromObjectiveCDiscriminator = 0x9a9b; // = 39579 + + /// Dynamic replacement pointers. + const uint16_t DynamicReplacementScope = 0x48F0; // = 18672 + const uint16_t DynamicReplacementKey = 0x2C7D; // = 11389 + + /// Resume functions for yield-once coroutines that yield a single + /// opaque borrowed/inout value. These aren't actually hard-coded, but + /// they're important enough to be worth writing in one place. + const uint16_t OpaqueReadResumeFunction = 56769; + const uint16_t OpaqueModifyResumeFunction = 3909; +} + /// The number of arguments that will be passed directly to a generic /// nominal type access function. The remaining arguments (if any) will be /// passed as an array. That array has enough storage for all of the arguments, diff --git a/include/swift/AST/ASTVisitor.h b/include/swift/AST/ASTVisitor.h index baac1b6a7ba07..7933933142f28 100644 --- a/include/swift/AST/ASTVisitor.h +++ b/include/swift/AST/ASTVisitor.h @@ -127,10 +127,6 @@ class ASTVisitor { llvm_unreachable("Not reachable, all cases handled"); } - TypeReprRetTy visitTypeRepr(TypeRepr *T, Args... AA) { - return TypeReprRetTy(); - } - #define TYPEREPR(CLASS, PARENT) \ TypeReprRetTy visit##CLASS##TypeRepr(CLASS##TypeRepr *T, Args... AA) {\ return static_cast(this)->visit##PARENT(T, \ diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 6925fd42d7703..60b2f7739a7a5 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -657,6 +657,9 @@ BUILTIN_MISC_OPERATION(WillThrow, "willThrow", "", Special) /// poundAssert has type (Builtin.Int1, Builtin.RawPointer) -> (). BUILTIN_MISC_OPERATION(PoundAssert, "poundAssert", "", Special) +// TypePtrAuthDiscriminator has type (T.Type) -> Int64 +BUILTIN_MISC_OPERATION(TypePtrAuthDiscriminator, "typePtrAuthDiscriminator", "n", Special) + // BUILTIN_MISC_OPERATION_WITH_SILGEN - Miscellaneous operations that are // specially emitted during SIL generation. // diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index d9630eaf6d9e0..bf67f039719e1 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -828,6 +828,14 @@ ERROR(sil_function_subst_expected_l_angle,none, "expected '<' to begin SIL function type substitution list after 'for'", ()) ERROR(sil_function_subst_expected_r_angle,none, "expected '>' to end SIL function type substitution list after 'for <...'", ()) +ERROR(sil_function_subst_expected_generics,none, + "expected '<' to begin substituted parameter list after '@substituted'", ()) +ERROR(sil_function_subst_expected_function,none, + "expected function type after '@substituted'", ()) +ERROR(sil_function_subst_expected_subs,none, + "expected 'for' to begin substitutions after '@substituted' function type", ()) +ERROR(sil_function_subs_without_generics,none, + "unexpected 'for' to begin substitutions after non-generic function type", ()) // Opaque types ERROR(opaque_mid_composition,none, diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index d4c34b5859b0f..65f6aadf3248b 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -536,6 +536,9 @@ ERROR(oslog_property_not_constant, none, "'OSLogInterpolation.%0' is not a " ERROR(oslog_message_alive_after_opts, none, "OSLogMessage instance must not " "be explicitly created and must be deletable", ()) +WARNING(oslog_call_in_unreachable_code, none, "os log call will never be " + "executed and may have undiagnosed errors", ()) + ERROR(global_string_pointer_on_non_constant, none, "globalStringTablePointer " "builtin must used only on string literals", ()) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index e8bca6bd79ce7..8236b5fa58873 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -577,9 +577,6 @@ ERROR(expr_swift_keypath_invalid_component,none, "invalid component of Swift key path", ()) ERROR(expr_swift_keypath_not_starting_with_type,none, "a Swift key path must begin with a type", ()) -ERROR(expr_swift_keypath_not_starting_with_dot,none, - "a Swift key path with contextual root must begin with a leading dot", - ()) ERROR(expr_smart_keypath_value_covert_to_contextual_type,none, "key path value type %0 cannot be converted to contextual type %1", (Type, Type)) @@ -1973,8 +1970,8 @@ WARNING(protocol_usable_from_inline_warn,none, "protocol %select{refined|used}0 by '@usableFromInline' protocol " "should be '@usableForInline' or public", (bool)) ERROR(protocol_property_must_be_computed_var,none, - "immutable property requirement must be declared as 'var' with a " - "'{ get }' specifier", ()) + "protocols cannot require properties to be immutable; declare read-only " + "properties by using 'var' with a '{ get }' specifier", ()) ERROR(protocol_property_must_be_computed,none, "property in protocol must have explicit { get } or { get set } specifier", ()) @@ -4019,6 +4016,8 @@ ERROR(sil_non_coro_yields,PointsToFirstBadToken, ERROR(sil_function_repeat_convention,PointsToFirstBadToken, "repeated %select{parameter|result|callee}0 convention attribute", (unsigned)) +ERROR(ast_subst_function_type,none, + "substitutions cannot be provided on a formal function type", ()) ERROR(sil_function_multiple_error_results,PointsToFirstBadToken, "SIL function types cannot have multiple @error results", ()) ERROR(unsupported_sil_convention,none, diff --git a/include/swift/AST/EducationalNotes.def b/include/swift/AST/EducationalNotes.def index d609013474514..745302b8177ed 100644 --- a/include/swift/AST/EducationalNotes.def +++ b/include/swift/AST/EducationalNotes.def @@ -21,6 +21,9 @@ // EDUCATIONAL_NOTES(DIAG_ID, EDUCATIONAL_NOTE_FILENAMES...) +EDUCATIONAL_NOTES(unsupported_existential_type, + "associated-type-requirements.md") + EDUCATIONAL_NOTES(non_nominal_no_initializers, "nominal-types.md") EDUCATIONAL_NOTES(non_nominal_extension, "nominal-types.md") EDUCATIONAL_NOTES(associated_type_witness_conform_impossible, diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 1ada3d32d0708..d18d5c94ab009 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -23,6 +23,7 @@ #include "swift/Basic/Sanitizers.h" #include "swift/Basic/OptionSet.h" #include "swift/Basic/OptimizationMode.h" +#include "clang/Basic/PointerAuthOptions.h" // FIXME: This include is just for llvm::SanitizerCoverageOptions. We should // split the header upstream so we don't include so much. #include "llvm/Transforms/Instrumentation.h" @@ -70,6 +71,59 @@ enum class IRGenEmbedMode : unsigned { EmbedBitcode }; +using clang::PointerAuthSchema; + +struct PointerAuthOptions : clang::PointerAuthOptions { + /// Native opaque function types, both thin and thick. + /// Never address-sensitive. + PointerAuthSchema SwiftFunctionPointers; + + /// Swift key path helpers. + PointerAuthSchema KeyPaths; + + /// Swift value witness functions. + PointerAuthSchema ValueWitnesses; + + /// Swift protocol witness functions. + PointerAuthSchema ProtocolWitnesses; + + /// Swift protocol witness table associated type metadata access functions. + PointerAuthSchema ProtocolAssociatedTypeAccessFunctions; + + /// Swift protocol witness table associated conformance witness table + /// access functions. + PointerAuthSchema ProtocolAssociatedTypeWitnessTableAccessFunctions; + + /// Swift class v-table functions. + PointerAuthSchema SwiftClassMethods; + + /// Swift dynamic replacement implementations. + PointerAuthSchema SwiftDynamicReplacements; + PointerAuthSchema SwiftDynamicReplacementKeys; + + /// Swift class v-table functions not signed with an address. This is the + /// return type of swift_lookUpClassMethod(). + PointerAuthSchema SwiftClassMethodPointers; + + /// Swift heap metadata destructors. + PointerAuthSchema HeapDestructors; + + /// Non-constant function pointers captured in a partial-apply context. + PointerAuthSchema PartialApplyCapture; + + /// Type descriptor data pointers. + PointerAuthSchema TypeDescriptors; + + /// Type descriptor data pointers when passed as arguments. + PointerAuthSchema TypeDescriptorsAsArguments; + + /// Resumption functions from yield-once coroutines. + PointerAuthSchema YieldOnceResumeFunctions; + + /// Resumption functions from yield-many coroutines. + PointerAuthSchema YieldManyResumeFunctions; +}; + /// The set of options supported by IR generation. class IRGenOptions { public: @@ -236,6 +290,9 @@ class IRGenOptions { /// Which sanitizer coverage is turned on. llvm::SanitizerCoverageOptions SanitizeCoverage; + /// Pointer authentication. + PointerAuthOptions PointerAuth; + /// The different modes for dumping IRGen type info. enum class TypeInfoDumpFilter { All, diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 307fb1b7289b1..8af23bb8edcd5 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -35,7 +35,9 @@ IDENTIFIER(buildBlock) IDENTIFIER(buildDo) IDENTIFIER(buildEither) IDENTIFIER(buildExpression) +IDENTIFIER(buildFinalResult) IDENTIFIER(buildIf) +IDENTIFIER(buildOptional) IDENTIFIER(callAsFunction) IDENTIFIER(Change) IDENTIFIER_WITH_NAME(code_, "_code") diff --git a/include/swift/AST/PlatformConditionKinds.def b/include/swift/AST/PlatformConditionKinds.def index d83914a16e5b2..147e74359ff2a 100644 --- a/include/swift/AST/PlatformConditionKinds.def +++ b/include/swift/AST/PlatformConditionKinds.def @@ -40,5 +40,8 @@ PLATFORM_CONDITION(CanImport, "canImport") /// Target Environment (currently just 'simulator' or absent) PLATFORM_CONDITION(TargetEnvironment, "targetEnvironment") +/// Pointer authentication enabled +PLATFORM_CONDITION_(PtrAuth, "ptrauth") + #undef PLATFORM_CONDITION #undef PLATFORM_CONDITION_ diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 530f3443a3ea5..74ea81959e15c 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1999,6 +1999,29 @@ class HasDynamicMemberLookupAttributeRequest } }; +/// Computes whether the specified type or a super-class/super-protocol has the +/// @dynamicCallable attribute on it. +class HasDynamicCallableAttributeRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, CanType ty) const; + +public: + bool isCached() const { + // Don't cache types containing type variables, as they must not outlive + // the constraint system that created them. + auto ty = std::get<0>(getStorage()); + return !ty->hasTypeVariable(); + } +}; + /// Determines the type of a given pattern. /// /// Note that this returns the "raw" pattern type, which can involve diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 11c47193ae626..5e425bff57100 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -81,6 +81,8 @@ SWIFT_REQUEST(TypeChecker, HasCircularRawValueRequest, bool(EnumDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, HasDynamicMemberLookupAttributeRequest, bool(CanType), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, HasDynamicCallableAttributeRequest, + bool(CanType), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest, GenericSignature (ModuleDecl *, GenericSignatureImpl *, GenericParamSource, diff --git a/include/swift/AST/TypeDifferenceVisitor.h b/include/swift/AST/TypeDifferenceVisitor.h new file mode 100644 index 0000000000000..3492c33151e46 --- /dev/null +++ b/include/swift/AST/TypeDifferenceVisitor.h @@ -0,0 +1,391 @@ +//===--- TypeDifferenceVisitor.h - Visitor for pairs of types ---*- 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 TypeDifferenceVisitor, a visitor which finds +// differences between canonical types. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_TYPEDIFFERENCEVISITOR_H +#define SWIFT_AST_TYPEDIFFERENCEVISITOR_H + +#include "swift/AST/SILLayout.h" +#include "swift/AST/Types.h" + +namespace swift { + +// TODO: maybe have a version of this that works on non-canonical types + +template +class CanTypePairVisitor { +public: + // Provide default implementations that chain to the base class. +#define ABSTRACT_TYPE(CLASS, PARENT) \ + RetTy visit##CLASS##Type(Can##CLASS##Type type1, \ + Can##CLASS##Type type2, \ + Args... args) { \ + return static_cast(*this) \ + .visit##PARENT(type1, type2, std::forward(args)...); \ + } +#define TYPE(CLASS, PARENT) ABSTRACT_TYPE(CLASS, PARENT) +#define ABSTRACT_SUGARED_TYPE(CLASS, PARENT) +#define SUGARED_TYPE(CLASS, PARENT) + // Don't allow unchecked types by default, but allow visitors to opt-in to + // handling them. +#define UNCHECKED_TYPE(CLASS, PARENT) \ + RetTy visit##CLASS##Type(Can##CLASS##Type type1, \ + Can##CLASS##Type type2, \ + Args... args) { \ + llvm_unreachable("unchecked type"); \ + } +#include "swift/AST/TypeNodes.def" +}; + +/// A CRTP class for finding differences between types. +/// +/// The visitors all short-circuit as soon as one returns true. +/// +/// visitDifferentTypes() +template +class CanTypeDifferenceVisitor : public CanTypePairVisitor { +protected: + Impl &asImpl() { return static_cast(*this); } +public: + /// Two component types differ. + bool visitDifferentComponentTypes(CanType type1, CanType type2) { + asImpl().visitDifferentTypes(type1, type2); + + // Short-circuit by default. + return true; + } + + /// Two types differ in non-type structure, like a convention or a label. + /// Generally, you can't usefully recover when this is called; it always + /// needs to return true. + bool visitDifferentTypeStructure(CanType type1, CanType type2) { + asImpl().visitDifferentTypes(type1, type2); + return true; + } + + /// Inform the subclass that a difference was detected. + void visitDifferentTypes(CanType type1, CanType type2) {} + + bool visit(CanType type1, CanType type2) { + if (type1 == type2) + return false; + + if (type1->getKind() != type2->getKind()) + return asImpl().visitDifferentComponentTypes(type1, type2); + + switch (type1->getKind()) { +#define SUGARED_TYPE(CLASS, PARENT) \ + case TypeKind::CLASS: +#define TYPE(CLASS, PARENT) +#include "swift/AST/TypeNodes.def" + llvm_unreachable("non-canonical type"); + +#define SUGARED_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) \ + case TypeKind::CLASS: \ + return asImpl().visit##CLASS##Type(cast(type1), \ + cast(type2)); +#include "swift/AST/TypeNodes.def" + } + llvm_unreachable("Not reachable, all cases handled"); + } + + // In the type-specific visitors, we know that we have + // non-identical types. + + // These types are singleton and can't actually differ. +#define SINGLETON_TYPE(TYPE) \ + bool visit##TYPE(Can##TYPE type1, Can##TYPE type2) { \ + llvm_unreachable("singleton type that wasn't identical"); \ + } + SINGLETON_TYPE(BuiltinIntegerLiteralType) + SINGLETON_TYPE(BuiltinRawPointerType) + SINGLETON_TYPE(BuiltinNativeObjectType) + SINGLETON_TYPE(BuiltinBridgeObjectType) + SINGLETON_TYPE(BuiltinUnsafeValueBufferType) + SINGLETON_TYPE(SILTokenType) +#undef SINGLETON_TYPE + + bool visitBuiltinIntegerType(CanBuiltinIntegerType type1, + CanBuiltinIntegerType type2) { + return asImpl().visitDifferentTypeStructure(type1, type2); + } + + bool visitBuiltinFloatType(CanBuiltinFloatType type1, + CanBuiltinFloatType type2) { + return asImpl().visitDifferentTypeStructure(type1, type2); + } + + bool visitBuiltinVectorType(CanBuiltinVectorType type1, + CanBuiltinVectorType type2) { + if (type1->getNumElements() != type2->getNumElements()) + return asImpl().visitDifferentTypeStructure(type1, type2); + return asImpl().visit(type1.getElementType(), type2.getElementType()); + } + + bool visitTupleType(CanTupleType type1, CanTupleType type2) { + return visitComponentArray(type1, type2, + type1->getElements(), type2->getElements()); + } + + bool visitComponent(CanType type1, CanType type2, + const TupleTypeElt &elt1, const TupleTypeElt &elt2) { + if (elt1.getName() != elt2.getName()) + return asImpl().visitDifferentTypeStructure(type1, type2); + return asImpl().visit(CanType(elt1.getType()), CanType(elt2.getType())); + } + + bool visitReferenceStorageType(CanReferenceStorageType type1, + CanReferenceStorageType type2) { + return asImpl().visit(type1.getReferentType(), type2.getReferentType()); + } + + bool visitUnboundGenericType(CanUnboundGenericType type1, + CanUnboundGenericType type2) { + assert(type1->getDecl() != type2->getDecl()); + return asImpl().visitDifferentTypeStructure(type1, type2); + } + + bool visitNominalType(CanNominalType type1, CanNominalType type2) { + assert(type1->getDecl() != type2->getDecl()); + return asImpl().visitDifferentTypeStructure(type1, type2); + } + + bool visitBoundGenericType(CanBoundGenericType type1, + CanBoundGenericType type2) { + if (type1->getDecl() != type2->getDecl()) + return asImpl().visitDifferentTypeStructure(type1, type2); + + return visitComponentArray(type1, type2, + type1.getGenericArgs(), type2.getGenericArgs()); + } + + bool visitAnyMetatypeType(CanAnyMetatypeType type1, + CanAnyMetatypeType type2) { + if (type1->hasRepresentation() != type2->hasRepresentation() || + (type1->hasRepresentation() && + type1->getRepresentation() != type2->getRepresentation())) + return asImpl().visitDifferentTypeStructure(type1, type2); + + return asImpl().visit(type1.getInstanceType(), type2.getInstanceType()); + } + + bool visitModuleType(CanModuleType type1, CanModuleType type2) { + return asImpl().visitDifferentTypeStructure(type1, type2); + } + + bool visitDynamicSelfType(CanDynamicSelfType type1, + CanDynamicSelfType type2) { + return asImpl().visit(type1.getSelfType(), type2.getSelfType()); + } + + bool visitSubstitutableType(CanSubstitutableType type1, + CanSubstitutableType type2) { + return asImpl().visitDifferentComponentTypes(type1, type2); + } + + bool visitDependentMemberType(CanDependentMemberType type1, + CanDependentMemberType type2) { + if (type1->getName() != type2->getName()) + return asImpl().visitDifferentTypeStructure(type1, type2); + return asImpl().visit(type1.getBase(), type2.getBase()); + } + + bool visitGenericFunctionType(CanGenericFunctionType type1, + CanGenericFunctionType type2) { + if (type1.getGenericSignature() != type2.getGenericSignature()) + return asImpl().visitDifferentTypeStructure(type1, type2); + + return asImpl().visitAnyFunctionType(type1, type2); + } + + bool visitAnyFunctionType(CanAnyFunctionType type1, + CanAnyFunctionType type2) { + if (type1->getExtInfo() != type2->getExtInfo()) + return asImpl().visitDifferentTypeStructure(type1, type2); + + if (asImpl().visit(type1.getResult(), type2.getResult())) + return true; + + return visitComponentArray(type1, type2, + type1.getParams(), type2.getParams()); + } + + bool visitComponent(CanType type1, CanType type2, + AnyFunctionType::CanParam param1, + AnyFunctionType::CanParam param2) { + if (param1.getLabel() != param2.getLabel() || + param1.getParameterFlags() != param2.getParameterFlags()) + return asImpl().visitDifferentTypeStructure(type1, type2); + return asImpl().visit(param1.getPlainType(), param2.getPlainType()); + } + + bool visitSILFunctionType(CanSILFunctionType type1, + CanSILFunctionType type2) { + return (asImpl().visitSILFunctionTypeStructure(type1, type2) || + asImpl().visitSILFunctionTypeSubstitutions(type1, type2) || + asImpl().visitSILFunctionTypeComponents(type1, type2)); + } + + bool visitSILFunctionTypeStructure(CanSILFunctionType type1, + CanSILFunctionType type2) { + if (type1->getExtInfo() != type2->getExtInfo() || + type1->getCoroutineKind() != type2->getCoroutineKind() || + type1->getInvocationGenericSignature() + != type2->getInvocationGenericSignature()) + return asImpl().visitDifferentTypeStructure(type1, type2); + return false; + } + + bool visitSILFunctionTypeSubstitutions(CanSILFunctionType type1, + CanSILFunctionType type2) { + return asImpl().visitOptSubstitutionMap(type1, type2, + type1->getPatternSubstitutions(), + type2->getPatternSubstitutions()) + || asImpl().visitOptSubstitutionMap(type1, type2, + type1->getInvocationSubstitutions(), + type2->getInvocationSubstitutions()); + } + + bool visitSILFunctionTypeComponents(CanSILFunctionType type1, + CanSILFunctionType type2) { + return visitComponentArray(type1, type2, + type1->getParameters(), type2->getParameters()) + || visitComponentArray(type1, type2, + type1->getResults(), type2->getResults()) + || visitComponentArray(type1, type2, + type1->getYields(), type2->getYields()); + } + + bool visitComponent(CanType type1, CanType type2, + SILParameterInfo param1, SILParameterInfo param2) { + if (param1.getConvention() != param2.getConvention() || + param1.getDifferentiability() != param2.getDifferentiability()) + return asImpl().visitDifferentTypeStructure(type1, type2); + + return asImpl().visit(param1.getInterfaceType(), + param2.getInterfaceType()); + } + + bool visitComponent(CanType type1, CanType type2, + SILResultInfo result1, SILResultInfo result2) { + if (result1.getConvention() != result2.getConvention()) + return asImpl().visitDifferentTypeStructure(type1, type2); + + return asImpl().visit(result1.getInterfaceType(), + result2.getInterfaceType()); + } + + bool visitComponent(CanType type1, CanType type2, + SILYieldInfo yield1, SILYieldInfo yield2) { + if (yield1.getConvention() != yield2.getConvention()) + return asImpl().visitDifferentTypeStructure(type1, type2); + + return asImpl().visit(yield1.getInterfaceType(), + yield2.getInterfaceType()); + } + + bool visitSILBoxType(CanSILBoxType type1, CanSILBoxType type2) { + return (asImpl().visitSILLayout(type1, type2, + type1->getLayout(), type2->getLayout()) || + asImpl().visitOptSubstitutionMap(type1, type2, + type1->getSubstitutions(), + type2->getSubstitutions())); + } + + bool visitSILLayout(CanType type1, CanType type2, + SILLayout *layout1, SILLayout *layout2) { + if (layout1->getGenericSignature() != layout2->getGenericSignature() || + layout1->isMutable() != layout2->isMutable()) + return asImpl().visitDifferentTypeStructure(type1, type2); + + return visitComponentArray(type1, type2, + layout1->getFields(), layout2->getFields()); + } + + bool visitComponent(CanType type1, CanType type2, + const SILField &field1, const SILField &field2) { + if (field1.isMutable() != field2.isMutable()) + return asImpl().visitDifferentTypeStructure(type1, type2); + return asImpl().visit(field1.getLoweredType(), field2.getLoweredType()); + } + + bool visitSILBlockStorageType(CanSILBlockStorageType type1, + CanSILBlockStorageType type2) { + return asImpl().visit(type1->getCaptureType(), type2->getCaptureType()); + } + + bool visitProtocolCompositionType(CanProtocolCompositionType type1, + CanProtocolCompositionType type2) { + return visitComponentArray(type1, type2, + type1->getMembers(), type2->getMembers()); + } + + bool visitLValueType(CanLValueType type1, CanLValueType type2) { + return asImpl().visit(type1.getObjectType(), type2.getObjectType()); + } + + bool visitInOutType(CanInOutType type1, CanInOutType type2) { + return asImpl().visit(type1.getObjectType(), type2.getObjectType()); + } + + bool visitErrorType(CanErrorType type1, CanErrorType type2) { + return false; + } + + bool visitOptSubstitutionMap(CanType type1, CanType type2, + SubstitutionMap subs1, SubstitutionMap subs2) { + if ((bool) subs1 != (bool) subs2) + return asImpl().visitDifferentTypeStructure(type1, type2); + if (subs1) + return asImpl().visitSubstitutionMap(type1, type2, subs1, subs2); + return false; + } + + bool visitSubstitutionMap(CanType type1, CanType type2, + SubstitutionMap subs1, SubstitutionMap subs2) { + if (CanGenericSignature(subs1.getGenericSignature()) + != CanGenericSignature(subs2.getGenericSignature())) + return asImpl().visitDifferentTypeStructure(type1, type2); + + return visitComponentArray(type1, type2, + subs1.getReplacementTypes(), + subs2.getReplacementTypes()); + } + +private: + bool visitComponent(CanType type1, CanType type2, + Type componentType1, Type componentType2) { + return asImpl().visit(CanType(componentType1), CanType(componentType2)); + } + + template + bool visitComponentArray(CanType type1, CanType type2, T array1, T array2) { + if (array1.size() != array2.size()) + return asImpl().visitDifferentTypeStructure(type1, type2); + + for (auto i : indices(array1)) { + if (asImpl().visitComponent(type1, type2, array1[i], array2[i])) + return true; + } + + return false; + } +}; + +} + +#endif \ No newline at end of file diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 56e4995aad08c..d72b3290e4765 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -472,12 +472,15 @@ inline IdentTypeRepr::ComponentRange IdentTypeRepr::getComponentRange() { /// (x: Foo, y: Bar) -> Baz /// \endcode class FunctionTypeRepr : public TypeRepr { - // These fields are only used in SIL mode, which is the only time - // we can have polymorphic and substituted function values. + // The generic params / environment / substitutions fields are only used + // in SIL mode, which is the only time we can have polymorphic and + // substituted function values. GenericParamList *GenericParams; GenericEnvironment *GenericEnv; - bool GenericParamsAreImplied; - ArrayRef GenericSubs; + ArrayRef InvocationSubs; + GenericParamList *PatternGenericParams; + GenericEnvironment *PatternGenericEnv; + ArrayRef PatternSubs; TupleTypeRepr *ArgsTy; TypeRepr *RetTy; @@ -487,21 +490,37 @@ class FunctionTypeRepr : public TypeRepr { public: FunctionTypeRepr(GenericParamList *genericParams, TupleTypeRepr *argsTy, SourceLoc throwsLoc, SourceLoc arrowLoc, TypeRepr *retTy, - bool GenericParamsAreImplied = false, - ArrayRef GenericSubs = {}) + GenericParamList *patternGenericParams = nullptr, + ArrayRef patternSubs = {}, + ArrayRef invocationSubs = {}) : TypeRepr(TypeReprKind::Function), - GenericParams(genericParams), - GenericEnv(nullptr), - GenericParamsAreImplied(GenericParamsAreImplied), - GenericSubs(GenericSubs), + GenericParams(genericParams), GenericEnv(nullptr), + InvocationSubs(invocationSubs), + PatternGenericParams(patternGenericParams), PatternGenericEnv(nullptr), + PatternSubs(patternSubs), ArgsTy(argsTy), RetTy(retTy), ArrowLoc(arrowLoc), ThrowsLoc(throwsLoc) { } GenericParamList *getGenericParams() const { return GenericParams; } GenericEnvironment *getGenericEnvironment() const { return GenericEnv; } - bool areGenericParamsImplied() const { return GenericParamsAreImplied; } - ArrayRef getSubstitutions() const { return GenericSubs; } + + GenericParamList *getPatternGenericParams() const { + return PatternGenericParams; + } + GenericEnvironment *getPatternGenericEnvironment() const { + return PatternGenericEnv; + } + + ArrayRef getPatternSubstitutions() const { return PatternSubs; } + ArrayRef getInvocationSubstitutions() const { + return InvocationSubs; + } + + void setPatternGenericEnvironment(GenericEnvironment *genericEnv) { + assert(PatternGenericEnv == nullptr); + PatternGenericEnv = genericEnv; + } void setGenericEnvironment(GenericEnvironment *genericEnv) { assert(GenericEnv == nullptr); diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 32769d030acfd..7b145879fd9f4 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -363,12 +363,14 @@ class alignas(1 << TypeAlignInBits) TypeBase { ID : 32 ); - SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+2, + SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+2+1+1, ExtInfoBits : NumSILExtInfoBits, HasUncommonInfo : 1, CalleeConvention : 3, HasErrorResult : 1, - CoroutineKind : 2 + CoroutineKind : 2, + HasInvocationSubs : 1, + HasPatternSubs : 1 ); SWIFT_INLINE_BITFIELD(AnyMetatypeType, TypeBase, 2, @@ -836,6 +838,10 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// Return true if the specified type or a super-class/super-protocol has the /// @dynamicMemberLookup attribute on it. bool hasDynamicMemberLookupAttribute(); + + /// Return true if the specified type or a super-class/super-protocol has the + /// @dynamicCallable attribute on it. + bool hasDynamicCallableAttribute(); /// Retrieve the superclass of this type. /// @@ -3832,6 +3838,11 @@ class SILParameterInfo { return SILParameterInfo(type, getConvention(), getDifferentiability()); } + /// Return a version of this parameter info with the convention replaced. + SILParameterInfo getWithConvention(ParameterConvention c) const { + return SILParameterInfo(getInterfaceType(), c, getDifferentiability()); + } + /// Transform this SILParameterInfo by applying the user-provided /// function to its type. /// @@ -3842,6 +3853,20 @@ class SILParameterInfo { return getWithInterfaceType(fn(getInterfaceType())); } + SILParameterInfo mapTypeOutOfContext() const { + return getWithInterfaceType(getInterfaceType()->mapTypeOutOfContext() + ->getCanonicalType()); + } + + /// Treating this parameter info as a component of the given function + /// type, apply any substitutions from the function type to it to + /// get a substituted version of it, as you would get from + /// SILFunctionType::getUnsubstitutedType. + SILParameterInfo getUnsubstituted(SILModule &M, + const SILFunctionType *fnType) const { + return getWithInterfaceType(getArgumentType(M, fnType)); + } + void profile(llvm::FoldingSetNodeID &id) { id.AddPointer(getInterfaceType().getPointer()); id.AddInteger((unsigned)getConvention()); @@ -3944,6 +3969,11 @@ class SILResultInfo { return SILResultInfo(type, getConvention()); } + /// Return a version of this result info with the convention replaced. + SILResultInfo getWithConvention(ResultConvention c) const { + return SILResultInfo(getInterfaceType(), c); + } + // Does this result convention require indirect storage? This reflects a // SILFunctionType's formal (immutable) conventions, as opposed to the // transient SIL conventions that dictate SILValue types. @@ -3964,6 +3994,20 @@ class SILResultInfo { return getWithInterfaceType(fn(getInterfaceType())); } + SILResultInfo mapTypeOutOfContext() const { + return getWithInterfaceType(getInterfaceType()->mapTypeOutOfContext() + ->getCanonicalType()); + } + + /// Treating this result info as a component of the given function + /// type, apply any substitutions from the function type to it to + /// get a substituted version of it, as you would get from + /// SILFunctionType::getUnsubstitutedType. + SILResultInfo getUnsubstituted(SILModule &M, + const SILFunctionType *fnType) const { + return getWithInterfaceType(getReturnValueType(M, fnType)); + } + void profile(llvm::FoldingSetNodeID &id) { id.AddPointer(TypeAndConvention.getOpaqueValue()); } @@ -4004,10 +4048,34 @@ class SILYieldInfo : public SILParameterInfo { return SILYieldInfo(type, getConvention()); } + /// Return a version of this yield info with the convention replaced. + SILYieldInfo getWithConvention(YieldConvention c) const { + return SILYieldInfo(getInterfaceType(), c); + } + template SILYieldInfo map(const F &fn) const { return getWithInterfaceType(fn(getInterfaceType())); } + + SILYieldInfo mapTypeOutOfContext() const { + return getWithInterfaceType(getInterfaceType()->mapTypeOutOfContext() + ->getCanonicalType()); + } + + CanType getYieldValueType(SILModule &M, + const SILFunctionType *fnType) const { + return getArgumentType(M, fnType); + } + + /// Treating this yield info as a component of the given function + /// type, apply any substitutions from the function type to it to + /// get a substituted version of it, as you would get from + /// SILFunctionType::getUnsubstitutedType. + SILYieldInfo getUnsubstituted(SILModule &M, + const SILFunctionType *fnType) const { + return getWithInterfaceType(getYieldValueType(M, fnType)); + } }; /// SILCoroutineKind - What kind of coroutine is this SILFunction? @@ -4046,7 +4114,8 @@ namespace Lowering { /// function parameter and result types. class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, private llvm::TrailingObjects { + SILResultInfo, SILYieldInfo, + SubstitutionMap, CanType> { friend TrailingObjects; size_t numTrailingObjects(OverloadToken) const { @@ -4065,6 +4134,11 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return hasResultCache() ? 2 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return size_t(hasPatternSubstitutions()) + + size_t(hasInvocationSubstitutions()); + } + public: using Language = SILFunctionLanguage; using Representation = SILFunctionTypeRepresentation; @@ -4249,12 +4323,12 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, // SILResultInfo[isCoroutine() ? 0 : NumAnyResults] // SILResultInfo? // if hasErrorResult() // SILYieldInfo[isCoroutine() ? NumAnyResults : 0] + // SubstitutionMap[HasPatternSubs + HasInvocationSubs] // CanType? // if !isCoro && NumAnyResults > 1, formal result cache // CanType? // if !isCoro && NumAnyResults > 1, all result cache - llvm::PointerIntPair GenericSigAndIsImplied; + CanGenericSignature InvocationGenericSig; ProtocolConformanceRef WitnessMethodConformance; - SubstitutionMap Substitutions; MutableArrayRef getMutableParameters() { return {getTrailingObjects(), NumParameters}; @@ -4273,6 +4347,17 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return *(getTrailingObjects() + getNumResults()); } + SubstitutionMap &getMutablePatternSubs() { + assert(hasPatternSubstitutions()); + return *getTrailingObjects(); + } + + SubstitutionMap &getMutableInvocationSubs() { + assert(hasInvocationSubstitutions()); + return *(getTrailingObjects() + + unsigned(hasPatternSubstitutions())); + } + /// Do we have slots for caches of the normal-result tuple type? bool hasResultCache() const { return NumAnyResults > 1 && !isCoroutine(); @@ -4296,7 +4381,8 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, ArrayRef yieldResults, ArrayRef normalResults, Optional errorResult, - SubstitutionMap substitutions, bool genericSigIsImplied, + SubstitutionMap patternSubs, + SubstitutionMap invocationSubs, const ASTContext &ctx, RecursiveTypeProperties properties, ProtocolConformanceRef witnessMethodConformance); @@ -4308,7 +4394,7 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, ArrayRef interfaceYields, ArrayRef interfaceResults, Optional interfaceErrorResult, - SubstitutionMap substitutions, bool genericSigIsImplied, + SubstitutionMap patternSubs, SubstitutionMap invocationSubs, const ASTContext &ctx, ProtocolConformanceRef witnessMethodConformance = ProtocolConformanceRef()); @@ -4500,28 +4586,93 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, return llvm::count_if(getParameters(), IndirectMutatingParameterFilter()); } - /// Get the generic signature used to apply the substitutions of a substituted function type + /// Get the generic signature that the component types are specified + /// in terms of, if any. CanGenericSignature getSubstGenericSignature() const { - return GenericSigAndIsImplied.getPointer(); + if (hasPatternSubstitutions()) + return getPatternGenericSignature(); + return getInvocationGenericSignature(); + } + + /// Return the combined substitutions that need to be applied to the + /// component types to render their expected types in the context. + SubstitutionMap getCombinedSubstitutions() const { + if (hasPatternSubstitutions()) { + auto subs = getPatternSubstitutions(); + if (hasInvocationSubstitutions()) + subs = subs.subst(getInvocationSubstitutions()); + return subs; + } + return getInvocationSubstitutions(); } + /// Get the generic signature used by callers to invoke the function. CanGenericSignature getInvocationGenericSignature() const { - if (isGenericSignatureImplied()) { - return CanGenericSignature(); - } else { - return getSubstGenericSignature(); - } + return InvocationGenericSig; } - - bool isGenericSignatureImplied() const { - return GenericSigAndIsImplied.getInt(); + + bool hasInvocationSubstitutions() const { + return Bits.SILFunctionType.HasInvocationSubs; } - SubstitutionMap getSubstitutions() const { - return Substitutions; + + /// Return the invocation substitutions. The presence of invocation + /// substitutions means that this is an applied or contextualized generic + /// function type. + SubstitutionMap getInvocationSubstitutions() const { + return hasInvocationSubstitutions() + ? const_cast(this)->getMutableInvocationSubs() + : SubstitutionMap(); + } + + bool hasPatternSubstitutions() const { + return Bits.SILFunctionType.HasPatternSubs; + } + + /// Return the generic signature which expresses the fine-grained + /// abstraction of this function. See the explanation for + /// `getPatternSubstitutions`. + /// + /// The exact structure of this signature is an implementation detail + /// for many function types, and tools must be careful not to expose + /// it in ways that must be kept stable. For example, ptrauth + /// discrimination does not distinguish between different generic + /// parameter types in this signature. + CanGenericSignature getPatternGenericSignature() const { + return hasPatternSubstitutions() + ? CanGenericSignature( + getPatternSubstitutions().getGenericSignature()) + : CanGenericSignature(); + } + + /// Return the "pattern" substitutions. The presence of pattern + /// substitutions means that the component types of this type are + /// abstracted in some additional way. + /// + /// For example, in the function: + /// + /// ``` + /// func consume(producer: () -> T) + /// ``` + /// + /// the argument function `producer` is abstracted differently from + /// a function of type `() -> Int`, even when `T` is concretely `Int`. + /// + /// Similarly, a protocol witness function that returns an `Int` might + /// return it differently if original requirement is abstract about its + /// return type. + /// + /// The most important abstraction differences are accounted for in + /// the structure and conventions of the function's component types, + /// but more subtle differences, like ptrauth discrimination, may + /// require more precise information. + SubstitutionMap getPatternSubstitutions() const { + return hasPatternSubstitutions() + ? const_cast(this)->getMutablePatternSubs() + : SubstitutionMap(); } bool isPolymorphic() const { - return !getInvocationGenericSignature().isNull(); + return getInvocationGenericSignature() && !getInvocationSubstitutions(); } CanType getSelfInstanceType(SILModule &M) const; @@ -4723,9 +4874,29 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, bool isNoReturnFunction(SILModule &M) const; // Defined in SILType.cpp - /// Create a SILFunctionType with the same parameters, results, and attributes as this one, but with - /// a different set of substitutions. - CanSILFunctionType withSubstitutions(SubstitutionMap subs) const; + /// Create a SILFunctionType with the same structure as this one, + /// but with a different (or new) set of invocation substitutions. + /// The substitutions must have the same generic signature as this. + CanSILFunctionType + withInvocationSubstitutions(SubstitutionMap subs) const; + + /// Create a SILFunctionType with the same structure as this one, + /// but with a different set of pattern substitutions. + /// This type must already have pattern substitutions, and they + /// must have the same signature as the new substitutions. + CanSILFunctionType + withPatternSubstitutions(SubstitutionMap subs) const; + + /// Create a SILFunctionType with the same structure as this one, + /// but replacing the invocation generic signature and pattern + /// substitutions. This type must either be polymorphic or have + /// pattern substitutions, and the substitution signature must + /// match `getSubstGenericSignature()`. + CanSILFunctionType + withPatternSpecialization(CanGenericSignature sign, + SubstitutionMap subs, + ProtocolConformanceRef witnessConformance = + ProtocolConformanceRef()) const; class ABICompatibilityCheckResult { friend class SILFunctionType; @@ -4789,18 +4960,19 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, CanSILFunctionType getUnsubstitutedType(SILModule &M) const; void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getSubstGenericSignature(), getExtInfo(), getCoroutineKind(), - getCalleeConvention(), getParameters(), getYields(), getResults(), + Profile(ID, getInvocationGenericSignature(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), + getParameters(), getYields(), getResults(), getOptionalErrorResult(), getWitnessMethodConformanceOrInvalid(), - isGenericSignatureImplied(), getSubstitutions()); + getPatternSubstitutions(), getInvocationSubstitutions()); } static void Profile(llvm::FoldingSetNodeID &ID, GenericSignature genericSig, ExtInfo info, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, ArrayRef yields, ArrayRef results, Optional errorResult, - ProtocolConformanceRef conformance, bool isGenericSigImplied, - SubstitutionMap substitutions); + ProtocolConformanceRef conformance, + SubstitutionMap patternSub, SubstitutionMap invocationSubs); // Implement isa/cast/dyncast/etc. static bool classof(const TypeBase *T) { diff --git a/include/swift/Basic/FrozenMultiMap.h b/include/swift/Basic/FrozenMultiMap.h index 8b171dd3abcfa..dd5656ffa47db 100644 --- a/include/swift/Basic/FrozenMultiMap.h +++ b/include/swift/Basic/FrozenMultiMap.h @@ -91,11 +91,17 @@ class FrozenMultiMap { frozen = true; } + /// Reset the frozen multimap in an unfrozen state with its storage cleared. + void reset() { + storage.clear(); + frozen = false; + } + unsigned size() const { return storage.size(); } bool empty() const { return storage.empty(); } struct iterator : std::iterator>> { + std::pair> { using base_iterator = typename decltype(storage)::iterator; FrozenMultiMap ↦ @@ -159,9 +165,11 @@ class FrozenMultiMap { } }; + using RangeType = llvm::iterator_range; + /// Return a range of (key, ArrayRef) pairs. The keys are guaranteed to /// be in key sorted order and the ArrayRef are in insertion order. - llvm::iterator_range getRange() const { + RangeType getRange() const { assert(isFrozen() && "Can not create range until data structure is frozen?!"); auto *self = const_cast(this); diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index fb4d94b444ec4..249a227bb7ed0 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -322,6 +322,9 @@ namespace swift { /// `@differentiable` declaration attribute, etc. bool EnableExperimentalDifferentiableProgramming = false; + /// Enable verification when every SubstitutionMap is constructed. + bool VerifyAllSubstitutionMaps = false; + /// Sets the target we are building for and updates platform conditions /// to match. /// @@ -412,7 +415,7 @@ namespace swift { } private: - llvm::SmallVector, 5> + llvm::SmallVector, 6> PlatformConditionValues; llvm::SmallVector CustomConditionalCompilationFlags; }; @@ -512,6 +515,7 @@ namespace swift { /// Enable constraint solver support for experimental /// operator protocol designator feature. bool SolverEnableOperatorDesignatedTypes = false; + }; } // end namespace swift diff --git a/include/swift/Basic/RelativePointer.h b/include/swift/Basic/RelativePointer.h index 31cfd2971ece2..8dadfaee635b9 100644 --- a/include/swift/Basic/RelativePointer.h +++ b/include/swift/Basic/RelativePointer.h @@ -240,7 +240,7 @@ class RelativeIndirectPointer { /// A relative reference to an object stored in memory. The reference may be /// direct or indirect, and uses the low bit of the (assumed at least /// 2-byte-aligned) pointer to differentiate. -template +template class RelativeIndirectablePointer { private: static_assert(std::is_integral::value && @@ -302,7 +302,7 @@ class RelativeIndirectablePointer { // If the low bit is set, then this is an indirect address. Otherwise, // it's direct. if (offsetPlusIndirect & 1) { - return *reinterpret_cast(address); + return *reinterpret_cast(address); } else { return reinterpret_cast(address); } @@ -327,7 +327,8 @@ class RelativeIndirectablePointer { /// 2-byte-aligned) pointer to differentiate. The remaining low bits store /// an additional tiny integer value. template + typename Offset = int32_t, + typename IndirectType = const ValueTy *> class RelativeIndirectablePointerIntPair { private: static_assert(std::is_integral::value && @@ -375,7 +376,7 @@ class RelativeIndirectablePointerIntPair { // If the low bit is set, then this is an indirect address. Otherwise, // it's direct. if (offsetPlusIndirect & 1) { - return *reinterpret_cast(address); + return *reinterpret_cast(address); } else { return reinterpret_cast(address); } @@ -459,10 +460,15 @@ class RelativeDirectPointerImpl { } }; -/// A direct relative reference to an object. -template -class RelativeDirectPointer : - private RelativeDirectPointerImpl +template +class RelativeDirectPointer; + +/// A direct relative reference to an object that is not a function pointer. +template +class RelativeDirectPointer::value>::type> + : private RelativeDirectPointerImpl { using super = RelativeDirectPointerImpl; public: @@ -487,26 +493,44 @@ class RelativeDirectPointer : /// A specialization of RelativeDirectPointer for function pointers, /// allowing for calls. -template -class RelativeDirectPointer : - private RelativeDirectPointerImpl +template +class RelativeDirectPointer::value>::type> + : private RelativeDirectPointerImpl { - using super = RelativeDirectPointerImpl; + using super = RelativeDirectPointerImpl; public: - using super::get; using super::super; - RelativeDirectPointer &operator=(RetTy (*absolute)(ArgTy...)) & { + RelativeDirectPointer &operator=(T absolute) & { super::operator=(absolute); return *this; } - + + typename super::PointerTy get() const & { + auto ptr = this->super::get(); +#if SWIFT_PTRAUTH + if (Nullable && !ptr) + return ptr; + return ptrauth_sign_unauthenticated(ptr, ptrauth_key_function_pointer, 0); +#else + return ptr; +#endif + } + operator typename super::PointerTy() const & { return this->get(); } - RetTy operator()(ArgTy...arg) const { - return this->get()(std::forward(arg)...); + template + typename std::result_of::type operator()(ArgTy...arg) const { +#if SWIFT_PTRAUTH + return ptrauth_sign_unauthenticated(this->super::get(), + ptrauth_key_function_pointer, + 0)(std::forward(arg)...); +#else + return this->super::get()(std::forward(arg)...); +#endif } using super::isNull; @@ -516,17 +540,17 @@ class RelativeDirectPointer : /// tiny integer value crammed into its low bits. template -class RelativeDirectPointerIntPair { +class RelativeDirectPointerIntPairImpl { Offset RelativeOffsetPlusInt; /// RelativePointers should appear in statically-generated metadata. They /// shouldn't be constructed or copied. - RelativeDirectPointerIntPair() = delete; - RelativeDirectPointerIntPair(RelativeDirectPointerIntPair &&) = delete; - RelativeDirectPointerIntPair(const RelativeDirectPointerIntPair &) = delete; - RelativeDirectPointerIntPair &operator=(RelativeDirectPointerIntPair &&) + RelativeDirectPointerIntPairImpl() = delete; + RelativeDirectPointerIntPairImpl(RelativeDirectPointerIntPairImpl &&) = delete; + RelativeDirectPointerIntPairImpl(const RelativeDirectPointerIntPairImpl &) = delete; + RelativeDirectPointerIntPairImpl &operator=(RelativeDirectPointerIntPairImpl &&) = delete; - RelativeDirectPointerIntPair &operator=(const RelativeDirectPointerIntPair&) + RelativeDirectPointerIntPairImpl &operator=(const RelativeDirectPointerIntPairImpl&) = delete; static Offset getMask() { @@ -558,6 +582,24 @@ class RelativeDirectPointerIntPair { } }; +/// A direct relative reference to an aligned object, with an additional +/// tiny integer value crammed into its low bits. +template +class RelativeDirectPointerIntPair; + +template +class RelativeDirectPointerIntPair::value>::type> + : private RelativeDirectPointerIntPairImpl +{ + using super = RelativeDirectPointerIntPairImpl; +public: + using super::getPointer; + using super::getInt; + using super::getOpaqueValue; +}; + // Type aliases for "far" relative pointers, which need to be able to reach // across the full address space instead of only across a single small-code- // model image. diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index a8ddf8992cd79..f13e126b4628e 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -113,10 +113,10 @@ NODE(ImplEscaping) NODE(ImplConvention) NODE(ImplFunctionAttribute) NODE(ImplFunctionType) -NODE(ImplImpliedSubstitutions) -NODE(ImplSubstitutions) +NODE(ImplInvocationSubstitutions) CONTEXT_NODE(ImplicitClosure) NODE(ImplParameter) +NODE(ImplPatternSubstitutions) NODE(ImplResult) NODE(ImplYield) NODE(ImplErrorResult) diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index c2e295c535428..5ef3445160e24 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -266,6 +266,10 @@ class FrontendOptions { /// Should we enable the dependency verifier for all primary files known to this frontend? bool EnableIncrementalDependencyVerifier = false; + /// The directory path we should use when print #include for the bridging header. + /// By default, we include ImplicitObjCHeaderPath directly. + llvm::Optional BridgingHeaderDirForPrint; + /// The different modes for validating TBD against the LLVM IR. enum class TBDValidationMode { Default, ///< Do the default validation for the current platform. diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 892bfe876ba3a..0d073846c18e3 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -1043,10 +1043,14 @@ class LinkEntity { ::getFromOpaqueValue(reinterpret_cast(Pointer)); } - SILFunction *getSILFunction() const { - assert(getKind() == Kind::SILFunction || + bool hasSILFunction() const { + return getKind() == Kind::SILFunction || getKind() == Kind::DynamicallyReplaceableFunctionVariable || - getKind() == Kind::DynamicallyReplaceableFunctionKey); + getKind() == Kind::DynamicallyReplaceableFunctionKey; + } + + SILFunction *getSILFunction() const { + assert(hasSILFunction()); return reinterpret_cast(Pointer); } @@ -1097,6 +1101,16 @@ class LinkEntity { assert(getKind() == Kind::SILFunction); return LINKENTITY_GET_FIELD(Data, IsDynamicallyReplaceableImpl); } + bool isDynamicallyReplaceableKey() const { + return getKind() == Kind::DynamicallyReplaceableFunctionKey || + getKind() == Kind::OpaqueTypeDescriptorAccessorKey; + } + bool isOpaqueTypeDescriptorAccessor() const { + return getKind() == Kind::OpaqueTypeDescriptorAccessor || + getKind() == Kind::OpaqueTypeDescriptorAccessorImpl || + getKind() == Kind::OpaqueTypeDescriptorAccessorKey || + getKind() == Kind::OpaqueTypeDescriptorAccessorVar; + } bool isAllocator() const { assert(getKind() == Kind::DynamicallyReplaceableFunctionImpl || getKind() == Kind::DynamicallyReplaceableFunctionKeyAST || @@ -1104,6 +1118,7 @@ class LinkEntity { return SecondaryPointer != nullptr; } bool isValueWitness() const { return getKind() == Kind::ValueWitness; } + bool isContextDescriptor() const; CanType getType() const { assert(isTypeKind(getKind())); return CanType(reinterpret_cast(Pointer)); @@ -1140,6 +1155,8 @@ class LinkEntity { /// Get the default LLVM type to use for forward declarations of this /// entity. llvm::Type *getDefaultDeclarationType(IRGenModule &IGM) const; + + bool isAlwaysSharedLinkage() const; #undef LINKENTITY_GET_FIELD #undef LINKENTITY_SET_FIELD }; diff --git a/include/swift/Markup/Markup.h b/include/swift/Markup/Markup.h index c5caefdd49b2a..b511f0b43c087 100644 --- a/include/swift/Markup/Markup.h +++ b/include/swift/Markup/Markup.h @@ -60,6 +60,7 @@ class MarkupContext final { LineList getLineList(swift::RawComment RC); }; +Document *parseDocument(MarkupContext &MC, StringRef String); Document *parseDocument(MarkupContext &MC, LineList &LL); } // namespace markup diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index b18dfb561ddc6..864f001ed385a 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -548,6 +548,9 @@ def sil_merge_partial_modules : Flag<["-"], "sil-merge-partial-modules">, def sil_verify_all : Flag<["-"], "sil-verify-all">, HelpText<"Verify SIL after each transform">; + +def verify_all_substitution_maps : Flag<["-"], "verify-all-substitution-maps">, + HelpText<"Verify all SubstitutionMaps on construction">; def sil_debug_serialization : Flag<["-"], "sil-debug-serialization">, HelpText<"Do not eliminate functions in Mandatory Inlining/SILCombine dead " @@ -687,4 +690,8 @@ def disable_type_layouts : Flag<["-"], "disable-type-layout">, def disable_interface_lockfile : Flag<["-"], "disable-interface-lock">, HelpText<"Don't lock interface file when building module">; + +def bridging_header_directory_for_print: Separate<["-"], "bridging-header-directory-for-print">, MetaVarName<"">, + HelpText<"Directory for bridging header to be printed in compatibility header">; + } // end let Flags = [FrontendOption, NoDriverOption, HelpHidden] diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index cfbda087504a7..5579346de70ab 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -751,50 +751,100 @@ class ReflectionContext return false; unsigned long NonPayloadCaseCount = FieldCount - 1; unsigned long PayloadExtraInhabitants = PayloadCase.TI.getNumExtraInhabitants(); - unsigned discriminator = 0; + unsigned Discriminator = 0; auto PayloadSize = PayloadCase.TI.getSize(); if (NonPayloadCaseCount >= PayloadExtraInhabitants) { // There are more cases than inhabitants, we need a separate discriminator. auto TagInfo = getEnumTagCounts(PayloadSize, NonPayloadCaseCount, 1); auto TagSize = TagInfo.numTagBytes; auto TagAddress = RemoteAddress(EnumAddress.getAddressData() + PayloadSize); - if (!getReader().readInteger(TagAddress, TagSize, &discriminator)) + if (!getReader().readInteger(TagAddress, TagSize, &Discriminator)) { + printf(">>>> readXI failed to read discriminator\n\n"); return false; + } } - if (PayloadExtraInhabitants == 0) { - // Payload has no XI, so discriminator fully determines the case - *CaseIndex = discriminator; + if (PayloadSize == 0) { + // Payload carries no information, so discriminator fully determines the case + *CaseIndex = Discriminator; return true; - } else if (discriminator == 0) { - // The value overlays the payload ... ask the payload to decode it. - int t; - if (!PayloadCase.TI.readExtraInhabitantIndex(getReader(), EnumAddress, &t)) { + } else if (Discriminator == 0) { + // The payload area carries all the information... + if (PayloadExtraInhabitants == 0) { + *CaseIndex = 0; + return true; + } + int XITag = 0; + if (!PayloadCase.TI.readExtraInhabitantIndex(getReader(), EnumAddress, &XITag)) { return false; } - if (t < 0) { - *CaseIndex = 0; + if (XITag < 0) { // Valid (not extra) inhabitant + *CaseIndex = 0; // Payload case is always #0 return true; - } else if ((unsigned long)t <= NonPayloadCaseCount) { - *CaseIndex = t + 1; + } else if ((unsigned)XITag <= NonPayloadCaseCount) { + *CaseIndex = XITag + 1; return true; } return false; } else { - // The entire payload area is available for additional cases: - auto TagSize = std::max(PayloadSize, 4U); // XXX TODO XXX CHECK THIS - auto offset = 1 + PayloadExtraInhabitants; // Cases coded with discriminator = 0 - unsigned casesInPayload = 1 << (TagSize * 8U); - unsigned payloadCode; - if (!getReader().readInteger(EnumAddress, TagSize, &payloadCode)) + // No payload: Payload area is reused for more cases + uint32_t PayloadTag = 0; + auto PayloadTagSize = std::min(PayloadSize, decltype(PayloadSize)(sizeof(PayloadTag))); + if (!getReader().readInteger(EnumAddress, PayloadTagSize, &PayloadTag)) { return false; - *CaseIndex = offset + (discriminator - 1) * casesInPayload + payloadCode; + } + auto XICases = 1U + PayloadExtraInhabitants; // Cases coded with XIs when discriminator = 0 + auto PayloadCases = 1U << (PayloadTagSize * 8U); + *CaseIndex = XICases + (Discriminator - 1) * PayloadCases + PayloadTag; return true; } } case RecordKind::MultiPayloadEnum: { - // TODO: Support multipayload enums + // Collect basic statistics about the enum + unsigned long PayloadCaseCount = 0; + unsigned long NonPayloadCaseCount = 0; + unsigned long PayloadSize = 0; + for (auto Field : Fields) { + if (Field.TR != 0) { + PayloadCaseCount += 1; + if (Field.TI.getSize() > PayloadSize) { + PayloadSize = Field.TI.getSize(); + } + } else { + NonPayloadCaseCount += 1; + } + } + if (EnumSize > PayloadSize) { + // If the compiler laid this out with a separate tag, use that. + unsigned tag = 0; + auto TagSize = EnumSize - PayloadSize; + auto TagAddress = remote::RemoteAddress(EnumAddress.getAddressData() + PayloadSize); + if (!getReader().readInteger(TagAddress, TagSize, &tag) + || tag >= Fields.size()) { + return false; + } + if (tag < PayloadCaseCount) { + *CaseIndex = tag; + return true; + } + auto PayloadTagSize = std::min(PayloadSize, 4UL); + // Treat the tag as a page selector; payload carries the offset within the page + auto Page = tag - PayloadCaseCount; + // Zero for 32-bit because we'll never have more than one page + auto PageSize = PayloadTagSize >= 4 ? 0 : 1 << (PayloadSize * 8U); + auto PageStart = Page * PageSize; + unsigned PayloadTag; + if (!getReader().readInteger(EnumAddress, PayloadTagSize, &PayloadTag)) { + return false; + } + *CaseIndex = PageStart + PayloadTag + PayloadCaseCount; + return true; + } else { + // XXX TODO: If the payloads have common spare bits (e.g., all pointers) + // then use those to decode the case. + return false; + } break; } diff --git a/include/swift/Remote/InProcessMemoryReader.h b/include/swift/Remote/InProcessMemoryReader.h index c2c4f0ee345ee..2f6b5b535a437 100644 --- a/include/swift/Remote/InProcessMemoryReader.h +++ b/include/swift/Remote/InProcessMemoryReader.h @@ -55,6 +55,15 @@ class InProcessMemoryReader final : public MemoryReader { *result = sizeof(size_t); return true; } + case DLQ_GetPtrAuthMask: { + auto result = static_cast(outBuffer); +#if __has_feature(ptrauth_calls) + *result = (uintptr_t)ptrauth_strip((void*)0x0007ffffffffffff, 0); +#else + *result = (uintptr_t)~0ull; +#endif + return true; + } case DLQ_GetObjCReservedLowBits: { auto result = static_cast(outBuffer); if (applePlatform && !iosDerivedPlatform && (sizeof(void *) == 8)) { diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h index e2ce2a63bdd27..fb2610f748d5d 100644 --- a/include/swift/Remote/MemoryReader.h +++ b/include/swift/Remote/MemoryReader.h @@ -64,44 +64,20 @@ class MemoryReader { /// Attempts to read an integer of the specified size from the given /// address in the remote process. /// - /// Returns false if the operation failed, the request size is not - /// 1, 2, 4, or 8, or the request size is larger than the provided destination. + /// Returns false if the operation failed, or the request size is + /// larger than the provided destination. template bool readInteger(RemoteAddress address, size_t bytes, IntegerType *dest) { - if (bytes > sizeof(IntegerType)) - return false; - switch (bytes) { - case 1: { - uint8_t n; - if (!readInteger(address, &n)) - return false; - *dest = n; - break; - } - case 2: { - uint16_t n; - if (!readInteger(address, &n)) - return false; - *dest = n; - break; - } - case 4: { - uint32_t n; - if (!readInteger(address, &n)) - return false; - *dest = n; - break; - } - case 8: { - uint64_t n; - if (!readInteger(address, &n)) - return false; - *dest = n; - break; - } - default: + *dest = 0; + if ((bytes > sizeof(IntegerType)) + || !readBytes(address, (uint8_t *)dest, bytes)) { return false; } + // FIXME: Assumes host and target have the same endianness. + // TODO: Query DLQ for endianness of target, compare to endianness of host. +#if defined(__BIG_ENDIAN__) + *dest >>= (sizeof(IntegerType) - bytes); +#endif return true; } diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index c117a4d15aba5..b11ee83f9a294 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -163,6 +163,7 @@ class MetadataReader { using BuiltTypeDecl = typename BuilderType::BuiltTypeDecl; using BuiltProtocolDecl = typename BuilderType::BuiltProtocolDecl; using StoredPointer = typename Runtime::StoredPointer; + using StoredSignedPointer = typename Runtime::StoredSignedPointer; using StoredSize = typename Runtime::StoredSize; private: @@ -346,11 +347,34 @@ class MetadataReader { std::shared_ptr Reader; + StoredPointer PtrAuthMask; + + StoredPointer stripSignedPointer(StoredSignedPointer P) { + return P.SignedValue & PtrAuthMask; + } + + RemoteAbsolutePointer stripSignedPointer(const RemoteAbsolutePointer &P) { + if (P.isResolved()) { + return RemoteAbsolutePointer("", + P.getResolvedAddress().getAddressData() & PtrAuthMask); + } + return P; + } + + StoredPointer queryPtrAuthMask() { + StoredPointer QueryResult; + if (Reader->queryDataLayout(DataLayoutQueryType::DLQ_GetPtrAuthMask, + nullptr, &QueryResult)) { + return QueryResult; + } + return ~StoredPointer(0); + } + template MetadataReader(std::shared_ptr reader, T &&... args) : Builder(std::forward(args)...), - Reader(std::move(reader)) { - + Reader(std::move(reader)), + PtrAuthMask(queryPtrAuthMask()) { } MetadataReader(const MetadataReader &other) = delete; @@ -383,7 +407,7 @@ class MetadataReader { RemoteAbsolutePointer resolved; if (directness == Directness::Indirect) { if (auto indirectAddress = readPointer(remoteAddress)) { - resolved = *indirectAddress; + resolved = stripSignedPointer(*indirectAddress); } else { return nullptr; } @@ -681,8 +705,8 @@ class MetadataReader { // Swift-native protocol. auto Demangled = - readDemanglingForContextDescriptor(ProtocolAddress.getSwiftProtocol(), - dem); + readDemanglingForContextDescriptor( + stripSignedPointer({ProtocolAddress.getSwiftProtocol()}), dem); if (!Demangled) return resolver.failure(); @@ -1516,7 +1540,10 @@ class MetadataReader { // Low bit set in the offset indicates that the offset leads to the absolute // address in memory. if (indirect) { - return readPointer(resultAddress); + if (auto ptr = readPointer(resultAddress)) { + return stripSignedPointer(*ptr); + } + return None; } return RemoteAbsolutePointer("", resultAddress); @@ -1681,7 +1708,8 @@ class MetadataReader { case MetadataKind::Class: { auto classMeta = cast>(metadata); while (true) { - auto descriptorAddress = classMeta->getDescription(); + StoredSignedPointer descriptorAddressSigned = classMeta->getDescriptionAsSignedPointer(); + StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); // If this class has a null descriptor, it's artificial, // and we need to skip it upon request. Otherwise, we're done. @@ -1709,12 +1737,16 @@ class MetadataReader { case MetadataKind::Optional: case MetadataKind::Enum: { auto valueMeta = cast>(metadata); - return valueMeta->getDescription(); + StoredSignedPointer descriptorAddressSigned = valueMeta->getDescriptionAsSignedPointer(); + StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); + return descriptorAddress; } case MetadataKind::ForeignClass: { auto foreignMeta = cast>(metadata); - return foreignMeta->Description; + StoredSignedPointer descriptorAddressSigned = foreignMeta->getDescriptionAsSignedPointer(); + StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); + return descriptorAddress; } default: @@ -2609,16 +2641,20 @@ class MetadataReader { // Otherwise, it's the RW-data; read the RO-data pointer from a // well-known position within the RW-data. + StoredSignedPointer signedDataPtr; static constexpr uint32_t OffsetToROPtr = 8; - if (!Reader->readInteger(RemoteAddress(dataPtr + OffsetToROPtr), &dataPtr)) + if (!Reader->readInteger(RemoteAddress(dataPtr + OffsetToROPtr), &signedDataPtr)) return StoredPointer(); + dataPtr = stripSignedPointer(signedDataPtr); // Newer Objective-C runtimes implement a size optimization where the RO // field is a tagged union. If the low-bit is set, then the pointer needs // to be dereferenced once more to yield the real class_ro_t pointer. - if (dataPtr & 1) - if (!Reader->readInteger(RemoteAddress(dataPtr^1), &dataPtr)) + if (dataPtr & 1) { + if (!Reader->readInteger(RemoteAddress(dataPtr^1), &signedDataPtr)) return StoredPointer(); + dataPtr = stripSignedPointer(signedDataPtr); + } return dataPtr; } diff --git a/include/swift/Runtime/Config.h b/include/swift/Runtime/Config.h index c8cc49083ad17..471f4f521e050 100644 --- a/include/swift/Runtime/Config.h +++ b/include/swift/Runtime/Config.h @@ -226,4 +226,95 @@ // so changing this value is not sufficient. #define SWIFT_DEFAULT_LLVM_CC llvm::CallingConv::C +// Pointer authentication. +#if __has_feature(ptrauth_calls) +#define SWIFT_PTRAUTH 1 +#include +#define __ptrauth_swift_runtime_function_entry \ + __ptrauth(ptrauth_key_function_pointer, 1, \ + SpecialPointerAuthDiscriminators::RuntimeFunctionEntry) +#define __ptrauth_swift_runtime_function_entry_with_key(__key) \ + __ptrauth(ptrauth_key_function_pointer, 1, __key) +#define __ptrauth_swift_runtime_function_entry_strip(__fn) \ + ptrauth_strip(__fn, ptrauth_key_function_pointer) +#define __ptrauth_swift_type_descriptor \ + __ptrauth(ptrauth_key_process_independent_data, 1, \ + SpecialPointerAuthDiscriminators::TypeDescriptor) +#define __ptrauth_swift_dynamic_replacement_key \ + __ptrauth(ptrauth_key_process_independent_data, 1, \ + SpecialPointerAuthDiscriminators::DynamicReplacementKey) +#define swift_ptrauth_sign_opaque_read_resume_function(__fn, __buffer) \ + ptrauth_auth_and_resign(__fn, ptrauth_key_function_pointer, 0, \ + ptrauth_key_process_independent_code, \ + ptrauth_blend_discriminator(__buffer, \ + SpecialPointerAuthDiscriminators::OpaqueReadResumeFunction)) +#define swift_ptrauth_sign_opaque_modify_resume_function(__fn, __buffer) \ + ptrauth_auth_and_resign(__fn, ptrauth_key_function_pointer, 0, \ + ptrauth_key_process_independent_code, \ + ptrauth_blend_discriminator(__buffer, \ + SpecialPointerAuthDiscriminators::OpaqueModifyResumeFunction)) +#else +#define SWIFT_PTRAUTH 0 +#define __ptrauth_swift_function_pointer(__typekey) +#define __ptrauth_swift_class_method_pointer(__declkey) +#define __ptrauth_swift_protocol_witness_function_pointer(__declkey) +#define __ptrauth_swift_value_witness_function_pointer(__key) +#define __ptrauth_swift_type_metadata_instantiation_function +#define __ptrauth_swift_runtime_function_entry +#define __ptrauth_swift_runtime_function_entry_with_key(__key) +#define __ptrauth_swift_runtime_function_entry_strip(__fn) (__fn) +#define __ptrauth_swift_heap_object_destructor +#define __ptrauth_swift_type_descriptor +#define __ptrauth_swift_dynamic_replacement_key +#define swift_ptrauth_sign_opaque_read_resume_function(__fn, __buffer) (__fn) +#define swift_ptrauth_sign_opaque_modify_resume_function(__fn, __buffer) (__fn) +#endif + +#ifdef __cplusplus + +/// Copy an address-discriminated signed pointer from the source to the dest. +template +SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +static inline void swift_ptrauth_copy(T *dest, const T *src, unsigned extra) { +#if SWIFT_PTRAUTH + *dest = ptrauth_auth_and_resign(*src, + ptrauth_key_function_pointer, + ptrauth_blend_discriminator(src, extra), + ptrauth_key_function_pointer, + ptrauth_blend_discriminator(dest, extra)); +#else + *dest = *src; +#endif +} + +/// Initialize the destination with an address-discriminated signed pointer. +/// This does not authenticate the source value, so be careful about how +/// you construct it. +template +SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +static inline void swift_ptrauth_init(T *dest, T value, unsigned extra) { + // FIXME: assert that T is not a function-pointer type? +#if SWIFT_PTRAUTH + *dest = ptrauth_sign_unauthenticated(value, + ptrauth_key_function_pointer, + ptrauth_blend_discriminator(dest, extra)); +#else + *dest = value; +#endif +} + +template +SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +static inline T swift_auth_data_non_address(T value, unsigned extra) { +#if SWIFT_PTRAUTH + return (T)ptrauth_auth_data((void *)value, + ptrauth_key_process_independent_data, + extra); +#else + return value; +#endif +} + +#endif + #endif // SWIFT_RUNTIME_CONFIG_H diff --git a/include/swift/Runtime/InstrumentsSupport.h b/include/swift/Runtime/InstrumentsSupport.h index ba8fe52f960f2..518db303adbba 100644 --- a/include/swift/Runtime/InstrumentsSupport.h +++ b/include/swift/Runtime/InstrumentsSupport.h @@ -18,23 +18,27 @@ #ifndef SWIFT_RUNTIME_INSTRUMENTS_SUPPORT_H #define SWIFT_RUNTIME_INSTRUMENTS_SUPPORT_H +#define SWIFT_RT_DECLARE_ENTRY \ + __ptrauth_swift_runtime_function_entry + namespace swift { // liboainject patches the function pointers and calls the functions below. SWIFT_RUNTIME_EXPORT -HeapObject *(*_swift_allocObject)(HeapMetadata const *metadata, +HeapObject *(*SWIFT_RT_DECLARE_ENTRY _swift_allocObject)( + HeapMetadata const *metadata, size_t requiredSize, size_t requiredAlignmentMask); SWIFT_RUNTIME_EXPORT -HeapObject *(*_swift_retain)(HeapObject *object); +HeapObject *(*SWIFT_RT_DECLARE_ENTRY _swift_retain)(HeapObject *object); SWIFT_RUNTIME_EXPORT -HeapObject *(*_swift_retain_n)(HeapObject *object, uint32_t n); +HeapObject *(*SWIFT_RT_DECLARE_ENTRY _swift_retain_n)(HeapObject *object, uint32_t n); SWIFT_RUNTIME_EXPORT -HeapObject *(*_swift_tryRetain)(HeapObject *object); +HeapObject *(*SWIFT_RT_DECLARE_ENTRY _swift_tryRetain)(HeapObject *object); SWIFT_RUNTIME_EXPORT -void (*_swift_release)(HeapObject *object); +void (*SWIFT_RT_DECLARE_ENTRY _swift_release)(HeapObject *object); SWIFT_RUNTIME_EXPORT -void (*_swift_release_n)(HeapObject *object, uint32_t n); +void (*SWIFT_RT_DECLARE_ENTRY _swift_release_n)(HeapObject *object, uint32_t n); SWIFT_RUNTIME_EXPORT size_t swift_retainCount(HeapObject *object); diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 4fcc015d4d4eb..09319d7b3a5af 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -97,6 +97,9 @@ struct EnumValueWitnessTable : ValueWitnessTable { #define WANT_ONLY_ENUM_VALUE_WITNESSES #define VALUE_WITNESS(LOWER_ID, UPPER_ID) \ ValueWitnessTypes::LOWER_ID LOWER_ID; +#define FUNCTION_VALUE_WITNESS(LOWER_ID, UPPER_ID, RET, PARAMS) \ + ValueWitnessTypes::LOWER_ID LOWER_ID; + #include "swift/ABI/ValueWitness.def" constexpr EnumValueWitnessTable() @@ -106,9 +109,11 @@ struct EnumValueWitnessTable : ValueWitnessTable { destructiveInjectEnumTag(nullptr) {} constexpr EnumValueWitnessTable( const ValueWitnessTable &base, - ValueWitnessTypes::getEnumTag getEnumTag, - ValueWitnessTypes::destructiveProjectEnumData destructiveProjectEnumData, - ValueWitnessTypes::destructiveInjectEnumTag destructiveInjectEnumTag) + ValueWitnessTypes::getEnumTagUnsigned getEnumTag, + ValueWitnessTypes::destructiveProjectEnumDataUnsigned + destructiveProjectEnumData, + ValueWitnessTypes::destructiveInjectEnumTagUnsigned + destructiveInjectEnumTag) : ValueWitnessTable(base), getEnumTag(getEnumTag), destructiveProjectEnumData(destructiveProjectEnumData), diff --git a/include/swift/SIL/AbstractionPattern.h b/include/swift/SIL/AbstractionPattern.h index 890b6222225f7..3c5791cb99728 100644 --- a/include/swift/SIL/AbstractionPattern.h +++ b/include/swift/SIL/AbstractionPattern.h @@ -323,8 +323,10 @@ class AbstractionPattern { TheKind = unsigned(kind); OrigType = origType; GenericSig = CanGenericSignature(); - if (OrigType->hasTypeParameter()) + if (OrigType->hasTypeParameter()) { + assert(OrigType == signature->getCanonicalTypeInContext(origType)); GenericSig = signature; + } } void initClangType(CanGenericSignature signature, diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 46cb8955b41fe..aacd83dc88580 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -598,6 +598,28 @@ struct OwnedValueIntroducer { return OwnedValueIntroducer(value, *kind); } + /// Returns true if this owned introducer is able to be converted into a + /// guaranteed form if none of its uses are consuming uses (looking through + /// forwarding uses). + bool isConvertableToGuaranteed() const { + switch (kind) { + case OwnedValueIntroducerKind::Copy: + case OwnedValueIntroducerKind::LoadCopy: + return true; + case OwnedValueIntroducerKind::Apply: + case OwnedValueIntroducerKind::BeginApply: + case OwnedValueIntroducerKind::TryApply: + case OwnedValueIntroducerKind::LoadTake: + case OwnedValueIntroducerKind::Phi: + case OwnedValueIntroducerKind::FunctionArgument: + case OwnedValueIntroducerKind::PartialApplyInit: + case OwnedValueIntroducerKind::AllocBoxInit: + case OwnedValueIntroducerKind::AllocRefInit: + return false; + } + llvm_unreachable("Covered switch isn't covered?!"); + } + bool operator==(const OwnedValueIntroducer &other) const { return value == other.value; } diff --git a/include/swift/SIL/SILConstants.h b/include/swift/SIL/SILConstants.h index c360726bd1ecb..4e04f3e8044e7 100644 --- a/include/swift/SIL/SILConstants.h +++ b/include/swift/SIL/SILConstants.h @@ -733,6 +733,8 @@ struct SymbolicClosure final SILType getClosureType() { return closureInst->getType(); } SubstitutionMap getCallSubstitutionMap() { return substitutionMap; } + + bool hasOnlyConstantCaptures() { return !hasNonConstantCaptures; } }; } // end namespace swift diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 12087cac3151b..4c87ced5bf378 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -354,6 +354,11 @@ class SILFunction return SILFunctionConventions(LoweredType, getModule()); } + SILFunctionConventions getConventionsInContext() const { + auto fnType = getLoweredFunctionTypeInContext(getTypeExpansionContext()); + return SILFunctionConventions(fnType, getModule()); + } + SILProfiler *getProfiler() const { return Profiler; } SILFunction *getDynamicallyReplacedFunction() const { diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 0a1b439dc0141..3366328915a74 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -6192,7 +6192,7 @@ class InitExistentialValueInst final class InitExistentialRefInst final : public UnaryInstructionWithTypeDependentOperandsBase< SILInstructionKind::InitExistentialRefInst, InitExistentialRefInst, - SingleValueInstruction> { + OwnershipForwardingSingleValueInst> { friend SILBuilder; CanType ConcreteType; @@ -6203,7 +6203,8 @@ class InitExistentialRefInst final ArrayRef TypeDependentOperands, ArrayRef Conformances) : UnaryInstructionWithTypeDependentOperandsBase( - DebugLoc, Instance, TypeDependentOperands, ExistentialType), + DebugLoc, Instance, TypeDependentOperands, ExistentialType, + Instance.getOwnershipKind()), ConcreteType(FormalConcreteType), Conformances(Conformances) {} static InitExistentialRefInst * diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 4e15caf4c932f..43269c325664c 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -380,6 +380,11 @@ class SILType { bool hasArchetype() const { return getASTType()->hasArchetype(); } + + /// True if the type involves any opaque archetypes. + bool hasOpaqueArchetype() const { + return getASTType()->hasOpaqueArchetype(); + } /// Returns the ASTContext for the referenced Swift type. ASTContext &getASTContext() const { @@ -532,6 +537,11 @@ class SILType { /// Returns a SILType with any archetypes mapped out of context. SILType mapTypeOutOfContext() const; + /// Given a lowered type (but without any particular value category), + /// map it out of its current context. Equivalent to + /// SILType::getPrimitiveObjectType(type).mapTypeOutOfContext().getASTType(). + static CanType mapTypeOutOfContext(CanType type); + /// Given two SIL types which are representations of the same type, /// check whether they have an abstraction difference. bool hasAbstractionDifference(SILFunctionTypeRepresentation rep, diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index eeea1c847d8c6..637b18ad93946 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -598,6 +598,8 @@ class TypeConverter { TypeExpansionContext expansionContext; + bool IsCacheable; + CachingTypeKey getCachingKey() const { assert(isCacheable()); return { (OrigType.hasGenericSignature() @@ -609,11 +611,27 @@ class TypeConverter { } bool isCacheable() const { - return OrigType.hasCachingKey(); + return IsCacheable; } TypeKey getKeyForMinimalExpansion() const { - return {OrigType, SubstType, TypeExpansionContext::minimal()}; + return {OrigType, SubstType, TypeExpansionContext::minimal(), + IsCacheable}; + } + + void computeCacheable() { + IsCacheable = (OrigType.hasCachingKey() && + !isTreacherousInterfaceType(SubstType)); + } + + static bool isTreacherousInterfaceType(CanType type) { + // Don't cache lowerings for interface function types that involve + // type parameters; we might need a contextual generic signature to + // handle them correctly. + if (!type->hasTypeParameter()) return false; + return type.findIf([](CanType type) { + return isa(type) && type->hasTypeParameter(); + }); } }; @@ -621,7 +639,9 @@ class TypeConverter { TypeKey getTypeKey(AbstractionPattern origTy, CanType substTy, TypeExpansionContext context) { - return {origTy, substTy, context}; + TypeKey result = {origTy, substTy, context, false}; + result.computeCacheable(); + return result; } struct OverrideKey { @@ -643,14 +663,16 @@ class TypeConverter { /// Find a cached TypeLowering by TypeKey, or return null if one doesn't /// exist. - const TypeLowering *find(TypeKey k); + const TypeLowering *find(const TypeKey &k); /// Insert a mapping into the cache. - void insert(TypeKey k, const TypeLowering *tl); + void insert(const TypeKey &k, const TypeLowering *tl); #ifndef NDEBUG /// Remove the nullptr entry from the type map. - void removeNullEntry(TypeKey k); + void removeNullEntry(const TypeKey &k); #endif + CanGenericSignature CurGenericSignature; + /// Mapping for types independent on contextual generic parameters. llvm::DenseMap LoweredTypes; @@ -696,6 +718,27 @@ class TypeConverter { TypeConverter(TypeConverter const &) = delete; TypeConverter &operator=(TypeConverter const &) = delete; + CanGenericSignature getCurGenericSignature() const { + return CurGenericSignature; + } + + class GenericContextRAII { + TypeConverter &TC; + CanGenericSignature SavedSig; + public: + GenericContextRAII(TypeConverter &TC, CanGenericSignature sig) + : TC(TC), SavedSig(TC.CurGenericSignature) { + TC.CurGenericSignature = sig; + } + + GenericContextRAII(const GenericContextRAII &) = delete; + GenericContextRAII &operator=(const GenericContextRAII &) = delete; + + ~GenericContextRAII() { + TC.CurGenericSignature = SavedSig; + } + }; + /// Return the CaptureKind to use when capturing a decl. CaptureKind getDeclCaptureKind(CapturedValue capture, TypeExpansionContext expansion); diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index 5d048881ccd6f..a84383d465039 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -243,6 +243,8 @@ PASS(NonTransparentFunctionOwnershipModelEliminator, "Eliminate Ownership Annotations from non-transparent SIL Functions") PASS(RCIdentityDumper, "rc-id-dumper", "Print Reference Count Identities") +PASS(AlwaysInlineInliner, "always-inline", + "Inline always inline functions") PASS(PerfInliner, "inline", "Performance Function Inlining") PASS(PerformanceConstantPropagation, "performance-constant-propagation", diff --git a/include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h b/include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h index e6933b2660706..cd0817ae896b6 100644 --- a/include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h +++ b/include/swift/SILOptimizer/Utils/PerformanceInlinerUtils.h @@ -35,7 +35,8 @@ class SideEffectAnalysis; enum class InlineSelection { Everything, NoGlobalInit, // and no availability semantics calls - NoSemanticsAndGlobalInit + NoSemanticsAndGlobalInit, + OnlyInlineAlways, }; // Returns the callee of an apply_inst if it is basically inlinable. diff --git a/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h b/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h index 5dd6da9b289b2..65d383de00db8 100644 --- a/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h +++ b/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h @@ -86,6 +86,11 @@ typedef enum { /// bytes. DLQ_GetSizeSize, + /// The query should ignore inBuffer, and treat outBuffer as pointer-sized + /// buffer (the size of a target pointer, not a swift_addr_t) which should be + /// populated with the mask of pointer addressable bits. + DLQ_GetPtrAuthMask, + /// The query should ignore inBuffer, and treat outBuffer as uint8_t* which /// should be populated with the number of low-order bits in each pointer /// reserved by Obj-C in the remote process. This is generally zero except diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a0e3ce76366ca..376ed1aa137d8 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3186,8 +3186,8 @@ void SILFunctionType::Profile( ArrayRef results, Optional errorResult, ProtocolConformanceRef conformance, - bool isGenericSignatureImplied, - SubstitutionMap substitutions) { + SubstitutionMap patternSubs, + SubstitutionMap invocationSubs) { id.AddPointer(genericParams.getPointer()); auto infoKey = info.getFuncAttrKey(); id.AddInteger(infoKey.first); @@ -3207,8 +3207,8 @@ void SILFunctionType::Profile( // Just allow the profile length to implicitly distinguish the // presence of an error result. if (errorResult) errorResult->profile(id); - id.AddBoolean(isGenericSignatureImplied); - substitutions.profile(id); + patternSubs.profile(id); + invocationSubs.profile(id); id.AddBoolean((bool)conformance); if (conformance) id.AddPointer(conformance.getRequirement()); @@ -3223,20 +3223,20 @@ SILFunctionType::SILFunctionType( ArrayRef yields, ArrayRef normalResults, Optional errorResult, - SubstitutionMap substitutions, - bool genericSigIsImplied, + SubstitutionMap patternSubs, + SubstitutionMap invocationSubs, const ASTContext &ctx, RecursiveTypeProperties properties, ProtocolConformanceRef witnessMethodConformance) : TypeBase(TypeKind::SILFunction, &ctx, properties), - GenericSigAndIsImplied(CanGenericSignature(genericSig), - genericSigIsImplied), - WitnessMethodConformance(witnessMethodConformance), - Substitutions(substitutions) { + InvocationGenericSig(CanGenericSignature(genericSig)), + WitnessMethodConformance(witnessMethodConformance) { Bits.SILFunctionType.HasErrorResult = errorResult.hasValue(); Bits.SILFunctionType.ExtInfoBits = ext.Bits; Bits.SILFunctionType.HasUncommonInfo = false; + Bits.SILFunctionType.HasPatternSubs = (bool) patternSubs; + Bits.SILFunctionType.HasInvocationSubs = (bool) invocationSubs; // The use of both assert() and static_assert() below is intentional. assert(Bits.SILFunctionType.ExtInfoBits == ext.Bits && "Bits were dropped!"); static_assert(ExtInfo::NumMaskBits == NumSILExtInfoBits, @@ -3269,6 +3269,11 @@ SILFunctionType::SILFunctionType( if (errorResult) getMutableErrorResult() = *errorResult; + if (patternSubs) + getMutablePatternSubs() = patternSubs; + if (invocationSubs) + getMutableInvocationSubs() = invocationSubs; + if (hasResultCache()) { getMutableFormalResultsCache() = CanType(); getMutableAllResultsCache() = CanType(); @@ -3282,14 +3287,11 @@ SILFunctionType::SILFunctionType( "non-witness_method SIL function with a conformance"); // Make sure the type follows invariants. - assert((!substitutions || genericSig) + assert((!invocationSubs || genericSig) && "can only have substitutions with a generic signature"); - assert((!genericSigIsImplied || substitutions) - && "genericSigIsImplied should only be set for a type with generic " - "types and substitutions"); - if (substitutions) { - assert(substitutions.getGenericSignature().getCanonicalSignature() == + if (invocationSubs) { + assert(invocationSubs.getGenericSignature().getCanonicalSignature() == genericSig.getCanonicalSignature() && "substitutions must match generic signature"); } @@ -3303,7 +3305,9 @@ SILFunctionType::SILFunctionType( (void)gparam; assert(gparam->isCanonical() && "generic signature is not canonicalized"); } + } + if (genericSig || patternSubs) { for (auto param : getParameters()) { (void)param; assert(!param.getInterfaceType()->hasError() @@ -3331,6 +3335,11 @@ SILFunctionType::SILFunctionType( assert(!getErrorResult().getInterfaceType()->hasArchetype() && "interface type of result should not contain context archetypes"); } + + if (genericSig && patternSubs) { + assert(!patternSubs.hasArchetypes() + && "pattern substitutions should not contain context archetypes"); + } } for (auto result : getResults()) { (void)result; @@ -3373,21 +3382,22 @@ CanSILFunctionType SILFunctionType::get( ArrayRef yields, ArrayRef normalResults, Optional errorResult, - SubstitutionMap substitutions, - bool genericSigIsImplied, + SubstitutionMap patternSubs, + SubstitutionMap invocationSubs, const ASTContext &ctx, ProtocolConformanceRef witnessMethodConformance) { assert(coroutineKind == SILCoroutineKind::None || normalResults.empty()); assert(coroutineKind != SILCoroutineKind::None || yields.empty()); assert(!ext.isPseudogeneric() || genericSig); - substitutions = substitutions.getCanonical(); + patternSubs = patternSubs.getCanonical(); + invocationSubs = invocationSubs.getCanonical(); llvm::FoldingSetNodeID id; SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee, params, yields, normalResults, errorResult, - witnessMethodConformance, genericSigIsImplied, - substitutions); + witnessMethodConformance, + patternSubs, invocationSubs); // Do we already have this generic function type? void *insertPos; @@ -3400,9 +3410,11 @@ CanSILFunctionType SILFunctionType::get( // See [SILFunctionType-layout] bool hasResultCache = normalResults.size() > 1; size_t bytes = - totalSizeToAlloc( + totalSizeToAlloc( params.size(), normalResults.size() + (errorResult ? 1 : 0), - yields.size(), hasResultCache ? 2 : 0); + yields.size(), (patternSubs ? 1 : 0) + (invocationSubs ? 1 : 0), + hasResultCache ? 2 : 0); void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); @@ -3420,19 +3432,20 @@ CanSILFunctionType SILFunctionType::get( // FIXME: If we ever have first-class polymorphic values, we'll need to // revisit this. - if (genericSig) { + if (genericSig || patternSubs) { properties.removeHasTypeParameter(); properties.removeHasDependentMember(); } - for (auto replacement : substitutions.getReplacementTypes()) { + auto outerSubs = genericSig ? invocationSubs : patternSubs; + for (auto replacement : outerSubs.getReplacementTypes()) { properties |= replacement->getRecursiveProperties(); } auto fnType = new (mem) SILFunctionType(genericSig, ext, coroutineKind, callee, params, yields, normalResults, errorResult, - substitutions, genericSigIsImplied, + patternSubs, invocationSubs, ctx, properties, witnessMethodConformance); assert(fnType->hasResultCache() == hasResultCache); diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 7be40882ef5b2..1b91a213bbb60 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -519,7 +519,7 @@ Type ASTBuilder::createImplFunctionType( return SILFunctionType::get(genericSig, einfo, funcCoroutineKind, funcCalleeConvention, funcParams, funcYields, funcResults, funcErrorResult, - SubstitutionMap(), false, Ctx); + SubstitutionMap(), SubstitutionMap(), Ctx); } Type ASTBuilder::createProtocolCompositionType( diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 02c192d3674b7..a02ac4d0999d3 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3003,6 +3003,31 @@ class PrintTypeRepr : public TypeReprVisitor { OS << " type="; Ty.dump(OS); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + + void visitSILBoxTypeRepr(SILBoxTypeRepr *T) { + printCommon("sil_box"); + Indent += 2; + + ArrayRef Fields = T->getFields(); + for (unsigned i = 0, end = Fields.size(); i != end; ++i) { + OS << '\n'; + printCommon("sil_box_field"); + if (Fields[i].isMutable()) { + OS << " mutable"; + } + OS << '\n'; + printRec(Fields[i].getFieldType()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + + for (auto genArg : T->getGenericArguments()) { + OS << '\n'; + printRec(genArg); + } + + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + Indent -= 2; + } }; } // end anonymous namespace @@ -3654,8 +3679,26 @@ namespace { void visitSILFunctionType(SILFunctionType *T, StringRef label) { printCommon(label, "sil_function_type"); - // FIXME: Print the structure of the type. printField("type", T->getString()); + + for (auto param : T->getParameters()) { + printRec("input", param.getInterfaceType()); + } + for (auto yield : T->getYields()) { + printRec("yield", yield.getInterfaceType()); + } + for (auto result : T->getResults()) { + printRec("result", result.getInterfaceType()); + } + if (auto error = T->getOptionalErrorResult()) { + printRec("error", error->getInterfaceType()); + } + OS << '\n'; + T->getPatternSubstitutions().dump(OS, SubstitutionMap::DumpStyle::Full, + Indent+2); + OS << '\n'; + T->getInvocationSubstitutions().dump(OS, SubstitutionMap::DumpStyle::Full, + Indent+2); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index a7c0548068a37..cb8445fb84dcc 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -357,8 +357,8 @@ std::string ASTMangler::mangleReabstractionThunkHelper( Type SelfType, ModuleDecl *Module) { Mod = Module; - assert(ThunkType->getSubstitutions().empty() && "not implemented"); - GenericSignature GenSig = ThunkType->getSubstGenericSignature(); + assert(ThunkType->getPatternSubstitutions().empty() && "not implemented"); + GenericSignature GenSig = ThunkType->getInvocationGenericSignature(); if (GenSig) CurGenericSignature = GenSig.getCanonicalSignature(); @@ -520,6 +520,10 @@ std::string ASTMangler::mangleTypeAsUSR(Type Ty) { std::string ASTMangler::mangleDeclAsUSR(const ValueDecl *Decl, StringRef USRPrefix) { +#if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB + return std::string(); // not needed for the parser library. +#endif + DWARFMangling = true; beginManglingWithoutPrefix(); llvm::SaveAndRestore allowUnnamedRAII(AllowNamelessEntities, true); @@ -1456,11 +1460,11 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) { llvm::SmallVector OpArgs; - if (fn->getSubstitutions()) { + if (fn->getPatternSubstitutions()) { OpArgs.push_back('s'); - if (!fn->isGenericSignatureImplied()) { - OpArgs.push_back('i'); - } + } + if (fn->getInvocationSubstitutions()) { + OpArgs.push_back('I'); } if (fn->isPolymorphic() && fn->isPseudogeneric()) @@ -1511,6 +1515,9 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) { OpArgs.push_back('G'); break; } + + auto outerGenericSig = CurGenericSignature; + CurGenericSignature = fn->getSubstGenericSignature(); // Mangle the parameters. for (auto param : fn->getParameters()) { @@ -1538,12 +1545,24 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) { OpArgs.push_back(getResultConvention(error.getConvention())); appendType(error.getInterfaceType()); } - if (auto sig = fn->getSubstGenericSignature()) { + + if (auto sig = fn->getInvocationGenericSignature()) { appendGenericSignature(sig); + CurGenericSignature = outerGenericSig; + } + if (auto subs = fn->getInvocationSubstitutions()) { + appendFlatGenericArgs(subs); + appendRetroactiveConformances(subs, Mod); } - if (auto subs = fn->getSubstitutions()) { + if (auto subs = fn->getPatternSubstitutions()) { + appendGenericSignature(subs.getGenericSignature()); + CurGenericSignature = + fn->getInvocationGenericSignature() + ? fn->getInvocationGenericSignature() + : outerGenericSig; appendFlatGenericArgs(subs); appendRetroactiveConformances(subs, Mod); + CurGenericSignature = outerGenericSig; } OpArgs.push_back('_'); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index ff382bbba98f2..648ce629f8c90 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4166,6 +4166,13 @@ class TypePrinter : public TypeVisitor { printFunctionExtInfo(T->getASTContext(), T->getExtInfo(), T->getWitnessMethodConformanceOrInvalid()); printCalleeConvention(T->getCalleeConvention()); + + if (auto sig = T->getInvocationGenericSignature()) { + printGenericSignature(sig, + PrintAST::PrintParams | + PrintAST::PrintRequirements); + Printer << " "; + } // If this is a substituted function type, then its generic signature is // independent of the enclosing context, and defines the parameters active @@ -4178,25 +4185,21 @@ class TypePrinter : public TypeVisitor { TypePrinter *sub = this; Optional subBuffer; PrintOptions subOptions = Options; - if (T->getSubstitutions()) { + if (auto substitutions = T->getPatternSubstitutions()) { subOptions.GenericEnv = nullptr; subBuffer.emplace(Printer, subOptions); sub = &*subBuffer; + + sub->Printer << "@substituted "; + sub->printGenericSignature(substitutions.getGenericSignature(), + PrintAST::PrintParams | + PrintAST::PrintRequirements); + sub->Printer << " "; } // Capture list used here to ensure we don't print anything using `this` // printer, but only the sub-Printer. - [T, sub, &subOptions]{ - if (auto sig = T->getSubstGenericSignature()) { - sub->printGenericSignature(sig, - PrintAST::PrintParams | - PrintAST::PrintRequirements); - sub->Printer << " "; - if (T->isGenericSignatureImplied()) { - sub->Printer << "in "; - } - } - + [T, sub, &subOptions] { sub->Printer << "("; bool first = true; for (auto param : T->getParameters()) { @@ -4205,10 +4208,8 @@ class TypePrinter : public TypeVisitor { } sub->Printer << ") -> "; - unsigned totalResults = - T->getNumYields() + T->getNumResults() + unsigned(T->hasErrorResult()); - - if (totalResults != 1) + bool parenthesizeResults = mustParenthesizeResults(T); + if (parenthesizeResults) sub->Printer << "("; first = true; @@ -4232,17 +4233,41 @@ class TypePrinter : public TypeVisitor { T->getErrorResult().getInterfaceType().print(sub->Printer, subOptions); } - if (totalResults != 1) + if (parenthesizeResults) sub->Printer << ")"; }(); - - // The substitution types are always in terms of the outer environment. - if (auto substitutions = T->getSubstitutions()) { + + // Both the pattern and invocation substitution types are always in + // terms of the outer environment. But this wouldn't necessarily be + // true with higher-rank polymorphism. + if (auto substitutions = T->getPatternSubstitutions()) { + Printer << " for"; + printSubstitutions(substitutions); + } + if (auto substitutions = T->getInvocationSubstitutions()) { Printer << " for"; printSubstitutions(substitutions); } } + static bool mustParenthesizeResults(SILFunctionType *T) { + // If we don't have exactly one result, we must parenthesize. + unsigned totalResults = + T->getNumYields() + T->getNumResults() + unsigned(T->hasErrorResult()); + if (totalResults != 1) + return true; + + // If we have substitutions, we must parenthesize if the single + // result is a function type. + if (!T->hasPatternSubstitutions() && !T->hasInvocationSubstitutions()) + return false; + if (T->getNumResults() == 1) + return isa(T->getResults()[0].getInterfaceType()); + if (T->getNumYields() == 1) + return isa(T->getYields()[0].getInterfaceType()); + return isa(T->getErrorResult().getInterfaceType()); + } + void visitSILBlockStorageType(SILBlockStorageType *T) { Printer << "@block_storage "; printWithParensIfNotSimple(T->getCaptureType()); diff --git a/lib/AST/AutoDiff.cpp b/lib/AST/AutoDiff.cpp index 0f36636810687..1b8dfbb59fbaa 100644 --- a/lib/AST/AutoDiff.cpp +++ b/lib/AST/AutoDiff.cpp @@ -143,7 +143,7 @@ GenericSignature autodiff::getConstrainedDerivativeGenericSignature( GenericSignature derivativeGenSig, LookupConformanceFn lookupConformance, bool isTranspose) { if (!derivativeGenSig) - derivativeGenSig = originalFnTy->getSubstGenericSignature(); + derivativeGenSig = originalFnTy->getInvocationGenericSignature(); if (!derivativeGenSig) return nullptr; auto &ctx = originalFnTy->getASTContext(); diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 0451bc6e3233c..c4f4bb276c874 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -227,7 +227,10 @@ AvailabilityContext ASTContext::getObjCGetClassHookAvailability() { AvailabilityContext ASTContext::getSwift50Availability() { auto target = LangOpts.Target; - + + if (target.getArchName() == "arm64e") + return AvailabilityContext::alwaysAvailable(); + if (target.isMacOSX()) { return AvailabilityContext( VersionRange::allGTE(llvm::VersionTuple(10,14,4))); @@ -253,6 +256,9 @@ AvailabilityContext ASTContext::getObjCClassStubsAvailability() { AvailabilityContext ASTContext::getSwift51Availability() { auto target = LangOpts.Target; + if (target.getArchName() == "arm64e") + return AvailabilityContext::alwaysAvailable(); + if (target.isMacOSX()) { return AvailabilityContext( VersionRange::allGTE(llvm::VersionTuple(10,15,0))); @@ -278,6 +284,9 @@ AvailabilityContext ASTContext::getPrespecializedGenericMetadataAvailability() { AvailabilityContext ASTContext::getSwift52Availability() { auto target = LangOpts.Target; + if (target.getArchName() == "arm64e") + return AvailabilityContext::alwaysAvailable(); + if (target.isMacOSX() ) { return AvailabilityContext( VersionRange::allGTE(llvm::VersionTuple(10, 99, 0))); diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index c3f85c992b6d9..d1d3e27b280fa 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -892,6 +892,15 @@ static ValueDecl *getUnsafeGuaranteedEnd(ASTContext &C, Identifier Id) { return getBuiltinFunction(Id, { Int8Ty }, TupleType::getEmpty(C)); } +static ValueDecl *getTypePtrAuthDiscriminator(ASTContext &C, Identifier Id) { + // (T.Type) -> Int64 + BuiltinFunctionBuilder builder(C); + builder.addParameter(makeMetatype(makeGenericParam())); + Type Int64Ty = BuiltinIntegerType::get(64, C); + builder.setResult(makeConcrete(Int64Ty)); + return builder.build(Id); +} + static ValueDecl *getOnFastPath(ASTContext &Context, Identifier Id) { return getBuiltinFunction(Id, {}, TupleType::getEmpty(Context)); } @@ -2049,6 +2058,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { {}, TupleType::getEmpty(Context)); + case BuiltinValueKind::TypePtrAuthDiscriminator: + return getTypePtrAuthDiscriminator(Context, Id); + case BuiltinValueKind::TypeJoin: return getTypeJoinOperation(Context, Id); diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index aa141e1454ea9..a535950cf82bb 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -34,6 +34,7 @@ #include "swift/Basic/LLVM.h" #include "clang/AST/ASTContext.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/Sema.h" using namespace swift; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index f79ef285d2093..1e77b96aa3737 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3655,21 +3655,20 @@ enum class DeclTypeKind : unsigned { static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) { ASTContext &ctx = decl->getASTContext(); - // Get the parent type. - Type Ty; + // If `decl` is a nested type, find the parent type. + Type ParentTy; DeclContext *dc = decl->getDeclContext(); if (!isa(decl) && dc->isTypeContext()) { switch (kind) { case DeclTypeKind::DeclaredType: { - auto *nominal = dc->getSelfNominalTypeDecl(); - if (nominal) - Ty = nominal->getDeclaredType(); + if (auto *nominal = dc->getSelfNominalTypeDecl()) + ParentTy = nominal->getDeclaredType(); break; } case DeclTypeKind::DeclaredInterfaceType: - Ty = dc->getDeclaredInterfaceType(); - if (Ty->is()) - Ty = Type(); + ParentTy = dc->getDeclaredInterfaceType(); + if (ParentTy->is()) + ParentTy = Type(); break; } } @@ -3677,7 +3676,7 @@ static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) { if (!isa(decl) && decl->getGenericParams()) { switch (kind) { case DeclTypeKind::DeclaredType: - return UnboundGenericType::get(decl, Ty, ctx); + return UnboundGenericType::get(decl, ParentTy, ctx); case DeclTypeKind::DeclaredInterfaceType: { // Note that here, we need to be able to produce a type // before the decl has been validated, so we rely on @@ -3687,13 +3686,13 @@ static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) { for (auto param : decl->getGenericParams()->getParams()) args.push_back(param->getDeclaredInterfaceType()); - return BoundGenericType::get(decl, Ty, args); + return BoundGenericType::get(decl, ParentTy, args); } } llvm_unreachable("Unhandled DeclTypeKind in switch."); } else { - return NominalType::get(decl, Ty, ctx); + return NominalType::get(decl, ParentTy, ctx); } } diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index dc90a47f7714a..026111141f832 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -56,7 +56,12 @@ SubstitutionMap::SubstitutionMap( GenericSignature genericSig, ArrayRef replacementTypes, ArrayRef conformances) - : storage(Storage::get(genericSig, replacementTypes, conformances)) { } + : storage(Storage::get(genericSig, replacementTypes, conformances)) { +#ifndef NDEBUG + if (genericSig->getASTContext().LangOpts.VerifyAllSubstitutionMaps) + verify(); +#endif +} ArrayRef SubstitutionMap::getReplacementTypesBuffer() const { return storage ? storage->getReplacementTypes() : ArrayRef(); @@ -355,8 +360,10 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const { // Check whether the superclass conforms. if (auto superclass = genericSig->getSuperclassBound(type)) { LookUpConformanceInSignature lookup(getGenericSignature().getPointer()); - if (auto conformance = lookup(type->getCanonicalType(), superclass, proto)) + auto substType = type.subst(*this); + if (auto conformance = lookup(type->getCanonicalType(), substType, proto)){ return conformance; + } } // If the type doesn't conform to this protocol, the result isn't formed @@ -474,7 +481,7 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs, newConformances.push_back( conformance.subst(substType, subs, conformances, options)); } - + oldConformances = oldConformances.slice(1); } @@ -657,6 +664,7 @@ void SubstitutionMap::verify() const { if (req.getKind() != RequirementKind::Conformance) continue; + SWIFT_DEFER { ++conformanceIndex; }; auto substType = req.getFirstType().subst(*this); if (substType->isTypeParameter() || substType->is() || @@ -677,15 +685,44 @@ void SubstitutionMap::verify() const { llvm::dbgs() << "SubstitutionMap:\n"; dump(llvm::dbgs()); llvm::dbgs() << "\n"; + llvm::dbgs() << "Requirement:\n"; + req.dump(llvm::dbgs()); + llvm::dbgs() << "\n"; } assert(conformance.isConcrete() && "Conformance should be concrete"); + + if (substType->is()) + continue; + + auto conformanceTy = conformance.getConcrete()->getType(); + if (conformanceTy->hasTypeParameter() + && !substType->hasTypeParameter()) { + conformanceTy = conformance.getConcrete()->getDeclContext() + ->mapTypeIntoContext(conformanceTy); + } + + if (!substType->isEqual(conformanceTy)) { + llvm::dbgs() << "Conformance must match concrete replacement type:\n"; + substType->dump(llvm::dbgs()); + llvm::dbgs() << "Conformance type:\n"; + conformance.getConcrete()->getType()->dump(llvm::dbgs()); + llvm::dbgs() << "Conformance:\n"; + conformance.dump(llvm::dbgs()); + llvm::dbgs() << "\n"; + llvm::dbgs() << "SubstitutionMap:\n"; + dump(llvm::dbgs()); + llvm::dbgs() << "\n"; + llvm::dbgs() << "Requirement:\n"; + req.dump(llvm::dbgs()); + llvm::dbgs() << "\n"; + } + assert(substType->isEqual(conformanceTy) + && "conformance should match corresponding type"); if (substType->isExistentialType()) { assert(isa(conformance.getConcrete()) && "Existential type cannot have normal conformance"); } - - ++conformanceIndex; } #endif } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 1b1e4521b297a..988d6fea07a85 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1493,12 +1493,25 @@ bool TypeBase::isCallableNominalType(DeclContext *dc) { } bool TypeBase::hasDynamicMemberLookupAttribute() { + if (!mayHaveMembers()) + return false; + auto canTy = getCanonicalType(); auto &ctx = canTy->getASTContext(); return evaluateOrDefault( ctx.evaluator, HasDynamicMemberLookupAttributeRequest{canTy}, false); } +bool TypeBase::hasDynamicCallableAttribute() { + if (!mayHaveMembers()) + return false; + + auto canTy = getCanonicalType(); + auto &ctx = canTy->getASTContext(); + return evaluateOrDefault( + ctx.evaluator, HasDynamicCallableAttributeRequest{canTy}, false); +} + Type TypeBase::getSuperclass(bool useArchetypes) { auto *nominalDecl = getAnyNominal(); auto *classDecl = dyn_cast_or_null(nominalDecl); @@ -1769,21 +1782,48 @@ class IsBindableVisitor if (auto substFunc = dyn_cast(subst)) { if (func->getExtInfo() != substFunc->getExtInfo()) return CanType(); - + + if (func->getInvocationGenericSignature() + || substFunc->getInvocationGenericSignature()) { + auto sig = func->getInvocationGenericSignature(); + if (sig != substFunc->getInvocationGenericSignature()) + return CanType(); + + auto origSubs = func->getPatternSubstitutions(); + auto substSubs = substFunc->getPatternSubstitutions(); + + if ((bool) origSubs != (bool) substSubs) + return CanType(); + + for (unsigned i : indices(origSubs.getReplacementTypes())) { + auto origType = + origSubs.getReplacementTypes()[i]->getCanonicalType(sig); + auto substType = + substSubs.getReplacementTypes()[i]->getCanonicalType(sig); + + auto newType = visit(origType, substType, nullptr, {}); + + if (!newType) + return CanType(); + + // We can test SILFunctionTypes for bindability, but we can't + // transform them. + assert(newType == substType + && "cannot transform SILFunctionTypes"); + } + } + // Compare substituted function types. - if (func->getSubstGenericSignature() - || substFunc->getSubstGenericSignature()) { - if (func->getSubstGenericSignature() - != substFunc->getSubstGenericSignature()) + if (func->getPatternGenericSignature() + || substFunc->getPatternGenericSignature()) { + if (func->getPatternGenericSignature() + != substFunc->getPatternGenericSignature()) return CanType(); - auto sig = func->getSubstGenericSignature(); - - auto origSubs = func->getSubstitutions(); - auto substSubs = substFunc->getSubstitutions(); + auto sig = func->getPatternGenericSignature(); - if (!origSubs || !substSubs) - return CanType(); + auto origSubs = func->getPatternSubstitutions(); + auto substSubs = substFunc->getPatternSubstitutions(); for (unsigned i : indices(origSubs.getReplacementTypes())) { auto origType = @@ -2360,7 +2400,7 @@ getForeignRepresentable(Type type, ForeignLanguage language, if (wasOptional && !result.isRepresentableAsOptional()) return failure(); - + // If our nominal type has type arguments, make sure they are // representable as well. Because type arguments are not actually // translated separately, whether they are trivially representable @@ -2407,6 +2447,16 @@ getForeignRepresentable(Type type, ForeignLanguage language, break; } } + + // Specialize the conformance we were given for the type we're testing. + if (result.getKind() == ForeignRepresentableKind::Bridged + && !result.getConformance()->getType()->isEqual(type)) { + auto specialized = type->getASTContext() + .getSpecializedConformance(type, result.getConformance(), + boundGenericType->getContextSubstitutionMap(dc->getParentModule(), + boundGenericType->getDecl())); + result = ForeignRepresentationInfo::forBridged(specialized); + } } return { result.getKind(), result.getConformance() }; @@ -3655,10 +3705,17 @@ static Type substType(Type derivedType, } if (auto silFnTy = dyn_cast(type)) { - if (auto subs = silFnTy->getSubstitutions()) { + if (silFnTy->isPolymorphic()) + return None; + if (auto subs = silFnTy->getInvocationSubstitutions()) { + auto newSubs = subs.subst(substitutions, lookupConformances, options); + return silFnTy->withInvocationSubstitutions(newSubs); + } + if (auto subs = silFnTy->getPatternSubstitutions()) { auto newSubs = subs.subst(substitutions, lookupConformances, options); - return silFnTy->withSubstitutions(newSubs); + return silFnTy->withPatternSubstitutions(newSubs); } + return None; } // Special-case TypeAliasType; we need to substitute conformances. @@ -4180,13 +4237,13 @@ case TypeKind::Id: case TypeKind::SILFunction: { auto fnTy = cast(base); bool changed = false; - - if (auto subs = fnTy->getSubstitutions()) { + + auto updateSubs = [&](SubstitutionMap &subs) -> bool { // This interface isn't suitable for updating the substitution map in a // substituted SILFunctionType. // TODO(SILFunctionType): Is it suitable for any SILFunctionType?? SmallVector newReplacements; - for (Type type : fnTy->getSubstitutions().getReplacementTypes()) { + for (Type type : subs.getReplacementTypes()) { auto transformed = type.transformRec(fn); assert((type->isEqual(transformed) || (type->hasTypeParameter() && transformed->hasTypeParameter())) @@ -4195,12 +4252,29 @@ case TypeKind::Id: if (!type->isEqual(transformed)) changed = true; } - + if (changed) { - auto newSubs = SubstitutionMap::get(fnTy->getSubstitutions().getGenericSignature(), - newReplacements, - fnTy->getSubstitutions().getConformances()); - return fnTy->withSubstitutions(newSubs); + subs = SubstitutionMap::get(subs.getGenericSignature(), + newReplacements, + subs.getConformances()); + } + + return changed; + }; + + if (fnTy->isPolymorphic()) + return fnTy; + + if (auto subs = fnTy->getInvocationSubstitutions()) { + if (updateSubs(subs)) { + return fnTy->withInvocationSubstitutions(subs); + } + return fnTy; + } + + if (auto subs = fnTy->getPatternSubstitutions()) { + if (updateSubs(subs)) { + return fnTy->withPatternSubstitutions(subs); } return fnTy; } @@ -4233,7 +4307,7 @@ case TypeKind::Id: if (!changed) return *this; return SILFunctionType::get( - fnTy->getSubstGenericSignature(), + fnTy->getInvocationGenericSignature(), fnTy->getExtInfo(), fnTy->getCoroutineKind(), fnTy->getCalleeConvention(), @@ -4242,7 +4316,7 @@ case TypeKind::Id: transInterfaceResults, transErrorResult, SubstitutionMap(), - /*genericSigIsImplied*/ false, + SubstitutionMap(), Ptr->getASTContext(), fnTy->getWitnessMethodConformanceOrInvalid()); } @@ -5168,17 +5242,60 @@ AnyFunctionType *AnyFunctionType::getAutoDiffDerivativeFunctionLinearMapType( } CanSILFunctionType -SILFunctionType::withSubstitutions(SubstitutionMap subs) const { - return SILFunctionType::get(getSubstGenericSignature(), +SILFunctionType::withInvocationSubstitutions(SubstitutionMap subs) const { + subs = subs.getCanonical(); + if (subs == getInvocationSubstitutions()) + return CanSILFunctionType(const_cast(this)); + + assert(!subs || CanGenericSignature(subs.getGenericSignature()) + == getInvocationGenericSignature()); + return SILFunctionType::get(getInvocationGenericSignature(), getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), - subs.getCanonical(), isGenericSignatureImplied(), + getPatternSubstitutions(), subs, const_cast(this)->getASTContext(), getWitnessMethodConformanceOrInvalid()); } +CanSILFunctionType +SILFunctionType::withPatternSubstitutions(SubstitutionMap subs) const { + subs = subs.getCanonical(); + if (subs == getPatternSubstitutions()) + return CanSILFunctionType(const_cast(this)); + + assert(!subs || CanGenericSignature(subs.getGenericSignature()) + == getPatternGenericSignature()); + return SILFunctionType::get(getInvocationGenericSignature(), + getExtInfo(), getCoroutineKind(), + getCalleeConvention(), + getParameters(), getYields(), getResults(), + getOptionalErrorResult(), + subs, getInvocationSubstitutions(), + const_cast(this)->getASTContext(), + getWitnessMethodConformanceOrInvalid()); +} + +CanSILFunctionType +SILFunctionType::withPatternSpecialization(CanGenericSignature sig, + SubstitutionMap subs, + ProtocolConformanceRef + witnessConformance) const { + assert(!hasInvocationSubstitutions()); + subs = subs.getCanonical(); + assert(!subs || CanGenericSignature(subs.getGenericSignature()) + == getSubstGenericSignature()); + return SILFunctionType::get(sig, + getExtInfo(), getCoroutineKind(), + getCalleeConvention(), + getParameters(), getYields(), getResults(), + getOptionalErrorResult(), + subs, SubstitutionMap(), + const_cast(this)->getASTContext(), + witnessConformance); +} + SourceLoc swift::extractNearestSourceLoc(Type ty) { if (auto nominal = ty->getAnyNominal()) return extractNearestSourceLoc(nominal); diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index 3491055221da7..aed203667230e 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -118,12 +118,20 @@ class Traversal : public TypeVisitor bool visitSILFunctionType(SILFunctionType *ty) { // TODO: Should this be the only kind of walk we allow? - if (auto subs = ty->getSubstitutions()) { + if (auto subs = ty->getInvocationSubstitutions()) { for (auto paramTy : subs.getReplacementTypes()) { if (doIt(paramTy)) return true; } - + + return false; + } + if (auto subs = ty->getPatternSubstitutions()) { + for (auto paramTy : subs.getReplacementTypes()) { + if (doIt(paramTy)) + return true; + } + return false; } diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index 10346cb67abd3..682f6e1010c61 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -81,6 +81,11 @@ static const SupportedConditionalValue SupportedConditionalCompilationTargetEnvi "macCatalyst", // A synonym for "macabi" when compiling for iOS }; +static const SupportedConditionalValue SupportedConditionalCompilationPtrAuthSchemes[] = { + "_none", + "_arm64e", +}; + static const PlatformConditionKind AllPublicPlatformConditionKinds[] = { #define PLATFORM_CONDITION(LABEL, IDENTIFIER) PlatformConditionKind::LABEL, #define PLATFORM_CONDITION_(LABEL, IDENTIFIER) @@ -101,6 +106,8 @@ ArrayRef getSupportedConditionalCompilationValues(con return { }; case PlatformConditionKind::TargetEnvironment: return SupportedConditionalCompilationTargetEnvironments; + case PlatformConditionKind::PtrAuth: + return SupportedConditionalCompilationPtrAuthSchemes; } llvm_unreachable("Unhandled PlatformConditionKind in switch"); } @@ -162,6 +169,7 @@ checkPlatformConditionSupported(PlatformConditionKind Kind, StringRef Value, case PlatformConditionKind::Endianness: case PlatformConditionKind::Runtime: case PlatformConditionKind::TargetEnvironment: + case PlatformConditionKind::PtrAuth: return isMatching(Kind, Value, suggestedKind, suggestedValues); case PlatformConditionKind::CanImport: // All importable names are valid. @@ -343,6 +351,13 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { addPlatformConditionValue(PlatformConditionKind::Runtime, EnableObjCInterop ? "_ObjC" : "_Native"); + // Set the pointer authentication scheme. + if (Target.getArchName() == "arm64e") { + addPlatformConditionValue(PlatformConditionKind::PtrAuth, "_arm64e"); + } else { + addPlatformConditionValue(PlatformConditionKind::PtrAuth, "_none"); + } + // Set the "targetEnvironment" platform condition if targeting a simulator // environment. Otherwise _no_ value is present for targetEnvironment; it's // an optional disambiguating refinement of the triple. @@ -359,4 +374,4 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { // in the common case. return { false, false }; -} \ No newline at end of file +} diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index 6e9aaafc40f33..0ae286fffc297 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -287,6 +287,7 @@ getArchForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { // .Case ("armv7s", "armv7s") // .Case ("armv7k", "armv7k") // .Case ("armv7", "armv7") + // .Case ("arm64e", "arm64e") .Default(tripleArchName); } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index e51bfac71ec93..52438a688643c 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -722,9 +722,12 @@ addCommonInvocationArguments(std::vector &invocationArgStrs, } else if (triple.isOSDarwin()) { // Special case: arm64 defaults to the "cyclone" CPU for Darwin, + // and arm64e defaults to the "vortex" CPU for Darwin, // but Clang only detects this if we use -arch. - if (triple.getArch() == llvm::Triple::aarch64 || - triple.getArch() == llvm::Triple::aarch64_be) { + if (triple.getArchName() == "arm64e") + invocationArgStrs.push_back("-mcpu=vortex"); + else if (triple.getArch() == llvm::Triple::aarch64 || + triple.getArch() == llvm::Triple::aarch64_be) { invocationArgStrs.push_back("-mcpu=cyclone"); } } else if (triple.getArch() == llvm::Triple::systemz) { diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 21b1e5b3f074a..e833f792390d1 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -47,6 +47,7 @@ #include "clang/AST/Attr.h" #include "clang/Basic/CharInfo.h" #include "swift/Basic/Statistic.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index ce598eff7d0cc..e65fe4a4b924b 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -1740,12 +1740,27 @@ NodePointer Demangler::demangleImplFunctionType() { NodePointer SubstitutionRetroConformances; if (!demangleBoundGenerics(Substitutions, SubstitutionRetroConformances)) return nullptr; - - bool isImplied = !nextIf('i'); - - auto subsNode = createNode(isImplied - ? Node::Kind::ImplImpliedSubstitutions - : Node::Kind::ImplSubstitutions); + + NodePointer sig = popNode(Node::Kind::DependentGenericSignature); + if (!sig) + return nullptr; + + auto subsNode = createNode(Node::Kind::ImplPatternSubstitutions); + subsNode->addChild(sig, *this); + assert(Substitutions.size() == 1); + subsNode->addChild(Substitutions[0], *this); + if (SubstitutionRetroConformances) + subsNode->addChild(SubstitutionRetroConformances, *this); + type->addChild(subsNode, *this); + } + + if (nextIf('I')) { + Vector Substitutions; + NodePointer SubstitutionRetroConformances; + if (!demangleBoundGenerics(Substitutions, SubstitutionRetroConformances)) + return nullptr; + + auto subsNode = createNode(Node::Kind::ImplInvocationSubstitutions); assert(Substitutions.size() == 1); subsNode->addChild(Substitutions[0], *this); if (SubstitutionRetroConformances) diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 63e645316de37..d7113bdddaa8d 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -390,8 +390,8 @@ class NodePrinter { case Node::Kind::ImplConvention: case Node::Kind::ImplFunctionAttribute: case Node::Kind::ImplFunctionType: - case Node::Kind::ImplImpliedSubstitutions: - case Node::Kind::ImplSubstitutions: + case Node::Kind::ImplInvocationSubstitutions: + case Node::Kind::ImplPatternSubstitutions: case Node::Kind::ImplicitClosure: case Node::Kind::ImplParameter: case Node::Kind::ImplResult: @@ -749,12 +749,21 @@ class NodePrinter { } void printImplFunctionType(NodePointer fn) { + NodePointer patternSubs = nullptr; + NodePointer invocationSubs = nullptr; enum State { Attrs, Inputs, Results } curState = Attrs; auto transitionTo = [&](State newState) { assert(newState >= curState); for (; curState != newState; curState = State(curState + 1)) { switch (curState) { - case Attrs: Printer << '('; continue; + case Attrs: + if (patternSubs) { + Printer << "@substituted "; + print(patternSubs->getChild(0)); + Printer << ' '; + } + Printer << '('; + continue; case Inputs: Printer << ") -> ("; continue; case Results: printer_unreachable("no state after Results"); } @@ -773,6 +782,10 @@ class NodePrinter { if (curState == Results) Printer << ", "; transitionTo(Results); print(child); + } else if (child->getKind() == Node::Kind::ImplPatternSubstitutions) { + patternSubs = child; + } else if (child->getKind() == Node::Kind::ImplInvocationSubstitutions) { + invocationSubs = child; } else { assert(curState == Attrs); print(child); @@ -781,6 +794,17 @@ class NodePrinter { } transitionTo(Results); Printer << ')'; + + if (patternSubs) { + Printer << " for <"; + printChildren(patternSubs->getChild(1)); + Printer << '>'; + } + if (invocationSubs) { + Printer << " for <"; + printChildren(invocationSubs->getChild(0)); + Printer << '>'; + } } void printFunctionSigSpecializationParams(NodePointer Node); @@ -2034,13 +2058,17 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { case Node::Kind::ImplFunctionType: printImplFunctionType(Node); return nullptr; - case Node::Kind::ImplSubstitutions: - case Node::Kind::ImplImpliedSubstitutions: + case Node::Kind::ImplInvocationSubstitutions: Printer << "for <"; printChildren(Node->getChild(0), ", "); Printer << '>'; - if (kind == Node::Kind::ImplImpliedSubstitutions) - Printer << " in"; + return nullptr; + case Node::Kind::ImplPatternSubstitutions: + Printer << "@substituted "; + print(Node->getChild(0)); + Printer << " for <"; + printChildren(Node->getChild(1), ", "); + Printer << '>'; return nullptr; case Node::Kind::ErrorType: Printer << ""; diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index 81ff490fd627f..f1f57c374ea6a 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -1267,11 +1267,11 @@ void Remangler::mangleImplEscaping(Node *node) { // The old mangler does not encode escaping. } -void Remangler::mangleImplSubstitutions(Node *node) { +void Remangler::mangleImplPatternSubstitutions(Node *node) { // The old mangler does not encode substituted function types. } -void Remangler::mangleImplImpliedSubstitutions(Node *node) { +void Remangler::mangleImplInvocationSubstitutions(Node *node) { // The old mangler does not encode substituted function types. } diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index e5f99794bb53a..56f2ba18bb748 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -1396,19 +1396,19 @@ void Remangler::mangleImplFunctionAttribute(Node *node) { unreachable("handled inline"); } -void Remangler::mangleImplSubstitutions(Node *node) { +void Remangler::mangleImplInvocationSubstitutions(Node *node) { unreachable("handled inline"); } -void Remangler::mangleImplImpliedSubstitutions(Node *node) { +void Remangler::mangleImplPatternSubstitutions(Node *node) { unreachable("handled inline"); } void Remangler::mangleImplFunctionType(Node *node) { const char *PseudoGeneric = ""; Node *GenSig = nullptr; - Node *GenSubs = nullptr; - bool isImplied; + Node *PatternSubs = nullptr; + Node *InvocationSubs = nullptr; for (NodePointer Child : *node) { switch (auto kind = Child->getKind()) { case Node::Kind::ImplParameter: @@ -1423,10 +1423,11 @@ void Remangler::mangleImplFunctionType(Node *node) { case Node::Kind::DependentGenericSignature: GenSig = Child; break; - case Node::Kind::ImplSubstitutions: - case Node::Kind::ImplImpliedSubstitutions: - GenSubs = Child; - isImplied = kind == Node::Kind::ImplImpliedSubstitutions; + case Node::Kind::ImplPatternSubstitutions: + PatternSubs = Child; + break; + case Node::Kind::ImplInvocationSubstitutions: + InvocationSubs = Child; break; default: break; @@ -1434,20 +1435,26 @@ void Remangler::mangleImplFunctionType(Node *node) { } if (GenSig) mangle(GenSig); - if (GenSubs) { + if (InvocationSubs) { + Buffer << 'y'; + mangleChildNodes(InvocationSubs->getChild(0)); + if (InvocationSubs->getNumChildren() >= 2) + mangleRetroactiveConformance(InvocationSubs->getChild(1)); + } + if (PatternSubs) { + mangle(PatternSubs->getChild(0)); Buffer << 'y'; - mangleChildNodes(GenSubs->getChild(0)); - if (GenSubs->getNumChildren() >= 2) - mangleRetroactiveConformance(GenSubs->getChild(1)); + mangleChildNodes(PatternSubs->getChild(1)); + if (PatternSubs->getNumChildren() >= 3) + mangleRetroactiveConformance(PatternSubs->getChild(2)); } Buffer << 'I'; - if (GenSubs) { + if (PatternSubs) Buffer << 's'; - if (!isImplied) - Buffer << 'i'; - } + if (InvocationSubs) + Buffer << 'I'; Buffer << PseudoGeneric; for (NodePointer Child : *node) { diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 786a37e7a541d..21b51dddc12a6 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -63,7 +63,9 @@ bool ArgsToFrontendOptionsConverter::convert( if (const Arg *A = Args.getLastArg(OPT_prebuilt_module_cache_path)) { Opts.PrebuiltModuleCachePath = A->getValue(); } - + if (const Arg *A = Args.getLastArg(OPT_bridging_header_directory_for_print)) { + Opts.BridgingHeaderDirForPrint = A->getValue(); + } Opts.IndexSystemModules |= Args.hasArg(OPT_index_system_modules); Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 3ea35141fb510..12db9b35232b0 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -565,6 +565,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Target.isOSDarwin()); Opts.EnableSILOpaqueValues |= Args.hasArg(OPT_enable_sil_opaque_values); + Opts.VerifyAllSubstitutionMaps |= Args.hasArg(OPT_verify_all_substitution_maps); + Opts.UseDarwinPreStableABIBit = (Target.isMacOSX() && Target.isMacOSXVersionLT(10, 14, 4)) || (Target.isiOS() && Target.isOSVersionLT(12, 2)) || @@ -795,7 +797,7 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, // Assumes exactly one of setMainExecutablePath() or setRuntimeIncludePath() // is called before setTargetTriple() and parseArgs(). // TODO: improve the handling of RuntimeIncludePath. - + return false; } diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 98fcf822969eb..d56a803c82a15 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -244,8 +244,18 @@ bool ModuleInterfaceBuilder::collectDepsForSerialization( bool ModuleInterfaceBuilder::buildSwiftModuleInternal( StringRef OutPath, bool ShouldSerializeDeps, std::unique_ptr *ModuleBuffer) { + + auto outerPrettyStackState = llvm::SavePrettyStackState(); + bool SubError = false; bool RunSuccess = llvm::CrashRecoveryContext().RunSafelyOnThread([&] { + // Pretend we're on the original thread for pretty-stack-trace purposes. + auto savedInnerPrettyStackState = llvm::SavePrettyStackState(); + llvm::RestorePrettyStackState(outerPrettyStackState); + SWIFT_DEFER { + llvm::RestorePrettyStackState(savedInnerPrettyStackState); + }; + // Note that we don't assume cachePath is the same as the Clang // module cache path at this point. if (!moduleCachePath.empty()) diff --git a/lib/Frontend/PrintingDiagnosticConsumer.cpp b/lib/Frontend/PrintingDiagnosticConsumer.cpp index 490bbf7e934db..ab5808c52986b 100644 --- a/lib/Frontend/PrintingDiagnosticConsumer.cpp +++ b/lib/Frontend/PrintingDiagnosticConsumer.cpp @@ -18,6 +18,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/SourceManager.h" +#include "swift/Markup/Markup.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -28,6 +29,7 @@ #include using namespace swift; +using namespace swift::markup; namespace { class ColoredStream : public raw_ostream { @@ -85,6 +87,190 @@ namespace { size_t preferred_buffer_size() const override { return 0; } }; +// MARK: Markdown Printing + class TerminalMarkupPrinter : public MarkupASTVisitor { + llvm::raw_ostream &OS; + unsigned Indent; + unsigned ShouldBold; + + void indent(unsigned Amount = 2) { Indent += Amount; } + + void dedent(unsigned Amount = 2) { + assert(Indent >= Amount && "dedent without matching indent"); + Indent -= Amount; + } + + void bold() { + ++ShouldBold; + updateFormatting(); + } + + void unbold() { + assert(ShouldBold > 0 && "unbolded without matching bold"); + --ShouldBold; + updateFormatting(); + } + + void updateFormatting() { + OS.resetColor(); + if (ShouldBold > 0) + OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, true); + } + + void print(StringRef Str) { + for (auto c : Str) { + OS << c; + if (c == '\n') + for (unsigned i = 0; i < Indent; ++i) + OS << ' '; + } + } + + public: + TerminalMarkupPrinter(llvm::raw_ostream &OS) + : OS(OS), Indent(0), ShouldBold(0) {} + + void printNewline() { print("\n"); } + + void visitDocument(const Document *D) { + for (const auto *Child : D->getChildren()) { + if (Child->getKind() == ASTNodeKind::Paragraph) { + // Add a newline before top-level paragraphs + printNewline(); + } + visit(Child); + } + } + + void visitBlockQuote(const BlockQuote *BQ) { + indent(); + printNewline(); + for (const auto *Child : BQ->getChildren()) + visit(Child); + dedent(); + } + + void visitList(const List *BL) { + indent(); + printNewline(); + for (const auto *Child : BL->getChildren()) + visit(Child); + dedent(); + } + + void visitItem(const Item *I) { + print("- "); + for (const auto *N : I->getChildren()) + visit(N); + } + + void visitCodeBlock(const CodeBlock *CB) { + indent(); + printNewline(); + print(CB->getLiteralContent()); + dedent(); + } + + void visitCode(const Code *C) { + print("'"); + print(C->getLiteralContent()); + print("'"); + } + + void visitHTML(const HTML *H) { print(H->getLiteralContent()); } + + void visitInlineHTML(const InlineHTML *IH) { + print(IH->getLiteralContent()); + } + + void visitSoftBreak(const SoftBreak *SB) { printNewline(); } + + void visitLineBreak(const LineBreak *LB) { + printNewline(); + printNewline(); + } + + void visitLink(const Link *L) { + print("["); + for (const auto *Child : L->getChildren()) + visit(Child); + print("]("); + print(L->getDestination()); + print(")"); + } + + void visitImage(const Image *I) { llvm_unreachable("unsupported"); } + + void visitParagraph(const Paragraph *P) { + for (const auto *Child : P->getChildren()) + visit(Child); + printNewline(); + } + + // TODO: add raw_ostream support for italics ANSI codes in LLVM. + void visitEmphasis(const Emphasis *E) { + for (const auto *Child : E->getChildren()) + visit(Child); + } + + void visitStrong(const Strong *E) { + bold(); + for (const auto *Child : E->getChildren()) + visit(Child); + unbold(); + } + + void visitHRule(const HRule *HR) { + print("--------------"); + printNewline(); + } + + void visitHeader(const Header *H) { + bold(); + for (const auto *Child : H->getChildren()) + visit(Child); + unbold(); + printNewline(); + } + + void visitText(const Text *T) { print(T->getLiteralContent()); } + + void visitPrivateExtension(const PrivateExtension *PE) { + llvm_unreachable("unsupported"); + } + + void visitParamField(const ParamField *PF) { + llvm_unreachable("unsupported"); + } + + void visitReturnField(const ReturnsField *RF) { + llvm_unreachable("unsupported"); + } + + void visitThrowField(const ThrowsField *TF) { + llvm_unreachable("unsupported"); + } + + #define MARKUP_SIMPLE_FIELD(Id, Keyword, XMLKind) \ + void visit##Id(const Id *Field) { llvm_unreachable("unsupported"); } + #include "swift/Markup/SimpleFields.def" + }; + + static void printMarkdown(StringRef Content, raw_ostream &Out, + bool UseColor) { + markup::MarkupContext ctx; + auto document = markup::parseDocument(ctx, Content); + if (UseColor) { + ColoredStream stream{Out}; + TerminalMarkupPrinter printer(stream); + printer.visit(document); + } else { + NoColorStream stream{Out}; + TerminalMarkupPrinter printer(stream); + printer.visit(document); + } + } + // MARK: Experimental diagnostic printing. static void printDiagnosticKind(DiagnosticKind kind, raw_ostream &out) { @@ -716,8 +902,10 @@ void PrintingDiagnosticConsumer::handleDiagnostic(SourceManager &SM, printDiagnostic(SM, Info); for (auto path : Info.EducationalNotePaths) { - if (auto buffer = SM.getFileSystem()->getBufferForFile(path)) - Stream << buffer->get()->getBuffer() << "\n"; + if (auto buffer = SM.getFileSystem()->getBufferForFile(path)) { + printMarkdown(buffer->get()->getBuffer(), Stream, ForceColors); + Stream << "\n"; + } } for (auto ChildInfo : Info.ChildDiagnosticInfo) { diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7a8d526ada4e1..eb869b11d0be5 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1174,9 +1174,22 @@ static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs( bool hadAnyError = false; if (opts.InputsAndOutputs.hasObjCHeaderOutputPath()) { + std::string BridgingHeaderPathForPrint; + if (!opts.ImplicitObjCHeaderPath.empty()) { + if (opts.BridgingHeaderDirForPrint.hasValue()) { + // User specified preferred directory for including, use that dir. + llvm::SmallString<32> Buffer(*opts.BridgingHeaderDirForPrint); + llvm::sys::path::append(Buffer, + llvm::sys::path::filename(opts.ImplicitObjCHeaderPath)); + BridgingHeaderPathForPrint = Buffer.str(); + } else { + // By default, include the given bridging header path directly. + BridgingHeaderPathForPrint = opts.ImplicitObjCHeaderPath; + } + } hadAnyError |= printAsObjCIfNeeded( Invocation.getObjCHeaderOutputPathForAtMostOnePrimary(), - Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); + Instance.getMainModule(), BridgingHeaderPathForPrint, moduleIsPublic); } if (opts.InputsAndOutputs.hasModuleInterfaceOutputPath()) { diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 2fc6213b12a8d..d078a1c25a5b1 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -3120,6 +3120,17 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } addMethodCall(FD, Reason, dynamicLookupInfo); + + // SE-0253: Callable values of user-defined nominal types. + if (FD->isCallAsFunctionMethod() && !HaveDot && + !ExprType->is()) { + Type funcType = getTypeOfMember(FD, dynamicLookupInfo) + ->castTo() + ->getResult(); + addFunctionCallPattern( + funcType->castTo(), FD, + getSemanticContext(FD, Reason, dynamicLookupInfo)); + } return; } @@ -3925,14 +3936,31 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } } - void addArgNameCompletionResults(ArrayRef Names) { - for (auto Name : Names) { - CodeCompletionResultBuilder Builder(Sink, - CodeCompletionResult::ResultKind::Keyword, - SemanticContextKind::ExpressionSpecific, {}); - Builder.addTextChunk(Name); - Builder.addCallParameterColon(); - Builder.addTypeAnnotation("Argument name"); + void addCallArgumentCompletionResults( + ArrayRef Args) { + Type ContextType; + if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) + ContextType = typeContext->getDeclaredTypeInContext(); + + for (auto *Arg : Args) { + CodeCompletionResultBuilder Builder( + Sink, CodeCompletionResult::ResultKind::Pattern, + SemanticContextKind::ExpressionSpecific, {}); + Builder.addCallParameter(Arg->getLabel(), Identifier(), + Arg->getPlainType(), ContextType, + Arg->isVariadic(), Arg->isInOut(), + /*isIUO=*/false, Arg->isAutoClosure()); + auto Ty = Arg->getPlainType(); + if (Arg->isInOut()) { + Ty = InOutType::get(Ty); + } else if (Arg->isAutoClosure()) { + // 'Ty' may be ErrorType. + if (auto funcTy = Ty->getAs()) + Ty = funcTy->getResult(); + } + addTypeAnnotation(Builder, Ty); + Builder.setExpectedTypeRelation( + CodeCompletionResult::ExpectedTypeRelation::NotApplicable); } } @@ -5421,7 +5449,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { } } else { // Add argument labels, then fallthrough to get values. - Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames()); + Lookup.addCallArgumentCompletionResults(ContextInfo.getPossibleParams()); } if (!Lookup.FoundFunctionCalls || @@ -5559,8 +5587,8 @@ void CodeCompletionCallbacksImpl::doneParsing() { !Lookup.FoundFunctionCalls || (Lookup.FoundFunctionCalls && Lookup.FoundFunctionsWithoutFirstKeyword); - } else if (!ContextInfo.getPossibleNames().empty()) { - Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames()); + } else if (!ContextInfo.getPossibleParams().empty()) { + Lookup.addCallArgumentCompletionResults(ContextInfo.getPossibleParams()); shouldPerformGlobalCompletion = !ContextInfo.getPossibleTypes().empty(); } diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 30ddb04f13747..f523705b97862 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -351,6 +351,14 @@ static void collectPossibleCalleesByQualifiedLookup( DeclContext &DC, Expr *baseExpr, DeclNameRef name, SmallVectorImpl &candidates) { ConcreteDeclRef ref = nullptr; + + // Re-typecheck TypeExpr so it's typechecked without the arguments which may + // affects the inference of the generic arguments. + if (TypeExpr *tyExpr = dyn_cast(baseExpr)) { + tyExpr->setType(nullptr); + tyExpr->getTypeLoc().setType(nullptr); + } + auto baseTyOpt = getTypeOfCompletionContextExpr( DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, baseExpr, ref); if (!baseTyOpt) @@ -435,8 +443,13 @@ static bool collectPossibleCalleesForApply( auto baseTy = AMT->getInstanceType(); if (isa(fnExpr) && baseTy->mayHaveMembers()) { collectPossibleCalleesByQualifiedLookup( - DC, AMT, DeclNameRef::createConstructor(), candidates); + DC, fnExpr, DeclNameRef::createConstructor(), candidates); } + } else { + // Otherwise, look for `callAsFunction` (SE-0253). + collectPossibleCalleesByQualifiedLookup( + DC, fnExpr, DeclNameRef(DC.getASTContext().Id_callAsFunction), + candidates); } return !candidates.empty(); @@ -524,7 +537,7 @@ class ExprContextAnalyzer { // Results populated by Analyze() SmallVectorImpl &PossibleTypes; - SmallVectorImpl &PossibleNames; + SmallVectorImpl &PossibleParams; SmallVectorImpl &PossibleCallees; bool &singleExpressionBody; @@ -535,7 +548,9 @@ class ExprContextAnalyzer { PossibleTypes.push_back(ty->getRValueType()); } - void recordPossibleName(StringRef name) { PossibleNames.push_back(name); } + void recordPossibleParam(const AnyFunctionType::Param &arg) { + PossibleParams.push_back(&arg); + } /// Collect context information at call argument position. bool analyzeApplyExpr(Expr *E) { @@ -572,7 +587,7 @@ class ExprContextAnalyzer { (isa(E) | isa(E) || isa(E)); SmallPtrSet seenTypes; - SmallPtrSet seenNames; + llvm::SmallSet, 4> seenArgs; for (auto &typeAndDecl : Candidates) { DeclContext *memberDC = nullptr; if (typeAndDecl.Decl) @@ -590,23 +605,27 @@ class ExprContextAnalyzer { } for (auto Pos = Position; Pos < Params.size(); ++Pos) { const auto &Param = Params[Pos]; + Type ty = Param.getPlainType(); + if (memberDC && ty->hasTypeParameter()) + ty = memberDC->mapTypeIntoContext(ty); + if (Param.hasLabel() && MayNeedName) { - if (seenNames.insert(Param.getLabel()).second) - recordPossibleName(Param.getLabel().str()); + if (seenArgs.insert({Param.getLabel(), ty.getPointer()}).second) + recordPossibleParam(Param); if (paramList && paramList->get(Position)->isDefaultArgument()) continue; } else { - Type ty = Param.getOldType(); - if (memberDC && ty->hasTypeParameter()) - ty = memberDC->mapTypeIntoContext(ty); - if (seenTypes.insert(ty.getPointer()).second) - recordPossibleType(ty); + auto argTy = ty; + if (Param.isInOut()) + argTy = InOutType::get(argTy); + if (seenTypes.insert(argTy.getPointer()).second) + recordPossibleType(argTy); } break; } } } - return !PossibleTypes.empty() || !PossibleNames.empty(); + return !PossibleTypes.empty() || !PossibleParams.empty(); } void analyzeExpr(Expr *Parent) { @@ -866,14 +885,14 @@ class ExprContextAnalyzer { } public: - ExprContextAnalyzer(DeclContext *DC, Expr *ParsedExpr, - SmallVectorImpl &PossibleTypes, - SmallVectorImpl &PossibleNames, - SmallVectorImpl &PossibleCallees, - bool &singleExpressionBody) + ExprContextAnalyzer( + DeclContext *DC, Expr *ParsedExpr, SmallVectorImpl &PossibleTypes, + SmallVectorImpl &PossibleArgs, + SmallVectorImpl &PossibleCallees, + bool &singleExpressionBody) : DC(DC), ParsedExpr(ParsedExpr), SM(DC->getASTContext().SourceMgr), Context(DC->getASTContext()), PossibleTypes(PossibleTypes), - PossibleNames(PossibleNames), PossibleCallees(PossibleCallees), + PossibleParams(PossibleArgs), PossibleCallees(PossibleCallees), singleExpressionBody(singleExpressionBody) {} void Analyze() { @@ -977,7 +996,7 @@ class ExprContextAnalyzer { } // end anonymous namespace ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) { - ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleNames, + ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleParams, PossibleCallees, singleExpressionBody); Analyzer.Analyze(); } diff --git a/lib/IDE/ExprContextAnalysis.h b/lib/IDE/ExprContextAnalysis.h index 5844603ec5517..bab0306057b9a 100644 --- a/lib/IDE/ExprContextAnalysis.h +++ b/lib/IDE/ExprContextAnalysis.h @@ -14,6 +14,7 @@ #define SWIFT_IDE_EXPRCONTEXTANALYSIS_H #include "swift/AST/Type.h" +#include "swift/AST/Types.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/SourceLoc.h" @@ -21,7 +22,6 @@ namespace swift { class DeclContext; class Expr; class ValueDecl; -class AnyFunctionType; namespace ide { enum class SemanticContextKind; @@ -54,7 +54,7 @@ struct FunctionTypeAndDecl { /// the expected type of the expression by analyzing its context. class ExprContextInfo { SmallVector PossibleTypes; - SmallVector PossibleNames; + SmallVector PossibleParams; SmallVector PossibleCallees; bool singleExpressionBody = false; @@ -73,7 +73,9 @@ class ExprContextInfo { // Returns a list of possible argument label names. // Valid only if \c getKind() is \c CallArgument. - ArrayRef getPossibleNames() const { return PossibleNames; } + ArrayRef getPossibleParams() const { + return PossibleParams; + } // Returns a list of possible callee // Valid only if \c getKind() is \c CallArgument. diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 41e15051c89d7..7ffe04cbe5b31 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -19,6 +19,7 @@ #include "swift/Subsystems.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt index 3c17f67add2aa..683a1ba91f145 100644 --- a/lib/IRGen/CMakeLists.txt +++ b/lib/IRGen/CMakeLists.txt @@ -27,6 +27,7 @@ add_swift_host_library(swiftIRGen STATIC GenMeta.cpp GenObjC.cpp GenOpaque.cpp + GenPointerAuth.cpp GenPoly.cpp GenProto.cpp GenReflection.cpp diff --git a/lib/IRGen/Callee.h b/lib/IRGen/Callee.h index a6e136a988657..5d134d4ac205d 100644 --- a/lib/IRGen/Callee.h +++ b/lib/IRGen/Callee.h @@ -19,16 +19,22 @@ #define SWIFT_IRGEN_CALLEE_H #include +#include "swift/AST/IRGenOptions.h" #include "llvm/IR/DerivedTypes.h" #include "swift/SIL/SILType.h" #include "IRGen.h" #include "Signature.h" +namespace llvm { + class ConstantInt; +} + namespace swift { namespace irgen { class Callee; class IRGenFunction; + class PointerAuthEntity; class CalleeInfo { public: @@ -50,31 +56,104 @@ namespace irgen { } }; + /// Information necessary for pointer authentication. + class PointerAuthInfo { + unsigned Signed : 1; + unsigned Key : 31; + llvm::Value *Discriminator; + public: + PointerAuthInfo() { + Signed = false; + } + PointerAuthInfo(unsigned key, llvm::Value *discriminator) + : Discriminator(discriminator) { + assert(discriminator->getType()->isIntegerTy() || + discriminator->getType()->isPointerTy()); + Signed = true; + Key = key; + } + + static PointerAuthInfo emit(IRGenFunction &IGF, + const PointerAuthSchema &schema, + llvm::Value *storageAddress, + const PointerAuthEntity &entity); + + static PointerAuthInfo forFunctionPointer(IRGenModule &IGM, + CanSILFunctionType fnType); + + static llvm::ConstantInt *getOtherDiscriminator(IRGenModule &IGM, + const PointerAuthSchema &schema, + const PointerAuthEntity &entity); + + explicit operator bool() const { + return isSigned(); + } + + bool isSigned() const { + return Signed; + } + + bool isConstant() const { + return (!isSigned() || isa(Discriminator)); + } + + unsigned getKey() const { + assert(isSigned()); + return Key; + } + llvm::Value *getDiscriminator() const { + assert(isSigned()); + return Discriminator; + } + + /// Are the auth infos obviously the same? + friend bool operator==(const PointerAuthInfo &lhs, + const PointerAuthInfo &rhs) { + if (!lhs.Signed) + return !rhs.Signed; + if (!rhs.Signed) + return false; + + return (lhs.Key == rhs.Key && lhs.Discriminator == rhs.Discriminator); + } + friend bool operator!=(const PointerAuthInfo &lhs, + const PointerAuthInfo &rhs) { + return !(lhs == rhs); + } + }; + /// A function pointer value. class FunctionPointer { /// The actual function pointer. llvm::Value *Value; + PointerAuthInfo AuthInfo; + Signature Sig; public: /// Construct a FunctionPointer for an arbitrary pointer value. /// We may add more arguments to this; try to use the other /// constructors/factories if possible. - explicit FunctionPointer(llvm::Value *value, const Signature &signature) - : Value(value), Sig(signature) { + explicit FunctionPointer(llvm::Value *value, PointerAuthInfo authInfo, + const Signature &signature) + : Value(value), AuthInfo(authInfo), Sig(signature) { // The function pointer should have function type. assert(value->getType()->getPointerElementType()->isFunctionTy()); // TODO: maybe assert similarity to signature.getType()? } + // Temporary only! + explicit FunctionPointer(llvm::Value *value, const Signature &signature) + : FunctionPointer(value, PointerAuthInfo(), signature) {} + static FunctionPointer forDirect(IRGenModule &IGM, llvm::Constant *value, CanSILFunctionType fnType); static FunctionPointer forDirect(llvm::Constant *value, const Signature &signature) { - return FunctionPointer(value, signature); + return FunctionPointer(value, PointerAuthInfo(), signature); } static FunctionPointer forExplosionValue(IRGenFunction &IGF, @@ -84,7 +163,7 @@ namespace irgen { /// Is this function pointer completely constant? That is, can it /// be safely moved to a different function context? bool isConstant() const { - return (isa(Value)); + return (isa(Value) && AuthInfo.isConstant()); } /// Return the actual function pointer. @@ -101,6 +180,10 @@ namespace irgen { Value->getType()->getPointerElementType()); } + const PointerAuthInfo &getAuthInfo() const { + return AuthInfo; + } + const Signature &getSignature() const { return Sig; } diff --git a/lib/IRGen/ConstantBuilder.h b/lib/IRGen/ConstantBuilder.h index 8c85f8d3c2a33..ec10026ab5fcb 100644 --- a/lib/IRGen/ConstantBuilder.h +++ b/lib/IRGen/ConstantBuilder.h @@ -24,8 +24,13 @@ #include "IRGenModule.h" #include "IRGenFunction.h" +namespace clang { +class PointerAuthSchema; +} + namespace swift { namespace irgen { +class PointerAuthEntity; class ConstantAggregateBuilderBase; class ConstantStructBuilder; @@ -140,6 +145,15 @@ class ConstantAggregateBuilderBase llvm::ArrayType::get(IGM().Int8Ty, align.getValue() - misalignment.getValue()))); } + + using super::addSignedPointer; + void addSignedPointer(llvm::Constant *pointer, + const clang::PointerAuthSchema &schema, + const PointerAuthEntity &entity); + + void addSignedPointer(llvm::Constant *pointer, + const clang::PointerAuthSchema &schema, + uint16_t otherDiscriminator); }; class ConstantArrayBuilder diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index 0dae3c3f72bde..c0f771259286b 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -28,6 +28,7 @@ #include "Explosion.h" #include "GenCall.h" #include "GenCast.h" +#include "GenPointerAuth.h" #include "GenIntegerLiteral.h" #include "IRGenFunction.h" #include "IRGenModule.h" @@ -1020,6 +1021,17 @@ if (Builtin.ID == BuiltinValueKind::id) { \ entrypointArgs); return; } + + if (Builtin.ID == BuiltinValueKind::TypePtrAuthDiscriminator) { + (void)args.claimAll(); + Type valueTy = substitutions.getReplacementTypes()[0]; + + // The type should lower statically to a SILFunctionType. + auto loweredTy = IGF.IGM.getLoweredType(valueTy).castTo(); + + out.add(PointerAuthEntity(loweredTy).getTypeDiscriminator(IGF.IGM)); + return; + } if (Builtin.ID == BuiltinValueKind::IsSameMetatype) { auto metatypeLHS = args.claimNext(); diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index db623ab9f4694..9c962ce94d5e3 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -29,11 +29,13 @@ #include "swift/ABI/MetadataValues.h" #include "swift/Runtime/Config.h" #include "llvm/IR/CallSite.h" +#include "llvm/IR/GlobalPtrAuthInfo.h" #include "llvm/Support/Compiler.h" #include "CallEmission.h" #include "Explosion.h" #include "GenObjC.h" +#include "GenPointerAuth.h" #include "GenPoly.h" #include "GenProto.h" #include "GenType.h" @@ -1647,8 +1649,19 @@ llvm::CallSite CallEmission::emitCallSite() { llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn, ArrayRef args) { + SmallVector bundles; + + // Add a pointer-auth bundle if necessary. + if (const auto &authInfo = fn.getAuthInfo()) { + auto key = getInt32(authInfo.getKey()); + auto discriminator = authInfo.getDiscriminator(); + llvm::Value *bundleArgs[] = { key, discriminator }; + bundles.emplace_back("ptrauth", bundleArgs); + } + assert(!isTrapIntrinsic(fn.getPointer()) && "Use CreateNonMergeableTrap"); - llvm::CallInst *call = IRBuilderBase::CreateCall(fn.getPointer(), args); + llvm::CallInst *call = + IRBuilderBase::CreateCall(fn.getPointer(), args, bundles); call->setAttributes(fn.getAttributes()); call->setCallingConv(fn.getCallingConv()); return call; @@ -2559,6 +2572,22 @@ void irgen::emitForeignParameter(IRGenFunction &IGF, Explosion ¶ms, } } +std::pair +irgen::getCoroutineResumeFunctionPointerAuth(IRGenModule &IGM, + CanSILFunctionType fnType) { + switch (fnType->getCoroutineKind()) { + case SILCoroutineKind::None: + llvm_unreachable("not a coroutine"); + case SILCoroutineKind::YieldMany: + return { IGM.getOptions().PointerAuth.YieldManyResumeFunctions, + PointerAuthEntity::forYieldTypes(fnType) }; + case SILCoroutineKind::YieldOnce: + return { IGM.getOptions().PointerAuth.YieldOnceResumeFunctions, + PointerAuthEntity::forYieldTypes(fnType) }; + } + llvm_unreachable("bad coroutine kind"); +} + static void emitRetconCoroutineEntry(IRGenFunction &IGF, CanSILFunctionType fnType, Explosion &allParamValues, @@ -3473,7 +3502,12 @@ Callee irgen::getBlockPointerCallee(IRGenFunction &IGF, auto sig = emitCastOfFunctionPointer(IGF, invokeFnPtr, info.OrigFnType); - FunctionPointer fn(invokeFnPtr, sig); + auto &schema = IGF.getOptions().PointerAuth.BlockInvocationFunctionPointers; + auto authInfo = PointerAuthInfo::emit(IGF, schema, + invokeFnPtrAddr.getAddress(), + info.OrigFnType); + + FunctionPointer fn(invokeFnPtr, authInfo, sig); return Callee(std::move(info), fn, blockPtr); } @@ -3482,8 +3516,10 @@ Callee irgen::getSwiftFunctionPointerCallee( IRGenFunction &IGF, llvm::Value *fnPtr, llvm::Value *dataPtr, CalleeInfo &&calleeInfo, bool castOpaqueToRefcountedContext) { auto sig = emitCastOfFunctionPointer(IGF, fnPtr, calleeInfo.OrigFnType); + auto authInfo = + PointerAuthInfo::forFunctionPointer(IGF.IGM, calleeInfo.OrigFnType); - FunctionPointer fn(fnPtr, sig); + FunctionPointer fn(fnPtr, authInfo, sig); if (castOpaqueToRefcountedContext) { assert(dataPtr && dataPtr->getType() == IGF.IGM.OpaquePtrTy && "Expecting trivial closure context"); @@ -3496,8 +3532,10 @@ Callee irgen::getCFunctionPointerCallee(IRGenFunction &IGF, llvm::Value *fnPtr, CalleeInfo &&calleeInfo) { auto sig = emitCastOfFunctionPointer(IGF, fnPtr, calleeInfo.OrigFnType); + auto authInfo = + PointerAuthInfo::forFunctionPointer(IGF.IGM, calleeInfo.OrigFnType); - FunctionPointer fn(fnPtr, sig); + FunctionPointer fn(fnPtr, authInfo, sig); return Callee(std::move(calleeInfo), fn); } @@ -3514,16 +3552,24 @@ FunctionPointer::forExplosionValue(IRGenFunction &IGF, llvm::Value *fnPtr, // Bitcast out of an opaque pointer type. assert(fnPtr->getType() == IGF.IGM.Int8PtrTy); auto sig = emitCastOfFunctionPointer(IGF, fnPtr, fnType); + auto authInfo = PointerAuthInfo::forFunctionPointer(IGF.IGM, fnType); - return FunctionPointer(fnPtr, sig); + return FunctionPointer(fnPtr, authInfo, sig); } llvm::Value * FunctionPointer::getExplosionValue(IRGenFunction &IGF, CanSILFunctionType fnType) const { + llvm::Value *fnPtr = getPointer(); + + // Re-sign to the appropriate schema for this function pointer type. + auto resultAuthInfo = PointerAuthInfo::forFunctionPointer(IGF.IGM, fnType); + if (getAuthInfo() != resultAuthInfo) { + fnPtr = emitPointerAuthResign(IGF, fnPtr, getAuthInfo(), resultAuthInfo); + } + // Bitcast to an opaque pointer type. - llvm::Value *fnPtr = - IGF.Builder.CreateBitCast(getPointer(), IGF.IGM.Int8PtrTy); + fnPtr = IGF.Builder.CreateBitCast(fnPtr, IGF.IGM.Int8PtrTy); return fnPtr; } diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index a80fe7cbb7048..e57de5c373a49 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -46,6 +46,7 @@ #include "GenFunc.h" #include "GenMeta.h" #include "GenObjC.h" +#include "GenPointerAuth.h" #include "GenProto.h" #include "GenType.h" #include "IRGenDebugInfo.h" @@ -1377,9 +1378,12 @@ namespace { if (hasUpdater) { // Class _Nullable (*metadataUpdateCallback)(Class _Nonnull cls, // void * _Nullable arg); - b.add(IGM.getAddrOfObjCMetadataUpdateFunction( + auto *impl = IGM.getAddrOfObjCMetadataUpdateFunction( TheEntity.get(), - NotForDefinition)); + NotForDefinition); + const auto &schema = + IGM.getOptions().PointerAuth.ObjCMethodListFunctionPointers; + b.addSignedPointer(impl, schema, PointerAuthEntity()); } // }; @@ -2441,7 +2445,11 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF, IGF.IGM.getPointerAlignment()); auto fnPtr = IGF.emitInvariantLoad(slot); - return FunctionPointer(fnPtr, signature); + auto &schema = IGF.getOptions().PointerAuth.SwiftClassMethods; + auto authInfo = + PointerAuthInfo::emit(IGF, schema, slot.getAddress(), method); + + return FunctionPointer(fnPtr, authInfo, signature); } FunctionPointer diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index ad22ef1c70374..81a73903bfe8e 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -60,6 +60,7 @@ #include "GenMeta.h" #include "GenObjC.h" #include "GenOpaque.h" +#include "GenPointerAuth.h" #include "GenProto.h" #include "GenType.h" #include "IRGenDebugInfo.h" @@ -1463,6 +1464,22 @@ static llvm::GlobalVariable *getChainEntryForDynamicReplacement( auto *funPtr = implFunction ? llvm::ConstantExpr::getBitCast(implFunction, IGM.Int8PtrTy) : llvm::ConstantExpr::getNullValue(IGM.Int8PtrTy); + + if (implFunction) { + llvm::Constant *indices[] = {llvm::ConstantInt::get(IGM.Int32Ty, 0), + llvm::ConstantInt::get(IGM.Int32Ty, 0)}; + auto *storageAddr = llvm::ConstantExpr::getInBoundsGetElementPtr( + nullptr, linkEntry, indices); + + auto &schema = IGM.getOptions().PointerAuth.SwiftDynamicReplacements; + assert(entity.hasSILFunction() || entity.isOpaqueTypeDescriptorAccessor()); + auto authEntity = entity.hasSILFunction() + ? PointerAuthEntity(entity.getSILFunction()) + : PointerAuthEntity::Special::TypeDescriptor; + funPtr = + IGM.getConstantSignedPointer(funPtr, schema, authEntity, storageAddr); + } + auto *nextEntry = llvm::ConstantExpr::getNullValue(IGM.DynamicReplacementLinkEntryPtrTy); llvm::Constant *fields[] = {funPtr, nextEntry}; @@ -1708,8 +1725,8 @@ void IRGenModule::emitVTableStubs() { static IRLinkage getIRLinkage(const UniversalLinkageInfo &info, SILLinkage linkage, - ForDefinition_t isDefinition, - bool isWeakImported) { + ForDefinition_t isDefinition, bool isWeakImported, + bool isKnownLocal = false) { #define RESULT(LINKAGE, VISIBILITY, DLL_STORAGE) \ IRLinkage{llvm::GlobalValue::LINKAGE##Linkage, \ llvm::GlobalValue::VISIBILITY##Visibility, \ @@ -1749,7 +1766,8 @@ getIRLinkage(const UniversalLinkageInfo &info, SILLinkage linkage, case SILLinkage::Private: { if (info.forcePublicDecls() && !isDefinition) return getIRLinkage(info, SILLinkage::PublicExternal, isDefinition, - isWeakImported); + isWeakImported, isKnownLocal); + auto linkage = info.needLinkerToMergeDuplicateSymbols() ? llvm::GlobalValue::LinkOnceODRLinkage : llvm::GlobalValue::InternalLinkage; @@ -1765,7 +1783,10 @@ getIRLinkage(const UniversalLinkageInfo &info, SILLinkage linkage, auto linkage = isWeakImported ? llvm::GlobalValue::ExternalWeakLinkage : llvm::GlobalValue::ExternalLinkage; - return {linkage, llvm::GlobalValue::DefaultVisibility, ImportedStorage}; + return {linkage, llvm::GlobalValue::DefaultVisibility, + isKnownLocal + ? llvm::GlobalValue::DefaultStorageClass + : ImportedStorage}; } case SILLinkage::HiddenExternal: @@ -1774,8 +1795,10 @@ getIRLinkage(const UniversalLinkageInfo &info, SILLinkage linkage, return RESULT(AvailableExternally, Hidden, Default); return {llvm::GlobalValue::ExternalLinkage, - llvm::GlobalValue::DefaultVisibility, ImportedStorage}; - + llvm::GlobalValue::DefaultVisibility, + isKnownLocal + ? llvm::GlobalValue::DefaultStorageClass + : ImportedStorage}; } llvm_unreachable("bad SIL linkage"); @@ -1790,9 +1813,15 @@ void irgen::updateLinkageForDefinition(IRGenModule &IGM, // entire linkage computation. UniversalLinkageInfo linkInfo(IGM); bool weakImported = entity.isWeakImported(IGM.getSwiftModule()); + + bool isKnownLocal = entity.isAlwaysSharedLinkage(); + if (const auto *DC = entity.getDeclContextForEmission()) + if (const auto *MD = DC->getParentModule()) + isKnownLocal = IGM.getSwiftModule() == MD; + auto IRL = getIRLinkage(linkInfo, entity.getLinkage(ForDefinition), - ForDefinition, weakImported); + ForDefinition, weakImported, isKnownLocal); ApplyIRLinkage(IRL).to(global); // Everything externally visible is considered used in Swift. @@ -1817,21 +1846,16 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo, const LinkEntity &entity, ForDefinition_t isDefinition) { LinkInfo result; - // FIXME: For anything in the standard library, we assume is locally defined. - // The only two ways imported interfaces are currently created is via a shims - // interface where the ClangImporter will correctly give us the proper DLL - // storage for the declaration. Otherwise, it is from a `@_silgen_name` - // attributed declaration, which we explicitly handle elsewhere. So, in the - // case of a standard library build, just assume everything is locally - // defined. Ideally, we would integrate the linkage calculation properly to - // avoid this special casing. - ForDefinition_t isStdlibOrDefinition = - ForDefinition_t(swiftModule->isStdlibModule() || isDefinition); + + bool isKnownLocal = entity.isAlwaysSharedLinkage(); + if (const auto *DC = entity.getDeclContextForEmission()) + if (const auto *MD = DC->getParentModule()) + isKnownLocal = MD == swiftModule; entity.mangle(result.Name); bool weakImported = entity.isWeakImported(swiftModule); - result.IRL = getIRLinkage(linkInfo, entity.getLinkage(isStdlibOrDefinition), - isDefinition, weakImported); + result.IRL = getIRLinkage(linkInfo, entity.getLinkage(isDefinition), + isDefinition, weakImported, isKnownLocal); result.ForDefinition = isDefinition; return result; } @@ -2312,7 +2336,17 @@ static llvm::GlobalVariable *createGlobalForDynamicReplacementFunctionKey( ConstantInitBuilder builder(IGM); auto B = builder.beginStruct(IGM.DynamicReplacementKeyTy); B.addRelativeAddress(linkEntry); - B.addInt32(0); + auto schema = IGM.getOptions().PointerAuth.SwiftDynamicReplacements; + if (schema) { + assert(keyEntity.hasSILFunction() || + keyEntity.isOpaqueTypeDescriptorAccessor()); + auto authEntity = keyEntity.hasSILFunction() + ? PointerAuthEntity(keyEntity.getSILFunction()) + : PointerAuthEntity::Special::TypeDescriptor; + B.addInt32(PointerAuthInfo::getOtherDiscriminator(IGM, schema, authEntity) + ->getZExtValue()); + } else + B.addInt32(0); B.finishAndSetAsInitializer(key); key->setConstant(true); IGM.setTrueConstGlobal(key); @@ -2352,20 +2386,25 @@ void IRGenModule::createReplaceableProlog(IRGenFunction &IGF, SILFunction *f) { auto *FnAddr = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( IGF.CurFn, FunctionPtrTy); - llvm::Value *ReplFn = nullptr, *rhs = nullptr; + auto &schema = getOptions().PointerAuth.SwiftDynamicReplacements; + llvm::Value *ReplFn = nullptr, *hasReplFn = nullptr; if (UseBasicDynamicReplacement) { ReplFn = IGF.Builder.CreateLoad(fnPtrAddr, getPointerAlignment()); - rhs = FnAddr; + llvm::Value *lhs = ReplFn; + if (schema.isEnabled()) { + lhs = emitPointerAuthStrip(IGF, lhs, schema.getKey()); + } + hasReplFn = IGF.Builder.CreateICmpEQ(lhs, FnAddr); } else { // Call swift_getFunctionReplacement to check which function to call. auto *callRTFunc = IGF.Builder.CreateCall(getGetReplacementFn(), {ReplAddr, FnAddr}); callRTFunc->setDoesNotThrow(); ReplFn = callRTFunc; - rhs = llvm::ConstantExpr::getNullValue(ReplFn->getType()); + hasReplFn = IGF.Builder.CreateICmpEQ(ReplFn, + llvm::ConstantExpr::getNullValue(ReplFn->getType())); } - auto *hasReplFn = IGF.Builder.CreateICmpEQ(ReplFn, rhs); auto *replacedBB = IGF.createBasicBlock("forward_to_replaced"); auto *origEntryBB = IGF.createBasicBlock("original_entry"); @@ -2380,7 +2419,11 @@ void IRGenModule::createReplaceableProlog(IRGenFunction &IGF, SILFunction *f) { auto *fnType = signature.getType()->getPointerTo(); auto *realReplFn = IGF.Builder.CreateBitCast(ReplFn, fnType); - auto *Res = IGF.Builder.CreateCall(FunctionPointer(realReplFn, signature), + auto authEntity = PointerAuthEntity(f); + auto authInfo = PointerAuthInfo::emit(IGF, schema, fnPtrAddr, authEntity); + + auto *Res = IGF.Builder.CreateCall(FunctionPointer(realReplFn, authInfo, + signature), forwardedArgs); Res->setTailCall(); if (IGF.CurFn->getReturnType()->isVoidTy()) @@ -2417,16 +2460,26 @@ static void emitDynamicallyReplaceableThunk(IRGenModule &IGM, IGM.DebugInfo->emitArtificialFunction(IGF, dispatchFn); llvm::Constant *indices[] = {llvm::ConstantInt::get(IGM.Int32Ty, 0), llvm::ConstantInt::get(IGM.Int32Ty, 0)}; - auto *fnPtr = IGF.Builder.CreateLoad( - llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, linkEntry, indices), - IGM.getPointerAlignment()); - auto *typeFnPtr = - IGF.Builder.CreateBitOrPointerCast(fnPtr, implFn->getType()); + + auto *fnPtrAddr = + llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, linkEntry, indices); + auto *fnPtr = IGF.Builder.CreateLoad(fnPtrAddr, IGM.getPointerAlignment()); + auto *typeFnPtr = IGF.Builder.CreateBitOrPointerCast(fnPtr, implFn->getType()); + SmallVector forwardedArgs; for (auto &arg : dispatchFn->args()) forwardedArgs.push_back(&arg); - auto *Res = IGF.Builder.CreateCall(FunctionPointer(typeFnPtr, signature), - forwardedArgs); + + auto &schema = IGM.getOptions().PointerAuth.SwiftDynamicReplacements; + assert(keyEntity.hasSILFunction() || + keyEntity.isOpaqueTypeDescriptorAccessor()); + auto authEntity = keyEntity.hasSILFunction() + ? PointerAuthEntity(keyEntity.getSILFunction()) + : PointerAuthEntity::Special::TypeDescriptor; + auto authInfo = PointerAuthInfo::emit(IGF, schema, fnPtrAddr, authEntity); + auto *Res = IGF.Builder.CreateCall( + FunctionPointer(typeFnPtr, authInfo, signature), forwardedArgs); + Res->setTailCall(); if (implFn->getReturnType()->isVoidTy()) IGF.Builder.CreateRetVoid(); @@ -2535,8 +2588,13 @@ void IRGenModule::emitDynamicReplacementOriginalFunctionThunk(SILFunction *f) { SmallVector forwardedArgs; for (auto &arg : implFn->args()) forwardedArgs.push_back(&arg); - auto *Res = IGF.Builder.CreateCall(FunctionPointer(typeFnPtr, signature), - forwardedArgs); + + auto &schema = getOptions().PointerAuth.SwiftDynamicReplacements; + auto authInfo = PointerAuthInfo::emit( + IGF, schema, fnPtrAddr, + PointerAuthEntity(f->getDynamicallyReplacedFunction())); + auto *Res = IGF.Builder.CreateCall( + FunctionPointer(typeFnPtr, authInfo, signature), forwardedArgs); if (implFn->getReturnType()->isVoidTy()) IGF.Builder.CreateRetVoid(); @@ -2677,6 +2735,28 @@ static llvm::GlobalVariable *createGOTEquivalent(IRGenModule &IGM, .to(gotEquivalent); } + // Context descriptor pointers need to be signed. + // TODO: We should really sign a pointer to *any* code entity or true-const + // metadata structure that may reference data structures with function + // pointers inside them. + if (entity.isContextDescriptor()) { + auto schema = IGM.getOptions().PointerAuth.TypeDescriptors; + if (schema) { + auto signedValue = IGM.getConstantSignedPointer( + global, schema, PointerAuthEntity::Special::TypeDescriptor, + /*storageAddress*/ gotEquivalent); + gotEquivalent->setInitializer(signedValue); + } + } else if (entity.isDynamicallyReplaceableKey()) { + auto schema = IGM.getOptions().PointerAuth.SwiftDynamicReplacementKeys; + if (schema) { + auto signedValue = IGM.getConstantSignedPointer( + global, schema, PointerAuthEntity::Special::DynamicReplacementKey, + /*storageAddress*/ gotEquivalent); + gotEquivalent->setInitializer(signedValue); + } + } + return gotEquivalent; } diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index d4f481db22505..407fa80015ffe 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -100,6 +100,7 @@ #include "GenHeap.h" #include "GenMeta.h" #include "GenObjC.h" +#include "GenPointerAuth.h" #include "GenPoly.h" #include "GenProto.h" #include "GenType.h" @@ -1018,6 +1019,8 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM, SILFunctionTypeRepresentation::WitnessMethod; Explosion witnessMethodSelfValue; + llvm::Value *lastCapturedFieldPtr = nullptr; + // If there's a data pointer required, but it's a swift-retainable // value being passed as the context, just forward it down. if (!layout) { @@ -1111,6 +1114,7 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM, Address fieldAddr = fieldLayout.project(subIGF, data, offsets); auto &fieldTI = fieldLayout.getType(); auto fieldSchema = fieldTI.getSchema(); + lastCapturedFieldPtr = fieldAddr.getAddress(); Explosion param; switch (fieldConvention) { @@ -1229,7 +1233,13 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM, // It comes out of the context as an i8*. Cast to the function type. fnPtr = subIGF.Builder.CreateBitCast(fnPtr, fnTy); - return FunctionPointer(fnPtr, origSig); + assert(lastCapturedFieldPtr); + auto authInfo = PointerAuthInfo::emit(subIGF, + IGM.getOptions().PointerAuth.PartialApplyCapture, + lastCapturedFieldPtr, + PointerAuthEntity::Special::PartialApplyCapture); + + return FunctionPointer(fnPtr, authInfo, origSig); }(); // Derive the context argument if needed. This is either: @@ -1472,6 +1482,8 @@ Optional irgen::emitFunctionPartialApplication( singleRefcountedConvention = origType->getCalleeConvention(); } } + + auto outAuthInfo = PointerAuthInfo::forFunctionPointer(IGF.IGM, outType); // If we have a single refcounted pointer context (and no polymorphic args // to capture), and the dest ownership semantics match the parameter's, @@ -1486,7 +1498,7 @@ Optional irgen::emitFunctionPartialApplication( hasSingleSwiftRefcountedContext == Yes && outType->getCalleeConvention() == *singleRefcountedConvention) { assert(args.size() == 1); - auto fnPtr = fn.getPointer(); + auto fnPtr = emitPointerAuthResign(IGF, fn, outAuthInfo).getPointer(); fnPtr = IGF.Builder.CreateBitCast(fnPtr, IGF.IGM.Int8PtrTy); out.add(fnPtr); llvm::Value *ctx = args.claimNext(); @@ -1525,6 +1537,7 @@ Optional irgen::emitFunctionPartialApplication( emitPartialApplicationForwarder(IGF.IGM, staticFn, fnContext != nullptr, origSig, origType, substType, outType, subs, nullptr, argConventions); + forwarder = emitPointerAuthSign(IGF, forwarder, outAuthInfo); forwarder = IGF.Builder.CreateBitCast(forwarder, IGF.IGM.Int8PtrTy); out.add(forwarder); @@ -1599,7 +1612,15 @@ Optional irgen::emitFunctionPartialApplication( // We don't add non-constant function pointers to the explosion above, // so we need to handle them specially now. if (i == nonStaticFnIndex) { - llvm::Value *fnPtr = fn.getPointer(); + llvm::Value *fnPtr; + if (auto &schema = IGF.getOptions().PointerAuth.PartialApplyCapture) { + auto schemaAuthInfo = + PointerAuthInfo::emit(IGF, schema, fieldAddr.getAddress(), + PointerAuthEntity::Special::PartialApplyCapture); + fnPtr = emitPointerAuthResign(IGF, fn, schemaAuthInfo).getPointer(); + } else { + fnPtr = fn.getPointer(); + } fnPtr = IGF.Builder.CreateBitCast(fnPtr, IGF.IGM.Int8PtrTy); IGF.Builder.CreateStore(fnPtr, fieldAddr); continue; @@ -1642,6 +1663,7 @@ Optional irgen::emitFunctionPartialApplication( subs, &layout, argConventions); + forwarder = emitPointerAuthSign(IGF, forwarder, outAuthInfo); forwarder = IGF.Builder.CreateBitCast(forwarder, IGF.IGM.Int8PtrTy); out.add(forwarder); out.add(data); @@ -1762,8 +1784,8 @@ void irgen::emitBlockHeader(IRGenFunction &IGF, // Collect the reserved and invoke pointer fields. auto reserved = llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0); - auto invokeVal = llvm::ConstantExpr::getBitCast(invokeFunction, - IGF.IGM.FunctionPtrTy); + llvm::Value *invokeVal = llvm::ConstantExpr::getBitCast(invokeFunction, + IGF.IGM.FunctionPtrTy); // Build the block descriptor. ConstantInitBuilder builder(IGF.IGM); @@ -1779,8 +1801,14 @@ void irgen::emitBlockHeader(IRGenFunction &IGF, if (!isPOD) { // Define the copy and dispose helpers. - descriptorFields.add(emitBlockCopyHelper(IGF.IGM, blockTy, storageTL)); - descriptorFields.add(emitBlockDisposeHelper(IGF.IGM, blockTy, storageTL)); + descriptorFields.addSignedPointer( + emitBlockCopyHelper(IGF.IGM, blockTy, storageTL), + IGF.getOptions().PointerAuth.BlockHelperFunctionPointers, + PointerAuthEntity::Special::BlockCopyHelper); + descriptorFields.addSignedPointer( + emitBlockDisposeHelper(IGF.IGM, blockTy, storageTL), + IGF.getOptions().PointerAuth.BlockHelperFunctionPointers, + PointerAuthEntity::Special::BlockDisposeHelper); } // Build the descriptor signature. @@ -1803,8 +1831,17 @@ void irgen::emitBlockHeader(IRGenFunction &IGF, IGF.Builder.CreateStructGEP(headerAddr, 1, layout)); IGF.Builder.CreateStore(reserved, IGF.Builder.CreateStructGEP(headerAddr, 2, layout)); - IGF.Builder.CreateStore(invokeVal, - IGF.Builder.CreateStructGEP(headerAddr, 3, layout)); + + auto invokeAddr = IGF.Builder.CreateStructGEP(headerAddr, 3, layout); + if (auto &schema = + IGF.getOptions().PointerAuth.BlockInvocationFunctionPointers) { + auto invokeAuthInfo = PointerAuthInfo::emit(IGF, schema, + invokeAddr.getAddress(), + invokeTy); + invokeVal = emitPointerAuthSign(IGF, invokeVal, invokeAuthInfo); + } + IGF.Builder.CreateStore(invokeVal, invokeAddr); + IGF.Builder.CreateStore(descriptorVal, IGF.Builder.CreateStructGEP(headerAddr, 4, layout)); } diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index 4c0f5e96a2983..e871a7505299f 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -33,6 +33,7 @@ #include "ConstantBuilder.h" #include "Explosion.h" #include "GenClass.h" +#include "GenPointerAuth.h" #include "GenProto.h" #include "GenType.h" #include "IRGenDebugInfo.h" @@ -481,7 +482,8 @@ static llvm::Constant *buildPrivateMetadata(IRGenModule &IGM, ConstantInitBuilder builder(IGM); auto fields = builder.beginStruct(IGM.FullBoxMetadataStructTy); - fields.add(dtorFn); + fields.addSignedPointer(dtorFn, IGM.getOptions().PointerAuth.HeapDestructors, + PointerAuthEntity::Special::HeapDestructor); fields.addNullPointer(IGM.WitnessTablePtrTy); { auto kindStruct = fields.beginStruct(IGM.TypeMetadataStructTy); diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index eae5bccef3316..2f40aae09c7d2 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -22,6 +22,7 @@ #include "GenClass.h" #include "GenDecl.h" #include "GenMeta.h" +#include "GenPointerAuth.h" #include "GenProto.h" #include "GenStruct.h" #include "GenTuple.h" @@ -363,12 +364,11 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, isTrivial &= ti.isPOD(ResilienceExpansion::Minimal); } - llvm::Constant *destroy; + llvm::Constant *destroy = nullptr; llvm::Constant *copy; if (isTrivial) { // We can use prefab witnesses for handling trivial copying and destruction. // A null destructor witness signals that the payload is trivial. - destroy = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); copy = IGM.getCopyKeyPathTrivialIndicesFn(); } else { // Generate a destructor for this set of indices. @@ -501,12 +501,23 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, genericEnv, requirements, !component.getSubscriptIndices().empty()); - auto witnesses = llvm::ConstantStruct::getAnon({destroy, copy, equals, hash}); - return new llvm::GlobalVariable(IGM.Module, witnesses->getType(), - /*constant*/ true, - llvm::GlobalValue::PrivateLinkage, - witnesses, - "keypath_witnesses"); + ConstantInitBuilder builder(IGM); + ConstantStructBuilder fields = builder.beginStruct(); + auto schemaKeyPath = IGM.getOptions().PointerAuth.KeyPaths; + if (destroy) + fields.addSignedPointer(destroy, schemaKeyPath, + PointerAuthEntity::Special::KeyPathDestroy); + else + fields.addNullPointer(IGM.FunctionPtrTy); + fields.addSignedPointer(copy, schemaKeyPath, + PointerAuthEntity::Special::KeyPathCopy); + fields.addSignedPointer(equals, schemaKeyPath, + PointerAuthEntity::Special::KeyPathEquals); + fields.addSignedPointer(hash, schemaKeyPath, + PointerAuthEntity::Special::KeyPathHash); + return fields.finishAndCreateGlobal( + "keypath_witnesses", IGM.getPointerAlignment(), /*constant*/ true, + llvm::GlobalVariable::PrivateLinkage); } /// Information about each index operand for a key path pattern that is used @@ -886,9 +897,10 @@ emitKeyPathComponent(IRGenModule &IGM, // Encode the settability. bool settable = kind == KeyPathPatternComponent::Kind::SettableProperty; + bool mutating = settable && component.isComputedSettablePropertyMutating(); KeyPathComponentHeader::ComputedPropertyKind componentKind; if (settable) { - componentKind = component.isComputedSettablePropertyMutating() + componentKind = mutating ? KeyPathComponentHeader::SettableMutating : KeyPathComponentHeader::SettableNonmutating; } else { @@ -903,6 +915,7 @@ emitKeyPathComponent(IRGenModule &IGM, switch (id.getKind()) { case KeyPathPatternComponent::ComputedPropertyId::Function: { idKind = KeyPathComponentHeader::Pointer; + // FIXME: Does this need to be signed? auto idRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( LinkEntity::forSILFunction(id.getFunction(), false)); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 1ce59fad4f4c2..e473554920621 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -51,6 +51,7 @@ #include "GenArchetype.h" #include "GenClass.h" #include "GenDecl.h" +#include "GenPointerAuth.h" #include "GenPoly.h" #include "GenStruct.h" #include "GenValueWitness.h" @@ -87,11 +88,13 @@ static Address emitAddressOfMetadataSlotAtIndex(IRGenFunction &IGF, /// Emit a load from the given metadata at a constant index. static llvm::LoadInst *emitLoadFromMetadataAtIndex(IRGenFunction &IGF, llvm::Value *metadata, + llvm::Value **slotPtr, int index, llvm::Type *objectTy, const llvm::Twine &suffix = "") { Address slot = emitAddressOfMetadataSlotAtIndex(IGF, metadata, index, objectTy); + if (slotPtr) *slotPtr = slot.getAddress(); // Load. return IGF.Builder.CreateLoad(slot, metadata->getName() + suffix); @@ -686,6 +689,11 @@ namespace { if (entry.isAssociatedType()) { auto flags = Flags(Flags::Kind::AssociatedTypeAccessFunction); + if (auto &schema = IGM.getOptions().PointerAuth + .ProtocolAssociatedTypeAccessFunctions) { + addDiscriminator(flags, schema, + AssociatedType(entry.getAssociatedType())); + } // Look for a default witness. llvm::Constant *defaultImpl = @@ -696,6 +704,13 @@ namespace { if (entry.isAssociatedConformance()) { auto flags = Flags(Flags::Kind::AssociatedConformanceAccessFunction); + if (auto &schema = IGM.getOptions().PointerAuth + .ProtocolAssociatedTypeWitnessTableAccessFunctions) { + addDiscriminator(flags, schema, + AssociatedConformance(Proto, + entry.getAssociatedConformancePath(), + entry.getAssociatedConformanceRequirement())); + } // Look for a default witness. llvm::Constant *defaultImpl = @@ -716,12 +731,29 @@ namespace { // Classify the function. auto flags = getMethodDescriptorFlags(func.getDecl()); + if (auto &schema = IGM.getOptions().PointerAuth.ProtocolWitnesses) { + SILDeclRef declRef(func.getDecl(), + isa(func.getDecl()) + ? SILDeclRef::Kind::Allocator + : SILDeclRef::Kind::Func); + addDiscriminator(flags, schema, declRef); + } + // Look for a default witness. llvm::Constant *defaultImpl = findDefaultWitness(func); return { flags, defaultImpl }; } + void addDiscriminator(ProtocolRequirementFlags &flags, + const PointerAuthSchema &schema, + const PointerAuthEntity &entity) { + assert(schema); + auto discriminator = + PointerAuthInfo::getOtherDiscriminator(IGM, schema, entity); + flags = flags.withExtraDiscriminator(discriminator->getZExtValue()); + } + void addRequirements() { auto &pi = IGM.getProtocolInfo(Proto, ProtocolInfoKind::Full); @@ -1522,6 +1554,13 @@ namespace { if (func->isObjCDynamic()) flags = flags.withIsDynamic(true); + // Include the pointer-auth discriminator. + if (auto &schema = IGM.getOptions().PointerAuth.SwiftClassMethods) { + auto discriminator = + PointerAuthInfo::getOtherDiscriminator(IGM, schema, fn); + flags = flags.withExtraDiscriminator(discriminator->getZExtValue()); + } + // TODO: final? open? descriptor.addInt(IGM.Int32Ty, flags.getIntValue()); @@ -2740,7 +2779,9 @@ namespace { void addDestructorFunction() { if (auto ptr = getAddrOfDestructorFunction(IGM, Target)) { - B.add(*ptr); + B.addSignedPointer(*ptr, + IGM.getOptions().PointerAuth.HeapDestructors, + PointerAuthEntity::Special::HeapDestructor); } else { // In case the optimizer removed the function. See comment in // addMethod(). @@ -2754,7 +2795,9 @@ namespace { /*isForeign=*/ false, NotForDefinition); if (dtorFunc) { - B.add(*dtorFunc); + B.addSignedPointer(*dtorFunc, + IGM.getOptions().PointerAuth.HeapDestructors, + PointerAuthEntity::Special::HeapDestructor); } else { B.addNullPointer(IGM.FunctionPtrTy); } @@ -2765,7 +2808,9 @@ namespace { } void addNominalTypeDescriptor() { - B.add(emitNominalTypeDescriptor()); + B.addSignedPointer(emitNominalTypeDescriptor(), + IGM.getOptions().PointerAuth.TypeDescriptors, + PointerAuthEntity::Special::TypeDescriptor); } bool canBeConstant() { @@ -2850,14 +2895,19 @@ namespace { auto entry = VTable->getEntry(IGM.getSILModule(), fn); // The class is fragile. Emit a direct reference to the vtable entry. + llvm::Constant *ptr; if (entry) { - B.add(IGM.getAddrOfSILFunction(entry->Implementation, NotForDefinition)); - return; + ptr = IGM.getAddrOfSILFunction(entry->Implementation, + NotForDefinition); + } else { + // The method is removed by dead method elimination. + // It should be never called. We add a pointer to an error function. + ptr = llvm::ConstantExpr::getBitCast(IGM.getDeletedMethodErrorFn(), + IGM.FunctionPtrTy); } - // The method is removed by dead method elimination. - // It should be never called. We add a pointer to an error function. - B.addBitCast(IGM.getDeletedMethodErrorFn(), IGM.FunctionPtrTy); + auto &schema = IGM.getOptions().PointerAuth.SwiftClassMethods; + B.addSignedPointer(ptr, schema, fn); } void addPlaceholder(MissingMemberDecl *m) { @@ -3198,6 +3248,15 @@ namespace { llvm::Value *descriptor, llvm::Value *arguments, llvm::Value *templatePointer) { + // Sign the descriptor. + auto schema = IGF.IGM.getOptions().PointerAuth.TypeDescriptorsAsArguments; + if (schema) { + auto authInfo = PointerAuthInfo::emit( + IGF, schema, nullptr, + PointerAuthEntity::Special::TypeDescriptorAsArgument); + descriptor = emitPointerAuthSign(IGF, descriptor, authInfo); + } + auto metadata = IGF.Builder.CreateCall(IGM.getAllocateGenericClassMetadataFn(), {descriptor, arguments, templatePointer}); @@ -3378,11 +3437,12 @@ void IRGenFunction::setDereferenceableLoad(llvm::LoadInst *load, static llvm::LoadInst * emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF, llvm::Value *metadata, + llvm::Value **slotPtr, int index, llvm::Type *objectTy, const Twine &suffix = Twine::createNull()) { - auto result = emitLoadFromMetadataAtIndex(IGF, metadata, index, objectTy, - suffix); + auto result = emitLoadFromMetadataAtIndex(IGF, metadata, slotPtr, + index, objectTy, suffix); IGF.setInvariantLoad(result); return result; } @@ -3390,8 +3450,8 @@ emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF, /// Given a type metadata pointer, load its value witness table. llvm::Value * IRGenFunction::emitValueWitnessTableRefForMetadata(llvm::Value *metadata) { - auto witness = emitInvariantLoadFromMetadataAtIndex(*this, metadata, -1, - IGM.WitnessTablePtrTy, + auto witness = emitInvariantLoadFromMetadataAtIndex(*this, metadata, nullptr, + -1, IGM.WitnessTablePtrTy, ".valueWitnesses"); // A value witness table is dereferenceable to the number of value witness // pointers. @@ -3520,7 +3580,10 @@ namespace { } void addNominalTypeDescriptor() { - B.add(asImpl().getNominalTypeDescriptor()); + auto descriptor = asImpl().getNominalTypeDescriptor(); + B.addSignedPointer(descriptor, + IGM.getOptions().PointerAuth.TypeDescriptors, + PointerAuthEntity::Special::TypeDescriptor); } ConstantReference emitValueWitnessTable(bool relativeReference) { @@ -3637,6 +3700,15 @@ namespace { - IGM.getOffsetOfStructTypeSpecificMetadataMembers(); auto extraSizeV = IGM.getSize(extraSize); + // Sign the descriptor. + auto schema = IGF.IGM.getOptions().PointerAuth.TypeDescriptorsAsArguments; + if (schema) { + auto authInfo = PointerAuthInfo::emit( + IGF, schema, nullptr, + PointerAuthEntity::Special::TypeDescriptorAsArgument); + descriptor = emitPointerAuthSign(IGF, descriptor, authInfo); + } + return IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(), {descriptor, arguments, templatePointer, extraSizeV}); @@ -3968,7 +4040,9 @@ namespace { } void addNominalTypeDescriptor() { - B.add(asImpl().getNominalTypeDescriptor()); + B.addSignedPointer(asImpl().getNominalTypeDescriptor(), + IGM.getOptions().PointerAuth.TypeDescriptors, + PointerAuthEntity::Special::TypeDescriptor); } void addGenericArgument(GenericRequirement requirement) { @@ -4083,6 +4157,15 @@ namespace { - IGM.getOffsetOfEnumTypeSpecificMetadataMembers(); auto extraSizeV = IGM.getSize(extraSize); + // Sign the descriptor. + auto schema = IGF.IGM.getOptions().PointerAuth.TypeDescriptorsAsArguments; + if (schema) { + auto authInfo = PointerAuthInfo::emit( + IGF, schema, nullptr, + PointerAuthEntity::Special::TypeDescriptorAsArgument); + descriptor = emitPointerAuthSign(IGF, descriptor, authInfo); + } + auto metadata = IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(), {descriptor, arguments, templatePointer, @@ -4356,7 +4439,9 @@ namespace { void addNominalTypeDescriptor() { auto descriptor = ClassContextDescriptorBuilder(this->IGM, Target, RequireMetadata).emit(); - B.add(descriptor); + B.addSignedPointer(descriptor, + IGM.getOptions().PointerAuth.TypeDescriptors, + PointerAuthEntity::Special::TypeDescriptor); } void addSuperclass() { @@ -4717,7 +4802,7 @@ llvm::Value *irgen::emitMetatypeInstanceType(IRGenFunction &IGF, llvm::Value *metatypeMetadata) { // The instance type field of MetatypeMetadata is immediately after // the isa field. - return emitInvariantLoadFromMetadataAtIndex(IGF, metatypeMetadata, 1, + return emitInvariantLoadFromMetadataAtIndex(IGF, metatypeMetadata, nullptr, 1, IGF.IGM.TypeMetadataPtrTy); } diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index cb719840d5549..0cc9795325e10 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -41,6 +41,7 @@ #include "GenClass.h" #include "GenFunc.h" #include "GenHeap.h" +#include "GenPointerAuth.h" #include "GenProto.h" #include "GenType.h" #include "HeapTypeInfo.h" @@ -898,17 +899,19 @@ void irgen::emitObjCPartialApplication(IRGenFunction &IGF, fieldType, false); // Create the forwarding stub. - llvm::Function *forwarder = emitObjCPartialApplicationForwarder(IGF.IGM, + llvm::Value *forwarder = emitObjCPartialApplicationForwarder(IGF.IGM, method, origMethodType, resultType, layout, selfType); - llvm::Value *forwarderValue = IGF.Builder.CreateBitCast(forwarder, - IGF.IGM.Int8PtrTy); - + forwarder = + IGF.IGM.getConstantSignedFunctionPointer(cast(forwarder), + resultType); + forwarder = IGF.Builder.CreateBitCast(forwarder, IGF.IGM.Int8PtrTy); + // Emit the result explosion. - out.add(forwarderValue); + out.add(forwarder); out.add(data); } @@ -1283,25 +1286,32 @@ irgen::emitObjCSetterDescriptorParts(IRGenModule &IGM, llvm_unreachable("unknown storage!"); } -static void buildMethodDescriptor(ConstantArrayBuilder &descriptors, +static void buildMethodDescriptor(IRGenModule &IGM, + ConstantArrayBuilder &descriptors, ObjCMethodDescriptor &parts) { auto descriptor = descriptors.beginStruct(); descriptor.add(parts.selectorRef); descriptor.add(parts.typeEncoding); - descriptor.add(parts.impl); + if (parts.impl->isNullValue()) { + descriptor.add(parts.impl); + } else { + descriptor.addSignedPointer(parts.impl, + IGM.getOptions().PointerAuth.ObjCMethodListFunctionPointers, + PointerAuthEntity()); + } descriptor.finishAndAddTo(descriptors); } static void emitObjCDescriptor(IRGenModule &IGM, ConstantArrayBuilder &descriptors, ObjCMethodDescriptor &descriptor) { - buildMethodDescriptor(descriptors, descriptor); + buildMethodDescriptor(IGM, descriptors, descriptor); auto *silFn = descriptor.silFunction; if (silFn && silFn->hasObjCReplacement()) { auto replacedSelector = IGM.getAddrOfObjCMethodName(silFn->getObjCReplacement().str()); descriptor.selectorRef = replacedSelector; - buildMethodDescriptor(descriptors, descriptor); + buildMethodDescriptor(IGM, descriptors, descriptor); } } @@ -1346,7 +1356,7 @@ void irgen::emitObjCIVarInitDestroyDescriptor(IRGenModule &IGM, descriptor.impl = llvm::ConstantExpr::getBitCast(objcImpl, IGM.Int8PtrTy); // Form the method_t instance. - buildMethodDescriptor(descriptors, descriptor); + buildMethodDescriptor(IGM, descriptors, descriptor); } llvm::Constant * diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp index c8c34e891ebcd..25d2635b1c195 100644 --- a/lib/IRGen/GenOpaque.cpp +++ b/lib/IRGen/GenOpaque.cpp @@ -31,6 +31,7 @@ #include "Callee.h" #include "Explosion.h" #include "FixedTypeInfo.h" +#include "GenPointerAuth.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "ProtocolInfo.h" @@ -312,7 +313,8 @@ llvm::PointerType *IRGenModule::getEnumValueWitnessTablePtrTy() { /// always an i8*. llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF, llvm::Value *table, - WitnessIndex index) { + WitnessIndex index, + llvm::Value **slotPtr) { assert(table->getType() == IGF.IGM.WitnessTablePtrTy); // GEP to the appropriate index, avoiding spurious IR in the trivial case. @@ -321,6 +323,8 @@ llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF, slot = IGF.Builder.CreateConstInBoundsGEP1_32( /*Ty=*/nullptr, table, index.getValue()); + if (slotPtr) *slotPtr = slot; + auto witness = IGF.Builder.CreateLoad(Address(slot, IGF.IGM.getPointerAlignment())); IGF.setInvariantLoad(witness); @@ -331,12 +335,15 @@ llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF, /// always an i8*. llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF, llvm::Value *table, - llvm::Value *index) { + llvm::Value *index, + llvm::Value **slotPtr) { assert(table->getType() == IGF.IGM.WitnessTablePtrTy); // GEP to the appropriate index. llvm::Value *slot = IGF.Builder.CreateInBoundsGEP(table, index); + if (slotPtr) *slotPtr = slot; + auto witness = IGF.Builder.CreateLoad(Address(slot, IGF.IGM.getPointerAlignment())); IGF.setInvariantLoad(witness); @@ -396,7 +403,6 @@ static FunctionPointer emitLoadOfValueWitnessFunction(IRGenFunction &IGF, llvm::Value *table, ValueWitness index) { assert(isValueWitnessFunction(index)); - WitnessIndex windex = [&] { unsigned i = unsigned(index); if (i > unsigned(ValueWitness::Flags)) { @@ -412,14 +418,20 @@ static FunctionPointer emitLoadOfValueWitnessFunction(IRGenFunction &IGF, return WitnessIndex(i, false); }(); - llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, windex); + llvm::Value *slot; + llvm::Value *witness = + emitInvariantLoadOfOpaqueWitness(IGF, table, windex, &slot); auto label = getValueWitnessLabel(index); auto signature = IGF.IGM.getValueWitnessSignature(index); auto type = signature.getType()->getPointerTo(); witness = IGF.Builder.CreateBitCast(witness, type, label); - return FunctionPointer(witness, signature); + auto authInfo = PointerAuthInfo::emit(IGF, + IGF.getOptions().PointerAuth.ValueWitnesses, + slot, index); + + return FunctionPointer(witness, authInfo, signature); } /// Given a type metadata pointer, load one of the function @@ -457,12 +469,26 @@ IRGenFunction::emitValueWitnessFunctionRef(SILType type, if (auto witness = tryGetLocalTypeDataForLayout(type, key)) { metadataSlot = emitTypeMetadataRefForLayout(type); auto signature = IGM.getValueWitnessSignature(index); - return FunctionPointer(witness, signature); + PointerAuthInfo authInfo; + if (auto &schema = getOptions().PointerAuth.ValueWitnesses) { + auto discriminator = + tryGetLocalTypeDataForLayout(type, + LocalTypeDataKind::forValueWitnessDiscriminator(index)); + assert(discriminator && "no saved discriminator for value witness fn!"); + authInfo = PointerAuthInfo(schema.getKey(), discriminator); + } + return FunctionPointer(witness, authInfo, signature); } auto vwtable = emitValueWitnessTableRef(type, &metadataSlot); auto witness = emitLoadOfValueWitnessFunction(*this, vwtable, index); setScopedLocalTypeDataForLayout(type, key, witness.getPointer()); + if (auto &authInfo = witness.getAuthInfo()) { + setScopedLocalTypeDataForLayout(type, + LocalTypeDataKind::forValueWitnessDiscriminator(index), + authInfo.getDiscriminator()); + } + return witness; } @@ -1287,6 +1313,8 @@ irgen::emitGetEnumTagSinglePayloadGenericCall(IRGenFunction &IGF, auto getExtraInhabitantTagFn = getOrCreateGetExtraInhabitantTagFunction(IGF.IGM, payloadType, payloadTI, emitter); + getExtraInhabitantTagFn = + IGF.IGM.getConstantSignedCFunctionPointer(getExtraInhabitantTagFn); // We assume this is never a reabstracted type. auto type = payloadType.getASTType(); @@ -1359,6 +1387,8 @@ irgen::emitStoreEnumTagSinglePayloadGenericCall(IRGenFunction &IGF, auto storeExtraInhabitantTagFn = getOrCreateStoreExtraInhabitantTagFunction(IGF.IGM, payloadType, payloadTI, emitter); + storeExtraInhabitantTagFn = + IGF.IGM.getConstantSignedCFunctionPointer(storeExtraInhabitantTagFn); // We assume this is never a reabstracted type. auto type = payloadType.getASTType(); diff --git a/lib/IRGen/GenOpaque.h b/lib/IRGen/GenOpaque.h index ea7733e662aab..d1421098d42bb 100644 --- a/lib/IRGen/GenOpaque.h +++ b/lib/IRGen/GenOpaque.h @@ -45,7 +45,8 @@ namespace irgen { /// the referenced witness table is still undergoing initialization. llvm::Value *emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF, llvm::Value *table, - WitnessIndex index); + WitnessIndex index, + llvm::Value **slot = nullptr); /// Given a witness table (protocol or value), load one of the /// witnesses. @@ -54,7 +55,8 @@ namespace irgen { /// the referenced witness table is still undergoing initialization. llvm::Value *emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF, llvm::Value *table, - llvm::Value *index); + llvm::Value *index, + llvm::Value **slot = nullptr); /// Emit a call to do an 'initializeBufferWithCopyOfBuffer' operation. llvm::Value *emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF, diff --git a/lib/IRGen/GenPointerAuth.cpp b/lib/IRGen/GenPointerAuth.cpp new file mode 100644 index 0000000000000..4506c6a63810b --- /dev/null +++ b/lib/IRGen/GenPointerAuth.cpp @@ -0,0 +1,690 @@ +//===--- GenPointerAuth.cpp - IRGen for pointer authentication ------------===// +// +// 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 implements general support for pointer authentication in Swift. +// +//===----------------------------------------------------------------------===// + +#include "GenPointerAuth.h" +#include "Callee.h" +#include "ConstantBuilder.h" +#include "GenType.h" +#include "IRGenFunction.h" +#include "IRGenMangler.h" +#include "IRGenModule.h" +#include "swift/AST/GenericEnvironment.h" +#include "swift/SIL/TypeLowering.h" +#include "clang/CodeGen/CodeGenABITypes.h" +#include "llvm/ADT/APInt.h" +#include "llvm/Support/raw_ostream.h" + +using namespace swift; +using namespace irgen; + +/**************************** INTRINSIC OPERATIONS ****************************/ + +/// Return the key and discriminator value for the given auth info, +/// as demanded by the ptrauth intrinsics. +static std::pair +getPointerAuthPair(IRGenFunction &IGF, const PointerAuthInfo &authInfo) { + auto key = llvm::ConstantInt::get(IGF.IGM.Int32Ty, authInfo.getKey()); + llvm::Value *discriminator = authInfo.getDiscriminator(); + if (discriminator->getType()->isPointerTy()) { + discriminator = IGF.Builder.CreatePtrToInt(discriminator, IGF.IGM.IntPtrTy); + } + return { key, discriminator }; +} + +llvm::Value *irgen::emitPointerAuthBlend(IRGenFunction &IGF, + llvm::Value *address, + llvm::Value *other) { + address = IGF.Builder.CreatePtrToInt(address, IGF.IGM.IntPtrTy); + auto intrinsic = + llvm::Intrinsic::getDeclaration(&IGF.IGM.Module, + llvm::Intrinsic::ptrauth_blend, + { IGF.IGM.IntPtrTy }); + return IGF.Builder.CreateCall(intrinsic, {address, other}); +} + +llvm::Value *irgen::emitPointerAuthStrip(IRGenFunction &IGF, + llvm::Value *fnPtr, + unsigned Key) { + auto fnVal = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.IntPtrTy); + auto keyArg = llvm::ConstantInt::get(IGF.IGM.Int32Ty, Key); + auto intrinsic = + llvm::Intrinsic::getDeclaration(&IGF.IGM.Module, + llvm::Intrinsic::ptrauth_strip, + { IGF.IGM.IntPtrTy }); + auto strippedPtr = IGF.Builder.CreateCall(intrinsic, {fnVal, keyArg}); + return IGF.Builder.CreateIntToPtr(strippedPtr, fnPtr->getType()); +} + +FunctionPointer irgen::emitPointerAuthResign(IRGenFunction &IGF, + const FunctionPointer &fn, + const PointerAuthInfo &newAuthInfo) { + llvm::Value *fnPtr = emitPointerAuthResign(IGF, fn.getPointer(), + fn.getAuthInfo(), newAuthInfo); + return FunctionPointer(fnPtr, newAuthInfo, fn.getSignature()); +} + +llvm::Value *irgen::emitPointerAuthResign(IRGenFunction &IGF, + llvm::Value *fnPtr, + const PointerAuthInfo &oldAuthInfo, + const PointerAuthInfo &newAuthInfo) { + // If the signatures match, there's nothing to do. + if (oldAuthInfo == newAuthInfo) + return fnPtr; + + // If the pointer is not currently signed, sign it. + if (!oldAuthInfo.isSigned()) { + return emitPointerAuthSign(IGF, fnPtr, newAuthInfo); + } + + // If the pointer is not supposed to be signed, auth it. + if (!newAuthInfo.isSigned()) { + return emitPointerAuthAuth(IGF, fnPtr, oldAuthInfo); + } + + // Otherwise, auth and resign it. + auto origTy = fnPtr->getType(); + fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.IntPtrTy); + + auto oldPair = getPointerAuthPair(IGF, oldAuthInfo); + auto newPair = getPointerAuthPair(IGF, newAuthInfo); + + auto intrinsic = + llvm::Intrinsic::getDeclaration(&IGF.IGM.Module, + llvm::Intrinsic::ptrauth_resign, + { IGF.IGM.IntPtrTy }); + llvm::Value *args[] = { + fnPtr, oldPair.first, oldPair.second, newPair.first, newPair.second + }; + fnPtr = IGF.Builder.CreateCall(intrinsic, args); + return IGF.Builder.CreateIntToPtr(fnPtr, origTy); +} + +llvm::Value *irgen::emitPointerAuthAuth(IRGenFunction &IGF, llvm::Value *fnPtr, + const PointerAuthInfo &oldAuthInfo) { + auto origTy = fnPtr->getType(); + fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.IntPtrTy); + + auto oldPair = getPointerAuthPair(IGF, oldAuthInfo); + + auto intrinsic = + llvm::Intrinsic::getDeclaration(&IGF.IGM.Module, + llvm::Intrinsic::ptrauth_auth, + { IGF.IGM.IntPtrTy }); + llvm::Value *args[] = { + fnPtr, oldPair.first, oldPair.second + }; + fnPtr = IGF.Builder.CreateCall(intrinsic, args); + return IGF.Builder.CreateIntToPtr(fnPtr, origTy); +} + +llvm::Value *irgen::emitPointerAuthSign(IRGenFunction &IGF, llvm::Value *fnPtr, + const PointerAuthInfo &newAuthInfo) { + if (!newAuthInfo.isSigned()) + return fnPtr; + + // Special-case constants. + if (auto constantFnPtr = dyn_cast(fnPtr)) { + if (auto constantDiscriminator = + dyn_cast(newAuthInfo.getDiscriminator())) { + llvm::Constant *other = nullptr, *address = nullptr; + if (constantDiscriminator->getType()->isPointerTy()) + address = constantDiscriminator; + else + other = constantDiscriminator; + return IGF.IGM.getConstantSignedPointer(constantFnPtr, + newAuthInfo.getKey(), + address, other); + } + } + + auto origTy = fnPtr->getType(); + fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.IntPtrTy); + + auto newPair = getPointerAuthPair(IGF, newAuthInfo); + + auto intrinsic = + llvm::Intrinsic::getDeclaration(&IGF.IGM.Module, + llvm::Intrinsic::ptrauth_sign, + { IGF.IGM.IntPtrTy }); + llvm::Value *args[] = { + fnPtr, newPair.first, newPair.second + }; + fnPtr = IGF.Builder.CreateCall(intrinsic, args); + return IGF.Builder.CreateIntToPtr(fnPtr, origTy); +} + +/******************************* DISCRIMINATORS *******************************/ + +struct IRGenModule::PointerAuthCachesType { + llvm::DenseMap Decls; + llvm::DenseMap Types; + llvm::DenseMap YieldTypes; + llvm::DenseMap AssociatedTypes; + llvm::DenseMap AssociatedConformances; +}; + +IRGenModule::PointerAuthCachesType &IRGenModule::getPointerAuthCaches() { + if (!PointerAuthCaches) + PointerAuthCaches = new PointerAuthCachesType(); + return *PointerAuthCaches; +} + +void IRGenModule::destroyPointerAuthCaches() { + delete PointerAuthCaches; +} + +static const PointerAuthSchema &getFunctionPointerSchema(IRGenModule &IGM, + CanSILFunctionType fnType) { + auto &options = IGM.getOptions().PointerAuth; + switch (fnType->getRepresentation()) { + case SILFunctionTypeRepresentation::CFunctionPointer: + return options.FunctionPointers; + + case SILFunctionTypeRepresentation::Thin: + case SILFunctionTypeRepresentation::Thick: + case SILFunctionTypeRepresentation::Method: + case SILFunctionTypeRepresentation::WitnessMethod: + case SILFunctionTypeRepresentation::Closure: + return options.SwiftFunctionPointers; + + case SILFunctionTypeRepresentation::ObjCMethod: + case SILFunctionTypeRepresentation::Block: + llvm_unreachable("not just a function pointer"); + } + llvm_unreachable("bad representation"); +} + +PointerAuthInfo PointerAuthInfo::forFunctionPointer(IRGenModule &IGM, + CanSILFunctionType fnType) { + auto &schema = getFunctionPointerSchema(IGM, fnType); + + // If the target doesn't sign function pointers, we're done. + if (!schema) return PointerAuthInfo(); + + assert(!schema.isAddressDiscriminated() && + "function pointer cannot be address-discriminated"); + + auto discriminator = getOtherDiscriminator(IGM, schema, fnType); + return PointerAuthInfo(schema.getKey(), discriminator); +} + +PointerAuthInfo PointerAuthInfo::emit(IRGenFunction &IGF, + const PointerAuthSchema &schema, + llvm::Value *storageAddress, + const PointerAuthEntity &entity) { + if (!schema) return PointerAuthInfo(); + + unsigned key = schema.getKey(); + + // Produce the 'other' discriminator. + auto otherDiscriminator = getOtherDiscriminator(IGF.IGM, schema, entity); + llvm::Value *discriminator = otherDiscriminator; + + // Factor in the address. + if (schema.isAddressDiscriminated()) { + assert(storageAddress && + "no storage address for address-discriminated schema"); + + if (!otherDiscriminator->isZero()) { + discriminator = emitPointerAuthBlend(IGF, storageAddress, discriminator); + } else { + discriminator = + IGF.Builder.CreatePtrToInt(storageAddress, IGF.IGM.IntPtrTy); + } + } + + return PointerAuthInfo(key, discriminator); +} + +llvm::ConstantInt * +PointerAuthInfo::getOtherDiscriminator(IRGenModule &IGM, + const PointerAuthSchema &schema, + const PointerAuthEntity &entity) { + assert(schema); + switch (schema.getOtherDiscrimination()) { + case PointerAuthSchema::Discrimination::None: + return llvm::ConstantInt::get(IGM.IntPtrTy, 0); + + case PointerAuthSchema::Discrimination::Decl: + return entity.getDeclDiscriminator(IGM); + + case PointerAuthSchema::Discrimination::Type: + return entity.getTypeDiscriminator(IGM); + + case PointerAuthSchema::Discrimination::Constant: + return llvm::ConstantInt::get(IGM.IntPtrTy, + schema.getConstantDiscrimination()); + } + llvm_unreachable("bad kind"); +} + +static llvm::ConstantInt *getDiscriminatorForHash(IRGenModule &IGM, + uint64_t rawHash) { + uint16_t reducedHash = (rawHash % 0xFFFF) + 1; + return IGM.getSize(Size(reducedHash)); +} + +static llvm::ConstantInt *getDiscriminatorForString(IRGenModule &IGM, + StringRef string) { + uint64_t rawHash = clang::CodeGen::computeStableStringHash(string); + return getDiscriminatorForHash(IGM, rawHash); +} + +static std::string mangle(AssociatedType association) { + return IRGenMangler() + .mangleAssociatedTypeAccessFunctionDiscriminator(association); +} + +static std::string mangle(const AssociatedConformance &association) { + return IRGenMangler() + .mangleAssociatedTypeWitnessTableAccessFunctionDiscriminator(association); +} + +llvm::ConstantInt * +PointerAuthEntity::getDeclDiscriminator(IRGenModule &IGM) const { + switch (StoredKind) { + case Kind::None: + case Kind::CanSILFunctionType: + case Kind::CoroutineYieldTypes: + llvm_unreachable("no declaration for schema using decl discrimination"); + + case Kind::Special: { + auto getSpecialDiscriminator = [](Special special) -> uint16_t { + switch (special) { + case Special::HeapDestructor: + return SpecialPointerAuthDiscriminators::HeapDestructor; + case Special::TypeDescriptor: + case Special::TypeDescriptorAsArgument: + return SpecialPointerAuthDiscriminators::TypeDescriptor; + case Special::PartialApplyCapture: + return PointerAuthDiscriminator_PartialApplyCapture; + case Special::KeyPathDestroy: + return SpecialPointerAuthDiscriminators::KeyPathDestroy; + case Special::KeyPathCopy: + return SpecialPointerAuthDiscriminators::KeyPathCopy; + case Special::KeyPathEquals: + return SpecialPointerAuthDiscriminators::KeyPathEquals; + case Special::KeyPathHash: + return SpecialPointerAuthDiscriminators::KeyPathHash; + case Special::KeyPathGetter: + return SpecialPointerAuthDiscriminators::KeyPathGetter; + case Special::KeyPathNonmutatingSetter: + return SpecialPointerAuthDiscriminators::KeyPathNonmutatingSetter; + case Special::KeyPathMutatingSetter: + return SpecialPointerAuthDiscriminators::KeyPathMutatingSetter; + case Special::KeyPathGetLayout: + return SpecialPointerAuthDiscriminators::KeyPathGetLayout; + case Special::KeyPathInitializer: + return SpecialPointerAuthDiscriminators::KeyPathInitializer; + case Special::KeyPathMetadataAccessor: + return SpecialPointerAuthDiscriminators::KeyPathMetadataAccessor; + case Special::DynamicReplacementKey: + return SpecialPointerAuthDiscriminators::DynamicReplacementKey; + case Special::BlockCopyHelper: + case Special::BlockDisposeHelper: + llvm_unreachable("no known discriminator for these foreign entities"); + } + llvm_unreachable("bad kind"); + }; + auto specialKind = Storage.get(StoredKind); + return IGM.getSize(Size(getSpecialDiscriminator(specialKind))); + } + + case Kind::ValueWitness: { + auto getValueWitnessDiscriminator = [](ValueWitness witness) -> uint16_t { + switch (witness) { +#define WANT_ALL_VALUE_WITNESSES +#define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE) +#define FUNCTION_VALUE_WITNESS(LOWER, ID, RET, PARAMS) \ + case ValueWitness::ID: return SpecialPointerAuthDiscriminators::ID; +#include "swift/ABI/ValueWitness.def" + case ValueWitness::Size: + case ValueWitness::Flags: + case ValueWitness::Stride: + case ValueWitness::ExtraInhabitantCount: + llvm_unreachable("not a function value witness"); + } + llvm_unreachable("bad kind"); + }; + auto witness = Storage.get(StoredKind); + return IGM.getSize(Size(getValueWitnessDiscriminator(witness))); + } + + case Kind::AssociatedType: { + auto association = Storage.get(StoredKind); + llvm::ConstantInt *&cache = + IGM.getPointerAuthCaches().AssociatedTypes[association]; + if (cache) return cache; + + auto mangling = mangle(association); + cache = getDiscriminatorForString(IGM, mangling); + return cache; + } + + case Kind::AssociatedConformance: { + auto conformance = Storage.get(StoredKind); + llvm::ConstantInt *&cache = + IGM.getPointerAuthCaches().AssociatedConformances[conformance]; + if (cache) return cache; + + auto mangling = mangle(conformance); + cache = getDiscriminatorForString(IGM, mangling); + return cache; + } + + case Kind::SILDeclRef: { + auto constant = Storage.get(StoredKind); + llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Decls[constant]; + if (cache) return cache; + + // Getting the discriminator for a foreign SILDeclRef just means + // converting it to a foreign declaration and asking Clang IRGen + // for the corresponding discriminator, but that's not completely + // trivial. + assert(!constant.isForeign && + "discriminator for foreign declaration not supported yet!"); + + auto mangling = constant.mangle(); + cache = getDiscriminatorForString(IGM, mangling); + return cache; + } + case Kind::SILFunction: { + auto fn = Storage.get(StoredKind); + return getDiscriminatorForString(IGM, fn->getName()); + } + } + llvm_unreachable("bad kind"); +} + +static void hashStringForFunctionType(IRGenModule &IGM, CanSILFunctionType type, + raw_ostream &Out, + GenericEnvironment *genericEnv); + +static void hashStringForType(IRGenModule &IGM, CanType Ty, raw_ostream &Out, + GenericEnvironment *genericEnv) { + if (Ty->isAnyClassReferenceType()) { + // Any class type has to be hashed opaquely. + Out << "-class"; + } else if (isa(Ty)) { + // Any metatype has to be hashed opaquely. + Out << "-metatype"; + } else if (auto UnwrappedTy = Ty->getOptionalObjectType()) { + if (UnwrappedTy->isBridgeableObjectType()) { + // Optional is compatible with T when T is class-based. + hashStringForType(IGM, UnwrappedTy->getCanonicalType(), Out, genericEnv); + } else if (UnwrappedTy->is()) { + // Optional is compatible with T when T is a metatype. + hashStringForType(IGM, UnwrappedTy->getCanonicalType(), Out, genericEnv); + } else { + // Optional is direct if and only if T is. + Out << "Optional<"; + hashStringForType(IGM, UnwrappedTy->getCanonicalType(), Out, genericEnv); + Out << ">"; + } + } else if (auto GTy = dyn_cast(Ty)) { + // For generic and non-generic value types, use the mangled declaration + // name, and ignore all generic arguments. + NominalTypeDecl *nominal = cast(GTy->getDecl()); + Out << Mangle::ASTMangler().mangleNominalType(nominal); + } else if (auto FTy = dyn_cast(Ty)) { + Out << "("; + hashStringForFunctionType(IGM, FTy, Out, genericEnv); + Out << ")"; + } else { + Out << "-"; + } +} + +template +static void hashStringForList(IRGenModule &IGM, const ArrayRef &list, + raw_ostream &Out, GenericEnvironment *genericEnv, + const SILFunctionType *fnType) { + for (auto paramOrRetVal : list) { + if (paramOrRetVal.isFormalIndirect()) { + // Indirect params and return values have to be opaque. + Out << "-indirect"; + } else { + CanType Ty = paramOrRetVal.getArgumentType(IGM.getSILModule(), fnType); + if (Ty->hasTypeParameter()) + Ty = genericEnv->mapTypeIntoContext(Ty)->getCanonicalType(); + hashStringForType(IGM, Ty, Out, genericEnv); + } + Out << ":"; + } +} + +static void hashStringForList(IRGenModule &IGM, + const ArrayRef &list, + raw_ostream &Out, GenericEnvironment *genericEnv, + const SILFunctionType *fnType) { + for (auto paramOrRetVal : list) { + if (paramOrRetVal.isFormalIndirect()) { + // Indirect params and return values have to be opaque. + Out << "-indirect"; + } else { + CanType Ty = paramOrRetVal.getReturnValueType(IGM.getSILModule(), fnType); + if (Ty->hasTypeParameter()) + Ty = genericEnv->mapTypeIntoContext(Ty)->getCanonicalType(); + hashStringForType(IGM, Ty, Out, genericEnv); + } + Out << ":"; + } +} + +static void hashStringForFunctionType(IRGenModule &IGM, CanSILFunctionType type, + raw_ostream &Out, + GenericEnvironment *genericEnv) { + Out << (type->isCoroutine() ? "coroutine" : "function") << ":"; + Out << type->getNumParameters() << ":"; + hashStringForList(IGM, type->getParameters(), Out, genericEnv, type); + Out << type->getNumResults() << ":"; + hashStringForList(IGM, type->getResults(), Out, genericEnv, type); + if (type->isCoroutine()) { + Out << type->getNumYields() << ":"; + hashStringForList(IGM, type->getYields(), Out, genericEnv, type); + } +} + +static uint64_t getTypeHash(IRGenModule &IGM, CanSILFunctionType type) { + // The hash we need to do here ignores: + // - thickness, so that we can promote thin-to-thick without rehashing; + // - error results, so that we can promote nonthrowing-to-throwing + // without rehashing; + // - types of indirect arguments/retvals, so they can be substituted freely; + // - types of class arguments/retvals + // - types of metatype arguments/retvals + // See isABICompatibleWith and areABICompatibleParamsOrReturns in + // SILFunctionType.cpp. + + SmallString<32> Buffer; + llvm::raw_svector_ostream Out(Buffer); + auto genericSig = type->getInvocationGenericSignature(); + hashStringForFunctionType( + IGM, type, Out, + genericSig ? genericSig->getCanonicalSignature()->getGenericEnvironment() + : nullptr); + return clang::CodeGen::computeStableStringHash(Out.str()); +} + +static uint64_t getYieldTypesHash(IRGenModule &IGM, CanSILFunctionType type) { + SmallString<32> buffer; + llvm::raw_svector_ostream out(buffer); + auto genericSig = type->getInvocationGenericSignature(); + GenericEnvironment *genericEnv = + genericSig ? genericSig->getCanonicalSignature()->getGenericEnvironment() + : nullptr; + + out << [&]() -> StringRef { + switch (type->getCoroutineKind()) { + case SILCoroutineKind::YieldMany: return "yield_many:"; + case SILCoroutineKind::YieldOnce: return "yield_once:"; + case SILCoroutineKind::None: llvm_unreachable("not a coroutine"); + } + llvm_unreachable("bad coroutine kind"); + }(); + + out << type->getNumYields() << ":"; + + for (auto yield: type->getYields()) { + // We can't mangle types on inout and indirect yields because they're + // absractable. + if (yield.isIndirectInOut()) { + out << "inout"; + } else if (yield.isFormalIndirect()) { + out << "indirect"; + } else { + CanType Ty = yield.getArgumentType(IGM.getSILModule(), type); + if (Ty->hasTypeParameter()) + Ty = genericEnv->mapTypeIntoContext(Ty)->getCanonicalType(); + hashStringForType(IGM, Ty, out, genericEnv); + } + out << ":"; + } + + return clang::CodeGen::computeStableStringHash(out.str()); +} + +llvm::ConstantInt * +PointerAuthEntity::getTypeDiscriminator(IRGenModule &IGM) const { + auto getTypeDiscriminator = [&](CanSILFunctionType fnType) { + switch (fnType->getRepresentation()) { + // Swift function types are type-discriminated. + case SILFunctionTypeRepresentation::Thick: + case SILFunctionTypeRepresentation::Thin: + case SILFunctionTypeRepresentation::Method: + case SILFunctionTypeRepresentation::WitnessMethod: + case SILFunctionTypeRepresentation::Closure: { + llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Types[fnType]; + if (cache) return cache; + + auto hash = getTypeHash(IGM, fnType); + cache = getDiscriminatorForHash(IGM, hash); + return cache; + } + + // C function pointers are undiscriminated. + case SILFunctionTypeRepresentation::CFunctionPointer: + return llvm::ConstantInt::get(IGM.Int64Ty, 0); + + case SILFunctionTypeRepresentation::ObjCMethod: + case SILFunctionTypeRepresentation::Block: { + llvm_unreachable("not type discriminated"); + } + } + }; + + auto getCoroutineYieldTypesDiscriminator = [&](CanSILFunctionType fnType) { + llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Types[fnType]; + if (cache) return cache; + + auto hash = getYieldTypesHash(IGM, fnType); + cache = getDiscriminatorForHash(IGM, hash); + return cache; + }; + + switch (StoredKind) { + case Kind::None: + case Kind::Special: + case Kind::ValueWitness: + case Kind::AssociatedType: + case Kind::AssociatedConformance: + case Kind::SILFunction: + llvm_unreachable("no type for schema using type discriminiation"); + + case Kind::CoroutineYieldTypes: { + auto fnType = Storage.get(StoredKind); + return getCoroutineYieldTypesDiscriminator(fnType); + } + + case Kind::CanSILFunctionType: { + auto fnType = Storage.get(StoredKind); + return getTypeDiscriminator(fnType); + } + + case Kind::SILDeclRef: { + SILDeclRef decl = Storage.get(StoredKind); + auto fnType = IGM.getSILTypes().getConstantFunctionType( + TypeExpansionContext::minimal(), decl); + return getTypeDiscriminator(fnType); + } + } + llvm_unreachable("bad kind"); +} + +llvm::Constant * +IRGenModule::getConstantSignedFunctionPointer(llvm::Constant *fn, + CanSILFunctionType fnType) { + if (auto &schema = getFunctionPointerSchema(*this, fnType)) { + return getConstantSignedPointer(fn, schema, fnType, nullptr); + } + return fn; +} + +llvm::Constant * +IRGenModule::getConstantSignedCFunctionPointer(llvm::Constant *fn) { + if (auto &schema = getOptions().PointerAuth.FunctionPointers) { + assert(!schema.hasOtherDiscrimination()); + return getConstantSignedPointer(fn, schema, PointerAuthEntity(), nullptr); + } + return fn; +} + +llvm::Constant *IRGenModule::getConstantSignedPointer(llvm::Constant *pointer, + unsigned key, + llvm::Constant *storageAddress, + llvm::Constant *otherDiscriminator) { + return clang::CodeGen::getConstantSignedPointer(getClangCGM(), pointer, key, + storageAddress, + otherDiscriminator); +} + +llvm::Constant *IRGenModule::getConstantSignedPointer(llvm::Constant *pointer, + const PointerAuthSchema &schema, + const PointerAuthEntity &entity, + llvm::Constant *storageAddress) { + // If the schema doesn't sign pointers, do nothing. + if (!schema) + return pointer; + + auto otherDiscriminator = + PointerAuthInfo::getOtherDiscriminator(*this, schema, entity); + return getConstantSignedPointer(pointer, schema.getKey(), storageAddress, + otherDiscriminator); +} + +void ConstantAggregateBuilderBase::addSignedPointer(llvm::Constant *pointer, + const PointerAuthSchema &schema, + const PointerAuthEntity &entity) { + // If the schema doesn't sign pointers, do nothing. + if (!schema) + return add(pointer); + + auto otherDiscriminator = + PointerAuthInfo::getOtherDiscriminator(IGM(), schema, entity); + addSignedPointer(pointer, schema.getKey(), schema.isAddressDiscriminated(), + otherDiscriminator); +} + +void ConstantAggregateBuilderBase::addSignedPointer(llvm::Constant *pointer, + const PointerAuthSchema &schema, + uint16_t otherDiscriminator) { + // If the schema doesn't sign pointers, do nothing. + if (!schema) + return add(pointer); + + addSignedPointer(pointer, schema.getKey(), schema.isAddressDiscriminated(), + llvm::ConstantInt::get(IGM().IntPtrTy, otherDiscriminator)); +} diff --git a/lib/IRGen/GenPointerAuth.h b/lib/IRGen/GenPointerAuth.h new file mode 100644 index 0000000000000..c30e4daf50668 --- /dev/null +++ b/lib/IRGen/GenPointerAuth.h @@ -0,0 +1,206 @@ +//===--- GenPointerAuth.h - IRGen for pointer authentication ----*- 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 the basic interface for generating LLVM IR for pointer +// authentication. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IRGEN_GENPOINTERAUTH_H +#define SWIFT_IRGEN_GENPOINTERAUTH_H + +#include "swift/IRGen/ValueWitness.h" +#include "swift/Basic/ExternalUnion.h" +#include "swift/AST/IRGenOptions.h" +#include "swift/AST/ProtocolAssociations.h" +#include "swift/AST/Types.h" +#include "swift/SIL/SILDeclRef.h" + +namespace llvm { +class ConstantInt; +class Value; +} + +namespace clang { +class PointerAuthSchema; +} + +namespace swift { +namespace irgen { +class FunctionPointer; +class IRGenFunction; +class IRGenModule; +class PointerAuthInfo; + +/// Additional information about the source of a function pointer. +class PointerAuthEntity { +public: + enum class Special { + BlockCopyHelper, + BlockDisposeHelper, + HeapDestructor, + PartialApplyCapture, + TypeDescriptor, + TypeDescriptorAsArgument, + KeyPathDestroy, + KeyPathCopy, + KeyPathEquals, + KeyPathHash, + KeyPathGetter, + KeyPathNonmutatingSetter, + KeyPathMutatingSetter, + KeyPathGetLayout, + KeyPathInitializer, + KeyPathMetadataAccessor, + DynamicReplacementKey, + }; + +private: + enum class Kind { + None, + Special, + ValueWitness, + AssociatedType, + AssociatedConformance, + CanSILFunctionType, + CoroutineYieldTypes, + SILDeclRef, + SILFunction, + } StoredKind; + + using Members = ExternalUnionMembers; + static Members::Index getStorageIndexForKind(Kind kind) { + switch (kind) { + case Kind::None: + return Members::indexOf(); + case Kind::Special: + return Members::indexOf(); + case Kind::ValueWitness: + return Members::indexOf(); + case Kind::CoroutineYieldTypes: + case Kind::CanSILFunctionType: + return Members::indexOf(); + case Kind::SILDeclRef: + return Members::indexOf(); + case Kind::AssociatedType: + return Members::indexOf(); + case Kind::AssociatedConformance: + return Members::indexOf(); + case Kind::SILFunction: + return Members::indexOf(); + } + llvm_unreachable("bad kind"); + } + ExternalUnion Storage; + + static_assert(decltype(Storage)::union_is_trivially_copyable, + "please add copy/move/dtor if you need a non-trivial type"); + +public: + PointerAuthEntity() + : StoredKind(Kind::None) { + } + PointerAuthEntity(Special specialKind) + : StoredKind(Kind::Special) { + Storage.emplace(StoredKind, specialKind); + } + PointerAuthEntity(CanSILFunctionType type) + : StoredKind(Kind::CanSILFunctionType) { + Storage.emplace(StoredKind, type); + } + PointerAuthEntity(SILDeclRef decl) + : StoredKind(Kind::SILDeclRef) { + Storage.emplace(StoredKind, decl); + } + PointerAuthEntity(ValueWitness witness) + : StoredKind(Kind::ValueWitness) { + assert(isValueWitnessFunction(witness)); + Storage.emplace(StoredKind, witness); + } + PointerAuthEntity(AssociatedType association) + : StoredKind(Kind::AssociatedType) { + Storage.emplaceAggregate(StoredKind, association); + } + PointerAuthEntity(const AssociatedConformance &association) + : StoredKind(Kind::AssociatedConformance) { + Storage.emplaceAggregate(StoredKind, association); + } + PointerAuthEntity(SILFunction *f) + : StoredKind(Kind::SILFunction) { + Storage.emplace(StoredKind, f); + } + + static PointerAuthEntity forYieldTypes(CanSILFunctionType fnType) { + assert(fnType->isCoroutine()); + PointerAuthEntity result; + result.StoredKind = Kind::CoroutineYieldTypes; + result.Storage.emplace(result.StoredKind, fnType); + return result; + } + + llvm::ConstantInt *getDeclDiscriminator(IRGenModule &IGM) const; + llvm::ConstantInt *getTypeDiscriminator(IRGenModule &IGM) const; +}; + +std::pair +getCoroutineResumeFunctionPointerAuth(IRGenModule &IGM, + CanSILFunctionType coroutineFnType); + +/// Blend a small integer discriminator with the given address value +/// in a way that is assumed to maximally preserve entropy from both. +llvm::Value *emitPointerAuthBlend(IRGenFunction &IGF, + llvm::Value *address, + llvm::Value *discriminator); + +/// Strip the signature of a signed pointer value. +/// The return value has the same type as the input. +llvm::Value *emitPointerAuthStrip(IRGenFunction &IGF, llvm::Value *fnPtr, + unsigned Key); + +/// Sign the given pointer value, which is assumed to be unsigned. +/// The return value has the same type as the input. This is a no-op if +/// the target auth info has disabled signing. +llvm::Value *emitPointerAuthSign(IRGenFunction &IGF, llvm::Value *fnPtr, + const PointerAuthInfo &newAuth); + +/// Authenticate the given pointer value and return an unsigned value. +llvm::Value *emitPointerAuthAuth(IRGenFunction &IGF, llvm::Value *fnPtr, + const PointerAuthInfo &oldAuth); + +/// Resign the given function pointer. +FunctionPointer emitPointerAuthResign(IRGenFunction &IGF, + const FunctionPointer &fn, + const PointerAuthInfo &newAuth); + +/// Resign the given pointer value. This function does the right thing +/// for unsigned input and result schemas. The result will have the same +/// type as the input. +llvm::Value *emitPointerAuthResign(IRGenFunction &IGF, + llvm::Value *fnPtr, + const PointerAuthInfo &oldAuth, + const PointerAuthInfo &newAuth); + +/// The (non-ABI) discriminator used for non-constant captures of +/// partial apply functions. +const uint16_t PointerAuthDiscriminator_PartialApplyCapture = 7185; + +} // end namespace irgen +} // end namespace swift + +#endif diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index e29f60a352f83..203fffc386ccf 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -65,6 +65,7 @@ #include "GenHeap.h" #include "GenMeta.h" #include "GenOpaque.h" +#include "GenPointerAuth.h" #include "GenPoly.h" #include "GenType.h" #include "GenericRequirement.h" @@ -789,6 +790,12 @@ namespace { void addMethod(SILDeclRef func) { auto decl = cast(func.getDecl()); + // If this assert needs to be changed, be sure to also change + // ProtocolDescriptorBuilder::getRequirementInfo. + assert((isa(decl) + ? (func.kind == SILDeclRef::Kind::Allocator) + : (func.kind == SILDeclRef::Kind::Func)) + && "unexpected kind for protocol witness declaration ref"); Entries.push_back(WitnessTableEntry::forFunction(decl)); } @@ -1141,36 +1148,20 @@ class AccessorConformanceInfo : public ConformanceInfo { } }; - /// A class which lays out a specific conformance to a protocol. - class WitnessTableBuilder : public SILWitnessVisitor { + /// A base class for some code shared between fragile and resilient witness + /// table layout. + class WitnessTableBuilderBase { + protected: IRGenModule &IGM; - ConstantArrayBuilder &Table; - unsigned TableSize = ~0U; // will get overwritten unconditionally SILWitnessTable *SILWT; CanType ConcreteType; const RootProtocolConformance &Conformance; const ProtocolConformance &ConformanceInContext; - ArrayRef SILEntries; - ArrayRef - SILConditionalConformances; Optional Fulfillments; - SmallVector, 4> - SpecializedBaseConformances; - - SmallVector ConditionalRequirementPrivateDataIndices; - // Conditional conformances and metadata caches are stored at negative - // offsets, with conditional conformances closest to 0. - unsigned NextPrivateDataIndex = 0; - bool ResilientConformance; - - const ProtocolInfo &PI; - - public: - WitnessTableBuilder(IRGenModule &IGM, ConstantArrayBuilder &table, - SILWitnessTable *SILWT) - : IGM(IGM), Table(table), SILWT(SILWT), + WitnessTableBuilderBase(IRGenModule &IGM, SILWitnessTable *SILWT) + : IGM(IGM), SILWT(SILWT), ConcreteType(SILWT->getConformance()->getDeclContext() ->mapTypeIntoContext( SILWT->getConformance()->getType()) @@ -1178,23 +1169,96 @@ class AccessorConformanceInfo : public ConformanceInfo { Conformance(*SILWT->getConformance()), ConformanceInContext( mapConformanceIntoContext(IGM, Conformance, - Conformance.getDeclContext())), + Conformance.getDeclContext())) {} + + void defineAssociatedTypeWitnessTableAccessFunction( + AssociatedConformance requirement, + CanType associatedType, + ProtocolConformanceRef conformance); + + llvm::Constant *getAssociatedConformanceWitness( + AssociatedConformance requirement, + CanType associatedType, + ProtocolConformanceRef conformance); + + const FulfillmentMap &getFulfillmentMap() { + if (Fulfillments) return *Fulfillments; + + Fulfillments.emplace(); + if (ConcreteType->hasArchetype()) { + struct Callback : FulfillmentMap::InterestingKeysCallback { + bool isInterestingType(CanType type) const override { + return isa(type); + } + bool hasInterestingType(CanType type) const override { + return type->hasArchetype(); + } + bool hasLimitedInterestingConformances(CanType type) const override { + return false; + } + GenericSignature::ConformsToArray + getInterestingConformances(CanType type) const override { + llvm_unreachable("no limits"); + } + CanType getSuperclassBound(CanType type) const override { + if (auto superclassTy = cast(type)->getSuperclass()) + return superclassTy->getCanonicalType(); + return CanType(); + } + } callback; + Fulfillments->searchTypeMetadata(IGM, ConcreteType, IsExact, + MetadataState::Abstract, + /*sourceIndex*/ 0, MetadataPath(), + callback); + } + return *Fulfillments; + } + }; + + /// A fragile witness table is emitted to look like one in memory, except + /// possibly with some blank slots which are filled in by an instantiation + /// function. + class FragileWitnessTableBuilder : public WitnessTableBuilderBase, + public SILWitnessVisitor { + ConstantArrayBuilder &Table; + unsigned TableSize = ~0U; // will get overwritten unconditionally + SmallVector, 4> + SpecializedBaseConformances; + + ArrayRef SILEntries; + ArrayRef + SILConditionalConformances; + + const ProtocolInfo &PI; + + SmallVector ConditionalRequirementPrivateDataIndices; + + void addConditionalConformances() { + for (auto reqtIndex : indices(SILConditionalConformances)) { + // We don't actually need to know anything about the specific + // conformances here, just make sure we get right private data slots. + ConditionalRequirementPrivateDataIndices.push_back(reqtIndex); + } + } + + public: + FragileWitnessTableBuilder(IRGenModule &IGM, ConstantArrayBuilder &table, + SILWitnessTable *SILWT) + : WitnessTableBuilderBase(IGM, SILWT), Table(table), SILEntries(SILWT->getEntries()), SILConditionalConformances(SILWT->getConditionalConformances()), - ResilientConformance(IGM.isResilientConformance(&Conformance)), PI(IGM.getProtocolInfo(SILWT->getConformance()->getProtocol(), - (ResilientConformance - ? ProtocolInfoKind::RequirementSignature - : ProtocolInfoKind::Full))) {} + ProtocolInfoKind::Full)) {} /// The number of entries in the witness table. unsigned getTableSize() const { return TableSize; } - /// The number of private entries in the witness table. - unsigned getTablePrivateSize() const { return NextPrivateDataIndex; } - /// The top-level entry point. - void build(); + void build() { + addConditionalConformances(); + visitProtocolDecl(Conformance.getProtocol()); + TableSize = Table.size(); + } /// Add reference to the protocol conformance descriptor that generated /// this table. @@ -1212,10 +1276,6 @@ class AccessorConformanceInfo : public ConformanceInfo { #endif SILEntries = SILEntries.slice(1); - // Resilient conformances get a resilient witness table. - if (ResilientConformance) - return; - #ifndef NDEBUG assert(entry.getKind() == SILWitnessTable::BaseProtocol && "sil witness table does not match protocol"); @@ -1250,10 +1310,6 @@ class AccessorConformanceInfo : public ConformanceInfo { auto &entry = SILEntries.front(); SILEntries = SILEntries.slice(1); - // Resilient conformances get a resilient witness table. - if (ResilientConformance) - return; - #ifndef NDEBUG assert(entry.getKind() == SILWitnessTable::Method && "sil witness table does not match protocol"); @@ -1275,7 +1331,10 @@ class AccessorConformanceInfo : public ConformanceInfo { // It should be never called. We add a pointer to an error function. witness = IGM.getDeletedMethodErrorFn(); } - Table.addBitCast(witness, IGM.Int8PtrTy); + witness = llvm::ConstantExpr::getBitCast(witness, IGM.Int8PtrTy); + + auto &schema = IGM.getOptions().PointerAuth.ProtocolWitnesses; + Table.addSignedPointer(witness, schema, requirement); return; } @@ -1287,10 +1346,6 @@ class AccessorConformanceInfo : public ConformanceInfo { auto &entry = SILEntries.front(); SILEntries = SILEntries.slice(1); - // Resilient conformances get a resilient witness table. - if (ResilientConformance) - return; - #ifndef NDEBUG assert(entry.getKind() == SILWitnessTable::AssociatedType && "sil witness table does not match protocol"); @@ -1312,7 +1367,11 @@ class AccessorConformanceInfo : public ConformanceInfo { associate, Conformance.getDeclContext()->getGenericSignatureOfContext(), /*inProtocolContext=*/false); - Table.addBitCast(witness, IGM.Int8PtrTy); + witness = llvm::ConstantExpr::getBitCast(witness, IGM.Int8PtrTy); + + auto &schema = IGM.getOptions().PointerAuth + .ProtocolAssociatedTypeAccessFunctions; + Table.addSignedPointer(witness, schema, requirement); } void addAssociatedConformance(AssociatedConformance requirement) { @@ -1322,9 +1381,6 @@ class AccessorConformanceInfo : public ConformanceInfo { (void)entry; SILEntries = SILEntries.slice(1); - if (ResilientConformance) - return; - auto associate = ConformanceInContext.getAssociatedType( requirement.getAssociation())->getCanonicalType(); @@ -1352,83 +1408,26 @@ class AccessorConformanceInfo : public ConformanceInfo { llvm::Constant *witnessEntry = getAssociatedConformanceWitness(requirement, associate, associatedConformance); - Table.addBitCast(witnessEntry, IGM.Int8PtrTy); + + auto &schema = IGM.getOptions().PointerAuth + .ProtocolAssociatedTypeWitnessTableAccessFunctions; + Table.addSignedPointer(witnessEntry, schema, requirement); } /// Build the instantiation function that runs at the end of witness /// table specialization. llvm::Constant *buildInstantiationFunction(); + }; - private: - void addConditionalConformances() { - assert(NextPrivateDataIndex == 0); - for (auto conditional : SILConditionalConformances) { - // We don't actually need to know anything about the specific - // conformances here, just make sure we get right private data slots. - (void)conditional; - - auto reqtIndex = getNextPrivateDataIndex(); - ConditionalRequirementPrivateDataIndices.push_back(reqtIndex); - } - } - - void defineAssociatedTypeWitnessTableAccessFunction( - AssociatedConformance requirement, - CanType associatedType, - ProtocolConformanceRef conformance); - - llvm::Constant *getAssociatedConformanceWitness( - AssociatedConformance requirement, - CanType associatedType, - ProtocolConformanceRef conformance); - - /// Allocate another word of private data storage in the conformance table. - unsigned getNextPrivateDataIndex() { - return NextPrivateDataIndex++; - } - - Address getAddressOfPrivateDataSlot(IRGenFunction &IGF, Address table, - unsigned index) { - assert(index < NextPrivateDataIndex); - return IGF.Builder.CreateConstArrayGEP( - table, privateWitnessTableIndexToTableOffset(index), - IGF.IGM.getPointerSize()); - } - - const FulfillmentMap &getFulfillmentMap() { - if (Fulfillments) return *Fulfillments; - - Fulfillments.emplace(); - if (ConcreteType->hasArchetype()) { - struct Callback : FulfillmentMap::InterestingKeysCallback { - bool isInterestingType(CanType type) const override { - return isa(type); - } - bool hasInterestingType(CanType type) const override { - return type->hasArchetype(); - } - bool hasLimitedInterestingConformances(CanType type) const override { - return false; - } - GenericSignature::ConformsToArray - getInterestingConformances(CanType type) const override { - llvm_unreachable("no limits"); - } - CanType getSuperclassBound(CanType type) const override { - if (auto superclassTy = cast(type)->getSuperclass()) - return superclassTy->getCanonicalType(); - return CanType(); - } - } callback; - Fulfillments->searchTypeMetadata(IGM, ConcreteType, IsExact, - MetadataState::Abstract, - /*sourceIndex*/ 0, MetadataPath(), - callback); - } - return *Fulfillments; - } - + /// A resilient witness table consists of a list of descriptor/witness pairs, + /// and a runtime function builds the actual witness table in memory, placing + /// entries in the correct oder and filling in default implementations as + /// needed. + class ResilientWitnessTableBuilder : public WitnessTableBuilderBase { public: + ResilientWitnessTableBuilder(IRGenModule &IGM, SILWitnessTable *SILWT) + : WitnessTableBuilderBase(IGM, SILWT) {} + /// Collect the set of resilient witnesses, which will become part of the /// protocol conformance descriptor. void collectResilientWitnesses( @@ -1436,13 +1435,6 @@ class AccessorConformanceInfo : public ConformanceInfo { }; } // end anonymous namespace -/// Build the witness table. -void WitnessTableBuilder::build() { - addConditionalConformances(); - visitProtocolDecl(Conformance.getProtocol()); - TableSize = Table.size(); -} - llvm::Constant *IRGenModule::getAssociatedTypeWitness(Type type, GenericSignature sig, bool inProtocolContext) { @@ -1456,11 +1448,11 @@ llvm::Constant *IRGenModule::getAssociatedTypeWitness(Type type, auto typeRef = getTypeRef(type, sig, role).first; // Set the low bit to indicate that this is a mangled name. - auto witness = llvm::ConstantExpr::getPtrToInt(typeRef, IntPtrTy); + auto witness = llvm::ConstantExpr::getBitCast(typeRef, Int8PtrTy); unsigned bit = ProtocolRequirementFlags::AssociatedTypeMangledNameBit; auto bitConstant = llvm::ConstantInt::get(IntPtrTy, bit); - witness = llvm::ConstantExpr::getAdd(witness, bitConstant); - return llvm::ConstantExpr::getIntToPtr(witness, Int8PtrTy); + return llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, witness, + bitConstant); } static void buildAssociatedTypeValueName(CanType depAssociatedType, @@ -1474,7 +1466,7 @@ static void buildAssociatedTypeValueName(CanType depAssociatedType, } } -llvm::Constant *WitnessTableBuilder::getAssociatedConformanceWitness( +llvm::Constant *WitnessTableBuilderBase::getAssociatedConformanceWitness( AssociatedConformance requirement, CanType associatedType, ProtocolConformanceRef conformance) { @@ -1485,7 +1477,7 @@ llvm::Constant *WitnessTableBuilder::getAssociatedConformanceWitness( return IGM.getMangledAssociatedConformance(conf, requirement); } -void WitnessTableBuilder::defineAssociatedTypeWitnessTableAccessFunction( +void WitnessTableBuilderBase::defineAssociatedTypeWitnessTableAccessFunction( AssociatedConformance requirement, CanType associatedType, ProtocolConformanceRef associatedConformance) { @@ -1604,11 +1596,8 @@ void WitnessTableBuilder::defineAssociatedTypeWitnessTableAccessFunction( IGF.Builder.CreateRet(wtable); } -void WitnessTableBuilder::collectResilientWitnesses( +void ResilientWitnessTableBuilder::collectResilientWitnesses( SmallVectorImpl &resilientWitnesses) { - if (!ResilientConformance) - return; - assert(isa(Conformance) && "resilient conformance should always be normal"); auto &conformance = cast(Conformance); @@ -1684,7 +1673,7 @@ void WitnessTableBuilder::collectResilientWitnesses( } } -llvm::Constant *WitnessTableBuilder::buildInstantiationFunction() { +llvm::Constant *FragileWitnessTableBuilder::buildInstantiationFunction() { // We need an instantiation function if any base conformance // is non-dependent. if (SpecializedBaseConformances.empty()) @@ -2138,24 +2127,22 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) { auto conf = wt->getConformance(); PrettyStackTraceConformance _st(Context, "emitting witness table for", conf); - // Build the witness table. - ConstantInitBuilder builder(*this); - auto wtableContents = builder.beginArray(Int8PtrTy); - WitnessTableBuilder wtableBuilder(*this, wtableContents, wt); - wtableBuilder.build(); - + unsigned tableSize = 0; + llvm::GlobalVariable *global = nullptr; + llvm::Constant *instantiationFunction = nullptr; + bool isDependent = isDependentConformance(conf); SmallVector resilientWitnesses; - // Collect the resilient witnesses to go into the conformance descriptor. - wtableBuilder.collectResilientWitnesses(resilientWitnesses); - // Produce the initializer value. - auto initializer = wtableContents.finishAndCreateFuture(); + if (!isResilientConformance(conf)) { + // Build the witness table. + ConstantInitBuilder builder(*this); + auto wtableContents = builder.beginArray(Int8PtrTy); + FragileWitnessTableBuilder wtableBuilder(*this, wtableContents, wt); + wtableBuilder.build(); - bool isDependent = isDependentConformance(conf); + // Produce the initializer value. + auto initializer = wtableContents.finishAndCreateFuture(); - llvm::GlobalVariable *global = nullptr; - unsigned tableSize; - if (!isResilientConformance(conf)) { global = cast( (isDependent && conf->getDeclContext()->isGenericContext()) ? getAddrOfWitnessTablePattern(cast(conf), @@ -2164,20 +2151,25 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) { global->setConstant(isConstantWitnessTable(wt)); global->setAlignment( llvm::MaybeAlign(getWitnessTableAlignment().getValue())); + tableSize = wtableBuilder.getTableSize(); + instantiationFunction = wtableBuilder.buildInstantiationFunction(); } else { - initializer.abandon(); - tableSize = 0; + // Build the witness table. + ResilientWitnessTableBuilder wtableBuilder(*this, wt); + + // Collect the resilient witnesses to go into the conformance descriptor. + wtableBuilder.collectResilientWitnesses(resilientWitnesses); } // Collect the information that will go into the protocol conformance // descriptor. + unsigned tablePrivateSize = wt->getConditionalConformances().size(); ConformanceDescription description(conf, wt, global, tableSize, - wtableBuilder.getTablePrivateSize(), - isDependent); + tablePrivateSize, isDependent); // Build the instantiation function, we if need one. - description.instantiationFn = wtableBuilder.buildInstantiationFunction(); + description.instantiationFn = instantiationFunction; description.resilientWitnesses = std::move(resilientWitnesses); // Record this conformance descriptor. @@ -3060,7 +3052,8 @@ GenericTypeRequirements::GenericTypeRequirements(IRGenModule &IGM, /*callee*/ ParameterConvention::Direct_Unowned, /*params*/ {}, /*yields*/ {}, /*results*/ {}, /*error*/ None, - /*subs*/ SubstitutionMap(), /*implied*/ false, + /*pattern subs*/ SubstitutionMap(), + /*invocation subs*/ SubstitutionMap(), IGM.Context); // Figure out what we're actually still required to pass @@ -3280,9 +3273,10 @@ FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF, // Find the witness we're interested in. auto &fnProtoInfo = IGF.IGM.getProtocolInfo(proto, ProtocolInfoKind::Full); auto index = fnProtoInfo.getFunctionIndex(fn); + llvm::Value *slot; llvm::Value *witnessFnPtr = emitInvariantLoadOfOpaqueWitness(IGF, wtable, - index.forProtocolWitnessTable()); + index.forProtocolWitnessTable(), &slot); auto fnType = IGF.IGM.getSILTypes().getConstantFunctionType( IGF.IGM.getMaximalTypeExpansionContext(), member); @@ -3290,7 +3284,10 @@ FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF, witnessFnPtr = IGF.Builder.CreateBitCast(witnessFnPtr, signature.getType()->getPointerTo()); - return FunctionPointer(witnessFnPtr, signature); + auto &schema = IGF.getOptions().PointerAuth.ProtocolWitnesses; + auto authInfo = PointerAuthInfo::emit(IGF, schema, slot, member); + + return FunctionPointer(witnessFnPtr, authInfo, signature); } FunctionPointer irgen::emitWitnessMethodValue( diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index cf74cb3113856..afdf4fe5e1ab8 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -1156,7 +1156,7 @@ class CaptureDescriptorBuilder : public ReflectionMetadataBuilder { B.addInt32(Layout.getBindings().size()); auto sig = - OrigCalleeType->getSubstGenericSignature().getCanonicalSignature(); + OrigCalleeType->getInvocationGenericSignature().getCanonicalSignature(); // Now add typerefs of all of the captures. for (auto CaptureType : CaptureTypes) { diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp index 14e27122d7fcc..6c951ed3eece4 100644 --- a/lib/IRGen/GenValueWitness.cpp +++ b/lib/IRGen/GenValueWitness.cpp @@ -37,6 +37,7 @@ #include "GenEnum.h" #include "GenMeta.h" #include "GenOpaque.h" +#include "GenPointerAuth.h" #include "IRGenDebugInfo.h" #include "IRGenFunction.h" #include "IRGenModule.h" @@ -800,7 +801,8 @@ static void addValueWitness(IRGenModule &IGM, SILType concreteType, const TypeInfo &concreteTI) { auto addFunction = [&](llvm::Constant *fn) { - B.addBitCast(fn, IGM.Int8PtrTy); + fn = llvm::ConstantExpr::getBitCast(fn, IGM.Int8PtrTy); + B.addSignedPointer(fn, IGM.getOptions().PointerAuth.ValueWitnesses, index); }; // Try to use a standard function. diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 1b96deca94d73..19e8fc85f650f 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -39,6 +39,7 @@ #include "swift/Subsystems.h" #include "../Serialization/ModuleFormat.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/CompilerInstance.h" #include "llvm/ADT/StringSet.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Bitcode/BitcodeWriter.h" @@ -666,6 +667,67 @@ bool swift::performLLVM(const IRGenOptions &Opts, return false; } +static void setPointerAuthOptions(PointerAuthOptions &opts, + const clang::PointerAuthOptions &clangOpts){ + // Intentionally do a slice-assignment to copy over the clang options. + static_cast(opts) = clangOpts; + + assert(clangOpts.FunctionPointers); + if (clangOpts.FunctionPointers.getKind() != PointerAuthSchema::Kind::ARM8_3) + return; + + using Discrimination = PointerAuthSchema::Discrimination; + auto key = clangOpts.FunctionPointers.getARM8_3Key(); + auto nonABIKey = PointerAuthSchema::ARM8_3Key::ASIB; + + // If you change anything here, be sure to update . + opts.SwiftFunctionPointers = + PointerAuthSchema(key, /*address*/ false, Discrimination::Type); + opts.KeyPaths = + PointerAuthSchema(key, /*address*/ true, Discrimination::Decl); + opts.ValueWitnesses = + PointerAuthSchema(key, /*address*/ true, Discrimination::Decl); + opts.ProtocolWitnesses = + PointerAuthSchema(key, /*address*/ true, Discrimination::Decl); + opts.ProtocolAssociatedTypeAccessFunctions = + PointerAuthSchema(key, /*address*/ true, Discrimination::Decl); + opts.ProtocolAssociatedTypeWitnessTableAccessFunctions = + PointerAuthSchema(key, /*address*/ true, Discrimination::Decl); + opts.SwiftClassMethods = + PointerAuthSchema(key, /*address*/ true, Discrimination::Decl); + opts.SwiftClassMethodPointers = + PointerAuthSchema(key, /*address*/ false, Discrimination::Decl); + opts.HeapDestructors = + PointerAuthSchema(key, /*address*/ true, Discrimination::Decl); + + // Partial-apply captures are not ABI and can use a more aggressive key. + opts.PartialApplyCapture = + PointerAuthSchema(nonABIKey, /*address*/ true, Discrimination::Decl); + + opts.TypeDescriptors = + PointerAuthSchema(PointerAuthSchema::ARM8_3Key::ASDA, /*address*/ true, + Discrimination::Decl); + opts.TypeDescriptorsAsArguments = + PointerAuthSchema(PointerAuthSchema::ARM8_3Key::ASDA, /*address*/ false, + Discrimination::Decl); + + opts.SwiftDynamicReplacements = + PointerAuthSchema(key, /*address*/ true, Discrimination::Decl); + opts.SwiftDynamicReplacementKeys = + PointerAuthSchema(PointerAuthSchema::ARM8_3Key::ASDA, /*address*/ true, + Discrimination::Decl); + + // Coroutine resumption functions are never stored globally in the ABI, + // so we can do some things that aren't normally okay to do. However, + // we can't use ASIB because that would break ARM64 interoperation. + // The address used in the discrimination is not the address where the + // function pointer is signed, but the address of the coroutine buffer. + opts.YieldManyResumeFunctions = + PointerAuthSchema(key, /*address*/ true, Discrimination::Type); + opts.YieldOnceResumeFunctions = + PointerAuthSchema(key, /*address*/ true, Discrimination::Type); +} + std::unique_ptr swift::createTargetMachine(const IRGenOptions &Opts, ASTContext &Ctx) { CodeGenOpt::Level OptLevel = Opts.shouldOptimize() @@ -690,6 +752,18 @@ swift::createTargetMachine(const IRGenOptions &Opts, ASTContext &Ctx) { targetFeatures = features.getString(); } + // Set up pointer-authentication. + if (auto loader = Ctx.getClangModuleLoader()) { + auto &clangInstance = loader->getClangInstance(); + if (clangInstance.getLangOpts().PointerAuthCalls) { + // FIXME: This is gross. This needs to be done in the Frontend + // after the module loaders are set up, and where these options are + // formally not const. + setPointerAuthOptions(const_cast(Opts).PointerAuth, + clangInstance.getCodeGenOpts().PointerAuth); + } + } + std::string Error; const Target *Target = TargetRegistry::lookupTarget(EffectiveTriple.str(), Error); diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 74b2271313cdc..1299f52c822a2 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -659,10 +659,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { } } - StringRef Sysroot = IGM.Context.SearchPathOpts.SDKPath; llvm::DIModule *M = - DBuilder.createModule(Parent, Name, ConfigMacros, RemappedIncludePath, - Sysroot); + DBuilder.createModule(Parent, Name, ConfigMacros, RemappedIncludePath); DIModuleCache.insert({Key, llvm::TrackingMDNodeRef(M)}); return M; } @@ -1697,13 +1695,18 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts, DBuilder.createFile(DebugPrefixMap.remapPath(SourcePath), DebugPrefixMap.remapPath(Opts.DebugCompilationDir)); + StringRef Sysroot = IGM.Context.SearchPathOpts.SDKPath; TheCU = DBuilder.createCompileUnit( Lang, MainFile, Producer, Opts.shouldOptimize(), Opts.getDebugFlags(PD), MajorRuntimeVersion, SplitName, Opts.DebugInfoLevel > IRGenDebugInfoLevel::LineTables ? llvm::DICompileUnit::FullDebug - : llvm::DICompileUnit::LineTablesOnly); + : llvm::DICompileUnit::LineTablesOnly, + /* DWOId */ 0, /* SplitDebugInlining */ true, + /* DebugInfoForProfiling */ false, + llvm::DICompileUnit::DebugNameTableKind::Default, + /* RangesBaseAddress */ false, Sysroot); // Because the swift compiler relies on Clang to setup the Module, // the clang CU is always created first. Several dwarf-reading diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h index 77198ae596dcb..f972d4c7eedc4 100644 --- a/lib/IRGen/IRGenMangler.h +++ b/lib/IRGen/IRGenMangler.h @@ -15,6 +15,7 @@ #include "IRGenModule.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/ProtocolAssociations.h" #include "swift/IRGen/ValueWitness.h" #include "llvm/Support/SaveAndRestore.h" @@ -347,6 +348,25 @@ class IRGenMangler : public Mangle::ASTMangler { return mangleConformanceSymbol(type, C, "WL"); } + std::string + mangleAssociatedTypeAccessFunctionDiscriminator(AssociatedType association) { + beginMangling(); + appendAnyGenericType(association.getSourceProtocol()); + appendIdentifier(association.getAssociation()->getNameStr()); + return finalize(); + } + + std::string mangleAssociatedTypeWitnessTableAccessFunctionDiscriminator( + const AssociatedConformance &conf) { + beginMangling(); + appendAnyGenericType(conf.getSourceProtocol()); + bool isFirstAssociatedTypeIdentifier = true; + appendAssociatedTypePath(conf.getAssociation(), + isFirstAssociatedTypeIdentifier); + appendAnyGenericType(conf.getAssociatedRequirement()); + return finalize(); + } + std::string mangleAssociatedTypeWitnessTableAccessFunction( const ProtocolConformance *Conformance, CanType AssociatedType, diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 28aa23b514ec9..04c83b269af9c 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Module.h" #include "swift/AST/DiagnosticsIRGen.h" +#include "swift/AST/GenericSignature.h" #include "swift/AST/IRGenOptions.h" #include "swift/Basic/Dwarf.h" #include "swift/Demangling/ManglingMacros.h" @@ -49,9 +50,11 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" +#include "Callee.h" #include "ConformanceDescription.h" #include "GenDecl.h" #include "GenEnum.h" +#include "GenPointerAuth.h" #include "GenIntegerLiteral.h" #include "GenType.h" #include "IRGenModule.h" @@ -141,6 +144,52 @@ static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context, return ClangCodeGen; } +#ifndef NDEBUG +static ValueDecl *lookupSimple(ModuleDecl *module, ArrayRef declPath) { + DeclContext *dc = module; + for (;; declPath = declPath.drop_front()) { + SmallVector results; + module->lookupMember(results, dc, module->getASTContext().getIdentifier(declPath.front()), Identifier()); + if (results.size() != 1) return nullptr; + if (declPath.size() == 1) return results.front(); + dc = dyn_cast(results.front()); + if (!dc) return nullptr; + } +} + +static void checkPointerAuthWitnessDiscriminator(IRGenModule &IGM, ArrayRef declPath, uint16_t expected) { + auto &schema = IGM.getOptions().PointerAuth.ProtocolWitnesses; + if (!schema.isEnabled()) return; + + auto decl = lookupSimple(IGM.getSwiftModule(), declPath); + assert(decl && "decl not found"); + auto discriminator = PointerAuthInfo::getOtherDiscriminator(IGM, schema, SILDeclRef(decl)); + assert(discriminator->getZExtValue() == expected && "discriminator value doesn't match"); +} + +static void checkPointerAuthAssociatedTypeDiscriminator(IRGenModule &IGM, ArrayRef declPath, uint16_t expected) { + auto &schema = IGM.getOptions().PointerAuth.ProtocolAssociatedTypeAccessFunctions; + if (!schema.isEnabled()) return; + + auto decl = dyn_cast_or_null(lookupSimple(IGM.getSwiftModule(), declPath)); + assert(decl && "decl not found"); + auto discriminator = PointerAuthInfo::getOtherDiscriminator(IGM, schema, AssociatedType(decl)); + assert(discriminator->getZExtValue() == expected && "discriminator value doesn't match"); +} + +static void sanityCheckStdlib(IRGenModule &IGM) { + if (!IGM.getSwiftModule()->isStdlibModule()) return; + + // Only run the sanity check when we're building the real stdlib. + if (!lookupSimple(IGM.getSwiftModule(), { "String" })) return; + + checkPointerAuthAssociatedTypeDiscriminator(IGM, { "_ObjectiveCBridgeable", "_ObjectiveCType" }, SpecialPointerAuthDiscriminators::ObjectiveCTypeDiscriminator); + checkPointerAuthWitnessDiscriminator(IGM, { "_ObjectiveCBridgeable", "_bridgeToObjectiveC" }, SpecialPointerAuthDiscriminators::bridgeToObjectiveCDiscriminator); + checkPointerAuthWitnessDiscriminator(IGM, { "_ObjectiveCBridgeable", "_forceBridgeFromObjectiveC" }, SpecialPointerAuthDiscriminators::forceBridgeFromObjectiveCDiscriminator); + checkPointerAuthWitnessDiscriminator(IGM, { "_ObjectiveCBridgeable", "_conditionallyBridgeFromObjectiveC" }, SpecialPointerAuthDiscriminators::conditionallyBridgeFromObjectiveCDiscriminator); +} +#endif + IRGenModule::IRGenModule(IRGenerator &irgen, std::unique_ptr &&target, SourceFile *SF, llvm::LLVMContext &LLVMContext, @@ -508,6 +557,10 @@ IRGenModule::IRGenModule(IRGenerator &irgen, clang::CodeGen::swiftcall::isSwiftErrorLoweredInRegister( ClangCodeGen->CGM()); +#ifndef NDEBUG + sanityCheckStdlib(*this); +#endif + DynamicReplacementsTy = llvm::StructType::get(getLLVMContext(), {Int8PtrPtrTy, Int8PtrTy}); DynamicReplacementsPtrTy = DynamicReplacementsTy->getPointerTo(DefaultAS); @@ -532,6 +585,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen, IRGenModule::~IRGenModule() { destroyClangTypeConverter(); destroyMetadataLayoutMap(); + destroyPointerAuthCaches(); delete &Types; } @@ -963,6 +1017,12 @@ void IRGenModule::constructInitialFnAttributes(llvm::AttrBuilder &Attrs, FuncOptMode = IRGen.Opts.OptMode; if (FuncOptMode == OptimizationMode::ForSize) Attrs.addAttribute(llvm::Attribute::MinSize); + + auto triple = llvm::Triple(ClangOpts.Triple); + if (triple.getArchName() == "arm64e") { + Attrs.addAttribute("ptrauth-returns"); + Attrs.addAttribute("ptrauth-calls"); + } } llvm::AttributeList IRGenModule::constructInitialAttributes() { @@ -976,7 +1036,7 @@ llvm::ConstantInt *IRGenModule::getInt32(uint32_t value) { return llvm::ConstantInt::get(Int32Ty, value); } -llvm::Constant *IRGenModule::getSize(Size size) { +llvm::ConstantInt *IRGenModule::getSize(Size size) { return llvm::ConstantInt::get(SizeTy, size.getValue()); } diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index d59328d773b49..9570deb2596ae 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -73,6 +73,7 @@ namespace clang { class Decl; class GlobalDecl; class Type; + class PointerAuthSchema; namespace CodeGen { class CGFunctionInfo; class CodeGenModule; @@ -139,6 +140,7 @@ namespace irgen { class NecessaryBindings; class NominalMetadataLayout; class OutliningMetadataCollector; + class PointerAuthEntity; class ProtocolInfo; enum class ProtocolInfoKind : uint8_t; class Signature; @@ -952,6 +954,20 @@ class IRGenModule { llvm::Constant *emitTypeMetadataRecords(); llvm::Constant *emitFieldDescriptors(); + llvm::Constant *getConstantSignedFunctionPointer(llvm::Constant *fn, + CanSILFunctionType fnType); + + llvm::Constant *getConstantSignedCFunctionPointer(llvm::Constant *fn); + + llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer, + unsigned key, + llvm::Constant *addrDiscriminator, + llvm::Constant *otherDiscriminator); + llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer, + const clang::PointerAuthSchema &schema, + const PointerAuthEntity &entity, + llvm::Constant *storageAddress); + llvm::Constant *getOrCreateHelperFunction(StringRef name, llvm::Type *resultType, ArrayRef paramTypes, @@ -1021,6 +1037,12 @@ class IRGenModule { llvm::StringMap GlobalConstantStrings; llvm::StringMap GlobalConstantUTF16Strings; + struct PointerAuthCachesType; + PointerAuthCachesType *PointerAuthCaches = nullptr; + PointerAuthCachesType &getPointerAuthCaches(); + void destroyPointerAuthCaches(); + friend class PointerAuthEntity; + /// LLVMUsed - List of global values which are required to be /// present in the object file; bitcast to i8*. This is used for /// forcing visibility of symbols which may otherwise be optimized @@ -1300,7 +1322,7 @@ private: \ ForeignFunctionInfo getForeignFunctionInfo(CanSILFunctionType type); llvm::ConstantInt *getInt32(uint32_t value); - llvm::Constant *getSize(Size size); + llvm::ConstantInt *getSize(Size size); llvm::Constant *getAlignment(Alignment align); llvm::Constant *getBool(bool condition); diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 0a53fd6257da6..77d7d3aee18dc 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -70,6 +70,7 @@ #include "GenObjC.h" #include "GenOpaque.h" #include "GenPoly.h" +#include "GenPointerAuth.h" #include "GenProto.h" #include "GenStruct.h" #include "GenTuple.h" @@ -2719,7 +2720,13 @@ void IRGenSILFunction::visitEndApply(BeginApplyInst *i, bool isAbort) { continuation = Builder.CreateBitCast(continuation, sig.getType()->getPointerTo()); - FunctionPointer callee(continuation, sig); + + auto schemaAndEntity = + getCoroutineResumeFunctionPointerAuth(IGM, i->getOrigCalleeType()); + auto pointerAuth = PointerAuthInfo::emit(*this, schemaAndEntity.first, + coroutine.Buffer.getAddress(), + schemaAndEntity.second); + FunctionPointer callee(continuation, pointerAuth, sig); Builder.CreateCall(callee, { coroutine.Buffer.getAddress(), @@ -5630,7 +5637,11 @@ void IRGenSILFunction::visitSuperMethodInst(swift::SuperMethodInst *i) { auto sig = IGM.getSignature(methodType); fnPtr = Builder.CreateBitCast(fnPtr, sig.getType()->getPointerTo()); - FunctionPointer fn(fnPtr, sig); + auto &schema = getOptions().PointerAuth.SwiftClassMethodPointers; + auto authInfo = + PointerAuthInfo::emit(*this, schema, /*storageAddress=*/nullptr, method); + + FunctionPointer fn(fnPtr, authInfo, sig); setLoweredFunctionPointer(i, fn); return; diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index 02eea30c2fc28..ab9aa8bfd5333 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -672,6 +672,75 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const { llvm_unreachable("bad link entity kind"); } +bool LinkEntity::isContextDescriptor() const { + switch (getKind()) { + case Kind::ModuleDescriptor: + case Kind::ExtensionDescriptor: + case Kind::AnonymousDescriptor: + case Kind::NominalTypeDescriptor: + case Kind::ProtocolDescriptor: + case Kind::OpaqueTypeDescriptor: + return true; + case Kind::PropertyDescriptor: + case Kind::DispatchThunk: + case Kind::DispatchThunkInitializer: + case Kind::DispatchThunkAllocator: + case Kind::MethodDescriptor: + case Kind::MethodDescriptorInitializer: + case Kind::MethodDescriptorAllocator: + case Kind::MethodLookupFunction: + case Kind::EnumCase: + case Kind::FieldOffset: + case Kind::ObjCClass: + case Kind::ObjCClassRef: + case Kind::ObjCMetaclass: + case Kind::ObjCMetadataUpdateFunction: + case Kind::ObjCResilientClassStub: + case Kind::SwiftMetaclassStub: + case Kind::ClassMetadataBaseOffset: + case Kind::TypeMetadataPattern: + case Kind::TypeMetadataInstantiationCache: + case Kind::TypeMetadataInstantiationFunction: + case Kind::TypeMetadataSingletonInitializationCache: + case Kind::TypeMetadataCompletionFunction: + case Kind::ProtocolRequirementsBaseDescriptor: + case Kind::AssociatedTypeDescriptor: + case Kind::AssociatedConformanceDescriptor: + case Kind::BaseConformanceDescriptor: + case Kind::DefaultAssociatedConformanceAccessor: + case Kind::SILFunction: + case Kind::SILGlobalVariable: + case Kind::ProtocolWitnessTable: + case Kind::ProtocolWitnessTablePattern: + case Kind::GenericProtocolWitnessTableInstantiationFunction: + case Kind::AssociatedTypeWitnessTableAccessFunction: + case Kind::ReflectionAssociatedTypeDescriptor: + case Kind::ProtocolConformanceDescriptor: + case Kind::ProtocolWitnessTableLazyAccessFunction: + case Kind::ProtocolWitnessTableLazyCacheVariable: + case Kind::ValueWitness: + case Kind::ValueWitnessTable: + case Kind::TypeMetadata: + case Kind::TypeMetadataAccessFunction: + case Kind::TypeMetadataLazyCacheVariable: + case Kind::TypeMetadataDemanglingCacheVariable: + case Kind::ReflectionBuiltinDescriptor: + case Kind::ReflectionFieldDescriptor: + case Kind::CoroutineContinuationPrototype: + case Kind::DynamicallyReplaceableFunctionVariableAST: + case Kind::DynamicallyReplaceableFunctionKeyAST: + case Kind::DynamicallyReplaceableFunctionImpl: + case Kind::DynamicallyReplaceableFunctionKey: + case Kind::DynamicallyReplaceableFunctionVariable: + case Kind::OpaqueTypeDescriptorAccessor: + case Kind::OpaqueTypeDescriptorAccessorImpl: + case Kind::OpaqueTypeDescriptorAccessorKey: + case Kind::OpaqueTypeDescriptorAccessorVar: + case Kind::DifferentiabilityWitness: + return false; + } +} + llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const { switch (getKind()) { case Kind::ModuleDescriptor: @@ -1008,6 +1077,7 @@ DeclContext *LinkEntity::getDeclContextForEmission() const { case Kind::TypeMetadataAccessFunction: case Kind::TypeMetadataLazyCacheVariable: case Kind::TypeMetadataDemanglingCacheVariable: + assert(isAlwaysSharedLinkage() && "kind should always be shared linkage"); return nullptr; // TODO @@ -1020,3 +1090,19 @@ DeclContext *LinkEntity::getDeclContextForEmission() const { return nullptr; } } + +bool LinkEntity::isAlwaysSharedLinkage() const { + switch (getKind()) { + case Kind::ModuleDescriptor: + case Kind::ExtensionDescriptor: + case Kind::AnonymousDescriptor: + case Kind::ObjCClassRef: + case Kind::TypeMetadataAccessFunction: + case Kind::TypeMetadataLazyCacheVariable: + case Kind::TypeMetadataDemanglingCacheVariable: + return true; + + default: + return false; + } +} diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 05fb06bbd7e47..933a7d1b78f36 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -150,7 +150,7 @@ bool LargeSILTypeMapper::shouldTransformFunctionType(GenericEnvironment *env, irgen::IRGenModule &IGM) { // Map substituted function types according to their substituted generic // signature. - if (fnType->getSubstitutions()) { + if (fnType->getPatternSubstitutions()) { env = getSubstGenericEnvironment(fnType); } @@ -287,7 +287,7 @@ LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env, // Map substituted function types according to their substituted generic // signature. - if (fnType->getSubstitutions()) { + if (fnType->getPatternSubstitutions()) { env = getSubstGenericEnvironment(fnType); } @@ -295,7 +295,7 @@ LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env, auto newYields = getNewYields(env, fnType, IGM); auto newResults = getNewResults(env, fnType, IGM); auto newFnType = SILFunctionType::get( - fnType->getSubstGenericSignature(), + fnType->getInvocationGenericSignature(), fnType->getExtInfo(), fnType->getCoroutineKind(), fnType->getCalleeConvention(), @@ -303,8 +303,8 @@ LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env, newYields, newResults, fnType->getOptionalErrorResult(), - fnType->getSubstitutions(), - fnType->isGenericSignatureImplied(), + fnType->getPatternSubstitutions(), + fnType->getInvocationSubstitutions(), fnType->getASTContext(), fnType->getWitnessMethodConformanceOrInvalid()); return newFnType; @@ -2359,7 +2359,8 @@ static bool rewriteFunctionReturn(StructLoweringState &pass) { loweredTy->getParameters(), loweredTy->getYields(), newSILResultInfo, loweredTy->getOptionalErrorResult(), - loweredTy->getSubstitutions(), loweredTy->isGenericSignatureImplied(), + loweredTy->getPatternSubstitutions(), + loweredTy->getInvocationSubstitutions(), F->getModule().getASTContext(), loweredTy->getWitnessMethodConformanceOrInvalid()); F->rewriteLoweredTypeUnsafe(NewTy); diff --git a/lib/IRGen/LocalTypeData.cpp b/lib/IRGen/LocalTypeData.cpp index 7ca002c90de82..28d0b71fc7e70 100644 --- a/lib/IRGen/LocalTypeData.cpp +++ b/lib/IRGen/LocalTypeData.cpp @@ -708,6 +708,11 @@ void LocalTypeDataKind::print(llvm::raw_ostream &out) const { out << "ValueWitnessTable"; } else { assert(isSingletonKind()); + if (Value >= ValueWitnessDiscriminatorBase) { + auto witness = ValueWitness(Value - ValueWitnessDiscriminatorBase); + out << "Discriminator(" << getValueWitnessName(witness) << ")"; + return; + } ValueWitness witness = ValueWitness(Value - ValueWitnessBase); out << getValueWitnessName(witness); } diff --git a/lib/IRGen/LocalTypeDataKind.h b/lib/IRGen/LocalTypeDataKind.h index b20657e85d479..f45aa30cb1755 100644 --- a/lib/IRGen/LocalTypeDataKind.h +++ b/lib/IRGen/LocalTypeDataKind.h @@ -21,6 +21,7 @@ #include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/Type.h" +#include "swift/IRGen/ValueWitness.h" #include #include "llvm/ADT/DenseMapInfo.h" @@ -28,7 +29,6 @@ namespace swift { class ProtocolDecl; namespace irgen { - enum class ValueWitness : unsigned; /// The kind of local type data we might want to store for a type. class LocalTypeDataKind { @@ -54,6 +54,9 @@ class LocalTypeDataKind { // The first enumerator for an individual value witness. ValueWitnessBase, + // The first enumerator for an individual value witness discriminator. + ValueWitnessDiscriminatorBase = ValueWitnessBase + MaxNumValueWitnesses, + FirstPayloadValue = 2048, Kind_Decl = 0, Kind_Conformance = 1, @@ -86,6 +89,11 @@ class LocalTypeDataKind { static LocalTypeDataKind forValueWitness(ValueWitness witness) { return LocalTypeDataKind(ValueWitnessBase + (unsigned)witness); } + + /// The discriminator for a specific value witness. + static LocalTypeDataKind forValueWitnessDiscriminator(ValueWitness witness) { + return LocalTypeDataKind(ValueWitnessDiscriminatorBase + (unsigned)witness); + } /// A reference to a protocol witness table for an archetype. /// diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 830c62cec2cf8..886e5ca5f694d 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -16,12 +16,14 @@ #include "MetadataRequest.h" +#include "Callee.h" #include "ConstantBuilder.h" #include "Explosion.h" #include "FixedTypeInfo.h" #include "GenArchetype.h" #include "GenClass.h" #include "GenMeta.h" +#include "GenPointerAuth.h" #include "GenProto.h" #include "GenType.h" #include "GenericArguments.h" @@ -1881,9 +1883,18 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( GenericArguments &genericArgs) { auto &IGM = IGF.IGM; - llvm::Constant *descriptor = + llvm::Value *descriptor = IGM.getAddrOfTypeContextDescriptor(nominal, RequireMetadata); + // Sign the descriptor. + auto schema = IGF.IGM.getOptions().PointerAuth.TypeDescriptorsAsArguments; + if (schema) { + auto authInfo = PointerAuthInfo::emit( + IGF, schema, nullptr, + PointerAuthEntity::Special::TypeDescriptorAsArgument); + descriptor = emitPointerAuthSign(IGF, descriptor, authInfo); + } + auto request = params.claimNext(); auto numArguments = genericArgs.Types.size(); diff --git a/lib/Markup/Markup.cpp b/lib/Markup/Markup.cpp index e6f55ab69288c..04f6cb50973cb 100644 --- a/lib/Markup/Markup.cpp +++ b/lib/Markup/Markup.cpp @@ -54,7 +54,7 @@ struct ParseResult { } }; -StringRef getLiteralContent(MarkupContext &MC, LineList &LL, cmark_node *Node) { +StringRef getLiteralContent(MarkupContext &MC, cmark_node *Node) { // Literal content nodes never have start/end column line information. // It is a floating piece of text that inherits location information from // its parent. @@ -63,50 +63,45 @@ StringRef getLiteralContent(MarkupContext &MC, LineList &LL, cmark_node *Node) { return MC.allocateCopy(StringRef(Literal)); } -ParseResult -parseElement(MarkupContext &MC, LineList &LL, ParseState State); +ParseResult parseElement(MarkupContext &MC, ParseState State); -ParseState parseChildren(MarkupContext &MC, LineList &LL, ParseState State, +ParseState parseChildren(MarkupContext &MC, ParseState State, SmallVectorImpl &Children) { auto Root = State.Node; State = State.next(); do { if (Root == State.Node && State.Event == CMARK_EVENT_EXIT) break; - auto Result = parseElement(MC, LL, State); + auto Result = parseElement(MC, State); Children.push_back(Result.Node); State = Result.State; } while (!(Root == State.Node && State.Event == CMARK_EVENT_EXIT)); return State; } -ParseResult parseText(MarkupContext &MC, LineList &LL, ParseState State) { +ParseResult parseText(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_TEXT && State.Event == CMARK_EVENT_ENTER); - return { Text::create(MC, getLiteralContent(MC, LL, State.Node)), - State.next() }; + return {Text::create(MC, getLiteralContent(MC, State.Node)), State.next()}; } -ParseResult
parseBlockQuote(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult
parseBlockQuote(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_BLOCK_QUOTE && State.Event == CMARK_EVENT_ENTER); SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); return { BlockQuote::create(MC, Children), ResultState.next() }; } -ParseResult parseCode(MarkupContext &MC, LineList &LL, ParseState State) { +ParseResult parseCode(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_CODE && State.Event == CMARK_EVENT_ENTER); - return { Code::create(MC, getLiteralContent(MC, LL, State.Node)), - State.next() }; + return {Code::create(MC, getLiteralContent(MC, State.Node)), State.next()}; } -ParseResult parseCodeBlock(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult parseCodeBlock(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_CODE_BLOCK && State.Event == CMARK_EVENT_ENTER); @@ -117,69 +112,62 @@ ParseResult parseCodeBlock(MarkupContext &MC, LineList &LL, if (!FenceInfoStr.empty()) Language = MC.allocateCopy(FenceInfoStr); } - return { CodeBlock::create(MC, getLiteralContent(MC, LL, State.Node), - Language), - State.next() }; + return {CodeBlock::create(MC, getLiteralContent(MC, State.Node), Language), + State.next()}; } -ParseResult parseEmphasis(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult parseEmphasis(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_EMPH && State.Event == CMARK_EVENT_ENTER); SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); return { Emphasis::create(MC, Children), ResultState.next() }; } -ParseResult parseStrong(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult parseStrong(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_STRONG && State.Event == CMARK_EVENT_ENTER); SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); return { Strong::create(MC, Children), ResultState.next() }; } -ParseResult
parseHeader(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult
parseHeader(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_HEADER && State.Event == CMARK_EVENT_ENTER); auto Level = cmark_node_get_header_level(State.Node); SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); (void) ResultState; return { Header::create(MC, Level, Children), State.next() }; } -ParseResult parseHRule(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult parseHRule(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_HRULE && State.Event == CMARK_EVENT_ENTER); return { HRule::create(MC), State.next() }; } -ParseResult parseHTML(MarkupContext &MC, LineList &LL, ParseState State) { +ParseResult parseHTML(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_HTML && State.Event == CMARK_EVENT_ENTER); - return { HTML::create(MC, getLiteralContent(MC, LL, State.Node)), - State.next() }; + return {HTML::create(MC, getLiteralContent(MC, State.Node)), State.next()}; } -ParseResult parseInlineHTML(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult parseInlineHTML(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_INLINE_HTML && State.Event == CMARK_EVENT_ENTER); - return { InlineHTML::create(MC, getLiteralContent(MC, LL, State.Node)), - State.next() }; + return {InlineHTML::create(MC, getLiteralContent(MC, State.Node)), + State.next()}; } -ParseResult parseImage(MarkupContext &MC, LineList &LL, ParseState State) { +ParseResult parseImage(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_IMAGE && State.Event == CMARK_EVENT_ENTER); std::string Destination(cmark_node_get_url(State.Node)); @@ -189,72 +177,68 @@ ParseResult parseImage(MarkupContext &MC, LineList &LL, ParseState State) auto Title = TitleString.empty() ? None : Optional(TitleString); SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); return { Image::create(MC, Destination, Title, Children), ResultState.next() }; } -ParseResult parseItem(MarkupContext &MC, LineList &LL, ParseState State) { +ParseResult parseItem(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_ITEM && State.Event == CMARK_EVENT_ENTER); SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); return { Item::create(MC, Children), ResultState.next() }; } -ParseResult parseLineBreak(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult parseLineBreak(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_LINEBREAK && State.Event == CMARK_EVENT_ENTER); return { LineBreak::create(MC), State.next() }; } -ParseResult parseSoftBreak(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult parseSoftBreak(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_SOFTBREAK && State.Event == CMARK_EVENT_ENTER); return { SoftBreak::create(MC), State.next() }; } -ParseResult parseLink(MarkupContext &MC, LineList &LL, ParseState State) { +ParseResult parseLink(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_LINK && State.Event == CMARK_EVENT_ENTER); std::string Destination(cmark_node_get_url(State.Node)); SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); return { Link::create(MC, Destination, Children), ResultState.next() }; } -ParseResult parseList(MarkupContext &MC, LineList &LL, ParseState State) { +ParseResult parseList(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_LIST && State.Event == CMARK_EVENT_ENTER); auto ListRoot = State.Node; auto IsOrdered = cmark_node_get_list_type(ListRoot) == CMARK_ORDERED_LIST; SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); return { List::create(MC, Children, IsOrdered), ResultState.next() }; } -ParseResult parseParagraph(MarkupContext &MC, LineList &LL, - ParseState State) { +ParseResult parseParagraph(MarkupContext &MC, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_PARAGRAPH && State.Event == CMARK_EVENT_ENTER); SmallVector Children; - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); return { Paragraph::create(MC, Children), ResultState.next() }; } -ParseResult -parseElement(MarkupContext &MC, LineList &LL, ParseState State) { +ParseResult parseElement(MarkupContext &MC, ParseState State) { assert(State.Event == CMARK_EVENT_ENTER); auto NodeType = cmark_node_get_type(State.Node); switch (NodeType) { @@ -262,55 +246,55 @@ parseElement(MarkupContext &MC, LineList &LL, ParseState State) { llvm_unreachable("Markup documents cannot be nested"); } case CMARK_NODE_BLOCK_QUOTE: { - return parseBlockQuote(MC, LL, State); + return parseBlockQuote(MC, State); } case CMARK_NODE_CODE: { - return parseCode(MC, LL, State); + return parseCode(MC, State); } case CMARK_NODE_CODE_BLOCK: { - return parseCodeBlock(MC, LL, State); + return parseCodeBlock(MC, State); } case CMARK_NODE_EMPH: { - return parseEmphasis(MC, LL, State); + return parseEmphasis(MC, State); } case CMARK_NODE_HEADER: { - return parseHeader(MC, LL, State); + return parseHeader(MC, State); } case CMARK_NODE_HRULE: { - return parseHRule(MC, LL, State); + return parseHRule(MC, State); } case CMARK_NODE_HTML: { - return parseHTML(MC, LL, State); + return parseHTML(MC, State); } case CMARK_NODE_IMAGE: { - return parseImage(MC, LL, State); + return parseImage(MC, State); } case CMARK_NODE_INLINE_HTML: { - return parseInlineHTML(MC, LL, State); + return parseInlineHTML(MC, State); } case CMARK_NODE_ITEM: { - return parseItem(MC, LL, State); + return parseItem(MC, State); } case CMARK_NODE_LINEBREAK: { - return parseLineBreak(MC, LL, State); + return parseLineBreak(MC, State); } case CMARK_NODE_LINK: { - return parseLink(MC, LL, State); + return parseLink(MC, State); } case CMARK_NODE_LIST: { - return parseList(MC, LL, State); + return parseList(MC, State); } case CMARK_NODE_PARAGRAPH: { - return parseParagraph(MC, LL, State); + return parseParagraph(MC, State); } case CMARK_NODE_SOFTBREAK: { - return parseSoftBreak(MC, LL, State); + return parseSoftBreak(MC, State); } case CMARK_NODE_STRONG: { - return parseStrong(MC, LL, State); + return parseStrong(MC, State); } case CMARK_NODE_TEXT: { - return parseText(MC, LL, State); + return parseText(MC, State); } default: { llvm_unreachable("Can't parse a Markup node of type 'None'"); @@ -318,10 +302,9 @@ parseElement(MarkupContext &MC, LineList &LL, ParseState State) { } } -Document *swift::markup::parseDocument(MarkupContext &MC, LineList &LL) { - auto Comment = LL.str(); - auto CMarkDoc = cmark_parse_document(Comment.c_str(), Comment.size(), - CMARK_OPT_SMART); +static Document *parseDocumentImpl(MarkupContext &MC, StringRef String) { + auto CMarkDoc = + cmark_parse_document(String.data(), String.size(), CMARK_OPT_SMART); if (CMarkDoc == nullptr) return nullptr; @@ -332,7 +315,7 @@ Document *swift::markup::parseDocument(MarkupContext &MC, LineList &LL) { SmallVector Children; assert(cmark_node_get_type(State.Node) == CMARK_NODE_DOCUMENT && State.Event == CMARK_EVENT_ENTER); - auto ResultState = parseChildren(MC, LL, State, Children); + auto ResultState = parseChildren(MC, State, Children); assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT); State = ResultState.next(); @@ -341,3 +324,11 @@ Document *swift::markup::parseDocument(MarkupContext &MC, LineList &LL) { cmark_iter_free(State.Iter); return Document::create(MC, Children); } + +Document *swift::markup::parseDocument(MarkupContext &MC, LineList &LL) { + return parseDocumentImpl(MC, LL.str()); +} + +Document *swift::markup::parseDocument(MarkupContext &MC, StringRef String) { + return parseDocumentImpl(MC, MC.allocateCopy(String)); +} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b0f08d6c71a0f..e89c35f27daa5 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3236,6 +3236,10 @@ bool Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier, SyntaxParsingContext AttrListCtx(SyntaxContext, SyntaxKind::AttributeList); while (Tok.is(tok::at_sign)) { + // Ignore @substituted in SIL mode and leave it for the type parser. + if (isInSILMode() && peekToken().getText() == "substituted") + return false; + if (Attributes.AtLoc.isInvalid()) Attributes.AtLoc = Tok.getLoc(); SyntaxParsingContext AttrCtx(SyntaxContext, SyntaxKind::Attribute); diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index b9abdc9800447..f8799b2ec9c43 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -296,6 +296,8 @@ class ValidateIfConfigCondition : DiagName = "import conditional"; break; case PlatformConditionKind::TargetEnvironment: DiagName = "target environment"; break; + case PlatformConditionKind::PtrAuth: + DiagName = "pointer authentication scheme"; break; case PlatformConditionKind::Runtime: llvm_unreachable("handled above"); } diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 897661f4c93d2..4e5c98472bec2 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -371,10 +371,12 @@ ParserResult Parser::parseType(Diag<> MessageID, parseTypeAttributeList(specifier, specifierLoc, attrs); Optional GenericsScope; + Optional patternGenericsScope; // Parse generic parameters in SIL mode. GenericParamList *generics = nullptr; - bool isImplied = false; + SourceLoc substitutedLoc; + GenericParamList *patternGenerics = nullptr; if (isInSILMode()) { // If this is part of a sil function decl, generic parameters are visible in // the function body; otherwise, they are visible when parsing the type. @@ -382,11 +384,24 @@ ParserResult Parser::parseType(Diag<> MessageID, GenericsScope.emplace(this, ScopeKind::Generics); generics = maybeParseGenericParams().getPtrOrNull(); - isImplied = consumeIf(tok::kw_in); + if (Tok.is(tok::at_sign) && peekToken().getText() == "substituted") { + consumeToken(tok::at_sign); + substitutedLoc = consumeToken(tok::identifier); + patternGenericsScope.emplace(this, ScopeKind::Generics); + patternGenerics = maybeParseGenericParams().getPtrOrNull(); + if (!patternGenerics) { + diagnose(Tok.getLoc(), diag::sil_function_subst_expected_generics); + patternGenericsScope.reset(); + } + } } // In SIL mode, parse box types { ... }. if (isInSILMode() && Tok.is(tok::l_brace)) { + if (patternGenerics) { + diagnose(Tok.getLoc(), diag::sil_function_subst_expected_function); + patternGenericsScope.reset(); + } return parseSILBoxType(generics, attrs, GenericsScope); } @@ -482,45 +497,81 @@ ParserResult Parser::parseType(Diag<> MessageID, } // Parse substitutions for substituted SIL types. - SourceLoc SubsLAngleLoc, SubsRAngleLoc; - MutableArrayRef SubsTypes; - if (isInSILMode() && consumeIf(tok::kw_for)) { - if (!startsWithLess(Tok)) { - diagnose(Tok, diag::sil_function_subst_expected_l_angle); - return makeParserError(); - } - - SubsLAngleLoc = consumeStartingLess(); + MutableArrayRef invocationSubsTypes; + MutableArrayRef patternSubsTypes; + if (isInSILMode()) { + auto parseSubstitutions = + [&](MutableArrayRef &subs) -> Optional { + if (!consumeIf(tok::kw_for)) return None; + + if (!startsWithLess(Tok)) { + diagnose(Tok, diag::sil_function_subst_expected_l_angle); + return false; + } + + consumeStartingLess(); + + SmallVector SubsTypesVec; + for (;;) { + auto argTy = parseType(); + if (!argTy.getPtrOrNull()) + return false; + SubsTypesVec.push_back(argTy.get()); + if (consumeIf(tok::comma)) + continue; + break; + } + if (!startsWithGreater(Tok)) { + diagnose(Tok, diag::sil_function_subst_expected_r_angle); + return false; + } + consumeStartingGreater(); - SmallVector SubsTypesVec; - for (;;) { - auto argTy = parseType(); - if (!argTy.getPtrOrNull()) + subs = Context.AllocateCopy(SubsTypesVec); + return true; + }; + + // Parse pattern substitutions. These must exist if we had pattern + // generics above. + if (patternGenerics) { + // These substitutions are outside of the scope of the + // pattern generics. + patternGenericsScope.reset(); + + auto result = parseSubstitutions(patternSubsTypes); + if (!result || patternSubsTypes.empty()) { + diagnose(Tok, diag::sil_function_subst_expected_subs); + patternGenerics = nullptr; + } else if (!*result) { return makeParserError(); - SubsTypesVec.push_back(argTy.get()); - if (consumeIf(tok::comma)) - continue; - break; + } } - if (!startsWithGreater(Tok)) { - diagnose(Tok, diag::sil_function_subst_expected_r_angle); - return makeParserError(); + + if (generics) { + // These substitutions are outside of the scope of the + // invocation generics. + GenericsScope.reset(); + + if (auto result = parseSubstitutions(invocationSubsTypes)) + if (!*result) return makeParserError(); } - - SubsRAngleLoc = consumeStartingGreater(); - SubsTypes = Context.AllocateCopy(SubsTypesVec); + if (Tok.is(tok::kw_for)) { + diagnose(Tok, diag::sil_function_subs_without_generics); + return makeParserError(); + } } tyR = new (Context) FunctionTypeRepr(generics, argsTyR, throwsLoc, arrowLoc, SecondHalf.get(), - isImplied, - SubsTypes); - } else if (generics) { + patternGenerics, patternSubsTypes, + invocationSubsTypes); + } else if (auto firstGenerics = generics ? generics : patternGenerics) { // Only function types may be generic. - auto brackets = generics->getSourceRange(); + auto brackets = firstGenerics->getSourceRange(); diagnose(brackets.Start, diag::generic_non_function); GenericsScope.reset(); + patternGenericsScope.reset(); // Forget any generic parameters we saw in the type. class EraseTypeParamWalker : public ASTWalker { diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index 4a5fa989a702a..1dd46e0a5a7db 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -1222,6 +1222,10 @@ bool SILParser::parseSILType(SILType &Result, auto env = handleSILGenericParams(generics, SF); fnType->setGenericEnvironment(env); } + if (auto generics = fnType->getPatternGenericParams()) { + auto env = handleSILGenericParams(generics, SF); + fnType->setPatternGenericEnvironment(env); + } } if (auto boxType = dyn_cast(T)) { if (auto generics = boxType->getGenericParams()) { @@ -1237,9 +1241,8 @@ bool SILParser::parseSILType(SILType &Result, // Save the top-level function generic environment if there was one. if (auto fnType = dyn_cast(TyR.get())) - if (!fnType->areGenericParamsImplied()) - if (auto env = fnType->getGenericEnvironment()) - ParsedGenericEnv = env; + if (auto env = fnType->getGenericEnvironment()) + ParsedGenericEnv = env; // Apply attributes to the type. TypeLoc Ty = P.applyAttributeToType(TyR.get(), attrs, specifier, specifierLoc); @@ -2071,6 +2074,12 @@ bool SILParser::parseSILDeclRef(SILDeclRef &Member, bool FnTypeRequired) { genericEnv = handleSILGenericParams(generics, &P.SF); fnType->setGenericEnvironment(genericEnv); } + if (auto generics = fnType->getPatternGenericParams()) { + assert(!Ty.wasValidated() && Ty.getType().isNull()); + + genericEnv = handleSILGenericParams(generics, &P.SF); + fnType->setPatternGenericEnvironment(genericEnv); + } } if (performTypeLocChecking(Ty, /*IsSILType=*/ false, genericEnv)) diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 0b609510f66c7..924ebd545d862 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -155,6 +155,25 @@ class DeclAndTypePrinter::Implementation return owningPrinter.shouldInclude(VD); } + bool isEmptyExtensionDecl(const ExtensionDecl *ED) { + auto members = ED->getMembers(); + auto hasMembers = std::any_of(members.begin(), members.end(), + [this](const Decl *D) -> bool { + if (auto VD = dyn_cast(D)) + if (shouldInclude(VD)) + return true; + return false; + }); + + auto protocols = ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit); + auto hasProtocols = std::any_of(protocols.begin(), protocols.end(), + [this](const ProtocolDecl *PD) -> bool { + return shouldInclude(PD); + }); + + return (!hasMembers && !hasProtocols); + } + private: /// Prints a protocol adoption list: <NSCoding, NSCopying> /// @@ -311,25 +330,6 @@ class DeclAndTypePrinter::Implementation os << "@end\n"; } - bool isEmptyExtensionDecl(ExtensionDecl *ED) { - auto members = ED->getMembers(); - auto hasMembers = std::any_of(members.begin(), members.end(), - [this](const Decl *D) -> bool { - if (auto VD = dyn_cast(D)) - if (shouldInclude(VD)) - return true; - return false; - }); - - auto protocols = ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit); - auto hasProtocols = std::any_of(protocols.begin(), protocols.end(), - [this](const ProtocolDecl *PD) -> bool { - return shouldInclude(PD); - }); - - return (!hasMembers && !hasProtocols); - } - void visitExtensionDecl(ExtensionDecl *ED) { if (isEmptyExtensionDecl(ED)) return; @@ -2063,6 +2063,10 @@ void DeclAndTypePrinter::printAdHocCategory( getImpl().printAdHocCategory(members); } +bool DeclAndTypePrinter::isEmptyExtensionDecl(const ExtensionDecl *ED) { + return getImpl().isEmptyExtensionDecl(ED); +} + StringRef DeclAndTypePrinter::maybeGetOSObjectBaseName(const clang::NamedDecl *decl) { StringRef name = decl->getName(); diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.h b/lib/PrintAsObjC/DeclAndTypePrinter.h index 61d159a98e502..933f2ea16a859 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.h +++ b/lib/PrintAsObjC/DeclAndTypePrinter.h @@ -70,6 +70,9 @@ class DeclAndTypePrinter { void print(const Decl *D); void print(Type ty); + /// Is \p ED empty of members and protocol conformances to include? + bool isEmptyExtensionDecl(const ExtensionDecl *ED); + /// Prints a category declaring the given members. /// /// All members must have the same parent type. The list must not be empty. diff --git a/lib/PrintAsObjC/ModuleContentsWriter.cpp b/lib/PrintAsObjC/ModuleContentsWriter.cpp index 333bcf8310ae5..a1653028bfdc2 100644 --- a/lib/PrintAsObjC/ModuleContentsWriter.cpp +++ b/lib/PrintAsObjC/ModuleContentsWriter.cpp @@ -400,6 +400,9 @@ class ModuleWriter { } bool writeExtension(const ExtensionDecl *ED) { + if (printer.isEmptyExtensionDecl(ED)) + return true; + bool allRequirementsSatisfied = true; const ClassDecl *CD = ED->getSelfClassDecl(); diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp index c17f185b29405..849dd0e5095b4 100644 --- a/lib/PrintAsObjC/PrintAsObjC.cpp +++ b/lib/PrintAsObjC/PrintAsObjC.cpp @@ -325,9 +325,12 @@ static void writeImports(raw_ostream &out, const clang::Module *module) { auto startIdx = allPaths.size(); if (module->IsFramework) { + SmallString<64> Buffer(header.NameAsWritten); + llvm::sys::path::replace_path_prefix(Buffer, "Headers/", StringRef()); + llvm::sys::path::replace_path_prefix(Buffer, "PrivateHeaders/", StringRef()); // For framworks, the header import should start from the framework name. allPaths.append(module->getTopLevelModuleName()); - llvm::sys::path::append(allPaths, header.NameAsWritten); + llvm::sys::path::append(allPaths, Buffer.str()); } else { // Otherwise, import the header directly. allPaths.append(header.NameAsWritten); diff --git a/lib/SIL/AbstractionPattern.cpp b/lib/SIL/AbstractionPattern.cpp index 65a6d7f145417..9a7e5de9625d4 100644 --- a/lib/SIL/AbstractionPattern.cpp +++ b/lib/SIL/AbstractionPattern.cpp @@ -46,12 +46,13 @@ TypeConverter::getAbstractionPattern(AbstractStorageDecl *decl, AbstractionPattern TypeConverter::getAbstractionPattern(SubscriptDecl *decl, bool isNonObjC) { + auto type = decl->getElementInterfaceType()->getCanonicalType(); CanGenericSignature genericSig; - if (auto sig = decl->getGenericSignatureOfContext()) + if (auto sig = decl->getGenericSignatureOfContext()) { genericSig = sig.getCanonicalSignature(); - return AbstractionPattern(genericSig, - decl->getElementInterfaceType() - ->getCanonicalType()); + type = sig->getCanonicalTypeInContext(type); + } + return AbstractionPattern(genericSig, type); } static const clang::Type *getClangType(const clang::Decl *decl) { @@ -76,13 +77,15 @@ static Bridgeability getClangDeclBridgeability(const clang::Decl *decl) { AbstractionPattern TypeConverter::getAbstractionPattern(VarDecl *var, bool isNonObjC) { - CanGenericSignature genericSig; - if (auto sig = var->getDeclContext()->getGenericSignatureOfContext()) - genericSig = sig.getCanonicalSignature(); - CanType swiftType = var->getInterfaceType() ->getCanonicalType(); + CanGenericSignature genericSig; + if (auto sig = var->getDeclContext()->getGenericSignatureOfContext()) { + genericSig = sig.getCanonicalSignature(); + swiftType = genericSig->getCanonicalTypeInContext(swiftType); + } + if (isNonObjC) return AbstractionPattern(genericSig, swiftType); @@ -109,12 +112,15 @@ AbstractionPattern TypeConverter::getAbstractionPattern(EnumElementDecl *decl) { "Optional.Some does not have a unique abstraction pattern because " "optionals are re-abstracted"); + CanType type = decl->getArgumentInterfaceType()->getCanonicalType(); + CanGenericSignature genericSig; - if (auto sig = decl->getParentEnum()->getGenericSignatureOfContext()) + if (auto sig = decl->getParentEnum()->getGenericSignatureOfContext()) { genericSig = sig.getCanonicalSignature(); - return AbstractionPattern(genericSig, - decl->getArgumentInterfaceType() - ->getCanonicalType()); + type = genericSig->getCanonicalTypeInContext(type); + } + + return AbstractionPattern(genericSig, type); } AbstractionPattern::EncodedForeignErrorInfo diff --git a/lib/SIL/OperandOwnership.cpp b/lib/SIL/OperandOwnership.cpp index 4e28d03d97bf3..74ae40bf0020e 100644 --- a/lib/SIL/OperandOwnership.cpp +++ b/lib/SIL/OperandOwnership.cpp @@ -173,7 +173,6 @@ CONSTANT_OWNERSHIP_INST(Owned, MustBeInvalidated, DeallocExistentialBox) CONSTANT_OWNERSHIP_INST(Owned, MustBeInvalidated, DeallocRef) CONSTANT_OWNERSHIP_INST(Owned, MustBeInvalidated, DestroyValue) CONSTANT_OWNERSHIP_INST(Owned, MustBeInvalidated, EndLifetime) -CONSTANT_OWNERSHIP_INST(Owned, MustBeInvalidated, InitExistentialRef) CONSTANT_OWNERSHIP_INST(None, MustBeLive, AbortApply) CONSTANT_OWNERSHIP_INST(None, MustBeLive, AddressToPointer) CONSTANT_OWNERSHIP_INST(None, MustBeLive, BeginAccess) @@ -348,6 +347,7 @@ FORWARD_ANY_OWNERSHIP_INST(UnconditionalCheckedCast) FORWARD_ANY_OWNERSHIP_INST(UncheckedEnumData) FORWARD_ANY_OWNERSHIP_INST(DestructureStruct) FORWARD_ANY_OWNERSHIP_INST(DestructureTuple) +FORWARD_ANY_OWNERSHIP_INST(InitExistentialRef) #undef FORWARD_ANY_OWNERSHIP_INST // An instruction that forwards a constant ownership or trivial ownership. @@ -435,27 +435,9 @@ OperandOwnershipKindClassifier::visitBranchInst(BranchInst *bi) { OperandOwnershipKindMap OperandOwnershipKindClassifier::visitCondBranchInst(CondBranchInst *cbi) { - // If our conditional branch is the condition, it is trivial. Check that the - // ownership kind is trivial. - if (cbi->isConditionOperandIndex(getOperandIndex())) - return Map::allLive(); - - // Otherwise, make sure that our operand matches the ownership of the relevant - // argument. - // - // TODO: Use more updated APIs here to get the operands/etc. - if (cbi->isTrueOperandIndex(getOperandIndex())) { - unsigned trueOffset = 1; - return checkTerminatorArgumentMatchesDestBB(cbi->getTrueBB(), - getOperandIndex() - trueOffset); - } - - assert(cbi->isFalseOperandIndex(getOperandIndex()) && - "If an operand is not the condition index or a true operand index, it " - "must be a false operand index"); - unsigned falseOffset = 1 + cbi->getTrueOperands().size(); - return checkTerminatorArgumentMatchesDestBB(cbi->getFalseBB(), - getOperandIndex() - falseOffset); + // In ossa, cond_br insts are not allowed to take non-trivial values. Thus, we + // just accept anything since we know all of our operands will be trivial. + return Map::allLive(); } OperandOwnershipKindMap @@ -1023,6 +1005,7 @@ ANY_OWNERSHIP_BUILTIN(ZeroInitializer) ANY_OWNERSHIP_BUILTIN(Swift3ImplicitObjCEntrypoint) ANY_OWNERSHIP_BUILTIN(PoundAssert) ANY_OWNERSHIP_BUILTIN(GlobalStringTablePointer) +ANY_OWNERSHIP_BUILTIN(TypePtrAuthDiscriminator) #undef ANY_OWNERSHIP_BUILTIN // This is correct today since we do not have any builtins which return diff --git a/lib/SIL/OwnershipUtils.cpp b/lib/SIL/OwnershipUtils.cpp index f5204dca8288e..51aa1eab1f806 100644 --- a/lib/SIL/OwnershipUtils.cpp +++ b/lib/SIL/OwnershipUtils.cpp @@ -42,10 +42,10 @@ bool swift::isOwnershipForwardingValueKind(SILNodeKind kind) { case SILNodeKind::SelectEnumInst: case SILNodeKind::SwitchEnumInst: case SILNodeKind::CheckedCastBranchInst: - case SILNodeKind::CondBranchInst: case SILNodeKind::DestructureStructInst: case SILNodeKind::DestructureTupleInst: case SILNodeKind::MarkDependenceInst: + case SILNodeKind::InitExistentialRefInst: return true; default: return false; diff --git a/lib/SIL/SILBuilder.cpp b/lib/SIL/SILBuilder.cpp index dced2ce800f5f..07ba5ff5d2b5a 100644 --- a/lib/SIL/SILBuilder.cpp +++ b/lib/SIL/SILBuilder.cpp @@ -97,9 +97,12 @@ SILType SILBuilder::getPartialApplyResultType( needsSubstFunctionType |= yield.getInterfaceType()->hasTypeParameter(); } - auto appliedFnType = SILFunctionType::get(needsSubstFunctionType - ? FTI->getSubstGenericSignature() - : nullptr, + SubstitutionMap appliedSubs; + if (needsSubstFunctionType) { + appliedSubs = FTI->getCombinedSubstitutions(); + } + + auto appliedFnType = SILFunctionType::get(nullptr, extInfo, FTI->getCoroutineKind(), calleeConvention, @@ -107,12 +110,8 @@ SILType SILBuilder::getPartialApplyResultType( FTI->getYields(), results, FTI->getOptionalErrorResult(), - needsSubstFunctionType - ? FTI->getSubstitutions() - : SubstitutionMap(), - needsSubstFunctionType - ? FTI->isGenericSignatureImplied() - : false, + appliedSubs, + SubstitutionMap(), M.getASTContext()); return SILType::getPrimitiveObjectType(appliedFnType); diff --git a/lib/SIL/SILConstants.cpp b/lib/SIL/SILConstants.cpp index b0a7e2ff00f68..013d8534e78cc 100644 --- a/lib/SIL/SILConstants.cpp +++ b/lib/SIL/SILConstants.cpp @@ -763,12 +763,26 @@ SymbolicClosure *SymbolicClosure::create(SILFunction *target, SingleValueInstruction *closureInst, SymbolicValueAllocator &allocator) { // Determine whether there are captured arguments without a symbolic value. + // Consider indirectly captured arguments as well, which can happen with + // @in_guaranteed convention for captures. bool hasNonConstantCapture = false; for (SymbolicClosureArgument closureArg : args) { if (!closureArg.second) { hasNonConstantCapture = true; break; } + SymbolicValue closureValue = closureArg.second.getValue(); + // Is capture non-constant? + if (!closureValue.isConstant()) { + hasNonConstantCapture = true; + break; + } + // Is the indirect capture non-constant? + if (closureValue.getKind() == SymbolicValue::Address && + !closureValue.getAddressValueMemoryObject()->getValue().isConstant()) { + hasNonConstantCapture = true; + break; + } } auto byteSizeOfArgs = diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index d1a553ee92356..ced29085cb089 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -43,50 +43,60 @@ using namespace swift::Lowering; SILType SILFunctionType::substInterfaceType(SILModule &M, SILType interfaceType) const { - if (getSubstitutions().empty()) - return interfaceType; - - return interfaceType.subst(M, getSubstitutions()); + // Apply pattern substitutions first, then invocation substitutions. + if (auto subs = getPatternSubstitutions()) + interfaceType = interfaceType.subst(M, subs); + if (auto subs = getInvocationSubstitutions()) + interfaceType = interfaceType.subst(M, subs); + return interfaceType; } CanSILFunctionType SILFunctionType::getUnsubstitutedType(SILModule &M) const { auto mutableThis = const_cast(this); - if (!getSubstitutions()) + + // If we have no substitutions, there's nothing to do. + if (!hasPatternSubstitutions() && !hasInvocationSubstitutions()) return CanSILFunctionType(mutableThis); - - if (!isGenericSignatureImplied()) - return withSubstitutions(SubstitutionMap()); - + + // Otherwise, substitute the component types. + SmallVector params; SmallVector yields; SmallVector results; Optional errorResult; + + auto subs = getCombinedSubstitutions(); + auto substComponentType = [&](CanType type) { + if (!type->hasTypeParameter()) return type; + return SILType::getPrimitiveObjectType(type) + .subst(M, subs).getASTType(); + }; for (auto param : getParameters()) { - params.push_back( - param.getWithInterfaceType(param.getArgumentType(M, this))); + params.push_back(param.map(substComponentType)); } for (auto yield : getYields()) { - yields.push_back( - yield.getWithInterfaceType(yield.getArgumentType(M, this))); + yields.push_back(yield.map(substComponentType)); } for (auto result : getResults()) { - results.push_back( - result.getWithInterfaceType(result.getReturnValueType(M, this))); + results.push_back(result.map(substComponentType)); } if (auto error = getOptionalErrorResult()) { - errorResult = - error->getWithInterfaceType(error->getReturnValueType(M, this)); + errorResult = error->map(substComponentType); } - - return SILFunctionType::get(GenericSignature(), getExtInfo(), + + auto signature = isPolymorphic() ? getInvocationGenericSignature() + : CanGenericSignature(); + return SILFunctionType::get(signature, + getExtInfo(), getCoroutineKind(), getCalleeConvention(), params, yields, results, errorResult, - SubstitutionMap(), false, + SubstitutionMap(), + SubstitutionMap(), mutableThis->getASTContext(), getWitnessMethodConformanceOrInvalid()); } @@ -219,10 +229,10 @@ SILFunctionType::getWithDifferentiability(DifferentiabilityKind kind, : SILParameterDifferentiability::NotDifferentiable)); } auto newExtInfo = getExtInfo().withDifferentiabilityKind(kind); - return get(getSubstGenericSignature(), newExtInfo, getCoroutineKind(), + return get(getInvocationGenericSignature(), newExtInfo, getCoroutineKind(), getCalleeConvention(), newParameters, getYields(), getResults(), - getOptionalErrorResult(), getSubstitutions(), - isGenericSignatureImplied(), getASTContext(), + getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationSubstitutions(), getASTContext(), getWitnessMethodConformanceOrInvalid()); } @@ -235,11 +245,13 @@ CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { for (auto ¶m : getParameters()) newParams.push_back(param.getWithDifferentiability( SILParameterDifferentiability::DifferentiableOrNotApplicable)); - return SILFunctionType::get(getSubstGenericSignature(), nondiffExtInfo, + return SILFunctionType::get(getInvocationGenericSignature(), nondiffExtInfo, getCoroutineKind(), getCalleeConvention(), newParams, getYields(), getResults(), - getOptionalErrorResult(), getSubstitutions(), - isGenericSignatureImplied(), getASTContext()); + getOptionalErrorResult(), + getPatternSubstitutions(), + getInvocationSubstitutions(), + getASTContext()); } CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( @@ -281,6 +293,8 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( // Given a type, returns its formal SIL parameter info. auto getTangentParameterInfoForOriginalResult = [&](CanType tanType, ResultConvention origResConv) -> SILParameterInfo { + if (derivativeFnGenSig) + tanType = derivativeFnGenSig->getCanonicalTypeInContext(tanType); AbstractionPattern pattern(derivativeFnGenSig, tanType); auto &tl = TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); @@ -305,6 +319,8 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( // Given a type, returns its formal SIL result info. auto getTangentResultInfoForOriginalParameter = [&](CanType tanType, ParameterConvention origParamConv) -> SILResultInfo { + if (derivativeFnGenSig) + tanType = derivativeFnGenSig->getCanonicalTypeInContext(tanType); AbstractionPattern pattern(derivativeFnGenSig, tanType); auto &tl = TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); @@ -366,8 +382,8 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( closureType = SILFunctionType::get( /*genericSignature*/ nullptr, ExtInfo(), SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, differentialParams, {}, - differentialResults, None, getSubstitutions(), - isGenericSignatureImplied(), ctx); + differentialResults, None, getCombinedSubstitutions(), + SubstitutionMap(), ctx); break; } case AutoDiffDerivativeFunctionKind::VJP: { @@ -402,7 +418,7 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( closureType = SILFunctionType::get( /*genericSignature*/ nullptr, ExtInfo(), SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, pullbackParams, {}, - pullbackResults, {}, getSubstitutions(), isGenericSignatureImplied(), + pullbackResults, {}, getCombinedSubstitutions(), SubstitutionMap(), ctx); break; } @@ -440,7 +456,7 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( cachedResult = SILFunctionType::get( canGenSig, extInfo, getCoroutineKind(), getCalleeConvention(), newParameters, getYields(), newResults, getOptionalErrorResult(), - getSubstitutions(), isGenericSignatureImplied(), ctx, + getPatternSubstitutions(), getInvocationSubstitutions(), ctx, getWitnessMethodConformanceOrInvalid()); return cachedResult; } @@ -528,7 +544,7 @@ CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( return SILFunctionType::get( canGenSig, getExtInfo(), getCoroutineKind(), getCalleeConvention(), newParameters, getYields(), newResults, getOptionalErrorResult(), - getSubstitutions(), isGenericSignatureImplied(), getASTContext()); + getPatternSubstitutions(), getInvocationSubstitutions(), getASTContext()); } static CanType getKnownType(Optional &cacheSlot, ASTContext &C, @@ -599,13 +615,13 @@ Lowering::adjustFunctionType(CanSILFunctionType type, type->getWitnessMethodConformanceOrInvalid() == witnessMethodConformance) return type; - return SILFunctionType::get(type->getSubstGenericSignature(), + return SILFunctionType::get(type->getInvocationGenericSignature(), extInfo, type->getCoroutineKind(), callee, type->getParameters(), type->getYields(), type->getResults(), type->getOptionalErrorResult(), - type->getSubstitutions(), - type->isGenericSignatureImplied(), + type->getPatternSubstitutions(), + type->getInvocationSubstitutions(), type->getASTContext(), witnessMethodConformance); } @@ -627,10 +643,10 @@ CanSILFunctionType SILFunctionType::getWithExtInfo(ExtInfo newExt) { : Lowering::DefaultThickCalleeConvention) : ParameterConvention::Direct_Unowned); - return get(getSubstGenericSignature(), newExt, getCoroutineKind(), + return get(getInvocationGenericSignature(), newExt, getCoroutineKind(), calleeConvention, getParameters(), getYields(), getResults(), - getOptionalErrorResult(), getSubstitutions(), - isGenericSignatureImplied(), getASTContext(), + getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationSubstitutions(), getASTContext(), getWitnessMethodConformanceOrInvalid()); } @@ -728,6 +744,7 @@ class SubstFunctionTypeCollector { public: TypeConverter &TC; TypeExpansionContext Expansion; + CanGenericSignature GenericSig; bool Enabled; SmallVector substGenericParams; @@ -736,8 +753,8 @@ class SubstFunctionTypeCollector { SmallVector substConformances; SubstFunctionTypeCollector(TypeConverter &TC, TypeExpansionContext context, - bool enabled) - : TC(TC), Expansion(context), Enabled(enabled) { + CanGenericSignature genericSig, bool enabled) + : TC(TC), Expansion(context), GenericSig(genericSig), Enabled(enabled) { } SubstFunctionTypeCollector(const SubstFunctionTypeCollector &) = delete; @@ -773,6 +790,7 @@ class SubstFunctionTypeCollector { } if (upperBoundSuperclass) { + upperBoundSuperclass = upperBoundSuperclass->mapTypeOutOfContext(); substRequirements.push_back( Requirement(RequirementKind::Superclass, param, upperBoundSuperclass)); } @@ -859,11 +877,9 @@ class SubstFunctionTypeCollector { auto origContextType = origType.getType(); - // TODO: If the substituted type is a subclass of the abstraction pattern - // type, then bail out. This should only come up when lowering override - // types for vtable entries, where we don't currently use substituted - // function types. - + // If the substituted type is a subclass of the abstraction pattern + // type, build substitutions for any type parameters in it. This only + // comes up when lowering override types for vtable entries. auto areDifferentClasses = [](Type a, Type b) -> bool { if (auto dynA = a->getAs()) { a = dynA->getSelfType(); @@ -880,17 +896,27 @@ class SubstFunctionTypeCollector { return false; }; + bool substituteBindingsInSubstType = false; if (areDifferentClasses(substType, origContextType)) { - return substType; + substituteBindingsInSubstType = true; } if (auto substMeta = dyn_cast(substType)) { if (auto origMeta = dyn_cast(origContextType)) { if (areDifferentClasses(substMeta->getInstanceType(), origMeta->getInstanceType())) { - return substType; + substituteBindingsInSubstType = true; } } } + + CanGenericSignature origSig = origType.getGenericSignature(); + if (substituteBindingsInSubstType) { + origContextType = substType; + origSig = TC.getCurGenericSignature(); + assert((!substType->hasTypeParameter() || origSig) && + "lowering mismatched interface types in a context without " + "a generic signature"); + } if (!origContextType->hasTypeParameter() && !origContextType->hasArchetype()) { @@ -902,10 +928,11 @@ class SubstFunctionTypeCollector { } // Extract structural substitutions. - if (origContextType->hasTypeParameter()) - origContextType = origType.getGenericSignature()->getGenericEnvironment() + if (origContextType->hasTypeParameter()) { + origContextType = origSig->getGenericEnvironment() ->mapTypeIntoContext(origContextType) - ->getCanonicalType(origType.getGenericSignature()); + ->getCanonicalType(origSig); + } auto result = origContextType ->substituteBindingsTo(substType, @@ -1476,6 +1503,17 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, } } +static AccessorDecl *getAsCoroutineAccessor(Optional constant) { + if (!constant || !constant->hasDecl()) + return nullptr;; + + auto accessor = dyn_cast(constant->getDecl()); + if (!accessor || !accessor->isCoroutine()) + return nullptr; + + return accessor; +} + static void destructureYieldsForReadAccessor(TypeConverter &TC, TypeExpansionContext expansion, AbstractionPattern origType, @@ -1525,11 +1563,8 @@ static void destructureYieldsForCoroutine(TypeConverter &TC, assert(coroutineKind == SILCoroutineKind::None); assert(yields.empty()); - if (!constant || !constant->hasDecl()) - return; - - auto accessor = dyn_cast(constant->getDecl()); - if (!accessor || !accessor->isCoroutine()) + auto accessor = getAsCoroutineAccessor(constant); + if (!accessor) return; auto origAccessor = cast(origConstant->getDecl()); @@ -1617,6 +1652,9 @@ static CanSILFunctionType getSILFunctionType( CanGenericSignature genericSig = substFnInterfaceType.getOptGenericSignature(); + Optional contextRAII; + if (genericSig) contextRAII.emplace(TC, genericSig); + // Per above, only fully honor opaqueness in the abstraction pattern // for thick or polymorphic functions. We don't need to worry about // non-opaque patterns because the type-checker forbids non-thick @@ -1653,21 +1691,35 @@ static CanSILFunctionType getSILFunctionType( substFormalResultType); } - - SubstFunctionTypeCollector subst(TC, - expansionContext, - TC.Context.LangOpts.EnableSubstSILFunctionTypesForFunctionValues + bool shouldBuildSubstFunctionType = [&]{ + if (!TC.Context.LangOpts.EnableSubstSILFunctionTypesForFunctionValues) + return false; + + // We always use substituted function types for coroutines that are + // being lowered in the context of another coroutine, which is to say, + // for class override thunks. This is required to make the yields + // match in abstraction to the base method's yields, which is necessary + // to make the extracted continuation-function signatures match. + if (constant != origConstant && getAsCoroutineAccessor(constant)) + return true; + // We don't currently use substituted function types for generic function // type lowering, though we should for generic methods on classes and // protocols. - && !genericSig + if (genericSig) + return false; + // We only currently use substituted function types for function values, // which will have standard thin or thick representation. (Per the previous // comment, it would be useful to do so for generic methods on classes and // protocols too.) - && (extInfo.getSILRepresentation() == SILFunctionTypeRepresentation::Thick - || extInfo.getSILRepresentation() == SILFunctionTypeRepresentation::Thin - )); + auto rep = extInfo.getSILRepresentation(); + return (rep == SILFunctionTypeRepresentation::Thick || + rep == SILFunctionTypeRepresentation::Thin); + }(); + + SubstFunctionTypeCollector subst(TC, expansionContext, genericSig, + shouldBuildSubstFunctionType); // Destructure the input tuple type. SmallVector inputs; @@ -1719,24 +1771,22 @@ static CanSILFunctionType getSILFunctionType( .withDifferentiabilityKind(extInfo.getDifferentiabilityKind()); // Build the substituted generic signature we extracted. - bool impliedSignature = false; SubstitutionMap substitutions; if (subst.Enabled) { if (!subst.substGenericParams.empty()) { - genericSig = GenericSignature::get(subst.substGenericParams, - subst.substRequirements) + auto subSig = GenericSignature::get(subst.substGenericParams, + subst.substRequirements) .getCanonicalSignature(); - substitutions = SubstitutionMap::get(genericSig, + substitutions = SubstitutionMap::get(subSig, llvm::makeArrayRef(subst.substReplacements), llvm::makeArrayRef(subst.substConformances)); - impliedSignature = true; } } return SILFunctionType::get(genericSig, silExtInfo, coroutineKind, calleeConvention, inputs, yields, results, errorResult, - substitutions, impliedSignature, + substitutions, SubstitutionMap(), TC.Context, witnessMethodConformance); } @@ -3081,42 +3131,175 @@ class SILTypeSubstituter : // When a function appears inside of another type, we only perform // substitutions if it is not polymorphic. CanSILFunctionType visitSILFunctionType(CanSILFunctionType origType) { - if (origType->isPolymorphic()) - return origType; - - return substSILFunctionType(origType); + return substSILFunctionType(origType, false); } - // Entry point for use by SILType::substGenericArgs(). - CanSILFunctionType substSILFunctionType(CanSILFunctionType origType) { - if (auto subs = origType->getSubstitutions()) { - // Substitute the substitutions. - SubstOptions options = None; - if (shouldSubstituteOpaqueArchetypes) - options |= SubstFlags::SubstituteOpaqueArchetypes; - - // Expand substituted type according to the expansion context. - auto newSubs = subs.subst(Subst, Conformances, options); - - // If we need to look through opaque types in this context, re-substitute - // according to the expansion context. - if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { - newSubs = newSubs.subst([&](SubstitutableType *s) -> Type { - return substOpaqueTypesWithUnderlyingTypes(s->getCanonicalType(), - typeExpansionContext); - }, [&](CanType dependentType, - Type conformingReplacementType, - ProtocolDecl *conformedProtocol) -> ProtocolConformanceRef { - return substOpaqueTypesWithUnderlyingTypes( - ProtocolConformanceRef(conformedProtocol), - conformingReplacementType->getCanonicalType(), - typeExpansionContext); - }, SubstFlags::SubstituteOpaqueArchetypes); + SubstitutionMap substSubstitutions(SubstitutionMap subs) { + // Substitute the substitutions. + SubstOptions options = None; + if (shouldSubstituteOpaqueArchetypes) + options |= SubstFlags::SubstituteOpaqueArchetypes; + + // Expand substituted type according to the expansion context. + auto newSubs = subs.subst(Subst, Conformances, options); + + // If we need to look through opaque types in this context, re-substitute + // according to the expansion context. + newSubs = substOpaqueTypes(newSubs); + + return newSubs; + } + + SubstitutionMap substOpaqueTypes(SubstitutionMap subs) { + if (!typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) + return subs; + + return subs.subst([&](SubstitutableType *s) -> Type { + return substOpaqueTypesWithUnderlyingTypes(s->getCanonicalType(), + typeExpansionContext); + }, [&](CanType dependentType, + Type conformingReplacementType, + ProtocolDecl *conformedProtocol) -> ProtocolConformanceRef { + return substOpaqueTypesWithUnderlyingTypes( + ProtocolConformanceRef(conformedProtocol), + conformingReplacementType->getCanonicalType(), + typeExpansionContext); + }, SubstFlags::SubstituteOpaqueArchetypes); + } + + // Substitute a function type. + CanSILFunctionType substSILFunctionType(CanSILFunctionType origType, + bool isGenericApplication) { + assert((!isGenericApplication || origType->isPolymorphic()) && + "generic application without invocation signature or with " + "existing arguments"); + assert((!isGenericApplication || !shouldSubstituteOpaqueArchetypes) && + "generic application while substituting opaque archetypes"); + + // The general substitution rule is that we should only substitute + // into the free components of the type, i.e. the components that + // aren't inside a generic signature. That rule would say: + // + // - If there are invocation substitutions, just substitute those; + // the other components are necessarily inside the invocation + // generic signature. + // + // - Otherwise, if there's an invocation generic signature, + // substitute nothing. If we are applying generic arguments, + // add the appropriate invocation substitutions. + // + // - Otherwise, if there are pattern substitutions, just substitute + // those; the other components are inside the patttern generic + // signature. + // + // - Otherwise, substitute the basic components. + // + // There are two caveats here. The first is that we haven't yet + // written all the code that would be necessary in order to handle + // invocation substitutions everywhere, and so we never build those. + // Instead, we substitute into the pattern substitutions if present, + // or the components if not, and build a type with no invocation + // signature. As a special case, when substituting a coroutine type, + // we build pattern substitutions instead of substituting the + // component types in order to preserve the original yield structure, + // which factors into the continuation function ABI. + // + // The second is that this function is also used when substituting + // opaque archetypes. In this case, we may need to substitute + // into component types even within generic signatures. This is + // safe because the substitutions used in this case don't change + // generics, they just narrowly look through certain opaque archetypes. + // If substitutions are present, we still don't substitute into + // the basic components, in order to maintain the information about + // what was abstracted there. + + auto patternSubs = origType->getPatternSubstitutions(); + + // If we have an invocation signatture, we generally shouldn't + // substitute into the pattern substitutions and component types. + if (auto sig = origType->getInvocationGenericSignature()) { + // Substitute the invocation substitutions if present. + if (auto invocationSubs = origType->getInvocationSubstitutions()) { + assert(!isGenericApplication); + invocationSubs = substSubstitutions(invocationSubs); + auto substType = + origType->withInvocationSubstitutions(invocationSubs); + + // Also do opaque-type substitutions on the pattern substitutions + // if requested and applicable. + if (patternSubs) { + patternSubs = substOpaqueTypes(patternSubs); + substType = substType->withPatternSubstitutions(patternSubs); + } + + return substType; } - - return origType->withSubstitutions(newSubs); + + // Otherwise, we shouldn't substitute any components except + // when substituting opaque archetypes. + + // If we're doing a generic application, and there are pattern + // substitutions, substitute into the pattern substitutions; or if + // it's a coroutine, build pattern substitutions; or else, fall + // through to substitute the component types as discussed above. + if (isGenericApplication) { + if (patternSubs || origType->isCoroutine()) { + CanSILFunctionType substType = origType; + if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { + substType = + origType->substituteOpaqueArchetypes(TC, typeExpansionContext); + } + + SubstitutionMap subs; + if (patternSubs) { + subs = substSubstitutions(patternSubs); + } else { + subs = SubstitutionMap::get(sig, Subst, Conformances); + } + auto witnessConformance = substWitnessConformance(origType); + substType = substType->withPatternSpecialization(nullptr, subs, + witnessConformance); + + return substType; + } + // else fall down to component substitution + + // If we're substituting opaque archetypes, and there are pattern + // substitutions present, just substitute those and preserve the + // basic structure in the component types. Otherwise, fall through + // to substitute the component types. + } else if (shouldSubstituteOpaqueArchetypes) { + if (patternSubs) { + patternSubs = substOpaqueTypes(patternSubs); + auto witnessConformance = substWitnessConformance(origType); + return origType->withPatternSpecialization(sig, patternSubs, + witnessConformance); + } + // else fall down to component substitution + + // Otherwise, don't try to substitute bound components. + } else { + auto substType = origType; + if (patternSubs) { + patternSubs = substOpaqueTypes(patternSubs); + auto witnessConformance = substWitnessConformance(origType); + substType = substType->withPatternSpecialization(sig, patternSubs, + witnessConformance); + } + return substType; + } + + // Otherwise, if there are pattern substitutions, just substitute + // into those and don't touch the component types. + } else if (patternSubs) { + patternSubs = substSubstitutions(patternSubs); + auto witnessConformance = substWitnessConformance(origType); + return origType->withPatternSpecialization(nullptr, patternSubs, + witnessConformance); } + // Otherwise, we need to substitute component types. + SmallVector substResults; substResults.reserve(origType->getNumResults()); for (auto origResult : origType->getResults()) { @@ -3140,44 +3323,7 @@ class SILTypeSubstituter : substYields.push_back(substInterface(origYield)); } - ProtocolConformanceRef witnessMethodConformance; - if (auto conformance = origType->getWitnessMethodConformanceOrInvalid()) { - assert(origType->getExtInfo().hasSelfParam()); - auto selfType = origType->getSelfParameter().getInterfaceType(); - - // Apply substitutions using ourselves, because we're inside the - // implementation of SILType::subst here. - if (origType->getSubstitutions()) { - llvm::SaveAndRestore OldSubst(Subst, - QuerySubstitutionMap{origType->getSubstitutions()}); - llvm::SaveAndRestore OldConformances(Conformances, - LookUpConformanceInSubstitutionMap(origType->getSubstitutions())); - selfType = visit(selfType); - } - - // The Self type can be nested in a few layers of metatypes (etc.). - while (auto metatypeType = dyn_cast(selfType)) { - auto next = metatypeType.getInstanceType(); - if (next == selfType) - break; - selfType = next; - } - - witnessMethodConformance = - conformance.subst(selfType, Subst, Conformances); - - // Substitute the underlying conformance of opaque type archetypes if we - // should look through opaque archetypes. - if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { - SubstOptions substOptions(None); - auto substType = selfType.subst(Subst, Conformances, substOptions) - ->getCanonicalType(); - if (substType->hasOpaqueArchetype()) { - witnessMethodConformance = substOpaqueTypesWithUnderlyingTypes( - witnessMethodConformance, substType, typeExpansionContext); - } - } - } + auto witnessMethodConformance = substWitnessConformance(origType); // The substituted type is no longer generic, so it'd never be // pseudogeneric. @@ -3186,18 +3332,50 @@ class SILTypeSubstituter : extInfo = extInfo.withIsPseudogeneric(false); auto genericSig = shouldSubstituteOpaqueArchetypes - ? origType->getSubstGenericSignature() - : nullptr; + ? origType->getInvocationGenericSignature() + : nullptr; return SILFunctionType::get(genericSig, extInfo, origType->getCoroutineKind(), origType->getCalleeConvention(), substParams, substYields, substResults, substErrorResult, - origType->getSubstitutions(), - origType->isGenericSignatureImplied(), + SubstitutionMap(), SubstitutionMap(), TC.Context, witnessMethodConformance); } + ProtocolConformanceRef substWitnessConformance(CanSILFunctionType origType) { + auto conformance = origType->getWitnessMethodConformanceOrInvalid(); + if (!conformance) return conformance; + + assert(origType->getExtInfo().hasSelfParam()); + auto selfType = origType->getSelfParameter().getInterfaceType(); + + // The Self type can be nested in a few layers of metatypes (etc.). + while (auto metatypeType = dyn_cast(selfType)) { + auto next = metatypeType.getInstanceType(); + if (next == selfType) + break; + selfType = next; + } + + auto substConformance = + conformance.subst(selfType, Subst, Conformances); + + // Substitute the underlying conformance of opaque type archetypes if we + // should look through opaque archetypes. + if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { + SubstOptions substOptions(None); + auto substType = selfType.subst(Subst, Conformances, substOptions) + ->getCanonicalType(); + if (substType->hasOpaqueArchetype()) { + substConformance = substOpaqueTypesWithUnderlyingTypes( + substConformance, substType, typeExpansionContext); + } + } + + return substConformance; + } + SILType subst(SILType type) { return SILType::getPrimitiveType(visit(type.getASTType()), type.getCategory()); @@ -3270,12 +3448,6 @@ class SILTypeSubstituter : } AbstractionPattern abstraction(Sig, origType); - // If we looked through an opaque archetype to a function type we need to - // use the function type's abstraction. - if (isa(origType) && - isa(substType)) - abstraction = AbstractionPattern(Sig, substType); - return TC.getLoweredRValueType(typeExpansionContext, abstraction, substType); } @@ -3345,7 +3517,7 @@ SILFunctionType::substGenericArgs(SILModule &silModule, SILTypeSubstituter substituter(silModule.Types, context, subs, conformances, getSubstGenericSignature(), /*shouldSubstituteOpaqueTypes*/ false); - return substituter.substSILFunctionType(CanSILFunctionType(this)); + return substituter.substSILFunctionType(CanSILFunctionType(this), true); } CanSILFunctionType @@ -3363,7 +3535,7 @@ SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, getSubstGenericSignature(), /*shouldSubstituteOpaqueTypes*/ true); auto resTy = - substituter.substSILFunctionType(CanSILFunctionType(this)); + substituter.substSILFunctionType(CanSILFunctionType(this), false); return resTy; } diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp index 9fb86036133bf..456469799df5d 100644 --- a/lib/SIL/SILOwnershipVerifier.cpp +++ b/lib/SIL/SILOwnershipVerifier.cpp @@ -605,71 +605,28 @@ bool SILValueOwnershipChecker::gatherUsers( continue; } - // See if our forwarding terminator is a transformation terminator. If so, - // just add all of the uses of its successors to the worklist to visit as - // users. - if (ti->isTransformationTerminator()) { - for (auto &succ : ti->getSuccessors()) { - auto *succBlock = succ.getBB(); - - // If we do not have any arguments, then continue. - if (succBlock->args_empty()) - continue; - - // Otherwise, make sure that all arguments are trivial or guaranteed. - // If we fail, emit an error. - // - // TODO: We could ignore this error and emit a more specific error on - // the actual terminator. - for (auto *succArg : succBlock->getSILPhiArguments()) { - // *NOTE* We do not emit an error here since we want to allow for - // more specific errors to be found during use_verification. - // - // TODO: Add a flag that associates the terminator instruction with - // needing to be verified. If it isn't verified appropriately, - // assert when the verifier is destroyed. - auto succArgOwnershipKind = succArg->getOwnershipKind(); - if (!succArgOwnershipKind.isCompatibleWith( - ValueOwnershipKind::Guaranteed)) { - // This is where the error would go. - continue; - } - - // If we have an any value, just continue. - if (succArgOwnershipKind == ValueOwnershipKind::None) - continue; - - // Otherwise add all users of this BBArg to the worklist to visit - // recursively. - llvm::copy(succArg->getUses(), std::back_inserter(users)); - } - } - continue; - } - - // We should not have a true phi here. So validate that our argument has an - // end_borrow that acts as a subscope that is compeltely enclosed within the - // scopes of all incoming values. We require all of our arguments to be - // either trivial or guaranteed. - for (auto &succ : ti->getSuccessors()) { - auto *succBlock = succ.getBB(); - + // At this point, the only type of thing we could have is a transformation + // terminator since all forwarding terminators are transformation + // terminators. + assert(ti->isTransformationTerminator() && + "Out of sync with isTransformationTerminator()"); + for (auto *succBlock : ti->getSuccessorBlocks()) { // If we do not have any arguments, then continue. if (succBlock->args_empty()) continue; - // Otherwise, make sure that all arguments are trivial or guaranteed. If - // we fail, emit an error. + // Otherwise, make sure that all arguments are trivial or guaranteed. + // If we fail, emit an error. // // TODO: We could ignore this error and emit a more specific error on // the actual terminator. for (auto *succArg : succBlock->getSILPhiArguments()) { - // *NOTE* We do not emit an error here since we want to allow for more - // specific errors to be found during use_verification. + // *NOTE* We do not emit an error here since we want to allow for + // more specific errors to be found during use_verification. // // TODO: Add a flag that associates the terminator instruction with - // needing to be verified. If it isn't verified appropriately, assert - // when the verifier is destroyed. + // needing to be verified. If it isn't verified appropriately, + // assert when the verifier is destroyed. auto succArgOwnershipKind = succArg->getOwnershipKind(); if (!succArgOwnershipKind.isCompatibleWith( ValueOwnershipKind::Guaranteed)) { @@ -681,16 +638,9 @@ bool SILValueOwnershipChecker::gatherUsers( if (succArgOwnershipKind == ValueOwnershipKind::None) continue; - // Otherwise add all end_borrow users for this BBArg to the - // implicit regular user list. We know that BBArg must be - // completely joint post-dominated by these users, so we use - // them to ensure that all of BBArg's uses are completely - // enclosed within the end_borrow of this argument. - for (auto *op : succArg->getUses()) { - if (isa(op->getUser())) { - implicitRegularUsers.push_back(op); - } - } + // Otherwise add all users of this BBArg to the worklist to visit + // recursively. + llvm::copy(succArg->getUses(), std::back_inserter(users)); } } } diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 17302665529ff..a326c9a0cc87b 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -445,7 +445,8 @@ static void printSILFunctionNameAndType( llvm::DenseMap &sugaredTypeNames) { function->printName(OS); OS << " : $"; - auto genSig = function->getLoweredFunctionType()->getSubstGenericSignature(); + auto genSig = + function->getLoweredFunctionType()->getInvocationGenericSignature(); auto *genEnv = function->getGenericEnvironment(); // If `genSig` and `genEnv` are both defined, get sugared names of generic // parameter types for printing. diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp index 99df4598d9fcb..748c495b15286 100644 --- a/lib/SIL/SILType.cpp +++ b/lib/SIL/SILType.cpp @@ -389,11 +389,14 @@ SILType::canUseExistentialRepresentation(ExistentialRepresentation repr, } SILType SILType::mapTypeOutOfContext() const { - return SILType::getPrimitiveType(getASTType()->mapTypeOutOfContext() - ->getCanonicalType(), + return SILType::getPrimitiveType(mapTypeOutOfContext(getASTType()), getCategory()); } +CanType SILType::mapTypeOutOfContext(CanType type) { + return type->mapTypeOutOfContext()->getCanonicalType(); +} + CanType swift::getSILBoxFieldLoweredType(TypeExpansionContext context, SILBoxType *type, TypeConverter &TC, unsigned index) { @@ -661,11 +664,13 @@ TypeBase::replaceSubstitutedSILFunctionTypesWithUnsubstituted(SILModule &M) cons if (!didChange) return sft; - return SILFunctionType::get(sft->getSubstGenericSignature(), + return SILFunctionType::get(sft->getInvocationGenericSignature(), sft->getExtInfo(), sft->getCoroutineKind(), sft->getCalleeConvention(), newParams, newYields, newResults, - newErrorResult, SubstitutionMap(), false, + newErrorResult, + SubstitutionMap(), + SubstitutionMap(), M.getASTContext()); } return t; diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index f31afa7253827..eead808e82c35 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -615,6 +615,19 @@ struct ImmutableAddressUseVerifier { llvm::copy(result->getUses(), std::back_inserter(worklist)); } break; + case SILInstructionKind::UncheckedTakeEnumDataAddrInst: { + auto type = + cast(inst)->getOperand()->getType(); + if (type.getOptionalObjectType()) { + for (auto result : inst->getResults()) { + llvm::copy(result->getUses(), std::back_inserter(worklist)); + } + break; + } + llvm::errs() << "Unhandled, unexpected instruction: " << *inst; + llvm_unreachable("invoking standard assertion failure"); + break; + } default: llvm::errs() << "Unhandled, unexpected instruction: " << *inst; llvm_unreachable("invoking standard assertion failure"); @@ -835,7 +848,7 @@ class SILVerifier : public SILVerifierBase { SILVerifier(const SILFunction &F, bool SingleFunction = true) : M(F.getModule().getSwiftModule()), F(F), - fnConv(F.getLoweredFunctionType(), F.getModule()), + fnConv(F.getConventionsInContext()), TC(F.getModule().Types), OpenedArchetypes(&F), Dominance(nullptr), InstNumbers(numInstsInFunction(F)), DEBlocks(&F), SingleFunction(SingleFunction) { @@ -1309,12 +1322,12 @@ class SILVerifier : public SILVerifierBase { } if (subs.getGenericSignature()->getCanonicalSignature() != - fnTy->getSubstGenericSignature()->getCanonicalSignature()) { + fnTy->getInvocationGenericSignature()->getCanonicalSignature()) { llvm::dbgs() << "substitution map's generic signature: "; subs.getGenericSignature()->print(llvm::dbgs()); llvm::dbgs() << "\n"; llvm::dbgs() << "callee's generic signature: "; - fnTy->getSubstGenericSignature()->print(llvm::dbgs()); + fnTy->getInvocationGenericSignature()->print(llvm::dbgs()); llvm::dbgs() << "\n"; require(false, "Substitution map does not match callee in apply instruction"); @@ -2957,7 +2970,7 @@ class SILVerifier : public SILVerifierBase { methodTy->getYields(), dynResults, methodTy->getOptionalErrorResult(), - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), F.getASTContext()); return SILType::getPrimitiveObjectType(fnTy); } @@ -3967,9 +3980,7 @@ class SILVerifier : public SILVerifierBase { void checkThrowInst(ThrowInst *TI) { LLVM_DEBUG(TI->print(llvm::dbgs())); - CanSILFunctionType fnType = - F.getLoweredFunctionTypeInContext(F.getTypeExpansionContext()); - require(fnType->hasErrorResult(), + require(fnConv.funcTy->hasErrorResult(), "throw in function that doesn't have an error result"); SILType functionResultType = @@ -3992,14 +4003,11 @@ class SILVerifier : public SILVerifierBase { } void checkYieldInst(YieldInst *YI) { - CanSILFunctionType fnType = - F.getLoweredFunctionTypeInContext(F.getTypeExpansionContext()) - ->getUnsubstitutedType(F.getModule()); - require(fnType->isCoroutine(), + require(fnConv.funcTy->isCoroutine(), "yield in non-coroutine function"); auto yieldedValues = YI->getYieldedValues(); - auto yieldInfos = fnType->getYields(); + auto yieldInfos = fnConv.funcTy->getYields(); require(yieldedValues.size() == yieldInfos.size(), "wrong number of yielded values for function"); for (auto i : indices(yieldedValues)) { @@ -4663,7 +4671,7 @@ class SILVerifier : public SILVerifierBase { for (auto result : fnConv.getIndirectSILResults()) { assert(fnConv.isSILIndirect(result)); - check("result", fnConv.getSILType(result)); + check("indirect result", fnConv.getSILType(result)); } for (auto param : F.getLoweredFunctionType()->getParameters()) { check("parameter", fnConv.getSILType(param)); diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 738b95d5bc4c8..3bd6187ec3e4e 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -26,6 +26,7 @@ #include "swift/AST/Pattern.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/PropertyWrappers.h" +#include "swift/AST/TypeDifferenceVisitor.h" #include "swift/AST/Types.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/SIL/PrettyStackTrace.h" @@ -1384,7 +1385,7 @@ void *TypeLowering::operator new(size_t size, TypeConverter &tc) { return tc.TypeLoweringBPA.Allocate(size, alignof(TypeLowering&)); } -const TypeLowering *TypeConverter::find(TypeKey k) { +const TypeLowering *TypeConverter::find(const TypeKey &k) { if (!k.isCacheable()) return nullptr; auto ck = k.getCachingKey(); @@ -1398,7 +1399,7 @@ const TypeLowering *TypeConverter::find(TypeKey k) { } #ifndef NDEBUG -void TypeConverter::removeNullEntry(TypeKey k) { +void TypeConverter::removeNullEntry(const TypeKey &k) { if (!k.isCacheable()) return; @@ -1412,7 +1413,7 @@ void TypeConverter::removeNullEntry(TypeKey k) { } #endif -void TypeConverter::insert(TypeKey k, const TypeLowering *tl) { +void TypeConverter::insert(const TypeKey &k, const TypeLowering *tl) { if (!k.isCacheable()) return; LoweredTypes[k.getCachingKey()] = tl; @@ -2537,6 +2538,63 @@ TypeConverter::checkForABIDifferences(SILModule &M, return ABIDifference::NeedsThunk; } +namespace { +class HaveDifferentAbstractStructure + : public CanTypeDifferenceVisitor { +public: + // Treat any sort of abstract type as equivalent. + static bool isAbstract(CanType type) { + return (isa(type) || isa(type)); + }; + + // We can fast-path some of these checks by proviing these two overrides: + bool visitSubstitutableType(CanSubstitutableType type1, + CanSubstitutableType type2) { + return false; + } + bool visitDependentMemberType(CanDependentMemberType type1, + CanDependentMemberType type2) { + return false; + } + + // We also need to handle the general case where we have different + // kinds of substitutable types. + bool visitDifferentComponentTypes(CanType type1, CanType type2) { + // This is a difference only if both types aren't abstract. + return !(isAbstract(type1) && isAbstract(type2)); + } + + // Change the rules used for SIL function types to only consider + // the basic structure, not any substitutions. + bool visitSILFunctionType(CanSILFunctionType type1, + CanSILFunctionType type2) { + return visitSILFunctionTypeStructure(type1, type2) + || visitSILFunctionTypeComponents(type1, type2); + } +}; +} + +static bool haveDifferentAbstractStructure(CanType type1, CanType type2) { + return HaveDifferentAbstractStructure().visit(type1, type2); +} + +static TypeConverter::ABIDifference +checkForABIDifferencesInYield(TypeConverter &TC, SILModule &M, + SILFunctionType *fnTy1, SILYieldInfo yield1, + SILFunctionType *fnTy2, SILYieldInfo yield2) { + // Require the interface types to have the same basic abstract + // structure, ignoring any substitutions from the function type. + // This structure is what determines the signature of the continuation + // function. + if (haveDifferentAbstractStructure(yield1.getInterfaceType(), + yield2.getInterfaceType())) + return TypeConverter::ABIDifference::NeedsThunk; + + // Also make sure that the actual yield types match in ABI. + return TC.checkForABIDifferences(M, yield1.getSILStorageType(M, fnTy1), + yield2.getSILStorageType(M, fnTy2)); +} + TypeConverter::ABIDifference TypeConverter::checkFunctionForABIDifferences(SILModule &M, SILFunctionType *fnTy1, @@ -2596,10 +2654,7 @@ TypeConverter::checkFunctionForABIDifferences(SILModule &M, if (yield1.getConvention() != yield2.getConvention()) return ABIDifference::NeedsThunk; - if (checkForABIDifferences(M, - yield1.getSILStorageType(M, fnTy1), - yield2.getSILStorageType(M, fnTy2), - /*thunk iuos*/ fnTy1->getLanguage() == SILFunctionLanguage::Swift) + if (checkForABIDifferencesInYield(*this, M, fnTy1, yield1, fnTy2, yield2) != ABIDifference::CompatibleRepresentation) return ABIDifference::NeedsThunk; } diff --git a/lib/SIL/ValueOwnership.cpp b/lib/SIL/ValueOwnership.cpp index 2ed019d8da2ad..a086223d11a21 100644 --- a/lib/SIL/ValueOwnership.cpp +++ b/lib/SIL/ValueOwnership.cpp @@ -78,13 +78,6 @@ CONSTANT_OWNERSHIP_INST(Owned, KeyPath) CONSTANT_OWNERSHIP_INST(Owned, InitExistentialValue) CONSTANT_OWNERSHIP_INST(Owned, GlobalValue) // TODO: is this correct? -// NOTE: Even though init_existential_ref from a reference counting perspective -// is not considered to be "owned" since it doesn't affect reference counts, -// conceptually we want to treat it as an owned value that produces owned -// things, rather than a forwarding thing since initialization is generally a -// consuming operation. -CONSTANT_OWNERSHIP_INST(Owned, InitExistentialRef) - // One would think that these /should/ be unowned. In truth they are owned since // objc metatypes do not go through the retain/release fast path. In their // implementations of retain/release nothing happens, so this is safe. @@ -260,6 +253,16 @@ FORWARDING_OWNERSHIP_INST(Upcast) FORWARDING_OWNERSHIP_INST(UncheckedEnumData) FORWARDING_OWNERSHIP_INST(SelectEnum) FORWARDING_OWNERSHIP_INST(Enum) +// NOTE: init_existential_ref from a reference counting perspective is not +// considered to be "owned" since it doesn't affect reference counts. That being +// said in the past, we wanted to conceptually treat it as an owned value that +// produces owned things, rather than a forwarding thing since initialization is +// generally a consuming operation. That being said, there are often cases in +// class based code where we are propagating around a plus zero version of a +// value and need to wrap the class in an existential wrapper in an intermediate +// frame from usage. In such cases, we have been creating unnecessary ref count +// traffic in code. +FORWARDING_OWNERSHIP_INST(InitExistentialRef) #undef FORWARDING_OWNERSHIP_INST ValueOwnershipKind @@ -522,6 +525,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, OnceWithContext) CONSTANT_OWNERSHIP_BUILTIN(None, TSanInoutAccess) CONSTANT_OWNERSHIP_BUILTIN(None, Swift3ImplicitObjCEntrypoint) CONSTANT_OWNERSHIP_BUILTIN(None, PoundAssert) +CONSTANT_OWNERSHIP_BUILTIN(None, TypePtrAuthDiscriminator) CONSTANT_OWNERSHIP_BUILTIN(None, GlobalStringTablePointer) #undef CONSTANT_OWNERSHIP_BUILTIN diff --git a/lib/SILGen/ArgumentSource.cpp b/lib/SILGen/ArgumentSource.cpp index 8969b34a81461..c3035d821d609 100644 --- a/lib/SILGen/ArgumentSource.cpp +++ b/lib/SILGen/ArgumentSource.cpp @@ -78,9 +78,11 @@ ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF, ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF, AbstractionPattern origFormalType, + SILType loweredTy, SGFContext C) && { auto substFormalType = getSubstRValueType(); - auto conversion = Conversion::getSubstToOrig(origFormalType, substFormalType); + auto conversion = + Conversion::getSubstToOrig(origFormalType, substFormalType, loweredTy); return std::move(*this).getConverted(SGF, conversion, C); } @@ -209,6 +211,7 @@ void ArgumentSource::forwardInto(SILGenFunction &SGF, SILLocation loc = getLocation(); ManagedValue outputValue = std::move(*this).getAsSingleValue(SGF, origFormalType, + destTL.getLoweredType(), SGFContext(dest)); if (outputValue.isInContext()) return; diff --git a/lib/SILGen/ArgumentSource.h b/lib/SILGen/ArgumentSource.h index 016e47c4ea411..b909ab09dc218 100644 --- a/lib/SILGen/ArgumentSource.h +++ b/lib/SILGen/ArgumentSource.h @@ -242,6 +242,7 @@ class ArgumentSource { SGFContext C = SGFContext()) &&; ManagedValue getAsSingleValue(SILGenFunction &SGF, AbstractionPattern origFormalType, + SILType loweredResultTy, SGFContext C = SGFContext()) &&; ManagedValue getConverted(SILGenFunction &SGF, const Conversion &conversion, diff --git a/lib/SILGen/Conversion.h b/lib/SILGen/Conversion.h index aa8aea9d9405e..e17f348bae8aa 100644 --- a/lib/SILGen/Conversion.h +++ b/lib/SILGen/Conversion.h @@ -73,6 +73,7 @@ class Conversion { struct ReabstractionTypes { AbstractionPattern OrigType; CanType SubstType; + SILType LoweredResultType; }; using Members = ExternalUnionMembers; @@ -104,20 +105,24 @@ class Conversion { loweredResultTy, isExplicit); } - Conversion(KindTy kind, AbstractionPattern origType, CanType substType) + Conversion(KindTy kind, AbstractionPattern origType, CanType substType, + SILType loweredResultTy) : Kind(kind) { - Types.emplaceAggregate(kind, origType, substType); + Types.emplaceAggregate(kind, origType, substType, + loweredResultTy); } public: static Conversion getOrigToSubst(AbstractionPattern origType, - CanType substType) { - return Conversion(OrigToSubst, origType, substType); + CanType substType, + SILType loweredResultTy) { + return Conversion(OrigToSubst, origType, substType, loweredResultTy); } static Conversion getSubstToOrig(AbstractionPattern origType, - CanType substType) { - return Conversion(SubstToOrig, origType, substType); + CanType substType, + SILType loweredResultTy) { + return Conversion(SubstToOrig, origType, substType, loweredResultTy); } static Conversion getBridging(KindTy kind, CanType origType, @@ -143,6 +148,10 @@ class Conversion { return Types.get(Kind).SubstType; } + SILType getReabstractionLoweredResultType() const { + return Types.get(Kind).LoweredResultType; + } + bool isBridgingExplicit() const { return Types.get(Kind).IsExplicit; } diff --git a/lib/SILGen/ResultPlan.cpp b/lib/SILGen/ResultPlan.cpp index 4bf82704cbd1a..f53fc3f4152d9 100644 --- a/lib/SILGen/ResultPlan.cpp +++ b/lib/SILGen/ResultPlan.cpp @@ -249,7 +249,8 @@ class ScalarResultPlan final : public ResultPlan { origType.getType(), substType, loweredResultTy); } else { - return Conversion::getOrigToSubst(origType, substType); + return Conversion::getOrigToSubst(origType, substType, + loweredResultTy); } }(); diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index f5e80b018c416..37b545156e376 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -75,12 +75,8 @@ getBridgingFn(Optional &cacheSlot, SILGenModule &SGM, Identifier moduleName, StringRef functionName, - Optional> inputTypes, - Optional outputType) { - // FIXME: the optionality of outputType and the presence of trustInputTypes - // are hacks for cases where coming up with those types is complicated, i.e., - // when dealing with generic bridging functions. - + std::initializer_list inputTypes, + Type outputType) { if (!cacheSlot) { ASTContext &ctx = SGM.M.getASTContext(); ModuleDecl *mod = ctx.getLoadedModule(moduleName); @@ -122,21 +118,18 @@ getBridgingFn(Optional &cacheSlot, return SGM.Types.getLoweredType(ty, TypeExpansionContext::minimal()); }; - if (inputTypes) { - if (fnConv.hasIndirectSILResults() - || funcTy->getNumParameters() != inputTypes->size() - || !std::equal( - fnConv.getParameterSILTypes().begin(), - fnConv.getParameterSILTypes().end(), - makeTransformIterator(inputTypes->begin(), toSILType))) { - SGM.diagnose(fd->getLoc(), diag::bridging_function_not_correct_type, - moduleName.str(), functionName); - llvm::report_fatal_error("unable to set up the ObjC bridge!"); - } + if (fnConv.hasIndirectSILResults() + || funcTy->getNumParameters() != inputTypes.size() + || !std::equal( + fnConv.getParameterSILTypes().begin(), + fnConv.getParameterSILTypes().end(), + makeTransformIterator(inputTypes.begin(), toSILType))) { + SGM.diagnose(fd->getLoc(), diag::bridging_function_not_correct_type, + moduleName.str(), functionName); + llvm::report_fatal_error("unable to set up the ObjC bridge!"); } - if (outputType - && fnConv.getSingleSILResultType() != toSILType(*outputType)) { + if (fnConv.getSingleSILResultType() != toSILType(outputType)) { SGM.diagnose(fd->getLoc(), diag::bridging_function_not_correct_type, moduleName.str(), functionName); llvm::report_fatal_error("unable to set up the ObjC bridge!"); @@ -153,16 +146,15 @@ getBridgingFn(Optional &cacheSlot, return *cacheSlot; } -#define REQUIRED(X) { Types.get##X##Type() } -#define OPTIONAL(X) { OptionalType::get(Types.get##X##Type()) } -#define GENERIC(X) None +#define REQUIRED(X) Types.get##X##Type() +#define OPTIONAL(X) OptionalType::get(Types.get##X##Type()) #define GET_BRIDGING_FN(Module, FromKind, FromTy, ToKind, ToTy) \ SILDeclRef SILGenModule::get##FromTy##To##ToTy##Fn() { \ return getBridgingFn(FromTy##To##ToTy##Fn, *this, \ getASTContext().Id_##Module, \ "_convert" #FromTy "To" #ToTy, \ - FromKind(FromTy), \ + { FromKind(FromTy) }, \ ToKind(ToTy)); \ } @@ -178,7 +170,6 @@ GET_BRIDGING_FN(WinSDK, REQUIRED, WindowsBool, REQUIRED, Bool) #undef GET_BRIDGING_FN #undef REQUIRED #undef OPTIONAL -#undef GENERIC static FuncDecl *diagnoseMissingIntrinsic(SILGenModule &sgm, SILLocation loc, @@ -434,7 +425,8 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, yields, /*results*/ {}, /*error result*/ {}, - SubstitutionMap(), false, + SubstitutionMap(), + SubstitutionMap(), getASTContext()); auto env = sig->getGenericEnvironment(); @@ -495,7 +487,7 @@ SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) { SILResultInfo(Int32Ty, ResultConvention::Unowned), None, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), C); SILGenFunctionBuilder builder(*this); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 96afe9971ab69..5c6bd4af366e7 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -2950,7 +2950,8 @@ class ArgEmitter { switch (getSILFunctionLanguage(Rep)) { case SILFunctionLanguage::Swift: return Conversion::getSubstToOrig(origParamType, - arg.getSubstRValueType()); + arg.getSubstRValueType(), + param.getSILStorageInterfaceType()); case SILFunctionLanguage::C: return Conversion::getBridging(Conversion::BridgeToObjC, arg.getSubstRValueType(), @@ -4789,7 +4790,8 @@ ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc, if (!payloadMV) { // If the payload was indirect, we already evaluated it and // have a single value. Otherwise, evaluate the payload. - payloadMV = std::move(payload).getAsSingleValue(*this, origFormalType); + payloadMV = std::move(payload).getAsSingleValue(*this, origFormalType, + loweredPayloadType); } SILValue argValue = payloadMV.forward(*this); @@ -4812,7 +4814,9 @@ ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc, } else if (payloadTL.isLoadable()) { // The payload of this specific enum case might be loadable // even if the overall enum is address-only. - payloadMV = std::move(payload).getAsSingleValue(*this, origFormalType); + payloadMV = + std::move(payload).getAsSingleValue(*this, origFormalType, + loweredPayloadType); B.emitStoreValueOperation(loc, payloadMV.forward(*this), resultData, StoreOwnershipQualifier::Init); } else { diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 0eb946aef1e42..6937700d0e4d0 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -37,14 +37,16 @@ static ManagedValue emitUnabstractedCast(SILGenFunction &SGF, SILLocation loc, ManagedValue value, CanType sourceFormalType, CanType targetFormalType) { - if (value.getType() == SGF.getLoweredType(targetFormalType)) + SILType loweredResultTy = SGF.getLoweredType(targetFormalType); + if (value.getType() == loweredResultTy) return value; return SGF.emitTransformedValue(loc, value, AbstractionPattern(sourceFormalType), sourceFormalType, AbstractionPattern(targetFormalType), - targetFormalType); + targetFormalType, + loweredResultTy); } static bool shouldBridgeThroughError(SILGenModule &SGM, CanType type, @@ -577,7 +579,8 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, genericSig, extInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, blockInterfaceTy->getResults(), - blockInterfaceTy->getOptionalErrorResult(), SubstitutionMap(), false, + blockInterfaceTy->getOptionalErrorResult(), + SubstitutionMap(), SubstitutionMap(), getASTContext()); // Create the invoke function. Borrow the mangling scheme from reabstraction diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp index f02c0b387765f..a6443b11bfcd9 100644 --- a/lib/SILGen/SILGenConvert.cpp +++ b/lib/SILGen/SILGenConvert.cpp @@ -1164,12 +1164,14 @@ ManagedValue Conversion::emit(SILGenFunction &SGF, SILLocation loc, case SubstToOrig: return SGF.emitSubstToOrigValue(loc, value, getReabstractionOrigType(), - getReabstractionSubstType(), C); + getReabstractionSubstType(), + getReabstractionLoweredResultType(), C); case OrigToSubst: return SGF.emitOrigToSubstValue(loc, value, getReabstractionOrigType(), - getReabstractionSubstType(), C); + getReabstractionSubstType(), + getReabstractionLoweredResultType(), C); } llvm_unreachable("bad kind"); } @@ -1231,6 +1233,8 @@ static void printReabstraction(const Conversion &conversion, conversion.getReabstractionOrigType().print(out); out << ", subst: "; conversion.getReabstractionSubstType().print(out); + out << ", loweredResult: "; + conversion.getReabstractionLoweredResultType().print(out); out << ')'; } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index ec6173cb0b774..0dc10f5e7b516 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2725,7 +2725,7 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, result, None, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), SGM.getASTContext()); }(); @@ -2885,7 +2885,7 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, {}, None, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), SGM.getASTContext()); }(); @@ -3077,7 +3077,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), C); // Mangle the name of the thunk to see if we already created it. @@ -3251,7 +3251,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, - SubstitutionMap(), false, C); + SubstitutionMap(), SubstitutionMap(), C); // Mangle the name of the thunk to see if we already created it. SmallString<64> nameBuf; diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 71e29ea3f89e2..53b9621c685bf 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -588,7 +588,7 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { SILResultInfo(OptNSStringTy, ResultConvention::Autoreleased), /*error result*/ None, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), ctx); auto NSStringFromClassFn = builder.getOrCreateFunction( mainClass, "NSStringFromClass", SILLinkage::PublicExternal, @@ -675,7 +675,7 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { SILResultInfo(argc->getType().getASTType(), ResultConvention::Unowned), /*error result*/ None, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), getASTContext()); SILGenFunctionBuilder builder(SGM); diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 588805ada7b50..0e6fef4e8be69 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -1778,10 +1778,20 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction AbstractionPattern origType, CanType substType, SGFContext ctx = SGFContext()); + ManagedValue emitOrigToSubstValue(SILLocation loc, ManagedValue input, + AbstractionPattern origType, + CanType substType, + SILType loweredResultTy, + SGFContext ctx = SGFContext()); RValue emitOrigToSubstValue(SILLocation loc, RValue &&input, AbstractionPattern origType, CanType substType, SGFContext ctx = SGFContext()); + RValue emitOrigToSubstValue(SILLocation loc, RValue &&input, + AbstractionPattern origType, + CanType substType, + SILType loweredResultTy, + SGFContext ctx = SGFContext()); /// Convert a value with the abstraction patterns of the substituted /// type to a value with the abstraction patterns of the original type. @@ -1793,6 +1803,16 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction AbstractionPattern origType, CanType substType, SGFContext ctx = SGFContext()); + ManagedValue emitSubstToOrigValue(SILLocation loc, ManagedValue input, + AbstractionPattern origType, + CanType substType, + SILType loweredResultTy, + SGFContext ctx = SGFContext()); + RValue emitSubstToOrigValue(SILLocation loc, RValue &&input, + AbstractionPattern origType, + CanType substType, + SILType loweredResultTy, + SGFContext ctx = SGFContext()); /// Transform the AST-level types in the function signature without an /// abstraction or representation change. @@ -1807,12 +1827,14 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction CanType inputSubstType, AbstractionPattern outputOrigType, CanType outputSubstType, + SILType loweredResultTy, SGFContext ctx = SGFContext()); RValue emitTransformedValue(SILLocation loc, RValue &&input, AbstractionPattern inputOrigType, CanType inputSubstType, AbstractionPattern outputOrigType, CanType outputSubstType, + SILType loweredResultTy, SGFContext ctx = SGFContext()); /// Used for emitting SILArguments of bare functions, such as thunks. diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index ad03e6452b389..cfbc04b17a66d 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -1969,8 +1969,11 @@ namespace { keyPathTy->getGenericArgs(), ArrayRef()); + auto origType = AbstractionPattern::getOpaque(); + auto loweredTy = SGF.getLoweredType(origType, value.getSubstRValueType()); + auto setValue = - std::move(value).getAsSingleValue(SGF, AbstractionPattern::getOpaque()); + std::move(value).getAsSingleValue(SGF, origType, loweredTy); if (!setValue.getType().isAddress()) { setValue = setValue.materialize(SGF, loc); } @@ -3523,7 +3526,8 @@ ManagedValue SILGenFunction::emitLoad(SILLocation loc, SILValue addr, ? Conversion::getBridging(Conversion::BridgeFromObjC, origFormalType.getType(), substFormalType, rvalueTL.getLoweredType()) - : Conversion::getOrigToSubst(origFormalType, substFormalType); + : Conversion::getOrigToSubst(origFormalType, substFormalType, + rvalueTL.getLoweredType()); return emitConvertedRValue(loc, conversion, C, [&](SILGenFunction &SGF, SILLocation loc, SGFContext C) { diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 66f58155f7870..827338185ff65 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -130,6 +130,7 @@ namespace { CanType inputSubstType, AbstractionPattern outputOrigType, CanType outputSubstType, + SILType outputLoweredTy, SGFContext ctxt); /// Transform an arbitrary value. @@ -138,6 +139,7 @@ namespace { CanType inputSubstType, AbstractionPattern outputOrigType, CanType outputSubstType, + SILType outputLoweredTy, SGFContext ctxt); /// Transform a metatype value. @@ -145,7 +147,8 @@ namespace { AbstractionPattern inputOrigType, CanMetatypeType inputSubstType, AbstractionPattern outputOrigType, - CanMetatypeType outputSubstType); + CanMetatypeType outputSubstType, + SILType outputLoweredTy); /// Transform a tuple value. ManagedValue transformTuple(ManagedValue input, @@ -153,6 +156,7 @@ namespace { CanTupleType inputSubstType, AbstractionPattern outputOrigType, CanTupleType outputSubstType, + SILType outputLoweredTy, SGFContext ctxt); /// Transform a function value. @@ -239,6 +243,7 @@ RValue Transform::transform(RValue &&input, CanType inputSubstType, AbstractionPattern outputOrigType, CanType outputSubstType, + SILType outputLoweredTy, SGFContext ctxt) { // Fast path: we don't have a tuple. auto inputTupleType = dyn_cast(inputSubstType); @@ -247,7 +252,8 @@ RValue Transform::transform(RValue &&input, "transformation introduced a tuple?"); auto result = transform(std::move(input).getScalarValue(), inputOrigType, inputSubstType, - outputOrigType, outputSubstType, ctxt); + outputOrigType, outputSubstType, + outputLoweredTy, ctxt); return RValue(SGF, Loc, outputSubstType, result); } @@ -260,6 +266,10 @@ RValue Transform::transform(RValue &&input, "subtype constraint erasing tuple is not currently implemented"); auto outputTupleType = cast(outputSubstType); assert(inputTupleType->getNumElements() == outputTupleType->getNumElements()); + assert(outputLoweredTy.is() && + "expected lowered output type wasn't a tuple when formal type was"); + assert(outputLoweredTy.castTo()->getNumElements() == + outputTupleType->getNumElements()); // Pull the r-value apart. SmallVector inputElts; @@ -295,6 +305,7 @@ RValue Transform::transform(RValue &&input, inputTupleType.getElementType(eltIndex), outputOrigType.getTupleElementType(eltIndex), outputTupleType.getElementType(eltIndex), + outputLoweredTy.getTupleElementType(eltIndex), eltCtxt); // Force the r-value into its context if necessary. @@ -345,6 +356,7 @@ ManagedValue Transform::transform(ManagedValue v, CanType inputSubstType, AbstractionPattern outputOrigType, CanType outputSubstType, + SILType loweredResultTy, SGFContext ctxt) { // Load if the result isn't address-only. All the translation routines // expect this. @@ -355,10 +367,11 @@ ManagedValue Transform::transform(ManagedValue v, } } - const TypeLowering &expectedTL = SGF.getTypeLowering(outputOrigType, - outputSubstType); - auto loweredResultTy = expectedTL.getLoweredType(); - + // Downstream code expects the lowered result type to be an object if + // it's loadable, so make sure that's satisfied. + auto &expectedTL = SGF.getTypeLowering(loweredResultTy); + loweredResultTy = expectedTL.getLoweredType(); + // Nothing to convert if (v.getType() == loweredResultTy) return v; @@ -376,7 +389,9 @@ ManagedValue Transform::transform(ManagedValue v, Loc, expectedTL, ctxt, [&](SGFContext objectCtxt) { return transform(v, inputOrigType, inputSubstType, outputOrigType.getOptionalObjectType(), - outputObjectType, objectCtxt); + outputObjectType, + loweredResultTy.getOptionalObjectType(), + objectCtxt); }); } @@ -415,7 +430,7 @@ ManagedValue Transform::transform(ManagedValue v, SILType loweredResultTy, SGFContext context) -> ManagedValue { return transform(input, inputOrigType.getOptionalObjectType(), inputObjectType, outputOrigType.getOptionalObjectType(), - outputObjectType, context); + outputObjectType, loweredResultTy, context); }; return SGF.emitOptionalToOptional(Loc, v, loweredResultTy, @@ -439,7 +454,7 @@ ManagedValue Transform::transform(ManagedValue v, return transformTuple(v, inputOrigType, inputTupleType, outputOrigType, outputTupleType, - ctxt); + loweredResultTy, ctxt); } // - metatypes @@ -447,7 +462,8 @@ ManagedValue Transform::transform(ManagedValue v, if (auto inputMetaType = dyn_cast(inputSubstType)) { return transformMetatype(v, inputOrigType, inputMetaType, - outputOrigType, outputMetaType); + outputOrigType, outputMetaType, + loweredResultTy); } } @@ -584,6 +600,7 @@ ManagedValue Transform::transform(ManagedValue v, openedType, outputOrigType, outputSubstType, + loweredResultTy, ctxt); } } @@ -612,11 +629,10 @@ ManagedValue Transform::transformMetatype(ManagedValue meta, AbstractionPattern inputOrigType, CanMetatypeType inputSubstType, AbstractionPattern outputOrigType, - CanMetatypeType outputSubstType) { + CanMetatypeType outputSubstType, + SILType expectedType) { assert(!meta.hasCleanup() && "metatype with cleanup?!"); - auto expectedType = SGF.getTypeLowering(outputOrigType, - outputSubstType).getLoweredType(); auto wasRepr = meta.getType().castTo()->getRepresentation(); auto willBeRepr = expectedType.castTo()->getRepresentation(); @@ -677,15 +693,16 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple, CanTupleType inputSubstType, AbstractionPattern outputOrigType, CanTupleType outputSubstType, + SILType outputLoweredTy, SGFContext ctxt) { const TypeLowering &outputTL = - SGF.getTypeLowering(outputOrigType, outputSubstType); + SGF.getTypeLowering(outputLoweredTy); assert((outputTL.isAddressOnly() == inputTuple.getType().isAddress() || !SGF.silConv.useLoweredAddresses()) && "expected loadable inputs to have been loaded"); // If there's no representation difference, we're done. - if (outputTL.getLoweredType() == inputTuple.getType()) + if (outputLoweredTy == inputTuple.getType().copyCategory(outputLoweredTy)) return inputTuple; assert(inputOrigType.matchesTuple(outputSubstType)); @@ -697,8 +714,7 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple, // If the tuple is address only, we need to do the operation in memory. SILValue outputAddr; if (outputTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) - outputAddr = SGF.getBufferForExprResult(Loc, outputTL.getLoweredType(), - ctxt); + outputAddr = SGF.getBufferForExprResult(Loc, outputLoweredTy, ctxt); // Explode the tuple into individual managed values. SmallVector inputElts; @@ -719,6 +735,7 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple, auto inputEltSubstType = inputSubstType.getElementType(index); auto outputEltOrigType = outputOrigType.getTupleElementType(index); auto outputEltSubstType = outputSubstType.getElementType(index); + auto outputEltLoweredTy = outputLoweredTy.getTupleElementType(index); // If we're emitting to memory, project out this element in the // destination buffer, then wrap that in an Initialization to @@ -727,7 +744,7 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple, if (outputAddr) { SILValue outputEltAddr = SGF.B.createTupleElementAddr(Loc, outputAddr, index); - auto &outputEltTL = SGF.getTypeLowering(outputEltAddr->getType()); + auto &outputEltTL = SGF.getTypeLowering(outputEltLoweredTy); assert(outputEltTL.isAddressOnly() == inputEltTL.isAddressOnly()); auto cleanup = SGF.enterDormantTemporaryCleanup(outputEltAddr, outputEltTL); @@ -739,7 +756,7 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple, auto outputElt = transform(inputElt, inputEltOrigType, inputEltSubstType, outputEltOrigType, outputEltSubstType, - eltCtxt); + outputEltLoweredTy, eltCtxt); // If we're not emitting to memory, remember this element for // later assembly into a tuple. @@ -777,7 +794,7 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple, // Otherwise, assemble the tuple value and manage that. auto outputTuple = - SGF.B.createTuple(Loc, outputTL.getLoweredType(), outputEltValues); + SGF.B.createTuple(Loc, outputLoweredTy, outputEltValues); return SGF.emitManagedRValueWithCleanup(outputTuple, outputTL); } @@ -849,6 +866,7 @@ namespace { auto mv = SGF.emitTransformedValue(loc, inputMV, InputOrigType, InputSubstType, OutputOrigType, OutputSubstType, + Output->getType().getObjectType(), SGFContext(outputInit.get())); emitForceInto(SGF, loc, mv, *outputInit); @@ -870,14 +888,16 @@ namespace { SILLocation Loc; ArrayRef Inputs; SmallVectorImpl &Outputs; + CanSILFunctionType OutputTypesFuncTy; ArrayRef OutputTypes; public: TranslateArguments(SILGenFunction &SGF, SILLocation loc, ArrayRef inputs, SmallVectorImpl &outputs, + CanSILFunctionType outputTypesFuncTy, ArrayRef outputTypes) : SGF(SGF), Loc(loc), Inputs(inputs), Outputs(outputs), - OutputTypes(outputTypes) {} + OutputTypesFuncTy(outputTypesFuncTy), OutputTypes(outputTypes) {} void translate(AbstractionPattern inputOrigFunctionType, AnyFunctionType::CanParamArrayRef inputSubstTypes, @@ -1045,7 +1065,7 @@ namespace { "Output is not a tuple and is not opaque?"); auto outputTy = SGF.getSILType(claimNextOutputType(), - CanSILFunctionType()); + OutputTypesFuncTy); auto &outputTL = SGF.getTypeLowering(outputTy); if (SGF.silConv.useLoweredAddresses()) { auto temp = SGF.emitTemporary(Loc, outputTL); @@ -1105,6 +1125,8 @@ namespace { SmallVector elements; assert(outputType->getNumElements() == inputType->getNumElements()); + assert(loweredOutputTy.castTo()->getNumElements() == + outputType->getNumElements()); for (unsigned i : indices(outputType->getElementTypes())) { auto inputOrigEltType = inputOrigType.getTupleElementType(i); auto inputEltType = inputType.getElementType(i); @@ -1137,7 +1159,7 @@ namespace { if (elt.getType() != loweredOutputEltTy) elt = translatePrimitive(inputOrigEltType, inputEltType, outputOrigEltType, outputEltType, - elt); + elt, loweredOutputEltTy); elements.push_back(elt); } @@ -1166,7 +1188,7 @@ namespace { auto &loweredTL = SGF.getTypeLowering(outputOrigType, outputTupleType); auto loweredTy = loweredTL.getLoweredType(); auto optionalTy = SGF.getSILType(claimNextOutputType(), - CanSILFunctionType()); + OutputTypesFuncTy); auto someDecl = SGF.getASTContext().getOptionalSomeDecl(); if (loweredTL.isLoadable() || !SGF.silConv.useLoweredAddresses()) { auto payload = @@ -1321,6 +1343,10 @@ namespace { assert(inputSubstType->getNumElements() == outputSubstType->getNumElements()); + auto outputLoweredTy = tupleInit.getAddress()->getType(); + assert(outputLoweredTy.castTo()->getNumElements() == + outputSubstType->getNumElements()); + SmallVector cleanups; for (auto index : indices(outputSubstType.getElementTypes())) { @@ -1374,9 +1400,12 @@ namespace { void translateIntoOwned(AbstractionPattern inputOrigType, CanType inputSubstType, AbstractionPattern outputOrigType, - CanType outputSubstType, ManagedValue input) { + CanType outputSubstType, + ManagedValue input, + SILType outputLoweredTy) { auto output = translatePrimitive(inputOrigType, inputSubstType, - outputOrigType, outputSubstType, input); + outputOrigType, outputSubstType, + input, outputLoweredTy); // If our output is guaranteed or unowned, we need to create a copy here. if (output.getOwnershipKind() != ValueOwnershipKind::Owned) @@ -1389,9 +1418,12 @@ namespace { void translateIntoGuaranteed(AbstractionPattern inputOrigType, CanType inputSubstType, AbstractionPattern outputOrigType, - CanType outputSubstType, ManagedValue input) { + CanType outputSubstType, + ManagedValue input, + SILType outputLoweredTy) { auto output = translatePrimitive(inputOrigType, inputSubstType, - outputOrigType, outputSubstType, input); + outputOrigType, outputSubstType, + input, outputLoweredTy); // If our output value is not guaranteed, we need to: // @@ -1422,8 +1454,9 @@ namespace { CanType outputSubstType, ManagedValue input, SILParameterInfo result) { + auto resultTy = SGF.getSILType(result, OutputTypesFuncTy); // Easy case: we want to pass exactly this value. - if (input.getType() == SGF.getSILType(result, CanSILFunctionType())) { + if (input.getType() == resultTy) { switch (result.getConvention()) { case ParameterConvention::Direct_Owned: case ParameterConvention::Indirect_In: @@ -1445,38 +1478,30 @@ namespace { case ParameterConvention::Direct_Owned: case ParameterConvention::Direct_Unowned: translateIntoOwned(inputOrigType, inputSubstType, outputOrigType, - outputSubstType, input); - assert(Outputs.back().getType() == SGF.getSILType(result, - CanSILFunctionType())); + outputSubstType, input, resultTy); return; case ParameterConvention::Direct_Guaranteed: translateIntoGuaranteed(inputOrigType, inputSubstType, outputOrigType, - outputSubstType, input); + outputSubstType, input, resultTy); return; case ParameterConvention::Indirect_In: { if (SGF.silConv.useLoweredAddresses()) { translateIndirect(inputOrigType, inputSubstType, outputOrigType, - outputSubstType, input, - SGF.getSILType(result, CanSILFunctionType())); + outputSubstType, input, resultTy); return; } translateIntoOwned(inputOrigType, inputSubstType, outputOrigType, - outputSubstType, input); - assert(Outputs.back().getType() == - SGF.getSILType(result, CanSILFunctionType())); + outputSubstType, input, resultTy); return; } case ParameterConvention::Indirect_In_Guaranteed: { if (SGF.silConv.useLoweredAddresses()) { translateIndirect(inputOrigType, inputSubstType, outputOrigType, - outputSubstType, input, - SGF.getSILType(result, CanSILFunctionType())); + outputSubstType, input, resultTy); return; } translateIntoGuaranteed(inputOrigType, inputSubstType, outputOrigType, - outputSubstType, input); - assert(Outputs.back().getType() == - SGF.getSILType(result, CanSILFunctionType())); + outputSubstType, input, resultTy); return; } case ParameterConvention::Indirect_Inout: @@ -1497,14 +1522,15 @@ namespace { CanType outputSubstType, ManagedValue input, SILParameterInfo result) { + auto resultTy = SGF.getSILType(result, OutputTypesFuncTy); assert(input.isLValue()); - if (input.getType() == SGF.getSILType(result, CanSILFunctionType())) { + if (input.getType() == resultTy) { Outputs.push_back(input); return; } // Create a temporary of the right type. - auto &temporaryTL = SGF.getTypeLowering(result.getInterfaceType()); + auto &temporaryTL = SGF.getTypeLowering(resultTy); auto temporary = SGF.emitTemporary(Loc, temporaryTL); // Take ownership of the input value. This leaves the input l-value @@ -1551,7 +1577,8 @@ namespace { TemporaryInitialization &temp) { auto output = translatePrimitive(inputOrigType, inputSubstType, outputOrigType, outputSubstType, - input, SGFContext(&temp)); + input, temp.getAddress()->getType(), + SGFContext(&temp)); forceInto(output, temp); } @@ -1561,11 +1588,12 @@ namespace { AbstractionPattern outputOrigType, CanType outputSubstType, ManagedValue input, + SILType loweredOutputTy, SGFContext context = SGFContext()) { return SGF.emitTransformedValue(Loc, input, inputOrigType, inputSubstType, outputOrigType, outputSubstType, - context); + loweredOutputTy, context); } /// Force the given result into the given initialization. @@ -1742,6 +1770,7 @@ static void translateYields(SILGenFunction &SGF, SILLocation loc, // Translate the yields as if they were arguments. SmallVector outerMVs; TranslateArguments translator(SGF, loc, innerMVs, outerMVs, + CanSILFunctionType(), outerLoweredTypesAsParameters); translator.translate(innerInfos.getOrigTypes(), innerInfos.getSubstTypes(), @@ -2763,9 +2792,15 @@ void ResultPlanner::execute(ArrayRef innerDirectResults, // Set up the context into which to emit the outer result. SGFContext outerResultCtxt; Optional outerResultInit; + SILType outerResultTy; if (outerIsIndirect) { + outerResultTy = op.OuterResultAddr->getType(); outerResultInit.emplace(op.OuterResultAddr, CleanupHandle::invalid()); outerResultCtxt = SGFContext(&*outerResultInit); + } else { + outerResultTy = + SGF.F.mapTypeIntoContext( + SGF.getSILType(op.OuterResult, CanSILFunctionType())); } // Perform the translation. @@ -2773,7 +2808,7 @@ void ResultPlanner::execute(ArrayRef innerDirectResults, SGF.emitTransformedValue(Loc, innerResult, op.InnerOrigType, op.InnerSubstType, op.OuterOrigType, op.OuterSubstType, - outerResultCtxt); + outerResultTy, outerResultCtxt); // If the outer is indirect, force it into the context. if (outerIsIndirect) { @@ -2911,7 +2946,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc, // other direction (the thunk receives an Int like a T, and passes it // like a normal Int when calling the inner function). SmallVector args; - TranslateArguments(SGF, loc, params, args, argTypes) + TranslateArguments(SGF, loc, params, args, fnType, argTypes) .translate(outputOrigType, outputSubstType.getParams(), inputOrigType, @@ -2973,7 +3008,8 @@ buildThunkSignature(SILGenFunction &SGF, // If there's no opened existential, we just inherit the generic environment // from the parent function. if (openedExistential == nullptr) { - auto genericSig = SGF.F.getLoweredFunctionType()->getSubstGenericSignature(); + auto genericSig = + SGF.F.getLoweredFunctionType()->getInvocationGenericSignature(); genericEnv = SGF.F.getGenericEnvironment(); interfaceSubs = SGF.F.getForwardingSubstitutionMap(); contextSubs = interfaceSubs; @@ -2984,7 +3020,8 @@ buildThunkSignature(SILGenFunction &SGF, int depth = 0; GenericSignature baseGenericSig; if (inheritGenericSig) { - if (auto genericSig = SGF.F.getLoweredFunctionType()->getSubstGenericSignature()) { + if (auto genericSig = + SGF.F.getLoweredFunctionType()->getInvocationGenericSignature()) { baseGenericSig = genericSig; depth = genericSig->getGenericParams().back()->getDepth() + 1; } @@ -3008,7 +3045,7 @@ buildThunkSignature(SILGenFunction &SGF, // Calculate substitutions to map the caller's archetypes to the thunk's // archetypes. if (auto calleeGenericSig = SGF.F.getLoweredFunctionType() - ->getSubstGenericSignature()) { + ->getInvocationGenericSignature()) { contextSubs = SubstitutionMap::get( calleeGenericSig, [&](SubstitutableType *type) -> Type { @@ -3042,8 +3079,10 @@ CanSILFunctionType SILGenFunction::buildThunkType( bool withoutActuallyEscaping) { // We shouldn't be thunking generic types here, and substituted function types // ought to have their substitutions applied before we get here. - assert(!expectedType->isPolymorphic() && !expectedType->getSubstitutions()); - assert(!sourceType->isPolymorphic() && !sourceType->getSubstitutions()); + assert(!expectedType->isPolymorphic() && + !expectedType->getCombinedSubstitutions()); + assert(!sourceType->isPolymorphic() && + !sourceType->getCombinedSubstitutions()); // Can't build a thunk without context, so we require ownership semantics // on the result type. @@ -3093,36 +3132,40 @@ CanSILFunctionType SILGenFunction::buildThunkType( newArchetype); } + auto substTypeHelper = [&](SubstitutableType *type) -> Type { + if (CanType(type) == openedExistential) + return newArchetype; + return Type(type).subst(contextSubs); + }; + auto substConformanceHelper = + LookUpConformanceInSubstitutionMap(contextSubs); + // Utility function to apply contextSubs, and also replace the // opened existential with the new archetype. - auto substIntoThunkContext = [&](CanType t) -> CanType { - return t.subst( - [&](SubstitutableType *type) -> Type { - if (CanType(type) == openedExistential) - return newArchetype; - return Type(type).subst(contextSubs); - }, - LookUpConformanceInSubstitutionMap(contextSubs), - SubstFlags::AllowLoweredTypes) - ->getCanonicalType(); + auto substFormalTypeIntoThunkContext = + [&](CanType t) -> CanType { + return t.subst(substTypeHelper, substConformanceHelper) + ->getCanonicalType(); + }; + auto substLoweredTypeIntoThunkContext = + [&](CanSILFunctionType t) -> CanSILFunctionType { + return SILType::getPrimitiveObjectType(t) + .subst(SGM.M, substTypeHelper, substConformanceHelper) + .castTo(); }; - sourceType = cast( - substIntoThunkContext(sourceType)); - expectedType = cast( - substIntoThunkContext(expectedType)); + sourceType = substLoweredTypeIntoThunkContext(sourceType); + expectedType = substLoweredTypeIntoThunkContext(expectedType); bool hasDynamicSelf = false; if (inputSubstType) { - inputSubstType = cast( - substIntoThunkContext(inputSubstType)); + inputSubstType = substFormalTypeIntoThunkContext(inputSubstType); hasDynamicSelf |= inputSubstType->hasDynamicSelfType(); } if (outputSubstType) { - outputSubstType = cast( - substIntoThunkContext(outputSubstType)); + outputSubstType = substFormalTypeIntoThunkContext(outputSubstType); hasDynamicSelf |= outputSubstType->hasDynamicSelfType(); } @@ -3159,40 +3202,35 @@ CanSILFunctionType SILGenFunction::buildThunkType( params.push_back({dynamicSelfType, ParameterConvention::Direct_Unowned}); } + auto mapTypeOutOfContext = [&](CanType type) -> CanType { + return type->mapTypeOutOfContext()->getCanonicalType(genericSig); + }; + // Map the parameter and expected types out of context to get the interface // type of the thunk. SmallVector interfaceParams; interfaceParams.reserve(params.size()); for (auto ¶m : params) { - auto paramIfaceTy = param.getInterfaceType()->mapTypeOutOfContext(); - interfaceParams.push_back( - SILParameterInfo(paramIfaceTy->getCanonicalType(genericSig), - param.getConvention())); + auto interfaceParam = param.map(mapTypeOutOfContext); + interfaceParams.push_back(interfaceParam); } SmallVector interfaceYields; for (auto &yield : expectedType->getYields()) { - auto yieldIfaceTy = yield.getInterfaceType()->mapTypeOutOfContext(); - auto interfaceYield = - yield.getWithInterfaceType(yieldIfaceTy->getCanonicalType(genericSig)); + auto interfaceYield = yield.map(mapTypeOutOfContext); interfaceYields.push_back(interfaceYield); } SmallVector interfaceResults; for (auto &result : expectedType->getResults()) { - auto resultIfaceTy = result.getInterfaceType()->mapTypeOutOfContext(); - auto interfaceResult = - result.getWithInterfaceType(resultIfaceTy->getCanonicalType(genericSig)); + auto interfaceResult = result.map(mapTypeOutOfContext); interfaceResults.push_back(interfaceResult); } Optional interfaceErrorResult; if (expectedType->hasErrorResult()) { auto errorResult = expectedType->getErrorResult(); - auto errorIfaceTy = errorResult.getInterfaceType()->mapTypeOutOfContext(); - interfaceErrorResult = SILResultInfo( - errorIfaceTy->getCanonicalType(genericSig), - expectedType->getErrorResult().getConvention()); + interfaceErrorResult = errorResult.map(mapTypeOutOfContext);; } // The type of the thunk function. @@ -3201,8 +3239,8 @@ CanSILFunctionType SILGenFunction::buildThunkType( ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, - expectedType->getSubstitutions(), - expectedType->isGenericSignatureImplied(), + expectedType->getPatternSubstitutions(), + SubstitutionMap(), getASTContext()); } @@ -3243,7 +3281,7 @@ static ManagedValue createThunk(SILGenFunction &SGF, // Apply substitutions in the source and destination types, since the thunk // doesn't change because of different function representations. CanSILFunctionType sourceType; - if (substSourceType->getSubstitutions()) { + if (substSourceType->getPatternSubstitutions()) { sourceType = substSourceType->getUnsubstitutedType(SGF.SGM.M); fn = SGF.B.createConvertFunction(loc, fn, SILType::getPrimitiveObjectType(sourceType)); @@ -3514,11 +3552,19 @@ SILGenFunction::emitOrigToSubstValue(SILLocation loc, ManagedValue v, AbstractionPattern origType, CanType substType, SGFContext ctxt) { - + return emitOrigToSubstValue(loc, v, origType, substType, + getLoweredType(substType), ctxt); +} +ManagedValue +SILGenFunction::emitOrigToSubstValue(SILLocation loc, ManagedValue v, + AbstractionPattern origType, + CanType substType, + SILType loweredResultTy, + SGFContext ctxt) { return emitTransformedValue(loc, v, origType, substType, AbstractionPattern(substType), substType, - ctxt); + loweredResultTy, ctxt); } /// Given a value with the abstraction patterns of the original formal @@ -3527,10 +3573,18 @@ RValue SILGenFunction::emitOrigToSubstValue(SILLocation loc, RValue &&v, AbstractionPattern origType, CanType substType, SGFContext ctxt) { + return emitOrigToSubstValue(loc, std::move(v), origType, substType, + getLoweredType(substType), ctxt); +} +RValue SILGenFunction::emitOrigToSubstValue(SILLocation loc, RValue &&v, + AbstractionPattern origType, + CanType substType, + SILType loweredResultTy, + SGFContext ctxt) { return emitTransformedValue(loc, std::move(v), origType, substType, AbstractionPattern(substType), substType, - ctxt); + loweredResultTy, ctxt); } /// Given a value with the abstraction patterns of the substituted @@ -3541,10 +3595,20 @@ SILGenFunction::emitSubstToOrigValue(SILLocation loc, ManagedValue v, AbstractionPattern origType, CanType substType, SGFContext ctxt) { + return emitSubstToOrigValue(loc, v, origType, substType, + getLoweredType(origType, substType), ctxt); +} + +ManagedValue +SILGenFunction::emitSubstToOrigValue(SILLocation loc, ManagedValue v, + AbstractionPattern origType, + CanType substType, + SILType loweredResultTy, + SGFContext ctxt) { return emitTransformedValue(loc, v, AbstractionPattern(substType), substType, origType, substType, - ctxt); + loweredResultTy, ctxt); } /// Given a value with the abstraction patterns of the substituted @@ -3554,10 +3618,19 @@ RValue SILGenFunction::emitSubstToOrigValue(SILLocation loc, RValue &&v, AbstractionPattern origType, CanType substType, SGFContext ctxt) { + return emitSubstToOrigValue(loc, std::move(v), origType, substType, + getLoweredType(origType, substType), ctxt); +} + +RValue SILGenFunction::emitSubstToOrigValue(SILLocation loc, RValue &&v, + AbstractionPattern origType, + CanType substType, + SILType loweredResultTy, + SGFContext ctxt) { return emitTransformedValue(loc, std::move(v), AbstractionPattern(substType), substType, origType, substType, - ctxt); + loweredResultTy, ctxt); } ManagedValue @@ -3601,6 +3674,7 @@ SILGenFunction::emitTransformedValue(SILLocation loc, ManagedValue v, return emitTransformedValue(loc, v, AbstractionPattern(inputType), inputType, AbstractionPattern(outputType), outputType, + getLoweredType(outputType), ctxt); } @@ -3610,12 +3684,14 @@ SILGenFunction::emitTransformedValue(SILLocation loc, ManagedValue v, CanType inputSubstType, AbstractionPattern outputOrigType, CanType outputSubstType, + SILType outputLoweredTy, SGFContext ctxt) { return Transform(*this, loc).transform(v, inputOrigType, inputSubstType, outputOrigType, - outputSubstType, ctxt); + outputSubstType, + outputLoweredTy, ctxt); } RValue @@ -3624,12 +3700,14 @@ SILGenFunction::emitTransformedValue(SILLocation loc, RValue &&v, CanType inputSubstType, AbstractionPattern outputOrigType, CanType outputSubstType, + SILType outputLoweredTy, SGFContext ctxt) { return Transform(*this, loc).transform(std::move(v), inputOrigType, inputSubstType, outputOrigType, - outputSubstType, ctxt); + outputSubstType, + outputLoweredTy, ctxt); } //===----------------------------------------------------------------------===// @@ -3665,7 +3743,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base, } auto subs = getForwardingSubstitutionMap(); - if (auto genericSig = derivedFTy->getSubstGenericSignature()) { + if (auto genericSig = derivedFTy->getInvocationGenericSignature()) { subs = SubstitutionMap::get(genericSig, subs); derivedFTy = @@ -3688,7 +3766,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base, // Reabstract the arguments. TranslateArguments(*this, loc, thunkArgs, substArgs, - derivedFTy->getParameters()) + derivedFTy, derivedFTy->getParameters()) .translate(inputOrigType, inputSubstType.getParams(), outputOrigType, @@ -3988,7 +4066,7 @@ void SILGenFunction::emitProtocolWitness(AbstractionPattern reqtOrigTy, AbstractionPattern witnessOrigTy(witnessInfo.LoweredType); TranslateArguments(*this, loc, origParams, witnessParams, - witnessUnsubstTy->getParameters()) + witnessUnsubstTy, witnessUnsubstTy->getParameters()) .translate(reqtOrigTy, reqtSubstParams, witnessOrigTy, diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index ca420cb1a55aa..cf937dbe5ddcc 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -211,7 +211,8 @@ void SILGenFunction::emitCurryThunk(SILDeclRef thunk) { toClosure = emitTransformedValue(loc, toClosure, appliedFnPattern, formalType, - appliedThunkPattern, formalType); + appliedThunkPattern, formalType, + resultTy); } } toClosure = S.popPreservingValue(toClosure); diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index e4ff2fc528cb6..23ee52279a411 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -749,7 +749,7 @@ static SILFunction *emitSelfConformanceWitness(SILGenModule &SGM, auto protocolType = protocol->getDeclaredInterfaceType(); auto reqtSubs = SubstitutionMap::getProtocolSubstitutions(protocol, protocolType, - ProtocolConformanceRef(protocol)); + ProtocolConformanceRef(conformance)); // Open the protocol type. auto openedType = OpenedArchetypeType::get(protocolType); diff --git a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp index 29b8422b8d676..353b63023702d 100644 --- a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp @@ -701,8 +701,11 @@ bool AliasAnalysis::canBuiltinDecrementRefCount(BuiltinInst *BI, SILValue Ptr) { continue; // A builtin can only release an object if it can escape to one of the - // builtin's arguments. - if (EA->mayReleaseContent(Arg, Ptr)) + // builtin's arguments. 'EscapeAnalysis::mayReleaseContent()' expects 'Arg' + // to be an owned reference and disallows addresses. Conservatively handle + // address type arguments as and conservatively treat all other values + // potential owned references. + if (Arg->getType().isAddress() || EA->mayReleaseContent(Arg, Ptr)) return true; } return false; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 108a2545e1f60..20d9f13dca4ca 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -381,7 +381,7 @@ ExistentialTransform::createExistentialSpecializedFunctionType() { NewGenericSig, ExtInfo, FTy->getCoroutineKind(), FTy->getCalleeConvention(), InterfaceParams, FTy->getYields(), FTy->getResults(), InterfaceErrorResult, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), Ctx, witnessMethodConformance); } diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 92e6036afb92d..909b9fbd80956 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -204,15 +204,26 @@ static bool usesGenerics(SILFunction *F, ArrayRef InterfaceParams, ArrayRef InterfaceResults) { CanSILFunctionType FTy = F->getLoweredFunctionType(); - auto HasGenericSignature = FTy->getSubstGenericSignature() != nullptr; + auto HasGenericSignature = FTy->getInvocationGenericSignature() != nullptr; if (!HasGenericSignature) return false; bool UsesGenerics = false; - auto FindArchetypesAndGenericTypes = [&UsesGenerics](Type Ty) { - if (Ty.findIf([](Type Ty) -> bool { - return (Ty->hasTypeParameter() || Ty->hasArchetype()); + auto FindArchetypesAndGenericTypes = [FTy, &UsesGenerics](Type Ty) { + if (Ty.findIf([FTy](Type Ty) -> bool { + // Assume archetypes are always a problem. + // TODO: This can ignore non-contextual archetypes. + if (Ty->hasArchetype()) return true; + + // Assume type parameters are always a problem. However, this + // can ignore types that would substitute to concrete types. + if (Ty->isTypeParameter()) { + auto subs = FTy->getPatternSubstitutions(); + return (!subs || Ty.subst(subs)->isTypeParameter()); + } + + return false; })) UsesGenerics = true; }; @@ -394,12 +405,12 @@ FunctionSignatureTransformDescriptor::createOptimizedSILFunctionType() { mapInterfaceTypes(F, InterfaceParams, InterfaceResults, InterfaceErrorResult); GenericSignature GenericSig = - UsesGenerics ? FTy->getSubstGenericSignature() : nullptr; + UsesGenerics ? FTy->getInvocationGenericSignature() : nullptr; return SILFunctionType::get( GenericSig, ExtInfo, FTy->getCoroutineKind(), FTy->getCalleeConvention(), InterfaceParams, InterfaceYields, InterfaceResults, InterfaceErrorResult, - FTy->getSubstitutions(), FTy->isGenericSignatureImplied(), + FTy->getPatternSubstitutions(), SubstitutionMap(), F->getModule().getASTContext(), witnessMethodConformance); } @@ -499,7 +510,7 @@ void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() { auto NewFTy = TransformDescriptor.createOptimizedSILFunctionType(); GenericEnvironment *NewFGenericEnv; - if (NewFTy->getSubstGenericSignature()) { + if (NewFTy->getInvocationGenericSignature()) { NewFGenericEnv = F->getGenericEnvironment(); } else { NewFGenericEnv = nullptr; diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp index 2bb212748025c..6c8245e71f5a0 100644 --- a/lib/SILOptimizer/IPO/CapturePromotion.cpp +++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp @@ -429,7 +429,7 @@ ClosureCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, OrigFTI->getInvocationGenericSignature(), OrigFTI->getExtInfo(), OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys, OrigFTI->getYields(), OrigFTI->getResults(), - OrigFTI->getOptionalErrorResult(), SubstitutionMap(), false, + OrigFTI->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrInvalid()); assert((Orig->isTransparent() || Orig->isBare() || Orig->getLocation()) diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index 6adcf3bd88da2..2330cddf381ff 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -665,13 +665,13 @@ ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, ExtInfo = ExtInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); auto ClonedTy = SILFunctionType::get( - ClosureUserFunTy->getSubstGenericSignature(), ExtInfo, + ClosureUserFunTy->getInvocationGenericSignature(), ExtInfo, ClosureUserFunTy->getCoroutineKind(), ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList, ClosureUserFunTy->getYields(), ClosureUserFunTy->getResults(), ClosureUserFunTy->getOptionalErrorResult(), - ClosureUserFunTy->getSubstitutions(), - ClosureUserFunTy->isGenericSignatureImplied(), + ClosureUserFunTy->getPatternSubstitutions(), + ClosureUserFunTy->getInvocationSubstitutions(), M.getASTContext()); // We make this function bare so we don't have to worry about decls in the diff --git a/lib/SILOptimizer/IPO/EagerSpecializer.cpp b/lib/SILOptimizer/IPO/EagerSpecializer.cpp index 9b0156909a7b6..984b58310ffcb 100644 --- a/lib/SILOptimizer/IPO/EagerSpecializer.cpp +++ b/lib/SILOptimizer/IPO/EagerSpecializer.cpp @@ -736,9 +736,12 @@ void EagerSpecializerTransform::run() { // Process functions in any order. for (auto &F : *getModule()) { - if (!F.shouldOptimize()) { + // TODO: we should support ownership here but first we'll have to support + // ownership in GenericFuncSpecializer. + if (!F.shouldOptimize() || F.hasOwnership()) { LLVM_DEBUG(dbgs() << " Cannot specialize function " << F.getName() - << " marked to be excluded from optimizations.\n"); + << " because it has ownership or is marked to be " + "excluded from optimizations.\n"); continue; } // Only specialize functions in their home module. diff --git a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp index b5e04745c4b79..60e8ec9c3bb4b 100644 --- a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp +++ b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// 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 @@ -16,7 +16,96 @@ // if this pass can prove that it has analyzed all assignments of an initial // value to this property and all those assignments assign the same value // to this property. -//===----------------------------------------------------------------------===// +// +// FIXME: +// +// This pass makes assumptions about the visibility of a type's memory +// based on the visibility of its properties. This is the wrong way to think +// about memory visibility. +// +// This pass wants assume that the contents of a property is known based on +// whether the property is declared as a 'let' and the visibility of the +// initializers that access the property. For example: +// +// public struct X { +// public let hidden: T +// +// init(t: T) { self.hidden = t } +// } +// +// The pass currently assumes that `X` only takes on values that are +// assigned by the invocations of `X.init`, which is only visible in `X`s +// module. This is wrong if the layout of `Impl` is exposed to other +// modules. A struct's memory may be initialized by any module with +// access to the struct's layout. +// +// In fact, this assumption is wrong even if the struct, and it's let +// property cannot be accessed externally by name. In this next example, +// external modules cannot access `Impl` or `Impl.hidden` by name, but +// can still access the memory because the layout is exposed via a public type +// that contains it. +// +// ``` +// internal struct Impl { +// let hidden: T +// +// init(t: T) { self.hidden = t } +// } +// +// public struct Wrapper { +// var impl: Impl +// +// public var property: T { +// get { +// return impl.hidden +// } +// } +// } +// ``` +// +// As long as `Wrapper`s layout is exposed to other modules, the contents of +// `Wrapper`, `Impl`, and `hidden' can all be initialized in another +// module. This following code is legal if Wrapper's home module is *not* +// built with library evolution (or if Wrapper is declared `@frozen`). +// +// func inExternalModule(buffer: UnsafeRawPointer) -> Wrapper { +// return buffer.load(as: Wrapper.self) +// } +// +// If library evolution is enabled and a `public` struct is not declared +// `@frozen` then external modules cannot assume its layout, and therefore +// cannot initialize the struct memory. In that case, it is possible to optimize +// `X.hidden` and `Impl.hidden` as if the properties are only initialized inside +// their home module. +// +// The right way to view a type's memory visibility is to consider whether +// external modules have access to the layout of the type. If not, then the +// property can still be optimized As long as a struct is never enclosed in a +// public effectively-`@frozen` type. However, finding all places where a struct +// is explicitly created is still insufficient. Instead, the optimization needs +// to find all uses of enclosing types and determine if every use has a known +// constant initialization, or is simply copied from another value. If an +// escaping unsafe pointer to any enclosing type is created, then the +// optimization is not valid. +// +// When viewed this way, the fact that a property is declared 'let' is mostly +// irrelevant to this optimization--it can be expanded to handle non-'let' +// properties. The more salient feature is whether the propery has a public +// setter. +// +// For now, this optimization only recognizes class properties because class +// properties are only accessibly via a ref_element_addr instruction. This is a +// side effect of the fact that accessing a class property requires a "formal +// access". This means that begin_access marker must be emitted directly on the +// address produced by a ref_element_addr. Struct properties are not handled, as +// explained above, because they can be indirectly accessed via addresses of +// outer types. +// +// Note: Propagating the initialized constants of non-addressable aggregate +// values (formation of 'struct's and 'tuple's) is a significantly different +// problem. It can be done better in a separate constant-propagation pass that +// propagates partial-constants into call arguments and out of returned values. +// ===---------------------------------------------------------------------===// #define DEBUG_TYPE "let-properties-opt" #include "swift/SIL/DebugUtils.h" @@ -53,9 +142,9 @@ struct InitSequence { /// TODO: Don't occupy any storage for such let properties with constant /// initializers. /// -/// Note: Storage from a let property can only be removed if this -/// property can never be referenced from another module. - +/// Note: Storage from a 'let' property can only be removed if this property if +/// the type is resilient (not fixed-layout) and the property cannot be read +/// from another module. class LetPropertiesOpt { SILModule *Module; @@ -88,8 +177,8 @@ class LetPropertiesOpt { protected: bool isConstantLetProperty(VarDecl *Property); - void collectPropertyAccess(SILInstruction *I, VarDecl *Property, bool NonRemovable); - void collectStructPropertiesAccess(StructInst *SI, bool NonRemovable); + void collectPropertyAccess(SingleValueInstruction *I, VarDecl *Property, + bool NonRemovable); void optimizeLetPropertyAccess(VarDecl *SILG, const InitSequence &Init); bool analyzeInitValue(SILInstruction *I, VarDecl *Prop); }; @@ -204,44 +293,25 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property, }; // Look for any instructions accessing let properties. - if (isa(Load) || isa(Load) || - isa(Load) || isa(Load)) { - auto proj = cast(Load); - - // Copy the initializer into the function - // Replace the access to a let property by the value - // computed by this initializer. - SILValue clonedInit = cloneInitAt(proj); - for (auto UI = proj->use_begin(), E = proj->use_end(); UI != E;) { - auto *User = UI->getUser(); - ++UI; - - // A nested begin_access will be mapped as a separate "Load". - if (isa(User) || isa(User)) - continue; - - if (!canReplaceLoadSequence(User)) - continue; - - replaceLoadSequence(User, clonedInit); - eraseUsesOfInstruction(User); - User->eraseFromParent(); - ++NumReplaced; - } - ChangedFunctions.insert(F); - } else if (auto proj = dyn_cast(Load)) { - // Copy the initializer into the function - // Replace the access to a let property by the value - // computed by this initializer. - SILValue clonedInit = cloneInitAt(proj); - proj->replaceAllUsesWith(clonedInit); - LLVM_DEBUG(llvm::dbgs() << "Access to " << *Property <<" was replaced:\n"; - clonedInit->dumpInContext()); - - proj->eraseFromParent(); + auto *proj = cast(Load); + + // Copy the initializer into the function + // Replace the access to a let property by the value + // computed by this initializer. + SILValue clonedInit = cloneInitAt(proj); + for (auto UI = proj->use_begin(), E = proj->use_end(); UI != E;) { + auto *User = UI->getUser(); + ++UI; + + if (!canReplaceLoadSequence(User)) + continue; + + replaceLoadSequence(User, clonedInit); + eraseUsesOfInstruction(User); + User->eraseFromParent(); ++NumReplaced; - ChangedFunctions.insert(F); } + ChangedFunctions.insert(F); } LLVM_DEBUG(llvm::dbgs() << "Access to " << *Property << " was replaced " @@ -379,12 +449,10 @@ bool LetPropertiesOpt::isConstantLetProperty(VarDecl *Property) { } static bool isProjectionOfProperty(SILValue addr, VarDecl *Property) { + addr = stripAccessMarkers(addr); if (auto *REA = dyn_cast(addr)) { return REA->getField() == Property; } - if (auto *SEA = dyn_cast(addr)) { - return SEA->getField() == Property; - } return false; } @@ -392,19 +460,19 @@ static bool isProjectionOfProperty(SILValue addr, VarDecl *Property) { bool LetPropertiesOpt::analyzeInitValue(SILInstruction *I, VarDecl *Property) { SILValue value; - if (auto SI = dyn_cast(I)) { - value = SI->getFieldValue(Property); - } else if (auto SI = dyn_cast(I)) { - auto Dest = stripAccessMarkers(SI->getDest()); - - assert(isProjectionOfProperty(stripAccessMarkers(SI->getDest()), Property) - && "Store instruction should store into a proper let property"); - (void) Dest; + SILValue dest; + if (auto SI = dyn_cast(I)) { + dest = stripAccessMarkers(SI->getDest()); value = SI->getSrc(); } else if (auto *copyAddr = dyn_cast(I)) { + dest = stripAccessMarkers(copyAddr->getDest()); value = copyAddr->getSrc(); + } else { + return false; } - + assert(isProjectionOfProperty(dest, Property) + && "Store instruction should store into a proper let property"); + (void)dest; // Check if it's just a copy from another instance of the struct. if (auto *LI = dyn_cast(value)) { SILValue addr = LI->getOperand(); @@ -432,61 +500,6 @@ LetPropertiesOpt::analyzeInitValue(SILInstruction *I, VarDecl *Property) { } } -// Analyze the 'struct' instruction and check if it initializes -// any let properties by statically known constant initializers. -void LetPropertiesOpt::collectStructPropertiesAccess(StructInst *SI, - bool NonRemovable) { - auto structDecl = SI->getStructDecl(); - // Check if this struct has any let properties. - - // Bail, if this struct is known to contain nothing interesting. - if (SkipTypeProcessing.count(structDecl)) - return; - - // Get the set of let properties defined by this struct. - if (!NominalTypeLetProperties.count(structDecl)) { - // Compute the let properties of this struct. - SmallVector LetProps; - - for (auto Prop : structDecl->getStoredProperties()) { - if (!isConstantLetProperty(Prop)) - continue; - LetProps.push_back(Prop); - } - - if (LetProps.empty()) { - // No interesting let properties in this struct. - SkipTypeProcessing.insert(structDecl); - return; - } - - NominalTypeLetProperties[structDecl] = LetProps; - LLVM_DEBUG(llvm::dbgs() << "Computed set of let properties for struct '" - << structDecl->getName() << "'\n"); - } - - auto &Props = NominalTypeLetProperties[structDecl]; - - LLVM_DEBUG(llvm::dbgs() << "Found a struct instruction initializing some " - "let properties: "; - SI->dumpInContext()); - // Figure out the initializing sequence for each - // of the properties. - for (auto Prop : Props) { - if (SkipProcessing.count(Prop)) - continue; - SILValue PropValue = SI->getOperandForField(Prop)->get(); - LLVM_DEBUG(llvm::dbgs() << "Check the value of property '" << *Prop - << "' :" << PropValue << "\n"); - if (!analyzeInitValue(SI, Prop)) { - SkipProcessing.insert(Prop); - LLVM_DEBUG(llvm::dbgs() << "The value of a let property '" << *Prop - << "' is not statically known\n"); - } - (void) PropValue; - } -} - /// Check if I is a sequence of projections followed by a load. /// Since it is supposed to be a load from a let property with /// statically known constant initializer, only struct_element_addr @@ -495,7 +508,8 @@ static bool isValidPropertyLoad(SILInstruction *I) { if (isa(I)) return true; - if (isa(I) || isa(I)) { + if (isa(I) || isa(I) + || isa(I)) { auto projection = cast(I); for (auto Use : getNonDebugUses(projection)) { if (isIncidentalUse(Use->getUser())) @@ -511,7 +525,7 @@ static bool isValidPropertyLoad(SILInstruction *I) { /// Remember where this property is accessed. -void LetPropertiesOpt::collectPropertyAccess(SILInstruction *I, +void LetPropertiesOpt::collectPropertyAccess(SingleValueInstruction *I, VarDecl *Property, bool NonRemovable) { if (!isConstantLetProperty(Property)) @@ -521,23 +535,24 @@ void LetPropertiesOpt::collectPropertyAccess(SILInstruction *I, << *Property << "':\n"; llvm::dbgs() << "The instructions are:\n"; I->dumpInContext()); - if (isa(I) || isa(I) || - isa(I) || isa(I) || - isa(I)) { + // Ignore the possibility of duplicate worklist entries. They cannot effect + // the SkipProcessing result, and we don't expect any exponential path + // explosion because none of the instructions have multiple address operands. + SmallVector worklist = {I}; + while (!worklist.empty()) { // Check if there is a store to this property. - auto projection = cast(I); + auto *projection = worklist.pop_back_val(); for (auto Use : getNonDebugUses(projection)) { auto *User = Use->getUser(); - if (isIncidentalUse(User)) + if (isIncidentalUse(User)) { continue; - - // Each begin_access is analyzed as a separate property access. Do not - // consider a begin_access a use of the current projection. - if (isa(User) || isa(I)) + } + if (auto *bai = dyn_cast(User)) { + worklist.push_back(bai); continue; - + } if (auto *copyAddr = dyn_cast(User)) { - if (copyAddr->getSrc() != projection || + if (copyAddr->getDest() != projection || !analyzeInitValue(copyAddr, Property)) { SkipProcessing.insert(Property); return; @@ -584,25 +599,10 @@ void LetPropertiesOpt::run(SILModuleTransform *T) { bool NonRemovable = !F.shouldOptimize(); for (auto &BB : F) { - for (auto &I : BB) - // Look for any instructions accessing let properties. - // It includes referencing this specific property (both reads and - // stores), as well as implicit stores by means of e.g. - // a struct instruction. - if (auto *BAI = dyn_cast(&I)) { - if (auto *REAI = - dyn_cast(stripAccessMarkers(BAI))) { - collectPropertyAccess(BAI, REAI->getField(), NonRemovable); - } - } else if (auto *REAI = dyn_cast(&I)) { + for (auto &I : BB) { + if (auto *REAI = dyn_cast(&I)) collectPropertyAccess(REAI, REAI->getField(), NonRemovable); - } else if (auto *SEI = dyn_cast(&I)) { - collectPropertyAccess(SEI, SEI->getField(), NonRemovable); - } else if (auto *SEAI = dyn_cast(&I)) { - collectPropertyAccess(SEAI, SEAI->getField(), NonRemovable); - } else if (auto *SI = dyn_cast(&I)) { - collectStructPropertiesAccess(SI, NonRemovable); - } + } } } diff --git a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp index 35c55ad1b8736..8902267199e4f 100644 --- a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp +++ b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp @@ -606,9 +606,8 @@ SILInstruction *getInstructionFollowingValueDefinition(SILValue value) { /// \p value is a trivial type, return the value itself. SILValue makeOwnedCopyOfSILValue(SILValue value, SILFunction &fun) { SILType type = value->getType(); - if (type.isTrivial(fun)) + if (type.isTrivial(fun) || type.isAddress()) return value; - assert(!type.isAddress() && "cannot make owned copy of addresses"); SILInstruction *instAfterValueDefinition = getInstructionFollowingValueDefinition(value); @@ -726,64 +725,66 @@ static SILValue emitCodeForSymbolicValue(SymbolicValue symVal, assert(expectedType->is() || expectedType->is()); - SymbolicClosure *closure = symVal.getClosure(); - SubstitutionMap callSubstMap = closure->getCallSubstitutionMap(); SILModule &module = builder.getModule(); - ArrayRef captures = closure->getCaptures(); - - // Recursively emit code for all captured values that are mapped to a - // symbolic value. If there is a captured value that is not mapped - // to a symbolic value, use the captured value as such (after possibly - // copying non-trivial captures). - SmallVector capturedSILVals; - for (SymbolicClosureArgument capture : captures) { - SILValue captureOperand = capture.first; - Optional captureSymVal = capture.second; - if (!captureSymVal) { - SILFunction &fun = builder.getFunction(); - assert(captureOperand->getFunction() == &fun && - "non-constant captured arugment not defined in this function"); - // If the captureOperand is a non-trivial value, it should be copied - // as it now used in a new folded closure. - SILValue captureCopy = makeOwnedCopyOfSILValue(captureOperand, fun); - capturedSILVals.push_back(captureCopy); - continue; + SymbolicClosure *closure = symVal.getClosure(); + SILValue resultVal; + if (!closure->hasOnlyConstantCaptures()) { + // If the closure captures a value that is not a constant, it should only + // come from the caller of the log call. Therefore, assert this and reuse + // the closure value. + SingleValueInstruction *originalClosureInst = closure->getClosureInst(); + SILFunction &fun = builder.getFunction(); + assert(originalClosureInst->getFunction() == &fun && + "closure with non-constant captures not defined in this function"); + // Copy the closure, since the returned value must be owned. + resultVal = makeOwnedCopyOfSILValue(originalClosureInst, fun); + } else { + SubstitutionMap callSubstMap = closure->getCallSubstitutionMap(); + ArrayRef captures = closure->getCaptures(); + // Recursively emit code for all captured values which must be mapped to a + // symbolic value. + SmallVector capturedSILVals; + for (SymbolicClosureArgument capture : captures) { + SILValue captureOperand = capture.first; + Optional captureSymVal = capture.second; + assert(captureSymVal); + // Note that the captured operand type may have generic parameters which + // has to be substituted with the substitution map that was inferred by + // the constant evaluator at the partial-apply site. + SILType operandType = captureOperand->getType(); + SILType captureType = operandType.subst(module, callSubstMap); + SILValue captureSILVal = emitCodeForSymbolicValue( + captureSymVal.getValue(), captureType.getASTType(), builder, loc, + stringInfo); + capturedSILVals.push_back(captureSILVal); } - // Here, we have a symbolic value for the capture. Therefore, use it to - // create a new constant at this point. Note that the captured operand - // type may have generic parameters which has to be substituted with the - // substitution map that was inferred by the constant evaluator at the - // partial-apply site. - SILType operandType = captureOperand->getType(); - SILType captureType = operandType.subst(module, callSubstMap); - SILValue captureSILVal = emitCodeForSymbolicValue( - captureSymVal.getValue(), captureType.getASTType(), builder, loc, - stringInfo); - capturedSILVals.push_back(captureSILVal); + FunctionRefInst *functionRef = + builder.createFunctionRef(loc, closure->getTarget()); + SILType closureType = closure->getClosureType(); + ParameterConvention convention = + closureType.getAs()->getCalleeConvention(); + resultVal = builder.createPartialApply(loc, functionRef, callSubstMap, + capturedSILVals, convention); } - - FunctionRefInst *functionRef = - builder.createFunctionRef(loc, closure->getTarget()); - SILType closureType = closure->getClosureType(); - ParameterConvention convention = - closureType.getAs()->getCalleeConvention(); - PartialApplyInst *papply = builder.createPartialApply( - loc, functionRef, callSubstMap, capturedSILVals, convention); - // The type of the created closure must be a lowering of the expected type. - auto resultType = papply->getType().castTo(); + // If the expected type is a SILFunctionType convert the closure to the + // expected type using a convert_function instruction. Otherwise, if the + // expected type is AnyFunctionType, nothing needs to be done. + // Note that we cannot assert the lowering in the latter case, as that + // utility doesn't exist yet. + auto resultType = resultVal->getType().castTo(); CanType expectedCanType = expectedType->getCanonicalType(); if (auto expectedFnType = dyn_cast(expectedCanType)) { assert(expectedFnType->getUnsubstitutedType(module) == resultType->getUnsubstitutedType(module)); // Convert to the expected type if necessary. if (expectedFnType != resultType) { - auto convert = builder.createConvertFunction(loc, papply, - SILType::getPrimitiveObjectType(expectedFnType), - false); + auto convert = builder.createConvertFunction( + loc, resultVal, SILType::getPrimitiveObjectType(expectedFnType), + false); return convert; } } - return papply; + return resultVal; } default: { llvm_unreachable("Symbolic value kind is not supported"); @@ -1329,6 +1330,17 @@ static SILInstruction *beginOfInterpolation(ApplyInst *oslogInit) { worklist.push_back(storeInst); candidateStartInstructions.insert(storeInst); } + // Skip other uses of alloc_stack including function calls on the + // alloc_stack and data dependenceis through them. This is done because + // all functions using the alloc_stack are expected to be constant evaluated + // and therefore should only be passed constants or auto closures. These + // constants must be constructed immediately before the call and would only + // appear in the SIL after the alloc_stack instruction. This invariant is + // relied upon here so as to restrict the backward dependency search, which + // in turn keeps the code that is constant evaluated small. + // Note that if the client code violates this assumption, it will be + // diagnosed by this pass (in function detectAndDiagnoseErrors) as it will + // result in non-constant values for OSLogMessage instance. } // Find the first basic block in the control-flow order. Typically, if @@ -1342,14 +1354,27 @@ static SILInstruction *beginOfInterpolation(ApplyInst *oslogInit) { } SILBasicBlock *firstBB = nullptr; - SILBasicBlock *entryBB = oslogInit->getFunction()->getEntryBlock(); - for (SILBasicBlock *bb: llvm::breadth_first(entryBB)) { - if (candidateBBs.count(bb)) { - firstBB = bb; - break; + if (candidateBBs.size() == 1) { + firstBB = *candidateBBs.begin(); + } else { + SILBasicBlock *entryBB = oslogInit->getFunction()->getEntryBlock(); + for (SILBasicBlock *bb : llvm::breadth_first(entryBB)) { + if (candidateBBs.count(bb)) { + firstBB = bb; + break; + } + } + if (!firstBB) { + // This case will be reached only if the log call appears in unreachable + // code and, for some reason, its data depedencies extend beyond a basic + // block. This case should generally not happen unless the library + // implementation of the os log APIs change. It is better to warn in this + // case, rather than skipping the call silently. + diagnose(callee->getASTContext(), oslogInit->getLoc().getSourceLoc(), + diag::oslog_call_in_unreachable_code); + return nullptr; } } - assert(firstBB); // Iterate over the instructions in the firstBB and find the instruction that // starts the interpolation. @@ -1360,7 +1385,7 @@ static SILInstruction *beginOfInterpolation(ApplyInst *oslogInit) { break; } } - assert(startInst); + assert(startInst && "could not find beginning of interpolation"); return startInst; } @@ -1450,7 +1475,10 @@ class OSLogOptimization : public SILFunctionTransform { // iteration. for (auto *oslogInit : oslogMessageInits) { SILInstruction *interpolationStart = beginOfInterpolation(oslogInit); - assert(interpolationStart); + if (!interpolationStart) { + // The log call is in unreachable code here. + continue; + } madeChange |= constantFold(interpolationStart, oslogInit, assertConfig); } diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index 61a868c6e5276..e02810668e55c 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -765,82 +765,82 @@ SILPassPipelinePlan::getPassPipelineForKinds(const SILOptions &Options, // Dumping And Loading Pass Pipelines from Yaml //===----------------------------------------------------------------------===// +namespace { + +struct YAMLPassPipeline { + std::string name; + std::vector passes; + + YAMLPassPipeline() {} + YAMLPassPipeline(const SILPassPipeline &pipeline, + SILPassPipelinePlan::PipelineKindRange pipelineKinds) + : name(pipeline.Name), passes() { + llvm::copy(pipelineKinds, std::back_inserter(passes)); + } +}; + +} // end anonymous namespace + +namespace llvm { +namespace yaml { + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, PassKind &value) { +#define PASS(ID, TAG, NAME) io.enumCase(value, #TAG, PassKind::ID); +#include "swift/SILOptimizer/PassManager/Passes.def" + } +}; + +template <> struct MappingTraits { + static void mapping(IO &io, YAMLPassPipeline &info) { + io.mapRequired("name", info.name); + io.mapRequired("passes", info.passes); + } +}; + +} // namespace yaml +} // namespace llvm + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(PassKind) +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(YAMLPassPipeline) + void SILPassPipelinePlan::dump() { print(llvm::errs()); llvm::errs() << '\n'; } void SILPassPipelinePlan::print(llvm::raw_ostream &os) { - // Our pipelines yaml representation is simple, we just output it ourselves - // rather than use the yaml writer interface. We want to use the yaml reader - // interface to be resilient against slightly different forms of yaml. - os << "[\n"; - interleave(getPipelines(), - [&](const SILPassPipeline &Pipeline) { - os << " [\n"; - - os << " \"" << Pipeline.Name << "\""; - for (PassKind Kind : getPipelinePasses(Pipeline)) { - os << ",\n [\"" << PassKindID(Kind) << "\"," - << "\"" << PassKindTag(Kind) << "\"]"; - } - }, - [&] { os << "\n ],\n"; }); - os << "\n ]\n"; - os << ']'; + llvm::yaml::Output out(os); + std::vector data; + transform(getPipelines(), std::back_inserter(data), + [&](const SILPassPipeline &pipeline) { + return YAMLPassPipeline(pipeline, getPipelinePasses(pipeline)); + }); + out << data; } SILPassPipelinePlan -SILPassPipelinePlan::getPassPipelineFromFile(const SILOptions &Options, - StringRef Filename) { - namespace yaml = llvm::yaml; - LLVM_DEBUG(llvm::dbgs() << "Parsing Pass Pipeline from " << Filename << "\n"); - - // Load the input file. - llvm::ErrorOr> FileBufOrErr = - llvm::MemoryBuffer::getFileOrSTDIN(Filename); - if (!FileBufOrErr) { - llvm_unreachable("Failed to read yaml file"); - } - - StringRef Buffer = FileBufOrErr->get()->getBuffer(); - llvm::SourceMgr SM; - yaml::Stream Stream(Buffer, SM); - yaml::document_iterator DI = Stream.begin(); - assert(DI != Stream.end() && "Failed to read a document"); - yaml::Node *N = DI->getRoot(); - assert(N && "Failed to find a root"); +SILPassPipelinePlan::getPassPipelineFromFile(const SILOptions &options, + StringRef filename) { + std::vector yamlPipelines; + { + // Load the input file. + llvm::ErrorOr> fileBufOrErr = + llvm::MemoryBuffer::getFileOrSTDIN(filename); + if (!fileBufOrErr) { + llvm_unreachable("Failed to read yaml file"); + } - SILPassPipelinePlan P(Options); + llvm::yaml::Input in(fileBufOrErr->get()->getBuffer()); + in >> yamlPipelines; + } - auto *RootList = cast(N); - llvm::SmallVector Passes; - for (yaml::Node &PipelineNode : - make_range(RootList->begin(), RootList->end())) { - Passes.clear(); - LLVM_DEBUG(llvm::dbgs() << "New Pipeline:\n"); - - auto *Desc = cast(&PipelineNode); - yaml::SequenceNode::iterator DescIter = Desc->begin(); - StringRef Name = cast(&*DescIter)->getRawValue(); - LLVM_DEBUG(llvm::dbgs() << " Name: \"" << Name << "\"\n"); - ++DescIter; - - for (auto DescEnd = Desc->end(); DescIter != DescEnd; ++DescIter) { - auto *InnerPassList = cast(&*DescIter); - auto *FirstNode = &*InnerPassList->begin(); - StringRef PassName = cast(FirstNode)->getRawValue(); - unsigned Size = PassName.size() - 2; - PassName = PassName.substr(1, Size); - LLVM_DEBUG(llvm::dbgs() << " Pass: \"" << PassName << "\"\n"); - auto Kind = PassKindFromString(PassName); - assert(Kind != PassKind::invalidPassKind && "Found invalid pass kind?!"); - Passes.push_back(Kind); - } + SILPassPipelinePlan silPlan(options); - P.startPipeline(Name); - P.addPasses(Passes); + for (auto &pipeline : yamlPipelines) { + silPlan.startPipeline(pipeline.name); + silPlan.addPasses(pipeline.passes); } - return P; + return silPlan; } diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp index f28a9c32ff6cf..ee73a35d78a92 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp @@ -136,6 +136,7 @@ static bool isBarrier(SILInstruction *inst) { case BuiltinValueKind::WillThrow: case BuiltinValueKind::CondFailMessage: case BuiltinValueKind::PoundAssert: + case BuiltinValueKind::TypePtrAuthDiscriminator: case BuiltinValueKind::GlobalStringTablePointer: return false; diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index d70e8c7305d79..8b35bfbc95a6d 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -620,11 +620,11 @@ SILFunction *PromotedParamCloner::initCloned(SILOptFunctionBuilder &FuncBuilder, // Create the new function type for the cloned function with some of // the parameters promoted. auto ClonedTy = SILFunctionType::get( - OrigFTI->getSubstGenericSignature(), OrigFTI->getExtInfo(), + OrigFTI->getInvocationGenericSignature(), OrigFTI->getExtInfo(), OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys, OrigFTI->getYields(), OrigFTI->getResults(), - OrigFTI->getOptionalErrorResult(), OrigFTI->getSubstitutions(), - OrigFTI->isGenericSignatureImplied(), M.getASTContext(), + OrigFTI->getOptionalErrorResult(), OrigFTI->getPatternSubstitutions(), + OrigFTI->getInvocationSubstitutions(), M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrInvalid()); assert((Orig->isTransparent() || Orig->isBare() || Orig->getLocation()) diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index a0a827199a37c..45d864e52f3a7 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -304,7 +304,7 @@ CanSILFunctionType BridgedProperty::getOutlinedFunctionType(SILModule &M) { nullptr, ExtInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, /*yields*/ {}, Results, None, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), M.getASTContext()); return FunctionType; } @@ -1189,7 +1189,7 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { nullptr, ExtInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, {}, Results, None, - SubstitutionMap(), false, + SubstitutionMap(), SubstitutionMap(), M.getASTContext()); return FunctionType; } diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp index 5749e2b826f24..73a144710dea1 100644 --- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp +++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp @@ -44,6 +44,11 @@ llvm::cl::opt EnableSILAggressiveInlining("sil-aggressive-inline", llvm::cl::init(false), llvm::cl::desc("Enable aggressive inlining")); +llvm::cl::opt EnableVerifyAfterInlining( + "sil-inline-verify-after-inline", llvm::cl::init(false), + llvm::cl::desc("Run sil verification after inlining all found callee apply " + "sites into a caller.")); + //===----------------------------------------------------------------------===// // Performance Inliner //===----------------------------------------------------------------------===// @@ -919,11 +924,9 @@ bool SILPerformanceInliner::inlineCallsIntoFunction(SILFunction *Caller) { } // If we have a callee that doesn't have ownership, but the caller does have - // ownership... do not inline. The two modes are incompatible. Today this - // should only happen with transparent functions. + // ownership... do not inline. The two modes are incompatible, so skip this + // apply site for now. if (!Callee->hasOwnership() && Caller->hasOwnership()) { - assert(Caller->isTransparent() && - "Should only happen with transparent functions"); continue; } @@ -953,6 +956,13 @@ bool SILPerformanceInliner::inlineCallsIntoFunction(SILFunction *Caller) { StackNesting().correctStackNesting(Caller); } + // If we were asked to verify our caller after inlining all callees we could + // find into it, do so now. This makes it easier to catch verification bugs in + // the inliner without running the entire inliner. + if (EnableVerifyAfterInlining) { + Caller->verify(); + } + return true; } @@ -1027,6 +1037,11 @@ class SILPerformanceInlinerPass : public SILFunctionTransform { }; } // end anonymous namespace +SILTransform *swift::createAlwaysInlineInliner() { + return new SILPerformanceInlinerPass(InlineSelection::OnlyInlineAlways, + "InlineAlways"); +} + /// Create an inliner pass that does not inline functions that are marked with /// the @_semantics, @_effects or global_init attributes. SILTransform *swift::createEarlyInliner() { diff --git a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp index feb17dd7e708c..b0b00dc259c34 100644 --- a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp @@ -12,6 +12,7 @@ #define DEBUG_TYPE "sil-semantic-arc-opts" #include "swift/Basic/BlotSetVector.h" +#include "swift/Basic/FrozenMultiMap.h" #include "swift/Basic/STLExtras.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/DebugUtils.h" @@ -46,17 +47,22 @@ STATISTIC(NumLoadCopyConvertedToLoadBorrow, namespace { class LiveRange { - /// The parent value that introduces the live range. - SILValue value; + /// The value that we are computing the LiveRange for. Expected to be an owned + /// introducer and not to be forwarding. + OwnedValueIntroducer introducer; /// A list of destroy_values of the live range. SmallVector destroyingUses; - /// A list of forwarding instructions that forward our destroys ownership, but - /// that are also able to forward guaranteed ownership. - SmallVector generalForwardingUses; + /// A list of forwarding instructions that forward owned ownership, but that + /// are also able to be converted to guaranteed ownership. If we are able to + /// eliminate this LiveRange due to it being from a guaranteed value, we must + /// flip the ownership of all of these instructions to guaranteed from owned. + /// + /// Corresponds to isOwnershipForwardingInst(...). + SmallVector ownershipForwardingUses; - /// Consuming users that we were not able to understand as a forwarding + /// Consuming uses that we were not able to understand as a forwarding /// instruction or a destroy_value. These must be passed a strongly control /// equivalent +1 value. SmallVector unknownConsumingUses; @@ -66,12 +72,19 @@ class LiveRange { LiveRange(const LiveRange &) = delete; LiveRange &operator=(const LiveRange &) = delete; + enum class HasConsumingUse_t { + No = 0, + YesButAllPhiArgs = 1, + Yes = 2, + }; + /// Return true if v only has invalidating uses that are destroy_value. Such /// an owned value is said to represent a dead "live range". /// /// Semantically this implies that a value is never passed off as +1 to memory /// or another function implying it can be used everywhere at +0. - bool hasConsumingUse() const { return unknownConsumingUses.size(); } + HasConsumingUse_t + hasUnknownConsumingUse(bool assumingFixedPoint = false) const; ArrayRef getDestroyingUses() const { return destroyingUses; } @@ -83,10 +96,32 @@ class LiveRange { TransformRange, OperandToUser>; DestroyingInstsRange getDestroyingInsts() const; - ArrayRef getNonConsumingForwardingUses() const { - return generalForwardingUses; + /// If this LiveRange has a single destroying use, return that use. Otherwise, + /// return nullptr. + Operand *getSingleDestroyingUse() const { + if (destroyingUses.size() != 1) { + return nullptr; + } + return destroyingUses.front(); + } + + /// If this LiveRange has a single unknown destroying use, return that + /// use. Otherwise, return nullptr. + Operand *getSingleUnknownConsumingUse() const { + if (unknownConsumingUses.size() != 1) { + return nullptr; + } + return unknownConsumingUses.front(); } + OwnedValueIntroducer getIntroducer() const { return introducer; } + + ArrayRef getOwnershipForwardingUses() const { + return ownershipForwardingUses; + } + + void convertOwnedGeneralForwardingUsesToGuaranteed(); + /// A consuming operation that: /// /// 1. If \p insertEndBorrows is true inserts end borrows at all @@ -104,6 +139,28 @@ class LiveRange { void convertToGuaranteedAndRAUW(SILValue newGuaranteedValue, InstModCallbacks callbacks) &&; + /// A consuming operation that in order: + /// + /// 1. Converts the phi argument to be guaranteed. + /// + /// 2. Inserts end_borrows at the relevant destroy_values. + /// + /// 3. Deletes all destroy_values. + /// + /// 4. Converts all of the general forwarding instructions from @owned -> + /// @guaranteed. "Like Dominoes". + /// + /// NOTE: This leaves all of the unknown consuming users alone. It is up to + /// the caller to handle converting their ownership. + /// + /// NOTE: This routine leaves inserting begin_borrows for the incoming values + /// to the caller since those are not part of the LiveRange itself. + /// + /// NOTE: Asserts that value is a phi argument. + void convertArgToGuaranteed(DeadEndBlocks &deadEndBlocks, + ValueLifetimeAnalysis::Frontier &scratch, + InstModCallbacks callbacks) &&; + /// Given a new guaranteed value, insert end_borrow for the newGuaranteedValue /// at all of our destroy_values in prepration for converting from owned to /// guaranteed. @@ -130,13 +187,13 @@ LiveRange::DestroyingInstsRange LiveRange::getDestroyingInsts() const { } LiveRange::LiveRange(SILValue value) - : value(value), destroyingUses(), generalForwardingUses(), - unknownConsumingUses() { - assert(value.getOwnershipKind() == ValueOwnershipKind::Owned); + : introducer(*OwnedValueIntroducer::get(value)), destroyingUses(), + ownershipForwardingUses(), unknownConsumingUses() { + assert(introducer.value.getOwnershipKind() == ValueOwnershipKind::Owned); // We know that our silvalue produces an @owned value. Look through all of our // uses and classify them as either consuming or not. - SmallVector worklist(value->getUses()); + SmallVector worklist(introducer.value->getUses()); while (!worklist.empty()) { auto *op = worklist.pop_back_val(); @@ -192,7 +249,7 @@ LiveRange::LiveRange(SILValue value) // Ok, this is a forwarding instruction whose ownership we can flip from // owned -> guaranteed. - generalForwardingUses.push_back(op); + ownershipForwardingUses.push_back(op); // If we have a non-terminator, just visit its users recursively to see if // the the users force the live range to be alive. @@ -239,10 +296,35 @@ void LiveRange::insertEndBorrowsAtDestroys( // we do not insert multiple end_borrow. // // TODO: Hoist this out? - auto *inst = value->getDefiningInstruction(); - assert(inst && "Should only call this with value's that are actually part of " - "an instruction"); - + SILInstruction *inst = introducer.value->getDefiningInstruction(); + if (!inst) { + // If our introducer was not for an inst, it should be from an arg. In such + // a case, we handle one of two cases: + // + // 1. If we have one destroy and that destroy is the initial instruction in + // the arguments block, we just insert the end_borrow here before the + // destroy_value and bail. If the destroy is not the initial instruction in + // the arg block, we delegate to the ValueLifetimeAnalysis code. + // + // 2. If we have multiple destroys, by the properties of owned values having + // a linear lifetime, we know that the destroys can not both be first in the + // args block since the only way that we could have two such destroys in the + // arg's block is if we destructured the arg. In such a case, the + // destructure instruction would have to be between the argument and any + // destroy meaning the destroys could not be first. In such a case, we + // delegate to the ValueLifetimeAnalysis code. + auto *arg = cast(introducer.value); + auto *beginInst = &*arg->getParent()->begin(); + if (auto *singleDestroyingUse = getSingleDestroyingUse()) { + if (singleDestroyingUse->getUser() == beginInst) { + auto loc = RegularLocation::getAutoGeneratedLocation(); + SILBuilderWithScope builder(beginInst); + builder.createEndBorrow(loc, newGuaranteedValue); + return; + } + } + inst = beginInst; + } ValueLifetimeAnalysis analysis(inst, getDestroyingInsts()); bool foundCriticalEdges = !analysis.computeFrontier( scratch, ValueLifetimeAnalysis::DontModifyCFG, &deadEndBlocks); @@ -256,24 +338,9 @@ void LiveRange::insertEndBorrowsAtDestroys( } } -void LiveRange::convertToGuaranteedAndRAUW(SILValue newGuaranteedValue, - InstModCallbacks callbacks) && { - assert(isa(value) && - "Can only convert single value instruction live ranges to guaranteed"); - while (!destroyingUses.empty()) { - auto *d = destroyingUses.pop_back_val(); - callbacks.deleteInst(d->getUser()); - ++NumEliminatedInsts; - } - - callbacks.eraseAndRAUWSingleValueInst(cast(value), - newGuaranteedValue); - - // Then change all of our guaranteed forwarding insts to have guaranteed - // ownership kind instead of what ever they previously had (ignoring trivial - // results); - while (!generalForwardingUses.empty()) { - auto *i = generalForwardingUses.pop_back_val()->getUser(); +void LiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() { + while (!ownershipForwardingUses.empty()) { + auto *i = ownershipForwardingUses.pop_back_val()->getUser(); // If this is a term inst, just convert all of its incoming values that are // owned to be guaranteed. @@ -330,6 +397,82 @@ void LiveRange::convertToGuaranteedAndRAUW(SILValue newGuaranteedValue, } } +void LiveRange::convertToGuaranteedAndRAUW(SILValue newGuaranteedValue, + InstModCallbacks callbacks) && { + auto *value = cast(introducer.value); + while (!destroyingUses.empty()) { + auto *d = destroyingUses.pop_back_val(); + callbacks.deleteInst(d->getUser()); + ++NumEliminatedInsts; + } + + callbacks.eraseAndRAUWSingleValueInst(value, newGuaranteedValue); + + // Then change all of our guaranteed forwarding insts to have guaranteed + // ownership kind instead of what ever they previously had (ignoring trivial + // results); + convertOwnedGeneralForwardingUsesToGuaranteed(); +} + +void LiveRange::convertArgToGuaranteed(DeadEndBlocks &deadEndBlocks, + ValueLifetimeAnalysis::Frontier &scratch, + InstModCallbacks callbacks) && { + // First convert the phi argument to be guaranteed. + auto *phiArg = cast(introducer.value); + phiArg->setOwnershipKind(ValueOwnershipKind::Guaranteed); + + // Then insert end_borrows at each of our destroys. We have to convert the phi + // to guaranteed first since otherwise, the ownership check when we create the + // end_borrows will trigger. + insertEndBorrowsAtDestroys(phiArg, deadEndBlocks, scratch); + + // Then eliminate all of the destroys... + while (!destroyingUses.empty()) { + auto *d = destroyingUses.pop_back_val(); + callbacks.deleteInst(d->getUser()); + ++NumEliminatedInsts; + } + + // and change all of our guaranteed forwarding insts to have guaranteed + // ownership kind instead of what ever they previously had (ignoring trivial + // results); + convertOwnedGeneralForwardingUsesToGuaranteed(); +} + +LiveRange::HasConsumingUse_t +LiveRange::hasUnknownConsumingUse(bool assumingAtFixPoint) const { + // First do a quick check if we have /any/ unknown consuming + // uses. If we do not have any, return false early. + if (unknownConsumingUses.empty()) { + return HasConsumingUse_t::No; + } + + // Ok, we do have some unknown consuming uses. If we aren't assuming we are at + // the fixed point yet, just bail. + if (!assumingAtFixPoint) { + return HasConsumingUse_t::Yes; + } + + // We do not know how to handle yet cases where an owned value is used by + // multiple phi nodes. So we bail early if unknown consuming uses is > 1. + // + // TODO: Build up phi node web. + auto *op = getSingleUnknownConsumingUse(); + if (!op) { + return HasConsumingUse_t::Yes; + } + + // Make sure our single unknown consuming use is a branch inst. If not, bail, + // this is a /real/ unknown consuming use. + if (!isa(op->getUser())) { + return HasConsumingUse_t::Yes; + } + + // Otherwise, setup the phi to incoming value map mapping the block arguments + // to our introducer. + return HasConsumingUse_t::YesButAllPhiArgs; +} + //===----------------------------------------------------------------------===// // Address Written To Analysis //===----------------------------------------------------------------------===// @@ -482,6 +625,39 @@ struct SemanticARCOptVisitor ValueLifetimeAnalysis::Frontier lifetimeFrontier; IsAddressWrittenToDefUseAnalysis isAddressWrittenToDefUseAnalysis; + /// Are we assuming that we reached a fix point and are re-processing to + /// prepare to use the phiToIncomingValueMultiMap. + bool assumingAtFixedPoint = false; + + /// A map from a value that acts as a "joined owned introducer" in the def-use + /// graph. + /// + /// A "joined owned introducer" is a value with owned ownership whose + /// ownership is derived from multiple non-trivial owned operands of a related + /// instruction. Some examples are phi arguments, tuples, structs. Naturally, + /// all of these instructions must be non-unary instructions and only have + /// this property if they have multiple operands that are non-trivial. + /// + /// In such a case, we can not just treat them like normal forwarding concepts + /// since we can only eliminate optimize such a value if we are able to reason + /// about all of its operands together jointly. This is not amenable to a + /// small peephole analysis. + /// + /// Instead, as we perform the peephole analysis, using the multimap, we map + /// each joined owned value introducer to the set of its @owned operands that + /// we thought we could convert to guaranteed only if we could do the same to + /// the joined owned value introducer. Then once we finish performing + /// peepholes, we iterate through the map and see if any of our joined phi + /// ranges had all of their operand's marked with this property by iterating + /// over the multimap. Since we are dealing with owned values and we know that + /// our LiveRange can not see through joined live ranges, we know that we + /// should only be able to have a single owned value introducer for each + /// consumed operand. + FrozenMultiMap joinedOwnedIntroducerToConsumedOperands; + + using FrozenMultiMapRange = + decltype(joinedOwnedIntroducerToConsumedOperands)::PairToSecondEltRange; + explicit SemanticARCOptVisitor(SILFunction &F) : F(F) {} DeadEndBlocks &getDeadEndBlocks() { @@ -513,6 +689,18 @@ struct SemanticARCOptVisitor eraseInstruction(i); } + /// Pop values off of visitedSinceLastMutation, adding .some values to the + /// worklist. + void drainVisitedSinceLastMutationIntoWorklist() { + while (!visitedSinceLastMutation.empty()) { + Optional nextValue = visitedSinceLastMutation.pop_back_val(); + if (!nextValue.hasValue()) { + continue; + } + worklist.insert(*nextValue); + } + } + /// Remove all results of the given instruction from the worklist and then /// erase the instruction. Assumes that the instruction does not have any /// users left. @@ -526,13 +714,7 @@ struct SemanticARCOptVisitor i->eraseFromParent(); // Add everything else from visitedSinceLastMutation to the worklist. - for (auto opt : visitedSinceLastMutation) { - if (!opt.hasValue()) { - continue; - } - worklist.insert(*opt); - } - visitedSinceLastMutation.clear(); + drainVisitedSinceLastMutationIntoWorklist(); } InstModCallbacks getCallbacks() { @@ -593,6 +775,7 @@ struct SemanticARCOptVisitor FORWARDING_INST(OpenExistentialValue) FORWARDING_INST(OpenExistentialBoxValue) FORWARDING_INST(MarkDependence) + FORWARDING_INST(InitExistentialRef) #undef FORWARDING_INST #define FORWARDING_TERM(NAME) \ @@ -608,16 +791,17 @@ struct SemanticARCOptVisitor FORWARDING_TERM(SwitchEnum) FORWARDING_TERM(CheckedCastBranch) FORWARDING_TERM(Branch) - FORWARDING_TERM(CondBranch) #undef FORWARDING_TERM bool isWrittenTo(LoadInst *li, const LiveRange &lr); bool processWorklist(); + bool optimize(); bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi); bool eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi); bool tryJoiningCopyValueLiveRangeWithOperand(CopyValueInst *cvi); + bool performPostPeepholeOwnedArgElimination(); }; } // end anonymous namespace @@ -626,6 +810,248 @@ static llvm::cl::opt VerifyAfterTransform("sil-semantic-arc-opts-verify-after-transform", llvm::cl::init(false), llvm::cl::Hidden); +static bool canEliminatePhi( + SemanticARCOptVisitor::FrozenMultiMapRange optimizableIntroducerRange, + ArrayRef incomingValueOperandList, + SmallVectorImpl &ownedValueIntroducerAccumulator) { + for (Operand *incomingValueOperand : incomingValueOperandList) { + SILValue incomingValue = incomingValueOperand->get(); + + // Before we do anything, see if we have an incoming value with trivial + // ownership. This can occur in the case where we are working with enums due + // to trivial non-payloaded cases. Skip that. + if (incomingValue.getOwnershipKind() == ValueOwnershipKind::None) { + continue; + } + + // Then see if this is an introducer that we actually saw as able to be + // optimized if we could flip this joined live range. + // + // NOTE: If this linear search is too slow, we can change the multimap to + // sort the mapped to list by pointer instead of insertion order. In such a + // case, we could then bisect. + if (llvm::find(optimizableIntroducerRange, incomingValueOperand) == + optimizableIntroducerRange.end()) { + return false; + } + + // Now that we know it is an owned value that we saw before, check for + // introducers of the owned value which are the copies that we may be able + // to eliminate. Since we do not look through joined live ranges, we must + // only have a single introducer. So look for that one and if not, bail. + auto singleIntroducer = getSingleOwnedValueIntroducer(incomingValue); + if (!singleIntroducer.hasValue()) { + return false; + } + + // Then make sure that our owned value introducer is able to be converted to + // guaranteed and that we found it to have a LiveRange that we could have + // eliminated /if/ we were to get rid of this phi. + if (!singleIntroducer->isConvertableToGuaranteed()) { + return false; + } + + // Otherwise, add the introducer to our result array. + ownedValueIntroducerAccumulator.push_back(*singleIntroducer); + } + +#ifndef NDEBUG + // Other parts of the pass ensure that we only add values to the list if their + // owned value introducer is not used by multiple live ranges. That being + // said, lets assert that. + { + SmallVector uniqueCheck; + llvm::copy(ownedValueIntroducerAccumulator, + std::back_inserter(uniqueCheck)); + sortUnique(uniqueCheck); + assert( + uniqueCheck.size() == ownedValueIntroducerAccumulator.size() && + "multiple joined live range operands are from the same live range?!"); + } +#endif + + return true; +} + +static bool getIncomingJoinedLiveRangeOperands( + SILValue joinedLiveRange, SmallVectorImpl &resultingOperands) { + if (auto *phi = dyn_cast(joinedLiveRange)) { + return phi->getIncomingPhiOperands(resultingOperands); + } + + llvm_unreachable("Unhandled joined live range?!"); +} + +bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { + bool madeChange = false; + + // First freeze our multi-map so we can use it for map queries. Also, setup a + // defer of the reset so we do not forget to reset the map when we are done. + joinedOwnedIntroducerToConsumedOperands.setFrozen(); + SWIFT_DEFER { joinedOwnedIntroducerToConsumedOperands.reset(); }; + + // Now for each phi argument that we have in our multi-map... + SmallVector incomingValueOperandList; + SmallVector ownedValueIntroducers; + for (auto pair : joinedOwnedIntroducerToConsumedOperands.getRange()) { + SWIFT_DEFER { + incomingValueOperandList.clear(); + ownedValueIntroducers.clear(); + }; + + // First compute the LiveRange for ownershipPhi value. For simplicity, we + // only handle cases now where the result does not have any additional + // ownershipPhi uses. + SILValue joinedIntroducer = pair.first; + LiveRange joinedLiveRange(joinedIntroducer); + if (bool(joinedLiveRange.hasUnknownConsumingUse())) { + continue; + } + + // Ok, we know that our phi argument /could/ be converted to guaranteed if + // our incoming values are able to be converted to guaranteed. Now for each + // incoming value, compute the incoming values ownership roots and see if + // all of the ownership roots are in our owned incoming value array. + if (!getIncomingJoinedLiveRangeOperands(joinedIntroducer, + incomingValueOperandList)) { + continue; + } + + // Grab our list of introducer values paired with this SILArgument. See if + // all of these introducer values were ones that /could/ have been + // eliminated if it was not for the given phi. If all of them are, we can + // optimize! + { + auto rawFoundOptimizableIntroducerArray = pair.second; + if (!canEliminatePhi(rawFoundOptimizableIntroducerArray, + incomingValueOperandList, ownedValueIntroducers)) { + continue; + } + } + + // Ok, at this point we know that we can eliminate this phi. First go + // through the list of incomingValueOperandList and stash the value/set the + // operand's stored value to undef. We will hook them back up later. + SmallVector originalIncomingValues; + for (Operand *incomingValueOperand : incomingValueOperandList) { + originalIncomingValues.push_back(incomingValueOperand->get()); + SILType type = incomingValueOperand->get()->getType(); + auto *undef = SILUndef::get(type, F); + incomingValueOperand->set(undef); + } + + // Then go through all of our owned value introducers, compute their live + // ranges, and eliminate them. We know it is safe to remove them from our + // previous proofs. + // + // NOTE: If our introducer is a copy_value that is one of our + // originalIncomingValues, we need to update the originalIncomingValue array + // with that value since we are going to delete the copy_value here. This + // creates a complication since we want to binary_search on + // originalIncomingValues to detect this same condition! So, we create a + // list of updates that we apply after we no longer need to perform + // binary_search, but before we start RAUWing things. + SmallVector, 8> incomingValueUpdates; + for (auto introducer : ownedValueIntroducers) { + SILValue v = introducer.value; + LiveRange lr(v); + + // For now, we only handle copy_value for simplicity. + // + // TODO: Add support for load [copy]. + if (introducer.kind == OwnedValueIntroducerKind::Copy) { + auto *cvi = cast(v); + // Before we convert from owned to guaranteed, we need to first see if + // cvi is one of our originalIncomingValues. If so, we need to set + // originalIncomingValues to be cvi->getOperand(). Otherwise, weirdness + // results since we are deleting one of our stashed values. + auto iter = find(originalIncomingValues, cvi); + if (iter != originalIncomingValues.end()) { + // We use an auxillary array here so we can continue to bisect on + // original incoming values. Once we are done processing here, we will + // not need that property anymore. + unsigned updateOffset = + std::distance(originalIncomingValues.begin(), iter); + incomingValueUpdates.emplace_back(cvi->getOperand(), updateOffset); + } + std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), + getCallbacks()); + continue; + } + llvm_unreachable("Unhandled optimizable introducer!"); + } + + // Now go through and update our original incoming value array now that we + // do not need it to be sorted for bisection purposes. + while (!incomingValueUpdates.empty()) { + auto pair = incomingValueUpdates.pop_back_val(); + originalIncomingValues[pair.second] = pair.first; + } + + // Then convert the phi's live range to be guaranteed. + std::move(joinedLiveRange) + .convertArgToGuaranteed(getDeadEndBlocks(), lifetimeFrontier, + getCallbacks()); + + // Now insert a begin_borrow along the incoming value edges and We have to + // do this after converting the incoming values to be guaranteed since + // SILBuilder checks simple ownership invariants (namely that def/use line + // up) when creating instructions. + assert(incomingValueOperandList.size() == originalIncomingValues.size()); + while (!incomingValueOperandList.empty()) { + auto *incomingValueOperand = incomingValueOperandList.pop_back_val(); + SILValue originalValue = originalIncomingValues.pop_back_val(); + + auto *br = cast(incomingValueOperand->getUser()); + if (originalValue.getOwnershipKind() != ValueOwnershipKind::None) { + auto loc = RegularLocation::getAutoGeneratedLocation(); + SILBuilderWithScope builder(br); + originalValue = builder.createBeginBorrow(loc, originalValue); + } + incomingValueOperand->set(originalValue); + } + + madeChange = true; + if (VerifyAfterTransform) { + F.verify(); + } + } + + return madeChange; +} + +bool SemanticARCOptVisitor::optimize() { + bool madeChange = false; + + // First process the worklist until we reach a fixed point. + madeChange |= processWorklist(); + + { + // If we made a change, set that we assume we are at fixed point and then + // re-run the worklist so that we can + // properly seeded the ARC peephole map. + assumingAtFixedPoint = true; + SWIFT_DEFER { assumingAtFixedPoint = false; }; + + // Add everything in visitedSinceLastMutation to the worklist so we + // recompute our fixed point. + drainVisitedSinceLastMutationIntoWorklist(); + + // Then re-run the worklist. We shouldn't modify anything since we are at a + // fixed point and are just using this to seed the + // joinedOwnedIntroducerToConsumedOperands after we have finished changing + // things. If we did change something, we did something weird, so assert! + bool madeAdditionalChanges = processWorklist(); + (void)madeAdditionalChanges; + assert(!madeAdditionalChanges && "Should be at the fixed point"); + } + + // Then use the newly seeded peephole map to + madeChange |= performPostPeepholeOwnedArgElimination(); + + return madeChange; +} + bool SemanticARCOptVisitor::processWorklist() { // NOTE: The madeChange here is not strictly necessary since we only have // items added to the worklist today if we have already made /some/ sort of @@ -658,6 +1084,8 @@ bool SemanticARCOptVisitor::processWorklist() { // the instruction). if (auto *defInst = next->getDefiningInstruction()) { if (isInstructionTriviallyDead(defInst)) { + assert(!assumingAtFixedPoint && + "Assumed was at fixed point and recomputing state?!"); deleteAllDebugUses(defInst); eraseInstruction(defInst); madeChange = true; @@ -672,6 +1100,8 @@ bool SemanticARCOptVisitor::processWorklist() { // perhaps), try to visit that value recursively. if (auto *svi = dyn_cast(next)) { bool madeSingleChange = visit(svi); + assert((!madeSingleChange || !assumingAtFixedPoint) && + "Assumed was at fixed point and modified state?!"); madeChange |= madeSingleChange; if (VerifyAfterTransform && madeSingleChange) { F.verify(); @@ -772,13 +1202,17 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst return false; // Then go over all of our uses and see if the value returned by our copy - // value forms a dead live range. If we do not have a dead live range, there - // must be some consuming use that we either do not understand is /actually/ - // forwarding or a user that truly represents a necessary consume of the - // value (e.x. storing into memory). + // value forms a dead live range or a live range that would be dead if it was + // not consumed by phi nodes. If we do not have such a live range, there must + // be some consuming use that we either do not understand is /actually/ + // forwarding or a user that truly represents a necessary consume of the value + // (e.x. storing into memory). LiveRange lr(cvi); - if (lr.hasConsumingUse()) + auto hasUnknownConsumingUseState = + lr.hasUnknownConsumingUse(assumingAtFixedPoint); + if (hasUnknownConsumingUseState == LiveRange::HasConsumingUse_t::Yes) { return false; + } // Next check if we do not have any destroys of our copy_value and are // processing a local borrow scope. In such a case, due to the way we ignore @@ -879,7 +1313,51 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst } // Otherwise, we know that our copy_value/destroy_values are all completely - // within the guaranteed value scope. So RAUW and convert to guaranteed! + // within the guaranteed value scope. So we /could/ optimize it. Now check if + // we were truly dead or if we are dead if we can eliminate phi arg uses. If + // we need to handle the phi arg uses, we bail. After we reach a fixed point, + // we will try to eliminate this value then. + if (hasUnknownConsumingUseState == + LiveRange::HasConsumingUse_t::YesButAllPhiArgs) { + auto *op = lr.getSingleUnknownConsumingUse(); + assert(op); + unsigned opNum = op->getOperandNumber(); + auto *br = cast(op->getUser()); + SmallVector scratchSpace; + SmallPtrSet visitedBlocks; + + for (auto *succBlock : br->getSuccessorBlocks()) { + SWIFT_DEFER { + scratchSpace.clear(); + visitedBlocks.clear(); + }; + + auto *arg = succBlock->getSILPhiArguments()[opNum]; + LiveRange phiArgLR(arg); + if (bool(phiArgLR.hasUnknownConsumingUse())) { + return false; + } + + if (llvm::any_of(borrowScopeIntroducers, + [&](BorrowScopeIntroducingValue borrowScope) { + return !borrowScope.areUsesWithinScope( + phiArgLR.getDestroyingUses(), scratchSpace, + visitedBlocks, getDeadEndBlocks()); + })) { + return false; + } + } + + for (auto *succBlock : br->getSuccessorBlocks()) { + auto *arg = succBlock->getSILPhiArguments()[opNum]; + joinedOwnedIntroducerToConsumedOperands.insert(arg, op); + } + + return false; + } + + // Otherwise, our copy must truly not be needed, o RAUW and convert to + // guaranteed! std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), getCallbacks()); ++NumEliminatedInsts; return true; @@ -1338,7 +1816,7 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) { // -> load_borrow if we can put a copy_value on a cold path and thus // eliminate RR traffic on a hot path. LiveRange lr(li); - if (lr.hasConsumingUse()) + if (bool(lr.hasUnknownConsumingUse())) return false; // Then check if our address is ever written to. If it is, then we cannot use @@ -1398,8 +1876,9 @@ struct SemanticARCOpts : SILFunctionTransform { // Then process the worklist. We only destroy instructions, so invalidate // that. Once we modify the ownership of block arguments, we will need to // perhaps invalidate branches as well. - if (visitor.processWorklist()) { - invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); + if (visitor.optimize()) { + invalidateAnalysis( + SILAnalysis::InvalidationKind::BranchesAndInstructions); } } }; diff --git a/lib/SILOptimizer/Transforms/TempRValueElimination.cpp b/lib/SILOptimizer/Transforms/TempRValueElimination.cpp index 929c6be7d163e..7bd20bd71d5f4 100644 --- a/lib/SILOptimizer/Transforms/TempRValueElimination.cpp +++ b/lib/SILOptimizer/Transforms/TempRValueElimination.cpp @@ -67,6 +67,9 @@ class TempRValueOptPass : public SILFunctionTransform { bool collectLoads(Operand *userOp, SILInstruction *userInst, SingleValueInstruction *addr, SILValue srcObject, SmallPtrSetImpl &loadInsts); + bool collectLoadsFromProjection(SingleValueInstruction *projection, + SILValue srcAddr, + SmallPtrSetImpl &loadInsts); bool checkNoSourceModification(CopyAddrInst *copyInst, SILValue copySrc, @@ -85,6 +88,29 @@ class TempRValueOptPass : public SILFunctionTransform { } // anonymous namespace +bool TempRValueOptPass::collectLoadsFromProjection( + SingleValueInstruction *projection, SILValue srcAddr, + SmallPtrSetImpl &loadInsts) { + if (!srcAddr) { + LLVM_DEBUG( + llvm::dbgs() + << " Temp has addr_projection use?! Can not yet promote to value" + << *projection); + return false; + } + + // Transitively look through projections on stack addresses. + for (auto *projUseOper : projection->getUses()) { + auto *user = projUseOper->getUser(); + if (user->isTypeDependentOperand(*projUseOper)) + continue; + + if (!collectLoads(projUseOper, user, projection, srcAddr, loadInsts)) + return false; + } + return true; +} + /// Transitively explore all data flow uses of the given \p address until /// reaching a load or returning false. /// @@ -199,32 +225,27 @@ bool TempRValueOptPass::collectLoads( << *user); return false; } - LLVM_FALLTHROUGH; + return collectLoadsFromProjection(oeai, srcAddr, loadInsts); } - case SILInstructionKind::StructElementAddrInst: - case SILInstructionKind::TupleElementAddrInst: { - auto *proj = cast(user); - - if (!srcAddr) { - LLVM_DEBUG( - llvm::dbgs() - << " Temp has addr_projection use?! Can not yet promote to value" - << *user); + case SILInstructionKind::UncheckedTakeEnumDataAddrInst: { + // In certain cases, unchecked_take_enum_data_addr invalidates the + // underlying memory, so by default we can not look through it... but this + // is not true in the case of Optional. This is an important case for us to + // handle, so handle it here. + auto *utedai = cast(user); + if (!utedai->getOperand()->getType().getOptionalObjectType()) { + LLVM_DEBUG(llvm::dbgs() + << " Temp use may write/destroy its source" << *utedai); return false; } - // Transitively look through projections on stack addresses. - for (auto *projUseOper : proj->getUses()) { - auto *user = projUseOper->getUser(); - if (user->isTypeDependentOperand(*projUseOper)) - continue; - - if (!collectLoads(projUseOper, user, proj, srcAddr, loadInsts)) - return false; - } - return true; + return collectLoadsFromProjection(utedai, srcAddr, loadInsts); + } + case SILInstructionKind::StructElementAddrInst: + case SILInstructionKind::TupleElementAddrInst: { + return collectLoadsFromProjection(cast(user), + srcAddr, loadInsts); } - case SILInstructionKind::LoadInst: // Loads are the end of the data flow chain. The users of the load can't // access the temporary storage. @@ -251,7 +272,11 @@ bool TempRValueOptPass::collectLoads( return false; loadInsts.insert(user); return true; - + case SILInstructionKind::FixLifetimeInst: + // If we have a fixed lifetime on our alloc_stack, we can just treat it like + // a load and re-write it so that it is on the old memory or old src object. + loadInsts.insert(user); + return true; case SILInstructionKind::CopyAddrInst: { // copy_addr which read from the temporary are like loads. auto *copyFromTmp = cast(user); @@ -618,6 +643,13 @@ TempRValueOptPass::tryOptimizeStoreIntoTemp(StoreInst *si) { toDelete.push_back(li); break; } + case SILInstructionKind::FixLifetimeInst: { + auto *fli = cast(user); + SILBuilderWithScope builder(fli); + builder.createFixLifetime(fli->getLoc(), si->getSrc()); + toDelete.push_back(fli); + break; + } // ASSUMPTION: no operations that may be handled by this default clause can // destroy tempObj. This includes operations that load the value from memory diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index c01d47a8ff74b..aa187b7d15815 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -90,7 +90,7 @@ class BugReducerTester : public SILFunctionTransform { nullptr /*clangFunctionType*/), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, ArrayRef(), ArrayRef(), ResultInfoArray, - None, SubstitutionMap(), false, + None, SubstitutionMap(), SubstitutionMap(), getFunction()->getModule().getASTContext()); SILOptFunctionBuilder FunctionBuilder(*this); diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index ad1b97c2b480d..a11ed7a47e459 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -758,8 +758,9 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF, // First substitute concrete types into the existing function type. CanSILFunctionType FnTy; { - FnTy = OrigF->getLoweredFunctionType()->substGenericArgs( - M, SubstMap, getResilienceExpansion()); + FnTy = OrigF->getLoweredFunctionType() + ->substGenericArgs(M, SubstMap, getResilienceExpansion()) + ->getUnsubstitutedType(M); // FIXME: Some of the added new requirements may not have been taken into // account by the substGenericArgs. So, canonicalize in the context of the // specialized signature. @@ -777,8 +778,9 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF, auto NewFnTy = SILFunctionType::get( CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->getCoroutineKind(), FnTy->getCalleeConvention(), FnTy->getParameters(), FnTy->getYields(), - FnTy->getResults(), FnTy->getOptionalErrorResult(), SubstitutionMap(), - false, M.getASTContext(), FnTy->getWitnessMethodConformanceOrInvalid()); + FnTy->getResults(), FnTy->getOptionalErrorResult(), + FnTy->getPatternSubstitutions(), SubstitutionMap(), M.getASTContext(), + FnTy->getWitnessMethodConformanceOrInvalid()); // This is an interface type. It should not have any archetypes. assert(!NewFnTy->hasArchetype()); @@ -789,12 +791,13 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF, /// on the ReabstractionInfo. CanSILFunctionType ReabstractionInfo:: createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const { - llvm::SmallVector SpecializedResults; - llvm::SmallVector SpecializedYields; - llvm::SmallVector SpecializedParams; + SmallVector SpecializedResults; + SmallVector SpecializedYields; + SmallVector SpecializedParams; unsigned IndirectResultIdx = 0; for (SILResultInfo RI : SubstFTy->getResults()) { + RI = RI.getUnsubstituted(M, SubstFTy); if (RI.isFormalIndirect()) { bool isTrivial = TrivialArgs.test(IndirectResultIdx); if (isFormalResultConverted(IndirectResultIdx++)) { @@ -804,7 +807,7 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const { auto C = (isTrivial ? ResultConvention::Unowned : ResultConvention::Owned); - SpecializedResults.push_back(SILResultInfo(RI.getReturnValueType(M, SubstFTy), C)); + SpecializedResults.push_back(RI.getWithConvention(C)); continue; } } @@ -813,6 +816,7 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const { } unsigned ParamIdx = 0; for (SILParameterInfo PI : SubstFTy->getParameters()) { + PI = PI.getUnsubstituted(M, SubstFTy); bool isTrivial = TrivialArgs.test(param2ArgIndex(ParamIdx)); if (!isParamConverted(ParamIdx++)) { // No conversion: re-use the original, substituted parameter info. @@ -832,17 +836,21 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const { C = ParameterConvention::Direct_Owned; } } - SpecializedParams.push_back(SILParameterInfo(PI.getArgumentType(M, SubstFTy), C)); + SpecializedParams.push_back(PI.getWithConvention(C)); } for (SILYieldInfo YI : SubstFTy->getYields()) { - // For now, always just use the original, substituted parameter info. - SpecializedYields.push_back(YI); + // For now, always re-use the original, substituted yield info. + SpecializedYields.push_back(YI.getUnsubstituted(M, SubstFTy)); } + + auto Signature = SubstFTy->isPolymorphic() + ? SubstFTy->getInvocationGenericSignature() + : CanGenericSignature(); return SILFunctionType::get( - SubstFTy->getInvocationGenericSignature(), SubstFTy->getExtInfo(), + Signature, SubstFTy->getExtInfo(), SubstFTy->getCoroutineKind(), SubstFTy->getCalleeConvention(), SpecializedParams, SpecializedYields, SpecializedResults, - SubstFTy->getOptionalErrorResult(), SubstitutionMap(), false, + SubstFTy->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), M.getASTContext(), SubstFTy->getWitnessMethodConformanceOrInvalid()); } @@ -910,7 +918,7 @@ static bool hasNonSelfContainedRequirements(ArchetypeType *Archetype, // we should return true. auto First = Req.getFirstType()->getCanonicalType(); auto Second = Req.getSecondType()->getCanonicalType(); - llvm::SmallSetVector UsedGenericParams; + SmallSetVector UsedGenericParams; First.visit([&](Type Ty) { if (auto *GP = Ty->getAs()) { UsedGenericParams.insert(GP); @@ -961,7 +969,7 @@ static void collectRequirements(ArchetypeType *Archetype, GenericSignature Sig, // we should return true. auto First = Req.getFirstType()->getCanonicalType(); auto Second = Req.getSecondType()->getCanonicalType(); - llvm::SmallSetVector UsedGenericParams; + SmallSetVector UsedGenericParams; First.visit([&](Type Ty) { if (auto *GP = Ty->getAs()) { UsedGenericParams.insert(GP); @@ -1931,8 +1939,8 @@ static void prepareCallArguments(ApplySite AI, SILBuilder &Builder, /// function being applied. static ApplySite replaceWithSpecializedCallee(ApplySite AI, SILValue Callee, - SILBuilder &Builder, const ReabstractionInfo &ReInfo) { + SILBuilderWithScope Builder(AI.getInstruction()); SILLocation Loc = AI.getLoc(); SmallVector Arguments; SILValue StoreResultTo; @@ -2021,7 +2029,7 @@ replaceWithSpecializedFunction(ApplySite AI, SILFunction *NewF, const ReabstractionInfo &ReInfo) { SILBuilderWithScope Builder(AI.getInstruction()); FunctionRefInst *FRI = Builder.createFunctionRef(AI.getLoc(), NewF); - return replaceWithSpecializedCallee(AI, FRI, Builder, ReInfo); + return replaceWithSpecializedCallee(AI, FRI, ReInfo); } namespace { @@ -2302,7 +2310,7 @@ static bool createPrespecializations(ApplySite Apply, SILFunction *ProxyFunc, void swift::trySpecializeApplyOfGeneric( SILOptFunctionBuilder &FuncBuilder, ApplySite Apply, DeadInstructionSet &DeadApplies, - llvm::SmallVectorImpl &NewFunctions, + SmallVectorImpl &NewFunctions, OptRemark::Emitter &ORE) { assert(Apply.hasSubstitutions() && "Expected an apply with substitutions!"); auto *F = Apply.getFunction(); @@ -2436,11 +2444,11 @@ void swift::trySpecializeApplyOfGeneric( // thunk which converts from the re-abstracted function back to the // original function with indirect parameters/results. auto *PAI = cast(Apply.getInstruction()); - SILBuilderWithScope Builder(PAI); SILFunction *Thunk = ReabstractionThunkGenerator(FuncBuilder, ReInfo, PAI, SpecializedF) .createThunk(); NewFunctions.push_back(Thunk); + SILBuilderWithScope Builder(PAI); auto *FRI = Builder.createFunctionRef(PAI->getLoc(), Thunk); SmallVector Arguments; for (auto &Op : PAI->getArgumentOperands()) { @@ -2468,8 +2476,7 @@ void swift::trySpecializeApplyOfGeneric( for (Operand *Use : NewPAI->getUses()) { SILInstruction *User = Use->getUser(); if (auto FAS = FullApplySite::isa(User)) { - SILBuilder Builder(User); - replaceWithSpecializedCallee(FAS, NewPAI, Builder, ReInfo); + replaceWithSpecializedCallee(FAS, NewPAI, ReInfo); DeadApplies.insert(FAS.getInstruction()); continue; } diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp index e5dee815a58c8..44da2a6458d8f 100644 --- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp +++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp @@ -637,6 +637,13 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI, if (!SILInliner::canInlineApplySite(AI)) return nullptr; + // If our inline selection is only always inline, do a quick check if we have + // an always inline function and bail otherwise. + if (WhatToInline == InlineSelection::OnlyInlineAlways && + Callee->getInlineStrategy() != AlwaysInline) { + return nullptr; + } + ModuleDecl *SwiftModule = Callee->getModule().getSwiftModule(); bool IsInStdlib = (SwiftModule->isStdlibModule() || SwiftModule->isOnoneSupportModule()); @@ -644,7 +651,7 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI, // Don't inline functions that are marked with the @_semantics or @_effects // attribute if the inliner is asked not to inline them. if (Callee->hasSemanticsAttrs() || Callee->hasEffectsKind()) { - if (WhatToInline == InlineSelection::NoSemanticsAndGlobalInit) { + if (WhatToInline >= InlineSelection::NoSemanticsAndGlobalInit) { if (shouldSkipApplyDuringEarlyInlining(AI)) return nullptr; if (Callee->hasSemanticsAttr("inline_late")) @@ -692,13 +699,14 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI, // Check if passed Self is the same as the Self of the caller. // In this case, it is safe to inline because both functions // use the same Self. - if (AI.hasSelfArgument() && Caller->hasSelfMetadataParam()) { - auto CalleeSelf = stripCasts(AI.getSelfArgument()); - auto CallerSelf = Caller->getSelfMetadataArgument(); - if (CalleeSelf != SILValue(CallerSelf)) - return nullptr; - } else + if (!AI.hasSelfArgument() || !Caller->hasSelfMetadataParam()) { return nullptr; + } + auto CalleeSelf = stripCasts(AI.getSelfArgument()); + auto CallerSelf = Caller->getSelfMetadataArgument(); + if (CalleeSelf != SILValue(CallerSelf)) { + return nullptr; + } } // Detect self-recursive calls. diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 2b9a9facf1dea..a63c2c697cb7c 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -49,6 +49,7 @@ class BuilderClosureVisitor ASTContext &ctx; Type builderType; NominalTypeDecl *builder = nullptr; + Identifier buildOptionalId; llvm::SmallDenseMap supportedOps; SkipUnhandledConstructInFunctionBuilder::UnhandledNode unhandledNode; @@ -201,6 +202,14 @@ class BuilderClosureVisitor builder = builderType->getAnyNominal(); applied.builderType = builderType; applied.bodyResultType = bodyResultType; + + // Use buildOptional(_:) if available, otherwise fall back to buildIf + // when available. + if (builderSupports(ctx.Id_buildOptional) || + !builderSupports(ctx.Id_buildIf)) + buildOptionalId = ctx.Id_buildOptional; + else + buildOptionalId = ctx.Id_buildIf; } /// Apply the builder transform to the given statement. @@ -210,6 +219,15 @@ class BuilderClosureVisitor return None; applied.returnExpr = buildVarRef(bodyVar, stmt->getEndLoc()); + + // If there is a buildFinalResult(_:), call it. + ASTContext &ctx = cs->getASTContext(); + if (builderSupports(ctx.Id_buildFinalResult, { Identifier() })) { + applied.returnExpr = buildCallIfWanted( + applied.returnExpr->getLoc(), ctx.Id_buildFinalResult, + { applied.returnExpr }, { Identifier() }); + } + applied.returnExpr = cs->buildTypeErasedExpr(applied.returnExpr, dc, applied.bodyResultType, CTP_ReturnStmt); @@ -407,8 +425,8 @@ class BuilderClosureVisitor if (!isBuildableIfChainRecursive(ifStmt, numPayloads, isOptional)) return false; - // If there's a missing 'else', we need 'buildIf' to exist. - if (isOptional && !builderSupports(ctx.Id_buildIf)) + // If there's a missing 'else', we need 'buildOptional' to exist. + if (isOptional && !builderSupports(buildOptionalId)) return false; // If there are multiple clauses, we need 'buildEither(first:)' and @@ -514,9 +532,9 @@ class BuilderClosureVisitor // The operand should have optional type if we had optional results, // so we just need to call `buildIf` now, since we're at the top level. if (isOptional && isTopLevel) { - thenExpr = buildCallIfWanted(ifStmt->getEndLoc(), ctx.Id_buildIf, + thenExpr = buildCallIfWanted(ifStmt->getEndLoc(), buildOptionalId, thenExpr, /*argLabels=*/{ }); - elseExpr = buildCallIfWanted(ifStmt->getEndLoc(), ctx.Id_buildIf, + elseExpr = buildCallIfWanted(ifStmt->getEndLoc(), buildOptionalId, elseExpr, /*argLabels=*/{ }); } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 4ea3abc130ede..1204d72ca2ff3 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -4219,7 +4219,7 @@ namespace { Type baseTy, leafTy; Type exprType = cs.getType(E); if (auto fnTy = exprType->getAs()) { - baseTy = fnTy->getParams()[0].getPlainType(); + baseTy = fnTy->getParams()[0].getParameterType(); leafTy = fnTy->getResult(); isFunctionType = true; } else { @@ -4228,12 +4228,15 @@ namespace { leafTy = keyPathTy->getGenericArgs()[1]; } + // Track the type of the current component. Once we finish projecting + // through each component of the key path, we should reach the leafTy. + auto componentTy = baseTy; for (unsigned i : indices(E->getComponents())) { auto &origComponent = E->getMutableComponents()[i]; // If there were unresolved types, we may end up with a null base for // following components. - if (!baseTy) { + if (!componentTy) { resolvedComponents.push_back(origComponent); continue; } @@ -4255,7 +4258,7 @@ namespace { if (!foundDecl) { // If we couldn't resolve the component, leave it alone. resolvedComponents.push_back(origComponent); - baseTy = origComponent.getComponentType(); + componentTy = origComponent.getComponentType(); continue; } @@ -4294,9 +4297,9 @@ namespace { didOptionalChain = true; // Chaining always forces the element to be an rvalue. auto objectTy = - baseTy->getWithoutSpecifierType()->getOptionalObjectType(); - if (baseTy->hasUnresolvedType() && !objectTy) { - objectTy = baseTy; + componentTy->getWithoutSpecifierType()->getOptionalObjectType(); + if (componentTy->hasUnresolvedType() && !objectTy) { + objectTy = componentTy; } assert(objectTy); @@ -4316,7 +4319,7 @@ namespace { } case KeyPathExpr::Component::Kind::Identity: { auto component = origComponent; - component.setComponentType(baseTy); + component.setComponentType(componentTy); resolvedComponents.push_back(component); break; } @@ -4327,21 +4330,20 @@ namespace { llvm_unreachable("already resolved"); } - // Update "baseTy" with the result type of the last component. + // Update "componentTy" with the result type of the last component. assert(!resolvedComponents.empty()); - baseTy = resolvedComponents.back().getComponentType(); + componentTy = resolvedComponents.back().getComponentType(); } // Wrap a non-optional result if there was chaining involved. - if (didOptionalChain && - baseTy && - !baseTy->hasUnresolvedType() && - !baseTy->getWithoutSpecifierType()->isEqual(leafTy)) { + if (didOptionalChain && componentTy && + !componentTy->hasUnresolvedType() && + !componentTy->getWithoutSpecifierType()->isEqual(leafTy)) { assert(leafTy->getOptionalObjectType()->isEqual( - baseTy->getWithoutSpecifierType())); + componentTy->getWithoutSpecifierType())); auto component = KeyPathExpr::Component::forOptionalWrap(leafTy); resolvedComponents.push_back(component); - baseTy = leafTy; + componentTy = leafTy; } // Set the resolved components, and cache their types. @@ -4367,8 +4369,8 @@ namespace { // The final component type ought to line up with the leaf type of the // key path. - assert(!baseTy || baseTy->hasUnresolvedType() - || baseTy->getWithoutSpecifierType()->isEqual(leafTy)); + assert(!componentTy || componentTy->hasUnresolvedType() + || componentTy->getWithoutSpecifierType()->isEqual(leafTy)); if (!isFunctionType) return E; @@ -4378,9 +4380,6 @@ namespace { // this; we're going to change E's type to KeyPath and // then wrap it in a larger closure expression with the appropriate type. - // baseTy has been overwritten by the loop above; restore it. - baseTy = exprType->getAs()->getParams()[0].getPlainType(); - // Compute KeyPath and set E's type back to it. auto kpDecl = cs.getASTContext().getKeyPathDecl(); auto keyPathTy = diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 335f8cb96dcf8..5b8eb766bbde9 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -30,17 +30,14 @@ void ConstraintSystem::inferTransitiveSupertypeBindings( llvm::SmallVector subtypeOf; // First, let's collect all of the `subtype` constraints associated // with this type variable. - llvm::copy_if( - bindings.Sources, std::back_inserter(subtypeOf), - [&](const Constraint *constraint) -> bool { - if (constraint->getKind() != ConstraintKind::Subtype && - constraint->getKind() != ConstraintKind::ArgumentConversion && - constraint->getKind() != ConstraintKind::OperatorArgumentConversion) - return false; - - auto rhs = simplifyType(constraint->getSecondType()); - return rhs->getAs() == typeVar; - }); + llvm::copy_if(bindings.Sources, std::back_inserter(subtypeOf), + [&](const Constraint *constraint) -> bool { + if (constraint->getKind() != ConstraintKind::Subtype) + return false; + + auto rhs = simplifyType(constraint->getSecondType()); + return rhs->getAs() == typeVar; + }); if (subtypeOf.empty()) return; @@ -635,7 +632,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { continue; literalBindings.push_back( - {defaultType, AllowedBindingKind::Exact, constraint}); + {defaultType, AllowedBindingKind::Subtypes, constraint}); continue; } @@ -661,7 +658,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { if (!matched) { exactTypes.insert(defaultType->getCanonicalType()); literalBindings.push_back( - {defaultType, AllowedBindingKind::Exact, constraint}); + {defaultType, AllowedBindingKind::Subtypes, constraint}); } break; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index d701dd5800030..9b730047338a6 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2366,10 +2366,11 @@ namespace { // Remove an optional from the object type. if (externalPatternType) { Type objVar = CS.createTypeVariable( - CS.getConstraintLocator(locator), TVO_CanBindToNoEscape); + CS.getConstraintLocator( + locator.withPathElement(ConstraintLocator::OptionalPayload)), + TVO_CanBindToNoEscape); CS.addConstraint( - ConstraintKind::OptionalObject, externalPatternType, - objVar, + ConstraintKind::OptionalObject, externalPatternType, objVar, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); externalPatternType = objVar; @@ -2392,9 +2393,11 @@ namespace { castType, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); - Type subPatternType = - getTypeForPattern(isPattern->getSubPattern(), locator, castType, - bindPatternVarsOneWay); + auto *subPattern = isPattern->getSubPattern(); + Type subPatternType = getTypeForPattern( + subPattern, + locator.withPathElement(LocatorPathElt::PatternMatch(subPattern)), + castType, bindPatternVarsOneWay); // Make sure we can cast from the subpattern type to the type we're // checking; if it's impossible, fail. @@ -2427,16 +2430,20 @@ namespace { // Resolve the parent type. Type parentType = resolveTypeReferenceInExpression(enumPattern->getParentType()); + parentType = CS.openUnboundGenericType( - parentType, - locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); + parentType, CS.getConstraintLocator( + locator, {LocatorPathElt::PatternMatch(pattern), + ConstraintLocator::ParentType})); // Perform member lookup into the parent's metatype. Type parentMetaType = MetatypeType::get(parentType); CS.addValueMemberConstraint( parentMetaType, enumPattern->getName(), memberType, CurDC, - functionRefKind, { }, - locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); + functionRefKind, {}, + CS.getConstraintLocator(locator, + {LocatorPathElt::PatternMatch(pattern), + ConstraintLocator::Member})); // Parent type needs to be convertible to the pattern type; this // accounts for cases where the pattern type is existential. diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 93f8c6dcda803..aa4dd1bdd2da7 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -651,58 +651,67 @@ matchCallArguments(SmallVectorImpl &args, // parameter (or even worse - OoO parameter with label re-naming), // we most likely have no idea what would be the best // diagnostic for this situation, so let's just try to re-label. - auto isOutOfOrderArgument = [&](bool hadLabelMismatch, unsigned argIdx, - unsigned prevArgIdx) { - if (hadLabelMismatch) + auto isOutOfOrderArgument = [&](unsigned toParamIdx, unsigned fromArgIdx, + unsigned toArgIdx) { + if (fromArgIdx <= toArgIdx) { return false; + } + + auto newLabel = args[fromArgIdx].getLabel(); + auto oldLabel = args[toArgIdx].getLabel(); - auto newLabel = args[argIdx].getLabel(); - auto oldLabel = args[prevArgIdx].getLabel(); + if (newLabel != params[toParamIdx].getLabel()) { + return false; + } - unsigned actualIndex = prevArgIdx; - for (; actualIndex != argIdx; ++actualIndex) { + auto paramIdx = toParamIdx + 1; + for (; paramIdx < params.size(); ++paramIdx) { // Looks like new position (excluding defaulted parameters), // has a valid label. - if (newLabel == params[actualIndex].getLabel()) + if (oldLabel == params[paramIdx].getLabel()) break; // If we are moving the the position with a different label // and there is no default value for it, can't diagnose the // problem as a simple re-ordering. - if (!paramInfo.hasDefaultArgument(actualIndex)) + if (!paramInfo.hasDefaultArgument(paramIdx)) return false; } - for (unsigned i = actualIndex + 1, n = params.size(); i != n; ++i) { - if (oldLabel == params[i].getLabel()) - break; - - if (!paramInfo.hasDefaultArgument(i)) - return false; + // label was not found + if (paramIdx == params.size()) { + return false; } return true; }; - unsigned argIdx = 0; + SmallVector paramToArgMap; + paramToArgMap.reserve(params.size()); + { + unsigned argIdx = 0; + for (const auto &binding : parameterBindings) { + paramToArgMap.push_back(argIdx); + argIdx += binding.size(); + } + } + // Enumerate the parameters and their bindings to see if any arguments are // our of order bool hadLabelMismatch = false; - for (auto binding : parameterBindings) { - for (auto boundArgIdx : binding) { + for (const auto paramIdx : indices(params)) { + const auto toArgIdx = paramToArgMap[paramIdx]; + const auto &binding = parameterBindings[paramIdx]; + for (const auto paramBindIdx : indices(binding)) { // We've found the parameter that has an out of order // argument, and know the indices of the argument that // needs to move (fromArgIdx) and the argument location // it should move to (toArgIdx). - auto fromArgIdx = boundArgIdx; - auto toArgIdx = argIdx; + const auto fromArgIdx = binding[paramBindIdx]; - // If there is no re-ordering going on, and index is past - // the number of parameters, it could only mean that this - // is variadic parameter, so let's just move on. - if (fromArgIdx == toArgIdx && toArgIdx >= params.size()) { + // Does nothing for variadic tail. + if (params[paramIdx].isVariadic() && paramBindIdx > 0) { assert(args[fromArgIdx].getLabel().empty()); - argIdx++; continue; } @@ -711,40 +720,40 @@ matchCallArguments(SmallVectorImpl &args, // one argument requires label and another one doesn't, but caller // doesn't provide either, problem is going to be identified as // out-of-order argument instead of label mismatch. - auto expectedLabel = params[toArgIdx].getLabel(); - auto argumentLabel = args[fromArgIdx].getLabel(); + const auto expectedLabel = params[paramIdx].getLabel(); + const auto argumentLabel = args[fromArgIdx].getLabel(); if (argumentLabel != expectedLabel) { // - The parameter is unnamed, in which case we try to fix the // problem by removing the name. if (expectedLabel.empty()) { hadLabelMismatch = true; - if (listener.extraneousLabel(toArgIdx)) + if (listener.extraneousLabel(paramIdx)) return true; // - The argument is unnamed, in which case we try to fix the // problem by adding the name. } else if (argumentLabel.empty()) { hadLabelMismatch = true; - if (listener.missingLabel(toArgIdx)) + if (listener.missingLabel(paramIdx)) return true; // - The argument label has a typo at the same position. } else if (fromArgIdx == toArgIdx) { hadLabelMismatch = true; - if (listener.incorrectLabel(toArgIdx)) - return true; + if (listener.incorrectLabel(paramIdx)) + return true; } } - if (boundArgIdx == argIdx) { + if (fromArgIdx == toArgIdx) { // If the argument is in the right location, just continue - argIdx++; continue; } // This situation looks like out-of-order argument but it's hard // to say exactly without considering other factors, because it // could be invalid labeling too. - if (isOutOfOrderArgument(hadLabelMismatch, fromArgIdx, toArgIdx)) + if (!hadLabelMismatch && + isOutOfOrderArgument(paramIdx, fromArgIdx, toArgIdx)) return listener.outOfOrderArgument(fromArgIdx, toArgIdx); SmallVector expectedLabels; @@ -7419,7 +7428,11 @@ ConstraintSystem::simplifyKeyPathConstraint( if (fnTy->getParams().size() != 1) return false; - boundRoot = fnTy->getParams()[0].getPlainType(); + // Match up the root and value types to the function's param and return + // types. Note that we're using the type of the parameter as referenced + // from inside the function body as we'll be transforming the code into: + // { root in root[keyPath: kp] }. + boundRoot = fnTy->getParams()[0].getParameterType(); boundValue = fnTy->getResult(); } @@ -9221,8 +9234,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( // subscript, which requires changes to declaration to become mutable. if (auto last = locator.last()) { impact += (last->is() || - last->is() || - last->is()) + last->is()) ? 1 : 0; } diff --git a/lib/Sema/CSStep.cpp b/lib/Sema/CSStep.cpp index 6ae08628df958..b89575c617016 100644 --- a/lib/Sema/CSStep.cpp +++ b/lib/Sema/CSStep.cpp @@ -220,6 +220,7 @@ bool SplitterStep::mergePartialSolutions() const { ArrayRef counts = countsVec; SmallVector indices(numComponents, 0); bool anySolutions = false; + size_t solutionMemory = 0; do { // Create a new solver scope in which we apply all of the relevant partial // solutions. @@ -236,6 +237,7 @@ bool SplitterStep::mergePartialSolutions() const { if (!CS.worseThanBestSolution()) { // Finalize this solution. auto solution = CS.finalize(); + solutionMemory += solution.getTotalMemory(); if (isDebugMode()) getDebugLogger() << "(composed solution " << CS.CurrentScore << ")\n"; @@ -243,6 +245,12 @@ bool SplitterStep::mergePartialSolutions() const { Solutions.push_back(std::move(solution)); anySolutions = true; } + + // Since merging partial solutions can go exponential, make sure we didn't + // pass the "too complex" thresholds including allocated memory and time. + if (CS.getExpressionTooComplex(solutionMemory)) + return false; + } while (nextCombination(counts, indices)); return anySolutions; diff --git a/lib/Sema/CSStep.h b/lib/Sema/CSStep.h index 54d2c863654a8..1b9317a8cd8a7 100644 --- a/lib/Sema/CSStep.h +++ b/lib/Sema/CSStep.h @@ -619,15 +619,6 @@ class TypeVariableStep final : public BindingStep { /// Check whether attempting type variable binding choices should /// be stopped, because optimal solution has already been found. bool shouldStopAt(const TypeVariableBinding &choice) const override { - if (CS.shouldAttemptFixes()) { - // Let's always attempt default types inferred from literals - // in diagnostic mode because that could lead to better - // diagnostics if the problem is contextual like argument/parameter - // conversion or collection element mismatch. - if (choice.hasDefaultedProtocol()) - return false; - } - // If we were able to solve this without considering // default literals, don't bother looking at default literals. return AnySolved && choice.hasDefaultedProtocol() && diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index ecefad1941da1..ba6e6975a5886 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -504,6 +504,12 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator( {LocatorPathElt::ApplyFunction(), LocatorPathElt::ImplicitCallAsFunction()}); } + + // Handling an apply for a nominal type that supports @dynamicCallable. + if (fnTy->hasDynamicCallableAttribute()) { + return getConstraintLocator(anchor, LocatorPathElt::ApplyFunction()); + } + return nullptr; }; @@ -919,7 +925,7 @@ Type ConstraintSystem::getUnopenedTypeOfReference(VarDecl *value, Type baseType, DeclContext *UseDC, const DeclRefExpr *base, bool wantInterfaceType) { - return TypeChecker::getUnopenedTypeOfReference( + return ConstraintSystem::getUnopenedTypeOfReference( value, baseType, UseDC, [&](VarDecl *var) -> Type { if (Type type = getTypeIfAvailable(var)) @@ -934,7 +940,7 @@ Type ConstraintSystem::getUnopenedTypeOfReference(VarDecl *value, Type baseType, base, wantInterfaceType); } -Type TypeChecker::getUnopenedTypeOfReference( +Type ConstraintSystem::getUnopenedTypeOfReference( VarDecl *value, Type baseType, DeclContext *UseDC, llvm::function_ref getType, const DeclRefExpr *base, bool wantInterfaceType) { @@ -1399,9 +1405,9 @@ ConstraintSystem::getTypeOfMemberReference( ->castTo()->getParams(); refType = FunctionType::get(indices, elementTy); } else { - refType = TypeChecker::getUnopenedTypeOfReference( - cast(value), baseTy, useDC, base, - /*wantInterfaceType=*/true); + refType = + getUnopenedTypeOfReference(cast(value), baseTy, useDC, base, + /*wantInterfaceType=*/true); } auto selfTy = outerDC->getSelfInterfaceType(); diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index f2e06f8d6d45a..35152414830b6 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3260,6 +3260,25 @@ class ConstraintSystem { const DeclRefExpr *base = nullptr, bool wantInterfaceType = false); + /// Return the type-of-reference of the given value. + /// + /// \param baseType if non-null, return the type of a member reference to + /// this value when the base has the given type + /// + /// \param UseDC The context of the access. Some variables have different + /// types depending on where they are used. + /// + /// \param base The optional base expression of this value reference + /// + /// \param wantInterfaceType Whether we want the interface type, if available. + /// + /// \param getType Optional callback to extract a type for given declaration. + static Type + getUnopenedTypeOfReference(VarDecl *value, Type baseType, DeclContext *UseDC, + llvm::function_ref getType, + const DeclRefExpr *base = nullptr, + bool wantInterfaceType = false); + /// Retrieve the type of a reference to the given value declaration, /// as a member with a base of the given type. /// @@ -4469,14 +4488,11 @@ class ConstraintSystem { /// Determine if we've already explored too many paths in an /// attempt to solve this expression. bool isExpressionAlreadyTooComplex = false; - bool getExpressionTooComplex(SmallVectorImpl const &solutions) { + bool getExpressionTooComplex(size_t solutionMemory) { if (isExpressionAlreadyTooComplex) return true; - auto used = getASTContext().getSolverMemory(); - for (auto const& s : solutions) { - used += s.getTotalMemory(); - } + auto used = getASTContext().getSolverMemory() + solutionMemory; MaxMemory = std::max(used, MaxMemory); auto threshold = getASTContext().TypeCheckerOpts.SolverMemoryThreshold; if (MaxMemory > threshold) { @@ -4503,6 +4519,14 @@ class ConstraintSystem { return false; } + bool getExpressionTooComplex(SmallVectorImpl const &solutions) { + size_t solutionMemory = 0; + for (auto const& s : solutions) { + solutionMemory += s.getTotalMemory(); + } + return getExpressionTooComplex(solutionMemory); + } + // Utility class that can collect information about the type of an // argument in an apply. // diff --git a/lib/Sema/NameBinding.cpp b/lib/Sema/NameBinding.cpp index c699aaf0e7060..bc7f152a2b64e 100644 --- a/lib/Sema/NameBinding.cpp +++ b/lib/Sema/NameBinding.cpp @@ -33,6 +33,7 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/SaveAndRestore.h" #include diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 7d02105bbced2..780793189f20b 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -1774,31 +1774,16 @@ void PreCheckExpression::resolveKeyPathExpr(KeyPathExpr *KPE) { auto traversePath = [&](Expr *expr, bool isInParsedPath, bool emitErrors = true) { Expr *outermostExpr = expr; - // We can end up in scenarios where the key path has contextual type, - // but is missing a leading dot. This can happen when we have an - // implicit TypeExpr or an implicit DeclRefExpr. - auto diagnoseMissingDot = [&]() { - DE.diagnose(expr->getLoc(), - diag::expr_swift_keypath_not_starting_with_dot) - .fixItInsert(expr->getStartLoc(), "."); - }; while (1) { // Base cases: we've reached the top. if (auto TE = dyn_cast(expr)) { assert(!isInParsedPath); rootType = TE->getTypeRepr(); - if (TE->isImplicit()) { - diagnoseMissingDot(); - } return; } else if (isa(expr)) { assert(isInParsedPath); // Nothing here: the type is either the root, or is inferred. return; - } else if (expr->isImplicit() && isa(expr)) { - assert(!isInParsedPath); - diagnoseMissingDot(); - return; } // Recurring cases: @@ -4233,18 +4218,18 @@ IsCallableNominalTypeRequest::evaluate(Evaluator &evaluator, CanType ty, }); } -llvm::Expected -HasDynamicMemberLookupAttributeRequest::evaluate(Evaluator &evaluator, - CanType ty) const { +template +static bool checkForDynamicAttribute(CanType ty, + llvm::function_ref hasAttribute) { // If this is an archetype type, check if any types it conforms to // (superclass or protocols) have the attribute. if (auto archetype = dyn_cast(ty)) { for (auto proto : archetype->getConformsTo()) { - if (proto->getDeclaredType()->hasDynamicMemberLookupAttribute()) + if (hasAttribute(proto->getDeclaredType())) return true; } if (auto superclass = archetype->getSuperclass()) { - if (superclass->hasDynamicMemberLookupAttribute()) + if (hasAttribute(superclass)) return true; } } @@ -4253,33 +4238,50 @@ HasDynamicMemberLookupAttributeRequest::evaluate(Evaluator &evaluator, // attribute. if (auto protocolComp = dyn_cast(ty)) { for (auto member : protocolComp->getMembers()) { - if (member->hasDynamicMemberLookupAttribute()) + if (hasAttribute(member)) return true; } } // Otherwise, this must be a nominal type. - // Dynamic member lookup doesn't work for tuples, etc. + // Neither Dynamic member lookup nor Dynamic Callable doesn't + // work for tuples, etc. auto nominal = ty->getAnyNominal(); if (!nominal) return false; // If this type has the attribute on it, then yes! - if (nominal->getAttrs().hasAttribute()) + if (nominal->getAttrs().hasAttribute()) return true; // Check the protocols the type conforms to. for (auto proto : nominal->getAllProtocols()) { - if (proto->getDeclaredType()->hasDynamicMemberLookupAttribute()) + if (hasAttribute(proto->getDeclaredType())) return true; } // Check the superclass if present. if (auto classDecl = dyn_cast(nominal)) { if (auto superclass = classDecl->getSuperclass()) { - if (superclass->hasDynamicMemberLookupAttribute()) + if (hasAttribute(superclass)) return true; } } return false; } + +llvm::Expected +HasDynamicMemberLookupAttributeRequest::evaluate(Evaluator &evaluator, + CanType ty) const { + return checkForDynamicAttribute(ty, [](Type type) { + return type->hasDynamicMemberLookupAttribute(); + }); +} + +llvm::Expected +HasDynamicCallableAttributeRequest::evaluate(Evaluator &evaluator, + CanType ty) const { + return checkForDynamicAttribute(ty, [](Type type) { + return type->hasDynamicCallableAttribute(); + }); +} diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index 4b29c80c079bd..6e61250fa73cf 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -23,6 +23,8 @@ #include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Parse/Lexer.h" +#include "ConstraintSystem.h" + using namespace swift; //===----------------------------------------------------------------------===// @@ -591,7 +593,9 @@ bool TypeChecker::requireArrayLiteralIntrinsics(ASTContext &ctx, Expr *TypeChecker::buildCheckedRefExpr(VarDecl *value, DeclContext *UseDC, DeclNameLoc loc, bool Implicit) { - auto type = TypeChecker::getUnopenedTypeOfReference(value, Type(), UseDC); + auto type = constraints::ConstraintSystem::getUnopenedTypeOfReference( + value, Type(), UseDC, + [&](VarDecl *var) -> Type { return value->getType(); }); auto semantics = value->getAccessSemanticsFromContext(UseDC, /*isAccessOnSelf*/false); return new (value->getASTContext()) diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 537fefb347202..c0b7666f971fe 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -429,7 +429,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, // Add the type to the result set, so that we can diagnose the // reference instead of just saying the member does not exist. if (types.insert(memberType->getCanonicalType()).second) - result.Results.push_back({typeDecl, memberType, nullptr}); + result.addResult({typeDecl, memberType, nullptr}); continue; } @@ -475,10 +475,10 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) - result.Results.push_back({typeDecl, memberType, nullptr}); + result.addResult({typeDecl, memberType, nullptr}); } - if (result.Results.empty()) { + if (!result) { // We couldn't find any normal declarations. Let's try inferring // associated types. ConformanceCheckOptions conformanceOptions; @@ -517,7 +517,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, auto memberType = substMemberTypeWithBase(dc->getParentModule(), typeDecl, type); if (types.insert(memberType->getCanonicalType()).second) - result.Results.push_back({typeDecl, memberType, assocType}); + result.addResult({typeDecl, memberType, assocType}); } } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index f315fae69d82a..9083f1ffab91e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2683,6 +2683,16 @@ Type TypeResolver::resolveASTFunctionType( auto extInfo = incompleteExtInfo.withRepresentation(representation) .withClangFunctionType(clangFnType); + // Diagnose a couple of things that we can parse in SIL mode but we don't + // allow in formal types. + if (auto patternParams = repr->getPatternGenericParams()) { + diagnose(patternParams->getLAngleLoc(), + diag::ast_subst_function_type); + } else if (!repr->getInvocationSubstitutions().empty()) { + diagnose(repr->getInvocationSubstitutions()[0]->getStartLoc(), + diag::ast_subst_function_type); + } + // SIL uses polymorphic function types to resolve overloaded member functions. if (auto genericEnv = repr->getGenericEnvironment()) { outputTy = outputTy->mapTypeOutOfContext(); @@ -2794,14 +2804,22 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, SmallVector yields; SmallVector results; Optional errorResult; + + // Resolve generic params in the pattern environment, if present, or + // else the function's generic environment, if it has one. + GenericEnvironment *genericEnv = repr->getGenericEnvironment(); + GenericEnvironment *componentTypeEnv = + repr->getPatternGenericEnvironment() + ? repr->getPatternGenericEnvironment() + : genericEnv; + { Optional resolveSILFunctionGenericParams; Optional> useSILFunctionGenericEnv; - - // Resolve generic params using the function's generic environment, if it - // has one. - if (auto env = repr->getGenericEnvironment()) { - resolveSILFunctionGenericParams = TypeResolution::forContextual(DC, env); + + if (componentTypeEnv) { + resolveSILFunctionGenericParams = + TypeResolution::forContextual(DC, componentTypeEnv); useSILFunctionGenericEnv.emplace(resolution, *resolveSILFunctionGenericParams); } @@ -2843,37 +2861,60 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, } } } // restore generic type resolution - - // Resolve substitutions if we have them. - SubstitutionMap subs; - if (!repr->getSubstitutions().empty()) { - auto sig = repr->getGenericEnvironment() - ->getGenericSignature() - .getCanonicalSignature(); + + auto resolveSubstitutions = [&](GenericEnvironment *env, + ArrayRef args) { + auto sig = env->getGenericSignature().getCanonicalSignature(); TypeSubstitutionMap subsMap; auto params = sig->getGenericParams(); - for (unsigned i : indices(repr->getSubstitutions())) { - auto resolved = resolveType(repr->getSubstitutions()[i], options); + for (unsigned i : indices(args)) { + auto resolved = resolveType(args[i], options); subsMap.insert({params[i], resolved->getCanonicalType()}); } - subs = SubstitutionMap::get(sig, QueryTypeSubstitutionMap{subsMap}, + return SubstitutionMap::get(sig, QueryTypeSubstitutionMap{subsMap}, TypeChecker::LookUpConformance(DC)) .getCanonical(); + }; + + // Resolve pattern substitutions in the invocation environment, if + // applicable. + SubstitutionMap patternSubs; + if (!repr->getPatternSubstitutions().empty()) { + Optional resolveSILFunctionGenericParams; + Optional> useSILFunctionGenericEnv; + if (genericEnv) { + resolveSILFunctionGenericParams = + TypeResolution::forContextual(DC, genericEnv); + useSILFunctionGenericEnv.emplace(resolution, + *resolveSILFunctionGenericParams); + } + + patternSubs = resolveSubstitutions(repr->getPatternGenericEnvironment(), + repr->getPatternSubstitutions()); + } + + // Resolve invocation substitutions if we have them. + SubstitutionMap invocationSubs; + if (!repr->getInvocationSubstitutions().empty()) { + invocationSubs = resolveSubstitutions(repr->getGenericEnvironment(), + repr->getInvocationSubstitutions()); } if (hasError) { return ErrorType::get(Context); } + CanGenericSignature genericSig = + genericEnv ? genericEnv->getGenericSignature().getCanonicalSignature() + : CanGenericSignature(); + + // FIXME: Remap the parsed context types to interface types. - CanGenericSignature genericSig; SmallVector interfaceParams; SmallVector interfaceYields; SmallVector interfaceResults; Optional interfaceErrorResult; - if (auto *genericEnv = repr->getGenericEnvironment()) { - genericSig = genericEnv->getGenericSignature().getCanonicalSignature(); - + if (componentTypeEnv) { for (auto ¶m : params) { auto transParamType = param.getInterfaceType()->mapTypeOutOfContext() ->getCanonicalType(); @@ -2903,6 +2944,13 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, interfaceResults = results; interfaceErrorResult = errorResult; } + + SubstitutionMap interfacePatternSubs = patternSubs; + if (interfacePatternSubs && repr->getGenericEnvironment()) { + interfacePatternSubs = + interfacePatternSubs.mapReplacementTypesOutOfContext(); + } + ProtocolConformanceRef witnessMethodConformance; if (witnessMethodProtocol) { auto resolved = resolveType(witnessMethodProtocol, options); @@ -2914,8 +2962,10 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, return ErrorType::get(Context); Type selfType = params.back().getInterfaceType(); - if (subs) { - selfType = selfType.subst(subs); + if (patternSubs) + selfType = selfType.subst(patternSubs); + if (invocationSubs) { + selfType = selfType.subst(invocationSubs); } // The Self type can be nested in a few layers of metatypes (etc.). @@ -2936,8 +2986,7 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, callee, interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, - subs, - repr->areGenericParamsImplied(), + interfacePatternSubs, invocationSubs, Context, witnessMethodConformance); } @@ -3625,6 +3674,10 @@ class UnsupportedProtocolVisitor return !checkStatements; } + void visitTypeRepr(TypeRepr *T) { + // Do nothing for all TypeReprs except the ones listed below. + } + void visitIdentTypeRepr(IdentTypeRepr *T) { if (T->isInvalid()) return; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index dbdce08253b0b..b14ad7fd2c902 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -90,8 +90,6 @@ class LookupTypeResult { /// The set of results found. SmallVector Results; - friend class TypeChecker; - public: using iterator = SmallVectorImpl::iterator; iterator begin() { return Results.begin(); } @@ -989,49 +987,6 @@ class TypeChecker final { static bool contextualizeInitializer(Initializer *DC, Expr *init); static void contextualizeTopLevelCode(TopLevelCodeDecl *TLCD); - /// Return the type-of-reference of the given value. - /// - /// \param baseType if non-null, return the type of a member reference to - /// this value when the base has the given type - /// - /// \param UseDC The context of the access. Some variables have different - /// types depending on where they are used. - /// - /// \param base The optional base expression of this value reference - /// - /// \param wantInterfaceType Whether we want the interface type, if available. - /// - /// \param getType Optional callback to extract a type for given declaration. - static Type - getUnopenedTypeOfReference(VarDecl *value, Type baseType, DeclContext *UseDC, - llvm::function_ref getType, - const DeclRefExpr *base = nullptr, - bool wantInterfaceType = false); - - /// Return the type-of-reference of the given value. - /// - /// \param baseType if non-null, return the type of a member reference to - /// this value when the base has the given type - /// - /// \param UseDC The context of the access. Some variables have different - /// types depending on where they are used. - /// - /// \param base The optional base expression of this value reference - /// - /// \param wantInterfaceType Whether we want the interface type, if available. - static Type getUnopenedTypeOfReference(VarDecl *value, Type baseType, - DeclContext *UseDC, - const DeclRefExpr *base = nullptr, - bool wantInterfaceType = false) { - return getUnopenedTypeOfReference( - value, baseType, UseDC, - [&](VarDecl *var) -> Type { - return wantInterfaceType ? value->getInterfaceType() - : value->getType(); - }, - base, wantInterfaceType); - } - /// Retrieve the default type for the given protocol. /// /// Some protocols, particularly those that correspond to literals, have diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt index 44a2a90660bdf..ebeb4ab7d3003 100644 --- a/lib/Serialization/CMakeLists.txt +++ b/lib/Serialization/CMakeLists.txt @@ -12,5 +12,6 @@ add_swift_host_library(swiftSerialization STATIC BitstreamReader ) target_link_libraries(swiftSerialization PRIVATE - swiftClangImporter) + swiftClangImporter + swiftSIL) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index badadd70e1d77..3daed88e91baf 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -5190,9 +5190,9 @@ class TypeDeserializer { unsigned numParams; unsigned numYields; unsigned numResults; - bool isGenericSignatureImplied; - GenericSignatureID rawGenericSig; - SubstitutionMapID rawSubs; + GenericSignatureID rawInvocationGenericSig; + SubstitutionMapID rawInvocationSubs; + SubstitutionMapID rawPatternSubs; ArrayRef variableData; ClangTypeID clangFunctionTypeID; @@ -5207,9 +5207,9 @@ class TypeDeserializer { numParams, numYields, numResults, - isGenericSignatureImplied, - rawGenericSig, - rawSubs, + rawInvocationGenericSig, + rawInvocationSubs, + rawPatternSubs, clangFunctionTypeID, variableData); @@ -5355,14 +5355,18 @@ class TypeDeserializer { witnessMethodConformance = MF.readConformance(MF.DeclTypeCursor); } - GenericSignature genericSig = MF.getGenericSignature(rawGenericSig); - SubstitutionMap subs = MF.getSubstitutionMap(rawSubs).getCanonical(); - - return SILFunctionType::get(genericSig, extInfo, coroutineKind.getValue(), + GenericSignature invocationSig = + MF.getGenericSignature(rawInvocationGenericSig); + SubstitutionMap invocationSubs = + MF.getSubstitutionMap(rawInvocationSubs).getCanonical(); + SubstitutionMap patternSubs = + MF.getSubstitutionMap(rawPatternSubs).getCanonical(); + + return SILFunctionType::get(invocationSig, extInfo, coroutineKind.getValue(), calleeConvention.getValue(), allParams, allYields, allResults, errorResult, - subs, isGenericSignatureImplied, + patternSubs, invocationSubs, ctx, witnessMethodConformance); } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 986dfcabd2110..2e2e641ab957a 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 544; // TypeEraser +const uint16_t SWIFTMODULE_VERSION_MINOR = 546; // Avoid conflict with downstream bump /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1027,9 +1027,9 @@ namespace decls_block { BCVBR<6>, // number of parameters BCVBR<5>, // number of yields BCVBR<5>, // number of results - BCFixed<1>, // generic signature implied - GenericSignatureIDField, // generic signature - SubstitutionMapIDField, // substitutions + GenericSignatureIDField, // invocation generic signature + SubstitutionMapIDField, // invocation substitutions + SubstitutionMapIDField, // pattern substitutions ClangTypeIDField, // clang function type, for foreign conventions BCArray // parameter types/conventions, alternating // followed by result types/conventions, alternating diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index b555f52dc38e2..a5bc682619f95 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -4201,8 +4201,12 @@ class Serializer::TypeSerializer : public TypeVisitor { variableData.push_back(TypeID(conv)); } - auto sigID = S.addGenericSignatureRef(fnTy->getSubstGenericSignature()); - auto substMapID = S.addSubstitutionMapRef(fnTy->getSubstitutions()); + auto invocationSigID = + S.addGenericSignatureRef(fnTy->getInvocationGenericSignature()); + auto invocationSubstMapID = + S.addSubstitutionMapRef(fnTy->getInvocationSubstitutions()); + auto patternSubstMapID = + S.addSubstitutionMapRef(fnTy->getPatternSubstitutions()); auto clangTypeID = S.addClangTypeRef(fnTy->getClangFunctionType()); auto stableCoroutineKind = @@ -4221,8 +4225,8 @@ class Serializer::TypeSerializer : public TypeVisitor { stableRepresentation, fnTy->isPseudogeneric(), fnTy->isNoEscape(), stableDiffKind, fnTy->hasErrorResult(), fnTy->getParameters().size(), fnTy->getNumYields(), fnTy->getNumResults(), - fnTy->isGenericSignatureImplied(), - sigID, substMapID, clangTypeID, variableData); + invocationSigID, invocationSubstMapID, patternSubstMapID, + clangTypeID, variableData); if (auto conformance = fnTy->getWitnessMethodConformanceOrInvalid()) S.writeConformance(conformance, S.DeclTypeAbbrCodes); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index e8c15720e89f1..3b3a772982e34 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Debug.h" @@ -46,11 +47,17 @@ void forEachTargetModuleBasename(const ASTContext &Ctx, // FIXME: We used to use "major architecture" names for these files---the // names checked in "#if arch(...)". Fall back to that name in the one case - // where it's different from what Swift 4.2 supported: 32-bit ARM platforms. + // where it's different from what Swift 4.2 supported: + // - 32-bit ARM platforms (formerly "arm") + // - arm64e (formerly shared with "arm64") // We should be able to drop this once there's an Xcode that supports the // new names. if (Ctx.LangOpts.Target.getArch() == llvm::Triple::ArchType::arm) body("arm"); + else if (Ctx.LangOpts.Target.getSubArch() == + llvm::Triple::SubArchType::AArch64SubArch_E) { + body("arm64"); + } } enum class SearchPathKind { diff --git a/lib/SymbolGraphGen/Edge.cpp b/lib/SymbolGraphGen/Edge.cpp index e0f517b1aa762..011ef56fa7467 100644 --- a/lib/SymbolGraphGen/Edge.cpp +++ b/lib/SymbolGraphGen/Edge.cpp @@ -43,5 +43,14 @@ void Edge::serialize(llvm::json::OStream &OS) const { Target.printPath(PathOS); OS.attribute("targetFallback", Scratch.str()); } + + if (ConformanceExtension && + !ConformanceExtension->getGenericRequirements().empty()) { + OS.attributeArray("swiftConstraints", [&](){ + for (const auto &Req : ConformanceExtension->getGenericRequirements()) { + ::serialize(Req, OS); + } + }); + } }); } diff --git a/lib/SymbolGraphGen/Edge.h b/lib/SymbolGraphGen/Edge.h index b5769eb126d80..06291e1c81ef9 100644 --- a/lib/SymbolGraphGen/Edge.h +++ b/lib/SymbolGraphGen/Edge.h @@ -126,6 +126,10 @@ struct Edge { /// The precise identifier of the target symbol node. Symbol Target; + + /// If this is a conformsTo relationship, the extension that defined + /// the conformance. + const ExtensionDecl *ConformanceExtension; void serialize(llvm::json::OStream &OS) const; }; @@ -137,13 +141,15 @@ namespace llvm { using SymbolGraph = swift::symbolgraphgen::SymbolGraph; using Symbol = swift::symbolgraphgen::Symbol; using Edge = swift::symbolgraphgen::Edge; +using ExtensionDecl = swift::ExtensionDecl; template <> struct DenseMapInfo { static inline Edge getEmptyKey() { return { DenseMapInfo::getEmptyKey(), { "Empty" }, DenseMapInfo::getEmptyKey(), - DenseMapInfo::getEmptyKey() + DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey(), }; } static inline Edge getTombstoneKey() { @@ -152,6 +158,7 @@ template <> struct DenseMapInfo { { "Tombstone" }, DenseMapInfo::getTombstoneKey(), DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey(), }; } static unsigned getHashValue(const Edge E) { @@ -159,12 +166,16 @@ template <> struct DenseMapInfo { H ^= DenseMapInfo::getHashValue(E.Kind.Name); H ^= DenseMapInfo::getHashValue(E.Source); H ^= DenseMapInfo::getHashValue(E.Target); + H ^= DenseMapInfo:: + getHashValue(E.ConformanceExtension); return H; } static bool isEqual(const Edge LHS, const Edge RHS) { return LHS.Kind == RHS.Kind && DenseMapInfo::isEqual(LHS.Source, RHS.Source) && - DenseMapInfo::isEqual(LHS.Target, RHS.Target); + DenseMapInfo::isEqual(LHS.Target, RHS.Target) && + DenseMapInfo::isEqual(LHS.ConformanceExtension, + RHS.ConformanceExtension); } }; } // end namespace llvm diff --git a/lib/SymbolGraphGen/JSON.cpp b/lib/SymbolGraphGen/JSON.cpp index 6bb117daaeeb4..71d8ffea1ebcb 100644 --- a/lib/SymbolGraphGen/JSON.cpp +++ b/lib/SymbolGraphGen/JSON.cpp @@ -12,6 +12,8 @@ // Adds Symbol Graph JSON serialization to other types. //===----------------------------------------------------------------------===// +#include "swift/AST/Decl.h" +#include "swift/AST/Module.h" #include "JSON.h" void swift::symbolgraphgen::serialize(const llvm::VersionTuple &VT, @@ -55,3 +57,47 @@ void swift::symbolgraphgen::serialize(const llvm::Triple &T, }); }); } + +void swift::symbolgraphgen::serialize(const ExtensionDecl *Extension, + llvm::json::OStream &OS) { + OS.attributeObject("swiftExtension", [&](){ + if (const auto *ExtendedNominal = Extension->getExtendedNominal()) { + if (const auto *ExtendedModule = ExtendedNominal->getModuleContext()) { + OS.attribute("extendedModule", ExtendedModule->getNameStr()); + } + } + auto Generics = Extension->getGenericSignature(); + if (Generics && !Generics->getRequirements().empty()) { + OS.attributeArray("constraints", [&](){ + for (const auto &Requirement : Generics->getRequirements()) { + serialize(Requirement, OS); + } + }); // end constraints: + } + }); // end swiftExtension: +} + +void swift::symbolgraphgen::serialize(const Requirement &Req, + llvm::json::OStream &OS) { + StringRef Kind; + switch (Req.getKind()) { + case swift::RequirementKind::Conformance: + Kind = "conformance"; + break; + case swift::RequirementKind::Superclass: + Kind = "superclass"; + break; + case swift::RequirementKind::SameType: + Kind = "sameType"; + break; + case swift::RequirementKind::Layout: + return; + } + + OS.object([&](){ + OS.attribute("kind", Kind); + OS.attribute("lhs", Req.getFirstType()->getString()); + OS.attribute("rhs", Req.getSecondType()->getString()); + }); + +} diff --git a/lib/SymbolGraphGen/JSON.h b/lib/SymbolGraphGen/JSON.h index 0c0018da724cb..c3d7fdfa7154e 100644 --- a/lib/SymbolGraphGen/JSON.h +++ b/lib/SymbolGraphGen/JSON.h @@ -38,6 +38,8 @@ struct AttributeRAII { void serialize(const llvm::VersionTuple &VT, llvm::json::OStream &OS); void serialize(const llvm::Triple &T, llvm::json::OStream &OS); +void serialize(const ExtensionDecl *Extension, llvm::json::OStream &OS); +void serialize(const Requirement &Req, llvm::json::OStream &OS); } // end namespace symbolgraphgen } // end namespace swift diff --git a/lib/SymbolGraphGen/Symbol.cpp b/lib/SymbolGraphGen/Symbol.cpp index 548372e5d459e..7b1ee572d51d1 100644 --- a/lib/SymbolGraphGen/Symbol.cpp +++ b/lib/SymbolGraphGen/Symbol.cpp @@ -162,14 +162,18 @@ void Symbol::serializeRange(size_t InitialIndentation, } void Symbol::serializeDocComment(llvm::json::OStream &OS) const { + const auto *DocCommentProvidingDecl = + dyn_cast_or_null( + getDocCommentProvidingDecl(VD, /*AllowSerialized=*/true)); + if (!DocCommentProvidingDecl) { + DocCommentProvidingDecl = VD; + } + auto RC = DocCommentProvidingDecl->getRawComment(/*SerializedOK=*/true); + if (RC.isEmpty()) { + return; + } + OS.attributeObject("docComment", [&](){ - const auto *DocCommentProvidingDecl = - dyn_cast_or_null( - getDocCommentProvidingDecl(VD, /*AllowSerialized=*/true)); - if (!DocCommentProvidingDecl) { - DocCommentProvidingDecl = VD; - } - auto RC = DocCommentProvidingDecl->getRawComment(/*SerializedOK=*/true); auto LL = Graph->Ctx.getLineList(RC); size_t InitialIndentation = LL.getLines().empty() ? 0 @@ -241,30 +245,6 @@ void Symbol::serializeGenericParam(const swift::GenericTypeParamType &Param, }); } -void Symbol::serializeGenericRequirement(const swift::Requirement &Req, - llvm::json::OStream &OS) const { - StringRef Kind; - switch (Req.getKind()) { - case swift::RequirementKind::Conformance: - Kind = "conformance"; - break; - case swift::RequirementKind::Superclass: - Kind = "superclass"; - break; - case swift::RequirementKind::SameType: - Kind = "sameType"; - break; - case swift::RequirementKind::Layout: - return; - } - - OS.object([&](){ - OS.attribute("kind", Kind); - OS.attribute("lhs", Req.getFirstType()->getString()); - OS.attribute("rhs", Req.getSecondType()->getString()); - }); -} - void Symbol::serializeSwiftGenericMixin(llvm::json::OStream &OS) const { if (const auto *GC = VD->getAsGenericContext()) { if (const auto Generics = GC->getGenericSignature()) { @@ -286,7 +266,7 @@ void Symbol::serializeSwiftGenericMixin(llvm::json::OStream &OS) const { if (!Generics->getRequirements().empty()) { OS.attributeArray("constraints", [&](){ for (const auto &Requirement : Generics->getRequirements()) { - serializeGenericRequirement(Requirement, OS); + ::serialize(Requirement, OS); } }); // end constraints: } @@ -299,21 +279,7 @@ void Symbol::serializeSwiftGenericMixin(llvm::json::OStream &OS) const { void Symbol::serializeSwiftExtensionMixin(llvm::json::OStream &OS) const { if (const auto *Extension = dyn_cast_or_null(VD->getInnermostDeclContext())) { - OS.attributeObject("swiftExtension", [&](){ - if (const auto *ExtendedNominal = Extension->getExtendedNominal()) { - if (const auto *ExtendedModule = ExtendedNominal->getModuleContext()) { - OS.attribute("extendedModule", ExtendedModule->getNameStr()); - } - } - auto Generics = Extension->getGenericSignature(); - if (Generics && !Generics->getRequirements().empty()) { - OS.attributeArray("constraints", [&](){ - for (const auto &Requirement : Generics->getRequirements()) { - serializeGenericRequirement(Requirement, OS); - } - }); // end constraints: - } - }); // end swiftExtension: + ::serialize(Extension, OS); } } diff --git a/lib/SymbolGraphGen/Symbol.h b/lib/SymbolGraphGen/Symbol.h index 7c9770596e43e..4e5987e5b0274 100644 --- a/lib/SymbolGraphGen/Symbol.h +++ b/lib/SymbolGraphGen/Symbol.h @@ -58,9 +58,6 @@ class Symbol { void serializeGenericParam(const swift::GenericTypeParamType &Param, llvm::json::OStream &OS) const; - void serializeGenericRequirement(const swift::Requirement &Req, - llvm::json::OStream &OS) const; - void serializeSwiftGenericMixin(llvm::json::OStream &OS) const; void serializeSwiftExtensionMixin(llvm::json::OStream &OS) const; diff --git a/lib/SymbolGraphGen/SymbolGraph.cpp b/lib/SymbolGraphGen/SymbolGraph.cpp index 2fa6870d25139..7d5d56b4128ed 100644 --- a/lib/SymbolGraphGen/SymbolGraph.cpp +++ b/lib/SymbolGraphGen/SymbolGraph.cpp @@ -24,20 +24,19 @@ #include "FormatVersion.h" #include "Symbol.h" #include "SymbolGraph.h" +#include "SymbolGraphASTWalker.h" using namespace swift; using namespace symbolgraphgen; -SymbolGraph::SymbolGraph(const SymbolGraphOptions &Options, +SymbolGraph::SymbolGraph(SymbolGraphASTWalker &Walker, ModuleDecl &M, Optional ExtendedModule, - llvm::Triple Target, markup::MarkupContext &Ctx, Optional ModuleVersion) -: Options(Options), +: Walker(Walker), M(M), ExtendedModule(ExtendedModule), - Target(Target), Ctx(Ctx), ModuleVersion(ModuleVersion) {} @@ -78,7 +77,8 @@ void SymbolGraph::recordNode(Symbol S) { // Record all of the possible relationships (edges) originating // with this declaration. recordMemberRelationship(S); - recordSynthesizedMemberRelationship(S); + recordConformanceSynthesizedMemberRelationships(S); + recordSuperclassSynthesizedMemberRelationships(S); recordConformanceRelationships(S); recordInheritanceRelationships(S); recordDefaultImplementationRelationships(S); @@ -91,13 +91,14 @@ void SymbolGraph::recordNode(Symbol S) { void SymbolGraph::recordEdge(Symbol Source, Symbol Target, - RelationshipKind Kind) { + RelationshipKind Kind, + const ExtensionDecl *ConformanceExtension) { if (isImplicitlyPrivate(Target.getSymbolDecl())) { // Don't record relationships to privately named things because // we'll never be able to look up the target anyway. return; } - Edges.insert({this, Kind, Source, Target}); + Edges.insert({this, Kind, Source, Target, ConformanceExtension}); } void SymbolGraph::recordMemberRelationship(Symbol S) { @@ -123,18 +124,12 @@ void SymbolGraph::recordMemberRelationship(Symbol S) { } } -void SymbolGraph::recordSynthesizedMemberRelationship(Symbol S) { - if (!Options.EmitSynthesizedMembers) { +void SymbolGraph::recordSuperclassSynthesizedMemberRelationships(Symbol S) { + if (!Walker.Options.EmitSynthesizedMembers) { return; } - const auto VD = S.getSymbolDecl(); - const auto *OwningNominal = dyn_cast(VD); - if (!OwningNominal) { - return; - } - // Via class inheritance... - if (const auto *C = dyn_cast(VD)) { + if (const auto *C = dyn_cast(S.getSymbolDecl())) { // Collect all superclass members up the inheritance chain. SmallPtrSet SuperClassMembers; const auto *Super = C->getSuperclassDecl(); @@ -166,9 +161,33 @@ void SymbolGraph::recordSynthesizedMemberRelationship(Symbol S) { } } } +} + +void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) { + if (!Walker.Options.EmitSynthesizedMembers) { + return; + } + const auto VD = S.getSymbolDecl(); + const NominalTypeDecl *OwningNominal = nullptr; + if (const auto *ThisNominal = dyn_cast(VD)) { + OwningNominal = ThisNominal; + } else if (const auto *Extension = dyn_cast(VD)) { + if (const auto *ExtendedNominal = Extension->getExtendedNominal()) { + if (!ExtendedNominal->getModuleContext()->getNameStr() + .equals(M.getNameStr())) { + OwningNominal = ExtendedNominal; + } else { + return; + } + } else { + return; + } + } else { + return; + } - // Via protocol conformance... - SynthesizedExtensionAnalyzer ExtensionAnalyzer(const_cast(OwningNominal), + SynthesizedExtensionAnalyzer + ExtensionAnalyzer(const_cast(OwningNominal), PrintOptions::printModuleInterface()); auto MergeGroupKind = SynthesizedExtensionAnalyzer::MergeGroupKind::All; ExtensionAnalyzer.forEachExtensionMergeGroup(MergeGroupKind, @@ -177,30 +196,34 @@ void SymbolGraph::recordSynthesizedMemberRelationship(Symbol S) { if (!Info.IsSynthesized) { continue; } + + // We are only interested in synthesized members that come from an + // extension that we defined in our module. + if (Info.EnablingExt && Info.EnablingExt->getModuleContext() != &M) { + continue; + } + for (const auto ExtensionMember : Info.Ext->getMembers()) { - if (const auto SynthesizedMember = dyn_cast(ExtensionMember)) { - if (SynthesizedMember->isObjC()) { + if (const auto SynthMember = dyn_cast(ExtensionMember)) { + if (SynthMember->isObjC()) { continue; } // There can be synthesized members on effectively private protocols // or things that conform to them. We don't want to include those. -// if (hasImplicitlyPrivateName(SynthesizedMember)) { - // FIXME: Does this work? - if (!canIncludeDeclAsNode(SynthesizedMember)) { + if (SynthMember->hasUnderscoredNaming()) { continue; } - Symbol Source(this, SynthesizedMember, OwningNominal); - Symbol Target(this, OwningNominal, nullptr); + auto ExtendedSG = + Walker.getModuleSymbolGraph(OwningNominal->getModuleContext()); - Nodes.insert(Source); + Symbol Source(this, SynthMember, OwningNominal); + Symbol Target(this, OwningNominal, nullptr); - // The target here is S, which already should've been included - // in recordSynthesizedMemberRelationship -> recordNode. - assert(Nodes.count(Target)); + ExtendedSG->Nodes.insert(Source); - recordEdge(Source, Target, RelationshipKind::MemberOf()); + ExtendedSG->recordEdge(Source, Target, RelationshipKind::MemberOf()); } } } @@ -281,8 +304,9 @@ SymbolGraph::recordConformanceRelationships(Symbol S) { if (const auto *NTD = dyn_cast(VD)) { for (const auto *Conformance : NTD->getAllConformances()) { recordEdge(Symbol(this, VD, nullptr), - Symbol(this, Conformance->getProtocol(), nullptr), - RelationshipKind::ConformsTo()); + Symbol(this, Conformance->getProtocol(), nullptr), + RelationshipKind::ConformsTo(), + dyn_cast_or_null(Conformance->getDeclContext())); } } } @@ -342,7 +366,7 @@ void SymbolGraph::serialize(llvm::json::OStream &OS) { auto Target = llvm::Triple(SerializedAST.getTargetTriple()); symbolgraphgen::serialize(Target, OS); } else { - symbolgraphgen::serialize(Target, OS); + symbolgraphgen::serialize(Walker.Options.Target, OS); } break; } @@ -410,13 +434,13 @@ bool SymbolGraph::isImplicitlyPrivate(const ValueDecl *VD) const { } // Don't record effectively internal declarations if specified - if (Options.MinimumAccessLevel > AccessLevel::Internal && + if (Walker.Options.MinimumAccessLevel > AccessLevel::Internal && VD->hasUnderscoredNaming()) { return true; } // Symbols must meet the minimum access level to be included in the graph. - if (VD->getFormalAccess() < Options.MinimumAccessLevel) { + if (VD->getFormalAccess() < Walker.Options.MinimumAccessLevel) { return true; } diff --git a/lib/SymbolGraphGen/SymbolGraph.h b/lib/SymbolGraphGen/SymbolGraph.h index 0779918578e94..0a21a9cdc92a0 100644 --- a/lib/SymbolGraphGen/SymbolGraph.h +++ b/lib/SymbolGraphGen/SymbolGraph.h @@ -31,7 +31,7 @@ struct SymbolGraph { /** The options to use while building the graph. */ - const SymbolGraphOptions &Options; + SymbolGraphASTWalker &Walker; /** The module this symbol graph represents. @@ -42,11 +42,6 @@ struct SymbolGraph { The module whose types were extended in `M`. */ Optional ExtendedModule; - - /** - The module's target triple. - */ - llvm::Triple Target; /** A context for allocations. @@ -69,10 +64,9 @@ struct SymbolGraph { */ llvm::DenseSet Edges; - SymbolGraph(const SymbolGraphOptions &Options, + SymbolGraph(SymbolGraphASTWalker &Walker, ModuleDecl &M, Optional ExtendedModule, - llvm::Triple Target, markup::MarkupContext &Ctx, Optional ModuleVersion = None); @@ -99,7 +93,8 @@ struct SymbolGraph { directed graph. \param Kind The kind of relationship the edge represents. */ - void recordEdge(Symbol Source, Symbol Target, RelationshipKind Kind); + void recordEdge(Symbol Source, Symbol Target, RelationshipKind Kind, + const ExtensionDecl *ConformanceExtension = nullptr); /** Record a MemberOf relationship, if the given declaration is nested @@ -109,8 +104,11 @@ struct SymbolGraph { /** If a declaration has members by conforming to a protocol, such as default - implementations, with a "synthesized" USR to disambiguate from the protocol's - real implementation. + implementations, record a symbol with a "synthesized" USR to disambiguate + from the protocol's real implementation. + + This makes it more convenient to curate symbols on + a conformer's documentation. The reason these "virtual" members are recorded is to show documentation under a conforming type for members with the concrete types substituted. @@ -120,7 +118,16 @@ struct SymbolGraph { wish to show this function as `subscript(index: Int) -> Element` instead, and show unique documentation for it. */ - void recordSynthesizedMemberRelationship(Symbol S); + void recordConformanceSynthesizedMemberRelationships(Symbol S); + + /** + If a declaration has members by subclassing, record a symbol with a + "synthesized" USR to disambiguate from the superclass's real implementation. + + This makes it more convenient + to curate symbols on a subclass's documentation. + */ + void recordSuperclassSynthesizedMemberRelationships(Symbol S); /** Record InheritsFrom relationships for every class from which the @@ -154,6 +161,12 @@ struct SymbolGraph { */ void recordConformanceRelationships(Symbol S); + /** + Record ConformsTo relationships for each protocol conformance of + a declaration through via an extension. + */ + void recordExtensionConformanceRelationships(Symbol S); + /** Records an Overrides relationship if the given declaration overrides another. diff --git a/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp b/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp index c2c071b16d38d..6ea178dc1d2aa 100644 --- a/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp +++ b/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp @@ -25,22 +25,25 @@ SymbolGraphASTWalker::SymbolGraphASTWalker(ModuleDecl &M, const SymbolGraphOptions &Options) : Options(Options), M(M), - Graph(Options, M, None, Options.Target, Ctx) {} + MainGraph(*this, M, None, Ctx) {} -/// Get a "sub" symbol graph for the parent module of a type that the main module `M` is extending. -SymbolGraph &SymbolGraphASTWalker::getExtendedModuleSymbolGraph(ModuleDecl *M) { +/// Get a "sub" symbol graph for the parent module of a type that +/// the main module `M` is extending. +SymbolGraph *SymbolGraphASTWalker::getModuleSymbolGraph(ModuleDecl *M) { + if (this->M.getNameStr().equals(M->getNameStr())) { + return &MainGraph; + } auto Found = ExtendedModuleGraphs.find(M); if (Found != ExtendedModuleGraphs.end()) { - return *Found->getSecond(); + return Found->getSecond(); } auto *Memory = Ctx.allocate(sizeof(SymbolGraph), alignof(SymbolGraph)); - auto *SG = new (Memory) SymbolGraph(Options, - Graph.M, + auto *SG = new (Memory) SymbolGraph(*this, + MainGraph.M, Optional(M), - Options.Target, Ctx); ExtendedModuleGraphs.insert({M, SG}); - return *SG; + return SG; } bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) { @@ -58,38 +61,107 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) { case swift::DeclKind::Subscript: case swift::DeclKind::TypeAlias: case swift::DeclKind::AssociatedType: - break; case swift::DeclKind::Extension: - // We don't want to descend into extensions on underscored types. - return !cast(D)->getExtendedNominal()->hasUnderscoredNaming(); + break; // We'll descend into everything else. default: return true; } - if (!Graph.canIncludeDeclAsNode(D)) { - return false; + auto SG = getModuleSymbolGraph(D->getModuleContext()); + + // If this is an extension, let's check that it implies some new conformances, + // potentially with generic requirements. + if (const auto *Extension = dyn_cast(D)) { + const auto *ExtendedNominal = Extension->getExtendedNominal(); + // Ignore effecively private decls. + if (ExtendedNominal->hasUnderscoredNaming()) { + return false; + } + + // If there are some protocol conformances on this extension, we'll + // grab them for some new conformsTo relationships. + if (!Extension->getInherited().empty()) { + auto ExtendedSG = + getModuleSymbolGraph(ExtendedNominal->getModuleContext()); + + // The symbol graph to use to record these relationships. + SmallVector Protocols; + SmallVector UnexpandedCompositions; + + auto HandleProtocolOrComposition = [&](Type Ty) { + if (const auto *Proto = + dyn_cast_or_null(Ty->getAnyNominal())) { + Protocols.push_back(Proto); + } else if (const auto *Comp = Ty->getAs()) { + UnexpandedCompositions.push_back(Comp); + } else { + abort(); + } + }; + + for (const auto InheritedLoc : Extension->getInherited()) { + auto InheritedTy = InheritedLoc.getType(); + if (!InheritedTy) { + continue; + } + HandleProtocolOrComposition(InheritedTy); + } + + while (!UnexpandedCompositions.empty()) { + const auto *Comp = UnexpandedCompositions.pop_back_val(); + for (const auto Member : Comp->getMembers()) { + HandleProtocolOrComposition(Member); + } + } + + Symbol Source(ExtendedSG, ExtendedNominal, nullptr); + + for (const auto *Proto : Protocols) { + Symbol Target(&MainGraph, Proto, nullptr); + ExtendedSG->recordEdge(Source, Target, RelationshipKind::ConformsTo(), + Extension); + } + + // While we won't record this node per se, or all of the other kinds of + // relationships, we might establish some synthesized members because we + // extended an external type. + if (ExtendedNominal->getModuleContext() != &M) { + ExtendedSG->recordConformanceSynthesizedMemberRelationships({ + ExtendedSG, + ExtendedNominal, + nullptr + }); + } + } + + // Continue looking into the extension. + return true; } auto *VD = cast(D); + if (!SG->canIncludeDeclAsNode(VD)) { + return false; + } + // If this symbol extends a type from another module, record it in that // module's symbol graph, which will be emitted separately. if (const auto *Extension - = dyn_cast_or_null(VD->getInnermostDeclContext())) { + = dyn_cast_or_null(VD->getDeclContext())) { if (const auto *ExtendedNominal = Extension->getExtendedNominal()) { auto ExtendedModule = ExtendedNominal->getModuleContext(); + auto ExtendedSG = getModuleSymbolGraph(ExtendedModule); if (ExtendedModule != &M) { - auto &SG = getExtendedModuleSymbolGraph(ExtendedModule); - SG.recordNode(Symbol(&Graph, VD, nullptr)); + ExtendedSG->recordNode(Symbol(ExtendedSG, VD, nullptr)); return true; } } } // Otherwise, record this in the main module `M`'s symbol graph. - Graph.recordNode(Symbol(&Graph, VD, nullptr)); + SG->recordNode(Symbol(SG, VD, nullptr)); return true; } diff --git a/lib/SymbolGraphGen/SymbolGraphASTWalker.h b/lib/SymbolGraphGen/SymbolGraphASTWalker.h index 651f54363e9cd..aa0ec2a356866 100644 --- a/lib/SymbolGraphGen/SymbolGraphASTWalker.h +++ b/lib/SymbolGraphGen/SymbolGraphASTWalker.h @@ -47,8 +47,8 @@ struct SymbolGraphASTWalker : public SourceEntityWalker { /// The module that this symbol graph will represent. const ModuleDecl &M; - /// The symbol graph for a module. - SymbolGraph Graph; + /// The symbol graph for the main module of interest. + SymbolGraph MainGraph; /// A map of modules whose types were extended by the main module of interest `M`. llvm::DenseMap ExtendedModuleGraphs; @@ -61,7 +61,7 @@ struct SymbolGraphASTWalker : public SourceEntityWalker { // MARK: - Utilities /// Get a "sub" symbol graph for the parent module of a type that the main module `M` is extending. - SymbolGraph &getExtendedModuleSymbolGraph(ModuleDecl *M); + SymbolGraph *getModuleSymbolGraph(ModuleDecl *M); // MARK: - SourceEntityWalker diff --git a/lib/SymbolGraphGen/SymbolGraphGen.cpp b/lib/SymbolGraphGen/SymbolGraphGen.cpp index 058664d708e77..20c3a995bfd34 100644 --- a/lib/SymbolGraphGen/SymbolGraphGen.cpp +++ b/lib/SymbolGraphGen/SymbolGraphGen.cpp @@ -66,12 +66,12 @@ symbolgraphgen::emitSymbolGraphForModule(ModuleDecl *M, } llvm::errs() - << "Found " << Walker.Graph.Nodes.size() << " symbols and " - << Walker.Graph.Edges.size() << " relationships.\n"; + << "Found " << Walker.MainGraph.Nodes.size() << " symbols and " + << Walker.MainGraph.Edges.size() << " relationships.\n"; int Success = EXIT_SUCCESS; - Success |= serializeSymbolGraph(Walker.Graph, Options); + Success |= serializeSymbolGraph(Walker.MainGraph, Options); for (auto Pair : Walker.ExtendedModuleGraphs) { Success |= serializeSymbolGraph(*Pair.getSecond(), Options); diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 2c46097780253..c0286fc70aaea 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -1,5 +1,6 @@ include(AddSwift) +include(SwiftSource) # Add a universal binary target created from the output of the given # set of targets by running 'lipo'. diff --git a/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake similarity index 100% rename from cmake/modules/SwiftSource.cmake rename to stdlib/cmake/modules/SwiftSource.cmake diff --git a/stdlib/public/Platform/winsdk.modulemap b/stdlib/public/Platform/winsdk.modulemap index 1fceac776c097..1a917fab8d40e 100644 --- a/stdlib/public/Platform/winsdk.modulemap +++ b/stdlib/public/Platform/winsdk.modulemap @@ -14,6 +14,8 @@ module WinSDK [system] [extern_c] { module WinSock2 { header "WinSock2.h" header "WS2tcpip.h" + header "MSWSock.h" + header "../shared/afunix.h" export * link "WS2_32.Lib" diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index df2e87866df27..d8278a5fd21e2 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -258,11 +258,24 @@ bool RecordTypeInfo::readExtraInhabitantIndex(remote::MemoryReader &reader, int *extraInhabitantIndex) const { switch (SubKind) { case RecordKind::Invalid: - case RecordKind::ThickFunction: case RecordKind::OpaqueExistential: case RecordKind::ClosureContext: return false; + case RecordKind::ThickFunction: { + if (Fields.size() != 2) { + return false; + } + auto function = Fields[0]; + auto context = Fields[1]; + if (function.Offset != 0) { + return false; + } + auto functionFieldAddress = address; + return function.TI.readExtraInhabitantIndex( + reader, functionFieldAddress, extraInhabitantIndex); + } + case RecordKind::ClassExistential: case RecordKind::ExistentialMetatype: case RecordKind::ErrorExistential: @@ -350,9 +363,53 @@ bool RecordTypeInfo::readExtraInhabitantIndex(remote::MemoryReader &reader, return false; } - case RecordKind::MultiPayloadEnum:// XXX TODO - return false; - + case RecordKind::MultiPayloadEnum: { + // Multi payload enums can export XIs from the tag, if any. + // They never export XIs from their payloads. + auto Fields = getFields(); + unsigned long PayloadCaseCount = 0; + unsigned long NonPayloadCaseCount = 0; + unsigned long PayloadSize = 0; + for (auto Field : Fields) { + if (Field.TR != 0) { + PayloadCaseCount += 1; + if (Field.TI.getSize() > PayloadSize) { + PayloadSize = Field.TI.getSize(); + } + } else { + NonPayloadCaseCount += 1; + } + } + if (getSize() > PayloadSize) { + // Multipayload enums that do use a separate tag + // export XIs from that tag. + unsigned tag = 0; + auto TagSize = getSize() - PayloadSize; + auto TagAddress = remote::RemoteAddress(address.getAddressData() + PayloadSize); + if (!reader.readInteger(TagAddress, TagSize, &tag)) + return false; + if (tag < Fields.size()) { + *extraInhabitantIndex = -1; // Valid payload, not an XI + } else if (TagSize >= 4) { + // This is really just the 32-bit 2s-complement negation of `tag`, but + // coded so as to ensure we cannot overflow or underflow. + *extraInhabitantIndex = static_cast( + std::numeric_limits::max() + - (tag & std::numeric_limits::max()) + + 1); + } else { + // XIs are coded starting from the highest value that fits + // E.g., for 1-byte tag, tag 255 == XI #0, tag 254 == XI #1, etc. + unsigned maxTag = (1U << (TagSize * 8U)) - 1; + *extraInhabitantIndex = maxTag - tag; + } + return true; + } else { + // Multipayload enums that don't use a separate tag never + // export XIs. + return false; + } + } } return false; } @@ -436,7 +493,7 @@ class ExistentialTypeInfoBuilder { } if (!isa(SuperclassTI)) { - DEBUG_LOG(fprintf(stderr, "Superclass not a reference type: ") + DEBUG_LOG(fprintf(stderr, "Superclass not a reference type: "); SuperclassTI->dump()); Invalid = true; continue; @@ -1121,7 +1178,10 @@ class EnumTypeInfoBuilder { } void addCase(const std::string &Name) { - Cases.push_back({Name, /*offset=*/0, /*value=*/-1, nullptr, TypeInfo()}); + // FieldInfo's TI field is a reference, so give it a reference to a value + // that stays alive forever. + static TypeInfo emptyTI; + Cases.push_back({Name, /*offset=*/0, /*value=*/-1, nullptr, emptyTI}); } void addCase(const std::string &Name, const TypeRef *TR, @@ -1244,7 +1304,7 @@ class EnumTypeInfoBuilder { Size += tagCounts.numTagBytes; // Dynamic multi-payload enums use the tag representations not assigned // to cases for extra inhabitants. - if (tagCounts.numTagBytes >= 32) { + if (tagCounts.numTagBytes >= 4) { NumExtraInhabitants = ValueWitnessFlags::MaxNumExtraInhabitants; } else { NumExtraInhabitants = @@ -1553,7 +1613,7 @@ const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR, unsigned start) { auto FD = getBuilder().getFieldTypeInfo(TR); if (FD == nullptr) { - DEBUG_LOG(fprintf(stderr, "No field descriptor: ";) TR->dump()); + DEBUG_LOG(fprintf(stderr, "No field descriptor: "); TR->dump()); return nullptr; } diff --git a/stdlib/public/SwiftShims/KeyPath.h b/stdlib/public/SwiftShims/KeyPath.h index 61c7749fb458d..9b6ba3bd40214 100644 --- a/stdlib/public/SwiftShims/KeyPath.h +++ b/stdlib/public/SwiftShims/KeyPath.h @@ -109,11 +109,26 @@ static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDUnresolvedI static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDUnresolvedFunctionCall = 0x00000001U; +#ifndef __cplusplus extern const void *_Nonnull (swift_keyPathGenericWitnessTable[]); static inline const void *_Nonnull __swift_keyPathGenericWitnessTable_addr(void) { return swift_keyPathGenericWitnessTable; } +#endif + +// Discriminators for pointer authentication in key path patterns and objects + +static const __swift_uint16_t _SwiftKeyPath_ptrauth_ArgumentDestroy = 0x7072; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_ArgumentCopy = 0x6f66; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_ArgumentEquals = 0x756e; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_ArgumentHash = 0x6374; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_Getter = 0x6f72; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_NonmutatingSetter = 0x6f70; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_MutatingSetter = 0x7469; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_ArgumentLayout = 0x6373; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_ArgumentInit = 0x6275; +static const __swift_uint16_t _SwiftKeyPath_ptrauth_MetadataAccessor = 0x7474; #ifdef __cplusplus } // extern "C" diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index dd1ef587f2d12..95ee7f07826a5 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -108,6 +108,7 @@ set(SWIFTLIB_ESSENTIAL Policy.swift PrefixWhile.swift Print.swift + PtrAuth.swift Random.swift RandomAccessCollection.swift Range.swift diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index c900b93b9410d..1b9a209004e67 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -226,7 +226,8 @@ "Comparable.swift", "Codable.swift", "LegacyABI.swift", - "MigrationSupport.swift" + "MigrationSupport.swift", + "PtrAuth.swift" ], "Result": [ "Result.swift" diff --git a/stdlib/public/core/KeyPath.swift b/stdlib/public/core/KeyPath.swift index 169aae54c9f03..d8f3bbe2ffa4a 100644 --- a/stdlib/public/core/KeyPath.swift +++ b/stdlib/public/core/KeyPath.swift @@ -456,7 +456,119 @@ internal struct ComputedPropertyID: Hashable { } } -internal struct ComputedArgumentWitnesses { +internal struct ComputedAccessorsPtr { +#if INTERNAL_CHECKS_ENABLED + internal let header: RawKeyPathComponent.Header +#endif + internal let _value: UnsafeRawPointer + + init(header: RawKeyPathComponent.Header, value: UnsafeRawPointer) { +#if INTERNAL_CHECKS_ENABLED + self.header = header +#endif + self._value = value + } + + @_transparent + static var getterPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_Getter) + } + @_transparent + static var nonmutatingSetterPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_NonmutatingSetter) + } + @_transparent + static var mutatingSetterPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_MutatingSetter) + } + + internal typealias Getter = @convention(thin) + (CurValue, UnsafeRawPointer, Int) -> NewValue + internal typealias NonmutatingSetter = @convention(thin) + (NewValue, CurValue, UnsafeRawPointer, Int) -> () + internal typealias MutatingSetter = @convention(thin) + (NewValue, inout CurValue, UnsafeRawPointer, Int) -> () + + internal var getterPtr: UnsafeRawPointer { +#if INTERNAL_CHECKS_ENABLED + _internalInvariant(header.kind == .computed, + "not a computed property") +#endif + return _value + } + internal var setterPtr: UnsafeRawPointer { +#if INTERNAL_CHECKS_ENABLED + _internalInvariant(header.isComputedSettable, + "not a settable property") +#endif + return _value + MemoryLayout.size + } + + internal func getter() + -> Getter { + + return getterPtr._loadAddressDiscriminatedFunctionPointer( + as: Getter.self, + discriminator: ComputedAccessorsPtr.getterPtrAuthKey) + } + + internal func nonmutatingSetter() + -> NonmutatingSetter { +#if INTERNAL_CHECKS_ENABLED + _internalInvariant(header.isComputedSettable && !header.isComputedMutating, + "not a nonmutating settable property") +#endif + + return setterPtr._loadAddressDiscriminatedFunctionPointer( + as: NonmutatingSetter.self, + discriminator: ComputedAccessorsPtr.nonmutatingSetterPtrAuthKey) + } + + internal func mutatingSetter() + -> MutatingSetter { +#if INTERNAL_CHECKS_ENABLED + _internalInvariant(header.isComputedSettable && header.isComputedMutating, + "not a mutating settable property") +#endif + + return setterPtr._loadAddressDiscriminatedFunctionPointer( + as: MutatingSetter.self, + discriminator: ComputedAccessorsPtr.mutatingSetterPtrAuthKey) + } +} + +internal struct ComputedArgumentWitnessesPtr { + internal let _value: UnsafeRawPointer + + init(_ value: UnsafeRawPointer) { + self._value = value + } + + @_transparent + static var destroyPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_ArgumentDestroy) + } + @_transparent + static var copyPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_ArgumentCopy) + } + @_transparent + static var equalsPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_ArgumentEquals) + } + @_transparent + static var hashPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_ArgumentHash) + } + @_transparent + static var layoutPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_ArgumentLayout) + } + @_transparent + static var initPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_ArgumentInit) + } + internal typealias Destroy = @convention(thin) (_ instanceArguments: UnsafeMutableRawPointer, _ size: Int) -> () internal typealias Copy = @convention(thin) @@ -472,17 +584,39 @@ internal struct ComputedArgumentWitnesses { (_ instanceArguments: UnsafeRawPointer, _ size: Int) -> Int - internal let destroy: Destroy? - internal let copy: Copy - internal let equals: Equals - internal let hash: Hash + // The witnesses are stored as address-discriminated authenticated + // pointers. + + internal var destroy: Destroy? { + return _value._loadAddressDiscriminatedFunctionPointer( + as: Optional.self, + discriminator: ComputedArgumentWitnessesPtr.destroyPtrAuthKey) + } + internal var copy: Copy { + return _value._loadAddressDiscriminatedFunctionPointer( + fromByteOffset: MemoryLayout.size, + as: Copy.self, + discriminator: ComputedArgumentWitnessesPtr.copyPtrAuthKey) + } + internal var equals: Equals { + return _value._loadAddressDiscriminatedFunctionPointer( + fromByteOffset: 2*MemoryLayout.size, + as: Equals.self, + discriminator: ComputedArgumentWitnessesPtr.equalsPtrAuthKey) + } + internal var hash: Hash { + return _value._loadAddressDiscriminatedFunctionPointer( + fromByteOffset: 3*MemoryLayout.size, + as: Hash.self, + discriminator: ComputedArgumentWitnessesPtr.hashPtrAuthKey) + } } internal enum KeyPathComponent: Hashable { internal struct ArgumentRef { internal init( data: UnsafeRawBufferPointer, - witnesses: UnsafePointer, + witnesses: ComputedArgumentWitnessesPtr, witnessSizeAdjustment: Int ) { self.data = data @@ -491,7 +625,7 @@ internal enum KeyPathComponent: Hashable { } internal var data: UnsafeRawBufferPointer - internal var witnesses: UnsafePointer + internal var witnesses: ComputedArgumentWitnessesPtr internal var witnessSizeAdjustment: Int } @@ -503,16 +637,17 @@ internal enum KeyPathComponent: Hashable { case `class`(offset: Int) /// The keypath projects using a getter. case get(id: ComputedPropertyID, - get: UnsafeRawPointer, argument: ArgumentRef?) + accessors: ComputedAccessorsPtr, + argument: ArgumentRef?) /// The keypath projects using a getter/setter pair. The setter can mutate /// the base value in-place. case mutatingGetSet(id: ComputedPropertyID, - get: UnsafeRawPointer, set: UnsafeRawPointer, + accessors: ComputedAccessorsPtr, argument: ArgumentRef?) /// The keypath projects using a getter/setter pair that does not mutate its /// base. case nonmutatingGetSet(id: ComputedPropertyID, - get: UnsafeRawPointer, set: UnsafeRawPointer, + accessors: ComputedAccessorsPtr, argument: ArgumentRef?) /// The keypath optional-chains, returning nil immediately if the input is /// nil, or else proceeding by projecting the value inside. @@ -532,19 +667,19 @@ internal enum KeyPathComponent: Hashable { (.optionalForce, .optionalForce), (.optionalWrap, .optionalWrap): return true - case (.get(id: let id1, get: _, argument: let argument1), - .get(id: let id2, get: _, argument: let argument2)), + case (.get(id: let id1, accessors: _, argument: let argument1), + .get(id: let id2, accessors: _, argument: let argument2)), - (.mutatingGetSet(id: let id1, get: _, set: _, argument: let argument1), - .mutatingGetSet(id: let id2, get: _, set: _, argument: let argument2)), + (.mutatingGetSet(id: let id1, accessors: _, argument: let argument1), + .mutatingGetSet(id: let id2, accessors: _, argument: let argument2)), - (.nonmutatingGetSet(id: let id1, get: _, set: _, argument: let argument1), - .nonmutatingGetSet(id: let id2, get: _, set: _, argument: let argument2)): + (.nonmutatingGetSet(id: let id1, accessors: _, argument: let argument1), + .nonmutatingGetSet(id: let id2, accessors: _, argument: let argument2)): if id1 != id2 { return false } if let arg1 = argument1, let arg2 = argument2 { - return arg1.witnesses.pointee.equals( + return arg1.witnesses.equals( arg1.data.baseAddress.unsafelyUnwrapped, arg2.data.baseAddress.unsafelyUnwrapped, arg1.data.count - arg1.witnessSizeAdjustment) @@ -571,7 +706,7 @@ internal enum KeyPathComponent: Hashable { _ argument: KeyPathComponent.ArgumentRef? ) { if let argument = argument { - let hash = argument.witnesses.pointee.hash( + let hash = argument.witnesses.hash( argument.data.baseAddress.unsafelyUnwrapped, argument.data.count - argument.witnessSizeAdjustment) // Returning 0 indicates that the arguments should not impact the @@ -595,15 +730,15 @@ internal enum KeyPathComponent: Hashable { hasher.combine(3) case .optionalWrap: hasher.combine(4) - case .get(id: let id, get: _, argument: let argument): + case .get(id: let id, accessors: _, argument: let argument): hasher.combine(5) hasher.combine(id) appendHashFromArgument(argument) - case .mutatingGetSet(id: let id, get: _, set: _, argument: let argument): + case .mutatingGetSet(id: let id, accessors: _, argument: let argument): hasher.combine(6) hasher.combine(id) appendHashFromArgument(argument) - case .nonmutatingGetSet(id: let id, get: _, set: _, argument: let argument): + case .nonmutatingGetSet(id: let id, accessors: _, argument: let argument): hasher.combine(7) hasher.combine(id) appendHashFromArgument(argument) @@ -676,7 +811,7 @@ internal final class ClassHolder { internal final class MutatingWritebackBuffer { internal let previous: AnyObject? internal let base: UnsafeMutablePointer - internal let set: @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer, Int) -> () + internal let set: ComputedAccessorsPtr.MutatingSetter internal let argument: UnsafeRawPointer internal let argumentSize: Int internal var value: NewValue @@ -687,7 +822,7 @@ internal final class MutatingWritebackBuffer { internal init(previous: AnyObject?, base: UnsafeMutablePointer, - set: @escaping @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer, Int) -> (), + set: @escaping ComputedAccessorsPtr.MutatingSetter, argument: UnsafeRawPointer, argumentSize: Int, value: NewValue) { @@ -704,7 +839,7 @@ internal final class MutatingWritebackBuffer { internal final class NonmutatingWritebackBuffer { internal let previous: AnyObject? internal let base: CurValue - internal let set: @convention(thin) (NewValue, CurValue, UnsafeRawPointer, Int) -> () + internal let set: ComputedAccessorsPtr.NonmutatingSetter internal let argument: UnsafeRawPointer internal let argumentSize: Int internal var value: NewValue @@ -716,7 +851,7 @@ internal final class NonmutatingWritebackBuffer { internal init(previous: AnyObject?, base: CurValue, - set: @escaping @convention(thin) (NewValue, CurValue, UnsafeRawPointer, Int) -> (), + set: @escaping ComputedAccessorsPtr.NonmutatingSetter, argument: UnsafeRawPointer, argumentSize: Int, value: NewValue) { @@ -756,6 +891,11 @@ internal struct RawKeyPathComponent { internal var header: Header internal var body: UnsafeRawBufferPointer + @_transparent + static var metadataAccessorPtrAuthKey: UInt64 { + return UInt64(_SwiftKeyPath_ptrauth_MetadataAccessor) + } + internal struct Header { internal static var payloadMask: UInt32 { return _SwiftKeyPathComponentHeader_PayloadMask @@ -1189,22 +1329,14 @@ internal struct RawKeyPathComponent { kind: header.computedIDKind) } - internal var _computedGetter: UnsafeRawPointer { + internal var _computedAccessors: ComputedAccessorsPtr { _internalInvariant(header.kind == .computed, "not a computed property") - return body.load( - fromByteOffset: Header.pointerAlignmentSkew + MemoryLayout.size, - as: UnsafeRawPointer.self) - } - - internal var _computedSetter: UnsafeRawPointer { - _internalInvariant(header.isComputedSettable, - "not a settable property") - - return body.load( - fromByteOffset: Header.pointerAlignmentSkew + MemoryLayout.size * 2, - as: UnsafeRawPointer.self) + return ComputedAccessorsPtr( + header: header, + value: body.baseAddress.unsafelyUnwrapped + + Header.pointerAlignmentSkew + MemoryLayout.size) } internal var _computedArgumentHeaderPointer: UnsafeRawPointer { @@ -1220,10 +1352,10 @@ internal struct RawKeyPathComponent { return _computedArgumentHeaderPointer.load(as: Int.self) } internal - var _computedArgumentWitnesses: UnsafePointer { + var _computedArgumentWitnesses: ComputedArgumentWitnessesPtr { return _computedArgumentHeaderPointer.load( fromByteOffset: MemoryLayout.size, - as: UnsafePointer.self) + as: ComputedArgumentWitnessesPtr.self) } internal var _computedArguments: UnsafeRawPointer { @@ -1266,7 +1398,7 @@ internal struct RawKeyPathComponent { let isMutating = header.isComputedMutating let id = _computedID - let get = _computedGetter + let accessors = _computedAccessors // Argument value is unused if there are no arguments. let argument: KeyPathComponent.ArgumentRef? if header.hasComputedArguments { @@ -1281,16 +1413,14 @@ internal struct RawKeyPathComponent { switch (isSettable, isMutating) { case (false, false): - return .get(id: id, get: get, argument: argument) + return .get(id: id, accessors: accessors, argument: argument) case (true, false): return .nonmutatingGetSet(id: id, - get: get, - set: _computedSetter, + accessors: accessors, argument: argument) case (true, true): return .mutatingGetSet(id: id, - get: get, - set: _computedSetter, + accessors: accessors, argument: argument) case (false, true): _internalInvariantFailure("impossible") @@ -1312,7 +1442,7 @@ internal struct RawKeyPathComponent { case .computed: // Run destructor, if any if header.hasComputedArguments, - let destructor = _computedArgumentWitnesses.pointee.destroy { + let destructor = _computedArgumentWitnesses.destroy { destructor(_computedMutableArguments, _computedArgumentSize - _computedArgumentWitnessSizeAdjustment) } @@ -1348,16 +1478,22 @@ internal struct RawKeyPathComponent { toByteOffset: componentSize, as: Int.self) componentSize += MemoryLayout.size - buffer.storeBytes(of: _computedGetter, - toByteOffset: componentSize, - as: UnsafeRawPointer.self) - componentSize += MemoryLayout.size + let accessors = _computedAccessors + (buffer.baseAddress.unsafelyUnwrapped + MemoryLayout.size * 2) + ._copyAddressDiscriminatedFunctionPointer( + from: accessors.getterPtr, + discriminator: ComputedAccessorsPtr.getterPtrAuthKey) + + componentSize += MemoryLayout.size if header.isComputedSettable { - buffer.storeBytes(of: _computedSetter, - toByteOffset: MemoryLayout.size * 3, - as: UnsafeRawPointer.self) + (buffer.baseAddress.unsafelyUnwrapped + MemoryLayout.size * 3) + ._copyAddressDiscriminatedFunctionPointer( + from: accessors.setterPtr, + discriminator: header.isComputedMutating + ? ComputedAccessorsPtr.mutatingSetterPtrAuthKey + : ComputedAccessorsPtr.nonmutatingSetterPtrAuthKey) componentSize += MemoryLayout.size } @@ -1370,7 +1506,7 @@ internal struct RawKeyPathComponent { componentSize += MemoryLayout.size buffer.storeBytes(of: _computedArgumentWitnesses, toByteOffset: componentSize, - as: UnsafePointer.self) + as: ComputedArgumentWitnessesPtr.self) componentSize += MemoryLayout.size if header.isComputedInstantiatedFromExternalWithArguments { @@ -1384,7 +1520,7 @@ internal struct RawKeyPathComponent { let adjustedSize = argumentSize - _computedArgumentWitnessSizeAdjustment let argumentDest = buffer.baseAddress.unsafelyUnwrapped + componentSize - _computedArgumentWitnesses.pointee.copy( + _computedArgumentWitnesses.copy( arguments, argumentDest, adjustedSize) @@ -1448,7 +1584,7 @@ internal struct RawKeyPathComponent { let offsetAddress = basePtr.advanced(by: offset) - // Perform an instaneous record access on the address in order to + // Perform an instantaneous record access on the address in order to // ensure that the read will not conflict with an already in-progress // 'modify' access. Builtin.performInstantaneousReadAccess(offsetAddress._rawValue, @@ -1457,15 +1593,12 @@ internal struct RawKeyPathComponent { .assumingMemoryBound(to: NewValue.self) .pointee) - case .get(id: _, get: let rawGet, argument: let argument), - .mutatingGetSet(id: _, get: let rawGet, set: _, argument: let argument), - .nonmutatingGetSet(id: _, get: let rawGet, set: _, argument: let argument): - typealias Getter - = @convention(thin) (CurValue, UnsafeRawPointer, Int) -> NewValue - let get = unsafeBitCast(rawGet, to: Getter.self) - return .continue(get(base, - argument?.data.baseAddress ?? rawGet, - argument?.data.count ?? 0)) + case .get(id: _, accessors: let accessors, argument: let argument), + .mutatingGetSet(id: _, accessors: let accessors, argument: let argument), + .nonmutatingGetSet(id: _, accessors: let accessors, argument: let argument): + return .continue(accessors.getter()(base, + argument?.data.baseAddress ?? accessors._value, + argument?.data.count ?? 0)) case .optionalChain: _internalInvariant(CurValue.self == Optional.self, @@ -1522,55 +1655,42 @@ internal struct RawKeyPathComponent { return offsetAddress - case .mutatingGetSet(id: _, get: let rawGet, set: let rawSet, + case .mutatingGetSet(id: _, accessors: let accessors, argument: let argument): - typealias Getter - = @convention(thin) (CurValue, UnsafeRawPointer, Int) -> NewValue - typealias Setter - = @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer, Int) -> () - let get = unsafeBitCast(rawGet, to: Getter.self) - let set = unsafeBitCast(rawSet, to: Setter.self) - let baseTyped = UnsafeMutablePointer( mutating: base.assumingMemoryBound(to: CurValue.self)) - let argValue = argument?.data.baseAddress ?? rawGet + let argValue = argument?.data.baseAddress ?? accessors._value let argSize = argument?.data.count ?? 0 - let writeback = MutatingWritebackBuffer(previous: keepAlive, - base: baseTyped, - set: set, - argument: argValue, - argumentSize: argSize, - value: get(baseTyped.pointee, argValue, argSize)) + let writeback = MutatingWritebackBuffer( + previous: keepAlive, + base: baseTyped, + set: accessors.mutatingSetter(), + argument: argValue, + argumentSize: argSize, + value: accessors.getter()(baseTyped.pointee, argValue, argSize)) keepAlive = writeback // A maximally-abstracted, final, stored class property should have // a stable address. return UnsafeRawPointer(Builtin.addressof(&writeback.value)) - case .nonmutatingGetSet(id: _, get: let rawGet, set: let rawSet, + case .nonmutatingGetSet(id: _, accessors: let accessors, argument: let argument): // A nonmutating property should only occur at the root of a mutation, // since otherwise it would be part of the reference prefix. _internalInvariant(isRoot, "nonmutating component should not appear in the middle of mutation") - typealias Getter - = @convention(thin) (CurValue, UnsafeRawPointer, Int) -> NewValue - typealias Setter - = @convention(thin) (NewValue, CurValue, UnsafeRawPointer, Int) -> () - - let get = unsafeBitCast(rawGet, to: Getter.self) - let set = unsafeBitCast(rawSet, to: Setter.self) - let baseValue = base.assumingMemoryBound(to: CurValue.self).pointee - let argValue = argument?.data.baseAddress ?? rawGet + let argValue = argument?.data.baseAddress ?? accessors._value let argSize = argument?.data.count ?? 0 - let writeback = NonmutatingWritebackBuffer(previous: keepAlive, - base: baseValue, - set: set, - argument: argValue, - argumentSize: argSize, - value: get(baseValue, argValue, argSize)) + let writeback = NonmutatingWritebackBuffer( + previous: keepAlive, + base: baseValue, + set: accessors.nonmutatingSetter(), + argument: argValue, + argumentSize: argSize, + value: accessors.getter()(baseValue, argValue, argSize)) keepAlive = writeback // A maximally-abstracted, final, stored class property should have // a stable address. @@ -2467,6 +2587,26 @@ internal func _resolveKeyPathGenericArgReference( // Adjust the reference. let referenceStart = reference - 1 + // If we have a symbolic reference to an accessor, call it. + let first = referenceStart.load(as: UInt8.self) + if first == 255 && reference.load(as: UInt8.self) == 9 { + typealias MetadataAccessor = + @convention(c) (UnsafeRawPointer?) -> UnsafeRawPointer + + // Unaligned load of the offset. + let pointerReference = reference + 1 + var offset: Int32 = 0 + _memcpy(dest: &offset, src: pointerReference, size: 4) + + let accessorPtrRaw = _resolveRelativeAddress(pointerReference, offset) + let accessorPtrSigned = + _PtrAuth.sign(pointer: accessorPtrRaw, + key: .processIndependentCode, + discriminator: _PtrAuth.discriminator(for: MetadataAccessor.self)) + let accessor = unsafeBitCast(accessorPtrSigned, to: MetadataAccessor.self) + return accessor(arguments) + } + let nameLength = _getSymbolicMangledNameLength(referenceStart) let namePtr = referenceStart.bindMemory(to: UInt8.self, capacity: nameLength + 1) @@ -2511,7 +2651,7 @@ internal enum KeyPathPatternStoredOffset { } internal struct KeyPathPatternComputedArguments { var getLayout: KeyPathComputedArgumentLayoutFn - var witnesses: UnsafePointer + var witnesses: ComputedArgumentWitnessesPtr var initializer: KeyPathComputedArgumentInitializerFn } @@ -2653,7 +2793,10 @@ internal func _walkKeyPathPattern( let getLayoutBase = componentBuffer.baseAddress.unsafelyUnwrapped let getLayoutRef = _pop(from: &componentBuffer, as: Int32.self) let getLayoutRaw = _resolveRelativeAddress(getLayoutBase, getLayoutRef) - let getLayout = unsafeBitCast(getLayoutRaw, + let getLayoutSigned = _PtrAuth.sign(pointer: getLayoutRaw, + key: .processIndependentCode, + discriminator: _PtrAuth.discriminator(for: KeyPathComputedArgumentLayoutFn.self)) + let getLayout = unsafeBitCast(getLayoutSigned, to: KeyPathComputedArgumentLayoutFn.self) let witnessesBase = componentBuffer.baseAddress.unsafelyUnwrapped @@ -2669,12 +2812,15 @@ internal func _walkKeyPathPattern( let initializerRef = _pop(from: &componentBuffer, as: Int32.self) let initializerRaw = _resolveRelativeAddress(initializerBase, initializerRef) - let initializer = unsafeBitCast(initializerRaw, + let initializerSigned = _PtrAuth.sign(pointer: initializerRaw, + key: .processIndependentCode, + discriminator: _PtrAuth.discriminator(for: KeyPathComputedArgumentInitializerFn.self)) + + let initializer = unsafeBitCast(initializerSigned, to: KeyPathComputedArgumentInitializerFn.self) return KeyPathPatternComputedArguments(getLayout: getLayout, - witnesses: - witnesses.assumingMemoryBound(to: ComputedArgumentWitnesses.self), + witnesses: ComputedArgumentWitnessesPtr(witnesses), initializer: initializer) } else { return nil @@ -3083,9 +3229,10 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor { var endOfReferencePrefixComponent: UnsafeMutableRawPointer? = nil var previousComponentAddr: UnsafeMutableRawPointer? = nil - mutating func pushDest(_ value: T) { - _internalInvariant(_isPOD(T.self)) - let size = MemoryLayout.size + mutating func adjustDestForAlignment(of: T.Type) -> ( + baseAddress: UnsafeMutableRawPointer, + misalign: Int + ) { let alignment = MemoryLayout.alignment var baseAddress = destData.baseAddress.unsafelyUnwrapped var misalign = Int(bitPattern: baseAddress) % alignment @@ -3093,6 +3240,13 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor { misalign = alignment - misalign baseAddress = baseAddress.advanced(by: misalign) } + return (baseAddress, misalign) + } + mutating func pushDest(_ value: T) { + _internalInvariant(_isPOD(T.self)) + let size = MemoryLayout.size + let alignment = MemoryLayout.alignment + let (baseAddress, misalign) = adjustDestForAlignment(of: T.self) withUnsafeBytes(of: value) { _memcpy(dest: baseAddress, src: $0.baseAddress.unsafelyUnwrapped, size: UInt(size)) @@ -3101,6 +3255,19 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor { start: baseAddress + size, count: destData.count - size - misalign) } + mutating func pushAddressDiscriminatedFunctionPointer( + _ unsignedPointer: UnsafeRawPointer, + discriminator: UInt64 + ) { + let size = MemoryLayout.size + let (baseAddress, misalign) = + adjustDestForAlignment(of: UnsafeRawPointer.self) + baseAddress._storeFunctionPointerWithAddressDiscrimination( + unsignedPointer, discriminator: discriminator) + destData = UnsafeMutableRawBufferPointer( + start: baseAddress + size, + count: destData.count - size - misalign) + } mutating func updatePreviousComponentAddr() -> UnsafeMutableRawPointer? { let oldValue = previousComponentAddr @@ -3217,7 +3384,11 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor { // The pointer in the pattern is to a function that generates the // identifier pointer. typealias Resolver = @convention(c) (UnsafeRawPointer?) -> UnsafeRawPointer? - let resolverFn = unsafeBitCast(absoluteID.unsafelyUnwrapped, + let resolverSigned = _PtrAuth.sign( + pointer: absoluteID.unsafelyUnwrapped, + key: .processIndependentCode, + discriminator: _PtrAuth.discriminator(for: Resolver.self)) + let resolverFn = unsafeBitCast(resolverSigned, to: Resolver.self) absoluteID = resolverFn(patternArgs) @@ -3234,9 +3405,12 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor { arguments != nil && externalArgs != nil) pushDest(header) pushDest(resolvedID) - pushDest(getter) + pushAddressDiscriminatedFunctionPointer(getter, + discriminator: ComputedAccessorsPtr.getterPtrAuthKey) if let setter = setter { - pushDest(setter) + pushAddressDiscriminatedFunctionPointer(setter, + discriminator: mutating ? ComputedAccessorsPtr.mutatingSetterPtrAuthKey + : ComputedAccessorsPtr.nonmutatingSetterPtrAuthKey) } if let arguments = arguments { @@ -3260,7 +3434,7 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor { // A nonnull destructor in the witnesses file indicates the instantiated // payload is nontrivial. - if let _ = arguments.witnesses.pointee.destroy { + if let _ = arguments.witnesses.destroy { isTrivial = false } diff --git a/stdlib/public/core/PtrAuth.swift b/stdlib/public/core/PtrAuth.swift new file mode 100644 index 0000000000000..f2beaebc3a736 --- /dev/null +++ b/stdlib/public/core/PtrAuth.swift @@ -0,0 +1,261 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +/// Pseudo-namespace for pointer authentication primitives. +internal enum _PtrAuth { + internal struct Key { + var _value: Int32 + + @_transparent + init(_value: Int32) { + self._value = _value + } + +#if _ptrauth(_arm64e) + @_transparent + static var ASIA: Key { return Key(_value: 0) } + @_transparent + static var ASIB: Key { return Key(_value: 1) } + @_transparent + static var ASDA: Key { return Key(_value: 2) } + @_transparent + static var ASDB: Key { return Key(_value: 3) } + + /// A process-independent key which can be used to sign code pointers. + /// Signing and authenticating with this key is a no-op in processes + /// which disable ABI pointer authentication. + @_transparent + static var processIndependentCode: Key { return .ASIA } + + /// A process-specific key which can be used to sign code pointers. + /// Signing and authenticating with this key is enforced even in processes + /// which disable ABI pointer authentication. + @_transparent + static var processDependentCode: Key { return .ASIB } + + /// A process-independent key which can be used to sign data pointers. + /// Signing and authenticating with this key is a no-op in processes + /// which disable ABI pointer authentication. + @_transparent + static var processIndependentData: Key { return .ASDA } + + /// A process-specific key which can be used to sign data pointers. + /// Signing and authenticating with this key is a no-op in processes + /// which disable ABI pointer authentication. + @_transparent + static var processDependentData: Key { return .ASDB } +#elseif _ptrauth(_none) + /// A process-independent key which can be used to sign code pointers. + /// Signing and authenticating with this key is a no-op in processes + /// which disable ABI pointer authentication. + @_transparent + static var processIndependentCode: Key { return Key(_value: 0) } + + /// A process-specific key which can be used to sign code pointers. + /// Signing and authenticating with this key is enforced even in processes + /// which disable ABI pointer authentication. + @_transparent + static var processDependentCode: Key { return Key(_value: 0) } + + /// A process-independent key which can be used to sign data pointers. + /// Signing and authenticating with this key is a no-op in processes + /// which disable ABI pointer authentication. + @_transparent + static var processIndependentData: Key { return Key(_value: 0) } + + /// A process-specific key which can be used to sign data pointers. + /// Signing and authenticating with this key is a no-op in processes + /// which disable ABI pointer authentication. + @_transparent + static var processDependentData: Key { return Key(_value: 0) } +#else + #error("unsupported ptrauth scheme") +#endif + } + +#if _ptrauth(_arm64e) + /// Blend a pointer and a small integer to form a new extra-data + /// discriminator. Not all bits of the inputs are guaranteed to + /// contribute to the result. + @_transparent + static func blend(pointer: UnsafeRawPointer, + discriminator: UInt64) -> UInt64 { + return UInt64(Builtin.int_ptrauth_blend_Int64( + UInt64(UInt(bitPattern: pointer))._value, + discriminator._value)) + } + + /// Sign an unauthenticated pointer. + @_transparent + static func sign(pointer: UnsafeRawPointer, + key: Key, + discriminator: UInt64) -> UnsafeRawPointer { + let bitPattern = UInt64(Builtin.int_ptrauth_sign_Int64( + UInt64(UInt(bitPattern: pointer))._value, + key._value._value, + discriminator._value)) + + return UnsafeRawPointer(bitPattern: + UInt(truncatingIfNeeded: bitPattern)).unsafelyUnwrapped + } + + /// Authenticate a pointer using one scheme and resign it using another. + @_transparent + static func authenticateAndResign(pointer: UnsafeRawPointer, + oldKey: Key, + oldDiscriminator: UInt64, + newKey: Key, + newDiscriminator: UInt64) -> UnsafeRawPointer { + let bitPattern = UInt64(Builtin.int_ptrauth_resign_Int64( + UInt64(UInt(bitPattern: pointer))._value, + oldKey._value._value, + oldDiscriminator._value, + newKey._value._value, + newDiscriminator._value)) + + return UnsafeRawPointer(bitPattern: + UInt(truncatingIfNeeded: bitPattern)).unsafelyUnwrapped + } + + /// Get the type-specific discriminator for a function type. + @_transparent + static func discriminator(for type: T.Type) -> UInt64 { + return UInt64(Builtin.typePtrAuthDiscriminator(type)) + } + +#elseif _ptrauth(_none) + /// Blend a pointer and a small integer to form a new extra-data + /// discriminator. Not all bits of the inputs are guaranteed to + /// contribute to the result. + @_transparent + static func blend(pointer _: UnsafeRawPointer, + discriminator _: UInt64) -> UInt64{ + return 0 + } + + /// Sign an unauthenticated pointer. + @_transparent + static func sign(pointer: UnsafeRawPointer, + key: Key, + discriminator: UInt64) -> UnsafeRawPointer { + return pointer + } + + /// Authenticate a pointer using one scheme and resign it using another. + @_transparent + static func authenticateAndResign(pointer: UnsafeRawPointer, + oldKey: Key, + oldDiscriminator: UInt64, + newKey: Key, + newDiscriminator: UInt64) -> UnsafeRawPointer { + return pointer + } + + /// Get the type-specific discriminator for a function type. + @_transparent + static func discriminator(for type: T.Type) -> UInt64 { + return 0 + } +#else + #error("Unsupported ptrauth scheme") +#endif +} + +// Helpers for working with authenticated function pointers. + +extension UnsafeRawPointer { + /// Load a function pointer from memory that has been authenticated + /// specifically for its given address. + @_transparent + internal func _loadAddressDiscriminatedFunctionPointer( + fromByteOffset offset: Int = 0, + as type: T.Type, + discriminator: UInt64 + ) -> T { + let src = self + offset + + let srcDiscriminator = _PtrAuth.blend(pointer: src, + discriminator: discriminator) + let ptr = src.load(as: UnsafeRawPointer.self) + let resigned = _PtrAuth.authenticateAndResign( + pointer: ptr, + oldKey: .processIndependentCode, + oldDiscriminator: srcDiscriminator, + newKey: .processIndependentCode, + newDiscriminator: _PtrAuth.discriminator(for: type)) + + return unsafeBitCast(resigned, to: type) + } + + @_transparent + internal func _loadAddressDiscriminatedFunctionPointer( + fromByteOffset offset: Int = 0, + as type: Optional.Type, + discriminator: UInt64 + ) -> Optional { + let src = self + offset + + let srcDiscriminator = _PtrAuth.blend(pointer: src, + discriminator: discriminator) + guard let ptr = src.load(as: Optional.self) else { + return nil + } + let resigned = _PtrAuth.authenticateAndResign( + pointer: ptr, + oldKey: .processIndependentCode, + oldDiscriminator: srcDiscriminator, + newKey: .processIndependentCode, + newDiscriminator: _PtrAuth.discriminator(for: T.self)) + + return .some(unsafeBitCast(resigned, to: T.self)) + } + +} + +extension UnsafeMutableRawPointer { + /// Copy a function pointer from memory that has been authenticated + /// specifically for its given address. + internal func _copyAddressDiscriminatedFunctionPointer( + from src: UnsafeRawPointer, + discriminator: UInt64 + ) { + if src == UnsafeRawPointer(self) { return } + + let srcDiscriminator = _PtrAuth.blend(pointer: src, + discriminator: discriminator) + let destDiscriminator = _PtrAuth.blend(pointer: self, + discriminator: discriminator) + + let ptr = src.load(as: UnsafeRawPointer.self) + let resigned = _PtrAuth.authenticateAndResign( + pointer: ptr, + oldKey: .processIndependentCode, + oldDiscriminator: srcDiscriminator, + newKey: .processIndependentCode, + newDiscriminator: destDiscriminator) + + storeBytes(of: resigned, as: UnsafeRawPointer.self) + } + + @_transparent + internal func _storeFunctionPointerWithAddressDiscrimination( + _ unsignedPointer: UnsafeRawPointer, + discriminator: UInt64 + ) { + let destDiscriminator = _PtrAuth.blend(pointer: self, + discriminator: discriminator) + let signed = _PtrAuth.sign(pointer: unsignedPointer, + key: .processIndependentCode, + discriminator: destDiscriminator) + storeBytes(of: signed, as: UnsafeRawPointer.self) + } +} diff --git a/stdlib/public/core/StringGuts.swift b/stdlib/public/core/StringGuts.swift index b94eeacd0175b..038cd5abda1ad 100644 --- a/stdlib/public/core/StringGuts.swift +++ b/stdlib/public/core/StringGuts.swift @@ -325,13 +325,10 @@ extension _StringGuts { public // SPI(corelibs-foundation) func _persistCString(_ p: UnsafePointer?) -> [CChar]? { guard let s = p else { return nil } - let count = Int(_swift_stdlib_strlen(s)) - let result = [CChar](unsafeUninitializedCapacity: count + 1) { buf, initializedCount in - for i in 0..Description; + const auto *conformance = witnessTable->getDescription(); const Metadata *baseTypeThatConformsToHashable = findConformingSuperclass(type, conformance); HashableConformances.getOrInsert(HashableConformanceKey{type}, diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index dc2144fac59f7..1605d7907d6dc 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -2525,22 +2525,24 @@ namespace { // protocol _ObjectiveCBridgeable { struct _ObjectiveCBridgeableWitnessTable : WitnessTable { + #define _protocolWitnessSignedPointer(n) \ + __ptrauth_swift_protocol_witness_function_pointer(SpecialPointerAuthDiscriminators::n##Discriminator) n + static_assert(WitnessTableFirstRequirementOffset == 1, "Witness table layout changed"); - // associatedtype _ObjectiveCType : class void *_ObjectiveCType; // func _bridgeToObjectiveC() -> _ObjectiveCType SWIFT_CC(swift) - HeapObject *(*bridgeToObjectiveC)( + HeapObject *(*_protocolWitnessSignedPointer(bridgeToObjectiveC))( SWIFT_CONTEXT OpaqueValue *self, const Metadata *Self, const _ObjectiveCBridgeableWitnessTable *witnessTable); // class func _forceBridgeFromObjectiveC(x: _ObjectiveCType, // inout result: Self?) SWIFT_CC(swift) - void (*forceBridgeFromObjectiveC)( + void (*_protocolWitnessSignedPointer(forceBridgeFromObjectiveC))( HeapObject *sourceValue, OpaqueValue *result, SWIFT_CONTEXT const Metadata *self, @@ -2550,7 +2552,7 @@ struct _ObjectiveCBridgeableWitnessTable : WitnessTable { // class func _conditionallyBridgeFromObjectiveC(x: _ObjectiveCType, // inout result: Self?) -> Bool SWIFT_CC(swift) - bool (*conditionallyBridgeFromObjectiveC)( + bool (*_protocolWitnessSignedPointer(conditionallyBridgeFromObjectiveC))( HeapObject *sourceValue, OpaqueValue *result, SWIFT_CONTEXT const Metadata *self, @@ -2566,7 +2568,7 @@ MetadataResponse _getBridgedObjectiveCType( const Metadata *conformingType, const _ObjectiveCBridgeableWitnessTable *wtable) { // FIXME: Can we directly reference the descriptor somehow? - const ProtocolConformanceDescriptor *conformance = wtable->Description; + const ProtocolConformanceDescriptor *conformance = wtable->getDescription(); const ProtocolDescriptor *protocol = conformance->getProtocol(); auto assocTypeRequirement = protocol->getRequirements().begin(); assert(assocTypeRequirement->Flags.getKind() == @@ -2874,10 +2876,30 @@ id _bridgeAnythingNonVerbatimToObjectiveC(OpaqueValue *src, extern "C" const _ObjectiveCBridgeableWitnessTable BRIDGING_CONFORMANCE_SYM; #endif +/// Nominal type descriptor for Swift.String. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SS); + +static const _ObjectiveCBridgeableWitnessTable * +swift_conformsToObjectiveCBridgeable(const Metadata *T) { + return reinterpret_cast + (swift_conformsToProtocol(T, &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable))); +} + static const _ObjectiveCBridgeableWitnessTable * findBridgeWitness(const Metadata *T) { - auto w = swift_conformsToProtocol(T, - &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable)); + // Special case: Memoize the bridge witness for Swift.String. + // Swift.String is the most heavily used bridge because of the prevalence of + // string-keyed dictionaries in Obj-C. It's worth burning a few words of static + // storage to avoid repeatedly looking up this conformance. + if (T->getKind() == MetadataKind::Struct) { + auto structDescription = cast(T)->Description; + if (structDescription == &NOMINAL_TYPE_DESCR_SYM(SS)) { + static auto *Swift_String_ObjectiveCBridgeable = swift_conformsToObjectiveCBridgeable(T); + return Swift_String_ObjectiveCBridgeable; + } + } + + auto w = swift_conformsToObjectiveCBridgeable(T); if (LLVM_LIKELY(w)) return reinterpret_cast(w); // Class and ObjC existential metatypes can be bridged, but metatypes can't diff --git a/stdlib/public/runtime/Exclusivity.cpp b/stdlib/public/runtime/Exclusivity.cpp index 59acc280dfadf..2b538c698c832 100644 --- a/stdlib/public/runtime/Exclusivity.cpp +++ b/stdlib/public/runtime/Exclusivity.cpp @@ -347,8 +347,14 @@ void swift::swift_endAccess(ValueBuffer *buffer) { char *swift::swift_getFunctionReplacement(char **ReplFnPtr, char *CurrFn) { char *ReplFn = *ReplFnPtr; - if (ReplFn == CurrFn) + char *RawReplFn = ReplFn; + +#if SWIFT_PTRAUTH + RawReplFn = ptrauth_strip(RawReplFn, ptrauth_key_function_pointer); +#endif + if (RawReplFn == CurrFn) return nullptr; + SwiftTLSContext &ctx = getTLSContext(); if (ctx.CallOriginalOfReplacedFunction) { ctx.CallOriginalOfReplacedFunction = false; diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 76aa40e0eedcb..2517f0349c1fd 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -80,8 +80,29 @@ static inline bool isValidPointerForNativeRetain(const void *p) { // the default implementation. This allows the compiler to inline the default // implementation and avoid the performance penalty of indirecting through // the function pointer in the common case. +// +// NOTE: the memcpy and asm("") naming shenanigans are to convince the compiler +// not to emit a bunch of ptrauth instructions just to perform the comparison. +// We only want to authenticate the function pointer if we actually call it. We +// can revert to a straight comparison once rdar://problem/55267009 is fixed. +static HeapObject *_swift_allocObject_(HeapMetadata const *metadata, + size_t requiredSize, + size_t requiredAlignmentMask) + asm("__swift_allocObject_"); +static HeapObject *_swift_retain_(HeapObject *object) asm("__swift_retain_"); +static HeapObject *_swift_retain_n_(HeapObject *object, uint32_t n) + asm("__swift_retain_n_"); +static void _swift_release_(HeapObject *object) asm("__swift_release_"); +static void _swift_release_n_(HeapObject *object, uint32_t n) + asm("__swift_release_n_"); +static HeapObject *_swift_tryRetain_(HeapObject *object) + asm("__swift_tryRetain_"); #define CALL_IMPL(name, args) do { \ - if (SWIFT_UNLIKELY(_ ## name != _ ## name ## _)) \ + void *fptr; \ + memcpy(&fptr, (void *)&_ ## name, sizeof(fptr)); \ + extern char _ ## name ## _as_char asm("__" #name "_"); \ + fptr = __ptrauth_swift_runtime_function_entry_strip(fptr); \ + if (SWIFT_UNLIKELY(fptr != &_ ## name ## _as_char)) \ return _ ## name args; \ return _ ## name ## _ args; \ } while(0) @@ -112,10 +133,10 @@ HeapObject *swift::swift_allocObject(HeapMetadata const *metadata, CALL_IMPL(swift_allocObject, (metadata, requiredSize, requiredAlignmentMask)); } -HeapObject *(*swift::_swift_allocObject)(HeapMetadata const *metadata, - size_t requiredSize, - size_t requiredAlignmentMask) = - _swift_allocObject_; +SWIFT_RUNTIME_EXPORT +HeapObject *(*SWIFT_RT_DECLARE_ENTRY _swift_allocObject)( + HeapMetadata const *metadata, size_t requiredSize, + size_t requiredAlignmentMask) = _swift_allocObject_; HeapObject * swift::swift_initStackObject(HeapMetadata const *metadata, @@ -326,7 +347,9 @@ HeapObject *swift::swift_retain(HeapObject *object) { CALL_IMPL(swift_retain, (object)); } -HeapObject *(*swift::_swift_retain)(HeapObject *object) = _swift_retain_; +SWIFT_RUNTIME_EXPORT +HeapObject *(*SWIFT_RT_DECLARE_ENTRY _swift_retain)(HeapObject *object) = + _swift_retain_; HeapObject *swift::swift_nonatomic_retain(HeapObject *object) { SWIFT_RT_TRACK_INVOCATION(object, swift_nonatomic_retain); @@ -346,8 +369,9 @@ HeapObject *swift::swift_retain_n(HeapObject *object, uint32_t n) { CALL_IMPL(swift_retain_n, (object, n)); } -HeapObject *(*swift::_swift_retain_n)(HeapObject *object, uint32_t n) = - _swift_retain_n_; +SWIFT_RUNTIME_EXPORT +HeapObject *(*SWIFT_RT_DECLARE_ENTRY _swift_retain_n)( + HeapObject *object, uint32_t n) = _swift_retain_n_; HeapObject *swift::swift_nonatomic_retain_n(HeapObject *object, uint32_t n) { SWIFT_RT_TRACK_INVOCATION(object, swift_nonatomic_retain_n); @@ -366,7 +390,9 @@ void swift::swift_release(HeapObject *object) { CALL_IMPL(swift_release, (object)); } -void (*swift::_swift_release)(HeapObject *object) = _swift_release_; +SWIFT_RUNTIME_EXPORT +void (*SWIFT_RT_DECLARE_ENTRY _swift_release)(HeapObject *object) = + _swift_release_; void swift::swift_nonatomic_release(HeapObject *object) { SWIFT_RT_TRACK_INVOCATION(object, swift_nonatomic_release); @@ -384,8 +410,9 @@ void swift::swift_release_n(HeapObject *object, uint32_t n) { CALL_IMPL(swift_release_n, (object, n)); } -void (*swift::_swift_release_n)(HeapObject *object, uint32_t n) = - _swift_release_n_; +SWIFT_RUNTIME_EXPORT +void (*SWIFT_RT_DECLARE_ENTRY _swift_release_n)(HeapObject *object, + uint32_t n) = _swift_release_n_; void swift::swift_nonatomic_release_n(HeapObject *object, uint32_t n) { SWIFT_RT_TRACK_INVOCATION(object, swift_nonatomic_release_n); @@ -522,7 +549,9 @@ HeapObject *swift::swift_tryRetain(HeapObject *object) { CALL_IMPL(swift_tryRetain, (object)); } -HeapObject *(*swift::_swift_tryRetain)(HeapObject *object) = _swift_tryRetain_; +SWIFT_RUNTIME_EXPORT +HeapObject *(*SWIFT_RT_DECLARE_ENTRY _swift_tryRetain)(HeapObject *object) = + _swift_tryRetain_; bool swift::swift_isDeallocating(HeapObject *object) { if (!isValidPointerForNativeRetain(object)) diff --git a/stdlib/public/runtime/KeyPaths.cpp b/stdlib/public/runtime/KeyPaths.cpp index f0cad6a4dc1a2..ba3f221b923ac 100644 --- a/stdlib/public/runtime/KeyPaths.cpp +++ b/stdlib/public/runtime/KeyPaths.cpp @@ -39,14 +39,21 @@ static intptr_t hashGenericArguments(const void *src, size_t bytes) { return 0; } +struct KeyPathGenericWitnessTable { + void *destroy; + SWIFT_CC(swift) void (* __ptrauth_swift_runtime_function_entry_with_key(swift::SpecialPointerAuthDiscriminators::KeyPathCopy) copy)(const void *src, void *dest, size_t bytes); + SWIFT_CC(swift) bool (* __ptrauth_swift_runtime_function_entry_with_key(swift::SpecialPointerAuthDiscriminators::KeyPathEquals) equals)(const void *, const void *, size_t); + SWIFT_CC(swift) intptr_t (* __ptrauth_swift_runtime_function_entry_with_key(swift::SpecialPointerAuthDiscriminators::KeyPathHash) hash)(const void *src, size_t bytes); +}; + /// A prefab witness table for computed key path components that only include /// captured generic arguments. SWIFT_RUNTIME_EXPORT -void *(swift_keyPathGenericWitnessTable[]) = { - nullptr, // no destructor necessary - (void*)(uintptr_t)swift_copyKeyPathTrivialIndices, - (void*)(uintptr_t)equateGenericArguments, - (void*)(uintptr_t)hashGenericArguments, +KeyPathGenericWitnessTable swift_keyPathGenericWitnessTable = { + nullptr, + swift_copyKeyPathTrivialIndices, + equateGenericArguments, + hashGenericArguments, }; /****************************************************************************/ @@ -143,7 +150,9 @@ swift::swift_readAtKeyPath(YieldOnceBuffer *buffer, // Return a continuation that destroys the value in the buffer // and deallocates it. - return { &_destroy_temporary_continuation, result }; + return { swift_ptrauth_sign_opaque_read_resume_function( + &_destroy_temporary_continuation, buffer), + result }; } static SWIFT_CC(swift) @@ -158,7 +167,9 @@ swift::swift_modifyAtWritableKeyPath(YieldOnceBuffer *buffer, _swift_modifyAtWritableKeyPath_impl(root, keyPath); buffer->Data[0] = addrAndOwner.Owner; - return { &_release_owner_continuation, addrAndOwner.Addr }; + return { swift_ptrauth_sign_opaque_modify_resume_function( + &_release_owner_continuation, buffer), + addrAndOwner.Addr }; } YieldOnceResult @@ -169,5 +180,7 @@ swift::swift_modifyAtReferenceWritableKeyPath(YieldOnceBuffer *buffer, _swift_modifyAtReferenceWritableKeyPath_impl(root, keyPath); buffer->Data[0] = addrAndOwner.Owner; - return { &_release_owner_continuation, addrAndOwner.Addr }; + return { swift_ptrauth_sign_opaque_modify_resume_function( + &_release_owner_continuation, buffer), + addrAndOwner.Addr }; } diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index df4910eab656f..ef6ce0b4f03b7 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -49,6 +49,11 @@ #include #endif // !defined(__wasi__) #endif +#if SWIFT_PTRAUTH +#include +extern "C" void _objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler) + (Class _Nonnull oldClass, Class _Nonnull newClass)); +#endif #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" #include "CompatibilityOverride.h" @@ -76,6 +81,10 @@ using namespace swift; using namespace metadataimpl; +static ClassMetadata * +_swift_relocateClassMetadata(const ClassDescriptor *description, + const ResilientClassMetadataPattern *pattern); + template<> Metadata *TargetSingletonMetadataInitialization::allocate( const TypeContextDescriptor *description) const { @@ -91,7 +100,7 @@ Metadata *TargetSingletonMetadataInitialization::allocate( // Otherwise, use the default behavior. auto *classDescription = cast(description); - return swift_relocateClassMetadata(classDescription, pattern); + return _swift_relocateClassMetadata(classDescription, pattern); } // Otherwise, we have a static template that we can initialize in-place. @@ -153,7 +162,7 @@ computeMetadataBoundsForSuperclass(const void *ref, TypeReferenceKind refKind) { switch (refKind) { case TypeReferenceKind::IndirectTypeDescriptor: { - auto description = *reinterpret_cast(ref); + auto description = *reinterpret_cast(ref); if (!description) { swift::fatalError(0, "instantiating class metadata for class with " "missing weak-linked ancestor"); @@ -381,6 +390,48 @@ static GenericMetadataCache &unsafeGetInitializedCache( return lazyCache->unsafeGetAlreadyInitialized(); } +#if SWIFT_PTRAUTH +static void swift_objc_classCopyFixupHandler(Class oldClass, Class newClass) { + auto oldClassMetadata = reinterpret_cast(oldClass); + + // Bail out if this isn't a Swift. + if (!oldClassMetadata->isTypeMetadata()) + return; + + // Otherwise, re-sign v-table entries using the extra discriminators stored + // in the v-table descriptor. + + auto *srcWords = reinterpret_cast(oldClass); + auto *dstWords = reinterpret_cast(newClass); + + while (oldClassMetadata && oldClassMetadata->isTypeMetadata()) { + const auto *description = oldClassMetadata->getDescription(); + + // Copy the vtable entries. + if (description && description->hasVTable()) { + auto *vtable = description->getVTableDescriptor(); + auto descriptors = description->getMethodDescriptors(); + auto src = srcWords + vtable->getVTableOffset(description); + auto dest = dstWords + vtable->getVTableOffset(description); + for (size_t i = 0, e = vtable->VTableSize; i != e; ++i) { + swift_ptrauth_copy(reinterpret_cast(&dest[i]), + reinterpret_cast(&src[i]), + descriptors[i].Flags.getExtraDiscriminator()); + } + } + + oldClassMetadata = oldClassMetadata->Superclass; + } +} + +SWIFT_ALLOWED_RUNTIME_GLOBAL_CTOR_BEGIN +static bool fixupHandlerInstaller = [] { + _objc_setClassCopyFixupHandler(&swift_objc_classCopyFixupHandler); + return true; +}(); +SWIFT_ALLOWED_RUNTIME_GLOBAL_CTOR_END +#endif + #if SWIFT_OBJC_INTEROP extern "C" void *_objc_empty_cache; #endif @@ -507,6 +558,9 @@ ClassMetadata * swift::swift_allocateGenericClassMetadata(const ClassDescriptor *description, const void *arguments, const GenericClassMetadataPattern *pattern){ + description = swift_auth_data_non_address( + description, SpecialPointerAuthDiscriminators::TypeDescriptor); + auto &generics = description->getFullGenericContextHeader(); auto &cache = unsafeGetInitializedCache(generics); @@ -574,6 +628,8 @@ swift::swift_allocateGenericValueMetadata(const ValueTypeDescriptor *description const void *arguments, const GenericValueMetadataPattern *pattern, size_t extraDataSize) { + description = swift_auth_data_non_address(description, SpecialPointerAuthDiscriminators::TypeDescriptor); + auto &generics = description->getFullGenericContextHeader(); auto &cache = unsafeGetInitializedCache(generics); @@ -608,6 +664,7 @@ MetadataResponse swift::swift_getGenericMetadata(MetadataRequest request, const void * const *arguments, const TypeContextDescriptor *description) { + description = swift_auth_data_non_address(description, SpecialPointerAuthDiscriminators::TypeDescriptor); auto &cache = getCache(*description); assert(description->getFullGenericContextHeader().Base.NumKeyArguments == cache.NumKeyParameters + cache.NumWitnessTables); @@ -1219,7 +1276,7 @@ static void tuple_destroy(OpaqueValue *tuple, const Metadata *_metadata) { // The operation doesn't have to be initializeWithCopy, but they all // have basically the same type. -typedef ValueWitnessTypes::initializeWithCopy forEachOperation; +typedef ValueWitnessTypes::initializeWithCopyUnsigned forEachOperation; /// Perform an operation for each field of two tuples. static OpaqueValue *tuple_forEachField(OpaqueValue *destTuple, @@ -1488,7 +1545,6 @@ static void performBasicLayout(TypeLayout &layout, layout.stride = std::max(size_t(1), roundUpToAlignMask(size, alignMask)); } - size_t swift::swift_getTupleTypeLayout2(TypeLayout *result, const TypeLayout *elt0, const TypeLayout *elt1) { @@ -1547,7 +1603,7 @@ swift::swift_getTupleTypeMetadata(MetadataRequest request, // Bypass the cache for the empty tuple. We might reasonably get called // by generic code, like a demangler that produces type objects. if (numElements == 0) - return { &METADATA_SYM(EMPTY_TUPLE_MANGLING), MetadataState::Complete }; + return MetadataResponse{ &METADATA_SYM(EMPTY_TUPLE_MANGLING), MetadataState::Complete }; // Search the cache. TupleCacheEntry::Key key = { numElements, elements, labels }; @@ -1625,7 +1681,7 @@ TupleCacheEntry::tryInitialize(Metadata *metadata, auto request = MetadataRequest(MetadataState::LayoutComplete, /*non-blocking*/ true); auto eltType = Data.getElement(i).Type; - auto response = swift_checkMetadataState(request, eltType); + MetadataResponse response = swift_checkMetadataState(request, eltType); // Immediately continue in the most common scenario, which is that // the element is transitively complete. @@ -2064,6 +2120,15 @@ static MetadataAllocator &getResilientMetadataAllocator() { ClassMetadata * swift::swift_relocateClassMetadata(const ClassDescriptor *description, const ResilientClassMetadataPattern *pattern) { + description = swift_auth_data_non_address( + description, SpecialPointerAuthDiscriminators::TypeDescriptor); + + return _swift_relocateClassMetadata(description, pattern); +} + +static ClassMetadata * +_swift_relocateClassMetadata(const ClassDescriptor *description, + const ResilientClassMetadataPattern *pattern) { auto bounds = description->getMetadataBounds(); auto metadata = reinterpret_cast( @@ -2320,9 +2385,18 @@ static void copySuperclassMetadataToSubclass(ClassMetadata *theClass, if (description->hasVTable() && !hasStaticVTable(layoutFlags)) { auto *vtable = description->getVTableDescriptor(); auto vtableOffset = vtable->getVTableOffset(description); - memcpy(classWords + vtableOffset, - superWords + vtableOffset, - vtable->VTableSize * sizeof(uintptr_t)); + auto dest = classWords + vtableOffset; + auto src = superWords + vtableOffset; +#if SWIFT_PTRAUTH + auto descriptors = description->getMethodDescriptors(); + for (size_t i = 0, e = vtable->VTableSize; i != e; ++i) { + swift_ptrauth_copy(reinterpret_cast(&dest[i]), + reinterpret_cast(&src[i]), + descriptors[i].Flags.getExtraDiscriminator()); + } +#else + memcpy(dest, src, vtable->VTableSize * sizeof(uintptr_t)); +#endif } // Copy the field offsets. @@ -2360,8 +2434,13 @@ static void initClassVTable(ClassMetadata *self) { if (description->hasVTable()) { auto *vtable = description->getVTableDescriptor(); auto vtableOffset = vtable->getVTableOffset(description); - for (unsigned i = 0, e = vtable->VTableSize; i < e; ++i) - classWords[vtableOffset + i] = description->getMethod(i); + auto descriptors = description->getMethodDescriptors(); + for (unsigned i = 0, e = vtable->VTableSize; i < e; ++i) { + auto &methodDescription = descriptors[i]; + swift_ptrauth_init(&classWords[vtableOffset + i], + methodDescription.Impl.get(), + methodDescription.Flags.getExtraDiscriminator()); + } } if (description->hasOverrideTable()) { @@ -2396,9 +2475,12 @@ static void initClassVTable(ClassMetadata *self) { // Install the method override in our vtable. auto baseVTable = baseClass->getVTableDescriptor(); - auto offset = baseMethod - baseClassMethods.data(); - classWords[baseVTable->getVTableOffset(baseClass) + offset] - = descriptor.Impl.get(); + auto offset = (baseVTable->getVTableOffset(baseClass) + + (baseMethod - baseClassMethods.data())); + + swift_ptrauth_init(&classWords[offset], + descriptor.Impl.get(), + baseMethod->Flags.getExtraDiscriminator()); } } } @@ -2949,7 +3031,19 @@ swift::swift_lookUpClassMethod(const ClassMetadata *metadata, auto vtableOffset = vtable->getVTableOffset(description) + index; auto *words = reinterpret_cast(metadata); - return *(words + vtableOffset); + auto *const *methodPtr = (words + vtableOffset); + +#if SWIFT_PTRAUTH + // Re-sign the return value without the address. + unsigned extra = method->Flags.getExtraDiscriminator(); + return ptrauth_auth_and_resign(*methodPtr, + ptrauth_key_function_pointer, + ptrauth_blend_discriminator(methodPtr, extra), + ptrauth_key_function_pointer, + extra); +#else + return *methodPtr; +#endif } /***************************************************************************/ @@ -4207,6 +4301,112 @@ static bool doesNotRequireInstantiation( return true; } +#if SWIFT_PTRAUTH +static const unsigned swift_ptrauth_key_associated_type = + ptrauth_key_process_independent_code; +#endif + +/// Given an unsigned pointer to an associated-type protocol witness, +/// fill in the appropriate slot in the witness table we're building. +static void initAssociatedTypeProtocolWitness(const Metadata **slot, + const Metadata *witness, + const ProtocolRequirement &reqt) { + assert(reqt.Flags.getKind() == + ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction); + // FIXME: this should use ptrauth_key_process_independent_data + // now that it no longer stores a function pointer. + swift_ptrauth_init(slot, witness, reqt.Flags.getExtraDiscriminator()); +} + +#if SWIFT_PTRAUTH +static const unsigned swift_ptrauth_key_associated_conformance = + ptrauth_key_process_independent_code; + +/// Given an unsigned pointer to an associated-conformance protocol witness, +/// fill in the appropriate slot in the witness table we're building. +static void initAssociatedConformanceProtocolWitness(void **slot, void *witness, + const ProtocolRequirement &reqt) { + assert(reqt.Flags.getKind() == + ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction); + // FIXME: this should use ptrauth_key_process_independent_data + // now that it no longer stores a function pointer. + swift_ptrauth_init(slot, witness, reqt.Flags.getExtraDiscriminator()); +} +#endif + +/// Given an unsigned pointer to an arbitrary protocol witness, fill +/// in a slot in the witness table we're building. +static void initProtocolWitness(void **slot, void *witness, + const ProtocolRequirement &reqt) { +#if SWIFT_PTRAUTH + switch (reqt.Flags.getKind()) { + // Base protocols use no signing at all right now. + case ProtocolRequirementFlags::Kind::BaseProtocol: + *slot = witness; + return; + + // Method requirements use address-discriminated signing with the + // function-pointer key. + case ProtocolRequirementFlags::Kind::Method: + case ProtocolRequirementFlags::Kind::Init: + case ProtocolRequirementFlags::Kind::Getter: + case ProtocolRequirementFlags::Kind::Setter: + case ProtocolRequirementFlags::Kind::ReadCoroutine: + case ProtocolRequirementFlags::Kind::ModifyCoroutine: + swift_ptrauth_init(slot, witness, reqt.Flags.getExtraDiscriminator()); + return; + + case ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction: + initAssociatedConformanceProtocolWitness(slot, witness, reqt); + return; + + case ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction: + initAssociatedTypeProtocolWitness(reinterpret_cast( + const_cast(slot)), + reinterpret_cast( + witness), + reqt); + return; + } + swift_runtime_unreachable("bad witness kind"); +#else + *slot = witness; +#endif +} + +/// Copy an arbitrary protocol witness from another table. +static void copyProtocolWitness(void **dest, void * const *src, + const ProtocolRequirement &reqt) { +#if SWIFT_PTRAUTH + switch (reqt.Flags.getKind()) { + // Base protocols use no signing at all right now. + case ProtocolRequirementFlags::Kind::BaseProtocol: + *dest = *src; + return; + + // Method requirements use address-discriminated signing with the + // function-pointer key. + case ProtocolRequirementFlags::Kind::Method: + case ProtocolRequirementFlags::Kind::Init: + case ProtocolRequirementFlags::Kind::Getter: + case ProtocolRequirementFlags::Kind::Setter: + case ProtocolRequirementFlags::Kind::ReadCoroutine: + case ProtocolRequirementFlags::Kind::ModifyCoroutine: + swift_ptrauth_copy(dest, src, reqt.Flags.getExtraDiscriminator()); + return; + + // FIXME: these should both use ptrauth_key_process_independent_data now. + case ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction: + case ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction: + swift_ptrauth_copy(dest, src, reqt.Flags.getExtraDiscriminator()); + return; + } + swift_runtime_unreachable("bad witness kind"); +#else + *dest = *src; +#endif +} + /// Initialize witness table entries from order independent resilient /// witnesses stored in the generic witness table structure itself. static void initializeResilientWitnessTable( @@ -4240,7 +4440,10 @@ static void initializeResilientWitnessTable( unsigned witnessIndex = (reqDescriptor - requirements.data()) + WitnessTableFirstRequirementOffset; - table[witnessIndex] = witness.Witness.get(); + auto &reqt = requirements[reqDescriptor - requirements.begin()]; + // This is an unsigned pointer formed from a relative address. + void *impl = witness.Witness.get(); + initProtocolWitness(&table[witnessIndex], impl, reqt); } // Loop over the requirements, filling in default implementations where @@ -4252,19 +4455,21 @@ static void initializeResilientWitnessTable( // If we already have a witness, there's nothing to do. auto &reqt = requirements[i]; if (!table[witnessIndex]) { + // This is an unsigned pointer formed from a relative address. void *impl = reqt.DefaultImplementation.get(); - table[witnessIndex] = impl; + initProtocolWitness(&table[witnessIndex], impl, reqt); } // Realize base protocol witnesses. if (reqt.Flags.getKind() == ProtocolRequirementFlags::Kind::BaseProtocol && table[witnessIndex]) { - // Realize the base protocol witness table. + // Realize the base protocol witness table. We call the slow function + // because the fast function doesn't allow base protocol requirements. auto baseReq = protocol->getRequirementBaseDescriptor(); - (void)swift_getAssociatedConformanceWitness((WitnessTable *)table, - conformingType, - conformingType, - baseReq, &reqt); + (void)swift_getAssociatedConformanceWitnessSlow((WitnessTable *)table, + conformingType, + conformingType, + baseReq, &reqt); } } } @@ -4302,9 +4507,16 @@ WitnessTableCacheEntry::allocate( if (auto pattern = reinterpret_cast( &*conformance->getWitnessTablePattern())) { + auto requirements = protocol->getRequirements(); + // Fill in the provided part of the requirements from the pattern. for (size_t i = 0, e = numPatternWitnesses; i < e; ++i) { - table[i] = pattern[i]; + size_t requirementIndex = i - WitnessTableFirstRequirementOffset; + if (i < WitnessTableFirstRequirementOffset) + table[i] = pattern[i]; + else + copyProtocolWitness(&table[i], &pattern[i], + requirements[requirementIndex]); } } else { // Put the conformance descriptor in place. Instantiation will fill in the @@ -4414,7 +4626,7 @@ swift_getAssociatedTypeWitnessSlowImpl( const ProtocolRequirement *assocType) { #ifndef NDEBUG { - const ProtocolConformanceDescriptor *conformance = wtable->Description; + const ProtocolConformanceDescriptor *conformance = wtable->getDescription(); const ProtocolDescriptor *protocol = conformance->getProtocol(); auto requirements = protocol->getRequirements(); assert(assocType >= requirements.begin() && @@ -4425,9 +4637,19 @@ swift_getAssociatedTypeWitnessSlowImpl( } #endif - // If the low bit of the witness is clear, it's already a metadata pointer. + // Retrieve the witness. unsigned witnessIndex = assocType - reqBase; - auto witness = ((const void* const *)wtable)[witnessIndex]; + auto *witnessAddr = &((const Metadata **)wtable)[witnessIndex]; + auto witness = *witnessAddr; + +#if SWIFT_PTRAUTH + uint16_t extraDiscriminator = assocType->Flags.getExtraDiscriminator(); + witness = ptrauth_auth_data(witness, swift_ptrauth_key_associated_type, + ptrauth_blend_discriminator(witnessAddr, + extraDiscriminator)); +#endif + + // If the low bit of the witness is clear, it's already a metadata pointer. if (LLVM_LIKELY((uintptr_t(witness) & ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) { // Cached metadata pointers are always complete. @@ -4449,7 +4671,7 @@ swift_getAssociatedTypeWitnessSlowImpl( } // Dig out the protocol. - const ProtocolConformanceDescriptor *conformance = wtable->Description; + const ProtocolConformanceDescriptor *conformance = wtable->getDescription(); const ProtocolDescriptor *protocol = conformance->getProtocol(); // Extract the mangled name itself. @@ -4519,7 +4741,10 @@ swift_getAssociatedTypeWitnessSlowImpl( // If the metadata was completed, record it in the witness table. if (response.State == MetadataState::Complete) { - reinterpret_cast(wtable)[witnessIndex] = assocTypeMetadata; + // We pass type metadata around as unsigned pointers, but we sign them + // in witness tables, which doesn't provide all that much extra security. + initAssociatedTypeProtocolWitness(witnessAddr, assocTypeMetadata, + *assocType); } return response; @@ -4531,9 +4756,21 @@ swift::swift_getAssociatedTypeWitness(MetadataRequest request, const Metadata *conformingType, const ProtocolRequirement *reqBase, const ProtocolRequirement *assocType) { + assert(assocType->Flags.getKind() == + ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction); + // If the low bit of the witness is clear, it's already a metadata pointer. unsigned witnessIndex = assocType - reqBase; - auto witness = ((const void* const *)wtable)[witnessIndex]; + auto *witnessAddr = &((const void* *)wtable)[witnessIndex]; + auto witness = *witnessAddr; + +#if SWIFT_PTRAUTH + uint16_t extraDiscriminator = assocType->Flags.getExtraDiscriminator(); + witness = ptrauth_auth_data(witness, swift_ptrauth_key_associated_type, + ptrauth_blend_discriminator(witnessAddr, + extraDiscriminator)); +#endif + if (LLVM_LIKELY((uintptr_t(witness) & ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) { // Cached metadata pointers are always complete. @@ -4553,7 +4790,7 @@ static const WitnessTable *swift_getAssociatedConformanceWitnessSlowImpl( const ProtocolRequirement *assocConformance) { #ifndef NDEBUG { - const ProtocolConformanceDescriptor *conformance = wtable->Description; + const ProtocolConformanceDescriptor *conformance = wtable->getDescription(); const ProtocolDescriptor *protocol = conformance->getProtocol(); auto requirements = protocol->getRequirements(); assert(assocConformance >= requirements.begin() && @@ -4569,7 +4806,22 @@ static const WitnessTable *swift_getAssociatedConformanceWitnessSlowImpl( // Retrieve the witness. unsigned witnessIndex = assocConformance - reqBase; - auto witness = ((const void* const *)wtable)[witnessIndex]; + auto *witnessAddr = &((void**)wtable)[witnessIndex]; + auto witness = *witnessAddr; + +#if SWIFT_PTRAUTH + // For associated protocols, the witness is signed with address + // discrimination. + // For base protocols, the witness isn't signed at all. + if (assocConformance->Flags.isSignedWithAddress()) { + uint16_t extraDiscriminator = + assocConformance->Flags.getExtraDiscriminator(); + witness = ptrauth_auth_data( + witness, swift_ptrauth_key_associated_conformance, + ptrauth_blend_discriminator(witnessAddr, extraDiscriminator)); + } +#endif + // Fast path: we've already resolved this to a witness table, so return it. if (LLVM_LIKELY((uintptr_t(witness) & ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) { @@ -4601,13 +4853,21 @@ static const WitnessTable *swift_getAssociatedConformanceWitnessSlowImpl( // Call the witness function. auto witnessFn = (AssociatedWitnessTableAccessFunction *)ptr; - auto assocWitnessTable = witnessFn(assocType, conformingType, wtable); +#if SWIFT_PTRAUTH + witnessFn = ptrauth_sign_unauthenticated(witnessFn, + ptrauth_key_function_pointer, + 0); +#endif + auto assocWitnessTable = witnessFn(assocType, conformingType, wtable); assert((uintptr_t(assocWitnessTable) & ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0); - // Update the cache. - reinterpret_cast(wtable)[witnessIndex] = assocWitnessTable; + // The access function returns an unsigned pointer for now. + + // We can't just use initAssociatedConformanceProtocolWitness because we + // also use this function for base protocols. + initProtocolWitness(witnessAddr, assocWitnessTable, *assocConformance); return assocWitnessTable; } @@ -4621,9 +4881,23 @@ const WitnessTable *swift::swift_getAssociatedConformanceWitness( const Metadata *assocType, const ProtocolRequirement *reqBase, const ProtocolRequirement *assocConformance) { + // We avoid using this function for initializing base protocol conformances + // so that we can have a better fast-path. + assert(assocConformance->Flags.getKind() == + ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction); + // Retrieve the witness. unsigned witnessIndex = assocConformance - reqBase; - auto witness = ((const void* const *)wtable)[witnessIndex]; + auto *witnessAddr = &((const void* *)wtable)[witnessIndex]; + auto witness = *witnessAddr; + +#if SWIFT_PTRAUTH + uint16_t extraDiscriminator = assocConformance->Flags.getExtraDiscriminator(); + witness = ptrauth_auth_data(witness, swift_ptrauth_key_associated_conformance, + ptrauth_blend_discriminator(witnessAddr, + extraDiscriminator)); +#endif + // Fast path: we've already resolved this to a witness table, so return it. if (LLVM_LIKELY((uintptr_t(witness) & ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) { @@ -4955,7 +5229,8 @@ checkTransitiveCompleteness(const Metadata *initialType) { // Check the metadata's current state with a non-blocking request. auto request = MetadataRequest(MetadataState::Complete, /*non-blocking*/ true); - auto state = swift_checkMetadataState(request, type).State; + auto state = + MetadataResponse(swift_checkMetadataState(request, type)).State; // If it's transitively complete, we're done. // This is the most likely result. diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index bc1f811105a95..29560bbf164cb 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -365,8 +365,8 @@ class MetadataCacheKey { if (awt == bwt) return 0; - auto *aDescription = awt->Description; - auto *bDescription = bwt->Description; + auto *aDescription = awt->getDescription(); + auto *bDescription = bwt->getDescription(); if (aDescription == bDescription) return 0; diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index dedbebd8591d2..8c1efa232cbf4 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -72,16 +72,39 @@ class DemanglerForRuntimeTypeResolution : public Base { } }; +/// Resolve the relative reference in a mangled symbolic reference. +static uintptr_t resolveSymbolicReferenceOffset(SymbolicReferenceKind kind, + Directness isIndirect, + int32_t offset, + const void *base) { + auto ptr = detail::applyRelativeOffset(base, offset); + + // Indirect references may be authenticated in a way appropriate for the + // referent. + if (isIndirect == Directness::Indirect) { + switch (kind) { + case SymbolicReferenceKind::Context: { + ContextDescriptor *contextPtr = + *(const TargetSignedContextPointer *)ptr; + return (uintptr_t)contextPtr; + } + case SymbolicReferenceKind::AccessorFunctionReference: { + swift_runtime_unreachable("should not be indirectly referenced"); + } + } + swift_runtime_unreachable("unknown symbolic reference kind"); + } else { + return ptr; + } +} + NodePointer ResolveAsSymbolicReference::operator()(SymbolicReferenceKind kind, Directness isIndirect, int32_t offset, const void *base) { // Resolve the absolute pointer to the entity being referenced. - auto ptr = detail::applyRelativeOffset(base, offset); - if (isIndirect == Directness::Indirect) { - ptr = *(const uintptr_t *)ptr; - } + auto ptr = resolveSymbolicReferenceOffset(kind, isIndirect, offset, base); // Figure out this symbolic reference's grammatical role. Node::Kind nodeKind; @@ -118,6 +141,11 @@ ResolveAsSymbolicReference::operator()(SymbolicReferenceKind kind, // invoke the function to resolve the thing they're trying to access. nodeKind = Node::Kind::AccessorFunctionReference; isType = false; +#if SWIFT_PTRAUTH + // The pointer refers to an accessor function, which we need to sign. + ptr = (uintptr_t)ptrauth_sign_unauthenticated((void*)ptr, + ptrauth_key_function_pointer, 0); +#endif break; } } @@ -140,6 +168,11 @@ _buildDemanglingForSymbolicReference(SymbolicReferenceKind kind, return _buildDemanglingForContext( (const ContextDescriptor *)resolvedReference, {}, Dem); case SymbolicReferenceKind::AccessorFunctionReference: +#if SWIFT_PTRAUTH + // The pointer refers to an accessor function, which we need to sign. + resolvedReference = ptrauth_sign_unauthenticated(resolvedReference, + ptrauth_key_function_pointer, 0); +#endif return Dem.createNode(Node::Kind::AccessorFunctionReference, (uintptr_t)resolvedReference); } @@ -152,11 +185,8 @@ ResolveToDemanglingForContext::operator()(SymbolicReferenceKind kind, Directness isIndirect, int32_t offset, const void *base) { - auto ptr = detail::applyRelativeOffset(base, offset); - if (isIndirect == Directness::Indirect) { - ptr = *(const uintptr_t *)ptr; - } - + auto ptr = resolveSymbolicReferenceOffset(kind, isIndirect, offset, base); + return _buildDemanglingForSymbolicReference(kind, (const void *)ptr, Dem); } @@ -1371,10 +1401,11 @@ class DecodedMetadataBuilder { auto flags = TupleTypeFlags().withNumElements(elements.size()); if (!labels.empty()) flags = flags.withNonConstantLabels(true); - return swift_getTupleTypeMetadata(MetadataState::Abstract, - flags, elements.data(), - labels.empty() ? nullptr : labels.c_str(), - /*proposedWitnesses=*/nullptr).Value; + return MetadataResponse(swift_getTupleTypeMetadata( + MetadataState::Abstract, flags, elements.data(), + labels.empty() ? nullptr : labels.c_str(), + /*proposedWitnesses=*/nullptr)) + .Value; } BuiltType createDependentMemberType(StringRef name, BuiltType base) const { @@ -1459,7 +1490,7 @@ static TypeInfo swift_getTypeByMangledNodeImpl( // The accessor function is passed the pointer to the original argument // buffer. It's assumed to match the generic context. auto accessorFn = - (const Metadata *(*)(const void * const *))node->getIndex(); + (const Metadata *(*)(const void * const *))node->getIndex(); auto type = accessorFn(origArgumentVector); // We don't call checkMetadataState here since the result may not really // *be* type metadata. If the accessor returns a type, it is responsible @@ -2090,18 +2121,31 @@ void DynamicReplacementDescriptor::enableReplacement() const { if (!shouldChain() && chainRoot->next) { auto *previous = chainRoot->next; chainRoot->next = previous->next; - chainRoot->implementationFunction = previous->implementationFunction; + //chainRoot->implementationFunction = previous->implementationFunction; + swift_ptrauth_copy( + reinterpret_cast(&chainRoot->implementationFunction), + reinterpret_cast(&previous->implementationFunction), + replacedFunctionKey->getExtraDiscriminator()); } // First populate the current replacement's chain entry. auto *currentEntry = const_cast(chainEntry.get()); - currentEntry->implementationFunction = chainRoot->implementationFunction; + // currentEntry->implementationFunction = chainRoot->implementationFunction; + swift_ptrauth_copy( + reinterpret_cast(¤tEntry->implementationFunction), + reinterpret_cast(&chainRoot->implementationFunction), + replacedFunctionKey->getExtraDiscriminator()); + currentEntry->next = chainRoot->next; // Link the replacement entry. chainRoot->next = chainEntry.get(); - chainRoot->implementationFunction = replacementFunction.get(); + // chainRoot->implementationFunction = replacementFunction.get(); + swift_ptrauth_init( + reinterpret_cast(&chainRoot->implementationFunction), + reinterpret_cast(replacementFunction.get()), + replacedFunctionKey->getExtraDiscriminator()); } void DynamicReplacementDescriptor::disableReplacement() const { @@ -2121,7 +2165,11 @@ void DynamicReplacementDescriptor::disableReplacement() const { // Unlink this entry. auto *previous = const_cast(prev); previous->next = thisEntry->next; - previous->implementationFunction = thisEntry->implementationFunction; + // previous->implementationFunction = thisEntry->implementationFunction; + swift_ptrauth_copy( + reinterpret_cast(&previous->implementationFunction), + reinterpret_cast(&thisEntry->implementationFunction), + replacedFunctionKey->getExtraDiscriminator()); } /// An automatic dymamic replacement entry. @@ -2166,7 +2214,10 @@ class AutomaticDynamicReplacements /// A map from original to replaced opaque type descriptor of a some type. class DynamicReplacementSomeDescriptor { - RelativeIndirectablePointer + RelativeIndirectablePointer< + const OpaqueTypeDescriptor, false, int32_t, + TargetSignedPointer> originalOpaqueTypeDesc; RelativeDirectPointer replacementOpaqueTypeDesc; @@ -2263,11 +2314,15 @@ void swift::addImageDynamicReplacementBlockCallback( void swift::swift_enableDynamicReplacementScope( const DynamicReplacementScope *scope) { + scope = swift_auth_data_non_address( + scope, SpecialPointerAuthDiscriminators::DynamicReplacementScope); DynamicReplacementLock.get().withLock([=] { scope->enable(); }); } void swift::swift_disableDynamicReplacementScope( const DynamicReplacementScope *scope) { + scope = swift_auth_data_non_address( + scope, SpecialPointerAuthDiscriminators::DynamicReplacementScope); DynamicReplacementLock.get().withLock([=] { scope->disable(); }); } #define OVERRIDE_METADATALOOKUP COMPATIBILITY_OVERRIDE diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index 3fe43c5e75598..33aee0ce006ce 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -1520,8 +1520,8 @@ void swift_objc_swift3ImplicitObjCEntrypoint(id self, SEL selector, RuntimeErrorDetails::FixIt fixit = { .filename = nullTerminatedFilename, .startLine = line, - .endLine = line, .startColumn = column, + .endLine = line, .endColumn = column, .replacementText = "@objc " }; diff --git a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp index b4d3a3e7ff780..e2dcc24b6e774 100644 --- a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp +++ b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp @@ -32,6 +32,10 @@ extern "C" char *swift_getFunctionReplacement50(char **ReplFnPtr, char *CurrFn) char *ReplFn = *ReplFnPtr; char *RawReplFn = ReplFn; +#if SWIFT_PTRAUTH + RawReplFn = ptrauth_strip(RawReplFn, ptrauth_key_function_pointer); +#endif + if (RawReplFn == CurrFn) return nullptr; diff --git a/stdlib/toolchain/legacy_layouts/iphoneos/layouts-arm64e.yaml b/stdlib/toolchain/legacy_layouts/iphoneos/layouts-arm64e.yaml new file mode 100644 index 0000000000000..a9f22fcda8e8b --- /dev/null +++ b/stdlib/toolchain/legacy_layouts/iphoneos/layouts-arm64e.yaml @@ -0,0 +1,452 @@ +--- +Name: ARKit +Decls: + - Name: So13ARPlaneAnchorC5ARKitE14ClassificationO + Size: 1 + Alignment: 1 + ExtraInhabitants: 248 + - Name: So13ARPlaneAnchorC5ARKitE14ClassificationO6StatusO + Size: 1 + Alignment: 1 + ExtraInhabitants: 253 + - Name: So8ARCameraC5ARKitE13TrackingStateO6ReasonO + Size: 1 + Alignment: 1 + ExtraInhabitants: 252 +... +--- +Name: AVFoundation +Decls: + - Name: So35AVCaptureSynchronizedDataCollectionC12AVFoundationE8IteratorV + Size: 217 + Alignment: 8 + ExtraInhabitants: 2147483647 +... +--- +Name: CloudKit +Decls: + - Name: 8CloudKit24CKRecordKeyValueIteratorV + Size: 24 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: So11CKContainerC8CloudKitE11ApplicationO + Size: 0 + Alignment: 1 + ExtraInhabitants: 0 + - Name: So7CKShareC8CloudKitE14SystemFieldKeyO + Size: 0 + Alignment: 1 + ExtraInhabitants: 0 + - Name: So8CKRecordC8CloudKitE10SystemTypeO + Size: 0 + Alignment: 1 + ExtraInhabitants: 0 + - Name: So8CKRecordC8CloudKitE14SystemFieldKeyO + Size: 0 + Alignment: 1 + ExtraInhabitants: 0 +... +--- +Name: CoreAudio +Decls: + - Name: 9CoreAudio013UnsafeMutableB17BufferListPointerV + Size: 8 + Alignment: 8 + ExtraInhabitants: 1 +... +--- +Name: CoreGraphics +Decls: + - Name: 12CoreGraphics14CGPathFillRuleO + Size: 1 + Alignment: 1 + ExtraInhabitants: 254 +... +--- +Name: Dispatch +Decls: + - Name: 8Dispatch0A12DataIteratorV + Size: 32 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 8Dispatch0A12TimeIntervalO + Size: 9 + Alignment: 8 + ExtraInhabitants: 251 + - Name: 8Dispatch0A13WorkItemFlagsV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 8Dispatch0A3QoSV + Size: 16 + Alignment: 8 + ExtraInhabitants: 250 + - Name: 8Dispatch0A3QoSV0B6SClassO + Size: 1 + Alignment: 1 + ExtraInhabitants: 250 + - Name: 8Dispatch0A4DataV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 8Dispatch0A4DataV11DeallocatorO + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483645 + - Name: 8Dispatch0A4TimeV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 8Dispatch0A8WallTimeV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 8Dispatch0A9PredicateO + Size: 9 + Alignment: 8 + ExtraInhabitants: 253 + - Name: So14OS_dispatch_ioC8DispatchE10CloseFlagsV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: So14OS_dispatch_ioC8DispatchE10StreamTypeO + Size: 1 + Alignment: 1 + ExtraInhabitants: 254 + - Name: So14OS_dispatch_ioC8DispatchE13IntervalFlagsV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: So17OS_dispatch_queueC8DispatchE10AttributesV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: So17OS_dispatch_queueC8DispatchE19GlobalQueuePriorityO + Size: 1 + Alignment: 1 + ExtraInhabitants: 252 + - Name: So17OS_dispatch_queueC8DispatchE20AutoreleaseFrequencyO + Size: 1 + Alignment: 1 + ExtraInhabitants: 253 + - Name: So18OS_dispatch_sourceC8DispatchE10TimerFlagsV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: So18OS_dispatch_sourceC8DispatchE12ProcessEventV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: So18OS_dispatch_sourceC8DispatchE13MachSendEventV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: So18OS_dispatch_sourceC8DispatchE15FileSystemEventV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: So18OS_dispatch_sourceC8DispatchE19MemoryPressureEventV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 +... +--- +Name: Foundation +Decls: + - Name: 10Foundation10CocoaErrorV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation10CocoaErrorV4CodeV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 10Foundation10POSIXErrorV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation10URLRequestV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation11JSONDecoderC19KeyDecodingStrategyO + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483645 + - Name: 10Foundation11JSONDecoderC20DataDecodingStrategyO + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483645 + - Name: 10Foundation11JSONDecoderC20DateDecodingStrategyO + Size: 17 + Alignment: 8 + ExtraInhabitants: 253 + - Name: 10Foundation11JSONDecoderC34NonConformingFloatDecodingStrategyO + Size: 48 + Alignment: 8 + ExtraInhabitants: 2147483646 + - Name: 10Foundation11JSONEncoderC16OutputFormattingV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 10Foundation11JSONEncoderC19KeyEncodingStrategyO + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483645 + - Name: 10Foundation11JSONEncoderC20DataEncodingStrategyO + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483645 + - Name: 10Foundation11JSONEncoderC20DateEncodingStrategyO + Size: 17 + Alignment: 8 + ExtraInhabitants: 253 + - Name: 10Foundation11JSONEncoderC34NonConformingFloatEncodingStrategyO + Size: 48 + Alignment: 8 + ExtraInhabitants: 2147483646 + - Name: 10Foundation11MeasurementV + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation12CharacterSetV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation12DateIntervalV + Size: 16 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 10Foundation12NotificationV + Size: 48 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation12URLQueryItemV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation13URLComponentsV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation14DateComponentsV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation16ErrorUserInfoKeyV + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation17URLResourceValuesV + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation18NSIndexSetIteratorV + Size: 25 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation20PersonNameComponentsV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation25NSFastEnumerationIteratorV + Size: 217 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation3URLV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation4DataV11DeallocatorO + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483643 + - Name: 10Foundation4DataV8IteratorV + Size: 64 + Alignment: 8 + ExtraInhabitants: 12 + - Name: 10Foundation4DateV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 10Foundation4UUIDV + Size: 16 + Alignment: 1 + ExtraInhabitants: 0 + - Name: 10Foundation6LocaleV + Size: 9 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation8CalendarV + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation8CalendarV10IdentifierO + Size: 1 + Alignment: 1 + ExtraInhabitants: 240 + - Name: 10Foundation8CalendarV14MatchingPolicyO + Size: 1 + Alignment: 1 + ExtraInhabitants: 252 + - Name: 10Foundation8CalendarV15SearchDirectionO + Size: 1 + Alignment: 1 + ExtraInhabitants: 254 + - Name: 10Foundation8CalendarV18RepeatedTimePolicyO + Size: 1 + Alignment: 1 + ExtraInhabitants: 254 + - Name: 10Foundation8CalendarV9ComponentO + Size: 1 + Alignment: 1 + ExtraInhabitants: 240 + - Name: 10Foundation8IndexSetV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation8IndexSetV0B0V + Size: 40 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 10Foundation8IndexSetV9RangeViewV + Size: 24 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation8TimeZoneV + Size: 9 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation8URLErrorV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 10Foundation8URLErrorV4CodeV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: 10Foundation9IndexPathV + Size: 17 + Alignment: 8 + ExtraInhabitants: 252 + - Name: 10Foundation9MachErrorV + Size: 8 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 8Dispatch0A4DataV10FoundationE6RegionV + Size: 32 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: SS10FoundationE8EncodingV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 +... +--- +Name: Intents +Decls: + - Name: 7Intents10INShortcutO + Size: 9 + Alignment: 8 + ExtraInhabitants: 254 +... +--- +Name: Network +Decls: + - Name: 7Network10NWEndpointO + Size: 89 + Alignment: 8 + ExtraInhabitants: 253 + - Name: 7Network10NWEndpointO4HostO + Size: 57 + Alignment: 8 + ExtraInhabitants: 253 + - Name: 7Network10NWEndpointO4PortV + Size: 2 + Alignment: 2 + ExtraInhabitants: 0 + - Name: 7Network10NWListenerC25ServiceRegistrationChangeO + Size: 90 + Alignment: 8 + ExtraInhabitants: 254 + - Name: 7Network10NWListenerC5StateO + Size: 5 + Alignment: 4 + ExtraInhabitants: 61 + - Name: 7Network10NWListenerC7ServiceV + Size: 64 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 7Network11IPv4AddressV + Size: 48 + Alignment: 8 + ExtraInhabitants: 2147483646 + - Name: 7Network11IPv6AddressV + Size: 56 + Alignment: 8 + ExtraInhabitants: 2147483646 + - Name: 7Network11IPv6AddressV5ScopeO + Size: 1 + Alignment: 1 + ExtraInhabitants: 251 + - Name: 7Network11NWInterfaceV + Size: 40 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 7Network11NWInterfaceV13InterfaceTypeO + Size: 1 + Alignment: 1 + ExtraInhabitants: 251 + - Name: 7Network12NWConnectionC14SendCompletionO + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483646 + - Name: 7Network12NWConnectionC5StateO + Size: 5 + Alignment: 4 + ExtraInhabitants: 61 + - Name: 7Network12NWParametersC12ServiceClassO + Size: 1 + Alignment: 1 + ExtraInhabitants: 250 + - Name: 7Network12NWParametersC18ExpiredDNSBehaviorO + Size: 1 + Alignment: 1 + ExtraInhabitants: 253 + - Name: 7Network12NWParametersC20MultipathServiceTypeO + Size: 1 + Alignment: 1 + ExtraInhabitants: 252 + - Name: 7Network12NWProtocolIPC3ECNO + Size: 1 + Alignment: 1 + ExtraInhabitants: 252 + - Name: 7Network12NWProtocolIPC7OptionsC7VersionO + Size: 1 + Alignment: 1 + ExtraInhabitants: 253 + - Name: 7Network6NWPathV + Size: 224 + Alignment: 8 + ExtraInhabitants: 2147483647 + - Name: 7Network6NWPathV6StatusO + Size: 1 + Alignment: 1 + ExtraInhabitants: 253 + - Name: 7Network7NWErrorO + Size: 5 + Alignment: 4 + ExtraInhabitants: 253 +... +--- +Name: os +Decls: + - Name: 2os12OSSignpostIDV + Size: 8 + Alignment: 8 + ExtraInhabitants: 0 + - Name: So9OS_os_logC0B0E8CategoryV + Size: 16 + Alignment: 8 + ExtraInhabitants: 2147483647 +... diff --git a/stdlib/tools/swift-reflection-test/swift-reflection-test.c b/stdlib/tools/swift-reflection-test/swift-reflection-test.c index fb5a3eec23b55..b4c0dcb2f3a33 100644 --- a/stdlib/tools/swift-reflection-test/swift-reflection-test.c +++ b/stdlib/tools/swift-reflection-test/swift-reflection-test.c @@ -38,6 +38,10 @@ #include #endif +#if __has_feature(ptrauth_calls) +#include +#endif + #if defined(__clang__) || defined(__GNUC__) #define NORETURN __attribute__((noreturn)) #elif defined(_MSC_VER) @@ -160,6 +164,15 @@ static int PipeMemoryReader_queryDataLayout(void *Context, *result = sizeof(size_t); return 1; } + case DLQ_GetPtrAuthMask: { + uintptr_t *result = (uintptr_t *)outBuffer; +#if __has_feature(ptrauth_calls) + *result = (uintptr_t)ptrauth_strip((void*)0x0007ffffffffffff, 0); +#else + *result = (uintptr_t)~0ull; +#endif + return 1; + } case DLQ_GetObjCReservedLowBits: { uint8_t *result = (uint8_t *)outBuffer; if (applePlatform && !iosDerivedPlatform && (sizeof(void *) == 8)) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4b48ab05502f2..8e272ed0d0912 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -66,6 +66,7 @@ function(get_test_dependencies SDK result_var_name) dsymutil FileCheck llc + llvm-ar llvm-as llvm-bcanalyzer llvm-cov @@ -241,11 +242,11 @@ foreach(SDK ${SWIFT_SDKS}) set(test_dependencies) get_test_dependencies("${SDK}" test_dependencies) - # NOTE create a stub BlocksRuntime library that can be used for the - # reflection tests - if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin AND (SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT)) + if(SWIFT_BUILD_STDLIB AND SWIFT_INCLUDE_TESTS AND NOT ${SDK} STREQUAL "WASI") + # NOTE create a stub BlocksRuntime library that can be used for the + # reflection tests file(WRITE ${test_bin_dir}/Inputs/BlocksRuntime.c - "void + "void #if defined(_WIN32) __declspec(dllexport) #endif @@ -264,9 +265,7 @@ _Block_release(void) { }\n") RUNTIME_OUTPUT_DIRECTORY ${test_bin_dir} OUTPUT_NAME BlocksRuntime) list(APPEND test_dependencies BlocksRuntimeStub${VARIANT_SUFFIX}) - endif() - if(SWIFT_BUILD_STDLIB AND SWIFT_INCLUDE_TESTS) list(APPEND test_dependencies "swift-test-stdlib-${SWIFT_SDK_${SDK}_LIB_SUBDIR}") diff --git a/test/Constraints/array_literal.swift b/test/Constraints/array_literal.swift index 73e772791ab15..0ac54dd53550b 100644 --- a/test/Constraints/array_literal.swift +++ b/test/Constraints/array_literal.swift @@ -50,7 +50,7 @@ useDoubleList([1.0,2,3]) useDoubleList([1.0,2.0,3.0]) useIntDict(["Niners" => 31, "Ravens" => 34]) -useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected element type 'Int'}} +useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Int'}} // QoI: Propagate contextual information in a call to operands useDoubleDict(["Niners" => 31, "Ravens" => 34.0]) useDoubleDict(["Niners" => 31.0, "Ravens" => 34]) diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index aeffde648599e..0d1109f6ab817 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -456,7 +456,13 @@ extension Collection { } } func fn_r28909024(n: Int) { - return (0..<10).r28909024 { // expected-error {{unexpected non-void return value in void function}} expected-note {{did you mean to add a return type?}} + // FIXME(diagnostics): Unfortunately there is no easy way to fix this diagnostic issue at the moment + // because the problem is related to ordering of the bindings - we'd attempt to bind result of the expression + // to contextual type of `Void` which prevents solver from discovering correct types for range - 0..<10 + // (since both arguments are literal they are ranked lower than contextual type). + // + // Good diagnostic for this is - `unexpected non-void return value in void function` + return (0..<10).r28909024 { // expected-error {{type of expression is ambiguous without more context}} _ in true } } diff --git a/test/Constraints/default_literals.swift b/test/Constraints/default_literals.swift index 02f79b446f64d..f52e85ec2ac62 100644 --- a/test/Constraints/default_literals.swift +++ b/test/Constraints/default_literals.swift @@ -42,14 +42,3 @@ extension Int { var (div, mod) = (9 / 4, 9 % 4) - -// rdar://problem/56212087 - solver fails to infer correct type for a generic parameter (Any vs. String) -func test_transitive_inference_of_default_literal_types() { - func foo(_: String, _: T) -> T { - fatalError() - } - - func bar(_: Any?) {} - - bar(foo("", "")) // Ok -} diff --git a/test/Constraints/function_builder.swift b/test/Constraints/function_builder.swift index b39332602c476..cd71f71d30177 100644 --- a/test/Constraints/function_builder.swift +++ b/test/Constraints/function_builder.swift @@ -617,3 +617,50 @@ testSwitchCombined(getE(1)) // CHECK: testSwitchCombined // CHECK-SAME: second("just 42") testSwitchCombined(getE(2)) + + +// Test buildOptional(_:) as an alternative to buildIf(_:). +@_functionBuilder +struct TupleBuilderWithOpt { + static func buildBlock(_ t1: T1) -> (T1) { + return (t1) + } + + static func buildBlock(_ t1: T1, _ t2: T2) -> (T1, T2) { + return (t1, t2) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) + -> (T1, T2, T3) { + return (t1, t2, t3) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) + -> (T1, T2, T3, T4) { + return (t1, t2, t3, t4) + } + + static func buildBlock( + _ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5 + ) -> (T1, T2, T3, T4, T5) { + return (t1, t2, t3, t4, t5) + } + + static func buildDo(_ value: T) -> T { return value } + static func buildOptional(_ value: T?) -> T? { return value } + + static func buildEither(first value: T) -> Either { + return .first(value) + } + static func buildEither(second value: U) -> Either { + return .second(value) + } +} + +func tuplifyWithOpt(_ cond: Bool, @TupleBuilderWithOpt body: (Bool) -> T) { + print(body(cond)) +} +tuplifyWithOpt(true) { c in + "1" + 3.14159 +} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 17579bbc2273c..9ebbc02cdc244 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -480,3 +480,63 @@ func testCaseVarTypes(e: E3) { } } } + +// Test for buildFinalResult. +@_functionBuilder +struct WrapperBuilder { + static func buildBlock() -> () { } + + static func buildBlock(_ t1: T1) -> T1 { + return t1 + } + + static func buildBlock(_ t1: T1, _ t2: T2) -> (T1, T2) { + return (t1, t2) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) + -> (T1, T2, T3) { + return (t1, t2, t3) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) + -> (T1, T2, T3, T4) { + return (t1, t2, t3, t4) + } + + static func buildBlock( + _ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5 + ) -> (T1, T2, T3, T4, T5) { + return (t1, t2, t3, t4, t5) + } + + static func buildDo(_ value: T) -> T { return value } + static func buildIf(_ value: T?) -> T? { return value } + + static func buildEither(first value: T) -> Either { + return .first(value) + } + static func buildEither(second value: U) -> Either { + return .second(value) + } + static func buildFinalResult(_ value: T) -> Wrapper { + return Wrapper(value: value) + } +} + +struct Wrapper { + var value: T +} + +func wrapperify(_ cond: Bool, @WrapperBuilder body: (Bool) -> T) -> T{ + return body(cond) +} + +func testWrapperBuilder() { + let x = wrapperify(true) { c in + 3.14159 + "hello" + } + + let _: Int = x // expected-error{{cannot convert value of type 'Wrapper<(Double, String)>' to specified type 'Int'}} +} diff --git a/test/Constraints/keypath.swift b/test/Constraints/keypath.swift index 9badc9039a2d9..e2919d7aa66c2 100644 --- a/test/Constraints/keypath.swift +++ b/test/Constraints/keypath.swift @@ -59,6 +59,24 @@ public extension Array { let sortedA = self.sorted(by: { $0[keyPath: keyPath] < $1[keyPath: keyPath] }) return sortedA } + + var i: Int { 0 } +} + +func takesVariadicFnWithGenericRet(_ fn: (S...) -> T) {} + +// rdar://problem/59445486 +func testVariadicKeypathAsFunc() { + // These are okay, the base type of the KeyPath is inferred to be [S]. + let _: (S...) -> Int = \.i + let _: (S...) -> Int = \Array.i + takesVariadicFnWithGenericRet(\.i) + takesVariadicFnWithGenericRet(\Array.i) + + // These are not okay, the KeyPath should have a base that matches the + // internal parameter type of the function, i.e [S]. + let _: (S...) -> Int = \S.i // expected-error {{key path value type 'S' cannot be converted to contextual type '[S]'}} + takesVariadicFnWithGenericRet(\S.i) // expected-error {{key path value type 'S' cannot be converted to contextual type '[S]'}} } // rdar://problem/54322807 diff --git a/test/Constraints/keyword_arguments.swift b/test/Constraints/keyword_arguments.swift index 2c9a07ab9605b..9d40b3ee6b9fe 100644 --- a/test/Constraints/keyword_arguments.swift +++ b/test/Constraints/keyword_arguments.swift @@ -240,6 +240,100 @@ func outOfOrder(_ a : Int, b: Int) { outOfOrder(b: 42, 52) // expected-error {{unnamed argument #2 must precede argument 'b'}} {{14-14=52, }} {{19-23=}} } +struct Variadics7 { + func f(alpha: Int..., bravo: Int) {} // expected-note {{'f(alpha:bravo:)' declared here}} + // expected-note@-1 {{'f(alpha:bravo:)' declared here}} + + func test() { + // no error + f(bravo: 0) + f(alpha: 0, bravo: 3) + f(alpha: 0, 1, bravo: 3) + f(alpha: 0, 1, 2, bravo: 3) + + // OoO + f(bravo: 0, alpha: 1) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f(bravo: 0, alpha: 1, 2) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f(bravo: 0, alpha: 1, 2, 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + + // typo A + f(alphax: 0, bravo: 3) // expected-error {{incorrect argument label in call (have 'alphax:bravo:', expected 'alpha:bravo:')}} + f(alphax: 0, 1, bravo: 3) // expected-error {{extra argument in call}} + f(alphax: 0, 1, 2, bravo: 3) // expected-error {{extra arguments at positions #2, #3 in call}} + + // typo B + f(bravox: 0) // expected-error {{incorrect argument label in call (have 'bravox:', expected 'bravo:')}} + f(alpha: 0, bravox: 3) // expected-error {{incorrect argument label in call (have 'alpha:bravox:', expected 'alpha:bravo:')}} + f(alpha: 0, 1, bravox: 3) // expected-error {{incorrect argument label in call (have 'alpha:_:bravox:', expected 'alpha:_:bravo:')}} + f(alpha: 0, 1, 2, bravox: 3) // expected-error {{incorrect argument label in call (have 'alpha:_:_:bravox:', expected 'alpha:_:_:bravo:')}} + + // OoO + typo A B + f(bravox: 0, alphax: 1) // expected-error {{incorrect argument labels in call (have 'bravox:alphax:', expected 'alpha:bravo:')}} + f(bravox: 0, alphax: 1, 2) // expected-error {{extra argument in call}} + f(bravox: 0, alphax: 1, 2, 3) // expected-error {{extra arguments at positions #3, #4 in call}} + } +} + +struct Variadics8 { + func f(alpha: Int..., bravo: Int, charlie: Int) {} // expected-note {{'f(alpha:bravo:charlie:)' declared here}} + + func test() { + // no error + f(bravo: 3, charlie: 4) + f(alpha: 0, bravo: 3, charlie: 4) + f(alpha: 0, 1, bravo: 3, charlie: 4) + f(alpha: 0, 1, 2, bravo: 3, charlie: 4) + + // OoO ACB + f(charlie: 3, bravo: 4) // expected-error {{argument 'bravo' must precede argument 'charlie'}} + f(alpha: 0, charlie: 3, bravo: 4) // expected-error {{argument 'bravo' must precede argument 'charlie'}} + f(alpha: 0, 1, charlie: 3, bravo: 4) // expected-error {{argument 'bravo' must precede argument 'charlie'}} + f(alpha: 0, 1, 2, charlie: 3, bravo: 4) // expected-error {{argument 'bravo' must precede argument 'charlie'}} + // OoO CAB + f(charlie: 0, alpha: 1, bravo: 4) // expected-error {{incorrect argument labels in call (have 'charlie:alpha:bravo:', expected 'alpha:bravo:charlie:')}} + f(charlie: 0, alpha: 1, 2, bravo: 4) // expected-error {{incorrect argument labels in call (have 'charlie:alpha:_:bravo:', expected 'alpha:bravo:charlie:')}} + f(charlie: 0, alpha: 1, 2, 3, bravo: 4) // expected-error {{incorrect argument labels in call (have 'charlie:alpha:_:_:bravo:', expected 'alpha:bravo:charlie:')}} + // OoO BAC + f(bravo: 0, alpha: 1, charlie: 4) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f(bravo: 0, alpha: 1, 2, charlie: 4) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f(bravo: 0, alpha: 1, 2, 3, charlie: 4) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + + // typo A + f(alphax: 0, bravo: 3, charlie: 4) // expected-error {{incorrect argument label in call (have 'alphax:bravo:charlie:', expected 'alpha:bravo:charlie:')}} + f(alphax: 0, 1, bravo: 3, charlie: 4) // expected-error {{extra argument in call}} + f(alphax: 0, 1, 2, bravo: 3, charlie: 4) // expected-error {{extra arguments at positions #2, #3 in call}} + // typo B + f(bravox: 3, charlie: 4) // expected-error {{incorrect argument label in call (have 'bravox:charlie:', expected 'bravo:charlie:')}} + f(alpha: 0, bravox: 3, charlie: 4) // expected-error {{incorrect argument label in call (have 'alpha:bravox:charlie:', expected 'alpha:bravo:charlie:')}} + f(alpha: 0, 1, bravox: 3, charlie: 4) // expected-error {{incorrect argument label in call (have 'alpha:_:bravox:charlie:', expected 'alpha:_:bravo:charlie:')}} + f(alpha: 0, 1, 2, bravox: 3, charlie: 4) // expected-error {{incorrect argument label in call (have 'alpha:_:_:bravox:charlie:', expected 'alpha:_:_:bravo:charlie:')}} + // typo C + f(bravo: 3, charliex: 4) // expected-error {{incorrect argument label in call (have 'bravo:charliex:', expected 'bravo:charlie:')}} + f(alpha: 0, bravo: 3, charliex: 4) // expected-error {{incorrect argument label in call (have 'alpha:bravo:charliex:', expected 'alpha:bravo:charlie:')}} + f(alpha: 0, 1, bravo: 3, charliex: 4) // expected-error {{incorrect argument label in call (have 'alpha:_:bravo:charliex:', expected 'alpha:_:bravo:charlie:')}} + f(alpha: 0, 1, 2, bravo: 3, charliex: 4) // expected-error {{incorrect argument label in call (have 'alpha:_:_:bravo:charliex:', expected 'alpha:_:_:bravo:charlie:')}} + + // OoO ACB + typo B + f(alpha: 0, charlie: 3, bravox: 4) // expected-error {{incorrect argument labels in call (have 'alpha:charlie:bravox:', expected 'alpha:bravo:charlie:')}} + f(alpha: 0, 1, charlie: 3, bravox: 4) // expected-error {{incorrect argument labels in call (have 'alpha:_:charlie:bravox:', expected 'alpha:bravo:charlie:')}} + f(alpha: 0, 1, 2, charlie: 3, bravox: 4) // expected-error {{incorrect argument labels in call (have 'alpha:_:_:charlie:bravox:', expected 'alpha:bravo:charlie:')}} + // OoO ACB + typo C + f(charliex: 3, bravo: 4) // expected-error {{incorrect argument labels in call (have 'charliex:bravo:', expected 'alpha:bravo:charlie:')}} + f(alpha: 0, charliex: 3, bravo: 4) // expected-error {{incorrect argument labels in call (have 'alpha:charliex:bravo:', expected 'alpha:bravo:charlie:')}} + f(alpha: 0, 1, charliex: 3, bravo: 4) // expected-error {{incorrect argument labels in call (have 'alpha:_:charliex:bravo:', expected 'alpha:bravo:charlie:')}} + f(alpha: 0, 1, 2, charliex: 3, bravo: 4) // expected-error {{incorrect argument labels in call (have 'alpha:_:_:charliex:bravo:', expected 'alpha:bravo:charlie:')}} + + // OoO BAC + typo B + f(bravox: 0, alpha: 1, charlie: 4) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:charlie:', expected 'alpha:bravo:charlie:')}} + f(bravox: 0, alpha: 1, 2, charlie: 4) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:_:charlie:', expected 'alpha:bravo:charlie:')}} + f(bravox: 0, alpha: 1, 2, 3, charlie: 4) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:_:_:charlie:', expected 'alpha:bravo:charlie:')}} + // OoO BAC + typo C + f(bravo: 0, alpha: 1, charliex: 4) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f(bravo: 0, alpha: 1, 2, charliex: 4) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f(bravo: 0, alpha: 1, 2, 3, charliex: 4) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + } +} + // ------------------------------------------- // Positions around defaults and variadics // ------------------------------------------- @@ -267,13 +361,18 @@ struct PositionsAroundDefaultsAndVariadics { f1(c: "3", [4]) - f1(b: "2", [3]) // expected-error {{unnamed argument #2 must precede argument 'b'}} + f1(b: "2", [3]) // expected-error {{incorrect argument labels in call (have 'b:_:', expected '_:_:c:_:')}} + // expected-error@-1 {{cannot convert value of type '[Int]' to expected argument type 'Bool'}} - f1(b: "2", 1) // expected-error {{unnamed argument #2 must precede argument 'b'}} + f1(b: "2", 1) // expected-error {{incorrect argument labels in call (have 'b:_:', expected '_:_:c:_:')}} + // expected-error@-1 {{type 'Int' cannot be used as a boolean; test for '!= 0' instead}} - f1(b: "2", [3], 1) // expected-error {{unnamed argument #2 must precede argument 'b'}} + f1(b: "2", [3], 1) // expected-error {{incorrect argument labels in call (have 'b:_:_:', expected '_:_:c:_:')}} + // expected-error@-1 {{cannot convert value of type '[Int]' to expected argument type 'Bool'}} - f1(b: "2", 1, [3]) // expected-error {{unnamed argument #2 must precede argument 'b'}} + f1(b: "2", 1, [3]) // expected-error {{incorrect argument labels in call (have 'b:_:_:', expected '_:_:c:_:')}} + // expected-error@-1 {{type 'Int' cannot be used as a boolean; test for '!= 0' instead}} + // expected-error@-2 {{cannot convert value of type '[Int]' to expected argument type 'Int'}} } // unlabeled variadics before labeled parameter @@ -375,13 +474,13 @@ struct PositionsAroundDefaultsAndVariadics { f3() - f3(c: "3", b: 21) // expected-error {{incorrect argument labels in call (have 'c:b:', expected '_:b:c:_:')}} + f3(c: "3", b: 21) // expected-error {{argument 'b' must precede argument 'c'}} - f3(c: "3", b: 21, [4]) // expected-error {{incorrect argument labels in call (have 'c:b:_:', expected '_:b:c:_:')}} + f3(c: "3", b: 21, [4]) // expected-error {{argument 'b' must precede argument 'c'}} // expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} // expected-note@-2 {{remove brackets to pass array elements directly}} - f3(c: "3", [4], b: 21) // expected-error {{incorrect argument labels in call (have 'c:_:b:', expected '_:b:c:_:')}} + f3(c: "3", [4], b: 21) // expected-error {{argument 'b' must precede argument 'c'}} } // unlabeled variadics after labeled parameter @@ -485,9 +584,9 @@ struct PositionsAroundDefaultsAndVariadics { f5(b: "2", c: 31, d: [4]) f5(b: "2", d: [4]) - f5(c: 31, b: "2", d: [4]) // expected-error {{incorrect argument labels in call (have 'c:b:d:', expected '_:b:c:d:')}} + f5(c: 31, b: "2", d: [4]) // expected-error {{argument 'b' must precede argument 'c'}} - f5(b: "2", d: [4], c: 31) // expected-error {{incorrect argument labels in call (have 'b:d:c:', expected '_:b:c:d:')}} + f5(b: "2", d: [4], c: 31) // expected-error {{argument 'c' must precede argument 'd'}} f5(b: "2", c: 31) f5(b: "2", c: 31, 32) @@ -531,6 +630,102 @@ mismatch1(foo: 5) // expected-error {{extra argument 'foo' in call}} mismatch1(baz: 1, wobble: 2) // expected-error{{incorrect argument labels in call (have 'baz:wobble:', expected 'bar:wibble:')}} {{11-14=bar}} {{19-25=wibble}} mismatch1(food: 1, zap: 2) // expected-error{{extra arguments at positions #1, #2 in call}} +// ------------------------------------------- +// Out of order and default +// ------------------------------------------- + +struct OutOfOrderAndDefault { + func f11(alpha: Int, bravo: Int) {} + func f12(alpha: Int = -1, bravo: Int) {} + func f13(alpha: Int, bravo: Int = -1) {} + func f14(alpha: Int = -1, bravo: Int = -1) {} + + func test1() { + // typo + f11(bravo: 0, alphax: 1) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:', expected 'alpha:bravo:')}} + f11(bravox: 0, alpha: 1) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:', expected 'alpha:bravo:')}} + f12(bravo: 0, alphax: 1) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:', expected 'alpha:bravo:')}} + f12(bravox: 0, alpha: 1) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:', expected 'alpha:bravo:')}} + f13(bravo: 0, alphax: 1) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:', expected 'alpha:bravo:')}} + f13(bravox: 0, alpha: 1) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:', expected 'alpha:bravo:')}} + f14(bravo: 0, alphax: 1) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:', expected 'alpha:bravo:')}} + f14(bravox: 0, alpha: 1) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:', expected 'alpha:bravo:')}} + } + + func f21(alpha: Int, bravo: Int, charlie: Int) {} + func f22(alpha: Int = -1, bravo: Int, charlie: Int) {} + func f23(alpha: Int = -1, bravo: Int = -1, charlie: Int) {} + + func test2() { + // BAC + f21(bravo: 0, alphax: 1, charlie: 2) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:charlie:', expected 'alpha:bravo:charlie:')}} + f21(bravox: 0, alpha: 1, charlie: 2) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:charlie:', expected 'alpha:bravo:charlie:')}} + f21(bravo: 0, alpha: 1, charliex: 2) // expected-error {{'alpha' must precede argument 'bravo'}} + f22(bravo: 0, alphax: 1, charlie: 2) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:charlie:', expected 'alpha:bravo:charlie:')}} + f22(bravox: 0, alpha: 1, charlie: 2) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:charlie:', expected 'alpha:bravo:charlie:')}} + f22(bravo: 0, alpha: 1, charliex: 2) // expected-error {{'alpha' must precede argument 'bravo'}} + f23(bravo: 0, alphax: 1, charlie: 2) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:charlie:', expected 'alpha:bravo:charlie:')}} + f23(bravox: 0, alpha: 1, charlie: 2) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:charlie:', expected 'alpha:bravo:charlie:')}} + f23(bravo: 0, alpha: 1, charliex: 2) // expected-error {{'alpha' must precede argument 'bravo'}} + + // BCA + f21(bravo: 0, charlie: 1, alphax: 2) // expected-error {{incorrect argument labels in call (have 'bravo:charlie:alphax:', expected 'alpha:bravo:charlie:')}} + f21(bravox: 0, charlie: 1, alpha: 2) // expected-error {{incorrect argument labels in call (have 'bravox:charlie:alpha:', expected 'alpha:bravo:charlie:')}} + f21(bravo: 0, charliex: 1, alpha: 2) // expected-error {{'alpha' must precede argument 'bravo'}} + f22(bravo: 0, charlie: 1, alphax: 2) // expected-error {{incorrect argument labels in call (have 'bravo:charlie:alphax:', expected 'alpha:bravo:charlie:')}} + f22(bravox: 0, charlie: 1, alpha: 2) // expected-error {{incorrect argument labels in call (have 'bravox:charlie:alpha:', expected 'alpha:bravo:charlie:')}} + f22(bravo: 0, charliex: 1, alpha: 2) // expected-error {{'alpha' must precede argument 'bravo'}} + f23(bravo: 0, charlie: 1, alphax: 2) // expected-error {{incorrect argument labels in call (have 'bravo:charlie:alphax:', expected 'alpha:bravo:charlie:')}} + f23(bravox: 0, charlie: 1, alpha: 2) // expected-error {{incorrect argument labels in call (have 'bravox:charlie:alpha:', expected 'alpha:bravo:charlie:')}} + f23(bravo: 0, charliex: 1, alpha: 2) // expected-error {{'alpha' must precede argument 'bravo'}} + + // CAB + f21(charlie: 0, alphax: 1, bravo: 2) // expected-error {{incorrect argument labels in call (have 'charlie:alphax:bravo:', expected 'alpha:bravo:charlie:')}} + f21(charlie: 0, alpha: 1, bravox: 2) // expected-error {{incorrect argument labels in call (have 'charlie:alpha:bravox:', expected 'alpha:bravo:charlie:')}} + f21(charliex: 0, alpha: 1, bravo: 2) // expected-error {{incorrect argument labels in call (have 'charliex:alpha:bravo:', expected 'alpha:bravo:charlie:')}} + f22(charlie: 0, alphax: 1, bravo: 2) // expected-error {{incorrect argument labels in call (have 'charlie:alphax:bravo:', expected 'alpha:bravo:charlie:')}} + f22(charlie: 0, alpha: 1, bravox: 2) // expected-error {{incorrect argument labels in call (have 'charlie:alpha:bravox:', expected 'alpha:bravo:charlie:')}} + f22(charliex: 0, alpha: 1, bravo: 2) // expected-error {{incorrect argument labels in call (have 'charliex:alpha:bravo:', expected 'alpha:bravo:charlie:')}} + f23(charlie: 0, alphax: 1, bravo: 2) // expected-error {{incorrect argument labels in call (have 'charlie:alphax:bravo:', expected 'alpha:bravo:charlie:')}} + f23(charlie: 0, alpha: 1, bravox: 2) // expected-error {{argument 'alpha' must precede argument 'charlie'}} + f23(charliex: 0, alpha: 1, bravo: 2) // expected-error {{incorrect argument labels in call (have 'charliex:alpha:bravo:', expected 'alpha:bravo:charlie:')}} + } + + func f31(alpha: Int, bravo: Int, charlie: Int, delta: Int) {} + func f32(alpha: Int = -1, bravo: Int = -1, charlie: Int, delta: Int) {} + func f33(alpha: Int = -1, bravo: Int = -1, charlie: Int, delta: Int = -1) {} + + func test3() { + // BACD + f31(bravo: 0, alphax: 2, charlie: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:charlie:delta:', expected 'alpha:bravo:charlie:delta:')}} + f31(bravox: 0, alpha: 2, charlie: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:charlie:delta:', expected 'alpha:bravo:charlie:delta:')}} + f31(bravo: 0, alpha: 2, charliex: 2, delta: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f31(bravo: 0, alpha: 2, charlie: 2, deltax: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f32(bravo: 0, alphax: 2, charlie: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:charlie:delta:', expected 'alpha:bravo:charlie:delta:')}} + f32(bravox: 0, alpha: 2, charlie: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:charlie:delta:', expected 'alpha:bravo:charlie:delta:')}} + f32(bravo: 0, alpha: 2, charliex: 2, delta: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f32(bravo: 0, alpha: 2, charlie: 2, deltax: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f33(bravo: 0, alphax: 2, charlie: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravo:alphax:charlie:delta:', expected 'alpha:bravo:charlie:delta:')}} + f33(bravox: 0, alpha: 2, charlie: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravox:alpha:charlie:delta:', expected 'alpha:bravo:charlie:delta:')}} + f33(bravo: 0, alpha: 2, charliex: 2, delta: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f33(bravo: 0, alpha: 2, charlie: 2, deltax: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + + // BCAD + f31(bravo: 0, charlie: 1, alphax: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravo:charlie:alphax:delta:', expected 'alpha:bravo:charlie:delta:')}} + f31(bravox: 0, charlie: 1, alpha: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravox:charlie:alpha:delta:', expected 'alpha:bravo:charlie:delta:')}} + f31(bravo: 0, charliex: 1, alpha: 2, delta: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f31(bravo: 0, charlie: 1, alpha: 2, deltax: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f32(bravo: 0, charlie: 1, alphax: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravo:charlie:alphax:delta:', expected 'alpha:bravo:charlie:delta:')}} + f32(bravox: 0, charlie: 1, alpha: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravox:charlie:alpha:delta:', expected 'alpha:bravo:charlie:delta:')}} + f32(bravo: 0, charliex: 1, alpha: 2, delta: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f32(bravo: 0, charlie: 1, alpha: 2, deltax: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f33(bravo: 0, charlie: 1, alphax: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravo:charlie:alphax:delta:', expected 'alpha:bravo:charlie:delta:')}} + f33(bravox: 0, charlie: 1, alpha: 2, delta: 3) // expected-error {{incorrect argument labels in call (have 'bravox:charlie:alpha:delta:', expected 'alpha:bravo:charlie:delta:')}} + f33(bravo: 0, charliex: 1, alpha: 2, delta: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + f33(bravo: 0, charlie: 1, alpha: 2, deltax: 3) // expected-error {{argument 'alpha' must precede argument 'bravo'}} + } +} + // ------------------------------------------- // Subscript keyword arguments // ------------------------------------------- diff --git a/test/Constraints/operator.swift b/test/Constraints/operator.swift index 3b85bda0b8792..5d6c04f1d5feb 100644 --- a/test/Constraints/operator.swift +++ b/test/Constraints/operator.swift @@ -254,3 +254,14 @@ extension Int { } _ = 1 ^^ 2 ^^ 3 * 4 // expected-error {{adjacent operators are in unordered precedence groups 'PowerPrecedence' and 'MultiplicationPrecedence'}} + +// rdar://problem/60185506 - Ambiguity with Float comparison +func rdar_60185506() { + struct X { + var foo: Float + } + + func test(x: X?) { + let _ = (x?.foo ?? 0) <= 0.5 // Ok + } +} diff --git a/test/Generics/deduction.swift b/test/Generics/deduction.swift index d35e1d3841627..f4b28eb794ac9 100644 --- a/test/Generics/deduction.swift +++ b/test/Generics/deduction.swift @@ -319,9 +319,8 @@ func foo() { let j = min(Int(3), Float(2.5)) // expected-error{{conflicting arguments to generic parameter 'T' ('Int' vs. 'Float')}} let k = min(A(), A()) // expected-error{{global function 'min' requires that 'A' conform to 'Comparable'}} let oi : Int? = 5 - let l = min(3, oi) // expected-error{{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}} - // expected-note@-1 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} - // expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} + let l = min(3, oi) // expected-error{{global function 'min' requires that 'Int?' conform to 'Comparable'}} + // expected-note@-1{{wrapped type 'Int' satisfies this requirement}} } infix operator +& diff --git a/test/IDE/complete_call_arg.swift b/test/IDE/complete_call_arg.swift index 5c82198b8a3e5..7c8a76087efb1 100644 --- a/test/IDE/complete_call_arg.swift +++ b/test/IDE/complete_call_arg.swift @@ -3,8 +3,8 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG3 | %FileCheck %s -check-prefix=ARG-NAME2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG4 | %FileCheck %s -check-prefix=EXPECT_INT // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG5 | %FileCheck %s -check-prefix=EXPECT_OSTRING -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG6 | %FileCheck %s -check-prefix=ARG-NAME2 -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG7 | %FileCheck %s -check-prefix=ARG-NAME1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG6 | %FileCheck %s -check-prefix=ARG-NAME3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG7 | %FileCheck %s -check-prefix=ARG-NAME4 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG8 | %FileCheck %s -check-prefix=EXPECT_STRING // RUN-FIXME: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOAD1 | %FileCheck %s -check-prefix=OVERLOAD1 @@ -94,6 +94,13 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARCHETYPE_GENERIC_1 | %FileCheck %s -check-prefix=ARCHETYPE_GENERIC_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PARAM_WITH_ERROR_AUTOCLOSURE| %FileCheck %s -check-prefix=PARAM_WITH_ERROR_AUTOCLOSURE // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPECHECKED_OVERLOADED | %FileCheck %s -check-prefix=TYPECHECKED_OVERLOADED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPECHECKED_TYPEEXPR | %FileCheck %s -check-prefix=TYPECHECKED_TYPEEXPR + +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG_PARAMFLAG_INOUT | %FileCheck %s -check-prefix=ARG_PARAMFLAG_INOUT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG_PARAMFLAG_AUTOCLOSURE| %FileCheck %s -check-prefix=ARG_PARAMFLAG_AUTOCLOSURE +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG_PARAMFLAG_IUO | %FileCheck %s -check-prefix=ARG_PARAMFLAG_IUO +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG_PARAMFLAG_VARIADIC | %FileCheck %s -check-prefix=ARG_PARAMFLAG_VARIADIC + var i1 = 1 var i2 = 2 @@ -170,11 +177,19 @@ class C1 { } // ARG-NAME1: Begin completions, 2 items -// ARG-NAME1-DAG: Keyword/ExprSpecific: b1: [#Argument name#]; name=b1: -// ARG-NAME1-DAG: Keyword/ExprSpecific: b2: [#Argument name#]; name=b2: +// ARG-NAME1-DAG: Pattern/ExprSpecific: {#b1: Int?#}[#Int?#]; +// ARG-NAME1-DAG: Pattern/ExprSpecific: {#b2: Int?#}[#Int?#]; // ARG-NAME2: Begin completions, 1 items -// ARG-NAME2-DAG: Keyword/ExprSpecific: b: [#Argument name#]; name=b: +// ARG-NAME2-DAG: Pattern/ExprSpecific: {#b: Int#}[#Int#]; + +// ARG-NAME3: Begin completions, 1 items +// ARG-NAME3-DAG: Pattern/ExprSpecific: {#b: String?#}[#String?#]; + +// ARG-NAME4: Begin completions, 2 items +// ARG-NAME4-DAG: Pattern/ExprSpecific: {#b1: String#}[#String#]; +// ARG-NAME4-DAG: Pattern/ExprSpecific: {#b2: String#}[#String#]; +// ARG-NAME4: End completions // EXPECT_OINT: Begin completions // EXPECT_OINT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended/TypeRelation[Invalid]: f1()[#Void#]; name=f1() @@ -335,7 +350,7 @@ extension C3 { // HASERROR2: End completions // HASERROR3: Begin completions -// HASERROR3-DAG: Keyword/ExprSpecific: b1: [#Argument name#]; +// HASERROR3-DAG: Pattern/ExprSpecific: {#b1: <>#}[#<>#]; // HASERROR3: End completions // HASERROR4: Begin completions @@ -463,7 +478,7 @@ func testArg2Name1() { func testArg2Name3() { firstArg(#^FIRST_ARG_NAME_3^#, } -// FIRST_ARG_NAME_3: Keyword/ExprSpecific: arg1: [#Argument name#] +// FIRST_ARG_NAME_3: Pattern/ExprSpecific: {#arg1: Int#}[#Int#]; // FIRST_ARG_NAME_4: Decl[FreeFunction]/CurrModule: ['(']{#arg1: Int#}, {#arg2: Int#}[')'][#Void#]; func takeArray(_ x: [T]) {} @@ -581,7 +596,7 @@ func testSubscript(obj: HasSubscript, intValue: Int, strValue: String) { let _ = obj[42, #^SUBSCRIPT_2^# // SUBSCRIPT_2: Begin completions, 1 items -// SUBSCRIPT_2-NEXT: Keyword/ExprSpecific: default: [#Argument name#]; name=default: +// SUBSCRIPT_2-NEXT: Pattern/ExprSpecific: {#default: String#}[#String#]; let _ = obj[42, .#^SUBSCRIPT_2_DOT^# // SUBSCRIPT_2_DOT-NOT: Begin completions @@ -658,16 +673,16 @@ func testStaticMemberCall() { let _ = TestStaticMemberCall.create2(1, #^STATIC_METHOD_SECOND^#) // STATIC_METHOD_SECOND: Begin completions, 3 items -// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg2: [#Argument name#]; -// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg3: [#Argument name#]; -// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg4: [#Argument name#]; +// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg2: Int#}[#Int#]; +// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; +// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // STATIC_METHOD_SECOND: End completions let _ = TestStaticMemberCall.create2(1, arg3: 2, #^STATIC_METHOD_SKIPPED^#) // STATIC_METHOD_SKIPPED: Begin completions, 2 items // FIXME: 'arg3' shouldn't be suggested. -// STATIC_METHOD_SKIPPED: Keyword/ExprSpecific: arg3: [#Argument name#]; -// STATIC_METHOD_SKIPPED: Keyword/ExprSpecific: arg4: [#Argument name#]; +// STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; +// STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // STATIC_METHOD_SKIPPED: End completions } func testImplicitMember() { @@ -686,16 +701,16 @@ func testImplicitMember() { let _: TestStaticMemberCall = .create2(1, #^IMPLICIT_MEMBER_SECOND^#) // IMPLICIT_MEMBER_SECOND: Begin completions, 3 items -// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg2: [#Argument name#]; -// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg3: [#Argument name#]; -// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg4: [#Argument name#]; +// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg2: Int#}[#Int#]; +// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; +// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // IMPLICIT_MEMBER_SECOND: End completions let _: TestStaticMemberCall = .create2(1, arg3: 2, #^IMPLICIT_MEMBER_SKIPPED^#) // IMPLICIT_MEMBER_SKIPPED: Begin completions, 2 items // FIXME: 'arg3' shouldn't be suggested. -// IMPLICIT_MEMBER_SKIPPED: Keyword/ExprSpecific: arg3: [#Argument name#]; -// IMPLICIT_MEMBER_SKIPPED: Keyword/ExprSpecific: arg4: [#Argument name#]; +// IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; +// IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // IMPLICIT_MEMBER_SKIPPED: End completions } func testImplicitMemberInArrayLiteral() { @@ -753,12 +768,13 @@ struct TestHasErrorAutoclosureParam { } } -struct MyType { +struct MyType { + init(arg1: String, arg2: T) {} func overloaded() {} func overloaded(_ int: Int) {} func overloaded(name: String, value: String) {} } -func testTypecheckedOverloaded(value: MyType) { +func testTypecheckedOverloaded(value: MyType) { value.overloaded(#^TYPECHECKED_OVERLOADED^#) // TYPECHECKED_OVERLOADED: Begin completions // TYPECHECKED_OVERLOADED-DAG: Decl[InstanceMethod]/CurrNominal: ['('][')'][#Void#]; @@ -766,3 +782,37 @@ func testTypecheckedOverloaded(value: MyType) { // TYPECHECKED_OVERLOADED-DAG: Decl[InstanceMethod]/CurrNominal: ['(']{#name: String#}, {#value: String#}[')'][#Void#]; // TYPECHECKED_OVERLOADED: End completions } + +extension MyType where T == Int { + init(_ intVal: T) {} +} +func testTypecheckedTypeExpr() { + MyType(#^TYPECHECKED_TYPEEXPR^# +} +// TYPECHECKED_TYPEEXPR: Begin completions +// TYPECHECKED_TYPEEXPR: Decl[Constructor]/CurrNominal: ['(']{#arg1: String#}, {#arg2: _#}[')'][#MyType<_>#]; name=arg1: String, arg2: _ +// TYPECHECKED_TYPEEXPR: Decl[Constructor]/CurrNominal: ['(']{#(intVal): Int#}[')'][#MyType#]; name=intVal: Int +// TYPECHECKED_TYPEEXPR: End completions + +func testPamrameterFlags(_: Int, inoutArg: inout Int, autoclosureArg: @autoclosure () -> Int, iuoArg: Int!, variadicArg: Int...) { + var intVal = 1 + testPamrameterFlags(intVal, #^ARG_PARAMFLAG_INOUT^#) +// ARG_PARAMFLAG_INOUT: Begin completions, 1 items +// ARG_PARAMFLAG_INOUT-DAG: Pattern/ExprSpecific: {#inoutArg: &Int#}[#inout Int#]; name=inoutArg: +// ARG_PARAMFLAG_INOUT: End completions + + testPamrameterFlags(intVal, inoutArg: &intVal, #^ARG_PARAMFLAG_AUTOCLOSURE^#) +// ARG_PARAMFLAG_AUTOCLOSURE: Begin completions, 1 items +// ARG_PARAMFLAG_AUTOCLOSURE-DAG: Pattern/ExprSpecific: {#autoclosureArg: Int#}[#Int#]; +// ARG_PARAMFLAG_AUTOCLOSURE: End completions + + testPamrameterFlags(intVal, inoutArg: &intVal, autoclosureArg: intVal, #^ARG_PARAMFLAG_IUO^#) +// ARG_PARAMFLAG_IUO: Begin completions, 1 items +// ARG_PARAMFLAG_IUO-DAG: Pattern/ExprSpecific: {#iuoArg: Int?#}[#Int?#]; +// ARG_PARAMFLAG_IUO: End completions + + testPamrameterFlags(intVal, inoutArg: &intVal, autoclosureArg: intVal, iuoArg: intVal, #^ARG_PARAMFLAG_VARIADIC^#) +// ARG_PARAMFLAG_VARIADIC: Begin completions, 1 items +// ARG_PARAMFLAG_VARIADIC-DAG: Pattern/ExprSpecific: {#variadicArg: Int...#}[#Int#]; +// ARG_PARAMFLAG_VARIADIC: End completions +} diff --git a/test/IDE/complete_call_as_function.swift b/test/IDE/complete_call_as_function.swift new file mode 100644 index 0000000000000..c50070ab4ed90 --- /dev/null +++ b/test/IDE/complete_call_as_function.swift @@ -0,0 +1,120 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_NO_DOT | %FileCheck %s -check-prefix=INSTANCE_NO_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_DOT | %FileCheck %s -check-prefix=INSTANCE_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_PAREN | %FileCheck %s -check-prefix=INSTANCE_PAREN +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_ARG2 | %FileCheck %s -check-prefix=INSTANCE_ARG2 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_NO_DOT | %FileCheck %s -check-prefix=METATYPE_NO_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_DOT | %FileCheck %s -check-prefix=METATYPE_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_PAREN | %FileCheck %s -check-prefix=METATYPE_PAREN +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEEXPR_NO_DOT | %FileCheck %s -check-prefix=TYPEEXPR_NO_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEEXPR_DOT | %FileCheck %s -check-prefix=TYPEEXPR_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEEXPR_PAREN | %FileCheck %s -check-prefix=TYPEEXPR_PAREN + +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_PAREN | %FileCheck %s -check-prefix=OVERLOADED_PAREN +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_ARG2_LABEL | %FileCheck %s -check-prefix=OVERLOADED_ARG2_LABEL +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_ARG2_VALUE | %FileCheck %s -check-prefix=OVERLOADED_ARG2_VALUE + +struct Adder { + private var base: Int + init(base: Int) { self.base = base } + func callAsFunction(x : Int, y : Int) -> Int { base + x + y } +} +func testCallAsFunction(add: Adder, addTy: Adder.Type) { + let _ = add#^INSTANCE_NO_DOT^#; +// INSTANCE_NO_DOT: Begin completions, 3 items +// INSTANCE_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: .callAsFunction({#x: Int#}, {#y: Int#})[#Int#]; +// INSTANCE_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: ({#x: Int#}, {#y: Int#})[#Int#]; +// INSTANCE_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#Adder#]; +// INSTANCE_NO_DOT: End completions + + let _ = add.#^INSTANCE_DOT^#; +// INSTANCE_DOT: Begin completions, 2 items +// INSTANCE_DOT-DAG: Decl[InstanceMethod]/CurrNominal: callAsFunction({#x: Int#}, {#y: Int#})[#Int#]; +// INSTANCE_DOT-DAG: Keyword[self]/CurrNominal: self[#Adder#]; +// INSTANCE_DOT: End completions + + let _ = add(#^INSTANCE_PAREN^#) +// INSTANCE_PAREN: Begin completions, 1 items +// INSTANCE_PAREN-DAG: Decl[InstanceMethod]/CurrNominal: ['(']{#x: Int#}, {#y: Int#}[')'][#Int#]; +// INSTANCE_PAREN: End completions + + let _ = add(x: 12, #^INSTANCE_ARG2^#) +// INSTANCE_ARG2: Begin completions, 1 items +// INSTANCE_ARG2: Pattern/ExprSpecific: {#y: Int#}[#Int#]; +// INSTANCE_ARG2: End completions + + let _ = addTy#^METATYPE_NO_DOT^#; +// METATYPE_NO_DOT: Begin completions, 3 items +// METATYPE_NO_DOT-NOT: {#x: Int#}, {#y: Int#} +// METATYPE_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: .callAsFunction({#(self): Adder#})[#(x: Int, y: Int) -> Int#]; +// METATYPE_NO_DOT-DAG: Decl[Constructor]/CurrNominal: .init({#base: Int#})[#Adder#]; +// METATYPE_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#Adder.Type#]; +// METATYPE_NO_DOT: End completions + + let _ = addTy.#^METATYPE_DOT^#; +// METATYPE_DOT: Begin completions, 3 items +// METATYPE_DOT-NOT: {#x: Int#}, {#y: Int#} +// METATYPE_DOT-DAG: Decl[InstanceMethod]/CurrNominal: callAsFunction({#(self): Adder#})[#(x: Int, y: Int) -> Int#]; +// METATYPE_DOT-DAG: Decl[Constructor]/CurrNominal: init({#base: Int#})[#Adder#]; +// METATYPE_DOT-DAG: Keyword[self]/CurrNominal: self[#Adder.Type#]; +// METATYPE_DOT: End completions + + let _ = addTy(#^METATYPE_PAREN^#) +// METATYPE_PAREN: Begin completions +// METATYPE_PAREN-NOT: {#x: Int#}, {#y: Int#} +// METATYPE_PAREN-NOT: {#base: Int#} +// METATYPE_PAREN: End completions + + let _ = Adder#^TYPEEXPR_NO_DOT^#; +// TYPEEXPR_NO_DOT: Begin completions, 4 items +// TYPEEXPR_NO_DOT-NOT: {#x: Int#}, {#y: Int#} +// TYPEEXPR_NO_DOT-DAG: Decl[Constructor]/CurrNominal: ({#base: Int#})[#Adder#]; name=(base: Int) +// TYPEEXPR_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: .callAsFunction({#(self): Adder#})[#(x: Int, y: Int) -> Int#]; +// TYPEEXPR_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#Adder.Type#]; +// TYPEEXPR_NO_DOT-DAG: Keyword/CurrNominal: .Type[#Adder.Type#]; +// TYPEEXPR_NO_DOT: End completions + + let _ = Adder.#^TYPEEXPR_DOT^#; +// TYPEEXPR_DOT: Begin completions, 4 items +// TYPEEXPR_DOT-NOT: {#x: Int#}, {#y: Int#} +// TYPEEXPR_DOT-DAG: Decl[InstanceMethod]/CurrNominal: callAsFunction({#(self): Adder#})[#(x: Int, y: Int) -> Int#]; +// TYPEEXPR_DOT-DAG: Decl[Constructor]/CurrNominal: init({#base: Int#})[#Adder#]; +// TYPEEXPR_DOT-DAG: Keyword[self]/CurrNominal: self[#Adder.Type#]; +// TYPEEXPR_DOT-DAG: Keyword/CurrNominal: Type[#Adder.Type#]; +// TYPEEXPR_DOT: End completions + + let _ = Adder(#^TYPEEXPR_PAREN^#) +// TYPEEXPR_PAREN: Begin completions, 1 items +// TYPEEXPR_PAREN-NOT: {#x: Int#}, {#y: Int#} +// TYPEEXPR_PAREN-DAG: Decl[Constructor]/CurrNominal: ['(']{#base: Int#}[')'][#Adder#]; +// TYPEEXPR_PAREN: End completions +} + +struct Functor { + enum Horizontal { case left, right } + enum Vertical { case up, down } + func callAsFunction(h: Horizontal, v: Vertical) {} + func callAsFunction(v: Vertical, h: Horizontal) {} +} +func testCallAsFunctionOverloaded(fn: Functor) { + fn(#^OVERLOADED_PAREN^#) +//OVERLOADED_PAREN: Begin completions, 2 items +//OVERLOADED_PAREN-DAG: Decl[InstanceMethod]/CurrNominal: ['(']{#h: Functor.Horizontal#}, {#v: Functor.Vertical#}[')'][#Void#]; +//OVERLOADED_PAREN-DAG: Decl[InstanceMethod]/CurrNominal: ['(']{#v: Functor.Vertical#}, {#h: Functor.Horizontal#}[')'][#Void#]; +//OVERLOADED_PAREN: End completions + + fn(h: .left, #^OVERLOADED_ARG2_LABEL^#) +// FIXME: Should only suggest 'v:' (rdar://problem/60346573). +//OVERLOADED_ARG2_LABEL: Begin completions, 2 items +//OVERLOADED_ARG2_LABEL-DAG: Pattern/ExprSpecific: {#v: Functor.Vertical#}[#Functor.Vertical#]; +//OVERLOADED_ARG2_LABEL-DAG: Pattern/ExprSpecific: {#h: Functor.Horizontal#}[#Functor.Horizontal#]; +//OVERLOADED_ARG2_LABEL: End completions + + fn(h: .left, v: .#^OVERLOADED_ARG2_VALUE^#) +// FIXME: Should only suggest 'up' and 'down' (rdar://problem/60346573). +//OVERLOADED_ARG2_VALUE: Begin completions, 4 items +//OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: up[#Functor.Vertical#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: down[#Functor.Vertical#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: left[#Functor.Horizontal#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: right[#Functor.Horizontal#]; +//OVERLOADED_ARG2_VALUE: End completions +} diff --git a/test/IDE/complete_subscript.swift b/test/IDE/complete_subscript.swift index 499337c69c507..afd47cb1fb798 100644 --- a/test/IDE/complete_subscript.swift +++ b/test/IDE/complete_subscript.swift @@ -91,12 +91,12 @@ func test2(value: MyStruct) { let _ = MyStruct[42, #^METATYPE_LABEL^# // METATYPE_LABEL: Begin completions, 1 items -// METATYPE_LABEL-DAG: Keyword/ExprSpecific: static: [#Argument name#]; +// METATYPE_LABEL-DAG: Pattern/ExprSpecific: {#static: U#}[#U#]; // METATYPE_LABEL: End completions let _ = value[42, #^INSTANCE_LABEL^# // INSTANCE_LABEL: Begin completions, 1 items -// INSTANCE_LABEL-DAG: Keyword/ExprSpecific: instance: [#Argument name#]; +// INSTANCE_LABEL-DAG: Pattern/ExprSpecific: {#instance: U#}[#U#]; // INSTANCE_LABEL: End completions } diff --git a/test/IDE/complete_value_expr.swift b/test/IDE/complete_value_expr.swift index 906fb09bbd477..f16a8ae567156 100644 --- a/test/IDE/complete_value_expr.swift +++ b/test/IDE/complete_value_expr.swift @@ -768,7 +768,7 @@ func testInsideFunctionCall4() { func testInsideFunctionCall5() { FooStruct().instanceFunc2(42, #^INSIDE_FUNCTION_CALL_5^# // INSIDE_FUNCTION_CALL_5: Begin completions -// INSIDE_FUNCTION_CALL_5-DAG: Keyword/ExprSpecific: b: [#Argument name#]; name=b: +// INSIDE_FUNCTION_CALL_5-DAG: Pattern/ExprSpecific: {#b: &Double#}[#inout Double#]; // INSIDE_FUNCTION_CALL_5: End completions } diff --git a/test/IRGen/Inputs/ptrauth-foreign.h b/test/IRGen/Inputs/ptrauth-foreign.h new file mode 100644 index 0000000000000..0b51e8c31214b --- /dev/null +++ b/test/IRGen/Inputs/ptrauth-foreign.h @@ -0,0 +1,13 @@ +struct IntPair { + int x; + int y; +}; + +__attribute__((objc_root_class)) +@interface Root +@end + +@interface ObjCWidget : Root +@end + +typedef struct __attribute__((objc_bridge(ObjCWidget))) __widget *WidgetRef; \ No newline at end of file diff --git a/test/IRGen/abitypes.swift b/test/IRGen/abitypes.swift index be7ae04892a48..41487f1f31d4a 100644 --- a/test/IRGen/abitypes.swift +++ b/test/IRGen/abitypes.swift @@ -14,6 +14,7 @@ import Foundation // armv7s-ios: [[ARMV7S_MYRECT:%.*]] = type { float, float, float, float } // arm64-ios: [[ARM64_MYRECT:%.*]] = type { float, float, float, float } +// arm64e-ios: [[ARM64E_MYRECT:%.*]] = type { float, float, float, float } // arm64-tvos: [[ARM64_MYRECT:%.*]] = type { float, float, float, float } // armv7k-watchos: [[ARMV7K_MYRECT:%.*]] = type { float, float, float, float } @@ -275,6 +276,11 @@ class Foo { // arm64-ios-fixme: [[R2:%[0-9]+]] = call i1 @"$s8abitypes3FooC6negate{{[_0-9a-zA-Z]*}}F" // arm64-ios-fixme: ret i1 [[R2]] // + // arm64e-ios-fixme: define hidden i1 @"$s8abitypes3FooC6negate{{[_0-9a-zA-Z]*}}F"(i1, %T8abitypes3FooC*) {{.*}} { + // arm64e-ios-fixme: define internal zeroext i1 @"$s8abitypes3FooC6negate{{[_0-9a-zA-Z]*}}FTo" + // arm64e-ios-fixme: [[R2:%[0-9]+]] = call i1 @"$s8abitypes3FooC6negate{{[_0-9a-zA-Z]*}}F" + // arm64e-ios-fixme: ret i1 [[R2]] + // // i386-ios-fixme: define hidden i1 @"$s8abitypes3FooC6negate{{[_0-9a-zA-Z]*}}F"(i1, %T8abitypes3FooC*) {{.*}} { // i386-ios-fixme: define internal signext i8 @"$s8abitypes3FooC6negate{{[_0-9a-zA-Z]*}}FTo"(i8*, i8*, i8 signext) {{[#0-9]*}} { // i386-ios-fixme: [[R1:%[0-9]+]] = call i1 @"$s10ObjectiveC22_convertObjCBoolToBool{{[_0-9a-zA-Z]*}}F" @@ -364,6 +370,11 @@ class Foo { // arm64-ios: [[TOOBJCBOOL:%[0-9]+]] = call swiftcc i1 @"$s10ObjectiveC22_convertBoolToObjCBool{{[_0-9a-zA-Z]*}}F"(i1 [[NEG]]) // arm64-ios: ret i1 [[TOOBJCBOOL]] // + // arm64e-ios: define hidden zeroext i1 @"$s8abitypes3FooC7negate2{{[_0-9a-zA-Z]*}}FTo"(i8* %0, i8* %1, i1 zeroext %2) + // arm64e-ios: [[NEG:%[0-9]+]] = call swiftcc i1 @"$s8abitypes3FooC7negate2{{[_0-9a-zA-Z]*}}F"(i1 + // arm64e-ios: [[TOOBJCBOOL:%[0-9]+]] = call swiftcc i1 @"$s10ObjectiveC22_convertBoolToObjCBool{{[_0-9a-zA-Z]*}}F"(i1 [[NEG]]) + // arm64e-ios: ret i1 [[TOOBJCBOOL]] + // // i386-ios: define hidden swiftcc i1 @"$s8abitypes3FooC7negate2{{[_0-9a-zA-Z]*}}F"(i1 %0, %T8abitypes3FooC* swiftself %1) {{.*}} { // i386-ios: [[TOOBJCBOOL:%[0-9]+]] = call swiftcc i8 @"$s10ObjectiveC22_convertBoolToObjCBool{{[_0-9a-zA-Z]*}}F"(i1 %0) // i386-ios: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(negate:)", align 4 @@ -516,6 +527,9 @@ class Foo { // arm64-ios: define hidden swiftcc { i64, i64, i64, i64 } @"$s8abitypes3FooC14callJustReturn{{[_0-9a-zA-Z]*}}F"(%TSo13StructReturnsC* %0, i64 %1, i64 %2, i64 %3, i64 %4, %T8abitypes3FooC* swiftself %5) {{.*}} { // arm64-ios: define hidden void @"$s8abitypes3FooC14callJustReturn{{[_0-9a-zA-Z]*}}FTo"(%TSo9BigStructV* noalias nocapture sret %0, i8* %1, i8* %2, [[OPAQUE:.*]]* %3, %TSo9BigStructV* %4) {{[#0-9]*}} { // + // arm64e-ios: define hidden swiftcc { i64, i64, i64, i64 } @"$s8abitypes3FooC14callJustReturn{{[_0-9a-zA-Z]*}}F"(%TSo13StructReturnsC* %0, i64 %1, i64 %2, i64 %3, i64 %4, %T8abitypes3FooC* swiftself %5) {{.*}} { + // arm64e-ios: define hidden void @"$s8abitypes3FooC14callJustReturn{{[_0-9a-zA-Z]*}}FTo"(%TSo9BigStructV* noalias nocapture sret %0, i8* %1, i8* %2, [[OPAQUE:.*]]* %3, %TSo9BigStructV* %4) {{.*}} { + // // arm64-tvos: define hidden swiftcc { i64, i64, i64, i64 } @"$s8abitypes3FooC14callJustReturn{{[_0-9a-zA-Z]*}}F"(%TSo13StructReturnsC* %0, i64 %1, i64 %2, i64 %3, i64 %4, %T8abitypes3FooC* swiftself %5) {{.*}} { // arm64-tvos: define hidden void @"$s8abitypes3FooC14callJustReturn{{[_0-9a-zA-Z]*}}FTo"(%TSo9BigStructV* noalias nocapture sret %0, i8* %1, i8* %2, [[OPAQUE:.*]]* %3, %TSo9BigStructV* %4) {{[#0-9]*}} { @objc dynamic func callJustReturn(_ r: StructReturns, with v: BigStruct) -> BigStruct { @@ -561,6 +575,16 @@ public func testInlineAgg(_ rect: MyRect) -> Float { // arm64-ios: store i1 false, i1* [[PTR2]], align 8 // arm64-ios: [[ARG:%.*]] = load i64, i64* [[COERCED]] // arm64-ios: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]]) +// +// arm64e-ios: define swiftcc void @"$s8abitypes14testBOOLStructyyF"() +// arm64e-ios: [[COERCED:%.*]] = alloca i64 +// arm64e-ios: [[STRUCTPTR:%.*]] = bitcast i64* [[COERCED]] to %TSo14FiveByteStructV +// arm64e-ios: [[PTR0:%.*]] = getelementptr inbounds %TSo14FiveByteStructV, %TSo14FiveByteStructV* [[STRUCTPTR]], {{i.*}} 0, {{i.*}} 0 +// arm64e-ios: [[PTR1:%.*]] = getelementptr inbounds %T10ObjectiveC8ObjCBoolV, %T10ObjectiveC8ObjCBoolV* [[PTR0]], {{i.*}} 0, {{i.*}} 0 +// arm64e-ios: [[PTR2:%.*]] = getelementptr inbounds %TSb, %TSb* [[PTR1]], {{i.*}} 0, {{i.*}} 0 +// arm64e-ios: store i1 false, i1* [[PTR2]], align 8 +// arm64e-ios: [[ARG:%.*]] = load i64, i64* [[COERCED]] +// arm64e-ios: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]]) public func testBOOLStruct() { let s = FiveByteStruct() MyClass.mymethod(s) diff --git a/test/IRGen/associated_type_witness.swift b/test/IRGen/associated_type_witness.swift index 298756bdb66db..0af07e62363b9 100644 --- a/test/IRGen/associated_type_witness.swift +++ b/test/IRGen/associated_type_witness.swift @@ -41,7 +41,7 @@ protocol HasThreeAssocTypes { // GLOBAL-SAME: @"$s23associated_type_witness13WithUniversalVAA8AssockedAAMc" // GLOBAL-SAME: @"associated conformance 23associated_type_witness13WithUniversalVAA8AssockedAA5AssocAaDP_AA1P", // GLOBAL-SAME: @"associated conformance 23associated_type_witness13WithUniversalVAA8AssockedAA5AssocAaDP_AA1Q" -// GLOBAL-SAME: i64 add (i64 ptrtoint (<{ {{.*}} }>* @"symbolic{{.*}}23associated_type_witness9UniversalV" to i64), i64 1) to i8*) +// GLOBAL-SAME: @"symbolic{{.*}}23associated_type_witness9UniversalV" // GLOBAL-SAME: ] struct WithUniversal : Assocked { typealias Assoc = Universal diff --git a/test/IRGen/autorelease.sil b/test/IRGen/autorelease.sil index 223cc89e49417..09fbf729c6477 100644 --- a/test/IRGen/autorelease.sil +++ b/test/IRGen/autorelease.sil @@ -46,6 +46,14 @@ bb0(%0 : @owned $C?): // arm64-NEXT: [[T3:%.*]] = ptrtoint i8* [[T2]] to i64 // arm64-NEXT: ret i64 [[T3]] +// arm64e: define{{( dllexport| protected)?}} swiftcc i64 @bar(i64 %0) +// arm64e: [[T0:%.*]] = call swiftcc i64 @foo(i64 %0) +// arm64e-NEXT: call void asm sideeffect "mov +// arm64e-NEXT: [[T1:%.*]] = inttoptr i64 [[T0]] to i8* +// arm64e-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T1]]) +// arm64e-NEXT: [[T3:%.*]] = ptrtoint i8* [[T2]] to i64 +// arm64e-NEXT: ret i64 [[T3]] + // aarch64: define{{( dllexport| protected)?}} swiftcc i64 @bar(i64 %0) // aarch64: [[T0:%.*]] = call swiftcc i64 @foo(i64 %0) // aarch64-NEXT: call void asm sideeffect "mov diff --git a/test/IRGen/big_types_corner_cases.swift b/test/IRGen/big_types_corner_cases.swift index 437cce3c3beb2..f9dc5d24b6ec9 100644 --- a/test/IRGen/big_types_corner_cases.swift +++ b/test/IRGen/big_types_corner_cases.swift @@ -209,8 +209,7 @@ public func testGetFunc() { // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} hidden swiftcc void @"$s22big_types_corner_cases7TestBigC4testyyF"(%T22big_types_corner_cases7TestBigC* swiftself %0) // CHECK: [[CALL1:%.*]] = call {{.*}} @__swift_instantiateConcreteTypeFromMangledName({{.*}} @"$sSayy22big_types_corner_cases9BigStructVcSgGMD" // CHECK: [[CALL2:%.*]] = call i8** @"$sSayy22big_types_corner_cases9BigStructVcSgGSayxGSlsWl -// CHECK: call swiftcc void @"$sSlsE10firstIndex5where0B0QzSgSb7ElementQzKXE_tKF"(%TSq.{{.*}}* noalias nocapture sret {{.*}}, i8* bitcast (i1 (%Txq_r0_ly22big_types_corner_cases9BigStructVytIsegnr_Sg*, %swift.refcounted*, %swift.error**)* @"$s22big_types_corner_cases9BigStructVIegy_SgSbs5Error_pIggdzo_xq_r0_lyACytIsegnr_SgSbsAE_pIegndzo_TRTA" to i8*), %swift.opaque* {{.*}}, %swift.type* [[CALL1]], i8** [[CALL2]], %swift.opaque* noalias nocapture swiftself -// CHECK: ret void +// CHECK: call swiftcc void @"$sSlsE10firstIndex5where0B0QzSgSb7ElementQzKXE_tKF"(%TSq.{{.*}}* noalias nocapture sret %{{[0-9]+}}, i8* bitcast ({{.*}}* @"$s22big_types_corner_cases9BigStruct{{.*}}_TRTA{{(\.ptrauth)?}}" to i8*), %swift.opaque* %{{[0-9]+}}, %swift.type* %{{[0-9]+}}, i8** [[CALL2]] // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} hidden swiftcc void @"$s22big_types_corner_cases7TestBigC5test2yyF"(%T22big_types_corner_cases7TestBigC* swiftself %0) // CHECK: [[CALL1:%.*]] = call {{.*}} @__swift_instantiateConcreteTypeFromMangledName({{.*}} @"$sSaySS2ID_y22big_types_corner_cases9BigStructVcSg7handlertGMD" diff --git a/test/IRGen/c_functions.swift b/test/IRGen/c_functions.swift index 5f87bd05f9643..3d42cfc1c3657 100644 --- a/test/IRGen/c_functions.swift +++ b/test/IRGen/c_functions.swift @@ -28,6 +28,7 @@ func test_indirect_by_val_alignment() { // aarch64: define hidden swiftcc void @"$s11c_functions30test_indirect_by_val_alignmentyyF"() // arm64: define hidden swiftcc void @"$s11c_functions30test_indirect_by_val_alignmentyyF"() +// arm64e: define hidden swiftcc void @"$s11c_functions30test_indirect_by_val_alignmentyyF"() // armv7k: define hidden swiftcc void @"$s11c_functions30test_indirect_by_val_alignmentyyF"() // armv7s: define hidden swiftcc void @"$s11c_functions30test_indirect_by_val_alignmentyyF"() // armv7: define hidden swiftcc void @"$s11c_functions30test_indirect_by_val_alignmentyyF"() diff --git a/test/IRGen/c_globals.swift b/test/IRGen/c_globals.swift index 9b95d1c1dfaca..20cdca7519981 100644 --- a/test/IRGen/c_globals.swift +++ b/test/IRGen/c_globals.swift @@ -32,4 +32,4 @@ public func testCaptureGlobal() { } // CHECK-DAG: attributes [[CLANG_FUNC_ATTR]] = { noinline nounwind {{.*}}"frame-pointer"="all"{{.*}} -// CHECK-DAG: attributes [[SWIFT_FUNC_ATTR]] = { "frame-pointer"="all" "target-cpu" +// CHECK-DAG: attributes [[SWIFT_FUNC_ATTR]] = { "frame-pointer"="all" {{.*}}"target-cpu" diff --git a/test/IRGen/c_layout.sil b/test/IRGen/c_layout.sil index 9ada704fb897c..8cdbc74113441 100644 --- a/test/IRGen/c_layout.sil +++ b/test/IRGen/c_layout.sil @@ -249,6 +249,22 @@ bb0: // CHECK-arm64-LABEL: declare{{( dllimport)?}} i32 @ints(i32) // CHECK-arm64-LABEL: declare{{( dllimport)?}} i32 @unsigneds(i32) +// CHECK-arm64e-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testIntegerExtension +// CHECK-arm64e: call signext i8 @chareth(i8 signext +// CHECK-arm64e: call signext i8 @signedChareth(i8 signext +// CHECK-arm64e: call zeroext i8 @unsignedChareth(i8 zeroext +// CHECK-arm64e: call signext i16 @eatMyShorts(i16 signext +// CHECK-arm64e: call zeroext i16 @eatMyUnsignedShorts(i16 zeroext +// CHECK-arm64e: call i32 @ints(i32 %5) +// CHECK-arm64e: call i32 @unsigneds(i32 %6) +// CHECK-arm64e-LABEL: declare{{( dllimport)?}} signext i8 @chareth(i8 signext) +// CHECK-arm64e-LABEL: declare{{( dllimport)?}} signext i8 @signedChareth(i8 signext) +// CHECK-arm64e-LABEL: declare{{( dllimport)?}} zeroext i8 @unsignedChareth(i8 zeroext) +// CHECK-arm64e-LABEL: declare{{( dllimport)?}} signext i16 @eatMyShorts(i16 signext) +// CHECK-arm64e-LABEL: declare{{( dllimport)?}} zeroext i16 @eatMyUnsignedShorts(i16 zeroext) +// CHECK-arm64e-LABEL: declare{{( dllimport)?}} i32 @ints(i32) +// CHECK-arm64e-LABEL: declare{{( dllimport)?}} i32 @unsigneds(i32) + // CHECK-aarch64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testIntegerExtension // CHECK-aarch64: call i8 @chareth(i8 %0) // CHECK-aarch64: call i8 @signedChareth(i8 %1) diff --git a/test/IRGen/class_metadata.swift b/test/IRGen/class_metadata.swift index e130c37d86921..ef631cc6a7897 100644 --- a/test/IRGen/class_metadata.swift +++ b/test/IRGen/class_metadata.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %{python} %utils/chex.py < %s > %t/class_metadata.swift -// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %t/class_metadata.swift -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize -check-prefix CHECK-%target-import-type +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %t/class_metadata.swift -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize -check-prefix CHECK-%target-import-type -check-prefix=CHECK-%target-cpu class A {} @@ -32,9 +32,13 @@ class A {} // CHECK-64-SAME: i32 10, // V-table length. // CHECK-SAME: i32 1, -// CHECK-SMAE: %swift.method_descriptor { +// CHECK-SAME: %swift.method_descriptor { // V-table entry #1: flags. -// CHECK-SAME: i32 1 +// CHECK-i386-SAME: i32 1, +// CHECK-x86_64-SAME: i32 1, +// CHECK-armv7k-SAME: i32 1, +// CHECK-arm64-SAME: i32 1, +// CHECK-arm64e-SAME: i32 1882783745 // V-table entry #1: invocation function. // CHECK-SAME: @"$s14class_metadata1ACACycfC" // CHECK-SAME: }>, section diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift index 662a785409c84..0d7e2cf8fb360 100644 --- a/test/IRGen/class_resilience.swift +++ b/test/IRGen/class_resilience.swift @@ -3,7 +3,7 @@ // RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift // RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift // RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_class.swiftmodule -module-name=resilient_class -I %t %S/../Inputs/resilient_class.swift -// RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution %t/class_resilience.swift | %FileCheck %t/class_resilience.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution %t/class_resilience.swift | %FileCheck %t/class_resilience.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime -check-prefix=CHECK-%target-cpu --check-prefix=CHECK-%target-runtime-STABLE-ABI-%target-mandates-stable-abi -DINT=i%target-ptrsize // RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution -O %t/class_resilience.swift // CHECK: @"$s16class_resilience26ClassWithResilientPropertyC1s16resilient_struct4SizeVvpWvd" = hidden global [[INT]] 0 @@ -381,7 +381,7 @@ public class ClassWithResilientThenEmpty { // CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// CHECK-NEXT: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @swift_getSingletonMetadata([[INT]] %0, %swift.type_descriptor* bitcast ({{.*}} @"$s16class_resilience26ClassWithResilientPropertyCMn" to %swift.type_descriptor*)) +// CHECK-NEXT: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @swift_getSingletonMetadata([[INT]] %0, %swift.type_descriptor* bitcast ({{.*}} @"$s16class_resilience26ClassWithResilientPropertyCMn{{(\.ptrauth.*)?}}" to %swift.type_descriptor*)) // CHECK-NEXT: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0 // CHECK-NEXT: [[STATUS:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 1 // CHECK-NEXT: br label %cont @@ -414,7 +414,9 @@ public class ClassWithResilientThenEmpty { // CHECK: dependency-satisfied: // -- ClassLayoutFlags = 0x100 (HasStaticVTable) -// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_initClassMetadata2(%swift.type* %0, [[INT]] 256, [[INT]] 3, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) +// CHECK-native: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_initClassMetadata2(%swift.type* %0, [[INT]] 256, [[INT]] 3, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) +// CHECK-objc-STABLE-ABI-TRUE: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_updateClassMetadata2(%swift.type* %0, [[INT]] 256, [[INT]] 3, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) +// CHECK-objc-STABLE-ABI-FALSE:[[T0:%.*]] = call swiftcc %swift.metadata_response @swift_initClassMetadata2(%swift.type* %0, [[INT]] 256, [[INT]] 3, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) // CHECK-NEXT: [[INITDEP_METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 // CHECK-NEXT: [[INITDEP_STATUS:%.*]] = extractvalue %swift.metadata_response [[T0]], 1 // CHECK-NEXT: [[INITDEP_PRESENT:%.*]] = icmp eq %swift.type* [[INITDEP_METADATA]], null @@ -443,7 +445,7 @@ public class ClassWithResilientThenEmpty { // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i8* @"$s16class_resilience26ClassWithResilientPropertyCMu"(%swift.type* %0, %swift.method_descriptor* %1) // CHECK-NEXT: entry: -// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_lookUpClassMethod(%swift.type* %0, %swift.method_descriptor* %1, %swift.type_descriptor* bitcast (<{{.*}}>* @"$s16class_resilience26ClassWithResilientPropertyCMn" to %swift.type_descriptor*)) +// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_lookUpClassMethod(%swift.type* %0, %swift.method_descriptor* %1, %swift.type_descriptor* bitcast ({{.*}}* @"$s16class_resilience26ClassWithResilientPropertyCMn{{(\.ptrauth.*)?}}" to %swift.type_descriptor*)) // CHECK-NEXT: ret i8* [[RESULT]] // CHECK-NEXT: } @@ -456,7 +458,7 @@ public class ClassWithResilientThenEmpty { // CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// CHECK-NEXT: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @swift_getSingletonMetadata([[INT]] %0, %swift.type_descriptor* bitcast ({{.*}} @"$s16class_resilience33ClassWithResilientlySizedPropertyCMn" to %swift.type_descriptor*)) +// CHECK-NEXT: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @swift_getSingletonMetadata([[INT]] %0, %swift.type_descriptor* bitcast ({{.*}} @"$s16class_resilience33ClassWithResilientlySizedPropertyCMn{{(\.ptrauth.*)?}}" to %swift.type_descriptor*)) // CHECK-NEXT: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0 // CHECK-NEXT: [[STATUS:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 1 // CHECK-NEXT: br label %cont @@ -490,7 +492,9 @@ public class ClassWithResilientThenEmpty { // CHECK: dependency-satisfied: // -- ClassLayoutFlags = 0x100 (HasStaticVTable) -// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_initClassMetadata2(%swift.type* %0, [[INT]] 256, [[INT]] 2, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) +// CHECK-native: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_initClassMetadata2(%swift.type* %0, [[INT]] 256, [[INT]] 2, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) +// CHECK-objc-STABLE-ABI-TRUE: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_updateClassMetadata2(%swift.type* %0, [[INT]] 256, [[INT]] 2, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) +// CHECK-objc-STABLE-ABI-FALSE:[[T0:%.*]] = call swiftcc %swift.metadata_response @swift_initClassMetadata2(%swift.type* %0, [[INT]] 256, [[INT]] 2, i8*** [[FIELDS_PTR]], [[INT]]* [[FIELDS_DEST]]) // CHECK-NEXT: [[INITDEP_METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 // CHECK-NEXT: [[INITDEP_STATUS:%.*]] = extractvalue %swift.metadata_response [[T0]], 1 // CHECK-NEXT: [[INITDEP_PRESENT:%.*]] = icmp eq %swift.type* [[INITDEP_METADATA]], null @@ -519,7 +523,7 @@ public class ClassWithResilientThenEmpty { // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i8* @"$s16class_resilience33ClassWithResilientlySizedPropertyCMu"(%swift.type* %0, %swift.method_descriptor* %1) // CHECK-NEXT: entry: -// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_lookUpClassMethod(%swift.type* %0, %swift.method_descriptor* %1, %swift.type_descriptor* bitcast (<{{.*}}>* @"$s16class_resilience33ClassWithResilientlySizedPropertyCMn" to %swift.type_descriptor*)) +// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_lookUpClassMethod(%swift.type* %0, %swift.method_descriptor* %1, %swift.type_descriptor* bitcast ({{.*}}* @"$s16class_resilience33ClassWithResilientlySizedPropertyCMn{{(\.ptrauth.*)?}}" to %swift.type_descriptor*)) // CHECK-NEXT: ret i8* [[RESULT]] // CHECK-NEXT: } @@ -538,10 +542,25 @@ public class ClassWithResilientThenEmpty { // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i8* @"$s16class_resilience14ResilientChildCMu"(%swift.type* %0, %swift.method_descriptor* %1) // CHECK-NEXT: entry: -// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_lookUpClassMethod(%swift.type* %0, %swift.method_descriptor* %1, %swift.type_descriptor* bitcast (<{{.*}}>* @"$s16class_resilience14ResilientChildCMn" to %swift.type_descriptor*)) +// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_lookUpClassMethod(%swift.type* %0, %swift.method_descriptor* %1, %swift.type_descriptor* bitcast ({{.*}}* @"$s16class_resilience14ResilientChildCMn{{(\.ptrauth.*)?}}" to %swift.type_descriptor*)) // CHECK-NEXT: ret i8* [[RESULT]] // CHECK-NEXT: } +// ResilientChild.field getter dispatch thunk + +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i32 @"$s16class_resilience14ResilientChildC5fields5Int32VvgTj"(%T16class_resilience14ResilientChildC* swiftself %0) +// CHECK: [[ISA_ADDR:%.*]] = getelementptr inbounds %T16class_resilience14ResilientChildC, %T16class_resilience14ResilientChildC* %0, i32 0, i32 0, i32 0 +// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]] +// CHECK-NEXT: [[BASE_ADDR:%.*]] = load [[INT]], [[INT]]* getelementptr inbounds ([[BOUNDS]], [[BOUNDS]]* @"$s16class_resilience14ResilientChildCMo", i32 0, i32 0) +// CHECK-NEXT: [[BASE:%.*]] = add [[INT]] [[BASE_ADDR]], {{4|8}} +// CHECK-NEXT: [[METADATA_BYTES:%.*]] = bitcast %swift.type* [[ISA]] to i8* +// CHECK-NEXT: [[VTABLE_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[METADATA_BYTES]], [[INT]] [[BASE]] +// CHECK-NEXT: [[VTABLE_OFFSET_ADDR:%.*]] = bitcast i8* [[VTABLE_OFFSET_TMP]] to i32 (%T16class_resilience14ResilientChildC*)** +// CHECK-NEXT: [[METHOD:%.*]] = load i32 (%T16class_resilience14ResilientChildC*)*, i32 (%T16class_resilience14ResilientChildC*)** [[VTABLE_OFFSET_ADDR]] +// CHECK-arm64e-NEXT: ptrtoint i32 (%T16class_resilience14ResilientChildC*)** [[VTABLE_OFFSET_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 +// CHECK-NEXT: [[RESULT:%.*]] = call swiftcc i32 [[METHOD]](%T16class_resilience14ResilientChildC* swiftself %0) +// CHECK-NEXT: ret i32 [[RESULT]] // ResilientChild.field setter dispatch thunk @@ -554,6 +573,8 @@ public class ClassWithResilientThenEmpty { // CHECK-NEXT: [[VTABLE_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[METADATA_BYTES]], [[INT]] [[METADATA_OFFSET]] // CHECK-NEXT: [[VTABLE_OFFSET_ADDR:%.*]] = bitcast i8* [[VTABLE_OFFSET_TMP]] to void (i32, %T16class_resilience14ResilientChildC*)** // CHECK-NEXT: [[METHOD:%.*]] = load void (i32, %T16class_resilience14ResilientChildC*)*, void (i32, %T16class_resilience14ResilientChildC*)** [[VTABLE_OFFSET_ADDR]] +// CHECK-arm64e-NEXT: ptrtoint void (i32, %T16class_resilience14ResilientChildC*)** [[VTABLE_OFFSET_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call swiftcc void [[METHOD]](i32 %0, %T16class_resilience14ResilientChildC* swiftself %1) // CHECK-NEXT: ret void @@ -561,7 +582,7 @@ public class ClassWithResilientThenEmpty { // ResilientGenericChild metadata initialization function // CHECK-LABEL: define internal %swift.type* @"$s16class_resilience21ResilientGenericChildCMi"(%swift.type_descriptor* %0, i8** %1, i8* %2) -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* {{.*}}, i8** %1, i8* %2) // CHECK: ret %swift.type* [[METADATA]] // CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$s16class_resilience21ResilientGenericChildCMr" @@ -575,6 +596,6 @@ public class ClassWithResilientThenEmpty { // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i8* @"$s16class_resilience21ResilientGenericChildCMu"(%swift.type* %0, %swift.method_descriptor* %1) // CHECK-NEXT: entry: -// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_lookUpClassMethod(%swift.type* %0, %swift.method_descriptor* %1, %swift.type_descriptor* bitcast (<{{.*}}>* @"$s16class_resilience21ResilientGenericChildCMn" to %swift.type_descriptor*)) +// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_lookUpClassMethod(%swift.type* %0, %swift.method_descriptor* %1, %swift.type_descriptor* bitcast ({{.*}}* @"$s16class_resilience21ResilientGenericChildCMn{{(\.ptrauth.*)?}}" to %swift.type_descriptor*)) // CHECK-NEXT: ret i8* [[RESULT]] // CHECK-NEXT: } diff --git a/test/IRGen/class_update_callback_without_fixed_layout.sil b/test/IRGen/class_update_callback_without_fixed_layout.sil index e6e8e71a45243..a905c46986b8b 100644 --- a/test/IRGen/class_update_callback_without_fixed_layout.sil +++ b/test/IRGen/class_update_callback_without_fixed_layout.sil @@ -5,6 +5,7 @@ // RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution -O %s -target %target-pre-stable-abi-triple // REQUIRES: objc_interop +// UNSUPPORTED: CPU=arm64e // With the old deployment target, these classes use the 'singleton' metadata // initialization pattern. The class is not statically visible to Objective-C, @@ -59,7 +60,7 @@ sil_vtable SubclassOfClassWithResilientField {} // CHECK-NEW-SAME: i32 192, // -- the update callback -// CHECK-NEW-SAME: @"$s42class_update_callback_without_fixed_layout23ClassWithResilientFieldCMU" +// CHECK-NEW-SAME: @"$s42class_update_callback_without_fixed_layout23ClassWithResilientFieldCMU{{(\.ptrauth)?}}" // CHECK-SAME: }, section "__DATA, __objc_const" diff --git a/test/IRGen/conditional_conformances.swift b/test/IRGen/conditional_conformances.swift index 6503c5aed0d06..7e41923027dd7 100644 --- a/test/IRGen/conditional_conformances.swift +++ b/test/IRGen/conditional_conformances.swift @@ -1,7 +1,7 @@ -// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=CHECK --check-prefix=%target-os -// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc.swift --check-prefix=CHECK --check-prefix=%target-os -// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass.swift --check-prefix=CHECK --check-prefix=%target-os -// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift --check-prefix=CHECK --check-prefix=%target-os +// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=CHECK --check-prefix=CHECK-STABLE-ABI-%target-mandates-stable-abi +// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc.swift --check-prefix=CHECK --check-prefix=CHECK-STABLE-ABI-%target-mandates-stable-abi +// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass.swift --check-prefix=CHECK --check-prefix=CHECK-STABLE-ABI-%target-mandates-stable-abi +// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift --check-prefix=CHECK --check-prefix=CHECK-STABLE-ABI-%target-mandates-stable-abi // Too many pointer-sized integers in the IR // REQUIRES: PTRSIZE=64 diff --git a/test/IRGen/conditional_conformances_future.swift b/test/IRGen/conditional_conformances_future.swift index 13fdff85501af..3bce444de7eff 100644 --- a/test/IRGen/conditional_conformances_future.swift +++ b/test/IRGen/conditional_conformances_future.swift @@ -1,7 +1,7 @@ // RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances_future.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=%target-os -// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc_future.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=%target-os -// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass_future.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=%target-os -// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=%target-os +// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc_future.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-STABLE-ABI-%target-mandates-stable-abi +// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass_future.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-STABLE-ABI-%target-mandates-stable-abi +// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-STABLE-ABI-%target-mandates-stable-abi // Too many pointer-sized integers in the IR // REQUIRES: PTRSIZE=64 diff --git a/test/IRGen/dead_method.swift b/test/IRGen/dead_method.swift index fd52c73d85240..1c31093657717 100644 --- a/test/IRGen/dead_method.swift +++ b/test/IRGen/dead_method.swift @@ -19,35 +19,35 @@ public class Class { // -- vtable // CHECK-SAME: %swift.method_descriptor { -// CHECK-SAME: i32 1, +// CHECK-SAME: i32 {{(1|-835911679)}}, // CHECK-SAME: @"$s11dead_method5ClassCACycfC" // CHECK-SAME: } // CHECK-SAME: %swift.method_descriptor { -// CHECK-SAME: i32 16, +// CHECK-SAME: i32 {{(16|-1609105392)}}, // CHECK-SAME: @"$s11dead_method5ClassC4liveyyF" // CHECK-SAME: } -// CHECK-SAME: %swift.method_descriptor { i32 16, i32 0 } +// CHECK-SAME: %swift.method_descriptor { i32 {{(16|-1887436784)}}, i32 0 } // CHECK-SAME: }> // CHECK-LABEL: @"$s11dead_method5ClassCMf" = internal global <{{.*}}> <{ // -- destructor -// CHECK-SAME: void (%T11dead_method5ClassC*)* @"$s11dead_method5ClassCfD", +// CHECK-SAME: void (%T11dead_method5ClassC*)* {{.*}}@"$s11dead_method5ClassCfD{{(.ptrauth)?}}" // -- value witness table // CHECK-SAME: i8** {{@"\$sBoWV"|null}}, // -- nominal type descriptor -// CHECK-SAME: @"$s11dead_method5ClassCMn", +// CHECK-SAME: @"$s11dead_method5ClassCMn{{(.ptrauth)?}}" // -- ivar destroyer // CHECK-SAME: i8* null, // -- vtable -// CHECK-SAME: %T11dead_method5ClassC* (%swift.type*)* @"$s11dead_method5ClassCACycfC", -// CHECK-SAME: void (%T11dead_method5ClassC*)* @"$s11dead_method5ClassC4liveyyF", -// CHECK-SAME: i8* bitcast (void ()* @swift_deletedMethodError to i8*) +// CHECK-SAME: %T11dead_method5ClassC* (%swift.type*)* {{.*}}@"$s11dead_method5ClassCACycfC{{(.ptrauth)?}}" +// CHECK-SAME: void (%T11dead_method5ClassC*)* {{.*}}@"$s11dead_method5ClassC4liveyyF{{(.ptrauth)?}}" +// CHECK-SAME: i8* bitcast {{.*}}@swift_deletedMethodError{{(.ptrauth)?}} to i8*) // CHECK-SAME: }> diff --git a/test/IRGen/dynamic_replaceable.sil b/test/IRGen/dynamic_replaceable.sil index 3f4cbe8fe45c2..15cb46788d38f 100644 --- a/test/IRGen/dynamic_replaceable.sil +++ b/test/IRGen/dynamic_replaceable.sil @@ -3,6 +3,9 @@ // REQUIRES: objc_interop +// The arm64e test is in ptrauth-dynamic_replaceable.sil. +// UNSUPPORTED: CPU=arm64e + // CHECK: @test_dynamically_replaceableTX = global %swift.dyn_repl_link_entry { i8* bitcast (void ()* @test_dynamically_replaceable to i8*), %swift.dyn_repl_link_entry* null } // CHECK: @test_dynamically_replaceableTx = constant %swift.dyn_repl_key { i32{{.*}}%swift.dyn_repl_link_entry* @test_dynamically_replaceableTX{{.*}}, i32 0 }, section "__TEXT,__const" // CHECK: @test_replacementTX = global %swift.dyn_repl_link_entry zeroinitializer @@ -24,7 +27,7 @@ // CHECK-LABEL: define swiftcc void @test_dynamically_replaceable() // CHECK-NEXT: entry: -// COMPAT-NEXT: [[FUN_PTR:%.*]] = call i8* @swift_getFunctionReplacement50(i8** getelementptr inbounds (%swift.dyn_repl_link_entry, %swift.dyn_repl_link_entry* @test_dynamically_replaceableTX, i32 0, i32 0), i8* bitcast (void ()* @test_dynamically_replaceable to i8*)) +// COMPAT-NEXT: [[FUN_PTR:%.*]] = call i8* @swift_getFunctionReplacement{{.*}}(i8** getelementptr inbounds (%swift.dyn_repl_link_entry, %swift.dyn_repl_link_entry* @test_dynamically_replaceableTX, i32 0, i32 0), i8* bitcast (void ()* @test_dynamically_replaceable to i8*)) // NONCOMPAT-NEXT: [[FUN_PTR:%.*]] = call i8* @swift_getFunctionReplacement(i8** getelementptr inbounds (%swift.dyn_repl_link_entry, %swift.dyn_repl_link_entry* @test_dynamically_replaceableTX, i32 0, i32 0), i8* bitcast (void ()* @test_dynamically_replaceable to i8*)) // CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[FUN_PTR]], null // CHECK-NEXT: br i1 [[CMP]], label %[[ORIGBB:[a-z_]*]], label %[[FWBB:[a-z_]*]] @@ -51,7 +54,7 @@ bb0: // The thunk that implement the prev_dynamic_function_ref lookup. // CHECK-LABEL: define swiftcc void @test_replacementTI() // CHECK: entry: -// COMPAT: [[FUN_PTR:%.*]] = call i8* @swift_getOrigOfReplaceable50(i8** getelementptr inbounds (%swift.dyn_repl_link_entry, %swift.dyn_repl_link_entry* @test_replacementTX, i32 0, i32 0)) +// COMPAT: [[FUN_PTR:%.*]] = call i8* @swift_getOrigOfReplaceable{{.*}}(i8** getelementptr inbounds (%swift.dyn_repl_link_entry, %swift.dyn_repl_link_entry* @test_replacementTX, i32 0, i32 0)) // NONCOMPAT: [[FUN_PTR:%.*]] = call i8* @swift_getOrigOfReplaceable(i8** getelementptr inbounds (%swift.dyn_repl_link_entry, %swift.dyn_repl_link_entry* @test_replacementTX, i32 0, i32 0)) // CHECK: [[TYPED_PTR:%.*]] = bitcast i8* [[FUN_PTR]] to void ()* // CHECK: call swiftcc void [[TYPED_PTR]]() diff --git a/test/IRGen/dynamic_replaceable_opaque_return.swift b/test/IRGen/dynamic_replaceable_opaque_return.swift index f4b9dec457e61..5c1c74ffc5e58 100644 --- a/test/IRGen/dynamic_replaceable_opaque_return.swift +++ b/test/IRGen/dynamic_replaceable_opaque_return.swift @@ -1,5 +1,7 @@ // RUN: %target-swift-frontend -disable-availability-checking -module-name A -swift-version 5 -primary-file %s -emit-ir | %FileCheck %s +// The arm64e test is in ptrauth-dynamic_replaceable.sil. +// UNSUPPORTED: CPU=arm64e // REQUIRES: objc_interop // No 32bit for now. diff --git a/test/IRGen/eager-class-initialization.swift b/test/IRGen/eager-class-initialization.swift index 40a3cf18692aa..c3d0bf4bc705d 100644 --- a/test/IRGen/eager-class-initialization.swift +++ b/test/IRGen/eager-class-initialization.swift @@ -3,6 +3,7 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -emit-ir -target %target-pre-stable-abi-triple | %FileCheck %s -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-OLD // REQUIRES: objc_interop +// UNSUPPORTED: CPU=arm64e // See also eager-class-initialization-stable-abi.swift, for the stable ABI // deployment target test. diff --git a/test/IRGen/enum_resilience.swift b/test/IRGen/enum_resilience.swift index 8edbc36b20a14..88a3038e9f268 100644 --- a/test/IRGen/enum_resilience.swift +++ b/test/IRGen/enum_resilience.swift @@ -6,7 +6,7 @@ // RUN: %target-swift-frontend -disable-type-layout -emit-ir -enable-library-evolution -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift | %FileCheck %t/enum_resilience.swift --check-prefix=ENUM_RES // RUN: %target-swift-frontend -disable-type-layout -emit-ir -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift | %FileCheck %t/enum_resilience.swift --check-prefix=ENUM_NOT_RES // RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift -// RUN: %target-swift-frontend -disable-type-layout -module-name enum_resilience -I %t -emit-ir -enable-library-evolution %s | %FileCheck %t/enum_resilience.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -disable-type-layout -module-name enum_resilience -I %t -emit-ir -enable-library-evolution %s | %FileCheck %t/enum_resilience.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-cpu // RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-library-evolution -O %s import resilient_enum @@ -100,6 +100,8 @@ public func functionWithResilientEnum(_ m: Medium) -> Medium { // CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]] +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* [[METADATA]]) // CHECK-NEXT: ret void @@ -118,6 +120,8 @@ public func functionWithIndirectResilientEnum(_ ia: IndirectApproach) -> Indirec // CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]] +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* [[METADATA]]) // CHECK-NEXT: ret void @@ -138,6 +142,8 @@ public func constructResilientEnumNoPayload() -> Medium { // CHECK-64-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 13 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]] +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 [[TAG]], %swift.type* [[METADATA]]) // CHECK-NEXT: ret void @@ -162,11 +168,15 @@ public func constructResilientEnumPayload(_ s: Size) -> Medium { // CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias [[ENUM_STORAGE]], %swift.opaque* noalias %1, %swift.type* [[METADATA]]) // CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[WITNESS_FN:%initializeWithTake]] = bitcast i8* [[WITNESS]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias %0, %swift.opaque* noalias [[ENUM_STORAGE]], %swift.type* [[METADATA]]) // CHECK-NEXT: [[TAG:%.*]] = load i32, i32* @"$s14resilient_enum6MediumO8PostcardyAC0A7_struct4SizeVcACmFWC" @@ -181,6 +191,8 @@ public func constructResilientEnumPayload(_ s: Size) -> Medium { // CHECK-64-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 13 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[WITNESS_FN:%destructiveInjectEnumTag]] = bitcast i8* [[WITNESS]] +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 [[TAG]], %swift.type* [[METADATA2]]) // CHECK-NEXT: [[STORAGE_ALLOCA:%.*]] = bitcast %swift.opaque* [[ENUM_STORAGE]] to i8* // CHECK-NEXT: call void @llvm.lifetime.end.p0i8({{(i32|i64)}} -1, i8* [[STORAGE_ALLOCA]]) @@ -268,7 +280,7 @@ public func resilientEnumPartialApply(_ f: (Medium) -> Int) { // CHECK: [[STACKALLOC:%.*]] = alloca i8 // CHECK: [[CONTEXT:%.*]] = bitcast i8* [[STACKALLOC]] to %swift.opaque* -// CHECK: call swiftcc void @"$s15enum_resilience13reabstractionyyx010resilient_A06MediumOXElF"(i8* bitcast (void (%TSi*, %swift.opaque*, %swift.refcounted*)* @"$s14resilient_enum6MediumOSiIgnd_ACSiIegnr_TRTA" to i8*), %swift.opaque* [[CONTEXT:%.*]], %swift.type* @"$sSiN") +// CHECK: call swiftcc void @"$s15enum_resilience13reabstractionyyx010resilient_A06MediumOXElF"(i8* bitcast ({{.*}} @"$s14resilient_enum6MediumOSiIgnd_ACSiIegnr_TRTA{{(\.ptrauth)?}}" to i8*), %swift.opaque* [[CONTEXT:%.*]], %swift.type* @"$sSiN") reabstraction(f) // CHECK: ret void @@ -334,6 +346,8 @@ extension ResilientMultiPayloadGenericEnum { // CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s16resilient_struct4SizeVMa"([[INT]] 0) // CHECK-NEXT: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 // CHECK: [[STORE_TAG:%.*]] = bitcast i8* {{%.+}} to void (%swift.opaque*, i32, i32, %swift.type*)* +// CHECK-arm64e-NEXT: ptrtoint i8** {{.*}} to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call void [[STORE_TAG]](%swift.opaque* noalias [[BUFFER]], i32 1, i32 1, %swift.type* [[METADATA]]) // CHECK-NEXT: ret void // CHECK-NEXT: {{^}$}} diff --git a/test/IRGen/errors.sil b/test/IRGen/errors.sil index 05c64e2d8e5fd..f8fba2b88c3a5 100644 --- a/test/IRGen/errors.sil +++ b/test/IRGen/errors.sil @@ -21,6 +21,7 @@ entry: // CHECK-LABEL-armv7s: define{{( dllexport)?}}{{( protected)?}} swiftcc void @does_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { // CHECK-LABEL-armv7k: define{{( dllexport)?}}{{( protected)?}} swiftcc void @does_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { // CHECK-LABEL-arm64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @does_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { +// CHECK-LABEL-arm64e: define{{( dllexport)?}}{{( protected)?}} swiftcc void @does_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { // CHECK-LABEL-aarch64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @does_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { sil @does_throw : $@convention(thin) () -> @error Error { // CHECK: [[T0:%.*]] = call swiftcc %swift.error* @create_error() @@ -42,6 +43,7 @@ sil @does_throw : $@convention(thin) () -> @error Error { // CHECK-LABEL-armv7s: define{{( dllexport)?}}{{( protected)?}} swiftcc void @doesnt_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { // CHECK-LABEL-armv7k: define{{( dllexport)?}}{{( protected)?}} swiftcc void @doesnt_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { // CHECK-LABEL-arm64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @doesnt_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { +// CHECK-LABEL-arm64e: define{{( dllexport)?}}{{( protected)?}} swiftcc void @doesnt_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { // CHECK-LABEL-aarch64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @doesnt_throw(%swift.refcounted* swiftself %0, %swift.error** swifterror %1) {{.*}} { sil @doesnt_throw : $@convention(thin) () -> @error Error { // We don't have to do anything here because the caller always @@ -64,6 +66,7 @@ entry(%0 : $AnyObject): // CHECK-armv7s: [[ERRORSLOT:%.*]] = alloca [[SWIFTERROR:.*]] %swift.error*, align // CHECK-armv7k: [[ERRORSLOT:%.*]] = alloca [[SWIFTERROR:.*]] %swift.error*, align // CHECK-arm64: [[ERRORSLOT:%.*]] = alloca [[SWIFTERROR:.*]] %swift.error*, align + // CHECK-arm64e: [[ERRORSLOT:%.*]] = alloca [[SWIFTERROR:.*]] %swift.error*, align // CHECK-aarch64: [[ERRORSLOT:%.*]] = alloca [[SWIFTERROR:.*]] %swift.error*, align // CHECK-powerpc64le: [[ERRORSLOT:%.*]] = alloca [[SWIFTERROR:.*]] %swift.error*, align // CHECK-NEXT: store %swift.error* null, %swift.error** [[ERRORSLOT]], align @@ -116,7 +119,8 @@ bb0(%0 : $Error): // rdar://21084084 - Partial application of throwing functions. // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i8*, %swift.refcounted* } @partial_apply_single(%T6errors1AC* %0) -// CHECK: insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (%swift.refcounted*, %swift.error**)* @"$s27partial_apply_single_helperTA" to i8*), %swift.refcounted* undef }, +// CHECK: insertvalue { i8*, %swift.refcounted* } { i8* bitcast ({{.*}}* @"$s27partial_apply_single_helperTA{{(\.ptrauth)?}}" to i8*), %swift.refcounted* undef }, + // CHECK: define internal swiftcc void @"$s27partial_apply_single_helperTA"(%swift.refcounted* swiftself %0, %swift.error** noalias nocapture{{( )?}}[[SWIFTERROR]]{{( )?}}dereferenceable({{.}}) %1) // CHECK: [[T0:%.*]] = bitcast %swift.refcounted* {{%.*}} to %T6errors1AC* // CHECK-NEXT: tail call swiftcc void @partial_apply_single_helper(%T6errors1AC* [[T0]], %swift.refcounted* swiftself undef, %swift.error** noalias nocapture{{( )?}}[[SWIFTERROR]]{{( )?}}dereferenceable({{.}}){{( )?}}{{%.*}}) diff --git a/test/IRGen/foreign_types.sil b/test/IRGen/foreign_types.sil index be1380db1c630..921f28825d597 100644 --- a/test/IRGen/foreign_types.sil +++ b/test/IRGen/foreign_types.sil @@ -18,7 +18,7 @@ import c_layout // CHECK-LABEL: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMf" = linkonce_odr hidden constant // CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVWV" // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMn" +// CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMn{{(\.ptrauth)?}}" // CHECK-SAME: i32 0, // CHECK-SAME: i32 4 } diff --git a/test/IRGen/foreign_types_future.sil b/test/IRGen/foreign_types_future.sil index 8e8e8c3a59671..d66891e01fde0 100644 --- a/test/IRGen/foreign_types_future.sil +++ b/test/IRGen/foreign_types_future.sil @@ -23,7 +23,7 @@ import c_layout // CHECK-LABEL: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMf" = linkonce_odr hidden constant // CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVWV" // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMn" +// CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMn // CHECK-SAME: i32 0, // CHECK-SAME: i32 4, // CHECK-SAME: i64 0 } diff --git a/test/IRGen/generic_vtable.swift b/test/IRGen/generic_vtable.swift index 96ed3dcd70698..1aaba1131ea8d 100644 --- a/test/IRGen/generic_vtable.swift +++ b/test/IRGen/generic_vtable.swift @@ -40,15 +40,15 @@ public class Concrete : Derived { // CHECK-LABEL: @"$s14generic_vtable4BaseCMf" = internal global // -- destructor -// CHECK-SAME: void (%T14generic_vtable4BaseC*)* @"$s14generic_vtable4BaseCfD" +// CHECK-SAME: @"$s14generic_vtable4BaseCfD{{(.ptrauth)?}}" // -- value witness table // CHECK-SAME: i8** {{@"\$sBoWV"|null}} // -- vtable entry for 'm1()' -// CHECK-SAME: void (%T14generic_vtable4BaseC*)* @"$s14generic_vtable4BaseC2m1yyF" +// CHECK-SAME: void (%T14generic_vtable4BaseC*)* {{@"\$s14generic_vtable4BaseC2m1yyF"|.* @"\$s14generic_vtable4BaseC2m1yyF.ptrauth"}} // -- vtable entry for 'm2()' -// CHECK-SAME: void (%T14generic_vtable4BaseC*)* @"$s14generic_vtable4BaseC2m2yyF" +// CHECK-SAME: void (%T14generic_vtable4BaseC*)* {{@"\$s14generic_vtable4BaseC2m2yyF"|.* @"\$s14generic_vtable4BaseC2m2yyF.ptrauth"}} // -- vtable entry for 'init()' -// CHECK-SAME: %T14generic_vtable4BaseC* (%swift.type*)* @"$s14generic_vtable4BaseCACycfC" +// CHECK-SAME: %T14generic_vtable4BaseC* (%swift.type*)* {{@"\$s14generic_vtable4BaseCACycfC"|.* @"\$s14generic_vtable4BaseCACycfC.ptrauth"}} // -- // CHECK-SAME: , align @@ -119,21 +119,21 @@ public class Concrete : Derived { // CHECK-LABEL: @"$s14generic_vtable8ConcreteCMf" = internal global <{{.*}}> <{ // -- destructor -// CHECK-SAME: void (%T14generic_vtable8ConcreteC*)* @"$s14generic_vtable8ConcreteCfD", +// CHECK-SAME: @"$s14generic_vtable8ConcreteCfD{{(.ptrauth)?}}" // -- value witness table is filled in at runtime // CHECK-SAME: i8** null, // -- nominal type descriptor -// CHECK-SAME: @"$s14generic_vtable8ConcreteCMn", +// CHECK-SAME: @"$s14generic_vtable8ConcreteCMn{{(.ptrauth)?}}" // -- vtable entry for 'm1()' -// CHECK-SAME: void (%T14generic_vtable4BaseC*)* @"$s14generic_vtable4BaseC2m1yyF" +// CHECK-SAME: void (%T14generic_vtable4BaseC*)* {{@"\$s14generic_vtable4BaseC2m1yyF"|.* @"\$s14generic_vtable4BaseC2m1yyF.ptrauth.1"}} // -- vtable entry for 'm2()' -// CHECK-SAME: void (%T14generic_vtable7DerivedC*)* @"$s14generic_vtable7DerivedC2m2yyF" +// CHECK-SAME: void (%T14generic_vtable7DerivedC*)* {{@"\$s14generic_vtable7DerivedC2m2yyF"|.* @"\$s14generic_vtable7DerivedC2m2yyF.ptrauth"}} // -- vtable entry for 'init()' -// CHECK-SAME: %T14generic_vtable8ConcreteC* (%swift.type*)* @"$s14generic_vtable8ConcreteCACycfC" +// CHECK-SAME: %T14generic_vtable8ConcreteC* (%swift.type*)* {{@"\$s14generic_vtable8ConcreteCACycfC"|.* @"\$s14generic_vtable8ConcreteCACycfC.ptrauth"}} // -- vtable entry for 'm3()' -// CHECK-SAME: void (%T14generic_vtable8ConcreteC*)* @"$s14generic_vtable8ConcreteC2m3yyF" +// CHECK-SAME: void (%T14generic_vtable8ConcreteC*)* {{@"\$s14generic_vtable8ConcreteC2m3yyF"|.* @"\$s14generic_vtable8ConcreteC2m3yyF.ptrauth"}} // -- vtable entry for 'm4()' -// CHECK-SAME: void (%T14generic_vtable8ConcreteC*)* @"$s14generic_vtable8ConcreteC2m4yyF" +// CHECK-SAME: void (%T14generic_vtable8ConcreteC*)* {{@"\$s14generic_vtable8ConcreteC2m4yyF"|.* @"\$s14generic_vtable8ConcreteC2m4yyF.ptrauth"}} // -- // CHECK-SAME: }>, align @@ -157,7 +157,7 @@ public class Concrete : Derived { // - 2 immediate members: // - type metadata for generic parameter T, // - and vtable entry for 'm3()' -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* {{.*}}, i8** %1, i8* %2) // CHECK: ret %swift.type* [[METADATA]] // CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$s14generic_vtable7DerivedCMr" diff --git a/test/IRGen/indirect_argument.sil b/test/IRGen/indirect_argument.sil index ea8ce00d0a4e8..ed24a2dc1676c 100644 --- a/test/IRGen/indirect_argument.sil +++ b/test/IRGen/indirect_argument.sil @@ -66,7 +66,7 @@ entry(%o : $*Huge, %x : $Huge): // CHECK-NOT: alloca // CHECK: [[CLOSURE:%.*]] = call noalias %swift.refcounted* @swift_allocObject // CHECK: bitcast %swift.refcounted* [[CLOSURE]] to <{ %swift.refcounted, %T17indirect_argument4HugeV }>* -// CHECK: call swiftcc void @"$s24huge_partial_applicationTA"(%T17indirect_argument4HugeV* noalias nocapture dereferenceable({{.*}}) %0, %swift.refcounted* swiftself [[CLOSURE]]) +// CHECK: call swiftcc {{.*}} @"$s24huge_partial_applicationTA{{(\.ptrauth)?}}"{{.*}}(%T17indirect_argument4HugeV* noalias nocapture dereferenceable({{.*}}) %0, %swift.refcounted* swiftself [[CLOSURE]]) // CHECK: define internal swiftcc void @"$s24huge_partial_applicationTA"(%T17indirect_argument4HugeV* noalias nocapture dereferenceable({{.*}}) %0, %swift.refcounted* swiftself %1) // CHECK: [[TMP_ARG:%.*]] = alloca // CHECK-NOT: tail @@ -83,7 +83,7 @@ entry(%x : $Huge, %y : $Huge): // CHECK: [[TMP_RET:%.*]] = alloca // CHECK: [[CLOSURE:%.*]] = call noalias %swift.refcounted* @swift_allocObject // CHECK: bitcast %swift.refcounted* [[CLOSURE]] to <{ %swift.refcounted, %T17indirect_argument4HugeV }>* -// CHECK: call swiftcc void @"$s30huge_partial_application_stretTA"(%T17indirect_argument4HugeV* noalias nocapture sret [[TMP_RET]], %T17indirect_argument4HugeV* noalias nocapture dereferenceable({{.*}}) %1, %swift.refcounted* swiftself [[CLOSURE]]) +// CHECK: call swiftcc {{.*}} @"$s30huge_partial_application_stretTA{{(\.ptrauth)?}}"{{.*}}(%T17indirect_argument4HugeV* noalias nocapture sret [[TMP_RET]], %T17indirect_argument4HugeV* noalias nocapture dereferenceable({{.*}}) %1, %swift.refcounted* swiftself [[CLOSURE]]) // CHECK: define internal swiftcc void @"$s30huge_partial_application_stretTA"(%T17indirect_argument4HugeV* noalias nocapture sret %0, %T17indirect_argument4HugeV* noalias nocapture dereferenceable({{.*}}) %1, %swift.refcounted* swiftself %2) // CHECK: [[TMP_ARG:%.*]] = alloca // CHECK-NOT: tail diff --git a/test/IRGen/keypaths.sil b/test/IRGen/keypaths.sil index 50f8778141b42..2b6b1eb24fbc1 100644 --- a/test/IRGen/keypaths.sil +++ b/test/IRGen/keypaths.sil @@ -172,7 +172,7 @@ sil_vtable C2 {} // -- computed, get-only, identified by (indirected) function pointer, no args // CHECK-SAME: , // CHECK-SAME: @{{got.|__imp_}}k_id -// CHECK-SAME: void (%TSi*, %T8keypaths1SV*)* @k_get +// CHECK-SAME: void (%TSi*, %T8keypaths1SV*)* {{.*}}@k_get{{.*}} // -- %l: computed // CHECK: [[KP_L:@keypath(\..*)?]] = private global <{ {{.*}} }> <{ @@ -185,7 +185,7 @@ sil_vtable C2 {} // CHECK-SAME: , // CHECK-SAME: @"$s8keypaths1CCMn" // CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_get -// CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_set +// CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_set{{.*}} // -- %m: computed // CHECK: [[KP_M:@keypath(\..*)?]] = private global <{ {{.*}} }> <{ @@ -197,8 +197,8 @@ sil_vtable C2 {} // -- computed, settable, nonmutating, identified by property offset, no args // CHECK-SAME: , // CHECK-SAME: [[WORD]] -// CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* @m_get -// CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* @m_set +// CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* {{.*}}@m_get +// CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* {{.*}}@m_set{{.*}} // -- %m2: reabstracted // Note: the contents here aren't interesting. The test triggered infinite @@ -338,8 +338,8 @@ entry: %k = keypath $KeyPath, (root $S; gettable_property $Int, id @k_id : $@convention(thin) () -> (), getter @k_get : $@convention(thin) (@in_guaranteed S) -> @out Int) %l = keypath $KeyPath, (root $C; settable_property $Int, id #C.w!getter.1, getter @l_get : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @l_set : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ()) - %m = keypath $KeyPath ()>, (root $S; settable_property $() -> (), id ##S.reabstracted, getter @m_get : $@convention(thin) (@in_guaranteed S) -> @out @callee_guaranteed in () -> @out A for <()>, setter @m_set : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out A for <()>, @inout S) -> ()) - %m2 = keypath $KeyPath ()>, (root $C2; settable_property $() -> (), id ##C2.reabstracted, getter @m2_get : $@convention(thin) (@in_guaranteed C2) -> @out @callee_guaranteed in () -> @out A for <()>, setter @m2_set : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out A for <()>, @inout C2) -> ()) + %m = keypath $KeyPath ()>, (root $S; settable_property $() -> (), id ##S.reabstracted, getter @m_get : $@convention(thin) (@in_guaranteed S) -> @out @callee_guaranteed @substituted () -> @out A for <()>, setter @m_set : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out A for <()>, @inout S) -> ()) + %m2 = keypath $KeyPath ()>, (root $C2; settable_property $() -> (), id ##C2.reabstracted, getter @m2_get : $@convention(thin) (@in_guaranteed C2) -> @out @callee_guaranteed @substituted () -> @out A for <()>, setter @m2_set : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out A for <()>, @inout C2) -> ()) // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_T0]] to i8*), i8* undef) %t0 = keypath $KeyPath, (root $T; stored_property #T.a : $(Int, String); tuple_element #0 : $Int) @@ -366,18 +366,18 @@ bb0(%0 : $*Int, %1 : $*C): unreachable } -sil @m_get : $@convention(thin) (@in_guaranteed S) -> @out @callee_guaranteed in () -> @out A for <()> { -bb0(%0 : $*@callee_guaranteed in () -> @out A for <()>, %1 : $*S): +sil @m_get : $@convention(thin) (@in_guaranteed S) -> @out @callee_guaranteed @substituted () -> @out A for <()> { +bb0(%0 : $*@callee_guaranteed @substituted () -> @out A for <()>, %1 : $*S): unreachable } -sil @m_set : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out A for <()>, @inout S) -> () { -bb0(%0 : $*@callee_guaranteed in () -> @out A for <()>, %1 : $*S): +sil @m_set : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out A for <()>, @inout S) -> () { +bb0(%0 : $*@callee_guaranteed @substituted () -> @out A for <()>, %1 : $*S): unreachable } -sil @m2_get : $@convention(thin) (@in_guaranteed C2) -> @out @callee_guaranteed in () -> @out A for <()> -sil @m2_set : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out A for <()>, @inout C2) -> () +sil @m2_get : $@convention(thin) (@in_guaranteed C2) -> @out @callee_guaranteed @substituted () -> @out A for <()> +sil @m2_set : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out A for <()>, @inout C2) -> () struct Gen { var x: T diff --git a/test/IRGen/lifetime.sil b/test/IRGen/lifetime.sil index 4e07ae0d912d8..e40bce795462e 100644 --- a/test/IRGen/lifetime.sil +++ b/test/IRGen/lifetime.sil @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -gnone -emit-ir %s | %FileCheck %s -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -gnone -emit-ir %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s -DINT=i%target-ptrsize // CHECK: [[OPAQUE:%swift.opaque]] = type opaque // CHECK: [[TYPE:%swift.type]] = type @@ -32,11 +32,15 @@ bb0(%x : $*T): // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align // CHECK-NEXT: [[INIT_WITH_COPY_FN:%.*]] = bitcast i8* [[T4]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[T3]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: [[Y:%.*]] = call [[OPAQUE]]* [[INIT_WITH_COPY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[OPAQUE]]* noalias [[X:%.*]], [[TYPE]]* %T) // Destroy 'y'. // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 1 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align // CHECK-NEXT: [[DESTROY_FN:%.*]] = bitcast i8* [[T4]] to void ([[OPAQUE]]*, [[TYPE]]*)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[T3]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call void [[DESTROY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[TYPE]]* %T) // Destroy 'x'. // CHECK-NEXT: call void [[DESTROY_FN]]([[OPAQUE]]* noalias [[X]], [[TYPE]]* %T) @@ -71,16 +75,22 @@ bb0(%x : $*T): // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align // CHECK-NEXT: [[INIT_WITH_COPY_FN:%.*]] = bitcast i8* [[T4]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[T3]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: [[Y:%.*]] = call [[OPAQUE]]* [[INIT_WITH_COPY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[OPAQUE]]* noalias [[X:%.*]], [[TYPE]]* %T) // Destroy 'y'. // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 1 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align // CHECK-NEXT: [[DESTROY_FN:%.*]] = bitcast i8* [[T4]] to void ([[OPAQUE]]*, [[TYPE]]*)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[T3]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call void [[DESTROY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[TYPE]]* %T) // Copy 'x' into 'y' again, this time as a take. // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4 // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align // CHECK-NEXT: [[TAKE_FN:%.*]] = bitcast i8* [[T4]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[T3]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call [[OPAQUE]]* [[TAKE_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[OPAQUE]]* noalias [[X]], [[TYPE]]* %T) // Destroy 'y'. // CHECK-NEXT: call void [[DESTROY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[TYPE]]* %T) diff --git a/test/IRGen/lowered_optional_self_metadata.sil b/test/IRGen/lowered_optional_self_metadata.sil index 99e33c0a18628..d8db59cd3a2d3 100644 --- a/test/IRGen/lowered_optional_self_metadata.sil +++ b/test/IRGen/lowered_optional_self_metadata.sil @@ -15,8 +15,8 @@ public protocol Protocol { sil @optional_method : $@convention(method) (@in_guaranteed Optional) -> () -sil @call_optional_method_with_lowered_function : $@convention(thin) (@in_guaranteed Optional<@callee_guaranteed in () -> @out T for <()>>) -> () { -entry(%x : $*Optional<@callee_guaranteed in () -> @out T for <()>>): +sil @call_optional_method_with_lowered_function : $@convention(thin) (@in_guaranteed Optional<@callee_guaranteed @substituted () -> @out T for <()>>) -> () { +entry(%x : $*Optional<@callee_guaranteed @substituted () -> @out T for <()>>): %f = function_ref @optional_method : $@convention(method) (@in_guaranteed Optional) -> () apply %f<() -> ()>(%x) : $@convention(method) (@in_guaranteed Optional) -> () %p = partial_apply [callee_guaranteed] %f<() -> ()>() : $@convention(method) (@in_guaranteed Optional) -> () diff --git a/test/IRGen/metadata.swift b/test/IRGen/metadata.swift index 73fd1b6bda8c6..f838c4e1f43b4 100644 --- a/test/IRGen/metadata.swift +++ b/test/IRGen/metadata.swift @@ -11,7 +11,7 @@ enum Singleton { // CHECK: @"$s1A1GC14zeroSizedFieldAA9SingletonOvpWvd" = hidden constant i{{(64|32)}} 0 // Check that the instance start is after the header (at 8 or 16). // CHECK-macosx: _DATA__TtC1A1G = private constant {{.*}} { i32 128, i32 {{(16|8)}} -// CHECK-ios: _DATA__TtC1A1G = private constant {{.*}} { i32 128, i32 {{(16|8)}} +// CHECK-ios: _DATA__TtC1A1G = private constant {{.*}} { i32 {{(128|129)}}, i32 {{(16|8|40)}} // CHECK-watchos: _DATA__TtC1A1G = private constant {{.*}} { i32 128, i32 {{(16|8)}} // CHECK-tvos: _DATA__TtC1A1G = private constant {{.*}} { i32 128, i32 {{(16|8)}} diff --git a/test/IRGen/mixed_mode_class_with_unimportable_fields.swift b/test/IRGen/mixed_mode_class_with_unimportable_fields.swift index dfd02d963228e..d66fa163abf84 100644 --- a/test/IRGen/mixed_mode_class_with_unimportable_fields.swift +++ b/test/IRGen/mixed_mode_class_with_unimportable_fields.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -o %t/UsingObjCStuff.swiftmodule -module-name UsingObjCStuff -I %t -I %S/Inputs/mixed_mode -swift-version 5 %S/Inputs/mixed_mode/UsingObjCStuff.swift -// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 4 %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-V4 -DWORD=i%target-ptrsize -// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 5 %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-V5 -DWORD=i%target-ptrsize +// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 4 %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-V4 -DWORD=i%target-ptrsize --check-prefix=CHECK-V4-STABLE-ABI-%target-mandates-stable-abi +// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 5 %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-V5 -DWORD=i%target-ptrsize --check-prefix=CHECK-V5-STABLE-ABI-%target-mandates-stable-abi // REQUIRES: objc_interop @@ -92,8 +92,10 @@ public func invokeMethod(on holder: SubButtHolder) { } // CHECK-V4-LABEL: define internal swiftcc %swift.metadata_response @"$s4main13SubButtHolderCMr"(%swift.type* %0, i8* %1, i8** %2) -// CHECK-V4: call swiftcc %swift.metadata_response @swift_initClassMetadata2( +// Under macCatalyst the deployment target is always >= 13 +// CHECK-V4-STABLE-ABI-TRUE: call swiftcc %swift.metadata_response @swift_updateClassMetadata2( +// CHECK-V4-STABLE-ABI-FALSE: call swiftcc %swift.metadata_response @swift_initClassMetadata2( // CHECK-V4-LABEL: define internal swiftcc %swift.metadata_response @"$s4main03SubB10ButtHolderCMr"(%swift.type* %0, i8* %1, i8** %2) -// CHECK-V4: call swiftcc %swift.metadata_response @swift_initClassMetadata2( - +// CHECK-V4-STABLE-ABI-TRUE: call swiftcc %swift.metadata_response @swift_updateClassMetadata2( +// CHECK-V4-STABLE-ABI-FALSE: call swiftcc %swift.metadata_response @swift_initClassMetadata2( diff --git a/test/IRGen/objc_int_encoding.sil b/test/IRGen/objc_int_encoding.sil index 538e4922d2d22..77d0ea80c3ffc 100644 --- a/test/IRGen/objc_int_encoding.sil +++ b/test/IRGen/objc_int_encoding.sil @@ -5,7 +5,7 @@ // CHECK-64: [[INT_UINT_METHOD_ENCODING:@.*]] = private unnamed_addr constant {{.*}} c"Q24@0:8q16\00" // CHECK-32: [[INT_UINT_METHOD_ENCODING:@.*]] = private unnamed_addr constant {{.*}} c"I12@0:4i8\00" -// CHECK: @_INSTANCE_METHODS__TtC17objc_int_encoding3Foo = private constant {{.*}} [[SELECTOR]], {{.*}} [[INT_UINT_METHOD_ENCODING]], {{.*}} @"$s17objc_int_encoding3FooC3foo1xSuSi_tFTo" +// CHECK: @_INSTANCE_METHODS__TtC17objc_int_encoding3Foo = private constant {{.*}} [[SELECTOR]], {{.*}} [[INT_UINT_METHOD_ENCODING]], {{.*}} @"$s17objc_int_encoding3FooC3foo1xSuSi_tFTo{{(\.ptrauth)?}}" sil_stage canonical diff --git a/test/IRGen/objc_simd.sil b/test/IRGen/objc_simd.sil index 1b243c2cd6e15..210094ed1f90b 100644 --- a/test/IRGen/objc_simd.sil +++ b/test/IRGen/objc_simd.sil @@ -17,6 +17,7 @@ func forceStuff(x: float4, y: float3) -> (Float, Float, Float, Float) { // i386-LABEL: define{{( dllexport)?}}{{( protected)?}} <2 x i64> @simd_c_args(<4 x float> %0) // aarch64-LABEL: define{{( dllexport)?}}{{( protected)?}} <4 x float> @simd_c_args(<4 x float> %0) // arm64-LABEL: define{{( dllexport)?}}{{( protected)?}} <4 x float> @simd_c_args(<4 x float> %0) +// arm64e-LABEL: define{{( dllexport)?}}{{( protected)?}} <4 x float> @simd_c_args(<4 x float> %0) // armv6-LABEL: define{{( dllexport)?}}{{( protected)?}} <4 x float> @simd_c_args(<4 x float> %0) // armv7-LABEL: define{{( dllexport)?}}{{( protected)?}} <4 x float> @simd_c_args(<4 x float> %0) // armv7s-LABEL: define{{( dllexport)?}}{{( protected)?}} <4 x float> @simd_c_args(<4 x float> %0) @@ -33,6 +34,7 @@ entry(%x : $float4): // i386-LABEL: define{{( dllexport)?}}{{( protected)?}} <2 x i64> @simd_c_args_float3(<3 x float> %0) // aarch64-LABEL: define{{( dllexport)?}}{{( protected)?}} <3 x float> @simd_c_args_float3(<4 x i32> %0) // arm64-LABEL: define{{( dllexport)?}}{{( protected)?}} <3 x float> @simd_c_args_float3(<4 x i32> %0) +// arm64e-LABEL: define{{( dllexport)?}}{{( protected)?}} <3 x float> @simd_c_args_float3(<4 x i32> %0) // armv6-LABEL: define{{( dllexport)?}}{{( protected)?}} <3 x float> @simd_c_args_float3(<4 x i32> %0) // armv7-ios-LABEL: define <3 x float> @simd_c_args_float3(<4 x i32> %0) // armv7-linux-LABEL: define protected <3 x float> @simd_c_args_float3(<4 x i32> %0) diff --git a/test/IRGen/objc_subclass.swift b/test/IRGen/objc_subclass.swift index 0f8063b6f1a18..bc317a21cc50b 100644 --- a/test/IRGen/objc_subclass.swift +++ b/test/IRGen/objc_subclass.swift @@ -68,47 +68,47 @@ // CHECK-32: [11 x { i8*, i8*, i8* }] [{ i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([2 x i8], [2 x i8]* @"\01L_selector_data(x)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[METHOD_TYPE_ENCODING1]], i32 0, i32 0), -// CHECK-32: i8* bitcast (i32 (%0*, i8*)* @"$s13objc_subclass10SwiftGizmoC1xSivgTo" to i8*) +// CHECK-32: i8* bitcast {{.*}}* @"$s13objc_subclass10SwiftGizmoC1xSivgTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(setX:)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([10 x i8], [10 x i8]* [[METHOD_TYPE_ENCODING2]], i32 0, i32 0), -// CHECK-32: i8* bitcast (void (%0*, i8*, i32)* @"$s13objc_subclass10SwiftGizmoC1xSivsTo" to i8*) +// CHECK-32: i8* bitcast {{.*}}* @"$s13objc_subclass10SwiftGizmoC1xSivsTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(getX)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[METHOD_TYPE_ENCODING1]], i32 0, i32 0), -// CHECK-32: i8* bitcast (i32 (%0*, i8*)* @"$s13objc_subclass10SwiftGizmoC4getXSiyFTo" to i8*) +// CHECK-32: i8* bitcast {{.*}}* @"$s13objc_subclass10SwiftGizmoC4getXSiyFTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([10 x i8], [10 x i8]* @"\01L_selector_data(duplicate)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[GETTER_ENCODING]], i32 0, i32 0), -// CHECK-32: i8* bitcast (%1* (%0*, i8*)* @"$s13objc_subclass10SwiftGizmoC9duplicateSo0D0CyFTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC9duplicateSo0D0CyFTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(init)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[GETTER_ENCODING]], i32 0, i32 0), -// CHECK-32: i8* bitcast (%0* (%0*, i8*)* @"$s13objc_subclass10SwiftGizmoCACycfcTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCACycfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([20 x i8], [20 x i8]* @"\01L_selector_data(initWithInt:string:)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[INIT_ENCODING]], i32 0, i32 0), -// CHECK-32: i8* bitcast (%0* (%0*, i8*, i32, %2*)* @"$s13objc_subclass10SwiftGizmoC3int6stringACSi_SStcfcTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC3int6stringACSi_SStcfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_selector_data(dealloc)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[DEALLOC_ENCODING]], i32 0, i32 0), -// CHECK-32: i8* bitcast (void (%0*, i8*)* @"$s13objc_subclass10SwiftGizmoCfDTo" to i8*) +// CHECK-32: i8* bitcast {{.*}}* @"$s13objc_subclass10SwiftGizmoCfDTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([10 x i8], [10 x i8]* @"\01L_selector_data(isEnabled)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* {{@[0-9]+}}, i32 0, i32 0), -// CHECK-32: i8* bitcast ({{(i8|i1)}} (%0*, i8*)* @"$s13objc_subclass10SwiftGizmoC7enabledSbvgTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC7enabledSbvgTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(setIsEnabled:)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([10 x i8], [10 x i8]* {{@[0-9]+}}, i32 0, i32 0), -// CHECK-32: i8* bitcast (void (%0*, i8*, {{(i8|i1)}})* @"$s13objc_subclass10SwiftGizmoC7enabledSbvsTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC7enabledSbvsTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([17 x i8], [17 x i8]* @"\01L_selector_data(initWithBellsOn:)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([10 x i8], [10 x i8]* {{@[0-9]+}}, i32 0, i32 0), -// CHECK-32: i8* bitcast (%0* (%0*, i8*, i32)* @"$s13objc_subclass10SwiftGizmoC7bellsOnACSgSi_tcfcTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC7bellsOnACSgSi_tcfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { i8*, i8*, i8* } { // CHECK-32: i8* getelementptr inbounds ([15 x i8], [15 x i8]* @"\01L_selector_data(.cxx_construct)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* {{@[0-9]+}}, i32 0, i32 0), -// CHECK-32: i8* bitcast (%0* (%0*, i8*)* @"$s13objc_subclass10SwiftGizmoCfeTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCfeTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }] // CHECK-32: }, section "__DATA, __objc_const", align 4 @@ -118,47 +118,47 @@ // CHECK-64: [11 x { i8*, i8*, i8* }] [{ // CHECK-64: i8* getelementptr inbounds ([2 x i8], [2 x i8]* @"\01L_selector_data(x)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[METHOD_TYPE_ENCODING1]], i64 0, i64 0) -// CHECK-64: i8* bitcast (i64 ([[OPAQUE2:%.*]]*, i8*)* @"$s13objc_subclass10SwiftGizmoC1xSivgTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC1xSivgTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(setX:)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[METHOD_TYPE_ENCODING2]], i64 0, i64 0) -// CHECK-64: i8* bitcast (void ([[OPAQUE3:%.*]]*, i8*, i64)* @"$s13objc_subclass10SwiftGizmoC1xSivsTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC1xSivsTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(getX)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[METHOD_TYPE_ENCODING1]], i64 0, i64 0) -// CHECK-64: i8* bitcast (i64 ([[OPAQUE2]]*, i8*)* @"$s13objc_subclass10SwiftGizmoC4getXSiyFTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC4getXSiyFTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([10 x i8], [10 x i8]* @"\01L_selector_data(duplicate)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[GETTER_ENCODING]], i64 0, i64 0), -// CHECK-64: i8* bitcast ([[OPAQUE1:.*]]* ([[OPAQUE0:%.*]]*, i8*)* @"$s13objc_subclass10SwiftGizmoC9duplicateSo0D0CyFTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC9duplicateSo0D0CyFTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(init)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[GETTER_ENCODING]], i64 0, i64 0), -// CHECK-64: i8* bitcast ([[OPAQUE5:.*]]* ([[OPAQUE6:.*]]*, i8*)* @"$s13objc_subclass10SwiftGizmoCACycfcTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCACycfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([20 x i8], [20 x i8]* @"\01L_selector_data(initWithInt:string:)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[INIT_ENCODING]], i64 0, i64 0), -// CHECK-64: i8* bitcast ([[OPAQUE7:%.*]]* ([[OPAQUE8:%.*]]*, i8*, i64, [[OPAQUEONE:.*]]*)* @"$s13objc_subclass10SwiftGizmoC3int6stringACSi_SStcfcTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC3int6stringACSi_SStcfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_selector_data(dealloc)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[DEALLOC_ENCODING]], i64 0, i64 0), -// CHECK-64: i8* bitcast (void ([[OPAQUE10:%.*]]*, i8*)* @"$s13objc_subclass10SwiftGizmoCfDTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCfDTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([10 x i8], [10 x i8]* @"\01L_selector_data(isEnabled)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* {{@[0-9]+}}, i64 0, i64 0), -// CHECK-64: i8* bitcast ({{(i8|i1)}} ([[OPAQUE11:%.*]]*, i8*)* @"$s13objc_subclass10SwiftGizmoC7enabledSbvgTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC7enabledSbvgTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(setIsEnabled:)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([11 x i8], [11 x i8]* {{@[0-9]+}}, i64 0, i64 0), -// CHECK-64: i8* bitcast (void ([[OPAQUE12:%.*]]*, i8*, {{(i8|i1)}})* @"$s13objc_subclass10SwiftGizmoC7enabledSbvsTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC7enabledSbvsTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([17 x i8], [17 x i8]* @"\01L_selector_data(initWithBellsOn:)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([11 x i8], [11 x i8]* {{@[0-9]+}}, i64 0, i64 0), -// CHECK-64: i8* bitcast ([[OPAQUE11:%.*]]* ([[OPAQUE12:%.*]]*, i8*, i64)* @"$s13objc_subclass10SwiftGizmoC7bellsOnACSgSi_tcfcTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoC7bellsOnACSgSi_tcfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([15 x i8], [15 x i8]* @"\01L_selector_data(.cxx_construct)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* {{@[0-9]+}}, i64 0, i64 0), -// CHECK-64: i8* bitcast ([[OPAQUE5]]* ([[OPAQUE6]]*, i8*)* @"$s13objc_subclass10SwiftGizmoCfeTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCfeTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }] // CHECK-64: }, section "__DATA, __objc_const", align 8 @@ -228,23 +228,23 @@ // CHECK-32: { // CHECK-32: i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_selector_data(sg)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[GETTER_ENCODING]], i32 0, i32 0), -// CHECK-32: i8* bitcast (%0* (%3*, i8*)* @"$s13objc_subclass11SwiftGizmo2C2sgAA0C5GizmoCvgTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2C2sgAA0C5GizmoCvgTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_selector_data(setSg:)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([10 x i8], [10 x i8]* [[SETTER_ENCODING]], i32 0, i32 0), -// CHECK-32: i8* bitcast (void (%3*, i8*, %0*)* @"$s13objc_subclass11SwiftGizmo2C2sgAA0C5GizmoCvsTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2C2sgAA0C5GizmoCvsTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { // CHECK-32: i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(init)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[GETTER_ENCODING]], i32 0, i32 0), -// CHECK-32: i8* bitcast (%3* (%3*, i8*)* @"$s13objc_subclass11SwiftGizmo2CACycfcTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2CACycfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { // CHECK-32: i8* getelementptr inbounds ([17 x i8], [17 x i8]* @"\01L_selector_data(initWithBellsOn:)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([10 x i8], [10 x i8]* {{@[0-9]+}}, i32 0, i32 0), -// CHECK-32: i8* bitcast (%3* (%3*, i8*, i32)* @"$s13objc_subclass11SwiftGizmo2C7bellsOnACSgSi_tcfcTo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2C7bellsOnACSgSi_tcfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }, { // CHECK-32: i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(.cxx_destruct)", i32 0, i32 0), // CHECK-32: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* {{@[0-9]+}}, i32 0, i32 0), -// CHECK-32: i8* bitcast (void (%3*, i8*)* @"$s13objc_subclass11SwiftGizmo2CfETo" to i8*) +// CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2CfETo{{(\.ptrauth)?}}" to i8*) // CHECK-32: } // CHECK-32: ] // CHECK-32: }, section "__DATA, __objc_const", align 4 @@ -256,23 +256,23 @@ // CHECK-64: { // CHECK-64: i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_selector_data(sg)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[GETTER_ENCODING]], i64 0, i64 0), -// CHECK-64: i8* bitcast ([[OPAQUE13:%.*]]* ([[OPAQUE14:%.*]]*, i8*)* @"$s13objc_subclass11SwiftGizmo2C2sgAA0C5GizmoCvgTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2C2sgAA0C5GizmoCvgTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_selector_data(setSg:)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[SETTER_ENCODING]], i64 0, i64 0), -// CHECK-64: i8* bitcast (void ([[OPAQUE15:%.*]]*, i8*, [[OPAQUE16:%.*]]*)* @"$s13objc_subclass11SwiftGizmo2C2sgAA0C5GizmoCvsTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2C2sgAA0C5GizmoCvsTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(init)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[GETTER_ENCODING]], i64 0, i64 0), -// CHECK-64: i8* bitcast ([[OPAQUE18:%.*]]* ([[OPAQUE19:%.*]]*, i8*)* @"$s13objc_subclass11SwiftGizmo2CACycfcTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2CACycfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([17 x i8], [17 x i8]* @"\01L_selector_data(initWithBellsOn:)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([11 x i8], [11 x i8]* {{@[0-9]+}}, i64 0, i64 0), -// CHECK-64: i8* bitcast ([[OPAQUE21:%.*]]* ([[OPAQUE22:%.*]]*, i8*, i64)* @"$s13objc_subclass11SwiftGizmo2C7bellsOnACSgSi_tcfcTo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2C7bellsOnACSgSi_tcfcTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }, { // CHECK-64: i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(.cxx_destruct)", i64 0, i64 0), // CHECK-64: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* {{@[0-9]+}}, i64 0, i64 0) -// CHECK-64: i8* bitcast (void ([[OPAQUE20:%.*]]*, i8*)* @"$s13objc_subclass11SwiftGizmo2CfETo" to i8*) +// CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2CfETo{{(\.ptrauth)?}}" to i8*) // CHECK-64: } // CHECK-64: ] } diff --git a/test/IRGen/opaque_values_irgen.sil b/test/IRGen/opaque_values_irgen.sil index 9fd5d5c12a9a7..5af2ca69eb851 100644 --- a/test/IRGen/opaque_values_irgen.sil +++ b/test/IRGen/opaque_values_irgen.sil @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -enable-sil-opaque-values -parse-stdlib -primary-file %s -emit-ir | %FileCheck %s +// RUN: %target-swift-frontend -enable-sil-opaque-values -parse-stdlib -primary-file %s -emit-ir | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s import Builtin @@ -7,6 +7,8 @@ sil_stage canonical // CHECK: define hidden swiftcc void @f010_irgen_identity(%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture %1, %swift.type* %T) // CHECK: entry: // CHECK-NOT: call +// CHECK-arm64e: call i64 @llvm.ptrauth.blend.i64 +// CHECK-NOT: call // CHECK: %{{.*}} = call %swift.opaque* %initializeWithTake(%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* %T) // CHECK-NOT: call // CHECK: ret void diff --git a/test/IRGen/optional_metatype.sil b/test/IRGen/optional_metatype.sil index 25348e464cd74..17c8aaa931365 100644 --- a/test/IRGen/optional_metatype.sil +++ b/test/IRGen/optional_metatype.sil @@ -14,6 +14,8 @@ import gizmo // i386: icmp eq i32 %0, 0 // arm64-LABEL: define{{( protected)?}} swiftcc void @optional_objc_metatype(i64 %0) // arm64: icmp eq i64 %0, 0 +// arm64e-LABEL: define{{( protected)?}} swiftcc void @optional_objc_metatype(i64 %0) +// arm64e: icmp eq i64 %0, 0 // armv7-LABEL: define{{( protected)?}} swiftcc void @optional_objc_metatype(i32 %0) // armv7: icmp eq i32 %0, 0 // armv7s-LABEL: define{{( protected)?}} swiftcc void @optional_objc_metatype(i32 %0) @@ -38,6 +40,8 @@ cont: // i386: icmp eq i32 %0, 0 // arm64-LABEL: define{{( protected)?}} swiftcc void @optional_swift_metatype(i64 %0) // arm64: icmp eq i64 %0, 0 +// arm64e-LABEL: define{{( protected)?}} swiftcc void @optional_swift_metatype(i64 %0) +// arm64e: icmp eq i64 %0, 0 // armv7-LABEL: define{{( protected)?}} swiftcc void @optional_swift_metatype(i32 %0) // armv7: icmp eq i32 %0, 0 // armv7s-LABEL: define{{( protected)?}} swiftcc void @optional_swift_metatype(i32 %0) diff --git a/test/IRGen/partial_apply_forwarder.sil b/test/IRGen/partial_apply_forwarder.sil index 08fc35adcbbc6..233b243eccca1 100644 --- a/test/IRGen/partial_apply_forwarder.sil +++ b/test/IRGen/partial_apply_forwarder.sil @@ -87,7 +87,7 @@ sil hidden_external @takingEmptyAndQ : $@convention(thin) <τ_0_0 where τ_0_0 // CHECK: [[OBJ:%.*]] = call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[WEAKBOXTYPE]] // CHECK: [[WB:%.*]] = bitcast %swift.refcounted* [[OBJ]] to %T23partial_apply_forwarder7WeakBoxC* // CHECK: [[REF:%.*]] = bitcast %T23partial_apply_forwarder7WeakBoxC* [[WB]] to %swift.refcounted* -// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (%swift.refcounted*)* @"$s7takingQTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[REF]], 1 +// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast ({{.*}}* @"$s7takingQTA{{(\.ptrauth)?}}" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[REF]], 1 // CHECK: ret { i8*, %swift.refcounted* } [[CLOSURE]] // CHECK-LABEL: define internal swiftcc void @"$s7takingQTA"(%swift.refcounted* swiftself %0) @@ -115,7 +115,7 @@ bb0(%0 : $*τ_0_1): // CHECK: [[OBJ:%.*]] = call {{.*}} @swift_allocObject // CHECK: [[WB:%.*]] = bitcast %swift.refcounted* [[OBJ]] // CHECK: [[REF:%.*]] = bitcast {{.*}}* [[WB]] to %swift.refcounted* -// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (%swift.refcounted*)* @"$s15takingQAndEmptyTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[REF]], 1 +// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast ({{.*}}* @"$s15takingQAndEmptyTA{{(\.ptrauth)?}}" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[REF]], 1 // CHECK: } sil public @bind_polymorphic_param_from_context_2 : $@convention(thin) <τ_0_1>(@in τ_0_1, EmptyType) -> @owned @callee_owned () -> () { bb0(%0 : $*τ_0_1, %2: $EmptyType): @@ -129,7 +129,7 @@ bb0(%0 : $*τ_0_1, %2: $EmptyType): // CHECK: [[OBJ:%.*]] = call {{.*}} @swift_allocObject // CHECK: [[WB:%.*]] = bitcast %swift.refcounted* [[OBJ]] // CHECK: [[REF:%.*]] = bitcast {{.*}}* [[WB]] to %swift.refcounted* -// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (%swift.refcounted*)* @"$s15takingEmptyAndQTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[REF]], 1 +// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast ({{.*}}* @"$s15takingEmptyAndQTA{{(\.ptrauth)?}}" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[REF]], 1 // CHECK: } sil public @bind_polymorphic_param_from_context_3 : $@convention(thin) <τ_0_1>(@in τ_0_1, EmptyType) -> @owned @callee_owned () -> () { @@ -176,7 +176,7 @@ struct S { sil hidden_external @takingQAndS : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (S, @owned WeakBox<τ_0_0>) -> () -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i8*, %swift.refcounted* } @bind_polymorphic_param_from_context_with_layout(%swift.opaque* noalias nocapture %0, i64 %1, %swift.type* %"\CF\84_0_1") +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc {{.*}} @bind_polymorphic_param_from_context_with_layout(%swift.opaque* noalias nocapture %0, i64 %1, %swift.type* %"\CF\84_0_1") // CHECK: entry: // CHECK: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$s23partial_apply_forwarder12BaseProducerVMa"([[INT]] 255, %swift.type* %"\CF\84_0_1") // CHECK: [[BPTY:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0 @@ -191,7 +191,7 @@ sil hidden_external @takingQAndS : $@convention(thin) <τ_0_0 where τ_0_0 : Q> // CHECK: store i64 %1, i64* [[XADDR]] // CHECK: [[WBADDR:%.*]] = getelementptr inbounds <{ %swift.refcounted,{{.*}} %T23partial_apply_forwarder1SV, %T23partial_apply_forwarder7WeakBoxC* }>, <{ %swift.refcounted,{{.*}} %T23partial_apply_forwarder1SV, %T23partial_apply_forwarder7WeakBoxC* }>* [[CONTEXT]], i32 0, i32 {{(2|3)}} // CHECK: store %T23partial_apply_forwarder7WeakBoxC* [[WB]], %T23partial_apply_forwarder7WeakBoxC** [[WBADDR]] -// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (%swift.refcounted*)* @"$s11takingQAndSTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[CONTEXT0]], 1 +// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast ({{.*}}* @"$s11takingQAndSTA{{(\.ptrauth)?}}" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[CONTEXT0]], 1 // CHECK: ret { i8*, %swift.refcounted* } [[CLOSURE]] // CHECK-LABEL: define internal swiftcc void @"$s11takingQAndSTA"(%swift.refcounted* swiftself %0) @@ -213,7 +213,6 @@ sil hidden_external @takingQAndS : $@convention(thin) <τ_0_0 where τ_0_0 : Q> // CHECK: %"BaseProducer<\CF\84_0_1>" = load %swift.type*, %swift.type** [[GENPARAMADDR]] // CHECK: [[WITNESS:%.*]] = call i8** @swift_getWitnessTable // CHECK: tail call swiftcc void @takingQAndS(i64 [[X]], %T23partial_apply_forwarder7WeakBoxC.1* %.asUnsubstituted, i8** [[WITNESS]]) - sil public @bind_polymorphic_param_from_context_with_layout : $@convention(thin) <τ_0_1>(@in τ_0_1, S) -> @owned @callee_owned () -> () { bb0(%0 : $*τ_0_1, %1: $S): %2 = alloc_ref $WeakBox> @@ -246,7 +245,7 @@ bb0: // CHECK-LABEL: define hidden swiftcc { i8*, %swift.refcounted* } @specializes_closure_returning_closure() #0 { // CHECK: entry: -// CHECK: ret { i8*, %swift.refcounted* } { i8* bitcast ({ %{{.*}}Empty{{.*}}*, i8*, %swift.refcounted* } (%{{.*}}Empty{{.*}}*, %swift.refcounted*)* @"{{.*}}returns_closure{{.*}}" to i8*), %swift.refcounted* null } +// CHECK: ret { i8*, %swift.refcounted* } { i8* bitcast ({{.*}} @"{{.*}}returns_closure{{.*}}" to i8*), %swift.refcounted* null } protocol MyEquatable { static func isEqual (lhs: Self, rhs: Self) -> Builtin.Int1 diff --git a/test/IRGen/pic.swift b/test/IRGen/pic.swift index 2670f87328179..8afc50ec49846 100644 --- a/test/IRGen/pic.swift +++ b/test/IRGen/pic.swift @@ -80,6 +80,12 @@ public func use_global() -> Int { // aarch64: bl swift_endAccess // aarch64: ldr x0, [sp] +// arm64e-LABEL: _$s4main10use_globalSiyF: +// arm64e: adrp [[REG1:x[0-9]+]], _$s4main6globalSivp@PAGE +// arm64e: add [[REG1]], [[REG1]], _$s4main6globalSivp@PAGEOFF +// arm64e: bl _swift_beginAccess +// arm64e: ldr {{x[0-9]+}}, {{\[}}[[REG1]]{{\]}} + // powerpc64le-LABEL: {{_?}}$s4main10use_globalSiyF: // powerpc64le: bl swift_beginAccess // powerpc64le: addi 3, 3, ($s4main6globalSivp)@toc@l diff --git a/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift index 968a3a3552386..189efc4770b1d 100644 --- a/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift @@ -14,7 +14,7 @@ // CHECK-SAME: }> <{ // i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5Value[[UNIQUE_ID_1]]OySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5Value[[UNIQUE_ID_1]]OMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.*}}$s4main5Value[[UNIQUE_ID_1]]OMn{{.*}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i64 3 // CHECK-SAME: }>, align [[ALIGNMENT]] @@ -83,6 +83,14 @@ doit() // CHECK-SAME: [[INT]] 0 // CHECK-SAME: } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5Value[[UNIQUE_ID_1]]OMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( +// CHECK-SAME: [[INT]] %0, +// CHECK-SAME: i8* [[ERASED_TYPE]], +// CHECK-SAME: i8* undef, +// CHECK-SAME: i8* undef, +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5Value[[UNIQUE_ID_1]]OMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) +// CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift index 18b485ad8699f..edc2e5c2fa271 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift @@ -18,7 +18,7 @@ // i32 0 // ), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main9NamespaceC5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.*}}$s4main9NamespaceC5ValueOMn{{.*}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i64 3 // CHECK-SAME: }>, align [[ALIGNMENT]] @@ -90,6 +90,14 @@ doit() // CHECK-SAME: [[INT]] 0 // CHECK-SAME: } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main9NamespaceC5ValueOMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( +// CHECK-SAME: [[INT]] %0, +// CHECK-SAME: i8* [[ERASED_TYPE_1]], +// CHECK-SAME: i8* undef, +// CHECK-SAME: i8* undef, +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main9NamespaceC5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) +// CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-0distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-0distinct_use.swift index 82edee93c8373..10cd548bd85e1 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-0distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-0distinct_use.swift @@ -31,9 +31,7 @@ doit() // CHECK-SAME: i8* undef, // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main5ValueOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift index a529c4736f79e..129e4e580ea9b 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift @@ -17,7 +17,9 @@ // CHECK-SAME: }> <{ // CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5ValueOySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1PAAWP", i32 0, i32 0), // CHECK-SAME: i64 3 @@ -92,6 +94,14 @@ doit() // CHECK-SAME: [[INT]] 0 // CHECK-SAME: } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*)) +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( +// CHECK-SAME: [[INT]] %0, +// CHECK-SAME: i8* [[ERASED_TYPE]], +// CHECK-SAME: i8* [[ERASED_TABLE]], +// CHECK-SAME: i8* undef, +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) +// CHECK-SAME: ) // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-external_nonresilient-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-external_nonresilient-1distinct_use.swift index 4549e0944fb28..b01eaee58d60b 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-external_nonresilient-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-external_nonresilient-1distinct_use.swift @@ -65,7 +65,9 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE]], // CHECK-SAME: i8* [[ERASED_TABLE]], // CHECK-SAME: i8* undef, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) // CHECK-SAME: ) // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-external_resilient-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-external_resilient-1distinct_use.swift index 1a55065719c32..941e5195b3471 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-external_resilient-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-external_resilient-1distinct_use.swift @@ -51,7 +51,9 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE]], // CHECK-SAME: i8* [[ERASED_TABLE]], // CHECK-SAME: i8* undef, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) // CHECK-SAME: ) // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift index 8a0c9f27ac343..de96de5c8537c 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift @@ -17,7 +17,9 @@ // CHECK-SAME: }> <{ // CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5ValueOySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1PAAWP", i32 0, i32 0), // CHECK-SAME: i64 3 @@ -92,6 +94,14 @@ doit() // CHECK-SAME: [[INT]] 0 // CHECK-SAME: } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*)) +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( +// CHECK-SAME: [[INT]] %0, +// CHECK-SAME: i8* [[ERASED_TYPE]], +// CHECK-SAME: i8* [[ERASED_TABLE]], +// CHECK-SAME: i8* undef, +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) +// CHECK-SAME: ) // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-stdlib_equatable-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-stdlib_equatable-1distinct_use.swift index e753fad55a3b6..8d395f11186d9 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-stdlib_equatable-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-stdlib_equatable-1distinct_use.swift @@ -36,8 +36,7 @@ doit() // CHECK-SAME: i8* [[ERASED_CONFORMANCE]], // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_generic_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_generic_use.swift index 4469578b00cd5..a991e4041c361 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_generic_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_generic_use.swift @@ -21,8 +21,7 @@ // CHECK-SAME: ), // CHECK-SAME: [[INT]] 513, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5OuterOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main5OuterOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ), // CHECK-SAME: %swift.type* getelementptr inbounds ( // CHECK-SAME: %swift.full_type, @@ -92,9 +91,7 @@ doit() // CHECK-SAME: i8* undef, // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main5OuterOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main5OuterOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift index 1c301b39dc4c1..f3b9bf1e8c802 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift @@ -6,20 +6,21 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueOySiGWV" = linkonce_odr hidden constant %swift.enum_vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOySiGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueOySiGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|[^@]+@__swift_memcpy[0-9]+_[0-9]+[^\)]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_noop_void_return{{[^\)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOySiGwet{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOySiGwst{{[^)]+}} to i8*), // CHECK-SAME: [[INT]] [[ALIGNMENT]], // CHECK-SAME: [[INT]] [[ALIGNMENT]], // CHECK-SAME: i32 {{[0-9]+}}, -// CHECK-SAME: i32 0, i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4main5ValueOySiGwug" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueOySiGwup" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOySiGwui" to i8*) +// CHECK-SAME: i32 0, +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOySiGwug{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOySiGwup{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOySiGwui{{[^)]+}} to i8*) // CHECK-SAME: }, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueOySiGMf" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, @@ -30,7 +31,9 @@ // CHECK-SAME: }> <{ // CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5ValueOySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i64 3 // CHECK-SAME: }>, align [[ALIGNMENT]] @@ -72,7 +75,9 @@ doit() // CHECK-SAME: i8* %2, // CHECK-SAME: i8* undef, // CHECK-SAME: i8* undef, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift index df2c791959058..97411bb9e3a8d 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift @@ -16,9 +16,7 @@ // i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main9NamespaceC5ValueOySS_SiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceC5ValueOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceC5ValueOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSSN", // CHECK-SAME: %swift.type* @"$sSiN", @@ -102,9 +100,7 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE_2]], // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceC5ValueOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceC5ValueOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift index b645be1bd5c60..16d18ceb2d919 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift @@ -16,9 +16,7 @@ // i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main9NamespaceO5ValueOySS_SiGWV", i32 0, i32 0) // CHECK-SAME: [[INT]] 513, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceO5ValueOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceO5ValueOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSSN", // CHECK-SAME: %swift.type* @"$sSiN", @@ -102,9 +100,7 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE_2]], // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceO5ValueOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceO5ValueOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift index c8ef86825afac..a94543fd86e22 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift @@ -16,9 +16,7 @@ // i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main9NamespaceV5ValueOySS_SiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceV5ValueOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceV5ValueOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSSN", // CHECK-SAME: %swift.type* @"$sSiN", @@ -101,9 +99,7 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE_2]], // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceV5ValueOMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceV5ValueOMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift index 45df509cdf9a9..3e84bbf699608 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift @@ -6,21 +6,21 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueOyS2iGWV" = linkonce_odr hidden constant %swift.enum_vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOyS2iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueOyS2iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|[^@]+@__swift_memcpy[0-9]+_[0-9]+[^\)]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_noop_void_return{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS2iGwet{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS2iGwst{{[^)]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4main5ValueOyS2iGwug" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueOyS2iGwup" to i8*), -// CHECK-SAME i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOyS2iGwui" to i8*) +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS2iGwug{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS2iGwup{{[^)]+}} to i8*), +// CHECK-SAME i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS2iGwui{{[^)]+}} to i8*) // CHECK-SAME: }, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueOyS2iGMf" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, @@ -31,7 +31,9 @@ // CHECK-SAME: }> <{ // CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5ValueOyS2iGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: [[INT]] {{16|8}}, @@ -108,11 +110,13 @@ doit() // CHECK-SAME: } // CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( -// CHECK-SAME: [[INT]] %0, -// CHECK-SAME: i8* [[ERASED_TYPE_1]], -// CHECK-SAME: i8* [[ERASED_TYPE_2]], -// CHECK-SAME: i8* undef, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) -// CHECK-SAME: ) #{{[0-9]+}} +// CHECK-SAME: [[INT]] %0, +// CHECK-SAME: i8* [[ERASED_TYPE_1]], +// CHECK-SAME: i8* [[ERASED_TYPE_2]], +// CHECK-SAME: i8* undef, +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) +// CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift index 8a7129e0db46d..f934d9f75d0a1 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift @@ -6,21 +6,21 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueOyS3iGWV" = linkonce_odr hidden constant %swift.enum_vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOyS3iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueOyS3iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{([^@]+@"\$s4main5ValueOyS3iGwCP[^\)]+ to i8\*|[^@]+@__swift_memcpy[0-9]+_[0-9]+[^\)]+ to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_noop_void_return{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS3iGwet{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS3iGwst{{[^)]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4main5ValueOyS3iGwug" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueOyS3iGwup" to i8*), -// CHECK-SAME i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOyS3iGwui" to i8*) +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS3iGwug{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS3iGwup{{[^)]+}} to i8*), +// CHECK-SAME i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS3iGwui{{[^)]+}} to i8*) // CHECK-SAME: }, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueOyS3iGMf" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, @@ -31,7 +31,9 @@ // CHECK-SAME: }> <{ // CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5ValueOyS3iGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: %swift.type* @"$sSiN", @@ -117,11 +119,13 @@ doit() // CHECK-SAME: } // CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( -// CHECK-SAME: [[INT]] %0, -// CHECK-SAME: i8* [[ERASED_TYPE_1]], -// CHECK-SAME: i8* [[ERASED_TYPE_2]], -// CHECK-SAME: i8* [[ERASED_TYPE_3]], -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) -// CHECK-SAME: ) #{{[0-9]+}} +// CHECK-SAME: [[INT]] %0, +// CHECK-SAME: i8* [[ERASED_TYPE_1]], +// CHECK-SAME: i8* [[ERASED_TYPE_2]], +// CHECK-SAME: i8* [[ERASED_TYPE_3]], +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) +// CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift index fe4c6bd8c9b71..8f1bdc4aa4aaf 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift @@ -6,21 +6,21 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueOyS4iGWV" = linkonce_odr hidden constant %swift.enum_vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOyS4iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueOyS4iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{([^@]+@"\$s4main5ValueOyS4iGwCP+[^\)]+ to i8\*|[^@]+@__swift_memcpy[0-9]+_[0-9]+[^\)]+ to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_noop_void_return{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS4iGwet{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS4iGwst{{[^)]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4main5ValueOyS4iGwug" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueOyS4iGwup" to i8*), -// CHECK-SAME i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOyS4iGwui" to i8*) +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS4iGwug{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS4iGwup{{[^)]+}} to i8*), +// CHECK-SAME i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS4iGwui{{[^)]+}} to i8*) // CHECK-SAME: }, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueOyS4iGMf" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, @@ -31,7 +31,9 @@ // CHECK-SAME: }> <{ // CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5ValueOyS4iGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: %swift.type* @"$sSiN", @@ -129,9 +131,11 @@ doit() // CHECK-SAME: } // CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata( -// CHECK-SAME: [[INT]] %0, -// CHECK-SAME: i8* [[ERASED_BUFFER]], -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) -// CHECK-SAME: ) #{{[0-9]+}} +// CHECK-SAME: [[INT]] %0, +// CHECK-SAME: i8* [[ERASED_BUFFER]], +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) +// CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift index a7c85109fc715..72fce0915a4fd 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift @@ -6,21 +6,21 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueOyS5iGWV" = linkonce_odr hidden constant %swift.enum_vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOyS5iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueOyS5iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{([^@]+@"\$s4main5ValueOyS5iGwCP+[^\)]+ to i8\*|[^@]+@__swift_memcpy[0-9]+_[0-9]+[^)]+ to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_noop_void_return{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[0-9]+}}_{{[0-9]+}}{{[^)]*}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS5iGwet{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS5iGwst{{[^)]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4main5ValueOyS5iGwug" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueOyS5iGwup" to i8*), -// CHECK-SAME i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueOyS5iGwui" to i8*) +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS5iGwug{{[^)]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS5iGwup{{[^)]+}} to i8*), +// CHECK-SAME i8* bitcast ({{[^@]+}}@"$s4main5ValueOyS5iGwui{{[^)]+}} to i8*) // CHECK-SAME: }, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueOyS5iGMf" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, @@ -31,7 +31,9 @@ // CHECK-SAME: }> <{ // CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5ValueOyS5iGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: [[INT]] {{40|20}}, // CHECK-SAME: i64 3 @@ -133,9 +135,11 @@ doit() // CHECK-SAME: } // CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata( -// CHECK-SAME: [[INT]] %0, -// CHECK-SAME: i8* [[ERASED_BUFFER]], -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) -// CHECK-SAME: ) #{{[0-9]+}} +// CHECK-SAME: [[INT]] %0, +// CHECK-SAME: i8* [[ERASED_BUFFER]], +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) +// CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift index 12c1cf5390ad2..acaf0cff5542f 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift @@ -20,7 +20,9 @@ import TestModule // CHECK-SAME: <{ // CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s4main5ValueOy10TestModule7IntegerVGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 513, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$s10TestModule7IntegerVN", // CHECK-SAME: i64 3 // CHECK-SAME: }>, align [[ALIGNMENT]] @@ -94,7 +96,9 @@ doit() // CHECK-SAME: i8* %2, // CHECK-SAME: i8* undef, // CHECK-SAME: i8* undef, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-nonfrozen.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-nonfrozen.swift index 984cdc68d569a..e3413fa9736d4 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-nonfrozen.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-nonfrozen.swift @@ -42,7 +42,9 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE]], // CHECK-SAME: i8* undef, // CHECK-SAME: i8* undef, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueOMn" to %swift.type_descriptor*) +// CHECK-SAME: %swift.type_descriptor* bitcast ( +// CHECK-SAME: {{.*}}$s4main5ValueOMn{{.*}} to %swift.type_descriptor* +// CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift index da010db18e5dd..ba6d6e172b0d8 100644 --- a/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift @@ -16,7 +16,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5Value33_BD97D79156BC586FAA2AE8FB32F3D812LLVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5Value[[UNIQUE_ID_1:[0-9A-Z_]+]]VMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5Value[[UNIQUE_ID_1:[0-9A-Z_]+]]VMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -52,6 +52,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5Value[[UNIQUE_ID_1]]VySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5Value[[UNIQUE_ID_1]]VMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5Value[[UNIQUE_ID_1]]VMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift index bcb6e153a18e7..c977ff866059f 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift @@ -15,7 +15,7 @@ // i8** @"$sB[[INT]]_WV", // getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main9NamespaceC5ValueVySi_GWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main9NamespaceC5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -54,6 +54,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_1]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main9NamespaceC5ValueVySi_GMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main9NamespaceC5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-0distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-0distinct_use.swift index 39213abad8591..43c1694f983b3 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-0distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-0distinct_use.swift @@ -25,6 +25,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift index d15fd7d0fe00a..4b904ed09cc01 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift @@ -19,7 +19,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1PAAWP", i32 0, i32 0), // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, @@ -59,6 +59,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-stdlib_equatable-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-stdlib_equatable-1distinct_use.swift index ac49ffcb3bee5..81e9ef5b5c96a 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-stdlib_equatable-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-stdlib_equatable-1distinct_use.swift @@ -30,6 +30,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_CONFORMANCE:%[0-9]+]] = bitcast i8** %2 to i8* -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_CONFORMANCE]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_CONFORMANCE]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift index 2e84778e287cc..174353f07fc17 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift @@ -107,9 +107,7 @@ doit() // CHECK-SAME: i8* undef, // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main5OuterVMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.+}}$s4main5OuterVMn{{.+}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} @@ -152,9 +150,7 @@ doit() // CHECK-SAME: i8* undef, // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main5InnerVMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.+}}$s4main5InnerVMn{{.+}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift index 22042edc3e72a..4fe989575ef83 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift @@ -16,7 +16,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -52,6 +52,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift index 4ea756bc704c2..15874f76018ff 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift @@ -20,7 +20,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1PAAWP", i32 0, i32 0), // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1QAAWP", i32 0, i32 0), @@ -64,6 +64,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE_1]], i8* [[ERASED_TABLE_2]], %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE_1]], i8* [[ERASED_TABLE_2]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift index f0e1320e98c38..604f867e7efb0 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift @@ -16,7 +16,7 @@ // i8** @"$sBi64_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdGWV", i32 0, i32 0), // CHECk-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSdN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -33,7 +33,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -77,6 +77,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_2]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift index ae717f872767c..9b0790f395684 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift @@ -21,7 +21,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1PAAWP", i32 0, i32 0), // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1QAAWP", i32 0, i32 0), @@ -68,6 +68,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift index 35f14e1eb5e7f..3e3c890e24d46 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift @@ -6,14 +6,14 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueVySSGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast (%swift.opaque* ([{{[0-9]+}} x i8]*, [{{[0-9]+}} x i8]*, %swift.type*)* @"$s4main5ValueVySSGwCP" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueVySSGwxx" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSGwcp" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSGwca" to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_[[ALIGNMENT]] to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSGwta" to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySSGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySSGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSGwCP{{[^@]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSGwxx{{[^@]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSGwcp{{[^@]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSGwca{{[^@]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSGwta{{[^@]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSGwet{{[^@]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSGwst{{[^@]* to i8\*}}), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -22,7 +22,7 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySSGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySSGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSSN", i32 0{{(, \[4 x i8\] zeroinitializer)?}}, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySSGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSSN", i32 0{{(, \[4 x i8\] zeroinitializer)?}}, i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySdGMf" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, @@ -35,7 +35,7 @@ // i8** @"$sBi64_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSdN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -52,7 +52,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -104,6 +104,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_3]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift index bf5aa4c372939..64632a842a242 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift @@ -22,7 +22,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1PAAWP", i32 0, i32 0), // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1QAAWP", i32 0, i32 0), @@ -72,6 +72,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift index f96ebe6de3006..80e50226d64bf 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift @@ -16,13 +16,13 @@ // i8** @"$sBi8_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVys5UInt8VGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$ss5UInt8VN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 // CHECK-SAME: }>, align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySSGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySSGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSSN", i32 0{{(, \[4 x i8\] zeroinitializer)?}}, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySSGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSSN", i32 0{{(, \[4 x i8\] zeroinitializer)?}}, i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySdGMf" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, @@ -35,7 +35,7 @@ // i8** @"$sBi64_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSdN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -52,7 +52,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECk-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -111,6 +111,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_4]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVys5UInt8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift index dcfb2d298f367..ff974470aa1a3 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift @@ -23,7 +23,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0) // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1PAAWP", i32 0, i32 0), // CHECK-SAME: i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1QAAWP", i32 0, i32 0), @@ -76,6 +76,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift index f284e9f4092a2..365fd0fb65d4e 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift @@ -17,7 +17,7 @@ // i8** @"$sBi8_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVys4Int8VGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$ss4Int8VN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -34,21 +34,21 @@ // i8** @"$sBi8_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVys5UInt8VGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$ss5UInt8VN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 // CHECK-SAME: }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySSGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast (%swift.opaque* ([{{[0-9]+}} x i8]*, [{{[0-9]+}} x i8]*, %swift.type*)* @"$s4main5ValueVySSGwCP" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueVySSGwxx" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSGwcp" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSGwca" to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_[[ALIGNMENT]] to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSGwta" to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySSGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySSGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{.+}}$s4main5ValueVySSGwCP{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSGwxx{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSGwcp{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSGwca{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSGwta{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSGwet{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSGwst{{[^[:space:]]+ to i8\*}}), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -57,7 +57,7 @@ // NOTE: ignore COMDAT on PE/COFF target // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySSGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySSGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSSN", i32 0{{(, \[4 x i8\] zeroinitializer)?}}, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySSGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSSN", i32 0{{(, \[4 x i8\] zeroinitializer)?}}, i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySdGMf" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, @@ -70,7 +70,7 @@ // i8** @"$sBi64_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSdN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -87,7 +87,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -155,6 +155,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_5]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVys4Int8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-clang_node-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-clang_node-1distinct_use.swift index 4e3557f23a6f4..6ecb89750a045 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-clang_node-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-clang_node-1distinct_use.swift @@ -38,6 +38,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift index de7ad60859204..e9a4f074aedf8 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift @@ -18,9 +18,7 @@ // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main9NamespaceC5ValueVySS_SiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceC5ValueVMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceC5ValueVMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSSN", // CHECK-SAME: %swift.type* @"$sSiN", @@ -107,9 +105,7 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE_2]], // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceC5ValueVMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift index 56bf17447aba0..2c4b5d76c63dc 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift @@ -18,9 +18,7 @@ // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main9NamespaceO5ValueVySS_SiGWV", i32 0, i32 0) // CHECK-SAME: [[INT]] 512, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceO5ValueVMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceO5ValueVMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSSN", // CHECK-SAME: %swift.type* @"$sSiN", @@ -107,9 +105,7 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE_2]], // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceO5ValueVMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.+}}$s4main9NamespaceO5ValueVMn{{.+}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift index b9cbdd876d37b..f2cdb53ab20cc 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift @@ -18,9 +18,7 @@ // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main9NamespaceV5ValueVySS_SiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceV5ValueVMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.*}}$s4main9NamespaceV5ValueVMn{{.*}} to %swift.type_descriptor* // CHECK-SAME: ), // CHECK-SAME: %swift.type* @"$sSSN", // CHECK-SAME: %swift.type* @"$sSiN", @@ -106,9 +104,7 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE_2]], // CHECK-SAME: i8* undef, // CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* -// CHECK-SAME: @"$s4main9NamespaceV5ValueVMn" -// CHECK-SAME: to %swift.type_descriptor* +// CHECK-SAME: {{.+}}$s4main9NamespaceV5ValueVMn{{.+}} to %swift.type_descriptor* // CHECK-SAME: ) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift index 48c394a732c59..5895295b7b6ee 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift @@ -22,11 +22,7 @@ // i32 0 // ), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* -// CHECK-SAME: @"$s4main9NamespaceVAAq_RszrlE5ValueVMn" -// CHECK-SAME: to %swift.type_descriptor* -// CHECK-SAME: ), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.*}}), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: %swift.type* @"$sSSN", // CHECK-SAME: i32 0, @@ -116,11 +112,7 @@ doit() // CHECK-SAME: i8* [[ERASED_TYPE_1]], // CHECK-SAME: i8* [[ERASED_TYPE_2]], // CHECK-SAME: i8* undef, -// CHECK-SAME: %swift.type_descriptor* bitcast ( -// CHECK-SAME: <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* -// CHECK-SAME: @"$s4main9NamespaceVAAq_RszrlE5ValueVMn" -// CHECK-SAME: to %swift.type_descriptor* -// CHECK-SAME: ) +// CHECK-SAME: %swift.type_descriptor* bitcast ({{[^)]*}}) // CHECK-SAME: ) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-0distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-0distinct_use.swift index a49b247524cff..8381bcfec18b0 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-0distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-0distinct_use.swift @@ -27,6 +27,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift index ef8938cddf10b..da1183d3c20ac 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift @@ -6,14 +6,14 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueVyS2iGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVyS2iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVyS2iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*|{ i8\*, i32, i64, i64 }\* @__swift_memcpy[0-9]+_[0-9]+.ptrauth to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVyS2iGwet{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVyS2iGwst{{[^[:space:]]* to i8\*}}), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -22,7 +22,7 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVyS2iGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] struct Value { let first: First let second: Second @@ -57,6 +57,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_1]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift index 64dcda8e8f4f0..b21075d56c43c 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift @@ -6,14 +6,14 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueVySdSiGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySdSiGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySdSiGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|[^@]+@__swift_memcpy[^[:space:]]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySdSiGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySdSiGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -22,17 +22,17 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySdSiGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdSiGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSdN", %swift.type* @"$sSiN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySdSiGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSdN", %swift.type* @"$sSiN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVyS2iGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVyS2iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVyS2iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|[^@]+@__swift_memcpy[^[:space:]]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVyS2iGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVyS2iGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -41,7 +41,7 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVyS2iGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] struct Value { let first: First let second: Second @@ -86,6 +86,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_2]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift index 8f13ae6002add..31fce124fd51f 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift @@ -6,14 +6,14 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueVySSSdGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast (%swift.opaque* ([{{[0-9]+}} x i8]*, [{{[0-9]+}} x i8]*, %swift.type*)* @"$s4main5ValueVySSSdGwCP" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwxx" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwcp" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwca" to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwta" to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySSSdGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySSSdGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwCP{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwxx{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwcp{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwca{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwta{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -22,17 +22,17 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySSSdGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySSSdGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSSN", %swift.type* @"$sSdN", i32 0, i32 16, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySSSdGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSSN", %swift.type* @"$sSdN", i32 0, i32 16, i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySdSiGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySdSiGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySdSiGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|[^@]+@__swift_memcpy[^[:space:]]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVy{{[^[:space:]]* to i8\*}}), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -41,17 +41,17 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySdSiGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdSiGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSdN", %swift.type* @"$sSiN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySdSiGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSdN", %swift.type* @"$sSiN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVyS2iGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVyS2iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVyS2iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9]+" to i8\*|[^@]+@__swift_memcpy[^[:space:]]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVyS2iGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVyS2iGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAMEL [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -60,7 +60,7 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVyS2iGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] struct Value { let first: First let second: Second @@ -115,6 +115,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_3]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySSSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift index 3fc64b98d1e8d..4a151bbe6db25 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift @@ -6,14 +6,14 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueVys5UInt8VSSGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast (%swift.opaque* ([{{[0-9]+}} x i8]*, [{{[0-9]+}} x i8]*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwCP" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwxx" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwcp" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwca" to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwta" to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVys5UInt8VSSGwCP{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVys5UInt8VSSGwxx{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVys5UInt8VSSGwcp{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVys5UInt8VSSGwca{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVys5UInt8VSSGwta{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVys5UInt8VSSGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVys5UInt8VSSGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -22,17 +22,17 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVys5UInt8VSSGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVys5UInt8VSSGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$ss5UInt8VN", %swift.type* @"$sSSN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVys5UInt8VSSGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$ss5UInt8VN", %swift.type* @"$sSSN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySSSdGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast (%swift.opaque* ([{{[0-9]+}} x i8]*, [{{[0-9]+}} x i8]*, %swift.type*)* @"$s4main5ValueVySSSdGwCP" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwxx" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwcp" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwca" to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwta" to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySSSdGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySSSdGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwCP{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwxx{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwcp{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwca{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwta{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySSSdGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -41,17 +41,17 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySSSdGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySSSdGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSSN", %swift.type* @"$sSdN", i32 0, i32 16, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySSSdGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSSN", %swift.type* @"$sSdN", i32 0, i32 16, i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySdSiGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySdSiGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySdSiGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|[^@]+@__swift_memcpy[^[:space:]]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySdSiGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVySdSiGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -60,17 +60,17 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySdSiGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdSiGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSdN", %swift.type* @"$sSiN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySdSiGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSdN", %swift.type* @"$sSiN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVyS2iGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVyS2iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVyS2iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|[^@]+@__swift_memcpy[^[:space:]]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVyS2iGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main5ValueVyS2iGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -79,7 +79,7 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVyS2iGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant {{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] struct Value { let first: First let second: Second @@ -144,6 +144,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_4]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVys5UInt8VSSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift index 156b7e43c0771..90e8cc77ac434 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift @@ -6,14 +6,14 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main5ValueVys5UInt8VSSGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast (%swift.opaque* ([{{[0-9]+}} x i8]*, [{{[0-9]+}} x i8]*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwCP" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwxx" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwcp" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwca" to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwta" to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVys5UInt8VSSGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVys5UInt8VSSGwCP{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVys5UInt8VSSGwxx{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVys5UInt8VSSGwcp{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVys5UInt8VSSGwca{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVys5UInt8VSSGwta{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVys5UInt8VSSGwet{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVys5UInt8VSSGwst{{[^[:space:]]* to i8\*}}), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -22,17 +22,35 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVys5UInt8VSSGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVys5UInt8VSSGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$ss5UInt8VN", %swift.type* @"$sSSN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVys5UInt8VSSGMf" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME:}> <{ +// CHECK-SAME: i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVys5UInt8VSSGWV", i32 0, i32 0), +// CHECK-SAME: [[INT]] 512, +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), +// CHECK-SAME: %swift.type* @"$ss5UInt8VN", +// CHECK-SAME: %swift.type* @"$sSSN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 [[ALIGNMENT]], +// CHECK-SAME: i64 3 +// CHECK-SAME:}>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySSSdGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast (%swift.opaque* ([{{[0-9]+}} x i8]*, [{{[0-9]+}} x i8]*, %swift.type*)* @"$s4main5ValueVySSSdGwCP" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwxx" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwcp" to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwca" to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s4main5ValueVySSSdGwta" to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySSSdGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySSSdGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSSdGwCP{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSSdGwxx{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSSdGwcp{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSSdGwca{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSSdGwta{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSSdGwet{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySSSdGwst{{[^[:space:]]* to i8\*}}), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -41,17 +59,35 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySSSdGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySSSdGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSSN", %swift.type* @"$sSdN", i32 0, i32 16, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySSSdGMf" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME:}> <{ +// CHECK-SAME: i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySSSdGWV", i32 0, i32 0), +// CHECK-SAME: [[INT]] 512, +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), +// CHECK-SAME: %swift.type* @"$sSSN", +// CHECK-SAME: %swift.type* @"$sSdN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 16, +// CHECK-SAME: i64 3 +// CHECK-SAME:}>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVySdSiGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK_SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVySdSiGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVySdSiGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|[^@]*@__swift_memcpy[^@]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK_SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySdSiGwet{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVySdSiGwst{{[^[:space:]]* to i8\*}}), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -60,17 +96,35 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVySdSiGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdSiGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSdN", %swift.type* @"$sSiN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVySdSiGMf" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME:}> <{ +// CHECK-SAME: i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySdSiGWV", i32 0, i32 0), +// CHECK-SAME: [[INT]] 512, +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), +// CHECK-SAME: %swift.type* @"$sSdN", +// CHECK-SAME: %swift.type* @"$sSiN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 8, +// CHECK-SAME: i64 3 +// CHECK-SAME:}>, align [[ALIGNMENT]] // CHECK: @"$s4main5ValueVyS2iGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main5ValueVyS2iGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main5ValueVyS2iGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|[^@]*@__swift_memcpy[^@]* to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_memcpy{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVyS2iGwet{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@"$s4main5ValueVyS2iGwst{{[^[:space:]]* to i8\*}}), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -79,7 +133,25 @@ // NOTE: ignore COMDAT on PE/COFF targets // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVyS2iGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSiN", %swift.type* @"$sSiN", i32 0, i32 [[ALIGNMENT]], i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main5ValueVyS2iGMf" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME:}> <{ +// CHECK-SAME: i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVyS2iGWV", i32 0, i32 0), +// CHECK-SAME: [[INT]] 512, +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), +// CHECK-SAME: %swift.type* @"$sSiN", +// CHECK-SAME: %swift.type* @"$sSiN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 [[ALIGNMENT]], +// CHECK-SAME: i64 3 +// CHECK-SAME:}>, align [[ALIGNMENT]] struct Value { let first: First let second: Second @@ -154,6 +226,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_5]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVys4Int8Vs5UInt8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift index 81920fe4ff816..7701e761a485f 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift @@ -6,14 +6,14 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK: @"$s4main9NamespaceC5ValueVySS_SiSdGWV" = linkonce_odr hidden constant %swift.vwtable { -// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|i8\* \(i8\*, i8\*, %swift.type\*\)\* @__swift_memcpy[0-9]+_[0-9]+ to i8\*)}}), -// CHECK-SAME: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy{{[0-9]+}}_{{[0-9]+}} to i8*), -// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s4main9NamespaceC5ValueVySS_SiSdGwet" to i8*), -// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s4main9NamespaceC5ValueVySS_SiSdGwst" to i8*), +// CHECK-SAME: i8* bitcast ({{(%swift.opaque\* \(\[[0-9]+ x i8\]\*, \[[0-9]+ x i8\]\*, %swift.type\*\)\* @"\$[a-zA-Z0-9_]+" to i8\*|[^@]+@__swift_memcpy[^[:space:]]+ to i8\*)}}), +// CHECK-SAME: i8* bitcast ({{[^@]*}}@__swift_noop_void_return{{[^[:space:]]* to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@__swift_memcpy{{[^[:space:]]+ to i8\*}}), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main9NamespaceC5ValueVySS_SiSdGwet{{[^@]+}} to i8*), +// CHECK-SAME: i8* bitcast ({{[^@]+}}@"$s4main9NamespaceC5ValueVySS_SiSdGwst{{[^@]+}} to i8*), // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: [[INT]] {{[0-9]+}}, // CHECK-SAME: i32 {{[0-9]+}}, @@ -22,7 +22,7 @@ // NOTE: ignore the COMDAT on PE/COFF platforms // CHECK-SAME: align [[ALIGNMENT]] -// CHECK: @"$s4main9NamespaceC5ValueVySS_SiSdGMf" = linkonce_odr hidden constant <{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, %swift.type*, i32, i32, i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main9NamespaceC5ValueVySS_SiSdGWV", i32 0, i32 0), [[INT]] 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main9NamespaceC5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSSN", %swift.type* @"$sSiN", %swift.type* @"$sSdN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] +// CHECK: @"$s4main9NamespaceC5ValueVySS_SiSdGMf" = linkonce_odr hidden constant {{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor*), %swift.type* @"$sSSN", %swift.type* @"$sSiN", %swift.type* @"$sSdN", i32 0, i32 8, i64 3 }>, align [[ALIGNMENT]] final class Namespace { struct Value { let first: First @@ -62,6 +62,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED_1]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main9NamespaceC5ValueVySS_SiSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* [[ERASED_TYPE_3]], %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main9NamespaceC5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* [[ERASED_TYPE_3]], %swift.type_descriptor* bitcast ({{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift index b588a226ba6cb..38549082d4bac 100644 --- a/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift @@ -16,7 +16,7 @@ // i8** @"$sB[[INT]]_WV", // i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVySiGWV", i32 0, i32 0), // CHECK-SAME: [[INT]] 512, -// CHECK-SAME: %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), +// CHECK-SAME: %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*), // CHECK-SAME: %swift.type* @"$sSiN", // CHECK-SAME: i32 0{{(, \[4 x i8\] zeroinitializer)?}}, // CHECK-SAME: i64 3 @@ -53,6 +53,6 @@ doit() // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: -// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}} +// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/property_descriptor.sil b/test/IRGen/property_descriptor.sil index 375f2bb3bba4c..df52659869d45 100644 --- a/test/IRGen/property_descriptor.sil +++ b/test/IRGen/property_descriptor.sil @@ -55,11 +55,11 @@ sil_property #ExternalGeneric.rw ( // -- 0x0108_0000 - computed, readonly, has arguments, identified by indirect // CHECK-SAME: <{ , // CHECK-SAME: @{{got.|__imp_}}id_computed -// CHECK-SAME: [[GET_COMPUTEDRO:@keypath_get[.0-9]*]] -// CHECK-SAME: [[GET_ARG_LAYOUT_COMPUTEDRO:@keypath_get_arg_layout[.0-9]*]] +// CHECK-SAME: [[GET_COMPUTEDRO:@keypath_get[.0-9]*]]{{(\.ptrauth)?}} +// CHECK-SAME: [[GET_ARG_LAYOUT_COMPUTEDRO:@keypath_get_arg_layout[.0-9]*]]{{(\.ptrauth)?}} // -- default witness table // CHECK-SAME: i32 0 -// CHECK-SAME: [[ARG_INIT_COMPUTEDRO:@keypath_arg_init[.0-9]*]] +// CHECK-SAME: [[ARG_INIT_COMPUTEDRO:@keypath_arg_init[.0-9]*]]{{(\.ptrauth.*)?}} sil_property #ExternalGeneric.computedRO ( gettable_property $T, id @id_computed : $@convention(thin) () -> (), @@ -69,11 +69,11 @@ sil_property #ExternalGeneric.computedRO ( // -- 0x01c8_0000 - computed, settable, mutating, has arguments, indirect id // CHECK-SAME: <{ , // CHECK-SAME: @{{got.|__imp_}}id_computed -// CHECK-SAME: [[GET_COMPUTEDRW:@keypath_get[.0-9]*]] -// CHECK-SAME: [[SET_COMPUTEDRW:@keypath_set[.0-9]*]] -// CHECK-SAME: [[GET_ARG_LAYOUT_COMPUTEDRW:@keypath_get_arg_layout[.0-9]*]] +// CHECK-SAME: [[GET_COMPUTEDRW:@keypath_get[.0-9]*]]{{(\.ptrauth)?}} +// CHECK-SAME: [[SET_COMPUTEDRW:@keypath_set[.0-9]*]]{{(\.ptrauth)?}} +// CHECK-SAME: [[GET_ARG_LAYOUT_COMPUTEDRW:@keypath_get_arg_layout[.0-9]*]]{{(\.ptrauth)?}} // CHECK-SAME: i32 0 -// CHECK-SAME: [[ARG_INIT_COMPUTEDRW:@keypath_arg_init[.0-9]*]] +// CHECK-SAME: [[ARG_INIT_COMPUTEDRW:@keypath_arg_init[.0-9]*]]{{(\.ptrauth.*)?}} sil_property #ExternalGeneric.computedRW ( settable_property $T, id @id_computed : $@convention(thin) () -> (), @@ -84,11 +84,11 @@ sil_property #ExternalGeneric.computedRW ( // -- 0x01c8_0000 - computed, settable, mutating, has arguments, indirect id // CHECK-SAME: <{ , // CHECK-SAME: @{{got.|__imp_}}id_computed -// CHECK-SAME: [[GET_SUBSCRIPT:@keypath_get[.0-9]*]] -// CHECK-SAME: [[SET_SUBSCRIPT:@keypath_set[.0-9]*]] -// CHECK-SAME: [[GET_ARG_LAYOUT_SUBSCRIPT:@keypath_get_arg_layout[.0-9]*]] +// CHECK-SAME: [[GET_SUBSCRIPT:@keypath_get[.0-9]*]]{{(\.ptrauth)?}} +// CHECK-SAME: [[SET_SUBSCRIPT:@keypath_set[.0-9]*]]{{(\.ptrauth)?}} +// CHECK-SAME: [[GET_ARG_LAYOUT_SUBSCRIPT:@keypath_get_arg_layout[.0-9]*]]{{(\.ptrauth)?}} // CHECK-SAME: i32 0 -// CHECK-SAME: [[ARG_INIT_SUBSCRIPT:@keypath_arg_init[.0-9]*]] +// CHECK-SAME: [[ARG_INIT_SUBSCRIPT:@keypath_arg_init[.0-9]*]]{{(\.ptrauth.*)?}} sil_property #ExternalGeneric.subscript ( settable_property $T, id @id_computed : $@convention(thin) () -> (), @@ -121,8 +121,8 @@ sil_property #ExternalReabstractions.ro ( sil_property #ExternalReabstractions.reabstracted ( settable_property $() -> (), id ##ExternalReabstractions.reabstracted, - getter @get_reabstracted : $@convention(thin) (@in_guaranteed ExternalReabstractions) -> @out @callee_guaranteed in () -> @out U for <()>, - setter @set_reabstracted : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out U for <()>, @inout ExternalReabstractions) -> ()) + getter @get_reabstracted : $@convention(thin) (@in_guaranteed ExternalReabstractions) -> @out @callee_guaranteed @substituted () -> @out U for <()>, + setter @set_reabstracted : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out U for <()>, @inout ExternalReabstractions) -> ()) // All trivial descriptors should share a definition by aliasing to the common // definition @@ -148,5 +148,5 @@ sil @set_computed_generic : $@convention(thin) (@in_guaranteed T sil @get_computed_generic_subscript : $@convention(thin) (@in_guaranteed ExternalGeneric, UnsafeRawPointer) -> @out T sil @set_computed_generic_subscript : $@convention(thin) (@in_guaranteed T, @inout ExternalGeneric, UnsafeRawPointer) -> () -sil @get_reabstracted : $@convention(thin) (@in_guaranteed ExternalReabstractions) -> @out @callee_guaranteed in () -> @out U for <()> -sil @set_reabstracted : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out U for <()>, @inout ExternalReabstractions) -> () +sil @get_reabstracted : $@convention(thin) (@in_guaranteed ExternalReabstractions) -> @out @callee_guaranteed @substituted () -> @out U for <()> +sil @set_reabstracted : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out U for <()>, @inout ExternalReabstractions) -> () diff --git a/test/IRGen/protocol_resilience.sil b/test/IRGen/protocol_resilience.sil index d0499378b2f2e..27b682b7b98b0 100644 --- a/test/IRGen/protocol_resilience.sil +++ b/test/IRGen/protocol_resilience.sil @@ -29,26 +29,26 @@ import resilient_protocol // CHECK-SAME: @"$s19protocol_resilience17ResilientProtocolMp" // Protocol requirements -// CHECK-SAME: %swift.protocol_requirement { i32 8, i32 0 }, -// CHECK-SAME: %swift.protocol_requirement { i32 7, i32 0 }, +// CHECK-SAME: %swift.protocol_requirement { i32 {{(1797193736)|(8)}}, i32 0 }, +// CHECK-SAME: %swift.protocol_requirement { i32 {{(-1947336697)|(7)}}, i32 0 }, -// CHECK-SAME: %swift.protocol_requirement { i32 17, i32 0 }, +// CHECK-SAME: %swift.protocol_requirement { i32 {{(-48627695)|(17)}}, i32 0 }, -// CHECK-SAME: %swift.protocol_requirement { i32 17, i32 0 }, +// CHECK-SAME: %swift.protocol_requirement { i32 {{(-1745420271)|(17)}}, i32 0 }, -// CHECK-SAME: %swift.protocol_requirement { i32 17, +// CHECK-SAME: %swift.protocol_requirement { i32 {{(-544407535)|(17)}}, // CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @defaultC to [[INT]]), // CHECK-SAME: }, -// CHECK-SAME: %swift.protocol_requirement { i32 17, +// CHECK-SAME: %swift.protocol_requirement { i32 {{(1717370897)|(17)}}, // CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @defaultD to [[INT]]), // CHECK-SAME: }, -// CHECK-SAME: %swift.protocol_requirement { i32 1, +// CHECK-SAME: %swift.protocol_requirement { i32 {{(297926657)|(1)}}, // CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.type*, %swift.type*, i8**)* @defaultE to [[INT]]), // CHECK-SAME: }, -// CHECK-SAME: %swift.protocol_requirement { i32 1, +// CHECK-SAME: %swift.protocol_requirement { i32 {{(351797249)|(1)}}, // CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.type*, %swift.type*, i8**)* @defaultF to [[INT]]), // CHECK-SAME: } // CHECK-SAME: } @@ -165,7 +165,7 @@ bb0(%0 : $*Self): // CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %SelfWitnessTable, i32 5 // CHECK-NEXT: [[WITNESS_FN:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[WITNESS:%.*]] = bitcast i8* [[WITNESS_FN]] to void (%swift.opaque*, %swift.type*, i8**)* - // CHECK-NEXT: call swiftcc void [[WITNESS]](%swift.opaque* noalias nocapture swiftself %0, %swift.type* %Self, i8** %SelfWitnessTable) + // CHECK: call swiftcc void [[WITNESS]](%swift.opaque* noalias nocapture swiftself %0, %swift.type* %Self, i8** %SelfWitnessTable) %fn2 = witness_method $Self, #ResilientProtocol.defaultC!1 : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () %ignore2 = apply %fn2(%0) : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () @@ -206,7 +206,7 @@ bb0(%0 : $@thick Self.Type): // CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %SelfWitnessTable, i32 8 // CHECK-NEXT: [[WITNESS_FN:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[WITNESS:%.*]] = bitcast i8* [[WITNESS_FN]] to void (%swift.type*, %swift.type*, i8**)* - // CHECK-NEXT: call swiftcc void [[WITNESS]](%swift.type* swiftself %0, %swift.type* %Self, i8** %SelfWitnessTable) + // CHECK: call swiftcc void [[WITNESS]](%swift.type* swiftself %0, %swift.type* %Self, i8** %SelfWitnessTable) %fn2 = witness_method $Self, #ResilientProtocol.defaultF!1 : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () %ignore2 = apply %fn2(%0) : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () diff --git a/test/IRGen/protocol_resilience_descriptors.swift b/test/IRGen/protocol_resilience_descriptors.swift index 3662ff601f9a4..cc652d276ef26 100644 --- a/test/IRGen/protocol_resilience_descriptors.swift +++ b/test/IRGen/protocol_resilience_descriptors.swift @@ -22,7 +22,7 @@ // CHECK-DEFINITION-SAME: @"default associated conformance2T218resilient_protocol29ProtocolWithAssocTypeDefaultsP_AB014OtherResilientD0" // Associated type default + flags -// CHECK-DEFINITION-SAME: [[INT]] add +// CHECK-DEFINITION-SAME: getelementptr // CHECK-DEFINITION-SAME: @"default assoc type _____y2T1_____QzG 18resilient_protocol7WrapperV AA29ProtocolWithAssocTypeDefaultsP" // CHECK-DEFINITION-SAME: [[INT]] 1 diff --git a/test/IRGen/protocol_resilience_thunks.swift b/test/IRGen/protocol_resilience_thunks.swift index dd0005a38bb6e..33054356a39cf 100644 --- a/test/IRGen/protocol_resilience_thunks.swift +++ b/test/IRGen/protocol_resilience_thunks.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../Inputs/resilient_protocol.swift -// RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution %s | %FileCheck %s +// RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s // RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution -O %s // CHECK: %swift.type = type { [[INT:i32|i64]] } @@ -42,6 +42,8 @@ public protocol MyResilientProtocol { // CHECK: [[WITNESS_GEP:%.*]] = getelementptr inbounds i8*, i8** %3, i32 1 // CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_GEP]] // CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to void (i1, %swift.opaque*, %swift.type*, i8**)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_GEP]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call swiftcc void [[FN]](i1 %0, %swift.opaque* noalias nocapture swiftself %1, %swift.type* %2, i8** %3) // CHECK-NEXT: ret void @@ -49,6 +51,8 @@ public protocol MyResilientProtocol { // CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %2, i32 2 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to i1 (%swift.opaque*, %swift.type*, i8**)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: [[RESULT:%.*]] = call swiftcc i1 [[FN]](%swift.opaque* noalias nocapture swiftself %0, %swift.type* %1, i8** %2) // CHECK-NEXT: ret i1 [[RESULT]] @@ -56,6 +60,8 @@ public protocol MyResilientProtocol { // CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %3, i32 3 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to void (%Any*, %swift.opaque*, %swift.type*, i8**)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call swiftcc void [[FN]](%Any* noalias nocapture sret %0, %swift.opaque* noalias nocapture swiftself %1, %swift.type* %2, i8** %3) // CHECK-NEXT: ret void @@ -63,6 +69,8 @@ public protocol MyResilientProtocol { // CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %3, i32 4 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to void (%swift.opaque*, %swift.error**, %swift.type*, i8**)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call swiftcc void [[FN]](%swift.opaque* noalias nocapture swiftself %0, %swift.error**{{( noalias nocapture( swifterror)? dereferenceable\(.\))?}} %1, %swift.type* %2, i8** %3) // CHECK-NEXT: ret void @@ -70,6 +78,8 @@ public protocol MyResilientProtocol { // CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %5, i32 5 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to void (%swift.opaque*, %swift.opaque*, %swift.type*, %swift.opaque*, %swift.type*, i8**)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call swiftcc void [[FN]](%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture %1, %swift.type* %2, %swift.opaque* noalias nocapture swiftself %3, %swift.type* %4, i8** %5) // CHECK-NEXT: ret void @@ -77,6 +87,8 @@ public protocol MyResilientProtocol { // CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %2, i32 6 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to i1 (%swift.opaque*, %swift.type*, i8**)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: [[RESULT:%.*]] = call swiftcc i1 %5(%swift.opaque* noalias nocapture swiftself %0, %swift.type* %1, i8** %2) // CHECK-NEXT: ret i1 [[RESULT]] @@ -84,6 +96,8 @@ public protocol MyResilientProtocol { // CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %3, i32 7 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to void (i1, %swift.opaque*, %swift.type*, i8**)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: call swiftcc void [[FN]](i1 %0, %swift.opaque* nocapture swiftself %1, %swift.type* %2, i8** %3) // CHECK-NEXT: ret void @@ -91,5 +105,7 @@ public protocol MyResilientProtocol { // CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %3, i32 8 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]] // CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to { i8*, %TSb* } (i8*, %swift.opaque*, %swift.type*, i8**)* +// CHECK-arm64e-NEXT: ptrtoint i8** [[WITNESS_ADDR]] to i64 +// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 // CHECK-NEXT: [[RESULT:%.*]] = call swiftcc { i8*, %TSb* } [[FN]](i8* noalias dereferenceable({{16|32}}) %0, %swift.opaque* nocapture swiftself %1, %swift.type* %2, i8** %3) // CHECK-NEXT: ret { i8*, %TSb* } [[RESULT]] diff --git a/test/IRGen/ptrauth-blocks.sil b/test/IRGen/ptrauth-blocks.sil new file mode 100644 index 0000000000000..fa2ce0b38aeef --- /dev/null +++ b/test/IRGen/ptrauth-blocks.sil @@ -0,0 +1,70 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +import Builtin + +// CHECK: [[VOID_BLOCK_SIGNATURE:@.*]] = private unnamed_addr constant {{.*}} c"v8@?0\00" + +// CHECK: [[TRIVIAL_BLOCK_DESCRIPTOR:@.*]] = internal constant { {{.*}} } { i64 0, i64 40, i8* getelementptr inbounds ({{.*}} [[VOID_BLOCK_SIGNATURE]], i64 0, i64 0) } + +// CHECK: @block_copy_helper.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast ({{.*}}* @block_copy_helper to i8*), i32 0, i64 ptrtoint ({{.*}} getelementptr inbounds ({{.*}} [[NONTRIVIAL_BLOCK_DESCRIPTOR:@.*]], i32 0, i32 2) to i64), i64 0 }, section "llvm.ptrauth" +// CHECK: @block_destroy_helper.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast ({{.*}}* @block_destroy_helper to i8*), i32 0, i64 ptrtoint ({{.*}} getelementptr inbounds ({{.*}} [[NONTRIVIAL_BLOCK_DESCRIPTOR:@.*]], i32 0, i32 3) to i64), i64 0 }, section "llvm.ptrauth" +// CHECK: [[NONTRIVIAL_BLOCK_DESCRIPTOR]] = internal constant { {{.*}} } { i64 0, i64 40, void ({ %objc_block, %swift.refcounted* }*, {{.*}} bitcast ({{.*}} @block_copy_helper.ptrauth to {{.*}}), {{.*}} bitcast ({{.*}} @block_destroy_helper.ptrauth to {{.*}}), i8* getelementptr inbounds ({{.*}} [[VOID_BLOCK_SIGNATURE]], i64 0, i64 0) } + +sil @init_header_trivial : $@convention(thin) (@inout_aliasable @block_storage Builtin.RawPointer) -> @convention(block) () -> () { +entry(%0 : $*@block_storage Builtin.RawPointer): + %i = function_ref @invoke_trivial : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> () + %b = init_block_storage_header %0 : $*@block_storage Builtin.RawPointer, invoke %i : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> (), type $@convention(block) () -> () + return %b : $@convention(block) () -> () +} +// CHECK-LABEL: define swiftcc %objc_block* @init_header_trivial({ %objc_block, i8* }* +// CHECK: [[HEADER:%.*]] = getelementptr inbounds { %objc_block, i8* }, { %objc_block, i8* }* %0, i32 0, i32 0 +// CHECK: [[SLOT:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 3 +// CHECK: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign.i64(i64 ptrtoint (void (void (...)*)* @invoke_trivial to i64), i32 0, i64 [[T0]]) +// CHECK: [[T0:%.*]] = inttoptr i64 [[SIGNED]] to i8* +// CHECK: store i8* [[T0]], i8** [[SLOT]], +// CHECK: [[SLOT:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 4 +// CHECK: store i8* bitcast ({{.*}} [[TRIVIAL_BLOCK_DESCRIPTOR]] to i8*), i8** [[SLOT]] + +sil @invoke_trivial : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> () { +entry(%0 : $*@block_storage Builtin.RawPointer): + %c = project_block_storage %0 : $*@block_storage Builtin.RawPointer + return undef : $() +} + +sil @init_header_nontrivial : $@convention(thin) (@inout_aliasable @block_storage Builtin.NativeObject) -> @convention(block) () -> () { +entry(%0 : $*@block_storage Builtin.NativeObject): + %i = function_ref @invoke_nontrivial : $@convention(c) (@inout_aliasable @block_storage Builtin.NativeObject) -> () + %b = init_block_storage_header %0 : $*@block_storage Builtin.NativeObject, invoke %i : $@convention(c) (@inout_aliasable @block_storage Builtin.NativeObject) -> (), type $@convention(block) () -> () + return %b : $@convention(block) () -> () +} +// CHECK-LABEL: define swiftcc %objc_block* @init_header_nontrivial({ %objc_block, %swift.refcounted* }* +// CHECK: [[HEADER:%.*]] = getelementptr inbounds { %objc_block, %swift.refcounted* }, { %objc_block, %swift.refcounted* }* %0, i32 0, i32 0 +// CHECK: [[SLOT:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 3 +// CHECK: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign.i64(i64 ptrtoint (void (void (...)*)* @invoke_nontrivial to i64), i32 0, i64 [[T0]]) +// CHECK: [[T0:%.*]] = inttoptr i64 [[SIGNED]] to i8* +// CHECK: store i8* [[T0]], i8** [[SLOT]], +// CHECK: [[SLOT:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 4 +// CHECK: store i8* bitcast ({{.*}} [[NONTRIVIAL_BLOCK_DESCRIPTOR]] to i8*), i8** [[SLOT]] + +sil @invoke_nontrivial : $@convention(c) (@inout_aliasable @block_storage Builtin.NativeObject) -> () { +entry(%0 : $*@block_storage Builtin.NativeObject): + %c = project_block_storage %0 : $*@block_storage Builtin.NativeObject + return undef : $() +} + +sil @invoke_block : $@convention(thin) (@convention(block) () -> ()) -> () { +entry(%0 : $@convention(block) () -> ()): + apply %0() : $@convention(block) () -> () + return undef : $() +} +// CHECK-LABEL: define swiftcc void @invoke_block(%objc_block* %0) +// CHECK: [[SLOT:%.*]] = getelementptr inbounds %objc_block, %objc_block* %0, i32 0, i32 3 +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]], align +// CHECK-NEXT: [[INVOKE:%.*]] = bitcast i8* [[T0]] to void (%objc_block*)* +// CHECK-NEXT: [[DISC:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK-NEXT: call void [[INVOKE]](%objc_block* %0) [ "ptrauth"(i32 0, i64 [[DISC]]) ] diff --git a/test/IRGen/ptrauth-class-methods.sil b/test/IRGen/ptrauth-class-methods.sil new file mode 100644 index 0000000000000..f74dca135ea92 --- /dev/null +++ b/test/IRGen/ptrauth-class-methods.sil @@ -0,0 +1,103 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +import Builtin + +// CHECK: @"$s4test1ACfD.ptrauth" = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%T4test1AC*)* @"$s4test1ACfD" to i8*), i32 0, i64 ptrtoint ({{.*}} @"$s4test1ACMf" to i64), i64 48063 }, section "llvm.ptrauth", align 8 +// CHECK: @A_foo.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%T4test1AC*)* @A_foo to i8*), i32 0, i64 ptrtoint ({{.*}} getelementptr inbounds ({{.*}} @"$s4test1ACMf", i32 0, i32 {{.*}}) to i64), i64 23008 }, section "llvm.ptrauth", align 8 +// CHECK: @"$s4test1BCfD.ptrauth" = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%T4test1BC*)* @"$s4test1BCfD" to i8*), i32 0, i64 ptrtoint ({{.*}} @"$s4test1BCMf" to i64), i64 48063 }, section "llvm.ptrauth", align 8 +// CHECK: @B_foo.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%T4test1BC*)* @B_foo to i8*), i32 0, i64 ptrtoint ({{.*}} getelementptr inbounds ({{.*}} @"$s4test1BCMf", i32 0, i32 {{.*}}) to i64), i64 23008 }, section "llvm.ptrauth", align 8 + +// CHECK: @"$s4test1GCMn" = +// -1212481520 == 0xb7bb0010. 0xb7bb == 47035. +// CHECK-SAME: i32 -1212481520, {{.*}} @G_bar + +open class A { + deinit {} + open func foo() +} + +open class B : A { + deinit {} + override open func foo() +} + +open class G { + open func bar() +} + +sil @A_foo : $@convention(method) (@guaranteed A) -> () +sil @B_foo : $@convention(method) (@guaranteed B) -> () +sil @G_bar : $@convention(method) (@guaranteed G) -> () + +sil @$s4test1ACfD : $@convention(method) (@owned A) -> () +sil @$s4test1BCfD : $@convention(method) (@owned B) -> () + +sil_vtable A { + #A.deinit!deallocator.1: (A) -> () -> () : @$s4test1ACfD + #A.foo!1: (A) -> () -> () : @A_foo +} +sil_vtable B { + #B.deinit!deallocator.1: (B) -> () -> () : @$s4test1BCfD + #A.foo!1: (A) -> () -> () : @B_foo [override] +} +sil_vtable G { + #G.bar!1: @G_bar +} + +sil @test_call_a : $@convention(thin) (@guaranteed A) -> () { +bb0(%0 : $A): + %1 = class_method %0 : $A, #A.foo!1 : (A) -> () -> (), $@convention(method) (@guaranteed A) -> () + %2 = apply %1(%0) : $@convention(method) (@guaranteed A) -> () + return %2 : $() +} +// CHECK-LABEL: define swiftcc void @test_call_a(%T4test1AC* %0) +// CHECK: [[T0:%.*]] = bitcast %T4test1AC* %0 to %swift.type** +// CHECK-NEXT: [[META:%.*]] = load %swift.type*, %swift.type** [[T0]], align +// CHECK-NEXT: [[T0:%.*]] = bitcast %swift.type* [[META]] to void (%T4test1AC*)** +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds void (%T4test1AC*)*, void (%T4test1AC*)** [[T0]], i64 {{.*}} +// CHECK-NEXT: [[FN:%.*]] = load void (%T4test1AC*)*, void (%T4test1AC*)** [[SLOT]] +// CHECK-NEXT: [[T0:%.*]] = ptrtoint void (%T4test1AC*)** [[SLOT]] to i64 +// Discriminator value is arbitrary, but must be the same as the next test. +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 23008) +// CHECK-NEXT: call swiftcc void [[FN]](%T4test1AC* swiftself %0) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +// CHECK-NEXT: ret void + +sil @test_call_b : $@convention(thin) (@guaranteed B) -> () { +bb0(%0 : $B): + %1 = class_method %0 : $B, #B.foo!1 : (B) -> () -> (), $@convention(method) (@guaranteed B) -> () + %2 = apply %1(%0) : $@convention(method) (@guaranteed B) -> () + return %2 : $() +} +// CHECK-LABEL: define swiftcc void @test_call_b(%T4test1BC* %0) +// CHECK: [[T0:%.*]] = bitcast %T4test1BC* %0 to %swift.type** +// CHECK-NEXT: [[META:%.*]] = load %swift.type*, %swift.type** [[T0]], align +// CHECK-NEXT: [[T0:%.*]] = bitcast %swift.type* [[META]] to void (%T4test1BC*)** +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds void (%T4test1BC*)*, void (%T4test1BC*)** [[T0]], i64 {{.*}} +// CHECK-NEXT: [[FN:%.*]] = load void (%T4test1BC*)*, void (%T4test1BC*)** [[SLOT]] +// CHECK-NEXT: [[T0:%.*]] = ptrtoint void (%T4test1BC*)** [[SLOT]] to i64 +// Discriminator value is arbitrary, but must be the same as the previous test. +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 23008) +// CHECK-NEXT: call swiftcc void [[FN]](%T4test1BC* swiftself %0) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +// CHECK-NEXT: ret void + +sil @test_call_g : $@convention(thin) (@guaranteed G) -> () { +bb0(%0 : $G): + %1 = class_method %0 : $G, #G.bar!1 : (G) -> () -> (), $@convention(method) (@guaranteed G) -> () + %2 = apply %1(%0) : $@convention(method) (@guaranteed G) -> () + return %2 : $() +} +// CHECK-LABEL: define swiftcc void @test_call_g(%T4test1GC* %0) +// CHECK: [[T0:%.*]] = bitcast %T4test1GC* %0 to %swift.type** +// CHECK: [[T0:%.*]] = bitcast %T4test1GC* %0 to %swift.type** +// CHECK-NEXT: [[META:%.*]] = load %swift.type*, %swift.type** [[T0]], align +// CHECK-NEXT: [[T0:%.*]] = bitcast %swift.type* [[META]] to void (%T4test1GC*)** +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds void (%T4test1GC*)*, void (%T4test1GC*)** [[T0]], i64 {{.*}} +// CHECK-NEXT: [[FN:%.*]] = load void (%T4test1GC*)*, void (%T4test1GC*)** [[SLOT]] +// CHECK-NEXT: [[T0:%.*]] = ptrtoint void (%T4test1GC*)** [[SLOT]] to i64 +// Discriminator value is arbitrary, but must be the same as the previous test. +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 47035) +// CHECK-NEXT: call swiftcc void [[FN]](%T4test1GC* swiftself %0) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +// CHECK-NEXT: ret void diff --git a/test/IRGen/ptrauth-classes.sil b/test/IRGen/ptrauth-classes.sil new file mode 100644 index 0000000000000..e97f71f290e71 --- /dev/null +++ b/test/IRGen/ptrauth-classes.sil @@ -0,0 +1,21 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +import Builtin + +class A {} +sil_vtable A {} + +// rdar://35018215 +struct S {} +class B : A {} +sil_vtable B {} + +// CHECK-LABEL: define internal %swift.type* @"$s4test1ACMi"(%swift.type_descriptor* %0, i8** %1, i8* %2) +// CHECK: [[INT:%.*]] = ptrtoint %swift.type_descriptor* %0 to i64 +// CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign.i64(i64 [[INT]], i32 2, i64 44678) +// CHECK: [[PTR:%.*]] = inttoptr i64 [[SIGNED]] to %swift.type_descriptor* +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_descriptor* [[PTR]], i8** %1, i8* %2) +// CHECK: ret %swift.type* [[METADATA]] diff --git a/test/IRGen/ptrauth-dynamic_replaceable.sil b/test/IRGen/ptrauth-dynamic_replaceable.sil new file mode 100644 index 0000000000000..c588977888bb8 --- /dev/null +++ b/test/IRGen/ptrauth-dynamic_replaceable.sil @@ -0,0 +1,100 @@ +// RUN: %target-swift-frontend %s -emit-ir -disable-objc-interop -module-name A | %FileCheck %s + +// REQUIRES: objc_interop +// REQUIRES: CPU=arm64e + +// CHECK: @test_dynamically_replaceableTX = global %swift.dyn_repl_link_entry { i8*{{.*}} @test_dynamically_replaceable.ptrauth to i8*), %swift.dyn_repl_link_entry* null } +// CHECK: @test_dynamically_replaceable.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (void ()* @test_dynamically_replaceable to i8*), i32 0, i64 ptrtoint (%swift.dyn_repl_link_entry* @test_dynamically_replaceableTX to i64), i64 679 }, section "llvm.ptrauth" +// CHECK: @test_dynamically_replaceableTx = constant %swift.dyn_repl_key { i32 trunc ([[INTPTR:i[0-9]+]] sub ([[INTPTR]] ptrtoint (%swift.dyn_repl_link_entry* @test_dynamically_replaceableTX to [[INTPTR]]), [[INTPTR]] ptrtoint (%swift.dyn_repl_key* @test_dynamically_replaceableTx to [[INTPTR]])) to i32), i32 679 }, section "__TEXT,__const" +// CHECK: @test_replacementTX = global %swift.dyn_repl_link_entry zeroinitializer +// CHECK: @test_replacement_for_externalTX = global %swift.dyn_repl_link_entry zeroinitializer +// CHECK: @external_test_dynamically_replaceableTx = external global %swift.dyn_repl_key +// CHECK: @got.external_test_dynamically_replaceableTx = private unnamed_addr constant %swift.dyn_repl_key* bitcast ({ i8*, i32, i64, i64 }* @external_test_dynamically_replaceableTx.ptrauth to %swift.dyn_repl_key*) +// CHECK: @external_test_dynamically_replaceableTx.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (%swift.dyn_repl_key* @external_test_dynamically_replaceableTx to i8*), i32 2, i64 ptrtoint (%swift.dyn_repl_key** @got.external_test_dynamically_replaceableTx to i64), i64 11389 }, section "llvm.ptrauth" + +// CHECK: @"\01l_unnamed_dynamic_replacements" = private constant { i32, i32, [2 x { i32, i32, i32, i32 }] } +// CHECK: { i32 0, +// CHECK: i32 2, +// CHECK: [2 x { i32, i32, i32, i32 }] +// CHECK: [{ i32, i32, i32, i32 } +// CHECK: %swift.dyn_repl_key* @test_dynamically_replaceableTx +// CHECK: @test_replacement +// CHECK: %swift.dyn_repl_link_entry* @test_replacementTX +// CHECK: i32 0 }, +// CHECK: { i32, i32, i32, i32 } +// CHECK: %swift.dyn_repl_key** @got.external_test_dynamically_replaceableTx +// CHECK: @test_replacement_for_external +// CHECK: %swift.dyn_repl_link_entry* @test_replacement_for_externalTX +// CHECK: i32 0 }] }, section "__TEXT,__const" + +// CHECK: @"\01l_auto_dynamic_replacements" = private constant { i32, i32, [2 x i32] } +// CHECK: { i32 0, i32 1, +// CHECK: [2 x i32] [{{.*}}@"\01l_unnamed_dynamic_replacements"{{.*}}, i32 0] +// CHECK: }, section "__TEXT, __swift5_replace, regular, no_dead_strip" + +// CHECK-LABEL: define swiftcc void @test_dynamically_replaceable() +// CHECK-NEXT: entry: +// CHECK-NEXT: [[FUN_PTR:%.*]] = call i8* @swift_getFunctionReplacement{{.*}}({{.*}} getelementptr {{.*}} @test_dynamically_replaceableTX, i32 0, i32 0 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[FUN_PTR]], null +// CHECK-NEXT: br i1 [[CMP]], label %original_entry, label %forward_to_replaced +// CHECK: forward_to_replaced: +// CHECK-NEXT: [[TYPED_PTR:%.*]] = bitcast i8* [[FUN_PTR]] to void ()* +// CHECK-NEXT: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 ptrtoint (%swift.dyn_repl_link_entry* @test_dynamically_replaceableTX to i64), i64 679) +// CHECK-NEXT: tail call swiftcc void [[TYPED_PTR]]() [ "ptrauth"(i32 0, i64 [[BLEND]]) ] +// CHECK-NEXT: ret void +// CHECK: original_entry: +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +sil [dynamically_replacable] @test_dynamically_replaceable : $@convention(thin) () -> () { +bb0: + %0 = tuple () + return %0 : $() +} + +// CHECK-LABEL: define swiftcc void @test_replacement() +// CHECK: entry: +// CHECK: call swiftcc void @test_replacementTI() +// CHECK: ret void +// CHECK: } + +// The thunk that implement the prev_dynamic_function_ref lookup. +// CHECK-LABEL: define swiftcc void @test_replacementTI() +// CHECK: entry: +// CHECK: [[FUN_PTR:%.*]] = call i8* @swift_getOrigOfReplaceable{{.*}}({{.*}} getelementptr {{.*}} @test_replacementTX, i32 0, i32 0 +// CHECK: [[TYPED_PTR:%.*]] = bitcast i8* [[FUN_PTR]] to void ()* +// CHECK-NEXT: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 ptrtoint (%swift.dyn_repl_link_entry* @test_replacementTX to i64), i64 679) +// CHECK-NEXT: call swiftcc void [[TYPED_PTR]]() [ "ptrauth"(i32 0, i64 [[BLEND]]) ] +// CHECK: ret void +// CHECK: } +sil [dynamic_replacement_for "test_dynamically_replaceable"] @test_replacement : $@convention(thin) () -> () { +bb0: + %0 = prev_dynamic_function_ref @test_replacement : $@convention(thin) () -> () + %1 = apply %0() : $@convention(thin) () -> () + %2 = tuple () + return %2 : $() +} + +// CHECK-LABEL: define swiftcc void @test_dynamic_call() +// CHECK: entry: +// CHECK: call swiftcc void @test_dynamically_replaceable() +// CHECK: ret void +// CHECK: } +sil @test_dynamic_call : $@convention(thin) () -> () { +bb0: + %0 = dynamic_function_ref @test_dynamically_replaceable : $@convention(thin) () -> () + %1 = apply %0() : $@convention(thin) () -> () + %2 = tuple () + return %2 : $() +} + + +sil [dynamically_replacable] @external_test_dynamically_replaceable : $@convention(thin) () -> () + +sil [dynamic_replacement_for "external_test_dynamically_replaceable"] @test_replacement_for_external : $@convention(thin) () -> () { +bb0: + %0 = prev_dynamic_function_ref @test_replacement : $@convention(thin) () -> () + %1 = apply %0() : $@convention(thin) () -> () + %2 = tuple () + return %2 : $() +} diff --git a/test/IRGen/ptrauth-dynamic_replaceable_opaque_return.swift b/test/IRGen/ptrauth-dynamic_replaceable_opaque_return.swift new file mode 100644 index 0000000000000..7001e34dd9d3b --- /dev/null +++ b/test/IRGen/ptrauth-dynamic_replaceable_opaque_return.swift @@ -0,0 +1,59 @@ +// RUN: %target-swift-frontend -disable-availability-checking -module-name A -swift-version 5 -primary-file %s -emit-ir | %FileCheck %s + +// REQUIRES: CPU=arm64e + +// CHECK: @"$s1A3baryQrSiFQOMk" = global %swift.dyn_repl_link_entry { {{.*}}@"$s1A3baryQrSiFQOMh.ptrauth" to i8*), %swift.dyn_repl_link_entry* null } +// CHECK: @"$s1A3baryQrSiFQOMh.ptrauth" = private constant { i8*, i32, i64, i64 } { {{.*}}@"$s1A3baryQrSiFQOMh" to i8*), i32 0, i64 ptrtoint (%swift.dyn_repl_link_entry* @"$s1A3baryQrSiFQOMk" to i64), i64 44678 }, section "llvm.ptrauth" +// CHECK: @"$s1A3baryQrSiFQOMj" = constant %swift.dyn_repl_key { {{.*}}%swift.dyn_repl_link_entry* @"$s1A3baryQrSiFQOMk"{{.*}}, i32 44678 }, section "__TEXT,__const" +// CHECK: @"$s1A16_replacement_bar1yQrSi_tFQOMk" = global %swift.dyn_repl_link_entry zeroinitializer +// CHECK: @"\01l_unnamed_dynamic_replacements" = +// CHECK: private constant { i32, i32, [2 x { i32, i32, i32, i32 }] } +// CHECK: { i32 0, i32 2, [2 x { i32, i32, i32, i32 }] [ +// CHECK: { i32, i32, i32, i32 } { {{.*}}%swift.dyn_repl_key* @"$s1A3baryQrSiFTx"{{.*}}@"$s1A16_replacement_bar1yQrSi_tF"{{.*}}%swift.dyn_repl_link_entry* @"$s1A16_replacement_bar1yQrSi_tFTX"{{.*}}, i32 0 }, +// CHECK: { i32, i32, i32, i32 } { {{.*}}%swift.dyn_repl_key* @"$s1A3baryQrSiFQOMj"{{.*}},{{.*}}@"$s1A16_replacement_bar1yQrSi_tFQOMg"{{.*}},{{.*}}@"$s1A16_replacement_bar1yQrSi_tFQOMk"{{.*}}, i32 0 }] }, section "__TEXT,__const", align 8 + +public protocol P { + func myValue() -> Int +} + +extension Int: P { + public func myValue() -> Int { + return self + } +} +// Opaque result type descriptor accessor for bar. +// CHECK-LABEL: define swiftcc %swift.type_descriptor* @"$s1A3baryQrSiFQOMg"() +// CHECK: entry: +// CHECK: %0 = load i8*, i8** getelementptr inbounds (%swift.dyn_repl_link_entry, %swift.dyn_repl_link_entry* @"$s1A3baryQrSiFQOMk", i32 0, i32 0) +// CHECK: %1 = bitcast i8* %0 to %swift.type_descriptor* ()* +// CHECK: %2 = call i64 @llvm.ptrauth.blend.i64(i64 ptrtoint (%swift.dyn_repl_link_entry* @"$s1A3baryQrSiFQOMk" to i64), i64 44678) +// CHECK: %3 = tail call swiftcc %swift.type_descriptor* %1() [ "ptrauth"(i32 0, i64 %2) ] +// CHECK: ret %swift.type_descriptor* %3 +// CHECK: } + +// Opaque result type descriptor accessor impl. +// CHECK-LABEL: define swiftcc %swift.type_descriptor* @"$s1A3baryQrSiFQOMh"() +// CHECK: entry: +// CHECK: ret %swift.type_descriptor* bitcast ({{.*}}* @"$s1A3baryQrSiFQOMQ" to %swift.type_descriptor*) +// CHECK: } + +public dynamic func bar(_ x: Int) -> some P { + return x +} + +struct Pair : P { + var x = 0 + var y = 1 + func myValue() -> Int{ + return y + } +} +// Opaque result type descriptor accessor for _replacement_bar. +// CHECK: define swiftcc %swift.type_descriptor* @"$s1A16_replacement_bar1yQrSi_tFQOMg"() +// CHECK: entry: +// CHECK: ret %swift.type_descriptor* bitcast ({{.*}} @"$s1A16_replacement_bar1yQrSi_tFQOMQ" to %swift.type_descriptor*) +// CHECK: } +@_dynamicReplacement(for:bar(_:)) +public func _replacement_bar(y x: Int) -> some P { + return Pair() +} diff --git a/test/IRGen/ptrauth-foreign.sil b/test/IRGen/ptrauth-foreign.sil new file mode 100644 index 0000000000000..17a3d6b2b90e4 --- /dev/null +++ b/test/IRGen/ptrauth-foreign.sil @@ -0,0 +1,29 @@ +// RUN: %swift -module-name test -import-objc-header %S/Inputs/ptrauth-foreign.h %s -parse-stdlib -parse-as-library -emit-ir -target arm64e-apple-ios12.0 | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +sil @test0 : $() -> () { +bb0: + %0 = metatype $@thick IntPair.Type + +// CHECK: @"$sSo9WidgetRefaMn.ptrauth" = +// CHECK-SAME: @"$sSo9WidgetRefaMn" +// CHECK-SAME: @"$sSo9WidgetRefaMf", i32 0, i32 2 +// CHECK-SAME: i64 44678 +// CHECK-SAME: section "llvm.ptrauth" +// CHECK: @"$sSo9WidgetRefaMf" = linkonce_odr hidden constant +// CHECK-SAME: @"$sSo9WidgetRefaMn.ptrauth" + %1 = metatype $@thick Widget.Type + +// CHECK: @"$sSo7IntPairVMn.ptrauth" = +// CHECK-SAME: @"$sSo7IntPairVMn" +// CHECK-SAME: @"$sSo7IntPairVMf", i32 0, i32 2 +// CHECK-SAME: i64 44678 +// CHECK-SAME: section "llvm.ptrauth" +// CHECK: @"$sSo7IntPairVMf" = linkonce_odr hidden constant +// CHECK-SAME: @"$sSo7IntPairVMn.ptrauth" + + %ret = tuple () + return %ret : $() +} diff --git a/test/IRGen/ptrauth-functions.sil b/test/IRGen/ptrauth-functions.sil new file mode 100644 index 0000000000000..9606671228345 --- /dev/null +++ b/test/IRGen/ptrauth-functions.sil @@ -0,0 +1,90 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +import Builtin + +// CHECK: @global_function.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (void ()* @global_function to i8*), i32 0, i64 0, i64 {{.*}} }, section "llvm.ptrauth", align 8 + +sil @global_function : $@convention(thin) () -> () + +sil @test_sign : $@convention(thin) () -> @convention(thin) () -> () { +bb0: + %0 = function_ref @global_function : $@convention(thin) () -> () + return %0 : $@convention(thin) () -> () +} +// CHECK-LABEL: define swiftcc i8* @test_sign() +// CHECK: ret i8* bitcast ({ i8*, i32, i64, i64 }* @global_function.ptrauth to i8*) + +sil @test_direct_call : $@convention(thin) () -> () { +bb0: + %0 = function_ref @global_function : $@convention(thin) () -> () + %1 = apply %0() : $@convention(thin) () -> () + return %1 : $() +} +// CHECK-LABEL: define swiftcc void @test_direct_call() +// CHECK: call swiftcc void @global_function(){{$}} + +sil @test_indirect_call_thin : $@convention(thin) (@convention(thin) () -> ()) -> () { +bb0(%0 : $@convention(thin) () -> ()): + %1 = apply %0() : $@convention(thin) () -> () + return %1 : $() +} +// CHECK-LABEL: define swiftcc void @test_indirect_call_thin(i8* %0) +// CHECK: [[CAST:%.*]] = bitcast i8* %0 to void ()* +// CHECK-NEXT: call swiftcc void [[CAST]]() [ "ptrauth"(i32 0, i64 {{.*}}) ] + +sil @test_indirect_call_thick : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () { +bb0(%0 : $@callee_guaranteed () -> ()): + %1 = apply %0() : $@callee_guaranteed () -> () + return %1 : $() +} +// CHECK-LABEL: define swiftcc void @test_indirect_call_thick(i8* %0, %swift.refcounted* %1) +// CHECK: [[CAST:%.*]] = bitcast i8* %0 to void (%swift.refcounted*)* +// CHECK-NEXT: call swiftcc void [[CAST]](%swift.refcounted* swiftself %1) [ "ptrauth"(i32 0, i64 {{.*}}) ] + +sil @test_indirect_call_c : $@convention(thin) (@convention(c) () -> ()) -> () { +bb0(%0 : $@convention(c) () -> ()): + %1 = apply %0() : $@convention(c) () -> () + return %1 : $() +} +// CHECK-LABEL: define swiftcc void @test_indirect_call_c(i8* %0) +// CHECK: [[CAST:%.*]] = bitcast i8* %0 to void ()* +// CHECK-NEXT: call void [[CAST]]() [ "ptrauth"(i32 0, i64 {{.*}}) ] + +sil @test_thin_to_thick : $@convention(thin) (@convention(thin) () -> ()) -> (@callee_guaranteed () -> ()) { +bb0(%0 : $@convention(thin) () -> ()): + %1 = thin_to_thick_function %0 : $@convention(thin) () -> () to $@callee_guaranteed () -> () + return %1 : $@callee_guaranteed () -> () +} + +// CHECK-LABEL: define swiftcc { i8*, %swift.refcounted* } @test_thin_to_thick(i8* %0) +// CHECK: [[T0:%.*]] = insertvalue { i8*, %swift.refcounted* } undef, i8* %0, 0 +// CHECK-NEXT: [[T1:%.*]] = insertvalue { i8*, %swift.refcounted* } [[T0]], %swift.refcounted* null, 1 +// CHECK-NEXT: ret { i8*, %swift.refcounted* } [[T1]] + +sil @test_sign_thin_to_thick : $@convention(thin) () -> (@callee_guaranteed () -> ()) { +bb0: + %0 = function_ref @global_function : $@convention(thin) () -> () + %1 = thin_to_thick_function %0 : $@convention(thin) () -> () to $@callee_guaranteed () -> () + return %1 : $@callee_guaranteed () -> () +} +// CHECK: define swiftcc { i8*, %swift.refcounted* } @test_sign_thin_to_thick() #[[ATTRS:[0-9]+]] { +// CHECK: ret { i8*, %swift.refcounted* } { i8* bitcast ({ i8*, i32, i64, i64 }* @global_function.ptrauth to i8*), %swift.refcounted* null } + +class F {} +sil @generic_return : $@convention(thin) @yield_once (@guaranteed T) -> @yields @guaranteed T + +sil @test_generic_return : $@convention(thin) (@guaranteed T) -> () { +bb0(%0 : $T): + %1 = function_ref @generic_return : $@convention(thin) @yield_once (@guaranteed T) -> (@yields @guaranteed T) + (%value, %token) = begin_apply %1(%0) : $@convention(thin) @yield_once (@guaranteed T) -> (@yields @guaranteed T) + end_apply %token + %ret = tuple () + return %ret : $() +} + +sil_vtable F { +} +// CHECK: #[[ATTRS]] = {{{.*}} "ptrauth-calls" "ptrauth-returns" diff --git a/test/IRGen/ptrauth-objc-partial-apply.sil b/test/IRGen/ptrauth-objc-partial-apply.sil new file mode 100644 index 0000000000000..4b82d971fc564 --- /dev/null +++ b/test/IRGen/ptrauth-objc-partial-apply.sil @@ -0,0 +1,34 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// REQUIRES: objc_interop + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +// CHECK: @"$sTa.ptrauth" = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%swift.refcounted*)* @"$sTa" to i8*), i32 0, i64 0, i64 {{.*}} }, section "llvm.ptrauth" + +@objc class A { + @objc func foo() {} +} + +sil_vtable A {} + +sil hidden @$s4test1AC3fooyyF : $@convention(method) (@guaranteed A) -> () { +bb0(%0 : $A): + unreachable +} +sil hidden [thunk] @$s4test1AC3fooyyFTo : $@convention(objc_method) (A) -> () { +bb0(%0 : $A): + unreachable +} + +// It would also be reasonable to not apply ptrauth here, but as long as we're partial_apply +// CHECK-LABEL: define swiftcc void @test0( +// CHECK: call swiftcc void bitcast ({ i8*, i32, i64, i64 }* @"$sTa.ptrauth" to void (%swift.refcounted*)*)(%swift.refcounted* swiftself {{%.*}}) [ "ptrauth"(i32 0, i64 {{.*}}) ] +sil @test0 : $@convention(thin) (@guaranteed A) -> () { +bb0(%0: $A): + %method = objc_method %0 : $A, #A.foo!1.foreign, $@convention(objc_method) (A) -> () + %partial = partial_apply [callee_guaranteed] %method(%0) : $@convention(objc_method) (A) -> () + apply %partial() : $ @callee_guaranteed () -> () + %result = tuple () + return %result : $() +} diff --git a/test/IRGen/ptrauth-objc.swift b/test/IRGen/ptrauth-objc.swift new file mode 100644 index 0000000000000..8393be7bd9fb5 --- /dev/null +++ b/test/IRGen/ptrauth-objc.swift @@ -0,0 +1,18 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +@objc class A { + @objc func foo() {} +} + +// CHECK: @"$s4test1AC3fooyyFTo.ptrauth" = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%0*, i8*)* @"$s4test1AC3fooyyFTo" to i8*), i32 0, i64 ptrtoint (i8** getelementptr inbounds ({ i32, i32, [1 x { i8*, i8*, i8* }] }, { i32, i32, [1 x { i8*, i8*, i8* }] }* @_INSTANCE_METHODS__TtC4test1A, i32 0, i32 2, i32 0, i32 2) to i64), i64 0 }, section "llvm.ptrauth" + +@objc protocol P { + func bar() +} +@objc class B : P { + func bar() {} +} +// CHECK: @_PROTOCOL_INSTANCE_METHODS__TtP4test1P_ = {{.*}} [{ i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(bar)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* {{@.*}}, i64 0, i64 0), i8* null }] diff --git a/test/IRGen/ptrauth-partial-apply.sil b/test/IRGen/ptrauth-partial-apply.sil new file mode 100644 index 0000000000000..52e6a651aa0bb --- /dev/null +++ b/test/IRGen/ptrauth-partial-apply.sil @@ -0,0 +1,64 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +import Builtin + +// CHECK: @"$sTA.ptrauth" = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%swift.refcounted*)* @"$sTA" to i8*), i32 0, i64 0, i64 {{.*}} }, section "llvm.ptrauth" + +sil @test_thin_indirect : $@convention(thin) (@convention(thin) (Builtin.Int32, Builtin.Int32) -> (), Builtin.Int32) -> @owned @callee_owned () -> () { +bb0(%0 : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> (), %1 : $Builtin.Int32): + %2 = partial_apply %0(%1, %1) : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> () + return %2 : $@callee_owned () -> () +} +// CHECK-LABEL: define swiftcc { i8*, %swift.refcounted* } @test_thin_indirect(i8* %0, i32 %1) +// CHECK: [[FN:%.*]] = bitcast i8* %0 to void (i32, i32)* +// CHECK: [[ALLOC:%.*]] = call {{.*}}swift_allocObject( +// CHECK: [[CTXT:%.*]] = bitcast %swift.refcounted* [[ALLOC]] to [[CTXT_TY:<{ %swift.refcounted, i32, i32, i8\* }>]]* +// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[CTXT_TY]], [[CTXT_TY]]* [[CTXT]], i32 0, i32 3 +// CHECK: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 7185) +// CHECK: [[T0:%.*]] = ptrtoint void (i32, i32)* [[FN]] to i64 +// CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.resign.i64(i64 [[T0]], i32 0, i64 {{.*}}, i32 1, i64 [[DISC]]) +// CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to void (i32, i32)* +// CHECK: [[T3:%.*]] = bitcast void (i32, i32)* [[T2]] to i8* +// CHECK: store i8* [[T3]], i8** [[SLOT]], align 8 +// CHECK: insertvalue { i8*, %swift.refcounted* } { i8* bitcast ({ i8*, i32, i64, i64 }* @"$sTA.ptrauth" to i8*), %swift.refcounted* undef }, %swift.refcounted* {{.*}}, 1 + +// CHECK-LABEL: define internal swiftcc void @"$sTA"(%swift.refcounted* swiftself %0) +// CHECK: [[T0:%.*]] = bitcast %swift.refcounted* %0 to [[CTXT_TY:<{ %swift.refcounted, i32, i32, i8\* }>]]* +// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[CTXT_TY]], [[CTXT_TY]]* [[T0]], i32 0, i32 3 +// CHECK: [[T0:%.*]] = load i8*, i8** [[SLOT]], align 8 +// CHECK: [[FN:%.*]] = bitcast i8* [[T0]] to void (i32, i32)* +// CHECK: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 7185) +// CHECK: call swiftcc void [[FN]](i32 {{.*}}, i32 {{.*}}) [ "ptrauth"(i32 1, i64 [[DISC]]) ] + +sil @test_thick_indirect : $@convention(thin) (@callee_owned (Builtin.Int32, Builtin.Int32) -> (), Builtin.Int32) -> @owned @callee_owned () -> () { +bb0(%0 : $@callee_owned (Builtin.Int32, Builtin.Int32) -> (), %1 : $Builtin.Int32): + %2 = partial_apply %0(%1, %1) : $@callee_owned (Builtin.Int32, Builtin.Int32) -> () + return %2 : $@callee_owned () -> () +} +// CHECK-LABEL: define swiftcc { i8*, %swift.refcounted* } @test_thick_indirect(i8* %0, %swift.refcounted* %1, i32 %2) +// CHECK: [[FN:%.*]] = bitcast i8* %0 to void (i32, i32, %swift.refcounted*)* +// CHECK: [[ALLOC:%.*]] = call {{.*}}swift_allocObject( +// CHECK: [[CTXT:%.*]] = bitcast %swift.refcounted* [[ALLOC]] to [[CTXT_TY:<{ %swift.refcounted, i32, i32, %swift.refcounted\*, i8\* }>]]* +// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[CTXT_TY]], [[CTXT_TY]]* {{%.*}}, i32 0, i32 4 +// CHECK: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 7185) +// CHECK: [[T0:%.*]] = ptrtoint void (i32, i32, %swift.refcounted*)* [[FN]] to i64 +// CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.resign.i64(i64 [[T0]], i32 0, i64 {{.*}}, i32 1, i64 [[DISC]]) +// CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to void (i32, i32, %swift.refcounted*)* +// CHECK: [[T3:%.*]] = bitcast void (i32, i32, %swift.refcounted*)* [[T2]] to i8* +// CHECK: store i8* [[T3]], i8** [[SLOT]], align 8 +// CHECK: insertvalue { i8*, %swift.refcounted* } { i8* bitcast ({ i8*, i32, i64, i64 }* @"$sTA{{.*}}.ptrauth" to i8*), %swift.refcounted* undef }, %swift.refcounted* {{.*}}, 1 + +// CHECK-LABEL: define internal swiftcc void @"$sTA{{.*}}"(%swift.refcounted* swiftself %0) +// CHECK: [[T0:%.*]] = bitcast %swift.refcounted* %0 to <{ %swift.refcounted, i32, i32, %swift.refcounted*, i8* }>* +// CHECK: [[SLOT:%.*]] = getelementptr inbounds <{ %swift.refcounted, i32, i32, %swift.refcounted*, i8* }>, <{ %swift.refcounted, i32, i32, %swift.refcounted*, i8* }>* [[T0]], i32 0, i32 4 +// CHECK: [[T0:%.*]] = load i8*, i8** [[SLOT]], align 8 +// CHECK: [[FN:%.*]] = bitcast i8* [[T0]] to void (i32, i32, %swift.refcounted*)* +// CHECK: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 7185) +// CHECK: call swiftcc void [[FN]](i32 {{.*}}, i32 {{.*}}, %swift.refcounted* {{.*}}) [ "ptrauth"(i32 1, i64 [[DISC]]) ] diff --git a/test/IRGen/ptrauth-protocols.sil b/test/IRGen/ptrauth-protocols.sil new file mode 100644 index 0000000000000..692ee75f2c4ef --- /dev/null +++ b/test/IRGen/ptrauth-protocols.sil @@ -0,0 +1,90 @@ +// RUN: %swift -swift-version 5 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +import Builtin + +protocol P { + static func foo() +} +protocol Q { + init() + associatedtype Assoc : P +} + +// CHECK: @"$s4test1PMp" = hidden constant +// CHECK-SAME: { i32 -775684095, i32 0 } + +// CHECK: @"$s4test1QMp" = hidden constant +// -687472632 == 0xd7060008. 0x8bb0 == 35760. +// CHECK-SAME: { i32 2053505032, i32 0 }, +// -1951399929 == 0x8bb00007. 0x81b8 == 33208. +// CHECK-SAME: { i32 -1951399929, i32 0 }, +// -2118647806 == 0x81b80002. 0xd706 == 55046. +// CHECK-SAME: { i32 -2118647806, i32 0 } + +struct A : P { + static func foo() {} +} + +struct B : Q { + typealias Assoc = A +} + +sil @A_foo : $@convention(witness_method : P) (@thick A.Type) -> () { +bb0(%0 : $@thick A.Type): + return undef : $() +} + + +sil_witness_table A : P module test { + method #P.foo!1: @A_foo +} +// CHECK: @A_foo.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%swift.type*, %swift.type*, i8**)* @A_foo to i8*), i32 0, i64 ptrtoint (i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"$s4test1AVAA1PAAWP", i32 0, i32 1) to i64), i64 53700 }, section "llvm.ptrauth" + +// CHECK: @"$s4test1AVAA1PAAWP" = hidden constant [2 x i8*] [i8* bitcast (%swift.protocol_conformance_descriptor* @"$s4test1AVAA1PAAMc" to i8*), i8* bitcast ({ i8*, i32, i64, i64 }* @A_foo.ptrauth to i8*)], align 8 + +sil @B_init : $@convention(witness_method : Q) (@thick B.Type) -> (@out B) { +bb0(%0 : $*B, %1 : $@thick B.Type): + return undef : $() +} + +sil_witness_table B : Q module test { + associated_type_protocol (Assoc: P): A: P module main + associated_type Assoc: A + method #Q.init!allocator.1: @B_init +} +// CHECK: @B_init.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (void (%T4test1BV*, %swift.type*, %swift.type*, i8**)* @B_init to i8*), i32 0, i64 ptrtoint (i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @"$s4test1BVAA1QAAWP", i32 0, i32 3) to i64), i64 33208 }, section "llvm.ptrauth" +// CHECK: @"$s4test1BVAA1QAAWP" = hidden global [4 x i8*] [ +// CHECK-SAME: i8* bitcast ({{.*}}* @"$s4test1BVAA1QAAMc" to i8*), +// CHECK-SAME: @.ptrauth +// CHECK-SAME: i8* bitcast ({ i8*, i32, i64, i64 }* @B_init.ptrauth to i8*)] + +sil @test_accesses : $@convention(thin) () -> () { +bb0: + %0 = witness_method $T.Assoc, #P.foo!1 : $@convention(witness_method : P) (@thick Self.Type) -> () + %1 = metatype $@thick T.Assoc.Type + apply %0(%1) : $@convention(witness_method : P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> () + return undef : $() +} +// CHECK-LABEL: define swiftcc void @test_accesses(%swift.type* %T, i8** %T.Q) +// Fetch T.Assoc. +// CHECK: %T.Assoc = extractvalue %swift.metadata_response [[TMP:%.*]], 0 +// Fetch T.Assoc : P. +// CHECK-NEXT: %T.Assoc.P = call swiftcc i8** @swift_getAssociatedConformanceWitness(i8** %T.Q, %swift.type* %T, %swift.type* %T.Assoc +// Fetch T.Assoc.foo +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8*, i8** %T.Assoc.P, i32 1 +// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]], align 8 +// CHECK-NEXT: [[FOO:%.*]] = bitcast i8* [[T1]] to void (%swift.type*, %swift.type*, i8**)* +// CHECK-NEXT: [[T1:%.*]] = ptrtoint i8** [[T0]] to i64 +// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T1]], i64 53700) +// CHECK-NEXT: call swiftcc void [[FOO]](%swift.type* swiftself %T.Assoc, %swift.type* %T.Assoc, i8** %T.Assoc.P) [ "ptrauth"(i32 0, i64 [[DISC]]) ] +// CHECK-NEXT: ret void + +sil @use_conformances : $@convention(thin) () -> () { +bb0: + %0 = function_ref @test_accesses : $@convention(thin) () -> () + apply %0() : $@convention(thin) () -> () + return undef : $() +} diff --git a/test/IRGen/ptrauth-resilient-classes.swift b/test/IRGen/ptrauth-resilient-classes.swift new file mode 100644 index 0000000000000..96b057661ec97 --- /dev/null +++ b/test/IRGen/ptrauth-resilient-classes.swift @@ -0,0 +1,22 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift + +// RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution %s -read-legacy-type-info-path=%S/Inputs/legacy_type_info/a.yaml | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize + +// We only use fragile class layouts when Objective-C interop is enabled. + +// REQUIRES: objc_interop +// REQUIRES: CPU=arm64e + +import resilient_struct + +public class HasResilientField { + let i: ResilientRef + + init(i: ResilientRef) { + self.i = i + } +} + +// CHECK-LABEL: @_DATA__TtC4main17HasResilientField = private constant +// CHECK-SAME: @"$s4main17HasResilientFieldCMU.ptrauth" diff --git a/test/IRGen/ptrauth-runtime.sil b/test/IRGen/ptrauth-runtime.sil new file mode 100644 index 0000000000000..cb8faa64e5fc4 --- /dev/null +++ b/test/IRGen/ptrauth-runtime.sil @@ -0,0 +1,19 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +import Builtin + +sil @global_function : $@convention(thin) () -> () + +sil @test_retain : $@convention(thin) (@guaranteed Builtin.NativeObject) -> (@owned Builtin.NativeObject) { +bb0(%0 : $Builtin.NativeObject): + strong_retain %0 : $Builtin.NativeObject + return %0 : $Builtin.NativeObject +} +// CHECK-LABEL: define swiftcc %swift.refcounted* @test_retain(%swift.refcounted* %0) +// CHECK: call %swift.refcounted* @swift_retain( +// CHECK-NEXT: ret %swift.refcounted* %0 + +// CHECK: declare %swift.refcounted* @swift_retain(%swift.refcounted* returned diff --git a/test/IRGen/ptrauth-value-witnesses.sil b/test/IRGen/ptrauth-value-witnesses.sil new file mode 100644 index 0000000000000..e297ec4d0fc35 --- /dev/null +++ b/test/IRGen/ptrauth-value-witnesses.sil @@ -0,0 +1,115 @@ +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +import Builtin + +struct S { var a, b, c: Builtin.NativeObject } +// CHECK: @"$s4test1SVwCP.ptrauth" = private constant {{.*}} i64 55882 +// CHECK: @"$s4test1SVwxx.ptrauth" = private constant {{.*}} i64 1272 +// CHECK: @"$s4test1SVwcp.ptrauth" = private constant {{.*}} i64 58298 +// CHECK: @"$s4test1SVwca.ptrauth" = private constant {{.*}} i64 34641 +// CHECK: @__swift_memcpy24_8.ptrauth = private constant {{.*}} i64 18648 +// CHECK: @"$s4test1SVwta.ptrauth" = private constant {{.*}} i64 61402 +// CHECK: @"$s4test1SVwet.ptrauth" = private constant {{.*}} i64 24816 +// CHECK: @"$s4test1SVwst.ptrauth" = private constant {{.*}} i64 41169 + +sil @test_destroy : $@convention(thin) (@in T) -> () { +bb0(%0 : $*T): + destroy_addr %0 : $*T + %result = tuple () + return %result : $() +} +// CHECK-LABEL: define swiftcc void @test_destroy( +// CHECK: [[VWT:%.*]] = load i8**, +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]], align +// CHECK-NEXT: [[WITNESS:%.*]] = bitcast i8* [[T0]] to +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 1272) +// CHECK-NEXT: call void [[WITNESS]](%swift.opaque* noalias %0, %swift.type* %T) {{#[0-9]+}} [ "ptrauth"(i32 0, i64 [[DISC]]) ] +// CHECK-NEXT: ret void + +sil @test_copy_init : $@convention(thin) (@in_guaranteed T) -> (@out T) { +bb0(%0 : $*T, %1 : $*T): + copy_addr %1 to [initialization] %0 : $*T + %result = tuple () + return %result : $() +} +// CHECK-LABEL: define swiftcc void @test_copy_init( +// CHECK: [[VWT:%.*]] = load i8**, +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]], align +// CHECK-NEXT: [[WITNESS:%.*]] = bitcast i8* [[T0]] to +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 58298) +// CHECK-NEXT: call %swift.opaque* [[WITNESS]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* %T) {{#[0-9]+}} [ "ptrauth"(i32 0, i64 [[DISC]]) ] +// CHECK-NEXT: ret void + +sil @test_take_init : $@convention(thin) (@in T) -> (@out T) { +bb0(%0 : $*T, %1 : $*T): + copy_addr [take] %1 to [initialization] %0 : $*T + %result = tuple () + return %result : $() +} +// CHECK-LABEL: define swiftcc void @test_take_init( +// CHECK: [[VWT:%.*]] = load i8**, +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]], align +// CHECK-NEXT: [[WITNESS:%.*]] = bitcast i8* [[T0]] to +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 18648) +// CHECK-NEXT: call %swift.opaque* [[WITNESS]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* %T) {{#[0-9]+}} [ "ptrauth"(i32 0, i64 [[DISC]]) ] +// CHECK-NEXT: ret void + +sil @test_copy_assign : $@convention(thin) (@inout T, @in_guaranteed T) -> () { +bb0(%0 : $*T, %1 : $*T): + copy_addr %1 to %0 : $*T + %result = tuple () + return %result : $() +} +// CHECK-LABEL: define swiftcc void @test_copy_assign( +// CHECK: [[VWT:%.*]] = load i8**, +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]], align +// CHECK-NEXT: [[WITNESS:%.*]] = bitcast i8* [[T0]] to +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 34641) +// CHECK-NEXT: call %swift.opaque* [[WITNESS]](%swift.opaque* %0, %swift.opaque* %1, %swift.type* %T) {{#[0-9]+}} [ "ptrauth"(i32 0, i64 [[DISC]]) ] +// CHECK-NEXT: ret void + +sil @test_take_assign : $@convention(thin) (@inout T, @in T) -> () { +bb0(%0 : $*T, %1 : $*T): + copy_addr [take] %1 to %0 : $*T + %result = tuple () + return %result : $() +} +// CHECK-LABEL: define swiftcc void @test_take_assign( +// CHECK: [[VWT:%.*]] = load i8**, +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]], align +// CHECK-NEXT: [[WITNESS:%.*]] = bitcast i8* [[T0]] to +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 61402) +// CHECK-NEXT: call %swift.opaque* [[WITNESS]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* %T) {{#[0-9]+}} [ "ptrauth"(i32 0, i64 [[DISC]]) ] +// CHECK-NEXT: ret void + +// Make sure that the local-type-data caching mechanism sets things up right. +sil @test_destroy_twice : $@convention(thin) (@in T, @in T) -> () { +bb0(%0 : $*T, %1 : $*T): + destroy_addr %0 : $*T + destroy_addr %1 : $*T + %result = tuple () + return %result : $() +} +// CHECK-LABEL: define swiftcc void @test_destroy_twice( +// CHECK: [[VWT:%.*]] = load i8**, +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]], align +// CHECK-NEXT: [[WITNESS:%.*]] = bitcast i8* [[T0]] to +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8** [[SLOT]] to i64 +// CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 1272) +// CHECK-NEXT: call void [[WITNESS]](%swift.opaque* noalias %0, %swift.type* %T) {{#[0-9]+}} [ "ptrauth"(i32 0, i64 [[DISC]]) ] +// CHECK-NEXT: call void [[WITNESS]](%swift.opaque* noalias %1, %swift.type* %T) {{#[0-9]+}} [ "ptrauth"(i32 0, i64 [[DISC]]) ] +// CHECK-NEXT: ret void diff --git a/test/IRGen/ptrauth_generalized_accessors.swift b/test/IRGen/ptrauth_generalized_accessors.swift new file mode 100644 index 0000000000000..1985045b20aa3 --- /dev/null +++ b/test/IRGen/ptrauth_generalized_accessors.swift @@ -0,0 +1,177 @@ +// RUN: %swift -swift-version 5 -target arm64e-apple-ios12.0 -parse-stdlib %s -emit-ir -disable-llvm-optzns -o - | %FileCheck %s --check-prefix=CHECK + +// REQUIRES: CODEGENERATOR=ARM + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +// UNSUPPORTED: CPU=arm64e + +// CHECK: [[PROTOTYPE_HOLDER_INOUT_VALUE:@"\$s29ptrauth_generalized_accessors6HolderVIetMl_TC.ptrauth"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors6HolderVIetMl_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_INOUT:3909]] }, section "llvm.ptrauth" +// CHECK: [[PROTOTYPE_HOLDER_BORROWED_VALUE:@"\$s29ptrauth_generalized_accessors6HolderVIetMg_TC.ptrauth"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors6HolderVIetMg_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_BORROWED_VALUE:51173]] }, section "llvm.ptrauth" +// CHECK: [[PROTOTYPE_HOLDER_INOUT_VALUE_1:@"\$s29ptrauth_generalized_accessors6HolderVIetMl_TC.ptrauth.1"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors6HolderVIetMl_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_INOUT]] }, section "llvm.ptrauth" +// CHECK: [[PROTOTYPE_OPAQUEOWNER_INOUT_HOLDER:@"\$s29ptrauth_generalized_accessors11OpaqueOwnerVIetMl_TC.ptrauth"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors11OpaqueOwnerVIetMl_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_INOUT]] }, section "llvm.ptrauth" +// CHECK: [[PROTOTYPE_OPAQUEOWNER_OPAQUE_INOUT_HOLDER:@"\$s29ptrauth_generalized_accessors11OpaqueOwnerVIetWl_TC.ptrauth"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors11OpaqueOwnerVIetWl_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_INOUT]] }, section "llvm.ptrauth" +// CHECK: [[PROTOTYPE_OPAQUEOWNER_OPAQUE_BORROWED_HOLDER:@"\$s29ptrauth_generalized_accessors11OpaqueOwnerVIetWn_TC.ptrauth"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors11OpaqueOwnerVIetWn_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_OPAQUE:56769]] }, section "llvm.ptrauth" +// CHECK: [[PROTOTYPE_OPAQUEOWNER_BORROWED_HOLDER:@"\$s29ptrauth_generalized_accessors11OpaqueOwnerVIetMg_TC.ptrauth"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors11OpaqueOwnerVIetMg_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_BORROWED_HOLDER:11564]] }, section "llvm.ptrauth" +// CHECK: [[PROTOTYPE_OWNER_INOUT_HOLDER:@"\$s29ptrauth_generalized_accessors5OwnerVIetWl_TC.ptrauth"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors5OwnerVIetWl_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_INOUT]] }, section "llvm.ptrauth" +// CHECK: [[PROTOTYPE_OWNER_BORROWED_HOLDER:@"\$s29ptrauth_generalized_accessors5OwnerVIetWn_TC.ptrauth"]] = +// CHECK-SAME: private constant { i8*, i32, i64, i64 } { i8* bitcast (void (i8*, i1)* @"$s29ptrauth_generalized_accessors5OwnerVIetWn_TC" to i8*), i32 0, i64 1, i64 [[PTRAUTH_BORROWED_HOLDER]] }, section "llvm.ptrauth" + +public class C {} + +public struct Value { + public var c: C + func use() {} + mutating func mutate() {} +} + +// Concrete accessor. +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors6HolderV5valueAA5ValueVvr" +// CHECK: call token @llvm.coro.id.retcon.once +// CHECK-SAME: [[PROTOTYPE_HOLDER_BORROWED_VALUE]] +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors6HolderV5valueAA5ValueVvM" +// CHECK: call token @llvm.coro.id.retcon.once +// CHECK-SAME: [[PROTOTYPE_HOLDER_INOUT_VALUE_1]] +public struct Holder { + public var _value: Value + public var value: Value { + _read { yield _value } + _modify { yield &_value } + } +} + +public protocol Owning { + @_borrowed + var holder: Holder { get set } +} + +public protocol OpaqueOwning { + associatedtype Holding + + @_borrowed + var holder: Holding { get set } +} + +// Thunks for Owning, which uses concrete types. +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors5OwnerVAA6OwningA2aDP6holderAA6HolderVvrTW" +// CHECK: call token @llvm.coro.id.retcon.once +// CHECK-SAME: [[PROTOTYPE_OWNER_BORROWED_HOLDER]] +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors5OwnerVAA6OwningA2aDP6holderAA6HolderVvMTW" +// CHECK: call token @llvm.coro.id.retcon.once +// CHECK-SAME: [[PROTOTYPE_OWNER_INOUT_HOLDER]] +public struct Owner: Owning { + public var holder: Holder +} + +// Concrete accessor. +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors11OpaqueOwnerV6holderAA6HolderVvM" +// CHECK: call token @llvm.coro.id.retcon.once +// CHECK-SAME: [[PROTOTYPE_OPAQUEOWNER_INOUT_HOLDER]] +// Thunks for OpaqueOwning, which uses abstract types. +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors11OpaqueOwnerVAA0D6OwningA2aDP6holder7HoldingQzvrTW" +// CHECK: call token @llvm.coro.id.retcon.once +// CHECK-SAME: [[PROTOTYPE_OPAQUEOWNER_OPAQUE_BORROWED_HOLDER]] +// Concrete accessor. +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors11OpaqueOwnerV6holderAA6HolderVvr" +// CHECK: call token @llvm.coro.id.retcon.once +// CHECK-SAME: [[PROTOTYPE_OPAQUEOWNER_BORROWED_HOLDER]] +public struct OpaqueOwner: OpaqueOwning { + public var holder: Holder +} + +// Thunks for OpaqueOwning, which uses abstract types. +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors11OpaqueOwnerVAA0D6OwningA2aDP6holder7HoldingQzvMTW" +// CHECK: call token @llvm.coro.id.retcon.once +// CHECK-SAME: [[PROTOTYPE_OPAQUEOWNER_OPAQUE_INOUT_HOLDER]] + +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors17testInOutConcrete6holderyAA6HolderVz_tF" +// CHECK: [[T0:%.*]] = alloca [32 x i8], align 8 +// CHECK-NEXT: [[BUFFER:%.*]] = getelementptr inbounds [32 x i8], [32 x i8]* [[T0]], i32 0, i32 0 +// CHECK: [[T0:%.*]] = call swiftcc { i8*, %T29ptrauth_generalized_accessors5ValueV* } {{.*}} [[BUFFER]] +// CHECK: [[T1:%.*]] = extractvalue { i8*, %T29ptrauth_generalized_accessors5ValueV* } [[T0]], 0 +// CHECK: call swiftcc void @"$s29ptrauth_generalized_accessors5ValueV6mutateyyF" +// CHECK: [[RESUME:%.*]] = bitcast i8* [[T1]] to void (i8*, i1)* +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8* [[BUFFER]] to i64 +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 [[PTRAUTH_INOUT]]) +// CHECK-NEXT: call swiftcc void [[RESUME]](i8* noalias dereferenceable(32) [[BUFFER]], i1 false) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +public func testInOutConcrete(holder: inout Holder) { + holder.value.mutate() +} + +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors20testBorrowedConcrete6holderyAA6HolderVz_tF" +// CHECK: [[T0:%.*]] = alloca [32 x i8], align 8 +// CHECK: [[BUFFER:%.*]] = getelementptr inbounds [32 x i8], [32 x i8]* [[T0]], i32 0, i32 0 +// CHECK: [[T0:%.*]] = call swiftcc { i8*, %T29ptrauth_generalized_accessors1CC* } {{.*}} [[BUFFER]] +// CHECK: [[T1:%.*]] = extractvalue { i8*, %T29ptrauth_generalized_accessors1CC* } [[T0]], 0 +// CHECK: [[RESUME:%.*]] = bitcast i8* [[T1]] to void (i8*, i1)* +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8* [[BUFFER]] to i64 +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 [[PTRAUTH_BORROWED_VALUE]]) +// CHECK-NEXT: call swiftcc void [[RESUME]](i8* noalias dereferenceable(32) [[BUFFER]], i1 false) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +public func testBorrowedConcrete(holder: inout Holder) { + holder.value.use() +} + +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors9testInOut5valueyxz_tAA6OwningRzlF" +// CHECK: [[T0:%.*]] = alloca [32 x i8], align 8 +// CHECK: [[BUFFER:%.*]] = getelementptr inbounds [32 x i8], [32 x i8]* [[T0]], i32 0, i32 0 +// CHECK: [[T0:%.*]] = call swiftcc { i8*, %T29ptrauth_generalized_accessors6HolderV* } {{.*}} [[BUFFER]] +// CHECK: [[T1:%.*]] = extractvalue { i8*, %T29ptrauth_generalized_accessors6HolderV* } [[T0]], 0 +// CHECK: call swiftcc void @"$s29ptrauth_generalized_accessors5ValueV6mutateyyF" +// CHECK: [[RESUME:%.*]] = bitcast i8* [[T1]] to void (i8*, i1)* +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8* [[BUFFER]] to i64 +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 [[PTRAUTH_INOUT]]) +// CHECK-NEXT: call swiftcc void [[RESUME]](i8* noalias dereferenceable(32) [[BUFFER]], i1 false) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +public func testInOut(value: inout T) { + value.holder.value.mutate() +} + +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors12testBorrowed5valueyxz_tAA6OwningRzlF" +// CHECK: [[T0:%.*]] = alloca [32 x i8], align 8 +// CHECK: [[BUFFER:%.*]] = getelementptr inbounds [32 x i8], [32 x i8]* [[T0]], i32 0, i32 0 +// CHECK: [[T0:%.*]] = call swiftcc { i8*, %T29ptrauth_generalized_accessors1CC* } {{.*}} [[BUFFER]] +// CHECK: [[T1:%.*]] = extractvalue { i8*, %T29ptrauth_generalized_accessors1CC* } [[T0]], 0 +// CHECK: [[RESUME:%.*]] = bitcast i8* [[T1]] to void (i8*, i1)* +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8* [[BUFFER]] to i64 +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 [[PTRAUTH_BORROWED_HOLDER]]) +// CHECK-NEXT: call swiftcc void [[RESUME]](i8* noalias dereferenceable(32) [[BUFFER]], i1 false) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +public func testBorrowed(value: inout T) { + value.holder.value.use() +} + +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors15testOpaqueInOut5valueyxz_tAA0E6OwningRzAA6HolderV7HoldingRtzlF" +// CHECK: [[T0:%.*]] = alloca [32 x i8], align 8 +// CHECK: [[BUFFER:%.*]] = getelementptr inbounds [32 x i8], [32 x i8]* [[T0]], i32 0, i32 0 +// CHECK: [[T0:%.*]] = call swiftcc { i8*, %swift.opaque* } {{.*}} [[BUFFER]] +// CHECK: [[T1:%.*]] = extractvalue { i8*, %swift.opaque* } [[T0]], 0 +// CHECK: call swiftcc void @"$s29ptrauth_generalized_accessors5ValueV6mutateyyF" +// CHECK: [[RESUME:%.*]] = bitcast i8* [[T1]] to void (i8*, i1)* +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8* [[BUFFER]] to i64 +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 [[PTRAUTH_INOUT]]) +// CHECK-NEXT: call swiftcc void [[RESUME]](i8* noalias dereferenceable(32) [[BUFFER]], i1 false) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +public func testOpaqueInOut(value: inout T) + where T.Holding == Holder { + value.holder.value.mutate() +} + +// CHECK-LABEL: define {{.*}} @"$s29ptrauth_generalized_accessors18testOpaqueBorrowed5valueyxz_tAA0E6OwningRzAA6HolderV7HoldingRtzlF" +// CHECK: [[T0:%.*]] = alloca [32 x i8], align 8 +// CHECK: [[BUFFER:%.*]] = getelementptr inbounds [32 x i8], [32 x i8]* [[T0]], i32 0, i32 0 +// CHECK: [[T0:%.*]] = call swiftcc { i8*, %swift.opaque* } {{.*}} [[BUFFER]] +// CHECK: [[T1:%.*]] = extractvalue { i8*, %swift.opaque* } [[T0]], 0 +// CHECK: [[RESUME:%.*]] = bitcast i8* [[T1]] to void (i8*, i1)* +// CHECK-NEXT: [[T0:%.*]] = ptrtoint i8* [[BUFFER]] to i64 +// CHECK-NEXT: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend.i64(i64 [[T0]], i64 [[PTRAUTH_OPAQUE]]) +// CHECK-NEXT: call swiftcc void [[RESUME]](i8* noalias dereferenceable(32) [[BUFFER]], i1 false) [ "ptrauth"(i32 0, i64 [[DISCRIMINATOR]]) ] +public func testOpaqueBorrowed(value: inout T) + where T.Holding == Holder { + value.holder.value.use() +} diff --git a/test/IRGen/witness_method_default.swift b/test/IRGen/witness_method_default.swift index 4a732e5400a54..683e5bd10bd63 100644 --- a/test/IRGen/witness_method_default.swift +++ b/test/IRGen/witness_method_default.swift @@ -18,6 +18,6 @@ public func callAbs(s: T) -> T { // CHECK: [[ABS_PTR:%[0-9]+]] = getelementptr inbounds i8*, i8** %T.SIMDScalarStub, i32 3 // CHECK-NEXT: [[ABS_VALUE:%[0-9]+]] = load i8*, i8** [[ABS_PTR]] // CHECK-NEXT: [[ABS:%[0-9]+]] = bitcast i8* [[ABS_VALUE]] - // CHECK-NEXT: call swiftcc void [[ABS]] + // CHECK: call swiftcc void [[ABS]] return s.abs() } diff --git a/test/IRGen/witness_method_phi.sil b/test/IRGen/witness_method_phi.sil index 2e1d48b820cd5..ff8a2d10497ab 100644 --- a/test/IRGen/witness_method_phi.sil +++ b/test/IRGen/witness_method_phi.sil @@ -9,7 +9,7 @@ entry: // CHECK: [[T0_GEP:%.*]] = getelementptr inbounds i8*, i8** %T.P, i32 1 // CHECK: [[LOAD:%.*]] = load i8*, i8** [[T0_GEP]], // CHECK: [[T0:%.*]] = bitcast i8* [[LOAD]] to void (%swift.opaque*, %swift.type*, i8**)* - // CHECK: [[FUNC:%.*]] = bitcast void (%swift.opaque*, %swift.type*, i8**)* [[T0]] to i8* + // CHECK: [[FUNC:%.*]] = bitcast void (%swift.opaque*, %swift.type*, i8**)* {{.*}} to i8* %1 = witness_method $T, #P.foo!1 : $@convention(witness_method: P) (@in T) -> () br bb1(%1 : $@convention(witness_method: P) (@in T) -> ()) diff --git a/test/IRGen/witness_table_indirect_conformances.swift b/test/IRGen/witness_table_indirect_conformances.swift index 7554c607c8126..cbf5ef0eba3c5 100644 --- a/test/IRGen/witness_table_indirect_conformances.swift +++ b/test/IRGen/witness_table_indirect_conformances.swift @@ -32,9 +32,8 @@ struct Z: P2 { // CHECK: @"$s35witness_table_indirect_conformances1WVAA2P3AAWP" = hidden global [5 x i8*] [ // CHECK-SAME: @"$s35witness_table_indirect_conformances1WVAA2P3AAMc" -// CHECK-SAME: @"associated conformance 35witness_table_indirect_conformances1WVAA2P3AA05AssocE0AaDP_AA2P2" -// CHECK-SAME: @"symbolic{{.*}}35witness_table_indirect_conformances1ZV" -// CHECK-SAME: i8* bitcast (void (%T35witness_table_indirect_conformances1ZV*, %T35witness_table_indirect_conformances1WV*, %swift.type*, i8**)* @"$s35witness_table_indirect_conformances1WVAA2P3A2aDP08getAssocE00gE0QzyFTW" to i8*)] +// CHECK-SAME: {{(associated conformance 35witness_table_indirect_conformances1WVAA2P3AA05AssocE0AaDP_AA2P2|.ptrauth)}} +// CHECK-SAME: @"$s35witness_table_indirect_conformances1WVAA2P3A2aDP08getAssocE00gE0QzyFTW{{(\.ptrauth)?}}" struct W: P3 { typealias AssocP3 = Z diff --git a/test/IRGen/witness_table_objc_associated_type.swift b/test/IRGen/witness_table_objc_associated_type.swift index 9888dba964b27..88b1fd83fa312 100644 --- a/test/IRGen/witness_table_objc_associated_type.swift +++ b/test/IRGen/witness_table_objc_associated_type.swift @@ -20,9 +20,8 @@ struct SB: B { func foo() {} } // CHECK-LABEL: @"$s34witness_table_objc_associated_type2SBVAA1BAAWP" = hidden global [4 x i8*] [ -// CHECK: @"associated conformance 34witness_table_objc_associated_type2SBVAA1BAA2AAAaDP_AA1A" -// CHECK: @"symbolic{{.*}}34witness_table_objc_associated_type2SAV" -// CHECK: i8* bitcast {{.*}} @"$s34witness_table_objc_associated_type2SBVAA1BA2aDP3fooyyFTW" +// CHECK: {{(associated conformance 34witness_table_objc_associated_type2SBVAA1BAA2AAAaDP_AA1A|.ptrauth)}} +// CHECK: i8* bitcast {{.*}} @"$s34witness_table_objc_associated_type2SBVAA1BA2aDP3fooyyFTW{{(\.ptrauth)?}}" // CHECK: ] class CO: O {} @@ -31,8 +30,7 @@ struct SO: C { func foo() {} } // CHECK-LABEL: @"$s34witness_table_objc_associated_type2SOVAA1CAAWP" = hidden global [3 x i8*] [ -// CHECK: @"symbolic{{.*}}34witness_table_objc_associated_type2COC" -// CHECK: i8* bitcast {{.*}} @"$s34witness_table_objc_associated_type2SOVAA1CA2aDP3fooyyFTW" +// CHECK: i8* bitcast {{.*}} @"$s34witness_table_objc_associated_type2SOVAA1CA2aDP3fooyyFTW{{(\.ptrauth)?}}" // CHECK: ] // CHECK-LABEL: define hidden swiftcc void @"$s34witness_table_objc_associated_type0A25OffsetAfterAssociatedTypeyyxAA1BRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* %T, i8** %T.B) diff --git a/test/IRGen/yield_once.sil b/test/IRGen/yield_once.sil index 210596979011b..0f9ca868fef5c 100644 --- a/test/IRGen/yield_once.sil +++ b/test/IRGen/yield_once.sil @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir -disable-llvm-optzns %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize +// RUN: %target-swift-frontend -emit-ir -disable-llvm-optzns %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth import Builtin @@ -68,6 +68,8 @@ entry(%flag : $Builtin.Int1): yes: // CHECK: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 false) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) end_apply %token @@ -77,6 +79,8 @@ yes: no: // CHECK: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 true) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) abort_apply %token @@ -117,6 +121,8 @@ entry: apply %marker(%first) : $@convention(thin) (Builtin.Int32) -> () // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 false) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) end_apply %token diff --git a/test/IRGen/yield_once_big.sil b/test/IRGen/yield_once_big.sil index 46c8f5ab411a7..a769d79146afd 100644 --- a/test/IRGen/yield_once_big.sil +++ b/test/IRGen/yield_once_big.sil @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir -disable-llvm-optzns %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -emit-ir -disable-llvm-optzns %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize import Builtin import Swift @@ -135,6 +135,8 @@ entry(%flag : $Builtin.Int1): yes: // CHECK: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 false) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) end_apply %token @@ -144,6 +146,8 @@ yes: no: // CHECK: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 true) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) abort_apply %token diff --git a/test/IRGen/yield_once_biggish.sil b/test/IRGen/yield_once_biggish.sil index b738a574acc9d..42265a6dd7f95 100644 --- a/test/IRGen/yield_once_biggish.sil +++ b/test/IRGen/yield_once_biggish.sil @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir -disable-llvm-optzns %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -emit-ir -disable-llvm-optzns %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize // i386 uses a scalar result count of 3 instead of 4, so this test would need // to be substantially different to test the functionality there. It's easier @@ -134,6 +134,8 @@ entry(%flag : $Builtin.Int1): yes: // CHECK: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 false) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) end_apply %token @@ -143,6 +145,8 @@ yes: no: // CHECK: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 true) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) abort_apply %token diff --git a/test/IRGen/yield_once_indirect.sil b/test/IRGen/yield_once_indirect.sil index 067da7239a029..973c3df364ee8 100644 --- a/test/IRGen/yield_once_indirect.sil +++ b/test/IRGen/yield_once_indirect.sil @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir -disable-llvm-optzns %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -emit-ir -disable-llvm-optzns %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize import Builtin import Swift @@ -118,6 +118,8 @@ entry(%flag : $Builtin.Int1): yes: // CHECK: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 false) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) end_apply %token @@ -127,6 +129,8 @@ yes: no: // CHECK: [[T0:%.*]] = bitcast i8* [[CONTINUATION]] to void (i8*, i1)* + // CHECK-64-ptrauth-NEXT: ptrtoint + // CHECK-64-ptrauth-NEXT: ptrauth.blend // CHECK-NEXT: call swiftcc void [[T0]](i8* noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 true) // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 [[BUFFER_SIZE]], i8* [[BUFFER]]) abort_apply %token diff --git a/test/Index/Inputs/cross_language.m b/test/Index/Inputs/cross_language.m index e0a7481b2a2be..d107761a51352 100644 --- a/test/Index/Inputs/cross_language.m +++ b/test/Index/Inputs/cross_language.m @@ -21,6 +21,13 @@ void test1() { [o someMethFromObjC]; // CHECK: [[@LINE-1]]:6 | instance-method/ObjC | someMethFromObjC | [[someMethFromObjC_USR]] | + o.prop = 1; + // CHECK: [[@LINE-1]]:5 | instance-property/Swift | prop | [[MyCls1_prop_USR]] | + // CHECK: [[@LINE-2]]:5 | instance-method/acc-set/Swift | setProp: | [[MyCls1_prop_set_USR]] | + int v = o.ext_prop; + // CHECK: [[@LINE-1]]:13 | instance-property/Swift | ext_prop | [[MyCls1_ext_prop_USR]] | + // CHECK: [[@LINE-2]]:13 | instance-method/acc-get/Swift | ext_prop | [[MyCls1_ext_prop_get_USR]] | + MyCls2 *o2 = [[MyCls2 alloc] initWithInt:0]; // CHECK: [[@LINE-1]]:32 | instance-method/Swift | initWithInt: | [[MyCls2_initwithInt_USR]] | diff --git a/test/Index/cross_language.swift b/test/Index/cross_language.swift index f23177ebd8fd8..79345ea973115 100644 --- a/test/Index/cross_language.swift +++ b/test/Index/cross_language.swift @@ -19,7 +19,13 @@ import Foundation // CHECK: [[@LINE-1]]:20 | class/Swift | MyCls1 | [[MyCls1_USR:.*]] | Def @objc public func someMeth() {} // CHECK: [[@LINE-1]]:21 | instance-method/Swift | someMeth() | [[MyCls1_someMeth_USR:.*]] | Def - // CHECK: [[@LINE-4]]:38 | constructor/Swift | init() | [[MyCls1_init_USR:.*]] | Def,Impl,RelChild,RelOver | rel: 2 + + @objc public var prop = 0 + // CHECK: [[@LINE-1]]:20 | instance-property/Swift | prop | [[MyCls1_prop_USR:.*]] | Def + // CHECK: [[@LINE-2]]:20 | instance-method/acc-get/Swift | getter:prop | [[MyCls1_prop_get_USR:.*]] | Def + // CHECK: [[@LINE-3]]:20 | instance-method/acc-set/Swift | setter:prop | [[MyCls1_prop_set_USR:.*]] | Def + + // CHECK: [[@LINE-10]]:38 | constructor/Swift | init() | [[MyCls1_init_USR:.*]] | Def,Impl,RelChild,RelOver | rel: 2 // CHECK-NEXT: RelOver | constructor/Swift | init() | c:objc(cs)NSObject(im)init // CHECK-NEXT: RelChild | class/Swift | MyCls1 | [[MyCls1_USR]] } @@ -40,6 +46,10 @@ public extension MyCls1 { // CHECK: [[@LINE-2]]:18 | class/Swift | MyCls1 | [[MyCls1_USR]] | @objc public func someExtMeth() {} // CHECK: [[@LINE-1]]:21 | instance-method/Swift | someExtMeth() | [[MyCls1_someExtMeth_USR:.*]] | Def + + @objc public var ext_prop: Int { 0 } + // CHECK: [[@LINE-1]]:20 | instance-property/Swift | ext_prop | [[MyCls1_ext_prop_USR:.*]] | Def + // CHECK: [[@LINE-2]]:34 | instance-method/acc-get/Swift | getter:ext_prop | [[MyCls1_ext_prop_get_USR:.*]] | Def } public extension SomeObjCClass { diff --git a/test/Inputs/conditional_conformance_basic_conformances.swift b/test/Inputs/conditional_conformance_basic_conformances.swift index cc890f809c99e..128d65f83bfc3 100644 --- a/test/Inputs/conditional_conformance_basic_conformances.swift +++ b/test/Inputs/conditional_conformance_basic_conformances.swift @@ -122,21 +122,10 @@ public func single_concrete() { // CHECK-NEXT: br i1 [[IS_NULL]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// macosx-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255) -// macosx-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// macosx-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// ios-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255) -// ios-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// ios-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// tvos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255) -// tvos-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// tvos-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// watchos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255) -// watchos-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// watchos-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// linux-gnu-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMD") -// linux-android-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMD") -// windows-msvc-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMD") +// CHECK-STABLE-ABI-FALSE-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255) +// CHECK-STABLE-ABI-FALSE-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 +// CHECK-STABLE-ABI-FALSE-NEXT: extractvalue %swift.metadata_response [[T0]], 1 +// CHECK-STABLE-ABI-TRUE-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMD") // CHECK-NEXT: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [1 x i8**], [1 x i8**]* %conditional.requirement.buffer, i32 0, i32 0 // CHECK-NEXT: [[A_P2_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[CONDITIONAL_REQUIREMENTS]], i32 0 @@ -312,21 +301,10 @@ public func double_concrete_concrete() { // CHECK-NEXT: br i1 [[IS_NULL]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// macosx-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255) -// macosx-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// macosx-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// ios-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255) -// ios-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// ios-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// tvos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255) -// tvos-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// tvos-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// watchos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255) -// watchos-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// watchos-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// linux-gnu-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMD") -// linux-android-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMD") -// windows-msvc-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMD") +// CHECK-STABLE-ABI-FALSE-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255) +// CHECK-STABLE-ABI-FALSE-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 +// CHECK-STABLE-ABI-FALSE-NEXT: extractvalue %swift.metadata_response [[T0]], 1 +// CHECK-STABLE-ABI-TRUE-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMD") // CHECK-NEXT: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [2 x i8**], [2 x i8**]* %conditional.requirement.buffer, i32 0, i32 0 // CHECK-NEXT: [[B_P2_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[CONDITIONAL_REQUIREMENTS]], i32 0 diff --git a/test/Inputs/conditional_conformance_subclass.swift b/test/Inputs/conditional_conformance_subclass.swift index 078f15b4abb0e..0eb7324a5713d 100644 --- a/test/Inputs/conditional_conformance_subclass.swift +++ b/test/Inputs/conditional_conformance_subclass.swift @@ -82,21 +82,10 @@ public func subclassgeneric_concrete() { // CHECK-NEXT: br i1 [[IS_NULL]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// macosx-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMa"(i64 255) -// macosx-NEXT: [[SubclassGeneric_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// macosx-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// ios-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMa"(i64 255) -// ios-NEXT: [[SubclassGeneric_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// ios-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// watchos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMa"(i64 255) -// watchos-NEXT: [[SubclassGeneric_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// watchos-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// tvos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMa"(i64 255) -// tvos-NEXT: [[SubclassGeneric_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// tvos-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// linux-gnu-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMD") -// linux-android-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMD") -// windows-msvc-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMD") +// CHECK-STABLE-ABI-FALSE-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMa"(i64 255) +// CHECK-STABLE-ABI-FALSE-NEXT: [[SubclassGeneric_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 +// CHECK-STABLE-ABI-FALSE-NEXT: extractvalue %swift.metadata_response [[T0]], 1 +// CHECK-STABLE-ABI-TRUE-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMD") // CHECK-NEXT: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [1 x i8**], [1 x i8**]* %conditional.requirement.buffer, i32 0, i32 0 // CHECK-NEXT: [[A_P2_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[CONDITIONAL_REQUIREMENTS]], i32 0 diff --git a/test/Inputs/conditional_conformance_subclass_future.swift b/test/Inputs/conditional_conformance_subclass_future.swift index 094d94a7aabc8..e65401939daa9 100644 --- a/test/Inputs/conditional_conformance_subclass_future.swift +++ b/test/Inputs/conditional_conformance_subclass_future.swift @@ -90,7 +90,7 @@ public func subclassgeneric_concrete() { // linux-android-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMD") // windows-msvc-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s32conditional_conformance_subclass15SubclassGenericCyAA4IsP2VGMD") -// CHECK-NEXT: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [1 x i8**], [1 x i8**]* %conditional.requirement.buffer, i32 0, i32 0 +// CHECK: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [1 x i8**], [1 x i8**]* %conditional.requirement.buffer, i32 0, i32 0 // CHECK-NEXT: [[A_P2_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[CONDITIONAL_REQUIREMENTS]], i32 0 // CHECK-NEXT: store i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$s32conditional_conformance_subclass4IsP2VAA0E0AAWP", i32 0, i32 0), i8*** [[A_P2_PTR]], align 8 // CHECK-NEXT: [[Base_P1:%.*]] = call i8** @swift_getWitnessTable diff --git a/test/Inputs/conditional_conformance_with_assoc.swift b/test/Inputs/conditional_conformance_with_assoc.swift index 3524e7edda75c..c9d9d3fe4a273 100644 --- a/test/Inputs/conditional_conformance_with_assoc.swift +++ b/test/Inputs/conditional_conformance_with_assoc.swift @@ -216,21 +216,10 @@ public func concrete_concrete() { // CHECK-NEXT: br i1 [[IS_NULL]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// macosx-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMa"(i64 255) -// macosx-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// macosx-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// ios-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMa"(i64 255) -// ios-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// ios-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// watchos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMa"(i64 255) -// watchos-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// watchos-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// tvos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMa"(i64 255) -// tvos-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 -// tvos-NEXT: extractvalue %swift.metadata_response [[T0]], 1 -// linux-gnu-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMD") -// linux-android-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMD") -// windows-msvc-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMD") +// CHECK-STABLE-ABI-FALSE-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMa"(i64 255) +// CHECK-STABLE-ABI-FALSE-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 +// CHECK-STABLE-ABI-FALSE-NEXT: extractvalue %swift.metadata_response [[T0]], 1 +// CHECK-STABLE-ABI-TRUE-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s34conditional_conformance_with_assoc6DoubleVyAA8IsAlsoP2VAA0F2P3VGMD") // CHECK-NEXT: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [3 x i8**], [3 x i8**]* %conditional.requirement.buffer, i32 0, i32 0 // CHECK-NEXT: [[C_P3_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[CONDITIONAL_REQUIREMENTS]], i32 0 // CHECK-NEXT: store i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"$s34conditional_conformance_with_assoc4IsP3VAA0F0AAWP", i32 0, i32 0), i8*** [[C_P3_PTR]], align 8 diff --git a/test/Interpreter/SDK/dynamic_subclass.swift b/test/Interpreter/SDK/dynamic_subclass.swift new file mode 100644 index 0000000000000..1ef031db6b4de --- /dev/null +++ b/test/Interpreter/SDK/dynamic_subclass.swift @@ -0,0 +1,27 @@ +// RUN: %target-run-simple-swift | %FileCheck %s +// REQUIRES: executable_test + +// REQUIRES: objc_interop + +import Foundation +import ObjectiveC + +func DoSwizzle(_ c: AnyClass) -> AnyClass { + let name = String(utf8String: class_getName(c))! + let subclass: AnyClass = objc_allocateClassPair(c, "\(name)Subclass", 0)! + objc_registerClassPair(subclass); + let subclassSubclass: AnyClass = objc_allocateClassPair(subclass, "\(name)SubclassSubclass", 0)! + objc_registerClassPair(subclassSubclass); + return subclassSubclass +} + +class MySwiftClassToBeSwizzled: NSObject { +} + +_ = DoSwizzle(NSArray.self) +print("Swizzled NSArray") +// CHECK: Swizzled NSArray + +_ = DoSwizzle(MySwiftClassToBeSwizzled.self) +print("Swizzled MySwiftClassToBeSwizzled") +// CHECK: Swizzled MySwiftClassToBeSwizzled diff --git a/test/Interpreter/convenience_init_peer_delegation.swift b/test/Interpreter/convenience_init_peer_delegation.swift index ae369ca717b29..be1cb83e66de3 100644 --- a/test/Interpreter/convenience_init_peer_delegation.swift +++ b/test/Interpreter/convenience_init_peer_delegation.swift @@ -11,6 +11,7 @@ // REQUIRES: executable_test // REQUIRES: objc_interop +// XFAIL: CPU=arm64e import Darwin diff --git a/test/Interpreter/ptrauth-function-pointers.swift b/test/Interpreter/ptrauth-function-pointers.swift new file mode 100644 index 0000000000000..8fb7efd1f0bfa --- /dev/null +++ b/test/Interpreter/ptrauth-function-pointers.swift @@ -0,0 +1,34 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test +// REQUIRES: CPU=arm64e + +import StdlibUnittest + +var PtrAuthFunctionPointersTestSuite = TestSuite("PtrAuthFunctionPointers") + +func foo() {} +func bar() {} + +struct FuncPtrs { + var a: ()->() + var b: ()->() +} + +PtrAuthFunctionPointersTestSuite.test("PointerAreSigned") { + var ptrs = FuncPtrs(a: foo, b: bar) + withUnsafeBytes(of: &ptrs) { bytes in + let p = bytes.load(fromByteOffset: 0, as: UInt.self) + expectEqual(UInt.bitWidth, 64) + let signature = p & 0x00fffff0_00000000 + let actualPointer = p & 0x0000000f_ffffffff + + // The top byte of a signed function pointer actually being zero is only + // guaranteed by ARMv8.3 if TBI is enabled, which it isn't for function + // pointers in new iOS releases + //expectEqual(topByte, 0) + expectNotEqual(signature, 0) + expectNotEqual(actualPointer, 0) + } +} + +runAllTests() diff --git a/test/Interpreter/ptrauth-kvo.swift b/test/Interpreter/ptrauth-kvo.swift new file mode 100644 index 0000000000000..1fbd9e85cc22c --- /dev/null +++ b/test/Interpreter/ptrauth-kvo.swift @@ -0,0 +1,47 @@ +// RUN: %target-run-simple-swift | %FileCheck %s +// REQUIRES: executable_test +// REQUIRES: objc_interop + +import Foundation + +class A : NSObject { + func a1() {} // never overridden + func x() {} // overriden 1x + func y() {} // overriden 2x + func z() {} // overriden 3x +} + +class B : A { + func b1() {} // never overridden + override func x() {} + override func y() {} + override func z() {} +} + +class C : B { + func c1() {} // never overridden + override func y() {} + override func z() {} +} + +class D : C { + @objc let name: String = "" + func d1() {} + override func z() {} +} + + +let o = D() +let observer = NSObject() +o.addObserver(observer, forKeyPath: "name", options: NSKeyValueObservingOptions(), context: nil) + +o.x() +o.y() +o.z() +o.a1() +o.b1() +o.c1() +o.d1() + +print("okay") +// CHECK: okay diff --git a/test/Misc/stats_dir_tracer.swift b/test/Misc/stats_dir_tracer.swift index 260e689cc604a..98ee6efcf7166 100644 --- a/test/Misc/stats_dir_tracer.swift +++ b/test/Misc/stats_dir_tracer.swift @@ -2,7 +2,7 @@ // RUN: %target-swiftc_driver -o %t/main -module-name main -stats-output-dir %t %s -trace-stats-events // RUN: %FileCheck -input-file %t/*.csv %s -// CHECK-DAG: {{[0-9]+,[0-9]+,"exit","typecheck-expr","Sema.NumConstraintScopes",[0-9]+,[0-9]+,"Sequence","\[.*stats_dir_tracer.swift.*\]"}} +// CHECK-DAG: {{[0-9]+,[0-9]+,"exit","check-conformance","Sema.NumConstraintScopes",[0-9]+,[0-9]+,"Bar: Proto module main",".*stats_dir_tracer.swift.*"}} // CHECK-DAG: {{[0-9]+,[0-9]+,"exit","SuperclassDeclRequest","Sema.SuperclassDeclRequest",[0-9]+,[0-9]+,"Bar","\[.*stats_dir_tracer.swift.*\]"}} public func foo() { diff --git a/test/Parse/omit_return.swift b/test/Parse/omit_return.swift index 07544df94e8da..6a1a3b39f4386 100644 --- a/test/Parse/omit_return.swift +++ b/test/Parse/omit_return.swift @@ -1005,7 +1005,7 @@ var fvs_stubMyOwnFatalError: () { var fvs_forceTryExplicit: String { get { "ok" } set { - return try! failableIdentity("shucks") // expected-error {{unexpected non-void return value in void function}} + return try! failableIdentity("shucks") // expected-error {{cannot convert value of type 'String' to expected argument type '()'}} } } diff --git a/test/PrintAsObjC/Inputs/CoreGraphics-Bridging-Header.h b/test/PrintAsObjC/Inputs/CoreGraphics-Bridging-Header.h new file mode 100644 index 0000000000000..1729ec0b11b9a --- /dev/null +++ b/test/PrintAsObjC/Inputs/CoreGraphics-Bridging-Header.h @@ -0,0 +1,6 @@ +@import Foundation; + +@interface UIColor : NSObject +- (UIColor *)colorWithAlphaComponent:(CGFloat)alpha; +- (UIColor *)resolvedColorWithTraitCollection:(CGFloat)traitCollection; +@end \ No newline at end of file diff --git a/test/PrintAsObjC/Inputs/custom-modules/MiserablePileOfSecrets.h b/test/PrintAsObjC/Inputs/custom-modules/MiserablePileOfSecrets.h index 071fce2592baf..8dfdad3637d37 100644 --- a/test/PrintAsObjC/Inputs/custom-modules/MiserablePileOfSecrets.h +++ b/test/PrintAsObjC/Inputs/custom-modules/MiserablePileOfSecrets.h @@ -3,3 +3,6 @@ @interface NSObject (Secrets) - (void)secretMethod; @end + +@interface SecretClass : NSObject +@end diff --git a/test/PrintAsObjC/imports.swift b/test/PrintAsObjC/imports.swift index 456373ab6ce18..6e24459589803 100644 --- a/test/PrintAsObjC/imports.swift +++ b/test/PrintAsObjC/imports.swift @@ -77,3 +77,7 @@ import MostlyPrivate2_Private @objc public class TestSubclass: NSObject { @_implementationOnly public override func secretMethod() {} } + +extension SecretClass { + private func somethingThatShouldNotBeIncluded() {} +} diff --git a/test/PrintAsObjC/include-underlying.swift b/test/PrintAsObjC/include-underlying.swift new file mode 100644 index 0000000000000..def2baf1a80f1 --- /dev/null +++ b/test/PrintAsObjC/include-underlying.swift @@ -0,0 +1,15 @@ +// REQUIRES: objc_interop + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse-as-library %s -typecheck -emit-objc-header-path %t/emit.h -disable-objc-attr-requires-foundation-module -import-objc-header %S/Inputs/CoreGraphics-Bridging-Header.h -import-underlying-module -module-name CoreGraphics -bridging-header-directory-for-print "" +// RUN: %FileCheck -check-prefix=CHECK-DEFAULT %s < %t/emit.h + +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse-as-library %s -typecheck -emit-objc-header-path %t/emit.h -disable-objc-attr-requires-foundation-module -import-objc-header %S/Inputs/CoreGraphics-Bridging-Header.h -import-underlying-module -module-name CoreGraphics -bridging-header-directory-for-print "Headers/PrivateHeaders/" +// RUN: %FileCheck -check-prefix=CHECK-DIR %s < %t/emit.h + +@objc public class X: UIColor { + @objc public func draw(_: UIColor) { } +} + +// CHECK-DEFAULT: #import "CoreGraphics-Bridging-Header.h" +// CHECK-DIR: #import "Headers/PrivateHeaders/CoreGraphics-Bridging-Header.h" diff --git a/test/Reflection/capture_descriptors.sil b/test/Reflection/capture_descriptors.sil index a878422b803e7..09d782b1462c9 100644 --- a/test/Reflection/capture_descriptors.sil +++ b/test/Reflection/capture_descriptors.sil @@ -96,9 +96,9 @@ bb0(%t : $*T): sil [ossa] @generic_caller3 : $@convention(thin) () -> @owned @callee_guaranteed () -> () { bb0: %f = function_ref @generic_callee3 : $@convention(thin) (@in_guaranteed T) -> () - %t = alloc_stack $Optional<@callee_guaranteed in (@in_guaranteed X) -> @out Y for > + %t = alloc_stack $Optional<@callee_guaranteed @substituted (@in_guaranteed X) -> @out Y for > %c = partial_apply [callee_guaranteed] %f B>, (B, (C) -> Int)>(%t) : $@convention(thin) (@in_guaranteed T) -> () - dealloc_stack %t : $*Optional<@callee_guaranteed in (@in_guaranteed X) -> @out Y for > + dealloc_stack %t : $*Optional<@callee_guaranteed @substituted (@in_guaranteed X) -> @out Y for > return %c : $@callee_guaranteed () -> () } diff --git a/test/Reflection/typeref_decoding_imported.swift b/test/Reflection/typeref_decoding_imported.swift index 96e57806e5681..80498ec9f0fb1 100644 --- a/test/Reflection/typeref_decoding_imported.swift +++ b/test/Reflection/typeref_decoding_imported.swift @@ -1,5 +1,7 @@ // XFAIL: OS=windows-msvc +// UNSUPPORTED: CPU=arm64e + // RUN: %empty-directory(%t) // RUN: %target-build-swift %S/Inputs/ImportedTypes.swift %S/Inputs/ImportedTypesOther.swift -parse-as-library -emit-module -emit-library -module-name TypesToReflect -o %t/%target-library-name(TypesToReflect) -I %S/Inputs diff --git a/test/Reflection/typeref_lowering.swift b/test/Reflection/typeref_lowering.swift index 5f79b92dea1ed..849d2dcd41929 100644 --- a/test/Reflection/typeref_lowering.swift +++ b/test/Reflection/typeref_lowering.swift @@ -2,6 +2,8 @@ // XFAIL: OS=windows-msvc // RUN: %empty-directory(%t) +// UNSUPPORTED: CPU=arm64e + // RUN: %target-build-swift -Xfrontend -disable-availability-checking %S/Inputs/TypeLowering.swift -parse-as-library -emit-module -emit-library -module-name TypeLowering -o %t/%target-library-name(TypesToReflect) // RUN: %target-build-swift -Xfrontend -disable-availability-checking %S/Inputs/TypeLowering.swift %S/Inputs/main.swift -emit-module -emit-executable -module-name TypeLowering -o %t/TypesToReflect diff --git a/test/SIL/Parser/apply_with_substitution.sil b/test/SIL/Parser/apply_with_substitution.sil index 53be16d71f86a..ccc5dc9176887 100644 --- a/test/SIL/Parser/apply_with_substitution.sil +++ b/test/SIL/Parser/apply_with_substitution.sil @@ -6,46 +6,46 @@ sil_stage raw import Builtin import Swift -// CHECK-LABEL: sil @_TF4test3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>>) -> () -sil @_TF4test3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed in () -> @out A for <()>>) -> () { -bb0(%0 : $Optional<@callee_guaranteed in () -> @out A for <()>>): - %1 = alloc_box $<τ_0_0> { var τ_0_0 } in () -> @out A for <()>>> // var f // users: %2, %6, %32 - %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } in () -> @out A for <()>>>, 0 - store %0 to %1a : $*Optional<@callee_guaranteed in () -> @out A for <()>> // id: %2 +// CHECK-LABEL: sil @_TF4test3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>>) -> () +sil @_TF4test3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed @substituted () -> @out A for <()>>) -> () { +bb0(%0 : $Optional<@callee_guaranteed @substituted () -> @out A for <()>>): + %1 = alloc_box $<τ_0_0> { var τ_0_0 } () -> @out A for <()>>> // var f // users: %2, %6, %32 + %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } () -> @out A for <()>>>, 0 + store %0 to %1a : $*Optional<@callee_guaranteed @substituted () -> @out A for <()>> // id: %2 %3 = alloc_stack $Optional<()> // users: %22, %28, %30, %31 %4 = alloc_stack $() // users: %12, %22, %25 - %5 = alloc_stack $Optional<@callee_guaranteed in () -> @out A for <()>> // users: %6, %8, %10, %11, %16, %24 - copy_addr %1a to [initialization] %5 : $*Optional<@callee_guaranteed in () -> @out A for <()>> // id: %6 + %5 = alloc_stack $Optional<@callee_guaranteed @substituted () -> @out A for <()>> // users: %6, %8, %10, %11, %16, %24 + copy_addr %1a to [initialization] %5 : $*Optional<@callee_guaranteed @substituted () -> @out A for <()>> // id: %6 %7 = function_ref @_TFs22_doesOptionalHaveValueU__FT1vRGSqQ___Bi1_ : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 // user: %8 %8 = apply %7<() -> ()>(%5) : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 // user: %9 br bb2 // id: %13 bb2: // Preds: bb0 %14 = function_ref @_TFs17_getOptionalValueU__FT1vGSqQ___Q_ : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>) -> @out τ_0_0 // user: %16 - %15 = alloc_stack $@callee_guaranteed in () -> @out A for <()> // users: %16, %17, %23 + %15 = alloc_stack $@callee_guaranteed @substituted () -> @out A for <()> // users: %16, %17, %23 // CHECK: apply %{{[0-9]+}}<() -> ()>(%{{[0-9]+}}, %{{[0-9]+}}) : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>) -> @out τ_0_0 %16 = apply %14<() -> ()>(%15, %5) : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>) -> @out τ_0_0 - %17 = load %15 : $*@callee_guaranteed in () -> @out A for <()> // user: %19 - %18 = function_ref @_TTRXFo_iT__iT__XFo__dT__ : $@convention(thin) (@guaranteed @callee_guaranteed in () -> @out A for <()>) -> () // user: %19 - %19 = partial_apply [callee_guaranteed] %18(%17) : $@convention(thin) (@guaranteed @callee_guaranteed in () -> @out A for <()>) -> () // user: %20 + %17 = load %15 : $*@callee_guaranteed @substituted () -> @out A for <()> // user: %19 + %18 = function_ref @_TTRXFo_iT__iT__XFo__dT__ : $@convention(thin) (@guaranteed @callee_guaranteed @substituted () -> @out A for <()>) -> () // user: %19 + %19 = partial_apply [callee_guaranteed] %18(%17) : $@convention(thin) (@guaranteed @callee_guaranteed @substituted () -> @out A for <()>) -> () // user: %20 %20 = apply %19() : $@callee_guaranteed () -> () %21 = function_ref @_TFs24_injectValueIntoOptionalU__FT1vQ__GSqQ__ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> // user: %22 // CHECK: apply %{{[0-9]+}}<()>(%{{[0-9]+}}, %{{[0-9]+}}) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> %22 = apply %21<()>(%3, %4) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> - dealloc_stack %15 : $*@callee_guaranteed in () -> @out A for <()> // id: %23 - dealloc_stack %5 : $*Optional<@callee_guaranteed in () -> @out A for <()>> // id: %24 + dealloc_stack %15 : $*@callee_guaranteed @substituted () -> @out A for <()> // id: %23 + dealloc_stack %5 : $*Optional<@callee_guaranteed @substituted () -> @out A for <()>> // id: %24 dealloc_stack %4 : $*() // id: %25 br bb4 // id: %26 bb4: // Preds: bb2 bb3 %30 = load %3 : $*Optional<()> dealloc_stack %3 : $*Optional<()> // id: %31 - strong_release %1 : $<τ_0_0> { var τ_0_0 } in () -> @out A for <()>>> + strong_release %1 : $<τ_0_0> { var τ_0_0 } () -> @out A for <()>>> %33 = tuple () // user: %34 return %33 : $() // id: %34 } sil [transparent] @_TFs22_doesOptionalHaveValueU__FT1vRGSqQ___Bi1_ : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 sil [transparent] @_TFs17_getOptionalValueU__FT1vGSqQ___Q_ : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>) -> @out τ_0_0 -sil [transparent] @_TTRXFo_iT__iT__XFo__dT__ : $@convention(thin) (@guaranteed @callee_guaranteed in () -> @out A for <()>) -> () +sil [transparent] @_TTRXFo_iT__iT__XFo__dT__ : $@convention(thin) (@guaranteed @callee_guaranteed @substituted () -> @out A for <()>) -> () sil [transparent] @_TFs24_injectValueIntoOptionalU__FT1vQ__GSqQ__ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> diff --git a/test/SIL/Parser/bound_generic.sil b/test/SIL/Parser/bound_generic.sil index d1bc784e063e0..37abbf9783b43 100644 --- a/test/SIL/Parser/bound_generic.sil +++ b/test/SIL/Parser/bound_generic.sil @@ -6,16 +6,16 @@ sil_stage raw import Builtin import Swift -// CHECK-LABEL: sil @_TF9optional3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>>) -> () -sil @_TF9optional3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed in () -> @out A for <()>>) -> () { -bb0(%0 : $Optional<@callee_guaranteed in () -> @out A for <()>>): - %1 = alloc_box $<τ_0_0> { var τ_0_0 } in () -> @out A for <()>>> - %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } in () -> @out A for <()>>>, 0 - store %0 to %1a : $*Optional<@callee_guaranteed in () -> @out A for <()>> +// CHECK-LABEL: sil @_TF9optional3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>>) -> () +sil @_TF9optional3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed @substituted () -> @out A for <()>>) -> () { +bb0(%0 : $Optional<@callee_guaranteed @substituted () -> @out A for <()>>): + %1 = alloc_box $<τ_0_0> { var τ_0_0 } () -> @out A for <()>>> + %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } () -> @out A for <()>>>, 0 + store %0 to %1a : $*Optional<@callee_guaranteed @substituted () -> @out A for <()>> %3 = alloc_stack $Optional<()> %4 = alloc_stack $() - %5 = alloc_stack $Optional<@callee_guaranteed in () -> @out A for <()>> - copy_addr %1a to [initialization] %5 : $*Optional<@callee_guaranteed in () -> @out A for <()>> + %5 = alloc_stack $Optional<@callee_guaranteed @substituted () -> @out A for <()>> + copy_addr %1a to [initialization] %5 : $*Optional<@callee_guaranteed @substituted () -> @out A for <()>> // function_ref Swift._doesOptionalHaveValue (v : @inout Swift.Optional) -> Builtin.Int1 %7 = function_ref @_TFs22_doesOptionalHaveValueU__FT1vRGSqQ___Bi1_ : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 // CHECK: apply %{{[0-9]+}}<() -> ()>(%{{[0-9]+}}) : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 @@ -23,8 +23,8 @@ bb0(%0 : $Optional<@callee_guaranteed in () -> @out A for <()>>): br bb1 bb1: - destroy_addr %5 : $*Optional<@callee_guaranteed in () -> @out A for <()>> - dealloc_stack %5 : $*Optional<@callee_guaranteed in () -> @out A for <()>> + destroy_addr %5 : $*Optional<@callee_guaranteed @substituted () -> @out A for <()>> + dealloc_stack %5 : $*Optional<@callee_guaranteed @substituted () -> @out A for <()>> dealloc_stack %4 : $*() br bb3 @@ -37,7 +37,7 @@ bb3: bb4: %30 = load %3 : $*Optional<()> dealloc_stack %3 : $*Optional<()> - release_value %1 : $<τ_0_0> { var τ_0_0 } in () -> @out A for <()>>> + release_value %1 : $<τ_0_0> { var τ_0_0 } () -> @out A for <()>>> %33 = tuple () return %33 : $() } diff --git a/test/SIL/Parser/errors.sil b/test/SIL/Parser/errors.sil index a0a1c331d24ab..72b780fa6e250 100644 --- a/test/SIL/Parser/errors.sil +++ b/test/SIL/Parser/errors.sil @@ -50,3 +50,9 @@ sil [ossa] @missing_type : $@convention(thin) (Int) -> () { bb0(%0 : $Int): br bb3(%0) // expected-error {{expected ':' before type in SIL value reference}} } + +sil @test_formal_substituted_type : $@convention(thin) (@owned Array<@substituted (Z) -> (Z) for >) -> () { +// expected-error@-1 {{substitutions cannot be provided on a formal function type}} +entry(%0 : $Array): + return undef : $() +} diff --git a/test/SIL/Parser/keypath.sil b/test/SIL/Parser/keypath.sil index 011cbc6420f23..5efc15982474e 100644 --- a/test/SIL/Parser/keypath.sil +++ b/test/SIL/Parser/keypath.sil @@ -96,8 +96,8 @@ sil @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int sil @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> () sil @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int sil @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> () -sil @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed in (@in_guaranteed A) -> @out B for ) -> @out @callee_guaranteed in (@in_guaranteed A) -> @out B for -sil @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed in (@in_guaranteed A) -> @out B for , @in_guaranteed @callee_guaranteed in (@in_guaranteed A) -> @out B for ) -> () +sil @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for ) -> @out @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for +sil @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for , @in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for ) -> () sil @get_s_int_subs : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out Int sil @set_s_int_subs : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S, UnsafeRawPointer) -> () sil @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool @@ -115,13 +115,13 @@ entry: %a = keypath $KeyPath, (root $S; gettable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int) // CHECK: keypath $WritableKeyPath, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ()) %b = keypath $WritableKeyPath, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ()) - // CHECK: keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> ()) + // CHECK: keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> ()) %c = keypath $WritableKeyPath<(S) -> S, (C) -> C>, ( root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), - getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed in (@in_guaranteed A) -> @out B for ) -> @out @callee_guaranteed in (@in_guaranteed A) -> @out B for , - setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed in (@in_guaranteed A) -> @out B for , @in_guaranteed @callee_guaranteed in (@in_guaranteed A) -> @out B for ) -> ()) + getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for ) -> @out @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for , + setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for , @in_guaranteed @callee_guaranteed @substituted (@in_guaranteed A) -> @out B for ) -> ()) // CHECK: keypath $WritableKeyPath, (root $C; settable_property $Int, id #C.overridable!getter.1 : (C) -> () -> Int, getter @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ()) %d = keypath $WritableKeyPath, (root $C; settable_property $Int, id #C.overridable!getter.1 : (C) -> () -> Int, getter @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ()) diff --git a/test/SIL/Parser/subst_function_type.sil b/test/SIL/Parser/subst_function_type.sil index 06052212b4e7b..1b9bb329b7f07 100644 --- a/test/SIL/Parser/subst_function_type.sil +++ b/test/SIL/Parser/subst_function_type.sil @@ -4,14 +4,20 @@ sil_stage raw import Swift -// CHECK-LABEL: sil @test : $@convention(thin) (@guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in τ_0_0, @in τ_0_1) -> () for ) -> () -sil @test : $@convention(thin) (@guaranteed @callee_guaranteed in (@in A, @in B) -> () for ) -> () { -entry(%0 : $@callee_guaranteed in (@in C, @in D) -> () for ): +// CHECK-LABEL: sil @test : $@convention(thin) (@guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_1) -> () for ) -> () +sil @test : $@convention(thin) (@guaranteed @callee_guaranteed @substituted (@in A, @in B) -> () for ) -> () { +entry(%0 : $@callee_guaranteed @substituted (@in C, @in D) -> () for ): return undef : $() } -// CHECK-LABEL: sil @test_generic_context : $@convention(thin) (@guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in τ_0_0, @in τ_0_1) -> () for ) -> () -sil @test_generic_context : $@convention(thin) (@guaranteed @callee_guaranteed in (@in A, @in B) -> () for ) -> () { -entry(%0 : $@callee_guaranteed in (@in C, @in D) -> () for ): +// CHECK-LABEL: sil @test_generic_context : $@convention(thin) (@guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_1) -> () for ) -> () +sil @test_generic_context : $@convention(thin) (@guaranteed @callee_guaranteed @substituted (@in A, @in B) -> () for ) -> () { +entry(%0 : $@callee_guaranteed @substituted (@in C, @in D) -> () for ): + return undef : $() +} + +sil @test_substituted_generic : $@convention(thin) @substituted (@in Z) -> (@out Z) for <(X, Y)> { +entry(%0 : $*(X, Y), %1 : $*(X, Y)): + copy_addr [take] %1 to [initialization] %0 : $*(X,Y) return undef : $() } diff --git a/test/SIL/Serialization/basic.sil b/test/SIL/Serialization/basic.sil index b4ad226fd01ae..8c7f8fcb4c5b9 100644 --- a/test/SIL/Serialization/basic.sil +++ b/test/SIL/Serialization/basic.sil @@ -38,9 +38,9 @@ struct Int32 { var x: Builtin.Int32 } -// CHECK-LABEL: sil [serialized] [ossa] @test_subst_function_type : $@convention(thin) (@guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in τ_0_0, @in τ_0_1) -> () for ) -> () -sil [serialized] [ossa] @test_subst_function_type : $@convention(thin) (@guaranteed @callee_guaranteed in (@in A, @in B) -> () for ) -> () { -entry(%0 : @guaranteed $@callee_guaranteed in (@in C, @in D) -> () for ): +// CHECK-LABEL: sil [serialized] [ossa] @test_subst_function_type : $@convention(thin) (@guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_1) -> () for ) -> () +sil [serialized] [ossa] @test_subst_function_type : $@convention(thin) (@guaranteed @callee_guaranteed @substituted (@in A, @in B) -> () for ) -> () { +entry(%0 : @guaranteed $@callee_guaranteed @substituted (@in C, @in D) -> () for ): return undef : $() } @@ -52,9 +52,9 @@ bb0(%0 : @owned $(Builtin.NativeObject, Builtin.Int32), %1 : @owned $TestArray2) return %7 : $(Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Int32, TestArrayStorage) } -// CHECK-LABEL: sil [serialized] [ossa] @test_subst_function_type_generic_context : $@convention(thin) (@guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in τ_0_0, @in τ_0_1) -> () for ) -> () -sil [serialized] [ossa] @test_subst_function_type_generic_context : $@convention(thin) (@guaranteed @callee_guaranteed in (@in A, @in B) -> () for ) -> () { -entry(%0 : @guaranteed $@callee_guaranteed in (@in C, @in D) -> () for ): +// CHECK-LABEL: sil [serialized] [ossa] @test_subst_function_type_generic_context : $@convention(thin) (@guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_1) -> () for ) -> () +sil [serialized] [ossa] @test_subst_function_type_generic_context : $@convention(thin) (@guaranteed @callee_guaranteed @substituted (@in A, @in B) -> () for ) -> () { +entry(%0 : @guaranteed $@callee_guaranteed @substituted (@in C, @in D) -> () for ): return undef : $() } diff --git a/test/SIL/Serialization/keypath.sil b/test/SIL/Serialization/keypath.sil index 87d9f749a0eae..60a65f10a9d6c 100644 --- a/test/SIL/Serialization/keypath.sil +++ b/test/SIL/Serialization/keypath.sil @@ -135,8 +135,8 @@ sil @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int sil @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> () sil @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int sil @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> () -sil @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for -sil @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +sil @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for +sil @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () sil @get_s_int_subs : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out Int sil @set_s_int_subs : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S, UnsafeRawPointer) -> () sil @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool @@ -153,8 +153,8 @@ entry: %a = keypath $KeyPath, (root $S; gettable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int) // CHECK: keypath $WritableKeyPath, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ()) %b = keypath $WritableKeyPath, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ()) - // CHECK: keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> ()) - %c = keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> ()) + // CHECK: keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> ()) + %c = keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> @out @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> ()) // CHECK: keypath $WritableKeyPath, (root $C; settable_property $Int, id #C.overridable!getter.1 : (C) -> () -> Int, getter @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ()) %d = keypath $WritableKeyPath, (root $C; settable_property $Int, id #C.overridable!getter.1 : (C) -> () -> Int, getter @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ()) diff --git a/test/SIL/ownership-verifier/over_consume.sil b/test/SIL/ownership-verifier/over_consume.sil index b8d8ce62d7e13..56f95118d1429 100644 --- a/test/SIL/ownership-verifier/over_consume.sil +++ b/test/SIL/ownership-verifier/over_consume.sil @@ -460,32 +460,6 @@ bb0(%0 : @owned $Klass): return %9999 : $() } -// CHECK-LABEL: Function: 'init_existential_ref_not_forwarding' -// CHECK: Have operand with incompatible ownership?! -// CHECK: Value: %0 = argument of bb0 : $ClassProtConformingRef -// CHECK: User: %2 = init_existential_ref %0 : $ClassProtConformingRef : $ClassProtConformingRef, $ClassProt -// CHECK: Operand Number: 0 -// CHECK: Conv: guaranteed -// CHECK: OwnershipMap: -// CHECK: -- OperandOwnershipKindMap -- -// CHECK: unowned: No. -// CHECK: owned: Yes. Liveness: MustBeInvalidated -// CHECK: guaranteed: No. -// CHECK: any: Yes. Liveness: MustBeLive -// CHECK-NOT: init_existential_ref %1 -// CHECK: Function: 'init_existential_ref_not_forwarding' -// CHECK: Error! Found a leaked owned value that was never consumed. -// CHECK: Value: %2 = init_existential_ref %0 : $ClassProtConformingRef : $ClassProtConformingRef, $ClassProt -// CHECK-NOT: init_existential_ref %1 -sil [ossa] @init_existential_ref_not_forwarding : $@convention(thin) (@guaranteed ClassProtConformingRef, @owned ClassProtConformingRef) -> @owned (ClassProt, ClassProt) { -bb0(%0 : @guaranteed $ClassProtConformingRef, %1 : @owned $ClassProtConformingRef): - %2 = init_existential_ref %0 : $ClassProtConformingRef : $ClassProtConformingRef, $ClassProt - %3 = copy_value %2 : $ClassProt - %4 = init_existential_ref %1 : $ClassProtConformingRef : $ClassProtConformingRef, $ClassProt - %5 = tuple(%3 : $ClassProt, %4 : $ClassProt) - return %5 : $(ClassProt, ClassProt) -} - sil [ossa] @eliminate_copy_try_apple_callee : $@convention(thin) (@owned Builtin.NativeObject) -> @error Error { entry(%0 : @owned $Builtin.NativeObject): %9999 = tuple() diff --git a/test/SIL/ownership-verifier/use_verifier.sil b/test/SIL/ownership-verifier/use_verifier.sil index 2f1b6c2933a15..066d20707bb85 100644 --- a/test/SIL/ownership-verifier/use_verifier.sil +++ b/test/SIL/ownership-verifier/use_verifier.sil @@ -109,6 +109,10 @@ class UnsafeUnownedFieldKlass { unowned(safe) var x: @sil_unowned Builtin.NativeObject } +class ClassProtConformingRef {} +protocol ClassProt : AnyObject {} +extension ClassProtConformingRef : ClassProt {} + //////////////// // Test Cases // //////////////// @@ -1292,3 +1296,12 @@ bb4: destroy_value %1 : $Builtin.NativeObject return %9999 : $() } + +sil [ossa] @init_existential_ref_forwarding : $@convention(thin) (@guaranteed ClassProtConformingRef, @owned ClassProtConformingRef) -> @owned (ClassProt, ClassProt) { +bb0(%0 : @guaranteed $ClassProtConformingRef, %1 : @owned $ClassProtConformingRef): + %2 = init_existential_ref %0 : $ClassProtConformingRef : $ClassProtConformingRef, $ClassProt + %3 = copy_value %2 : $ClassProt + %4 = init_existential_ref %1 : $ClassProtConformingRef : $ClassProtConformingRef, $ClassProt + %5 = tuple(%3 : $ClassProt, %4 : $ClassProt) + return %5 : $(ClassProt, ClassProt) +} diff --git a/test/SILGen/addressors.swift b/test/SILGen/addressors.swift index 9f99ab9ce7c0b..465b14ccb71c2 100644 --- a/test/SILGen/addressors.swift +++ b/test/SILGen/addressors.swift @@ -175,7 +175,7 @@ func test_carray(_ array: inout CArray<(Int32) -> Int32>) -> Int32 { // CHECK: [[T0:%.*]] = function_ref @$s10addressors6CArrayVyxSiciau : // CHECK: [[T1:%.*]] = apply [[T0]]<(Int32) -> Int32>({{%.*}}, [[WRITE]]) // CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<(Int32) -> Int32>, #UnsafeMutablePointer._rawValue -// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for +// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[T3]] // CHECK: store {{%.*}} to [[ACCESS]] : array[0] = id_int @@ -185,7 +185,7 @@ func test_carray(_ array: inout CArray<(Int32) -> Int32>) -> Int32 { // CHECK: [[T1:%.*]] = function_ref @$s10addressors6CArrayVyxSicilu : // CHECK: [[T2:%.*]] = apply [[T1]]<(Int32) -> Int32>({{%.*}}, [[T0]]) // CHECK: [[T3:%.*]] = struct_extract [[T2]] : $UnsafePointer<(Int32) -> Int32>, #UnsafePointer._rawValue -// CHECK: [[T4:%.*]] = pointer_to_address [[T3]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for +// CHECK: [[T4:%.*]] = pointer_to_address [[T3]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for // CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[T4]] // CHECK: [[T5:%.*]] = load [[ACCESS]] return array[1](5) diff --git a/test/SILGen/apply_abstraction_nested.swift b/test/SILGen/apply_abstraction_nested.swift index bd275b486028b..1d458baafc1fd 100644 --- a/test/SILGen/apply_abstraction_nested.swift +++ b/test/SILGen/apply_abstraction_nested.swift @@ -19,8 +19,8 @@ struct X : P {} var a = X() (a~>bar)(()) -// CHECK: [[CHAINED_FUNC:%.*]] = apply {{%.*}}({{%.*}}, {{%.*}}) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P> (@inout τ_0_0, @noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (@inout τ_0_0) -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_1, τ_0_2> for <τ_0_0, τ_0_1, τ_0_2>) -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_1, τ_0_2> -// CHECK: [[CHAINED_FUNC_CONV:%.*]] = convert_function [[CHAINED_FUNC]] : $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for <(), ()> to $@callee_guaranteed (@in_guaranteed ()) -> @out () +// CHECK: [[CHAINED_FUNC:%.*]] = apply {{%.*}}({{%.*}}, {{%.*}}) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P> (@inout τ_0_0, @noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@inout τ_0_0) -> (@owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_1, τ_0_2>) for <τ_0_0, τ_0_1, τ_0_2>) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_1, τ_0_2> +// CHECK: [[CHAINED_FUNC_CONV:%.*]] = convert_function [[CHAINED_FUNC]] : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <(), ()> to $@callee_guaranteed (@in_guaranteed ()) -> @out () // CHECK: [[REABSTRACT:%.*]] = function_ref @$sytytIegnr_Ieg_TR // CHECK: [[CHAINED_FUNC_REABSTRACTED:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]([[CHAINED_FUNC_CONV]]) // CHECK: [[BORROW:%.*]] = begin_borrow [[CHAINED_FUNC_REABSTRACTED]] diff --git a/test/SILGen/array_literal_abstraction.swift b/test/SILGen/array_literal_abstraction.swift index beca7cc09eee7..2b7b3e5a1379b 100644 --- a/test/SILGen/array_literal_abstraction.swift +++ b/test/SILGen/array_literal_abstraction.swift @@ -5,13 +5,13 @@ // // CHECK-LABEL: sil hidden [ossa] @$s25array_literal_abstraction0A9_of_funcsSayyycGyF -// CHECK: pointer_to_address {{.*}} $*@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()> +// CHECK: pointer_to_address {{.*}} $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()> func array_of_funcs() -> [(() -> ())] { return [{}, {}] } // CHECK-LABEL: sil hidden [ossa] @$s25array_literal_abstraction13dict_of_funcsSDySiyycGyF -// CHECK: pointer_to_address {{.*}} $*(Int, @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>) +// CHECK: pointer_to_address {{.*}} $*(Int, @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>) func dict_of_funcs() -> Dictionary ()> { return [0: {}, 1: {}] } @@ -19,7 +19,7 @@ func dict_of_funcs() -> Dictionary ()> { func vararg_funcs(_ fs: (() -> ())...) {} // CHECK-LABEL: sil hidden [ossa] @$s25array_literal_abstraction17call_vararg_funcsyyF -// CHECK: pointer_to_address {{.*}} $*@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()> +// CHECK: pointer_to_address {{.*}} $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()> func call_vararg_funcs() { vararg_funcs({}, {}) } diff --git a/test/SILGen/capture_typed_boxes.swift b/test/SILGen/capture_typed_boxes.swift index 11a11df774bd5..e7cfe9a10ab1a 100644 --- a/test/SILGen/capture_typed_boxes.swift +++ b/test/SILGen/capture_typed_boxes.swift @@ -27,6 +27,6 @@ func closure_generic(_ f: @escaping (T) -> T, x: T) -> T { return bar(x) } -// CHECK-LABEL: sil private [ossa] @$s19capture_typed_boxes15closure_generic{{.*}} : $@convention(thin) (@in_guaranteed T, @guaranteed <τ_0_0> { var @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_0, τ_0_0> } ) -> @out T { -// CHECK-LABEL: bb0(%0 : $*T, %1 : $*T, %2 : @guaranteed $<τ_0_0> { var @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_0, τ_0_0> } ): +// CHECK-LABEL: sil private [ossa] @$s19capture_typed_boxes15closure_generic{{.*}} : $@convention(thin) (@in_guaranteed T, @guaranteed <τ_0_0> { var @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_0, τ_0_0> } ) -> @out T { +// CHECK-LABEL: bb0(%0 : $*T, %1 : $*T, %2 : @guaranteed $<τ_0_0> { var @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_0, τ_0_0> } ): diff --git a/test/SILGen/closures.swift b/test/SILGen/closures.swift index 0acac2812ce70..33ab5c1747db4 100644 --- a/test/SILGen/closures.swift +++ b/test/SILGen/closures.swift @@ -7,7 +7,7 @@ import Swift var zero = 0 // -// CHECK-LABEL: sil hidden [ossa] @$s8closures46return_local_generic_function_without_captures{{[_0-9a-zA-Z]*}}F : $@convention(thin) () -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for { +// CHECK-LABEL: sil hidden [ossa] @$s8closures46return_local_generic_function_without_captures{{[_0-9a-zA-Z]*}}F : $@convention(thin) () -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for { func return_local_generic_function_without_captures() -> (A) -> R { func f(_: A) -> R { diff --git a/test/SILGen/coroutine_subst_function_types.swift b/test/SILGen/coroutine_subst_function_types.swift new file mode 100644 index 0000000000000..3e53ec257b617 --- /dev/null +++ b/test/SILGen/coroutine_subst_function_types.swift @@ -0,0 +1,122 @@ +// RUN: %target-swift-emit-silgen -module-name mod %s | %FileCheck %s + +class Generic { + init() { preconditionFailure("death") } + + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC7genericxvM : $@yield_once @convention(method) (@guaranteed Generic) -> @yields @inout T + var generic: T + + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC15genericFunctionxycvM : $@yield_once @convention(method) (@guaranteed Generic) -> @yields @inout @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for + var genericFunction: () -> T + + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC09returningB0xqd___tcluiM : $@yield_once @convention(method) (@in_guaranteed U, @guaranteed Generic) -> @yields @inout T + subscript(returningGeneric i: U) -> T { + get { return generic } + set {} + } + + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC012returningOwnB0qd__qd___tcluiM : $@yield_once @convention(method) (@in_guaranteed U, @guaranteed Generic) -> @yields @inout U { + subscript(returningOwnGeneric i: U) -> U { + get { return i } + set {} + } + + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod7GenericC12complexTuplexSg_SDySSxGtvM : $@yield_once @convention(method) (@guaranteed Generic) -> @yields @inout (Optional, Dictionary) + var complexTuple: (T?, [String: T]) +} + +class ConcreteWithInt: Generic { + override init() { preconditionFailure("death") } + + // The concrete implementations. Not actually important. + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC7genericSivM : $@yield_once @convention(method) (@guaranteed ConcreteWithInt) -> @yields @inout Int + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC15genericFunctionSiycvM : $@yield_once @convention(method) (@guaranteed ConcreteWithInt) -> @yields @inout @callee_guaranteed () -> Int + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC16returningGenericSix_tcluiM : $@yield_once @convention(method) (@in_guaranteed U, @guaranteed ConcreteWithInt) -> @yields @inout Int + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC19returningOwnGenericxx_tcluiM : $@yield_once @convention(method) (@in_guaranteed U, @guaranteed ConcreteWithInt) -> @yields @inout U + // CHECK-LABEL: sil hidden [transparent] [ossa] @$s3mod15ConcreteWithIntC12complexTupleSiSg_SDySSSiGtvM : $@yield_once @convention(method) (@guaranteed ConcreteWithInt) -> @yields @inout (Optional, Dictionary) + + // The override thunks. Note that the yields all exactly match the + // original methods above in terms of where archetypes / type parameters + // appear. + + // CHECK-LABEL: sil private [thunk] [ossa] @$s3mod15ConcreteWithIntC7genericSivMAA7GenericCADxvMTV : $@yield_once @convention(method) @substituted <τ_0_0> (@guaranteed ConcreteWithInt) -> @yields @inout τ_0_0 for + override var generic: Int { + get { super.generic } + set {} + } + + // CHECK-LABEL: sil private [thunk] [ossa] @$s3mod15ConcreteWithIntC15genericFunctionSiycvMAA7GenericCADxycvMTV : $@yield_once @convention(method) @substituted <τ_0_0> (@guaranteed ConcreteWithInt) -> (@yields @inout @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>) for + override var genericFunction: () -> Int { + get { super.genericFunction } + set {} + } + + // CHECK-LABEL: sil private [thunk] [ossa] @$s3mod15ConcreteWithIntC16returningGenericSix_tcluiMAA0F0CADxqd___tcluiMTV : $@yield_once @convention(method) <τ_0_0> @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed ConcreteWithInt) -> @yields @inout τ_0_1 for <τ_0_0, Int> + override subscript(returningGeneric i: U) -> Int { + get { return 0 } + set {} + } + + // This one doesn't need a thunk. + override subscript(returningOwnGeneric i: U) -> U { + get { return i } + set {} + } + + // CHECK-LABEL: sil private [thunk] [ossa] @$s3mod15ConcreteWithIntC12complexTupleSiSg_SDySSSiGtvMAA7GenericCADxSg_SDySSxGtvMTV : $@yield_once @convention(method) @substituted <τ_0_0, τ_0_1> (@guaranteed ConcreteWithInt) -> @yields @inout (Optional<τ_0_0>, Dictionary) for + override var complexTuple: (Int?, [String: Int]) { + get { super.complexTuple } + set {} + } +} + +protocol ProtoWithAssoc { + associatedtype Assoc + + @_borrowed + var generic: Assoc { get set } + + @_borrowed + var genericFunction: () -> Assoc { get set } + + @_borrowed + subscript(returningGeneric i: U) -> Assoc { get set } + + @_borrowed + subscript(returningOwnGeneric i: U) -> U { get set } + + @_borrowed + var complexTuple: (Assoc?, [String: Assoc]) { get set } +} +extension ConcreteWithInt : ProtoWithAssoc { + // The unsubstituted yields here should match the natural + // abstractions for the protocol. + + // var generic + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP7generic0F0QzvrTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_1 for + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP7generic0F0QzvMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> @yields @inout τ_0_1 for + + // var genericFunction + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP15genericFunction0F0QzycvrTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> (@yields @guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_1>) for + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP15genericFunction0F0QzycvMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> (@yields @inout @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_1>) for + + // subscript(returningGeneric:) + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP16returningGeneric0F0Qzqd___tcluirTW : $@yield_once @convention(witness_method: ProtoWithAssoc) <τ_0_0> @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @yields @in_guaranteed τ_0_2 for <τ_0_0, ConcreteWithInt, Int> + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP16returningGeneric0F0Qzqd___tcluiMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) <τ_0_0> @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @inout τ_0_1) -> @yields @inout τ_0_2 for <τ_0_0, ConcreteWithInt, Int> + + // subscript(returningOwnGeneric:) + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP19returningOwnGenericqd__qd___tcluirTW : $@yield_once @convention(witness_method: ProtoWithAssoc) <τ_0_0> @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @yields @in_guaranteed τ_0_2 for <τ_0_0, ConcreteWithInt, τ_0_0> + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP19returningOwnGenericqd__qd___tcluiMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) <τ_0_0> @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0, @inout τ_0_1) -> @yields @inout τ_0_2 for <τ_0_0, ConcreteWithInt, τ_0_0> + + // var complexTuple + // CHECK-LABEL: sil shared [ossa] @$s3mod15ConcreteWithIntC12complexTupleSiSg_SDySSSiGtvr : $@yield_once @convention(method) (@guaranteed ConcreteWithInt) -> (@yields Optional, @yields @guaranteed Dictionary) + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s3mod15ConcreteWithIntCAA05ProtoC5AssocA2aDP12complexTuple0F0QzSg_SDySSAHGtvMTW : $@yield_once @convention(witness_method: ProtoWithAssoc) @substituted <τ_0_0, τ_0_1, τ_0_2> (@inout τ_0_0) -> @yields @inout (Optional<τ_0_1>, Dictionary) for +} + +// CHECK-LABEL: sil_vtable ConcreteWithInt { +// CHECK: #Generic.generic!modify.1: (Generic) -> () -> () : @$s3mod15ConcreteWithIntC7genericSivMAA7GenericCADxvMTV [override] +// CHECK: #Generic.genericFunction!modify.1: (Generic) -> () -> () : @$s3mod15ConcreteWithIntC15genericFunctionSiycvMAA7GenericCADxycvMTV [override] +// CHECK: #Generic.subscript!modify.1: (Generic) -> (U) -> () : @$s3mod15ConcreteWithIntC16returningGenericSix_tcluiMAA0F0CADxqd___tcluiMTV [override] +// CHECK: #Generic.subscript!modify.1: (Generic) -> (U) -> () : @$s3mod15ConcreteWithIntC19returningOwnGenericxx_tcluiM [override] +// CHECK: #Generic.complexTuple!modify.1: (Generic) -> () -> () : @$s3mod15ConcreteWithIntC12complexTupleSiSg_SDySSSiGtvMAA7GenericCADxSg_SDySSxGtvMTV [override] +// CHECK: } diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift index 48c5870970832..8fc06fb8ed67a 100644 --- a/test/SILGen/default_arguments.swift +++ b/test/SILGen/default_arguments.swift @@ -236,8 +236,8 @@ class ReabstractDefaultArgument { // CHECK-LABEL: sil hidden [ossa] @$s17default_arguments32testDefaultArgumentReabstractionyyF // function_ref default_arguments.ReabstractDefaultArgument.__allocating_init (default_arguments.ReabstractDefaultArgument.Type)(a : (A, A) -> Swift.Bool) -> default_arguments.ReabstractDefaultArgument -// CHECK: [[FN:%.*]] = function_ref @$s17default_arguments25ReabstractDefaultArgument{{.*}} : $@convention(thin) <τ_0_0> () -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> Bool for <τ_0_0, τ_0_0> -// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]() : $@convention(thin) <τ_0_0> () -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> Bool for <τ_0_0, τ_0_0> +// CHECK: [[FN:%.*]] = function_ref @$s17default_arguments25ReabstractDefaultArgument{{.*}} : $@convention(thin) <τ_0_0> () -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> Bool for <τ_0_0, τ_0_0> +// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]() : $@convention(thin) <τ_0_0> () -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> Bool for <τ_0_0, τ_0_0> // CHECK-NEXT: [[RESULT_CONV:%.*]] = convert_function [[RESULT]] // CHECK-NEXT: function_ref reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed Swift.Int, @in_guaranteed Swift.Int) -> (@unowned Swift.Bool) to @escaping @callee_guaranteed (@unowned Swift.Int, @unowned Swift.Int) -> (@unowned Swift.Bool) // CHECK-NEXT: [[THUNK:%.*]] = function_ref @$sS2iSbIegnnd_S2iSbIegyyd_TR : $@convention(thin) (Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed Int, @in_guaranteed Int) -> Bool) -> Bool diff --git a/test/SILGen/dependent_member_lowering.swift b/test/SILGen/dependent_member_lowering.swift index c56c5bb527101..741d3abed47d1 100644 --- a/test/SILGen/dependent_member_lowering.swift +++ b/test/SILGen/dependent_member_lowering.swift @@ -17,6 +17,6 @@ struct Bar: P { typealias A = (Int) -> T func f(_ t: @escaping (Int) -> T) {} - // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s25dependent_member_lowering3BarVyxGAA1PA2aEP1fyy1AQzFTW : $@convention(witness_method: P) <τ_0_0> (@in_guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed Bar<τ_0_0>) -> () - // CHECK: bb0(%0 : $*@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , %1 : $*Bar<τ_0_0>): + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s25dependent_member_lowering3BarVyxGAA1PA2aEP1fyy1AQzFTW : $@convention(witness_method: P) <τ_0_0> (@in_guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed Bar<τ_0_0>) -> () + // CHECK: bb0(%0 : $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , %1 : $*Bar<τ_0_0>): } diff --git a/test/SILGen/downcast_reabstraction.swift b/test/SILGen/downcast_reabstraction.swift index e1e46f0e3c0d3..9d240f8555adc 100644 --- a/test/SILGen/downcast_reabstraction.swift +++ b/test/SILGen/downcast_reabstraction.swift @@ -2,7 +2,7 @@ // RUN: %target-swift-emit-silgen -module-name downcast_reabstraction %s | %FileCheck %s // CHECK-LABEL: sil hidden [ossa] @$s22downcast_reabstraction19condFunctionFromAnyyyypF -// CHECK: checked_cast_addr_br take_always Any in [[IN:%.*]] : $*Any to () -> () in [[OUT:%.*]] : $*@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]] +// CHECK: checked_cast_addr_br take_always Any in [[IN:%.*]] : $*Any to () -> () in [[OUT:%.*]] : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]] // CHECK: [[YES]]: // CHECK: [[ORIG_VAL:%.*]] = load [take] [[OUT]] // CHECK: [[CONV_VAL:%.*]] = convert_function [[ORIG_VAL]] @@ -16,7 +16,7 @@ func condFunctionFromAny(_ x: Any) { } // CHECK-LABEL: sil hidden [ossa] @$s22downcast_reabstraction21uncondFunctionFromAnyyyypF : $@convention(thin) (@in_guaranteed Any) -> () { -// CHECK: unconditional_checked_cast_addr Any in [[IN:%.*]] : $*Any to () -> () in [[OUT:%.*]] : $*@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()> +// CHECK: unconditional_checked_cast_addr Any in [[IN:%.*]] : $*Any to () -> () in [[OUT:%.*]] : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()> // CHECK: [[ORIG_VAL:%.*]] = load [take] [[OUT]] // CHECK: [[CONV_VAL:%.*]] = convert_function [[ORIG_VAL]] // CHECK: [[REABSTRACT:%.*]] = function_ref @$sytIegr_Ieg_TR diff --git a/test/SILGen/enum_curry_thunks.swift b/test/SILGen/enum_curry_thunks.swift index b239c50cd4e03..7325745b24f1f 100644 --- a/test/SILGen/enum_curry_thunks.swift +++ b/test/SILGen/enum_curry_thunks.swift @@ -35,17 +35,17 @@ func partialApplyEnumCases(_ x: S, y: C) { _ = PartialApplyEnumPayload.autoclosure } -// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO4leftyACyxq_GxcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (@in_guaranteed τ_0_0) -> @out PartialApplyEnumPayload<τ_0_1, τ_0_2> for { +// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO4leftyACyxq_GxcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> @out PartialApplyEnumPayload<τ_0_1, τ_0_2> for { // CHECK-LABEL: sil shared [transparent] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO4leftyACyxq_GxcAEmr0_lF : $@convention(method) (@in T, @thin PartialApplyEnumPayload.Type) -> @out PartialApplyEnumPayload { -// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO4bothyACyxq_Gx_q_tcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3> in (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out PartialApplyEnumPayload<τ_0_2, τ_0_3> for { +// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO4bothyACyxq_Gx_q_tcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out PartialApplyEnumPayload<τ_0_2, τ_0_3> for { // CHECK-LABEL: sil shared [transparent] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO4bothyACyxq_Gx_q_tcAEmr0_lF : $@convention(method) (@in T, @in U, @thin PartialApplyEnumPayload.Type) -> @out PartialApplyEnumPayload { -// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO13leftWithLabelyACyxq_Gx_tcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (@in_guaranteed τ_0_0) -> @out PartialApplyEnumPayload<τ_0_1, τ_0_2> for { +// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO13leftWithLabelyACyxq_Gx_tcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> @out PartialApplyEnumPayload<τ_0_1, τ_0_2> for { // CHECK-LABEL: sil shared [transparent] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO13leftWithLabelyACyxq_Gx_tcAEmr0_lF : $@convention(method) (@in T, @thin PartialApplyEnumPayload.Type) -> @out PartialApplyEnumPayload { -// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO14tupleWithLabelyACyxq_Gx_q_t_tcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3> in (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out PartialApplyEnumPayload<τ_0_2, τ_0_3> for { +// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO14tupleWithLabelyACyxq_Gx_q_t_tcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out PartialApplyEnumPayload<τ_0_2, τ_0_3> for { // CHECK-LABEL: sil shared [transparent] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO14tupleWithLabelyACyxq_Gx_q_t_tcAEmr0_lF : $@convention(method) (@in T, @in U, @thin PartialApplyEnumPayload.Type) -> @out PartialApplyEnumPayload { -// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO11autoclosureyACyxq_GyyXAcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@guaranteed @callee_guaranteed () -> ()) -> @out PartialApplyEnumPayload<τ_0_0, τ_0_1> for { +// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO11autoclosureyACyxq_GyyXAcAEmr0_lFTc : $@convention(thin) (@thin PartialApplyEnumPayload.Type) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@guaranteed @callee_guaranteed () -> ()) -> @out PartialApplyEnumPayload<τ_0_0, τ_0_1> for { // CHECK-LABEL: sil shared [transparent] [ossa] @$s17enum_curry_thunks23PartialApplyEnumPayloadO11autoclosureyACyxq_GyyXAcAEmr0_lF : $@convention(method) (@owned @callee_guaranteed () -> (), @thin PartialApplyEnumPayload.Type) -> @out PartialApplyEnumPayload { diff --git a/test/SILGen/function_conversion.swift b/test/SILGen/function_conversion.swift index e00d8f06ed936..c658b84712938 100644 --- a/test/SILGen/function_conversion.swift +++ b/test/SILGen/function_conversion.swift @@ -349,7 +349,7 @@ func convFuncExistential(_ f1: @escaping (Any) -> (Int) -> Int) { // CHECK-NEXT: partial_apply // CHECK-NEXT: convert_function // CHECK-NEXT: init_existential_addr %0 : $*Any, $(Int) -> Int -// CHECK-NEXT: store {{.*}} to {{.*}} : $*@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for +// CHECK-NEXT: store {{.*}} to {{.*}} : $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for // CHECK: return // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sS2iIegyd_S2iIegnr_TR : $@convention(thin) (@in_guaranteed Int, @guaranteed @callee_guaranteed (Int) -> Int) -> @out Int @@ -440,8 +440,8 @@ func convTupleToOptionalDirect(_ f: @escaping (Int) -> (Int, Int)) -> (Int) -> ( return f } -// CHECK-LABEL: sil hidden [ossa] @$s19function_conversion27convTupleToOptionalIndirectyx_xtSgxcx_xtxclF : $@convention(thin) (@guaranteed @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for ) -> @owned @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (@in_guaranteed τ_0_0) -> @out Optional<(τ_0_1, τ_0_2)> for -// CHECK: bb0([[ARG:%.*]] : @guaranteed $@callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for ): +// CHECK-LABEL: sil hidden [ossa] @$s19function_conversion27convTupleToOptionalIndirectyx_xtSgxcx_xtxclF : $@convention(thin) (@guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for ) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> @out Optional<(τ_0_1, τ_0_2)> for +// CHECK: bb0([[ARG:%.*]] : @guaranteed $@callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for ): // CHECK: [[FN:%.*]] = copy_value [[ARG]] // CHECK-NEXT: [[FN_CONV:%.*]] = convert_function [[FN]] // CHECK: [[THUNK_FN:%.*]] = function_ref @$sxxxIegnrr_xx_xtSgIegnr_lTR diff --git a/test/SILGen/function_type_conversion.swift b/test/SILGen/function_type_conversion.swift index 3e2aab4fbbdca..5bd4898377eb8 100644 --- a/test/SILGen/function_type_conversion.swift +++ b/test/SILGen/function_type_conversion.swift @@ -4,7 +4,7 @@ func generic(_ f: @escaping (T) -> U) -> (T) -> U { return f } // CHECK-LABEL: sil {{.*}}4main{{.*}}11sameGeneric func sameGeneric(_: X, _: Y, _ f: @escaping (Z) -> Z) -> (Z) -> Z { -// CHECK: bb0({{.*}}, [[F:%[0-9]+]] : @guaranteed $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for +// CHECK: bb0({{.*}}, [[F:%[0-9]+]] : @guaranteed $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for // Similarly generic types should be directly substitutable // CHECK: [[GENERIC:%.*]] = function_ref @{{.*}}4main{{.*}}7generic // CHECK: [[RET:%.*]] = apply [[GENERIC]]([[F]]) @@ -18,7 +18,7 @@ func concreteIndirect(_ f: @escaping (Any) -> Any) -> (Any) -> Any { // Any is passed indirectly, but is a concrete type, so we need to convert // to the generic abstraction level // CHECK: [[F2:%.*]] = copy_value [[F]] - // CHECK: [[GENERIC_F:%.*]] = convert_function [[F2]] : {{.*}} to $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for + // CHECK: [[GENERIC_F:%.*]] = convert_function [[F2]] : {{.*}} to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for // CHECK: [[GENERIC:%.*]] = function_ref @{{.*}}4main{{.*}}7generic // CHECK: [[GENERIC_RET:%.*]] = apply [[GENERIC]]([[GENERIC_F]]) // CHECK: [[RET:%.*]] = convert_function [[GENERIC_RET]] : {{.*}} @@ -33,7 +33,7 @@ func concreteDirect(_ f: @escaping (Int) -> String) -> (Int) -> String { // thunking and conversion to the substituted form // CHECK: [[F2:%.*]] = copy_value [[F]] // CHECK: [[REABSTRACT_F:%.*]] = partial_apply {{.*}}([[F2]]) - // CHECK: [[GENERIC_F:%.*]] = convert_function [[REABSTRACT_F]] : {{.*}} to $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for + // CHECK: [[GENERIC_F:%.*]] = convert_function [[REABSTRACT_F]] : {{.*}} to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for // CHECK: [[GENERIC:%.*]] = function_ref @{{.*}}4main{{.*}}7generic // CHECK: [[GENERIC_RET:%.*]] = apply [[GENERIC]]([[GENERIC_F]]) // CHECK: [[REABSTRACT_RET:%.*]] = convert_function [[GENERIC_RET]] : {{.*}} diff --git a/test/SILGen/function_type_lowering.swift b/test/SILGen/function_type_lowering.swift index 0b348af345d67..94c7e6a2003d9 100644 --- a/test/SILGen/function_type_lowering.swift +++ b/test/SILGen/function_type_lowering.swift @@ -4,19 +4,19 @@ // Similarly-abstract generic signatures should share an unsubstituted type // even in different generic contexts -// CHECK-LABEL: sil {{.*}}1a{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1a{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func a(_ x: (T) -> U) {} -// CHECK-LABEL: sil {{.*}}1b{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1b{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func b(_ x: (U) -> T) {} -// CHECK-LABEL: sil {{.*}}1c{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed U) -> () +// CHECK-LABEL: sil {{.*}}1c{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , @in_guaranteed U) -> () func c(_ x: (V) -> T, _: U) {} -// CHECK-LABEL: sil {{.*}}003Hca{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}003Hca{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func ç(_ x: (T) -> T) {} -// CHECK-LABEL: sil {{.*}}returnsThrowing{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for <τ_0_1, τ_0_2> for ) -> () +// CHECK-LABEL: sil {{.*}}returnsThrowing{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for <τ_0_1, τ_0_2>) for ) -> () { func returnsThrowing(_ x: (T) -> (U) throws -> V) {} @@ -26,26 +26,26 @@ protocol P { associatedtype A } -// CHECK-LABEL: sil {{.*}}1d{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1d{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func d(_ x: (T) -> T.A) {} -// CHECK-LABEL: sil {{.*}}1e{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1e{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func e(_ x: (T.A) -> T) {} // Preserve class constraints, because they're less abstract for layout and // calling convention purposes than unconstrained types -// CHECK-LABEL: sil {{.*}}1f{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1f{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func f(_ x: (T) -> U) {} -// CHECK-LABEL: sil {{.*}}1g{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_1 : _RefCountedObject> in (@in_guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1g{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_1 : _RefCountedObject> (@in_guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () func g(_ x: (U) -> T) {} -// CHECK-LABEL: sil {{.*}}1h{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> in (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1h{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () func h(_ x: (T) -> U) {} -// CHECK-LABEL: sil {{.*}}1i{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> in (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1i{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () func i(_ x: (U) -> T) {} @@ -53,19 +53,19 @@ func i(_ x: (U) -> T) {} protocol PC: AnyObject { } -// CHECK-LABEL: sil {{.*}}1j{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1j{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func j(_ x: (T) -> U) {} -// CHECK-LABEL: sil {{.*}}1k{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_1 : _RefCountedObject> in (@in_guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1k{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_1 : _RefCountedObject> (@in_guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () func k(_ x: (U) -> T) {} -// CHECK-LABEL: sil {{.*}}1l{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> in (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1l{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () func l(_ x: (T) -> U) {} -// CHECK-LABEL: sil {{.*}}1m{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> in (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1m{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () func m(_ x: (U) -> T) {} -// CHECK-LABEL: sil {{.*}}1n{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1n{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func n(_ x: (T) -> T.A) {} @@ -73,7 +73,7 @@ func n(_ x: (T) -> T.A) {} class Base {} -// CHECK-LABEL: sil {{.*}}1o{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1o{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func o (_ x: (T) -> U) {} @@ -91,11 +91,11 @@ protocol PCAC: AnyObject { associatedtype A: AnyObject } -// CHECK-LABEL: sil {{.*}}1p{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1p{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> @out τ_0_1 for ) -> () func p (_ x: (T) -> T.A) {} -// CHECK-LABEL: sil {{.*}}1q{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_1 : _RefCountedObject> in (@in_guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1q{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_1 : _RefCountedObject> (@in_guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () func q (_ x: (T) -> T.A) {} -// CHECK-LABEL: sil {{.*}}1r{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> in (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () +// CHECK-LABEL: sil {{.*}}1r{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> (@guaranteed τ_0_0) -> @owned τ_0_1 for ) -> () func r (_ x: (T) -> T.A) {} @@ -112,35 +112,35 @@ struct S { } } -// CHECK-LABEL: sil {{.*}}1t{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_1 : _RefCountedObject, τ_0_3 : _RefCountedObject> in (S<τ_0_0, τ_0_1>) -> (@out τ_0_2, @owned τ_0_3) for ) -> () +// CHECK-LABEL: sil {{.*}}1t{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_1 : _RefCountedObject, τ_0_3 : _RefCountedObject> (S<τ_0_0, τ_0_1>) -> (@out τ_0_2, @owned τ_0_3) for ) -> () func t(_: (S) -> (T, U)) {} -// CHECK-LABEL: sil {{.*}}2t2{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4 where τ_0_1 : _RefCountedObject, τ_0_2 : _RefCountedObject, τ_0_4 : _RefCountedObject> in (S<τ_0_0, τ_0_1>.Nested<τ_0_2>) -> (@out τ_0_3, @owned τ_0_4) for ) -> () +// CHECK-LABEL: sil {{.*}}2t2{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4 where τ_0_1 : _RefCountedObject, τ_0_2 : _RefCountedObject, τ_0_4 : _RefCountedObject> (S<τ_0_0, τ_0_1>.Nested<τ_0_2>) -> (@out τ_0_3, @owned τ_0_4) for ) -> () func t2(_: (S.Nested) -> (T, U)) {} -// CHECK-LABEL: sil {{.*}}2t3{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4, τ_0_5 where τ_0_1 : _RefCountedObject, τ_0_2 : _RefCountedObject, τ_0_5 : _RefCountedObject> in (S<τ_0_0, τ_0_1>.Nested<τ_0_2>.NesNestedted<τ_0_3>) -> (@out τ_0_4, @owned τ_0_5) for ) -> () +// CHECK-LABEL: sil {{.*}}2t3{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4, τ_0_5 where τ_0_1 : _RefCountedObject, τ_0_2 : _RefCountedObject, τ_0_5 : _RefCountedObject> (S<τ_0_0, τ_0_1>.Nested<τ_0_2>.NesNestedted<τ_0_3>) -> (@out τ_0_4, @owned τ_0_5) for ) -> () func t3(_: (S.Nested.NesNestedted) -> (T, U)) {} -// CHECK-LABEL: sil {{.*}}2t4{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4 where τ_0_1 : _RefCountedObject, τ_0_2 : _RefCountedObject, τ_0_4 : _RefCountedObject> in (S<τ_0_0, τ_0_1>.Nested<τ_0_2>.NestedNonGeneric) -> (@out τ_0_3, @owned τ_0_4) for ) -> () +// CHECK-LABEL: sil {{.*}}2t4{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4 where τ_0_1 : _RefCountedObject, τ_0_2 : _RefCountedObject, τ_0_4 : _RefCountedObject> (S<τ_0_0, τ_0_1>.Nested<τ_0_2>.NestedNonGeneric) -> (@out τ_0_3, @owned τ_0_4) for ) -> () func t4(_: (S.Nested.NestedNonGeneric) -> (T, U)) {} -// CHECK-LABEL: sil {{.*}}2t5{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_1 : _RefCountedObject, τ_0_3 : _RefCountedObject> in (S<τ_0_0, τ_0_1>.NestedNonGeneric) -> (@out τ_0_2, @owned τ_0_3) for ) -> () +// CHECK-LABEL: sil {{.*}}2t5{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_1 : _RefCountedObject, τ_0_3 : _RefCountedObject> (S<τ_0_0, τ_0_1>.NestedNonGeneric) -> (@out τ_0_2, @owned τ_0_3) for ) -> () func t5(_: (S.NestedNonGeneric) -> (T, U)) {} -// CHECK-LABEL: sil {{.*}}2t6{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4 where τ_0_1 : _RefCountedObject, τ_0_4 : _RefCountedObject> in (S<τ_0_0, τ_0_1>.NestedNonGeneric.NesNestedted<τ_0_2>) -> (@out τ_0_3, @owned τ_0_4) for ) -> () +// CHECK-LABEL: sil {{.*}}2t6{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4 where τ_0_1 : _RefCountedObject, τ_0_4 : _RefCountedObject> (S<τ_0_0, τ_0_1>.NestedNonGeneric.NesNestedted<τ_0_2>) -> (@out τ_0_3, @owned τ_0_4) for ) -> () func t6(_: (S.NestedNonGeneric.NesNestedted) -> (T, U)) {} -// CHECK-LABEL: sil {{.*}}2t7{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_1 : _RefCountedObject, τ_0_3 : _RefCountedObject> in (S<τ_0_0, τ_0_1>.NestedNonGeneric.NestedNonGeneric) -> (@out τ_0_2, @owned τ_0_3) for ) -> () +// CHECK-LABEL: sil {{.*}}2t7{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_1 : _RefCountedObject, τ_0_3 : _RefCountedObject> (S<τ_0_0, τ_0_1>.NestedNonGeneric.NestedNonGeneric) -> (@out τ_0_2, @owned τ_0_3) for ) -> () func t7(_: (S.NestedNonGeneric.NestedNonGeneric) -> (T, U)) {} -// CHECK-LABEL: sil {{.*}}1u{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (S<τ_0_0, τ_0_1>) -> @out τ_0_2 for ) -> () +// CHECK-LABEL: sil {{.*}}1u{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (S<τ_0_0, τ_0_1>) -> @out τ_0_2 for ) -> () func u(_: (S) -> T) {} class C {} -// CHECK-LABEL: sil {{.*}}1v{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_1 : _RefCountedObject, τ_0_3 : _RefCountedObject> in (@guaranteed C<τ_0_0, τ_0_1>) -> (@out τ_0_2, @owned τ_0_3) for ) -> () +// CHECK-LABEL: sil {{.*}}1v{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_1 : _RefCountedObject, τ_0_3 : _RefCountedObject> (@guaranteed C<τ_0_0, τ_0_1>) -> (@out τ_0_2, @owned τ_0_3) for ) -> () func v(_: (C) -> (T, U)) {} -// CHECK-LABEL: sil {{.*}}1w{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0, τ_0_1, τ_0_2> in (@guaranteed C<τ_0_0, τ_0_1>) -> @out τ_0_2 for ) -> () +// CHECK-LABEL: sil {{.*}}1w{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@guaranteed C<τ_0_0, τ_0_1>) -> @out τ_0_2 for ) -> () func w(_: (C) -> T) {} -// CHECK-LABEL: sil {{.*}}1x{{.*}} : $@convention(thin) > (@noescape @callee_guaranteed <τ_0_0 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> () for ) -> () +// CHECK-LABEL: sil {{.*}}1x{{.*}} : $@convention(thin) > (@noescape @callee_guaranteed @substituted <τ_0_0 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> () for ) -> () func x>(_: (V) -> Void) {} // We can't generally lower away protocol constraints @@ -151,17 +151,18 @@ func x>(_: (V) -> Void) {} struct SP { var x: T.A } class CP { } -// CHECK-LABEL: sil {{.*}}1z{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0 where τ_0_0 : P> in (@in_guaranteed SP<τ_0_0>) -> () for ) -> () +// CHECK-LABEL: sil {{.*}}1z{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0 where τ_0_0 : P> (@in_guaranteed SP<τ_0_0>) -> () for ) -> () func z(_: (SP) -> Void) {} struct SCP> {} -// CHECK-LABEL: sil {{.*}}2z2{{.*}} : $@convention(thin) > (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : P, τ_0_1 : CP, τ_0_1 : _NativeClass> in (SCP<τ_0_0, τ_0_1>) -> () for ) -> () +// CHECK-LABEL: sil {{.*}}2z2{{.*}} : $@convention(thin) > (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : P, τ_0_1 : CP<τ_0_0>, τ_0_1 : _NativeClass> (SCP<τ_0_0, τ_0_1>) -> () for ) -> () func z2>(_: (SCP) -> Void) {} -// CHECK-LABEL: sil {{.*}}3z2a{{.*}} : $@convention(thin) > (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_0 : P, τ_0_1 : CP, τ_0_1 : _NativeClass> in (SCP<τ_0_0, τ_0_1>) -> () for ) -> () + +// CHECK-LABEL: sil {{.*}}3z2a{{.*}} : $@convention(thin) > (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_0 : P, τ_0_1 : CP<τ_0_0>, τ_0_1 : _NativeClass> (SCP<τ_0_0, τ_0_1>) -> () for ) -> () func z2a>(_: (SCP) -> Void) {} -// CHECK-LABEL: sil {{.*}}2z3{{.*}} : $@convention(thin) > (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> in (S<τ_0_0, τ_0_1>) -> () for ) -> () +// CHECK-LABEL: sil {{.*}}2z3{{.*}} : $@convention(thin) > (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> (S<τ_0_0, τ_0_1>) -> () for ) -> () func z3>(_: (S) -> Void) {} // Opaque types should not be extracted as substituted arguments because they diff --git a/test/SILGen/function_type_lowering_inherited_conformance.swift b/test/SILGen/function_type_lowering_inherited_conformance.swift new file mode 100644 index 0000000000000..5a7721270d08b --- /dev/null +++ b/test/SILGen/function_type_lowering_inherited_conformance.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-emit-silgen %s | %FileCheck %s +protocol P {} + +class C: P {} +class D: C {} + +struct Butt {} + +func foo(_: (Butt) -> ()) {} + +// CHECK-LABEL: sil{{.*}}3bar +func bar(_ f: (Butt) -> ()) { + // CHECK: convert_function {{.*}} $@noescape @callee_guaranteed (Butt) -> () to $@noescape @callee_guaranteed @substituted <τ_0_0 where τ_0_0 : P> (Butt<τ_0_0>) -> () for + foo(f) +} diff --git a/test/SILGen/function_type_lowering_objc.swift b/test/SILGen/function_type_lowering_objc.swift index 8f12566fdac81..ffb5c23dac232 100644 --- a/test/SILGen/function_type_lowering_objc.swift +++ b/test/SILGen/function_type_lowering_objc.swift @@ -6,7 +6,7 @@ import Foundation -// CHECK-LABEL: sil {{.*}}3foo{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> () +// CHECK-LABEL: sil {{.*}}3foo{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> () func foo(f: (T) -> ()) {} -// CHECK-LABEL: sil {{.*}}3bar{{.*}} : $@convention(thin) (@noescape @callee_guaranteed <τ_0_0 where τ_0_0 : _RefCountedObject> in (@guaranteed Optional<τ_0_0>) -> () +// CHECK-LABEL: sil {{.*}}3bar{{.*}} : $@convention(thin) (@noescape @callee_guaranteed @substituted <τ_0_0 where τ_0_0 : _RefCountedObject> (@guaranteed Optional<τ_0_0>) -> () func bar(f: (T?) -> ()) {} diff --git a/test/SILGen/generic_closures.swift b/test/SILGen/generic_closures.swift index a09f142dd0be7..d208874ecaf8a 100644 --- a/test/SILGen/generic_closures.swift +++ b/test/SILGen/generic_closures.swift @@ -208,7 +208,7 @@ class Class {} protocol HasClassAssoc { associatedtype Assoc : Class } // CHECK-LABEL: sil hidden [ossa] @$s16generic_closures027captures_class_constrained_A0_1fyx_5AssocQzAEctAA08HasClassF0RzlF -// CHECK: bb0([[ARG1:%.*]] : $*T, [[ARG2:%.*]] : @guaranteed $@callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> in (@guaranteed τ_0_0) -> @owned τ_0_1 for ): +// CHECK: bb0([[ARG1:%.*]] : $*T, [[ARG2:%.*]] : @guaranteed $@callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject, τ_0_1 : _RefCountedObject> (@guaranteed τ_0_0) -> @owned τ_0_1 for ): // CHECK: [[GENERIC_FN:%.*]] = function_ref @$s16generic_closures027captures_class_constrained_A0_1fyx_5AssocQzAEctAA08HasClassF0RzlFA2EcycfU_ // CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]] // CHECK: [[CONCRETE_FN:%.*]] = partial_apply [callee_guaranteed] [[GENERIC_FN]]([[ARG2_COPY]]) diff --git a/test/SILGen/guaranteed_normal_args_curry_thunks.swift b/test/SILGen/guaranteed_normal_args_curry_thunks.swift index b0f767c17c153..484efb026e713 100644 --- a/test/SILGen/guaranteed_normal_args_curry_thunks.swift +++ b/test/SILGen/guaranteed_normal_args_curry_thunks.swift @@ -170,7 +170,7 @@ func testLoadableStructInitLoadable() { // extra thunk. // // CHECK-LABEL: sil hidden [ossa] @$ss37testAddrOnlyStructInitGenericConcreteyyF : $@convention(thin) () -> () { -// CHECK: [[THUNK_REF:%.*]] = function_ref @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) <τ_0_0> (@thin AddrOnlyStructInitGeneric<τ_0_0>.Type) -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_1> for <τ_0_0, τ_0_0> +// CHECK: [[THUNK_REF:%.*]] = function_ref @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) <τ_0_0> (@thin AddrOnlyStructInitGeneric<τ_0_0>.Type) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_1> for <τ_0_0, τ_0_0> // CHECK: [[CURRY_THUNK:%.*]] = apply [[THUNK_REF]]( // CHECK: [[CURRY_THUNK_CONV:%.*]] = convert_function [[CURRY_THUNK]] // CHECK: [[CANONICAL_THUNK_REF:%.*]] = function_ref @$ss5KlassCs25AddrOnlyStructInitGenericVyABGIegnr_AbEIeggo_TR : $@convention(thin) (@guaranteed Klass, @guaranteed @callee_guaranteed (@in_guaranteed Klass) -> @out AddrOnlyStructInitGeneric) -> @owned AddrOnlyStructInitGeneric @@ -184,7 +184,7 @@ func testLoadableStructInitLoadable() { // Curry thunk // -// CHECK-LABEL: sil shared [thunk] [ossa] @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) (@thin AddrOnlyStructInitGeneric.Type) -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_1> for { +// CHECK-LABEL: sil shared [thunk] [ossa] @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) (@thin AddrOnlyStructInitGeneric.Type) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_1> for { // CHECK: [[ALLOCATING_INIT_REF:%.*]] = function_ref @$ss25AddrOnlyStructInitGenericVyAByxGxcfC : $@convention(method) <τ_0_0> (@in τ_0_0, @thin AddrOnlyStructInitGeneric<τ_0_0>.Type) -> @out AddrOnlyStructInitGeneric<τ_0_0> // CHECK: [[ALLOCATING_INIT:%.*]] = partial_apply [callee_guaranteed] [[ALLOCATING_INIT_REF]]( // CHECK: [[THUNK_REF:%.*]] = function_ref @$sxs25AddrOnlyStructInitGenericVyxGIegir_xACIegnr_lTR : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_0>) -> @out AddrOnlyStructInitGeneric<τ_0_0> @@ -217,7 +217,7 @@ func testAddrOnlyStructInitGenericConcrete() { } // CHECK-LABEL: sil hidden [ossa] @$ss029testAddrOnlyStructInitGenericbC01tyx_ts08Protocole7AddressC0RzlF : $@convention(thin) (@in_guaranteed T) -> () { -// CHECK: [[CURRY_THUNK_REF:%.*]] = function_ref @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) <τ_0_0> (@thin AddrOnlyStructInitGeneric<τ_0_0>.Type) -> @owned @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_1> for <τ_0_0, τ_0_0> +// CHECK: [[CURRY_THUNK_REF:%.*]] = function_ref @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) <τ_0_0> (@thin AddrOnlyStructInitGeneric<τ_0_0>.Type) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_1> for <τ_0_0, τ_0_0> // CHECK: [[CURRY_THUNK:%.*]] = apply [[CURRY_THUNK_REF]]( // CHECK: [[Y:%.*]] = alloc_stack $AddrOnlyStructInitGeneric, let, name "y" // CHECK: [[BORROWED_CURRY_THUNK:%.*]] = begin_borrow [[CURRY_THUNK]] @@ -234,7 +234,7 @@ func testAddrOnlyStructInitGenericAddrOnly(t: T) { } // CHECK-LABEL: sil hidden [ossa] @$ss20testGenericInitClass1tyx_ts08ProtocolC8LoadableRzlF : $@convention(thin) (@in_guaranteed T) -> () { -// CHECK: [[CURRY_THUNK_REF:%.*]] = function_ref @$ss20ProtocolInitLoadableP1txs5KlassC_tcfCTc : $@convention(thin) <τ_0_0 where τ_0_0 : ProtocolInitLoadable> (@thick τ_0_0.Type) -> @owned @callee_guaranteed <τ_0_0> in (@guaranteed Klass) -> @out τ_0_0 for <τ_0_0> +// CHECK: [[CURRY_THUNK_REF:%.*]] = function_ref @$ss20ProtocolInitLoadableP1txs5KlassC_tcfCTc : $@convention(thin) <τ_0_0 where τ_0_0 : ProtocolInitLoadable> (@thick τ_0_0.Type) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed Klass) -> @out τ_0_0 for <τ_0_0> // CHECK: [[CURRY_THUNK:%.*]] = apply [[CURRY_THUNK_REF]]( // CHECK: [[Y:%.*]] = alloc_stack $T, let, name "y" // CHECK: [[BORROWED_CURRY_THUNK:%.*]] = begin_borrow [[CURRY_THUNK]] @@ -247,7 +247,7 @@ func testAddrOnlyStructInitGenericAddrOnly(t: T) { // Curry thunk. // -// CHECK-LABEL: sil shared [thunk] [ossa] @$ss20ProtocolInitLoadableP1txs5KlassC_tcfCTc : $@convention(thin) (@thick Self.Type) -> @owned @callee_guaranteed <τ_0_0> in (@guaranteed Klass) -> @out τ_0_0 for { +// CHECK-LABEL: sil shared [thunk] [ossa] @$ss20ProtocolInitLoadableP1txs5KlassC_tcfCTc : $@convention(thin) (@thick Self.Type) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed Klass) -> @out τ_0_0 for { // CHECK: [[WITNESS_METHOD_REF:%.*]] = witness_method $Self, #ProtocolInitLoadable.init!allocator.1 : (Self.Type) -> (Klass) -> Self : $@convention(witness_method: ProtocolInitLoadable) <τ_0_0 where τ_0_0 : ProtocolInitLoadable> (@owned Klass, @thick τ_0_0.Type) -> @out τ_0_0 // CHECK: [[WITNESS_METHOD:%.*]] = partial_apply [callee_guaranteed] [[WITNESS_METHOD_REF]]( // CHECK: [[CANONICAL_THUNK_REF:%.*]] = function_ref @$ss5KlassCxIegxr_ABxIeggr_s20ProtocolInitLoadableRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : ProtocolInitLoadable> (@guaranteed Klass, @guaranteed @callee_guaranteed (@owned Klass) -> @out τ_0_0) -> @out τ_0_0 diff --git a/test/SILGen/keypath_application.swift b/test/SILGen/keypath_application.swift index 514d070a3a74e..7fc83b8c0f318 100644 --- a/test/SILGen/keypath_application.swift +++ b/test/SILGen/keypath_application.swift @@ -200,12 +200,12 @@ func writebackNesting(x: inout Int, // -- get 'b' // CHECK: function_ref @$sSi19keypath_applicationE1bSivg // -- apply keypath y - // CHECK: [[PROJECT_FN:%.*]] = function_ref @swift_modifyAtWritableKeyPath : + // CHECK: [[PROJECT_FN:%.*]] = function_ref @swift_modifyAtWritableKeyPath : $@yield_once @convention(thin) <τ_0_0, τ_0_1> (@inout τ_0_0, @guaranteed WritableKeyPath<τ_0_0, τ_0_1>) -> @yields @inout τ_0_1 // CHECK: ([[Y_ADDR:%.*]], [[Y_TOKEN:%.*]]) = begin_apply [[PROJECT_FN]] // -- get 'u' // CHECK: function_ref @$sSi19keypath_applicationE1uSivg // -- apply keypath z - // CHECK: [[PROJECT_FN:%.*]] = function_ref @swift_modifyAtWritableKeyPath : + // CHECK: [[PROJECT_FN:%.*]] = function_ref @swift_modifyAtWritableKeyPath : $@yield_once @convention(thin) <τ_0_0, τ_0_1> (@inout τ_0_0, @guaranteed WritableKeyPath<τ_0_0, τ_0_1>) -> @yields @inout τ_0_1 // CHECK: ([[Z_ADDR:%.*]], [[Z_TOKEN:%.*]]) = begin_apply [[PROJECT_FN]] // -- set 'tt' diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift index 4a83001d2d3a3..5629ec01e14cf 100644 --- a/test/SILGen/keypaths.swift +++ b/test/SILGen/keypaths.swift @@ -111,8 +111,8 @@ func computedProperties(_: T) { // CHECK-SAME: root $C<τ_0_0>; // CHECK-SAME: settable_property $() -> (), // CHECK-SAME: id ##C.reabstracted, - // CHECK-SAME: getter @$s8keypaths1CC12reabstractedyycvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed C<τ_0_0>) -> @out @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>, - // CHECK-SAME: setter @$s8keypaths1CC12reabstractedyycvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>, @in_guaranteed C<τ_0_0>) -> () + // CHECK-SAME: getter @$s8keypaths1CC12reabstractedyycvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed C<τ_0_0>) -> @out @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>, + // CHECK-SAME: setter @$s8keypaths1CC12reabstractedyycvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>, @in_guaranteed C<τ_0_0>) -> () // CHECK-SAME: ) _ = \C.reabstracted @@ -140,8 +140,8 @@ func computedProperties(_: T) { // CHECK-SAME: root $S<τ_0_0>; // CHECK-SAME: settable_property $() -> (), // CHECK-SAME: id ##S.reabstracted, - // CHECK-SAME: getter @$s8keypaths1SV12reabstractedyycvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed S<τ_0_0>) -> @out @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>, - // CHECK-SAME: setter @$s8keypaths1SV12reabstractedyycvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>, @inout S<τ_0_0>) -> () + // CHECK-SAME: getter @$s8keypaths1SV12reabstractedyycvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed S<τ_0_0>) -> @out @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>, + // CHECK-SAME: setter @$s8keypaths1SV12reabstractedyycvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>, @inout S<τ_0_0>) -> () // CHECK-SAME: ) _ = \S.reabstracted diff --git a/test/SILGen/modify.swift b/test/SILGen/modify.swift index 00aa7621023c9..328819da93f7d 100644 --- a/test/SILGen/modify.swift +++ b/test/SILGen/modify.swift @@ -64,7 +64,7 @@ extension Derived : Abstractable {} // CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base // CHECK-NEXT: [[FN:%.*]] = class_method [[SELF]] : $Base, #Base.storedFunction!modify.1 // CHECK-NEXT: ([[SUPER_ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[FN]]([[SELF]]) -// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for +// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for // CHECK-NEXT: [[SUPER_FN:%.*]] = load [take] [[SUPER_ADDR]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int @@ -92,7 +92,7 @@ extension Derived : Abstractable {} // CHECK-NEXT: // function_ref // CHECK-NEXT: [[FN:%.*]] = function_ref @$s6modify4BaseC19finalStoredFunctionSiycvM // CHECK-NEXT: ([[SUPER_ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[FN]]([[SELF]]) -// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for +// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for // CHECK-NEXT: [[SUPER_FN:%.*]] = load [take] [[SUPER_ADDR]] // CHECK-NEXT: function_ref // CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int @@ -119,7 +119,7 @@ extension Derived : Abstractable {} // CHECK-NEXT: // function_ref // CHECK-NEXT: [[FN:%.*]] = function_ref @$s6modify4BaseC14staticFunctionSiycvMZ // CHECK-NEXT: ([[SUPER_ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[FN]]([[SELF]]) -// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for +// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for // CHECK-NEXT: [[SUPER_FN:%.*]] = load [take] [[SUPER_ADDR]] // CHECK-NEXT: function_ref // CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int diff --git a/test/SILGen/modify_objc.swift b/test/SILGen/modify_objc.swift index bf178d58cc311..b36bbab724ea6 100644 --- a/test/SILGen/modify_objc.swift +++ b/test/SILGen/modify_objc.swift @@ -35,7 +35,7 @@ extension ClassWithBlockProperty : ProtocolWithBlockProperty {} // CHECK-NEXT: // function_ref // CHECK-NEXT: [[FN:%.*]] = function_ref @$sSo22ClassWithBlockPropertyC09dependentC0ySSSgcSgvM // CHECK-NEXT: ([[YIELD_ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[FN]]([[SELF]]) -// CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $Optional<@callee_guaranteed <τ_0_0> in (@in_guaranteed τ_0_0) -> () for >> +// CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $Optional<@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for >> // CHECK-NEXT: [[IN_FUNCTION:%.*]] = load [take] [[YIELD_ADDR]] // CHECK: {{^}}bb3([[OUT_FUNCTION:%.*]] : // CHECK-NEXT: store [[OUT_FUNCTION]] to [init] [[TEMP]] : diff --git a/test/SILGen/multi_file.swift b/test/SILGen/multi_file.swift index 4cd418818c91b..af0e44769835a 100644 --- a/test/SILGen/multi_file.swift +++ b/test/SILGen/multi_file.swift @@ -52,4 +52,4 @@ class HasComputedProperty: ProtocolWithProperty { } } // CHECK-LABEL: sil hidden [transparent] [ossa] @$s10multi_file19HasComputedPropertyC3fooSivM : $@yield_once @convention(method) (@guaranteed HasComputedProperty) -> @yields @inout Int { -// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s10multi_file19HasComputedPropertyCAA012ProtocolWithE0A2aDP3fooSivMTW : $@yield_once @convention(witness_method: ProtocolWithProperty) (@inout HasComputedProperty) -> @yields @inout Int { +// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s10multi_file19HasComputedPropertyCAA012ProtocolWithE0A2aDP3fooSivMTW : $@yield_once @convention(witness_method: ProtocolWithProperty) @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout Int for { diff --git a/test/SILGen/nested_generics.swift b/test/SILGen/nested_generics.swift index f752e3bab4554..a4b4b88663a5d 100644 --- a/test/SILGen/nested_generics.swift +++ b/test/SILGen/nested_generics.swift @@ -48,7 +48,7 @@ struct Lunch where T.Topping : CuredMeat { // CHECK-LABEL: sil private [ossa] @$s15nested_generics5LunchV6DinnerV15coolCombination1t1uy7ToppingQz_AA4DeliC7MustardOyAA6PepperV_GtF0A7GenericL_1x1yqd0___qd0_0_tqd0___qd0_0_tAA5PizzaRzAA6HotDogRd__AA9CuredMeatAJRQAQ9CondimentRtd__r__0_lF : $@convention(thin) .Mustard> (@in_guaranteed X, @in_guaranteed Y) -> (@out X, @out Y) // CHECK-LABEL: // nested_generics.Lunch.Dinner.init(firstCourse: A, secondCourse: Swift.Optional, leftovers: A, transformation: (A) -> A1) -> nested_generics.Lunch.Dinner -// CHECK-LABEL: sil hidden [ossa] @$s15nested_generics5LunchV6DinnerV11firstCourse06secondF09leftovers14transformationAEyx_qd__Gx_qd__Sgxqd__xctcfC : $@convention(method) .Mustard> (@owned T, @in Optional, @owned T, @owned @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> @out τ_0_1 for , @thin Lunch.Dinner.Type) -> @out Lunch.Dinner +// CHECK-LABEL: sil hidden [ossa] @$s15nested_generics5LunchV6DinnerV11firstCourse06secondF09leftovers14transformationAEyx_qd__Gx_qd__Sgxqd__xctcfC : $@convention(method) .Mustard> (@owned T, @in Optional, @owned T, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> @out τ_0_1 for , @thin Lunch.Dinner.Type) -> @out Lunch.Dinner // Non-generic nested inside generic diff --git a/test/SILGen/objc_bridging_any.swift b/test/SILGen/objc_bridging_any.swift index 56477d559ca40..3fee4b8be0b28 100644 --- a/test/SILGen/objc_bridging_any.swift +++ b/test/SILGen/objc_bridging_any.swift @@ -664,7 +664,7 @@ class AnyHashableClass : NSObject { // CHECK: [[BRIDGE:%.*]] = function_ref @$sSq19_bridgeToObjectiveCyXlyF // CHECK: [[FN:%.*]] = function_ref @$sIeg_ytIegr_TR // CHECK: partial_apply [callee_guaranteed] [[FN]] -// CHECK: [[SELF:%.*]] = alloc_stack $Optional<@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>> +// CHECK: [[SELF:%.*]] = alloc_stack $Optional<@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>> // CHECK: apply [[BRIDGE]]<() -> ()>([[SELF]]) func bridgeOptionalFunctionToAnyObject(fn: (() -> ())?) -> AnyObject { return fn as AnyObject diff --git a/test/SILGen/optional.swift b/test/SILGen/optional.swift index 316257a7fabcf..d6cd08fb27514 100644 --- a/test/SILGen/optional.swift +++ b/test/SILGen/optional.swift @@ -30,8 +30,8 @@ func testAddrOnlyCallResult(_ f: (() -> T)?) { var x = f?() } // CHECK-LABEL: sil hidden [ossa] @{{.*}}testAddrOnlyCallResult{{.*}} : -// CHECK: bb0([[T0:%.*]] : @guaranteed $Optional<@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for >): -// CHECK: [[F:%.*]] = alloc_box $<τ_0_0> { var Optional<@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <τ_0_0>> } , var, name "f" +// CHECK: bb0([[T0:%.*]] : @guaranteed $Optional<@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for >): +// CHECK: [[F:%.*]] = alloc_box $<τ_0_0> { var Optional<@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>> } , var, name "f" // CHECK-NEXT: [[PBF:%.*]] = project_box [[F]] // CHECK: [[T0_COPY:%.*]] = copy_value [[T0]] // CHECK: store [[T0_COPY]] to [init] [[PBF]] diff --git a/test/SILGen/partial_apply_protocol.swift b/test/SILGen/partial_apply_protocol.swift index 9c6443962e8ee..af84fdbdae632 100644 --- a/test/SILGen/partial_apply_protocol.swift +++ b/test/SILGen/partial_apply_protocol.swift @@ -86,7 +86,7 @@ func testClonable(c: Clonable) { // CHECK-NEXT: [[OUTER_RESULT:%.*]] = init_existential_metatype [[INNER_RESULT]] // CHECK-NEXT: return [[OUTER_RESULT]] -// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sxlyxIsegr_Iego_22partial_apply_protocol8Clonable_pIegr_Iego_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @owned @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <τ_0_0>) -> @owned @callee_guaranteed () -> @out Clonable +// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sxlyxIsegr_Iego_22partial_apply_protocol8Clonable_pIegr_Iego_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>) -> @owned @callee_guaranteed () -> @out Clonable // CHECK: bb0(%0 : // CHECK-NEXT: [[INNER_RESULT:%.*]] = apply %0() // CHECK-NEXT: [[INNER_RESULT_CONV:%.*]] = convert_function [[INNER_RESULT]] @@ -144,8 +144,8 @@ func testClonableInGenericContext(c: Clonable, t: T) { // CHECK-NEXT: dealloc_stack [[INNER_RESULT]] // CHECK-NEXT: return [[EMPTY]] -// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sxxlyqd__Isegr_Iegno_x22partial_apply_protocol8Clonable_pIegr_Iegno_AaBRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <τ_1_0>) -> @owned @callee_guaranteed () -> @out Clonable { -// CHECK: bb0(%0 : $*τ_0_0, %1 : @guaranteed $@callee_guaranteed (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <τ_1_0>): +// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sxxlyqd__Isegr_Iegno_x22partial_apply_protocol8Clonable_pIegr_Iegno_AaBRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_1_0>) -> @owned @callee_guaranteed () -> @out Clonable { +// CHECK: bb0(%0 : $*τ_0_0, %1 : @guaranteed $@callee_guaranteed (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_1_0>): // CHECK-NEXT: [[RES:%.*]] = apply %1(%0) // CHECK-NEXT: [[RES_CONV:%.*]] = convert_function [[RES]] // CHECK: [[THUNK_FN:%.*]] = function_ref @$sqd__Iegr_22partial_apply_protocol8Clonable_pIegr_AaBRd__r__lTR diff --git a/test/SILGen/pointer_conversion.swift b/test/SILGen/pointer_conversion.swift index ae5e29b4bb3d9..2bd148cd4537f 100644 --- a/test/SILGen/pointer_conversion.swift +++ b/test/SILGen/pointer_conversion.swift @@ -268,7 +268,7 @@ func functionInoutToPointer() { // CHECK: [[BOX:%.*]] = alloc_box ${ var @callee_guaranteed () -> () } var f: () -> () = {} - // CHECK: [[REABSTRACT_BUF:%.*]] = alloc_stack $@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()> + // CHECK: [[REABSTRACT_BUF:%.*]] = alloc_stack $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()> // CHECK: address_to_pointer [[REABSTRACT_BUF]] takesMutableVoidPointer(&f) } diff --git a/test/SILGen/property_abstraction.swift b/test/SILGen/property_abstraction.swift index 592326a7d9ee7..fd3971750636b 100644 --- a/test/SILGen/property_abstraction.swift +++ b/test/SILGen/property_abstraction.swift @@ -120,7 +120,7 @@ struct T20341012 { private var options: ArrayLike { get {} set {} } // CHECK-LABEL: sil hidden [ossa] @$s20property_abstraction9T20341012V1t{{[_0-9a-zA-Z]*}}F - // CHECK: [[TMP1:%.*]] = alloc_stack $(title: (), action: @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>) + // CHECK: [[TMP1:%.*]] = alloc_stack $(title: (), action: @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>) // CHECK: apply {{.*}}<(title: (), action: () -> ())>([[TMP1]], mutating func t() { _ = self.options[()].title diff --git a/test/SILGen/reabstract-tuple.swift b/test/SILGen/reabstract-tuple.swift index 30de079aeb690..a28b58d90f8db 100644 --- a/test/SILGen/reabstract-tuple.swift +++ b/test/SILGen/reabstract-tuple.swift @@ -21,14 +21,14 @@ class Box { // CHECK: [[THUNK1:%.*]] = function_ref @$sIeg_ytIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> @out () // CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[THUNK1]]([[ELTA_1]]) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> @out () // CHECK: [[PA_CONV:%.*]] = convert_function [[PA]] -// CHECK: [[TUPLEB:%.*]] = tuple ([[ELTA_0]] : $Int, [[PA_CONV]] : $@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>) +// CHECK: [[TUPLEB:%.*]] = tuple ([[ELTA_0]] : $Int, [[PA_CONV]] : $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>) // CHECK: ([[TUPLEB_0:%.*]], [[TUPLEB_1:%.*]]) = destructure_tuple [[TUPLEB]] // CHECK: // function_ref Box.__allocating_init(_:) // CHECK: [[INIT_F:%.*]] = function_ref @$s4main3BoxCyACyxGxcfC : $@convention(method) <τ_0_0> (@in τ_0_0, @thick Box<τ_0_0>.Type) -> @owned Box<τ_0_0> // CHECK: [[CALL:%.*]] = apply [[INIT_F]]<(Int, () -> ())>(%{{.*}}, %{{.*}}) : $@convention(method) <τ_0_0> (@in τ_0_0, @thick Box<τ_0_0>.Type) -> @owned Box<τ_0_0> // CHECK: [[BORROW_CALL:%.*]] = begin_borrow [[CALL]] : $Box<(Int, () -> ())> // CHECK: [[REF:%.*]] = ref_element_addr [[BORROW_CALL]] : $Box<(Int, () -> ())>, #Box.value -// CHECK: [[TUPLEC:%.*]] = load [copy] [[REF]] : $*(Int, @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>) +// CHECK: [[TUPLEC:%.*]] = load [copy] [[REF]] : $*(Int, @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>) // CHECK: ([[TUPLEC_0:%.*]], [[TUPLEC_1:%.*]]) = destructure_tuple [[TUPLEC]] // CHECK: [[TUPLEC_1_CONV:%.*]] = convert_function [[TUPLEC_1]] // CHECK: [[THUNK2:%.*]] = function_ref @$sytIegr_Ieg_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out ()) -> () diff --git a/test/SILGen/reabstract_lvalue.swift b/test/SILGen/reabstract_lvalue.swift index 0e863d5ef07a6..f1e39e74a9780 100644 --- a/test/SILGen/reabstract_lvalue.swift +++ b/test/SILGen/reabstract_lvalue.swift @@ -19,7 +19,7 @@ func reabstractFunctionInOut() { // CHECK: [[THICK_ARG:%.*]] = thin_to_thick_function [[ARG]] // CHECK: store [[THICK_ARG:%.*]] to [init] [[PB]] // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]] : $*@callee_guaranteed (Int) -> Double - // CHECK: [[ABSTRACTED_BOX:%.*]] = alloc_stack $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for + // CHECK: [[ABSTRACTED_BOX:%.*]] = alloc_stack $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for // CHECK: [[THICK_ARG:%.*]] = load [copy] [[WRITE]] // CHECK: [[THUNK1:%.*]] = function_ref @$sSiSdIegyd_SiSdIegnr_TR // CHECK: [[ABSTRACTED_ARG:%.*]] = partial_apply [callee_guaranteed] [[THUNK1]]([[THICK_ARG]]) diff --git a/test/SILGen/tuple_attribute_reabstraction.swift b/test/SILGen/tuple_attribute_reabstraction.swift index 234b1645e7af6..9ed293475a7cd 100644 --- a/test/SILGen/tuple_attribute_reabstraction.swift +++ b/test/SILGen/tuple_attribute_reabstraction.swift @@ -16,7 +16,7 @@ public func f() { // We shouldn't have @autoclosure and @escaping attributes in the lowered tuple type: -// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sIg_Ieg_Iegyg_xlyytIsgr_xlyytIsegr_ytIegnnr_TR : $@convention(thin) (@in_guaranteed @noescape @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>, @in_guaranteed @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for <()>, @guaranteed @callee_guaranteed (@noescape @callee_guaranteed () -> (), @guaranteed @callee_guaranteed () -> ()) -> ()) -> @out () +// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sIg_Ieg_Iegyg_xlyytIsgr_xlyytIsegr_ytIegnnr_TR : $@convention(thin) (@in_guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>, @in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>, @guaranteed @callee_guaranteed (@noescape @callee_guaranteed () -> (), @guaranteed @callee_guaranteed () -> ()) -> ()) -> @out () // The one-element vararg tuple ([Int]...) should be exploded and not treated as opaque, // even though its materializable: diff --git a/test/SILGen/variant_overrides.swift b/test/SILGen/variant_overrides.swift new file mode 100644 index 0000000000000..8e09feb506cef --- /dev/null +++ b/test/SILGen/variant_overrides.swift @@ -0,0 +1,39 @@ +// RUN: %target-swift-emit-silgen %s | %FileCheck %s + +// CHECK-LABEL: sil hidden [ossa] @$s17variant_overrides1AC3foo5blockyyACc_tF : +// CHECK-SAME: $@convention(method) (@guaranteed @callee_guaranteed (@guaranteed A) -> (), @guaranteed A) -> () +class A { + func foo(block: @escaping (A) -> Void) {} +} + +// CHECK-LABEL: sil hidden [ossa] @$s17variant_overrides1BC3foo5blockyyACyxGc_tF : +// CHECK-SAME: $@convention(method) (@guaranteed @callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for , @guaranteed B) -> () +class B : A { + override func foo(block: @escaping (B) -> Void) {} +} + +// CHECK-LABEL: sil hidden [ossa] @$s17variant_overrides12useAtGeneric1byAA1BCyxG_tlF +func useAtGeneric(b: B) { + // CHECK: [[CLOSURE_FUNC:%.*]] = function_ref @$s17variant_overrides12useAtGeneric1byAA1BCyxG_tlFyAFcfU_ : $@convention(thin) <τ_0_0> (@guaranteed B<τ_0_0>) -> () + // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE_FUNC]]() : $@convention(thin) <τ_0_0> (@guaranteed B<τ_0_0>) -> () + // CHECK: [[CLOSURE_CONVERTED:%.*]] = convert_function [[CLOSURE]] : $@callee_guaranteed (@guaranteed B) -> () to $@callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for + // CHECK: [[METHOD:%.*]] = class_method %0 : $B, #B.foo!1 : (B) -> (@escaping (B) -> ()) -> (), $@convention(method) <τ_0_0> (@guaranteed @callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for <τ_0_0>, @guaranteed B<τ_0_0>) -> () + // CHECK: apply [[METHOD]](%4, %0) : $@convention(method) <τ_0_0> (@guaranteed @callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for <τ_0_0>, @guaranteed B<τ_0_0>) -> () + + b.foo {_ in ()} +} + +// CHECK-LABEL: sil hidden [ossa] @$s17variant_overrides13useAtConcrete1byAA1BCySiG_tF +func useAtConcrete(b: B) { + // CHECK: [[CLOSURE_FUNC:%.*]] = function_ref @$s17variant_overrides13useAtConcrete1byAA1BCySiG_tFyAFcfU_ : $@convention(thin) (@guaranteed B) -> () + // CHECK: [[CLOSURE:%.*]] = thin_to_thick_function [[CLOSURE_FUNC]] : $@convention(thin) (@guaranteed B) -> () to $@callee_guaranteed (@guaranteed B) -> () + // CHECK: [[CLOSURE_CONVERTED:%.*]] = convert_function [[CLOSURE]] : $@callee_guaranteed (@guaranteed B) -> () to $@callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for + // CHECK: [[METHOD:%.*]] = class_method %0 : $B, #B.foo!1 : (B) -> (@escaping (B) -> ()) -> (), $@convention(method) <τ_0_0> (@guaranteed @callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for <τ_0_0>, @guaranteed B<τ_0_0>) -> () + // CHECK: apply [[METHOD]](%4, %0) : $@convention(method) <τ_0_0> (@guaranteed @callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for <τ_0_0>, @guaranteed B<τ_0_0>) -> () + + b.foo {_ in ()} +} + +// FIXME: allowing this without a thunk silently reinterprets the function to a different abstraction! +// CHECK-LABEL: sil_vtable B { +// CHECK: #A.foo!1: (A) -> (@escaping (A) -> ()) -> () : @$s17variant_overrides1BC3foo5blockyyACyxGc_tF [override] diff --git a/test/SILOptimizer/OSLogPrototypeCompileDiagnostics.swift b/test/SILOptimizer/OSLogPrototypeCompileDiagnostics.swift index 3b354ec9b2b6d..6634c8403776a 100644 --- a/test/SILOptimizer/OSLogPrototypeCompileDiagnostics.swift +++ b/test/SILOptimizer/OSLogPrototypeCompileDiagnostics.swift @@ -5,7 +5,8 @@ // performs compile-time analysis and optimization of the new os log prototype // APIs. The tests here check whether bad user inputs are diagnosed correctly. // The tests here model the possible invalid inputs to the os log methods. -// TODO: diagnostics will be improved. +// TODO: diagnostics will be improved. globalStringTablePointer builtin error +// must be suppressed. import OSLogPrototype @@ -43,10 +44,91 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { let logMessage: OSLogMessage = "Maximum integer value: \(Int.max)" // expected-error @-1 {{OSLogMessage instance must not be explicitly created and must be deletable}} if !b { - return; + return } h.log(level: .debug, logMessage) // expected-error @-1 {{globalStringTablePointer builtin must used only on string literals}} } + + func testNoninlinedFormatOptions(h: Logger) { + let formatOption: OSLogIntegerFormatting = .hex(includePrefix: true) + h.debug("Minimum integer value: \(Int.min, format: formatOption)") + // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} + // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} + } + + func testNoninlinedFormatOptionsComplex(h: Logger, b: Bool) { + let formatOption: OSLogIntegerFormatting = .hex(includePrefix: true) + if !b { + return + } + h.debug("Minimum integer value: \(Int.min, format: formatOption)") + // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} + // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} + } } +internal enum Color { + case red + case blue +} + +if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { + + // Invoking the log calls in unreachable code should not crash the compiler. + func testUnreachableLogCall(h: Logger, c: Color) { + let arg = 10 + switch c { + case .red: + return + case .blue: + return + default: // expected-warning {{default will never be executed}} + h.debug("Unreachable log call") + h.info("Unreachable log call with argument \(arg)") + h.log( + """ + Unreachable log call with argument and formatting \ + \(arg, align: .right(columns: 10)) + """) + } + } + + // Passing InOut values to the logger should not crash the compiler. + func foo(_ logger: Logger, _ mutableValue: inout String) { + logger.log("FMFLabelledLocation: initialized with coder \(mutableValue)") + // expected-error@-1 {{escaping closure captures 'inout' parameter 'mutableValue'}} + // expected-note@-3 {{parameter 'mutableValue' is declared 'inout'}} + // expected-note@-3 {{captured here}} + } +} + +// This is an extension used only for testing a diagnostic that doesn't arise +// normally but may be triggered by changes to the library. +extension OSLogInterpolation { + @_transparent + mutating func appendInterpolation(_ c: Color) { + switch c { + case .red: + appendInterpolation(1) + case .blue: + appendInterpolation(0) + } + } +} + +if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { + + func testUnreachableLogCallComplex(h: Logger, c: Color) { + switch c { + case .red: + return + case .blue: + return + default: // expected-warning {{default will never be executed}} + h.info("Some call \(c)") + // expected-warning@-1 {{os log call will never be executed and may have undiagnosed errors}} + // expected-error@-2 {{globalStringTablePointer builtin must used only on string literals}} + } + } +} diff --git a/test/SILOptimizer/OSLogPrototypeCompileTest.sil b/test/SILOptimizer/OSLogPrototypeCompileTest.sil index bb7209eee437c..943f0436d872e 100644 --- a/test/SILOptimizer/OSLogPrototypeCompileTest.sil +++ b/test/SILOptimizer/OSLogPrototypeCompileTest.sil @@ -733,16 +733,15 @@ bb0(%0 : @guaranteed $String): destroy_value %6 : $OSLogMessageStringCapture %18 = tuple () return %18 : $() - // The first instance of function_ref @idString will be dead code eliminated. - // CHECK: [[ORIGCAPTURE:%[0-9]+]] = copy_value %0 : $String - // CHECK: [[NEWCAPTURE:%[0-9]+]] = copy_value [[ORIGCAPTURE]] : $String // CHECK: [[FUNREF:%[0-9]+]] = function_ref @idString - // CHECK: [[CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[FUNREF]]([[NEWCAPTURE]]) - // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[CLOSURE]] : $@callee_guaranteed () -> @owned String + // CHECK: [[ORIGCAPTURE:%[0-9]+]] = copy_value %0 : $String + // CHECK: [[CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[FUNREF]]([[ORIGCAPTURE]]) + // CHECK: [[CLOSURECOPY:%[0-9]+]] = copy_value [[CLOSURE]] + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[CLOSURECOPY]] : $@callee_guaranteed () -> @owned String // CHECK: [[USE:%[0-9]+]] = function_ref @useStringCapture // CHECK: apply [[USE]]([[BORROW]]) // CHECK: end_borrow [[BORROW]] - // CHECK: destroy_value [[CLOSURE]] + // CHECK: destroy_value [[CLOSURECOPY]] } sil [ossa] @genericFunction : $@convention(thin) (@in_guaranteed U, @in_guaranteed V) -> Int32 { @@ -790,11 +789,12 @@ bb0: // The first instance of function_ref @genericFunction will be dead-code eliminated. // CHECK: [[FUNREF:%[0-9]+]] = function_ref @genericFunction // CHECK: [[CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[FUNREF]]([[CAPTURE1:%[0-9]+]], [[CAPTURE2:%[0-9]+]]) - // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[CLOSURE]] : $@callee_guaranteed () -> Int32 + // CHECK: [[CLOSURECOPY:%[0-9]+]] = copy_value [[CLOSURE]] + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[CLOSURECOPY]] : $@callee_guaranteed () -> Int32 // CHECK: [[USE:%[0-9]+]] = function_ref @useClosure // CHECK: apply [[USE]]([[BORROW]]) // CHECK: end_borrow [[BORROW]] - // CHECK: destroy_value [[CLOSURE]] + // CHECK: destroy_value [[CLOSURECOPY]] } // Check folding of array of closures. This is essentially the feature needed @@ -834,15 +834,15 @@ bb0(%0 : $Builtin.Int1): %3 = apply %2<() -> Int32>(%1) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) %4 = tuple_extract %3 : $(Array<() -> Int32>, Builtin.RawPointer), 0 %5 = tuple_extract %3 : $(Array<() -> Int32>, Builtin.RawPointer), 1 - %6 = pointer_to_address %5 : $Builtin.RawPointer to [strict] $*@callee_guaranteed in () -> @out A for + %6 = pointer_to_address %5 : $Builtin.RawPointer to [strict] $*@callee_guaranteed @substituted () -> @out A for %7 = integer_literal $Builtin.Int32, 81 %8 = struct $Int32 (%7 : $Builtin.Int32) %9 = function_ref @closure1 : $@convention(thin) (Int32) -> Int32 %10 = partial_apply [callee_guaranteed] %9(%8) : $@convention(thin) (Int32) -> Int32 %11 = function_ref @$ss5Int32VIegd_ABIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int32) -> @out Int32 %12 = partial_apply [callee_guaranteed] %11(%10) : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int32) -> @out Int32 - %13 = convert_function %12 : $@callee_guaranteed () -> @out Int32 to $@callee_guaranteed in () -> @out A for - store %13 to %6 : $*@callee_guaranteed in () -> @out A for + %13 = convert_function %12 : $@callee_guaranteed () -> @out Int32 to $@callee_guaranteed @substituted () -> @out A for + store %13 to %6 : $*@callee_guaranteed @substituted () -> @out A for // Create an instance of OSLogMessageClosureArrayStub using the above array // of closures. diff --git a/test/SILOptimizer/OSLogPrototypeCompileTest.swift b/test/SILOptimizer/OSLogPrototypeCompileTest.swift index 69d0358e05553..f7774fb0848f0 100644 --- a/test/SILOptimizer/OSLogPrototypeCompileTest.swift +++ b/test/SILOptimizer/OSLogPrototypeCompileTest.swift @@ -600,3 +600,21 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { } } +protocol Proto { + var property: String { get set } +} + +// Test capturing of address-only types in autoclosures. + +if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { + // CHECK-LABEL: @${{.*}}testInterpolationOfExistentialsL_ + func testInterpolationOfExistentials(h: Logger, p: Proto) { + h.debug("A protocol's property \(p.property)") + } + + // CHECK-LABEL: @${{.*}}testInterpolationOfGenericsL_ + func testInterpolationOfGenerics(h: Logger, p: T) { + h.debug("A generic argument's property \(p.property)") + } +} + diff --git a/test/SILOptimizer/OSLogPrototypeFullOptTest.swift b/test/SILOptimizer/OSLogPrototypeFullOptTest.swift index aa1b6e4ce247d..3a4eedbcb9832 100644 --- a/test/SILOptimizer/OSLogPrototypeFullOptTest.swift +++ b/test/SILOptimizer/OSLogPrototypeFullOptTest.swift @@ -128,8 +128,10 @@ func testInterpolationWithMultipleArguments(h: Logger) { @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) func testNSObjectInterpolation(h: Logger, nsArray: NSArray) { h.log("NSArray: \(nsArray, privacy: .public)") + // TODO: check why the ARC optimizer cannot eliminate the many retain/release pairs here. // CHECK: entry: // CHECK-NEXT: bitcast %TSo7NSArrayC* %1 to i8* + // CHECK-NEXT: tail call i8* @llvm.objc.retain // CHECK-NEXT: [[NSARRAY_ARG:%.+]] = tail call i8* @llvm.objc.retain // CHECK-NEXT: [[LOGLEVEL:%.+]] = tail call swiftcc i8 @"$sSo13os_log_type_ta0A0E7defaultABvgZ"() // CHECK-NEXT: tail call swiftcc %TSo9OS_os_logC* @"$s14OSLogPrototype6LoggerV9logObjectSo06OS_os_D0Cvg" @@ -154,18 +156,22 @@ func testNSObjectInterpolation(h: Logger, nsArray: NSArray) { // CHECK-NEXT: [[OFFSET3:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 3 // CHECK-64-NEXT: store i8 8, i8* [[OFFSET3]], align 1 // CHECK-32-NEXT: store i8 4, i8* [[OFFSET3]], align 1 + // CHECK-NEXT: tail call void @llvm.objc.release // CHECK-NEXT: [[OFFSET4:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 4 // CHECK-NEXT: [[BITCASTED_DEST:%.+]] = bitcast i8* [[OFFSET4]] to %TSo7NSArrayC** // CHECK-NEXT: [[BITCASTED_SRC:%.+]] = bitcast i8* [[NSARRAY_ARG]] to %TSo7NSArrayC* // CHECK-NEXT: store %TSo7NSArrayC* [[BITCASTED_SRC]], %TSo7NSArrayC** [[BITCASTED_DEST]], align 1 - // TODO: check why the ARC optimizer cannot eliminate this retain/release pair // CHECK-64-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([20 x i8], [20 x i8]* @{{.*}}, i64 0, i64 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) // CHECK-32-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([20 x i8], [20 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] - // CHECK-NEXT: br label %[[NOT_ENABLED]] + // CHECK-NEXT: br label %[[EXIT:[0-9]+]] // CHECK: [[NOT_ENABLED]]: + // CHECK-NEXT: tail call void @llvm.objc.release + // CHECK-NEXT: br label %[[EXIT]] + + // CHECK: [[EXIT]]: // CHECK-NEXT: tail call void @llvm.objc.release(i8* [[NSARRAY_ARG]]) // CHECK-NEXT: bitcast // CHECK-NEXT: tail call void @llvm.objc.release diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift index 6a95a2c40d117..5228ae8131173 100644 --- a/test/SILOptimizer/access_marker_verify.swift +++ b/test/SILOptimizer/access_marker_verify.swift @@ -558,7 +558,7 @@ enum OptionalWithMap { } } } -// CHECK-LABEL: sil hidden [ossa] @$s20access_marker_verify15OptionalWithMapO3mapyqd__Sgqd__xKXEKlF : $@convention(method) (@noescape @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , @in_guaranteed OptionalWithMap) -> (@out Optional, @error Error) +// CHECK-LABEL: sil hidden [ossa] @$s20access_marker_verify15OptionalWithMapO3mapyqd__Sgqd__xKXEKlF : $@convention(method) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , @in_guaranteed OptionalWithMap) -> (@out Optional, @error Error) // CHECK: [[STK:%.]] = alloc_stack $OptionalWithMap // CHECK-NOT: begin_access // CHECK: copy_addr %2 to [initialization] [[STK]] : $*OptionalWithMap diff --git a/test/SILOptimizer/arcsequenceopts.sil b/test/SILOptimizer/arcsequenceopts.sil index b6e024270a495..1ae5be9e85384 100644 --- a/test/SILOptimizer/arcsequenceopts.sil +++ b/test/SILOptimizer/arcsequenceopts.sil @@ -2251,3 +2251,47 @@ bb0: %9999 = tuple() return %9999 : $() } + +//===----------------------------------------------------------------------===// +// Test invoking EscapeAnalysis:mayReleaseContent on a builtin that takes +// an address. This should simply not assert. +// +// Escape analysis crashes with +// "an address is never a reference" error with -O -thread=sanitize +//===----------------------------------------------------------------------===// + +// bufferMemory +sil_global hidden @$s4test12bufferMemorySpys5UInt8VGvp : $UnsafeMutablePointer + +// x +sil_global hidden @$s4test1xypvp : $Any + +sil [serialized] [always_inline] [readonly] [_semantics "string.makeUTF8"] @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String + +// CHECK-LABEL: sil @testTsanInoutAccess : $@convention(thin) () -> () { +// CHECK: alloc_global @$s4test12bufferMemorySpys5UInt8VGvp +// CHECK: [[GLOBAL:%.*]] = global_addr @$s4test12bufferMemorySpys5UInt8VGvp : $*UnsafeMutablePointer +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] : $*UnsafeMutablePointer +// CHECK: builtin "tsanInoutAccess"([[ACCESS]] : $*UnsafeMutablePointer) : $() +// CHECK-LABEL: } // end sil function 'testTsanInoutAccess' +sil @testTsanInoutAccess : $@convention(thin) () -> () { +bb0: + alloc_global @$s4test12bufferMemorySpys5UInt8VGvp + %1 = global_addr @$s4test12bufferMemorySpys5UInt8VGvp : $*UnsafeMutablePointer + %2 = integer_literal $Builtin.Int1, -1 + alloc_global @$s4test1xypvp + %4 = global_addr @$s4test1xypvp : $*Any + %5 = string_literal utf8 "" + %6 = integer_literal $Builtin.Word, 0 + %7 = metatype $@thin String.Type + // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:) + %8 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String + %9 = apply %8(%5, %6, %2, %7) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String + %10 = init_existential_addr %4 : $*Any, $String + store %9 to %10 : $*String + %12 = begin_access [modify] [dynamic] %1 : $*UnsafeMutablePointer + %13 = builtin "tsanInoutAccess"(%12 : $*UnsafeMutablePointer) : $() + end_access %12 : $*UnsafeMutablePointer + %15 = tuple () + return %15 : $() +} diff --git a/test/SILOptimizer/capture_promotion_generic_context.sil b/test/SILOptimizer/capture_promotion_generic_context.sil index 952695f0f7898..eba5c4bf18682 100644 --- a/test/SILOptimizer/capture_promotion_generic_context.sil +++ b/test/SILOptimizer/capture_promotion_generic_context.sil @@ -92,9 +92,9 @@ entry(%0: $*R, %1 : $*Int, %b : $<τ_0_0> { var E< (R<τ_0_0>)->Int > } ): %e = load %a : $*E<(R)->Int> switch_enum %e : $E<(R)->Int>, case #E.Some!enumelt.1 : bb1, default bb2 -bb1(%f : $@callee_guaranteed in (@in_guaranteed A) -> @out B for , Int>): +bb1(%f : $@callee_guaranteed @substituted (@in_guaranteed A) -> @out B for , Int>): %t = tuple () - apply %f(%1, %0) : $@callee_guaranteed in (@in_guaranteed A) -> @out B for , Int> + apply %f(%1, %0) : $@callee_guaranteed @substituted (@in_guaranteed A) -> @out B for , Int> br exit bb2: br exit diff --git a/test/SILOptimizer/capture_promotion_generic_context_ownership.sil b/test/SILOptimizer/capture_promotion_generic_context_ownership.sil index 2a9e93ece6065..4b03d6a0462c9 100644 --- a/test/SILOptimizer/capture_promotion_generic_context_ownership.sil +++ b/test/SILOptimizer/capture_promotion_generic_context_ownership.sil @@ -94,11 +94,11 @@ entry(%0 : $*R, %1 : $*Int, %b : @owned $<τ_0_0> { var E<(R<τ_0_0>)->Int> } %e = load [copy] %a : $*E<(R)->Int> switch_enum %e : $E<(R)->Int>, case #E.Some!enumelt.1 : bb1, default bb2 -bb1(%f : @owned $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int>): - %bf = begin_borrow %f : $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int> - apply %bf(%1, %0) : $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int> - end_borrow %bf : $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int> - destroy_value %f : $@callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int> +bb1(%f : @owned $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int>): + %bf = begin_borrow %f : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int> + apply %bf(%1, %0) : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int> + end_borrow %bf : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int> + destroy_value %f : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for , Int> br exit bb2(%original : @owned $E<(R)->Int>): diff --git a/test/SILOptimizer/eager_specialize.sil b/test/SILOptimizer/eager_specialize.sil index 54f38697eea08..5e618dd026e5c 100644 --- a/test/SILOptimizer/eager_specialize.sil +++ b/test/SILOptimizer/eager_specialize.sil @@ -1,6 +1,6 @@ // RUN: %target-sil-opt -enable-sil-verify-all -eager-specializer %s | %FileCheck %s // RUN: %target-sil-opt -enable-sil-verify-all -eager-specializer -sil-deadfuncelim %s | %FileCheck --check-prefix=CHECK-DEADFUNCELIM %s -// RUN: %target-sil-opt -enable-sil-verify-all -eager-specializer %s -o %t.sil && %target-swift-frontend -module-name=eager_specialize -emit-ir %t.sil | %FileCheck --check-prefix=CHECK-IRGEN %s +// RUN: %target-sil-opt -enable-sil-verify-all -eager-specializer %s -o %t.sil && %target-swift-frontend -module-name=eager_specialize -emit-ir %t.sil | %FileCheck --check-prefix=CHECK-IRGEN --check-prefix=CHECK-IRGEN-%target-cpu %s // RUN: %target-sil-opt -enable-sil-verify-all -eager-specializer -sil-inline-generics=true -inline %s | %FileCheck --check-prefix=CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE %s sil_stage canonical @@ -727,7 +727,9 @@ bb0(%0 : $*Self, %1 : $*Self, %2 : $@thick Self.Type): // CHECK-IRGEN-NEXT: %5 = getelementptr inbounds i8*, i8** %S.valueWitnesses // CHECK-IRGEN-NEXT: %6 = load i8*, i8** %5 // CHECK-IRGEN-NEXT: %initializeWithCopy = {{.*}} -// CHECK-IRGEN-NEXT: %7 = call {{.*}} %initializeWithCopy +// CHECK-IRGEN-arm64e-NEXT: ptrtoint i8** %5 to i64 +// CHECK-IRGEN-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64 +// CHECK-IRGEN-NEXT: call {{.*}} %initializeWithCopy // CHECK-IRGEN-NEXT: ret void // CHECK-IRGEN-NEXT: } diff --git a/test/SILOptimizer/for_each_loop_unroll_test.sil b/test/SILOptimizer/for_each_loop_unroll_test.sil index 5557a8ea4fafd..8930a7f112a65 100644 --- a/test/SILOptimizer/for_each_loop_unroll_test.sil +++ b/test/SILOptimizer/for_each_loop_unroll_test.sil @@ -74,25 +74,25 @@ bb2(%39 : @owned $Error): // CHECK: dealloc_stack [[STACK]] // CHECK: unreachable -sil @forEachBody2 : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out A for ) -> @error Error +sil @forEachBody2 : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out A for ) -> @error Error -sil hidden [ossa] @nonTrivialForEachLoopUnrollTest : $@convention(thin) (@owned @callee_guaranteed in () -> @out A for , @owned @callee_guaranteed in () -> @out A for ) -> () { -bb0(%0: @owned $@callee_guaranteed in () -> @out A for , %1: @owned $@callee_guaranteed in () -> @out A for ): +sil hidden [ossa] @nonTrivialForEachLoopUnrollTest : $@convention(thin) (@owned @callee_guaranteed @substituted () -> @out A for , @owned @callee_guaranteed @substituted () -> @out A for ) -> () { +bb0(%0: @owned $@callee_guaranteed @substituted () -> @out A for , %1: @owned $@callee_guaranteed @substituted () -> @out A for ): %2 = integer_literal $Builtin.Word, 2 %3 = function_ref @_allocateUninitializedArray : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) %4 = apply %3<() -> Int>(%2) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) (%5, %6) = destructure_tuple %4 : $(Array<()->Int>, Builtin.RawPointer) - %7 = pointer_to_address %6 : $Builtin.RawPointer to [strict] $*@callee_guaranteed in () -> @out A for - store %0 to [init] %7 : $*@callee_guaranteed in () -> @out A for + %7 = pointer_to_address %6 : $Builtin.RawPointer to [strict] $*@callee_guaranteed @substituted () -> @out A for + store %0 to [init] %7 : $*@callee_guaranteed @substituted () -> @out A for %12 = integer_literal $Builtin.Word, 1 - %13 = index_addr %7 : $*@callee_guaranteed in () -> @out A for , %12 : $Builtin.Word - store %1 to [init] %13 : $*@callee_guaranteed in () -> @out A for + %13 = index_addr %7 : $*@callee_guaranteed @substituted () -> @out A for , %12 : $Builtin.Word + store %1 to [init] %13 : $*@callee_guaranteed @substituted () -> @out A for %21 = begin_borrow %5 : $Array<()->Int> %22 = alloc_stack $Array<()->Int> %23 = store_borrow %21 to %22 : $*Array<()->Int> - %24 = function_ref @forEachBody2 : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out A for ) -> @error Error - %25 = convert_function %24 : $@convention(thin) (@in_guaranteed @callee_guaranteed in () -> @out A for ) -> @error Error to $@convention(thin) @noescape (@in_guaranteed @callee_guaranteed in () -> @out A for ) -> @error Error - %26 = thin_to_thick_function %25 : $@convention(thin) @noescape (@in_guaranteed @callee_guaranteed in () -> @out A for ) -> @error Error to $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed in () -> @out A for ) -> @error Error + %24 = function_ref @forEachBody2 : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out A for ) -> @error Error + %25 = convert_function %24 : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted () -> @out A for ) -> @error Error to $@convention(thin) @noescape (@in_guaranteed @callee_guaranteed @substituted () -> @out A for ) -> @error Error + %26 = thin_to_thick_function %25 : $@convention(thin) @noescape (@in_guaranteed @callee_guaranteed @substituted () -> @out A for ) -> @error Error to $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted () -> @out A for ) -> @error Error // A stub for Sequence.forEach(_:) %30 = function_ref @forEach : $@convention(method) <τ_0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error try_apply %30<[() -> Int]>(%26, %22) : $@convention(method) <τ_0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error, normal bb1, error bb2 @@ -109,16 +109,16 @@ bb2(%39 : @owned $Error): } // CHECK-LABEL: nonTrivialForEachLoopUnrollTest // CHECK: [[ELEM1:%[0-9]+]] = copy_value %0 -// CHECK-NEXT: store %0 to [init] %{{.*}} : $*@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for +// CHECK-NEXT: store %0 to [init] %{{.*}} : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for // CHECK: [[ELEM2:%[0-9]+]] = copy_value %1 -// CHECK-NEXT: store %1 to [init] %{{.*}} : $*@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for +// CHECK-NEXT: store %1 to [init] %{{.*}} : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for // CHECK: [[BODYCLOSURE:%[0-9]+]] = thin_to_thick_function // CHECK-NOT: forEach -// CHECK: [[STACK:%[0-9]+]] = alloc_stack $@callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for +// CHECK: [[STACK:%[0-9]+]] = alloc_stack $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for // CHECK: [[ELEM1BORROW:%[0-9]+]] = begin_borrow [[ELEM1]] // CHECK: store_borrow [[ELEM1BORROW]] to [[STACK]] // CHECK: end_borrow [[ELEM1BORROW]] -// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for ) -> @error Error, normal [[NORMAL:bb[0-9]+]], error [[ERROR:bb[0-9]+]] +// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for ) -> @error Error, normal [[NORMAL:bb[0-9]+]], error [[ERROR:bb[0-9]+]] // CHECK: [[ERROR]]([[ERRPARAM:%[0-9]+]] : @owned $Error): // CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM]] : $Error) @@ -127,7 +127,7 @@ bb2(%39 : @owned $Error): // CHECK: [[ELEM2BORROW:%[0-9]+]] = begin_borrow [[ELEM2]] // CHECK: store_borrow [[ELEM2BORROW]] to [[STACK]] // CHECK: end_borrow [[ELEM2BORROW]] -// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed <τ_0_0> in () -> @out τ_0_0 for ) -> @error Error, normal [[NORMAL2:bb[0-9]+]], error [[ERROR2:bb[0-9]+]] +// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for ) -> @error Error, normal [[NORMAL2:bb[0-9]+]], error [[ERROR2:bb[0-9]+]] // CHECK: [[ERROR2]]([[ERRPARAM2:%[0-9]+]] : @owned $Error): // CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM2]] : $Error) diff --git a/test/SILOptimizer/inlinealways_inliner.sil b/test/SILOptimizer/inlinealways_inliner.sil new file mode 100644 index 0000000000000..770d6a8ae45af --- /dev/null +++ b/test/SILOptimizer/inlinealways_inliner.sil @@ -0,0 +1,44 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -always-inline | %FileCheck %s + +sil @doSomething1 : $@convention(thin) () -> () +sil @doSomething2 : $@convention(thin) () -> () +sil @doSomething3 : $@convention(thin) () -> () + +sil [ossa] [always_inline] @do_inline_this : $@convention(thin) () -> () { +bb0: + %d1 = function_ref @doSomething1 : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + %9999 = tuple() + return %9999 : $() +} + +sil [ossa] @donot_inline_this : $@convention(thin) () -> () { +bb0: + %d1 = function_ref @doSomething2 : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + %9999 = tuple() + return %9999 : $() +} + +sil [ossa] @empty_function : $@convention(thin) () -> () { +bb0: + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @caller : $@convention(thin) () -> () { +// CHECK-NOT: function_ref @do_inline_this : $@convention(thin) () -> () +// CHECK: function_ref @donot_inline_this : $@convention(thin) () -> () +// CHECK: function_ref @empty_function : $@convention(thin) () -> () +// CHECK: } // end sil function 'caller' +sil [ossa] @caller : $@convention(thin) () -> () { +bb0: + %c1 = function_ref @do_inline_this : $@convention(thin) () -> () + apply %c1() : $@convention(thin) () -> () + %c2 = function_ref @donot_inline_this : $@convention(thin) () -> () + apply %c2() : $@convention(thin) () -> () + %c3 = function_ref @empty_function : $@convention(thin) () -> () + apply %c3() : $@convention(thin) () -> () + %9999 = tuple() + return %9999 : $() +} diff --git a/test/SILOptimizer/let_propagation.swift b/test/SILOptimizer/let_propagation.swift index f68dac47bb187..2c390774c4c20 100644 --- a/test/SILOptimizer/let_propagation.swift +++ b/test/SILOptimizer/let_propagation.swift @@ -173,6 +173,13 @@ public func testUseGlobalLet() -> Int32 { } */ +// FIXME: 'A1's let properties cannot be optimized in -primary-file +// mode. However, this case could potentially be handled in WMO mode +// by finding all enclosing types that reference 'A1'. If they are all +// either internal or resilient and no pointers to these types escape, +// then it may be possible to prove that code outside this module +// never overwrites a value of type 'A1'. This will be easier to do +// when access markers are guaranteed complete in the -O pipeline. struct A1 { private let x: Int32 @@ -190,14 +197,14 @@ struct A1 { } // CHECK-LABEL: sil hidden @$s15let_propagation2A1V2f1{{[_0-9a-zA-Z]*}}F - // CHECK: bb0 - // CHECK: struct_extract {{.*}}#A1.x - // CHECK: struct_extract {{.*}}#Int32._value - // CHECK-NOT: load - // CHECK-NOT: struct_extract - // CHECK-NOT: struct_element_addr - // CHECK-NOT: ref_element_addr - // CHECK-NOT: bb1 + // FIX_CHECK: bb0 + // FIX_CHECK: struct_extract {{.*}}#A1.x + // FIX_CHECK: struct_extract {{.*}}#Int32._value + // FIX_CHECK-NOT: load + // FIX_CHECK-NOT: struct_extract + // FIX_CHECK-NOT: struct_element_addr + // FIX_CHECK-NOT: ref_element_addr + // FIX_CHECK-NOT: bb1 // CHECK: return func f1() -> Int32 { // x should be loaded only once. @@ -206,9 +213,9 @@ struct A1 { // CHECK-LABEL: sil hidden @$s15let_propagation2A1V2f2{{[_0-9a-zA-Z]*}}F // CHECK: bb0 - // CHECK: integer_literal $Builtin.Int32, 200 - // CHECK-NEXT: struct $Int32 - // CHECK-NEXT: return + // FIX_CHECK: integer_literal $Builtin.Int32, 200 + // FIX_CHECK-NEXT: struct $Int32 + // FIX_CHECK-NEXT: return func f2() -> Int32 { // load y only once. return y + y diff --git a/test/SILOptimizer/let_properties_opts.sil b/test/SILOptimizer/let_properties_opts.sil index 749bcddb16f8d..552c3cc9b33f7 100644 --- a/test/SILOptimizer/let_properties_opts.sil +++ b/test/SILOptimizer/let_properties_opts.sil @@ -78,3 +78,64 @@ bb0(%0 : @owned $HasCenter): destroy_value %0 : $HasCenter return %9 : $HasCenter } + +// ----------------------------------------------------------------------------- +// Test that struct 'let's are not replaced with constants. A struct +// 'let' is part of a larger mutable value. + +private struct Inner { + @_hasStorage let val: Int32 { get } + init(val: Int32) +} + +private struct Outer { + @_hasStorage @_hasInitialValue var inner: Inner { get set } + init(inner: Inner) +} + +sil [transparent] @initInnerLet : $@convention(thin) () -> Inner { +bb0: + %0 = integer_literal $Builtin.Int32, 1 + %1 = struct $Int32 (%0 : $Builtin.Int32) + %2 = struct $Inner (%1 : $Int32) + return %2 : $Inner +} + +// Check that the returned value is reloaded from inner.val after the memcpy. +// +// CHECK-LABEL: sil hidden @testStructLet : $@convention(thin) (@inout Outer) -> Int32 { +// CHECK: bb0(%0 : $*Outer): +// CHECK: [[OUTADR:%.*]] = address_to_pointer %0 : $*Outer to $Builtin.RawPointer +// CHECK: builtin "int_memcpy_RawPointer_RawPointer_Int64"([[OUTADR]] : $Builtin.RawPointer, %{{.*}} : $Builtin.RawPointer, %{{.*}} : $Builtin.Int64, %{{.*}} : $Builtin.Int1) : $() +// CHECK: [[INADR:%.*]] = struct_element_addr %0 : $*Outer, #Outer.inner +// CHECK: [[VALADR:%.*]] = struct_element_addr [[INADR]] : $*Inner, #Inner.val +// CHECK: [[VAL:%.*]] = load %22 : $*Int32 +// CHECK: return [[VAL]] : $Int32 +// CHECK-LABEL: } // end sil function 'testStructLet' +sil hidden @testStructLet : $@convention(thin) (@inout Outer) -> Int32 { +bb0(%0 : $*Outer): + %1 = address_to_pointer %0 : $*Outer to $Builtin.RawPointer + %2 = metatype $@thick Outer.Type + %3 = builtin "sizeof"(%2 : $@thick Outer.Type) : $Builtin.Word + %4 = builtin "sextOrBitCast_Word_Int64"(%3 : $Builtin.Word) : $Builtin.Int64 + %5 = integer_literal $Builtin.Int64, 0 + %6 = builtin "cmp_slt_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1 + cond_fail %6 : $Builtin.Int1, "UnsafeMutableRawBufferPointer with negative count" + %8 = integer_literal $Builtin.Int32, 0 + %9 = struct $Int32 (%8 : $Builtin.Int32) + %10 = integer_literal $Builtin.Int1, 0 + %11 = alloc_stack $Int32 + store %9 to %11 : $*Int32 + %13 = address_to_pointer %11 : $*Int32 to $Builtin.RawPointer + %14 = metatype $@thick Int32.Type + %15 = builtin "sizeof"(%14 : $@thick Int32.Type) : $Builtin.Word + %16 = builtin "sextOrBitCast_Word_Int64"(%15 : $Builtin.Word) : $Builtin.Int64 + %17 = builtin "cmp_slt_Int64"(%16 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1 + cond_fail %17 : $Builtin.Int1, "Negative value is not representable" + %19 = builtin "int_memcpy_RawPointer_RawPointer_Int64"(%1 : $Builtin.RawPointer, %13 : $Builtin.RawPointer, %16 : $Builtin.Int64, %10 : $Builtin.Int1) : $() + dealloc_stack %11 : $*Int32 + %21 = struct_element_addr %0 : $*Outer, #Outer.inner + %22 = struct_element_addr %21 : $*Inner, #Inner.val + %23 = load %22 : $*Int32 + return %23 : $Int32 +} diff --git a/test/SILOptimizer/let_properties_opts.swift b/test/SILOptimizer/let_properties_opts.swift index cf230c39ebe25..c22d41d74e4de 100644 --- a/test/SILOptimizer/let_properties_opts.swift +++ b/test/SILOptimizer/let_properties_opts.swift @@ -1,7 +1,8 @@ - // RUN: %target-swift-frontend -module-name let_properties_opts %s -O -enforce-exclusivity=checked -emit-sil | %FileCheck -check-prefix=CHECK-WMO %s // RUN: %target-swift-frontend -module-name let_properties_opts -primary-file %s -O -emit-sil | %FileCheck %s +// REQUIRES: optimized_stdlib + // Test propagation of non-static let properties with compile-time constant values. // TODO: Once this optimization can remove the propagated fileprivate/internal let properties or @@ -78,6 +79,11 @@ public class Foo1 { } } +// FIXME: Handle properties of non-private structs in WMO mode at +// least. All enclosing types need to be analyzed to determine if any +// pointer that may reach the struct property has unknown uses. This +// will be easier to do when access markers are guaranteed complete in +// the -O pipeline. public struct Boo { public let Prop0: Int32 = 1 let Prop1: Int32 = 1 + 4/2 + 8 @@ -101,6 +107,11 @@ public class Foo2 { public class C {} +// FIXME: Handle properties of non-private structs in WMO mode at +// least. All enclosing types need to be analyzed to determine if any +// pointer that may reach the struct property has unknown uses. This +// will be easier to do when access markers are guaranteed complete in +// the -O pipeline. struct Boo3 { //public let Prop0: Int32 @@ -126,6 +137,12 @@ struct Boo3 { // The initializer of this struct can be defined elsewhere, // e.g. in an extension of this struct in a different module. +// +// FIXME: Handle properties of non-private structs in WMO mode at +// least. All enclosing types need to be analyzed to determine if any +// pointer that may reach the struct property has unknown uses. This +// will be easier to do when access markers are guaranteed complete in +// the -O pipeline. public struct StructWithOnlyPublicLetProperties { public let Prop0: Int32 public let Prop1: Int32 @@ -139,6 +156,12 @@ public struct StructWithOnlyPublicLetProperties { // The initializer of this struct cannot be defined outside // of the current module, because it contains an internal stored // property, which is impossible to initialize outside of this module. +// +// FIXME: Handle properties of non-private structs in WMO mode at +// least. All enclosing types need to be analyzed to determine if any +// pointer that may reach the struct property has unknown uses. This +// will be easier to do when access markers are guaranteed complete in +// the -O pipeline. public struct StructWithPublicAndInternalLetProperties { public let Prop0: Int32 internal let Prop1: Int32 @@ -152,6 +175,12 @@ public struct StructWithPublicAndInternalLetProperties { // The initializer of this struct cannot be defined elsewhere, // because it contains a fileprivate stored property, which is // impossible to initialize outside of this file. +// +// FIXME: Handle properties of non-private structs in WMO mode at +// least. All enclosing types need to be analyzed to determine if any +// pointer that may reach the struct property has unknown uses. This +// will be easier to do when access markers are guaranteed complete in +// the -O pipeline. public struct StructWithPublicAndInternalAndPrivateLetProperties { public let Prop0: Int32 internal let Prop1: Int32 @@ -221,29 +250,42 @@ public func testClassPublicLet(_ f: Foo) -> Int32 { return f.Prop0 } +// FIXME: Handle struct properties. +// // CHECK-LABEL: sil @$s19let_properties_opts13testStructLetys5Int32VAA3BooVF : $@convention(thin) (Boo) -> Int32 -// CHECK: bb0 -// CHECK: integer_literal $Builtin.Int32, 75 -// CHECK-NEXT: struct $Int32 -// CHECK-NEXT: return +// FIX_CHECK: integer_literal $Builtin.Int32, 75 +// FIX_CHECK-NEXT: struct $Int32 +// FIX_CHECK-NEXT: return +// CHECK: struct_extract %0 : $Boo, #Boo.Prop1 +// CHECK: struct_extract %0 : $Boo, #Boo.Prop2 +// CHECK: struct_extract %0 : $Boo, #Boo.Prop3 +// CHECK-LABEL: } // end sil function '$s19let_properties_opts13testStructLetys5Int32VAA3BooVF' public func testStructLet(_ b: Boo) -> Int32 { return b.Prop1 + b.Prop1 + b.Prop2 + b.Prop3 } +// FIXME: Handle struct properties. +// // CHECK-LABEL: sil @$s19let_properties_opts13testStructLetys5Int32VAA3BooVzF : $@convention(thin) (@inout Boo) -> Int32 -// CHECK: bb0 -// CHECK: integer_literal $Builtin.Int32, 75 -// CHECK-NEXT: struct $Int32 -// CHECK-NEXT: return +// FIX_CHECK: integer_literal $Builtin.Int32, 75 +// FIX_CHECK-NEXT: struct $Int32 +// FIX_CHECK-NEXT: return +// CHECK: struct_element_addr %0 : $*Boo, #Boo.Prop1 +// CHECK: struct_element_addr %0 : $*Boo, #Boo.Prop2 +// CHECK: struct_element_addr %0 : $*Boo, #Boo.Prop3 +// CHECK-LABEL: } // end sil function '$s19let_properties_opts13testStructLetys5Int32VAA3BooVzF' public func testStructLet(_ b: inout Boo) -> Int32 { return b.Prop1 + b.Prop1 + b.Prop2 + b.Prop3 } +// FIXME: Handle struct properties. +// // CHECK-LABEL: sil @$s19let_properties_opts19testStructPublicLetys5Int32VAA3BooVF : $@convention(thin) (Boo) -> Int32 -// CHECK: bb0 -// CHECK: integer_literal $Builtin.Int32, 1 -// CHECK-NEXT: struct $Int32 -// CHECK-NEXT: return +// FIX_CHECK: integer_literal $Builtin.Int32, 1 +// FIX_CHECK-NEXT: struct $Int32 +// FIX_CHECK-NEXT: return +// CHECK: struct_extract %0 : $Boo, #Boo.Prop0 +// CHECK-LABEL: } // end sil function '$s19let_properties_opts19testStructPublicLetys5Int32VAA3BooVF' public func testStructPublicLet(_ b: Boo) -> Int32 { return b.Prop0 } @@ -251,11 +293,10 @@ public func testStructPublicLet(_ b: Boo) -> Int32 { // Check that f.x is not constant folded, because the initializer of Foo2 has multiple // assignments to the property x with different values. // CHECK-LABEL: sil @$s19let_properties_opts13testClassLet2ys5Int32VAA4Foo2CF : $@convention(thin) (@guaranteed Foo2) -> Int32 -// bb0 // CHECK: ref_element_addr %{{[0-9]+}} : $Foo2, #Foo2.x // CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo2, #Foo2.x // CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo2, #Foo2.x -// CHECK: return +// CHECK-LABEL: } // end sil function '$s19let_properties_opts13testClassLet2ys5Int32VAA4Foo2CF' public func testClassLet2(_ f: Foo2) -> Int32 { return f.x + f.x } @@ -266,7 +307,7 @@ public func testClassLet2(_ f: Foo2) -> Int32 { // No constant folding should have been performed. // CHECK-WMO-NOT: integer_literal $Builtin.Int32, 92 // CHECK-WMO: struct_extract -// CHECK-WMO: } +// CHECK-WMO-LABEL: } // end sil function '$s19let_properties_opts27testStructWithMultipleInitsys5Int32VAA4Boo3V_AFtF' @inline(never) func testStructWithMultipleInits( _ boos1: Boo3, _ boos2: Boo3) -> Int32 { let count1 = boos1.Prop0 + boos1.Prop1 + boos1.Prop2 + boos1.Prop3 @@ -315,28 +356,43 @@ public func testStructPropertyAccessibility(_ b: StructWithOnlyPublicLetProperti // CHECK: struct_extract %0 : $StructWithPublicAndInternalLetProperties, #StructWithPublicAndInternalLetProperties.Prop0 // CHECK-NOT: integer_literal $Builtin.Int32, 21 // CHECK: return +// CHECK-LABEL: } // end sil function '$s19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0E34WithPublicAndInternalLetPropertiesVF' +// FIXME: Handle struct properties. +// // CHECK-WMO-LABEL: sil @$s19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0E34WithPublicAndInternalLetPropertiesVF -// CHECK-WMO: integer_literal $Builtin.Int32, 21 -// CHECK-WMO-NEXT: struct $Int32 -// CHECK-WMO-NEXT: return +// FIX_CHECK-WMO: integer_literal $Builtin.Int32, 21 +// FIX_CHECK-WMO-NEXT: struct $Int32 +// FIX_CHECK-WMO-NEXT: return +// CHECK-WMO: struct_extract %0 : $StructWithPublicAndInternalLetProperties, #StructWithPublicAndInternalLetProperties.Prop0 +// CHECK-WMO: struct_extract %0 : $StructWithPublicAndInternalLetProperties, #StructWithPublicAndInternalLetProperties.Prop1 +// CHECK-WMO-LABEL: } // end sil function '$s19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0E34WithPublicAndInternalLetPropertiesVF' public func testStructPropertyAccessibility(_ b: StructWithPublicAndInternalLetProperties) -> Int32 { return b.Prop0 + b.Prop1 } +// FIXME: Handle struct properties. +// // Properties can be initialized only in this file, because one of the // properties is fileprivate. // Therefore their values are known and can be propagated. -// CHECK: sil @$s19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0e21WithPublicAndInternalK20PrivateLetPropertiesVF -// CHECK: integer_literal $Builtin.Int32, 33 -// CHECK-NEXT: struct $Int32 -// CHECK-NEXT: return +// CHECK-LABEL: sil @$s19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0e21WithPublicAndInternalK20PrivateLetPropertiesVF +// FIX_CHECK: integer_literal $Builtin.Int32, 33 +// FIX_CHECK-NEXT: struct $Int32 +// FIX_CHECK-NEXT: return +// CHECK: struct_extract %0 : $StructWithPublicAndInternalAndPrivateLetProperties, #StructWithPublicAndInternalAndPrivateLetProperties.Prop0 +// CHECK: struct_extract %0 : $StructWithPublicAndInternalAndPrivateLetProperties, #StructWithPublicAndInternalAndPrivateLetProperties.Prop1 +// CHECK: struct_extract %0 : $StructWithPublicAndInternalAndPrivateLetProperties, #StructWithPublicAndInternalAndPrivateLetProperties.Prop2 +// CHECK-LABEL: } // end sil function '$s19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0e21WithPublicAndInternalK20PrivateLetPropertiesVF' // CHECK-WMO-LABEL: sil @$s19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0e21WithPublicAndInternalK20PrivateLetPropertiesVF -// CHECK-WMO: integer_literal $Builtin.Int32, 33 -// CHECK-WMO-NEXT: struct $Int32 -// CHECK-WMO-NEXT: return +// FIX_CHECK-WMO: integer_literal $Builtin.Int32, 33 +// FIX_CHECK-WMO-NEXT: struct $Int32 +// FIX_CHECK-WMO-NEXT: return +// CHECK-WMO:struct_extract %0 : $StructWithPublicAndInternalAndPrivateLetProperties, #StructWithPublicAndInternalAndPrivateLetProperties.Prop0 +// CHECK-WMO:struct_extract %0 : $StructWithPublicAndInternalAndPrivateLetProperties, #StructWithPublicAndInternalAndPrivateLetProperties.Prop1 +// CHECK-WMO-LABEL: } // end sil function '$s19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0e21WithPublicAndInternalK20PrivateLetPropertiesVF' public func testStructPropertyAccessibility(_ b: StructWithPublicAndInternalAndPrivateLetProperties) -> Int32 { return b.Prop0 + b.Prop1 + b.Prop2 } @@ -361,12 +417,16 @@ struct RACStruct { var startIndex: Int { return 0 } + // FIXME: Handle struct properties. + // // CHECK-LABEL: RACStruct.endIndex.getter // CHECK-NEXT: sil hidden @{{.*}}endIndexSivg - // CHECK-NEXT: bb0 - // CHECK-NEXT: %1 = integer_literal $Builtin.Int{{.*}}, 27 - // CHECK-NEXT: %2 = struct $Int (%1 : $Builtin.Int{{.*}}) - // CHECK-NEXT: return %2 : $Int + // FIX_CHECK-NEXT: bb0 + // FIX_CHECK-NEXT: %1 = integer_literal $Builtin.Int{{.*}}, 27 + // FIX_CHECK-NEXT: %2 = struct $Int (%1 : $Builtin.Int{{.*}}) + // FIX_CHECK-NEXT: return %2 : $Int + // CHECK: struct_extract %0 : $RACStruct, #RACStruct.end + // CHECK-LABEL: } // end sil function '${{.*}}9RACStructV8endIndexSivg' var endIndex: Int { return end } subscript(_ bitIndex: Int) -> Bool { @@ -376,3 +436,74 @@ struct RACStruct { } extension RACStruct : RandomAccessCollection {} + +// ----------------------------------------------------------------------------- +// Test that struct 'let's are not replaced with constants. A struct +// 'let' is part of a larger mutable value. + +fileprivate struct Inner { + let val: Int32 +} + +fileprivate struct Outer { + var inner = Inner(val:1) +} + +// CHECK-LABEL: sil private [noinline] @$s19let_properties_opts19testInnerStructLet1{{.*}}ys5Int32VAA5OuterACLLVzF : $@convention(thin) (@inout Outer) -> Int32 { +// CHECK: bb0(%0 : $*Outer): +// CHECK: [[OUTADR:%.*]] = address_to_pointer %0 : $*Outer to $Builtin.RawPointer +// CHECK: builtin "int_memcpy_RawPointer_RawPointer_Int64"([[OUTADR]] : $Builtin.RawPointer, %{{.*}} : $Builtin.RawPointer, %{{.*}} : $Builtin.Int64, %{{.*}} : $Builtin.Int1) : $() +// CHECK: [[INADR:%.*]] = struct_element_addr %0 : $*Outer, #Outer.inner +// CHECK: [[VALADR:%.*]] = struct_element_addr [[INADR]] : $*Inner, #Inner.val +// CHECK: [[VAL:%.*]] = load [[VALADR]] : $*Int32 +// CHECK: return [[VAL]] : $Int32 +// CHECK-LABEL: } // end sil function '$s19let_properties_opts19testInnerStructLet1{{.*}}ys5Int32VAA5OuterACLLVzF' +// +// CHECK-WMO-LABEL: sil private [noinline] @$s19let_properties_opts19testInnerStructLet1{{.*}} : $@convention(thin) (@inout Outer) -> Int32 { +// CHECK-WMO: bb0(%0 : $*Outer): +// CHECK-WMO: [[OUTADR:%.*]] = address_to_pointer %0 : $*Outer to $Builtin.RawPointer +// CHECK-WMO: builtin "int_memcpy_RawPointer_RawPointer_Int64"([[OUTADR]] : $Builtin.RawPointer, %{{.*}} : $Builtin.RawPointer, %{{.*}} : $Builtin.Int64, %{{.*}} : $Builtin.Int1) : $() +// CHECK-WMO: [[INADR:%.*]] = struct_element_addr %0 : $*Outer, #Outer.inner +// CHECK-WMO: [[VALADR:%.*]] = struct_element_addr [[INADR]] : $*Inner, #Inner.val +// CHECK-WMO: [[VAL:%.*]] = load [[VALADR]] : $*Int32 +// CHECK-WMO: return [[VAL]] : $Int32 +// CHECK-WMO-LABEL: } // end sil function '$s19let_properties_opts19testInnerStructLet +@inline(never) +private func testInnerStructLet1(_ outer: inout Outer) -> Int32 { + withUnsafeMutableBytes(of: &outer) { + $0.storeBytes(of: 0, as: Int32.self) + } + return outer.inner.val +} + +// CHECK-LABEL: sil private [noinline] @$s19let_properties_opts19testInnerStructLet2{{.*}}ys5Int32VAA5OuterACLLVzF : $@convention(thin) (@inout Outer) -> Int32 { +// CHECK: bb0(%0 : $*Outer): +// CHECK: [[INADR:%.*]] = struct_element_addr %0 : $*Outer, #Outer.inner +// CHECK: [[OUTADR:%.*]] = address_to_pointer [[INADR]] : $*Inner to $Builtin.RawPointer +// CHECK: builtin "int_memcpy_RawPointer_RawPointer_Int64"([[OUTADR]] : $Builtin.RawPointer, %{{.*}} : $Builtin.RawPointer, %{{.*}} : $Builtin.Int64, %{{.*}} : $Builtin.Int1) : $() +// CHECK: [[VALADR:%.*]] = struct_element_addr [[INADR]] : $*Inner, #Inner.val +// CHECK: [[VAL:%.*]] = load [[VALADR]] : $*Int32 +// CHECK: return [[VAL]] : $Int32 +// CHECK-LABEL: } // end sil function '$s19let_properties_opts19testInnerStructLet2{{.*}}ys5Int32VAA5OuterACLLVzF' +// +// CHECK-WMO-LABEL: sil private [noinline] @$s19let_properties_opts19testInnerStructLet2{{.*}} : $@convention(thin) (@inout Outer) -> Int32 { +// CHECK-WMO: bb0(%0 : $*Outer): +// CHECK-WMO: [[INADR:%.*]] = struct_element_addr %0 : $*Outer, #Outer.inner +// CHECK-WMO: [[OUTADR:%.*]] = address_to_pointer [[INADR]] : $*Inner to $Builtin.RawPointer +// CHECK-WMO: builtin "int_memcpy_RawPointer_RawPointer_Int64"([[OUTADR]] : $Builtin.RawPointer, %{{.*}} : $Builtin.RawPointer, %{{.*}} : $Builtin.Int64, %{{.*}} : $Builtin.Int1) : $() +// CHECK-WMO: [[VALADR:%.*]] = struct_element_addr [[INADR]] : $*Inner, #Inner.val +// CHECK-WMO: [[VAL:%.*]] = load [[VALADR]] : $*Int32 +// CHECK-WMO: return [[VAL]] : $Int32 +// CHECK-WMO-LABEL: } // end sil function '$s19let_properties_opts19testInnerStructLet2 +@inline(never) +private func testInnerStructLet2(_ outer: inout Outer) -> Int32 { + withUnsafeMutableBytes(of: &outer.inner) { + $0.storeBytes(of: 0, as: Int32.self) + } + return outer.inner.val +} + +public func testInnerStructLetEntry() -> Int32 { + var outer = Outer() + return testInnerStructLet1(&outer) + testInnerStructLet2(&outer) +} diff --git a/test/SILOptimizer/semantic-arc-opts.sil b/test/SILOptimizer/semantic-arc-opts.sil index 98c6b8e78563d..852b8a2d71d29 100644 --- a/test/SILOptimizer/semantic-arc-opts.sil +++ b/test/SILOptimizer/semantic-arc-opts.sil @@ -8,6 +8,8 @@ import Builtin // Declarations // ////////////////// +typealias AnyObject = Builtin.AnyObject + enum MyNever {} enum FakeOptional { case none @@ -26,7 +28,14 @@ struct NativeObjectPair { sil @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair -class Klass {} +protocol MyFakeAnyObject : Klass { + func myFakeMethod() +} + +final class Klass {} +extension Klass : MyFakeAnyObject { + func myFakeMethod() +} sil @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () sil @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional) -> () sil @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional) -> () @@ -35,15 +44,15 @@ struct MyInt { var value: Builtin.Int32 } -struct AnotherStruct { - var i : Builtin.Int32 - var c : Klass +struct StructWithDataAndOwner { + var data : Builtin.Int32 + var owner : Klass } struct StructMemberTest { var c : Klass - var s : AnotherStruct - var t : (Builtin.Int32, AnotherStruct) + var s : StructWithDataAndOwner + var t : (Builtin.Int32, StructWithDataAndOwner) } class ClassLet { @@ -328,12 +337,12 @@ bb3: sil [ossa] @destructure_test : $@convention(thin) (@guaranteed StructMemberTest) -> Builtin.Int32 { bb0(%0 : @guaranteed $StructMemberTest): %2 = struct_extract %0 : $StructMemberTest, #StructMemberTest.t - %3 = copy_value %2 : $(Builtin.Int32, AnotherStruct) - (%4, %5) = destructure_tuple %3 : $(Builtin.Int32, AnotherStruct) - %6 = begin_borrow %5 : $AnotherStruct - %7 = struct_extract %6 : $AnotherStruct, #AnotherStruct.i - end_borrow %6 : $AnotherStruct - destroy_value %5 : $AnotherStruct + %3 = copy_value %2 : $(Builtin.Int32, StructWithDataAndOwner) + (%4, %5) = destructure_tuple %3 : $(Builtin.Int32, StructWithDataAndOwner) + %6 = begin_borrow %5 : $StructWithDataAndOwner + %7 = struct_extract %6 : $StructWithDataAndOwner, #StructWithDataAndOwner.data + end_borrow %6 : $StructWithDataAndOwner + destroy_value %5 : $StructWithDataAndOwner return %7 : $Builtin.Int32 } @@ -1781,3 +1790,417 @@ bb0(%0 : @guaranteed $ClassLet): %9999 = tuple() return %9999 : $() } + +// Make sure we can chew through this and get rid of all ARC traffic. +// CHECK-LABEL: sil [ossa] @init_existential_ref_forwarding_test : $@convention(thin) (@guaranteed Klass) -> () { +// CHECK-NOT: copy_value +// CHECK-NOT: begin_borrow +// CHECK: } // end sil function 'init_existential_ref_forwarding_test' +sil [ossa] @init_existential_ref_forwarding_test : $@convention(thin) (@guaranteed Klass) -> () { +bb0(%0 : @guaranteed $Klass): + %0a = copy_value %0 : $Klass + %1 = init_existential_ref %0a : $Klass : $Klass, $MyFakeAnyObject + %1a = begin_borrow %1 : $MyFakeAnyObject + %2 = open_existential_ref %1a : $MyFakeAnyObject to $@opened("A2E21C52-6089-11E4-9866-3C0754723233") MyFakeAnyObject + %3 = witness_method $@opened("A2E21C52-6089-11E4-9866-3C0754723233") MyFakeAnyObject, #MyFakeAnyObject.myFakeMethod!1, %2 : $@opened("A2E21C52-6089-11E4-9866-3C0754723233") MyFakeAnyObject : $@convention(witness_method: MyFakeAnyObject) <τ_0_0 where τ_0_0 : MyFakeAnyObject> (@guaranteed τ_0_0) -> () + apply %3<@opened("A2E21C52-6089-11E4-9866-3C0754723233") MyFakeAnyObject>(%2) : $@convention(witness_method: MyFakeAnyObject) <τ_0_0 where τ_0_0 : MyFakeAnyObject> (@guaranteed τ_0_0) -> () + end_borrow %1a : $MyFakeAnyObject + destroy_value %1 : $MyFakeAnyObject + %9999 = tuple() + return %9999 : $() +} + +/////////////////// +// Phi Web Tests // +/////////////////// + +// CHECK-LABEL: sil [ossa] @copy_of_guaranteed_simple_case : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () { +// CHECK-NOT: copy_value +// CHECK: } // end sil function 'copy_of_guaranteed_simple_case' +sil [ossa] @copy_of_guaranteed_simple_case : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () { +bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass): + cond_br undef, bb1, bb2 + +bb1: + %0a = copy_value %0 : $Klass + br bb3(%0a : $Klass) + +bb2: + %1a = copy_value %1 : $Klass + br bb3(%1a : $Klass) + +bb3(%2 : @owned $Klass): + %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () + apply %f(%2) : $@convention(thin) (@guaranteed Klass) -> () + destroy_value %2 : $Klass + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @copy_of_guaranteed_forwarding_use : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () { +// CHECK-NOT: copy_value +// CHECK: } // end sil function 'copy_of_guaranteed_forwarding_use' +sil [ossa] @copy_of_guaranteed_forwarding_use : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () { +bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass): + cond_br undef, bb1, bb2 + +bb1: + %0a = copy_value %0 : $Klass + %0b = unchecked_ref_cast %0a : $Klass to $Klass + br bb3(%0b : $Klass) + +bb2: + %1a = copy_value %1 : $Klass + %1b = unchecked_ref_cast %1a : $Klass to $Klass + br bb3(%1b : $Klass) + +bb3(%2 : @owned $Klass): + %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () + apply %f(%2) : $@convention(thin) (@guaranteed Klass) -> () + destroy_value %2 : $Klass + %9999 = tuple() + return %9999 : $() +} + +// A combined test of a common pattern, casting in an optional diamond. +// +// CHECK-LABEL: sil [ossa] @optional_cast_diamond : $@convention(thin) (@guaranteed FakeOptional) -> () { +// CHECK-NOT: copy_value +// CHECK: } // end sil function 'optional_cast_diamond' +sil [ossa] @optional_cast_diamond : $@convention(thin) (@guaranteed FakeOptional) -> () { +bb0(%0 : @guaranteed $FakeOptional): + %1 = copy_value %0 : $FakeOptional + switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt.1: bb2, case #FakeOptional.none!enumelt: bb1 + +bb1: + %2 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%2 : $FakeOptional) + +bb2(%3 : @owned $Klass): + %4 = unchecked_ref_cast %3 : $Klass to $Klass + %5 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %4 : $Klass + br bb3(%5 : $FakeOptional) + +bb3(%6 : @owned $FakeOptional): + %f = function_ref @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional) -> () + apply %f(%6) : $@convention(thin) (@guaranteed FakeOptional) -> () + destroy_value %6 : $FakeOptional + %9999 = tuple() + return %9999 : $() +} + +// A larger chained example. We can not handle this today, but we should be able +// to. +// +// CHECK-LABEL: sil [ossa] @optional_cast_diamond_chained : $@convention(thin) (@guaranteed FakeOptional) -> () { +// CHECK: copy_value +// CHECK: } // end sil function 'optional_cast_diamond_chained' +sil [ossa] @optional_cast_diamond_chained : $@convention(thin) (@guaranteed FakeOptional) -> () { +bb0(%0 : @guaranteed $FakeOptional): + %f = function_ref @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional) -> () + %1 = copy_value %0 : $FakeOptional + switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt.1: bb2, case #FakeOptional.none!enumelt: bb1 + +bb1: + %2 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%2 : $FakeOptional) + +bb2(%3 : @owned $Klass): + %4 = unchecked_ref_cast %3 : $Klass to $Klass + %5 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %4 : $Klass + br bb3(%5 : $FakeOptional) + +bb3(%6 : @owned $FakeOptional): + apply %f(%6) : $@convention(thin) (@guaranteed FakeOptional) -> () + switch_enum %6 : $FakeOptional, case #FakeOptional.some!enumelt.1: bb5, case #FakeOptional.none!enumelt: bb4 + +bb4: + %2a = enum $FakeOptional, #FakeOptional.none!enumelt + br bb6(%2a : $FakeOptional) + +bb5(%3a : @owned $Klass): + %4a = unchecked_ref_cast %3a : $Klass to $Klass + %5a = enum $FakeOptional, #FakeOptional.some!enumelt.1, %4a : $Klass + br bb6(%5a : $FakeOptional) + +bb6(%6a : @owned $FakeOptional): + apply %f(%6a) : $@convention(thin) (@guaranteed FakeOptional) -> () + destroy_value %6a : $FakeOptional + %9999 = tuple() + return %9999 : $() +} + +// Make sure we do not crash here. We need to be able to think about multiple +// phi node at the same time. +// +// CHECK-LABEL: sil [ossa] @multiple_phi_node_uses_of_one_copy : $@convention(thin) (@guaranteed Klass) -> () { +// CHECK: copy_value +// CHECK: } // end sil function 'multiple_phi_node_uses_of_one_copy' +sil [ossa] @multiple_phi_node_uses_of_one_copy : $@convention(thin) (@guaranteed Klass) -> () { +bb0(%0 : @guaranteed $Klass): + %1 = copy_value %0 : $Klass + cond_br undef, bb1, bb2 + +bb1: + br bb3(%1 : $Klass) + +bb2: + br bb3(%1 : $Klass) + +bb3(%2 : @owned $Klass): + destroy_value %2 : $Klass + %9999 = tuple() + return %9999 : $() +} + +// Lets do a phi tree. +// +// CHECK-LABEL: sil [ossa] @copy_guaranteed_three_copy_simple : $@convention(thin) (@guaranteed Klass) -> () { +// CHECK-NOT: copy_value +// CHECK: } // end sil function 'copy_guaranteed_three_copy_simple' +sil [ossa] @copy_guaranteed_three_copy_simple : $@convention(thin) (@guaranteed Klass) -> () { +bb0(%0 : @guaranteed $Klass): + cond_br undef, bb1, bb2 + +bb1: + cond_br undef, bb3, bb4 + +bb2: + %1 = copy_value %0 : $Klass + br bb5(%1 : $Klass) + +bb3: + %2 = copy_value %0 : $Klass + br bb5(%2 : $Klass) + +bb4: + %3 = copy_value %0 : $Klass + br bb5(%3 : $Klass) + +bb5(%end : @owned $Klass): + destroy_value %end : $Klass + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_simple : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> () { +// CHECK-NOT: copy_value +// CHECK-NOT: destroy_value +// CHECK: } // end sil function 'cast_with_optional_result_and_default_simple' +sil [ossa] @cast_with_optional_result_and_default_simple : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> () { +bb0(%0 : @guaranteed $StructWithDataAndOwner): + %1 = struct_extract %0 : $StructWithDataAndOwner, #StructWithDataAndOwner.owner + %2 = copy_value %1 : $Klass + checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2 + +bb1(%3 : @owned $Builtin.NativeObject): + %4 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %3 : $Builtin.NativeObject + br bb3(%4 : $FakeOptional) + +bb2(%5 : @owned $Klass): + destroy_value %5 : $Klass + %6 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%6 : $FakeOptional) + +bb3(%7 : @owned $FakeOptional): + destroy_value %7 : $FakeOptional + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_simple_unremoved_store : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional { +// CHECK-NOT: destroy_value +// CHECK: copy_value +// CHECK-NOT: destroy_value +// CHECK: } // end sil function 'cast_with_optional_result_and_default_simple_unremoved_store' +sil [ossa] @cast_with_optional_result_and_default_simple_unremoved_store : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional { +bb0(%result : $*FakeOptional, %0 : @guaranteed $StructWithDataAndOwner): + %1 = struct_extract %0 : $StructWithDataAndOwner, #StructWithDataAndOwner.owner + %2 = copy_value %1 : $Klass + checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2 + +bb1(%3 : @owned $Builtin.NativeObject): + %4 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %3 : $Builtin.NativeObject + br bb3(%4 : $FakeOptional) + +bb2(%5 : @owned $Klass): + destroy_value %5 : $Klass + %6 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%6 : $FakeOptional) + +bb3(%7 : @owned $FakeOptional): + %8 = copy_value %7 : $FakeOptional + store %8 to [init] %result : $*FakeOptional + destroy_value %7 : $FakeOptional + %9999 = tuple() + return %9999 : $() +} + +// The pass visits the blocks in order, so we know that the failure to do the +// copy_value in block 1 will occur before any copy removal in later +// blocks. Lets take advantage of that to make sure that if we fail to copy +// multiple times, we ignore the duplicate copy_value in the phi list. +// +// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_simple_unremoved_store_multiple_mods : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional { +// CHECK: copy_value +// CHECK-NOT: copy_value +// CHECK-NOT: destroy_value +// CHECK: } // end sil function 'cast_with_optional_result_and_default_simple_unremoved_store_multiple_mods' +sil [ossa] @cast_with_optional_result_and_default_simple_unremoved_store_multiple_mods : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional { +bb0(%result : $*FakeOptional, %0 : @guaranteed $StructWithDataAndOwner): + %1 = struct_extract %0 : $StructWithDataAndOwner, #StructWithDataAndOwner.owner + %2 = copy_value %1 : $Klass + checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2 + +bb1(%3 : @owned $Builtin.NativeObject): + %4 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %3 : $Builtin.NativeObject + br bb3(%4 : $FakeOptional) + +bb2(%5 : @owned $Klass): + destroy_value %5 : $Klass + %6 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%6 : $FakeOptional) + +bb3(%7 : @owned $FakeOptional): + %8 = copy_value %7 : $FakeOptional + %9 = copy_value %8 : $FakeOptional + destroy_value %9 : $FakeOptional + store %8 to [init] %result : $*FakeOptional + destroy_value %7 : $FakeOptional + %9999 = tuple() + return %9999 : $() +} + +// We can not eliminate the copy_value here since we store it into the out +// parameter. +// +// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional { +// CHECK: bb0( +// CHECK: copy_value +// CHECK: checked_cast_br +// CHECK: } // end sil function 'cast_with_optional_result_and_default_and_switchenum_after' +sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional { +bb0(%result : $*FakeOptional, %0 : @guaranteed $StructWithDataAndOwner): + %1 = struct_extract %0 : $StructWithDataAndOwner, #StructWithDataAndOwner.owner + %2 = copy_value %1 : $Klass + checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2 + +bb1(%3 : @owned $Builtin.NativeObject): + %4 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %3 : $Builtin.NativeObject + br bb3(%4 : $FakeOptional) + +bb2(%5 : @owned $Klass): + destroy_value %5 : $Klass + %6 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%6 : $FakeOptional) + +bb3(%7 : @owned $FakeOptional): + switch_enum %7 : $FakeOptional, case #FakeOptional.some!enumelt.1: bb5, case #FakeOptional.none!enumelt: bb4 + +bb4: + %8 = enum $FakeOptional, #FakeOptional.none!enumelt + store %8 to [init] %result : $*FakeOptional + br bb6 + +bb5(%9 : @owned $Builtin.NativeObject): + %10 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %9 : $Builtin.NativeObject + store %10 to [init] %result : $*FakeOptional + br bb6 + +bb6: + %9999 = tuple() + return %9999 : $() +} + +// Once we support converting struct_extract to a destructure here (since only +// one non-trivial leaf field), we should be able to optimize this case. +// +// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after_owned_arg : $@convention(thin) (@owned StructWithDataAndOwner) -> @out FakeOptional { +// CHECK: bb0( +// CHECK: copy_value +// CHECK: checked_cast_br +// CHECK: } // end sil function 'cast_with_optional_result_and_default_and_switchenum_after_owned_arg' +sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after_owned_arg : $@convention(thin) (@owned StructWithDataAndOwner) -> @out FakeOptional { +bb0(%result : $*FakeOptional, %0 : @owned $StructWithDataAndOwner): + %0a = begin_borrow %0 : $StructWithDataAndOwner + %1 = struct_extract %0a : $StructWithDataAndOwner, #StructWithDataAndOwner.owner + %2 = copy_value %1 : $Klass + checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2 + +bb1(%3 : @owned $Builtin.NativeObject): + %4 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %3 : $Builtin.NativeObject + br bb3(%4 : $FakeOptional) + +bb2(%5 : @owned $Klass): + destroy_value %5 : $Klass + %6 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%6 : $FakeOptional) + +bb3(%7 : @owned $FakeOptional): + switch_enum %7 : $FakeOptional, case #FakeOptional.some!enumelt.1: bb5, case #FakeOptional.none!enumelt: bb4 + +bb4: + %8 = enum $FakeOptional, #FakeOptional.none!enumelt + store %8 to [init] %result : $*FakeOptional + br bb6 + +bb5(%9 : @owned $Builtin.NativeObject): + %10 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %9 : $Builtin.NativeObject + store %10 to [init] %result : $*FakeOptional + br bb6 + +bb6: + end_borrow %0a : $StructWithDataAndOwner + destroy_value %0 : $StructWithDataAndOwner + %9999 = tuple() + return %9999 : $() +} + +// We can not eliminate this copy_value since the scope for %0a ends before the +// begin_borrow. +// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after_owned_arg_1 : $@convention(thin) (@owned StructWithDataAndOwner) -> @out FakeOptional { +// CHECK: bb0( +// CHECK: copy_value +// CHECK: checked_cast_br +// CHECK: } // end sil function 'cast_with_optional_result_and_default_and_switchenum_after_owned_arg_1' +sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after_owned_arg_1 : $@convention(thin) (@owned StructWithDataAndOwner) -> @out FakeOptional { +bb0(%result : $*FakeOptional, %0 : @owned $StructWithDataAndOwner): + %0a = begin_borrow %0 : $StructWithDataAndOwner + %1 = struct_extract %0a : $StructWithDataAndOwner, #StructWithDataAndOwner.owner + %2 = copy_value %1 : $Klass + checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2 + +bb1(%3 : @owned $Builtin.NativeObject): + %4 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %3 : $Builtin.NativeObject + br bb3(%4 : $FakeOptional) + +bb2(%5 : @owned $Klass): + destroy_value %5 : $Klass + %6 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%6 : $FakeOptional) + +bb3(%7 : @owned $FakeOptional): + switch_enum %7 : $FakeOptional, case #FakeOptional.some!enumelt.1: bb5, case #FakeOptional.none!enumelt: bb4 + +bb4: + end_borrow %0a : $StructWithDataAndOwner + destroy_value %0 : $StructWithDataAndOwner + %8 = enum $FakeOptional, #FakeOptional.none!enumelt + store %8 to [init] %result : $*FakeOptional + br bb6 + +bb5(%9 : @owned $Builtin.NativeObject): + end_borrow %0a : $StructWithDataAndOwner + %9a = begin_borrow %9 : $Builtin.NativeObject + %9b = copy_value %9a : $Builtin.NativeObject + %10 = enum $FakeOptional, #FakeOptional.some!enumelt.1, %9b : $Builtin.NativeObject + store %10 to [init] %result : $*FakeOptional + end_borrow %9a : $Builtin.NativeObject + destroy_value %9 : $Builtin.NativeObject + destroy_value %0 : $StructWithDataAndOwner + br bb6 + +bb6: + %9999 = tuple() + return %9999 : $() +} diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil index 890cfba8d02a8..ad673d269d351 100644 --- a/test/SILOptimizer/sil_combine.sil +++ b/test/SILOptimizer/sil_combine.sil @@ -3670,9 +3670,9 @@ bb0(%0 : $@thin T.Type): // CHECK: apply %0 sil @convert_function_substitution : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out ()) -> () { bb0(%0 : $@callee_guaranteed () -> @out ()): - %1 = convert_function %0 : $@callee_guaranteed () -> @out () to $@callee_guaranteed in () -> @out A for <()> + %1 = convert_function %0 : $@callee_guaranteed () -> @out () to $@callee_guaranteed @substituted () -> @out A for <()> %2 = alloc_stack $() - apply %1(%2) : $@callee_guaranteed in () -> @out A for <()> + apply %1(%2) : $@callee_guaranteed @substituted () -> @out A for <()> dealloc_stack %2 : $*() return undef : $() } @@ -3680,10 +3680,10 @@ bb0(%0 : $@callee_guaranteed () -> @out ()): // CHECK-LABEL: sil @convert_function_substitution_pa : sil @convert_function_substitution_pa : $@convention(thin) (@guaranteed @callee_guaranteed (@in Int, @in Int) -> @out (), @in Int) -> @owned @callee_guaranteed () -> @out () { bb0(%0 : $@callee_guaranteed (@in Int, @in Int) -> @out (), %1 : $*Int): - %2 = convert_function %0 : $@callee_guaranteed (@in Int, @in Int) -> @out () to $@callee_guaranteed in (@in A, @in B) -> @out C for - %3 = partial_apply [callee_guaranteed] %2(%1) : $@callee_guaranteed in (@in A, @in B) -> @out C for - %4 = partial_apply [callee_guaranteed] %3(%1) : $@callee_guaranteed in (@in A) -> @out C for - %5 = convert_function %4 : $@callee_guaranteed in () -> @out C for to $@callee_guaranteed () -> @out () + %2 = convert_function %0 : $@callee_guaranteed (@in Int, @in Int) -> @out () to $@callee_guaranteed @substituted (@in A, @in B) -> @out C for + %3 = partial_apply [callee_guaranteed] %2(%1) : $@callee_guaranteed @substituted (@in A, @in B) -> @out C for + %4 = partial_apply [callee_guaranteed] %3(%1) : $@callee_guaranteed @substituted (@in A) -> @out C for + %5 = convert_function %4 : $@callee_guaranteed @substituted () -> @out C for to $@callee_guaranteed () -> @out () return %5 : $@callee_guaranteed () -> @out () } diff --git a/test/SILOptimizer/temp_rvalue_opt.sil b/test/SILOptimizer/temp_rvalue_opt.sil index fb336341725a6..f88eda065e6c2 100644 --- a/test/SILOptimizer/temp_rvalue_opt.sil +++ b/test/SILOptimizer/temp_rvalue_opt.sil @@ -324,11 +324,11 @@ bb1: %6 = alloc_stack $UnfoldSequence copy_addr %1 to [initialization] %6 : $*UnfoldSequence %8 = struct_element_addr %6 : $*UnfoldSequence, #UnfoldSequence._next - %9 = load %8 : $*@callee_guaranteed <τ_0_0, τ_0_1> in (@inout τ_0_0) -> @out Optional<τ_0_1> for + %9 = load %8 : $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> @out Optional<τ_0_1> for %10 = alloc_stack $Optional %11 = struct_element_addr %1 : $*UnfoldSequence, #UnfoldSequence._state - strong_retain %9 : $@callee_guaranteed <τ_0_0, τ_0_1> in (@inout τ_0_0) -> @out Optional<τ_0_1> for - %13 = apply %9(%10, %11) : $@callee_guaranteed <τ_0_0, τ_0_1> in (@inout τ_0_0) -> @out Optional<τ_0_1> for + strong_retain %9 : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> @out Optional<τ_0_1> for + %13 = apply %9(%10, %11) : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> @out Optional<τ_0_1> for switch_enum_addr %10 : $*Optional, case #Optional.some!enumelt.1: bb3, case #Optional.none!enumelt: bb2 bb2: @@ -655,3 +655,19 @@ bb0(%0 : $*Builtin.NativeObject): %v = tuple () return %v : $() } + +// CHECK-LABEL: sil @eliminate_fix_lifetime_on_dest_copyaddr : $@convention(thin) (@inout Klass) -> () { +// CHECK-NOT: alloc_stack +// CHECK: fix_lifetime %0 +// CHECK-NOT: alloc_stack +// CHECK: } // end sil function 'eliminate_fix_lifetime_on_dest_copyaddr' +sil @eliminate_fix_lifetime_on_dest_copyaddr : $@convention(thin) (@inout Klass) -> () { +bb0(%0 : $*Klass): + %3 = alloc_stack $Klass + copy_addr %0 to [initialization] %3 : $*Klass + fix_lifetime %3 : $*Klass + destroy_addr %3 : $*Klass + dealloc_stack %3 : $*Klass + %9999 = tuple() + return %9999 : $() +} \ No newline at end of file diff --git a/test/SILOptimizer/temp_rvalue_opt_ossa.sil b/test/SILOptimizer/temp_rvalue_opt_ossa.sil index 5c15490bf2600..2a8b6a267c843 100644 --- a/test/SILOptimizer/temp_rvalue_opt_ossa.sil +++ b/test/SILOptimizer/temp_rvalue_opt_ossa.sil @@ -328,11 +328,11 @@ bb1: %6 = alloc_stack $UnfoldSequence copy_addr %1 to [initialization] %6 : $*UnfoldSequence %8 = struct_element_addr %6 : $*UnfoldSequence, #UnfoldSequence._next - %9 = load [copy] %8 : $*@callee_guaranteed <τ_0_0, τ_0_1> in (@inout τ_0_0) -> @out Optional<τ_0_1> for + %9 = load [copy] %8 : $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> @out Optional<τ_0_1> for %10 = alloc_stack $Optional %11 = struct_element_addr %1 : $*UnfoldSequence, #UnfoldSequence._state - %13 = apply %9(%10, %11) : $@callee_guaranteed <τ_0_0, τ_0_1> in (@inout τ_0_0) -> @out Optional<τ_0_1> for - destroy_value %9 : $@callee_guaranteed <τ_0_0, τ_0_1> in (@inout τ_0_0) -> @out Optional<τ_0_1> for + %13 = apply %9(%10, %11) : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> @out Optional<τ_0_1> for + destroy_value %9 : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@inout τ_0_0) -> @out Optional<τ_0_1> for switch_enum_addr %10 : $*Optional, case #Optional.some!enumelt.1: bb3, case #Optional.none!enumelt: bb2 bb2: @@ -1075,3 +1075,87 @@ bb0(%0 : @owned $GS): %v = tuple () return %v : $() } + +//////////////////////////////////////// +// Unchecked Take Enum Data Addr Inst // +//////////////////////////////////////// + +// Make sure we only handle this in the copy_addr case. With time, we should +// also handle the store case. +// +// CHECK-LABEL: sil [ossa] @unchecked_take_enum_data_addr_rvalue_simple : $@convention(thin) (@in_guaranteed Optional>, @inout Optional>) -> () { +// CHECK-NOT: alloc_stack +// CHECK: } // end sil function 'unchecked_take_enum_data_addr_rvalue_simple' +sil [ossa] @unchecked_take_enum_data_addr_rvalue_simple : $@convention(thin) (@in_guaranteed Optional>, @inout Optional>) -> () { +bb0(%0 : $*Optional>, %1 : $*Optional>): + %0a = unchecked_take_enum_data_addr %0 : $*Optional>, #Optional.some!enumelt.1 + %2 = struct_element_addr %0a : $*GS, #GS._value + %3 = load [trivial] %2 : $*Builtin.Int64 + %4 = alloc_stack $Optional> + copy_addr %1 to [initialization] %4 : $*Optional> + %4a = unchecked_take_enum_data_addr %4 : $*Optional>, #Optional.some!enumelt.1 + %6 = struct_element_addr %4a : $*GS, #GS._value + %7 = load [trivial] %6 : $*Builtin.Int64 + %8 = builtin "cmp_slt_Int64"(%3 : $Builtin.Int64, %7 : $Builtin.Int64) : $Builtin.Int1 + destroy_addr %4 : $*Optional> + dealloc_stack %4 : $*Optional> + %9999 = tuple() + return %9999 : $() +} + +// We do not support this today, since I am still bringing up store support. +// +// CHECK-LABEL: sil [ossa] @unchecked_take_enum_data_addr_store_rvalue_simple : $@convention(thin) (@in_guaranteed Optional>, @owned Optional>) -> () { +// CHECK: alloc_stack +// CHECK: } // end sil function 'unchecked_take_enum_data_addr_store_rvalue_simple' +sil [ossa] @unchecked_take_enum_data_addr_store_rvalue_simple : $@convention(thin) (@in_guaranteed Optional>, @owned Optional>) -> () { +bb0(%0 : $*Optional>, %1 : @owned $Optional>): + %0a = unchecked_take_enum_data_addr %0 : $*Optional>, #Optional.some!enumelt.1 + %2 = struct_element_addr %0a : $*GS, #GS._value + %3 = load [trivial] %2 : $*Builtin.Int64 + %4 = alloc_stack $Optional> + store %1 to [init] %4 : $*Optional> + %4a = unchecked_take_enum_data_addr %4 : $*Optional>, #Optional.some!enumelt.1 + %6 = struct_element_addr %4a : $*GS, #GS._value + %7 = load [trivial] %6 : $*Builtin.Int64 + %8 = builtin "cmp_slt_Int64"(%3 : $Builtin.Int64, %7 : $Builtin.Int64) : $Builtin.Int1 + destroy_addr %4 : $*Optional> + dealloc_stack %4 : $*Optional> + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @eliminate_fix_lifetime_on_dest_copyaddr : $@convention(thin) (@inout Klass) -> () { +// CHECK-NOT: alloc_stack +// CHECK: fix_lifetime %0 +// CHECK-NOT: alloc_stack +// CHECK: } // end sil function 'eliminate_fix_lifetime_on_dest_copyaddr' +sil [ossa] @eliminate_fix_lifetime_on_dest_copyaddr : $@convention(thin) (@inout Klass) -> () { +bb0(%0 : $*Klass): + %3 = alloc_stack $Klass + copy_addr %0 to [initialization] %3 : $*Klass + fix_lifetime %3 : $*Klass + destroy_addr %3 : $*Klass + dealloc_stack %3 : $*Klass + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @eliminate_fix_lifetime_on_dest_store : $@convention(thin) (@inout Klass) -> () { +// CHECK-NOT: alloc_stack +// CHECK: [[VALUE:%.*]] = load [copy] %0 +// CHECK-NEXT: fix_lifetime [[VALUE]] +// CHECK-NEXT: destroy_value [[VALUE]] +// CHECK-NOT: alloc_stack +// CHECK: } // end sil function 'eliminate_fix_lifetime_on_dest_store' +sil [ossa] @eliminate_fix_lifetime_on_dest_store : $@convention(thin) (@inout Klass) -> () { +bb0(%0 : $*Klass): + %2 = load [copy] %0 : $*Klass + %3 = alloc_stack $Klass + store %2 to [init] %3 : $*Klass + fix_lifetime %3 : $*Klass + destroy_addr %3 : $*Klass + dealloc_stack %3 : $*Klass + %9999 = tuple() + return %9999 : $() +} diff --git a/test/Sema/fixed_ambiguities/rdar35623181.swift b/test/Sema/fixed_ambiguities/rdar35623181.swift index eee6a869205f2..7470b0a7477df 100644 --- a/test/Sema/fixed_ambiguities/rdar35623181.swift +++ b/test/Sema/fixed_ambiguities/rdar35623181.swift @@ -2,7 +2,7 @@ extension Sequence where Element == String { func record() -> String { - // CHECK: function_ref @$ss20LazySequenceProtocolPsE3mapys0a3MapB0Vy8ElementsQzqd__Gqd__7ElementQzclF : $@convention(method) <τ_0_0 where τ_0_0 : LazySequenceProtocol><τ_1_0> (@guaranteed @callee_guaranteed <τ_0_0, τ_0_1> in (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_0.Element, τ_1_0>, @in_guaranteed τ_0_0) -> @out LazyMapSequence<τ_0_0.Elements, τ_1_0 + // CHECK: function_ref @$ss20LazySequenceProtocolPsE3mapys0a3MapB0Vy8ElementsQzqd__Gqd__7ElementQzclF : $@convention(method) <τ_0_0 where τ_0_0 : LazySequenceProtocol><τ_1_0> (@guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_0.Element, τ_1_0>, @in_guaranteed τ_0_0) -> @out LazyMapSequence<τ_0_0.Elements, τ_1_0 return lazy.map({ $0 }).joined(separator: ",") } } diff --git a/test/Serialization/load-arch-fallback-arm64e.swift b/test/Serialization/load-arch-fallback-arm64e.swift new file mode 100644 index 0000000000000..97e8f943de888 --- /dev/null +++ b/test/Serialization/load-arch-fallback-arm64e.swift @@ -0,0 +1,19 @@ +// Test the fallback for arm64e platforms. + +// RUN: %empty-directory(%t) +// RUN: mkdir %t/empty.swiftmodule +// RUN: %target-swift-frontend -emit-module -o %t/empty.swiftmodule/arm64.swiftmodule %S/../Inputs/empty.swift -module-name empty +// RUN: %target-swift-frontend -typecheck %s -I %t + +// RUN: mv %t/empty.swiftmodule/arm64.swiftmodule %t/empty.swiftmodule/%target-swiftmodule-name +// RUN: touch %t/empty.swiftmodule/arm64.swiftmodule +// RUN: %target-swift-frontend -typecheck %s -I %t + +// RUN: rm %t/empty.swiftmodule/%target-swiftmodule-name +// RUN: not %target-swift-frontend -typecheck %s -I %t 2>&1 | %FileCheck %s + +// REQUIRES: CPU=arm64e + +import empty +// CHECK: :[[@LINE-1]]:8: error: malformed compiled module: {{.*}}arm64.swiftmodule + diff --git a/test/Serialization/load-target-normalization.swift b/test/Serialization/load-target-normalization.swift index cdf0899e483d5..21040c0c2aab8 100644 --- a/test/Serialization/load-target-normalization.swift +++ b/test/Serialization/load-target-normalization.swift @@ -65,11 +65,12 @@ import ForeignModule // RUN: not %target-swift-frontend %s -typecheck -I %t -parse-stdlib -Xcc -arch -Xcc i386 -target arm64-apple-ios40.0 2>&1 | %FileCheck -DNORM=arm64-apple-ios %s // RUN: not %target-swift-frontend %s -typecheck -I %t -parse-stdlib -Xcc -arch -Xcc i386 -target aarch64-apple-ios40.0 2>&1 | %FileCheck -DNORM=arm64-apple-ios %s -// armv7s, armv7k, armv7 should be accepted. +// armv7s, armv7k, armv7, arm64e should be accepted. // RUN: not %target-swift-frontend %s -typecheck -I %t -parse-stdlib -Xcc -arch -Xcc i386 -target armv7s-apple-ios40.0 2>&1 | %FileCheck -DNORM=armv7s-apple-ios %s // RUN: not %target-swift-frontend %s -typecheck -I %t -parse-stdlib -Xcc -arch -Xcc i386 -target armv7k-apple-ios40.0 2>&1 | %FileCheck -DNORM=armv7k-apple-ios %s // RUN: not %target-swift-frontend %s -typecheck -I %t -parse-stdlib -Xcc -arch -Xcc i386 -target armv7-apple-ios40.0 2>&1 | %FileCheck -DNORM=armv7-apple-ios %s +// RUN: not %target-swift-frontend %s -typecheck -I %t -parse-stdlib -Xcc -arch -Xcc i386 -target arm64e-apple-ios40.0 2>&1 | %FileCheck -DNORM=arm64e-apple-ios %s // x86_64h should be accepted. diff --git a/test/SymbolGraph/Relationships/Synthesized/ConditionalConformance.swift b/test/SymbolGraph/Relationships/Synthesized/ConditionalConformance.swift new file mode 100644 index 0000000000000..f7ac63561f8aa --- /dev/null +++ b/test/SymbolGraph/Relationships/Synthesized/ConditionalConformance.swift @@ -0,0 +1,66 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name ConditionalConformance -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name ConditionalConformance -I %t -pretty-print -output-dir %t + +// R\UN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json +// RUN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json --check-prefix=SYNTH +// RUN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json --check-prefix=CONFORMS +// RUN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json --check-prefix=MEMBER + +// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefix=SYNTHEXT +// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefix=CONFORMSEXT +// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefix=MEMBEREXT + +// Relationships to Swift.Array should only go into the @Swift file. +// C\HECK-NOT: "s:Sa" + +public protocol P { + func foo() +} + +extension P { + public func foo() {} +} + +public struct S { + var x: T + public init(x: T) { + self.x = x + } +} + +// CONFORMS: "kind": "conformsTo" +// CONFORMS-NEXT: "source": "s:22ConditionalConformance1SV" +// CONFORMS-NEXT: "target": "s:22ConditionalConformance1PP" +// CONFORMS-NEXT: swiftConstraints +// CONFORMS: "kind": "sameType" +// CONFORMS-NEXT: "lhs": "T" +// CONFORMS-NEXT: "rhs": "Int" + +extension S: P where T == Int { + // SYNTH: "source": "s:22ConditionalConformance1PPAAE3fooyyF::SYNTHESIZED::s:22ConditionalConformance1SV" + // SYNTH-NEXT: "target": "s:22ConditionalConformance1SV" + + // MEMBER: "source": "s:22ConditionalConformance1SVAASiRszlE3baryyF", + // MEMBER-NEXT: "target": "s:22ConditionalConformance1SV" + public func bar() { + foo() + } +} + +// CONFORMSEXT: "kind": "conformsTo" +// CONFORMSEXT-NEXT: "source": "s:Sa" +// CONFORMSEXT-NEXT: "target": "s:22ConditionalConformance1PP" +// CONFORMSEXT-NEXT: swiftConstraints +// CONFORMSEXT: "kind": "sameType" +// CONFORMSEXT-NEXT: "lhs": "Element" +// CONFORMSEXT-NEXT: "rhs": "Int" + +extension Array: P where Element == Int { + // SYNTHEXT: "source": "s:22ConditionalConformance1PPAAE3fooyyF::SYNTHESIZED::s:Sa" + // SYNTHEXT-NEXT: "target": "s:Sa" + + // MEMBEREXT: "source": "s:Sa22ConditionalConformanceSiRszlE3baryyF", + // MEMBEREXT-NEXT: "target": "s:Sa", + public func bar() {} +} diff --git a/test/SymbolGraph/Symbols/DocComment/NoDocComment.swift b/test/SymbolGraph/Symbols/DocComment/NoDocComment.swift new file mode 100644 index 0000000000000..0b7099df62749 --- /dev/null +++ b/test/SymbolGraph/Symbols/DocComment/NoDocComment.swift @@ -0,0 +1,8 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name NoDocComment -emit-module-path %t/NoDocComment.swiftmodule +// RUN: %target-swift-symbolgraph-extract -module-name NoDocComment -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/NoDocComment.symbols.json + +public struct S {} + +// CHECK-NOT: docComment diff --git a/test/TBD/arm64e-arch.swift b/test/TBD/arm64e-arch.swift new file mode 100644 index 0000000000000..5f6d2f1987a0e --- /dev/null +++ b/test/TBD/arm64e-arch.swift @@ -0,0 +1,7 @@ +// RUN: %swift -typecheck -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -module-name TBDTester -emit-tbd -emit-tbd-path - | %FileCheck %s + +public func testSwiftFunc() {} + +// CHECK: --- !tapi-tbd-v3 +// CHECK: archs: [ arm64e ] +// CHECK: symbols: [ '_$s{{.*}}testSwiftFunc{{.*}}' ] diff --git a/test/attr/attr_dynamic_callable.swift b/test/attr/attr_dynamic_callable.swift index 94da1fbcc41f3..daa05ecccd228 100644 --- a/test/attr/attr_dynamic_callable.swift +++ b/test/attr/attr_dynamic_callable.swift @@ -487,3 +487,37 @@ struct B { B()("hello") // ok B()("\(1)") // ok + +// SR-12019 +@dynamicCallable +struct SR12019_S { + func dynamicallyCall(withArguments: [T]) { // expected-note {{where 'T' = 'Int'}} + print("hi") + } +} + +@dynamicCallable +protocol SR12019 { + func dynamicallyCall(withArguments: [T]) // expected-note 2{{where 'T' = 'Int'}} +} + +class SR12019Class: SR12019 { + func dynamicallyCall(withArguments: [T]) {} // expected-note {{where 'T' = 'Int'}} +} + +class SR12019SubClass: SR12019Class {} + +let sr12019s = SR12019_S() +sr12019s(1) // expected-error {{instance method 'dynamicallyCall(withArguments:)' requires that 'Int' conform to 'StringProtocol'}} + +// Protocol composition +let sr12019: SR12019&AnyObject = SR12019Class() +sr12019(1) // expected-error {{instance method 'dynamicallyCall(withArguments:)' requires that 'Int' conform to 'StringProtocol'}} + +// Protocol +let sr12019c: SR12019 = SR12019Class() +sr12019c(1) // expected-error {{instance method 'dynamicallyCall(withArguments:)' requires that 'Int' conform to 'StringProtocol'}} + +// Subclass +let sr12019sub = SR12019SubClass() +sr12019sub(1) // expected-error {{instance method 'dynamicallyCall(withArguments:)' requires that 'Int' conform to 'StringProtocol'}} diff --git a/test/attr/attr_dynamic_member_lookup.swift b/test/attr/attr_dynamic_member_lookup.swift index a98e650d44d0b..e61209fe76cb5 100644 --- a/test/attr/attr_dynamic_member_lookup.swift +++ b/test/attr/attr_dynamic_member_lookup.swift @@ -600,7 +600,9 @@ func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>, func keypath_with_incorrect_return_type(_ arr: Lens>) { for idx in 0..' to expected argument type 'Int'}} + // expected-error@-1 {{protocol 'Sequence' requires that 'Lens' conform to 'Strideable'}} + // expected-error@-2 {{cannot convert value of type 'Int' to expected argument type 'Lens'}} + // expected-error@-3 {{referencing operator function '..<' on 'Comparable' requires that 'Lens' conform to 'Comparable'}} let _ = arr[idx] } } diff --git a/test/decl/protocol/conforms/nscoding.swift b/test/decl/protocol/conforms/nscoding.swift index 2ec04609a7367..69f839bc0721c 100644 --- a/test/decl/protocol/conforms/nscoding.swift +++ b/test/decl/protocol/conforms/nscoding.swift @@ -8,6 +8,7 @@ // RUN: %FileCheck --check-prefix=NEGATIVE %s < %t/old.ast // REQUIRES: objc_interop +// UNSUPPORTED: CPU=arm64e // See also nscoding_stable_abi.swift, for the stable ABI deployment // target test. diff --git a/test/decl/protocol/protocols.swift b/test/decl/protocol/protocols.swift index 2ed52c88bd3b7..5893137278c22 100644 --- a/test/decl/protocol/protocols.swift +++ b/test/decl/protocol/protocols.swift @@ -17,7 +17,7 @@ protocol Test { var subminor : Int // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} {{21-21= { get <#set#> \}}} static var staticProperty: Int // expected-error{{property in protocol must have explicit { get } or { get set } specifier}} {{33-33= { get <#set#> \}}} - let bugfix // expected-error {{type annotation missing in pattern}} expected-error {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}} + let bugfix // expected-error {{type annotation missing in pattern}} expected-error {{protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier}} var comment // expected-error {{type annotation missing in pattern}} expected-error {{property in protocol must have explicit { get } or { get set } specifier}} } @@ -458,7 +458,7 @@ protocol ShouldntCrash { let fullName: String { get } // expected-error {{'let' declarations cannot be computed properties}} {{3-6=var}} // Let in protocol causes unclear errors and crashes - let fullName2: String // expected-error {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}} {{3-6=var}} {{24-24= { get \}}} + let fullName2: String // expected-error {{protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier}} {{3-6=var}} {{24-24= { get \}}} // Assert on protocol property requirement without a type var propertyWithoutType { get } // expected-error {{type annotation missing in pattern}} @@ -514,7 +514,7 @@ class C4 : P4 { // expected-error {{type 'C4' does not conform to protocol 'P4'} // Crash with invalid 'let' property in protocol protocol LetThereBeCrash { let x: Int - // expected-error@-1 {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}} {{13-13= { get \}}} + // expected-error@-1 {{protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier}} {{13-13= { get \}}} // expected-note@-2 {{declared here}} } diff --git a/test/decl/typealias/generic.swift b/test/decl/typealias/generic.swift index 3d6678db37bb8..27a6c4f4790b5 100644 --- a/test/decl/typealias/generic.swift +++ b/test/decl/typealias/generic.swift @@ -103,7 +103,7 @@ _ = A(a: "foo", // expected-error {{cannot convert value of type 'S b: 42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} _ = B(a: 12, b: 42) _ = B(a: 12, b: 42 as Float) -_ = B(a: "foo", b: 42) // expected-error {{conflicting arguments to generic parameter 'T1' ('String' vs. 'Int')}} +_ = B(a: "foo", b: 42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} _ = C(a: "foo", b: 42) _ = C(a: 42, // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} b: 42) diff --git a/test/decl/var/properties.swift b/test/decl/var/properties.swift index de196e6a94f21..91ab10d3ab6a2 100644 --- a/test/decl/var/properties.swift +++ b/test/decl/var/properties.swift @@ -884,7 +884,7 @@ protocol ProtocolWillSetDidSet4 { var a: Int { didSet willSet } // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} {{14-32={ get <#set#> \}}} expected-error 2 {{expected get or set in a protocol property}} } protocol ProtocolWillSetDidSet5 { - let a: Int { didSet willSet } // expected-error {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}} {{3-6=var}} {{13-13= { get \}}} {{none}} expected-error 2 {{expected get or set in a protocol property}} expected-error {{'let' declarations cannot be computed properties}} {{3-6=var}} + let a: Int { didSet willSet } // expected-error {{protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier}} {{3-6=var}} {{13-13= { get \}}} {{none}} expected-error 2 {{expected get or set in a protocol property}} expected-error {{'let' declarations cannot be computed properties}} {{3-6=var}} } var globalDidsetWillSet: Int { // expected-error {{non-member observing properties require an initializer}} diff --git a/test/decl/var/static_var.swift b/test/decl/var/static_var.swift index a4f67da5deedf..799aa5e00c769 100644 --- a/test/decl/var/static_var.swift +++ b/test/decl/var/static_var.swift @@ -177,8 +177,8 @@ protocol P { // expected-note{{extended type declared here}} class var v2: Int { get } // expected-error {{class properties are only allowed within classes; use 'static' to declare a requirement fulfilled by either a static or class property}} {{3-8=static}} static final var v3: Int { get } // expected-error {{only classes and class members may be marked with 'final'}} - static let l1: Int // expected-error {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}} - class let l2: Int // expected-error {{class properties are only allowed within classes; use 'static' to declare a requirement fulfilled by either a static or class property}} {{3-8=static}} expected-error {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}} + static let l1: Int // expected-error {{protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier}} + class let l2: Int // expected-error {{class properties are only allowed within classes; use 'static' to declare a requirement fulfilled by either a static or class property}} {{3-8=static}} expected-error {{protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier}} } extension P { diff --git a/test/diagnostics/educational-notes.swift b/test/diagnostics/educational-notes.swift index 8cafa26c28922..ea794d5ff250f 100644 --- a/test/diagnostics/educational-notes.swift +++ b/test/diagnostics/educational-notes.swift @@ -1,15 +1,68 @@ -// RUN: not %target-swift-frontend -enable-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s +// RUN: not %target-swift-frontend -color-diagnostics -enable-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s --match-full-lines --strict-whitespace +// RUN: not %target-swift-frontend -no-color-diagnostics -enable-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s --match-full-lines --strict-whitespace --check-prefix=NO-COLOR // A diagnostic with no educational notes let x = 1 + -// CHECK: error: expected expression after operator +// CHECK:{{.*}}[0merror: expected expression after operator // CHECK-NOT: {{-+$}} -// A diagnostic with an educational note +// NO-COLOR:{{.*}}error: expected expression after operator +// NO-COLOR-NOT: {{-+$}} + +// A diagnostic with an educational note using supported markdown features extension (Int, Int) {} -// CHECK: error: non-nominal type '(Int, Int)' cannot be extended -// CHECK-NEXT: extension (Int, Int) {} -// CHECK-NEXT: ^ ~~~~~~~~~~ -// CHECK-NEXT: Nominal Types -// CHECK-NEXT: ------------- -// CHECK-NEXT: Nominal types documentation content +// CHECK:{{.*}}[0merror: non-nominal type '(Int, Int)' cannot be extended +// CHECK-NEXT:extension (Int, Int) {} +// CHECK-NEXT:^ ~~~~~~~~~~ +// CHECK-NEXT:Nominal Types +// CHECK-NEXT:-------------- +// CHECK-EMPTY: +// CHECK-NEXT:Nominal types documentation content. This is a paragraph +// CHECK-EMPTY: +// CHECK-NEXT: blockquote +// CHECK-NEXT: {{$}} +// CHECK-NEXT: - item 1 +// CHECK-NEXT: - item 2 +// CHECK-NEXT: - item 3 +// CHECK-NEXT: {{$}} +// CHECK-NEXT: let x = 42 +// CHECK-NEXT: if x > 0 { +// CHECK-NEXT: print("positive") +// CHECK-NEXT: } +// CHECK-NEXT: {{$}} +// CHECK-NEXT:Type 'MyClass' +// CHECK-EMPTY: +// CHECK-NEXT:[Swift](swift.org) +// CHECK-EMPTY: +// CHECK-NEXT:bold italics +// CHECK-NEXT:-------------- +// CHECK-NEXT:Header 1 +// CHECK-NEXT:Header 3 + +// NO-COLOR:{{.*}}error: non-nominal type '(Int, Int)' cannot be extended +// NO-COLOR-NEXT:extension (Int, Int) {} +// NO-COLOR-NEXT:^ ~~~~~~~~~~ +// NO-COLOR-NEXT:Nominal Types +// NO-COLOR-NEXT:-------------- +// NO-COLOR-EMPTY: +// NO-COLOR-NEXT:Nominal types documentation content. This is a paragraph +// NO-COLOR-EMPTY: +// NO-COLOR-NEXT: blockquote +// NO-COLOR-NEXT: {{$}} +// NO-COLOR-NEXT: - item 1 +// NO-COLOR-NEXT: - item 2 +// NO-COLOR-NEXT: - item 3 +// NO-COLOR-NEXT: {{$}} +// NO-COLOR-NEXT: let x = 42 +// NO-COLOR-NEXT: if x > 0 { +// NO-COLOR-NEXT: print("positive") +// NO-COLOR-NEXT: } +// NO-COLOR-NEXT: {{$}} +// NO-COLOR-NEXT:Type 'MyClass' +// NO-COLOR-EMPTY: +// NO-COLOR-NEXT:[Swift](swift.org) +// NO-COLOR-EMPTY: +// NO-COLOR-NEXT:bold italics +// NO-COLOR-NEXT:-------------- +// NO-COLOR-NEXT:Header 1 +// NO-COLOR-NEXT:Header 3 diff --git a/test/diagnostics/test-docs/nominal-types.md b/test/diagnostics/test-docs/nominal-types.md index 67ccc055740ce..66f53d5befe67 100644 --- a/test/diagnostics/test-docs/nominal-types.md +++ b/test/diagnostics/test-docs/nominal-types.md @@ -1,3 +1,27 @@ -Nominal Types -------------- -Nominal types documentation content +# Nominal Types +*** +Nominal types documentation content. This is a paragraph + +> blockquote + +- item 1 +- item 2 +- item 3 + +``` +let x = 42 +if x > 0 { + print("positive") +} +``` + +Type `MyClass` + +[Swift](swift.org) + +**bold** *italics* + +*** + +# Header 1 +### Header 3 \ No newline at end of file diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index 95b23de79e9b6..d7d8f7126cc16 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -791,9 +791,8 @@ func testNilCoalescePrecedence(cond: Bool, a: Int?, r: ClosedRange?) { // ?? should have lower precedence than range and arithmetic operators. let r1 = r ?? (0...42) // ok - let r2 = (r ?? 0)...42 // not ok - // expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'ClosedRange'}} - // expected-error@-2 {{cannot convert value of type 'ClosedRange' to expected argument type 'Int'}} + let r2 = (r ?? 0)...42 // not ok: expected-error 2 {{cannot convert value of type 'Int' to expected argument type 'ClosedRange'}} + // expected-error@-1 {{referencing operator function '...' on 'Comparable' requires that 'ClosedRange' conform to 'Comparable'}} let r3 = r ?? 0...42 // parses as the first one, not the second. diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index 250ea33b3e92a..fb8346bac874c 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -864,25 +864,6 @@ func sr11562() { // expected-error@-1 {{subscript index of type '(Int, Int)' in a key path must be Hashable}} } -// SR-12290: Ban keypaths with contextual root and without a leading dot -struct SR_12290 { - let property: [Int] = [] - let kp1: KeyPath = \property.count // expected-error {{a Swift key path with contextual root must begin with a leading dot}}{{38-38=.}} - let kp2: KeyPath = \.property.count // Ok - let kp3: KeyPath = \SR_12290.property.count // Ok - - func foo1(_: KeyPath = \property.count) {} // expected-error {{a Swift key path with contextual root must begin with a leading dot}}{{42-42=.}} - func foo2(_: KeyPath = \.property.count) {} // Ok - func foo3(_: KeyPath = \SR_12290.property.count) {} // Ok - - func foo4(_: KeyPath) {} - func useFoo4() { - foo4(\property.count) // expected-error {{a Swift key path with contextual root must begin with a leading dot}}{{11-11=.}} - foo4(\.property.count) // Ok - foo4(\SR_12290.property.count) // Ok - } -} - func testSyntaxErrors() { // expected-note{{}} _ = \. ; // expected-error{{expected member name following '.'}} _ = \.a ; diff --git a/test/lit.cfg b/test/lit.cfg index e558168a86c89..cabbca8f0c90f 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -328,6 +328,7 @@ if run_os == 'ios' and run_vers.endswith('-macabi'): run_os = 'maccatalyst' run_ptrsize = '64' if ('64' in run_cpu or run_cpu == "s390x") else '32' +run_ptrauth = 'ptrauth' if run_cpu == 'arm64e' else 'noptrauth' run_endian = 'little' if run_cpu != 's390x' else 'big' sdk_overlay_link_path = "" @@ -433,6 +434,7 @@ config.substitutions.append( ('%swift-demangle-yamldump', config.swift_demangle_ config.substitutions.append( ('%Benchmark_O', config.benchmark_o) ) config.substitutions.append( ('%Benchmark_Driver', config.benchmark_driver) ) config.substitutions.append( ('%llvm-strings', config.llvm_strings) ) +config.substitutions.append( ('%target-ptrauth', run_ptrauth ) ) # This must come after all substitutions containing "%swift". config.substitutions.append( @@ -687,14 +689,23 @@ config.substitutions.append(('%target-cpu', run_cpu)) target_os_abi = run_os target_os_is_maccatalyst = "FALSE" +target_mandates_stable_abi = "FALSE" +if (run_cpu == 'arm64e'): + target_mandates_stable_abi = "TRUE" + config.available_features.add('swift_only_stable_abi') if (run_os == 'maccatalyst'): # For purposes of ABI, treat maccatalyst as macosx since the maccatalyst ABI # must match the macosx ABI. target_os_abi = 'macosx' target_os_is_maccatalyst = "TRUE" config.available_features.add("OS=ios") +if (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'windows-cygnus', 'windows-gnu', 'windows-msvc', 'linux-android']): + target_mandates_stable_abi = "TRUE" + config.available_features.add('swift_only_stable_abi') config.substitutions.append(('%target-os-abi', target_os_abi)) config.substitutions.append(('%target-os-is-maccatalyst', target_os_is_maccatalyst)) +config.substitutions.append(('%target-mandates-stable-abi', + target_mandates_stable_abi)) config.substitutions.append(('%target-endian', run_endian)) config.substitutions.append(('%target-os', run_os)) config.substitutions.append(('%target-ptrsize', run_ptrsize)) diff --git a/test/multifile/nested_types.swift b/test/multifile/nested_types.swift index 03596a4386535..08a634d1e9562 100644 --- a/test/multifile/nested_types.swift +++ b/test/multifile/nested_types.swift @@ -2,10 +2,10 @@ // Make sure we generate the outer metadata. -// CHECK-DAG: @"$s4test5OuterVMf" = internal constant {{.*}} {{@"\$sytWV"|i8\*\* getelementptr inbounds \(%swift.vwtable, %swift.vwtable\* @"\$s4test5OuterVWV", i32 0, i32 0\)}}, {{.*}} @"$s4test5OuterVMn" -// CHECK-DAG: @"$s4test6Outer2VMf" = internal constant {{.*}} {{@"\$sytWV"|i8\*\* getelementptr inbounds \(%swift.vwtable, %swift.vwtable\* @"\$s4test6Outer2VWV", i32 0, i32 0\)}}, {{.*}} @"$s4test6Outer2VMn" -// CHECK-DAG: @"$s4test6Outer3VMf" = internal constant {{.*}} {{@"\$sytWV"|i8\*\* getelementptr inbounds \(%swift.vwtable, %swift.vwtable\* @"\$s4test6Outer3VWV", i32 0, i32 0\)}}, {{.*}} @"$s4test6Outer3VMn" -// CHECK-DAG: @"$s4test6Outer4VMf" = internal constant {{.*}} {{@"\$sytWV"|i8\*\* getelementptr inbounds \(%swift.vwtable, %swift.vwtable\* @"\$s4test6Outer4VWV", i32 0, i32 0\)}}, {{.*}} @"$s4test6Outer4VMn" +// CHECK-DAG: @"$s4test5OuterVMf" = internal constant {{.*}} {{@"\$sytWV"|i8\*\* getelementptr inbounds \(%swift.vwtable, %swift.vwtable\* @"\$s4test5OuterVWV", i32 0, i32 0\)}}, {{.*}} @"$s4test5OuterVMn{{(\.ptrauth)?}}" +// CHECK-DAG: @"$s4test6Outer2VMf" = internal constant {{.*}} {{@"\$sytWV"|i8\*\* getelementptr inbounds \(%swift.vwtable, %swift.vwtable\* @"\$s4test6Outer2VWV", i32 0, i32 0\)}}, {{.*}} @"$s4test6Outer2VMn{{(\.ptrauth)?}}" +// CHECK-DAG: @"$s4test6Outer3VMf" = internal constant {{.*}} {{@"\$sytWV"|i8\*\* getelementptr inbounds \(%swift.vwtable, %swift.vwtable\* @"\$s4test6Outer3VWV", i32 0, i32 0\)}}, {{.*}} @"$s4test6Outer3VMn{{(\.ptrauth)?}}" +// CHECK-DAG: @"$s4test6Outer4VMf" = internal constant {{.*}} {{@"\$sytWV"|i8\*\* getelementptr inbounds \(%swift.vwtable, %swift.vwtable\* @"\$s4test6Outer4VWV", i32 0, i32 0\)}}, {{.*}} @"$s4test6Outer4VMn{{(\.ptrauth[.0-9]*)?}}" class C { } diff --git a/test/sil-passpipeline-dump/basic.test-sh b/test/sil-passpipeline-dump/basic.test-sh index ffa2b12f21347..e435b2a63194d 100644 --- a/test/sil-passpipeline-dump/basic.test-sh +++ b/test/sil-passpipeline-dump/basic.test-sh @@ -1,15 +1,13 @@ // RUN: %sil-passpipeline-dumper -Onone | %FileCheck %s -// RUN: %sil-passpipeline-dumper -Onone | %{python} -c 'import json; import sys; json.load(sys.stdin)' -// CHECK: [ -// CHECK: [ -// CHECK: "Serialization", -// CHECK: ["SerializeSILPass","serialize-sil"] -// CHECK: ], -// CHECK: [ -// CHECK: "Rest of Onone", -// CHECK: ["UsePrespecialized","use-prespecialized"], -// CHECK: ["AssumeSingleThreaded","sil-assume-single-threaded"], -// CHECK: ["SILDebugInfoGenerator","sil-debuginfo-gen"] -// CHECK: ] -// CHECK: ] \ No newline at end of file +// CHECK: --- +// CHECK: name: Mandatory Combines +// CHECK: passes: [ "for-each-loop-unroll", "mandatory-combine" ] +// CHECK: --- +// CHECK: name: Serialization +// CHECK: passes: [ "serialize-sil", "ownership-model-eliminator" ] +// CHECK: --- +// CHECK: name: Rest of Onone +// CHECK: passes: [ "use-prespecialized", "sil-assume-single-threaded", +// CHECK: "sil-debuginfo-gen" ] +// CHECK: ... diff --git a/test/stdlib/FloatingPointIR.swift b/test/stdlib/FloatingPointIR.swift index 73ae3eaeea4e9..2dda71d57be1b 100644 --- a/test/stdlib/FloatingPointIR.swift +++ b/test/stdlib/FloatingPointIR.swift @@ -38,6 +38,9 @@ func testConstantFoldFloatLiterals() { // arm64: call swiftcc void @"$s15FloatingPointIR13acceptFloat32yySfF{{.*}}"(float 1.000000e+00) // arm64: call swiftcc void @"$s15FloatingPointIR13acceptFloat64yySdF{{.*}}"(double 1.000000e+00) +// arm64e: call swiftcc void @"$s15FloatingPointIR13acceptFloat32yySfF{{.*}}"(float 1.000000e+00) +// arm64e: call swiftcc void @"$s15FloatingPointIR13acceptFloat64yySdF{{.*}}"(double 1.000000e+00) + // aarch64: call swiftcc void @"$s15FloatingPointIR13acceptFloat32yySfF{{.*}}"(float 1.000000e+00) // aarch64: call swiftcc void @"$s15FloatingPointIR13acceptFloat64yySdF{{.*}}"(double 1.000000e+00) diff --git a/test/stdlib/KeyPath.swift b/test/stdlib/KeyPath.swift index 9c279a5590f6d..7d3359f53a93c 100644 --- a/test/stdlib/KeyPath.swift +++ b/test/stdlib/KeyPath.swift @@ -970,6 +970,10 @@ keyPath.test("key path literal closures") { // Did we compute the indices once per closure construction, or once per // closure application? expectEqual(2, callsToComputeIndex) + + // rdar://problem/59445486 + let variadicFn: (String...) -> Int = \.count + expectEqual(3, variadicFn("a", "b", "c")) } // SR-6096 diff --git a/test/stdlib/TestNSNumberBridging.swift b/test/stdlib/TestNSNumberBridging.swift index 208889cd1d52e..10d8f009bf3a2 100644 --- a/test/stdlib/TestNSNumberBridging.swift +++ b/test/stdlib/TestNSNumberBridging.swift @@ -24,6 +24,7 @@ // UNSUPPORTED: CPU=armv7s // UNSUPPORTED: CPU=armv7k // UNSUPPORTED: CPU=arm64 +// UNSUPPORTED: CPU=arm64e import StdlibUnittest import Foundation diff --git a/test/stdlib/unmanaged_rc.swift b/test/stdlib/unmanaged_rc.swift index 9736b81ad8038..7f2616d5367b3 100644 --- a/test/stdlib/unmanaged_rc.swift +++ b/test/stdlib/unmanaged_rc.swift @@ -14,12 +14,12 @@ public func myPrint(_ k: Klass) { print(k) } // Check the codegen of _withUnsafeGuaranteedRef // -// CHECK-LABEL: sil public_external [transparent] [serialized] @$ss9UnmanagedV24_withUnsafeGuaranteedRefyqd__qd__xKXEKlF : $@convention(method) (@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , Unmanaged) -> (@out Result, @error Error) { -// CHECK: bb0([[RESULT:%.*]] : $*Result, [[FUNC:%.*]] : $@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , [[UNMANAGED:%.*]] : $Unmanaged): +// CHECK-LABEL: sil public_external [transparent] [serialized] @$ss9UnmanagedV24_withUnsafeGuaranteedRefyqd__qd__xKXEKlF : $@convention(method) (@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , Unmanaged) -> (@out Result, @error Error) { +// CHECK: bb0([[RESULT:%.*]] : $*Result, [[FUNC:%.*]] : $@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , [[UNMANAGED:%.*]] : $Unmanaged): // CHECK: [[UNMANAGED_REF:%.*]] = struct_extract [[UNMANAGED]] // CHECK: [[REF:%.*]] = unmanaged_to_ref [[UNMANAGED_REF]] // CHECK: [[REF_MARK_DEP:%.*]] = mark_dependence [[REF]] -// CHECK: try_apply {{%.*}}([[RESULT]], [[REF_MARK_DEP]]) : $@noescape @callee_guaranteed <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> in (@guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , normal bb2, error bb1 +// CHECK: try_apply {{%.*}}([[RESULT]], [[REF_MARK_DEP]]) : $@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : _RefCountedObject> (@guaranteed τ_0_0) -> (@out τ_0_1, @error Error) for , normal bb2, error bb1 // CHECK-NOT: destroy_value // CHECK: } // end sil function '$ss9UnmanagedV24_withUnsafeGuaranteedRefyqd__qd__xKXEKlF' diff --git a/test/type/protocol_composition.swift b/test/type/protocol_composition.swift index 602cb721a11ae..b78a9af3a5fd0 100644 --- a/test/type/protocol_composition.swift +++ b/test/type/protocol_composition.swift @@ -173,7 +173,7 @@ takesP1AndP2([Swift.AnyObject & P1 & P2]()) takesP1AndP2([AnyObject & protocol_composition.P1 & P2]()) takesP1AndP2([AnyObject & P1 & protocol_composition.P2]()) takesP1AndP2([DoesNotExist & P1 & P2]()) // expected-error {{use of unresolved identifier 'DoesNotExist'}} -takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}} expected-error {{cannot call value of non-function type 'Array<_>'}} +takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}} typealias T08 = P1 & inout P2 // expected-error {{'inout' may only be used on parameters}} typealias T09 = P1 & __shared P2 // expected-error {{'__shared' may only be used on parameters}} diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 83d674c93b73e..23f1654593201 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -34,9 +34,9 @@ swift_create_post_build_symlink(swift WORKING_DIRECTORY "${SWIFT_RUNTIME_OUTPUT_INTDIR}") add_swift_tool_symlink(swiftc swift compiler) +add_swift_tool_symlink(swift-symbolgraph-extract swift compiler) add_swift_tool_symlink(swift-autolink-extract swift autolink-driver) add_swift_tool_symlink(swift-indent swift editor-integration) -add_swift_tool_symlink(swift-symbolgraph-extract swift toolchain-tools) # If building as part of clang, make sure the headers are installed. if(NOT SWIFT_BUILT_STANDALONE) @@ -47,6 +47,9 @@ add_dependencies(compiler swift) swift_install_in_component(FILES "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swiftc${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION "bin" COMPONENT compiler) +swift_install_in_component(FILES "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swift-symbolgraph-extract${CMAKE_EXECUTABLE_SUFFIX}" + DESTINATION "bin" + COMPONENT compiler) add_dependencies(autolink-driver swift) swift_install_in_component(FILES "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swift-autolink-extract${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION "bin" @@ -55,7 +58,4 @@ add_dependencies(editor-integration swift) swift_install_in_component(FILES "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swift-indent${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION "bin" COMPONENT editor-integration) -add_dependencies(toolchain-tools swift) -swift_install_in_component(FILES "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swift-symbolgraph-extract${CMAKE_EXECUTABLE_SUFFIX}" - DESTINATION "bin" - COMPONENT toolchain-tools) + diff --git a/tools/sil-passpipeline-dumper/CMakeLists.txt b/tools/sil-passpipeline-dumper/CMakeLists.txt index a968e53fc2a6d..7c4a87a59ea6c 100644 --- a/tools/sil-passpipeline-dumper/CMakeLists.txt +++ b/tools/sil-passpipeline-dumper/CMakeLists.txt @@ -2,13 +2,11 @@ add_swift_host_tool(sil-passpipeline-dumper SILPassPipelineDumper.cpp SWIFT_COMPONENT tools ) -target_link_libraries(sil-passpipeline-dumper - PRIVATE - swiftClangImporter - swiftFrontend - swiftSerialization - swiftSILGen - swiftSILOptimizer - # FIXME: Circular dependencies require re-listing these libraries. - swiftAST - swiftSema) +target_link_libraries(sil-passpipeline-dumper PRIVATE + swiftFrontend + swiftIRGen + swiftSILGen + swiftSILOptimizer + # Clang libraries included to appease the linker on linux. + clangBasic + clangCodeGen) diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp index 62b10d0e450dc..f84ae1049e9dd 100644 --- a/tools/swift-reflection-dump/swift-reflection-dump.cpp +++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp @@ -286,6 +286,17 @@ class Image { Segments.push_back({HeaderAddress, O->getData()}); } + bool isMachOWithPtrAuth() const { + auto macho = dyn_cast(O); + if (!macho) + return false; + + auto &header = macho->getHeader(); + + return header.cputype == llvm::MachO::CPU_TYPE_ARM64 + && header.cpusubtype == llvm::MachO::CPU_SUBTYPE_ARM64E; + } + public: explicit Image(const ObjectFile *O) : O(O) { // Unfortunately llvm doesn't provide a uniform interface for iterating @@ -301,6 +312,8 @@ class Image { abort(); } } + + const ObjectFile *getObjectFile() const { return O; } unsigned getBytesInAddress() const { return O->getBytesInAddress(); @@ -338,7 +351,15 @@ class Image { auto found = DynamicRelocations.find(Addr); RemoteAbsolutePointer result; if (found == DynamicRelocations.end()) - result = RemoteAbsolutePointer("", pointerValue); + // In Mach-O images with ptrauth, the pointer value has an offset from + // the base address in the low 32 bits, and ptrauth discriminator info + // in the top 32 bits. + if (isMachOWithPtrAuth()) { + result = RemoteAbsolutePointer("", + HeaderAddress + (pointerValue & 0xffffffffull)); + } else { + result = RemoteAbsolutePointer("", pointerValue); + } else result = RemoteAbsolutePointer(found->second.Symbol, found->second.Offset); @@ -454,6 +475,13 @@ class ObjectMemoryReader : public MemoryReader { *result = wordSize; return true; } + case DLQ_GetPtrAuthMask: { + // We don't try to sign pointers at all in our view of the object + // mapping. + auto result = static_cast(outBuffer); + *result = (uintptr_t)~0ull; + return true; + } case DLQ_GetObjCReservedLowBits: { auto result = static_cast(outBuffer); if (applePlatform && !iosDerivedPlatform && wordSize == 8) { diff --git a/unittests/Basic/FrozenMultiMapTest.cpp b/unittests/Basic/FrozenMultiMapTest.cpp index e5b37393c6087..4645ce4707679 100644 --- a/unittests/Basic/FrozenMultiMapTest.cpp +++ b/unittests/Basic/FrozenMultiMapTest.cpp @@ -90,6 +90,37 @@ TEST(FrozenMultiMapCustomTest, SimpleFind) { } } +TEST(FrozenMultiMapCustomTest, TestResetWorks) { + Canary::resetIDs(); + FrozenMultiMap map; + + auto key1 = Canary(); + auto key2 = Canary(); + map.insert(key1, Canary()); + map.insert(key1, Canary()); + map.insert(key1, Canary()); + map.insert(key2, Canary()); + map.insert(key2, Canary()); + + map.setFrozen(); + map.reset(); + map.insert(key1, Canary()); + map.insert(key1, Canary()); + map.insert(key1, Canary()); + map.insert(key2, Canary()); + map.insert(key2, Canary()); + + map.setFrozen(); + + // Just do a quick sanity test. + auto range = map.getRange(); + auto begin = range.begin(); + auto end = range.end(); + ++begin; + ++begin; + EXPECT_EQ(std::distance(begin, end), 0); +} + TEST(FrozenMultiMapCustomTest, SimpleIter) { Canary::resetIDs(); FrozenMultiMap map; diff --git a/userdocs/diagnostics/associated-type-requirements.md b/userdocs/diagnostics/associated-type-requirements.md new file mode 100644 index 0000000000000..9071e19d1d24b --- /dev/null +++ b/userdocs/diagnostics/associated-type-requirements.md @@ -0,0 +1,23 @@ +Using Protocols with `Self` or Associated Type Requirements +--- +Protocols in Swift may be used as types, as part of a generic constraint, or as part of an opaque result type. +``` +// CustomStringConvertible can be used as a type. +func foo(bar: CustomStringConvertible) { /* ... */ } + +// ...or as a generic constraint on 'T'. +func bar(baz: T) { /* ... */ } + +// ...or as part of an opaque result type. +func baz() -> some CustomStringConvertible { /* ... */ } +``` + +While all Swift protocols can be used as generic constraints and as part of opaque result types, not all protocols can be used as types in general. Specifically, if a protocol has a requirement which references `Self` or an associated type, it cannot be used as a type. One such protocol is `Identifiable`, which has the requirement `var id: ID { get }`, where `ID` is an associated type. As a result, the following code is not allowed: +``` +func foo(bar: Identifiable) { /* ... */ } +// error: protocol 'Identifiable' can only be used as a generic constraint because it has Self or associated type requirements +``` + +Protocols like `Identifiable` which have `Self` or associated type requirements cannot be used as types because such types would rarely be useful in practice. They would be unable to allow use of `Self` or associated type requirements like `var id: ID { get }` because the associated type is not specified. + +When working with protocols having `Self` or associated type requirements constrained generics, opaque result types, or manual type erasure is sufficient to support most use cases. To learn more, see the [Protocols](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html), [Generics](https://docs.swift.org/swift-book/LanguageGuide/Generics.html), and [Opaque Types](https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html) sections of _The Swift Programming Language_. \ No newline at end of file diff --git a/userdocs/diagnostics/nominal-types.md b/userdocs/diagnostics/nominal-types.md index 58d8a2b4244fc..6a4484bdadead 100644 --- a/userdocs/diagnostics/nominal-types.md +++ b/userdocs/diagnostics/nominal-types.md @@ -1,7 +1,7 @@ -Nominal types -------------- -In Swift, a type is considered a nominal type if it is named. In other words, it has been defined by declaring the type somewhere in code. Examples of nominal types include classes, structs and enums, all of which must be declared before using them. Nominal types are an important concept in Swift because they can be extended, explicitly initialized using the 'MyType()' syntax, and may conform to protocols. +## Nominal types +*** +In Swift, a type is considered a nominal type if it is named. In other words, it has been defined by declaring the type somewhere in code. Examples of nominal types include classes, structs and enums, all of which must be declared before using them. Nominal types are an important concept in Swift because they can be extended, explicitly initialized using the `MyType()` syntax, and may conform to protocols. -In contrast, non-nominal types have none of these capabilities. A non-nominal type is any type which is not nominal. They are sometimes called ”structural types” because they are usually obtained by composing other types. Examples include function types like '(Int) -> (String)', tuple types like '(Int, String)', metatypes like 'Int.Type', and special types like 'Any' and 'AnyObject'. +In contrast, non-nominal types have none of these capabilities. A non-nominal type is any type which is not nominal. They are sometimes called "structural types" because they are usually obtained by composing other types. Examples include function types like `(Int) -> (String)`, tuple types like `(Int, String)`, metatypes like `Int.Type`, and special types like `Any` and `AnyObject`. -Whether the name of a protocol refers to a nominal or non-nominal type depends on where it appears in code. When used in a declaration or extension like 'extension MyProtocol { … }', 'MyProtocol' refers to a protocol type, which is nominal. This means that it may be extended and conform to protocols. However, when written as the type of a constant or variable, MyProtocol instead refers to a non-nominal, existential type. As a result, code like 'let value: MyProtocol = MyProtocol()' is not allowed because 'MyProtocol' refers to a non-nominal type in this context and cannot be explicitly initialized. +Whether the name of a protocol refers to a nominal or non-nominal type depends on where it appears in code. When used in a declaration or extension like `extension MyProtocol { … }`, `MyProtocol` refers to a protocol type, which is nominal. This means that it may be extended and conform to protocols. However, when written as the type of a constant or variable, `MyProtocol` instead refers to a non-nominal, existential type. As a result, code like `let value: MyProtocol = MyProtocol()` is not allowed because `MyProtocol` refers to a non-nominal type in this context and cannot be explicitly initialized. diff --git a/utils/build-script-impl b/utils/build-script-impl index 9549a2d3f2a59..76c81c76998cf 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -431,6 +431,7 @@ function verify_host_is_supported() { | iphoneos-armv7 \ | iphoneos-armv7s \ | iphoneos-arm64 \ + | iphoneos-arm64e \ | appletvsimulator-x86_64 \ | appletvos-arm64 \ | watchsimulator-i386 \ @@ -531,6 +532,13 @@ function set_build_options_for_host() { SWIFT_HOST_TRIPLE="arm64-apple-ios${DARWIN_DEPLOYMENT_VERSION_IOS}" llvm_target_arch="AArch64" + SWIFT_HOST_VARIANT_SDK="IOS" + cmake_osx_deployment_target="" + ;; + iphoneos-arm64e) + SWIFT_HOST_TRIPLE="arm64e-apple-ios${DARWIN_DEPLOYMENT_VERSION_IOS}" + llvm_target_arch="AArch64" + SWIFT_HOST_VARIANT_SDK="IOS" cmake_osx_deployment_target="" ;; diff --git a/utils/gyb.py b/utils/gyb.py index b0f6e78c63d5a..2df9a0311dbb6 100755 --- a/utils/gyb.py +++ b/utils/gyb.py @@ -1208,13 +1208,12 @@ def succ(a): help='''Bindings to be set in the template's execution context''') parser.add_argument( - 'file', type=argparse.FileType('rb'), + 'file', type=argparse.FileType(), help='Path to GYB template file (defaults to stdin)', nargs='?', - default=sys.stdin) # FIXME: stdin not binary mode on Windows + default=sys.stdin) parser.add_argument( - '-o', dest='target', type=argparse.FileType('wb'), - help='Output file (defaults to stdout)', - default=sys.stdout) # FIXME: stdout not binary mode on Windows + '-o', dest='target', type=argparse.FileType('w'), + help='Output file (defaults to stdout)', default=sys.stdout) parser.add_argument( '--test', action='store_true', default=False, help='Run a self-test') diff --git a/utils/swift_build_support/swift_build_support/targets.py b/utils/swift_build_support/swift_build_support/targets.py index 6a2f8f55c5013..f29bc1b5427a8 100644 --- a/utils/swift_build_support/swift_build_support/targets.py +++ b/utils/swift_build_support/swift_build_support/targets.py @@ -117,7 +117,7 @@ class StdlibDeploymentTarget(object): OSX = DarwinPlatform("macosx", archs=["x86_64"], sdk_name="OSX") - iOS = DarwinPlatform("iphoneos", archs=["armv7", "armv7s", "arm64"], + iOS = DarwinPlatform("iphoneos", archs=["armv7", "armv7s", "arm64", "arm64e"], sdk_name="IOS") iOSSimulator = DarwinPlatform("iphonesimulator", archs=["i386", "x86_64"], sdk_name="IOS_SIMULATOR", diff --git a/utils/webassembly/build-swiftpm.sh b/utils/webassembly/build-swiftpm.sh index cb00f0e96def9..5a7899166c7d7 100755 --- a/utils/webassembly/build-swiftpm.sh +++ b/utils/webassembly/build-swiftpm.sh @@ -12,9 +12,9 @@ SWIFT_BUILD=${NIGHTLY_TOOLCHAIN}/usr/bin/swift-build build_swiftpm() { local build_flags=$SWIFT_BUILD_FLAGS if [[ "$(uname)" == "Darwin" ]]; then - rpath_prefix='@executable_path/../' + rpath_prefix='@executable_path/../lib/swift/macosx' else - rpath_prefix='$ORIGIN/../' + rpath_prefix='$ORIGIN/../lib/swift/linux' fi build_flags="${build_flags} -Xlinker -rpath -Xlinker ${rpath_prefix}" cd ${SOURCE_PATH}/swiftpm diff --git a/validation-test/Reflection/existentials_objc.swift b/validation-test/Reflection/existentials_objc.swift index b631fe61061c8..c805ca8365d0d 100644 --- a/validation-test/Reflection/existentials_objc.swift +++ b/validation-test/Reflection/existentials_objc.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import Foundation diff --git a/validation-test/Reflection/functions.swift b/validation-test/Reflection/functions.swift index 4c7e490acb66f..ba7a9582d67b4 100644 --- a/validation-test/Reflection/functions.swift +++ b/validation-test/Reflection/functions.swift @@ -9,6 +9,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib /* This file pokes at the swift_reflection_infoForInstance() API diff --git a/validation-test/Reflection/functions_objc.swift b/validation-test/Reflection/functions_objc.swift index 9feda85161a83..8eb0deb85022e 100644 --- a/validation-test/Reflection/functions_objc.swift +++ b/validation-test/Reflection/functions_objc.swift @@ -7,6 +7,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest import Foundation diff --git a/validation-test/Reflection/inherits_NSObject.swift b/validation-test/Reflection/inherits_NSObject.swift index 05a08b2388dc9..a009165227bab 100644 --- a/validation-test/Reflection/inherits_NSObject.swift +++ b/validation-test/Reflection/inherits_NSObject.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import Foundation import simd diff --git a/validation-test/Reflection/inherits_ObjCClasses.swift b/validation-test/Reflection/inherits_ObjCClasses.swift index 2e3150344c5c9..3a32c9487a760 100644 --- a/validation-test/Reflection/inherits_ObjCClasses.swift +++ b/validation-test/Reflection/inherits_ObjCClasses.swift @@ -9,6 +9,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import simd import ObjCClasses diff --git a/validation-test/Reflection/inherits_Swift.swift b/validation-test/Reflection/inherits_Swift.swift index 3f46ed4466fd2..73870a5dae213 100644 --- a/validation-test/Reflection/inherits_Swift.swift +++ b/validation-test/Reflection/inherits_Swift.swift @@ -7,6 +7,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Array.swift b/validation-test/Reflection/reflect_Array.swift index 784e431a4f299..ecd5d5e828e1d 100644 --- a/validation-test/Reflection/reflect_Array.swift +++ b/validation-test/Reflection/reflect_Array.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Bool.swift b/validation-test/Reflection/reflect_Bool.swift index 2512574537b84..b7ffa6dd89e90 100644 --- a/validation-test/Reflection/reflect_Bool.swift +++ b/validation-test/Reflection/reflect_Bool.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Character.swift b/validation-test/Reflection/reflect_Character.swift index 4ed4305174f31..2a71b98cba693 100644 --- a/validation-test/Reflection/reflect_Character.swift +++ b/validation-test/Reflection/reflect_Character.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Dictionary.swift b/validation-test/Reflection/reflect_Dictionary.swift index 6b2d7328a6808..b0d8b2656ec57 100644 --- a/validation-test/Reflection/reflect_Dictionary.swift +++ b/validation-test/Reflection/reflect_Dictionary.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Double.swift b/validation-test/Reflection/reflect_Double.swift index 3107012845b6a..eb7364f6b5bab 100644 --- a/validation-test/Reflection/reflect_Double.swift +++ b/validation-test/Reflection/reflect_Double.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Enum_NoCase.swift b/validation-test/Reflection/reflect_Enum_NoCase.swift index ca6a1132b0f5f..3b158dacd5740 100644 --- a/validation-test/Reflection/reflect_Enum_NoCase.swift +++ b/validation-test/Reflection/reflect_Enum_NoCase.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Enum_SingleCaseIntPayload.swift b/validation-test/Reflection/reflect_Enum_SingleCaseIntPayload.swift index c2084141fe6b0..fa7479e5a15dd 100644 --- a/validation-test/Reflection/reflect_Enum_SingleCaseIntPayload.swift +++ b/validation-test/Reflection/reflect_Enum_SingleCaseIntPayload.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Enum_SingleCaseNoPayload.swift b/validation-test/Reflection/reflect_Enum_SingleCaseNoPayload.swift index 5f86f7aae6bf9..bc8cbd3a86264 100644 --- a/validation-test/Reflection/reflect_Enum_SingleCaseNoPayload.swift +++ b/validation-test/Reflection/reflect_Enum_SingleCaseNoPayload.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Enum_SingleCasePointerPayload.swift b/validation-test/Reflection/reflect_Enum_SingleCasePointerPayload.swift index 12f09c6807cbb..b51dbcb9a9adb 100644 --- a/validation-test/Reflection/reflect_Enum_SingleCasePointerPayload.swift +++ b/validation-test/Reflection/reflect_Enum_SingleCasePointerPayload.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Enum_TwoCaseOnePointerPayload.swift b/validation-test/Reflection/reflect_Enum_TwoCaseOnePointerPayload.swift index 16de7ce5c2cbf..9e0140ad57063 100644 --- a/validation-test/Reflection/reflect_Enum_TwoCaseOnePointerPayload.swift +++ b/validation-test/Reflection/reflect_Enum_TwoCaseOnePointerPayload.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Enum_TwoCaseOneStructPayload.swift b/validation-test/Reflection/reflect_Enum_TwoCaseOneStructPayload.swift index afb3380658791..9670c5e6dacb8 100644 --- a/validation-test/Reflection/reflect_Enum_TwoCaseOneStructPayload.swift +++ b/validation-test/Reflection/reflect_Enum_TwoCaseOneStructPayload.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Enum_TwoCaseTwoPayloads.swift b/validation-test/Reflection/reflect_Enum_TwoCaseTwoPayloads.swift index 0382910f0cc48..e480d760beb9a 100644 --- a/validation-test/Reflection/reflect_Enum_TwoCaseTwoPayloads.swift +++ b/validation-test/Reflection/reflect_Enum_TwoCaseTwoPayloads.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest @@ -268,6 +269,30 @@ reflect(object: ClassWithTwoCaseTwoPayloadsEnum()) // CHECK-32: (case name=none index=1))) // CHECK-32: (case name=none index=1)))) +reflect(enumValue: TwoCaseTwoPayloadsEnum.valid(Marker())) + +// CHECK-64: Reflecting an enum value. +// CHECK-64-NEXT: Type reference: +// CHECK-64-NEXT: (enum reflect_Enum_TwoCaseTwoPayloads.TwoCaseTwoPayloadsEnum) +// CHECK-64-NEXT: Value: .valid(_) + +// CHECK-32: Reflecting an enum value. +// CHECK-32-NEXT: Type reference: +// CHECK-32-NEXT: (enum reflect_Enum_TwoCaseTwoPayloads.TwoCaseTwoPayloadsEnum) +// CHECK-32-NEXT: Value: .valid(_) + +reflect(enumValue: TwoCaseTwoPayloadsEnum.invalid(7)) + +// CHECK-64: Reflecting an enum value. +// CHECK-64-NEXT: Type reference: +// CHECK-64-NEXT: (enum reflect_Enum_TwoCaseTwoPayloads.TwoCaseTwoPayloadsEnum) +// CHECK-64-NEXT: Value: .invalid(_) + +// CHECK-32: Reflecting an enum value. +// CHECK-32-NEXT: Type reference: +// CHECK-32-NEXT: (enum reflect_Enum_TwoCaseTwoPayloads.TwoCaseTwoPayloadsEnum) +// CHECK-32-NEXT: Value: .invalid(_) + doneReflecting() // CHECK-64: Done. diff --git a/validation-test/Reflection/reflect_Enum_value.swift b/validation-test/Reflection/reflect_Enum_value.swift index 9bebbb72a7c39..58666d9bf4492 100644 --- a/validation-test/Reflection/reflect_Enum_value.swift +++ b/validation-test/Reflection/reflect_Enum_value.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import Foundation import SwiftReflectionTest @@ -60,8 +61,9 @@ var a: Int enum OneStructPayload { case payloadA(StructInt) -case otherA -case otherB +case cowboyAlice +case cowboyBob +case cowboyCharlie } reflect(enumValue: OneStructPayload.payloadA(StructInt(a: 0))) @@ -71,12 +73,12 @@ reflect(enumValue: OneStructPayload.payloadA(StructInt(a: 0))) // CHECK-NEXT: (enum reflect_Enum_value.OneStructPayload) // CHECK-NEXT: Value: .payloadA(_) -reflect(enumValue: OneStructPayload.otherA) +reflect(enumValue: OneStructPayload.cowboyCharlie) // CHECK: Reflecting an enum value. // CHECK-NEXT: Type reference: // CHECK-NEXT: (enum reflect_Enum_value.OneStructPayload) -// CHECK-NEXT: Value: .otherA +// CHECK-NEXT: Value: .cowboyCharlie @objc class ObjCClass : NSObject { var a: Int = 0 @@ -172,14 +174,14 @@ reflect(enumValue: Optional>.some(.none)) // CHECK-NEXT: (enum reflect_Enum_value.OneSwiftClassPayload))) // CHECK-NEXT: Value: .some(.none) -reflect(enumValue: Optional>.some(.some(.otherA))) +reflect(enumValue: Optional>.some(.some(.otherC))) // CHECK: Reflecting an enum value. // CHECK-NEXT: Type reference: // CHECK-NEXT: (bound_generic_enum Swift.Optional // CHECK-NEXT: (bound_generic_enum Swift.Optional // CHECK-NEXT: (enum reflect_Enum_value.OneSwiftClassPayload))) -// CHECK-NEXT: Value: .some(.some(.otherA)) +// CHECK-NEXT: Value: .some(.some(.otherC)) reflect(enumValue: Optional>.some(.some(.otherE))) @@ -210,12 +212,12 @@ case otherB case payloadA(MixedStruct) } -reflect(enumValue: OneMixedStructPayload.otherA) +reflect(enumValue: OneMixedStructPayload.otherB) // CHECK: Reflecting an enum value. // CHECK-NEXT: Type reference: // CHECK-NEXT: (enum reflect_Enum_value.OneMixedStructPayload) -// CHECK-NEXT: Value: .otherA +// CHECK-NEXT: Value: .otherB reflect(enumValue: OneMixedStructPayload.payloadA(MixedStruct())) @@ -246,7 +248,239 @@ reflect(enumValue: OneNestedPayload.alternateB) // CHECK-NEXT: (enum reflect_Enum_value.OneNestedPayload) // CHECK-NEXT: Value: .alternateB -// XXX TODO: enum with tuple payload, enum with optional payload, indirect enum, enum with closure/function payload XXX + +enum OneTuplePayload { +case holderA((i: Int, c: SwiftClass)) +case emptyA +case emptyB +case emptyC +} + +reflect(enumValue: OneTuplePayload.holderA((i: 7, c: SwiftClass()))) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.OneTuplePayload) +// CHECK-NEXT: Value: .holderA(_) + +reflect(enumValue: OneTuplePayload.emptyB) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.OneTuplePayload) +// CHECK-NEXT: Value: .emptyB + +func foo() -> Int { return 7; } + +enum OneFunctionPayload { +case cargoA(() -> Int) +case alternateA +case alternateB +case alternateC +} + +reflect(enumValue: OneFunctionPayload.cargoA(foo)) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.OneFunctionPayload) +// CHECK-NEXT: Value: .cargoA(_) + +reflect(enumValue: OneFunctionPayload.alternateC) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.OneFunctionPayload) +// CHECK-NEXT: Value: .alternateC + +func tester1() { + let a = 7 + + func foo() -> Int { return a; } + + enum OneClosurePayload { + case cargoA(() -> Int) + case alternateA + case alternateB + case alternateC + } + + reflect(enumValue: OneClosurePayload.cargoA(foo)) + + // CHECK: Reflecting an enum value. + // CHECK-NEXT: Type reference: + + // XXX TODO: Figure out why the type reference is dumped differently sometimes: + // XXXX-NEXT: (nominal with unmangled suffix + // XXXX-NEXT: (enum OneClosurePayload #1 in reflect_Enum_value.tester1() -> ()) + + // CHECK: Value: .cargoA(_) + + reflect(enumValue: OneClosurePayload.alternateB) + + // CHECK: Reflecting an enum value. + // CHECK-NEXT: Type reference: + + // XXX TODO: Figure out why the type reference is dumped differently sometimes: + // XXXX-NEXT: (nominal with unmangled suffix + // XXXX-NEXT: (enum OneClosurePayload #1 in reflect_Enum_value.tester1() -> ()) + + // CHECK: Value: .alternateB +} + +tester1() + + +enum OneOptionalPayload { +case boxA(Optional) +case unboxA +case unboxB +case unboxC +case unboxD +case unboxE +} + +reflect(enumValue: OneOptionalPayload.boxA(7)) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.OneOptionalPayload) +// CHECK-NEXT: Value: .boxA(.some(_)) + +reflect(enumValue: OneOptionalPayload.unboxE) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.OneOptionalPayload) +// CHECK-NEXT: Value: .unboxE + +indirect enum OneIndirectPayload { +case child(OneIndirectPayload) +case leafA +case leafB +case leafC +case leafD +case leafE +case leafF +} + +reflect(enumValue: OneIndirectPayload.child(.leafF)) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.OneIndirectPayload) +// CHECK-NEXT: Value: .child(_) + +reflect(enumValue: OneIndirectPayload.leafF) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.OneIndirectPayload) +// CHECK-NEXT: Value: .leafF + +enum MultiPayload { +case stampA +case envelopeA(Int64) +case stampB +case envelopeB(Double) +case stampC +case envelopeC((Int32, Int32)) +case stampD +case stampE +} + +enum SinglePayloadEnumWithMultiPayloadEnumPayload { +case payloadA(MultiPayload) +case alsoA +case alsoB +case alsoC +case alsoD +} + +reflect(enumValue: SinglePayloadEnumWithMultiPayloadEnumPayload.payloadA(.stampB)) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.SinglePayloadEnumWithMultiPayloadEnumPayload) +// CHECK-NEXT: Value: .payloadA(.stampB) + +reflect(enumValue: SinglePayloadEnumWithMultiPayloadEnumPayload.payloadA(.envelopeC((1,2)))) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.SinglePayloadEnumWithMultiPayloadEnumPayload) +// CHECK-NEXT: Value: .payloadA(.envelopeC(_)) + +reflect(enumValue: SinglePayloadEnumWithMultiPayloadEnumPayload.alsoC) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.SinglePayloadEnumWithMultiPayloadEnumPayload) +// CHECK-NEXT: Value: .alsoC + +reflect(enumValue: Optional>.some(.none)) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (bound_generic_enum Swift.Optional +// CHECK-NEXT: (bound_generic_enum Swift.Optional +// CHECK-NEXT: (enum reflect_Enum_value.SinglePayloadEnumWithMultiPayloadEnumPayload))) +// CHECK-NEXT: Value: .some(.none) + +enum SmallMultiPayload { +case stampA +case envelopeA(Int8) +case stampB +case envelopeB(Int16) +case stampC +case envelopeC((UInt8, Int8)) +case stampD +case stampE +} + +enum SinglePayloadEnumWithSmallMultiPayloadEnumPayload { +case payloadA(SmallMultiPayload) +case alsoA +case alsoB +case alsoC +case alsoD +} + +reflect(enumValue: SinglePayloadEnumWithSmallMultiPayloadEnumPayload.payloadA(.stampB)) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.SinglePayloadEnumWithSmallMultiPayloadEnumPayload) +// CHECK-NEXT: Value: .payloadA(.stampB) + +reflect(enumValue: SinglePayloadEnumWithSmallMultiPayloadEnumPayload.payloadA(.envelopeC((1,2)))) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.SinglePayloadEnumWithSmallMultiPayloadEnumPayload) +// CHECK-NEXT: Value: .payloadA(.envelopeC(_)) + +reflect(enumValue: SinglePayloadEnumWithSmallMultiPayloadEnumPayload.alsoC) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (enum reflect_Enum_value.SinglePayloadEnumWithSmallMultiPayloadEnumPayload) +// CHECK-NEXT: Value: .alsoC + +reflect(enumValue: Optional>.some(.none)) + +// CHECK: Reflecting an enum value. +// CHECK-NEXT: Type reference: +// CHECK-NEXT: (bound_generic_enum Swift.Optional +// CHECK-NEXT: (bound_generic_enum Swift.Optional +// CHECK-NEXT: (enum reflect_Enum_value.SinglePayloadEnumWithSmallMultiPayloadEnumPayload))) +// CHECK-NEXT: Value: .some(.none) + + +// XXX TODO: Multipayload enums with pointer payloads + + +// XXX TODO: test enum with thin function payload XXX doneReflecting() // CHECK: Done. diff --git a/validation-test/Reflection/reflect_Enum_values.swift b/validation-test/Reflection/reflect_Enum_values.swift index 0f4590fc53d74..9903f7d92fb0b 100644 --- a/validation-test/Reflection/reflect_Enum_values.swift +++ b/validation-test/Reflection/reflect_Enum_values.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest @@ -1574,12 +1575,9 @@ reflect(enum: ManyCasesOneStringPayload.payload("hello, world")) // CHECK32-NEXT: (case name=otherC index=3)) // CHECKALL: Enum value: -// CHECK64-NEXT: (enum_value name=payload index=0 -// CHECK64-NEXT: (struct Swift.String) -// CHECK64-NEXT: ) - -// XXX Note: 32-bit String contains a multi_payload_enum which projectEnumValue cannot yet handle. -// CHECK32-NEXT: swift_reflection_projectEnumValue failed. +// CHECKALL-NEXT: (enum_value name=payload index=0 +// CHECKALL-NEXT: (struct Swift.String) +// CHECKALL-NEXT: ) reflect(enum: ManyCasesOneStringPayload.otherB) @@ -1645,12 +1643,7 @@ reflect(enum: ManyCasesOneStringPayload.otherB) // CHECKALL: Enum value: -// CHECK64-NEXT: (enum_value name=otherB index=2) - -// XXX Note: 32-bit String contains a multi_payload_enum which projectEnumValue cannot yet handle. -// CHECK32-NEXT: swift_reflection_projectEnumValue failed. - -//reflect(enum: ManyCasesManyPayloads.a("hi, world")) +// CHECKALL-NEXT: (enum_value name=otherB index=2) doneReflecting() diff --git a/validation-test/Reflection/reflect_Float.swift b/validation-test/Reflection/reflect_Float.swift index b1a87488836fe..f6715a43a0a53 100644 --- a/validation-test/Reflection/reflect_Float.swift +++ b/validation-test/Reflection/reflect_Float.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Int.swift b/validation-test/Reflection/reflect_Int.swift index b650728a786ea..f64184722f9f9 100644 --- a/validation-test/Reflection/reflect_Int.swift +++ b/validation-test/Reflection/reflect_Int.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Int16.swift b/validation-test/Reflection/reflect_Int16.swift index 0041fb1757a01..b916435e418c2 100644 --- a/validation-test/Reflection/reflect_Int16.swift +++ b/validation-test/Reflection/reflect_Int16.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Int32.swift b/validation-test/Reflection/reflect_Int32.swift index 99e24287e0e13..971b0aee5549d 100644 --- a/validation-test/Reflection/reflect_Int32.swift +++ b/validation-test/Reflection/reflect_Int32.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Int64.swift b/validation-test/Reflection/reflect_Int64.swift index b641c299f30d4..1da3ca423a08c 100644 --- a/validation-test/Reflection/reflect_Int64.swift +++ b/validation-test/Reflection/reflect_Int64.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_Int8.swift b/validation-test/Reflection/reflect_Int8.swift index 4e4d251703487..94affe524ee1a 100644 --- a/validation-test/Reflection/reflect_Int8.swift +++ b/validation-test/Reflection/reflect_Int8.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_NSArray.swift b/validation-test/Reflection/reflect_NSArray.swift index 621b055a0b928..a26ac252960fc 100644 --- a/validation-test/Reflection/reflect_NSArray.swift +++ b/validation-test/Reflection/reflect_NSArray.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest import Foundation diff --git a/validation-test/Reflection/reflect_NSNumber.swift b/validation-test/Reflection/reflect_NSNumber.swift index d90cdc1f56c8f..50402c1c4cc38 100644 --- a/validation-test/Reflection/reflect_NSNumber.swift +++ b/validation-test/Reflection/reflect_NSNumber.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest import Foundation diff --git a/validation-test/Reflection/reflect_NSSet.swift b/validation-test/Reflection/reflect_NSSet.swift index 2a42157e9abfd..06fe66ae11308 100644 --- a/validation-test/Reflection/reflect_NSSet.swift +++ b/validation-test/Reflection/reflect_NSSet.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest import Foundation diff --git a/validation-test/Reflection/reflect_NSString.swift b/validation-test/Reflection/reflect_NSString.swift index e3bd7b11fb0a0..ef462ab9f599e 100644 --- a/validation-test/Reflection/reflect_NSString.swift +++ b/validation-test/Reflection/reflect_NSString.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest import Foundation diff --git a/validation-test/Reflection/reflect_Set.swift b/validation-test/Reflection/reflect_Set.swift index d31609f49931d..722576c5d6d86 100644 --- a/validation-test/Reflection/reflect_Set.swift +++ b/validation-test/Reflection/reflect_Set.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_String.swift b/validation-test/Reflection/reflect_String.swift index 4984cd0e6cf1f..98a9b1df34773 100644 --- a/validation-test/Reflection/reflect_String.swift +++ b/validation-test/Reflection/reflect_String.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_UInt.swift b/validation-test/Reflection/reflect_UInt.swift index c0ce6730e90f4..422085238a4a2 100644 --- a/validation-test/Reflection/reflect_UInt.swift +++ b/validation-test/Reflection/reflect_UInt.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_UInt16.swift b/validation-test/Reflection/reflect_UInt16.swift index 4ed509b3857a7..1ed7849465df0 100644 --- a/validation-test/Reflection/reflect_UInt16.swift +++ b/validation-test/Reflection/reflect_UInt16.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_UInt32.swift b/validation-test/Reflection/reflect_UInt32.swift index 2742138f21a96..ac1231f779b89 100644 --- a/validation-test/Reflection/reflect_UInt32.swift +++ b/validation-test/Reflection/reflect_UInt32.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_UInt64.swift b/validation-test/Reflection/reflect_UInt64.swift index 2e8e0d19adf98..419ce0531fc90 100644 --- a/validation-test/Reflection/reflect_UInt64.swift +++ b/validation-test/Reflection/reflect_UInt64.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_UInt8.swift b/validation-test/Reflection/reflect_UInt8.swift index 224b078b0b3cf..c4301e3a5bb04 100644 --- a/validation-test/Reflection/reflect_UInt8.swift +++ b/validation-test/Reflection/reflect_UInt8.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_empty_class.swift b/validation-test/Reflection/reflect_empty_class.swift index 1bbafbc59ad23..e74f62bb3f370 100644 --- a/validation-test/Reflection/reflect_empty_class.swift +++ b/validation-test/Reflection/reflect_empty_class.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_empty_struct.swift b/validation-test/Reflection/reflect_empty_struct.swift index 85f4d50cf7e74..74c2441fc1cf4 100644 --- a/validation-test/Reflection/reflect_empty_struct.swift +++ b/validation-test/Reflection/reflect_empty_struct.swift @@ -7,6 +7,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test // REQUIRES: OS=macosx +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_empty_struct_compat.swift b/validation-test/Reflection/reflect_empty_struct_compat.swift index 33670754ffebd..d9a68c814be2a 100644 --- a/validation-test/Reflection/reflect_empty_struct_compat.swift +++ b/validation-test/Reflection/reflect_empty_struct_compat.swift @@ -7,6 +7,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test // REQUIRES: OS=macosx +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_existential.swift b/validation-test/Reflection/reflect_existential.swift index ff8489d9cc14d..6e976ab4e8dee 100644 --- a/validation-test/Reflection/reflect_existential.swift +++ b/validation-test/Reflection/reflect_existential.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Reflection/reflect_multiple_types.swift b/validation-test/Reflection/reflect_multiple_types.swift index 687549afa229f..878c38b678852 100644 --- a/validation-test/Reflection/reflect_multiple_types.swift +++ b/validation-test/Reflection/reflect_multiple_types.swift @@ -6,6 +6,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest import Foundation diff --git a/validation-test/Reflection/reflect_nested.swift b/validation-test/Reflection/reflect_nested.swift index 4984ca5f081fb..f3ac29f10fd29 100644 --- a/validation-test/Reflection/reflect_nested.swift +++ b/validation-test/Reflection/reflect_nested.swift @@ -3,6 +3,7 @@ // RUN: %target-run %target-swift-reflection-test %t/reflect_nested 2>&1 | %FileCheck %s --check-prefix=CHECK-%target-ptrsize // REQUIRES: objc_interop // REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib import SwiftReflectionTest diff --git a/validation-test/Sema/type_checker_perf/slow/rdar53589951.swift b/validation-test/Sema/type_checker_perf/slow/rdar53589951.swift new file mode 100644 index 0000000000000..702c92ee62ea9 --- /dev/null +++ b/validation-test/Sema/type_checker_perf/slow/rdar53589951.swift @@ -0,0 +1,27 @@ +// RUN: %target-typecheck-verify-swift -solver-expression-time-threshold=1 +// REQUIRES: tools-release,no_asan + +class Color { + init(hue: Double, saturation: Double, brightness: Double, alpha: Double) {} + init(red: Double, green: Double, blue: Double, alpha: Double) {} +} + +// expected-error@+1 {{reasonable time}} +let _: [Color] = [ + Color(r: 3, g: 72, b: 14, a: 48), + Color(r: 0, g: 240, b: 64, a: 77), + Color(r: 0, g: 255, b: 0, a: 160), + Color(r: 0, g: 168, b: 0, a: 255), + Color(r: 0, g: 140, b: 0, a: 255), + Color(r: 0, g: 112, b: 0, a: 255), + Color(r: 255, g: 255, b: 0, a: 255), + Color(r: 184, g: 184, b: 0, a: 255), + Color(r: 224, g: 112, b: 0, a: 255), + Color(r: 255, g: 0, b: 0, a: 255), + Color(r: 184, g: 0, b: 0, a: 255), + Color(r: 112, g: 0, b: 0, a: 255), + Color(r: 255, g: 0, b: 255, a: 255), + Color(r: 255, g: 0, b: 255, a: 255), + Color(r: 255, g: 0, b: 255, a: 255), + Color(r: 0, g: 0, b: 0, a: 0), +] diff --git a/validation-test/stdlib/FixedPointDiagnostics.swift.gyb b/validation-test/stdlib/FixedPointDiagnostics.swift.gyb index d025940e14c65..e091805af22b7 100644 --- a/validation-test/stdlib/FixedPointDiagnostics.swift.gyb +++ b/validation-test/stdlib/FixedPointDiagnostics.swift.gyb @@ -3,13 +3,13 @@ // RUN: %line-directive %t/main.swift -- %target-swift-frontend -typecheck -verify -swift-version 4.2 %t/main.swift func testUnaryMinusInUnsigned() { - var a: UInt8 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt8'}} expected-note * {{}} expected-warning * {{}} + var a: UInt8 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt8'}} expected-note * {{}} expected-warning * {{}} - var b: UInt16 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt16'}} expected-note * {{}} expected-warning * {{}} + var b: UInt16 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt16'}} expected-note * {{}} expected-warning * {{}} - var c: UInt32 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt32'}} expected-note * {{}} expected-warning * {{}} + var c: UInt32 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt32'}} expected-note * {{}} expected-warning * {{}} - var d: UInt64 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt64'}} expected-note * {{}} expected-warning * {{}} + var d: UInt64 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt64'}} expected-note * {{}} expected-warning * {{}} } // Int and UInt are not identical to any fixed-size integer type