diff --git a/include/swift/AST/PlatformKinds.def b/include/swift/AST/PlatformKinds.def index 9b2fcdadd554a..885bd81c16850 100644 --- a/include/swift/AST/PlatformKinds.def +++ b/include/swift/AST/PlatformKinds.def @@ -37,5 +37,6 @@ AVAILABILITY_PLATFORM(macCatalystApplicationExtension, "application extensions f AVAILABILITY_PLATFORM(FreeBSD, "FreeBSD") AVAILABILITY_PLATFORM(OpenBSD, "OpenBSD") AVAILABILITY_PLATFORM(Windows, "Windows") +AVAILABILITY_PLATFORM(Android, "Android") #undef AVAILABILITY_PLATFORM diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 7709fc11dac54..ffe1c72ed3ec2 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -2133,6 +2133,16 @@ FUNCTION(TSanInoutAccess, tsan, __tsan_external_write, C_CC, AlwaysAvailable, EFFECT(RuntimeEffect::NoEffect), UNKNOWN_MEMEFFECTS) +// int32 __isOSVersionAtLeast(uint32_t major, uint32_t minor, uint32_t patch); +// This a C builtin provided by compiler-rt. +FUNCTION(OSVersionAtLeast, libgcc, __isOSVersionAtLeast, + C_CC, AlwaysAvailable, + RETURNS(Int32Ty), + ARGS(Int32Ty, Int32Ty, Int32Ty), + ATTRS(NoUnwind), + EFFECT(RuntimeEffect::NoEffect), + UNKNOWN_MEMEFFECTS) + // int32 __isPlatformVersionAtLeast(uint32_t platform, uint32_t major, // uint32_t minor, uint32_t patch); // This a C builtin provided by compiler-rt. diff --git a/lib/AST/PlatformKindUtils.cpp b/lib/AST/PlatformKindUtils.cpp index e54e6be019bee..bf8fca3bad5d1 100644 --- a/lib/AST/PlatformKindUtils.cpp +++ b/lib/AST/PlatformKindUtils.cpp @@ -118,6 +118,7 @@ swift::basePlatformForExtensionPlatform(PlatformKind Platform) { case PlatformKind::FreeBSD: case PlatformKind::OpenBSD: case PlatformKind::Windows: + case PlatformKind::Android: case PlatformKind::none: return std::nullopt; } @@ -164,6 +165,8 @@ static bool isPlatformActiveForTarget(PlatformKind Platform, return Target.isOSFreeBSD(); case PlatformKind::Windows: return Target.isOSWindows(); + case PlatformKind::Android: + return Target.isAndroid(); case PlatformKind::none: llvm_unreachable("handled above"); } @@ -219,6 +222,10 @@ static PlatformKind platformForTriple(const llvm::Triple &triple, : PlatformKind::visionOS); } + if (triple.isAndroid()) { + return PlatformKind::Android; + } + return PlatformKind::none; } @@ -291,6 +298,8 @@ swift::tripleOSTypeForPlatform(PlatformKind platform) { return llvm::Triple::OpenBSD; case PlatformKind::Windows: return llvm::Triple::Win32; + case PlatformKind::Android: + return llvm::Triple::Linux; case PlatformKind::none: return std::nullopt; } @@ -326,6 +335,7 @@ bool swift::isPlatformSPI(PlatformKind Platform) { case PlatformKind::OpenBSD: case PlatformKind::FreeBSD: case PlatformKind::Windows: + case PlatformKind::Android: case PlatformKind::none: return false; } diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index 8906bce54be32..8c6f1200c0a39 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -301,6 +301,8 @@ llvm::VersionTuple swift::getVersionForTriple(const llvm::Triple &triple) { return triple.getOSVersion(); } else if (triple.isOSWindows()) { return triple.getOSVersion(); + } else if (triple.isAndroid()) { + return triple.getEnvironmentVersion(); } return llvm::VersionTuple(/*Major=*/0, /*Minor=*/0, /*Subminor=*/0); } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 9d0bed0087c8d..4301af40d09f4 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -665,6 +665,12 @@ void importer::getNormalInvocationArguments( }); } + if (triple.isAndroid()) { + invocationArgStrs.insert(invocationArgStrs.end(), { + "-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__", + }); + } + if (triple.isOSWindows()) { switch (triple.getArch()) { default: llvm_unreachable("unsupported Windows architecture"); @@ -2568,6 +2574,10 @@ PlatformAvailability::PlatformAvailability(const LangOptions &langOpts) deprecatedAsUnavailableMessage = ""; break; + case PlatformKind::Android: + deprecatedAsUnavailableMessage = ""; + break; + case PlatformKind::none: break; } @@ -2616,6 +2626,9 @@ bool PlatformAvailability::isPlatformRelevant(StringRef name) const { case PlatformKind::Windows: return name == "windows"; + case PlatformKind::Android: + return name == "android"; + case PlatformKind::none: return false; } @@ -2692,6 +2705,10 @@ bool PlatformAvailability::treatDeprecatedAsUnavailable( case PlatformKind::Windows: // No deprecation filter on Windows return false; + + case PlatformKind::Android: + // The minimum Android API level supported by Swift is 21 + return major <= 20; } llvm_unreachable("Unexpected platform"); diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 13750fee1c517..4ea5a89aaf4bc 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -9855,6 +9855,7 @@ void ClangImporter::Implementation::importAttributes( PlatformKind::watchOSApplicationExtension) .Case("xros_app_extension", PlatformKind::visionOSApplicationExtension) + .Case("android", PlatformKind::Android) .Default(std::nullopt); if (!platformK) continue; diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp index 34606f3353a9a..ffc4cd94919cd 100644 --- a/lib/IRGen/IRGenFunction.cpp +++ b/lib/IRGen/IRGenFunction.cpp @@ -307,11 +307,18 @@ llvm::Value * IRGenFunction::emitTargetOSVersionAtLeastCall(llvm::Value *major, llvm::Value *minor, llvm::Value *patch) { - auto fn = IGM.getPlatformVersionAtLeastFunctionPointer(); + // compiler-rt in the NDK does not include __isPlatformVersionAtLeast + // but only __isOSVersionAtLeast + if (IGM.Triple.isAndroid()) { + auto fn = IGM.getOSVersionAtLeastFunctionPointer(); + return Builder.CreateCall(fn, {major, minor, patch}); + } else { + auto fn = IGM.getPlatformVersionAtLeastFunctionPointer(); - llvm::Value *platformID = - llvm::ConstantInt::get(IGM.Int32Ty, getBaseMachOPlatformID(IGM.Triple)); - return Builder.CreateCall(fn, {platformID, major, minor, patch}); + llvm::Value *platformID = + llvm::ConstantInt::get(IGM.Int32Ty, getBaseMachOPlatformID(IGM.Triple)); + return Builder.CreateCall(fn, {platformID, major, minor, patch}); + } } llvm::Value * diff --git a/lib/IRGen/TBDGen.cpp b/lib/IRGen/TBDGen.cpp index 5512e5062e0a9..5fcb78af93c44 100644 --- a/lib/IRGen/TBDGen.cpp +++ b/lib/IRGen/TBDGen.cpp @@ -251,6 +251,8 @@ getLinkerPlatformId(OriginallyDefinedInAttr::ActiveVersion Ver, llvm_unreachable("not used for this platform"); case swift::PlatformKind::Windows: llvm_unreachable("not used for this platform"); + case swift::PlatformKind::Android: + llvm_unreachable("not used for this platform"); case swift::PlatformKind::iOS: case swift::PlatformKind::iOSApplicationExtension: if (target && target->isMacCatalystEnvironment()) diff --git a/lib/PrintAsClang/DeclAndTypePrinter.cpp b/lib/PrintAsClang/DeclAndTypePrinter.cpp index ea84364f60407..868238a4e8d32 100644 --- a/lib/PrintAsClang/DeclAndTypePrinter.cpp +++ b/lib/PrintAsClang/DeclAndTypePrinter.cpp @@ -1830,6 +1830,9 @@ class DeclAndTypePrinter::Implementation case PlatformKind::Windows: plat = "windows"; break; + case PlatformKind::Android: + plat = "android"; + break; case PlatformKind::none: llvm_unreachable("handled above"); } diff --git a/lib/SymbolGraphGen/AvailabilityMixin.cpp b/lib/SymbolGraphGen/AvailabilityMixin.cpp index 4678641bf1598..6da42c72e55dc 100644 --- a/lib/SymbolGraphGen/AvailabilityMixin.cpp +++ b/lib/SymbolGraphGen/AvailabilityMixin.cpp @@ -60,6 +60,8 @@ StringRef getDomain(const SemanticAvailableAttr &AvAttr) { return { "OpenBSD" }; case swift::PlatformKind::Windows: return { "Windows" }; + case swift::PlatformKind::Android: + return { "Android" }; case swift::PlatformKind::none: return { "*" }; } diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index e47c9db33ab65..b2d4e34bc98a3 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -2250,6 +2250,9 @@ function(add_swift_target_library name) elseif(sdk STREQUAL "LINUX") list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_LINUX}) + elseif(sdk STREQUAL "ANDROID") + list(APPEND swiftlib_module_depends_flattened + ${SWIFTLIB_SWIFT_MODULE_DEPENDS_ANDROID}) elseif(sdk STREQUAL "LINUX_STATIC") list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_LINUX_STATIC}) @@ -2541,6 +2544,11 @@ function(add_swift_target_library name) list(APPEND swiftlib_link_flags_all "-Wl,-z,max-page-size=16384") endif() + # This is a Android-specific hack till we transition the stdlib fully to versioned triples. + if(sdk STREQUAL "ANDROID" AND name STREQUAL "swiftSwiftReflectionTest") + list(APPEND swiftlib_swift_compile_flags_all "-target" "${SWIFT_SDK_ANDROID_ARCH_${arch}_TRIPLE}${SWIFT_ANDROID_API_LEVEL}") + endif() + if (SWIFTLIB_BACK_DEPLOYMENT_LIBRARY) set(back_deployment_library_option BACK_DEPLOYMENT_LIBRARY ${SWIFTLIB_BACK_DEPLOYMENT_LIBRARY}) else() diff --git a/stdlib/public/core/Availability.swift b/stdlib/public/core/Availability.swift index 08880a2ee57d5..0fd92086e961d 100644 --- a/stdlib/public/core/Availability.swift +++ b/stdlib/public/core/Availability.swift @@ -75,7 +75,7 @@ public func _stdlib_isOSVersionAtLeast_AEIC( _ minor: Builtin.Word, _ patch: Builtin.Word ) -> Builtin.Int1 { -#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(visionOS)) && SWIFT_RUNTIME_OS_VERSIONING +#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) || os(Android)) && SWIFT_RUNTIME_OS_VERSIONING if Int(major) == 9999 { return true._value } diff --git a/test/ClangImporter/Inputs/custom-modules/AndroidVersioning.h b/test/ClangImporter/Inputs/custom-modules/AndroidVersioning.h new file mode 100644 index 0000000000000..813d9b9fa7137 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/AndroidVersioning.h @@ -0,0 +1,5 @@ +#include + +void FunctionIntroducedIn24() __INTRODUCED_IN(24); +void FunctionIntroducedIn28() __INTRODUCED_IN(28); + diff --git a/test/ClangImporter/Inputs/custom-modules/module.modulemap b/test/ClangImporter/Inputs/custom-modules/module.modulemap index b37985ec675e0..7332d7d643539 100644 --- a/test/ClangImporter/Inputs/custom-modules/module.modulemap +++ b/test/ClangImporter/Inputs/custom-modules/module.modulemap @@ -2,6 +2,11 @@ module script { header "script.h" } +module AndroidVersioning { + header "AndroidVersioning.h" + export * +} + module AvailabilityExtras { header "AvailabilityExtras.h" export * diff --git a/test/ClangImporter/android-sdk-macros.swift b/test/ClangImporter/android-sdk-macros.swift new file mode 100644 index 0000000000000..3eee516879a2a --- /dev/null +++ b/test/ClangImporter/android-sdk-macros.swift @@ -0,0 +1,4 @@ +// RUN: %swift -target aarch64-unknown-linux-android28 -typecheck %s -parse-stdlib -dump-clang-diagnostics 2>&1 | %FileCheck %s -check-prefix CHECK-WEAK-SYMBOLS + +// CHECK-WEAK-SYMBOLS: -D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__ + diff --git a/test/ClangImporter/availability_android.swift b/test/ClangImporter/availability_android.swift new file mode 100644 index 0000000000000..bab53776770b2 --- /dev/null +++ b/test/ClangImporter/availability_android.swift @@ -0,0 +1,26 @@ +// RUN: %target-swift-frontend -typecheck -verify -I %S/Inputs/custom-modules -verify-ignore-unknown -target aarch64-unknown-linux-android24 %s + +// REQUIRES: OS=linux-android || OS=linux-androideabi + +import AndroidVersioning +import Android + +FunctionIntroducedIn24() + +FunctionIntroducedIn28() +// expected-error@-1 {{'FunctionIntroducedIn28()' is only available in Android 28 or newer}} +// expected-note@-2 {{add 'if #available' version check}} + +func test_ifaddrs_introduced_in_24() { + var ifaddr_ptr: UnsafeMutablePointer? = nil + if getifaddrs(&ifaddr_ptr) == 0 { + freeifaddrs(ifaddr_ptr) + } +} + +func test_getentropy_introduced_in_28() { + var buffer: [UInt8] = .init(repeating: 0, count: 16) + getentropy(&buffer, buffer.count) + // expected-error@-1 {{'getentropy' is only available in Android 28 or newer}} + // expected-note@-2 {{add 'if #available' version check}} +} \ No newline at end of file diff --git a/test/IRGen/availability_android.swift b/test/IRGen/availability_android.swift new file mode 100644 index 0000000000000..470eaa8a9462f --- /dev/null +++ b/test/IRGen/availability_android.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-frontend -target aarch64-unknown-linux-android24 -primary-file %s -emit-ir | %FileCheck %s + +// CHECK-LABEL: define{{.*}}$s20availability_android0A5CheckyyF +// CHECK: call swiftcc i1 @"$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF"( + +// REQUIRES: OS=linux-android || OS=linux-androideabi + +public func availabilityCheck() { + if #available(Android 28, *) { + print("test") + } +} diff --git a/test/attr/attr_availability_android.swift b/test/attr/attr_availability_android.swift new file mode 100644 index 0000000000000..560c361a1cb9e --- /dev/null +++ b/test/attr/attr_availability_android.swift @@ -0,0 +1,59 @@ +// RUN: %swift -typecheck -verify -parse-stdlib -target aarch64-unknown-linux-android28 %s + +@available(Android, introduced: 1.0, deprecated: 2.0, obsoleted: 28.0, + message: "you don't want to do that anyway") +func doSomething() { } +// expected-note @-1{{'doSomething()' was obsoleted in Android 28.0}} + +doSomething() // expected-error{{'doSomething()' is unavailable in Android: you don't want to do that anyway}} + +// Preservation of major.minor.micro +@available(Android, introduced: 1.0, deprecated: 2.0, obsoleted: 27.0) +func doSomethingElse() { } +// expected-note @-1{{'doSomethingElse()' was obsoleted in Android 27.0}} + +doSomethingElse() // expected-error{{'doSomethingElse()' is unavailable in Android}} + +// Test deprecations in 28.0 and later + +@available(Android, introduced: 1.1, deprecated: 28.0, + message: "Use another function") +func deprecatedFunctionWithMessage() { } + +deprecatedFunctionWithMessage() // expected-warning{{'deprecatedFunctionWithMessage()' was deprecated in Android 28.0: Use another function}} + + +@available(Android, introduced: 1.0, deprecated: 28.0) +func deprecatedFunctionWithoutMessage() { } + +deprecatedFunctionWithoutMessage() // expected-warning{{'deprecatedFunctionWithoutMessage()' was deprecated in Android 28.0}} + +@available(Android, introduced: 1.0, deprecated: 28.0, + message: "Use BetterClass instead") +class DeprecatedClass { } + +func functionWithDeprecatedParameter(p: DeprecatedClass) { } // expected-warning{{'DeprecatedClass' was deprecated in Android 28.0: Use BetterClass instead}} + +@available(tvOS, introduced: 7.0, deprecated: 29, + message: "Use BetterClass instead") +class DeprecatedClassIn29_0 { } + +// Elements deprecated later than the minimum deployment target (which is 28.0, in this case) should not generate warnings +func functionWithDeprecatedLaterParameter(p: DeprecatedClassIn29_0) { } + +@available(Android, introduced: 30) +func functionIntroducedOnAndroid30() { } + +if #available(iOS 17.3, *) { + functionIntroducedOnAndroid30() // expected-error{{'functionIntroducedOnAndroid30()' is only available in Android 30 or newer}} + // expected-note @-1{{add 'if #available' version check}}{{3-34=if #available(Android 30, *) {\n functionIntroducedOnAndroid30()\n \} else {\n // Fallback on earlier versions\n \}}} +} + +if #available(Android 28, *) { + functionIntroducedOnAndroid30() // expected-error{{'functionIntroducedOnAndroid30()' is only available in Android 30 or newer}} + // expected-note @-1{{add 'if #available' version check}}{{3-34=if #available(Android 30, *) {\n functionIntroducedOnAndroid30()\n \} else {\n // Fallback on earlier versions\n \}}} +} + +if #available(Android 30, *) { + functionIntroducedOnAndroid30() +} diff --git a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp index c5d2c5f3b2612..211f88ff38bf1 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp @@ -688,6 +688,7 @@ static void reportAvailabilityAttributes(ASTContext &Ctx, const Decl *D, static UIdent PlatformFreeBSD("source.availability.platform.freebsd"); static UIdent PlatformOpenBSD("source.availability.platform.openbsd"); static UIdent PlatformWindows("source.availability.platform.windows"); + static UIdent PlatformAndroid("source.availability.platform.android"); std::vector Scratch; for (auto Attr : getAvailableAttrs(D, Scratch)) { @@ -743,6 +744,9 @@ static void reportAvailabilityAttributes(ASTContext &Ctx, const Decl *D, case PlatformKind::Windows: PlatformUID = PlatformWindows; break; + case PlatformKind::Android: + PlatformUID = PlatformAndroid; + break; } // FIXME: [availability] Handle other availability domains?