-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[cxx-interop] Add flag to set minimum access level for reverse interop #84816
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
base: main
Are you sure you want to change the base?
Conversation
8e4b387
to
8f0dc63
Compare
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.
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.
test/Interop/SwiftToCxx/core/set-min-access-level-and-expose-explicitly.swift
Outdated
Show resolved
Hide resolved
} | ||
|
||
@_expose(Cxx) | ||
private func privateFunc(_ x: Int) -> Int { |
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.
Since this is never emitted, should we warn about sub-internal decls being annotated?
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.
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.
8f0dc63
to
96bf7db
Compare
@swift-ci please smoke test |
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.
This is a really nice enhancement, but I’d like it to work differently for C and ObjC interop.
static AccessLevel getRequiredAccess(const ModuleDecl &M, | ||
AccessLevel minAccess) { | ||
return M.isExternallyConsumed() ? minAccess : AccessLevel::Internal; |
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.
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:
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)); |
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 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)); |
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.
Same here.
llvm::raw_string_ostream moduleContents{moduleContentsBuf}; | ||
auto deps = printModuleContentsAsCxx( | ||
moduleContents, *M, interopContext, | ||
frontendOpts.ClangHeaderMinAccess.value_or(AccessLevel::Public), |
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.
Possibly here too.
os, *M->getASTContext().getStdlibModule(), interopContext, | ||
/*requiresExposedAttribute=*/true, exposedModules); | ||
printModuleContentsAsCxx(os, *M->getASTContext().getStdlibModule(), | ||
interopContext, AccessLevel::Public, |
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.
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); |
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.
Should there be an explicit spelling for the default behavior? Something like auto
or default
?
rdar://159211965