Skip to content

Commit 8c73ba7

Browse files
authored
Merge pull request #37047 from apple/5.4-post-back-xcode-12.5-rc
Update the branch to build with Xcode 12.5
2 parents 4dd4e0d + 89733a7 commit 8c73ba7

File tree

6 files changed

+108
-18
lines changed

6 files changed

+108
-18
lines changed

include/swift/Runtime/Bincompat.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,18 @@ namespace bincompat {
2222

2323
/// Whether protocol conformance iteration should be reversed, to prefer
2424
/// conformances from images that are later in the list over earlier ones.
25+
/// Default is false starting with Swift 5.4.
2526
bool workaroundProtocolConformanceReverseIteration();
2627

28+
/// Whether we should crash when we encounter a non-nullable Obj-C
29+
/// reference with a null value as the source of a cast.
30+
/// Default is true starting with Swift 5.4.
31+
bool unexpectedObjCNullWhileCastingIsFatal();
32+
33+
/// Whether we should use the legacy semantics for casting nil optionals
34+
/// to nested optionals
35+
bool useLegacyOptionalNilInjection();
36+
2737
} // namespace bincompat
2838

2939
} // namespace runtime

stdlib/public/runtime/Bincompat.cpp

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,92 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "swift/Runtime/Bincompat.h"
18+
#include <stdint.h>
19+
20+
// If this is an Apple OS, use the Apple binary compatibility rules
21+
#if __has_include(<mach-o/dyld_priv.h>)
22+
#include <mach-o/dyld_priv.h>
23+
#ifndef BINARY_COMPATIBILITY_APPLE
24+
#define BINARY_COMPATIBILITY_APPLE 1
25+
#endif
26+
#else
27+
#undef BINARY_COMPATIBILITY_APPLE
28+
#endif
1829

1930
namespace swift {
2031

2132
namespace runtime {
2233

2334
namespace bincompat {
2435

25-
bool workaroundProtocolConformanceReverseIteration() { return false; }
36+
// Should we mimic the old override behavior when scanning protocol conformance records?
37+
38+
// Old apps expect protocol conformances to override each other in a particular
39+
// order. Starting with Swift 5.4, that order has changed as a result of
40+
// significant performance improvements to protocol conformance scanning. If
41+
// this returns `true`, the protocol conformance scan will do extra work to
42+
// mimic the old override behavior.
43+
bool workaroundProtocolConformanceReverseIteration() {
44+
#if BINARY_COMPATIBILITY_APPLE
45+
// If this is a newer Apple OS ...
46+
if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) {
47+
const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301};
48+
// ... but the app was compiled before Spring 2021, use the legacy behavior.
49+
return !dyld_program_sdk_at_least(spring_2021_os_versions);
50+
} else {
51+
return false; // Use new (non-legacy) behavior on old Apple OSes
52+
}
53+
#else
54+
return false; // Never use the legacy behavior on non-Apple OSes
55+
#endif
56+
}
57+
58+
// Should the dynamic cast operation crash when it sees
59+
// a non-nullable Obj-C pointer with a null value?
60+
61+
// Obj-C does not strictly enforce non-nullability in all cases, so it is
62+
// possible for Obj-C code to pass null pointers into Swift code even when
63+
// declared non-nullable. Such null pointers can lead to undefined behavior
64+
// later on. Starting in Swift 5.4, these unexpected null pointers are fatal
65+
// runtime errors, but this is selectively disabled for old apps.
66+
bool unexpectedObjCNullWhileCastingIsFatal() {
67+
#if BINARY_COMPATIBILITY_APPLE
68+
// If this is a new enough Apple OS ...
69+
if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) {
70+
const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301};
71+
// ... use strict behavior for apps compiled on or after Spring 2021.
72+
return dyld_program_sdk_at_least(spring_2021_os_versions);
73+
} else {
74+
return false; // Use permissive behavior on old Apple OS
75+
}
76+
#else
77+
return true; // Always use the strict behavior on non-Apple OSes
78+
#endif
79+
}
80+
81+
// Should casting a nil optional to another optional
82+
// use the legacy semantics?
83+
84+
// For consistency, starting with Swift 5.4, casting Optional<Int> to
85+
// Optional<Optional<Int>> always wraps the source in another layer
86+
// of Optional.
87+
// Earlier versions of the Swift runtime did not do this if the source
88+
// optional was nil. In that case, the outer target optional would be
89+
// set to nil.
90+
bool useLegacyOptionalNilInjection() {
91+
#if BINARY_COMPATIBILITY_APPLE
92+
// If this is a new enough Apple OS ...
93+
if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) {
94+
const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301};
95+
// It's using Spring 2021 or later SDK, so don't use the legacy behavior.
96+
return !dyld_program_sdk_at_least(spring_2021_os_versions);
97+
} else {
98+
return true; // Use the legacy behavior on old Apple OS
99+
}
100+
#else
101+
return false; // Always use the 5.4 behavior on non-Apple OSes
102+
#endif
103+
}
26104

