Skip to content

Commit 89f8855

Browse files
committed
[cxx-interop] Check for NS_OPTIONS macro in findOptionSetEnum()
importer::findOptionSetEnum() uses some fragile heuristics to determine whether a typedef is involved in the construction of a CF_OPTIONS or NS_OPTIONS type. This patch adds an explicit check that the typedef is expanded from either of those macros, to prevent, e.g., an unavailable NS_ENUM, from being mistakenly recognized as an NS_OPTIONS. Note that doing this is still kind of fragile, and prevents users from building {NS,CF}_OPTIONS with their own macros. The right thing to do is probably specifically look for the flag_enum attribute, but that is not currently what we're doing for reasons whose discovery is left as an exercise to the future git archaeologist. This patch also removes (part of) a test case that builds a CF_OPTIONS-like type with the "SOME_OPTIONS" macro, which is no longer supported as of this patch. rdar://150399978
1 parent fa5c4f2 commit 89f8855

8 files changed

+28
-83
lines changed

lib/ClangImporter/ImportEnumInfo.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ ImportedType importer::findOptionSetEnum(clang::QualType type,
255255
// then this definitely isn't used for {CF,NS}_OPTIONS.
256256
return ImportedType();
257257

258+
if (Impl.SwiftContext.LangOpts.EnableCXXInterop &&
259+
!isCFOptionsMacro(typedefType->getDecl(), Impl.getClangPreprocessor())) {
260+
return ImportedType();
261+
}
262+
258263
auto clangEnum = findAnonymousEnumForTypedef(Impl.SwiftContext, typedefType);
259264
if (!clangEnum)
260265
return ImportedType();

lib/ClangImporter/ImportEnumInfo.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/Decl.h"
22+
#include "clang/Lex/Preprocessor.h"
23+
#include "clang/Sema/Sema.h"
2224
#include "llvm/ADT/APSInt.h"
2325
#include "llvm/ADT/DenseMap.h"
2426

@@ -164,14 +166,18 @@ StringRef getCommonPluralPrefix(StringRef singular, StringRef plural);
164166
/// an elaborated type, an unwrapped type is returned.
165167
const clang::Type *getUnderlyingType(const clang::EnumDecl *decl);
166168

167-
inline bool isCFOptionsMacro(StringRef macroName) {
168-
return llvm::StringSwitch<bool>(macroName)
169+
inline bool isCFOptionsMacro(const clang::NamedDecl *decl,
170+
clang::Preprocessor &preprocessor) {
171+
auto loc = decl->getEndLoc();
172+
if (!loc.isMacroID())
173+
return false;
174+
return llvm::StringSwitch<bool>(preprocessor.getImmediateMacroName(loc))
169175
.Case("CF_OPTIONS", true)
170176
.Case("NS_OPTIONS", true)
171177
.Default(false);
172178
}
173179

174-
}
175-
}
180+
} // namespace importer
181+
} // namespace swift
176182

177183
#endif // SWIFT_CLANG_IMPORT_ENUM_H

lib/ClangImporter/ImportName.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "CFTypeInfo.h"
1919
#include "ClangClassTemplateNamePrinter.h"
2020
#include "ClangDiagnosticConsumer.h"
21+
#include "ImportEnumInfo.h"
2122
#include "ImporterImpl.h"
2223
#include "swift/AST/ASTContext.h"
2324
#include "swift/AST/ClangSwiftTypeCorrespondence.h"
@@ -1877,15 +1878,9 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
18771878
// imported into Swift to avoid having two types with the same name, which
18781879
// cause subtle name lookup issues.
18791880
if (swiftCtx.LangOpts.EnableCXXInterop &&
1880-
isUnavailableInSwift(D, nullptr, true)) {
1881-
auto loc = D->getEndLoc();
1882-
if (loc.isMacroID()) {
1883-
StringRef macroName =
1884-
clangSema.getPreprocessor().getImmediateMacroName(loc);
1885-
if (isCFOptionsMacro(macroName))
1886-
return ImportedName();
1887-
}
1888-
}
1881+
isUnavailableInSwift(D, nullptr, true) &&
1882+
isCFOptionsMacro(D, clangSema.getPreprocessor()))
1883+
return ImportedName();
18891884

18901885
/// Whether the result is a function name.
18911886
bool isFunction = false;

