Skip to content

[cxx-interop] Fix spurious ambiguous member lookup for eagerly imported members #78673

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

Merged
merged 6 commits into from
Jan 22, 2025

Conversation

j-hui
Copy link
Contributor

@j-hui j-hui commented Jan 16, 2025

Follow-up from #78132, which did not fix issues related to eagerly imported members like subscripts.

This patch restructures recursive ClangRecordMemberLookup requests to importBaseMemberDecl() in the recursive calls, rather than propagating base member decls up to the initial lookup request and doing the import. Doing so seems to fix lingering resolution issues (which I've added to the regression tests).

rdar://141069984

@j-hui j-hui added the c++ interop Feature: Interoperability with C++ label Jan 16, 2025
@j-hui
Copy link
Contributor Author

j-hui commented Jan 16, 2025

@swift-ci Please smoke test

@j-hui j-hui marked this pull request as ready for review January 16, 2025 02:02
Copy link
Contributor

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor questions inline but looks good to me overall.

recordDecl->getClangDecl()) {
// Don't import constructors on foreign reference types.
if (isa<clang::CXXConstructorDecl>(named) && isa<ClassDecl>(recordDecl))
if (dyn_cast<clang::Decl>(named->getDeclContext()) !=
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this dyn_cast could ever fail. Do you know a DeclContext that is not a declaration itself?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what cases will this check be triggered?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great question... and I'm not actually sure. This logic is copied from the original implementation.

I'll try to get to the bottom of this before merging.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok so I think this check is redundant, because ClangDirectLookupRequest is already checking this:

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(foundClangDecl,
firstDecl, secondDecl);
else
return false;
}
return first == second;
});

where isDirectLookupMemberContext() is:

static bool isDirectLookupMemberContext(const clang::Decl *foundClangDecl,
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(foundClangDecl, memberCtxParent,
parent);
}
}
// Enum constant decl can be found in the parent context of the enum decl.
if (auto *ED = dyn_cast<clang::EnumDecl>(memberContext)) {
if (isa<clang::EnumConstantDecl>(foundClangDecl)) {
if (auto *firstDecl = dyn_cast<clang::Decl>(ED->getDeclContext()))
return firstDecl->getCanonicalDecl() == parent->getCanonicalDecl();
}
}
return false;
}

If anything, ClangDirectLookupRequest seems to be somewhat more thorough and accounting for things like canonical decls and namespaces (though they shouldn't be relevant here), so the check here is more restrictive ClangDirectLookupRequest for reasons that aren't obvious to me (and there don't seem to be clues in the commit history either).

I'm going to remove this check and be ready to revert it in case there's some edge case this check was supposed to account for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whelp, that check was doing something after all. It seemingly prevents a crash from happening in this test: https://github.com/swiftlang/swift/blob/439f7d9b672ab2072ad458900752c39c171fd7f7/test/ClangImporter/enum-anon.swift

I'll revert that change.

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked into the implementation bits super closely, but this LGTM in principle, thanks!

@j-hui
Copy link
Contributor Author

j-hui commented Jan 17, 2025

@swift-ci Please test

@j-hui j-hui enabled auto-merge (squash) January 17, 2025 00:43
@j-hui
Copy link
Contributor Author

j-hui commented Jan 17, 2025

@swift-ci please test

@j-hui j-hui disabled auto-merge January 17, 2025 03:32
@j-hui j-hui enabled auto-merge (squash) January 17, 2025 03:32
@j-hui
Copy link
Contributor Author

j-hui commented Jan 17, 2025

Not sure why that failed. Relevant output that I could find:

/Users/ec2-user/jenkins/workspace/swift-PR-macos/branch-main/swift-docc/Sources/SwiftDocCUtilities/PreviewServer/PreviewHTTPHandler.swift:114:34: error: 'assumeIsolated' is inaccessible due to 'internal' protection level
112 |         // If we don't need to keep the connection alive, close `context` after flushing the response
113 |         if !self.keepAlive {
114 |             promise.futureResult.assumeIsolated().whenComplete { _ in context.close(promise: nil) }
    |                                  `- error: 'assumeIsolated' is inaccessible due to 'internal' protection level
115 |         }
116 | 
FAIL: Building swift-docc failed

Gonna try this one more time

@j-hui
Copy link
Contributor Author

j-hui commented Jan 17, 2025

@swift-ci Please test

@j-hui
Copy link
Contributor Author

j-hui commented Jan 18, 2025

swiftlang/swift-docc#1145

@swift-ci please smoke test

@j-hui j-hui force-pushed the fix-inherited-member-lookup branch from 439f7d9 to dd29200 Compare January 21, 2025 17:11
@j-hui
Copy link
Contributor Author

j-hui commented Jan 21, 2025

@swift-ci please smoke test

@j-hui
Copy link
Contributor Author

j-hui commented Jan 22, 2025

@swift-ci please smoke test linux

@j-hui j-hui merged commit 1341516 into swiftlang:main Jan 22, 2025
3 checks passed
@j-hui j-hui deleted the fix-inherited-member-lookup branch January 30, 2025 07:08
j-hui added a commit that referenced this pull request Feb 2, 2025
This should have been fixed in #78673 but it was missed because it
requires a fairly complex trigger. The fix is to ensure that we never
try to clone inherited methods that are themselves inherited.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants