-
Notifications
You must be signed in to change notification settings - Fork 10.7k
[interop] clang name lookup should find declarations in inline namesp… #40127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
hyp marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| //--- 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'}} | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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}} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 "" | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're going to duplicate the code anyway, might as well unconditionally take this path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code isn't duplicated, the regular path does something additional - it marks the name as
markLazilyCompletein the table.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so, if we know that there are no lazy members (i.e., all members are in the lookup table for a given name), then we don't have to emit a namespace lookup request? Makes sense.