Skip to content

Commit 249e3ee

Browse files
committed
[cxx-interop] Remove workarounds for CF_OPTIONS default arguments
ClangImporter has logic that infers default arguments of certain C/C++ types, such as the types declared via `CF_OPTIONS`/`NS_OPTIONS` macros. There were some workarounds in place which triggered for C++ interop mode specifically. The workarounds were applying a heuristic based on the name of the type, which tried to match the behavior to non-C++ interop mode for certain types from the OS SDK. That was not working well for user-defined types, causing source compatibility breakages when enabling C++ interop. This change replaces the name-based heuristic with a more robust criteria. See also 3791ccb. rdar://142961112
1 parent 737b5ec commit 249e3ee

File tree

4 files changed

+50
-49
lines changed

4 files changed

+50
-49
lines changed

lib/ClangImporter/ImportEnumInfo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ StringRef getCommonPluralPrefix(StringRef singular, StringRef plural);
163163
/// Returns the underlying integer type of an enum. If clang treats the type as
164164
/// an elaborated type, an unwrapped type is returned.
165165
const clang::Type *getUnderlyingType(const clang::EnumDecl *decl);
166+
167+
inline bool isCFOptionsMacro(StringRef macroName) {
168+
return macroName == "CF_OPTIONS" || macroName == "NS_OPTIONS";
169+
}
170+
166171
}
167172
}
168173

lib/ClangImporter/ImportName.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1875,7 +1875,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
18751875
if (loc.isMacroID()) {
18761876
StringRef macroName =
18771877
clangSema.getPreprocessor().getImmediateMacroName(loc);
1878-
if (macroName == "CF_OPTIONS" || macroName == "NS_OPTIONS")
1878+
if (isCFOptionsMacro(macroName))
18791879
return ImportedName();
18801880
}
18811881
}

