Serialization: Error on xref to implementation-only dependencies

Introduce a last resort check reporting references to
implementation-only dependencies that would appear in the generated
swiftmodule. This check is applied at serialization, long after
exportability checking applied at typechecking. It should act as a back
stop to references missed by typechecking or @_implementationOnly decls
that should have been skipped.

This check is gated behind CheckImplementationOnlyStrict and should be
used with embedded only.

rdar://160697599
This commit is contained in:
Alexis Laferrière
2025-10-20 13:57:11 -07:00
parent ac41fb60ff
commit 5a49e34426
6 changed files with 180 additions and 8 deletions

View File

@@ -756,6 +756,16 @@ IdentifierID Serializer::addContainingModuleRef(const DeclContext *DC,
if (M->isClangHeaderImportModule())
return OBJC_HEADER_MODULE_ID;
// Reject references to hidden dependencies.
if (getASTContext().LangOpts.hasFeature(
Feature::CheckImplementationOnlyStrict) &&
!allowCompilerErrors() &&
this->M->isImportedImplementationOnly(M, /*assumeImported=*/false)) {
getASTContext().Diags.diagnose(SourceLoc(),
diag::serialization_xref_to_hidden_dependency,
M, crossReferencedDecl);
}
auto exportedModuleName = file->getExportedModuleName();
assert(!exportedModuleName.empty());
auto moduleID = M->getASTContext().getIdentifier(exportedModuleName);
@@ -2452,6 +2462,8 @@ void Serializer::writeCrossReference(const Decl *D) {
unsigned abbrCode;
llvm::SaveAndRestore<const Decl *> SaveDecl(crossReferencedDecl, D);
if (auto op = dyn_cast<OperatorDecl>(D)) {
writeCrossReference(op->getDeclContext(), 1);
@@ -5397,8 +5409,7 @@ void Serializer::writeASTBlockEntity(const Decl *D) {
// Skip non-public @export(interface) functions.
auto FD = dyn_cast<AbstractFunctionDecl>(D);
if (FD &&
FD->getAttrs().hasAttribute<NeverEmitIntoClientAttr>() &&
if (FD && FD->isNeverEmittedIntoClient() &&
!FD->getFormalAccessScope(/*useDC*/nullptr,
/*treatUsableFromInlineAsPublic*/true).isPublicOrPackage())
return;