Skip to content

Commit ecf0423

Browse files
authored
Merge pull request #68622 from apple/egorzhdan/5.9-reland-nsoptions
🍒Revert "Revert "[cxx-interop] Import custom `NS_OPTIONS` correctly""
2 parents 49fe7f7 + 42db1b1 commit ecf0423

File tree

9 files changed

+104
-75
lines changed

9 files changed

+104
-75
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,6 @@ class ClangModuleLoader : public ModuleLoader {
306306
virtual EffectiveClangContext getEffectiveClangContext(
307307
const NominalTypeDecl *nominal) = 0;
308308

309-
virtual const clang::TypedefType *
310-
getTypeDefForCXXCFOptionsDefinition(const clang::Decl *candidateDecl) = 0;
311-
312309
virtual SourceLoc importSourceLocation(clang::SourceLocation loc) = 0;
313310
};
314311

include/swift/ClangImporter/ClangImporter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,8 +592,8 @@ class ClangImporter final : public ClangModuleLoader {
592592
/// Enable the symbolic import experimental feature for the given callback.
593593
void withSymbolicFeatureEnabled(llvm::function_ref<void(void)> callback);
594594

595-
const clang::TypedefType *getTypeDefForCXXCFOptionsDefinition(
596-
const clang::Decl *candidateDecl) override;
595+
static const clang::TypedefType *getTypedefForCXXCFOptionsDefinition(
596+
const clang::Decl *candidateDecl, const ASTContext &ctx);
597597

598598
SourceLoc importSourceLocation(clang::SourceLocation loc) override;
599599
};

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2551,8 +2551,8 @@ ASTMangler::getTypeDefForCXXCFOptionsDefinition(const ValueDecl *decl) {
25512551
if (!clangDecl)
25522552
return nullptr;
25532553

2554-
const auto &clangModuleLoader = decl->getASTContext().getClangModuleLoader();
2555-
return clangModuleLoader->getTypeDefForCXXCFOptionsDefinition(clangDecl);
2554+
auto &ctx = decl->getASTContext();
2555+
return ClangImporter::getTypedefForCXXCFOptionsDefinition(clangDecl, ctx);
25562556
}
25572557

25582558
const clang::NamedDecl *

lib/ClangImporter/ClangImporter.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6958,26 +6958,23 @@ void ClangImporter::withSymbolicFeatureEnabled(
69586958
oldImportSymbolicCXXDecls.get());
69596959
}
69606960

