From e0dd80fe3b9156bed07e792247d9a5beeccc2023 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 5 Aug 2022 19:02:37 -0700 Subject: [PATCH 01/22] Handle long tagged NSStrings --- stdlib/public/core/SmallString.swift | 19 ++++-- stdlib/public/core/StringBridge.swift | 24 ++++++-- .../NSSlowTaggedLocalizedString.h | 10 ++++ .../NSSlowTaggedLocalizedString.m | 60 +++++++++++++++++++ .../NSSlowTaggedLocalizedString/module.map | 3 + test/stdlib/NSSlowTaggedLocalizedString.swift | 32 ++++++++++ 6 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.h create mode 100644 test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m create mode 100644 test/stdlib/Inputs/NSSlowTaggedLocalizedString/module.map create mode 100644 test/stdlib/NSSlowTaggedLocalizedString.swift diff --git a/stdlib/public/core/SmallString.swift b/stdlib/public/core/SmallString.swift index dafaef8a93d2e..49680b5163aa6 100644 --- a/stdlib/public/core/SmallString.swift +++ b/stdlib/public/core/SmallString.swift @@ -353,13 +353,22 @@ extension _SmallString { // @_effects(readonly) // @opaque @usableFromInline // testable - internal init(taggedCocoa cocoa: AnyObject) { + internal init?(taggedCocoa cocoa: AnyObject) { self.init() + var success = true self.withMutableCapacity { - let len = _bridgeTagged(cocoa, intoUTF8: $0) - _internalInvariant(len != nil && len! <= _SmallString.capacity, - "Internal invariant violated: large tagged NSStrings") - return len._unsafelyUnwrappedUnchecked + /* + For regular NSTaggedPointerStrings we will always succeed here, but + tagged NSLocalizedStrings may not fit in a SmallString + */ + if let len = _bridgeTagged(cocoa, intoUTF8: $0) { + return len + } + success = false + return 0 + } + if !success { + return nil } self._invariantCheck() } diff --git a/stdlib/public/core/StringBridge.swift b/stdlib/public/core/StringBridge.swift index a62dbeec5365a..e8d24b5115f24 100644 --- a/stdlib/public/core/StringBridge.swift +++ b/stdlib/public/core/StringBridge.swift @@ -335,8 +335,9 @@ internal enum _KnownCocoaString { #if !(arch(i386) || arch(arm) || arch(arm64_32)) // Resiliently write a tagged _CocoaString's contents into a buffer. -// TODO: move this to the Foundation overlay and reimplement it with -// _NSTaggedPointerStringGetBytes +// The Foundation overlay takes care of bridging tagged pointer strings before +// they reach us, but this may still be called by older code, or by strings +// entering our domain via the arguments to -isEqual:, etc... @_effects(releasenone) // @opaque internal func _bridgeTagged( _ cocoa: _CocoaString, @@ -370,8 +371,11 @@ private func _withCocoaASCIIPointer( if requireStableAddress { return nil // tagged pointer strings don't support _fastCStringContents } - let tmp = _StringGuts(_SmallString(taggedCocoa: str)) - return tmp.withFastUTF8 { work($0.baseAddress._unsafelyUnwrappedUnchecked) } + if let smol = _SmallString(taggedCocoa: str) { + return _StringGuts(smol).withFastUTF8 { + work($0.baseAddress._unsafelyUnwrappedUnchecked) + } + } } #endif defer { _fixLifetime(str) } @@ -503,7 +507,11 @@ internal func _bridgeCocoaString(_ cocoaString: _CocoaString) -> _StringGuts { cocoaString, to: __SharedStringStorage.self).asString._guts #if !(arch(i386) || arch(arm) || arch(arm64_32)) case .tagged: - return _StringGuts(_SmallString(taggedCocoa: cocoaString)) + // Foundation should be taking care of tagged pointer strings before they + // reach here, so the only ones reaching this point should be back deployed, + // which will never have tagged pointer strings that aren't small, hence + // the force unwrap here. + return _StringGuts(_SmallString(taggedCocoa: cocoaString)!) #if arch(arm64) case .constantTagged: let taggedContents = getConstantTaggedCocoaContents(cocoaString)! @@ -530,7 +538,11 @@ internal func _bridgeCocoaString(_ cocoaString: _CocoaString) -> _StringGuts { #if !(arch(i386) || arch(arm) || arch(arm64_32)) if _isObjCTaggedPointer(immutableCopy) { - return _StringGuts(_SmallString(taggedCocoa: immutableCopy)) + // Copying a tagged pointer can produce a tagged pointer, but only if it's + // small enough to definitely fit in a _SmallString + return _StringGuts( + _SmallString(taggedCocoa: immutableCopy).unsafelyUnwrapped + ) } #endif diff --git a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.h b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.h new file mode 100644 index 0000000000000..e39908cb40465 --- /dev/null +++ b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.h @@ -0,0 +1,10 @@ +#import +#import + + +@interface NSSlowTaggedLocalizedString : NSObject + ++ (instancetype) createTestString; ++ (void) setContents: (const char *)newContents; + +@end diff --git a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m new file mode 100644 index 0000000000000..b0e7354591aa4 --- /dev/null +++ b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m @@ -0,0 +1,60 @@ +#import +#import "NSSlowTaggedLocalizedString.h" +#import + +@implementation NSSlowTaggedLocalizedString + +uintptr_t *obfuscator; +void (*_objc_registerTaggedPointerClass)(uint16_t tag, Class cls); + ++ (instancetype) createTestString { +#if __LP64__ + if (obfuscator == NULL) { + obfuscator = dlsym(RTLD_DEFAULT, "objc_debug_taggedpointer_obfuscator"); + *obfuscator = 0; + _objc_registerTaggedPointerClass = dlsym(RTLD_DEFAULT, "_objc_registerTaggedPointerClass"); + (*_objc_registerTaggedPointerClass)(0, self); //0 would be unsafe if we loaded Foundation, but we aren't doing that + } +#if __x86_64__ + return (id)(void *)(uintptr_t)1; //x86_64 uses the LSB as the tag bit, and we want tag 0 +#else + return (id)(void *)(uintptr_t)(1llu << 63); //MSB everywhere else +#endif +#else + return nil; +#endif +} + +static const char *contents = NULL; + ++ (void) setContents: (const char *)newContents { + const char *oldContents = contents; + contents = strdup(newContents); + free((void *)oldContents); +} + +- (const char *)_fastCStringContents:(BOOL)nullTerminationRequired { + return contents; +} + +- (uint64_t)length { + return strlen(contents); +} + +- (id)copyWithZone:(id)unused { + return self; +} + +- (uint16_t)characterAtIndex:(NSUInteger)index { + if (index >= [self length]) { + //throw the appropriate exception + abort(); + } + return (uint16_t)contents[index]; +} + +- (void *) _fastCharacterContents { + return nil; +} + +@end diff --git a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/module.map b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/module.map new file mode 100644 index 0000000000000..0761d14942800 --- /dev/null +++ b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/module.map @@ -0,0 +1,3 @@ +module NSSlowTaggedLocalizedString { + header "NSSlowTaggedLocalizedString.h" +} diff --git a/test/stdlib/NSSlowTaggedLocalizedString.swift b/test/stdlib/NSSlowTaggedLocalizedString.swift new file mode 100644 index 0000000000000..22fd875e4c464 --- /dev/null +++ b/test/stdlib/NSSlowTaggedLocalizedString.swift @@ -0,0 +1,32 @@ +// RUN: mkdir -p %t +// RUN: %target-clang -fobjc-arc %S/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m -fno-objc-arc -c -o %t/NSSlowTaggedLocalizedString.o +// RUN: %target-build-swift -Xfrontend -disable-access-control -I %S/Inputs/NSSlowTaggedLocalizedString/ %t/NSSlowTaggedLocalizedString.o %s -o %t/a.out +// RUN: %target-codesign %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: executable_test +// REQUIRES: objc_interop + +import NSSlowTaggedLocalizedString +import Swift + +import StdlibUnittest + +let longTaggedTests = TestSuite("NonContiguousTaggedStrings") + +longTaggedTests.test("EqualLongTagged") { + var native = "Send Message to different Team" + let longTagged = NSSlowTaggedLocalizedString.createTestString() + NSSlowTaggedLocalizedString.setContents(&native) + defer { + NSSlowTaggedLocalizedString.setContents(nil) + } + let reverseBridged = native._guts._object.objCBridgeableObject + expectEqual( + reverseBridged.isEqual(to: longTagged), + longTagged.isEqual(to: reverseBridged) + ) +} + +runAllTests() + From 93b6e1bf05cca6e94037f9002386001a61371e68 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Mon, 8 Aug 2022 10:18:06 -0700 Subject: [PATCH 02/22] [interop][SwiftToCxx] NFC, add test coverage for resilient mutating method --- .../structs/resilient-struct-in-cxx-execution.cpp | 5 +++++ .../SwiftToCxx/structs/resilient-struct-in-cxx.swift | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx-execution.cpp b/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx-execution.cpp index dee3b043680b6..8effef0d2795a 100644 --- a/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx-execution.cpp +++ b/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx-execution.cpp @@ -40,6 +40,11 @@ int main() { // CHECK: find - small dump // CURRENT-NEXT: x = 66 // CHANGE-NEXT: x&y = 0&65 + copySmallStruct.mutate(); + copySmallStruct.dump(); +// CHECK: find - small dump +// CURRENT-NEXT: x = 132 +// CHANGE-NEXT: x&y = 0&4294967230 printSmallAndLarge(smallStruct, largeStruct); // CHECK: find - small dump diff --git a/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift b/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift index fb9efe969ceef..74f3fbc5e028d 100644 --- a/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift +++ b/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift @@ -16,6 +16,13 @@ public struct FirstSmallStruct { print("x&y = \(x)&\(y)") #else print("x = \(x)") +#endif + } + + public mutating func mutate() { + x = x * 2 +#if CHANGE_LAYOUT + y = ~y #endif } } @@ -61,6 +68,9 @@ public struct FirstSmallStruct { // CHECK-NEXT: inline void FirstSmallStruct::dump() const { // CHECK-NEXT: return _impl::$s7Structs16FirstSmallStructV4dumpyyF(_getOpaquePointer()); // CHECK-NEXT: } +// CHECK-NEXT: inline void FirstSmallStruct::mutate() { +// CHECK-NEXT: return _impl::$s7Structs16FirstSmallStructV6mutateyyF(_getOpaquePointer()); +// CHECK-NEXT: } @frozen public struct FrozenStruct { private let storedInt: Int32 From 7ecf84a77193b465d2be5e9177f4f903b62f76b3 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Mon, 8 Aug 2022 12:00:06 -0700 Subject: [PATCH 03/22] [interop][SwiftToCxx] ensure that resilient class values are supported --- lib/PrintAsClang/PrintClangFunction.cpp | 3 ++- .../Interop/SwiftToCxx/class/swift-class-execution.cpp | 10 ++++++++++ test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift | 5 +++++ .../class/swift-class-inheritance-execution.cpp | 10 ++++++++++ .../class/swift-class-inheritance-in-cxx.swift | 5 +++++ 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index 78aa66c732e8f..52e8916aa3196 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -347,7 +347,8 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature( bool isIndirectReturnType = kind == FunctionSignatureKind::CFunctionProto && !isKnownCType(resultTy, typeMapping) && - (isResilientType(resultTy) || isGenericType(resultTy) || + ((isResilientType(resultTy) && !resultTy->isAnyClassReferenceType()) || + isGenericType(resultTy) || interopContext.getIrABIDetails().shouldReturnIndirectly(resultTy)); if (!isIndirectReturnType) { OptionalTypeKind retKind; diff --git a/test/Interop/SwiftToCxx/class/swift-class-execution.cpp b/test/Interop/SwiftToCxx/class/swift-class-execution.cpp index 70279a8ab6a12..f027688ab5644 100644 --- a/test/Interop/SwiftToCxx/class/swift-class-execution.cpp +++ b/test/Interop/SwiftToCxx/class/swift-class-execution.cpp @@ -8,6 +8,16 @@ // RUN: %target-codesign %t/swift-class-execution // RUN: %target-run %t/swift-class-execution | %FileCheck %s +// RUN: %empty-directory(%t-evo) + +// RUN: %target-swift-frontend %S/swift-class-in-cxx.swift -typecheck -module-name Class -clang-header-expose-public-decls -enable-library-evolution -emit-clang-header-path %t-evo/class.h + +// RUN: %target-interop-build-clangxx -c %s -I %t-evo -o %t-evo/swift-class-execution.o +// RUN: %target-interop-build-swift %S/swift-class-in-cxx.swift -o %t-evo/swift-class-execution-evo -Xlinker %t-evo/swift-class-execution.o -module-name Class -enable-library-evolution -Xfrontend -entry-point-function-name -Xfrontend swiftMain + +// RUN: %target-codesign %t-evo/swift-class-execution-evo +// RUN: %target-run %t-evo/swift-class-execution-evo | %FileCheck %s + // REQUIRES: executable_test #include diff --git a/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift b/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift index 20ab96a478a00..b3649bb24b64d 100644 --- a/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift +++ b/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift @@ -4,6 +4,11 @@ // RUN: %check-interop-cxx-header-in-clang(%t/class.h) +// RUN: %target-swift-frontend %s -typecheck -module-name Class -enable-library-evolution -clang-header-expose-public-decls -emit-clang-header-path %t/class-evo.h +// RUN: %FileCheck %s < %t/class-evo.h + +// RUN: %check-interop-cxx-header-in-clang(%t/class-evo.h) + public final class ClassWithIntField { var field: Int64 diff --git a/test/Interop/SwiftToCxx/class/swift-class-inheritance-execution.cpp b/test/Interop/SwiftToCxx/class/swift-class-inheritance-execution.cpp index 02f5f8b60df1c..040932a577f21 100644 --- a/test/Interop/SwiftToCxx/class/swift-class-inheritance-execution.cpp +++ b/test/Interop/SwiftToCxx/class/swift-class-inheritance-execution.cpp @@ -11,6 +11,16 @@ // RUN: not %target-interop-build-clangxx -c %s -I %t -o %t/swift-class-execution.o -DERROR1 // RUN: not %target-interop-build-clangxx -c %s -I %t -o %t/swift-class-execution.o -DERROR2 +// RUN: %empty-directory(%t-evo) + +// RUN: %target-swift-frontend %S/swift-class-inheritance-in-cxx.swift -typecheck -module-name Class -enable-library-evolution -clang-header-expose-public-decls -emit-clang-header-path %t-evo/class.h + +// RUN: %target-interop-build-clangxx -c %s -I %t-evo -o %t-evo/swift-class-execution.o +// RUN: %target-interop-build-swift %S/swift-class-inheritance-in-cxx.swift -o %t-evo/swift-class-execution-evo -Xlinker %t-evo/swift-class-execution.o -module-name Class -enable-library-evolution -Xfrontend -entry-point-function-name -Xfrontend swiftMain + +// RUN: %target-codesign %t-evo/swift-class-execution-evo +// RUN: %target-run %t-evo/swift-class-execution-evo | %FileCheck %s + // REQUIRES: executable_test #include diff --git a/test/Interop/SwiftToCxx/class/swift-class-inheritance-in-cxx.swift b/test/Interop/SwiftToCxx/class/swift-class-inheritance-in-cxx.swift index 749621cd4d664..1d207d2f49dc9 100644 --- a/test/Interop/SwiftToCxx/class/swift-class-inheritance-in-cxx.swift +++ b/test/Interop/SwiftToCxx/class/swift-class-inheritance-in-cxx.swift @@ -4,6 +4,11 @@ // RUN: %check-interop-cxx-header-in-clang(%t/class.h) +// RUN: %target-swift-frontend %s -typecheck -module-name Class -enable-library-evolution -clang-header-expose-public-decls -emit-clang-header-path %t/class-evo.h +// RUN: %FileCheck %s < %t/class-evo.h + +// RUN: %check-interop-cxx-header-in-clang(%t/class-evo.h) + public class BaseClass { var field: Int64 From 8f4658f98392ec4883a5e2a6c0f91f7933fa1164 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 8 Aug 2022 13:38:37 -0700 Subject: [PATCH 04/22] [CSClosure] Start using recorded targets for `ReturnStmt`s Multi-statement closures and result builder transformed entities record a target for `return` statement during constraint generation. Single-statement closure do not but they'd be handled in a special way. --- lib/Sema/CSClosure.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/Sema/CSClosure.cpp b/lib/Sema/CSClosure.cpp index 93a97578a6c6b..6808d4cc1b291 100644 --- a/lib/Sema/CSClosure.cpp +++ b/lib/Sema/CSClosure.cpp @@ -1584,6 +1584,8 @@ class SyntacticElementSolutionApplication } ASTNode visitReturnStmt(ReturnStmt *returnStmt) { + auto &cs = solution.getConstraintSystem(); + if (!returnStmt->hasResult()) { // If contextual is not optional, there is nothing to do here. if (resultType->isVoid()) @@ -1598,8 +1600,6 @@ class SyntacticElementSolutionApplication assert(resultType->getOptionalObjectType() && resultType->lookThroughAllOptionalTypes()->isVoid()); - auto &cs = solution.getConstraintSystem(); - auto target = *cs.getSolutionApplicationTarget(returnStmt); returnStmt->setResult(target.getAsExpr()); } @@ -1629,13 +1629,24 @@ class SyntacticElementSolutionApplication mode = convertToResult; } - SolutionApplicationTarget resultTarget( - resultExpr, context.getAsDeclContext(), - mode == convertToResult ? CTP_ReturnStmt : CTP_Unused, - mode == convertToResult ? resultType : Type(), - /*isDiscarded=*/false); - if (auto newResultTarget = rewriteTarget(resultTarget)) + Optional resultTarget; + if (auto target = cs.getSolutionApplicationTarget(returnStmt)) { + resultTarget = *target; + } else { + // Single-expression closures have to handle returns in a special + // way so the target has to be created for them during solution + // application based on the resolved type. + assert(isSingleExpression); + resultTarget = SolutionApplicationTarget( + resultExpr, context.getAsDeclContext(), + mode == convertToResult ? CTP_ReturnStmt : CTP_Unused, + mode == convertToResult ? resultType : Type(), + /*isDiscarded=*/false); + } + + if (auto newResultTarget = rewriteTarget(*resultTarget)) { resultExpr = newResultTarget->getAsExpr(); + } switch (mode) { case convertToResult: From 422dbe493a207046926920cf031fcbab9e1c945e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 8 Aug 2022 13:40:50 -0700 Subject: [PATCH 05/22] [ResultBuilder] AST transform: don't try type erasure of result expressions Constraint generation is going to erase when appropriate and rewrite the target, no need to do that explicitly during result builder transform. --- lib/Sema/BuilderTransform.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 571f519955cd6..17017ca816a9f 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -919,8 +919,6 @@ class ResultBuilderTransform using UnsupportedElt = SkipUnhandledConstructInResultBuilder::UnhandledNode; - /// The constraint system this transform is associated with. - ConstraintSystem &CS; /// The result type of this result builder body. Type ResultType; @@ -930,8 +928,7 @@ class ResultBuilderTransform public: ResultBuilderTransform(ConstraintSystem &cs, DeclContext *dc, Type builderType, Type resultTy) - : BuilderTransformerBase(&cs, dc, builderType), CS(cs), - ResultType(resultTy) {} + : BuilderTransformerBase(&cs, dc, builderType), ResultType(resultTy) {} UnsupportedElt getUnsupportedElement() const { return FirstUnsupported; } @@ -1180,10 +1177,6 @@ class ResultBuilderTransform {buildBlockResult}, {Identifier()}); } - // Type erase return if the result type requires it. - buildBlockResult = CS.buildTypeErasedExpr(buildBlockResult, dc, - ResultType, CTP_ReturnStmt); - elements.push_back(new (ctx) ReturnStmt(resultLoc, buildBlockResult, /*Implicit=*/true)); } From bf224c75a6ec818e99e7b3be37eb97590a12e574 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Mon, 8 Aug 2022 15:28:00 -0700 Subject: [PATCH 06/22] [interop][SwiftToCxx] pass structs to generic functions --- lib/PrintAsClang/PrintClangClassType.cpp | 43 +--------------- lib/PrintAsClang/PrintClangValueType.cpp | 51 +++++++++++++++++++ lib/PrintAsClang/PrintClangValueType.h | 4 ++ .../generics/generic-function-execution.cpp | 36 +++++++++++++ .../generics/generic-function-in-cxx.swift | 31 ++++++++++- .../structs/swift-struct-in-cxx.swift | 17 +++++++ 6 files changed, 140 insertions(+), 42 deletions(-) diff --git a/lib/PrintAsClang/PrintClangClassType.cpp b/lib/PrintAsClang/PrintClangClassType.cpp index 081365d9e16cf..3dd242e4f0848 100644 --- a/lib/PrintAsClang/PrintClangClassType.cpp +++ b/lib/PrintAsClang/PrintClangClassType.cpp @@ -94,47 +94,8 @@ void ClangClassTypePrinter::printClassTypeDecl( os << "};\n"; }); - // FIXME: avoid popping out of the module's namespace here. - os << "} // end namespace \n\n"; - os << "namespace swift {\n"; - - os << "#pragma clang diagnostic push\n"; - os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n"; - os << "template<>\n"; - os << "static inline const constexpr bool isUsableInGenericContext<"; - printer.printBaseName(typeDecl->getModuleContext()); - os << "::"; - printer.printBaseName(typeDecl); - os << "> = true;\n"; - os << "#pragma clang diagnostic pop\n"; - - os << "template<>\n"; - os << "inline void * _Nonnull getTypeMetadata<"; - printer.printBaseName(typeDecl->getModuleContext()); - os << "::"; - printer.printBaseName(typeDecl); - os << ">() {\n"; - os << " return "; - printer.printBaseName(typeDecl->getModuleContext()); - os << "::" << cxx_synthesis::getCxxImplNamespaceName() - << "::" << typeMetadataFuncName << "(0)._0;\n"; - os << "}\n"; - os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n"; - os << "template<>\n"; - os << "struct implClassFor<"; - printer.printBaseName(typeDecl->getModuleContext()); - os << "::"; - printer.printBaseName(typeDecl); - os << "> { using type = "; - printer.printBaseName(typeDecl->getModuleContext()); - os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::"; - printCxxImplClassName(os, typeDecl); - os << "; };\n"; - os << "} // namespace\n"; - os << "} // namespace swift\n"; - os << "\nnamespace "; - printer.printBaseName(typeDecl->getModuleContext()); - os << " {\n"; + ClangValueTypePrinter::printTypeGenericTraits(os, typeDecl, + typeMetadataFuncName); } void ClangClassTypePrinter::printClassTypeReturnScaffold( diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index 9fe2d0463afca..8969ad5766ab9 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -281,6 +281,8 @@ void ClangValueTypePrinter::printValueTypeDecl( if (!isOpaqueLayout) printCValueTypeStorageStruct(cPrologueOS, typeDecl, *typeSizeAlign); + + printTypeGenericTraits(os, typeDecl, typeMetadataFuncName); } /// Print the name of the C stub struct for passing/returning a value type @@ -456,3 +458,52 @@ void ClangValueTypePrinter::printValueTypeDirectReturnScaffold( os << ");\n"; os << " });\n"; } + +void ClangValueTypePrinter::printTypeGenericTraits( + raw_ostream &os, const NominalTypeDecl *typeDecl, + StringRef typeMetadataFuncName) { + ClangSyntaxPrinter printer(os); + // FIXME: avoid popping out of the module's namespace here. + os << "} // end namespace \n\n"; + os << "namespace swift {\n"; + + os << "#pragma clang diagnostic push\n"; + os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n"; + os << "template<>\n"; + os << "static inline const constexpr bool isUsableInGenericContext<"; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::"; + printer.printBaseName(typeDecl); + os << "> = true;\n"; + os << "#pragma clang diagnostic pop\n"; + + os << "template<>\n"; + os << "inline void * _Nonnull getTypeMetadata<"; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::"; + printer.printBaseName(typeDecl); + os << ">() {\n"; + os << " return "; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::" << cxx_synthesis::getCxxImplNamespaceName() + << "::" << typeMetadataFuncName << "(0)._0;\n"; + os << "}\n"; + if (isa(typeDecl)) { + os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n"; + os << "template<>\n"; + os << "struct implClassFor<"; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::"; + printer.printBaseName(typeDecl); + os << "> { using type = "; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::"; + printCxxImplClassName(os, typeDecl); + os << "; };\n"; + os << "} // namespace\n"; + } + os << "} // namespace swift\n"; + os << "\nnamespace "; + printer.printBaseName(typeDecl->getModuleContext()); + os << " {\n"; +} diff --git a/lib/PrintAsClang/PrintClangValueType.h b/lib/PrintAsClang/PrintClangValueType.h index 3be80722ea47f..a457506f28784 100644 --- a/lib/PrintAsClang/PrintClangValueType.h +++ b/lib/PrintAsClang/PrintClangValueType.h @@ -94,6 +94,10 @@ class ClangValueTypePrinter { StringRef metadataVarName = "metadata", StringRef vwTableVarName = "vwTable"); + static void printTypeGenericTraits(raw_ostream &os, + const NominalTypeDecl *typeDecl, + StringRef typeMetadataFuncName); + private: /// Prints out the C stub name used to pass/return value directly for the /// given value type. diff --git a/test/Interop/SwiftToCxx/generics/generic-function-execution.cpp b/test/Interop/SwiftToCxx/generics/generic-function-execution.cpp index 330396aa84e95..ed39581b3bcfb 100644 --- a/test/Interop/SwiftToCxx/generics/generic-function-execution.cpp +++ b/test/Interop/SwiftToCxx/generics/generic-function-execution.cpp @@ -156,5 +156,41 @@ int main() { } // CHECK-NEXT: deinit TestClass // CHECK-NEXT: deinit TestClass + + { + auto x = createTestLargeStruct(0); + genericPrintFunction(x); + } +// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 0, x2: 1, x3: -1, x4: 0, x5: 2, x6: -2) + + { + auto x = createTestLargeStruct(11); + auto y = createTestLargeStruct(-9); + genericPrintFunction(x); + genericPrintFunction(y); + genericSwap(x, y); + genericPrintFunction(x); + genericPrintFunction(y); + } +// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9) +// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11) +// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11) + // CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9) + + { + auto x = createTestSmallStruct(45); + auto y = createTestSmallStruct(0xFed1); + genericPrintFunction(x); + genericPrintFunction(y); + genericSwap(y, x); + genericPrintFunction(x); + genericPrintFunction(y); + } +// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 45) +// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233) +// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233) +// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 45) + +// FIXME: return struct. return 0; } diff --git a/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift b/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift index 0d5e2451af4cb..d7399e233e119 100644 --- a/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift +++ b/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift @@ -2,7 +2,7 @@ // RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h // RUN: %FileCheck %s < %t/functions.h -// RUN: %check-generic-interop-cxx-header-in-clang(%t/functions.h) +// RUN: %check-generic-interop-cxx-header-in-clang(%t/functions.h -Wno-unused-function) public func genericPrintFunctionTwoArg(_ x: T, _ y: Int) { @@ -40,12 +40,41 @@ public class TestClass { public func createTestClass() -> TestClass { return TestClass() } +public struct TestLargeStruct { + var x1, x2, x3, x4, x5, x6: Int + + init(_ x: Int) { + x1 = x + x2 = x+1 + x3 = x-1 + x4 = x + x5 = x+2 + x6 = x-2 + } +} + +public func createTestLargeStruct(_ x: Int) -> TestLargeStruct { + return TestLargeStruct(x) +} + +public struct TestSmallStruct { + var x1: UInt32 +} + +public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct { + return TestSmallStruct(x1: x) +} + // CHECK: SWIFT_EXTERN void $s9Functions20genericPrintFunctionyyxlF(const void * _Nonnull x, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunction(_:) // CHECK-NEXT: SWIFT_EXTERN void $s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(ptrdiff_t x, const void * _Nonnull t1, const void * _Nonnull t1p, ptrdiff_t y, const void * _Nonnull t2, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionMultiGeneric(_:_:_:_:_:) // CHECK-NEXT: SWIFT_EXTERN void $s9Functions26genericPrintFunctionTwoArgyyx_SitlF(const void * _Nonnull x, ptrdiff_t y, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionTwoArg(_:_:) // CHECK-NEXT: SWIFT_EXTERN void $s9Functions10genericRetyxxlF(SWIFT_INDIRECT_RESULT void * _Nonnull, const void * _Nonnull x, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericRet(_:) // CHECK-NEXT: SWIFT_EXTERN void $s9Functions11genericSwapyyxz_xztlF(void * _Nonnull x, void * _Nonnull y, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericSwap(_:_:) +// Skip templates in impl classes. +// CHECK: _impl_TestSmallStruct +// CHECK: template + // CHECK: template // CHECK-NEXT: requires swift::isUsableInGenericContext // CHECK-NEXT: inline void genericPrintFunction(const T & x) noexcept { diff --git a/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift b/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift index 12aa53cf8be27..92a414e628c06 100644 --- a/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift +++ b/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift @@ -61,6 +61,23 @@ // CHECK-NEXT: }; // CHECK-EMPTY: // CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: } // end namespace +// CHECK-EMPTY: +// CHECK-NEXT: namespace swift { +// CHECK-NEXT: #pragma clang diagnostic push +// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" +// CHECK-NEXT: template<> +// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext = true; +// CHECK-NEXT: #pragma clang diagnostic pop +// CHECK-NEXT: template<> +// CHECK-NEXT: inline void * _Nonnull getTypeMetadata() { +// CHECK-NEXT: return Structs::_impl::$s7Structs18StructWithIntFieldVMa(0)._0; +// CHECK-NEXT: } +// CHECK-NEXT: } // namespace swift +// CHECK-EMPTY: +// CHECK-NEXT: namespace Structs { + public struct StructWithIntField { let field: Int64 } From b3d887583445a6b13e60e13e1ee11a3830023a35 Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 8 Aug 2022 16:23:54 -0700 Subject: [PATCH 07/22] Iterate on the long tagged string test --- .../NSSlowTaggedLocalizedString.m | 84 +++++++++++++++---- test/stdlib/NSSlowTaggedLocalizedString.swift | 28 ++++--- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m index b0e7354591aa4..a961692fe97ea 100644 --- a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m +++ b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m @@ -1,25 +1,53 @@ #import #import "NSSlowTaggedLocalizedString.h" #import +#import + +//If and when CF starts linking Swift we may need to rethink this +#import @implementation NSSlowTaggedLocalizedString -uintptr_t *obfuscator; -void (*_objc_registerTaggedPointerClass)(uint16_t tag, Class cls); +typedef struct _NSRange { + uint64_t location; + uint64_t length; +} NSRange; + (instancetype) createTestString { #if __LP64__ - if (obfuscator == NULL) { - obfuscator = dlsym(RTLD_DEFAULT, "objc_debug_taggedpointer_obfuscator"); - *obfuscator = 0; - _objc_registerTaggedPointerClass = dlsym(RTLD_DEFAULT, "_objc_registerTaggedPointerClass"); - (*_objc_registerTaggedPointerClass)(0, self); //0 would be unsafe if we loaded Foundation, but we aren't doing that - } -#if __x86_64__ - return (id)(void *)(uintptr_t)1; //x86_64 uses the LSB as the tag bit, and we want tag 0 -#else - return (id)(void *)(uintptr_t)(1llu << 63); //MSB everywhere else -#endif + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class tagClass = objc_lookUpClass("NSTaggedPointerString"); + Class ourClass = [NSSlowTaggedLocalizedString class]; + + Method fastCString = class_getInstanceMethod(ourClass, @selector(_fastCStringContents:)); + class_replaceMethod(tagClass, @selector(_fastCStringContents:), method_getImplementation(fastCString), method_getTypeEncoding(fastCString)); + + Method length = class_getInstanceMethod(ourClass, @selector(length)); + class_replaceMethod(tagClass, @selector(length), method_getImplementation(length), method_getTypeEncoding(length)); + + Method charIndex = class_getInstanceMethod(ourClass, @selector(characterAtIndex:)); + class_replaceMethod(tagClass, @selector(characterAtIndex:), method_getImplementation(charIndex), method_getTypeEncoding(charIndex)); + + Method fastChars = class_getInstanceMethod(ourClass, @selector(_fastCharacterContents)); + class_replaceMethod(tagClass, @selector(_fastCharacterContents), method_getImplementation(fastChars), method_getTypeEncoding(fastChars)); + + Method retain = class_getInstanceMethod(ourClass, @selector(retain)); + class_replaceMethod(tagClass, @selector(retain), method_getImplementation(retain), method_getTypeEncoding(retain)); + + Method release = class_getInstanceMethod(ourClass, @selector(release)); + class_replaceMethod(tagClass, @selector(release), method_getImplementation(release), method_getTypeEncoding(release)); + + Method typeID = class_getInstanceMethod(ourClass, @selector(_cfTypeID)); + class_replaceMethod(tagClass, @selector(_cfTypeID), method_getImplementation(typeID), method_getTypeEncoding(typeID)); + + Method description = class_getInstanceMethod(ourClass, @selector(description)); + class_replaceMethod(tagClass, @selector(description), method_getImplementation(description), method_getTypeEncoding(description)); + + Method getBytes = class_getInstanceMethod(ourClass, @selector(getBytes:maxLength:usedLength:encoding:options:range:remainingRange:)); + class_replaceMethod(tagClass, @selector(getBytes:maxLength:usedLength:encoding:options:range:remainingRange:), method_getImplementation(getBytes), method_getTypeEncoding(getBytes)); + }); + return (NSSlowTaggedLocalizedString *)(void *)CFStringCreateWithCString(NULL, "a", kCFStringEncodingASCII); //make a tagged pointer string #else return nil; #endif @@ -29,7 +57,11 @@ + (instancetype) createTestString { + (void) setContents: (const char *)newContents { const char *oldContents = contents; - contents = strdup(newContents); + if (newContents) { + contents = strdup(newContents); + } else { + contents = NULL; + } free((void *)oldContents); } @@ -46,6 +78,7 @@ - (id)copyWithZone:(id)unused { } - (uint16_t)characterAtIndex:(NSUInteger)index { + abort(); if (index >= [self length]) { //throw the appropriate exception abort(); @@ -57,4 +90,27 @@ - (void *) _fastCharacterContents { return nil; } +- (id) retain { return self; } +- (oneway void) release {} + +- (uint64_t)_cfTypeID { + return 7; //CFString +} + +- (id) description { + return self; +} + +- (BOOL)getBytes:(void *)buffer maxLength:(uint64_t)max usedLength:(uint64_t *)used encoding:(uint64_t)encoding options:(uint64_t)options range:(NSRange)range remainingRange:(NSRange *)leftover { + strncpy(buffer, contents, max); + if (strlen(contents) > max) { + leftover->location = max; + leftover->length = strlen(contents) - max; + return false; + } + leftover->location = 0; + leftover->length = 0; + return true; +} + @end diff --git a/test/stdlib/NSSlowTaggedLocalizedString.swift b/test/stdlib/NSSlowTaggedLocalizedString.swift index 22fd875e4c464..5f385745e702f 100644 --- a/test/stdlib/NSSlowTaggedLocalizedString.swift +++ b/test/stdlib/NSSlowTaggedLocalizedString.swift @@ -1,6 +1,6 @@ // RUN: mkdir -p %t -// RUN: %target-clang -fobjc-arc %S/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m -fno-objc-arc -c -o %t/NSSlowTaggedLocalizedString.o -// RUN: %target-build-swift -Xfrontend -disable-access-control -I %S/Inputs/NSSlowTaggedLocalizedString/ %t/NSSlowTaggedLocalizedString.o %s -o %t/a.out +// RUN: %target-clang %S/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m -fno-objc-arc -c -o %t/NSSlowTaggedLocalizedString.o +// RUN: %target-build-swift -g -parse-stdlib -Xfrontend -disable-access-control -I %S/Inputs/NSSlowTaggedLocalizedString/ %t/NSSlowTaggedLocalizedString.o %s -o %t/a.out // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out @@ -13,19 +13,25 @@ import Swift import StdlibUnittest let longTaggedTests = TestSuite("NonContiguousTaggedStrings") +var constant = "Send Message to different Team" -longTaggedTests.test("EqualLongTagged") { - var native = "Send Message to different Team" - let longTagged = NSSlowTaggedLocalizedString.createTestString() - NSSlowTaggedLocalizedString.setContents(&native) +func runEqualLongTagged() { + let native = constant.withUTF8 { String(decoding: $0, as: UTF8.self) } + let longTagged = NSSlowTaggedLocalizedString.createTest()! + constant.withCString { + NSSlowTaggedLocalizedString.setContents($0) + } defer { NSSlowTaggedLocalizedString.setContents(nil) } - let reverseBridged = native._guts._object.objCBridgeableObject - expectEqual( - reverseBridged.isEqual(to: longTagged), - longTagged.isEqual(to: reverseBridged) - ) + let reverseBridged = unsafeBitCast(native._guts._object.largeAddressBits, to: AnyObject.self) + let eq = reverseBridged.isEqual(to: longTagged) + expectEqual(eq, 1) + _fixLifetime(native) +} + +longTaggedTests.test("EqualLongTagged") { + runEqualLongTagged() } runAllTests() From f966017c9cafb202f90733a822acdf44082a42d6 Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 8 Aug 2022 17:27:23 -0700 Subject: [PATCH 08/22] Review feedback --- test/api-digester/stability-stdlib-abi-without-asserts.test | 2 ++ .../NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/api-digester/stability-stdlib-abi-without-asserts.test b/test/api-digester/stability-stdlib-abi-without-asserts.test index f36f60149490a..d4872d1ea1e30 100644 --- a/test/api-digester/stability-stdlib-abi-without-asserts.test +++ b/test/api-digester/stability-stdlib-abi-without-asserts.test @@ -65,6 +65,8 @@ Protocol CodingKey has added inherited protocol Sendable Protocol CodingKey has generic signature change from to Protocol Error has added inherited protocol Sendable Protocol Error has generic signature change from to +Constructor _SmallString.init(taggedCocoa:) has mangled name changing from 'Swift._SmallString.init(taggedCocoa: Swift.AnyObject) -> Swift._SmallString' to 'Swift._SmallString.init(taggedCocoa: Swift.AnyObject) -> Swift.Optional' +Constructor _SmallString.init(taggedCocoa:) has return type change from Swift._SmallString to Swift._SmallString? Enum Never has added a conformance to an existing protocol Identifiable // These haven't actually been removed; they are simply marked unavailable. diff --git a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m index a961692fe97ea..63ea5a7bec7c0 100644 --- a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m +++ b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m @@ -78,9 +78,7 @@ - (id)copyWithZone:(id)unused { } - (uint16_t)characterAtIndex:(NSUInteger)index { - abort(); if (index >= [self length]) { - //throw the appropriate exception abort(); } return (uint16_t)contents[index]; @@ -102,6 +100,7 @@ - (id) description { } - (BOOL)getBytes:(void *)buffer maxLength:(uint64_t)max usedLength:(uint64_t *)used encoding:(uint64_t)encoding options:(uint64_t)options range:(NSRange)range remainingRange:(NSRange *)leftover { + assert(encoding == kCFStringEncodingASCII || encoding == kCFStringEncodingUTF8); strncpy(buffer, contents, max); if (strlen(contents) > max) { leftover->location = max; From 330fc0b07a3cd32f994bb26f033407fcddd42d80 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 9 Aug 2022 05:20:58 -0700 Subject: [PATCH 09/22] [interop][SwiftToCxx] generic functions should return value types correctly --- lib/PrintAsClang/PrintClangFunction.cpp | 10 +++++++- lib/PrintAsClang/PrintClangValueType.cpp | 24 ++++++++++++------- .../SwiftShims/_SwiftCxxInteroperability.h | 7 ++++-- .../SwiftToCxx/class/swift-class-in-cxx.swift | 2 +- .../generics/generic-function-execution.cpp | 20 +++++++++++++--- .../generics/generic-function-in-cxx.swift | 13 ++++++++++ .../structs/swift-struct-in-cxx.swift | 8 ++++++- 7 files changed, 68 insertions(+), 16 deletions(-) diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index 52e8916aa3196..8578fd5a87682 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -576,10 +576,10 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody( if (!isKnownCxxType(resultTy, typeMapping) && !hasKnownOptionalNullableCxxMapping(resultTy)) { if (isGenericType(resultTy)) { - // FIXME: Support returning value types. std::string returnAddress; llvm::raw_string_ostream ros(returnAddress); ros << "reinterpret_cast(&returnValue)"; + StringRef resultTyName = "T"; // FIXME os << " if constexpr (std::is_base_of<::swift::" << cxx_synthesis::getCxxImplNamespaceName() @@ -589,6 +589,14 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody( os << ";\n"; os << " return ::swift::" << cxx_synthesis::getCxxImplNamespaceName() << "::implClassFor::type::makeRetained(returnValue);\n"; + os << " } else if constexpr (::swift::" + << cxx_synthesis::getCxxImplNamespaceName() << "::isValueType<" + << resultTyName << ">) {\n"; + os << " return ::swift::" << cxx_synthesis::getCxxImplNamespaceName() + << "::implClassFor<" << resultTyName + << ">::type::returnNewValue([&](void * _Nonnull returnValue) {\n"; + printCallToCFunc(/*additionalParam=*/StringRef("returnValue")); + os << ";\n });\n"; os << " } else {\n"; os << " T returnValue;\n"; printCallToCFunc(/*additionalParam=*/StringRef(ros.str())); diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index 8969ad5766ab9..03a810347b106 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -475,8 +475,6 @@ void ClangValueTypePrinter::printTypeGenericTraits( os << "::"; printer.printBaseName(typeDecl); os << "> = true;\n"; - os << "#pragma clang diagnostic pop\n"; - os << "template<>\n"; os << "inline void * _Nonnull getTypeMetadata<"; printer.printBaseName(typeDecl->getModuleContext()); @@ -488,8 +486,18 @@ void ClangValueTypePrinter::printTypeGenericTraits( os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::" << typeMetadataFuncName << "(0)._0;\n"; os << "}\n"; - if (isa(typeDecl)) { + os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n"; + + if (!isa(typeDecl)) { + os << "template<>\n"; + os << "static inline const constexpr bool isValueType<"; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::"; + printer.printBaseName(typeDecl); + os << "> = true;\n"; + } + os << "template<>\n"; os << "struct implClassFor<"; printer.printBaseName(typeDecl->getModuleContext()); @@ -501,9 +509,9 @@ void ClangValueTypePrinter::printTypeGenericTraits( printCxxImplClassName(os, typeDecl); os << "; };\n"; os << "} // namespace\n"; - } - os << "} // namespace swift\n"; - os << "\nnamespace "; - printer.printBaseName(typeDecl->getModuleContext()); - os << " {\n"; + os << "#pragma clang diagnostic pop\n"; + os << "} // namespace swift\n"; + os << "\nnamespace "; + printer.printBaseName(typeDecl->getModuleContext()); + os << " {\n"; } diff --git a/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h b/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h index e731df27c369a..41ca4e4381471 100644 --- a/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h +++ b/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h @@ -104,8 +104,6 @@ using UInt = size_t; template static inline const constexpr bool isUsableInGenericContext = false; -#pragma clang diagnostic pop - /// Returns the type metadat for the given Swift type T. template inline void *_Nonnull getTypeMetadata(); @@ -117,8 +115,13 @@ template struct implClassFor { // using type = ...; }; +/// True if the given type is a Swift value type. +template static inline const constexpr bool isValueType = false; + } // namespace _impl +#pragma clang diagnostic pop + } // namespace swift #endif diff --git a/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift b/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift index b3649bb24b64d..a0295fa25df9b 100644 --- a/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift +++ b/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift @@ -65,7 +65,6 @@ public final class ClassWithIntField { // CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" // CHECK-NEXT: template<> // CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext = true; -// CHECK-NEXT: #pragma clang diagnostic pop // CHECK-NEXT: template<> // CHECK-NEXT: inline void * _Nonnull getTypeMetadata() { // CHECK-NEXT: return Class::_impl::$s5Class0A12WithIntFieldCMa(0)._0; @@ -74,6 +73,7 @@ public final class ClassWithIntField { // CHECK-NEXT: template<> // CHECK-NEXT: struct implClassFor { using type = Class::_impl::_impl_ClassWithIntField; }; // CHECK-NEXT: } // namespace +// CHECK-NEXT: #pragma clang diagnostic pop // CHECK-NEXT: } // namespace swift // CHECK-EMPTY: // CHECK-NEXT: namespace Class { diff --git a/test/Interop/SwiftToCxx/generics/generic-function-execution.cpp b/test/Interop/SwiftToCxx/generics/generic-function-execution.cpp index ed39581b3bcfb..716b9957357de 100644 --- a/test/Interop/SwiftToCxx/generics/generic-function-execution.cpp +++ b/test/Interop/SwiftToCxx/generics/generic-function-execution.cpp @@ -171,11 +171,19 @@ int main() { genericSwap(x, y); genericPrintFunction(x); genericPrintFunction(y); + auto xy = genericRet(x); + genericPrintFunction(xy); + xy.mut(); + genericPrintFunction(xy); + genericPrintFunction(x); } // CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9) // CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11) // CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11) - // CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9) +// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9) +// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11) +// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -7) +// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11) { auto x = createTestSmallStruct(45); @@ -185,12 +193,18 @@ int main() { genericSwap(y, x); genericPrintFunction(x); genericPrintFunction(y); + auto xy = genericRet(x); + genericPrintFunction(xy); + xy.mut(); + genericPrintFunction(xy); + genericPrintFunction(x); } // CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 45) // CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233) // CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233) // CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 45) - -// FIXME: return struct. +// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233) +// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 4294902062) +// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233) return 0; } diff --git a/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift b/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift index d7399e233e119..04a27920abddf 100644 --- a/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift +++ b/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift @@ -51,6 +51,11 @@ public struct TestLargeStruct { x5 = x+2 x6 = x-2 } + + public mutating func mut() { + x1 = -x1 + x6 = x5 + } } public func createTestLargeStruct(_ x: Int) -> TestLargeStruct { @@ -59,6 +64,10 @@ public func createTestLargeStruct(_ x: Int) -> TestLargeStruct { public struct TestSmallStruct { var x1: UInt32 + + public mutating func mut() { + x1 = ~x1 + } } public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct { @@ -102,6 +111,10 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct { // CHECK-NEXT: void *returnValue; // CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast(&returnValue), reinterpret_cast(&x), swift::getTypeMetadata()); // CHECK-NEXT: return ::swift::_impl::implClassFor::type::makeRetained(returnValue); +// CHECK-NEXT: } else if constexpr (::swift::_impl::isValueType) { +// CHECK-NEXT: return ::swift::_impl::implClassFor::type::returnNewValue([&](void * _Nonnull returnValue) { +// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, reinterpret_cast(&x), swift::getTypeMetadata()); +// CHECK-NEXT: }); // CHECK-NEXT: } else { // CHECK-NEXT: T returnValue; // CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast(&returnValue), reinterpret_cast(&x), swift::getTypeMetadata()); diff --git a/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift b/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift index 92a414e628c06..968ff81239d7d 100644 --- a/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift +++ b/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift @@ -69,11 +69,17 @@ // CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" // CHECK-NEXT: template<> // CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext = true; -// CHECK-NEXT: #pragma clang diagnostic pop // CHECK-NEXT: template<> // CHECK-NEXT: inline void * _Nonnull getTypeMetadata() { // CHECK-NEXT: return Structs::_impl::$s7Structs18StructWithIntFieldVMa(0)._0; // CHECK-NEXT: } +// CHECK-NEXT: namespace _impl{ +// CHECK-NEXT: template<> +// CHECK-NEXT: static inline const constexpr bool isValueType = true; +// CHECK-NEXT: template<> +// CHECK-NEXT: struct implClassFor { using type = Structs::_impl::_impl_StructWithIntField; }; +// CHECK-NEXT: } // namespace +// CHECK-NEXT: #pragma clang diagnostic pop // CHECK-NEXT: } // namespace swift // CHECK-EMPTY: // CHECK-NEXT: namespace Structs { From 7a4bcffb2fda3d8bd25d722d2a3cf2e7a9cefbb3 Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Tue, 9 Aug 2022 07:15:59 -0700 Subject: [PATCH 10/22] Revert "Merge pull request #60453 from etcwilde/ewilde/add-missing-bootstrap-compat-dependencies" This reverts commit 2ea1c81f3487bb39aff202b165806c3eff55fc26, reversing changes made to 329d5846bccf8b7d94a9eca2568ced3d354ce7cc. --- SwiftCompilerSources/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/SwiftCompilerSources/CMakeLists.txt b/SwiftCompilerSources/CMakeLists.txt index 7a32e273c5df5..cc24ca661126e 100644 --- a/SwiftCompilerSources/CMakeLists.txt +++ b/SwiftCompilerSources/CMakeLists.txt @@ -295,8 +295,6 @@ else() set(compatibility_libs "swiftCompatibility50-${platform}" "swiftCompatibility51-${platform}" - "swiftCompatibility56-${platform}" - "swiftCompatibilityConcurrency-${platform}" "swiftCompatibilityDynamicReplacements-${platform}") list(APPEND b0_deps ${compatibility_libs}) From 15b365948467c95bf6f4f9c616198067178e1b26 Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Tue, 9 Aug 2022 07:16:02 -0700 Subject: [PATCH 11/22] Revert "Merge pull request #60368 from etcwilde/ewilde/backdeploy56" This reverts commit a3941bf215e6f9592ecae0649f99a660b3a3f45e, reversing changes made to b39302a585829683cb43ffa55cfaf700eba6e0e1. --- include/swift/Frontend/BackDeploymentLibs.def | 1 - lib/Driver/DarwinToolChains.cpp | 2 - lib/Frontend/CompilerInvocation.cpp | 2 - stdlib/CMakeLists.txt | 2 - stdlib/toolchain/CMakeLists.txt | 1 - .../toolchain/Compatibility56/CMakeLists.txt | 39 - .../Compatibility56/CompatibilityOverride.h | 137 --- .../CompatibilityOverrideConcurrency.def | 356 ------ .../CompatibilityOverrideRuntime.def | 227 ---- .../Compatibility56/Concurrency/Actor.cpp | 48 - .../Compatibility56/Concurrency/AsyncLet.cpp | 0 .../Compatibility56/Concurrency/Error.cpp | 19 - .../Compatibility56/Concurrency/Task.cpp | 33 - .../toolchain/Compatibility56/Overrides.cpp | 55 - stdlib/toolchain/Compatibility56/Overrides.h | 61 - .../include/Concurrency/Actor.h | 45 - .../include/Concurrency/AsyncLet.h | 65 -- .../include/Concurrency/Error.h | 30 - .../include/Concurrency/Executor.h | 221 ---- .../include/Concurrency/Task.h | 776 ------------- .../include/Concurrency/TaskPrivate.h | 71 -- .../include/Concurrency/TaskStatus.h | 166 --- .../include/Concurrency/VoucherShims.h | 103 -- .../include/Runtime/Concurrency.h | 82 -- .../include/Runtime/Threading/Mutex.h | 1011 ----------------- .../include/Runtime/Threading/MutexPThread.h | 157 --- .../Runtime/Threading/MutexSingleThreaded.h | 74 -- .../include/Runtime/Threading/MutexWin32.h | 101 -- .../include/Runtime/Threading/Once.h | 54 - .../include/Runtime/Threading/ThreadLocal.h | 176 --- .../Runtime/Threading/ThreadLocalStorage.h | 128 --- .../Concurrency/Backdeploy/weak_linking.swift | 25 +- 32 files changed, 7 insertions(+), 4261 deletions(-) delete mode 100644 stdlib/toolchain/Compatibility56/CMakeLists.txt delete mode 100644 stdlib/toolchain/Compatibility56/CompatibilityOverride.h delete mode 100644 stdlib/toolchain/Compatibility56/CompatibilityOverrideConcurrency.def delete mode 100644 stdlib/toolchain/Compatibility56/CompatibilityOverrideRuntime.def delete mode 100644 stdlib/toolchain/Compatibility56/Concurrency/Actor.cpp delete mode 100644 stdlib/toolchain/Compatibility56/Concurrency/AsyncLet.cpp delete mode 100644 stdlib/toolchain/Compatibility56/Concurrency/Error.cpp delete mode 100644 stdlib/toolchain/Compatibility56/Concurrency/Task.cpp delete mode 100644 stdlib/toolchain/Compatibility56/Overrides.cpp delete mode 100644 stdlib/toolchain/Compatibility56/Overrides.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Concurrency/Actor.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Concurrency/AsyncLet.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Concurrency/Error.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Concurrency/Executor.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Concurrency/Task.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Concurrency/TaskPrivate.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Concurrency/TaskStatus.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Concurrency/VoucherShims.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Runtime/Concurrency.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Runtime/Threading/Mutex.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexPThread.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexSingleThreaded.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexWin32.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Runtime/Threading/Once.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Runtime/Threading/ThreadLocal.h delete mode 100644 stdlib/toolchain/Compatibility56/include/Runtime/Threading/ThreadLocalStorage.h diff --git a/include/swift/Frontend/BackDeploymentLibs.def b/include/swift/Frontend/BackDeploymentLibs.def index 9f12ae773e7dc..58eefb62bf493 100644 --- a/include/swift/Frontend/BackDeploymentLibs.def +++ b/include/swift/Frontend/BackDeploymentLibs.def @@ -28,6 +28,5 @@ BACK_DEPLOYMENT_LIB((5, 0), all, "swiftCompatibility50") BACK_DEPLOYMENT_LIB((5, 1), all, "swiftCompatibility51") BACK_DEPLOYMENT_LIB((5, 0), executable, "swiftCompatibilityDynamicReplacements") BACK_DEPLOYMENT_LIB((5, 4), all, "swiftCompatibilityConcurrency") -BACK_DEPLOYMENT_LIB((5, 6), all, "swiftCompatibility56") #undef BACK_DEPLOYMENT_LIB diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 704d892816f47..8b5933d8f9650 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -411,8 +411,6 @@ toolchains::Darwin::addArgsToLinkStdlib(ArgStringList &Arguments, runtimeCompatibilityVersion = llvm::VersionTuple(5, 1); } else if (value.equals("5.5")) { runtimeCompatibilityVersion = llvm::VersionTuple(5, 5); - } else if (value.equals("5.6")) { - runtimeCompatibilityVersion = llvm::VersionTuple(5, 6); } else if (value.equals("none")) { runtimeCompatibilityVersion = None; } else { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 0c13a550e164a..dc2c2b579f1bd 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2292,8 +2292,6 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, runtimeCompatibilityVersion = llvm::VersionTuple(5, 1); } else if (version.equals("5.5")) { runtimeCompatibilityVersion = llvm::VersionTuple(5, 5); - } else if (version.equals("5.6")) { - runtimeCompatibilityVersion = llvm::VersionTuple(5, 6); } else { Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, versionArg->getAsString(Args), version); diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index b3590fdf6fc3b..7e0d2d27666a6 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -39,8 +39,6 @@ include(StdlibOptions) # End of user-configurable options. # -set(SWIFT_STDLIB_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - # Remove llvm-project/llvm/include directory from -I search part when building # the stdlib. We have our own fork of LLVM includes (Support, ADT) in # stdlib/include/llvm and we don't want to silently use headers from LLVM. diff --git a/stdlib/toolchain/CMakeLists.txt b/stdlib/toolchain/CMakeLists.txt index 9016c376b07de..20a75bddaedaa 100644 --- a/stdlib/toolchain/CMakeLists.txt +++ b/stdlib/toolchain/CMakeLists.txt @@ -50,7 +50,6 @@ if(SWIFT_STDLIB_SUPPORT_BACK_DEPLOYMENT) add_subdirectory(legacy_layouts) add_subdirectory(Compatibility50) add_subdirectory(Compatibility51) - add_subdirectory(Compatibility56) add_subdirectory(CompatibilityDynamicReplacements) add_subdirectory(CompatibilityConcurrency) endif() diff --git a/stdlib/toolchain/Compatibility56/CMakeLists.txt b/stdlib/toolchain/Compatibility56/CMakeLists.txt deleted file mode 100644 index dc5b736927c48..0000000000000 --- a/stdlib/toolchain/Compatibility56/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -set(library_name "swiftCompatibility56") - -include_directories("include/" "${SWIFT_STDLIB_SOURCE_DIR}") - -add_swift_target_library("${library_name}" STATIC - Overrides.cpp - Concurrency/Task.cpp - Concurrency/Error.cpp - Concurrency/Actor.cpp - Concurrency/AsyncLet.cpp - - TARGET_SDKS ${SWIFT_DARWIN_PLATFORMS} - - C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} - LINK_FLAGS ${CXX_LINK_FLAGS} - INCORPORATE_OBJECT_LIBRARIES swiftThreading - SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} - DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} - DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} - DEPLOYMENT_VERSION_TVOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_TVOS} - DEPLOYMENT_VERSION_WATCHOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_WATCHOS} - - INSTALL_IN_COMPONENT compiler - INSTALL_WITH_SHARED) - - -# FIXME: We need a more flexible mechanism to add lipo targets generated by -# add_swift_target_library to the ALL target. Until then this hack is necessary -# to ensure these libraries build. -foreach(sdk ${SWIFT_SDKS}) - set(target_name "${library_name}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}") - if(NOT TARGET "${target_name}") - continue() - endif() - - set_target_properties("${target_name}" - PROPERTIES - EXCLUDE_FROM_ALL FALSE) -endforeach() diff --git a/stdlib/toolchain/Compatibility56/CompatibilityOverride.h b/stdlib/toolchain/Compatibility56/CompatibilityOverride.h deleted file mode 100644 index 842447fd0bbe4..0000000000000 --- a/stdlib/toolchain/Compatibility56/CompatibilityOverride.h +++ /dev/null @@ -1,137 +0,0 @@ -//===--- CompatibiltyOverride.h - Back-deploying compatibility fixes --*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2018 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 -// -//===----------------------------------------------------------------------===// -// -// Support back-deploying compatibility fixes for newer apps running on older runtimes. -// -//===----------------------------------------------------------------------===// - -#ifndef COMPATIBILITY_OVERRIDE_H -#define COMPATIBILITY_OVERRIDE_H - -#include "public/runtime/Private.h" - -#include "Runtime/Concurrency.h" -#include "swift/Runtime/Metadata.h" -#include "swift/Runtime/Once.h" -#include - -namespace swift { - -// Macro utilities. -#define COMPATIBILITY_UNPAREN(...) __VA_ARGS__ -#define COMPATIBILITY_CONCAT2(x, y) x##y -#define COMPATIBILITY_CONCAT(x, y) COMPATIBILITY_CONCAT2(x, y) - -// This ridiculous construct will remove the parentheses from the argument and -// add a trailing comma, or will produce nothing when passed no argument. For -// example: -// COMPATIBILITY_UNPAREN_WITH_COMMA((1, 2, 3)) -> 1, 2, 3, -// COMPATIBILITY_UNPAREN_WITH_COMMA((4)) -> 4, -// COMPATIBILITY_UNPAREN_WITH_COMMA() -> -#define COMPATIBILITY_UNPAREN_WITH_COMMA(x) \ - COMPATIBILITY_CONCAT(COMPATIBILITY_UNPAREN_ADD_TRAILING_COMMA_, \ - COMPATIBILITY_UNPAREN_WITH_COMMA2 x) -#define COMPATIBILITY_UNPAREN_WITH_COMMA2(...) PARAMS(__VA_ARGS__) -#define COMPATIBILITY_UNPAREN_ADD_TRAILING_COMMA_PARAMS(...) __VA_ARGS__, -#define COMPATIBILITY_UNPAREN_ADD_TRAILING_COMMA_COMPATIBILITY_UNPAREN_WITH_COMMA2 - -// This ridiculous construct will preserve the parentheses around the argument, -// or will produce an empty pair of parentheses when passed no argument. For -// example: -// COMPATIBILITY_PAREN((1, 2, 3)) -> (1, 2, 3) -// COMPATIBILITY_PAREN((4)) -> (4) -// COMPATIBILITY_PAREN() -> () -#define COMPATIBILITY_PAREN(x) \ - COMPATIBILITY_CONCAT(COMPATIBILITY_PAREN_, COMPATIBILITY_PAREN2 x) -#define COMPATIBILITY_PAREN2(...) PARAMS(__VA_ARGS__) -#define COMPATIBILITY_PAREN_PARAMS(...) (__VA_ARGS__) -#define COMPATIBILITY_PAREN_COMPATIBILITY_PAREN2 () - -// Include path computation. Code that includes this file can write -// `#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH` to include the appropriate -// .def file for the current library. -#define COMPATIBILITY_OVERRIDE_INCLUDE_PATH_swiftRuntime \ - "CompatibilityOverrideRuntime.def" -#define COMPATIBILITY_OVERRIDE_INCLUDE_PATH_swift_Concurrency \ - "CompatibilityOverrideConcurrency.def" - -#define COMPATIBILITY_OVERRIDE_INCLUDE_PATH \ - COMPATIBILITY_CONCAT(COMPATIBILITY_OVERRIDE_INCLUDE_PATH_, \ - SWIFT_TARGET_LIBRARY_NAME) - -// Compatibility overrides are only supported on Darwin. -#ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES -#if !(defined(__APPLE__) && defined(__MACH__)) -#define SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES -#endif -#endif - -#ifdef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES - -# error Back-deployment library must always be built with compatibilty overrides - -#else // #ifdef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES - -// Override section name computation. `COMPATIBILITY_OVERRIDE_SECTION_NAME` will -// resolve to string literal containing the appropriate section name for the -// current library. -#define COMPATIBILITY_OVERRIDE_SECTION_NAME_swift_Concurrency "__s_async_hook" - -#define COMPATIBILITY_OVERRIDE_SECTION_NAME \ - COMPATIBILITY_CONCAT(COMPATIBILITY_OVERRIDE_SECTION_NAME_, \ - SWIFT_TARGET_LIBRARY_NAME) - -// Create typedefs for function pointers to call the original implementation. -#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ - ccAttrs typedef ret(*Original_##name) COMPATIBILITY_PAREN(typedArgs); -#include "CompatibilityOverrideRuntime.def" -#include "CompatibilityOverrideConcurrency.def" -#undef OVERRIDE - - -// Create typedefs for override function pointers. -#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ - ccAttrs typedef ret (*Override_##name)(COMPATIBILITY_UNPAREN_WITH_COMMA( \ - typedArgs) Original_##name originalImpl); -#include "CompatibilityOverrideRuntime.def" -#include "CompatibilityOverrideConcurrency.def" -#undef OVERRIDE - -// Create declarations for getOverride functions. -#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ - Override_ ## name getOverride_ ## name(); -#include "CompatibilityOverrideRuntime.def" -#include "CompatibilityOverrideConcurrency.def" -#undef OVERRIDE - -/// Used to define an override point. The override point #defines the appropriate -/// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes -/// the file to generate the override points. The original implementation of the -/// functionality must be available as swift_funcNameHereImpl. -#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, \ - typedArgs, namedArgs) \ - attrs ccAttrs ret namespace swift_##name COMPATIBILITY_PAREN(typedArgs) { \ - static Override_##name Override; \ - static swift_once_t Predicate; \ - swift_once( \ - &Predicate, [](void *) { Override = getOverride_##name(); }, nullptr); \ - if (Override != nullptr) \ - return Override(COMPATIBILITY_UNPAREN_WITH_COMMA(namedArgs) \ - swift_##name##Impl); \ - return swift_##name##Impl COMPATIBILITY_PAREN(namedArgs); \ - } - -#endif // #else SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES - -} /* end namespace swift */ - -#endif /* COMPATIBILITY_OVERRIDE_H */ diff --git a/stdlib/toolchain/Compatibility56/CompatibilityOverrideConcurrency.def b/stdlib/toolchain/Compatibility56/CompatibilityOverrideConcurrency.def deleted file mode 100644 index deedd1177a257..0000000000000 --- a/stdlib/toolchain/Compatibility56/CompatibilityOverrideConcurrency.def +++ /dev/null @@ -1,356 +0,0 @@ -//===--- CompatibilityOverridesConcurrency.def - Overrides Info -*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2018 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 x-macros used for metaprogramming with the set of -// compatibility override functions. -// -//===----------------------------------------------------------------------===// - -/// #define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) -/// Provides information about an overridable function. -/// - name is the name of the function, without any leading swift_ or -/// namespace. -/// - ret is the return type of the function. -/// - attrs is the attributes, if any, applied to the function definition. -/// - ccAttrs is the calling convention attributes, if any, applied to the -/// function definition and corresponding typedefs -/// - namespace is the namespace, if any, the function is in, including a -/// trailing :: -/// - typedArgs is the argument list, including types, surrounded by -/// parentheses -/// - namedArgs is the list of argument names, with no types, surrounded by -/// parentheses -/// -/// The entries are organized by group. A user may define OVERRIDE to get all -/// entries, or define one or more of the more specific OVERRIDE_* variants to -/// get only those entries. - -// NOTE: this file is used to build the definition of OverrideSection in -// CompatibilityOverride.cpp, which is part of the ABI. Moving or removing -// entries in this file will break the ABI. Additional entries can be added to -// the end. ABI breaks or version-specific changes can be accommodated by -// changing the name of the override section in that file. - -#ifdef OVERRIDE -# define OVERRIDE_ACTOR OVERRIDE -# define OVERRIDE_TASK OVERRIDE -# define OVERRIDE_ASYNC_LET OVERRIDE -# define OVERRIDE_TASK_GROUP OVERRIDE -# define OVERRIDE_TASK_LOCAL OVERRIDE -# define OVERRIDE_TASK_STATUS OVERRIDE -#else -# ifndef OVERRIDE_ACTOR -# define OVERRIDE_ACTOR(...) -# endif -# ifndef OVERRIDE_TASK -# define OVERRIDE_TASK(...) -# endif -# ifndef OVERRIDE_ASYNC_LET -# define OVERRIDE_ASYNC_LET(...) -# endif -# ifndef OVERRIDE_TASK_GROUP -# define OVERRIDE_TASK_GROUP(...) -# endif -# ifndef OVERRIDE_TASK_LOCAL -# define OVERRIDE_TASK_LOCAL(...) -# endif -# ifndef OVERRIDE_TASK_STATUS -# define OVERRIDE_TASK_STATUS(...) -# endif -#endif - -OVERRIDE_ACTOR(task_enqueue, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (class Job *job, ExecutorRef executor), - (job, executor)) - -OVERRIDE_ACTOR(job_run, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (class Job *job, ExecutorRef executor), - (job, executor)) - -OVERRIDE_ACTOR(task_getCurrentExecutor, ExecutorRef, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, ,) - -OVERRIDE_ACTOR(task_isCurrentExecutor, bool, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (ExecutorRef executor), (executor)) - -OVERRIDE_ACTOR(task_switch, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, (SWIFT_ASYNC_CONTEXT AsyncContext *resumeToContext, - TaskContinuationFunction *resumeFunction, ExecutorRef newExecutor), - (resumeToContext, resumeFunction, newExecutor)) - -OVERRIDE_TASK(task_create_common, AsyncTaskAndContext, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::, - (size_t taskCreateFlags, - TaskOptionRecord *options, - const Metadata *futureResultType, - FutureAsyncSignature::FunctionType *function, - void *closureContext, - size_t initialContextSize), - (taskCreateFlags, options, futureResultType, function, - closureContext, initialContextSize)) - -OVERRIDE_TASK(task_future_wait, void, SWIFT_EXPORT_FROM(swift_Concurrency), - SWIFT_CC(swiftasync), swift::, - (OpaqueValue *result, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, AsyncTask *task, - TaskContinuationFunction *resumeFunction, - AsyncContext *callContext), - (result, callerContext, task, resumeFunction, callContext)) - -OVERRIDE_TASK(task_future_wait_throwing, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, - (OpaqueValue *result, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, AsyncTask *task, - ThrowingTaskFutureWaitContinuationFunction *resumeFunction, - AsyncContext *callContext), - (result, callerContext, task, resumeFunction, callContext)) - -OVERRIDE_TASK(continuation_resume, void, SWIFT_EXPORT_FROM(swift_Concurrency), - SWIFT_CC(swift), swift::, - (AsyncTask *continuation), - (continuation)) - -OVERRIDE_TASK(continuation_throwingResume, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::, - (AsyncTask *continuation), - (continuation)) - -OVERRIDE_TASK(continuation_throwingResumeWithError, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::, - (AsyncTask *continuation, SwiftError *error), - (continuation, error)) - -OVERRIDE_TASK(task_addCancellationHandler, - CancellationNotificationStatusRecord *, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::, - (CancellationNotificationStatusRecord::FunctionType handler, - void *context), - (handler, context)) - -OVERRIDE_TASK(task_removeCancellationHandler, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::, - (CancellationNotificationStatusRecord *record), (record)) - -OVERRIDE_TASK(task_createNullaryContinuationJob, NullaryContinuationJob *, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::, - (size_t priority, - AsyncTask *continuation), (priority, continuation)) - -OVERRIDE_TASK(task_asyncMainDrainQueue, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::, - , ) - -OVERRIDE_TASK(task_suspend, AsyncTask *, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, ,) - -OVERRIDE_TASK(continuation_init, AsyncTask *, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (ContinuationAsyncContext *context, - AsyncContinuationFlags flags), - (context, flags)) - -OVERRIDE_TASK(continuation_await, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, (ContinuationAsyncContext *context), - (context)) - -OVERRIDE_ASYNC_LET(asyncLet_wait, void, SWIFT_EXPORT_FROM(swift_Concurrency), - SWIFT_CC(swiftasync), swift::, - (OpaqueValue *result, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncLet *alet, TaskContinuationFunction *resumeFn, - AsyncContext *callContext), - (result, callerContext, alet, resumeFn, callContext)) - -OVERRIDE_ASYNC_LET(asyncLet_wait_throwing, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, - (OpaqueValue *result, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncLet *alet, - ThrowingTaskFutureWaitContinuationFunction *resume, - AsyncContext *callContext), - (result, callerContext, alet, resume, callContext)) - -OVERRIDE_ASYNC_LET(asyncLet_end, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (AsyncLet *alet), (alet)) - -OVERRIDE_ASYNC_LET(asyncLet_get, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, - (SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncLet *alet, void *resultBuffer, - TaskContinuationFunction *resumeFn, - AsyncContext *callContext), - (callerContext, alet, resultBuffer, resumeFn, callContext)) - -OVERRIDE_ASYNC_LET(asyncLet_get_throwing, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, - (SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncLet *alet, void *resultBuffer, - ThrowingTaskFutureWaitContinuationFunction *resumeFn, - AsyncContext *callContext), - (callerContext, alet, resultBuffer, resumeFn, callContext)) - -OVERRIDE_ASYNC_LET(asyncLet_consume, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, - (SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncLet *alet, void *resultBuffer, - TaskContinuationFunction *resumeFn, - AsyncContext *callContext), - (callerContext, alet, resultBuffer, resumeFn, callContext)) - -OVERRIDE_ASYNC_LET(asyncLet_consume_throwing, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, - (SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncLet *alet, void *resultBuffer, - ThrowingTaskFutureWaitContinuationFunction *resumeFn, - AsyncContext *callContext), - (callerContext, alet, resultBuffer, resumeFn, callContext)) - -OVERRIDE_ASYNC_LET(asyncLet_finish, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, - (SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncLet *alet, void *resultBuffer, - TaskContinuationFunction *resumeFn, - AsyncContext *callContext), - (callerContext, alet, resultBuffer, resumeFn, callContext)) - -OVERRIDE_TASK_GROUP(taskGroup_initialize, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskGroup *group, const Metadata *T), (group, T)) - -OVERRIDE_TASK_STATUS(taskGroup_attachChild, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskGroup *group, AsyncTask *child), - (group, child)) - -OVERRIDE_TASK_GROUP(taskGroup_destroy, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskGroup *group), (group)) - -OVERRIDE_TASK_GROUP(taskGroup_wait_next_throwing, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swiftasync), - swift::, - (OpaqueValue *resultPointer, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - TaskGroup *_group, - ThrowingTaskFutureWaitContinuationFunction *resumeFn, - AsyncContext *callContext), - (resultPointer, callerContext, _group, resumeFn, - callContext)) - -OVERRIDE_TASK_GROUP(taskGroup_isEmpty, bool, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskGroup *group), (group)) - -OVERRIDE_TASK_GROUP(taskGroup_isCancelled, bool, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskGroup *group), (group)) - -OVERRIDE_TASK_GROUP(taskGroup_cancelAll, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskGroup *group), (group)) - -OVERRIDE_TASK_GROUP(taskGroup_addPending, bool, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskGroup *group, bool unconditionally), - (group, unconditionally)) - - -OVERRIDE_TASK_LOCAL(task_reportIllegalTaskLocalBindingWithinWithTaskGroup, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::, - (const unsigned char *file, uintptr_t fileLength, - bool fileIsASCII, uintptr_t line), - (file, fileLength, fileIsASCII, line)) - -OVERRIDE_TASK_LOCAL(task_localValuePush, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, - (const HeapObject *key, OpaqueValue *value, - const Metadata *valueType), - (key, value, valueType)) - -OVERRIDE_TASK_LOCAL(task_localValueGet, OpaqueValue *, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, - (const HeapObject *key), - (key)) - -OVERRIDE_TASK_LOCAL(task_localValuePop, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, ,) - -OVERRIDE_TASK_LOCAL(task_localsCopyTo, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, - (AsyncTask *target), - (target)) - -OVERRIDE_TASK_STATUS(task_addStatusRecord, bool, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskStatusRecord *newRecord), (newRecord)) - -OVERRIDE_TASK_STATUS(task_tryAddStatusRecord, bool, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskStatusRecord *newRecord), (newRecord)) - -OVERRIDE_TASK_STATUS(task_removeStatusRecord, bool, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskStatusRecord *record), (record)) - -OVERRIDE_TASK_STATUS(task_hasTaskGroupStatusRecord, bool, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, , ) - -OVERRIDE_TASK_STATUS(task_attachChild, ChildTaskStatusRecord *, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (AsyncTask *child), (child)) - -OVERRIDE_TASK_STATUS(task_detachChild, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (ChildTaskStatusRecord *record), (record)) - -OVERRIDE_TASK_STATUS(task_cancel, void, SWIFT_EXPORT_FROM(swift_Concurrency), - SWIFT_CC(swift), swift::, (AsyncTask *task), (task)) - -OVERRIDE_TASK_STATUS(task_cancel_group_child_tasks, void, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (TaskGroup *group), (group)) - -OVERRIDE_TASK_STATUS(task_escalate, JobPriority, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (AsyncTask *task, JobPriority newPriority), - (task, newPriority)) - -OVERRIDE_TASK_STATUS(task_getNearestDeadline, NearestTaskDeadline, - SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), - swift::, (AsyncTask *task), (task)) - -#undef OVERRIDE_ACTOR -#undef OVERRIDE_TASK -#undef OVERRIDE_ASYNC_LET -#undef OVERRIDE_TASK_GROUP -#undef OVERRIDE_TASK_LOCAL -#undef OVERRIDE_TASK_STATUS diff --git a/stdlib/toolchain/Compatibility56/CompatibilityOverrideRuntime.def b/stdlib/toolchain/Compatibility56/CompatibilityOverrideRuntime.def deleted file mode 100644 index 65ba46990b0f8..0000000000000 --- a/stdlib/toolchain/Compatibility56/CompatibilityOverrideRuntime.def +++ /dev/null @@ -1,227 +0,0 @@ -//===--- CompatibilityOverridesRuntime.def - Overrides Database -*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2018 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 x-macros used for metaprogramming with the set of -// compatibility override functions. -// -//===----------------------------------------------------------------------===// - -/// #define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) -/// Provides information about an overridable function. -/// - name is the name of the function, without any leading swift_ or -/// namespace. -/// - ret is the return type of the function. -/// - attrs is the attributes, if any, applied to the function definition. -/// - ccAttrs is the calling convention attributes, if any, applied to the -/// function definition and corresponding typedefs -/// - namespace is the namespace, if any, the function is in, including a -/// trailing :: -/// - typedArgs is the argument list, including types, surrounded by -/// parentheses -/// - namedArgs is the list of argument names, with no types, surrounded by -/// parentheses -/// -/// The entries are organized by group. A user may define OVERRIDE to get all -/// entries, or define one or more of OVERRIDE_METADATALOOKUP, OVERRIDE_CASTING, -/// OVERRIDE_OBJC, OVERRIDE_FOREIGN, OVERRIDE_PROTOCOLCONFORMANCE, -/// and OVERRIDE_KEYPATH to get only those entries. - -// NOTE: this file is used to build the definition of OverrideSection in -// CompatibilityOverride.cpp, which is part of the ABI. Moving or removing -// entries in this file will break the ABI. Additional entries can be added to -// the end. ABI breaks or version-specific changes can be accommodated by -// changing the name of the override section in that file. - -#ifdef OVERRIDE -# define OVERRIDE_METADATALOOKUP OVERRIDE -# define OVERRIDE_CASTING OVERRIDE -# define OVERRIDE_DYNAMICCASTING OVERRIDE -# define OVERRIDE_OBJC OVERRIDE -# define OVERRIDE_FOREIGN OVERRIDE -# define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE -# define OVERRIDE_KEYPATH OVERRIDE -# define OVERRIDE_WITNESSTABLE OVERRIDE -#else -# ifndef OVERRIDE_METADATALOOKUP -# define OVERRIDE_METADATALOOKUP(...) -# endif -# ifndef OVERRIDE_CASTING -# define OVERRIDE_CASTING(...) -# endif -# ifndef OVERRIDE_DYNAMICCASTING -# define OVERRIDE_DYNAMICCASTING(...) -# endif -# ifndef OVERRIDE_OBJC -# define OVERRIDE_OBJC(...) -# endif -# ifndef OVERRIDE_FOREIGN -# define OVERRIDE_FOREIGN(...) -# endif -# ifndef OVERRIDE_PROTOCOLCONFORMANCE -# define OVERRIDE_PROTOCOLCONFORMANCE(...) -# endif -# ifndef OVERRIDE_KEYPATH -# define OVERRIDE_KEYPATH(...) -# endif -# ifndef OVERRIDE_WITNESSTABLE -# define OVERRIDE_WITNESSTABLE(...) -# endif -#endif - -OVERRIDE_DYNAMICCASTING(dynamicCast, bool, , , swift::, - (OpaqueValue *dest, OpaqueValue *src, - const Metadata *srcType, - const Metadata *targetType, - DynamicCastFlags flags), - (dest, src, srcType, targetType, flags)) - - -OVERRIDE_CASTING(dynamicCastClass, const void *, , , swift::, - (const void *object, - const ClassMetadata *targetType), - (object, targetType)) - - -OVERRIDE_CASTING(dynamicCastClassUnconditional, const void *, , , swift::, - (const void *object, - const ClassMetadata *targetType, - const char *file, unsigned line, unsigned column), - (object, targetType, file, line, column)) - - - -OVERRIDE_CASTING(dynamicCastUnknownClass, const void *, , , swift::, - (const void *object, const Metadata *targetType), - (object, targetType)) - - -OVERRIDE_CASTING(dynamicCastUnknownClassUnconditional, const void *, , , swift::, - (const void *object, const Metadata *targetType, - const char *file, unsigned line, unsigned column), - (object, targetType, file, line, column)) - - -OVERRIDE_CASTING(dynamicCastMetatype, const Metadata *, , , swift::, - (const Metadata *sourceType, - const Metadata *targetType), - (sourceType, targetType)) - - -OVERRIDE_CASTING(dynamicCastMetatypeUnconditional, const Metadata *, , , swift::, - (const Metadata *sourceType, - const Metadata *targetType, - const char *file, unsigned line, unsigned column), - (sourceType, targetType, file, line, column)) - - -OVERRIDE_FOREIGN(dynamicCastForeignClassMetatype, const ClassMetadata *, , , swift::, - (const ClassMetadata *sourceType, - const ClassMetadata *targetType), - (sourceType, targetType)) - - -OVERRIDE_FOREIGN(dynamicCastForeignClassMetatypeUnconditional, - const ClassMetadata *, , , swift::, - (const ClassMetadata *sourceType, - const ClassMetadata *targetType, - const char *file, unsigned line, unsigned column), - (sourceType, targetType, file, line, column)) - - -OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocol, const WitnessTable *, , , swift::, - (const Metadata * const type, - const ProtocolDescriptor *protocol), - (type, protocol)) - -OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, - (const void *pattern, const void *arguments), - (pattern, arguments)) - -OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeLookupErrorOr, , SWIFT_CC(swift), swift::, - (MetadataRequest request, - Demangler &demangler, - Demangle::NodePointer node, - const void * const *arguments, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable), - (request, demangler, node, arguments, substGenericParam, substWitnessTable)) -OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeLookupErrorOr, , SWIFT_CC(swift), swift::, - (MetadataRequest request, - StringRef typeName, - const void * const *arguments, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable), - (request, typeName, arguments, substGenericParam, substWitnessTable)) - -OVERRIDE_WITNESSTABLE(getAssociatedTypeWitnessSlow, MetadataResponse, - SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, - (MetadataRequest request, WitnessTable *wtable, - const Metadata *conformingType, - const ProtocolRequirement *reqBase, - const ProtocolRequirement *assocType), - (request, wtable, conformingType, reqBase, assocType)) - -OVERRIDE_WITNESSTABLE(getAssociatedConformanceWitnessSlow, const WitnessTable *, - SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, - (WitnessTable *wtable, const Metadata *conformingType, - const Metadata *assocType, - const ProtocolRequirement *reqBase, - const ProtocolRequirement *assocConformance), - (wtable, conformingType, assocType, reqBase, - assocConformance)) -#if SWIFT_OBJC_INTEROP - -OVERRIDE_OBJC(dynamicCastObjCClass, const void *, , , swift::, - (const void *object, - const ClassMetadata *targetType), - (object, targetType)) - - -OVERRIDE_OBJC(dynamicCastObjCClassUnconditional, const void *, , , swift::, - (const void *object, - const ClassMetadata *targetType, - const char *file, unsigned line, unsigned column), - (object, targetType, file, line, column)) - -OVERRIDE_OBJC(dynamicCastObjCClassMetatype, const ClassMetadata *, , , swift::, - (const ClassMetadata *sourceType, - const ClassMetadata *targetType), - (sourceType, targetType)) - - -OVERRIDE_OBJC(dynamicCastObjCClassMetatypeUnconditional, const ClassMetadata *, , , swift::, - (const ClassMetadata *sourceType, const ClassMetadata *targetType, - const char *file, unsigned line, unsigned column), - (sourceType, targetType, file, line, column)) - - -OVERRIDE_FOREIGN(dynamicCastForeignClass, const void *, , , swift::, - (const void *object, - const ForeignClassMetadata *targetType), - (object, targetType)) - - -OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift::, - (const void *object, const ForeignClassMetadata *targetType, - const char *file, unsigned line, unsigned column), - (object, targetType, file, line, column)) - -#endif - -#undef OVERRIDE_METADATALOOKUP -#undef OVERRIDE_CASTING -#undef OVERRIDE_DYNAMICCASTING -#undef OVERRIDE_OBJC -#undef OVERRIDE_FOREIGN -#undef OVERRIDE_PROTOCOLCONFORMANCE -#undef OVERRIDE_KEYPATH -#undef OVERRIDE_WITNESSTABLE diff --git a/stdlib/toolchain/Compatibility56/Concurrency/Actor.cpp b/stdlib/toolchain/Compatibility56/Concurrency/Actor.cpp deleted file mode 100644 index 58922a8edd00b..0000000000000 --- a/stdlib/toolchain/Compatibility56/Concurrency/Actor.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "Runtime/Concurrency.h" -#include "Concurrency/Actor.h" -#include "Concurrency/Task.h" - -#include "swift/Runtime/Atomic.h" -#include "swift/Runtime/Casting.h" -#include "Runtime/Threading/Mutex.h" -#include "Runtime/Threading/Once.h" -#include "Runtime/Threading/ThreadLocal.h" -#include "Runtime/Threading/ThreadLocalStorage.h" - -#include -#include - -using namespace swift; - -namespace { - -/// An extremely silly class which exists to make pointer -/// default-initialization constexpr. -template struct Pointer { - T *Value; - constexpr Pointer() : Value(nullptr) {} - constexpr Pointer(T *value) : Value(value) {} - operator T *() const { return Value; } - T *operator->() const { return Value; } -}; - - -class ActiveTask { - /// A thread-local variable pointing to the active tracking - /// information about the current thread, if any. - static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(Pointer, Value, - SWIFT_CONCURRENCY_TASK_KEY); - -public: - static void set(AsyncTask *task) { Value.set(task); } - static AsyncTask *get() { return Value.get(); } -}; - -/// Define the thread-locals. -SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, - ActiveTask::Value, - SWIFT_CONCURRENCY_TASK_KEY); - - -} // namespace diff --git a/stdlib/toolchain/Compatibility56/Concurrency/AsyncLet.cpp b/stdlib/toolchain/Compatibility56/Concurrency/AsyncLet.cpp deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/stdlib/toolchain/Compatibility56/Concurrency/Error.cpp b/stdlib/toolchain/Compatibility56/Concurrency/Error.cpp deleted file mode 100644 index 78d0331550c01..0000000000000 --- a/stdlib/toolchain/Compatibility56/Concurrency/Error.cpp +++ /dev/null @@ -1,19 +0,0 @@ -//===--- Error.cpp - Error handling support code --------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "Concurrency/Error.h" - -// swift::fatalError is not exported from libswiftCore and not shared, so define another -// internal function instead. -SWIFT_NORETURN void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, ...) { - abort(); -} diff --git a/stdlib/toolchain/Compatibility56/Concurrency/Task.cpp b/stdlib/toolchain/Compatibility56/Concurrency/Task.cpp deleted file mode 100644 index c5d5edea3a559..0000000000000 --- a/stdlib/toolchain/Compatibility56/Concurrency/Task.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "Concurrency/Task.h" - -#include "Concurrency/TaskPrivate.h" -#include "Concurrency/Error.h" -#include "Overrides.h" - -using namespace swift; -using FutureFragment = AsyncTask::FutureFragment; -using TaskGroup = swift::TaskGroup; - -//===--- swift_task_future_wait -------------------------------------------===// - -void SWIFT_CC(swiftasync) swift::swift56override_swift_task_future_wait( - OpaqueValue *result, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncTask *task, - TaskContinuationFunction *resumeFn, - AsyncContext *callContext, - TaskFutureWait_t *original) { - original(result, callerContext, task, resumeFn, callContext); -} - -//===--- swift_task_future_wait_throwing ----------------------------------===// - -void SWIFT_CC(swiftasync) swift::swift56override_swift_task_future_wait_throwing( - OpaqueValue *result, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncTask *task, - ThrowingTaskFutureWaitContinuationFunction *resumeFunction, - AsyncContext *callContext, - TaskFutureWaitThrowing_t *original) { - original(result, callerContext, task, resumeFunction, callContext); -} diff --git a/stdlib/toolchain/Compatibility56/Overrides.cpp b/stdlib/toolchain/Compatibility56/Overrides.cpp deleted file mode 100644 index 440b499dccd03..0000000000000 --- a/stdlib/toolchain/Compatibility56/Overrides.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//===--- Overrides.cpp - Compat override table for Swift 5.6 runtime ------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This file provides compatibility override hooks for Swift 5.6 runtimes. -// -//===----------------------------------------------------------------------===// - -#include "Overrides.h" - -#include -#include -#include - -using namespace swift; - -#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ - Override_ ## name name; - -struct RuntimeOverrideSection { - uintptr_t version; -#include "CompatibilityOverrideRuntime.def" -}; - -struct ConcurrencyOverrideSection { - uintptr_t version; -#include "CompatibilityOverrideConcurrency.def" -}; - -#undef OVERRIDE - -ConcurrencyOverrideSection Swift56ConcurrencyOverrides -__attribute__((used, section("__DATA,__s_async_hook"))) = { - .version = 0, - .task_future_wait = swift56override_swift_task_future_wait, - .task_future_wait_throwing = swift56override_swift_task_future_wait_throwing, -}; - -RuntimeOverrideSection Swift56RuntimeOverrides -__attribute__((used, section("__DATA,__swift56_hooks"))) = { - .version = 0, -}; - -// Allow this library to get force-loaded by autolinking -__attribute__((weak, visibility("hidden"))) -extern "C" -char _swift_FORCE_LOAD_$_swiftCompatibility56 = 0; diff --git a/stdlib/toolchain/Compatibility56/Overrides.h b/stdlib/toolchain/Compatibility56/Overrides.h deleted file mode 100644 index e722cb2c22974..0000000000000 --- a/stdlib/toolchain/Compatibility56/Overrides.h +++ /dev/null @@ -1,61 +0,0 @@ -//===--- Overrides.h - Compat overrides for Swift 5.6 runtime ------s------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This file provides compatibility override hooks for Swift 5.6 runtimes. -// -//===----------------------------------------------------------------------===// - -#include "swift/Runtime/Metadata.h" -#include "llvm/ADT/StringRef.h" -#include "CompatibilityOverride.h" - -namespace swift { -struct OpaqueValue; -class AsyncContext; -class AsyncTask; - -using TaskFutureWait_t = SWIFT_CC(swiftasync) void( - OpaqueValue *result, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncTask *task, - TaskContinuationFunction *resumeFn, - AsyncContext *callContext); - -using TaskFutureWaitThrowing_t = SWIFT_CC(swiftasync) void( - OpaqueValue *result, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - AsyncTask *task, - ThrowingTaskFutureWaitContinuationFunction *resumeFn, - AsyncContext *callContext); - -void SWIFT_CC(swiftasync) swift56override_swift_task_future_wait( - OpaqueValue *, - SWIFT_ASYNC_CONTEXT AsyncContext *, - AsyncTask *, - TaskContinuationFunction *, - AsyncContext *, - TaskFutureWait_t *original); - -void SWIFT_CC(swiftasync) swift56override_swift_task_future_wait_throwing( - OpaqueValue *, - SWIFT_ASYNC_CONTEXT AsyncContext *, - AsyncTask *, - ThrowingTaskFutureWaitContinuationFunction *, - AsyncContext *, - TaskFutureWaitThrowing_t *original); - - -using AsyncMainDrainQueue_t = SWIFT_CC(swift) void(); - -void SWIFT_CC(swift) swift56override_swift_asyncMainDrainQueue(AsyncMainDrainQueue_t *); - -} // namespace swift diff --git a/stdlib/toolchain/Compatibility56/include/Concurrency/Actor.h b/stdlib/toolchain/Compatibility56/include/Concurrency/Actor.h deleted file mode 100644 index 31867e3f9f920..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Concurrency/Actor.h +++ /dev/null @@ -1,45 +0,0 @@ -//===--- Actor.h - ABI structures for actors --------------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Swift ABI describing actors. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_ABI_ACTOR_BACKDEPLOY56_H -#define SWIFT_ABI_ACTOR_BACKDEPLOY56_H - -#include "swift/ABI/HeapObject.h" -#include "swift/ABI/MetadataValues.h" - -namespace swift { - -/// The default actor implementation. This is the layout of both -/// the DefaultActor and NSDefaultActor classes. -class alignas(Alignment_DefaultActor) DefaultActor : public HeapObject { -public: - // These constructors do not initialize the actor instance, and the - // destructor does not destroy the actor instance; you must call - // swift_defaultActor_{initialize,destroy} yourself. - constexpr DefaultActor(const HeapMetadata *metadata) - : HeapObject(metadata), PrivateData{} {} - - constexpr DefaultActor(const HeapMetadata *metadata, - InlineRefCounts::Immortal_t immortal) - : HeapObject(metadata, immortal), PrivateData{} {} - - void *PrivateData[NumWords_DefaultActor]; -}; - -} // end namespace swift - -#endif // SWIFT_ABI_ACTOR_BACKDEPLOY56_H - diff --git a/stdlib/toolchain/Compatibility56/include/Concurrency/AsyncLet.h b/stdlib/toolchain/Compatibility56/include/Concurrency/AsyncLet.h deleted file mode 100644 index 8415f1260dbc6..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Concurrency/AsyncLet.h +++ /dev/null @@ -1,65 +0,0 @@ -//===--- AsyncLet.h - ABI structures for async let -00-----------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Swift ABI describing task groups. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_ABI_TASK_ASYNC_LET_BACKDEPLOY56_H -#define SWIFT_ABI_TASK_ASYNC_LET_BACKDEPLOY56_H - -#include "Task.h" -#include "swift/ABI/HeapObject.h" -#include "swift/Runtime/Config.h" -#include "swift/Basic/RelativePointer.h" -#include "swift/Basic/STLExtras.h" - -namespace swift { - -/// Represents an in-flight `async let`, i.e. the Task that is computing the -/// result of the async let, along with the awaited status and other metadata. -class alignas(Alignment_AsyncLet) AsyncLet { -public: - // These constructors do not initialize the AsyncLet instance, and the - // destructor does not destroy the AsyncLet instance; you must call - // swift_asyncLet_{start,end} yourself. - constexpr AsyncLet() - : PrivateData{} {} - - void *PrivateData[NumWords_AsyncLet]; - - // TODO: we could offer a "was awaited on" check here - - /// Returns the child task that is associated with this async let. - /// The tasks completion is used to fulfil the value represented by this async let. - AsyncTask *getTask() const; - - // The compiler preallocates a large fixed space for the `async let`, with the - // intent that most of it be used for the child task context. The next two - // methods return the address and size of that space. - - /// Return a pointer to the unused space within the async let block. - void *getPreallocatedSpace(); - - /// Return the size of the unused space within the async let block. - static size_t getSizeOfPreallocatedSpace(); - - /// Was the task allocated out of the parent's allocator? - bool didAllocateFromParentTask(); - - /// Flag that the task was allocated from the parent's allocator. - void setDidAllocateFromParentTask(bool value = true); -}; - -} // end namespace swift - -#endif // SWIFT_ABI_TASK_ASYNC_LET_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Concurrency/Error.h b/stdlib/toolchain/Compatibility56/include/Concurrency/Error.h deleted file mode 100644 index cfb89b4685648..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Concurrency/Error.h +++ /dev/null @@ -1,30 +0,0 @@ -//===--- Error.h - Swift Concurrency error helpers --------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Error handling support. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_CONCURRENCY_ERROR_BACKDEPLOY56_H -#define SWIFT_CONCURRENCY_ERROR_BACKDEPLOY56_H - -#include "public/SwiftShims/Visibility.h" -#include -#include - -namespace swift { - -SWIFT_NORETURN void swift_Concurrency_fatalError(uint32_t flags, const char *format, ...); - -} // namespace swift - -#endif // SWIFT_CONCURRENCY_ERROR_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Concurrency/Executor.h b/stdlib/toolchain/Compatibility56/include/Concurrency/Executor.h deleted file mode 100644 index 013f013c82251..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Concurrency/Executor.h +++ /dev/null @@ -1,221 +0,0 @@ -//===--- Executor.h - ABI structures for executors --------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Swift ABI describing executors. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_ABI_EXECUTOR_BACKDEPLOY56_H -#define SWIFT_ABI_EXECUTOR_BACKDEPLOY56_H - -#include - -#include "Actor.h" -#include "swift/ABI/HeapObject.h" -#include "swift/Runtime/Casting.h" - -namespace swift { -class AsyncContext; -class AsyncTask; -class DefaultActor; -class Job; -class SerialExecutorWitnessTable; - -/// An unmanaged reference to an executor. -/// -/// This type corresponds to the type Optional in -/// Swift. The representation of nil in Optional -/// aligns with what this type calls the generic executor, so the -/// notional subtype of this type which is never generic corresponds -/// to the type Builtin.Executor. -/// -/// An executor reference is divided into two pieces: -/// -/// - The identity, which is just a (potentially ObjC) object -/// reference; when this is null, the reference is generic. -/// Equality of executor references is based solely on equality -/// of identity. -/// -/// - The implementation, which is an optional reference to a -/// witness table for the SerialExecutor protocol. When this -/// is null, but the identity is non-null, the reference is to -/// a default actor. The low bits of the implementation pointer -/// are reserved for the use of marking interesting properties -/// about the executor's implementation. The runtime masks these -/// bits off before accessing the witness table, so setting them -/// in the future should back-deploy as long as the witness table -/// reference is still present. -class ExecutorRef { - HeapObject *Identity; // Not necessarily Swift reference-countable - uintptr_t Implementation; - - // We future-proof the ABI here by masking the low bits off the - // implementation pointer before using it as a witness table. - enum: uintptr_t { - WitnessTableMask = ~uintptr_t(alignof(void*) - 1) - }; - - constexpr ExecutorRef(HeapObject *identity, uintptr_t implementation) - : Identity(identity), Implementation(implementation) {} - -public: - /// A generic execution environment. When running in a generic - /// environment, it's presumed to be okay to switch synchronously - /// to an actor. As an executor request, this represents a request - /// to drop whatever the current actor is. - constexpr static ExecutorRef generic() { - return ExecutorRef(nullptr, 0); - } - - /// Given a pointer to a default actor, return an executor reference - /// for it. - static ExecutorRef forDefaultActor(DefaultActor *actor) { - assert(actor); - return ExecutorRef(actor, 0); - } - - /// Given a pointer to a serial executor and its SerialExecutor - /// conformance, return an executor reference for it. - static ExecutorRef forOrdinary(HeapObject *identity, - const SerialExecutorWitnessTable *witnessTable) { - assert(identity); - assert(witnessTable); - return ExecutorRef(identity, reinterpret_cast(witnessTable)); - } - - HeapObject *getIdentity() const { - return Identity; - } - - /// Is this the generic executor reference? - bool isGeneric() const { - return Identity == 0; - } - - /// Is this a default-actor executor reference? - bool isDefaultActor() const { - return !isGeneric() && Implementation == 0; - } - DefaultActor *getDefaultActor() const { - assert(isDefaultActor()); - return reinterpret_cast(Identity); - } - - const SerialExecutorWitnessTable *getSerialExecutorWitnessTable() const { - assert(!isGeneric() && !isDefaultActor()); - auto table = Implementation & WitnessTableMask; - return reinterpret_cast(table); - } - - /// Do we have to do any work to start running as the requested - /// executor? - bool mustSwitchToRun(ExecutorRef newExecutor) const { - return Identity != newExecutor.Identity; - } - - /// Is this executor the main executor? - bool isMainExecutor() const; - - bool operator==(ExecutorRef other) const { - return Identity == other.Identity; - } - bool operator!=(ExecutorRef other) const { - return !(*this == other); - } -}; - -using JobInvokeFunction = - SWIFT_CC(swiftasync) - void (Job *); - -using TaskContinuationFunction = - SWIFT_CC(swiftasync) - void (SWIFT_ASYNC_CONTEXT AsyncContext *); - -using ThrowingTaskFutureWaitContinuationFunction = - SWIFT_CC(swiftasync) - void (SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT void *); - - -template -class AsyncFunctionPointer; -template -struct AsyncFunctionTypeImpl; - -/// The abstract signature for an asynchronous function. -template -struct AsyncSignature; - -template -struct AsyncSignature { - bool hasDirectResult = !std::is_same::value; - using DirectResultType = DirectResultTy; - - bool hasErrorResult = HasErrorResult; - - using FunctionPointer = AsyncFunctionPointer; - using FunctionType = typename AsyncFunctionTypeImpl::type; -}; - -/// A signature for a thin async function that takes no arguments -/// and returns no results. -using ThinNullaryAsyncSignature = - AsyncSignature; - -/// A signature for a thick async function that takes no formal -/// arguments and returns no results. -using ThickNullaryAsyncSignature = - AsyncSignature; - -/// A class which can be used to statically query whether a type -/// is a specialization of AsyncSignature. -template -struct IsAsyncSignature { - static const bool value = false; -}; -template -struct IsAsyncSignature> { - static const bool value = true; -}; - -template -struct AsyncFunctionTypeImpl { - static_assert(IsAsyncSignature::value, - "template argument is not an AsyncSignature"); - - // TODO: expand and include the arguments in the parameters. - using type = TaskContinuationFunction; -}; - -template -using AsyncFunctionType = typename AsyncFunctionTypeImpl::type; - -/// A "function pointer" for an async function. -/// -/// Eventually, this will always be signed with the data key -/// using a type-specific discriminator. -template -class AsyncFunctionPointer { -public: - /// The function to run. - RelativeDirectPointer, - /*nullable*/ false, - int32_t> Function; - - /// The expected size of the context. - uint32_t ExpectedContextSize; -}; - -} - -#endif // SWIFT_ABI_EXECUTOR_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Concurrency/Task.h b/stdlib/toolchain/Compatibility56/include/Concurrency/Task.h deleted file mode 100644 index 47b9076d85e7a..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Concurrency/Task.h +++ /dev/null @@ -1,776 +0,0 @@ -//===--- Task.h - ABI structures for asynchronous tasks ---------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Swift ABI describing tasks. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_ABI_TASK_BACKDEPLOY56_H -#define SWIFT_ABI_TASK_BACKDEPLOY56_H - -#include "Executor.h" -#include "swift/ABI/HeapObject.h" -#include "swift/ABI/Metadata.h" -#include "swift/ABI/MetadataValues.h" // Maybe replace? - -#include "swift/Runtime/Config.h" -#include "VoucherShims.h" -#include "swift/Basic/STLExtras.h" -#include -#include - -namespace swift { -class AsyncTask; -class AsyncContext; -class Job; -struct OpaqueValue; -struct SwiftError; -class TaskStatusRecord; -class TaskOptionRecord; -class TaskGroup; - -extern FullMetadata jobHeapMetadata; - -/// A schedulable job. -class alignas(2 * alignof(void*)) Job : - // For async-let tasks, the refcount bits are initialized as "immortal" - // because such a task is allocated with the parent's stack allocator. - public HeapObject { -public: - // Indices into SchedulerPrivate, for use by the runtime. - enum { - /// The next waiting task link, an AsyncTask that is waiting on a future. - NextWaitingTaskIndex = 0, - - // The Dispatch object header is one pointer and two ints, which is - // equivalent to three pointers on 32-bit and two pointers 64-bit. Set the - // indexes accordingly so that DispatchLinkageIndex points to where Dispatch - // expects. - DispatchHasLongObjectHeader = sizeof(void *) == sizeof(int), - - /// An opaque field used by Dispatch when enqueueing Jobs directly. - DispatchLinkageIndex = DispatchHasLongObjectHeader ? 1 : 0, - - /// The dispatch queue being used when enqueueing a Job directly with - /// Dispatch. - DispatchQueueIndex = DispatchHasLongObjectHeader ? 0 : 1, - }; - - // Reserved for the use of the scheduler. - void *SchedulerPrivate[2]; - - JobFlags Flags; - - // Derived classes can use this to store a Job Id. - uint32_t Id = 0; - - /// The voucher associated with the job. Note: this is currently unused on - /// non-Darwin platforms, with stub implementations of the functions for - /// consistency. - voucher_t Voucher = nullptr; - - /// Reserved for future use. - void *Reserved = nullptr; - - // We use this union to avoid having to do a second indirect branch - // when resuming an asynchronous task, which we expect will be the - // common case. - union { - // A function to run a job that isn't an AsyncTask. - JobInvokeFunction * __ptrauth_swift_job_invoke_function RunJob; - - // A function to resume an AsyncTask. - TaskContinuationFunction * __ptrauth_swift_task_resume_function ResumeTask; - }; - - Job(JobFlags flags, JobInvokeFunction *invoke, - const HeapMetadata *metadata = &jobHeapMetadata) - : HeapObject(metadata), Flags(flags), RunJob(invoke) { - Voucher = voucher_copy(); - assert(!isAsyncTask() && "wrong constructor for a task"); - } - - Job(JobFlags flags, TaskContinuationFunction *invoke, - const HeapMetadata *metadata = &jobHeapMetadata, - bool captureCurrentVoucher = true) - : HeapObject(metadata), Flags(flags), ResumeTask(invoke) { - if (captureCurrentVoucher) - Voucher = voucher_copy(); - assert(isAsyncTask() && "wrong constructor for a non-task job"); - } - - /// Create a job with "immortal" reference counts. - /// Used for async let tasks. - Job(JobFlags flags, TaskContinuationFunction *invoke, - const HeapMetadata *metadata, InlineRefCounts::Immortal_t immortal, - bool captureCurrentVoucher = true) - : HeapObject(metadata, immortal), Flags(flags), ResumeTask(invoke) { - if (captureCurrentVoucher) - Voucher = voucher_copy(); - assert(isAsyncTask() && "wrong constructor for a non-task job"); - } - - ~Job() { swift_voucher_release(Voucher); } - - bool isAsyncTask() const { - return Flags.isAsyncTask(); - } - - JobPriority getPriority() const { - return Flags.getPriority(); - } - - /// Given that we've fully established the job context in the current - /// thread, actually start running this job. To establish the context - /// correctly, call swift_job_run or runJobInExecutorContext. - SWIFT_CC(swiftasync) - void runInFullyEstablishedContext(); - - /// Given that we've fully established the job context in the - /// current thread, and that the job is a simple (non-task) job, - /// actually start running this job. - SWIFT_CC(swiftasync) - void runSimpleInFullyEstablishedContext() { - return RunJob(this); // 'return' forces tail call - } -}; - -// The compiler will eventually assume these. -#if SWIFT_POINTER_IS_8_BYTES -static_assert(sizeof(Job) == 8 * sizeof(void*), - "Job size is wrong"); -#else -static_assert(sizeof(Job) == 10 * sizeof(void*), - "Job size is wrong"); -#endif -static_assert(alignof(Job) == 2 * alignof(void*), - "Job alignment is wrong"); - -class NullaryContinuationJob : public Job { - -private: - AsyncTask* Task; - AsyncTask* Continuation; - -public: - NullaryContinuationJob(AsyncTask *task, JobPriority priority, AsyncTask *continuation) - : Job({JobKind::NullaryContinuation, priority}, &process), - Task(task), Continuation(continuation) {} - - SWIFT_CC(swiftasync) - static void process(Job *job); - - static bool classof(const Job *job) { - return job->Flags.getKind() == JobKind::NullaryContinuation; - } -}; - -/// An asynchronous task. Tasks are the analogue of threads for -/// asynchronous functions: that is, they are a persistent identity -/// for the overall async computation. -/// -/// ### Fragments -/// An AsyncTask may have the following fragments: -/// -/// +--------------------------+ -/// | childFragment? | -/// | groupChildFragment? | -/// | futureFragment? |* -/// +--------------------------+ -/// -/// * The future fragment is dynamic in size, based on the future result type -/// it can hold, and thus must be the *last* fragment. -class AsyncTask : public Job { -public: - // On 32-bit targets, there is a word of tail padding remaining - // in Job, and ResumeContext will fit into that, at offset 28. - // Private then has offset 32. - // On 64-bit targets, there is no tail padding in Job, and so - // ResumeContext has offset 48. There is therefore another word - // of reserved storage prior to Private (which needs to have - // double-word alignment), which has offset 64. - // We therefore converge and end up with 16 words of storage on - // all platforms. - - /// The context for resuming the job. When a task is scheduled - /// as a job, the next continuation should be installed as the - /// ResumeTask pointer in the job header, with this serving as - /// the context pointer. - /// - /// We can't protect the data in the context from being overwritten - /// by attackers, but we can at least sign the context pointer to - /// prevent it from being corrupted in flight. - AsyncContext * __ptrauth_swift_task_resume_context ResumeContext; - -#if SWIFT_POINTER_IS_8_BYTES - void *Reserved64; -#endif - - struct PrivateStorage; - - /// Private storage for the use of the runtime. - struct alignas(2 * alignof(void*)) OpaquePrivateStorage { - void *Storage[14]; - - /// Initialize this storage during the creation of a task. - void initialize(JobPriority basePri); - void initializeWithSlab(JobPriority basePri, void *slab, - size_t slabCapacity); - - /// React to the completion of the enclosing task's execution. - void complete(AsyncTask *task); - - /// React to the final destruction of the enclosing task. - void destroy(); - - PrivateStorage &get(); - const PrivateStorage &get() const; - }; - PrivateStorage &_private(); - const PrivateStorage &_private() const; - - OpaquePrivateStorage Private; - - /// Create a task. - /// This does not initialize Private; callers must call - /// Private.initialize separately. - AsyncTask(const HeapMetadata *metadata, JobFlags flags, - TaskContinuationFunction *run, - AsyncContext *initialContext, - bool captureCurrentVoucher) - : Job(flags, run, metadata, captureCurrentVoucher), - ResumeContext(initialContext) { - assert(flags.isAsyncTask()); - setTaskId(); - } - - /// Create a task with "immortal" reference counts. - /// Used for async let tasks. - /// This does not initialize Private; callers must call - /// Private.initialize separately. - AsyncTask(const HeapMetadata *metadata, InlineRefCounts::Immortal_t immortal, - JobFlags flags, - TaskContinuationFunction *run, - AsyncContext *initialContext, - bool captureCurrentVoucher) - : Job(flags, run, metadata, immortal, captureCurrentVoucher), - ResumeContext(initialContext) { - assert(flags.isAsyncTask()); - setTaskId(); - } - - ~AsyncTask(); - - /// Set the task's ID field to the next task ID. - void setTaskId(); - uint64_t getTaskId(); - - /// Get the task's resume function, for logging purposes only. This will - /// attempt to see through the various adapters that are sometimes used, and - /// failing that will return ResumeTask. The returned function pointer may - /// have a different signature than ResumeTask, and it's only for identifying - /// code associated with the task. - const void *getResumeFunctionForLogging(); - - /// Given that we've already fully established the job context - /// in the current thread, start running this task. To establish - /// the job context correctly, call swift_job_run or - /// runInExecutorContext. - SWIFT_CC(swiftasync) - void runInFullyEstablishedContext() { - return ResumeTask(ResumeContext); // 'return' forces tail call - } - - /// A task can have the following states: - /// * suspended: In this state, a task is considered not runnable - /// * enqueued: In this state, a task is considered runnable - /// * running on a thread - /// * completed - /// - /// The following state transitions are possible: - /// suspended -> enqueued - /// suspended -> running - /// enqueued -> running - /// running -> suspended - /// running -> completed - /// running -> enqueued - /// - /// The 4 methods below are how a task switches from one state to another. - - /// Flag that this task is now running. This can update - /// the priority stored in the job flags if the priority has been - /// escalated. - /// - /// Generally this should be done immediately after updating - /// ActiveTask. - void flagAsRunning(); - - /// Flag that this task is now suspended. - void flagAsSuspended(); - - /// Flag that the task is to be enqueued on the provided executor and actually - /// enqueue it - void flagAsAndEnqueueOnExecutor(ExecutorRef newExecutor); - - /// Flag that this task is now completed. This normally does not do anything - /// but can be used to locally insert logging. - void flagAsCompleted(); - - /// Check whether this task has been cancelled. - /// Checking this is, of course, inherently race-prone on its own. - bool isCancelled() const; - - // ==== Task Local Values ---------------------------------------------------- - - void localValuePush(const HeapObject *key, - /* +1 */ OpaqueValue *value, - const Metadata *valueType); - - OpaqueValue *localValueGet(const HeapObject *key); - - /// Returns true if storage has still more bindings. - bool localValuePop(); - - // ==== Child Fragment ------------------------------------------------------- - - /// A fragment of an async task structure that happens to be a child task. - class ChildFragment { - /// The parent task of this task. - AsyncTask *Parent; - - // TODO: Document more how this is used from the `TaskGroupTaskStatusRecord` - - /// The next task in the singly-linked list of child tasks. - /// The list must start in a `ChildTaskStatusRecord` registered - /// with the parent task. - /// - /// Note that the parent task may have multiple such records. - /// - /// WARNING: Access can only be performed by the `Parent` of this task. - AsyncTask *NextChild = nullptr; - - public: - ChildFragment(AsyncTask *parent) : Parent(parent) {} - - AsyncTask *getParent() const { - return Parent; - } - - AsyncTask *getNextChild() const { - return NextChild; - } - - /// Set the `NextChild` to to the passed task. - /// - /// WARNING: This must ONLY be invoked from the parent of both - /// (this and the passed-in) tasks for thread-safety reasons. - void setNextChild(AsyncTask *task) { - NextChild = task; - } - }; - - bool hasChildFragment() const { - return Flags.task_isChildTask(); - } - - ChildFragment *childFragment() { - assert(hasChildFragment()); - - auto offset = reinterpret_cast(this); - offset += sizeof(AsyncTask); - - return reinterpret_cast(offset); - } - - // ==== TaskGroup Child ------------------------------------------------------ - - /// A child task created by `group.add` is called a "task group child." - /// Upon completion, in addition to the usual future notifying all its waiters, - /// it must also `group->offer` itself to the group. - /// - /// This signalling is necessary to correctly implement the group's `next()`. - class GroupChildFragment { - private: - TaskGroup* Group; - - friend class AsyncTask; - friend class TaskGroup; - - public: - explicit GroupChildFragment(TaskGroup *group) - : Group(group) {} - - /// Return the group this task should offer into when it completes. - TaskGroup* getGroup() { - return Group; - } - }; - - // Checks if task is a child of a TaskGroup task. - // - // A child task that is a group child knows that it's parent is a group - // and therefore may `groupOffer` to it upon completion. - bool hasGroupChildFragment() const { return Flags.task_isGroupChildTask(); } - - GroupChildFragment *groupChildFragment() { - assert(hasGroupChildFragment()); - - auto offset = reinterpret_cast(this); - offset += sizeof(AsyncTask); - if (hasChildFragment()) - offset += sizeof(ChildFragment); - - return reinterpret_cast(offset); - } - - // ==== Future --------------------------------------------------------------- - - class FutureFragment { - public: - /// Describes the status of the future. - /// - /// Futures always begin in the "Executing" state, and will always - /// make a single state change to either Success or Error. - enum class Status : uintptr_t { - /// The future is executing or ready to execute. The storage - /// is not accessible. - Executing = 0, - - /// The future has completed with result (of type \c resultType). - Success, - - /// The future has completed by throwing an error (an \c Error - /// existential). - Error, - }; - - /// An item within the wait queue, which includes the status and the - /// head of the list of tasks. - struct WaitQueueItem { - /// Mask used for the low status bits in a wait queue item. - static const uintptr_t statusMask = 0x03; - - uintptr_t storage; - - Status getStatus() const { - return static_cast(storage & statusMask); - } - - AsyncTask *getTask() const { - return reinterpret_cast(storage & ~statusMask); - } - - static WaitQueueItem get(Status status, AsyncTask *task) { - return WaitQueueItem{ - reinterpret_cast(task) | static_cast(status)}; - } - }; - - private: - /// Queue containing all of the tasks that are waiting in `get()`. - /// - /// The low bits contain the status, the rest of the pointer is the - /// AsyncTask. - std::atomic waitQueue; - - /// The type of the result that will be produced by the future. - const Metadata *resultType; - - SwiftError *error = nullptr; - - // Trailing storage for the result itself. The storage will be - // uninitialized, contain an instance of \c resultType. - - friend class AsyncTask; - - public: - explicit FutureFragment(const Metadata *resultType) - : waitQueue(WaitQueueItem::get(Status::Executing, nullptr)), - resultType(resultType) { } - - /// Destroy the storage associated with the future. - void destroy(); - - const Metadata *getResultType() const { - return resultType; - } - - /// Retrieve a pointer to the storage of the result. - OpaqueValue *getStoragePtr() { - // The result storage starts at the first aligned offset following - // the fragment header. This offset will agree with the abstract - // calculation for `resultOffset` in the fragmentSize function below - // because the entire task is aligned to at least the target - // alignment (because it's aligned to MaxAlignment), which means - // `this` must have the same value modulo that alignment as - // `fragmentOffset` has in that function. - char *fragmentAddr = reinterpret_cast(this); - uintptr_t alignment = resultType->vw_alignment(); - char *resultAddr = fragmentAddr + sizeof(FutureFragment); - uintptr_t unalignedResultAddrInt = - reinterpret_cast(resultAddr); - uintptr_t alignedResultAddrInt = - (unalignedResultAddrInt + alignment - 1) & ~(alignment - 1); - // We could just cast alignedResultAddrInt back to a pointer, but - // doing pointer arithmetic is more strictly conformant and less - // likely to annoy the optimizer. - resultAddr += (alignedResultAddrInt - unalignedResultAddrInt); - return reinterpret_cast(resultAddr); - } - - /// Retrieve the error. - SwiftError *&getError() { return error; } - - /// Determine the size of the future fragment given the result type - /// of the future. - static size_t fragmentSize(size_t fragmentOffset, - const Metadata *resultType) { - assert((fragmentOffset & (alignof(FutureFragment) - 1)) == 0); - size_t alignment = resultType->vw_alignment(); - size_t resultOffset = fragmentOffset + sizeof(FutureFragment); - resultOffset = (resultOffset + alignment - 1) & ~(alignment - 1); - size_t endOffset = resultOffset + resultType->vw_size(); - return (endOffset - fragmentOffset); - } - }; - - bool isFuture() const { return Flags.task_isFuture(); } - - FutureFragment *futureFragment() { - assert(isFuture()); - auto offset = reinterpret_cast(this); - offset += sizeof(AsyncTask); - if (hasChildFragment()) - offset += sizeof(ChildFragment); - if (hasGroupChildFragment()) - offset += sizeof(GroupChildFragment); - - return reinterpret_cast(offset); - } - - /// Wait for this future to complete. - /// - /// \returns the status of the future. If this result is - /// \c Executing, then \c waitingTask has been added to the - /// wait queue and will be scheduled when the future completes. Otherwise, - /// the future has completed and can be queried. - /// The waiting task's async context will be initialized with the parameters if - /// the current's task state is executing. - FutureFragment::Status waitFuture(AsyncTask *waitingTask, - AsyncContext *waitingTaskContext, - TaskContinuationFunction *resumeFn, - AsyncContext *callerContext, - OpaqueValue *result); - - /// Complete this future. - /// - /// Upon completion, any waiting tasks will be scheduled on the given - /// executor. - void completeFuture(AsyncContext *context); - - // ==== ---------------------------------------------------------------------- - - static bool classof(const Job *job) { - return job->isAsyncTask(); - } - -private: - /// Access the next waiting task, which establishes a singly linked list of - /// tasks that are waiting on a future. - AsyncTask *&getNextWaitingTask() { - return reinterpret_cast( - SchedulerPrivate[NextWaitingTaskIndex]); - } -}; - -// The compiler will eventually assume these. -static_assert(sizeof(AsyncTask) == NumWords_AsyncTask * sizeof(void*), - "AsyncTask size is wrong"); -static_assert(alignof(AsyncTask) == 2 * alignof(void*), - "AsyncTask alignment is wrong"); -// Libc hardcodes this offset to extract the TaskID -static_assert(offsetof(AsyncTask, Id) == 4 * sizeof(void *) + 4, - "AsyncTask::Id offset is wrong"); - -SWIFT_CC(swiftasync) -inline void Job::runInFullyEstablishedContext() { - if (auto task = dyn_cast(this)) - return task->runInFullyEstablishedContext(); // 'return' forces tail call - else - return runSimpleInFullyEstablishedContext(); // 'return' forces tail call -} - -// ==== ------------------------------------------------------------------------ - -/// An asynchronous context within a task. Generally contexts are -/// allocated using the task-local stack alloc/dealloc operations, but -/// there's no guarantee of that, and the ABI is designed to permit -/// contexts to be allocated within their caller's frame. -class alignas(MaximumAlignment) AsyncContext { -public: - /// The parent context. - AsyncContext * __ptrauth_swift_async_context_parent Parent; - - /// The function to call to resume running in the parent context. - /// Generally this means a semantic return, but for some temporary - /// translation contexts it might mean initiating a call. - /// - /// Eventually, the actual type here will depend on the types - /// which need to be passed to the parent. For now, arguments - /// are always written into the context, and so the type is - /// always the same. - TaskContinuationFunction * __ptrauth_swift_async_context_resume - ResumeParent; - - AsyncContext(TaskContinuationFunction *resumeParent, - AsyncContext *parent) - : Parent(parent), ResumeParent(resumeParent) {} - - AsyncContext(const AsyncContext &) = delete; - AsyncContext &operator=(const AsyncContext &) = delete; - - /// Perform a return from this context. - /// - /// Generally this should be tail-called. - SWIFT_CC(swiftasync) - void resumeParent() { - // TODO: destroy context before returning? - // FIXME: force tail call - return ResumeParent(Parent); - } -}; - -/// An async context that supports yielding. -class YieldingAsyncContext : public AsyncContext { -public: - /// The function to call to temporarily resume running in the - /// parent context. Generally this means a semantic yield. - TaskContinuationFunction * __ptrauth_swift_async_context_yield - YieldToParent; - - YieldingAsyncContext(TaskContinuationFunction *resumeParent, - TaskContinuationFunction *yieldToParent, - AsyncContext *parent) - : AsyncContext(resumeParent, parent), - YieldToParent(yieldToParent) {} -}; - -/// An async context that can be resumed as a continuation. -class ContinuationAsyncContext : public AsyncContext { -public: - class FlagsType : public FlagSet { - public: - enum { - CanThrow = 0, - IsExecutorSwitchForced = 1, - }; - - explicit FlagsType(size_t bits) : FlagSet(bits) {} - constexpr FlagsType() {} - - /// Whether this is a throwing continuation. - FLAGSET_DEFINE_FLAG_ACCESSORS(CanThrow, - canThrow, - setCanThrow) - - /// See AsyncContinuationFlags::isExecutorSwitchForced(). - FLAGSET_DEFINE_FLAG_ACCESSORS(IsExecutorSwitchForced, - isExecutorSwitchForced, - setIsExecutorSwitchForced) - }; - - /// Flags for the continuation. Not public ABI. - FlagsType Flags; - - /// An atomic object used to ensure that a continuation is not - /// scheduled immediately during a resume if it hasn't yet been - /// awaited by the function which set it up. Not public ABI. - std::atomic AwaitSynchronization; - - /// The error result value of the continuation. - /// This should be null-initialized when setting up the continuation. - /// Throwing resumers must overwrite this with a non-null value. - /// Public ABI. - SwiftError *ErrorResult; - - /// A pointer to the normal result value of the continuation. - /// Normal resumers must initialize this before resuming. - /// Public ABI. - OpaqueValue *NormalResult; - - /// The executor that should be resumed to. - /// Public ABI. - ExecutorRef ResumeToExecutor; - - void setErrorResult(SwiftError *error) { - ErrorResult = error; - } - - bool isExecutorSwitchForced() const { - return Flags.isExecutorSwitchForced(); - } -}; - -/// An asynchronous context within a task that describes a general "Future". -/// task. -/// -/// This type matches the ABI of a function ` () async throws -> T`, which -/// is the type used by `detach` and `Task.group.add` to create -/// futures. -class FutureAsyncContext : public AsyncContext { -public: - using AsyncContext::AsyncContext; -}; - -/// This matches the ABI of a closure `() async throws -> ()` -using AsyncVoidClosureEntryPoint = - SWIFT_CC(swiftasync) - void (SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT void *); - -/// This matches the ABI of a closure `() async throws -> T` -using AsyncGenericClosureEntryPoint = - SWIFT_CC(swiftasync) - void(OpaqueValue *, - SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT void *); - -/// This matches the ABI of the resume function of a closure -/// `() async throws -> ()`. -using AsyncVoidClosureResumeEntryPoint = - SWIFT_CC(swiftasync) - void(SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT SwiftError *); - -class AsyncContextPrefix { -public: - // Async closure entry point adhering to compiler calling conv (e.g directly - // passing the closure context instead of via the async context) - AsyncVoidClosureEntryPoint *__ptrauth_swift_task_resume_function - asyncEntryPoint; - void *closureContext; - SwiftError *errorResult; -}; - -/// Storage that is allocated before the AsyncContext to be used by an adapter -/// of Swift's async convention and the ResumeTask interface. -class FutureAsyncContextPrefix { -public: - OpaqueValue *indirectResult; - // Async closure entry point adhering to compiler calling conv (e.g directly - // passing the closure context instead of via the async context) - AsyncGenericClosureEntryPoint *__ptrauth_swift_task_resume_function - asyncEntryPoint; - void *closureContext; - SwiftError *errorResult; -}; - -} // end namespace swift - -#endif // SWIFT_ABI_TASK_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Concurrency/TaskPrivate.h b/stdlib/toolchain/Compatibility56/include/Concurrency/TaskPrivate.h deleted file mode 100644 index b51f3b437ce2e..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Concurrency/TaskPrivate.h +++ /dev/null @@ -1,71 +0,0 @@ -//===--- TaskPrivate.h - Concurrency library internal interface -*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Internal functions for the concurrency library. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_CONCURRENCY_TASKPRIVATE_BACKDEPLOY56_H -#define SWIFT_CONCURRENCY_TASKPRIVATE_BACKDEPLOY56_H - -#include "Concurrency/Error.h" -#include "Concurrency/Task.h" -#include "swift/Runtime/Error.h" - -namespace swift { -namespace { - -/// The layout of a context to call one of the following functions: -/// -/// @_silgen_name("swift_task_future_wait") -/// func _taskFutureGet(_ task: Builtin.NativeObject) async -> T -/// -/// @_silgen_name("swift_task_future_wait_throwing") -/// func _taskFutureGetThrowing(_ task: Builtin.NativeObject) async throws -> T -/// -/// @_silgen_name("swift_asyncLet_wait") -/// func _asyncLetGet(_ task: Builtin.RawPointer) async -> T -/// -/// @_silgen_name("swift_asyncLet_waitThrowing") -/// func _asyncLetGetThrowing(_ task: Builtin.RawPointer) async throws -> T -/// -/// @_silgen_name("swift_taskGroup_wait_next_throwing") -/// func _taskGroupWaitNext(group: Builtin.RawPointer) async throws -> T? -/// -class TaskFutureWaitAsyncContext : public AsyncContext { -public: - SwiftError *errorResult; - - OpaqueValue *successResultPointer; - - void fillWithSuccess(AsyncTask::FutureFragment *future) { - fillWithSuccess(future->getStoragePtr(), future->getResultType(), - successResultPointer); - } - void fillWithSuccess(OpaqueValue *src, const Metadata *successType, - OpaqueValue *result) { - successType->vw_initializeWithCopy(result, src); - } - - void fillWithError(AsyncTask::FutureFragment *future) { - fillWithError(future->getError()); - } - void fillWithError(SwiftError *error) { - errorResult = error; - swift_errorRetain(error); - } -}; - -} -} // namespace swift - -#endif // SWIFT_CONCURRENCY_TASKPRIVATE_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Concurrency/TaskStatus.h b/stdlib/toolchain/Compatibility56/include/Concurrency/TaskStatus.h deleted file mode 100644 index 665f94048b2ed..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Concurrency/TaskStatus.h +++ /dev/null @@ -1,166 +0,0 @@ -//===--- TaskStatusRecord.h - Structures to track task status --*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Swift ABI describing "status records", the mechanism by which -// tasks track dynamic information about their child tasks, custom -// cancellation hooks, and other information which may need to be exposed -// asynchronously outside of the task. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_ABI_TASKSTATUS_BACKDEPLOY56_H -#define SWIFT_ABI_TASKSTATUS_BACKDEPLOY56_H - -#include "swift/ABI/MetadataValues.h" -#include "Task.h" - -namespace swift { - -/// The abstract base class for all status records. -/// -/// TaskStatusRecords are typically allocated on the stack (possibly -/// in the task context), partially initialized, and then atomically -/// added to the task with `swift_task_addTaskStatusRecord`. While -/// registered with the task, a status record should only be -/// modified in ways that respect the possibility of asynchronous -/// access by a cancelling thread. In particular, the chain of -/// status records must not be disturbed. When the task leaves -/// the scope that requires the status record, the record can -/// be unregistered from the task with `removeStatusRecord`, -/// at which point the memory can be returned to the system. -class TaskStatusRecord { -public: - TaskStatusRecordFlags Flags; - TaskStatusRecord *Parent; - - TaskStatusRecord(TaskStatusRecordKind kind, - TaskStatusRecord *parent = nullptr) - : Flags(kind) { - resetParent(parent); - } - - TaskStatusRecord(const TaskStatusRecord &) = delete; - TaskStatusRecord &operator=(const TaskStatusRecord &) = delete; - - TaskStatusRecordKind getKind() const { return Flags.getKind(); } - - TaskStatusRecord *getParent() const { return Parent; } - - /// Change the parent of this unregistered status record to the - /// given record. - /// - /// This should be used when the record has been previously initialized - /// without knowing what the true parent is. If we decide to cache - /// important information (e.g. the earliest timeout) in the innermost - /// status record, this is the method that should fill that in - /// from the parent. - void resetParent(TaskStatusRecord *newParent) { - Parent = newParent; - // TODO: cache - } - - /// Splice a record out of the status-record chain. - /// - /// Unlike resetParent, this assumes that it's just removing one or - /// more records from the chain and that there's no need to do any - /// extra cache manipulation. - void spliceParent(TaskStatusRecord *newParent) { Parent = newParent; } -}; - -/// A deadline for the task. If this is reached, the task will be -/// automatically cancelled. The deadline can also be queried and used -/// in other ways. -struct TaskDeadline { - // FIXME: I don't really know what this should look like right now. - // It's probably target-specific. - uint64_t Value; - - bool operator==(const TaskDeadline &other) const { - return Value == other.Value; - } - bool operator<(const TaskDeadline &other) const { - return Value < other.Value; - } -}; - -/// A status record which states that a task has one or -/// more active child tasks. -class ChildTaskStatusRecord : public TaskStatusRecord { - AsyncTask *FirstChild; - -public: - ChildTaskStatusRecord(AsyncTask *child) - : TaskStatusRecord(TaskStatusRecordKind::ChildTask), FirstChild(child) {} - - ChildTaskStatusRecord(AsyncTask *child, TaskStatusRecordKind kind) - : TaskStatusRecord(kind), FirstChild(child) { - assert(kind == TaskStatusRecordKind::ChildTask); - assert(!child->hasGroupChildFragment() && - "Group child tasks must be tracked in their respective " - "TaskGroupTaskStatusRecord, and not as independent " - "ChildTaskStatusRecord " - "records."); - } - - /// Return the first child linked by this record. This may be null; - /// if not, it (and all of its successors) are guaranteed to satisfy - /// `isChildTask()`. - AsyncTask *getFirstChild() const { return FirstChild; } - - static AsyncTask *getNextChildTask(AsyncTask *task) { - return task->childFragment()->getNextChild(); - } - - using child_iterator = LinkedListIterator; - llvm::iterator_range children() const { - return child_iterator::rangeBeginning(getFirstChild()); - } - - static bool classof(const TaskStatusRecord *record) { - return record->getKind() == TaskStatusRecordKind::ChildTask; - } -}; - -/// A cancellation record which states that a task has an arbitrary -/// function that needs to be called if the task is cancelled. -/// -/// The end of any call to the function will be ordered before the -/// end of a call to unregister this record from the task. That is, -/// code may call `removeStatusRecord` and freely -/// assume after it returns that this function will not be -/// subsequently used. -class CancellationNotificationStatusRecord : public TaskStatusRecord { -public: - using FunctionType = SWIFT_CC(swift) void(SWIFT_CONTEXT void *); - -private: - FunctionType *__ptrauth_swift_cancellation_notification_function Function; - void *Argument; - -public: - CancellationNotificationStatusRecord(FunctionType *fn, void *arg) - : TaskStatusRecord(TaskStatusRecordKind::CancellationNotification), - Function(fn), Argument(arg) {} - - void run() { Function(Argument); } - - static bool classof(const TaskStatusRecord *record) { - return record->getKind() == TaskStatusRecordKind::CancellationNotification; - } -}; - -/// Return the current thread's active task reference. -SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) -AsyncTask *swift_task_getCurrent(void); -} // namespace swift - -#endif // SWIFT_ABI_TASKSTATUS_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Concurrency/VoucherShims.h b/stdlib/toolchain/Compatibility56/include/Concurrency/VoucherShims.h deleted file mode 100644 index 50927c2a614b7..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Concurrency/VoucherShims.h +++ /dev/null @@ -1,103 +0,0 @@ -//===--- VoucherShims.h - Shims for OS vouchers --------------------*- C++ -*-// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2021 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 -// -//===----------------------------------------------------------------------===// -// -// Shims for interfacing with OS voucher calls. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_CONCURRENCY_VOUCHERSHIMS_BACKDEPLOY56_H -#define SWIFT_CONCURRENCY_VOUCHERSHIMS_BACKDEPLOY56_H - -#include -#include "swift/Runtime/Config.h" - -// swift-corelibs-libdispatch has os/voucher_private.h but it doesn't work for -// us yet, so only look for it on Apple platforms. -#if __APPLE__ && __has_include() -#define SWIFT_HAS_VOUCHER_HEADER 1 -#include -#endif - -// A "dead" voucher pointer, indicating that a voucher has been removed from -// a Job, distinct from a NULL voucher that could just mean no voucher was -// present. This allows us to catch problems like adopting a voucher from the -// same Job twice without restoring it. -#define SWIFT_DEAD_VOUCHER ((voucher_t)-1) - -// The OS has voucher support if it has the header or if it has ObjC interop. -#if SWIFT_HAS_VOUCHER_HEADER || SWIFT_OBJC_INTEROP -#define SWIFT_HAS_VOUCHERS 1 -#endif - -#if SWIFT_HAS_VOUCHERS - -#if SWIFT_HAS_VOUCHER_HEADER - -#else - -// If the header isn't available, declare the necessary calls here. - -#include - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" -OS_OBJECT_DECL_CLASS(voucher); -#pragma clang diagnostic pop - -extern "C" voucher_t _Nullable voucher_copy(void); - -// Consumes argument, returns retained value. -extern "C" voucher_t _Nullable voucher_adopt(voucher_t _Nullable voucher); - -#endif // __has_include() - -static inline void swift_voucher_release(voucher_t _Nullable voucher) { - // This NULL check isn't necessary, but NULL vouchers will be common, so - // optimize for that. - if (!voucher) - return; - if (voucher == SWIFT_DEAD_VOUCHER) - return; - os_release(voucher); -} - -#else // __APPLE__ - -// Declare some do-nothing stubs for OSes without voucher support. -typedef void *voucher_t; -static inline voucher_t _Nullable voucher_copy(void) { return nullptr; } -static inline voucher_t _Nullable voucher_adopt(voucher_t _Nullable voucher) { - return nullptr; -} -static inline void swift_voucher_release(voucher_t _Nullable voucher) {} -#endif // __APPLE__ - -// Declare our own voucher_needs_adopt for when we don't get it from the SDK. -// This declaration deliberately takes `void *` instead of `voucher_t`. When the -// SDK provides one that takes `voucher_t`, then C++ overload resolution will -// favor that one. When the SDK does not provide a declaration, then the call -// site will invoke this stub instead. -static inline bool voucher_needs_adopt(void * _Nullable voucher) { - return true; -} - -static inline bool swift_voucher_needs_adopt(voucher_t _Nullable voucher) { -#if __APPLE__ - if (__builtin_available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)) - return voucher_needs_adopt(voucher); - return true; -#else - return voucher_needs_adopt(voucher); -#endif -} - -#endif // SWIFT_CONCURRENCY_VOUCHERSHIMS_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Runtime/Concurrency.h b/stdlib/toolchain/Compatibility56/include/Runtime/Concurrency.h deleted file mode 100644 index f74d614cb507f..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Runtime/Concurrency.h +++ /dev/null @@ -1,82 +0,0 @@ -//===--- Concurrency.h - Runtime interface for concurrency ------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// The runtime interface for concurrency. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_CONCURRENCY_BACKDEPLOY56_H -#define SWIFT_RUNTIME_CONCURRENCY_BACKDEPLOY56_H - -#include "Concurrency/Task.h" -#include "Concurrency/TaskStatus.h" -#include "Concurrency/AsyncLet.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" - -// Does the runtime use a cooperative global executor? -#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) -#define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 1 -#else -#define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 0 -#endif - -// Does the runtime integrate with libdispatch? -#ifndef SWIFT_CONCURRENCY_ENABLE_DISPATCH -#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR -#define SWIFT_CONCURRENCY_ENABLE_DISPATCH 0 -#else -#define SWIFT_CONCURRENCY_ENABLE_DISPATCH 1 -#endif -#endif - -namespace swift { -class DefaultActor; -class TaskOptionRecord; - -struct SwiftError; - -struct AsyncTaskAndContext { - AsyncTask *Task; - AsyncContext *InitialContext; -}; - -/// This should have the same representation as an enum like this: -/// enum NearestTaskDeadline { -/// case none -/// case alreadyCancelled -/// case active(TaskDeadline) -/// } -/// TODO: decide what this interface should really be. -struct NearestTaskDeadline { - enum Kind : uint8_t { - None, - AlreadyCancelled, - Active - }; - - TaskDeadline Value; - Kind ValueKind; -}; - - -/// Caution: not all future-initializing functions actually throw, so -/// this signature may be incorrect. -using FutureAsyncSignature = - AsyncSignature; - -} // namespace swift - -#pragma clang diagnostic pop - -#endif // SWIFT_RUNTIME_CONCURRENCY_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/Mutex.h b/stdlib/toolchain/Compatibility56/include/Runtime/Threading/Mutex.h deleted file mode 100644 index e485b68cfcd32..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/Mutex.h +++ /dev/null @@ -1,1011 +0,0 @@ -//===--- Mutex.h - Mutex, ConditionVariable, & ReadWriteLock ----*- 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex, ConditionVariable, Read/Write lock, and Scoped lock abstractions -// for use in Swift runtime. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_MUTEX_BACKDEPLOY56_H -#define SWIFT_RUNTIME_MUTEX_BACKDEPLOY56_H - -#include -#include - -#if __has_include() -#include -#endif - -#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) || defined(__wasi__) -#include "MutexSingleThreaded.h" -#elif defined(_POSIX_THREADS) -#include "MutexPThread.h" -#elif defined(_WIN32) -#include "MutexWin32.h" -#else -#error "Implement equivalent of MutexPThread.h/cpp for your platform." -#endif - -namespace swift { - -/// A stack based object that notifies one thread waiting on a condition -/// variable on destruction. -template -class ScopedNotifyOneT { - ScopedNotifyOneT() = delete; - ScopedNotifyOneT(const ScopedNotifyOneT &) = delete; - ScopedNotifyOneT &operator=(const ScopedNotifyOneT &) = delete; - - ConditionVariable &Condition; -public: - explicit ScopedNotifyOneT(ConditionVariable &c) : Condition(c) {} - - ~ScopedNotifyOneT() { - Condition.notifyOne(); - } -}; - -/// A stack based object that notifies all threads waiting on a condition -/// variable on destruction. -template -class ScopedNotifyAllT { - ScopedNotifyAllT() = delete; - ScopedNotifyAllT(const ScopedNotifyAllT &) = delete; - ScopedNotifyAllT &operator=(const ScopedNotifyAllT &) = delete; - - ConditionVariable &Condition; -public: - explicit ScopedNotifyAllT(ConditionVariable &c) : Condition(c) {} - - ~ScopedNotifyAllT() { - Condition.notifyAll(); - } -}; - -/// Compile time adjusted stack based object that locks/unlocks the supplied -/// Mutex type. Use the provided typedefs instead of this directly. -template class ScopedLockT { - ScopedLockT() = delete; - ScopedLockT(const ScopedLockT &) = delete; - ScopedLockT &operator=(const ScopedLockT &) = delete; - ScopedLockT(ScopedLockT &&) = delete; - ScopedLockT &operator=(ScopedLockT &&) = delete; - -public: - explicit ScopedLockT(T &l) : Lock(l) { - if (Inverted) { - Lock.unlock(); - } else { - Lock.lock(); - } - } - - ~ScopedLockT() { - if (Inverted) { - Lock.lock(); - } else { - Lock.unlock(); - } - } - -private: - T &Lock; -}; - -/// A ConditionVariable that works with Mutex to allow -- as an example -- -/// multi-threaded producers and consumers to signal each other in a safe way. -class ConditionVariable { - friend class ConditionMutex; - friend class StaticConditionVariable; - - ConditionVariable(const ConditionVariable &) = delete; - ConditionVariable &operator=(const ConditionVariable &) = delete; - ConditionVariable(ConditionVariable &&) = delete; - ConditionVariable &operator=(ConditionVariable &&) = delete; - -public: - ConditionVariable() { ConditionPlatformHelper::init(Handle); } - ~ConditionVariable() { ConditionPlatformHelper::destroy(Handle); } - - /// Notifies one waiter (if any exists) that the condition has been met. - /// - /// Note: To avoid missed notification it is best hold the related mutex - // lock when calling notifyOne. - void notifyOne() { ConditionPlatformHelper::notifyOne(Handle); } - - /// Notifies all waiters (if any exists) that the condition has been met. - /// - /// Note: To avoid missed notification it is best hold the related mutex - // lock when calling notifyAll. - void notifyAll() { ConditionPlatformHelper::notifyAll(Handle); } - -private: - ConditionHandle Handle; - -public: - /// A Mutex object that also supports ConditionVariables. - /// - /// This is NOT a recursive mutex. - class Mutex { - - Mutex(const Mutex &) = delete; - Mutex &operator=(const Mutex &) = delete; - Mutex(Mutex &&) = delete; - Mutex &operator=(Mutex &&) = delete; - - public: - /// Constructs a non-recursive mutex. - /// - /// If `checked` is true the mutex will attempt to check for misuse and - /// fatalError when detected. If `checked` is false (the default) the - /// mutex will make little to no effort to check for misuse (more - /// efficient). - explicit Mutex(bool checked = false) { - MutexPlatformHelper::init(Handle, checked); - } - ~Mutex() { MutexPlatformHelper::destroy(Handle); } - - /// The lock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Blocks the calling thread until exclusive ownership of the mutex - /// can be obtained. - /// - Prior m.unlock() operations on the same mutex synchronize-with - /// this lock operation. - /// - The behavior is undefined if the calling thread already owns - /// the mutex (likely a deadlock). - /// - Does not throw exceptions but will halt on error (fatalError). - void lock() { MutexPlatformHelper::lock(Handle); } - - /// The unlock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Releases the calling thread's ownership of the mutex and - /// synchronizes-with the subsequent successful lock operations on - /// the same object. - /// - The behavior is undefined if the calling thread does not own - /// the mutex. - /// - Does not throw exceptions but will halt on error (fatalError). - void unlock() { MutexPlatformHelper::unlock(Handle); } - - /// The try_lock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Attempts to obtain exclusive ownership of the mutex for the calling - /// thread without blocking. If ownership is not obtained, returns - /// immediately. The function is allowed to spuriously fail and return - /// even if the mutex is not currently owned by another thread. - /// - If try_lock() succeeds, prior unlock() operations on the same object - /// synchronize-with this operation. lock() does not synchronize with a - /// failed try_lock() - /// - The behavior is undefined if the calling thread already owns - /// the mutex (likely a deadlock)? - /// - Does not throw exceptions but will halt on error (fatalError). - bool try_lock() { return MutexPlatformHelper::try_lock(Handle); } - - /// Releases lock, waits on supplied condition, and relocks before - /// returning. - /// - /// Precondition: Mutex held by this thread, undefined otherwise. - void wait(ConditionVariable &condition) { - ConditionPlatformHelper::wait(condition.Handle, Handle); - } - - /// Acquires lock before calling the supplied critical section and releases - /// lock on return from critical section. - /// - /// This call can block while waiting for the lock to become available. - /// - /// For example the following mutates value while holding the mutex lock. - /// - /// ``` - /// mutex.lock([&value] { value++; }); - /// ``` - /// - /// Precondition: Mutex not held by this thread, undefined otherwise. - template - auto withLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedLock guard(*this); - return std::forward(criticalSection)(); - } - - /// Acquires lock before calling the supplied critical section. If critical - /// section returns `false` then it will wait on the supplied condition and - /// call the critical section again when wait returns (after acquiring - /// lock). If critical section returns `true` (done) it will no longer wait, - /// it will release the lock and return (lockOrWait returns to caller). - /// - /// This call can block while waiting for the lock to become available. - /// - /// For example the following will loop waiting on the condition until - /// `value > 0`. It will then "consume" that value and stop looping. - /// ...all while being correctly protected by mutex. - /// - /// ``` - /// mutex.withLockOrWait(condition, [&value] { - /// if (value > 0) { - /// value--; - /// return true; - /// } - /// return false; - /// }); - /// ``` - /// - /// Precondition: Mutex not held by this thread, undefined otherwise. - template - void withLockOrWait(ConditionVariable &condition, - CriticalSection &&criticalSection) { - withLock([&] { - while (!criticalSection()) { - wait(condition); - } - }); - } - - /// Acquires lock before calling the supplied critical section and on return - /// from critical section it notifies one waiter of supplied condition and - /// then releases the lock. - /// - /// This call can block while waiting for the lock to become available. - /// - /// For example the following mutates value while holding the mutex lock and - /// then notifies one condition waiter about this change. - /// - /// ``` - /// mutex.withLockThenNotifyOne(condition, [&value] { value++; }); - /// ``` - /// - /// Precondition: Mutex not held by this thread, undefined otherwise. - template - auto withLockThenNotifyOne(ConditionVariable &condition, - CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - return withLock([&] { - ScopedNotifyOne guard(condition); - return std::forward(criticalSection)(); - }); - } - - /// Acquires lock before calling the supplied critical section and on return - /// from critical section it notifies all waiters of supplied condition and - /// then releases the lock. - /// - /// This call can block while waiting for the lock to become available. - /// - /// For example the following mutates value while holding the mutex lock and - /// then notifies all condition waiters about this change. - /// - /// ``` - /// mutex.withLockThenNotifyAll(condition, [&value] { value++; }); - /// ``` - /// - /// Precondition: Mutex not held by this thread, undefined otherwise. - template - auto withLockThenNotifyAll(ConditionVariable &condition, - CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - return withLock([&] { - ScopedNotifyAll guard(condition); - return std::forward(criticalSection)(); - }); - } - - /// A stack based object that locks the supplied mutex on construction - /// and unlocks it on destruction. - /// - /// Precondition: Mutex unlocked by this thread, undefined otherwise. - typedef ScopedLockT ScopedLock; - - /// A stack based object that unlocks the supplied mutex on construction - /// and relocks it on destruction. - /// - /// Precondition: Mutex locked by this thread, undefined otherwise. - typedef ScopedLockT ScopedUnlock; - - private: - ConditionMutexHandle Handle; - }; - - using ScopedNotifyOne = ScopedNotifyOneT; - using ScopedNotifyAll = ScopedNotifyAllT; -}; - -/// A Mutex object that supports `BasicLockable` and `Lockable` C++ concepts. -/// See http://en.cppreference.com/w/cpp/concept/BasicLockable -/// See http://en.cppreference.com/w/cpp/concept/Lockable -/// -/// This is NOT a recursive mutex. -class Mutex { - - Mutex(const Mutex &) = delete; - Mutex &operator=(const Mutex &) = delete; - Mutex(Mutex &&) = delete; - Mutex &operator=(Mutex &&) = delete; - -public: - /// Constructs a non-recursive mutex. - /// - /// If `checked` is true the mutex will attempt to check for misuse and - /// fatalError when detected. If `checked` is false (the default) the - /// mutex will make little to no effort to check for misuse (more efficient). - explicit Mutex(bool checked = false) { - MutexPlatformHelper::init(Handle, checked); - } - ~Mutex() { MutexPlatformHelper::destroy(Handle); } - - /// The lock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Blocks the calling thread until exclusive ownership of the mutex - /// can be obtained. - /// - Prior m.unlock() operations on the same mutex synchronize-with - /// this lock operation. - /// - The behavior is undefined if the calling thread already owns - /// the mutex (likely a deadlock). - /// - Does not throw exceptions but will halt on error (fatalError). - void lock() { MutexPlatformHelper::lock(Handle); } - - /// The unlock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Releases the calling thread's ownership of the mutex and - /// synchronizes-with the subsequent successful lock operations on - /// the same object. - /// - The behavior is undefined if the calling thread does not own - /// the mutex. - /// - Does not throw exceptions but will halt on error (fatalError). - void unlock() { MutexPlatformHelper::unlock(Handle); } - - /// The try_lock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Attempts to obtain exclusive ownership of the mutex for the calling - /// thread without blocking. If ownership is not obtained, returns - /// immediately. The function is allowed to spuriously fail and return - /// even if the mutex is not currently owned by another thread. - /// - If try_lock() succeeds, prior unlock() operations on the same object - /// synchronize-with this operation. lock() does not synchronize with a - /// failed try_lock() - /// - The behavior is undefined if the calling thread already owns - /// the mutex (likely a deadlock)? - /// - Does not throw exceptions but will halt on error (fatalError). - bool try_lock() { return MutexPlatformHelper::try_lock(Handle); } - - /// Acquires lock before calling the supplied critical section and releases - /// lock on return from critical section. - /// - /// This call can block while waiting for the lock to become available. - /// - /// For example the following mutates value while holding the mutex lock. - /// - /// ``` - /// mutex.lock([&value] { value++; }); - /// ``` - /// - /// Precondition: Mutex not held by this thread, undefined otherwise. - template - auto withLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedLock guard(*this); - return std::forward(criticalSection)(); - } - - /// A stack based object that locks the supplied mutex on construction - /// and unlocks it on destruction. - /// - /// Precondition: Mutex unlocked by this thread, undefined otherwise. - typedef ScopedLockT ScopedLock; - - /// A stack based object that unlocks the supplied mutex on construction - /// and relocks it on destruction. - /// - /// Precondition: Mutex locked by this thread, undefined otherwise. - typedef ScopedLockT ScopedUnlock; - -private: - MutexHandle Handle; -}; - -/// Compile time adjusted stack based object that locks/unlocks the supplied -/// ReadWriteLock type. Use the provided typedefs instead of this directly. -template class ScopedRWLockT { - - ScopedRWLockT() = delete; - ScopedRWLockT(const ScopedRWLockT &) = delete; - ScopedRWLockT &operator=(const ScopedRWLockT &) = delete; - ScopedRWLockT(ScopedRWLockT &&) = delete; - ScopedRWLockT &operator=(ScopedRWLockT &&) = delete; - -public: - explicit ScopedRWLockT(T &l) : Lock(l) { - if (Inverted) { - if (Read) { - Lock.readUnlock(); - } else { - Lock.writeUnlock(); - } - } else { - if (Read) { - Lock.readLock(); - } else { - Lock.writeLock(); - } - } - } - - ~ScopedRWLockT() { - if (Inverted) { - if (Read) { - Lock.readLock(); - } else { - Lock.writeLock(); - } - } else { - if (Read) { - Lock.readUnlock(); - } else { - Lock.writeUnlock(); - } - } - } - -private: - T &Lock; -}; - -class ReadWriteLock; -class StaticReadWriteLock; - -/// A stack based object that unlocks the supplied ReadWriteLock on -/// construction and locks it for reading on destruction. -/// -/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise. -typedef ScopedRWLockT ScopedReadLock; -typedef ScopedRWLockT StaticScopedReadLock; - -/// A stack based object that unlocks the supplied ReadWriteLock on -/// construction and locks it for reading on destruction. -/// -/// Precondition: ReadWriteLock unlocked by this thread, undefined -/// otherwise. -typedef ScopedRWLockT ScopedReadUnlock; -typedef ScopedRWLockT StaticScopedReadUnlock; - -/// A stack based object that unlocks the supplied ReadWriteLock on -/// construction and locks it for reading on destruction. -/// -/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise. -typedef ScopedRWLockT ScopedWriteLock; -typedef ScopedRWLockT StaticScopedWriteLock; - -/// A stack based object that unlocks the supplied ReadWriteLock on -/// construction and locks it for writing on destruction. -/// -/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise. -typedef ScopedRWLockT ScopedWriteUnlock; -typedef ScopedRWLockT StaticScopedWriteUnlock; - -/// A Read / Write lock object that has semantics similar to `BasicLockable` -/// and `Lockable` C++ concepts however it supports multiple concurrent -/// threads holding the reader lock as long as the write lock isn't held and -/// only one thread can hold the write local at the same time. -/// -/// If you need static allocated ReadWriteLock use StaticReadWriteLock. -/// -/// See http://en.cppreference.com/w/cpp/concept/BasicLockable -/// See http://en.cppreference.com/w/cpp/concept/Lockable -/// -/// This is NOT a recursive mutex. -class ReadWriteLock { - - ReadWriteLock(const ReadWriteLock &) = delete; - ReadWriteLock &operator=(const ReadWriteLock &) = delete; - ReadWriteLock(ReadWriteLock &&) = delete; - ReadWriteLock &operator=(ReadWriteLock &&) = delete; - -public: - ReadWriteLock() { ReadWriteLockPlatformHelper::init(Handle); } - ~ReadWriteLock() { ReadWriteLockPlatformHelper::destroy(Handle); } - - /// The readLock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Blocks the calling thread while the write lock is held by another - /// thread and once the read lock is acquired by the calling thread - /// other threads are prevented from acquiring the write lock. - /// - Multiple threads can hold the read lock at the same time. - /// - Prior unlock() operations on the same lock synchronize-with - /// this lock operation. - /// - The behavior is undefined if the calling thread already owns - /// the read or write lock (likely a deadlock). - /// - Does not throw exceptions but will halt on error (fatalError). - /// - /// Callers must not mutate the data protected by the ReadWriteLock while - /// holding the read lock, the write lock must be used. - void readLock() { ReadWriteLockPlatformHelper::readLock(Handle); } - - /// The try_readLock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Attempts to obtain the read lock without blocking the calling thread. - /// If ownership is not obtained, returns immediately. The function is - /// allowed to spuriously fail and return even if the lock is not - /// currently owned by another thread. - /// - If try_readLock() succeeds, prior unlock() operations on the same - /// object synchronize-with this operation. unlock() does not synchronize - /// with a failed try_readLock(). - /// - The behavior is undefined if the calling thread already owns - /// the read or write lock (likely a deadlock)? - /// - Does not throw exceptions but will halt on error (fatalError). - /// - /// Callers must not mutate the data protected by the ReadWriteLock while - /// holding the read lock, the write lock must be used. - bool try_readLock() { - return ReadWriteLockPlatformHelper::try_readLock(Handle); - } - - /// The readUnlock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Releases the calling thread's ownership of the read lock - /// and synchronizes-with the subsequent successful lock operations on - /// the same object. - /// - The behavior is undefined if the calling thread does not own - /// the read lock. - /// - Does not throw exceptions but will halt on error (fatalError). - void readUnlock() { ReadWriteLockPlatformHelper::readUnlock(Handle); } - - /// The writeLock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Blocks the calling thread while the write lock or a read lock is held - /// by another thread and once the write lock is acquired by the calling - /// thread other threads are prevented from acquiring the write lock or a - /// read lock. - /// - Only one thread can hold the write lock at the same time. - /// - Prior unlock() operations on the same lock synchronize-with - /// this lock operation. - /// - The behavior is undefined if the calling thread already owns - /// the read or write lock (likely a deadlock). - /// - Does not throw exceptions but will halt on error (fatalError). - void writeLock() { ReadWriteLockPlatformHelper::writeLock(Handle); } - - /// The try_writeLock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Attempts to obtain the write lock without blocking the calling thread. - /// If ownership is not obtained, returns immediately. The function is - /// allowed to spuriously fail and return even if the lock is not - /// currently owned by another thread. - /// - If try_writeLock() succeeds, prior unlock() operations on the same - /// object synchronize-with this operation. unlock() does not synchronize - /// with a failed try_writeLock(). - /// - The behavior is undefined if the calling thread already owns - /// the read or write lock (likely a deadlock)? - /// - Does not throw exceptions but will halt on error (fatalError). - bool try_writeLock() { - return ReadWriteLockPlatformHelper::try_writeLock(Handle); - } - - /// The writeUnlock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Releases the calling thread's ownership of the write lock - /// and synchronizes-with the subsequent successful lock operations on - /// the same object. - /// - The behavior is undefined if the calling thread does not own - /// the write lock. - /// - Does not throw exceptions but will halt on error (fatalError). - void writeUnlock() { ReadWriteLockPlatformHelper::writeUnlock(Handle); } - - /// Acquires read lock before calling the supplied critical section and - /// releases lock on return from critical section. Callers must not mutate - /// the data protected by the ReadWriteLock while holding the read lock, the - /// write lock must be used. - /// - /// This call can block while waiting for the lock to become available. - /// - /// For example the following reads the cached value while holding - /// the read lock. - /// - /// ``` - /// rw.withReadLock([&value] { value = cachedValue; }); - /// ``` - /// - /// Precondition: ReadWriteLock not held by this thread, undefined otherwise. - template - auto withReadLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedReadLock guard(*this); - return std::forward(criticalSection)(); - } - - /// Acquires write lock before calling the supplied critical section and - /// releases lock on return from critical section. - /// - /// This call can block while waiting for the lock to become available. - /// - /// For example the following updates the cached value while holding - /// the write lock. - /// - /// ``` - /// rw.withWriteLock([&newValue] { cachedValue = newValue }); - /// ``` - /// - /// Precondition: ReadWriteLock not held by this thread, undefined otherwise. - template - auto withWriteLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedWriteLock guard(*this); - return std::forward(criticalSection)(); - } - -private: - ReadWriteLockHandle Handle; -}; - -/// A static allocation variant of ConditionVariable. -/// -/// Use ConditionVariable instead unless you need static allocation. -class StaticConditionVariable { - StaticConditionVariable(const StaticConditionVariable &) = delete; - StaticConditionVariable &operator=(const StaticConditionVariable &) = delete; - StaticConditionVariable(StaticConditionVariable &&) = delete; - StaticConditionVariable &operator=(StaticConditionVariable &&) = delete; - -public: -#if SWIFT_CONDITION_SUPPORTS_CONSTEXPR - constexpr -#endif - StaticConditionVariable() - : Handle(ConditionPlatformHelper::staticInit()) { - } - - /// See ConditionVariable::notifyOne - void notifyOne() { ConditionPlatformHelper::notifyOne(Handle); } - - /// See ConditionVariable::notifyAll - void notifyAll() { ConditionPlatformHelper::notifyAll(Handle); } - - using ScopedNotifyOne = ScopedNotifyOneT; - using ScopedNotifyAll = ScopedNotifyAllT; - - /// A static allocation variant of ConditionVariable::Mutex. - /// - /// Use ConditionVariable::Mutex instead unless you need static allocation. - class StaticMutex { - - StaticMutex(const StaticMutex &) = delete; - StaticMutex &operator=(const StaticMutex &) = delete; - StaticMutex(StaticMutex &&) = delete; - StaticMutex &operator=(StaticMutex &&) = delete; - - public: -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR - constexpr -#endif - StaticMutex() - : Handle(MutexPlatformHelper::conditionStaticInit()) { - } - - /// See Mutex::lock - void lock() { MutexPlatformHelper::lock(Handle); } - - /// See Mutex::unlock - void unlock() { MutexPlatformHelper::unlock(Handle); } - - /// See Mutex::try_lock - bool try_lock() { return MutexPlatformHelper::try_lock(Handle); } - - /// See Mutex::wait - void wait(StaticConditionVariable &condition) { - ConditionPlatformHelper::wait(condition.Handle, Handle); - } - void wait(ConditionVariable &condition) { - ConditionPlatformHelper::wait(condition.Handle, Handle); - } - - /// See Mutex::lock - template - auto withLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedLock guard(*this); - return std::forward(criticalSection)(); - } - - /// See Mutex::withLockOrWait - template - void withLockOrWait(StaticConditionVariable &condition, - CriticalSection &&criticalSection) { - withLock([&] { - while (!criticalSection()) { - wait(condition); - } - }); - } - - /// See Mutex::withLockThenNotifyOne - template - auto withLockThenNotifyOne(StaticConditionVariable &condition, - CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - return withLock([&] { - StaticConditionVariable::ScopedNotifyOne guard(condition); - return std::forward(criticalSection)(); - }); - } - - /// See Mutex::withLockThenNotifyAll - template - auto withLockThenNotifyAll(StaticConditionVariable &condition, - CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - return withLock([&] { - StaticConditionVariable::ScopedNotifyAll guard(condition); - return std::forward(criticalSection)(); - }); - } - - /// A stack based object that locks the supplied mutex on construction - /// and unlocks it on destruction. - /// - /// Precondition: Mutex unlocked by this thread, undefined otherwise. - typedef ScopedLockT ScopedLock; - - /// A stack based object that unlocks the supplied mutex on construction - /// and relocks it on destruction. - /// - /// Precondition: Mutex locked by this thread, undefined otherwise. - typedef ScopedLockT ScopedUnlock; - - private: - ConditionMutexHandle Handle; - }; - -private: - ConditionHandle Handle; -}; - -/// A static allocation variant of Mutex. -/// -/// Use Mutex instead unless you need static allocation. -class StaticMutex { - - StaticMutex(const StaticMutex &) = delete; - StaticMutex &operator=(const StaticMutex &) = delete; - StaticMutex(StaticMutex &&) = delete; - StaticMutex &operator=(StaticMutex &&) = delete; - -public: -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR - constexpr -#endif - StaticMutex() - : Handle(MutexPlatformHelper::staticInit()) { - } - - /// See Mutex::lock - void lock() { MutexPlatformHelper::lock(Handle); } - - /// See Mutex::unlock - void unlock() { MutexPlatformHelper::unlock(Handle); } - - /// See Mutex::try_lock - bool try_lock() { return MutexPlatformHelper::try_lock(Handle); } - - /// See Mutex::lock - template - auto withLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedLock guard(*this); - return std::forward(criticalSection)(); - } - - /// A stack based object that locks the supplied mutex on construction - /// and unlocks it on destruction. - /// - /// Precondition: Mutex unlocked by this thread, undefined otherwise. - typedef ScopedLockT ScopedLock; - - /// A stack based object that unlocks the supplied mutex on construction - /// and relocks it on destruction. - /// - /// Precondition: Mutex locked by this thread, undefined otherwise. - typedef ScopedLockT ScopedUnlock; - -private: - MutexHandle Handle; -}; - -/// A static allocation variant of ReadWriteLock. -/// -/// Use ReadWriteLock instead unless you need static allocation. -class StaticReadWriteLock { - - StaticReadWriteLock(const StaticReadWriteLock &) = delete; - StaticReadWriteLock &operator=(const StaticReadWriteLock &) = delete; - StaticReadWriteLock(StaticReadWriteLock &&) = delete; - StaticReadWriteLock &operator=(StaticReadWriteLock &&) = delete; - -public: -#if SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR - constexpr -#endif - StaticReadWriteLock() - : Handle(ReadWriteLockPlatformHelper::staticInit()) { - } - - /// See ReadWriteLock::readLock - void readLock() { ReadWriteLockPlatformHelper::readLock(Handle); } - - /// See ReadWriteLock::try_readLock - bool try_readLock() { - return ReadWriteLockPlatformHelper::try_readLock(Handle); - } - - /// See ReadWriteLock::readUnlock - void readUnlock() { ReadWriteLockPlatformHelper::readUnlock(Handle); } - - /// See ReadWriteLock::writeLock - void writeLock() { ReadWriteLockPlatformHelper::writeLock(Handle); } - - /// See ReadWriteLock::try_writeLock - bool try_writeLock() { - return ReadWriteLockPlatformHelper::try_writeLock(Handle); - } - - /// See ReadWriteLock::writeUnlock - void writeUnlock() { ReadWriteLockPlatformHelper::writeUnlock(Handle); } - - /// See ReadWriteLock::withReadLock - template - auto withReadLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - StaticScopedReadLock guard(*this); - return std::forward(criticalSection)(); - } - - /// See ReadWriteLock::withWriteLock - template - auto withWriteLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - StaticScopedWriteLock guard(*this); - return std::forward(criticalSection)(); - } - -private: - ReadWriteLockHandle Handle; -}; - -/// A Mutex object that supports `BasicLockable` C++ concepts. It is -/// considered -/// unsafe to use because it doesn't do any error checking. It is only for -/// use in pathways that deal with reporting fatalErrors to avoid the -/// potential -/// for recursive fatalErrors that could happen if you used Mutex. -/// -/// Always use Mutex, unless in the above mentioned error pathway situation. -class StaticUnsafeMutex { - - StaticUnsafeMutex(const StaticUnsafeMutex &) = delete; - StaticUnsafeMutex &operator=(const StaticUnsafeMutex &) = delete; - StaticUnsafeMutex(StaticUnsafeMutex &&) = delete; - StaticUnsafeMutex &operator=(StaticUnsafeMutex &&) = delete; - -public: -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR - constexpr -#endif - StaticUnsafeMutex() - : Handle(MutexPlatformHelper::staticInit()) { - } - - /// The lock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Blocks the calling thread until exclusive ownership of the mutex - /// can be obtained. - /// - Prior m.unlock() operations on the same mutex synchronize-with - /// this lock operation. - /// - The behavior is undefined if the calling thread already owns - /// the mutex (likely a deadlock). - /// - Ignores errors that may happen, undefined when an error happens. - void lock() { MutexPlatformHelper::unsafeLock(Handle); } - - /// The unlock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Releases the calling thread's ownership of the mutex and - /// synchronizes-with the subsequent successful lock operations on - /// the same object. - /// - The behavior is undefined if the calling thread does not own - /// the mutex. - /// - Ignores errors that may happen, undefined when an error happens. - void unlock() { MutexPlatformHelper::unsafeUnlock(Handle); } - - template - auto withLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedLock guard(*this); - return std::forward(criticalSection)(); - } - - typedef ScopedLockT ScopedLock; - typedef ScopedLockT ScopedUnlock; - -private: - MutexHandle Handle; -}; - -/// An indirect variant of a Mutex. This allocates the mutex on the heap, for -/// places where having the mutex inline takes up too much space. Used for -/// SmallMutex on platforms where Mutex is large. -class IndirectMutex { - IndirectMutex(const IndirectMutex &) = delete; - IndirectMutex &operator=(const IndirectMutex &) = delete; - IndirectMutex(IndirectMutex &&) = delete; - IndirectMutex &operator=(IndirectMutex &&) = delete; - -public: - explicit IndirectMutex(bool checked = false) { Ptr = new Mutex(checked); } - ~IndirectMutex() { delete Ptr; } - - void lock() { Ptr->lock(); } - - void unlock() { Ptr->unlock(); } - - bool try_lock() { return Ptr->try_lock(); } - - template - auto withLock(CriticalSection &&criticalSection) - -> decltype(criticalSection()) { - return Ptr->withLock(std::forward(criticalSection)); - } - - /// A stack based object that locks the supplied mutex on construction - /// and unlocks it on destruction. - /// - /// Precondition: Mutex unlocked by this thread, undefined otherwise. - typedef ScopedLockT ScopedLock; - - /// A stack based object that unlocks the supplied mutex on construction - /// and relocks it on destruction. - /// - /// Precondition: Mutex locked by this thread, undefined otherwise. - typedef ScopedLockT ScopedUnlock; - -private: - Mutex *Ptr; -}; - -/// A "small" mutex, which is pointer sized or smaller, for places where the -/// mutex is stored inline with limited storage space. This uses a normal Mutex -/// when that is small, and otherwise uses IndirectMutex. -using SmallMutex = - std::conditional_t; - -// Enforce literal requirements for static variants. -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR -static_assert(std::is_literal_type::value, - "StaticMutex must be literal type"); -static_assert(std::is_literal_type::value, - "StaticUnsafeMutex must be literal type"); -#else -// Your platform doesn't currently support statically allocated Mutex -// you will possibly see global-constructors warnings -#endif - -#if SWIFT_CONDITION_SUPPORTS_CONSTEXPR -static_assert(std::is_literal_type::value, - "StaticConditionVariable must be literal type"); -#else -// Your platform doesn't currently support statically allocated ConditionVar -// you will possibly see global-constructors warnings -#endif - -#if SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR -static_assert(std::is_literal_type::value, - "StaticReadWriteLock must be literal type"); -#else -// Your platform doesn't currently support statically allocated ReadWriteLocks -// you will possibly see global-constructors warnings -#endif -} - -#endif // SWIFT_RUNTIME_MUTEX_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexPThread.h b/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexPThread.h deleted file mode 100644 index d4f3c97c5f751..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexPThread.h +++ /dev/null @@ -1,157 +0,0 @@ -//===--- MutexPThread.h - Supports Mutex.h using PThreads -------*- 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex, ConditionVariable, Read/Write lock, and Scoped lock implementations -// using PThreads. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_MUTEX_PHTREAD_BACKDEPLOY56_H -#define SWIFT_RUNTIME_MUTEX_PHTREAD_BACKDEPLOY56_H - -#include - -#if defined(__APPLE__) && defined(__MACH__) -#include -#define HAS_OS_UNFAIR_LOCK 1 -#endif - -namespace swift { - -typedef pthread_cond_t ConditionHandle; -typedef pthread_mutex_t ConditionMutexHandle; -typedef pthread_rwlock_t ReadWriteLockHandle; - -#if HAS_OS_UNFAIR_LOCK -typedef os_unfair_lock MutexHandle; -#else -typedef pthread_mutex_t MutexHandle; -#endif - -#if defined(__CYGWIN__) || defined(__HAIKU__) || defined(__wasi__) -// At the moment CYGWIN pthreads implementation doesn't support the use of -// constexpr for static allocation versions. The way they define things -// results in a reinterpret_cast which violates constexpr. -// WASI currently doesn't support threading/locking at all. -#define SWIFT_CONDITION_SUPPORTS_CONSTEXPR 0 -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 0 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 0 -#else -#define SWIFT_CONDITION_SUPPORTS_CONSTEXPR 1 -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 1 -#endif - -/// PThread low-level implementation that supports ConditionVariable -/// found in Mutex.h -/// -/// See ConditionVariable -struct ConditionPlatformHelper { -#if SWIFT_CONDITION_SUPPORTS_CONSTEXPR - static constexpr -#else - static -#endif - ConditionHandle - staticInit() { - return PTHREAD_COND_INITIALIZER; - }; - static void init(ConditionHandle &condition); - static void destroy(ConditionHandle &condition); - static void notifyOne(ConditionHandle &condition); - static void notifyAll(ConditionHandle &condition); - static void wait(ConditionHandle &condition, ConditionMutexHandle &mutex); -}; - -/// PThread low-level implementation that supports Mutex -/// found in Mutex.h -/// -/// See Mutex -struct MutexPlatformHelper { -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR - static constexpr -#else - static -#endif - ConditionMutexHandle - conditionStaticInit() { - return PTHREAD_MUTEX_INITIALIZER; - }; -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR - static constexpr -#else - static -#endif - MutexHandle - staticInit() { -#if HAS_OS_UNFAIR_LOCK - return OS_UNFAIR_LOCK_INIT; -#else - return PTHREAD_MUTEX_INITIALIZER; -#endif - } - static void init(ConditionMutexHandle &mutex, bool checked = false); - static void destroy(ConditionMutexHandle &mutex); - static void lock(ConditionMutexHandle &mutex); - static void unlock(ConditionMutexHandle &mutex); - static bool try_lock(ConditionMutexHandle &mutex); - - // The ConditionMutexHandle versions handle everything on-Apple platforms. -#if HAS_OS_UNFAIR_LOCK - - static void init(MutexHandle &mutex, bool checked = false); - static void destroy(MutexHandle &mutex); - static void lock(MutexHandle &mutex); - static void unlock(MutexHandle &mutex); - static bool try_lock(MutexHandle &mutex); - - // os_unfair_lock always checks for errors, so just call through. - static void unsafeLock(MutexHandle &mutex) { lock(mutex); } - static void unsafeUnlock(MutexHandle &mutex) { unlock(mutex); } -#endif - - // The unsafe versions don't do error checking. - static void unsafeLock(ConditionMutexHandle &mutex) { - (void)pthread_mutex_lock(&mutex); - } - static void unsafeUnlock(ConditionMutexHandle &mutex) { - (void)pthread_mutex_unlock(&mutex); - } -}; - -/// PThread low-level implementation that supports ReadWriteLock -/// found in Mutex.h -/// -/// See ReadWriteLock -struct ReadWriteLockPlatformHelper { -#if SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR - static constexpr -#else - static -#endif - ReadWriteLockHandle - staticInit() { - return PTHREAD_RWLOCK_INITIALIZER; - }; - - static void init(ReadWriteLockHandle &rwlock); - static void destroy(ReadWriteLockHandle &rwlock); - static void readLock(ReadWriteLockHandle &rwlock); - static bool try_readLock(ReadWriteLockHandle &rwlock); - static void readUnlock(ReadWriteLockHandle &rwlock); - static void writeLock(ReadWriteLockHandle &rwlock); - static bool try_writeLock(ReadWriteLockHandle &rwlock); - static void writeUnlock(ReadWriteLockHandle &rwlock); -}; -} - -#endif // SWIFT_RUNTIME_MUTEX_PHTREAD_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexSingleThreaded.h b/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexSingleThreaded.h deleted file mode 100644 index 44c53beee8f8c..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexSingleThreaded.h +++ /dev/null @@ -1,74 +0,0 @@ -//===--- MutexSingleThreaded.h - --------------------------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// No-op implementation of locks for single-threaded environments. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_BACKDEPLOY56_H -#define SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_BACKDEPLOY56_H - -#include -#include "swift/Runtime/Debug.h" - -namespace swift { - -typedef void* ConditionHandle; -typedef void* ConditionMutexHandle; -typedef void* MutexHandle; -typedef void* ReadWriteLockHandle; - -#define SWIFT_CONDITION_SUPPORTS_CONSTEXPR 1 -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 1 - -struct ConditionPlatformHelper { - static constexpr ConditionHandle staticInit() { - return nullptr; - }; - static void init(ConditionHandle &condition) {} - static void destroy(ConditionHandle &condition) {} - static void notifyOne(ConditionHandle &condition) {} - static void notifyAll(ConditionHandle &condition) {} - static void wait(ConditionHandle &condition, MutexHandle &mutex) { - fatalError(0, "single-threaded runtime cannot wait for condition"); - } -}; - -struct MutexPlatformHelper { - static constexpr MutexHandle staticInit() { return nullptr; } - static constexpr ConditionMutexHandle conditionStaticInit() { - return nullptr; - } - static void init(MutexHandle &mutex, bool checked = false) {} - static void destroy(MutexHandle &mutex) {} - static void lock(MutexHandle &mutex) {} - static void unlock(MutexHandle &mutex) {} - static bool try_lock(MutexHandle &mutex) { return true; } - static void unsafeLock(MutexHandle &mutex) {} - static void unsafeUnlock(MutexHandle &mutex) {} -}; - -struct ReadWriteLockPlatformHelper { - static constexpr ReadWriteLockHandle staticInit() { return nullptr; } - static void init(ReadWriteLockHandle &rwlock) {} - static void destroy(ReadWriteLockHandle &rwlock) {} - static void readLock(ReadWriteLockHandle &rwlock) {} - static bool try_readLock(ReadWriteLockHandle &rwlock) { return true; } - static void readUnlock(ReadWriteLockHandle &rwlock) {} - static void writeLock(ReadWriteLockHandle &rwlock) {} - static bool try_writeLock(ReadWriteLockHandle &rwlock) { return true; } - static void writeUnlock(ReadWriteLockHandle &rwlock) {} -}; -} - -#endif // SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexWin32.h b/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexWin32.h deleted file mode 100644 index e41cbef7d5f96..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/MutexWin32.h +++ /dev/null @@ -1,101 +0,0 @@ -//===--- MutexWin32.h - -----------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex, ConditionVariable, Read/Write lock, and Scoped lock implementations -// using Windows Slim Reader/Writer Locks and Conditional Variables. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_MUTEX_WIN32_BACKDEPLOY56_H -#define SWIFT_RUNTIME_MUTEX_WIN32_BACKDEPLOY56_H - -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include - -namespace swift { - -typedef CONDITION_VARIABLE ConditionHandle; -typedef SRWLOCK ConditionMutexHandle; -typedef SRWLOCK MutexHandle; -typedef SRWLOCK ReadWriteLockHandle; - -#define SWIFT_CONDITION_SUPPORTS_CONSTEXPR 1 -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 1 - -struct ConditionPlatformHelper { - static constexpr ConditionHandle staticInit() { - return CONDITION_VARIABLE_INIT; - }; - static void init(ConditionHandle &condition) { - InitializeConditionVariable(&condition); - } - static void destroy(ConditionHandle &condition) {} - static void notifyOne(ConditionHandle &condition) { - WakeConditionVariable(&condition); - } - static void notifyAll(ConditionHandle &condition) { - WakeAllConditionVariable(&condition); - } - static void wait(ConditionHandle &condition, MutexHandle &mutex); -}; - -struct MutexPlatformHelper { - static constexpr MutexHandle staticInit() { return SRWLOCK_INIT; } - static constexpr ConditionMutexHandle conditionStaticInit() { - return SRWLOCK_INIT; - } - static void init(MutexHandle &mutex, bool checked = false) { - InitializeSRWLock(&mutex); - } - static void destroy(MutexHandle &mutex) {} - static void lock(MutexHandle &mutex) { AcquireSRWLockExclusive(&mutex); } - static void unlock(MutexHandle &mutex) { ReleaseSRWLockExclusive(&mutex); } - static bool try_lock(MutexHandle &mutex) { - return TryAcquireSRWLockExclusive(&mutex) != 0; - } - // The unsafe versions don't do error checking. - static void unsafeLock(MutexHandle &mutex) { - AcquireSRWLockExclusive(&mutex); - } - static void unsafeUnlock(MutexHandle &mutex) { - ReleaseSRWLockExclusive(&mutex); - } -}; - -struct ReadWriteLockPlatformHelper { - static constexpr ReadWriteLockHandle staticInit() { return SRWLOCK_INIT; } - static void init(ReadWriteLockHandle &rwlock) { InitializeSRWLock(&rwlock); } - static void destroy(ReadWriteLockHandle &rwlock) {} - static void readLock(ReadWriteLockHandle &rwlock) { - AcquireSRWLockShared(&rwlock); - } - static bool try_readLock(ReadWriteLockHandle &rwlock) { - return TryAcquireSRWLockShared(&rwlock) != 0; - } - static void readUnlock(ReadWriteLockHandle &rwlock) { - ReleaseSRWLockShared(&rwlock); - } - static void writeLock(ReadWriteLockHandle &rwlock) { - AcquireSRWLockExclusive(&rwlock); - } - static bool try_writeLock(ReadWriteLockHandle &rwlock) { - return TryAcquireSRWLockExclusive(&rwlock) != 0; - } - static void writeUnlock(ReadWriteLockHandle &rwlock) { - ReleaseSRWLockExclusive(&rwlock); - } -}; -} - -#endif // SWIFT_RUNTIME_MUTEX_WIN32_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/Once.h b/stdlib/toolchain/Compatibility56/include/Runtime/Threading/Once.h deleted file mode 100644 index 336eae735eade..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/Once.h +++ /dev/null @@ -1,54 +0,0 @@ -//===--- Once.h - Runtime support for lazy initialization -------*- 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 -// -//===----------------------------------------------------------------------===// -// -// Swift runtime functions in support of lazy initialization. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_ONCE_BACKDEPLOY56_H -#define SWIFT_RUNTIME_ONCE_BACKDEPLOY56_H - -#include "swift/Runtime/HeapObject.h" -#include - -namespace swift { - -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME - -typedef bool swift_once_t; - -#elif defined(__APPLE__) - -// On OS X and iOS, swift_once_t matches dispatch_once_t. -typedef long swift_once_t; - -#elif defined(__CYGWIN__) - -// On Cygwin, std::once_flag can not be used because it is larger than the -// platform word. -typedef uintptr_t swift_once_t; -#else - -// On other platforms swift_once_t is std::once_flag -typedef std::once_flag swift_once_t; - -#endif - -/// Runs the given function with the given context argument exactly once. -/// The predicate argument must point to a global or static variable of static -/// extent of type swift_once_t. -SWIFT_RUNTIME_EXPORT -void swift_once(swift_once_t *predicate, void (*fn)(void *), void *context); - -} - -#endif // SWIFT_RUNTIME_ONCE_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/ThreadLocal.h b/stdlib/toolchain/Compatibility56/include/Runtime/Threading/ThreadLocal.h deleted file mode 100644 index f1f10927b8cda..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/ThreadLocal.h +++ /dev/null @@ -1,176 +0,0 @@ -//===--- ThreadLocal.h - Thread-local storage -------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// Declarations and macros for working with thread-local storage in the -// Swift runtime. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_THREADLOCAL_BACKDEPLOY56_H -#define SWIFT_RUNTIME_THREADLOCAL_BACKDEPLOY56_H - -#include -#include "ThreadLocalStorage.h" - -/// SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL - Does the current configuration -/// allow the use of SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL? -#if defined(__APPLE__) -// The pthread TLS APIs work better than C++ TLS on Apple platforms. -#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 0 -#elif defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) -// We define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL to nothing in this -// configuration and just use a global variable, so this is okay. -#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 1 -#elif __has_feature(tls) -// If __has_feature reports that TLS is available, use it. -#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 1 -#elif !defined(__clang__) -// If we're not using Clang, assume that __has_feature is unreliable -// and that we can safely use TLS. -#else -// Otherwise we can't use TLS and have to fall back on something else. -#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 0 -#endif - -/// SWIFT_RUNTIME_THREAD_LOCAL - Declare that something is a -/// thread-local variable in the runtime. -#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) -// In a single-threaded runtime, thread-locals are global. -#define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL -#elif defined(__GNUC__) -// In GCC-compatible compilers, we prefer __thread because it's understood -// to guarantee a constant initializer, which permits more efficient access -// patterns. -#define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL __thread -#else -// Otherwise, just fall back on the standard C++ feature. -#define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL thread_local -#endif - -// Implementation of SWIFT_RUNTIME_DECLARE_THREAD_LOCAL -#if !SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL -#include -#include -#endif - -namespace swift { -// Validate a type stored in thread-local storage, using static asserts. Such -// types must fit in a pointer and be trivially copyable/destructible. -#define VALIDATE_THREAD_LOCAL_TYPE(T) \ - static_assert(sizeof(T) <= sizeof(void *), \ - "cannot store more than a pointer"); \ - static_assert(std::is_trivially_copyable::value, \ - "ThreadLocal values must be trivially copyable"); \ - static_assert(std::is_trivially_destructible::value, \ - "ThreadLocal cleanup is not supported, stored types must be " \ - "trivially destructible"); - -// A wrapper class for thread-local storage. -// -// - On platforms that report SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL -// above, an object of this type is declared with -// SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL. This makes the object -// itself thread-local, and no internal support is required. -// -// Note that this includes platforms that set -// SWIFT_STDLIB_SINGLE_THREADED_RUNTIME, for which -// SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL is empty; -// thread-local declarations then create an ordinary global. -// -// - On platforms that don't report SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL, -// we have to simulate thread-local storage. Fortunately, all of -// these platforms (at least for now) support pthread_getspecific. -#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL -template -class ThreadLocal { - VALIDATE_THREAD_LOCAL_TYPE(T) - - T value; - -public: - constexpr ThreadLocal() {} - - T get() { return value; } - - void set(T newValue) { value = newValue; } -}; -#else -// A wrapper around a pthread_key_t that is lazily initialized using -// dispatch_once. -class ThreadLocalKey { - // We rely on the zero-initialization of objects with static storage - // duration. - dispatch_once_t once; - pthread_key_t key; - -public: - pthread_key_t getKey() { - dispatch_once_f(&once, &key, [](void *ctx) { - pthread_key_create(reinterpret_cast(ctx), nullptr); - }); - return key; - } -}; - -// A type representing a constant pthread_key_t, for use on platforms that -// provide reserved keys. -template -class ConstantThreadLocalKey { -public: - pthread_key_t getKey() { return constantKey; } -}; - -template -class ThreadLocal { - VALIDATE_THREAD_LOCAL_TYPE(T) - - Key key; - -public: - constexpr ThreadLocal() {} - - T get() { - void *storedValue = SWIFT_THREAD_GETSPECIFIC(key.getKey()); - T value; - memcpy(&value, &storedValue, sizeof(T)); - return value; - } - - void set(T newValue) { - void *storedValue; - memcpy(&storedValue, &newValue, sizeof(T)); - SWIFT_THREAD_SETSPECIFIC(key.getKey(), storedValue); - } -}; -#endif - -} // end namespace swift - -/// SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME) - Declare a variable -/// to be a thread-local variable. The declaration must have static -/// storage duration; it may be prefixed with "static". -/// -/// Because of the fallback path, the default-initialization of the -/// type must be equivalent to a bitwise zero-initialization, and the -/// type must be small and trivially copyable and destructible. -#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL -#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME, KEY) \ - SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL swift::ThreadLocal NAME -#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC -#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME, KEY) \ - swift::ThreadLocal> NAME -#else -#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME, KEY) \ - swift::ThreadLocal NAME -#endif - -#endif // SWIFT_RUNTIME_THREADLOCAL_BACKDEPLOY56_H diff --git a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/ThreadLocalStorage.h b/stdlib/toolchain/Compatibility56/include/Runtime/Threading/ThreadLocalStorage.h deleted file mode 100644 index 88c8b90e01bd3..0000000000000 --- a/stdlib/toolchain/Compatibility56/include/Runtime/Threading/ThreadLocalStorage.h +++ /dev/null @@ -1,128 +0,0 @@ -//===--- ThreadLocalStorage.h - Thread-local storage interface. --*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2018 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 -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_THREADLOCALSTORAGE_BACKDEPLOY56_H -#define SWIFT_RUNTIME_THREADLOCALSTORAGE_BACKDEPLOY56_H - -#include "swift/Runtime/Config.h" - -// Depending on the target, we may be able to use dedicated TSD keys or -// thread_local variables. When dedicated TSD keys aren't available, -// wrap the target's API for thread-local data for things that don't want -// to use thread_local. - -// On Apple platforms, we have dedicated TSD keys. -#if defined(__APPLE__) -# define SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC 1 -#endif - -#if SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC -// Use reserved TSD keys. -# if __has_include() -# include -# else -// We still need to use the SPI for setting the destructor, so declare it here. -extern "C" int pthread_key_init_np(int key, void (*destructor)(void *)); -# endif - -// If the keys are not available from the header, define them ourselves. The values match -// what tsd_private.h provides. -# ifndef __PTK_FRAMEWORK_SWIFT_KEY0 -# define __PTK_FRAMEWORK_SWIFT_KEY0 100 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY1 -# define __PTK_FRAMEWORK_SWIFT_KEY1 101 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY2 -# define __PTK_FRAMEWORK_SWIFT_KEY2 102 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY3 -# define __PTK_FRAMEWORK_SWIFT_KEY3 103 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY4 -# define __PTK_FRAMEWORK_SWIFT_KEY4 104 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY5 -# define __PTK_FRAMEWORK_SWIFT_KEY5 105 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY6 -# define __PTK_FRAMEWORK_SWIFT_KEY6 106 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY7 -# define __PTK_FRAMEWORK_SWIFT_KEY7 107 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY8 -# define __PTK_FRAMEWORK_SWIFT_KEY8 108 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY9 -# define __PTK_FRAMEWORK_SWIFT_KEY9 109 -# endif - - -# define SWIFT_RUNTIME_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY0 -# define SWIFT_STDLIB_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY1 -# define SWIFT_COMPATIBILITY_50_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY2 -# define SWIFT_CONCURRENCY_TASK_KEY __PTK_FRAMEWORK_SWIFT_KEY3 -# define SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY __PTK_FRAMEWORK_SWIFT_KEY4 -# define SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY \ - __PTK_FRAMEWORK_SWIFT_KEY5 - -#endif - -// If the reserved key path didn't already provide get/setspecific macros, -// wrap the platform's APIs. -#ifndef SWIFT_THREAD_GETSPECIFIC - -// Pick the right typedef for the key. -# if defined(__linux__) -# if defined(__ANDROID__) -typedef int __swift_thread_key_t; -# else -typedef unsigned int __swift_thread_key_t; -# endif -# elif defined(__FreeBSD__) -typedef int __swift_thread_key_t; -# elif defined(__OpenBSD__) -typedef int __swift_thread_key_t; -# elif defined(_WIN32) -typedef unsigned long __swift_thread_key_t; -# elif defined(__HAIKU__) -typedef int __swift_thread_key_t; -# else -typedef unsigned long __swift_thread_key_t; -# endif - -# if defined(_WIN32) && !defined(__CYGWIN__) -// Windows has its own flavor of API. -# include -# define WIN32_LEAN_AND_MEAN -# include - -#include - -static_assert(std::is_same<__swift_thread_key_t, DWORD>::value, - "__swift_thread_key_t is not a DWORD"); - -# define SWIFT_THREAD_KEY_CREATE _stdlib_thread_key_create -# define SWIFT_THREAD_GETSPECIFIC FlsGetValue -# define SWIFT_THREAD_SETSPECIFIC(key, value) (FlsSetValue(key, value) == FALSE) - -# elif !defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) -// Otherwise use the pthread API. -# include -# define SWIFT_THREAD_KEY_CREATE pthread_key_create -# define SWIFT_THREAD_GETSPECIFIC pthread_getspecific -# define SWIFT_THREAD_SETSPECIFIC pthread_setspecific -# endif -#endif - -#endif // SWIFT_RUNTIME_THREADLOCALSTORAGE_BACKDEPLOY56_H diff --git a/test/Concurrency/Backdeploy/weak_linking.swift b/test/Concurrency/Backdeploy/weak_linking.swift index 886668036bd8c..ae074486eb793 100644 --- a/test/Concurrency/Backdeploy/weak_linking.swift +++ b/test/Concurrency/Backdeploy/weak_linking.swift @@ -1,14 +1,8 @@ // RUN: %empty-directory(%t) - -// RUN: %target-swift-frontend %s -target %target-cpu-apple-macosx13.0 -module-name main -emit-ir -o %t/new.ir +// RUN: %target-swift-frontend %s -target %target-cpu-apple-macosx12.0 -module-name main -emit-ir -o %t/new.ir // RUN: %FileCheck %s --check-prefix=NEW < %t/new.ir - -// RUN: %target-swift-frontend %s -target %target-cpu-apple-macosx12.0 -module-name main -emit-ir -o %t/backdeploy_56.ir -// RUN: %FileCheck %s --check-prefix=BACKDEPLOY56 < %t/backdeploy_56.ir - -// RUN: %target-swift-frontend %s -target %target-cpu-apple-macosx10.15 -module-name main -emit-ir -o %t/backdeployed_concurrency.ir -disable-availability-checking -// RUN: %FileCheck %s --check-prefixes=BACKDEPLOY_CONCURRENCY,BACKDEPLOY56 < %t/backdeployed_concurrency.ir - +// RUN: %target-swift-frontend %s -target %target-cpu-apple-macosx10.15 -module-name main -emit-ir -o %t/old.ir -disable-availability-checking +// RUN: %FileCheck %s --check-prefix=OLD < %t/old.ir // RUN: %target-swift-frontend %s -target %target-cpu-apple-macosx10.15 -O -module-name main -emit-ir -o %t/optimized.ir -disable-availability-checking // RUN: %FileCheck %s --check-prefix=OPTIMIZED < %t/optimized.ir @@ -16,15 +10,10 @@ // REQUIRES: OS=macosx // NEW-NOT: extern_weak - -// BACKDEPLOY_CONCURRENCY: @"$sScPMn" = extern_weak global -// BACKDEPLOY_CONCURRENCY: declare extern_weak swiftcc i8* @swift_task_alloc -// BACKDEPLOY_CONCURRENCY: declare extern_weak swiftcc %swift.metadata_response @"$sScPMa" - -// BACKDEPLOY_CONCURRENCY: declare extern_weak void @"_swift_FORCE_LOAD_$_swiftCompatibilityConcurrency"() -// BACKDEPLOY56: declare extern_weak void @"_swift_FORCE_LOAD_$_swiftCompatibility56"() - -// BACKDEPLOY_CONCURRENCY: declare extern_weak swiftcc i8 @"$sScP8rawValues5UInt8Vvg" +// OLD: @"$sScPMn" = extern_weak global +// OLD: declare extern_weak swiftcc i8* @swift_task_alloc +// OLD: declare extern_weak swiftcc %swift.metadata_response @"$sScPMa" +// OLD: declare extern_weak swiftcc i8 @"$sScP8rawValues5UInt8Vvg" // OPTIMIZED: @swift_async_extendedFramePointerFlags = extern_weak global i8* // OPTIMIZED: @_swift_async_extendedFramePointerFlagsUser = linkonce_odr hidden global i8** @swift_async_extendedFramePointerFlags From 58420a164b23300e3e785e2d589d0d067b5f92f4 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Fri, 5 Aug 2022 13:51:42 -0700 Subject: [PATCH 12/22] LoadableByAddress: Updating global variables' types Because of pointer authentication the type of global variables needs to be updated. rdar://93688980 --- include/swift/SIL/SILGlobalVariable.h | 6 ++ lib/IRGen/LoadableByAddress.cpp | 130 +++++++++++++++++++++++++- test/IRGen/ptrauth-global.swift | 43 +++++++++ 3 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 test/IRGen/ptrauth-global.swift diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index 0b6ee4942f1b3..72318d31584ca 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -125,6 +125,12 @@ class SILGlobalVariable return getLoweredTypeInContext(context).castTo(); } + void unsafeSetLoweredType(SILType newType) { LoweredType = newType; } + void unsafeAppend(SILInstruction *i) { StaticInitializerBlock.push_back(i); } + void unsafeRemove(SILInstruction *i, SILModule &mod) { + StaticInitializerBlock.erase(i, mod); + } + StringRef getName() const { return Name; } void setDeclaration(bool isD) { IsDeclaration = isD; } diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index ce2dcc8ef848d..c7ca9b8f79761 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -1711,6 +1711,8 @@ class LoadableByAddress : public SILModuleTransform { bool recreateDifferentiabilityWitnessFunction( SILInstruction &I, SmallVectorImpl &Delete); + bool shouldTransformGlobal(SILGlobalVariable *global); + private: llvm::SetVector modFuncs; llvm::SetVector conversionInstrs; @@ -2907,6 +2909,24 @@ void LoadableByAddress::updateLoweredTypes(SILFunction *F) { F->rewriteLoweredTypeUnsafe(newFuncTy); } +bool LoadableByAddress::shouldTransformGlobal(SILGlobalVariable *global) { + SILInstruction *init = global->getStaticInitializerValue(); + if (!init) + return false; + auto silTy = global->getLoweredType(); + if (!isa(silTy.getASTType())) + return false; + + auto *decl = global->getDecl(); + IRGenModule *currIRMod = getIRGenModule()->IRGen.getGenModule( + decl ? decl->getDeclContext() : nullptr); + auto silFnTy = global->getLoweredFunctionType(); + GenericEnvironment *genEnv = getSubstGenericEnvironment(silFnTy); + if (MapperCache.shouldTransformFunctionType(genEnv, silFnTy, *currIRMod)) + return true; + return false; +} + /// The entry point to this function transformation. void LoadableByAddress::run() { // Set the SIL state before the PassManager has a chance to run @@ -2922,10 +2942,23 @@ void LoadableByAddress::run() { // Scan the module for all references of the modified functions: llvm::SetVector funcRefs; + llvm::SetVector globalRefs; for (SILFunction &CurrF : *getModule()) { for (SILBasicBlock &BB : CurrF) { for (SILInstruction &I : BB) { - if (auto *FRI = dyn_cast(&I)) { + if (auto *allocGlobal = dyn_cast(&I)) { + auto *global = allocGlobal->getReferencedGlobal(); + if (shouldTransformGlobal(global)) + globalRefs.insert(allocGlobal); + } else if (auto *globalAddr = dyn_cast(&I)) { + auto *global = globalAddr->getReferencedGlobal(); + if (shouldTransformGlobal(global)) + globalRefs.insert(globalAddr); + } else if (auto *globalVal = dyn_cast(&I)) { + auto *global = globalVal->getReferencedGlobal(); + if (shouldTransformGlobal(global)) + globalRefs.insert(globalVal); + } else if (auto *FRI = dyn_cast(&I)) { SILFunction *RefF = FRI->getInitiallyReferencedFunction(); if (modFuncs.count(RefF) != 0) { // Go over the uses and add them to lists to modify @@ -2954,7 +2987,7 @@ void LoadableByAddress::run() { case SILInstructionKind::LinearFunctionExtractInst: case SILInstructionKind::DifferentiableFunctionExtractInst: { conversionInstrs.insert( - cast(currInstr)); + cast(currInstr)); break; } case SILInstructionKind::BuiltinInst: { @@ -3032,6 +3065,99 @@ void LoadableByAddress::run() { updateLoweredTypes(F); } + auto computeNewResultType = [&](SILType ty, IRGenModule *mod) -> SILType { + auto currSILFunctionType = ty.castTo(); + GenericEnvironment *genEnv = + getSubstGenericEnvironment(currSILFunctionType); + return SILType::getPrimitiveObjectType( + MapperCache.getNewSILFunctionType(genEnv, currSILFunctionType, *mod)); + }; + + // Update globals' initializer. + SmallVector deadGlobals; + for (SILGlobalVariable &global : getModule()->getSILGlobals()) { + SILInstruction *init = global.getStaticInitializerValue(); + if (!init) + continue; + auto silTy = global.getLoweredType(); + if (!isa(silTy.getASTType())) + continue; + auto *decl = global.getDecl(); + IRGenModule *currIRMod = getIRGenModule()->IRGen.getGenModule( + decl ? decl->getDeclContext() : nullptr); + auto silFnTy = global.getLoweredFunctionType(); + GenericEnvironment *genEnv = getSubstGenericEnvironment(silFnTy); + + // Update the global's type. + if (MapperCache.shouldTransformFunctionType(genEnv, silFnTy, *currIRMod)) { + auto newSILFnType = + MapperCache.getNewSILFunctionType(genEnv, silFnTy, *currIRMod); + global.unsafeSetLoweredType( + SILType::getPrimitiveObjectType(newSILFnType)); + + // Rewrite the init basic block... + SmallVector initBlockInsts; + for (auto it = global.begin(), end = global.end(); it != end; ++it) { + initBlockInsts.push_back(const_cast(&*it)); + } + for (auto *oldInst : initBlockInsts) { + if (auto *f = dyn_cast(oldInst)) { + SILBuilder builder(&global); + auto *newInst = builder.createFunctionRef( + f->getLoc(), f->getInitiallyReferencedFunction(), f->getKind()); + f->replaceAllUsesWith(newInst); + global.unsafeRemove(f, *getModule()); + } else if (auto *cvt = dyn_cast(oldInst)) { + auto newType = computeNewResultType(cvt->getType(), currIRMod); + SILBuilder builder(&global); + auto *newInst = builder.createConvertFunction( + cvt->getLoc(), cvt->getOperand(), newType, + cvt->withoutActuallyEscaping()); + cvt->replaceAllUsesWith(newInst); + global.unsafeRemove(cvt, *getModule()); + } else if (auto *thinToThick = + dyn_cast(oldInst)) { + auto newType = + computeNewResultType(thinToThick->getType(), currIRMod); + SILBuilder builder(&global); + auto *newInstr = builder.createThinToThickFunction( + thinToThick->getLoc(), thinToThick->getOperand(), newType); + thinToThick->replaceAllUsesWith(newInstr); + global.unsafeRemove(thinToThick, *getModule()); + } else { + auto *sv = cast(oldInst); + auto *newInst = cast(oldInst->clone()); + global.unsafeAppend(newInst); + sv->replaceAllUsesWith(newInst); + global.unsafeRemove(oldInst, *getModule()); + } + } + } + } + + // Rewrite global variable users. + for (auto *inst : globalRefs) { + if (auto *allocGlobal = dyn_cast(inst)) { + // alloc_global produces no results. + SILBuilderWithScope builder(inst); + builder.createAllocGlobal(allocGlobal->getLoc(), + allocGlobal->getReferencedGlobal()); + allocGlobal->eraseFromParent(); + } else if (auto *globalAddr = dyn_cast(inst)) { + SILBuilderWithScope builder(inst); + auto *newInst = builder.createGlobalAddr( + globalAddr->getLoc(), globalAddr->getReferencedGlobal()); + globalAddr->replaceAllUsesWith(newInst); + globalAddr->eraseFromParent(); + } else if (auto *globalVal = dyn_cast(inst)) { + SILBuilderWithScope builder(inst); + auto *newInst = builder.createGlobalValue( + globalVal->getLoc(), globalVal->getReferencedGlobal()); + globalVal->replaceAllUsesWith(newInst); + globalVal->eraseFromParent(); + } + } + // Update all references: // Note: We don't need to update the witness tables and vtables // They just contain a pointer to the function diff --git a/test/IRGen/ptrauth-global.swift b/test/IRGen/ptrauth-global.swift new file mode 100644 index 0000000000000..bf7e3ce05645f --- /dev/null +++ b/test/IRGen/ptrauth-global.swift @@ -0,0 +1,43 @@ +// RUN: %swift-frontend -swift-version 4 -target arm64e-apple-ios12.0 -primary-file %s -emit-ir -module-name A | %FileCheck %s --check-prefix=CHECK +// RUN: %swift-frontend -swift-version 4 -target arm64e-apple-ios12.0 %s -primary-file %S/Inputs/ptrauth-global-2.swift -emit-ir -module-name A | %FileCheck %s --check-prefix=CHECK2 + +// REQUIRES: CPU=arm64e +// REQUIRES: OS=ios + +// Make sure that the key at the definition of the global matches call sites. + +// CHECK-DAG: @"$s1A9ContainerV3AllAA1GVySiGycAA1VVySiGcycvpZ" = global %swift.function { {{.*}} @"$s1A9ContainerV3AllAA1GVySiGycAA1VVySiGcycvpZfiAGycAJcycfU_.ptrauth" +// CHECK-DAG: @"$s1A9ContainerV3AllAA1GVySiGycAA1VVySiGcycvpZfiAGycAJcycfU_.ptrauth" = {{.*}} @"$s1A9ContainerV3AllAA1GVySiGycAA1VVySiGcycvpZfiAGycAJcycfU_" {{.*}} i64 58141 }, section "llvm.ptrauth" + + + +// CHECK2: define {{.*}}swiftcc void @"$s1A4testyyF"() +// CHECK2: [[T:%.*]] = call swiftcc i8* @"$s1A9ContainerV3AllAA1GVySiGycAA1VVySiGcycvau"() +// CHECK2: [[T2:%.*]] = bitcast i8* [[T]] to %swift.function* +// CHECK2: [[T3:%.*]] = getelementptr inbounds %swift.function, %swift.function* [[T2]], i32 0, i32 0 +// CHECK2: [[T4:%.*]] = load i8*, i8** [[T3]] +// CHECK2: [[T5:%.*]] = bitcast i8* [[T4]] to { i8*, %swift.refcounted* } (%swift.refcounted*)* +// CHECK2: call swiftcc { i8*, %swift.refcounted* } [[T5]]({{.*}}) [ "ptrauth"(i32 0, i64 58141) ] + +public struct G { + init(_ t: T) {} +} + +public struct V { + var str: String = "" + var str1: String = "" + var str2: String = "" + var str3: String = "" + var str4: String = "" + var str5: String = "" + var str6: String = "" + var str7: String = "" + var str8: String = "" + init(_ t: T) {} +} + +// Because of the large parameter type the signature gets transformed by the +// large loadable pass. The types in the global initializer need to follow. +public struct Container { + public static let All = { return { (_ v: V) in { return G(5) } } } +} From 9d96ed940f320512c73b2cca9b72487220b40d7b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 9 Aug 2022 12:46:30 -0400 Subject: [PATCH 13/22] AST: Rename 'canonical wrt. generic signature' to 'reduced' We had two notions of canonical types, one is the structural property where it doesn't contain sugared types, the other one where it does not contain reducible type parameters with respect to a generic signature. Rename the second one to a 'reduced type'. --- include/swift/AST/GenericSignature.h | 14 ++--- include/swift/AST/Types.h | 4 +- include/swift/SIL/AbstractionPattern.h | 2 +- .../Analysis/DifferentiableActivityAnalysis.h | 2 +- .../Differentiation/LinearMapInfo.h | 2 +- lib/AST/ASTContext.cpp | 8 +-- lib/AST/ASTMangler.cpp | 2 +- lib/AST/Decl.cpp | 2 +- lib/AST/GenericSignature.cpp | 59 +++++++++---------- .../GenericSignatureQueries.cpp | 47 ++++++++------- .../RequirementMachine/RequirementMachine.cpp | 2 +- .../RequirementMachine/RequirementMachine.h | 8 +-- .../RequirementMachineRequests.cpp | 8 +-- lib/AST/RequirementMachine/RuleBuilder.cpp | 2 +- lib/AST/SubstitutionMap.cpp | 4 +- lib/AST/Type.cpp | 20 +++---- lib/IRGen/GenArchetype.cpp | 2 +- lib/IRGen/GenKeyPath.cpp | 2 +- lib/IRGen/GenMeta.cpp | 4 +- lib/IRGen/GenProto.cpp | 2 +- lib/IRGen/GenReflection.cpp | 4 +- lib/SIL/IR/AbstractionPattern.cpp | 14 ++--- lib/SIL/IR/SIL.cpp | 2 +- lib/SIL/IR/SILFunctionType.cpp | 22 +++---- lib/SIL/IR/TypeLowering.cpp | 19 +++--- lib/SIL/Verifier/SILVerifier.cpp | 4 +- lib/SILGen/ResultPlan.cpp | 8 +-- lib/SILGen/SILGen.cpp | 4 +- lib/SILGen/SILGenApply.cpp | 2 +- lib/SILGen/SILGenExpr.cpp | 5 +- lib/SILGen/SILGenLazyConformance.cpp | 6 +- lib/SILGen/SILGenProlog.cpp | 4 +- lib/SILGen/SILGenType.cpp | 2 +- .../Differentiation/JVPCloner.cpp | 14 ++--- .../Differentiation/PullbackCloner.cpp | 6 +- .../Differentiation/VJPCloner.cpp | 20 +++---- .../ExistentialTransform.cpp | 7 +-- .../SILCombiner/SILCombinerCastVisitors.cpp | 3 +- lib/SILOptimizer/Utils/Generics.cpp | 4 +- lib/Sema/ConstraintSystem.cpp | 4 +- lib/Sema/TypeCheckAttr.cpp | 6 +- lib/Sema/TypeCheckDeclOverride.cpp | 6 +- lib/Sema/TypeCheckProtocolInference.cpp | 4 +- lib/Sema/TypeCheckType.cpp | 6 +- .../member_type_of_superclass_bound.swift | 2 +- 45 files changed, 180 insertions(+), 194 deletions(-) diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index 4145bc87d3f46..1105c47d7d79c 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -213,9 +213,9 @@ class GenericSignature { SmallVector requirementsNotSatisfiedBy(GenericSignature otherSig) const; - /// Return the canonical version of the given type under this generic + /// Return the reduced version of the given type under this generic /// signature. - CanType getCanonicalTypeInContext(Type type) const; + CanType getReducedType(Type type) const; /// Check invariants. void verify() const; @@ -383,7 +383,7 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final /// generic signature. /// /// The type parameters must be known to not be concrete within the context. - bool areSameTypeParameterInContext(Type type1, Type type2) const; + bool areReducedTypeParametersEqual(Type type1, Type type2) const; /// Determine if \c sig can prove \c requirement, meaning that it can deduce /// T: Foo or T == U (etc.) with the information it knows. This includes @@ -392,11 +392,11 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final bool isRequirementSatisfied( Requirement requirement, bool allowMissing = false) const; - bool isCanonicalTypeInContext(Type type) const; + bool isReducedType(Type type) const; /// Determine whether the given type parameter is defined under this generic /// signature. - bool isValidTypeInContext(Type type) const; + bool isValidTypeParameter(Type type) const; /// Retrieve the conformance access path used to extract the conformance of /// interface \c type to the given \c protocol. @@ -487,9 +487,9 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final SmallVector requirementsNotSatisfiedBy(GenericSignature otherSig) const; - /// Return the canonical version of the given type under this generic + /// Return the reduced version of the given type under this generic /// signature. - CanType getCanonicalTypeInContext(Type type) const; + CanType getReducedType(Type type) const; }; void simple_display(raw_ostream &out, GenericSignature sig); diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index d01a8c0bbd293..4d26b2801bfb2 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -503,9 +503,9 @@ class alignas(1 << TypeAlignInBits) TypeBase return const_cast(this)->computeCanonicalType(); } - /// getCanonicalType - Stronger canonicalization which folds away equivalent + /// getReducedType - Stronger canonicalization which folds away equivalent /// associated types, or type parameters that have been made concrete. - CanType getCanonicalType(GenericSignature sig); + CanType getReducedType(GenericSignature sig); /// Canonical protocol composition types are minimized only to a certain /// degree to preserve ABI compatibility. This routine enables performing diff --git a/include/swift/SIL/AbstractionPattern.h b/include/swift/SIL/AbstractionPattern.h index 4d3f8f1ec62ad..631717e24dda2 100644 --- a/include/swift/SIL/AbstractionPattern.h +++ b/include/swift/SIL/AbstractionPattern.h @@ -514,7 +514,7 @@ class AbstractionPattern { OrigType = origType; GenericSig = CanGenericSignature(); if (OrigType->hasTypeParameter()) { - assert(OrigType == signature.getCanonicalTypeInContext(origType)); + assert(OrigType == signature.getReducedType(origType)); GenericSig = signature; } } diff --git a/include/swift/SILOptimizer/Analysis/DifferentiableActivityAnalysis.h b/include/swift/SILOptimizer/Analysis/DifferentiableActivityAnalysis.h index 209aec0fdc252..b8b678fe0584c 100644 --- a/include/swift/SILOptimizer/Analysis/DifferentiableActivityAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/DifferentiableActivityAnalysis.h @@ -135,7 +135,7 @@ class DifferentiableActivityInfo { auto type = value->getType().getASTType(); // Remap archetypes in the derivative generic signature, if it exists. if (type->hasArchetype()) { - type = derivativeGenericSignature.getCanonicalTypeInContext( + type = derivativeGenericSignature.getReducedType( type->mapTypeOutOfContext()); } // Look up conformance in the current module. diff --git a/include/swift/SILOptimizer/Differentiation/LinearMapInfo.h b/include/swift/SILOptimizer/Differentiation/LinearMapInfo.h index 13735902d38dd..f6ce574362909 100644 --- a/include/swift/SILOptimizer/Differentiation/LinearMapInfo.h +++ b/include/swift/SILOptimizer/Differentiation/LinearMapInfo.h @@ -165,7 +165,7 @@ class LinearMapInfo { derivative->getLoweredFunctionType()->getSubstGenericSignature(); auto *linMapStruct = getLinearMapStruct(origBB); auto linMapStructType = - linMapStruct->getDeclaredInterfaceType()->getCanonicalType( + linMapStruct->getDeclaredInterfaceType()->getReducedType( derivativeGenSig); Lowering::AbstractionPattern pattern(derivativeGenSig, linMapStructType); return typeConverter.getLoweredType(pattern, linMapStructType, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a53383c3e1fe7..6ba12479ea20f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3541,7 +3541,7 @@ isGenericFunctionTypeCanonical(GenericSignature sig, return false; for (auto param : params) { - if (!sig->isCanonicalTypeInContext(param.getPlainType())) + if (!sig->isReducedType(param.getPlainType())) return false; if (!param.getInternalLabel().empty()) { // Canonical types don't have internal labels @@ -3549,7 +3549,7 @@ isGenericFunctionTypeCanonical(GenericSignature sig, } } - return sig->isCanonicalTypeInContext(result); + return sig->isReducedType(result); } AnyFunctionType *AnyFunctionType::withExtInfo(ExtInfo info) const { @@ -3771,7 +3771,7 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig, } // We have to construct this generic function type. Determine whether - // it's canonical. Unfortunately, isCanonicalTypeInContext can cause + // it's canonical. Unfortunately, isReducedType() can cause // new GenericFunctionTypes to be created and thus invalidate our insertion // point. bool isCanonical = isGenericFunctionTypeCanonical(sig, params, result); @@ -3788,7 +3788,7 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig, if (info.hasValue()) globalActor = info->getGlobalActor(); - if (globalActor && !sig->isCanonicalTypeInContext(globalActor)) + if (globalActor && !sig->isReducedType(globalActor)) isCanonical = false; size_t allocSize = totalSizeToAlloc( diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index ee66188b8b236..2f3e90f589f0c 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -3488,7 +3488,7 @@ void ASTMangler::appendConcreteProtocolConformance( auto type = conditionalReq.getFirstType(); if (type->hasArchetype()) type = type->mapTypeOutOfContext(); - CanType canType = type->getCanonicalType(sig); + CanType canType = type->getReducedType(sig); auto proto = conditionalReq.getProtocolDecl(); ProtocolConformanceRef conformance; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 247f75679588c..59730f407de9d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -4106,7 +4106,7 @@ findGenericParameterReferences(CanGenericSignature genericSig, // If the type parameter is beyond the domain of the existential generic // signature, ignore it. - if (!genericSig->isValidTypeInContext(type)) { + if (!genericSig->isValidTypeParameter(type)) { return GenericParameterReferenceInfo(); } diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 57d4bb6a14428..98ec05c3a7b11 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -357,7 +357,7 @@ LayoutConstraint GenericSignatureImpl::getLayoutConstraint(Type type) const { return getRequirementMachine()->getLayoutConstraint(type); } -bool GenericSignatureImpl::areSameTypeParameterInContext(Type type1, +bool GenericSignatureImpl::areReducedTypeParametersEqual(Type type1, Type type2) const { assert(type1->isTypeParameter()); assert(type2->isTypeParameter()); @@ -365,7 +365,7 @@ bool GenericSignatureImpl::areSameTypeParameterInContext(Type type1, if (type1.getPointer() == type2.getPointer()) return true; - return getRequirementMachine()->areSameTypeParameterInContext(type1, type2); + return getRequirementMachine()->areReducedTypeParametersEqual(type1, type2); } bool GenericSignatureImpl::isRequirementSatisfied( @@ -431,43 +431,40 @@ SmallVector GenericSignatureImpl::requirementsNotSatisfiedBy( return result; } -bool GenericSignatureImpl::isCanonicalTypeInContext(Type type) const { - // If the type isn't independently canonical, it's certainly not canonical - // in this context. +bool GenericSignatureImpl::isReducedType(Type type) const { + // If the type isn't canonical, it's not reduced. if (!type->isCanonical()) return false; - // All the contextual canonicality rules apply to type parameters, so if the - // type doesn't involve any type parameters, it's already canonical. + // A fully concrete canonical type is reduced. if (!type->hasTypeParameter()) return true; - return getRequirementMachine()->isCanonicalTypeInContext(type); + return getRequirementMachine()->isReducedType(type); } -CanType GenericSignature::getCanonicalTypeInContext(Type type) const { +CanType GenericSignature::getReducedType(Type type) const { // The null generic signature has no requirements so cannot influence the // structure of the can type computed here. if (isNull()) { return type->getCanonicalType(); } - return getPointer()->getCanonicalTypeInContext(type); + return getPointer()->getReducedType(type); } -CanType GenericSignatureImpl::getCanonicalTypeInContext(Type type) const { +CanType GenericSignatureImpl::getReducedType(Type type) const { type = type->getCanonicalType(); - // All the contextual canonicality rules apply to type parameters, so if the - // type doesn't involve any type parameters, it's already canonical. + // A fully concrete type is already reduced. if (!type->hasTypeParameter()) return CanType(type); - return getRequirementMachine()->getCanonicalTypeInContext( + return getRequirementMachine()->getReducedType( type, { })->getCanonicalType(); } -bool GenericSignatureImpl::isValidTypeInContext(Type type) const { - return getRequirementMachine()->isValidTypeInContext(type); +bool GenericSignatureImpl::isValidTypeParameter(Type type) const { + return getRequirementMachine()->isValidTypeParameter(type); } ArrayRef> @@ -850,8 +847,8 @@ void GenericSignature::verify(ArrayRef reqts) const { abort(); } - if (!canSig->isCanonicalTypeInContext(reqt.getFirstType())) { - llvm::errs() << "Left-hand side is not canonical: "; + if (!canSig->isReducedType(reqt.getFirstType())) { + llvm::errs() << "Left-hand side is not reduced: "; reqt.dump(llvm::errs()); llvm::errs() << "\n"; abort(); @@ -861,8 +858,8 @@ void GenericSignature::verify(ArrayRef reqts) const { // Check canonicalization of requirement itself. switch (reqt.getKind()) { case RequirementKind::Superclass: - if (!canSig->isCanonicalTypeInContext(reqt.getSecondType())) { - llvm::errs() << "Right-hand side is not canonical: "; + if (!canSig->isReducedType(reqt.getSecondType())) { + llvm::errs() << "Right-hand side is not reduced: "; reqt.dump(llvm::errs()); llvm::errs() << "\n"; abort(); @@ -873,9 +870,9 @@ void GenericSignature::verify(ArrayRef reqts) const { break; case RequirementKind::SameType: { - auto hasCanonicalOrConcreteParent = [&](Type type) { + auto hasReducedOrConcreteParent = [&](Type type) { if (auto *dmt = type->getAs()) { - return (canSig->isCanonicalTypeInContext(dmt->getBase()) || + return (canSig->isReducedType(dmt->getBase()) || canSig->isConcreteType(dmt->getBase())); } return type->is(); @@ -884,19 +881,19 @@ void GenericSignature::verify(ArrayRef reqts) const { auto firstType = reqt.getFirstType(); auto secondType = reqt.getSecondType(); - auto canType = canSig->getCanonicalTypeInContext(firstType); + auto canType = canSig->getReducedType(firstType); auto &component = sameTypeComponents[canType]; - if (!hasCanonicalOrConcreteParent(firstType)) { - llvm::errs() << "Left hand side does not have a canonical parent: "; + if (!hasReducedOrConcreteParent(firstType)) { + llvm::errs() << "Left hand side does not have a reduced parent: "; reqt.dump(llvm::errs()); llvm::errs() << "\n"; abort(); } if (reqt.getSecondType()->isTypeParameter()) { - if (!hasCanonicalOrConcreteParent(secondType)) { - llvm::errs() << "Right hand side does not have a canonical parent: "; + if (!hasReducedOrConcreteParent(secondType)) { + llvm::errs() << "Right hand side does not have a reduced parent: "; reqt.dump(llvm::errs()); llvm::errs() << "\n"; abort(); @@ -920,8 +917,8 @@ void GenericSignature::verify(ArrayRef reqts) const { component.push_back(secondType); } else { - if (!canSig->isCanonicalTypeInContext(secondType)) { - llvm::errs() << "Right hand side is not canonical: "; + if (!canSig->isReducedType(secondType)) { + llvm::errs() << "Right hand side is not reduced: "; reqt.dump(llvm::errs()); llvm::errs() << "\n"; abort(); @@ -1004,9 +1001,9 @@ void GenericSignature::verify(ArrayRef reqts) const { // Check same-type components for consistency. for (const auto &pair : sameTypeComponents) { if (pair.second.front()->isTypeParameter() && - !canSig->isCanonicalTypeInContext(pair.second.front())) { + !canSig->isReducedType(pair.second.front())) { llvm::errs() << "Abstract same-type requirement involving concrete types\n"; - llvm::errs() << "Canonical type: " << pair.first << "\n"; + llvm::errs() << "Reduced type: " << pair.first << "\n"; llvm::errs() << "Left hand side of first requirement: " << pair.second.front() << "\n"; abort(); diff --git a/lib/AST/RequirementMachine/GenericSignatureQueries.cpp b/lib/AST/RequirementMachine/GenericSignatureQueries.cpp index 1458c1de29143..dd587aa9e5753 100644 --- a/lib/AST/RequirementMachine/GenericSignatureQueries.cpp +++ b/lib/AST/RequirementMachine/GenericSignatureQueries.cpp @@ -20,12 +20,12 @@ // Each query is generally implemented in the same manner: // // - First, convert the subject type parameter into a Term. -// - Simplify the Term to obtain a canonical Term. +// - Simplify the Term to obtain a reduced Term. // - Perform a property map lookup on the Term. // - Return the appropriate piece of information from the property map. // -// A few are slightly different; for example, getCanonicalTypeInContext() takes -// an arbitrary type, not just a type parameter, and recursively transforms the +// A few are slightly different; for example, getReducedType() takes an +// arbitrary type, not just a type parameter, and recursively transfozms the // type parameters it contains, if any. // // Also, getConformanceAccessPath() is another one-off operation. @@ -214,7 +214,7 @@ getConcreteType(Type depType, return props->getConcreteType(genericParams, term, Map); } -bool RequirementMachine::areSameTypeParameterInContext(Type depType1, +bool RequirementMachine::areReducedTypeParametersEqual(Type depType1, Type depType2) const { auto term1 = Context.getMutableTermForType(depType1->getCanonicalType(), /*proto=*/nullptr); @@ -282,11 +282,10 @@ RequirementMachine::getLongestValidPrefix(const MutableTerm &term) const { /// type parameter. /// /// Returns true if all structural components that are type parameters are -/// in their canonical form, and are not concrete (in which case they're -/// not considered canonical, since they can be replaced with their -/// concrete type). -bool RequirementMachine::isCanonicalTypeInContext(Type type) const { - // Look for non-canonical type parameters. +/// reduced, and in particular not concrete (in which case they're not +/// considered reduced, since they can be replaced with their concrete type). +bool RequirementMachine::isReducedType(Type type) const { + // Look for non-reduced type parameters. class Walker : public TypeWalker { const RequirementMachine &Self; @@ -315,7 +314,7 @@ bool RequirementMachine::isCanonicalTypeInContext(Type type) const { if (props && props->isConcreteType()) return Action::Stop; - // The parent of a canonical type parameter might be non-canonical + // The parent of a reduced type parameter might be non-reduced // because it is concrete. return Action::SkipChildren; } @@ -343,11 +342,11 @@ static Type substPrefixType(Type type, unsigned suffixLength, Type prefixType, /// type parameter. /// /// Replaces all structural components that are type parameters with their -/// most canonical form, which is either a (possibly different) -/// type parameter, or a concrete type, in which case we recursively -/// simplify any type parameters appearing in structural positions of -/// that concrete type as well, and so on. -Type RequirementMachine::getCanonicalTypeInContext( +/// reduced form, which is either a (possibly different) type parameter, +/// or a concrete type, in which case we recursively reduce any type +/// parameters appearing in structural positions of that concrete type +/// as well, and so on. +Type RequirementMachine::getReducedType( Type type, TypeArrayView genericParams) const { @@ -364,21 +363,21 @@ Type RequirementMachine::getCanonicalTypeInContext( System.simplify(term); // We need to handle "purely concrete" member types, eg if I have a - // signature , and we're asked to canonicalize the + // signature , and we're asked to reduce the // type T.[P:A] where Foo : A. // // This comes up because we can derive the signature // from a generic signature like ; adding the // concrete requirement 'T == Foo' renders 'T : P' redundant. We then // want to take interface types written against the original signature - // and canonicalize them with respect to the derived signature. + // and reduce them with respect to the derived signature. // // The problem is that T.[P:A] is not a valid term in the rewrite system // for , since we do not have the requirement T : P. // // A more principled solution would build a substitution map when // building a derived generic signature that adds new requirements; - // interface types would first be substituted before being canonicalized + // interface types would first be substituted before being reduced // in the new signature. // // For now, we handle this with a two-step process; we split a term up @@ -406,7 +405,7 @@ Type RequirementMachine::getCanonicalTypeInContext( return concreteType; // FIXME: Recursion guard is needed here - return getCanonicalTypeInContext(concreteType, genericParams); + return getReducedType(concreteType, genericParams); } // Skip this part if the entire input term is valid, because in that @@ -421,7 +420,7 @@ Type RequirementMachine::getCanonicalTypeInContext( return superclass; // FIXME: Recursion guard is needed here - return getCanonicalTypeInContext(superclass, genericParams); + return getReducedType(superclass, genericParams); } } @@ -438,7 +437,7 @@ Type RequirementMachine::getCanonicalTypeInContext( // If U is not concrete, we have an invalid member type of a dependent // type, which is not valid in this generic signature. Give up. if (prefixType->isTypeParameter()) { - llvm::errs() << "Invalid type parameter in getCanonicalTypeInContext()\n"; + llvm::errs() << "Invalid type parameter in getReducedType()\n"; llvm::errs() << "Original type: " << type << "\n"; llvm::errs() << "Simplified term: " << term << "\n"; llvm::errs() << "Longest valid prefix: " << prefix << "\n"; @@ -453,13 +452,13 @@ Type RequirementMachine::getCanonicalTypeInContext( prefixType, Sig); // FIXME: Recursion guard is needed here - return getCanonicalTypeInContext(substType, genericParams); + return getReducedType(substType, genericParams); }); } /// Determine if the given type parameter is valid with respect to this /// requirement machine's generic signature. -bool RequirementMachine::isValidTypeInContext(Type type) const { +bool RequirementMachine::isValidTypeParameter(Type type) const { assert(type->isTypeParameter()); auto term = Context.getMutableTermForType(type->getCanonicalType(), @@ -557,7 +556,7 @@ RequirementMachine::getConformanceAccessPath(Type type, } // We enumerate conformance access paths in shortlex order until we find the - // path whose corresponding type canonicalizes to the one we are looking for. + // path whose corresponding type reduces to the one we are looking for. while (true) { auto found = ConformanceAccessPaths.find( std::make_pair(term, protocol)); diff --git a/lib/AST/RequirementMachine/RequirementMachine.cpp b/lib/AST/RequirementMachine/RequirementMachine.cpp index c82c4ffc92228..2b71be1537fa0 100644 --- a/lib/AST/RequirementMachine/RequirementMachine.cpp +++ b/lib/AST/RequirementMachine/RequirementMachine.cpp @@ -18,7 +18,7 @@ // type parameters expressed by this set of generic requirements. These are // called "generic signature queries", and are defined as methods on the // GenericSignature class; for example, two of the more common ones are -// getCanonicalTypeInContext() and requiresProtocol(). +// getReducedType() and requiresProtocol(). // // The terms of the rewrite system describe all possible type parameters that // can be written -- the generic parameters themselves, together with all nested diff --git a/lib/AST/RequirementMachine/RequirementMachine.h b/lib/AST/RequirementMachine/RequirementMachine.h index 7dac363813a21..02037c2293c00 100644 --- a/lib/AST/RequirementMachine/RequirementMachine.h +++ b/lib/AST/RequirementMachine/RequirementMachine.h @@ -153,11 +153,11 @@ class RequirementMachine final { Type getConcreteType(Type depType, TypeArrayView genericParams, const ProtocolDecl *proto=nullptr) const; - bool areSameTypeParameterInContext(Type depType1, Type depType2) const; - bool isCanonicalTypeInContext(Type type) const; - Type getCanonicalTypeInContext(Type type, + bool areReducedTypeParametersEqual(Type depType1, Type depType2) const; + bool isReducedType(Type type) const; + Type getReducedType(Type type, TypeArrayView genericParams) const; - bool isValidTypeInContext(Type type) const; + bool isValidTypeParameter(Type type) const; ConformanceAccessPath getConformanceAccessPath(Type type, ProtocolDecl *protocol); TypeDecl *lookupNestedType(Type depType, Identifier name) const; diff --git a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp index 8c8fabedf3049..d5c518bc3b73e 100644 --- a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp +++ b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp @@ -920,14 +920,14 @@ InferredGenericSignatureRequest::evaluate( if (!allowConcreteGenericParams) { for (auto genericParam : result.getInnermostGenericParams()) { - auto canonical = result.getCanonicalTypeInContext(genericParam); + auto reduced = result.getReducedType(genericParam); - if (canonical->hasError() || canonical->isEqual(genericParam)) + if (reduced->hasError() || reduced->isEqual(genericParam)) continue; - if (canonical->isTypeParameter()) { + if (reduced->isTypeParameter()) { ctx.Diags.diagnose(loc, diag::requires_generic_params_made_equal, - genericParam, result->getSugaredType(canonical)) + genericParam, result->getSugaredType(reduced)) .warnUntilSwiftVersion(6); } else { ctx.Diags.diagnose(loc, diff --git a/lib/AST/RequirementMachine/RuleBuilder.cpp b/lib/AST/RequirementMachine/RuleBuilder.cpp index 41edacbd1d4db..dd6338528052f 100644 --- a/lib/AST/RequirementMachine/RuleBuilder.cpp +++ b/lib/AST/RequirementMachine/RuleBuilder.cpp @@ -104,7 +104,7 @@ void RuleBuilder::initWithProtocolSignatureRequirements( // If completion failed, we'll have a totally empty requirement signature, // but to maintain invariants around what constitutes a valid rewrite term - // between getTypeForTerm() and isValidTypeInContext(), we need to add rules + // between getTypeForTerm() and isValidTypeParameter(), we need to add rules // for inherited protocols. if (reqs.getErrors().contains(GenericSignatureErrorFlags::CompletionFailed)) { for (auto *inheritedProto : Context.getInheritedProtocols(proto)) { diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index a266225417523..b0e238bea1533 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -299,9 +299,9 @@ Type SubstitutionMap::lookupSubstitution(CanSubstitutableType type) const { return replacementType; } - // The generic parameter may not be canonical. Retrieve the canonical + // The generic parameter may not be reduced. Retrieve the reduced // type, which will be dependent. - CanType canonicalType = genericSig.getCanonicalTypeInContext(genericParam); + CanType canonicalType = genericSig.getReducedType(genericParam); // If nothing changed, we don't have a replacement. if (canonicalType == type) return Type(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 6cbe25c5c0aed..283fb7a65bf4e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1537,7 +1537,7 @@ getCanonicalParams(AnyFunctionType *funcType, for (auto param : origParams) { // Canonicalize the type and drop the internal label to canonicalize the // Param. - canParams.emplace_back(param.getPlainType()->getCanonicalType(genericSig), + canParams.emplace_back(param.getPlainType()->getReducedType(genericSig), param.getLabel(), param.getParameterFlags(), /*InternalLabel=*/Identifier()); } @@ -1673,7 +1673,7 @@ CanType TypeBase::computeCanonicalType() { // Transform the parameter and result types. SmallVector canParams; getCanonicalParams(funcTy, genericSig, canParams); - auto resultTy = funcTy->getResult()->getCanonicalType(genericSig); + auto resultTy = funcTy->getResult()->getReducedType(genericSig); Optional extInfo = None; if (funcTy->hasExtInfo()) @@ -1775,8 +1775,8 @@ CanType TypeBase::computeCanonicalType() { return CanonicalType = CanType(Result); } -CanType TypeBase::getCanonicalType(GenericSignature sig) { - return sig.getCanonicalTypeInContext(this); +CanType TypeBase::getReducedType(GenericSignature sig) { + return sig.getReducedType(this); } CanType TypeBase::getMinimalCanonicalType(const DeclContext *useDC) const { @@ -2555,9 +2555,9 @@ class IsBindableVisitor for (unsigned i : indices(origSubs.getReplacementTypes())) { auto origType = - origSubs.getReplacementTypes()[i]->getCanonicalType(sig); + origSubs.getReplacementTypes()[i]->getReducedType(sig); auto substType = - substSubs.getReplacementTypes()[i]->getCanonicalType(sig); + substSubs.getReplacementTypes()[i]->getReducedType(sig); auto newType = visit(origType, substType, nullptr, {}); @@ -2585,9 +2585,9 @@ class IsBindableVisitor for (unsigned i : indices(origSubs.getReplacementTypes())) { auto origType = - origSubs.getReplacementTypes()[i]->getCanonicalType(sig); + origSubs.getReplacementTypes()[i]->getReducedType(sig); auto substType = - substSubs.getReplacementTypes()[i]->getCanonicalType(sig); + substSubs.getReplacementTypes()[i]->getReducedType(sig); auto newType = visit(origType, substType, nullptr, {}); @@ -3570,7 +3570,7 @@ SequenceArchetypeType::SequenceArchetypeType( CanType OpaqueTypeArchetypeType::getCanonicalInterfaceType(Type interfaceType) { auto sig = Environment->getOpaqueTypeDecl() ->getOpaqueInterfaceGenericSignature(); - CanType canonicalType = interfaceType->getCanonicalType(sig); + CanType canonicalType = interfaceType->getReducedType(sig); return Environment->maybeApplyOpaqueTypeSubstitutions(canonicalType) ->getCanonicalType(); } @@ -4001,7 +4001,7 @@ Type ArchetypeType::getNestedTypeByName(Identifier name) { Type interfaceType = getInterfaceType(); Type memberInterfaceType = DependentMemberType::get(interfaceType, name); auto genericSig = getGenericEnvironment()->getGenericSignature(); - if (genericSig->isValidTypeInContext(memberInterfaceType)) { + if (genericSig->isValidTypeParameter(memberInterfaceType)) { return getGenericEnvironment()->getOrCreateArchetypeFromInterfaceType( memberInterfaceType); } diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp index 71e0833453915..c342f864636da 100644 --- a/lib/IRGen/GenArchetype.cpp +++ b/lib/IRGen/GenArchetype.cpp @@ -437,7 +437,7 @@ withOpaqueTypeGenericArgs(IRGenFunction &IGF, opaqueDecl->getGenericSignature().getCanonicalSignature(), [&](GenericRequirement reqt) { auto ty = reqt.TypeParameter.subst(archetype->getSubstitutions()) - ->getCanonicalType(opaqueDecl->getGenericSignature()); + ->getReducedType(opaqueDecl->getGenericSignature()); if (reqt.Protocol) { auto ref = ProtocolConformanceRef(reqt.Protocol) diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 90c8d79ae77a9..be40fe65675fe 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -1402,7 +1402,7 @@ void IRGenModule::emitSILProperty(SILProperty *prop) { prop->getDecl()->getInnermostDeclContext() ->getInnermostTypeContext() ->getSelfInterfaceType() - ->getCanonicalType(genericSig), + ->getReducedType(genericSig), {}, hasSubscriptIndices); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 24e377df12b86..1ceb01f63b9a3 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -2189,7 +2189,7 @@ namespace { auto *genericParam = O->getOpaqueGenericParams()[opaqueParamIdx]; auto underlyingType = - Type(genericParam).subst(*unique)->getCanonicalType(sig); + Type(genericParam).subst(*unique)->getReducedType(sig); return IGM .getTypeRef(underlyingType, contextSig, MangledTypeRefRole::Metadata) @@ -2450,7 +2450,7 @@ namespace { auto type = Type(O->getOpaqueGenericParams()[OpaqueParamIndex]) .subst(substitutions) - ->getCanonicalType(O->getOpaqueInterfaceGenericSignature()); + ->getReducedType(O->getOpaqueInterfaceGenericSignature()); type = genericEnv ? genericEnv->mapTypeIntoContext(type)->getCanonicalType() diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index f83fd2aae53ab..788dcfda0d545 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -3310,7 +3310,7 @@ GenericTypeRequirements::GenericTypeRequirements(IRGenModule &IGM, // Figure out what we're actually still required to pass PolymorphicConvention convention(IGM, fnType); convention.enumerateUnfulfilledRequirements([&](GenericRequirement reqt) { - assert(generics->isCanonicalTypeInContext(reqt.TypeParameter)); + assert(generics->isReducedType(reqt.TypeParameter)); Requirements.push_back(reqt); }); diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index dd26d8c5ee51d..55daa5564e0eb 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -357,7 +357,7 @@ IRGenModule::getTypeRef(CanType type, CanGenericSignature sig, std::pair IRGenModule::getTypeRef(Type type, GenericSignature genericSig, MangledTypeRefRole role) { - return getTypeRef(type->getCanonicalType(genericSig), + return getTypeRef(type->getReducedType(genericSig), genericSig.getCanonicalSignature(), role); } @@ -554,7 +554,7 @@ class ReflectionMetadataBuilder { void addTypeRef(Type type, GenericSignature genericSig, MangledTypeRefRole role = MangledTypeRefRole::Reflection) { - addTypeRef(type->getCanonicalType(genericSig), + addTypeRef(type->getReducedType(genericSig), genericSig.getCanonicalSignature(), role); } diff --git a/lib/SIL/IR/AbstractionPattern.cpp b/lib/SIL/IR/AbstractionPattern.cpp index cc65465cfb238..826802e7dff97 100644 --- a/lib/SIL/IR/AbstractionPattern.cpp +++ b/lib/SIL/IR/AbstractionPattern.cpp @@ -50,7 +50,7 @@ TypeConverter::getAbstractionPattern(AbstractStorageDecl *decl, AbstractionPattern TypeConverter::getAbstractionPattern(SubscriptDecl *decl, bool isNonObjC) { auto sig = decl->getGenericSignatureOfContext().getCanonicalSignature(); - auto type = sig.getCanonicalTypeInContext(decl->getElementInterfaceType()); + auto type = sig.getReducedType(decl->getElementInterfaceType()); return AbstractionPattern(sig, type); } @@ -79,7 +79,7 @@ TypeConverter::getAbstractionPattern(VarDecl *var, bool isNonObjC) { auto sig = var->getDeclContext() ->getGenericSignatureOfContext() .getCanonicalSignature(); - auto swiftType = sig.getCanonicalTypeInContext(var->getInterfaceType()); + auto swiftType = sig.getReducedType(var->getInterfaceType()); if (isNonObjC) return AbstractionPattern(sig, swiftType); @@ -111,7 +111,7 @@ AbstractionPattern TypeConverter::getAbstractionPattern(EnumElementDecl *decl) { auto sig = decl->getParentEnum() ->getGenericSignatureOfContext() .getCanonicalSignature(); - auto type = sig.getCanonicalTypeInContext(decl->getArgumentInterfaceType()); + auto type = sig.getReducedType(decl->getArgumentInterfaceType()); return AbstractionPattern(sig, type); } @@ -1231,7 +1231,7 @@ const { case Kind::Discard: auto memberTy = getType()->getTypeOfMember(member->getModuleContext(), member, origMemberInterfaceType) - ->getCanonicalType(getGenericSignature()); + ->getReducedType(getGenericSignature()); return AbstractionPattern(getGenericSignature(), memberTy); } @@ -1253,7 +1253,7 @@ AbstractionPattern AbstractionPattern::getAutoDiffDerivativeFunctionType( assert(derivativeFnTy); return AbstractionPattern( getGenericSignature(), - derivativeFnTy->getCanonicalType(getGenericSignature())); + derivativeFnTy->getReducedType(getGenericSignature())); } case Kind::Opaque: return getOpaqueDerivativeFunction(); @@ -1882,10 +1882,10 @@ const { auto yieldType = visitor.substYieldType; if (yieldType) - yieldType = yieldType->getCanonicalType(substSig); + yieldType = yieldType->getReducedType(substSig); return std::make_tuple( - AbstractionPattern(substSig, substTy->getCanonicalType(substSig)), + AbstractionPattern(substSig, substTy->getReducedType(substSig)), subMap, yieldType ? AbstractionPattern(substSig, yieldType) diff --git a/lib/SIL/IR/SIL.cpp b/lib/SIL/IR/SIL.cpp index 11f189b6f28ee..bb7815b12cbbe 100644 --- a/lib/SIL/IR/SIL.cpp +++ b/lib/SIL/IR/SIL.cpp @@ -353,7 +353,7 @@ bool AbstractStorageDecl::exportsPropertyDescriptor() const { return false; auto indexTy = index->getInterfaceType() - ->getCanonicalType(sub->getGenericSignatureOfContext()); + ->getReducedType(sub->getGenericSignatureOfContext()); // TODO: Handle reabstraction and tuple explosion in thunk generation. // This wasn't previously a concern because anything that was Hashable diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index bceac099ce847..38412802f9c9d 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -485,7 +485,7 @@ static CanSILFunctionType getAutoDiffDifferentialType( auto sig = buildDifferentiableGenericSignature( originalFnTy->getSubstGenericSignature(), tanType, origTypeOfAbstraction); - tanType = tanType->getCanonicalType(sig); + tanType = tanType->getReducedType(sig); AbstractionPattern pattern(sig, tanType); auto &tl = TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); @@ -513,7 +513,7 @@ static CanSILFunctionType getAutoDiffDifferentialType( auto sig = buildDifferentiableGenericSignature( originalFnTy->getSubstGenericSignature(), tanType, origTypeOfAbstraction); - tanType = tanType->getCanonicalType(sig); + tanType = tanType->getReducedType(sig); AbstractionPattern pattern(sig, tanType); auto &tl = TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); @@ -633,7 +633,7 @@ static CanSILFunctionType getAutoDiffPullbackType( auto sig = buildDifferentiableGenericSignature( originalFnTy->getSubstGenericSignature(), tanType, origTypeOfAbstraction); - tanType = tanType->getCanonicalType(sig); + tanType = tanType->getReducedType(sig); AbstractionPattern pattern(sig, tanType); auto &tl = TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); @@ -664,7 +664,7 @@ static CanSILFunctionType getAutoDiffPullbackType( auto sig = buildDifferentiableGenericSignature( originalFnTy->getSubstGenericSignature(), tanType, origTypeOfAbstraction); - tanType = tanType->getCanonicalType(sig); + tanType = tanType->getReducedType(sig); AbstractionPattern pattern(sig, tanType); auto &tl = TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); @@ -801,7 +801,7 @@ static SILFunctionType *getConstrainedAutoDiffOriginalFunctionType( newParameters.reserve(original->getNumParameters()); for (auto ¶m : original->getParameters()) { newParameters.push_back( - param.getWithInterfaceType(param.getInterfaceType()->getCanonicalType( + param.getWithInterfaceType(param.getInterfaceType()->getReducedType( constrainedInvocationGenSig))); } @@ -809,7 +809,7 @@ static SILFunctionType *getConstrainedAutoDiffOriginalFunctionType( newResults.reserve(original->getNumResults()); for (auto &result : original->getResults()) { newResults.push_back( - result.getWithInterfaceType(result.getInterfaceType()->getCanonicalType( + result.getWithInterfaceType(result.getInterfaceType()->getReducedType( constrainedInvocationGenSig))); } return SILFunctionType::get( @@ -1680,7 +1680,7 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, auto selfMetatype = MetatypeType::get(dynamicSelfInterfaceType, MetatypeRepresentation::Thick); - auto canSelfMetatype = selfMetatype->getCanonicalType(origGenericSig); + auto canSelfMetatype = selfMetatype->getReducedType(origGenericSig); SILParameterInfo param(canSelfMetatype, convention); inputs.push_back(param); @@ -1690,7 +1690,7 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, if (capture.isOpaqueValue()) { OpaqueValueExpr *opaqueValue = capture.getOpaqueValue(); auto canType = opaqueValue->getType()->mapTypeOutOfContext() - ->getCanonicalType(origGenericSig); + ->getReducedType(origGenericSig); auto &loweredTL = TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, expansion); @@ -1710,7 +1710,7 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, auto *VD = capture.getDecl(); auto type = VD->getInterfaceType(); - auto canType = type->getCanonicalType(origGenericSig); + auto canType = type->getReducedType(origGenericSig); auto &loweredTL = TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, @@ -1962,7 +1962,7 @@ static CanSILFunctionType getSILFunctionType( valueType = valueType.subst(*reqtSubs); } - coroutineSubstYieldType = valueType->getCanonicalType(genericSig); + coroutineSubstYieldType = valueType->getReducedType(genericSig); } bool shouldBuildSubstFunctionType = [&]{ @@ -2645,7 +2645,7 @@ CanSILFunctionType swift::buildSILFunctionThunkType( } auto mapTypeOutOfContext = [&](CanType type) -> CanType { - return type->mapTypeOutOfContext()->getCanonicalType(genericSig); + return type->mapTypeOutOfContext()->getCanonicalType(); }; // Map the parameter and expected types out of context to get the interface diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index bc4e7256d8015..7c4e20dffc6fc 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -2055,7 +2055,7 @@ namespace { // would, we use the substituted field type in order to accurately // preserve the properties of the aggregate. auto sig = field->getDeclContext()->getGenericSignatureOfContext(); - auto interfaceTy = field->getInterfaceType()->getCanonicalType(sig); + auto interfaceTy = field->getInterfaceType()->getReducedType(sig); auto origFieldType = origType.unsafeGetSubstFieldType(field, interfaceTy); @@ -2116,7 +2116,7 @@ namespace { auto origEltType = origType.unsafeGetSubstFieldType(elt, elt->getArgumentInterfaceType() - ->getCanonicalType(D->getGenericSignature())); + ->getReducedType(D->getGenericSignature())); properties.addSubobject(classifyType(origEltType, substEltType, TC, Expansion)); } @@ -2734,7 +2734,7 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( // The result type might be written in terms of type parameters // that have been made fully concrete. - CanType canResultTy = resultTy->getCanonicalType( + CanType canResultTy = resultTy->getReducedType( vd->getInnermostDeclContext() ->getGenericSignatureOfContext()); @@ -2812,7 +2812,7 @@ static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd, bool isDeallocating, bool isForeign) { auto classType = dd->getDeclContext()->getDeclaredInterfaceType() - ->getCanonicalType(dd->getGenericSignatureOfContext()); + ->getReducedType(dd->getGenericSignatureOfContext()); assert((!isForeign || isDeallocating) && "There are no foreign destroying destructors"); @@ -2848,7 +2848,7 @@ static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd, bool isObjC, bool isDestroyer) { auto classType = cd->getDeclaredInterfaceType() - ->getCanonicalType(cd->getGenericSignatureOfContext()); + ->getReducedType(cd->getGenericSignatureOfContext()); auto resultType = (isDestroyer ? TupleType::getEmpty(cd->getASTContext()) @@ -3778,12 +3778,7 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured, /*captures generics*/ false); // Instantiate the layout with identity substitutions. - auto subMap = SubstitutionMap::get( - signature, - [&](SubstitutableType *type) -> Type { - return signature.getCanonicalTypeInContext(type); - }, - MakeAbstractConformanceForGenericType()); + auto subMap = signature->getIdentitySubstitutionMap(); auto boxTy = SILBoxType::get(C, layout, subMap); #ifndef NDEBUG @@ -3817,7 +3812,7 @@ TypeConverter::getContextBoxTypeForCapture(ValueDecl *captured, ->getGenericSignatureOfContext(); loweredInterfaceType = loweredInterfaceType->mapTypeOutOfContext() - ->getCanonicalType(homeSig); + ->getReducedType(homeSig); } auto boxType = getInterfaceBoxTypeForCapture(captured, diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 47ec7edf491b1..bdc1ae2aadfce 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -5945,8 +5945,8 @@ void SILProperty::verify(const SILModule &M) const { // TODO: base type for global/static descriptors auto sig = dc->getGenericSignatureOfContext(); auto baseTy = dc->getInnermostTypeContext()->getSelfInterfaceType() - ->getCanonicalType(sig); - auto leafTy = decl->getValueInterfaceType()->getCanonicalType(sig); + ->getReducedType(sig); + auto leafTy = decl->getValueInterfaceType()->getReducedType(sig); SubstitutionMap subs; if (sig) { auto env = dc->getGenericEnvironmentOfContext(); diff --git a/lib/SILGen/ResultPlan.cpp b/lib/SILGen/ResultPlan.cpp index 9621f035fe8be..11f8d50867b01 100644 --- a/lib/SILGen/ResultPlan.cpp +++ b/lib/SILGen/ResultPlan.cpp @@ -179,7 +179,7 @@ class IndirectOpenedSelfResultPlan final : public ResultPlan { layoutSubs.getGenericSignature().getCanonicalSignature(); auto boxLayout = SILLayout::get(SGF.getASTContext(), layoutSig, - SILField(layoutTy->getCanonicalType(layoutSig), true), + SILField(layoutTy->getReducedType(layoutSig), true), /*captures generics*/ false); resultBox = SGF.B.createAllocBox(loc, @@ -576,8 +576,8 @@ class ForeignAsyncInitializationPlan final : public ResultPlan { SILFunction *impl = SGF.SGM.getOrCreateForeignAsyncCompletionHandlerImplFunction( cast( - impFnTy->mapTypeOutOfContext()->getCanonicalType(sig)), - continuationTy->mapTypeOutOfContext()->getCanonicalType(sig), + impFnTy->mapTypeOutOfContext()->getReducedType(sig)), + continuationTy->mapTypeOutOfContext()->getReducedType(sig), origFormalType, sig, *calleeTypeInfo.foreign.async, calleeTypeInfo.foreign.error); auto impRef = SGF.B.createFunctionRef(loc, impl); @@ -660,7 +660,7 @@ class ForeignAsyncInitializationPlan final : public ResultPlan { auto sig = env ? env->getGenericSignature().getCanonicalSignature() : CanGenericSignature(); auto mappedContinuationTy = - continuationBGT->mapTypeOutOfContext()->getCanonicalType(sig); + continuationBGT->mapTypeOutOfContext()->getReducedType(sig); auto resumeType = cast(mappedContinuationTy).getGenericArgs()[0]; auto continuationTy = continuationBGT->getCanonicalType(); diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 38a16aa4b872e..b5c3a8ec9c9ce 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1902,8 +1902,8 @@ void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) { assert(!decl->isStatic()); baseTy = decl->getDeclContext()->getSelfInterfaceType() - ->getCanonicalType(decl->getInnermostDeclContext() - ->getGenericSignatureOfContext()); + ->getReducedType(decl->getInnermostDeclContext() + ->getGenericSignatureOfContext()); } else { // TODO: Global variables should eventually be referenceable as // key paths from (), viz. baseTy = TupleType::getEmpty(getASTContext()); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 4c7817e52b285..63b60b98bd233 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -6164,7 +6164,7 @@ ManagedValue SILGenFunction::emitReadAsyncLetBinding(SILLocation loc, // Load and reabstract the value if needed. auto genericSig = F.getLoweredFunctionType()->getInvocationGenericSignature(); - auto substVarTy = var->getType()->getCanonicalType(genericSig); + auto substVarTy = var->getType()->getReducedType(genericSig); auto substAbstraction = AbstractionPattern(genericSig, substVarTy); return emitLoad(loc, visitor.varAddr, substAbstraction, substVarTy, getTypeLowering(substAbstraction, substVarTy), diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index af37e99a81fa7..5e98c7437631b 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -3264,7 +3264,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, = GenericEnvironment::mapConformanceRefIntoContext(genericEnv, formalTy, hashable); - auto formalCanTy = formalTy->getCanonicalType(genericSig); + auto formalCanTy = formalTy->getReducedType(genericSig); // Get the Equatable conformance from the Hashable conformance. auto equatable = hashable.getAssociatedConformance( @@ -3690,8 +3690,7 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc, ->getTypeOfMember(SwiftModule, var) ->getReferenceStorageReferent() ->mapTypeOutOfContext() - ->getCanonicalType( - genericEnv ? genericEnv->getGenericSignature() : nullptr); + ->getCanonicalType(); // The component type for an @objc optional requirement needs to be // wrapped in an optional. diff --git a/lib/SILGen/SILGenLazyConformance.cpp b/lib/SILGen/SILGenLazyConformance.cpp index 31ead79fed57d..949bf54a75149 100644 --- a/lib/SILGen/SILGenLazyConformance.cpp +++ b/lib/SILGen/SILGenLazyConformance.cpp @@ -334,7 +334,7 @@ void SILGenModule::emitLazyConformancesForType(NominalTypeDecl *NTD) { for (auto *EED : ED->getAllElements()) { if (EED->hasAssociatedValues()) { useConformancesFromType(EED->getArgumentInterfaceType() - ->getCanonicalType(genericSig)); + ->getReducedType(genericSig)); } } } @@ -342,13 +342,13 @@ void SILGenModule::emitLazyConformancesForType(NominalTypeDecl *NTD) { if (isa(NTD) || isa(NTD)) { for (auto *VD : NTD->getStoredProperties()) { useConformancesFromType(VD->getValueInterfaceType() - ->getCanonicalType(genericSig)); + ->getReducedType(genericSig)); } } if (auto *CD = dyn_cast(NTD)) if (auto superclass = CD->getSuperclass()) - useConformancesFromType(superclass->getCanonicalType(genericSig)); + useConformancesFromType(superclass->getReducedType(genericSig)); if (auto *PD = dyn_cast(NTD)) { for (auto reqt : PD->getRequirementSignature().getRequirements()) { diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index 5cf19d7f1e321..3a5e75a963598 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -458,7 +458,7 @@ static void emitCaptureArguments(SILGenFunction &SGF, // Local function to get the captured variable type within the capturing // context. auto getVarTypeInCaptureContext = [&]() -> Type { - auto interfaceType = VD->getInterfaceType()->getCanonicalType( + auto interfaceType = VD->getInterfaceType()->getReducedType( origGenericSig); return SGF.F.mapTypeIntoContext(interfaceType); }; @@ -1014,7 +1014,7 @@ uint16_t SILGenFunction::emitBasicProlog(ParameterList *paramList, Optional origClosureType) { // Create the indirect result parameters. auto genericSig = DC->getGenericSignatureOfContext(); - resultType = resultType->getCanonicalType(genericSig); + resultType = resultType->getReducedType(genericSig); AbstractionPattern origResultType = origClosureType ? origClosureType->getFunctionResultType() diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 3d5955b751cce..21015cc8106f0 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -732,7 +732,7 @@ SILFunction *SILGenModule::emitProtocolWitness( // The type of the witness thunk. auto reqtSubstTy = cast( reqtOrigTy->substGenericArgs(reqtSubMap) - ->getCanonicalType(genericSig)); + ->getReducedType(genericSig)); // Generic signatures where all parameters are concrete are lowered away // at the SILFunctionType level. diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index 0ac7cbfa9edca..387e08018e8ee 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -145,7 +145,7 @@ class JVPCloner::Implementation final SILType getLoweredType(Type type) { auto jvpGenSig = jvp->getLoweredFunctionType()->getSubstGenericSignature(); Lowering::AbstractionPattern pattern(jvpGenSig, - type->getCanonicalType(jvpGenSig)); + type->getReducedType(jvpGenSig)); return jvp->getLoweredType(pattern, type); } @@ -352,7 +352,7 @@ class JVPCloner::Implementation final /// Find the tangent space of a given canonical type. Optional getTangentSpace(CanType type) { // Use witness generic signature to remap types. - type = witness->getDerivativeGenericSignature().getCanonicalTypeInContext( + type = witness->getDerivativeGenericSignature().getReducedType( type); return type->getAutoDiffTangentSpace( LookUpConformanceInModule(getModule().getSwiftModule())); @@ -1627,12 +1627,12 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { // Handle formal original result. auto origResult = origTy->getResults()[resultIndex]; origResult = origResult.getWithInterfaceType( - origResult.getInterfaceType()->getCanonicalType(witnessCanGenSig)); + origResult.getInterfaceType()->getReducedType(witnessCanGenSig)); dfResults.push_back( SILResultInfo(origResult.getInterfaceType() ->getAutoDiffTangentSpace(lookupConformance) ->getType() - ->getCanonicalType(witnessCanGenSig), + ->getReducedType(witnessCanGenSig), origResult.getConvention())); } else { // Handle original `inout` parameter. @@ -1659,12 +1659,12 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { for (auto i : config.parameterIndices->getIndices()) { auto origParam = origParams[i]; origParam = origParam.getWithInterfaceType( - origParam.getInterfaceType()->getCanonicalType(witnessCanGenSig)); + origParam.getInterfaceType()->getReducedType(witnessCanGenSig)); dfParams.push_back( SILParameterInfo(origParam.getInterfaceType() ->getAutoDiffTangentSpace(lookupConformance) ->getType() - ->getCanonicalType(witnessCanGenSig), + ->getReducedType(witnessCanGenSig), origParam.getConvention())); } @@ -1673,7 +1673,7 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto *origEntry = original->getEntryBlock(); auto *dfStruct = linearMapInfo->getLinearMapStruct(origEntry); auto dfStructType = - dfStruct->getDeclaredInterfaceType()->getCanonicalType(witnessCanGenSig); + dfStruct->getDeclaredInterfaceType()->getReducedType(witnessCanGenSig); dfParams.push_back({dfStructType, ParameterConvention::Direct_Owned}); Mangle::DifferentiationMangler mangler; diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index b97d2a85effa1..0f5d901321552 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -194,7 +194,7 @@ class PullbackCloner::Implementation final auto pbGenSig = getPullback().getLoweredFunctionType()->getSubstGenericSignature(); Lowering::AbstractionPattern pattern(pbGenSig, - type->getCanonicalType(pbGenSig)); + type->getReducedType(pbGenSig)); return getPullback().getTypeLowering(pattern, type); } @@ -202,7 +202,7 @@ class PullbackCloner::Implementation final SILType remapType(SILType ty) { if (ty.hasArchetype()) ty = ty.mapTypeOutOfContext(); - auto remappedType = ty.getASTType()->getCanonicalType( + auto remappedType = ty.getASTType()->getReducedType( getPullback().getLoweredFunctionType()->getSubstGenericSignature()); auto remappedSILType = SILType::getPrimitiveType(remappedType, ty.getCategory()); @@ -212,7 +212,7 @@ class PullbackCloner::Implementation final Optional getTangentSpace(CanType type) { // Use witness generic signature to remap types. type = - getWitness()->getDerivativeGenericSignature().getCanonicalTypeInContext( + getWitness()->getDerivativeGenericSignature().getReducedType( type); return type->getAutoDiffTangentSpace( LookUpConformanceInModule(getModule().getSwiftModule())); diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index fea64e520a8d7..b11b61ea47ff0 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -137,7 +137,7 @@ class VJPCloner::Implementation final SILType getLoweredType(Type type) { auto vjpGenSig = vjp->getLoweredFunctionType()->getSubstGenericSignature(); Lowering::AbstractionPattern pattern(vjpGenSig, - type->getCanonicalType(vjpGenSig)); + type->getReducedType(vjpGenSig)); return vjp->getLoweredType(pattern, type); } @@ -809,7 +809,7 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { // Given a type, returns its formal SIL parameter info. auto getTangentParameterInfoForOriginalResult = [&](CanType tanType, ResultConvention origResConv) -> SILParameterInfo { - tanType = tanType->getCanonicalType(witnessCanGenSig); + tanType = tanType->getReducedType(witnessCanGenSig); Lowering::AbstractionPattern pattern(witnessCanGenSig, tanType); auto &tl = context.getTypeConverter().getTypeLowering( pattern, tanType, TypeExpansionContext::minimal()); @@ -836,7 +836,7 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { // Given a type, returns its formal SIL result info. auto getTangentResultInfoForOriginalParameter = [&](CanType tanType, ParameterConvention origParamConv) -> SILResultInfo { - tanType = tanType->getCanonicalType(witnessCanGenSig); + tanType = tanType->getReducedType(witnessCanGenSig); Lowering::AbstractionPattern pattern(witnessCanGenSig, tanType); auto &tl = context.getTypeConverter().getTypeLowering( pattern, tanType, TypeExpansionContext::minimal()); @@ -886,12 +886,12 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { if (resultIndex < origTy->getNumResults()) { auto origResult = origTy->getResults()[resultIndex]; origResult = origResult.getWithInterfaceType( - origResult.getInterfaceType()->getCanonicalType(witnessCanGenSig)); + origResult.getInterfaceType()->getReducedType(witnessCanGenSig)); pbParams.push_back(getTangentParameterInfoForOriginalResult( origResult.getInterfaceType() ->getAutoDiffTangentSpace(lookupConformance) ->getType() - ->getCanonicalType(witnessCanGenSig), + ->getReducedType(witnessCanGenSig), origResult.getConvention())); continue; } @@ -911,7 +911,7 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { } auto inoutParam = origParams[paramIndex]; auto origResult = inoutParam.getWithInterfaceType( - inoutParam.getInterfaceType()->getCanonicalType(witnessCanGenSig)); + inoutParam.getInterfaceType()->getReducedType(witnessCanGenSig)); auto inoutParamTanConvention = config.isWrtParameter(paramIndex) ? inoutParam.getConvention() @@ -920,7 +920,7 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { origResult.getInterfaceType() ->getAutoDiffTangentSpace(lookupConformance) ->getType() - ->getCanonicalType(witnessCanGenSig), + ->getReducedType(witnessCanGenSig), inoutParamTanConvention); pbParams.push_back(inoutParamTanParam); } @@ -937,7 +937,7 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { auto *origExit = &*original->findReturnBB(); auto *pbStruct = pullbackInfo.getLinearMapStruct(origExit); auto pbStructType = - pbStruct->getDeclaredInterfaceType()->getCanonicalType(witnessCanGenSig); + pbStruct->getDeclaredInterfaceType()->getReducedType(witnessCanGenSig); pbParams.push_back({pbStructType, ParameterConvention::Direct_Owned}); } @@ -947,12 +947,12 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { if (origParam.isIndirectMutating()) continue; origParam = origParam.getWithInterfaceType( - origParam.getInterfaceType()->getCanonicalType(witnessCanGenSig)); + origParam.getInterfaceType()->getReducedType(witnessCanGenSig)); adjResults.push_back(getTangentResultInfoForOriginalParameter( origParam.getInterfaceType() ->getAutoDiffTangentSpace(lookupConformance) ->getType() - ->getCanonicalType(witnessCanGenSig), + ->getReducedType(witnessCanGenSig), origParam.getConvention())); } diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 54e013eee793f..04c5c9af7f988 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -345,11 +345,6 @@ ExistentialTransform::createExistentialSpecializedFunctionType() { std::move(GenericParams), std::move(Requirements)); - /// Create a lambda for GenericParams. - auto getCanonicalType = [&](Type t) -> CanType { - return t->getCanonicalType(NewGenericSig); - }; - /// Original list of parameters SmallVector params; params.append(FTy->getParameters().begin(), FTy->getParameters().end()); @@ -362,7 +357,7 @@ ExistentialTransform::createExistentialSpecializedFunctionType() { auto iter = ArgToGenericTypeMap.find(Idx); if (iter != ArgToGenericTypeMap.end()) { auto GenericParam = iter->second; - InterfaceParams.push_back(SILParameterInfo(getCanonicalType(GenericParam), + InterfaceParams.push_back(SILParameterInfo(GenericParam->getReducedType(NewGenericSig), param.getConvention())); } else { InterfaceParams.push_back(param); diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp index 0635c36a6836a..53760d54c8280 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp @@ -291,7 +291,8 @@ SILCombiner::optimizeAlignment(PointerToAddressInst *ptrAdrInst) { if (match(alignOper, m_ApplyInst(BuiltinValueKind::Alignof))) { CanType formalType = cast(alignOper)->getSubstitutions() - .getReplacementTypes()[0]->getCanonicalType(ptrAdrInst->getFunction()->getGenericSignature()); + .getReplacementTypes()[0]->getReducedType( + ptrAdrInst->getFunction()->getGenericSignature()); SILType instanceType = ptrAdrInst->getFunction()->getLoweredType( Lowering::AbstractionPattern::getOpaque(), formalType); diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index af88f3fb33f48..505cf3472ef21 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -812,7 +812,7 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF, // First substitute concrete types into the existing function type. CanSILFunctionType FnTy = - cast(CanSpecializedGenericSig.getCanonicalTypeInContext( + cast(CanSpecializedGenericSig.getReducedType( OrigF->getLoweredFunctionType() ->substGenericArgs(M, SubstMap, getResilienceExpansion()) ->getUnsubstitutedType(M))); @@ -1449,7 +1449,7 @@ void FunctionSignaturePartialSpecializer:: createGenericParamsForCalleeGenericParams() { for (auto GP : CalleeGenericSig.getGenericParams()) { auto CanTy = GP->getCanonicalType(); - auto CanTyInContext = CalleeGenericSig.getCanonicalTypeInContext(CanTy); + auto CanTyInContext = CalleeGenericSig.getReducedType(CanTy); auto Replacement = CanTyInContext.subst(CalleeInterfaceToCallerArchetypeMap); LLVM_DEBUG(llvm::dbgs() << "\n\nChecking callee generic parameter:\n"; CanTy->dump(llvm::dbgs())); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index c14711f758cf1..f7c7aa9c45a26 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1988,7 +1988,7 @@ typeEraseExistentialSelfReferences( // If the type parameter is beyond the domain of the existential generic // signature, ignore it. - if (!existentialSig->isValidTypeInContext(t)) { + if (!existentialSig->isValidTypeParameter(t)) { return Type(t); } @@ -6540,7 +6540,7 @@ static bool doesMemberHaveUnfulfillableConstraintsWithExistentialBase( return Action::SkipChildren; } - if (!Sig->isValidTypeInContext(ty)) { + if (!Sig->isValidTypeParameter(ty)) { return Action::SkipChildren; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 0f938861e4df1..bb2244bf8c566 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2517,7 +2517,7 @@ static void checkSpecializeAttrRequirements(SpecializeAttr *attr, for (auto *paramTy : specializedSig.getGenericParams()) { auto canTy = paramTy->getCanonicalType(); - if (specializedSig->isCanonicalTypeInContext(canTy) && + if (specializedSig->isReducedType(canTy) && (!specializedSig->getLayoutConstraint(canTy) || originalSig->getLayoutConstraint(canTy))) { unspecializedParams.push_back(paramTy); @@ -4547,7 +4547,7 @@ static bool checkFunctionSignature( auto xInstanceTy = x.getOldType()->getMetatypeInstanceType(); auto yInstanceTy = y.getOldType()->getMetatypeInstanceType(); return xInstanceTy->isEqual( - requiredGenSig.getCanonicalTypeInContext(yInstanceTy)); + requiredGenSig.getReducedType(yInstanceTy)); })) return false; @@ -4555,7 +4555,7 @@ static bool checkFunctionSignature( // match exactly. auto requiredResultFnTy = dyn_cast(required.getResult()); auto candidateResultTy = - requiredGenSig.getCanonicalTypeInContext(candidateFnTy.getResult()); + requiredGenSig.getReducedType(candidateFnTy.getResult()); if (!requiredResultFnTy) { auto requiredResultTupleTy = dyn_cast(required.getResult()); auto candidateResultTupleTy = dyn_cast(candidateResultTy); diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index cc4e7d345830c..bc497b8abf133 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -151,7 +151,7 @@ bool swift::isOverrideBasedOnType(const ValueDecl *decl, Type declTy, auto genericSig = decl->getInnermostDeclContext()->getGenericSignatureOfContext(); - auto canDeclTy = declTy->getCanonicalType(genericSig); + auto canDeclTy = declTy->getReducedType(genericSig); auto declIUOAttr = decl->isImplicitlyUnwrappedOptional(); auto parentDeclIUOAttr = parentDecl->isImplicitlyUnwrappedOptional(); @@ -198,7 +198,7 @@ bool swift::isOverrideBasedOnType(const ValueDecl *decl, Type declTy, if (parentDeclTy->hasError()) return false; - auto canParentDeclTy = parentDeclTy->getCanonicalType(genericSig); + auto canParentDeclTy = parentDeclTy->getReducedType(genericSig); // If this is a constructor, let's compare only parameter types. if (isa(decl)) { @@ -1264,7 +1264,7 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl, auto parentPropertyTy = getSuperMemberDeclType(baseDecl); CanType parentPropertyCanTy = - parentPropertyTy->getCanonicalType( + parentPropertyTy->getReducedType( decl->getInnermostDeclContext()->getGenericSignatureOfContext()); if (!propertyTy->matches(parentPropertyCanTy, TypeMatchFlags::AllowOverride)) { diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 3cb1762b649b0..2278a8f4171f7 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -834,7 +834,7 @@ Type AssociatedTypeInference::computeFixedTypeWitness( continue; auto structuralTy = DependentMemberType::get(selfTy, assocType->getName()); - const auto ty = sig.getCanonicalTypeInContext(structuralTy); + const auto ty = sig.getReducedType(structuralTy); // A dependent member type with an identical base and name indicates that // the protocol does not same-type constrain it in any way; move on to @@ -1286,7 +1286,7 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses( std::function substCurrentTypeWitnesses; substCurrentTypeWitnesses = [&](Type ty) -> Type { if (auto *gp = ty->getAs()) { - // FIXME: 'computeFixedTypeWitness' uses 'getCanonicalTypeInContext', + // FIXME: 'computeFixedTypeWitness' uses 'getReducedType', // so if a generic parameter is canonical here, it's 'Self'. if (gp->isCanonical() || isa(gp->getDecl()->getDeclContext()->getAsDecl())) { diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 594109b7ffd5b..d0f63ee3a3c3e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -235,10 +235,10 @@ bool TypeResolution::areSameType(Type type1, Type type2) const { // If both are type parameters, we can use a cheaper check // that avoids transforming the type and computing anchors. if (type1->isTypeParameter() && type2->isTypeParameter()) { - return genericSig->areSameTypeParameterInContext(type1, type2); + return genericSig->areReducedTypeParametersEqual(type1, type2); } - return genericSig.getCanonicalTypeInContext(type1) == - genericSig.getCanonicalTypeInContext(type2); + return genericSig.getReducedType(type1) == + genericSig.getReducedType(type2); } } diff --git a/test/Generics/member_type_of_superclass_bound.swift b/test/Generics/member_type_of_superclass_bound.swift index 3d482dd5a8d4d..1310c522c8a10 100644 --- a/test/Generics/member_type_of_superclass_bound.swift +++ b/test/Generics/member_type_of_superclass_bound.swift @@ -6,7 +6,7 @@ // // The latter generic signature does not have a conformance requirement T : P, // but the superclass bound C of T conforms to P concretely; make sure that -// the requirement machine's getCanonicalTypeInContext() can handle this. +// the requirement machine's getReducedType() can handle this. public protocol P { associatedtype T } From 4a041c57d0096b7edad8d19f83c314202086bbeb Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 9 Aug 2022 13:30:38 -0400 Subject: [PATCH 14/22] AST: Rename ConformanceAccessPath to ConformancePath --- docs/Lexicon.md | 2 +- include/swift/AST/ASTMangler.h | 4 +- include/swift/AST/GenericSignature.h | 16 +++--- include/swift/Basic/Statistics.def | 12 +---- lib/AST/ASTMangler.cpp | 18 +++---- lib/AST/GenericSignature.cpp | 12 ++--- .../GenericSignatureQueries.cpp | 54 +++++++++---------- .../RequirementMachine/RequirementMachine.cpp | 4 +- .../RequirementMachine/RequirementMachine.h | 14 +++-- .../RequirementMachineRequests.cpp | 2 +- lib/AST/SubstitutionMap.cpp | 5 +- lib/IRGen/GenArchetype.cpp | 6 +-- 12 files changed, 68 insertions(+), 81 deletions(-) diff --git a/docs/Lexicon.md b/docs/Lexicon.md index 51264ef16a25a..fd24af590c699 100644 --- a/docs/Lexicon.md +++ b/docs/Lexicon.md @@ -49,7 +49,7 @@ thunk helpers" sometimes seen in Swift backtraces come from.) Broadly, an "access path" is a list of "accesses" which must be chained together to compute some output from an input. For instance, the generics system has a -type called a `ConformanceAccessPath` which explains how to, for example, +type called a `ConformancePath` which explains how to, for example, walk from `T: Collection` to `T: Sequence` to `T.Iterator: IteratorProtocol`. There are several different kinds of "access path" in different parts of the compiler, but they all follow this basic theme. diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 87a8956b08b6e..0bd3fc15ad51d 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -25,7 +25,7 @@ class NamedDecl; namespace swift { class AbstractClosureExpr; -class ConformanceAccessPath; +class ConformancePath; class RootProtocolConformance; namespace Mangle { @@ -560,7 +560,7 @@ class ASTMangler : public Mangler { void appendConcreteProtocolConformance( const ProtocolConformance *conformance, GenericSignature sig); - void appendDependentProtocolConformance(const ConformanceAccessPath &path, + void appendDependentProtocolConformance(const ConformancePath &path, GenericSignature sig); void appendOpParamForLayoutConstraint(LayoutConstraint Layout); diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index 1105c47d7d79c..b05d5cccca7f6 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -70,7 +70,7 @@ namespace rewriting { /// \c Sequence conformance of \c C (because \c Collection inherits /// \c Sequence). Finally, it extracts the conformance of the associated type /// \c Iterator to \c IteratorProtocol from the \c Sequence protocol. -class ConformanceAccessPath { +class ConformancePath { public: /// An entry in the conformance access path, which is described by the /// dependent type on which the conformance is stated as the protocol to @@ -80,7 +80,7 @@ class ConformanceAccessPath { private: ArrayRef path; - ConformanceAccessPath(ArrayRef path) : path(path) {} + ConformancePath(ArrayRef path) : path(path) {} friend class GenericSignatureImpl; friend class rewriting::RequirementMachine; @@ -398,20 +398,20 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final /// signature. bool isValidTypeParameter(Type type) const; - /// Retrieve the conformance access path used to extract the conformance of + /// Retrieve the conformance path used to extract the conformance of /// interface \c type to the given \c protocol. /// - /// \param type The interface type whose conformance access path is to be + /// \param type The type parameter whose conformance path is to be /// queried. /// \param protocol A protocol to which \c type conforms. /// - /// \returns the conformance access path that starts at a requirement of + /// \returns the conformance path that starts at a requirement of /// this generic signature and ends at the conformance that makes \c type /// conform to \c protocol. /// - /// \seealso ConformanceAccessPath - ConformanceAccessPath getConformanceAccessPath(Type type, - ProtocolDecl *protocol) const; + /// \seealso ConformancePath + ConformancePath getConformancePath(Type type, + ProtocolDecl *protocol) const; /// Lookup a nested type with the given name within this type parameter. TypeDecl *lookupNestedType(Type type, Identifier name) const; diff --git a/include/swift/Basic/Statistics.def b/include/swift/Basic/Statistics.def index 6300f1f0c1d0e..4f7d9d2ceb734 100644 --- a/include/swift/Basic/Statistics.def +++ b/include/swift/Basic/Statistics.def @@ -230,16 +230,8 @@ FRONTEND_STATISTIC(Sema, NumRequirementMachineCompletionSteps) /// Number of new rules added by concrete term unification. FRONTEND_STATISTIC(Sema, NumRequirementMachineUnifiedConcreteTerms) -/// Number of generic signature builders constructed. Rough proxy for -/// amount of work the GSB does analyzing type signatures. -FRONTEND_STATISTIC(Sema, NumGenericSignatureBuilders) - -/// Number of steps in the GSB's redundant requirements algorithm, which is in -/// the worst-case exponential. -FRONTEND_STATISTIC(Sema, NumRedundantRequirementSteps) - -/// Number of conformance access paths we had to compute. -FRONTEND_STATISTIC(Sema, NumConformanceAccessPathsRecorded) +/// Number of conformance paths we had to compute. +FRONTEND_STATISTIC(Sema, NumConformancePathsRecorded) /// Number of lazy requirement signatures registered. FRONTEND_STATISTIC(Sema, NumLazyRequirementSignatures) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 2f3e90f589f0c..166a95f7593c5 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -3357,9 +3357,9 @@ void ASTMangler::appendProtocolConformanceRef( } /// Retrieve the index of the conformance requirement indicated by the -/// conformance access path entry within the given set of requirements. +/// conformance path entry within the given set of requirements. static unsigned conformanceRequirementIndex( - const ConformanceAccessPath::Entry &entry, + const ConformancePath::Entry &entry, ArrayRef requirements) { unsigned result = 0; for (const auto &req : requirements) { @@ -3377,7 +3377,7 @@ static unsigned conformanceRequirementIndex( } void ASTMangler::appendDependentProtocolConformance( - const ConformanceAccessPath &path, + const ConformancePath &path, GenericSignature sig) { ProtocolDecl *currentProtocol = nullptr; for (const auto &entry : path) { @@ -3441,19 +3441,19 @@ void ASTMangler::appendAnyProtocolConformance( if (conformingType->isTypeParameter()) { assert(genericSig && "Need a generic signature to resolve conformance"); - auto path = genericSig->getConformanceAccessPath(conformingType, - conformance.getAbstract()); + auto path = genericSig->getConformancePath(conformingType, + conformance.getAbstract()); appendDependentProtocolConformance(path, genericSig); } else if (auto opaqueType = conformingType->getAs()) { GenericSignature opaqueSignature = opaqueType->getDecl()->getOpaqueInterfaceGenericSignature(); - ConformanceAccessPath conformanceAccessPath = - opaqueSignature->getConformanceAccessPath( + ConformancePath conformancePath = + opaqueSignature->getConformancePath( opaqueType->getInterfaceType(), conformance.getAbstract()); - // Append the conformance access path with the signature of the opaque type. - appendDependentProtocolConformance(conformanceAccessPath, opaqueSignature); + // Append the conformance path with the signature of the opaque type. + appendDependentProtocolConformance(conformancePath, opaqueSignature); appendType(conformingType, genericSig); appendOperator("HO"); } else { diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 98ec05c3a7b11..b29f1463054ee 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -29,7 +29,7 @@ using namespace swift; -void ConformanceAccessPath::print(raw_ostream &out) const { +void ConformancePath::print(raw_ostream &out) const { llvm::interleave( begin(), end(), [&](const Entry &entry) { @@ -39,7 +39,7 @@ void ConformanceAccessPath::print(raw_ostream &out) const { [&] { out << " -> "; }); } -void ConformanceAccessPath::dump() const { +void ConformancePath::dump() const { print(llvm::errs()); llvm::errs() << "\n"; } @@ -475,10 +475,10 @@ CanGenericSignature::getGenericParams() const { return {base, params.size()}; } -ConformanceAccessPath -GenericSignatureImpl::getConformanceAccessPath(Type type, - ProtocolDecl *protocol) const { - return getRequirementMachine()->getConformanceAccessPath(type, protocol); +ConformancePath +GenericSignatureImpl::getConformancePath(Type type, + ProtocolDecl *protocol) const { + return getRequirementMachine()->getConformancePath(type, protocol); } TypeDecl * diff --git a/lib/AST/RequirementMachine/GenericSignatureQueries.cpp b/lib/AST/RequirementMachine/GenericSignatureQueries.cpp index dd587aa9e5753..f292d8ced5bbe 100644 --- a/lib/AST/RequirementMachine/GenericSignatureQueries.cpp +++ b/lib/AST/RequirementMachine/GenericSignatureQueries.cpp @@ -28,7 +28,7 @@ // arbitrary type, not just a type parameter, and recursively transfozms the // type parameters it contains, if any. // -// Also, getConformanceAccessPath() is another one-off operation. +// Also, getConformancePath() is another one-off operation. // //===----------------------------------------------------------------------===// @@ -469,7 +469,7 @@ bool RequirementMachine::isValidTypeParameter(Type type) const { return (prefix == term); } -/// Retrieve the conformance access path used to extract the conformance of +/// Retrieve the conformance path used to extract the conformance of /// interface \c type to the given \c protocol. /// /// \param type The interface type whose conformance access path is to be @@ -480,10 +480,10 @@ bool RequirementMachine::isValidTypeParameter(Type type) const { /// this generic signature and ends at the conformance that makes \c type /// conform to \c protocol. /// -/// \seealso ConformanceAccessPath -ConformanceAccessPath -RequirementMachine::getConformanceAccessPath(Type type, - ProtocolDecl *protocol) { +/// \seealso ConformancePath +ConformancePath +RequirementMachine::getConformancePath(Type type, + ProtocolDecl *protocol) { assert(type->isTypeParameter()); auto mutTerm = Context.getMutableTermForType(type->getCanonicalType(), @@ -505,9 +505,9 @@ RequirementMachine::getConformanceAccessPath(Type type, auto term = Term::get(mutTerm, Context); // Check if we've already cached the result before doing anything else. - auto found = ConformanceAccessPaths.find( + auto found = ConformancePaths.find( std::make_pair(term, protocol)); - if (found != ConformanceAccessPaths.end()) { + if (found != ConformancePaths.end()) { return found->second; } @@ -516,25 +516,25 @@ RequirementMachine::getConformanceAccessPath(Type type, FrontendStatsTracer tracer(Stats, "get-conformance-access-path"); auto recordPath = [&](Term term, ProtocolDecl *proto, - ConformanceAccessPath path) { + ConformancePath path) { // Add the path to the buffer. - CurrentConformanceAccessPaths.emplace_back(term, path); + CurrentConformancePaths.emplace_back(term, path); // Add the path to the map. auto key = std::make_pair(term, proto); - auto inserted = ConformanceAccessPaths.insert( + auto inserted = ConformancePaths.insert( std::make_pair(key, path)); assert(inserted.second); (void) inserted; if (Stats) - ++Stats->getFrontendCounters().NumConformanceAccessPathsRecorded; + ++Stats->getFrontendCounters().NumConformancePathsRecorded; }; // If this is the first time we're asked to look up a conformance access path, // visit all of the root conformance requirements in our generic signature and // add them to the buffer. - if (ConformanceAccessPaths.empty()) { + if (ConformancePaths.empty()) { for (const auto &req : Sig.getRequirements()) { // We only care about conformance requirements. if (req.getKind() != RequirementKind::Conformance) @@ -543,9 +543,9 @@ RequirementMachine::getConformanceAccessPath(Type type, auto rootType = CanType(req.getFirstType()); auto *rootProto = req.getProtocolDecl(); - ConformanceAccessPath::Entry root(rootType, rootProto); - ArrayRef path(root); - ConformanceAccessPath result(ctx.AllocateCopy(path)); + ConformancePath::Entry root(rootType, rootProto); + ArrayRef path(root); + ConformancePath result(ctx.AllocateCopy(path)); auto mutTerm = Context.getMutableTermForType(rootType, nullptr); System.simplify(mutTerm); @@ -555,17 +555,17 @@ RequirementMachine::getConformanceAccessPath(Type type, } } - // We enumerate conformance access paths in shortlex order until we find the + // We enumerate conformance paths in shortlex order until we find the // path whose corresponding type reduces to the one we are looking for. while (true) { - auto found = ConformanceAccessPaths.find( + auto found = ConformancePaths.find( std::make_pair(term, protocol)); - if (found != ConformanceAccessPaths.end()) { + if (found != ConformancePaths.end()) { return found->second; } - if (CurrentConformanceAccessPaths.empty()) { - llvm::errs() << "Failed to find conformance access path for "; + if (CurrentConformancePaths.empty()) { + llvm::errs() << "Failed to find conformance path for "; llvm::errs() << type << " (" << term << ")" << " : "; llvm::errs() << protocol->getName() << ":\n"; type.dump(llvm::errs()); @@ -574,18 +574,18 @@ RequirementMachine::getConformanceAccessPath(Type type, abort(); } - // The buffer consists of all conformance access paths of length N. + // The buffer consists of all conformance paths of length N. // Swap it out with an empty buffer, and fill it with all paths of // length N+1. - std::vector> oldPaths; - std::swap(CurrentConformanceAccessPaths, oldPaths); + std::vector> oldPaths; + std::swap(CurrentConformancePaths, oldPaths); for (const auto &pair : oldPaths) { const auto &lastElt = pair.second.back(); auto *lastProto = lastElt.second; // A copy of the current path, populated as needed. - SmallVector entries; + SmallVector entries; auto reqs = lastProto->getRequirementSignature().getRequirements(); for (const auto &req : reqs) { @@ -607,7 +607,7 @@ RequirementMachine::getConformanceAccessPath(Type type, // don't add it to the buffer. Note that because we iterate over // conformance access paths in shortlex order, the existing // conformance access path is shorter than the one we found just now. - if (ConformanceAccessPaths.count( + if (ConformancePaths.count( std::make_pair(nextTerm, nextProto))) continue; @@ -620,7 +620,7 @@ RequirementMachine::getConformanceAccessPath(Type type, // Add the next entry. entries.emplace_back(nextSubjectType, nextProto); - ConformanceAccessPath result = ctx.AllocateCopy(entries); + ConformancePath result = ctx.AllocateCopy(entries); entries.pop_back(); recordPath(nextTerm, nextProto, result); diff --git a/lib/AST/RequirementMachine/RequirementMachine.cpp b/lib/AST/RequirementMachine/RequirementMachine.cpp index 2b71be1537fa0..497d101be5d8d 100644 --- a/lib/AST/RequirementMachine/RequirementMachine.cpp +++ b/lib/AST/RequirementMachine/RequirementMachine.cpp @@ -565,8 +565,8 @@ void RequirementMachine::dump(llvm::raw_ostream &out) const { System.dump(out); Map.dump(out); - out << "Conformance access paths: {\n"; - for (auto pair : ConformanceAccessPaths) { + out << "Conformance paths: {\n"; + for (auto pair : ConformancePaths) { out << "- " << pair.first.first << " : "; out << pair.first.second->getName() << " => "; pair.second.print(out); diff --git a/lib/AST/RequirementMachine/RequirementMachine.h b/lib/AST/RequirementMachine/RequirementMachine.h index 02037c2293c00..bb8f7c67a6081 100644 --- a/lib/AST/RequirementMachine/RequirementMachine.h +++ b/lib/AST/RequirementMachine/RequirementMachine.h @@ -71,16 +71,15 @@ class RequirementMachine final { UnifiedStatsReporter *Stats; - /// All conformance access paths computed so far. + /// All conformance paths computed so far. llvm::DenseMap, - ConformanceAccessPath> ConformanceAccessPaths; + ConformancePath> ConformancePaths; /// Conformance access paths computed during the last round. All elements /// have the same length. If a conformance access path of greater length - /// is requested, we refill CurrentConformanceAccessPaths with all paths of - /// length N+1, and add them to the ConformanceAccessPaths map. - std::vector> - CurrentConformanceAccessPaths; + /// is requested, we refill CurrentConformancePaths with all paths of + /// length N+1, and add them to the ConformancePaths map. + std::vector> CurrentConformancePaths; explicit RequirementMachine(RewriteContext &rewriteCtx); @@ -158,8 +157,7 @@ class RequirementMachine final { Type getReducedType(Type type, TypeArrayView genericParams) const; bool isValidTypeParameter(Type type) const; - ConformanceAccessPath getConformanceAccessPath(Type type, - ProtocolDecl *protocol); + ConformancePath getConformancePath(Type type, ProtocolDecl *protocol); TypeDecl *lookupNestedType(Type depType, Identifier name) const; llvm::DenseMap diff --git a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp index d5c518bc3b73e..4c0dc291e17ce 100644 --- a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp +++ b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp @@ -482,7 +482,7 @@ RequirementMachine::computeMinimalGenericSignature( auto sig = GenericSignature::get(getGenericParams(), reqs); // Remember the signature for generic signature queries. In particular, - // getConformanceAccessPath() needs the current requirement machine's + // getConformancePath() needs the current requirement machine's // generic signature. Sig = sig.getCanonicalSignature(); diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index b0e238bea1533..6f697083bfc1d 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -367,11 +367,10 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const { return ProtocolConformanceRef::forMissingOrInvalid(substType, proto); } - auto accessPath = - genericSig->getConformanceAccessPath(type, proto); + auto path = genericSig->getConformancePath(type, proto); ProtocolConformanceRef conformance; - for (const auto &step : accessPath) { + for (const auto &step : path) { // For the first step, grab the initial conformance. if (conformance.isInvalid()) { if (auto initialConformance = getSignatureConformance( diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp index c342f864636da..c12460527f8d7 100644 --- a/lib/IRGen/GenArchetype.cpp +++ b/lib/IRGen/GenArchetype.cpp @@ -191,8 +191,7 @@ llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF, auto environment = archetype->getGenericEnvironment(); - // Otherwise, ask the generic signature for the environment for the best - // path to the conformance. + // Otherwise, ask the generic signature for the best path to the conformance. // TODO: this isn't necessarily optimal if the direct conformance isn't // concretely available; we really ought to be comparing the full paths // to this conformance from concrete sources. @@ -200,8 +199,7 @@ llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF, auto signature = environment->getGenericSignature().getCanonicalSignature(); auto archetypeDepType = archetype->getInterfaceType(); - auto astPath = signature->getConformanceAccessPath(archetypeDepType, - protocol); + auto astPath = signature->getConformancePath(archetypeDepType, protocol); auto i = astPath.begin(), e = astPath.end(); assert(i != e && "empty path!"); From ad26df09ab6893e6a554d9b9c6b04971318b6d04 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Tue, 9 Aug 2022 19:29:35 +0100 Subject: [PATCH 15/22] Revert "[Sema] Propagate nonisolated attribute from wrapped property to the synthesized projectedValue property (#60421)" (#60462) This reverts commit 2aa47b86ddfa22987a3c0ca4ad90c37ce6e6b897. --- lib/Sema/TypeCheckStorage.cpp | 7 --- test/Concurrency/global_actor_inference.swift | 44 ------------------- 2 files changed, 51 deletions(-) diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index b2e4efa990f60..fcc683e700ddb 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -2682,13 +2682,6 @@ static VarDecl *synthesizePropertyWrapperProjectionVar( var->getAttrs().add( new (ctx) ProjectedValuePropertyAttr(name, SourceLoc(), SourceRange(), /*Implicit=*/true)); - - // If the wrapped property has a nonisolated attribute, propagate it to - // the synthesized projectedValue as well. - if (var->getAttrs().getAttribute()) { - property->getAttrs().add(new (ctx) NonisolatedAttr(/*Implicit=*/true)); - } - return property; } diff --git a/test/Concurrency/global_actor_inference.swift b/test/Concurrency/global_actor_inference.swift index b2e4058345208..9fbe0dc0dfc11 100644 --- a/test/Concurrency/global_actor_inference.swift +++ b/test/Concurrency/global_actor_inference.swift @@ -457,51 +457,7 @@ func testInferredFromWrapper(x: InferredFromPropertyWrapper) { // expected-note{ _ = x.test() // expected-error{{call to global actor 'SomeGlobalActor'-isolated instance method 'test()' in a synchronous nonisolated context}} } -// https://github.com/apple/swift/issues/59380 -// https://github.com/apple/swift/issues/59494 -// Make sure the nonisolated attribute propagates to the synthesized projectedValue -// variable as well. - -@propertyWrapper -struct SimplePropertyWrapper { - var wrappedValue: Int { .zero } - var projectedValue: Int { .max } -} - -@MainActor -class HasNonIsolatedProperty { - @SimplePropertyWrapper nonisolated var value - - deinit { - _ = value - _ = $value // Ok - } -} - -@propertyWrapper -struct SimplePropertyWrapper2 { - var wrappedValue: Int - var projectedValue: SimplePropertyWrapper2 { self } -} - -@MainActor -class HasNonIsolatedProperty2 { - @SimplePropertyWrapper2 nonisolated var value = 0 - nonisolated init() {} -} - -let hasNonIsolatedProperty2 = HasNonIsolatedProperty2() - -Task { @MainActor in - hasNonIsolatedProperty2.value = 10 - _ = hasNonIsolatedProperty2.$value.wrappedValue -} - -Task.detached { - hasNonIsolatedProperty2.value = 10 - _ = hasNonIsolatedProperty2.$value.wrappedValue // Ok -} // ---------------------------------------------------------------------- // Unsafe global actors From 74d47a165132dc564f9adc9b1d8c1177e8d8b8ff Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 9 Aug 2022 11:55:28 -0700 Subject: [PATCH 16/22] [interop][SwiftToCxx] update swift type representation docs with different opaque type layout --- .../SwiftTypeRepresentationInC++.md | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/docs/CppInteroperability/SwiftTypeRepresentationInC++.md b/docs/CppInteroperability/SwiftTypeRepresentationInC++.md index 8a36a9bdea84e..8255dc56c1443 100644 --- a/docs/CppInteroperability/SwiftTypeRepresentationInC++.md +++ b/docs/CppInteroperability/SwiftTypeRepresentationInC++.md @@ -8,7 +8,7 @@ C++. ### Value Types -1) Primitive Swift types like `Int`, `Float` , `OpaquePointer`, `UnsafePointer?` are mapped to primitive C++ types. `int` , `float`, `void *`, int `* _Nullable` . +1) Primitive Swift types like `Int`, `Float` , `OpaquePointer`, `UnsafePointer?` are mapped to primitive C++ types. `int` , `float`, `void *`, `int * _Nullable`. * Debug info: Does C++ debug info suffices? @@ -29,13 +29,23 @@ class swift::String { ```c++ class Foundation::URL { ... - union { - alignas(8) char buffer[8]; // Swift value is stored here. - void *resilientPtr; - }; + uintptr_t pointer; // pointer has alignment to compute buffer offset? + alignas(N) char buffer[M]; // Swift value is stored here. }; ``` +concrete examples: + +```c++ +// representation for buffer aligned at 8: +{/*pointer=*/0x3, ....}; // buffer is alignas(2^3 = 8) + +// representation for buffer aligned at 16: +{/*pointer=*/0x4, ....}; // buffer is alignas(2^4 = 16) + +// where pointer < 10 for inline stores. +``` + * Debug info: ... @@ -44,10 +54,8 @@ class Foundation::URL { ```c++ class CryptoKit::SHA256 { ... - union { - alignas(8) char buffer[8]; - void *resilientPtr; // Swift value is stored on the heap pointed by this pointer. - }; + uintptr_t pointer; // Swift value is stored on the heap pointed by this pointer. + alignas(8) char buffer[8]; }; ``` @@ -66,15 +74,13 @@ class swift::Array { * Debug info: ... -6) Generic opaque-layout / resilient / opaque-layout template type params Swift value type, e.g. SHA256`?`, is mapped to a C++ class that stores the value boxed up on the heap, e.g.: +6) Generic opaque-layout / resilient / opaque-layout template type params Swift value type, e.g. `SHA256?`, is mapped to a C++ class that stores the value boxed up on the heap, e.g.: ```c++ class swift::Optional { ... - union { - alignas(8) char buffer[8]; - void *resilientPtr; // Swift value is stored on the heap pointed by this pointer. - }; + uintptr_t pointer; // Swift value is stored on the heap pointed by this pointer. + alignas(N) char buffer[M]; } ``` From c537cd238350e61d24459bb75ad0579c937c7584 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 9 Aug 2022 13:57:34 -0700 Subject: [PATCH 17/22] [interop][SwiftToCxx] NFC, move swift::_impl::OpaqueStorage into _SwiftCxxInteroperability shims header --- lib/PrintAsClang/PrintClangValueType.cpp | 7 +++- .../PrintSwiftToClangCoreScaffold.cpp | 39 +------------------ .../SwiftShims/_SwiftCxxInteroperability.h | 36 +++++++++++++++++ .../core/swift-impl-defs-in-cxx.swift | 18 +-------- .../structs/resilient-struct-in-cxx.swift | 10 ++--- 5 files changed, 50 insertions(+), 60 deletions(-) diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index 03a810347b106..1cb79538df113 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -152,7 +152,8 @@ void ClangValueTypePrinter::printValueTypeDecl( if (isOpaqueLayout) { os << " _storage = "; printer.printSwiftImplQualifier(); - os << cxx_synthesis::getCxxOpaqueStorageClassName() << "(vwTable);\n"; + os << cxx_synthesis::getCxxOpaqueStorageClassName() + << "(vwTable->size, vwTable->getAlignment());\n"; } os << " vwTable->initializeWithCopy(_getOpaquePointer(), const_cast(other._getOpaquePointer()), metadata._0);\n"; @@ -172,10 +173,12 @@ void ClangValueTypePrinter::printValueTypeDecl( // Print out private default constructor. os << " inline "; printer.printBaseName(typeDecl); + // FIXME: make noexcept. if (isOpaqueLayout) { os << "("; printer.printSwiftImplQualifier(); - os << "ValueWitnessTable * _Nonnull vwTable) : _storage(vwTable) {}\n"; + os << "ValueWitnessTable * _Nonnull vwTable) : _storage(vwTable->size, " + "vwTable->getAlignment()) {}\n"; } else { os << "() {}\n"; } diff --git a/lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp b/lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp index 213120db42984..f79d3afc1e31c 100644 --- a/lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp +++ b/lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp @@ -111,6 +111,8 @@ static void printValueWitnessTable(raw_ostream &os) { #define VOID_TYPE "void" #include "swift/ABI/ValueWitness.def" + membersOS << "\n constexpr size_t getAlignment() const { return (flags & " + << TargetValueWitnessFlags::AlignmentMask << ") + 1; }\n"; os << "\nstruct ValueWitnessTable {\n" << membersOS.str() << "};\n\n"; membersOS.str().clear(); @@ -154,43 +156,7 @@ static void printTypeMetadataResponseType(SwiftToClangInteropContext &ctx, funcSig.parameterTypes[0]); } -static void printSwiftResilientStorageClass(raw_ostream &os) { - auto name = cxx_synthesis::getCxxOpaqueStorageClassName(); - static_assert(TargetValueWitnessFlags::AlignmentMask == - TargetValueWitnessFlags::AlignmentMask, - "alignment mask doesn't match"); - os << "/// Container for an opaque Swift value, like resilient struct.\n"; - os << "class " << name << " {\n"; - os << "public:\n"; - os << " inline " << name << "() noexcept : storage(nullptr) { }\n"; - os << " inline " << name - << "(ValueWitnessTable * _Nonnull vwTable) noexcept : storage(" - "reinterpret_cast(opaqueAlloc(vwTable->size, (vwTable->flags &" - << TargetValueWitnessFlags::AlignmentMask << ") + 1))) { }\n"; - os << " inline " << name << "(" << name - << "&& other) noexcept : storage(other.storage) { other.storage = " - "nullptr; }\n"; - os << " inline " << name << "(const " << name << "&) noexcept = delete;\n"; - os << " inline ~" << name - << "() noexcept { if (storage) { opaqueFree(static_cast(storage)); } }\n"; - os << " void operator =(" << name - << "&& other) noexcept { auto temp = storage; storage = other.storage; " - "other.storage = temp; }\n"; - os << " void operator =(const " << name << "&) noexcept = delete;\n"; - os << " inline char * _Nonnull getOpaquePointer() noexcept { return " - "static_cast(storage); }\n"; - os << " inline const char * _Nonnull getOpaquePointer() const noexcept { " - "return " - "static_cast(storage); }\n"; - os << "private:\n"; - os << " char * _Nullable storage;\n"; - os << "};\n"; -} - void printCxxNaiveException(raw_ostream &os) { - os << "\n"; os << "/// Naive exception class that should be thrown\n"; os << "class NaiveException {\n"; os << "public:\n"; @@ -273,7 +239,6 @@ void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx, /*isCForwardDefinition=*/true); }); os << "\n"; - printSwiftResilientStorageClass(os); printCxxNaiveException(os); }); os << "\n"; diff --git a/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h b/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h index 41ca4e4381471..4566714eab64b 100644 --- a/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h +++ b/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h @@ -53,6 +53,42 @@ inline void opaqueFree(void *_Nonnull p) noexcept { #endif } +/// Base class for a container for an opaque Swift value, like resilient struct. +class OpaqueStorage { +public: + inline OpaqueStorage() noexcept : storage(nullptr) {} + inline OpaqueStorage(size_t size, size_t alignment) noexcept + : storage(reinterpret_cast(opaqueAlloc(size, alignment))) {} + inline OpaqueStorage(OpaqueStorage &&other) noexcept + : storage(other.storage) { + other.storage = nullptr; + } + inline OpaqueStorage(const OpaqueStorage &) noexcept = delete; + + inline ~OpaqueStorage() noexcept { + if (storage) { + opaqueFree(static_cast(storage)); + } + } + + void operator=(OpaqueStorage &&other) noexcept { + auto temp = storage; + storage = other.storage; + other.storage = temp; + } + void operator=(const OpaqueStorage &) noexcept = delete; + + inline char *_Nonnull getOpaquePointer() noexcept { + return static_cast(storage); + } + inline const char *_Nonnull getOpaquePointer() const noexcept { + return static_cast(storage); + } + +private: + char *_Nullable storage; +}; + /// Base class for a Swift reference counted class value. class RefCountedClass { public: diff --git a/test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift b/test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift index d28fc27daa443..dce6eb74dbf46 100644 --- a/test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift +++ b/test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift @@ -51,6 +51,8 @@ // CHECK-NEXT: size_t stride; // CHECK-NEXT: unsigned flags; // CHECK-NEXT: unsigned extraInhabitantCount; +// CHECK-EMPTY: +// CHECK-NEXT: constexpr size_t getAlignment() const { return (flags & 255) + 1; } // CHECK-NEXT: }; // CHECK-EMPTY: // CHECK-NEXT: using EnumValueWitnessGetEnumTagTy = int(* __ptrauth_swift_value_witness_function_pointer(41909))(const void * _Nonnull, void * _Nonnull) SWIFT_NOEXCEPT_FUNCTION_PTR; @@ -96,22 +98,6 @@ // CHECK-NEXT: } // CHECK-NEXT: #endif // CHECK-EMPTY: -// CHECK-NEXT: /// Container for an opaque Swift value, like resilient struct. -// CHECK-NEXT: class OpaqueStorage { -// CHECK-NEXT: public: -// CHECK-NEXT: inline OpaqueStorage() noexcept : storage(nullptr) { } -// CHECK-NEXT: inline OpaqueStorage(ValueWitnessTable * _Nonnull vwTable) noexcept : storage(reinterpret_cast(opaqueAlloc(vwTable->size, (vwTable->flags &255) + 1))) { } -// CHECK-NEXT: inline OpaqueStorage(OpaqueStorage&& other) noexcept : storage(other.storage) { other.storage = nullptr; } -// CHECK-NEXT: inline OpaqueStorage(const OpaqueStorage&) noexcept = delete; -// CHECK-NEXT: inline ~OpaqueStorage() noexcept { if (storage) { opaqueFree(static_cast(storage)); } } -// CHECK-NEXT: void operator =(OpaqueStorage&& other) noexcept { auto temp = storage; storage = other.storage; other.storage = temp; } -// CHECK-NEXT: void operator =(const OpaqueStorage&) noexcept = delete; -// CHECK-NEXT: inline char * _Nonnull getOpaquePointer() noexcept { return static_cast(storage); } -// CHECK-NEXT: inline const char * _Nonnull getOpaquePointer() const noexcept { return static_cast(storage); } -// CHECK-NEXT: private: -// CHECK-NEXT: char * _Nullable storage; -// CHECK-NEXT: }; -// CHECK-EMPTY: // CHECK-NEXT: /// Naive exception class that should be thrown // CHECK-NEXT: class NaiveException { // CHECK-NEXT: public: diff --git a/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift b/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift index 74f3fbc5e028d..84025412549b7 100644 --- a/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift +++ b/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift @@ -37,11 +37,11 @@ public struct FirstSmallStruct { // CHECK-NEXT: #else // CHECK-NEXT: auto *vwTable = *vwTableAddr; // CHECK-NEXT: #endif -// CHECK-NEXT: _storage = swift::_impl::OpaqueStorage(vwTable); +// CHECK-NEXT: _storage = swift::_impl::OpaqueStorage(vwTable->size, vwTable->getAlignment()); // CHECK-NEXT: vwTable->initializeWithCopy(_getOpaquePointer(), const_cast(other._getOpaquePointer()), metadata._0); // CHECK-NEXT: } // CHECK: private: -// CHECK-NEXT: inline FirstSmallStruct(swift::_impl::ValueWitnessTable * _Nonnull vwTable) : _storage(vwTable) {} +// CHECK-NEXT: inline FirstSmallStruct(swift::_impl::ValueWitnessTable * _Nonnull vwTable) : _storage(vwTable->size, vwTable->getAlignment()) {} // CHECK-NEXT: static inline FirstSmallStruct _make() { // CHECK-NEXT: auto metadata = _impl::$s7Structs16FirstSmallStructVMa(0); // CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; @@ -103,11 +103,11 @@ public struct LargeStruct { // CHECK-NEXT: #else // CHECK-NEXT: auto *vwTable = *vwTableAddr; // CHECK-NEXT: #endif -// CHECK-NEXT: _storage = swift::_impl::OpaqueStorage(vwTable); +// CHECK-NEXT: _storage = swift::_impl::OpaqueStorage(vwTable->size, vwTable->getAlignment()); // CHECK-NEXT: vwTable->initializeWithCopy(_getOpaquePointer(), const_cast(other._getOpaquePointer()), metadata._0); // CHECK-NEXT: } // CHECK: private: -// CHECK-NEXT: inline LargeStruct(swift::_impl::ValueWitnessTable * _Nonnull vwTable) : _storage(vwTable) {} +// CHECK-NEXT: inline LargeStruct(swift::_impl::ValueWitnessTable * _Nonnull vwTable) : _storage(vwTable->size, vwTable->getAlignment()) {} // CHECK-NEXT: static inline LargeStruct _make() { // CHECK-NEXT: auto metadata = _impl::$s7Structs11LargeStructVMa(0); // CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; @@ -161,7 +161,7 @@ public struct StructWithRefCountStoredProp { } } -// CHECK: inline StructWithRefCountStoredProp(swift::_impl::ValueWitnessTable * _Nonnull vwTable) : _storage(vwTable) {} +// CHECK: inline StructWithRefCountStoredProp(swift::_impl::ValueWitnessTable * _Nonnull vwTable) : _storage(vwTable->size, vwTable->getAlignment()) {} // CHECK: inline void StructWithRefCountStoredProp::dump() const { // CHECK-NEXT: return _impl::$s7Structs28StructWithRefCountStoredPropV4dumpyyF(_getOpaquePointer()); // CHECK-NEXT: } From ad00633cf163038a85ad46420201a1eb1ee38fb4 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 9 Aug 2022 14:12:20 -0700 Subject: [PATCH 18/22] Fix assert --- .../NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m index 63ea5a7bec7c0..b46602b14a513 100644 --- a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m +++ b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m @@ -100,7 +100,7 @@ - (id) description { } - (BOOL)getBytes:(void *)buffer maxLength:(uint64_t)max usedLength:(uint64_t *)used encoding:(uint64_t)encoding options:(uint64_t)options range:(NSRange)range remainingRange:(NSRange *)leftover { - assert(encoding == kCFStringEncodingASCII || encoding == kCFStringEncodingUTF8); + assert(encoding == 1 /* ASCII */ || encoding == 4 /* UTF8 */); strncpy(buffer, contents, max); if (strlen(contents) > max) { leftover->location = max; From f371c4307b452a47419ee0bd59830d2637132574 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 9 Aug 2022 14:16:58 -0700 Subject: [PATCH 19/22] [interop][SwiftToCxx] pass boxed resilient value types to generic functions correctly --- lib/PrintAsClang/PrintClangFunction.cpp | 9 ++---- lib/PrintAsClang/PrintClangValueType.cpp | 8 +++++ .../SwiftShims/_SwiftCxxInteroperability.h | 18 +++++++++++ .../generics/generic-function-in-cxx.swift | 18 ++++++----- .../resilient-generic-function-execution.cpp | 13 ++++++++ .../structs/resilient-struct-in-cxx.swift | 30 +++++++++++++++++++ 6 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 test/Interop/SwiftToCxx/generics/resilient-generic-function-execution.cpp diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index 8578fd5a87682..fe586222e4116 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -451,13 +451,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse( if (type->getAs() && type->getAs() ->getInterfaceType() ->is()) { - // FIXME: NEED to handle boxed resilient type. - // os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() << - // "::getOpaquePointer("; - os << "reinterpret_cast<"; - if (!isInOut) - os << "const "; - os << "void *>(&"; + os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() + << "::getOpaquePointer("; namePrinter(); os << ')'; return; diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index 1cb79538df113..c6108c4d26634 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -499,6 +499,14 @@ void ClangValueTypePrinter::printTypeGenericTraits( os << "::"; printer.printBaseName(typeDecl); os << "> = true;\n"; + if (typeDecl->isResilient()) { + os << "template<>\n"; + os << "static inline const constexpr bool isOpaqueLayout<"; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::"; + printer.printBaseName(typeDecl); + os << "> = true;\n"; + } } os << "template<>\n"; diff --git a/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h b/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h index 4566714eab64b..88549f9d4afe6 100644 --- a/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h +++ b/stdlib/public/SwiftShims/_SwiftCxxInteroperability.h @@ -154,6 +154,24 @@ template struct implClassFor { /// True if the given type is a Swift value type. template static inline const constexpr bool isValueType = false; +/// True if the given type is a Swift value type with opaque layout that can be +/// boxed. +template static inline const constexpr bool isOpaqueLayout = false; + +/// Returns the opaque pointer to the given value. +template +inline const void *_Nonnull getOpaquePointer(const T &value) { + if constexpr (isOpaqueLayout) + return reinterpret_cast(value).getOpaquePointer(); + return reinterpret_cast(&value); +} + +template inline void *_Nonnull getOpaquePointer(T &value) { + if constexpr (isOpaqueLayout) + return reinterpret_cast(value).getOpaquePointer(); + return reinterpret_cast(&value); +} + } // namespace _impl #pragma clang diagnostic pop diff --git a/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift b/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift index 04a27920abddf..71a16b49e158f 100644 --- a/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift +++ b/test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift @@ -4,6 +4,10 @@ // RUN: %check-generic-interop-cxx-header-in-clang(%t/functions.h -Wno-unused-function) +// RUN: %target-swift-frontend %s -typecheck -module-name Functions -enable-library-evolution -clang-header-expose-public-decls -emit-clang-header-path %t/functions-evo.h +// RUN: %FileCheck %s < %t/functions-evo.h + +// RUN: %check-generic-interop-cxx-header-in-clang(%t/functions-evo.h -Wno-unused-function) public func genericPrintFunctionTwoArg(_ x: T, _ y: Int) { print("X:", x) @@ -87,21 +91,21 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct { // CHECK: template // CHECK-NEXT: requires swift::isUsableInGenericContext // CHECK-NEXT: inline void genericPrintFunction(const T & x) noexcept { -// CHECK-NEXT: return _impl::$s9Functions20genericPrintFunctionyyxlF(reinterpret_cast(&x), swift::getTypeMetadata()); +// CHECK-NEXT: return _impl::$s9Functions20genericPrintFunctionyyxlF(swift::_impl::getOpaquePointer(x), swift::getTypeMetadata()); // CHECK-NEXT: } // CHECK: template // CHECK-NEXT: requires swift::isUsableInGenericContext && swift::isUsableInGenericContext // CHECK-NEXT: inline void genericPrintFunctionMultiGeneric(swift::Int x, const T1 & t1, const T1 & t1p, swift::Int y, const T2 & t2) noexcept { -// CHECK-NEXT: return _impl::$s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(x, reinterpret_cast(&t1), reinterpret_cast(&t1p), y, reinterpret_cast(&t2), swift::getTypeMetadata(), swift::getTypeMetadata()); +// CHECK-NEXT: return _impl::$s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(x, swift::_impl::getOpaquePointer(t1), swift::_impl::getOpaquePointer(t1p), y, swift::_impl::getOpaquePointer(t2), swift::getTypeMetadata(), swift::getTypeMetadata()); // CHECK-NEXT: } // CHECK: template // CHECK-NEXT: requires swift::isUsableInGenericContext // CHECK-NEXT: inline void genericPrintFunctionTwoArg(const T & x, swift::Int y) noexcept { -// CHECK-NEXT: return _impl::$s9Functions26genericPrintFunctionTwoArgyyx_SitlF(reinterpret_cast(&x), y, swift::getTypeMetadata()); +// CHECK-NEXT: return _impl::$s9Functions26genericPrintFunctionTwoArgyyx_SitlF(swift::_impl::getOpaquePointer(x), y, swift::getTypeMetadata()); // CHECK-NEXT: } // CHECK: template @@ -109,15 +113,15 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct { // CHECK-NEXT: inline T genericRet(const T & x) noexcept SWIFT_WARN_UNUSED_RESULT { // CHECK-NEXT: if constexpr (std::is_base_of<::swift::_impl::RefCountedClass, T>::value) { // CHECK-NEXT: void *returnValue; -// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast(&returnValue), reinterpret_cast(&x), swift::getTypeMetadata()); +// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast(&returnValue), swift::_impl::getOpaquePointer(x), swift::getTypeMetadata()); // CHECK-NEXT: return ::swift::_impl::implClassFor::type::makeRetained(returnValue); // CHECK-NEXT: } else if constexpr (::swift::_impl::isValueType) { // CHECK-NEXT: return ::swift::_impl::implClassFor::type::returnNewValue([&](void * _Nonnull returnValue) { -// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, reinterpret_cast(&x), swift::getTypeMetadata()); +// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, swift::_impl::getOpaquePointer(x), swift::getTypeMetadata()); // CHECK-NEXT: }); // CHECK-NEXT: } else { // CHECK-NEXT: T returnValue; -// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast(&returnValue), reinterpret_cast(&x), swift::getTypeMetadata()); +// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast(&returnValue), swift::_impl::getOpaquePointer(x), swift::getTypeMetadata()); // CHECK-NEXT: return returnValue; // CHECK-NEXT: } // CHECK-NEXT: } @@ -125,5 +129,5 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct { // CHECK: template // CHECK-NEXT: requires swift::isUsableInGenericContext // CHECK-NEXT: inline void genericSwap(T & x, T & y) noexcept { -// CHECK-NEXT: return _impl::$s9Functions11genericSwapyyxz_xztlF(reinterpret_cast(&x), reinterpret_cast(&y), swift::getTypeMetadata()); +// CHECK-NEXT: return _impl::$s9Functions11genericSwapyyxz_xztlF(swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::getTypeMetadata()); // CHECK-NEXT: } diff --git a/test/Interop/SwiftToCxx/generics/resilient-generic-function-execution.cpp b/test/Interop/SwiftToCxx/generics/resilient-generic-function-execution.cpp new file mode 100644 index 0000000000000..a6e7d11804616 --- /dev/null +++ b/test/Interop/SwiftToCxx/generics/resilient-generic-function-execution.cpp @@ -0,0 +1,13 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend %S/generic-function-in-cxx.swift -typecheck -module-name Functions -enable-library-evolution -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h + +// RUN: %target-interop-build-clangxx -std=gnu++20 -c %s -I %t -o %t/swift-functions-execution.o +// RUN: %target-interop-build-swift %S/generic-function-in-cxx.swift -o %t/swift-functions-execution -Xlinker %t/swift-functions-execution.o -enable-library-evolution -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain + +// RUN: %target-codesign %t/swift-functions-execution +// RUN: %target-run %t/swift-functions-execution | %FileCheck %S/generic-function-execution.cpp + +// REQUIRES: executable_test + +#include "generic-function-execution.cpp" diff --git a/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift b/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift index 84025412549b7..b32a83165a46a 100644 --- a/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift +++ b/test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift @@ -59,6 +59,36 @@ public struct FirstSmallStruct { // CHECK-NEXT: friend class _impl::_impl_FirstSmallStruct; // CHECK-NEXT:}; +// CHECK: class _impl_FirstSmallStruct { +// CHECK: }; +// CHECK-EMPTY: +// CHECK-NEXT: } + +// CHECK-EMPTY: +// CHECK-NEXT: } // end namespace +// CHECK-EMPTY: +// CHECK-NEXT: namespace swift { +// CHECK-NEXT: #pragma clang diagnostic push +// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" +// CHECK-NEXT: template<> +// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext = true; +// CHECK-NEXT: template<> +// CHECK-NEXT: inline void * _Nonnull getTypeMetadata() { +// CHECK-NEXT: return Structs::_impl::$s7Structs16FirstSmallStructVMa(0)._0; +// CHECK-NEXT: } +// CHECK-NEXT: namespace _impl{ +// CHECK-NEXT: template<> +// CHECK-NEXT: static inline const constexpr bool isValueType = true; +// CHECK-NEXT: template<> +// CHECK-NEXT: static inline const constexpr bool isOpaqueLayout = true; +// CHECK-NEXT: template<> +// CHECK-NEXT: struct implClassFor { using type = Structs::_impl::_impl_FirstSmallStruct; }; +// CHECK-NEXT: } // namespace +// CHECK-NEXT: #pragma clang diagnostic pop +// CHECK-NEXT: } // namespace swift +// CHECK-EMPTY: +// CHECK-NEXT: namespace Structs { + // CHECK: inline uint32_t FirstSmallStruct::getX() const { // CHECK-NEXT: return _impl::$s7Structs16FirstSmallStructV1xs6UInt32Vvg(_getOpaquePointer()); // CHECK-NEXT: } From d23a64e6227e5b227b7377e4bb407a008c725c00 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 9 Aug 2022 14:20:41 -0700 Subject: [PATCH 20/22] [interop][SwiftToCxx] NFC, reformat printTypeGenericTraits --- lib/PrintAsClang/PrintClangValueType.cpp | 50 ++++++++++++------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index c6108c4d26634..8d3773d823b10 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -490,39 +490,39 @@ void ClangValueTypePrinter::printTypeGenericTraits( << "::" << typeMetadataFuncName << "(0)._0;\n"; os << "}\n"; - os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n"; + os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n"; - if (!isa(typeDecl)) { + if (!isa(typeDecl)) { + os << "template<>\n"; + os << "static inline const constexpr bool isValueType<"; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::"; + printer.printBaseName(typeDecl); + os << "> = true;\n"; + if (typeDecl->isResilient()) { os << "template<>\n"; - os << "static inline const constexpr bool isValueType<"; + os << "static inline const constexpr bool isOpaqueLayout<"; printer.printBaseName(typeDecl->getModuleContext()); os << "::"; printer.printBaseName(typeDecl); os << "> = true;\n"; - if (typeDecl->isResilient()) { + } + } + os << "template<>\n"; - os << "static inline const constexpr bool isOpaqueLayout<"; + os << "struct implClassFor<"; printer.printBaseName(typeDecl->getModuleContext()); os << "::"; printer.printBaseName(typeDecl); - os << "> = true;\n"; - } - } - - os << "template<>\n"; - os << "struct implClassFor<"; - printer.printBaseName(typeDecl->getModuleContext()); - os << "::"; - printer.printBaseName(typeDecl); - os << "> { using type = "; - printer.printBaseName(typeDecl->getModuleContext()); - os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::"; - printCxxImplClassName(os, typeDecl); - os << "; };\n"; - os << "} // namespace\n"; - os << "#pragma clang diagnostic pop\n"; - os << "} // namespace swift\n"; - os << "\nnamespace "; - printer.printBaseName(typeDecl->getModuleContext()); - os << " {\n"; + os << "> { using type = "; + printer.printBaseName(typeDecl->getModuleContext()); + os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::"; + printCxxImplClassName(os, typeDecl); + os << "; };\n"; + os << "} // namespace\n"; + os << "#pragma clang diagnostic pop\n"; + os << "} // namespace swift\n"; + os << "\nnamespace "; + printer.printBaseName(typeDecl->getModuleContext()); + os << " {\n"; } From 27a27fe034b3738e75530dd6f20c85385582e493 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 9 Aug 2022 14:35:10 -0700 Subject: [PATCH 21/22] Fix test --- .../NSSlowTaggedLocalizedString.m | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m index b46602b14a513..2a3f643ea46aa 100644 --- a/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m +++ b/test/stdlib/Inputs/NSSlowTaggedLocalizedString/NSSlowTaggedLocalizedString.m @@ -2,21 +2,22 @@ #import "NSSlowTaggedLocalizedString.h" #import #import +#import -//If and when CF starts linking Swift we may need to rethink this -#import +/* + This horrific mess is simulating the new-in-macOS-Ventura tagged pointer strings, + which can have lengths >15 characters, which can cause problems in SmallString, + which used to assume that would never happen. Once CI is running on Ventura or + later, this can be rewritten to use a regular NSLocalizedString. + */ @implementation NSSlowTaggedLocalizedString -typedef struct _NSRange { - uint64_t location; - uint64_t length; -} NSRange; - + (instancetype) createTestString { #if __LP64__ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ + [[[NSString alloc] init] release]; //Make sure NSString is initialized Class tagClass = objc_lookUpClass("NSTaggedPointerString"); Class ourClass = [NSSlowTaggedLocalizedString class]; From 25e17930cc8578a6f5382cda12ad60c084c8f1e5 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 10 Aug 2022 10:39:12 +0900 Subject: [PATCH 22/22] [Distributed] more specific errorCodes for dist failures; hide the make error func --- .../public/Distributed/DistributedActor.cpp | 3 +- .../Distributed/DistributedActorSystem.swift | 41 +++++++++++++++---- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/stdlib/public/Distributed/DistributedActor.cpp b/stdlib/public/Distributed/DistributedActor.cpp index 17962d301a19b..36536e1cbb3ae 100644 --- a/stdlib/public/Distributed/DistributedActor.cpp +++ b/stdlib/public/Distributed/DistributedActor.cpp @@ -109,8 +109,7 @@ static void swift_distributed_execute_target_resume( return resumeInParent(parentCtx, error); } -SWIFT_CC(swift) -SWIFT_EXPORT_FROM(swiftDistributed) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL SwiftError* swift_distributed_makeDistributedTargetAccessorNotFoundError( const char *targetNameStart, size_t targetNameLength); diff --git a/stdlib/public/Distributed/DistributedActorSystem.swift b/stdlib/public/Distributed/DistributedActorSystem.swift index 47092b332b876..1f632a2fb72e3 100644 --- a/stdlib/public/Distributed/DistributedActorSystem.swift +++ b/stdlib/public/Distributed/DistributedActorSystem.swift @@ -251,7 +251,8 @@ extension DistributedActorSystem { let subs = try invocationDecoder.decodeGenericSubstitutions() if subs.isEmpty { throw ExecuteDistributedTargetError( - message: "Cannot call generic method without generic argument substitutions") + message: "Cannot call generic method without generic argument substitutions", + errorCode: .missingGenericSubstitutions) } substitutionsBuffer = .allocate(capacity: subs.count) @@ -265,7 +266,8 @@ extension DistributedActorSystem { genericArguments: substitutionsBuffer!) if numWitnessTables < 0 { throw ExecuteDistributedTargetError( - message: "Generic substitutions \(subs) do not satisfy generic requirements of \(target) (\(targetName))") + message: "Generic substitutions \(subs) do not satisfy generic requirements of \(target) (\(targetName))", + errorCode: .invalidGenericSubstitutions) } } @@ -279,7 +281,8 @@ extension DistributedActorSystem { Failed to decode distributed invocation target expected parameter count, error code: \(paramCount) mangled name: \(targetName) - """) + """, + errorCode: .invalidParameterCount) } // Prepare buffer for the parameter types to be decoded into: @@ -304,7 +307,8 @@ extension DistributedActorSystem { Failed to decode the expected number of params of distributed invocation target, error code: \(decodedNum) (decoded: \(decodedNum), expected params: \(paramCount) mangled name: \(targetName) - """) + """, + errorCode: .invalidParameterCount) } // Copy the types from the buffer into a Swift Array @@ -325,12 +329,14 @@ extension DistributedActorSystem { genericEnv: genericEnv, genericArguments: substitutionsBuffer) else { throw ExecuteDistributedTargetError( - message: "Failed to decode distributed target return type") + message: "Failed to decode distributed target return type", + errorCode: .typeDeserializationFailure) } guard let resultBuffer = _openExistential(returnTypeFromTypeInfo, do: allocateReturnTypeBuffer) else { throw ExecuteDistributedTargetError( - message: "Failed to allocate buffer for distributed target return type") + message: "Failed to allocate buffer for distributed target return type", + errorCode: .typeDeserializationFailure) } func destroyReturnTypeBuffer(_: R.Type) { @@ -576,19 +582,38 @@ public protocol DistributedTargetInvocationResultHandler { @available(SwiftStdlib 5.7, *) public protocol DistributedActorSystemError: Error {} +/// Error thrown by ``DistributedActorSystem/executeDistributedTarget(on:target:invocationDecoder:handler:)``. +/// +/// Inspect the ``errorCode`` for details about the underlying reason this error was thrown. @available(SwiftStdlib 5.7, *) public struct ExecuteDistributedTargetError: DistributedActorSystemError { public let errorCode: ErrorCode public let message: String public enum ErrorCode { - /// Thrown when unable to resolve the target identifier to a function accessor. + /// Unable to resolve the target identifier to a function accessor. /// This can happen when the identifier is corrupt, illegal, or wrong in the /// sense that the caller and callee do not have the called function recorded /// using the same identifier. case targetAccessorNotFound - /// A general issue during the execution of the distributed call target ocurred. + /// Call target has different number of parameters than arguments + /// provided by the invocation decoder. + case invalidParameterCount + + /// Target expects generic environment information, but invocation decoder + /// provided no generic substitutions. + case missingGenericSubstitutions + + /// Generic substitutions provided by invocation decoder are incompatible + /// with target of the call. E.g. the generic requirements on the actual + /// target could not be fulfilled by the obtained generic substitutions. + case invalidGenericSubstitutions + + // Failed to deserialize type or obtain type information for call. + case typeDeserializationFailure + + /// A general issue during the execution of the distributed call target occurred. case other }