Skip to content

Package import warning incorrectly fires when using macro attributes on package declarations #86375

@hi2gage

Description

@hi2gage

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 build

Output:

/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 declarations

Expected 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 attributes
  • checkAvailabilityDomains(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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.triage neededThis issue needs more specific labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions