Skip to content

Commit 76feb8c

Browse files
authored
Merge pull request #67639 from hyp/eng/nested-enums
[cxx-interop] correctly add and lookup enumerators added to enums tha…
2 parents 6bb6427 + 0eed1a9 commit 76feb8c

File tree

7 files changed

+107
-15
lines changed

7 files changed

+107
-15
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,23 +2399,38 @@ static void addNamespaceMembers(Decl *decl,
23992399
}
24002400
}
24012401

2402+
auto lookupAndAddMembers = [&](DeclName name) {
2403+
auto allResults = evaluateOrDefault(
2404+
ctx.evaluator, ClangDirectLookupRequest({decl, redecl, name}), {});
2405+
2406+
for (auto found : allResults) {
2407+
auto clangMember = found.get<clang::NamedDecl *>();
2408+
if (auto importedDecl =
2409+
ctx.getClangModuleLoader()->importDeclDirectly(clangMember)) {
2410+
if (addedMembers.insert(importedDecl).second)
2411+
members.push_back(importedDecl);
2412+
}
2413+
}
2414+
};
2415+
24022416
auto namedDecl = dyn_cast<clang::NamedDecl>(member);
24032417
if (!namedDecl)
24042418
continue;
2405-
24062419
auto name = ctx.getClangModuleLoader()->importName(namedDecl);
24072420
if (!name)
24082421
continue;
2409-
2410-
auto allResults = evaluateOrDefault(
2411-
ctx.evaluator, ClangDirectLookupRequest({decl, redecl, name}), {});
2412-
2413-
for (auto found : allResults) {
2414-
auto clangMember = found.get<clang::NamedDecl *>();
2415-
if (auto importedDecl =
2416-
ctx.getClangModuleLoader()->importDeclDirectly(clangMember)) {
2417-
if (addedMembers.insert(importedDecl).second)
2418-
members.push_back(importedDecl);
2422+
lookupAndAddMembers(name);
2423+
2424+
// Unscoped enums could have their enumerators present
2425+
// in the parent namespace.
2426+
if (auto *ed = dyn_cast<clang::EnumDecl>(member)) {
2427+
if (!ed->isScoped()) {
2428+
for (const auto *ecd : ed->enumerators()) {
2429+
auto name = ctx.getClangModuleLoader()->importName(ecd);
2430+
if (!name)
2431+
continue;
2432+
lookupAndAddMembers(name);
2433+
}
24192434
}
24202435
}
24212436
}

lib/ClangImporter/ClangImporter.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4539,15 +4539,24 @@ lookupInClassTemplateSpecialization(
45394539
return found;
45404540
}
45414541

4542-
static bool isDirectLookupMemberContext(const clang::Decl *memberContext,
4542+
static bool isDirectLookupMemberContext(const clang::Decl *foundClangDecl,
4543+
const clang::Decl *memberContext,
45434544
const clang::Decl *parent) {
45444545
if (memberContext->getCanonicalDecl() == parent->getCanonicalDecl())
45454546
return true;
45464547
if (auto namespaceDecl = dyn_cast<clang::NamespaceDecl>(memberContext)) {
45474548
if (namespaceDecl->isInline()) {
45484549
if (auto memberCtxParent =
45494550
dyn_cast<clang::Decl>(namespaceDecl->getParent()))
4550-
return isDirectLookupMemberContext(memberCtxParent, parent);
4551+
return isDirectLookupMemberContext(foundClangDecl, memberCtxParent,
4552+
parent);
4553+
}
4554+
}
4555+
// Enum constant decl can be found in the parent context of the enum decl.
4556+
if (auto *ED = dyn_cast<clang::EnumDecl>(memberContext)) {
4557+
if (isa<clang::EnumConstantDecl>(foundClangDecl)) {
4558+
if (auto *firstDecl = dyn_cast<clang::Decl>(ED->getDeclContext()))
4559+
return firstDecl->getCanonicalDecl() == parent->getCanonicalDecl();
45514560
}
45524561
}
45534562
return false;
@@ -4585,7 +4594,8 @@ ClangDirectLookupRequest::evaluate(Evaluator &evaluator,
45854594
auto second = cast<clang::DeclContext>(clangDecl);
45864595
if (auto firstDecl = dyn_cast<clang::Decl>(first)) {
45874596
if (auto secondDecl = dyn_cast<clang::Decl>(second))
4588-
return isDirectLookupMemberContext(firstDecl, secondDecl);
4597+
return isDirectLookupMemberContext(foundClangDecl,
4598+
firstDecl, secondDecl);
45894599
else
45904600
return false;
45914601
}

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2985,7 +2985,7 @@ namespace {
29852985
return nullptr;
29862986

29872987
// Create the global constant.
2988-
bool isStatic = enumKind != EnumKind::Unknown && dc->isTypeContext();
2988+
bool isStatic = dc->isTypeContext();
29892989
auto result = synthesizer.createConstant(
29902990
name, dc, type, clang::APValue(decl->getInitVal()),
29912991
enumKind == EnumKind::Unknown ? ConstantConvertKind::Construction

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,8 @@ module CenumsNSOptionsExternC [extern_c] {
3636
module CFAvailability {
3737
header "CFAvailability.h"
3838
}
39+
40+
module NestedEnums {
41+
header "nested-enums.h"
42+
requires cplusplus
43+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef TEST_INTEROP_CXX_ENUM_INPUTS_NESTED_ENUMS_H
2+
#define TEST_INTEROP_CXX_ENUM_INPUTS_NESTED_ENUMS_H
3+
4+
namespace ns {
5+
6+
enum EnumInNS {
7+
kA = 0,
8+
kB
9+
};
10+
11+
enum class ScopedEnumInNS {
12+
scopeA,
13+
scopeB
14+
};
15+
16+
namespace nestedNS {
17+
18+
enum EnumInNestedNS {
19+
kNestedA = 0,
20+
kNestedB
21+
};
22+
23+
}
24+
25+
}
26+
27+
#endif // TEST_INTEROP_CXX_ENUM_INPUTS_NESTED_ENUMS_H
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=NestedEnums -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
2+
3+
// CHECK: enum ns {
4+
// CHECK: struct EnumInNS : Equatable, RawRepresentable {
5+
// CHECK: }
6+
// CHECK-NEXT: static var kA: ns.EnumInNS { get }
7+
// CHECK-NEXT: static var kB: ns.EnumInNS { get }
8+
// CHECK-NEXT: enum ScopedEnumInNS : Int32 {
9+
// CHECK: case scopeA
10+
// CHECK: case scopeB
11+
// CHECK-NEXT: }
12+
// CHECK-NEXT: enum nestedNS {
13+
// CHECK-NEXT: struct EnumInNestedNS : Equatable, RawRepresentable {
14+
// CHECK: }
15+
// CHECK-NEXT: static var kNestedA: ns.nestedNS.EnumInNestedNS { get }
16+
// CHECK-NEXT: static var kNestedB: ns.nestedNS.EnumInNestedNS { get }
17+
// CHECK-NEXT: }
18+
// CHECK-NEXT:}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop)
2+
3+
// REQUIRES: executable_test
4+
5+
import NestedEnums
6+
import StdlibUnittest
7+
8+
var NestedEnumsTestSuite = TestSuite("Nested Enums")
9+
10+
NestedEnumsTestSuite.test("Make and compare") {
11+
let val: ns.EnumInNS = ns.kA
12+
expectNotEqual(val, ns.kB)
13+
let valNested = ns.nestedNS.kNestedA
14+
expectNotEqual(valNested, ns.nestedNS.kNestedB)
15+
}
16+
17+
runAllTests()

0 commit comments

Comments
 (0)