Skip to content

Commit 837a180

Browse files
authored
[ClangImporter] Import-as-member support for anonymous enum constants. (#9633)
Previously this (1) did not work (the constant just disappeared), and (2) would actually crash if the destination context was a class. rdar://problem/32208235
1 parent 5886bc1 commit 837a180

File tree

5 files changed

+62
-25
lines changed

5 files changed

+62
-25
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3067,7 +3067,7 @@ namespace {
30673067
auto result = Impl.createConstant(name, dc, type,
30683068
clang::APValue(decl->getInitVal()),
30693069
ConstantConvertKind::Coerce,
3070-
/*static*/ false, decl);
3070+
/*static*/dc->isTypeContext(), decl);
30713071
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
30723072

30733073
// If this is a compatibility stub, mark it as such.
@@ -7423,8 +7423,7 @@ ClangImporter::Implementation::importDeclContextOf(
74237423

74247424
// If the declaration was not global to start with, we're done.
74257425
bool isGlobal =
7426-
decl->getDeclContext()->getRedeclContext()->isTranslationUnit() &&
7427-
!isa<clang::EnumConstantDecl>(decl);
7426+
decl->getDeclContext()->getRedeclContext()->isTranslationUnit();
74287427
if (!isGlobal) return importedDC;
74297428

74307429
// If the resulting declaration context is not a nominal type,
@@ -7592,6 +7591,7 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc,
75927591
func->setStatic(isStatic);
75937592
func->setInterfaceType(getterType);
75947593
func->setAccessibility(getOverridableAccessibility(dc));
7594+
func->setImplicit();
75957595

75967596
// If we're not done type checking, build the getter body.
75977597
if (!hasFinishedTypeChecking()) {

lib/ClangImporter/SwiftLookupTable.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,9 +418,13 @@ static bool isGlobalAsMember(SwiftLookupTable::SingleEntry entry,
418418
// We have a declaration.
419419
auto decl = entry.get<clang::NamedDecl *>();
420420

421-
// Enumerators are always stored within the enumeration, despite
422-
// having the translation unit as their redeclaration context.
423-
if (isa<clang::EnumConstantDecl>(decl)) return false;
421+
// Enumerators have the translation unit as their redeclaration context,
422+
// but members of anonymous enums are still allowed to be in the
423+
// global-as-member category.
424+
if (isa<clang::EnumConstantDecl>(decl)) {
425+
const auto *theEnum = cast<clang::EnumDecl>(decl->getDeclContext());
426+
return !theEnum->hasNameForLinkage();
427+
}
424428

425429
// If the redeclaration context is namespace-scope, then we're
426430
// mapping as a member.

test/ClangImporter/Inputs/custom-modules/SwiftName.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#define SWIFT_NAME(X) __attribute__((swift_name(#X)))
22

3-
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum __attribute__((enum_extensibility(open))) _name : _type
3+
#if __OBJC__
4+
# define SWIFT_ENUM(_type, _name) \
5+
enum _name : _type _name; enum __attribute__((enum_extensibility(open))) _name : _type
6+
#else
7+
# define SWIFT_ENUM(_type, _name) \
8+
enum _name _name; enum __attribute__((enum_extensibility(open))) _name
9+
#endif
410

511
void drawString(const char *, int x, int y) SWIFT_NAME(drawString(_:x:y:));
612

@@ -26,9 +32,25 @@ typedef int my_int_t SWIFT_NAME(MyInt);
2632
void spuriousAPINotedSwiftName(int);
2733
void poorlyNamedFunction(const char *);
2834

35+
struct BoxForConstants {
36+
int dummy;
37+
};
38+
39+
enum {
40+
AnonymousEnumConstant SWIFT_NAME(BoxForConstants.anonymousEnumConstant)
41+
};
42+
43+
#if __OBJC__
2944
@interface Foo
3045
- (instancetype)init;
3146
@end
3247

3348
void acceptsClosure(id value, void (*fn)(void)) SWIFT_NAME(Foo.accepts(self:closure:));
3449
void acceptsClosureStatic(void (*fn)(void)) SWIFT_NAME(Foo.accepts(closure:));
50+
51+
enum {
52+
// Note that there was specifically a crash when renaming onto an ObjC class,
53+
// not just a struct.
54+
AnonymousEnumConstantObjC SWIFT_NAME(Foo.anonymousEnumConstant)
55+
};
56+
#endif
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -Xcc -w -typecheck -verify %s
2+
3+
// REQUIRES: objc_interop
4+
5+
import SwiftName
6+
7+
func test() {
8+
// This particular instance method mapping previously caused a crash because
9+
// of the trailing closure.
10+
acceptsClosure(Foo(), test) // expected-error {{'acceptsClosure' has been replaced by instance method 'Foo.accepts(closure:)'}} {{3-17=(Foo()).accepts}} {{18-25=}} {{25-25=closure: }}
11+
acceptsClosure(Foo()) {} // expected-error {{'acceptsClosure' has been replaced by instance method 'Foo.accepts(closure:)'}} {{3-17=(Foo()).accepts}} {{18-23=}}
12+
13+
Foo().accepts(closure: test)
14+
Foo().accepts() {}
15+
Foo().accepts {}
16+
17+
acceptsClosureStatic(test) // expected-error {{'acceptsClosureStatic' has been replaced by 'Foo.accepts(closure:)'}} {{3-23=Foo.accepts}}
18+
acceptsClosureStatic() {} // expected-error {{'acceptsClosureStatic' has been replaced by 'Foo.accepts(closure:)'}} {{3-23=Foo.accepts}}
19+
acceptsClosureStatic {} // expected-error {{'acceptsClosureStatic' has been replaced by 'Foo.accepts(closure:)'}} {{3-23=Foo.accepts}}
20+
21+
Foo.accepts(closure: test)
22+
Foo.accepts() {}
23+
Foo.accepts {}
24+
25+
_ = AnonymousEnumConstantObjC // expected-error {{'AnonymousEnumConstantObjC' has been renamed to 'Foo.anonymousEnumConstant'}}
26+
_ = Foo.anonymousEnumConstant // okay
27+
}

test/ClangImporter/attr-swift_name_renaming.swift

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -Xcc -w -typecheck -verify %s
22

3-
// XFAIL: linux
4-
53
import SwiftName
64

75
func test() {
@@ -34,20 +32,6 @@ func test() {
3432
spuriousAPINotedSwiftName(0)
3533
nicelyRenamedFunction("go apinotes!")
3634

37-
// This particular instance method mapping previously caused a crash because
38-
// of the trailing closure.
39-
acceptsClosure(Foo(), test) // expected-error {{'acceptsClosure' has been replaced by instance method 'Foo.accepts(closure:)'}} {{3-17=(Foo()).accepts}} {{18-25=}} {{25-25=closure: }}
40-
acceptsClosure(Foo()) {} // expected-error {{'acceptsClosure' has been replaced by instance method 'Foo.accepts(closure:)'}} {{3-17=(Foo()).accepts}} {{18-23=}}
41-
42-
Foo().accepts(closure: test)
43-
Foo().accepts() {}
44-
Foo().accepts {}
45-
46-
acceptsClosureStatic(test) // expected-error {{'acceptsClosureStatic' has been replaced by 'Foo.accepts(closure:)'}} {{3-23=Foo.accepts}}
47-
acceptsClosureStatic() {} // expected-error {{'acceptsClosureStatic' has been replaced by 'Foo.accepts(closure:)'}} {{3-23=Foo.accepts}}
48-
acceptsClosureStatic {} // expected-error {{'acceptsClosureStatic' has been replaced by 'Foo.accepts(closure:)'}} {{3-23=Foo.accepts}}
49-
50-
Foo.accepts(closure: test)
51-
Foo.accepts() {}
52-
Foo.accepts {}
35+
_ = AnonymousEnumConstant // expected-error {{'AnonymousEnumConstant' has been renamed to 'BoxForConstants.anonymousEnumConstant'}}
36+
_ = BoxForConstants.anonymousEnumConstant // okay
5337
}

0 commit comments

Comments
 (0)