27105
} // namespace bincompat
28106

stdlib/public/runtime/DynamicCast.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "SwiftHashableSupport.h"
2121
#include "swift/ABI/MetadataValues.h"
2222
#include "swift/Basic/Lazy.h"
23+
#include "swift/Runtime/Bincompat.h"
2324
#include "swift/Runtime/Casting.h"
2425
#include "swift/Runtime/Config.h"
2526
#include "swift/Runtime/ExistentialContainer.h"
@@ -110,12 +111,6 @@ extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sh);
110111
/// Nominal type descriptor for Swift.String.
111112
extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SS);
112113

113-
// If this returns `true`, then we will call `fatalError` when we encounter a
114-
// null reference in a storage locaation whose type does not allow null.
115-
static bool unexpectedNullIsFatal() {
116-
return true; // Placeholder for an upcoming check.
117-
}
118-
119114
/// This issues a fatal error or warning if the srcValue contains a null object
120115
/// reference. It is used when the srcType is a non-nullable reference type, in
121116
/// which case it is dangerous to continue with a null reference. The null
@@ -134,7 +129,7 @@ static HeapObject * getNonNullSrcObject(OpaqueValue *srcValue,
134129
const char *msg = "Found unexpected null pointer value"
135130
" while trying to cast value of type '%s' (%p)"
136131
" to '%s' (%p)%s\n";
137-
if (unexpectedNullIsFatal()) {
132+
if (runtime::bincompat::unexpectedObjCNullWhileCastingIsFatal()) {
138133
// By default, Swift 5.4 and later issue a fatal error.
139134
swift::fatalError(/* flags = */ 0, msg,
140135
srcTypeName.c_str(), srcType,
@@ -1044,7 +1039,7 @@ initializeToNilAtDepth(OpaqueValue *destLocation, const Metadata *destType, int
10441039
}
10451040

10461041
static void
1047-
copyNil(OpaqueValue *destLocation, const Metadata *destType, const Metadata *srcType)
1042+
copyNilPreservingDepth(OpaqueValue *destLocation, const Metadata *destType, const Metadata *srcType)
10481043
{
10491044
assert(srcType->getKind() == MetadataKind::Optional);
10501045
assert(destType->getKind() == MetadataKind::Optional);
@@ -1087,7 +1082,13 @@ tryCastUnwrappingOptionalBoth(
10871082
srcValue, /*emptyCases=*/1);
10881083
auto sourceIsNil = (sourceEnumCase != 0);
10891084
if (sourceIsNil) {
1090-
copyNil(destLocation, destType, srcType);
1085+
if (runtime::bincompat::useLegacyOptionalNilInjection()) {
1086+
auto destInnerType = cast<EnumMetadata>(destType)->getGenericArgs()[0];
1087+
// Set .none at the outer level
1088+
destInnerType->vw_storeEnumTagSinglePayload(destLocation, 1, 1);
1089+
} else {
1090+
copyNilPreservingDepth(destLocation, destType, srcType);
1091+
}
10911092
return DynamicCastResult::SuccessViaCopy; // nil was essentially copied to dest
10921093
} else {
10931094
auto destEnumType = cast<EnumMetadata>(destType);

test/Casting/Casts.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ CastsTests.test("Dynamic cast to ObjC protocol") {
342342
#endif
343343

344344
// SR-6126
345-
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
345+
if #available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *) {
346346
CastsTests.test("Nil handling for Optionals and Arrays (SR-6126)") {
347347
func check(_ arg: Int??) -> String {
348348
switch arg {
@@ -621,6 +621,7 @@ CastsTests.test("NSNull?.none -> Any? should set outer nil") {
621621
}
622622
#endif
623623

624+
if #available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *) {
624625
CastsTests.test("Int??.some(nil) => Int??? should inject naturally") {
625626
let a: Int?? = .some(nil)
626627
let b = a as? Int???
@@ -629,7 +630,9 @@ CastsTests.test("Int??.some(nil) => Int??? should inject naturally") {
629630
let e = d!
630631
expectNil(e)
631632
}
633+
}
632634

635+
if #available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *) {
633636
CastsTests.test("Int??.some(nil) => String??? should inject naturally") {
634637
let a: Int?? = .some(nil)
635638
let b = runtimeCast(a, to: String???.self)
@@ -638,7 +641,9 @@ CastsTests.test("Int??.some(nil) => String??? should inject naturally") {
638641
let e = d!
639642
expectNil(e)
640643
}
644+
}
641645

646+
if #available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *) {
642647
CastsTests.test("Int??.some(nil) => Any??? should inject naturally") {
643648
let a: Int?? = .some(nil)
644649
let b = a as? Any???
@@ -647,6 +652,7 @@ CastsTests.test("Int??.some(nil) => Any??? should inject naturally") {
647652
let e = d!
648653
expectNil(e)
649654
}
655+
}
650656

651657
#if _runtime(_ObjC)
652658
CastsTests.test("NSString -> String fast path") {

test/Runtime/protocol_conformance_collision.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
// UNSUPPORTED: use_os_stdlib
1818

19-
// REQUIRES: rdar73049300
20-
2119
import Accelerate
2220
import Foundation
2321
import StdlibUnittest
@@ -48,10 +46,7 @@ func firstHashValue(_ x: P) -> Int {
4846
}
4947

5048
let osHasWorkaround: Bool
51-
// These are deliberately NOT version 9999, as we don't want to hit the special
52-
// case where development runtimes always return true for 9999. This check needs
53-
// to be false until real version numbers are put in.
54-
if #available(macOS 99990, iOS 99990, tvOS 99990, watchOS 99990, *) {
49+
if #available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *) {
5550
osHasWorkaround = true
5651
} else {
5752
osHasWorkaround = false

utils/find-overlay-deps-closure.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
set -o pipefail
1616
set -e
1717

18-
OVERLAY_NAME_ALTERNATION="AppKit|AssetsLibrary|AVFoundation|CallKit|CloudKit|Compression|Contacts|CoreAudio|CoreData|CoreGraphics|CoreImage|CoreLocation|CoreMedia|CryptoTokenKit|dispatch|Foundation|GameplayKit|GLKit|HomeKit|IOKit|Intents|MapKit|objc|OpenCL|os|Photos|QuartzCore|SafariServices|SceneKit|simd|SpriteKit|UIKit|WatchKit|XCTest|xpc"
18+
OVERLAY_NAME_ALTERNATION="AppKit|AssetsLibrary|AVFoundation|CallKit|CloudKit|Compression|Contacts|CoreAudio|CoreData|CoreGraphics|CoreImage|CoreLocation|CoreMedia|CoreML|CryptoTokenKit|dispatch|Foundation|GameplayKit|GLKit|HomeKit|IOKit|Intents|MapKit|objc|OpenCL|os|Photos|QuartzCore|SafariServices|SceneKit|simd|SpriteKit|UIKit|WatchKit|XCTest|xpc"
1919

2020
function find_deps() {
2121
local OVERLAY_ARG=$1

0 commit comments

Comments
 (0)