Skip to content

Commit 3a555bd

Browse files
committed
Fix effective context construction for NS_OPTIONS in linkage spec
When the ClangImporter imports a name, it associates it with a an EffectiveClangContext. An EffectiveClangContext can be thought of as the Clang scope the declaration will reside in, as far as importing into Swift is concerned. This helps API notes and NS_SWIFT_NAME to manipulate the SDK interface presented to Swift users. When a entry is added to the Swift lookup table, it is associated with a context. This context is a type and a name, used to effectively namespace entries in the table. This context is derived from the EffectiveClangContext associated with the name. This translation is handled by SwiftLookupTable::translateContextDecl among other machinery. This method in particular, understands only how to translate a set of Clang nodes, and fails to create a context in other cases. Prior to this patch, the EffectiveClangContext of declarations annotated with UIKIT_EXTERN, with cxx-interop turned on, was a LinkageSpecDecl. This results in context translation failure, and warnings produced in SwiftLookupTable::finalizeLookupTable. This patch corrects name import behavior to skip over the LinkageSpecDecl, and use the enclosing TranslationUnit instead. This is appropriate and performed by `determineEffectiveContext` as a LinkageSpecDecl is a so called "transparent" context. That is its members are semantically declared and accessible outside the context without additional qualification. This patch tests using API notes, as that is the method UIKit uses. The issue could just as easily be surface with a NS_SWIFT_NAME annotation. Even without any annotation at all, the we would still fail to translate, though there would likely be no corresponding warnings.
1 parent aecd449 commit 3a555bd

8 files changed

+100
-4
lines changed

lib/ClangImporter/SwiftLookupTable.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ class EffectiveClangContext {
188188
EffectiveClangContext(const clang::DeclContext *dc)
189189
: KindOrBiasedLength(DeclContext) {
190190
assert(dc != nullptr && "use null constructor instead");
191+
192+
// Skip over any linkage spec decl contexts
193+
while (auto externCDecl = dyn_cast<clang::LinkageSpecDecl>(dc)) {
194+
dc = externCDecl->getLexicalDeclContext();
195+
}
196+
191197
if (auto tagDecl = dyn_cast<clang::TagDecl>(dc)) {
192198
DC = tagDecl->getCanonicalDecl();
193199
} else if (auto oiDecl = dyn_cast<clang::ObjCInterfaceDecl>(dc)) {
@@ -198,11 +204,8 @@ class EffectiveClangContext {
198204
DC = omDecl->getCanonicalDecl();
199205
} else if (auto fDecl = dyn_cast<clang::FunctionDecl>(dc)) {
200206
DC = fDecl->getCanonicalDecl();
201-
} else if (auto externCDecl = dyn_cast<clang::LinkageSpecDecl>(dc)) {
202-
DC = externCDecl->getLexicalDeclContext();
203207
} else {
204208
assert(isa<clang::TranslationUnitDecl>(dc) ||
205-
isa<clang::LinkageSpecDecl>(dc) ||
206209
isa<clang::NamespaceDecl>(dc) ||
207210
isa<clang::ObjCContainerDecl>(dc) &&
208211
"No other kinds of effective Clang contexts");
@@ -526,7 +529,7 @@ class SwiftLookupTable {
526529

527530
/// Retrieve the set of base names that are stored in the globals-as-members lookup table.
528531
SmallVector<SerializedSwiftName, 4> allGlobalsAsMembersBaseNames();
529-
532+
530533
/// Lookup Objective-C members with the given base name, regardless
531534
/// of context.
532535
SmallVector<clang::NamedDecl *, 4>

test/Interop/Cxx/enum/Inputs/CenumsNSOptions.apinotes

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ Enumerators:
88
SwiftName: SwiftOptionThreeApiNotes
99
- Name: API_NOTES_NAMED_OptionFour
1010
SwiftName: SwiftOptionFourApiNotes
11+
Tags:
12+
- Name: UIPrinterJobTypes
13+
SwiftName: UIPrinter.JobTypes
14+
SwiftVersions:
15+
- Version: 4
16+
Tags:
17+
- Name: UIPrinterJobTypes
18+
SwiftName: UIPrinterJobTypes
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Name: CenumsNSOptionsExternC
2+
Tags:
3+
- Name: UIPrinterJobTypes
4+
SwiftName: UIPrinter.JobTypes
5+
SwiftVersions:
6+
- Version: 4
7+
Tags:
8+
- Name: UIPrinterJobTypes
9+
SwiftName: UIPrinterJobTypes

test/Interop/Cxx/enum/Inputs/c-enums-NS_OPTIONS.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ extern "C" {
1818
#define CF_OPTIONS(_type, _name) _type __attribute__((availability(swift, unavailable))) _name; enum __CF_OPTIONS_ATTRIBUTES : _name
1919
#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)
2020
#define NS_REFINED_FOR_SWIFT __attribute__((swift_private))
21+
#define UIKIT_EXTERN extern "C" __attribute__((visibility("default")))
2122

2223
typedef unsigned long NSUInteger;
24+
typedef long NSInteger;
2325

2426
typedef NS_OPTIONS(NSUInteger, NSBinarySearchingOptions) {
2527
NSBinarySearchingFirstEqual = (1UL << 8),
@@ -39,6 +41,23 @@ typedef NS_OPTIONS(NSUInteger, NSAttributedStringFormattingOptions) {
3941
- (instancetype)initWithOptions:(NSAttributedStringFormattingOptions)options
4042
NS_REFINED_FOR_SWIFT;
4143
@end
44+
45+
UIKIT_EXTERN
46+
@interface UIPrinter
47+
48+
typedef NS_OPTIONS(NSInteger, UIPrinterJobTypes) {
49+
UIPrinterJobTypeUnknown = 0,
50+
UIPrinterJobTypeDocument = 1 << 0,
51+
UIPrinterJobTypeEnvelope = 1 << 1,
52+
UIPrinterJobTypeLabel = 1 << 2,
53+
UIPrinterJobTypePhoto = 1 << 3,
54+
UIPrinterJobTypeReceipt = 1 << 4,
55+
UIPrinterJobTypeRoll = 1 << 5,
56+
UIPrinterJobTypeLargeFormat = 1 << 6,
57+
UIPrinterJobTypePostcard = 1 << 7
58+
};
59+
60+
@end
4261
}
4362

4463
typedef NS_OPTIONS(NSUInteger, Foo) {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#if __has_attribute(enum_extensibility)
2+
#define __CF_ENUM_ATTRIBUTES __attribute__((enum_extensibility(open)))
3+
#define __CF_CLOSED_ENUM_ATTRIBUTES __attribute__((enum_extensibility(closed)))
4+
#define __CF_OPTIONS_ATTRIBUTES __attribute__((flag_enum,enum_extensibility(open)))
5+
#else
6+
#define __CF_ENUM_ATTRIBUTES
7+
#define __CF_CLOSED_ENUM_ATTRIBUTES
8+
#define __CF_OPTIONS_ATTRIBUTES
9+
#endif
10+
11+
#define CF_OPTIONS(_type, _name) _type __attribute__((availability(swift, unavailable))) _name; enum __CF_OPTIONS_ATTRIBUTES : _name
12+
#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)
13+
#define UIKIT_EXTERN extern "C" __attribute__((visibility("default")))
14+
15+
typedef long NSInteger;
16+
17+
UIKIT_EXTERN
18+
@interface UIPrinter
19+
20+
typedef NS_OPTIONS(NSInteger, UIPrinterJobTypes) {
21+
UIPrinterJobTypeUnknown = 0,
22+
UIPrinterJobTypeDocument = 1 << 0,
23+
UIPrinterJobTypeEnvelope = 1 << 1,
24+
UIPrinterJobTypeLabel = 1 << 2,
25+
UIPrinterJobTypePhoto = 1 << 3,
26+
UIPrinterJobTypeReceipt = 1 << 4,
27+
UIPrinterJobTypeRoll = 1 << 5,
28+
UIPrinterJobTypeLargeFormat = 1 << 6,
29+
UIPrinterJobTypePostcard = 1 << 7
30+
};
31+
32+
@end

test/Interop/Cxx/enum/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ module TypedUntypedEnums {
2727
header "typed-untyped-enums.h"
2828
requires cplusplus
2929
}
30+
31+
module CenumsNSOptionsExternC [extern_c] {
32+
header "c-enums-NS_OPTIONS_without_extern_C.h"
33+
requires cplusplus
34+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t/cache)
2+
// RUN: %target-swift-frontend %s -swift-version 5 -I %S/Inputs -typecheck -module-cache-path %t/cache -enable-experimental-cxx-interop 2>&1 | %FileCheck --allow-empty %s
3+
4+
// REQUIRES: objc_interop
5+
6+
import CenumsNSOptionsExternC
7+
8+
// CHECK-NOT: warning: imported declaration '' could not be mapped to 'UIPrinter.JobTypes'
9+
// CHECK-NOT: note: please report this issue to the owners of 'CenumsNSOptions'
10+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t/cache)
2+
// RUN: %target-swift-frontend %s -swift-version 5 -I %S/Inputs -typecheck -module-cache-path %t/cache -enable-experimental-cxx-interop 2>&1 | %FileCheck --allow-empty %s
3+
4+
// REQUIRES: objc_interop
5+
6+
import CenumsNSOptions
7+
8+
// CHECK-NOT: warning: imported declaration '' could not be mapped to 'UIPrinter.JobTypes'
9+
// CHECK-NOT: note: please report this issue to the owners of 'CenumsNSOptions'
10+

0 commit comments

Comments
 (0)