6961-
const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition(
6962-
const clang::Decl *candidateDecl) {
6963-
6964-
if (!Impl.SwiftContext.LangOpts.EnableCXXInterop)
6961+
const clang::TypedefType *ClangImporter::getTypedefForCXXCFOptionsDefinition(
6962+
const clang::Decl *candidateDecl, const ASTContext &ctx) {
6963+
if (!ctx.LangOpts.EnableCXXInterop)
69656964
return nullptr;
69666965

69676966
auto enumDecl = dyn_cast<clang::EnumDecl>(candidateDecl);
69686967
if (!enumDecl)
69696968
return nullptr;
6970-
69716969
if (!enumDecl->getDeclName().isEmpty())
69726970
return nullptr;
69736971

69746972
const clang::ElaboratedType *elaboratedType =
6975-
dyn_cast<clang::ElaboratedType>(enumDecl->getIntegerType().getTypePtr());
6973+
enumDecl->getIntegerType()->getAs<clang::ElaboratedType>();
69766974
if (auto typedefType =
69776975
elaboratedType
69786976
? dyn_cast<clang::TypedefType>(elaboratedType->desugar())
6979-
: dyn_cast<clang::TypedefType>(
6980-
enumDecl->getIntegerType().getTypePtr())) {
6977+
: enumDecl->getIntegerType()->getAs<clang::TypedefType>()) {
69816978
auto enumExtensibilityAttr =
69826979
elaboratedType
69836980
? enumDecl->getAttr<clang::EnumExtensibilityAttr>()
@@ -6990,8 +6987,13 @@ const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition(
69906987
enumExtensibilityAttr->getExtensibility() ==
69916988
clang::EnumExtensibilityAttr::Open &&
69926989
hasFlagEnumAttr) {
6993-
return Impl.isUnavailableInSwift(typedefType->getDecl()) ? typedefType
6994-
: nullptr;
6990+
// Make sure the typedef is marked as unavailable in Swift.
6991+
auto typedefDecl = typedefType->getDecl();
6992+
for (auto *attr :
6993+
typedefDecl->specific_attrs<clang::AvailabilityAttr>()) {
6994+
if (attr->getPlatform()->getName() == "swift")
6995+
return typedefType;
6996+
}
69956997
}
69966998
}
69976999

lib/ClangImporter/ImportType.cpp

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2642,44 +2642,30 @@ ArgumentAttrs ClangImporter::Implementation::inferDefaultArgument(
26422642
}
26432643
} else if (const clang::TypedefType *typedefType =
26442644
type->getAs<clang::TypedefType>()) {
2645-
// Get the AvailabilityAttr that would be set from CF/NS_OPTIONS
2646-
if (importer::isUnavailableInSwift(typedefType->getDecl(), nullptr, true)) {
2647-
// If we've taken this branch it means we have an enum type, and it is
2648-
// likely an integer or NSInteger that is being used by NS/CF_OPTIONS to
2649-
// behave like a C enum in the presence of C++.
2650-
auto enumName = typedefType->getDecl()->getName();
2651-
ArgumentAttrs argumentAttrs(DefaultArgumentKind::None, true, enumName);
2652-
auto camelCaseWords = camel_case::getWords(enumName);
2653-
for (auto it = camelCaseWords.rbegin(); it != camelCaseWords.rend();
2654-
++it) {
2655-
auto word = *it;
2656-
auto next = std::next(it);
2657-
if (camel_case::sameWordIgnoreFirstCase(word, "options")) {
2658-
argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray;
2659-
return argumentAttrs;
2645+
clang::TypedefNameDecl *typedefDecl = typedefType->getDecl();
2646+
// Find the next decl in the same context. If this typedef is a part of an
2647+
// NS/CF_OPTIONS declaration, the next decl will be an enum.
2648+
auto declsInContext = typedefDecl->getDeclContext()->decls();
2649+
auto declIter = llvm::find(declsInContext, typedefDecl);
2650+
if (declIter != declsInContext.end())
2651+
declIter++;
2652+
if (declIter != declsInContext.end()) {
2653+
if (auto enumDecl = dyn_cast<clang::EnumDecl>(*declIter)) {
2654+
if (auto cfOptionsTy =
2655+
ClangImporter::getTypedefForCXXCFOptionsDefinition(
2656+
enumDecl, nameImporter.getContext())) {
2657+
if (cfOptionsTy->getDecl() == typedefDecl) {
2658+
auto enumName = typedefDecl->getName();
2659+
ArgumentAttrs argumentAttrs(DefaultArgumentKind::None, true,
2660+
enumName);
2661+
for (auto word : llvm::reverse(camel_case::getWords(enumName))) {
2662+
if (camel_case::sameWordIgnoreFirstCase(word, "options")) {
2663+
argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray;
2664+
}
2665+
}
2666+
return argumentAttrs;
2667+
}
26602668
}
2661-
if (camel_case::sameWordIgnoreFirstCase(word, "units"))
2662-
return argumentAttrs;
2663-
if (camel_case::sameWordIgnoreFirstCase(word, "domain"))
2664-
return argumentAttrs;
2665-
if (camel_case::sameWordIgnoreFirstCase(word, "action"))
2666-
return argumentAttrs;
2667-
if (camel_case::sameWordIgnoreFirstCase(word, "event"))
2668-
return argumentAttrs;
2669-
if (camel_case::sameWordIgnoreFirstCase(word, "events") &&
2670-
next != camelCaseWords.rend() &&
2671-
camel_case::sameWordIgnoreFirstCase(*next, "control"))
2672-
return argumentAttrs;
2673-
if (camel_case::sameWordIgnoreFirstCase(word, "state"))
2674-
return argumentAttrs;
2675-
if (camel_case::sameWordIgnoreFirstCase(word, "unit"))
2676-
return argumentAttrs;
2677-
if (camel_case::sameWordIgnoreFirstCase(word, "position") &&
2678-
next != camelCaseWords.rend() &&
2679-
camel_case::sameWordIgnoreFirstCase(*next, "scroll"))
2680-
return argumentAttrs;
2681-
if (camel_case::sameWordIgnoreFirstCase(word, "edge"))
2682-
return argumentAttrs;
26832669
}
26842670
}
26852671
}

test/Interop/Cxx/enum/Inputs/c-enums-withOptions-omit.h

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,57 @@
1-
// Enum usage that is bitwise-able and assignable in C++, aka how CF_OPTIONS
2-
// does things.
3-
typedef int __attribute__((availability(swift, unavailable))) NSEnumerationOptions;
4-
enum : NSEnumerationOptions { NSEnumerationConcurrent, NSEnumerationReverse };
1+
typedef unsigned NSUInteger;
2+
3+
#define __CF_OPTIONS_ATTRIBUTES __attribute__((flag_enum,enum_extensibility(open)))
4+
#if (__cplusplus)
5+
#define CF_OPTIONS(_type, _name) __attribute__((availability(swift,unavailable))) _type _name; enum __CF_OPTIONS_ATTRIBUTES : _name
6+
#else
7+
#define CF_OPTIONS(_type, _name) enum __CF_OPTIONS_ATTRIBUTES _name : _type _name; enum _name : _type
8+
#endif
9+
10+
typedef CF_OPTIONS(NSUInteger, NSEnumerationOptions) {
11+
NSEnumerationConcurrent = (1UL << 0),
12+
NSEnumerationReverse = (1UL << 1),
13+
};
514

615
@interface NSSet
716
- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts ;
817
@end
918

10-
typedef int __attribute__((availability(swift, unavailable))) NSOrderedCollectionDifferenceCalculationOptions;
11-
enum : NSOrderedCollectionDifferenceCalculationOptions {
19+
typedef CF_OPTIONS(NSUInteger, NSOrderedCollectionDifferenceCalculationOptions) {
1220
NSOrderedCollectionDifferenceCalculationOptions1,
1321
NSOrderedCollectionDifferenceCalculationOptions2
1422
};
1523

16-
typedef int __attribute__((availability(swift, unavailable))) NSCalendarUnit;
17-
enum : NSCalendarUnit { NSCalendarUnit1, NSCalendarUnit2 };
24+
typedef CF_OPTIONS(NSUInteger, NSCalendarUnit) {
25+
NSCalendarUnit1,
26+
NSCalendarUnit2
27+
};
1828

19-
typedef int __attribute__((availability(swift, unavailable))) NSSearchPathDomainMask;
20-
enum : NSSearchPathDomainMask { NSSearchPathDomainMask1, NSSearchPathDomainMask2 };
29+
typedef CF_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
30+
NSSearchPathDomainMask1,
31+
NSSearchPathDomainMask2
32+
};
2133

22-
typedef int __attribute__((availability(swift, unavailable))) NSControlCharacterAction;
23-
enum : NSControlCharacterAction { NSControlCharacterAction1, NSControlCharacterAction2 };
34+
typedef CF_OPTIONS(NSUInteger, NSControlCharacterAction) {
35+
NSControlCharacterAction1,
36+
NSControlCharacterAction2
37+
};
2438

25-
typedef int __attribute__((availability(swift, unavailable))) UIControlState;
26-
enum : UIControlState { UIControlState1, UIControlState2 };
39+
typedef CF_OPTIONS(NSUInteger, UIControlState) {
40+
UIControlState1,
41+
UIControlState2
42+
};
2743

28-
typedef int __attribute__((availability(swift, unavailable))) UITableViewCellStateMask;
29-
enum : UITableViewCellStateMask { UITableViewCellStateMask1, UITableViewCellStateMask2 };
44+
typedef CF_OPTIONS(NSUInteger, UITableViewCellStateMask) {
45+
UITableViewCellStateMask1,
46+
UITableViewCellStateMask2
47+
};
3048

31-
typedef int __attribute__((availability(swift, unavailable))) UIControlEvents;
32-
enum : UIControlEvents { UIControlEvents1, UIControlEvents2 };
49+
typedef CF_OPTIONS(NSUInteger, UIControlEvents) {
50+
UIControlEvents1,
51+
UIControlEvents2
52+
};
3353

34-
typedef int __attribute__((availability(swift, unavailable)))
35-
UITableViewScrollPosition;
36-
enum : UITableViewScrollPosition {
54+
typedef CF_OPTIONS(NSUInteger, UITableViewScrollPosition) {
3755
UITableViewScrollPosition1,
3856
UITableViewScrollPosition2
3957
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include "CFOptions.h"
2+
3+
typedef CF_OPTIONS(unsigned, MyControlFlags) {
4+
MyControlFlagsNone = 0,
5+
MyControlFlagsFirst
6+
};

test/Interop/Cxx/objc-correctness/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ module CxxClassWithNSStringInit {
99
requires cplusplus
1010
}
1111

12+
module CustomNSOptions {
13+
header "customNSOptions.h"
14+
}
15+
1216
module NSOptionsMangling {
1317
header "NSOptionsMangling.h"
1418
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t/pch
3+
4+
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -enable-objc-interop -enable-experimental-cxx-interop
5+
6+
// RUN: %target-swift-frontend -emit-pch -enable-objc-interop -enable-experimental-cxx-interop -o %t/pch/customNSOptions.pch %S/Inputs/customNSOptions.h
7+
// RUN: %target-typecheck-verify-swift -D BRIDGING_HEADER -I %S/Inputs -import-objc-header %t/pch/customNSOptions.pch -enable-objc-interop -enable-experimental-cxx-interop %s
8+
9+
// REQUIRES: objc_interop
10+
11+
#if !BRIDGING_HEADER
12+
import CustomNSOptions
13+
#endif
14+
15+
let flags1: MyControlFlags = []
16+
let flags2: MyControlFlags = [.first]

0 commit comments

Comments
 (0)