Skip to content

Commit fd59933

Browse files
authored
Merge pull request #73179 from xymus/deprecated-impl-only
Sema: Warn that resilient uses of `@_implementationOnly` are deprecated
2 parents 590c7cd + 3d611e2 commit fd59933

19 files changed

+74
-10
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,9 @@ WARNING(implementation_only_requires_library_evolution,none,
11671167
"using '@_implementationOnly' without enabling library evolution "
11681168
"for %0 may lead to instability during execution",
11691169
(Identifier))
1170+
WARNING(implementation_only_deprecated,none,
1171+
"'@_implementationOnly' is deprecated, use 'internal import' instead",
1172+
())
11701173

11711174
ERROR(module_allowable_client_violation,none,
11721175
"module %0 doesn't allow importation from module %1",

include/swift/AST/Import.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -592,17 +592,22 @@ struct AttributedImport {
592592
/// if the access level was implicit or explicit.
593593
SourceRange accessLevelRange;
594594

595+
/// Location of the `@_implementationOnly` attribute if set.
596+
SourceRange implementationOnlyRange;
597+
595598
AttributedImport(ModuleInfo module, SourceLoc importLoc = SourceLoc(),
596599
ImportOptions options = ImportOptions(),
597600
StringRef filename = {}, ArrayRef<Identifier> spiGroups = {},
598601
SourceRange preconcurrencyRange = {},
599602
std::optional<AccessLevel> docVisibility = std::nullopt,
600603
AccessLevel accessLevel = AccessLevel::Public,
601-
SourceRange accessLevelRange = SourceRange())
604+
SourceRange accessLevelRange = SourceRange(),
605+
SourceRange implementationOnlyRange = SourceRange())
602606
: module(module), importLoc(importLoc), options(options),
603607
sourceFileArg(filename), spiGroups(spiGroups),
604608
preconcurrencyRange(preconcurrencyRange), docVisibility(docVisibility),
605-
accessLevel(accessLevel), accessLevelRange(accessLevelRange) {
609+
accessLevel(accessLevel), accessLevelRange(accessLevelRange),
610+
implementationOnlyRange(implementationOnlyRange) {
606611
assert(!(options.contains(ImportFlags::Exported) &&
607612
options.contains(ImportFlags::ImplementationOnly)) ||
608613
options.contains(ImportFlags::Reserved));
@@ -613,7 +618,8 @@ struct AttributedImport {
613618
: AttributedImport(module, other.importLoc, other.options,
614619
other.sourceFileArg, other.spiGroups,
615620
other.preconcurrencyRange, other.docVisibility,
616-
other.accessLevel, other.accessLevelRange) { }
621+
other.accessLevel, other.accessLevelRange,
622+
other.implementationOnlyRange) { }
617623

618624
friend bool operator==(const AttributedImport<ModuleInfo> &lhs,
619625
const AttributedImport<ModuleInfo> &rhs) {
@@ -623,7 +629,8 @@ struct AttributedImport {
623629
lhs.spiGroups == rhs.spiGroups &&
624630
lhs.docVisibility == rhs.docVisibility &&
625631
lhs.accessLevel == rhs.accessLevel &&
626-
lhs.accessLevelRange == rhs.accessLevelRange;
632+
lhs.accessLevelRange == rhs.accessLevelRange &&
633+
lhs.implementationOnlyRange == rhs.implementationOnlyRange;
627634
}
628635

629636
AttributedImport<ImportedModule> getLoaded(ModuleDecl *loadedModule) const {

lib/Sema/ImportResolution.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,10 @@ UnboundImport::UnboundImport(ImportDecl *ID)
586586
if (ID->getAttrs().hasAttribute<TestableAttr>())
587587
import.options |= ImportFlags::Testable;
588588

589-
if (ID->getAttrs().hasAttribute<ImplementationOnlyAttr>())
589+
if (auto attr = ID->getAttrs().getAttribute<ImplementationOnlyAttr>()) {
590590
import.options |= ImportFlags::ImplementationOnly;
591+
import.implementationOnlyRange = attr->Range;
592+
}
591593

592594
import.accessLevel = ID->getAccessLevel();
593595
if (auto attr = ID->getAttrs().getAttribute<AccessControlAttr>()) {
@@ -811,7 +813,14 @@ void UnboundImport::validateResilience(NullablePtr<ModuleDecl> topLevelModule,
811813
// We exempt some imports using @_implementationOnly in a safe way from
812814
// packages that cannot be resilient.
813815
if (import.options.contains(ImportFlags::ImplementationOnly) &&
814-
!SF.getParentModule()->isResilient() && topLevelModule &&
816+
import.implementationOnlyRange.isValid()) {
817+
if (SF.getParentModule()->isResilient()) {
818+
// Encourage replacing `@_implementationOnly` with `internal import`.
819+
auto inFlight =
820+
ctx.Diags.diagnose(import.importLoc,
821+
diag::implementation_only_deprecated);
822+
inFlight.fixItReplace(import.implementationOnlyRange, "internal");
823+
} else if ( // Non-resilient
815824
!(((targetName.str() == "CCryptoBoringSSL" ||
816825
targetName.str() == "CCryptoBoringSSLShims") &&
817826
(importerName.str() == "Crypto" ||
@@ -820,11 +829,13 @@ void UnboundImport::validateResilience(NullablePtr<ModuleDecl> topLevelModule,
820829
((targetName.str() == "CNIOBoringSSL" ||
821830
targetName.str() == "CNIOBoringSSLShims") &&
822831
importerName.str() == "NIOSSL"))) {
823-
ctx.Diags.diagnose(import.importLoc,
824-
diag::implementation_only_requires_library_evolution,
825-
importerName);
832+
ctx.Diags.diagnose(import.importLoc,
833+
diag::implementation_only_requires_library_evolution,
834+
importerName);
835+
}
826836
}
827837

838+
// Report public imports of non-resilient modules from a resilient module.
828839
if (import.options.contains(ImportFlags::ImplementationOnly) ||
829840
import.accessLevel < AccessLevel::Public)
830841
return;

test/Concurrency/preconcurrency_implementationonly_override.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
// REQUIRES: asserts
1212

1313
@_implementationOnly import ImplementationOnlyDefs
14+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
1415

1516
class D: C {
1617
@_implementationOnly

test/ModuleInterface/module_shadowing.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import ShadowyHorror
3030
// OTHER-DAG: ShadowyHorror.module_shadowing:{{[0-9]+:[0-9]+}}: warning: public class 'ShadowyHorror.module_shadowing' shadows module 'module_shadowing', which may cause failures when importing 'module_shadowing' or its clients in some configurations; please rename either the class 'ShadowyHorror.module_shadowing' or the module 'module_shadowing', or see https://github.com/apple/swift/issues/56573 for workarounds{{$}}
3131

32-
@_implementationOnly import TestModule
32+
internal import TestModule
3333
#endif
3434

3535
public struct ShadowyHorror {

test/SPI/implementation_only_spi_import_exposability.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public protocol IOIProtocol {}
2727
#elseif CLIENT
2828

2929
@_spi(A) @_implementationOnly import Lib
30+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
3031

3132
@_spi(B) public func leakSPIStruct(_ a: SPIStruct) -> SPIStruct { fatalError() } // expected-warning 2 {{cannot use struct 'SPIStruct' here; 'Lib' has been imported as implementation-only}}
3233
@_spi(B) public func leakIOIStruct(_ a: IOIStruct) -> IOIStruct { fatalError() } // expected-warning 2 {{cannot use struct 'IOIStruct' here; 'Lib' has been imported as implementation-only}}

test/SPI/report-ioi-in-spi.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public struct IOIStruct {
2626
//--- ClientSPIOnlyMode.swift
2727

2828
@_implementationOnly import Lib
29+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
2930

3031
@_spi(X) public func spiClient(s: IOIStruct) -> IOIStruct { // expected-error 2 {{cannot use struct 'IOIStruct' here; 'Lib' has been imported as implementation-only}}
3132
return IOIStruct()
@@ -39,6 +40,7 @@ public struct IOIStruct {
3940
//--- ClientDefaultMode.swift
4041

4142
@_implementationOnly import Lib
43+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
4244

4345
@_spi(X) public func spiClient(s: IOIStruct) -> IOIStruct { // expected-warning 2 {{cannot use struct 'IOIStruct' here; 'Lib' has been imported as implementation-only}}
4446
return IOIStruct()

test/SPI/spi-only-import-conflicting.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,15 @@ import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
6060
// expected-warning @-1 {{'Lib' inconsistently imported as implementation-only}}
6161
@_implementationOnly import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
6262
// expected-note @-1 {{imported as implementation-only here}}
63+
// expected-warning @-2 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
6364

6465
/// Many confliciting imports lead to many diagnostics.
6566
//--- SPIOnly_IOI_Exported_Default.swift
6667
@_spiOnly import Lib // expected-note 3 {{imported for SPI only here}}
6768
// expected-warning @-1 {{'Lib' inconsistently imported as implementation-only}}
6869
@_implementationOnly import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
6970
// expected-note @-1 3 {{imported as implementation-only here}}
71+
// expected-warning @-2 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
7072
@_exported import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
7173
// expected-warning @-1 {{'Lib' inconsistently imported as implementation-only}}
7274
import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
@@ -82,6 +84,7 @@ import Lib
8284
/// Different IOI in different files of the same module are still rejected.
8385
//--- IOI_Default_FileA.swift
8486
@_implementationOnly import Lib // expected-note {{imported as implementation-only here}}
87+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
8588

8689
//--- IOI_Default_FileB.swift
8790
import Lib // expected-warning {{'Lib' inconsistently imported as implementation-only}}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t --leading-lines
3+
4+
// RUN: %target-swift-frontend -emit-module %t/Lib.swift \
5+
// RUN: -enable-library-evolution -swift-version 5 \
6+
// RUN: -emit-module-path %t/Lib.swiftmodule
7+
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t \
8+
// RUN: -enable-library-evolution -swift-version 5 \
9+
// RUN: -verify
10+
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t \
11+
// RUN: -enable-library-evolution -swift-version 5 \
12+
// RUN: -enable-upcoming-feature InternalImportsByDefault \
13+
// RUN: -verify
14+
15+
//--- Lib.swift
16+
public struct SomeType {}
17+
18+
//--- Client.swift
19+
@_implementationOnly import Lib
20+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}} {{1-21=internal}}
21+
22+
internal func foo(_: SomeType) {}

test/Sema/implementation-only-import-from-non-resilient.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import B
2727

2828
//--- client-resilient.swift
2929
@_implementationOnly import A
30+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
3031
import B
3132

3233
//--- Crypto.swift

test/Sema/implementation-only-import-in-decls.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import NormalLibrary
1111
@_implementationOnly import BADLibrary
12+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
1213

1314
public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
1415

test/Sema/implementation-only-import-inlinable-conformances.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// RUN: %target-typecheck-verify-swift -I %t -enable-library-evolution -swift-version 5
88

99
@_implementationOnly import BADLibrary
10+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
1011
import NormalLibrary
1112

1213
@available(*, unavailable)

test/Sema/implementation-only-import-inlinable-indirect.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// RUN: -enable-library-evolution -swift-version 5
99

1010
@_implementationOnly import directs
11+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
1112

1213
// Types
1314

test/Sema/implementation-only-import-inlinable-multifile.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// RUN: -enable-library-evolution -swift-version 5
99

1010
@_implementationOnly import directs
11+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
1112
// 'indirects' is imported for re-export in a secondary file
1213

1314
// Types

test/Sema/implementation-only-import-inlinable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// RUN: -enable-library-evolution -swift-version 5
99

1010
@_implementationOnly import directs
11+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
1112
import indirects
1213

1314
// Types

test/Sema/implementation-only-import-library-evolution.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// RUN: %target-typecheck-verify-swift -I %t -enable-library-evolution
66

77
@_implementationOnly import BADLibrary
8+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
89

910
public struct PublicStructStoredProperties {
1011
public var publiclyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}}

test/Sema/missing-import-inlinable-code.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public import libA
7575
// BEGIN clientFileA-OldCheck.swift
7676
public import libA
7777
@_implementationOnly import empty
78+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
7879

7980
@inlinable public func bar() {
8081
let a = ImportedType()
@@ -102,6 +103,7 @@ public import libA
102103

103104
// BEGIN clientFileB.swift
104105
@_implementationOnly import libB
106+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
105107
public import libA
106108
extension ImportedType {
107109
public func localModuleMethod() {}

test/Sema/missing-import-typealias.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ extension StructAlias {
9797

9898
import Aliases
9999
@_implementationOnly import Original
100+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
100101

101102
@inlinable public func inlinableFunc() {
102103
// expected-warning@+1 {{'StructAlias' aliases 'Original.Struct' and cannot be used in an '@inlinable' function because 'Original' has been imported as implementation-only; this is an error in the Swift 6 language mode}}

test/Sema/restricted-imports-priorities.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,22 @@ public struct LibAStruct {}
4545

4646
//--- TwoIOI.swift
4747
@_implementationOnly import LibB
48+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
4849
@_implementationOnly import LibC
50+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
4951

5052
public func foo(a: LibAStruct) {} // expected-error {{cannot use struct 'LibAStruct' here; 'LibA' has been imported as implementation-only}}
5153

5254
//--- SPIOnlyAndIOI1.swift
5355
@_spiOnly import LibB
5456
@_implementationOnly import LibC
57+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
5558

5659
public func foo(a: LibAStruct) {} // expected-error {{cannot use struct 'LibAStruct' here; 'LibA' was imported for SPI only}}
5760

5861
//--- SPIOnlyAndIOI2.swift
5962
@_implementationOnly import LibB
63+
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
6064
@_spiOnly import LibC
6165

6266
public func foo(a: LibAStruct) {} // expected-error {{cannot use struct 'LibAStruct' here; 'LibA' was imported for SPI only}}

0 commit comments

Comments
 (0)