mirror of
https://github.com/apple/swift.git
synced 2026-03-04 18:24:35 +01:00
[interop] clang name lookup should find declarations in inline namespaces
This commit is contained in:
@@ -1456,10 +1456,25 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
|
||||
auto allFound = evaluateOrDefault(
|
||||
ctx.evaluator, CXXNamespaceMemberLookup({cast<EnumDecl>(decl), name}),
|
||||
{});
|
||||
for (auto found : allFound)
|
||||
Table.addMember(found);
|
||||
|
||||
populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
|
||||
|
||||
// Bypass the regular member lookup table if we find something in
|
||||
// the original C++ namespace. We don't want to store the C++ decl in the
|
||||
// lookup table as the decl can be referenced from multiple namespace
|
||||
// declarations due to inline namespaces. We still merge in the other
|
||||
// entries found in the lookup table, to support finding members in
|
||||
// namespace extensions.
|
||||
if (!allFound.empty()) {
|
||||
auto known = Table.find(name);
|
||||
if (known != Table.end()) {
|
||||
auto swiftLookupResult = maybeFilterOutAttrImplements(
|
||||
known->second, name, includeAttrImplements);
|
||||
for (auto foundSwiftDecl : swiftLookupResult) {
|
||||
allFound.push_back(foundSwiftDecl);
|
||||
}
|
||||
}
|
||||
return allFound;
|
||||
}
|
||||
} else if (isa_and_nonnull<clang::RecordDecl>(decl->getClangDecl())) {
|
||||
auto allFound = evaluateOrDefault(
|
||||
ctx.evaluator,
|
||||
|
||||
@@ -4040,6 +4040,20 @@ lookupInClassTemplateSpecialization(
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool isDirectLookupMemberContext(const clang::Decl *memberContext,
|
||||
const clang::Decl *parent) {
|
||||
if (memberContext->getCanonicalDecl() == parent->getCanonicalDecl())
|
||||
return true;
|
||||
if (auto namespaceDecl = dyn_cast<clang::NamespaceDecl>(memberContext)) {
|
||||
if (namespaceDecl->isInline()) {
|
||||
if (auto memberCtxParent =
|
||||
dyn_cast<clang::Decl>(namespaceDecl->getParent()))
|
||||
return isDirectLookupMemberContext(memberCtxParent, parent);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SmallVector<SwiftLookupTable::SingleEntry, 4>
|
||||
ClangDirectLookupRequest::evaluate(Evaluator &evaluator,
|
||||
ClangDirectLookupDescriptor desc) const {
|
||||
@@ -4053,28 +4067,25 @@ ClangDirectLookupRequest::evaluate(Evaluator &evaluator,
|
||||
getClangOwningModule(clangDecl, clangDecl->getASTContext());
|
||||
auto *lookupTable = ctx.getClangModuleLoader()->findLookupTable(clangModule);
|
||||
|
||||
auto *swiftDeclContext = desc.decl->getInnermostDeclContext();
|
||||
auto *declContextTypeDecl = swiftDeclContext->getSelfNominalTypeDecl();
|
||||
auto effectiveClangContext =
|
||||
ctx.getClangModuleLoader()->getEffectiveClangContext(declContextTypeDecl);
|
||||
|
||||
auto foundDecls = lookupTable->lookup(
|
||||
SerializedSwiftName(desc.name.getBaseName()), effectiveClangContext);
|
||||
SerializedSwiftName(desc.name.getBaseName()), EffectiveClangContext());
|
||||
// Make sure that `clangDecl` is the parent of all the members we found.
|
||||
SmallVector<SwiftLookupTable::SingleEntry, 4> filteredDecls;
|
||||
llvm::copy_if(
|
||||
foundDecls, std::back_inserter(filteredDecls),
|
||||
[clangDecl](SwiftLookupTable::SingleEntry decl) {
|
||||
auto first = decl.get<clang::NamedDecl *>()->getDeclContext();
|
||||
auto second = cast<clang::DeclContext>(clangDecl);
|
||||
if (auto firstDecl = dyn_cast<clang::Decl>(first)) {
|
||||
if (auto secondDecl = dyn_cast<clang::Decl>(second))
|
||||
return firstDecl->getCanonicalDecl() == secondDecl->getCanonicalDecl();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return first == second;
|
||||
});
|
||||
llvm::copy_if(foundDecls, std::back_inserter(filteredDecls),
|
||||
[clangDecl](SwiftLookupTable::SingleEntry decl) {
|
||||
auto foundClangDecl = decl.dyn_cast<clang::NamedDecl *>();
|
||||
if (!foundClangDecl)
|
||||
return false;
|
||||
auto first = foundClangDecl->getDeclContext();
|
||||
auto second = cast<clang::DeclContext>(clangDecl);
|
||||
if (auto firstDecl = dyn_cast<clang::Decl>(first)) {
|
||||
if (auto secondDecl = dyn_cast<clang::Decl>(second))
|
||||
return isDirectLookupMemberContext(firstDecl, secondDecl);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return first == second;
|
||||
});
|
||||
return filteredDecls;
|
||||
}
|
||||
|
||||
|
||||
125
test/Interop/Cxx/namespace/class-inline-namespace-irgen.swift
Normal file
125
test/Interop/Cxx/namespace/class-inline-namespace-irgen.swift
Normal file
@@ -0,0 +1,125 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: %target-swift-emit-ir -I %t/Inputs -enable-cxx-interop %t/test.swift | %FileCheck %t/test.swift
|
||||
|
||||
|
||||
//--- Inputs/module.modulemap
|
||||
module namespaces {
|
||||
header "test.h"
|
||||
requires cplusplus
|
||||
}
|
||||
//--- Inputs/test.h
|
||||
namespace Parent {
|
||||
inline namespace InlineChild {
|
||||
|
||||
void functionInInlineChild();
|
||||
|
||||
template<class CharT>
|
||||
struct TemplateInInlineChild {
|
||||
};
|
||||
|
||||
typedef TemplateInInlineChild<char> TypedefInInlineChild;
|
||||
|
||||
struct InInlineChild {
|
||||
};
|
||||
|
||||
namespace NamespaceInInlineChild {
|
||||
|
||||
struct InNamespaceInInlineChild {
|
||||
};
|
||||
|
||||
} // namespace NamespaceInInlineChild
|
||||
|
||||
inline namespace SecondInlineChild {
|
||||
|
||||
struct InSecondInlineChild {
|
||||
};
|
||||
|
||||
} // namespace SecondInlineChild
|
||||
} // namespace InlineChild
|
||||
} // namespace Parent
|
||||
|
||||
//--- test.swift
|
||||
|
||||
import namespaces;
|
||||
|
||||
extension Parent.TypedefInInlineChild {
|
||||
var string: String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
// CHECK: define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"()
|
||||
|
||||
extension Parent.InInlineChild {
|
||||
func doSomething() {
|
||||
}
|
||||
}
|
||||
// CHECK: define hidden swiftcc void @"$sSo6ParentO11InlineChildO02InbC0V4testE11doSomethingyyF"()
|
||||
|
||||
extension Parent.InSecondInlineChild {
|
||||
var x: Int {
|
||||
return 2
|
||||
}
|
||||
}
|
||||
// CHECK: define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1xSivg"()
|
||||
|
||||
extension Parent.InlineChild.InSecondInlineChild {
|
||||
var y: Int {
|
||||
return 3
|
||||
}
|
||||
}
|
||||
// define hidden swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1ySivg"()
|
||||
|
||||
// CHECK: define hidden swiftcc {{.*}} @"$s4test3useySSSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11d7Child21g2IndE4IcEEVF"()
|
||||
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"
|
||||
func use(_ x: Parent.TypedefInInlineChild) -> String {
|
||||
let s = x.string
|
||||
return s
|
||||
}
|
||||
|
||||
// CHECK: define hidden swiftcc {{.*}} @"$s4test4use2ySSSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11d7Child21g2IndE4IcEEVF"()
|
||||
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV4testE6stringSSvg"
|
||||
func use2(_ x: Parent.InlineChild.TypedefInInlineChild) -> String {
|
||||
let s = x.string
|
||||
return s
|
||||
}
|
||||
|
||||
// define swiftcc void @"$s4testAAyySo6ParentO11InlineChildO02IncD0VF"()
|
||||
// CHECK: alloca %TSo6ParentO11InlineChildO027__CxxTemplateInstN6Parent11b7Child21e2InbC4IcEEV
|
||||
// CHECK: call {{.*}} @{{_ZN6Parent11InlineChild21TemplateInInlineChildIcEC|"\?\?0\?\$TemplateInInlineChild@D@InlineChild@Parent@@QEAA@XZ"}}
|
||||
// CHECK: call swiftcc void @"$sSo6ParentO11InlineChildO02InbC0V4testE11doSomethingyyF"(
|
||||
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1xSivg"(
|
||||
// CHECK: call swiftcc {{.*}} @"$sSo6ParentO11InlineChildO06SecondbC0O02IndbC0V4testE1ySivg"(
|
||||
// CHECK: call void @{{_ZN6Parent11InlineChild21functionInInlineChildEv|"\?functionInInlineChild@InlineChild@Parent@@YAXXZ"}}()
|
||||
public func test(_ y: Parent.InlineChild.InInlineChild) {
|
||||
let s = Parent.TypedefInInlineChild()
|
||||
let s2 = use(s) + use2(s)
|
||||
y.doSomething()
|
||||
var i: Parent.InlineChild.SecondInlineChild.InSecondInlineChild?
|
||||
let i2 = i?.x
|
||||
let i3 = i?.y
|
||||
Parent.InlineChild.functionInInlineChild()
|
||||
}
|
||||
|
||||
extension Parent.InlineChild {
|
||||
// CHECK: define hidden swiftcc void @"$sSo6ParentO11InlineChildO4testE011swiftFuncInB9NamespaceyyFZ"()
|
||||
static func swiftFuncInInlineNamespace() {
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}} swiftcc void @"$s4test5test2yyF"()
|
||||
// CHECK: call swiftcc void @"$sSo6ParentO11InlineChildO4testE011swiftFuncInB9NamespaceyyFZ"()
|
||||
public func test2() {
|
||||
Parent.InlineChild.swiftFuncInInlineNamespace()
|
||||
}
|
||||
|
||||
// CHECK: define hidden swiftcc void @"$sSo6ParentO11InlineChildO011NamespaceInbC0O0edebC0V4testE15doSomethingElseyyF"()
|
||||
extension Parent.NamespaceInInlineChild.InNamespaceInInlineChild {
|
||||
func doSomethingElse() {}
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}} swiftcc void @"$s4test5test3yySo6ParentO11InlineChildO011NamespaceIndE0O0gfgdE0VF"()
|
||||
// CHECK: call swiftcc void @"$sSo6ParentO11InlineChildO011NamespaceInbC0O0edebC0V4testE15doSomethingElseyyF"()
|
||||
public func test3(_ x: Parent.InlineChild.NamespaceInInlineChild.InNamespaceInInlineChild) {
|
||||
x.doSomethingElse()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: %target-swift-emit-ir -I %t/Inputs -enable-cxx-interop %t/test.swift | %FileCheck %t/test.swift
|
||||
|
||||
|
||||
//--- Inputs/module.modulemap
|
||||
module namespaces {
|
||||
header "test.h"
|
||||
requires cplusplus
|
||||
}
|
||||
//--- Inputs/test.h
|
||||
namespace ExtendedInSwift {
|
||||
void test(int, int);
|
||||
} // namespace ExtendedInSwift
|
||||
|
||||
//--- test.swift
|
||||
|
||||
import namespaces;
|
||||
|
||||
extension ExtendedInSwift {
|
||||
static func test() {
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: call void @{{.*}}(i32 0, i32 0)
|
||||
// CHECK: call swiftcc void @"$sSo15ExtendedInSwiftO4testEACyyFZ"()
|
||||
public func doTest() {
|
||||
ExtendedInSwift.test(0, 0)
|
||||
ExtendedInSwift.test()
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t/Inputs %t/test.swift -enable-cxx-interop
|
||||
|
||||
//--- Inputs/module.modulemap
|
||||
module namespaces {
|
||||
header "test.h"
|
||||
requires cplusplus
|
||||
}
|
||||
//--- Inputs/test.h
|
||||
namespace Parent {
|
||||
inline namespace InlineChild {
|
||||
|
||||
struct StructInInlineChildAndParent {};
|
||||
|
||||
struct StructInInlineChildAndSiblingInlineChild {};
|
||||
|
||||
inline namespace SecondInlineChild {
|
||||
} // namespace SecondInlineChild
|
||||
} // namespace InlineChild
|
||||
|
||||
struct StructInInlineChildAndParent {};
|
||||
|
||||
inline namespace SiblingInlineChild {
|
||||
|
||||
struct StructInInlineChildAndSiblingInlineChild {};
|
||||
|
||||
} // namespace SiblingInlineChild
|
||||
|
||||
} // namespace Parent
|
||||
|
||||
//--- test.swift
|
||||
|
||||
import namespaces;
|
||||
|
||||
extension Parent.StructInInlineChildAndParent { // expected-error {{ambiguous type name 'StructInInlineChildAndParent' in 'Parent'}}
|
||||
}
|
||||
|
||||
extension Parent.StructInInlineChildAndSiblingInlineChild { // expected-error {{ambiguous type name 'StructInInlineChildAndSiblingInlineChild' in 'Parent'}}
|
||||
}
|
||||
|
||||
extension Parent.InlineChild.StructInInlineChildAndParent { // ok
|
||||
var string: String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
extension Parent.InlineChild.StructInInlineChildAndSiblingInlineChild { // ok
|
||||
var string: String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
extension Parent.InlineChild.SecondInlineChild.StructInInlineChildAndParent { // expected-error {{'StructInInlineChildAndParent' is not a member type of enum '__ObjC.Parent.InlineChild.SecondInlineChild'}}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t/Inputs %t/test.swift -enable-cxx-interop
|
||||
|
||||
//--- Inputs/module.modulemap
|
||||
module namespaces {
|
||||
header "test.h"
|
||||
requires cplusplus
|
||||
}
|
||||
//--- Inputs/test.h
|
||||
namespace Parent {
|
||||
inline namespace InlineChild {
|
||||
|
||||
void functionInInlineChild();
|
||||
|
||||
} // namespace InlineChild
|
||||
} // namespace Parent
|
||||
|
||||
//--- test.swift
|
||||
|
||||
import namespaces;
|
||||
|
||||
// Swift's typechecker currently doesn't allow calling a function from inline namespace when it's referenced through the parent namespace.
|
||||
func test() {
|
||||
Parent.functionInInlineChild() // expected-error {{type of expression is ambiguous without more context}}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t/Inputs %t/test.swift -enable-cxx-interop
|
||||
|
||||
//--- Inputs/module.modulemap
|
||||
module namespaces {
|
||||
header "test.h"
|
||||
requires cplusplus
|
||||
}
|
||||
//--- Inputs/test.h
|
||||
inline namespace TopLevelInline {
|
||||
|
||||
struct InTopLevelInline {
|
||||
};
|
||||
|
||||
} // namespace TopLevelInline
|
||||
|
||||
//--- test.swift
|
||||
|
||||
import namespaces;
|
||||
|
||||
extension InTopLevelInline { // expected-error {{cannot find type 'InTopLevelInline' in scope}}
|
||||
}
|
||||
|
||||
extension TopLevelInline.InTopLevelInline { // ok
|
||||
var string: String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user