diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 8362d415f47b3..8690329f33f6c 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1456,10 +1456,25 @@ DirectLookupRequest::evaluate(Evaluator &evaluator, auto allFound = evaluateOrDefault( ctx.evaluator, CXXNamespaceMemberLookup({cast(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(decl->getClangDecl())) { auto allFound = evaluateOrDefault( ctx.evaluator, diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 2d62ad7d7286b..c0ecd0aeeb417 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -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(memberContext)) { + if (namespaceDecl->isInline()) { + if (auto memberCtxParent = + dyn_cast(namespaceDecl->getParent())) + return isDirectLookupMemberContext(memberCtxParent, parent); + } + } + return false; +} + SmallVector 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 filteredDecls; - llvm::copy_if( - foundDecls, std::back_inserter(filteredDecls), - [clangDecl](SwiftLookupTable::SingleEntry decl) { - auto first = decl.get()->getDeclContext(); - auto second = cast(clangDecl); - if (auto firstDecl = dyn_cast(first)) { - if (auto secondDecl = dyn_cast(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(); + if (!foundClangDecl) + return false; + auto first = foundClangDecl->getDeclContext(); + auto second = cast(clangDecl); + if (auto firstDecl = dyn_cast(first)) { + if (auto secondDecl = dyn_cast(second)) + return isDirectLookupMemberContext(firstDecl, secondDecl); + else + return false; + } + return first == second; + }); return filteredDecls; } diff --git a/test/Interop/Cxx/namespace/class-inline-namespace-irgen.swift b/test/Interop/Cxx/namespace/class-inline-namespace-irgen.swift new file mode 100644 index 0000000000000..7774adb56110a --- /dev/null +++ b/test/Interop/Cxx/namespace/class-inline-namespace-irgen.swift @@ -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 +struct TemplateInInlineChild { +}; + +typedef TemplateInInlineChild 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() +} diff --git a/test/Interop/Cxx/namespace/function-overload-in-namespace-extension-irgen.swift b/test/Interop/Cxx/namespace/function-overload-in-namespace-extension-irgen.swift new file mode 100644 index 0000000000000..f8fe337b6d92f --- /dev/null +++ b/test/Interop/Cxx/namespace/function-overload-in-namespace-extension-irgen.swift @@ -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() +} diff --git a/test/Interop/Cxx/namespace/inline-namespace-ambiguity-error.swift b/test/Interop/Cxx/namespace/inline-namespace-ambiguity-error.swift new file mode 100644 index 0000000000000..2324e1706945e --- /dev/null +++ b/test/Interop/Cxx/namespace/inline-namespace-ambiguity-error.swift @@ -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'}} +} diff --git a/test/Interop/Cxx/namespace/inline-namespace-function-call-broken.swift b/test/Interop/Cxx/namespace/inline-namespace-function-call-broken.swift new file mode 100644 index 0000000000000..8a1e1bfebe840 --- /dev/null +++ b/test/Interop/Cxx/namespace/inline-namespace-function-call-broken.swift @@ -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}} +} diff --git a/test/Interop/Cxx/namespace/top-level-inline-namespace-lookup.swift b/test/Interop/Cxx/namespace/top-level-inline-namespace-lookup.swift new file mode 100644 index 0000000000000..d3966d3076797 --- /dev/null +++ b/test/Interop/Cxx/namespace/top-level-inline-namespace-lookup.swift @@ -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 "" + } +}