Skip to content

Commit 1255a5c

Browse files
committed
[Clang importer] Make sure an unavailable superclass init doesn't override an available import-as-member-init.
More generally, an unavailable initializer shouldn't stomp on an available initializer, because it's possible that (for example) a designated initializer will be unavailable but a factory initializer will be available, so one still construct objects of that type. Fixes rdar://problem/26238032.
1 parent ee4d9d3 commit 1255a5c

File tree

5 files changed

+63
-25
lines changed

5 files changed

+63
-25
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,30 +1650,7 @@ static bool hasErrorMethodNameCollision(ClangImporter::Implementation &importer,
16501650
// been marked NS_SWIFT_UNAVAILABLE, because it's actually marked unavailable,
16511651
// or because it was deprecated before our API sunset. We can handle
16521652
// "conflicts" where one form is unavailable.
1653-
// FIXME: Somewhat duplicated from Implementation::importAttributes.
1654-
clang::AvailabilityResult availability = conflict->getAvailability();
1655-
if (availability != clang::AR_Unavailable &&
1656-
importer.DeprecatedAsUnavailableFilter) {
1657-
for (auto *attr : conflict->specific_attrs<clang::AvailabilityAttr>()) {
1658-
if (attr->getPlatform()->getName() == "swift") {
1659-
availability = clang::AR_Unavailable;
1660-
break;
1661-
}
1662-
if (importer.PlatformAvailabilityFilter &&
1663-
!importer.PlatformAvailabilityFilter(attr->getPlatform()->getName())){
1664-
continue;
1665-
}
1666-
clang::VersionTuple version = attr->getDeprecated();
1667-
if (version.empty())
1668-
continue;
1669-
if (importer.DeprecatedAsUnavailableFilter(version.getMajor(),
1670-
version.getMinor())) {
1671-
availability = clang::AR_Unavailable;
1672-
break;
1673-
}
1674-
}
1675-
}
1676-
return availability != clang::AR_Unavailable;
1653+
return !importer.isUnavailableInSwift(conflict);
16771654
}
16781655

16791656
/// Determine the optionality of the given Objective-C method.
@@ -2809,7 +2786,8 @@ auto ClangImporter::Implementation::importFullName(
28092786
(isa<clang::TypeDecl>(D) ||
28102787
(isa<clang::ObjCInterfaceDecl>(D) &&
28112788
!hasOrInheritsSwiftBridgeAttr(cast<clang::ObjCInterfaceDecl>(D))) ||
2812-
isa<clang::ObjCProtocolDecl>(D))) {
2789+
isa<clang::ObjCProtocolDecl>(D)) &&
2790+
!isUnavailableInSwift(D)) {
28132791
// Find the original declaration, from which we can determine
28142792
// the owning module.
28152793
const clang::Decl *owningD = D->getCanonicalDecl();

lib/ClangImporter/ImportDecl.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3856,6 +3856,14 @@ namespace {
38563856
CtorInitializerKind kind) {
38573857
CtorInitializerKind existingKind = existingCtor->getInitKind();
38583858

3859+
// If one constructor is unavailable in Swift and the other is
3860+
// not, keep the available one.
3861+
bool existingIsUnavailable =
3862+
existingCtor->getAttrs().isUnavailable(Impl.SwiftContext);
3863+
bool newIsUnavailable = Impl.isUnavailableInSwift(objcMethod);
3864+
if (existingIsUnavailable != newIsUnavailable)
3865+
return existingIsUnavailable;
3866+
38593867
// If the new kind is the same as the existing kind, stick with
38603868
// the existing constructor.
38613869
if (existingKind == kind)
@@ -6167,6 +6175,35 @@ void ClangImporter::Implementation::importAttributes(
61676175
}
61686176
}
61696177

6178+
bool ClangImporter::Implementation::isUnavailableInSwift(
6179+
const clang::Decl *decl) {
6180+
// FIXME: Somewhat duplicated from importAttributes(), but this is a
6181+
// more direct path.
6182+
if (decl->getAvailability() == clang::AR_Unavailable) return true;
6183+
6184+
// Apply the deprecated-as-unavailable filter.
6185+
if (!DeprecatedAsUnavailableFilter) return false;
6186+
6187+
for (auto *attr : decl->specific_attrs<clang::AvailabilityAttr>()) {
6188+
if (attr->getPlatform()->getName() == "swift")
6189+
return true;
6190+
6191+
if (PlatformAvailabilityFilter &&
6192+
!PlatformAvailabilityFilter(attr->getPlatform()->getName())){
6193+
continue;
6194+
}
6195+
6196+
clang::VersionTuple version = attr->getDeprecated();
6197+
if (version.empty())
6198+
continue;
6199+
if (DeprecatedAsUnavailableFilter(version.getMajor(),
6200+
version.getMinor()))
6201+
return true;
6202+
}
6203+
6204+
return false;
6205+
}
6206+
61706207
Decl *
61716208
ClangImporter::Implementation::importDeclImpl(const clang::NamedDecl *ClangDecl,
61726209
bool useSwift2Name,

lib/ClangImporter/ImporterImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
10961096
bool isStatic,
10971097
ClangNode ClangN);
10981098

1099+
/// Determine whether the given declaration is considered
1100+
/// 'unavailable' in Swift.
1101+
bool isUnavailableInSwift(const clang::Decl *decl);
1102+
10991103
/// \brief Add "Unavailable" annotation to the swift declaration.
11001104
void markUnavailable(ValueDecl *decl, StringRef unavailabilityMsg);
11011105

test/IDE/Inputs/custom-modules/ImportAsMemberClass.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,17 @@ __attribute__((swift_name("SomeClass.applyOptions(self:_:)")))
1919
void IAMSomeClassApplyOptions(IAMSomeClass * _Nonnull someClass,
2020
IAMSomeClassOptions options);
2121

22+
@interface UnavailableDefaultInit : NSObject
23+
-(instancetype)init __attribute__((availability(swift,unavailable)));
24+
@end
25+
26+
@interface UnavailableDefaultInitSub : UnavailableDefaultInit
27+
@end
28+
29+
__attribute__((swift_name("UnavailableDefaultInit.init()")))
30+
UnavailableDefaultInit * _Nonnull MakeUnavailableDefaultInit(void);
31+
32+
__attribute__((swift_name("UnavailableDefaultInitSub.init()")))
33+
UnavailableDefaultInitSub * _Nonnull MakeUnavailableDefaultInitSub(void);
34+
2235
#endif

test/IDE/import_as_member_objc.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,9 @@ FooErr.mutateSomeStaticState()
6767
let someClassOpts: SomeClass.Options = .fuzzyDice
6868
let someClass = SomeClass(value: 3.14159)
6969
someClass.applyOptions(someClassOpts)
70+
71+
class SomeSub : UnavailableDefaultInitSub { }
72+
73+
// Handle default initializers.
74+
let udi1 = UnavailableDefaultInit()
75+
let udis1 = UnavailableDefaultInitSub()

0 commit comments

Comments
 (0)