Skip to content

Commit ae8e95d

Browse files
committed
[Embedded] Introduce a test for @_implementationOnly + @_neverEmitIntoClient
In Desktop Swift, @_implementationOnly imports allow one to hide the implementation so long as you're careful to only reference entities from the imported modules in code that gets compiled into the object file and *not* referenced by the corresponding Swift module file. Until very recently, there was no such affordance for Embedded Swift, because all functions would have their SIL serialized to the Swift module file. Using them from a client module would then attempt to deserialize the SIL, loading the @_implementationOnly-imported module and causing the compiler to abort. With the introduction of @_neverEmitIntoClient, we now have a way to say "only in the object file, never in the module file" for the definition of functions. Introduce a test that makes sure @_implementationOnly + @_neverEmitIntoClient has the desired effect of hiding the imported modules from clients. It's still brittle and hard to use, just like the existing @_implementationOnly, but this shows that it's at least possible to do this implementation hiding in Embedded Swift.
1 parent 2f60d72 commit ae8e95d

File tree

4 files changed

+88
-0
lines changed

4 files changed

+88
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
typedef struct {
2+
double x, y;
3+
} Point;
4+
5+
Point getPoint(double x, double y);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public struct A {
2+
private var string: String
3+
4+
public init() { self.string = "Hello" }
5+
6+
public func doSomething() { }
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module CDependency {
2+
header "CHeader.h"
3+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// This elaborate test ensures that @_implementationOnly with Embedded Swift
2+
// can hide some dependencies if you are very, very careful.
3+
4+
// RUN: %empty-directory(%t)
5+
// RUN: mkdir -p %t/Dependencies
6+
// RUN: mkdir -p %t/Files
7+
// RUN: mkdir -p %t/Modules
8+
9+
// Copy Swift file + C header + module map into a separate directory we'll use
10+
// when building the module whose implementation we want to hide.
11+
// RUN: cp %S/Inputs/SwiftDependency.swift %t/Dependencies/
12+
// RUN: cp %S/Inputs/CHeader.h %t/Dependencies/
13+
// RUN: cp %S/Inputs/module.modulemap %t/Dependencies/
14+
15+
// RUN: split-file %s %t/Files
16+
17+
// Compile the Swift dependencies into that same location.
18+
// RUN: %target-swift-frontend -parse-as-library -emit-module %t/Dependencies/SwiftDependency.swift -enable-experimental-feature Embedded -o %t/Dependencies/SwiftDependency.swiftmodule
19+
20+
// Build the library (which is supposed to encapsulate those dependencies)
21+
// against the dependencies.
22+
// RUN: %target-swift-frontend -parse-as-library -emit-module %t/Files/Library.swift -enable-experimental-feature Embedded -I %t/Dependencies/ -o %t/Modules/Library.swiftmodule
23+
24+
// Remove the dependencies so there is no way we can find them later.
25+
// RUN: rm -rf %t/Dependencies
26+
27+
// Build the application against the library. This is expected to work because
28+
// @_neverEmitIntoClient hides the body of test().
29+
// RUN: %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir
30+
31+
// Build the application against the library, but intentionally trigger
32+
// deserialization of some serialized SIL that refers to an implementation-only
33+
// dependency. Right now, these fail spectacularly. Over time, we want them to
34+
// become compile-time errors or start working.
35+
// RUN: not --crash %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir -DBAD_C_USAGE
36+
// RUN: not --crash %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir -DBAD_SWIFT_USAGE
37+
38+
// REQUIRES: swift_in_compiler
39+
// REQUIRES: swift_feature_Embedded
40+
41+
//--- Library.swift
42+
@_implementationOnly import CDependency
43+
@_implementationOnly import SwiftDependency
44+
45+
@_neverEmitIntoClient
46+
public func test() {
47+
_ = getPoint(3.14159, 2.71828)
48+
A().doSomething()
49+
}
50+
51+
public func badCLibraryUsage() {
52+
_ = getPoint(3.14159, 2.71828)
53+
}
54+
55+
public func badSwiftLibraryUsage() {
56+
A().doSomething()
57+
}
58+
59+
//--- Application.swift
60+
61+
import Library
62+
63+
public func useTest() {
64+
test()
65+
66+
#if BAD_C_USAGE
67+
badCLibraryUsage()
68+
#endif
69+
70+
#if BAD_SWIFT_USAGE
71+
badSwiftLibraryUsage()
72+
#endif
73+
}

0 commit comments

Comments
 (0)