lib/ClangImporter/ImportType.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "CFTypeInfo.h"
18+
#include "ImportEnumInfo.h"
1819
#include "ImporterImpl.h"
1920
#include "SwiftDeclSynthesizer.h"
2021
#include "swift/ABI/MetadataValues.h"
@@ -2909,13 +2910,8 @@ ArgumentAttrs ClangImporter::Implementation::inferDefaultArgument(
29092910
return argumentAttrs;
29102911
}
29112912
}
2912-
auto loc = typedefDecl->getEndLoc();
2913-
if (loc.isMacroID()) {
2914-
StringRef macroName =
2915-
nameImporter.getClangPreprocessor().getImmediateMacroName(loc);
2916-
if (isCFOptionsMacro(macroName))
2917-
return argumentAttrs;
2918-
}
2913+
if (isCFOptionsMacro(typedefDecl, nameImporter.getClangPreprocessor()))
2914+
return argumentAttrs;
29192915
}
29202916
}
29212917

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,28 @@
11
#ifndef TEST_INTEROP_CXX_ENUM_INPUTS_ANONYMOUS_WITH_SWIFT_NAME_H
22
#define TEST_INTEROP_CXX_ENUM_INPUTS_ANONYMOUS_WITH_SWIFT_NAME_H
33

4-
#define SOME_OPTIONS(_type, _name) __attribute__((availability(swift, unavailable))) _type _name; enum __attribute__((flag_enum,enum_extensibility(open))) : _name
54
#define CF_OPTIONS(_type, _name) __attribute__((availability(swift, unavailable))) _type _name; enum : _name
65

7-
typedef SOME_OPTIONS(unsigned, SOColorMask) {
8-
kSOColorMaskRed = (1 << 1),
9-
kSOColorMaskGreen = (1 << 2),
10-
kSOColorMaskBlue = (1 << 3),
11-
kSOColorMaskAll = ~0U
12-
};
13-
14-
156
typedef CF_OPTIONS(unsigned, CFColorMask) {
167
kCFColorMaskRed = (1 << 1),
178
kCFColorMaskGreen = (1 << 2),
189
kCFColorMaskBlue = (1 << 3),
1910
kCFColorMaskAll = ~0U
2011
};
2112

22-
inline SOColorMask useSOColorMask(SOColorMask mask) { return mask; }
2313
inline CFColorMask useCFColorMask(CFColorMask mask) { return mask; }
2414

2515
struct ParentStruct { };
2616

2717
inline CFColorMask renameCFColorMask(ParentStruct parent)
2818
__attribute__((swift_name("ParentStruct.childFn(self:)")))
29-
{ return kSOColorMaskRed; }
19+
{ return kCFColorMaskRed; }
3020

3121
inline CFColorMask getCFColorMask(ParentStruct parent)
3222
__attribute__((swift_name("getter:ParentStruct.colorProp(self:)")))
33-
{ return kSOColorMaskRed; }
23+
{ return kCFColorMaskRed; }
3424

35-
inline void getCFColorMask(ParentStruct parent, CFColorMask newValue)
25+
inline void setCFColorMask(ParentStruct parent, CFColorMask newValue)
3626
__attribute__((swift_name("setter:ParentStruct.colorProp(self:newValue:)")))
3727
{ }
3828

