Skip to content

[ModuleInterface] Report importing modules built from a swiftinterface without resilience #61765

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,11 @@ ERROR(module_allowable_client_violation,none,
"module %0 doesn't allow importation from module %1",
(Identifier, Identifier))

ERROR(import_not_compiled_with_library_evolution_but_rebuilt,none,
"module %0 was rebuilt from a swiftinterface without library evolution; "
"it cannot be used to build a binary",
(Identifier))

REMARK(cross_import_added,none,
"import of %0 and %1 triggered a cross-import of %2",
(Identifier, Identifier, Identifier))
Expand Down
28 changes: 23 additions & 5 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1923,24 +1923,26 @@ class DeclChecker : public DeclVisitor<DeclChecker> {

void visitImportDecl(ImportDecl *ID) {
TypeChecker::checkDeclAttributes(ID);
ModuleDecl *importTarget = ID->getModule();
if (!importTarget)
return;

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

// Report the public import of a private module.
if (ID->getASTContext().LangOpts.LibraryLevel == LibraryLevel::API) {
auto target = ID->getModule();
auto importer = ID->getModuleContext();
if (target &&
if (importTarget &&
!ID->getAttrs().hasAttribute<ImplementationOnlyAttr>() &&
!ID->getAttrs().hasAttribute<SPIOnlyAttr>() &&
target->getLibraryLevel() == LibraryLevel::SPI) {
importTarget->getLibraryLevel() == LibraryLevel::SPI) {

auto &diags = ID->getASTContext().Diags;
InFlightDiagnostic inFlight =
diags.diagnose(ID, diag::error_public_import_of_private_module,
target->getName(), importer->getName());
importTarget->getName(), importer->getName());
if (ID->getAttrs().isEmpty()) {
inFlight.fixItInsert(ID->getStartLoc(),
"@_implementationOnly ");
Expand All @@ -1952,7 +1954,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
static bool enableTreatAsError = getenv("ENABLE_PUBLIC_IMPORT_OF_PRIVATE_AS_ERROR");
#endif

bool isImportOfUnderlying = importer->getName() == target->getName();
bool isImportOfUnderlying = importer->getName() ==
importTarget->getName();
auto *SF = ID->getDeclContext()->getParentSourceFile();
bool treatAsError = enableTreatAsError &&
!isImportOfUnderlying &&
Expand All @@ -1961,6 +1964,21 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
inFlight.limitBehavior(DiagnosticBehavior::Warning);
}
}

// Report imports of non-resilient modules built from a module interface.
if (importTarget->isBuiltFromInterface() &&
importTarget->getResilienceStrategy() != ResilienceStrategy::Resilient) {
auto &diags = ID->getASTContext().Diags;
auto inFlight =
diags.diagnose(ID,
diag::import_not_compiled_with_library_evolution_but_rebuilt,
importTarget->getName());

static const char* acceptNonResilientInterfaes =
::getenv("SWIFT_ACCEPT_NON_RESILIENT_INTERFACES");
if (acceptNonResilientInterfaes)
inFlight.limitBehavior(DiagnosticBehavior::Warning);
}
}

void visitOperatorDecl(OperatorDecl *OD) {
Expand Down
6 changes: 4 additions & 2 deletions test/DebugInfo/ParseableInterfaceImports.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend-typecheck %S/basic.swift \
// RUN: -emit-module-interface-path %t/basic.swiftinterface
// RUN: %target-swift-frontend -emit-ir -module-name Foo %s -I %t -g -o - \
// RUN: env SWIFT_ACCEPT_NON_RESILIENT_INTERFACES=1 \
// RUN: %target-swift-frontend -emit-ir -module-name Foo %s -I %t -g -o - \
// RUN: | %FileCheck %s
// RUN: %target-swift-frontend -emit-ir -module-name Foo %s -I %t -g -o - \
// RUN: env SWIFT_ACCEPT_NON_RESILIENT_INTERFACES=1 \
// RUN: %target-swift-frontend -emit-ir -module-name Foo %s -I %t -g -o - \
// RUN: -sdk %t | %FileCheck %s --check-prefix=SDK

import basic
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %empty-directory(%t)

// RUN: %target-build-swift -emit-library -module-name TestModule -module-link-name TestModule %S/Inputs/class-open-0argument.swift -emit-module-interface -swift-version 5 -o %t/%target-library-name(TestModule)
// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir -I %t -L %t %s | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment --check-prefix=CHECK --check-prefix=CHECK-%target-vendor
// RUN: env SWIFT_ACCEPT_NON_RESILIENT_INTERFACES=1 %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir -I %t -L %t %s | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment --check-prefix=CHECK --check-prefix=CHECK-%target-vendor

// REQUIRES: VENDOR=apple || OS=linux-gnu
// UNSUPPORTED: CPU=i386 && OS=ios
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// RUN: %empty-directory(%t)

// RUN: %target-build-swift -emit-library -module-name TestModule -module-link-name TestModule %S/Inputs/protocol-public-empty.swift -emit-module-interface -swift-version 5 -o %t/%target-library-name(TestModule)
// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir -I %t -L %t %s | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment
// RUN: env SWIFT_ACCEPT_NON_RESILIENT_INTERFACES=1 \
// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir -I %t -L %t %s | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment

// REQUIRES: VENDOR=apple || OS=linux-gnu
// UNSUPPORTED: CPU=i386 && OS=ios
Expand Down
3 changes: 2 additions & 1 deletion test/Misc/stats_dir_module_interface.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %empty-directory(%t)
// RUN: mkdir %t/stats
// RUN: mkdir %t/cache
// RUN: %target-swift-frontend -typecheck %s -I %S/Inputs -stats-output-dir %t/stats -module-cache-path %t/cache
// RUN: env SWIFT_ACCEPT_NON_RESILIENT_INTERFACES=1 \
// RUN: %target-swift-frontend -typecheck %s -I %S/Inputs -stats-output-dir %t/stats -module-cache-path %t/cache

import empty
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -swift-version 5 -enforce-exclusivity=checked -module-name SIMod
// swift-module-flags: -swift-version 5 -enforce-exclusivity=checked -module-name SIMod -enable-library-evolution
import CIMod

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -target x86_64-apple-macos10.9 -module-name OtherModule -O
// swift-module-flags: -target x86_64-apple-macos10.9 -module-name OtherModule -O -enable-library-evolution

import Swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -target x86_64-apple-macos10.9 -module-name Swift -parse-stdlib
// swift-module-flags: -target x86_64-apple-macos10.9 -module-name Swift -parse-stdlib -enable-library-evolution

public struct Int {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -target x86_64-apple-macos10.9 -module-name _Concurrency -parse-stdlib
// swift-module-flags: -target x86_64-apple-macos10.9 -module-name _Concurrency -parse-stdlib -enable-library-evolution

@frozen public enum Task {}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -parse-stdlib -module-name ExportedLib
// swift-module-flags: -parse-stdlib -module-name ExportedLib -enable-library-evolution

@_exported import SomeCModule

public struct ExportedInterface {
@inlinable public init() {}
@inlinable public init() { self.init() }
}
public var testValue: ExportedInterface {
@inlinable get { return ExportedInterface() }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -parse-stdlib -module-name SdkLib
// swift-module-flags: -parse-stdlib -module-name SdkLib -enable-library-evolution

@_exported import ExportedLib

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -parse-stdlib -module-name Lib
// swift-module-flags: -parse-stdlib -module-name Lib -enable-library-evolution

public struct FromInterface {
@inlinable public init() {}
@inlinable public init() { self.init() }
}
public var testValue: FromInterface {
@inlinable get { return FromInterface() }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -parse-stdlib -module-name LibExporter
// swift-module-flags: -parse-stdlib -module-name LibExporter -enable-library-evolution

@_exported import Lib
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// RUN: echo 'public func publicFunction() {}' > %t/TestModule.swift

// 2. Create an interface for it
// RUN: %target-swift-frontend -typecheck %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5
// RUN: %target-swift-frontend -typecheck %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5 -enable-library-evolution

// 3. Create an empty .swiftmodule, which will force recompiling from the interface
// RUN: touch %t/Build/TestModule.swiftmodule
Expand All @@ -16,4 +16,4 @@

import TestModule // expected-remark {{rebuilding module 'TestModule' from interface}}
// expected-note @-1 {{is out of date}}
// expected-note @-2 {{malformed}}
// expected-note @-2 {{malformed}}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// RUN: echo 'public func publicFunction() {}' > %t/TestModule.swift

// 2. Create both an interface and a compiled module for it
// RUN: %target-swift-frontend -emit-module -o %t/Build/TestModule.swiftmodule %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5 -module-name TestModule
// RUN: %target-swift-frontend -emit-module -o %t/Build/TestModule.swiftmodule %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5 -module-name TestModule -enable-library-evolution

// 3. Make the compiled module unreadable so it gets added as a dependency but is not used
// RUN: mv %t/Build/TestModule.swiftmodule %t/Build/TestModule.swiftmodule.moved-aside
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// RUN: echo 'public func publicFunction() {}' > %t/TestModule.swift

// 2. Create an interface for it
// RUN: %target-swift-frontend -typecheck %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5
// RUN: %target-swift-frontend -typecheck %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5 -enable-library-evolution

// 3. Try to import the interface, which will pass and create a cached module
// RUN: %target-swift-frontend -typecheck %s -I %t/Build -module-cache-path %t/ModuleCache
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// RUN: echo 'public func publicFunction() {}' > %t/TestModule.swift

// 2. Create an interface for it
// RUN: %target-swift-frontend -typecheck %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5
// RUN: %target-swift-frontend -typecheck %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5 -enable-library-evolution

// 3. Build the .swiftinterface to a .swiftmodule, which will have a dependency on the interface
// RUN: %target-swift-frontend -compile-module-from-interface -o %t/Build/TestModule.swiftmodule %t/Build/TestModule.swiftinterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// RUN: echo 'public func publicFunction() {}' > %t/TestModule.swift

// 2. Create an interface for it
// RUN: %target-swift-frontend -typecheck %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5
// RUN: %target-swift-frontend -typecheck %t/TestModule.swift -emit-module-interface-path %t/Build/TestModule.swiftinterface -swift-version 5 -enable-library-evolution

// 3. Build the .swiftinterface to a .swiftmodule in the prebuilt cache, which will have a dependency on the interface
// RUN: %target-swift-frontend -compile-module-from-interface %t/Build/TestModule.swiftinterface -o %t/PrebuiltCache/TestModule.swiftmodule
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name SystemDependencies
// swift-module-flags: -module-name SystemDependencies -enable-library-evolution

// RUN: %empty-directory(%t)
// RUN: cp -r %S/Inputs/mock-sdk %t/mock-sdk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
//
// Phase 1: build LeafModule into a .swiftinterface file with -target %target-cpu-macosx-10.9:
//
// RUN: %swift -target %target-cpu-apple-macosx10.9 -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -typecheck
// RUN: %swift -target %target-cpu-apple-macosx10.9 -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -typecheck -enable-library-evolution
//
// Phase 2: build OtherModule into a .swiftinterface file with -target %target-cpu-macosx-10.10:
//
// RUN: %swift -target %target-cpu-apple-macosx10.10 -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -typecheck
// RUN: %swift -target %target-cpu-apple-macosx10.10 -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -typecheck -enable-library-evolution
//
// Phase 3: build TestModule in -target %target-cpu-apple-macosx10.11 and import both of these:
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
// Setup phase 2: build modules, pushing timestamps of inputs and intermediates into the past as we go.
//
// RUN: %{python} %S/Inputs/make-old.py %t/leaf.swift %t/other.swift
// RUN: %target-swift-frontend -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -emit-module -o /dev/null
// RUN: %target-swift-frontend -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -emit-module -o /dev/null -enable-library-evolution
// RUN: %{python} %S/Inputs/make-old.py %t/LeafModule.swiftinterface
// RUN: %target-swift-frontend -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -emit-module -o /dev/null
// RUN: %target-swift-frontend -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -emit-module -o /dev/null -enable-library-evolution
// RUN: %{python} %S/Inputs/make-old.py %t/modulecache/LeafModule-*.swiftmodule %t/OtherModule.swiftinterface
// RUN: %target-swift-frontend -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -module-cache-path %t/modulecache -emit-module -o %t/TestModule.swiftmodule -module-name TestModule %s
// RUN: %{python} %S/Inputs/make-old.py %t/modulecache/OtherModule-*.swiftmodule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
//
// Phase 1: build LeafModule into a .swiftinterface file with -swift-version 4:
//
// RUN: %target-swift-frontend -swift-version 4 -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -typecheck
// RUN: %target-swift-frontend -swift-version 4 -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -typecheck -enable-library-evolution
//
// Phase 2: build OtherModule into a .swiftinterface file with -swift-version 4.2:
//
// RUN: %target-swift-frontend -swift-version 4.2 -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -typecheck
// RUN: %target-swift-frontend -swift-version 4.2 -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -typecheck -enable-library-evolution
//
// Phase 3: build TestModule in -swift-version 5 and import both of these:
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

// Setup phase 2: build the module.
//
// RUN: %target-swift-frontend -I %t -emit-module-interface-path %t/SomeModule.swiftinterface -module-name SomeModule %t/some-module.swift -emit-module -o /dev/null
// RUN: %target-swift-frontend -I %t -emit-module-interface-path %t/SomeModule.swiftinterface -module-name SomeModule %t/some-module.swift -emit-module -o /dev/null -enable-library-evolution

// Actual test: compile and verify the import succeeds (i.e. we only report the error in this file)
//
Expand Down
4 changes: 2 additions & 2 deletions test/ModuleInterface/ModuleCache/module-cache-init.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
//
// Phase 1: build LeafModule into a .swiftinterface file:
//
// RUN: %target-swift-frontend -I %t -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -emit-module -o /dev/null
// RUN: %target-swift-frontend -I %t -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -emit-module -o /dev/null -enable-library-evolution
// RUN: test -f %t/LeafModule.swiftinterface
// RUN: %FileCheck %s -check-prefix=CHECK-LEAFINTERFACE <%t/LeafModule.swiftinterface
// CHECK-LEAFINTERFACE: LeafFunc
//
//
// Phase 2: build OtherModule into a .swiftinterface _using_ LeafModule via LeafModule.swiftinterface, creating LeafModule-*.swiftmodule along the way.
//
// RUN: %target-swift-frontend -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -emit-module -o /dev/null
// RUN: %target-swift-frontend -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -emit-module -o /dev/null -enable-library-evolution
// RUN: test -f %t/OtherModule.swiftinterface
// RUN: %FileCheck %s -check-prefix=CHECK-OTHERINTERFACE <%t/OtherModule.swiftinterface
// CHECK-OTHERINTERFACE: OtherFunc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
// Setup phase 2: build modules, pushing timestamps of inputs and intermediates into the past as we go.
//
// RUN: %{python} %S/Inputs/make-old.py %t/leaf.swift %t/other.swift
// RUN: %target-swift-frontend -I %t -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -emit-module -o /dev/null
// RUN: %target-swift-frontend -I %t -emit-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -emit-module -o /dev/null -enable-library-evolution
// RUN: %{python} %S/Inputs/make-old.py %t/LeafModule.swiftinterface
// RUN: %target-swift-frontend -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -emit-module -o /dev/null
// RUN: %target-swift-frontend -I %t -module-cache-path %t/modulecache -emit-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -emit-module -o /dev/null -enable-library-evolution
// RUN: %{python} %S/Inputs/make-old.py %t/modulecache/LeafModule-*.swiftmodule %t/OtherModule.swiftinterface
// RUN: %target-swift-frontend -I %t -module-cache-path %t/modulecache -emit-module -o %t/TestModule.swiftmodule -module-name TestModule %s
// RUN: %{python} %S/Inputs/make-old.py %t/modulecache/OtherModule-*.swiftmodule
Expand Down
Loading