Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/modules/DarwinSDKs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ endif()
set(SUPPORTED_TVOS_ARCHS "arm64")
set(SUPPORTED_TVOS_SIMULATOR_ARCHS "x86_64;arm64")
set(SUPPORTED_WATCHOS_ARCHS "armv7k")
set(SUPPORTED_WATCHOS_SIMULATOR_ARCHS "i386;arm64")
set(SUPPORTED_WATCHOS_SIMULATOR_ARCHS "i386;x86_64;arm64")
set(SUPPORTED_OSX_ARCHS "x86_64;arm64;arm64e")

is_sdk_requested(OSX swift_build_osx)
Expand Down
10 changes: 10 additions & 0 deletions include/swift/Runtime/Bincompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,18 @@ namespace bincompat {

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

/// Whether we should crash when we encounter a non-nullable Obj-C
/// reference with a null value as the source of a cast.
/// Default is true starting with Swift 5.4.
bool unexpectedObjCNullWhileCastingIsFatal();

/// Whether we should use the legacy semantics for casting nil optionals
/// to nested optionals
bool useLegacyOptionalNilInjection();

} // namespace bincompat

} // namespace runtime
Expand Down
3 changes: 3 additions & 0 deletions lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ AvailabilityContext ASTContext::getSwift50Availability() {
return AvailabilityContext(
VersionRange::allGTE(llvm::VersionTuple(12,2)));
} else if (target.isWatchOS()) {
if (target.getArch() == llvm::Triple::ArchType::x86_64)
return AvailabilityContext::alwaysAvailable();

return AvailabilityContext(
VersionRange::allGTE(llvm::VersionTuple(5,2)));
} else {
Expand Down
80 changes: 79 additions & 1 deletion stdlib/public/runtime/Bincompat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,92 @@
//===----------------------------------------------------------------------===//

#include "swift/Runtime/Bincompat.h"
#include <stdint.h>

// If this is an Apple OS, use the Apple binary compatibility rules
#if __has_include(<mach-o/dyld_priv.h>)
#include <mach-o/dyld_priv.h>
#ifndef BINARY_COMPATIBILITY_APPLE
#define BINARY_COMPATIBILITY_APPLE 1
#endif
#else
#undef BINARY_COMPATIBILITY_APPLE
#endif

namespace swift {

namespace runtime {

namespace bincompat {

bool workaroundProtocolConformanceReverseIteration() { return false; }
// Should we mimic the old override behavior when scanning protocol conformance records?

// Old apps expect protocol conformances to override each other in a particular
// order. Starting with Swift 5.4, that order has changed as a result of
// significant performance improvements to protocol conformance scanning. If
// this returns `true`, the protocol conformance scan will do extra work to
// mimic the old override behavior.
bool workaroundProtocolConformanceReverseIteration() {
#if BINARY_COMPATIBILITY_APPLE
// If this is a newer Apple OS ...
if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) {
const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301};
// ... but the app was compiled before Spring 2021, use the legacy behavior.
return !dyld_program_sdk_at_least(spring_2021_os_versions);
} else {
return false; // Use new (non-legacy) behavior on old Apple OSes
}
#else
return false; // Never use the legacy behavior on non-Apple OSes
#endif
}

// Should the dynamic cast operation crash when it sees
// a non-nullable Obj-C pointer with a null value?

// Obj-C does not strictly enforce non-nullability in all cases, so it is
// possible for Obj-C code to pass null pointers into Swift code even when
// declared non-nullable. Such null pointers can lead to undefined behavior
// later on. Starting in Swift 5.4, these unexpected null pointers are fatal
// runtime errors, but this is selectively disabled for old apps.
bool unexpectedObjCNullWhileCastingIsFatal() {
#if BINARY_COMPATIBILITY_APPLE
// If this is a new enough Apple OS ...
if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) {
const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301};
// ... use strict behavior for apps compiled on or after Spring 2021.
return dyld_program_sdk_at_least(spring_2021_os_versions);
} else {
return false; // Use permissive behavior on old Apple OS
}
#else
return true; // Always use the strict behavior on non-Apple OSes
#endif
}

