Skip to content

Commit 1089959

Browse files
committed
[interop] clang name lookup should find declarations in inline namespaces
1 parent 71cdfff commit 1089959

7 files changed

+313
-22
lines changed

lib/AST/NameLookup.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,10 +1456,25 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
14561456
auto allFound = evaluateOrDefault(
14571457
ctx.evaluator, CXXNamespaceMemberLookup({cast<EnumDecl>(decl), name}),
14581458
{});
1459-
for (auto found : allFound)
1460-
Table.addMember(found);
1461-
14621459
populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
1460+
1461+
// Bypass the regular member lookup table if we find something in
1462+
// the original C++ namespace. We don't want to store the C++ decl in the
1463+
// lookup table as the decl can be referenced from multiple namespace
1464+
// declarations due to inline namespaces. We still merge in the other
1465+
// entries found in the lookup table, to support finding members in
1466+
// namespace extensions.
1467+
if (!allFound.empty()) {
1468+
auto known = Table.find(name);
1469+
if (known != Table.end()) {
1470+
auto swiftLookupResult = maybeFilterOutAttrImplements(
1471+
known->second, name, includeAttrImplements);
1472+
for (auto foundSwiftDecl : swiftLookupResult) {
1473+
allFound.push_back(foundSwiftDecl);
1474+
}
1475+
}
1476+
return allFound;
1477+
}
14631478
} else if (isa_and_nonnull<clang::RecordDecl>(decl->getClangDecl())) {
14641479
auto allFound = evaluateOrDefault(
14651480
ctx.evaluator,

lib/ClangImporter/ClangImporter.cpp

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4040,6 +4040,20 @@ lookupInClassTemplateSpecialization(
40404040
return found;
40414041
}
40424042

4043+
static bool isDirectLookupMemberContext(const clang::Decl *memberContext,
4044+
const clang::Decl *parent) {
4045+
if (memberContext->getCanonicalDecl() == parent->getCanonicalDecl())
4046+
return true;
4047+
if (auto namespaceDecl = dyn_cast<clang::NamespaceDecl>(memberContext)) {
4048+
if (namespaceDecl->isInline()) {
4049+
if (auto memberCtxParent =
4050+
dyn_cast<clang::Decl>(namespaceDecl->getParent()))
4051+
return isDirectLookupMemberContext(memberCtxParent, parent);
4052+
}
4053+
}
4054+
return false;
4055+
}
4056+
40434057
SmallVector<SwiftLookupTable::SingleEntry, 4>
40444058
ClangDirectLookupRequest::evaluate(Evaluator &evaluator,
40454059
ClangDirectLookupDescriptor desc) const {
@@ -4053,28 +4067,25 @@ ClangDirectLookupRequest::evaluate(Evaluator &evaluator,
40534067
getClangOwningModule(clangDecl, clangDecl->getASTContext());
40544068
auto *lookupTable = ctx.getClangModuleLoader()->findLookupTable(clangModule);
40554069

4056-
auto *swiftDeclContext = desc.decl->getInnermostDeclContext();
4057-
auto *declContextTypeDecl = swiftDeclContext->getSelfNominalTypeDecl();
4058-
auto effectiveClangContext =
4059-
ctx.getClangModuleLoader()->getEffectiveClangContext(declContextTypeDecl);
4060-
40614070
auto foundDecls = lookupTable->lookup(
4062-
SerializedSwiftName(desc.name.getBaseName()), effectiveClangContext);
4071+
SerializedSwiftName(desc.name.getBaseName()), EffectiveClangContext());
40634072
// Make sure that `clangDecl` is the parent of all the members we found.
40644073
SmallVector<SwiftLookupTable::SingleEntry, 4> filteredDecls;
4065-
llvm::copy_if(
4066-
foundDecls, std::back_inserter(filteredDecls),
4067-
[clangDecl](SwiftLookupTable::SingleEntry decl) {
4068-
auto first = decl.get<clang::NamedDecl *>()->getDeclContext();
4069-
auto second = cast<clang::DeclContext>(clangDecl);
4070-
if (auto firstDecl = dyn_cast<clang::Decl>(first)) {
4071-
if (auto secondDecl = dyn_cast<clang::Decl>(second))
4072-
return firstDecl->getCanonicalDecl() == secondDecl->getCanonicalDecl();
4073-
else
4074-
return false;
4075-
}
4076-
return first == second;
4077-
});
4074+
llvm::copy_if(foundDecls, std::back_inserter(filteredDecls),
4075+
[clangDecl](SwiftLookupTable::SingleEntry decl) {
4076+
auto foundClangDecl = decl.dyn_cast<clang::NamedDecl *>();
4077+
if (!foundClangDecl)
4078+
return false;
4079+
auto first = foundClangDecl->getDeclContext();
4080+
auto second = cast<clang::DeclContext>(clangDecl);
4081+
if (auto firstDecl = dyn_cast<clang::Decl>(first)) {
4082+
if (auto secondDecl = dyn_cast<clang::Decl>(second))
4083+
return isDirectLookupMemberContext(firstDecl, secondDecl);
4084+
else
4085+
return false;
4086+
}
4087+
return first == second;
4088+
});
40784089
return filteredDecls;
40794090
}
40804091

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-emit-ir -I %t/Inputs -enable-cxx-interop %t/test.swift | %FileCheck %t/test.swift
4+
5+
6+
//--- Inputs/module.modulemap
7+
module namespaces {
8+
header "test.h"
9+
requires cplusplus
10+
}
11+
//--- Inputs/test.h
12+
namespace Parent {
13+
inline namespace InlineChild {
14+
15+
void functionInInlineChild();
16+
17+
template<class CharT>
18+
struct TemplateInInlineChild {
19+
};
20+
21+
typedef TemplateInInlineChild<char> TypedefInInlineChild;
22+
23+
struct InInlineChild {
24+
};
25+
26+
namespace NamespaceInInlineChild {
27+
28+
struct InNamespaceInInlineChild {
29+
};
30+
31+
} // namespace NamespaceInInlineChild
32+
33+
inline namespace SecondInlineChild {
34+
35+
struct InSecondInlineChild {
36+
};
37+
38+
} // namespace SecondInlineChild
39+
} // namespace InlineChild
40+
} // namespace Parent
41+
42+
//--- test.swift
43+
44+
import namespaces;
45+
46+
extension Parent.TypedefInInlineChild {
47+
var string: String {
48+
return ""
49+
}
50+
}
51+
// CHECK: define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"()
52+
53+
extension Parent.InInlineChild {
54+
func doSomething() {
55+
}
56+
}
57+
// CHECK: define hidden swiftcc void @"$sSo6ParentO11InlineChildO02InbC0V4testE11doSomethingyyF"()
58+
59+
extension Parent.InSecondInlineChild {
60+
var x: Int {
61+
return 2
62+
}
63+
}
64+
// CHECK: define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1xSivg"()
65+
66+
extension Parent.InlineChild.InSecondInlineChild {
67+
var y: Int {
68+
return 3
69+
}
70+
}
71+
// define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1ySivg"()
72+
73+
// CHECK: define hidden swiftcc {{.*}} @"$s4test3useySSSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11d7Child21g2IndE4IcEEVF"()
74+
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"
75+
func use(_ x: Parent.TypedefInInlineChild) -> String {
76+
let s = x.string
77+
return s
78+
}
79+
80+
// CHECK: define hidden swiftcc {{.*}} @"$s4test4use2ySSSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11d7Child21g2IndE4IcEEVF"()
81+
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"
82+
func use2(_ x: Parent.InlineChild.TypedefInInlineChild) -> String {
83+
let s = x.string
84+
return s
85+
}
86+
87+
// define swiftcc void @"$s4testAAyySo6ParentO11InlineChildO02IncD0VF"()
88+
// CHECK: alloca %TSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV
89+
// CHECK: call {{.*}} @{{_ZN6Parent11InlineChild21TemplateInInlineChildIcEC|"\?\?0\?\$TemplateInInlineChild@D@InlineChild@Parent@@QEAA@XZ"}}
90+
// CHECK: call swiftcc void @"$sSo6ParentO11InlineChildO02InbC0V4testE11doSomethingyyF"(
91+
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1xSivg"(
92+
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1ySivg"(
93+
// CHECK: call void @{{_ZN6Parent11InlineChild21functionInInlineChildEv|"\?functionInInlineChild@InlineChild@Parent@@YAXXZ"}}()
94+
public func test(_ y: Parent.InlineChild.InInlineChild) {
95+
let s = Parent.TypedefInInlineChild()
96+
let s2 = use(s) + use2(s)
97+
y.doSomething()
98+
var i: Parent.InlineChild.SecondInlineChild.InSecondInlineChild?
99+
let i2 = i?.x
100+
let i3 = i?.y
101+
Parent.InlineChild.functionInInlineChild()
102+
}
103+
104+
extension Parent.InlineChild {
105+
// CHECK: define hidden swiftcc void @"$sSo6ParentO11InlineChildO4testE011swiftFuncInB9NamespaceyyFZ"()
106+
static func swiftFuncInInlineNamespace() {
107+
}
108+
}
109+
110+
// CHECK: define{{.*}} swiftcc void @"$s4test5test2yyF"()
111+
// CHECK: call swiftcc void @"$sSo6ParentO11InlineChildO4testE011swiftFuncInB9NamespaceyyFZ"()
112+
public func test2() {
113+
Parent.InlineChild.swiftFuncInInlineNamespace()
114+
}
115+
116+
// CHECK: define hidden swiftcc void @"$sSo6ParentO11InlineChildO011NamespaceInbC0O0edebC0V4testE15doSomethingElseyyF"()
117+
extension Parent.NamespaceInInlineChild.InNamespaceInInlineChild {
118+
func doSomethingElse() {}
119+
}
120+
121+
// CHECK: define{{.*}} swiftcc void @"$s4test5test3yySo6ParentO11InlineChildO011NamespaceIndE0O0gfgdE0VF"()
122+
// CHECK: call swiftcc void @"$sSo6ParentO11InlineChildO011NamespaceInbC0O0edebC0V4testE15doSomethingElseyyF"()
123+
public func test3(_ x: Parent.InlineChild.NamespaceInInlineChild.InNamespaceInInlineChild) {
124+
x.doSomethingElse()
125+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-emit-ir -I %t/Inputs -enable-cxx-interop %t/test.swift | %FileCheck %t/test.swift
4+
5+
6+
//--- Inputs/module.modulemap
7+
module namespaces {
8+
header "test.h"
9+
requires cplusplus
10+
}
11+
//--- Inputs/test.h
12+
namespace ExtendedInSwift {
13+
void test(int, int);
14+
} // namespace ExtendedInSwift
15+
16+
//--- test.swift
17+
18+
import namespaces;
19+
20+
extension ExtendedInSwift {
21+
static func test() {
22+
}
23+
}
24+
25+
// CHECK: call void @{{.*}}(i32 0, i32 0)
26+
// CHECK: call swiftcc void @"$sSo15ExtendedInSwiftO4testEACyyFZ"()
27+
public func doTest() {
28+
ExtendedInSwift.test(0, 0)
29+
ExtendedInSwift.test()
30+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t/Inputs %t/test.swift -enable-cxx-interop
4+
5+
//--- Inputs/module.modulemap
6+
module namespaces {
7+
header "test.h"
8+
requires cplusplus
9+
}
10+
//--- Inputs/test.h
11+
namespace Parent {
12+
inline namespace InlineChild {
13+
14+
struct StructInInlineChildAndParent {};
15+
16+
struct StructInInlineChildAndSiblingInlineChild {};
17+
18+
inline namespace SecondInlineChild {
19+
} // namespace SecondInlineChild
20+
} // namespace InlineChild
21+
22+
struct StructInInlineChildAndParent {};
23+
24+
inline namespace SiblingInlineChild {
25+
26+
struct StructInInlineChildAndSiblingInlineChild {};
27+
28+
} // namespace SiblingInlineChild
29+
30+
} // namespace Parent
31+
32+
//--- test.swift
33+
34+
import namespaces;
35+
36+
extension Parent.StructInInlineChildAndParent { // expected-error {{ambiguous type name 'StructInInlineChildAndParent' in 'Parent'}}
37+
}
38+
39+
extension Parent.StructInInlineChildAndSiblingInlineChild { // expected-error {{ambiguous type name 'StructInInlineChildAndSiblingInlineChild' in 'Parent'}}
40+
}
41+
42+
extension Parent.InlineChild.StructInInlineChildAndParent { // ok
43+
var string: String {
44+
return ""
45+
}
46+
}
47+
48+
extension Parent.InlineChild.StructInInlineChildAndSiblingInlineChild { // ok
49+
var string: String {
50+
return ""
51+
}
52+
}
53+
54+
extension Parent.InlineChild.SecondInlineChild.StructInInlineChildAndParent { // expected-error {{'StructInInlineChildAndParent' is not a member type of enum '__ObjC.Parent.InlineChild.SecondInlineChild'}}
55+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t/Inputs %t/test.swift -enable-cxx-interop
4+
5+
//--- Inputs/module.modulemap
6+
module namespaces {
7+
header "test.h"
8+
requires cplusplus
9+
}
10+
//--- Inputs/test.h
11+
namespace Parent {
12+
inline namespace InlineChild {
13+
14+
void functionInInlineChild();
15+
16+
} // namespace InlineChild
17+
} // namespace Parent
18+
19+
//--- test.swift
20+
21+
import namespaces;
22+
23+
// Swift's typechecker currently doesn't allow calling a function from inline namespace when it's referenced through the parent namespace.
24+
func test() {
25+
Parent.functionInInlineChild() // expected-error {{type of expression is ambiguous without more context}}
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t/Inputs %t/test.swift -enable-cxx-interop
4+
5+
//--- Inputs/module.modulemap
6+
module namespaces {
7+
header "test.h"
8+
requires cplusplus
9+
}
10+
//--- Inputs/test.h
11+
inline namespace TopLevelInline {
12+
13+
struct InTopLevelInline {
14+
};
15+
16+
} // namespace TopLevelInline
17+
18+
//--- test.swift
19+
20+
import namespaces;
21+
22+
extension InTopLevelInline { // expected-error {{cannot find type 'InTopLevelInline' in scope}}
23+
}
24+
25+
extension TopLevelInline.InTopLevelInline { // ok
26+
var string: String {
27+
return ""
28+
}
29+
}

0 commit comments

Comments
 (0)