Skip to content

Conversation

Xazax-hun
Copy link
Contributor

rdar://159211965

@Xazax-hun Xazax-hun added the c++ interop Feature: Interoperability with C++ label Oct 10, 2025
@Xazax-hun Xazax-hun force-pushed the reverse-interop-non-public branch from 8e4b387 to 8f0dc63 Compare October 10, 2025 16:44
Copy link
Contributor

@j-hui j-hui left a comment

Choose a reason for hiding this comment

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

LGTM, aside from one suggestion:

Can you add a test checking that the filter works for non-top-level items? Eg a struct with a mix of public and internal methods and fields.

}

@_expose(Cxx)
private func privateFunc(_ x: Int) -> Int {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is never emitted, should we warn about sub-internal decls being annotated?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe. This is also used for wasm and that is a bit special. I will need to double check with someone to see it is OK to rule that out.

@Xazax-hun Xazax-hun force-pushed the reverse-interop-non-public branch from 8f0dc63 to 96bf7db Compare October 10, 2025 17:32
@Xazax-hun
Copy link
Contributor Author

@swift-ci please smoke test

Copy link
Contributor

@beccadax beccadax left a comment

Choose a reason for hiding this comment

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

This is a really nice enhancement, but I’d like it to work differently for C and ObjC interop.

Comment on lines +1155 to +1157
static AccessLevel getRequiredAccess(const ModuleDecl &M,
AccessLevel minAccess) {
return M.isExternallyConsumed() ? minAccess : AccessLevel::Internal;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don’t think I like this behavior. If you explicitly specify an access level on the command line, that ought to override the implicit computation completely, even when isExternallyConsumed() is false. In other words, I’d like to see:

Suggested change
static AccessLevel getRequiredAccess(const ModuleDecl &M,
AccessLevel minAccess) {
return M.isExternallyConsumed() ? minAccess : AccessLevel::Internal;
static AccessLevel getRequiredAccess(const ModuleDecl &M,
std::optional<AccessLevel> minAccess) {
if (minAccess)
return *minAccess;
return M.isExternallyConsumed() ? AccessLevel::Public : AccessLevel::Internal;

With matching changes upstream of this function to preserve the optionality of ClangHeaderMinAccess up to this point.

printModuleContentsAsC(cModuleContents, imports, *M, interopContext);
printModuleContentsAsC(
cModuleContents, imports, *M, interopContext,
frontendOpts.ClangHeaderMinAccess.value_or(AccessLevel::Public));
Copy link
Contributor

Choose a reason for hiding this comment

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

The value_or here would need to be removed for my suggestion above.

printModuleContentsAsObjC(objcModuleContents, imports, *M, interopContext);
printModuleContentsAsObjC(
objcModuleContents, imports, *M, interopContext,
frontendOpts.ClangHeaderMinAccess.value_or(AccessLevel::Public));
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here.

llvm::raw_string_ostream moduleContents{moduleContentsBuf};
auto deps = printModuleContentsAsCxx(
moduleContents, *M, interopContext,
frontendOpts.ClangHeaderMinAccess.value_or(AccessLevel::Public),
Copy link
Contributor

@beccadax beccadax Oct 10, 2025

Choose a reason for hiding this comment

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

Possibly here too.

os, *M->getASTContext().getStdlibModule(), interopContext,
/*requiresExposedAttribute=*/true, exposedModules);
printModuleContentsAsCxx(os, *M->getASTContext().getStdlibModule(),
interopContext, AccessLevel::Public,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this fixed as AccessLevel::Public? (Quite possible there’s a legitimate reason; I’m just wondering what it is.)

.Case("public", AccessLevel::Public)
.Case("package", AccessLevel::Package)
.Case("internal", AccessLevel::Internal)
.Default(std::nullopt);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should there be an explicit spelling for the default behavior? Something like auto or default?

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.

3 participants