-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Description
Description
When a macro attribute from an external module is applied to a package-level declaration, the compiler incorrectly emits:
warning: package import of 'X' was not used in package declarations
This happens because AccessControlChecker tracks import usage for types but not for macro attributes. The public import case works correctly, but package declarations have gaps in import usage tracking, so macro attribute usage is never recorded.
Reproduction
https://github.com/hi2gage/swift-package-macro-import-warning-repro
package import Mocking
package import Foundation
@Mocked(compilationCondition: .none)
package protocol ExampleProtocol {
var value: URL { get }
}swift buildOutput:
/path/to/Sources/MacroImportWarningRepro/Example.swift:1:17: warning: package import of 'Mocking' was not used in package declarations
package import Mocking
`- warning: package import of 'Mocking' was not used in package declarationsExpected behavior
No warning should be emitted. The @Mocked macro attribute is using the Mocking module at the package access level.
Environment
swift-driver version: 1.127.14.1 Apple Swift version 6.2 (swiftlang-6.2.0.19.9 clang-1700.3.19.1)
Target: arm64-apple-macosx26.0
Additional information
Why the public case works
Changing package to public produces no warning. The public case seems to have more comprehensive import usage tracking that catches the macro attribute usage, while package declarations have gaps.
This gap is acknowledged in TypeCheckAccess.cpp:
/// superfluously public imports which usually relies on exportability checking
/// that is not currently executed for package decls.Root Cause
AccessControlChecker::visit() calls:
checkGlobalActorAccess(D)- records import usage for global actor attributescheckAvailabilityDomains(D)- records import usage for availability attributes
There is no corresponding check for attached macro attributes. When a macro like @mocked is attached to a package protocol, the compiler never calls recordRequiredImportAccessLevelForDecl() for the macro declaration.
Proposed Fix
Add checkAttachedMacroAccess() to AccessControlCheckerBase in lib/Sema/TypeCheckAccess.cpp, following the same pattern as checkGlobalActorAccess():
void AccessControlCheckerBase::checkAttachedMacroAccess(const Decl *D) {
auto VD = dyn_cast<ValueDecl>(D);
if (!VD)
return;
AccessScope declAccessScope = VD->getFormalAccessScope(
/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true);
if (!declAccessScope.isPackage())
return;
AccessLevel accessLevel = declAccessScope.accessLevelForDiagnostics();
for (auto *customAttr : D->getExpandedAttrs().getAttributes<CustomAttr>()) {
auto *macroDecl = customAttr->getResolvedMacro();
if (!macroDecl)
continue;
recordRequiredImportAccessLevelForDecl(
macroDecl, VD->getDeclContext(), accessLevel,
customAttr->getLocation());
}
}Then call it from AccessControlChecker::visit() and UsableFromInlineChecker::visit().
I tried this locally and this resolved the warning.