lib/ClangImporter/ImportType.cpp

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2919,42 +2919,24 @@ ArgumentAttrs ClangImporter::Implementation::inferDefaultArgument(
29192919
} else if (const clang::TypedefType *typedefType =
29202920
type->getAs<clang::TypedefType>()) {
29212921
// Get the AvailabilityAttr that would be set from CF/NS_OPTIONS
2922-
if (importer::isUnavailableInSwift(typedefType->getDecl(), nullptr, true)) {
2922+
auto typedefDecl = typedefType->getDecl();
2923+
if (importer::isUnavailableInSwift(typedefDecl, nullptr, true)) {
29232924
// If we've taken this branch it means we have an enum type, and it is
29242925
// likely an integer or NSInteger that is being used by NS/CF_OPTIONS to
29252926
// behave like a C enum in the presence of C++.
2926-
auto enumName = typedefType->getDecl()->getName();
2927+
auto enumName = typedefDecl->getName();
29272928
ArgumentAttrs argumentAttrs(DefaultArgumentKind::None, true, enumName);
2928-
auto camelCaseWords = camel_case::getWords(enumName);
2929-
for (auto it = camelCaseWords.rbegin(); it != camelCaseWords.rend();
2930-
++it) {
2931-
auto word = *it;
2932-
auto next = std::next(it);
2929+
for (auto word : llvm::reverse(camel_case::getWords(enumName))) {
29332930
if (camel_case::sameWordIgnoreFirstCase(word, "options")) {
29342931
argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray;
29352932
return argumentAttrs;
29362933
}
2937-
if (camel_case::sameWordIgnoreFirstCase(word, "units"))
2938-
return argumentAttrs;
2939-
if (camel_case::sameWordIgnoreFirstCase(word, "domain"))
2940-
return argumentAttrs;
2941-
if (camel_case::sameWordIgnoreFirstCase(word, "action"))
2942-
return argumentAttrs;
2943-
if (camel_case::sameWordIgnoreFirstCase(word, "event"))
2944-
return argumentAttrs;
2945-
if (camel_case::sameWordIgnoreFirstCase(word, "events") &&
2946-
next != camelCaseWords.rend() &&
2947-
camel_case::sameWordIgnoreFirstCase(*next, "control"))
2948-
return argumentAttrs;
2949-
if (camel_case::sameWordIgnoreFirstCase(word, "state"))
2950-
return argumentAttrs;
2951-
if (camel_case::sameWordIgnoreFirstCase(word, "unit"))
2952-
return argumentAttrs;
2953-
if (camel_case::sameWordIgnoreFirstCase(word, "position") &&
2954-
next != camelCaseWords.rend() &&
2955-
camel_case::sameWordIgnoreFirstCase(*next, "scroll"))
2956-
return argumentAttrs;
2957-
if (camel_case::sameWordIgnoreFirstCase(word, "edge"))
2934+
}
2935+
auto loc = typedefDecl->getEndLoc();
2936+
if (loc.isMacroID()) {
2937+
StringRef macroName =
2938+
nameImporter.getClangPreprocessor().getImmediateMacroName(loc);
2939+
if (isCFOptionsMacro(macroName))
29582940
return argumentAttrs;
29592941
}
29602942
}

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

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,57 @@
1+
#include "CFAvailability.h"
2+
3+
typedef unsigned long NSUInteger;
4+
15
// Enum usage that is bitwise-able and assignable in C++, aka how CF_OPTIONS
26
// does things.
3-
typedef int __attribute__((availability(swift, unavailable))) NSEnumerationOptions;
4-
enum : NSEnumerationOptions { NSEnumerationConcurrent, NSEnumerationReverse };
7+
typedef CF_OPTIONS(NSUInteger, NSEnumerationOptions) {
8+
NSEnumerationConcurrent = (1UL << 0),
9+
NSEnumerationReverse = (1UL << 1),
10+
};
511

612
@interface NSSet
713
- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts ;
814
@end
915

10-
typedef int __attribute__((availability(swift, unavailable))) NSOrderedCollectionDifferenceCalculationOptions;
11-
enum : NSOrderedCollectionDifferenceCalculationOptions {
16+
typedef CF_OPTIONS(NSUInteger, NSOrderedCollectionDifferenceCalculationOptions) {
1217
NSOrderedCollectionDifferenceCalculationOptions1,
1318
NSOrderedCollectionDifferenceCalculationOptions2
1419
};
1520

16-
typedef int __attribute__((availability(swift, unavailable))) NSCalendarUnit;
17-
enum : NSCalendarUnit { NSCalendarUnit1, NSCalendarUnit2 };
21+
typedef CF_OPTIONS(NSUInteger, NSCalendarUnit) {
22+
NSCalendarUnit1,
23+
NSCalendarUnit2
24+
};
1825

19-
typedef int __attribute__((availability(swift, unavailable))) NSSearchPathDomainMask;
20-
enum : NSSearchPathDomainMask { NSSearchPathDomainMask1, NSSearchPathDomainMask2 };
26+
typedef CF_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
27+
NSSearchPathDomainMask1,
28+
NSSearchPathDomainMask2
29+
};
2130

22-
typedef int __attribute__((availability(swift, unavailable))) NSControlCharacterAction;
23-
enum : NSControlCharacterAction { NSControlCharacterAction1, NSControlCharacterAction2 };
31+
typedef CF_OPTIONS(NSUInteger, NSControlCharacterAction) {
32+
NSControlCharacterAction1,
33+
NSControlCharacterAction2
34+
};
2435

25-
typedef int __attribute__((availability(swift, unavailable))) UIControlState;
26-
enum : UIControlState { UIControlState1, UIControlState2 };
36+
typedef CF_OPTIONS(NSUInteger, UIControlState) {
37+
UIControlState1,
38+
UIControlState2
39+
};
2740

28-
typedef int __attribute__((availability(swift, unavailable))) UITableViewCellStateMask;
29-
enum : UITableViewCellStateMask { UITableViewCellStateMask1, UITableViewCellStateMask2 };
41+
typedef CF_OPTIONS(NSUInteger, UITableViewCellStateMask) {
42+
UITableViewCellStateMask1,
43+
UITableViewCellStateMask2
44+
};
3045

31-
typedef int __attribute__((availability(swift, unavailable))) UIControlEvents;
32-
enum : UIControlEvents { UIControlEvents1, UIControlEvents2 };
46+
typedef CF_OPTIONS(NSUInteger, UIControlEvents) {
47+
UIControlEvents1,
48+
UIControlEvents2
49+
};
3350

34-
typedef int __attribute__((availability(swift, unavailable)))
35-
UITableViewScrollPosition;
36-
enum : UITableViewScrollPosition {
51+
typedef CF_OPTIONS(NSUInteger, UITableViewScrollPosition) {
3752
UITableViewScrollPosition1,
3853
UITableViewScrollPosition2
3954
};
40-
4155
@interface NSIndexPath
4256
@end
4357

0 commit comments

Comments
 (0)