// Should casting a nil optional to another optional
// use the legacy semantics?

// For consistency, starting with Swift 5.4, casting Optional<Int> to
// Optional<Optional<Int>> always wraps the source in another layer
// of Optional.
// Earlier versions of the Swift runtime did not do this if the source
// optional was nil. In that case, the outer target optional would be
// set to nil.
bool useLegacyOptionalNilInjection() {
#if BINARY_COMPATIBILITY_APPLE
// If this is a new enough Apple OS ...
if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) {
const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301};
// It's using Spring 2021 or later SDK, so don't use the legacy behavior.
return !dyld_program_sdk_at_least(spring_2021_os_versions);
} else {
return true; // Use the legacy behavior on old Apple OS
}
#else
return false; // Always use the 5.4 behavior on non-Apple OSes
#endif
}

} // namespace bincompat

Expand Down
19 changes: 10 additions & 9 deletions stdlib/public/runtime/DynamicCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "SwiftHashableSupport.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/Basic/Lazy.h"
#include "swift/Runtime/Bincompat.h"
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Config.h"
#include "swift/Runtime/ExistentialContainer.h"
Expand Down Expand Up @@ -110,12 +111,6 @@ extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sh);
/// Nominal type descriptor for Swift.String.
extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SS);

// If this returns `true`, then we will call `fatalError` when we encounter a
// null reference in a storage locaation whose type does not allow null.
static bool unexpectedNullIsFatal() {
return true; // Placeholder for an upcoming check.
}

