Skip to content

Commit

Permalink
[C++ Interop] Implement lookup within namespace. (swiftlang#26439)
Browse files Browse the repository at this point in the history
Known problems:
- The same namespace in multiple c++ modules will be subtly confused when doing
  lookup.
  • Loading branch information
pschuh authored Aug 2, 2019
1 parent 3dc53c0 commit 2a2ed0f
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3657,7 +3657,7 @@ ClangImporter::Implementation::loadNamedMembers(

clang::ASTContext &clangCtx = getClangASTContext();

assert(isa<clang::ObjCContainerDecl>(CD));
assert(isa<clang::ObjCContainerDecl>(CD) || isa<clang::NamespaceDecl>(CD));

TinyPtrVector<ValueDecl *> Members;
for (auto entry : table->lookup(SerializedSwiftName(N),
Expand Down
26 changes: 25 additions & 1 deletion lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2385,6 +2385,7 @@ namespace {
importedName.getDeclName().getBaseIdentifier(),
Impl.importSourceLoc(decl->getLocation()), None, nullptr, dc);
enumDecl->computeType();
enumDecl->setMemberLoader(&Impl, 0);
return enumDecl;
}

Expand Down Expand Up @@ -3649,7 +3650,8 @@ namespace {
return nullptr;

DeclName name = accessorInfo ? DeclName() : importedName.getDeclName();
if (importedName.importAsMember()) {

if (!dc->isModuleScopeContext() && !isa<clang::CXXMethodDecl>(decl)) {
// Handle initializers.
if (name.getBaseName() == DeclBaseName::createConstructor()) {
assert(!accessorInfo);
Expand Down Expand Up @@ -8461,6 +8463,28 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
loadAllMembersOfObjcContainer(D, objcContainer);
return;
}

auto namespaceDecl =
dyn_cast_or_null<clang::NamespaceDecl>(D->getClangDecl());
if (namespaceDecl) {
auto *enumDecl = cast<EnumDecl>(D);
// TODO: This redecls should only match redecls that are in the same
// module as namespaceDecl after we import one namespace per clang module.
for (auto ns : namespaceDecl->redecls()) {
for (auto m : ns->decls()) {
auto nd = dyn_cast<clang::NamedDecl>(m);
if (!nd)
continue;
auto member = importDecl(nd, CurrentVersion);
if (!member)
continue;

enumDecl->addMember(member);
}
}
return;
}

loadAllMembersIntoExtension(D, extra);
}

Expand Down
15 changes: 14 additions & 1 deletion lib/ClangImporter/SwiftLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ translateDeclToContext(clang::NamedDecl *decl) {
return None;
}

// Namespace declaration.
if (auto namespaceDecl = dyn_cast<clang::NamespaceDecl>(decl)) {
if (namespaceDecl->getIdentifier())
return std::make_pair(SwiftLookupTable::ContextKind::Tag,
namespaceDecl->getName());
return None;
}

// Objective-C class context.
if (auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(decl))
return std::make_pair(SwiftLookupTable::ContextKind::ObjCClass,
Expand Down Expand Up @@ -230,6 +238,11 @@ auto SwiftLookupTable::translateDeclContext(const clang::DeclContext *dc)
if (auto tag = dyn_cast<clang::TagDecl>(dc))
return translateDeclToContext(const_cast<clang::TagDecl *>(tag));

// Namespace declaration context.
if (auto namespaceDecl = dyn_cast<clang::NamespaceDecl>(dc))
return translateDeclToContext(
const_cast<clang::NamespaceDecl *>(namespaceDecl));

// Objective-C class context.
if (auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(dc))
return std::make_pair(ContextKind::ObjCClass, objcClass->getName());
Expand Down Expand Up @@ -1672,7 +1685,7 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table,
// Walk the members of any context that can have nested members.
if (isa<clang::TagDecl>(named) || isa<clang::ObjCInterfaceDecl>(named) ||
isa<clang::ObjCProtocolDecl>(named) ||
isa<clang::ObjCCategoryDecl>(named)) {
isa<clang::ObjCCategoryDecl>(named) || isa<clang::NamespaceDecl>(named)) {
clang::DeclContext *dc = cast<clang::DeclContext>(named);
for (auto member : dc->decls()) {
if (auto namedMember = dyn_cast<clang::NamedDecl>(member))
Expand Down
2 changes: 2 additions & 0 deletions test/ClangImporter/Inputs/custom-modules/cxx_interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// Ensure c++ features are used.
namespace ns {
class T {};

T *doMakeT();
} // namespace ns

struct Basic {
Expand Down
6 changes: 6 additions & 0 deletions test/ClangImporter/cxx_interop.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ do {
tmp.a = 3
tmp.b = nil
}

// Namespace lookup
func namespaceLookup() -> UnsafeMutablePointer<ns.T> {
var tmp: UnsafeMutablePointer<ns.T> = ns.doMakeT()!
return tmp
}
7 changes: 7 additions & 0 deletions test/ClangImporter/cxx_interop_ir.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ func reflectionInfo(arg: namespacedT) -> Any.Type {
func namespaceManglesIntoName(arg: namespacedT) {
}

// CHECK-LABEL: define hidden swiftcc void @"$s6cxx_ir14accessNSMemberyyF"()
// CHECK: %0 = call %"class.ns::T"* @{{_ZN2ns7doMakeTEv|"\?doMakeT@ns@@YAPEAVT@1@XZ"}}()
// CHECK: call void @{{_Z4useTPN2ns1TE|"\?useT@@YAXPE?AVT@ns@@@Z"}}(%"class.ns::T"* %2)
func accessNSMember() {
useT(ns.doMakeT())
}

// CHECK-LABEL: define hidden swiftcc i32 @"$s6cxx_ir12basicMethods1as5Int32VSpySo0D0VG_tF"(i8*)
// CHECK: [[THIS_PTR1:%.*]] = bitcast i8* %0 to %TSo7MethodsV*
// CHECK: [[THIS_PTR2:%.*]] = bitcast %TSo7MethodsV* [[THIS_PTR1]] to %class.Methods*
Expand Down

0 comments on commit 2a2ed0f

Please sign in to comment.