Skip to content

Commit d710b5c

Browse files
committed
[Sema] Report importing modules built from a swiftinterface without resilience
Generating a swiftinterface for a module without library-evolution is not currently a recommended configuration, and it leads to a warning at building the module. We’re now considering generating more swiftinterface even without library evolution as the swiftinterface can be useful for documentation tools. However, while we can build against such a swiftinterface we shouldn’t expect the executable to work reliably. This PR adds the infrastructure necessary to detect when we’re importing a module from a swiftinterface without it having enabled library-evoluation. It is reported as an error which can be downgraded to a warning with an env var. Compiler engineers may still want a full build even if the binary is unusable. rdar://101637436
1 parent 1b46726 commit d710b5c

File tree

3 files changed

+85
-5
lines changed

3 files changed

+85
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,11 @@ WARNING(module_not_compiled_with_library_evolution,none,
984984
"using it means binary compatibility for %1 can't be guaranteed",
985985
(Identifier, Identifier))
986986

987+
ERROR(import_not_compiled_with_library_evolution_but_rebuilt,none,
988+
"module %0 was rebuilt from its swiftinterface but not compiled with "
989+
"library evolution support; execution will be unreliable",
990+
(Identifier))
991+
987992
REMARK(cross_import_added,none,
988993
"import of %0 and %1 triggered a cross-import of %2",
989994
(Identifier, Identifier, Identifier))

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,24 +1913,24 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
19131913

19141914
void visitImportDecl(ImportDecl *ID) {
19151915
TypeChecker::checkDeclAttributes(ID);
1916+
ModuleDecl *importTarget = ID->getModule();
19161917

19171918
// Force the lookup of decls referenced by a scoped import in case it emits
19181919
// diagnostics.
19191920
(void)ID->getDecls();
19201921

19211922
// Report the public import of a private module.
19221923
if (ID->getASTContext().LangOpts.LibraryLevel == LibraryLevel::API) {
1923-
auto target = ID->getModule();
19241924
auto importer = ID->getModuleContext();
1925-
if (target &&
1925+
if (importTarget &&
19261926
!ID->getAttrs().hasAttribute<ImplementationOnlyAttr>() &&
19271927
!ID->getAttrs().hasAttribute<SPIOnlyAttr>() &&
1928-
target->getLibraryLevel() == LibraryLevel::SPI) {
1928+
importTarget->getLibraryLevel() == LibraryLevel::SPI) {
19291929

19301930
auto &diags = ID->getASTContext().Diags;
19311931
InFlightDiagnostic inFlight =
19321932
diags.diagnose(ID, diag::error_public_import_of_private_module,
1933-
target->getName(), importer->getName());
1933+
importTarget->getName(), importer->getName());
19341934
if (ID->getAttrs().isEmpty()) {
19351935
inFlight.fixItInsert(ID->getStartLoc(),
19361936
"@_implementationOnly ");
@@ -1942,7 +1942,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
19421942
static bool enableTreatAsError = getenv("ENABLE_PUBLIC_IMPORT_OF_PRIVATE_AS_ERROR");
19431943
#endif
19441944

1945-
bool isImportOfUnderlying = importer->getName() == target->getName();
1945+
bool isImportOfUnderlying = importer->getName() ==
1946+
importTarget->getName();
19461947
auto *SF = ID->getDeclContext()->getParentSourceFile();
19471948
bool treatAsError = enableTreatAsError &&
19481949
!isImportOfUnderlying &&
@@ -1951,6 +1952,21 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
19511952
inFlight.limitBehavior(DiagnosticBehavior::Warning);
19521953
}
19531954
}
1955+
1956+
// Report imports of non-resilient modules built from a module interface.
1957+
if (importTarget->isBuiltFromInterface() &&
1958+
importTarget->getResilienceStrategy() != ResilienceStrategy::Resilient) {
1959+
auto &diags = ID->getASTContext().Diags;
1960+
auto inFlight =
1961+
diags.diagnose(ID,
1962+
diag::import_not_compiled_with_library_evolution_but_rebuilt,
1963+
importTarget->getName());
1964+
1965+
static const char* acceptNonResilientInterfaes =
1966+
::getenv("SWIFT_ACCEPT_NON_RESILIENT_INTERFACES");
1967+
if (acceptNonResilientInterfaes)
1968+
inFlight.limitBehavior(DiagnosticBehavior::Warning);
1969+
}
19541970
}
19551971

19561972
void visitOperatorDecl(OperatorDecl *OD) {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -emit-module %t/NonResilientLib.swift \
5+
// RUN: -module-name NonResilientLib -swift-version 5 \
6+
// RUN: -emit-module-path %t/NonResilientLib.swiftmodule \
7+
// RUN: -emit-module-interface-path %t/NonResilientLib.swiftinterface 2>&1 \
8+
// RUN: | grep "warning: module interfaces are only supported with -enable-library-evolution"
9+
10+
// RUN: %target-swift-frontend -emit-module %t/ResilientLib.swift \
11+
// RUN: -module-name ResilientLib -swift-version 5 \
12+
// RUN: -enable-library-evolution \
13+
// RUN: -emit-module-path %t/ResilientLib.swiftmodule \
14+
// RUN: -emit-module-interface-path %t/ResilientLib.swiftinterface
15+
16+
/// Expecting no diagnostics when importing the swiftmodule.
17+
// RUN: %target-swift-frontend -typecheck %t/ClientClean.swift \
18+
// RUN: -swift-version 5 -I %t -verify
19+
20+
/// Expecting diagnostics when importing the non-resilient swiftinterface.
21+
// RUN: rm %t/*.swiftmodule
22+
// RUN: %target-swift-frontend -typecheck %t/ClientError.swift \
23+
// RUN: -swift-version 5 -I %t -verify
24+
25+
// RUN: env SWIFT_ACCEPT_NON_RESILIENT_INTERFACES=1 \
26+
// RUN: %target-swift-frontend -typecheck %t/ClientWarning.swift \
27+
// RUN: -swift-version 5 -I %t -verify
28+
29+
//--- NonResilientLib.swift
30+
31+
public func NonResilientFunc() {}
32+
33+
//--- ResilientLib.swift
34+
35+
public func ResilientFunc() {}
36+
37+
//--- ClientClean.swift
38+
39+
import NonResilientLib
40+
import ResilientLib
41+
42+
NonResilientFunc()
43+
ResilientFunc()
44+
45+
//--- ClientError.swift
46+
47+
import NonResilientLib // expected-error {{module 'NonResilientLib' was rebuilt from its swiftinterface but not compiled with library evolution support; execution will be unreliable}}
48+
import ResilientLib
49+
50+
NonResilientFunc()
51+
ResilientFunc()
52+
53+
//--- ClientWarning.swift
54+
55+
import NonResilientLib // expected-warning {{module 'NonResilientLib' was rebuilt from its swiftinterface but not compiled with library evolution support; execution will be unreliable}}
56+
import ResilientLib
57+
58+
NonResilientFunc()
59+
ResilientFunc()

0 commit comments

Comments
 (0)