@@ -52,9 +42,8 @@ enum __attribute__((flag_enum,enum_extensibility(open))) : GlobalOldName {
5242

5343
#if __OBJC__
5444
@interface ColorMaker
55-
- (void)makeColorWithOptions:(SOColorMask)opts;
5645
- (void)makeOtherColorWithInt:(int) x withOptions:(CFColorMask)opts;
5746
@end
5847
#endif // SWIFT_OBJC_INTEROP
5948

60-
#endif // TEST_INTEROP_CXX_ENUM_INPUTS_ANONYMOUS_WITH_SWIFT_NAME_H
49+
#endif // TEST_INTEROP_CXX_ENUM_INPUTS_ANONYMOUS_WITH_SWIFT_NAME_H

test/Interop/Cxx/enum/anonymous-with-swift-name-module-interface.swift

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,5 @@
11
// RUN: %target-swift-ide-test -print-module -module-to-print=AnonymousWithSwiftName -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
22

3-
// CHECK: @available(*, unavailable, message: "Not available in Swift")
4-
// CHECK: typealias SOColorMask = UInt32
5-
6-
// CHECK: struct SOColorMask : OptionSet, @unchecked Sendable {
7-
// CHECK: init(rawValue: UInt32)
8-
// CHECK: let rawValue: UInt32
9-
// CHECK: typealias RawValue = UInt32
10-
// CHECK: typealias Element = SOColorMask
11-
// CHECK: typealias ArrayLiteralElement = SOColorMask
12-
13-
// CHECK: static var red: SOColorMask { get }
14-
// CHECK: @available(swift, obsoleted: 3, renamed: "red")
15-
// CHECK: static var Red: SOColorMask { get }
16-
17-
// CHECK: static var green: SOColorMask { get }
18-
// CHECK: @available(swift, obsoleted: 3, renamed: "green")
19-
// CHECK: static var Green: SOColorMask { get }
20-
21-
// CHECK: static var blue: SOColorMask { get }
22-
// CHECK: @available(swift, obsoleted: 3, renamed: "blue")
23-
// CHECK: static var Blue: SOColorMask { get }
24-
25-
// CHECK: static var all: SOColorMask { get }
26-
// CHECK: @available(swift, obsoleted: 3, renamed: "all")
27-
// CHECK: static var All: SOColorMask { get }
28-
// CHECK: }
29-
303
// CHECK-NOT: typealias CFColorMask = UInt32
314

325
// CHECK: struct CFColorMask : OptionSet {
@@ -53,7 +26,6 @@
5326
// CHECK: static var All: CFColorMask { get }
5427
// CHECK: }
5528

56-
// CHECK: func useSOColorMask(_ mask: SOColorMask) -> SOColorMask
5729
// CHECK: func useCFColorMask(_ mask: CFColorMask) -> CFColorMask
5830

5931
// Test rename with "swift_name" attr:

test/Interop/Cxx/enum/anonymous-with-swift-name-objc-module-interface.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@
33
// REQUIRES: objc_interop
44

55
// CHECK: class ColorMaker {
6-
// CHECK: class func makeColor(withOptions opts: SOColorMask)
7-
// CHECK: func makeColor(withOptions opts: SOColorMask)
8-
// CHECK: @available(swift, obsoleted: 3, renamed: "makeColor(withOptions:)")
9-
// CHECK: class func makeColorWithOptions(_ opts: SOColorMask)
10-
// CHECK: @available(swift, obsoleted: 3, renamed: "makeColor(withOptions:)")
11-
// CHECK: func makeColorWithOptions(_ opts: SOColorMask)
126
// CHECK: class func makeOtherColor(with x: Int32, withOptions opts: CFColorMask)
137
// CHECK: func makeOtherColor(with x: Int32, withOptions opts: CFColorMask)
148
// CHECK: @available(swift, obsoleted: 3, renamed: "makeOtherColor(with:withOptions:)")

test/Interop/Cxx/enum/anonymous-with-swift-name.swift

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,6 @@ import StdlibUnittest
77

88
var AnonymousEnumsTestSuite = TestSuite("Anonymous Enums With Swift Name")
99

10-
AnonymousEnumsTestSuite.test("SOME_OPTIONS") {
11-
let red: SOColorMask = .red
12-
let green = SOColorMask.green
13-
let blue = .blue as SOColorMask
14-
let all: SOColorMask = .all
15-
16-
expectEqual(red.rawValue, 2)
17-
expectEqual(green.rawValue, 4)
18-
expectEqual(blue.rawValue, 8)
19-
expectEqual(all.rawValue, ~CUnsignedInt(0))
20-
}
21-
2210
AnonymousEnumsTestSuite.test("CF_OPTIONS") {
2311
let red: CFColorMask = .red
2412
let green = CFColorMask.green
@@ -35,8 +23,8 @@ AnonymousEnumsTestSuite.test("Parameter types") {
3523
let red: CFColorMask = .red
3624
let green = CFColorMask.green
3725

38-
let blue = useSOColorMask(.blue)
39-
let all = useSOColorMask(.all)
26+
let blue = useCFColorMask(.blue)
27+
let all = useCFColorMask(.all)
4028

4129
expectEqual(red, useCFColorMask(.red))
4230
expectEqual(green, useCFColorMask(.green))

0 commit comments

Comments
 (0)