Skip to content

Commit 2ef0196

Browse files
committed
[Sema] Error on resilient importing publicly a non-resilient module
Importing a non-library-evolution enabled module from a library-evolution enabled module will lead to generating a swiftinterface that can't be rebuilt by a different compiler. Make it a hard error when using access level imports, and keep it as a warning for @_implementationOnly imports.
1 parent c6c96c4 commit 2ef0196

File tree

3 files changed

+71
-11
lines changed

3 files changed

+71
-11
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,10 +1011,10 @@ ERROR(import_restriction_conflict,none,
10111011
"%select{implementation-only|SPI only|exported}2 ",
10121012
(Identifier, unsigned, unsigned))
10131013

1014-
WARNING(module_not_compiled_with_library_evolution,none,
1015-
"module %0 was not compiled with library evolution support; "
1016-
"using it means binary compatibility for %1 can't be guaranteed",
1017-
(Identifier, Identifier))
1014+
ERROR(module_not_compiled_with_library_evolution,none,
1015+
"module %0 was not compiled with library evolution support; "
1016+
"using it means binary compatibility for %1 can't be guaranteed",
1017+
(Identifier, Identifier))
10181018

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

lib/Sema/ImportResolution.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,8 @@ void UnboundImport::validateAllowableClient(ModuleDecl *importee,
737737

738738
void UnboundImport::validateResilience(NullablePtr<ModuleDecl> topLevelModule,
739739
SourceFile &SF) {
740-
if (import.options.contains(ImportFlags::ImplementationOnly))
740+
if (import.options.contains(ImportFlags::ImplementationOnly) ||
741+
import.accessLevel < AccessLevel::Public)
741742
return;
742743

743744
// Per getTopLevelModule(), we'll only get nullptr here for non-Swift modules,
@@ -760,12 +761,20 @@ void UnboundImport::validateResilience(NullablePtr<ModuleDecl> topLevelModule,
760761
topLevelModule.get()->isResilient())
761762
return;
762763

763-
ctx.Diags.diagnose(import.module.getModulePath().front().Loc,
764-
diag::module_not_compiled_with_library_evolution,
765-
topLevelModule.get()->getName(),
766-
SF.getParentModule()->getName());
767-
// FIXME: Once @_implementationOnly is a real feature, we should have a fix-it
768-
// to add it.
764+
auto inFlight = ctx.Diags.diagnose(import.module.getModulePath().front().Loc,
765+
diag::module_not_compiled_with_library_evolution,
766+
topLevelModule.get()->getName(),
767+
SF.getParentModule()->getName());
768+
769+
if (ctx.LangOpts.hasFeature(Feature::AccessLevelOnImport)) {
770+
SourceLoc attrLoc = import.accessLevelLoc;
771+
if (attrLoc.isValid())
772+
inFlight.fixItReplace(attrLoc, "internal");
773+
else
774+
inFlight.fixItInsert(import.importLoc, "internal ");
775+
} else {
776+
inFlight.limitBehavior(DiagnosticBehavior::Warning);
777+
}
769778
}
770779

771780
void UnboundImport::diagnoseInvalidAttr(DeclAttrKind attrKind,
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
/// Build the libraries.
5+
// RUN: %target-swift-frontend -emit-module %t/DefaultLib.swift -o %t
6+
// RUN: %target-swift-frontend -emit-module %t/PublicLib.swift -o %t
7+
// RUN: %target-swift-frontend -emit-module %t/PackageLib.swift -o %t
8+
// RUN: %target-swift-frontend -emit-module %t/InternalLib.swift -o %t
9+
// RUN: %target-swift-frontend -emit-module %t/FileprivateLib.swift -o %t
10+
// RUN: %target-swift-frontend -emit-module %t/PrivateLib.swift -o %t
11+
12+
/// A resilient client will error on public imports.
13+
// RUN: %target-swift-frontend -typecheck %t/Client_Swift5.swift -I %t \
14+
// RUN: -enable-library-evolution -swift-version 5 \
15+
// RUN: -enable-experimental-feature AccessLevelOnImport -verify
16+
// RUN: %target-swift-frontend -typecheck %t/Client_Swift6.swift -I %t \
17+
// RUN: -enable-library-evolution -swift-version 6 \
18+
// RUN: -enable-experimental-feature AccessLevelOnImport -verify
19+
20+
/// A non-resilient client doesn't complain.
21+
// RUN: %target-swift-frontend -typecheck %t/Client_Swift5.swift -I %t \
22+
// RUN: -swift-version 5 \
23+
// RUN: -enable-experimental-feature AccessLevelOnImport
24+
// RUN: %target-swift-frontend -typecheck %t/Client_Swift6.swift -I %t \
25+
// RUN: -swift-version 6 \
26+
// RUN: -enable-experimental-feature AccessLevelOnImport
27+
28+
//--- DefaultLib.swift
29+
//--- PublicLib.swift
30+
//--- PackageLib.swift
31+
//--- InternalLib.swift
32+
//--- FileprivateLib.swift
33+
//--- PrivateLib.swift
34+
35+
//--- Client_Swift5.swift
36+
37+
import DefaultLib // expected-error {{module 'DefaultLib' was not compiled with library evolution support; using it means binary compatibility for 'Client_Swift5' can't be guaranteed}} {{1-1=internal }}
38+
public import PublicLib // expected-error {{module 'PublicLib' was not compiled with library evolution support; using it means binary compatibility for 'Client_Swift5' can't be guaranteed}} {{1-7=internal}}
39+
package import PackageLib
40+
internal import InternalLib
41+
fileprivate import FileprivateLib
42+
private import PrivateLib
43+
44+
//--- Client_Swift6.swift
45+
46+
import DefaultLib
47+
public import PublicLib // expected-error {{module 'PublicLib' was not compiled with library evolution support; using it means binary compatibility for 'Client_Swift6' can't be guaranteed}} {{1-7=internal}}
48+
package import PackageLib
49+
internal import InternalLib
50+
fileprivate import FileprivateLib
51+
private import PrivateLib

0 commit comments

Comments
 (0)