/// This issues a fatal error or warning if the srcValue contains a null object
/// reference. It is used when the srcType is a non-nullable reference type, in
/// which case it is dangerous to continue with a null reference. The null
Expand All @@ -134,7 +129,7 @@ static HeapObject * getNonNullSrcObject(OpaqueValue *srcValue,
const char *msg = "Found unexpected null pointer value"
" while trying to cast value of type '%s' (%p)"
" to '%s' (%p)%s\n";
if (unexpectedNullIsFatal()) {
if (runtime::bincompat::unexpectedObjCNullWhileCastingIsFatal()) {
// By default, Swift 5.4 and later issue a fatal error.
swift::fatalError(/* flags = */ 0, msg,
srcTypeName.c_str(), srcType,
Expand Down Expand Up @@ -1044,7 +1039,7 @@ initializeToNilAtDepth(OpaqueValue *destLocation, const Metadata *destType, int
}

static void
copyNil(OpaqueValue *destLocation, const Metadata *destType, const Metadata *srcType)
copyNilPreservingDepth(OpaqueValue *destLocation, const Metadata *destType, const Metadata *srcType)
{
assert(srcType->getKind() == MetadataKind::Optional);
assert(destType->getKind() == MetadataKind::Optional);
Expand Down Expand Up @@ -1087,7 +1082,13 @@ tryCastUnwrappingOptionalBoth(
srcValue, /*emptyCases=*/1);
auto sourceIsNil = (sourceEnumCase != 0);
if (sourceIsNil) {
copyNil(destLocation, destType, srcType);
if (runtime::bincompat::useLegacyOptionalNilInjection()) {
auto destInnerType = cast<EnumMetadata>(destType)->getGenericArgs()[0];
// Set .none at the outer level
destInnerType->vw_storeEnumTagSinglePayload(destLocation, 1, 1);
} else {
copyNilPreservingDepth(destLocation, destType, srcType);
}
return DynamicCastResult::SuccessViaCopy; // nil was essentially copied to dest
} else {
auto destEnumType = cast<EnumMetadata>(destType);
Expand Down
8 changes: 7 additions & 1 deletion test/Casting/Casts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ CastsTests.test("Dynamic cast to ObjC protocol") {
#endif

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

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

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

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

#if _runtime(_ObjC)
CastsTests.test("NSString -> String fast path") {
Expand Down
2 changes: 2 additions & 0 deletions test/IRGen/abitypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class Foo {
// i386-watchos: define hidden void @"$s8abitypes3FooC3bar{{[_0-9a-zA-Z]*}}FTo"(%TSo6MyRectV* noalias nocapture sret %0, i8* %1, i8* %2) {{[#0-9]*}} {
// armv7k-watchos: define hidden swiftcc { float, float, float, float } @"$s8abitypes3FooC3bar{{[_0-9a-zA-Z]*}}F"(%T8abitypes3FooC* swiftself %0) {{.*}} {
// armv7k-watchos: define hidden [[ARMV7K_MYRECT]] @"$s8abitypes3FooC3bar{{[_0-9a-zA-Z]*}}FTo"(i8* %0, i8* %1) {{[#0-9]*}} {
// x86_64-watchos: define hidden swiftcc { float, float, float, float } @"$s8abitypes3FooC3bar{{[_0-9a-zA-Z]*}}F"(%T8abitypes3FooC* swiftself %0) {{.*}} {
// x86_64-watchos: define hidden { <2 x float>, <2 x float> } @"$s8abitypes3FooC3bar{{[_0-9a-zA-Z]*}}FTo"(i8* %0, i8* %1) {{[#0-9]*}} {
@objc dynamic func bar() -> MyRect {
return MyRect(x: 1, y: 2, width: 3, height: 4)
}
Expand Down
1 change: 1 addition & 0 deletions test/IRGen/class_update_callback_with_fixed_layout.sil
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

// REQUIRES: objc_interop
// REQUIRES: CPU=x86_64
// UNSUPPORTED: swift_only_stable_abi

sil_stage canonical

Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ enum Singleton {
// Check that the instance start is after the header (at 8 or 16).
// CHECK-macosx: _DATA__TtC1A1G = internal constant {{.*}} { i32 {{(128|129)}}, i32 {{(16|8|40)}}
// CHECK-ios: _DATA__TtC1A1G = internal constant {{.*}} { i32 {{(128|129)}}, i32 {{(16|8|40)}}
// CHECK-watchos: _DATA__TtC1A1G = internal constant {{.*}} { i32 128, i32 {{(16|8)}}
// CHECK-watchos: _DATA__TtC1A1G = internal constant {{.*}} { i32 {{(128|129)}}, i32 {{(16|8|40)}}
// CHECK-tvos: _DATA__TtC1A1G = internal constant {{.*}} { i32 128, i32 {{(16|8)}}

class G {
Expand Down
6 changes: 5 additions & 1 deletion test/IRGen/objc_methods.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// RUN: %empty-directory(%t)
// RUN: %build-irgen-test-overlays
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-os %s
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-os-abi %s

// REQUIRES: CPU=x86_64
// REQUIRES: objc_interop

// rdar://76863553
// UNSUPPORTED: OS=watchos && CPU=x86_64

import Foundation

// Protocol methods require extended method type encodings to capture block
Expand Down Expand Up @@ -50,6 +53,7 @@ class ObjcDestructible: NSObject {
// CHECK-macosx: [[FAIL_SIGNATURE:@.*]] = private unnamed_addr constant [12 x i8] c"c24@0:8^@16\00"
// CHECK-ios: [[FAIL_SIGNATURE:@.*]] = private unnamed_addr constant [12 x i8] c"B24@0:8^@16\00"
// CHECK-tvos: [[FAIL_SIGNATURE:@.*]] = private unnamed_addr constant [12 x i8] c"B24@0:8^@16\00"
// CHECK-watchos: [[FAIL_SIGNATURE:@.*]] = private unnamed_addr constant [12 x i8] c"B24@0:8^@16\00"
// CHECK: @_INSTANCE_METHODS__TtC12objc_methods3Foo = internal constant { {{.*}}] } {
// CHECK: i32 24,
// CHECK: i32 10,
Expand Down
Loading