From d144524209452611a7939cbb7456fda6a7934893 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Mon, 17 Nov 2025 12:49:01 -0800 Subject: [PATCH] CustomAvailability: synthesized dynamic availability checking function should be private When compiling a Swift module in incremental mode, each Swift source file is compiled into an object file and we use linker to link them together. Because the predicate function for checking dynamic feature availability is eagerly synthesized per compilation unit, the linker will complain about duplicated symbols for them. Setting their visibility as private ensures that linker doesn't see them, thus addressing the linker errors. One workaround for this problem is to enable WMO. rdar://164971313 --- lib/ClangImporter/SwiftDeclSynthesizer.cpp | 2 +- test/Availability/Inputs/AvailabilityDomains.c | 5 +++++ .../Inputs/custom_availability_file1.swift | 15 +++++++++++++++ .../Inputs/custom_availability_file2.swift | 12 ++++++++++++ .../availability_custom_domains_clang_build.swift | 6 ++++++ .../availability_query_custom_domains_clang.swift | 2 +- 6 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 test/Availability/Inputs/AvailabilityDomains.c create mode 100644 test/Availability/Inputs/custom_availability_file1.swift create mode 100644 test/Availability/Inputs/custom_availability_file2.swift create mode 100644 test/Availability/availability_custom_domains_clang_build.swift diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.cpp b/lib/ClangImporter/SwiftDeclSynthesizer.cpp index 40ed851c99a31..19b774af92d83 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.cpp +++ b/lib/ClangImporter/SwiftDeclSynthesizer.cpp @@ -3183,7 +3183,7 @@ FuncDecl *SwiftDeclSynthesizer::makeAvailabilityDomainPredicate( BuiltinIntegerType::get(1, ctx), ImporterImpl.ImportedHeaderUnit); funcDecl->setBodySynthesizer(synthesizeAvailabilityDomainPredicateBody, (void *)var); - funcDecl->setAccess(AccessLevel::Internal); + funcDecl->setAccess(AccessLevel::Private); ImporterImpl.availabilityDomainPredicates[var] = funcDecl; diff --git a/test/Availability/Inputs/AvailabilityDomains.c b/test/Availability/Inputs/AvailabilityDomains.c new file mode 100644 index 0000000000000..a33c881207ee1 --- /dev/null +++ b/test/Availability/Inputs/AvailabilityDomains.c @@ -0,0 +1,5 @@ +#include "AvailabilityDomains.h" + +int dynamic_domain_pred() { + return 1; +} diff --git a/test/Availability/Inputs/custom_availability_file1.swift b/test/Availability/Inputs/custom_availability_file1.swift new file mode 100644 index 0000000000000..7138211ee3e4d --- /dev/null +++ b/test/Availability/Inputs/custom_availability_file1.swift @@ -0,0 +1,15 @@ +@available(DynamicDomain) +public struct X { + public init() { } +} + +public struct Z { + public init() { + if #available(DynamicDomain) { + print("#available") + print(X()) + } else { + print("#unavailable") + } + } +} diff --git a/test/Availability/Inputs/custom_availability_file2.swift b/test/Availability/Inputs/custom_availability_file2.swift new file mode 100644 index 0000000000000..f1d340dd10cbc --- /dev/null +++ b/test/Availability/Inputs/custom_availability_file2.swift @@ -0,0 +1,12 @@ +public struct Y { + init() { + if #available(DynamicDomain) { + print("#available") + print(X()) + print(Z()) + } else { + print("#unavailable") + print(Z()) + } + } +} diff --git a/test/Availability/availability_custom_domains_clang_build.swift b/test/Availability/availability_custom_domains_clang_build.swift new file mode 100644 index 0000000000000..6cb43e976b455 --- /dev/null +++ b/test/Availability/availability_custom_domains_clang_build.swift @@ -0,0 +1,6 @@ +// REQUIRES: swift_feature_CustomAvailability + +// RUN: %empty-directory(%t) +// RUN: %target-clang -x c %S/Inputs/AvailabilityDomains.c -o %t/AvailabilityDomains.c.o -c +// RUN: %target-build-swift -emit-library %S/Inputs/custom_availability_file1.swift %S/Inputs/custom_availability_file2.swift -module-name main -enable-experimental-feature CustomAvailability -import-bridging-header %S/Inputs/AvailabilityDomains.h -Xlinker %t/AvailabilityDomains.c.o +// RUN: %target-build-swift -wmo -emit-library %S/Inputs/custom_availability_file1.swift %S/Inputs/custom_availability_file2.swift -module-name main -enable-experimental-feature CustomAvailability -import-bridging-header %S/Inputs/AvailabilityDomains.h -Xlinker %t/AvailabilityDomains.c.o diff --git a/test/SILGen/availability_query_custom_domains_clang.swift b/test/SILGen/availability_query_custom_domains_clang.swift index c13e3b92cc4a1..ccfc6aae16ed4 100644 --- a/test/SILGen/availability_query_custom_domains_clang.swift +++ b/test/SILGen/availability_query_custom_domains_clang.swift @@ -101,7 +101,7 @@ public func testIfAvailableDynamicDomain() { } // CHECK: end sil function '$s4Test28testIfAvailableDynamicDomainyyF' -// CHECK-LABEL: sil hidden [ossa] @$sSC33__swift_DynamicDomain_isAvailableBi1_yF : $@convention(thin) () -> Builtin.Int1 +// CHECK-LABEL: sil private [ossa] @$sSC33__swift_DynamicDomain_isAvailableBi1_yF : $@convention(thin) () -> Builtin.Int1 // CHECK: bb0: // CHECK: [[QUERY_FUNC:%.*]] = function_ref @$sSo27__DynamicDomain_isAvailableSbyFTo : $@convention(c) () -> Bool // CHECK: [[QUERY_RESULT:%.*]] = apply [[QUERY_FUNC]]() : $@convention(c) () -> Bool