[interop] clang name lookup should find declarations in inline namespaces

This commit is contained in:
Alex Lorenz
2021-11-10 12:53:09 -08:00
parent 71cdfff4b9
commit 1089959b0f
7 changed files with 313 additions and 22 deletions

View File

@@ -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,

View File

@@ -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;
}

View 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()
}

View File

@@ -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()
}

View File

@@ -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'}}
}

View File

@@ -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}}
}

View File

@@ -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 ""
}
}