CustomAvailability: avoid exposing the synthesized function for dynamic availability checking as an API entry

For dynamic features defined from a header, we synthesize a pure Clang function to check whether the feature should
be enabled at runtime. Swift modules don't have capability to deserialize this clang predicate function, leading to
crasher as a result. This change fixes the crasher by hiding the synthesized function to be a module internal one.

rdar://164410957
This commit is contained in:
Xi Ge
2025-11-09 15:04:26 -08:00
parent 6b5abb6cdd
commit e31c1cc7f8
4 changed files with 78 additions and 4 deletions

View File

@@ -3183,9 +3183,7 @@ FuncDecl *SwiftDeclSynthesizer::makeAvailabilityDomainPredicate(
BuiltinIntegerType::get(1, ctx), ImporterImpl.ImportedHeaderUnit);
funcDecl->setBodySynthesizer(synthesizeAvailabilityDomainPredicateBody,
(void *)var);
funcDecl->setAccess(AccessLevel::Public);
funcDecl->addAttribute(
new (ctx) ExportAttr(ExportKind::Implementation, /*IsImplicit=*/true));
funcDecl->setAccess(AccessLevel::Internal);
ImporterImpl.availabilityDomainPredicates[var] = funcDecl;

View File

@@ -0,0 +1,33 @@
#ifndef __AVAILABILITY_DOMAIN_TEST_H
#define __AVAILABILITY_DOMAIN_TEST_H
#include <availability_domain.h>
int dynamic_domain_pred();
CLANG_ENABLED_AVAILABILITY_DOMAIN(EnabledDomain);
CLANG_DISABLED_AVAILABILITY_DOMAIN(DisabledDomain);
CLANG_DYNAMIC_AVAILABILITY_DOMAIN(DynamicDomain, dynamic_domain_pred);
#define AVAIL 0
#define UNAVAIL 1
__attribute__((availability(domain : EnabledDomain, AVAIL))) void
available_in_enabled_domain(void);
__attribute__((availability(domain : EnabledDomain, UNAVAIL))) void
unavailable_in_enabled_domain(void);
__attribute__((availability(domain : DisabledDomain, AVAIL))) void
available_in_disabled_domain(void);
__attribute__((availability(domain : DisabledDomain, UNAVAIL))) void
unavailable_in_disabled_domain(void);
__attribute__((availability(domain : DynamicDomain, AVAIL))) void
available_in_dynamic_domain(void);
__attribute__((availability(domain : DynamicDomain, UNAVAIL))) void
unavailable_in_dynamic_domain(void);
#endif // __AVAILABILITY_DOMAIN_TEST_H

View File

@@ -0,0 +1,43 @@
// REQUIRES: swift_feature_CustomAvailability
// RUN: %empty-directory(%t/mod)
// RUN: %target-swift-frontend -emit-module %s -o %t/mod/Foo.swiftmodule -parse-as-library -enable-library-evolution -module-name Foo -import-bridging-header %S/Inputs/AvailabilityDomains.h -enable-experimental-feature CustomAvailability -D FOO
// RUN: %target-swift-frontend -emit-module %s -o %t/mod/Bar.swiftmodule -parse-as-library -enable-library-evolution -module-name Bar -import-bridging-header %S/Inputs/AvailabilityDomains.h -enable-experimental-feature CustomAvailability -I %t/mod -D BAR
#if FOO
@available(DynamicDomain)
public struct X {
public init() { }
}
public struct Z {
public init() {
if #available(DynamicDomain) {
print("#available")
print(X())
} else {
print("#unavailable")
}
}
}
#endif
#if BAR
import Foo
public struct Y {
init() {
if #available(DynamicDomain) {
print("#available")
print(X())
print(Z())
} else {
print("#unavailable")
print(Z())
}
}
}
#endif

View File

@@ -101,7 +101,7 @@ public func testIfAvailableDynamicDomain() {
}
// CHECK: end sil function '$s4Test28testIfAvailableDynamicDomainyyF'
// CHECK-LABEL: sil non_abi [serialized] [ossa] @$sSC33__swift_DynamicDomain_isAvailableBi1_yF : $@convention(thin) () -> Builtin.Int1
// CHECK-LABEL: sil hidden [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