Skip to content

[nfc][cxx-interop] Mark lazy member loading complete only after members are loaded. #40336

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 1 commit into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/DeclContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,9 @@ class IterableDeclContext {
/// Setup the loader for lazily-loaded members.
void setMemberLoader(LazyMemberLoader *loader, uint64_t contextData);

/// Externally tell this context that it has no more lazy members, i.e. all lazy member loading is complete.
void setHasLazyMembers(bool hasLazyMembers) const;

/// Load all of the members of this context.
void loadAllMembers() const;

Expand Down
6 changes: 5 additions & 1 deletion lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,10 @@ bool IterableDeclContext::hasUnparsedMembers() const {
return true;
}

void IterableDeclContext::setHasLazyMembers(bool hasLazyMembers) const {
FirstDeclAndLazyMembers.setInt(hasLazyMembers);
}

void IterableDeclContext::loadAllMembers() const {
ASTContext &ctx = getASTContext();

Expand All @@ -990,7 +994,7 @@ void IterableDeclContext::loadAllMembers() const {
return;

// Don't try to load all members re-entrant-ly.
FirstDeclAndLazyMembers.setInt(false);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@CodaFi maybe I'm confused about what's going on here, but it seems like this logic is not correct. Shouldn't we mark the members as lazily complete after we load them?

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, after investigating some test failures, I see why this is needed now. Otherwise we get into a re-entrant loop where we keep adding the same members.

setHasLazyMembers(false);

const Decl *container = getDecl();
auto contextInfo = ctx.getOrCreateLazyIterableContextData(this,
Expand Down
15 changes: 8 additions & 7 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9773,18 +9773,19 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
}

if (isa_and_nonnull<clang::RecordDecl>(D->getClangDecl())) {
// TODO: this is a hack to set member loading as lazy again. It got set to
// non-lazy when getMembers was called.
cast<StructDecl>(D)->setMemberLoader(this, 0);
// We haven't loaded any members yet, so tell our context that it still has
// lazy members. Otherwise, we won't be able to look up any individual
// members (lazily) in "loadAllMembersOfRecordDecl".
cast<StructDecl>(D)->setHasLazyMembers(true);
loadAllMembersOfRecordDecl(cast<StructDecl>(D));
// Now that all members are loaded, mark the context as lazily complete.
cast<StructDecl>(D)->setHasLazyMembers(false);
return;
}

// Namespace members will only be loaded lazily.
if (isa_and_nonnull<clang::NamespaceDecl>(D->getClangDecl())) {
// TODO: this is a hack to set member loading as lazy again. It got set to
// non-lazy when getMembers was called.
cast<EnumDecl>(D)->setMemberLoader(this, 0);
// Namespace members will only be loaded lazily.
cast<EnumDecl>(D)->setHasLazyMembers(true);
return;
}

Expand Down