Skip to content

Commit 93704f6

Browse files
authored
Merge pull request #63248 from xymus/swift-export-as
[ModuleInterface] Intro the flag `-export-as` for Swift modules
2 parents c8ef200 + c285c5e commit 93704f6

17 files changed

+165
-3
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ ERROR(error_stdlib_module_name,none,
180180
"module name \"%0\" is reserved for the standard library"
181181
"%select{|; use -module-name flag to specify an alternate name}1",
182182
(StringRef, bool))
183+
184+
ERROR(error_bad_export_as_name,none,
185+
"export-as name \"%0\" is not a valid identifier",
186+
(StringRef))
187+
183188
ERROR(error_bad_package_name,none,
184189
"package name \"%0\" is not a valid identifier",
185190
(StringRef))

include/swift/AST/FileUnit.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,11 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
322322
/// The 'real name' is the actual binary name of the module, which can be different from the 'name'
323323
/// if module aliasing was used (via -module-alias flag).
324324
///
325-
/// Usually this is the module real name itself, but certain Clang features allow
326-
/// substituting another name instead.
325+
/// This is usually the module real name which can be overriden by an
326+
/// `export_as` definition of a clang module, or `-export-as` flag on an
327+
/// imported Swift module. Swift modules built from source do not apply
328+
/// their own `-export-as` flag, this way the swiftinterface can be
329+
/// verified.
327330
virtual StringRef getExportedModuleName() const {
328331
return getParentModule()->getRealName().str();
329332
}

include/swift/AST/Module.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ class ModuleDecl
175175

176176
/// The name of the package this module belongs to
177177
mutable Identifier PackageName;
178+
179+
/// Module name to use when referenced in clients module interfaces.
180+
mutable Identifier ExportAsName;
181+
178182
public:
179183
/// Produces the components of a given module's full name in reverse order.
180184
///
@@ -410,6 +414,12 @@ class ModuleDecl
410414
PackageName = name;
411415
}
412416

417+
Identifier getExportAsName() const { return ExportAsName; }
418+
419+
void setExportAsName(Identifier name) {
420+
ExportAsName = name;
421+
}
422+
413423
/// Retrieve the actual module name of an alias used for this module (if any).
414424
///
415425
/// For example, if '-module-alias Foo=Bar' is passed in when building the main module,

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ class FrontendOptions {
6767
/// The name of the package this module belongs to.
6868
std::string PackageName;
6969

70+
/// Module name to use when referenced in clients module interfaces.
71+
std::string ExportAsName;
72+
7073
/// Arguments which should be passed in immediate mode.
7174
std::vector<std::string> ImmediateArgv;
7275

include/swift/Option/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ def module_abi_name : Separate<["-"], "module-abi-name">,
484484
def package_name : Separate<["-"], "package-name">,
485485
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable]>,
486486
HelpText<"Name of the package the module belongs to">;
487+
def export_as : Separate<["-"], "export-as">,
488+
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable]>,
489+
HelpText<"Module name to use when referenced in clients module interfaces">;
487490

488491
def emit_module : Flag<["-"], "emit-module">,
489492
Flags<[FrontendOption, NoInteractiveOption, SupplementaryOutput]>,

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ class SerializedASTFile final : public LoadedFile {
455455

456456
virtual StringRef getModuleDefiningPath() const override;
457457

458+
virtual StringRef getExportedModuleName() const override;
459+
458460
ValueDecl *getMainDecl() const override;
459461

460462
bool hasEntryPoint() const override;

include/swift/Serialization/Validation.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class ExtendedValidationInfo {
108108
std::string SDKPath;
109109
StringRef ModuleABIName;
110110
StringRef ModulePackageName;
111+
StringRef ExportAsName;
111112
struct {
112113
unsigned ArePrivateImportsEnabled : 1;
113114
unsigned IsSIB : 1;
@@ -183,6 +184,9 @@ class ExtendedValidationInfo {
183184
StringRef getModulePackageName() const { return ModulePackageName; }
184185
void setModulePackageName(StringRef name) { ModulePackageName = name; }
185186

187+
StringRef getExportAsName() const { return ExportAsName; }
188+
void setExportAsName(StringRef name) { ExportAsName = name; }
189+
186190
bool isConcurrencyChecked() const {
187191
return Bits.IsConcurrencyChecked;
188192
}

lib/Driver/ToolChains.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
253253
inputArgs.AddLastArg(arguments, options::OPT_module_link_name);
254254
inputArgs.AddLastArg(arguments, options::OPT_module_abi_name);
255255
inputArgs.AddLastArg(arguments, options::OPT_package_name);
256+
inputArgs.AddLastArg(arguments, options::OPT_export_as);
256257
inputArgs.AddLastArg(arguments, options::OPT_nostdimport);
257258
inputArgs.AddLastArg(arguments, options::OPT_parse_stdlib);
258259
inputArgs.AddLastArg(arguments, options::OPT_resource_dir);

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ bool ArgsToFrontendOptionsConverter::convert(
279279
Opts.PackageName = pkgName;
280280
}
281281

282+
if (const Arg *A = Args.getLastArg(OPT_export_as)) {
283+
auto exportAs = A->getValue();
284+
if (!Lexer::isIdentifier(exportAs))
285+
Diags.diagnose(SourceLoc(), diag::error_bad_export_as_name, exportAs);
286+
else
287+
Opts.ExportAsName = exportAs;
288+
}
289+
282290
// This must be called after computing module name, module abi name,
283291
// and module link name. If computing module aliases is unsuccessful,
284292
// return early.

lib/Frontend/Frontend.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,10 @@ ModuleDecl *CompilerInstance::getMainModule() const {
10851085
MainModule->setPackageName(getASTContext().getIdentifier(
10861086
Invocation.getFrontendOptions().PackageName));
10871087
}
1088+
if (!Invocation.getFrontendOptions().ExportAsName.empty()) {
1089+
MainModule->setExportAsName(getASTContext().getIdentifier(
1090+
Invocation.getFrontendOptions().ExportAsName));
1091+
}
10881092
if (Invocation.getFrontendOptions().EnableLibraryEvolution)
10891093
MainModule->setResilienceStrategy(ResilienceStrategy::Resilient);
10901094
if (Invocation.getLangOptions().isSwiftVersionAtLeast(6))

lib/Serialization/ModuleFile.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,3 +1324,10 @@ StringRef SerializedASTFile::getModuleDefiningPath() const {
13241324

13251325
return moduleFilename;
13261326
}
1327+
1328+
StringRef SerializedASTFile::getExportedModuleName() const {
1329+
auto name = File.getModuleExportAsName();
1330+
if (!name.empty())
1331+
return name;
1332+
return FileUnit::getExportedModuleName();
1333+
}

lib/Serialization/ModuleFile.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,11 @@ class ModuleFile
535535
StringRef getModulePackageName() const {
536536
return Core->ModulePackageName;
537537
}
538+
539+
StringRef getModuleExportAsName() const {
540+
return Core->ModuleExportAsName;
541+
}
542+
538543
/// The ABI name of the module.
539544
StringRef getModuleABIName() const {
540545
return Core->ModuleABIName;

lib/Serialization/ModuleFileSharedCore.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
166166
case options_block::MODULE_PACKAGE_NAME:
167167
extendedInfo.setModulePackageName(blobData);
168168
break;
169+
case options_block::MODULE_EXPORT_AS_NAME:
170+
extendedInfo.setExportAsName(blobData);
171+
break;
169172
default:
170173
// Unknown options record, possibly for use by a future version of the
171174
// module format.
@@ -1350,6 +1353,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
13501353
MiscVersion = info.miscVersion;
13511354
ModuleABIName = extInfo.getModuleABIName();
13521355
ModulePackageName = extInfo.getModulePackageName();
1356+
ModuleExportAsName = extInfo.getExportAsName();
13531357

13541358
hasValidControlBlock = true;
13551359
break;

lib/Serialization/ModuleFileSharedCore.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ class ModuleFileSharedCore {
8585
/// The name of the package this module belongs to.
8686
StringRef ModulePackageName;
8787

88+
/// Module name to use when referenced in clients module interfaces.
89+
StringRef ModuleExportAsName;
90+
8891
/// \c true if this module has incremental dependency information.
8992
bool HasIncrementalInfo = false;
9093

lib/Serialization/ModuleFormat.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 739; // CxxStdlib
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 740; // export-as
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -861,6 +861,7 @@ namespace options_block {
861861
MODULE_ABI_NAME,
862862
IS_CONCURRENCY_CHECKED,
863863
MODULE_PACKAGE_NAME,
864+
MODULE_EXPORT_AS_NAME,
864865
};
865866

866867
using SDKPathLayout = BCRecordLayout<
@@ -924,6 +925,11 @@ namespace options_block {
924925
MODULE_PACKAGE_NAME,
925926
BCBlob
926927
>;
928+
929+
using ModuleExportAsNameLayout = BCRecordLayout<
930+
MODULE_EXPORT_AS_NAME,
931+
BCBlob
932+
>;
927933
}
928934

929935
/// The record types within the input block.

lib/Serialization/Serialization.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,11 @@ void Serializer::writeHeader(const SerializationOptions &options) {
10731073
PackageName.emit(ScratchRecord, M->getPackageName().str());
10741074
}
10751075

1076+
if (!M->getExportAsName().empty()) {
1077+
options_block::ModuleExportAsNameLayout ExportAs(Out);
1078+
ExportAs.emit(ScratchRecord, M->getExportAsName().str());
1079+
}
1080+
10761081
if (M->isConcurrencyChecked()) {
10771082
options_block::IsConcurrencyCheckedLayout IsConcurrencyChecked(Out);
10781083
IsConcurrencyChecked.emit(ScratchRecord);
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -emit-module %t/PrivateLib.swift \
5+
// RUN: -swift-version 5 -enable-library-evolution \
6+
// RUN: -export-as PublicLib \
7+
// RUN: -o %t/PrivateLib.swiftmodule \
8+
// RUN: -emit-module-interface-path %t/PrivateLib.swiftinterface \
9+
// RUN: -emit-private-module-interface-path %t/PrivateLib.private.swiftinterface
10+
// RUN: %target-swift-typecheck-module-from-interface(%t/PrivateLib.swiftinterface)
11+
// RUN: %target-swift-typecheck-module-from-interface(%t/PrivateLib.private.swiftinterface) \
12+
// RUN: -module-name PrivateLib
13+
// RUN: cat %t/PrivateLib.swiftinterface | %FileCheck --check-prefixes=PRIVATELIB-PUBLIC %s
14+
// RUN: cat %t/PrivateLib.private.swiftinterface | %FileCheck --check-prefixes=PRIVATELIB-PUBLIC %s
15+
16+
// RUN: %target-swift-frontend -emit-module %t/PublicLib.swift -I %t \
17+
// RUN: -swift-version 5 -enable-library-evolution \
18+
// RUN: -o %t/PublicLib.swiftmodule \
19+
// RUN: -emit-module-interface-path %t/PublicLib.swiftinterface \
20+
// RUN: -emit-private-module-interface-path %t/PublicLib.private.swiftinterface
21+
// RUN: %target-swift-typecheck-module-from-interface(%t/PublicLib.swiftinterface) -I %t
22+
// RUN: %target-swift-typecheck-module-from-interface(%t/PublicLib.private.swiftinterface) -I %t \
23+
// RUN: -module-name PublicLib
24+
// RUN: cat %t/PublicLib.swiftinterface | %FileCheck --check-prefixes=PUBLICLIB-PUBLIC %s
25+
// RUN: cat %t/PublicLib.private.swiftinterface | %FileCheck --check-prefixes=PUBLICLIB-PUBLIC %s
26+
27+
/// Default logic applying export-as in both swiftinterface.
28+
// RUN: %target-swift-frontend -emit-module %t/ClientLib.swift -I %t \
29+
// RUN: -swift-version 5 -enable-library-evolution \
30+
// RUN: -o %t/ClientLib.swiftmodule \
31+
// RUN: -emit-module-interface-path %t/ClientLib.swiftinterface \
32+
// RUN: -emit-private-module-interface-path %t/ClientLib.private.swiftinterface
33+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.swiftinterface) -I %t
34+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.private.swiftinterface) -I %t
35+
// RUN: cat %t/ClientLib.swiftinterface | %FileCheck --check-prefixes=CLIENT-PUBLIC %s
36+
// RUN: cat %t/ClientLib.private.swiftinterface | %FileCheck --check-prefixes=CLIENT-PUBLIC %s
37+
38+
/// New logic applying export-as only in the public swiftinterface with
39+
/// `-enable-experimental-feature ModuleInterfaceExportAs`.
40+
// RUN: %target-swift-frontend -emit-module %t/ClientLib.swift -I %t \
41+
// RUN: -swift-version 5 -enable-library-evolution \
42+
// RUN: -o %t/ClientLib.swiftmodule \
43+
// RUN: -emit-module-interface-path %t/ClientLib.swiftinterface \
44+
// RUN: -emit-private-module-interface-path %t/ClientLib.private.swiftinterface \
45+
// RUN: -enable-experimental-feature ModuleInterfaceExportAs
46+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.swiftinterface) -I %t
47+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.private.swiftinterface) -I %t
48+
// RUN: cat %t/ClientLib.swiftinterface | %FileCheck --check-prefixes=CLIENT-PUBLIC %s
49+
// RUN: cat %t/ClientLib.private.swiftinterface | %FileCheck --check-prefixes=CLIENT-PRIVATE %s
50+
51+
/// Check that we get the same behavior using swiftinterfaces only.
52+
// RUN: rm -f %t/PrivateLib.swiftmodule %t/PublicLib.swiftmodule
53+
// RUN: %target-swift-frontend -emit-module %t/ClientLib.swift -I %t \
54+
// RUN: -swift-version 5 -enable-library-evolution \
55+
// RUN: -o %t/ClientLib.swiftmodule \
56+
// RUN: -emit-module-interface-path %t/ClientLib.swiftinterface \
57+
// RUN: -emit-private-module-interface-path %t/ClientLib.private.swiftinterface \
58+
// RUN: -enable-experimental-feature ModuleInterfaceExportAs
59+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.swiftinterface) -I %t
60+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.private.swiftinterface) -I %t
61+
// RUN: cat %t/ClientLib.swiftinterface | %FileCheck --check-prefixes=CLIENT-PUBLIC %s
62+
// RUN: cat %t/ClientLib.private.swiftinterface | %FileCheck --check-prefixes=CLIENT-PRIVATE %s
63+
64+
//--- PrivateLib.swift
65+
66+
public struct PrivateNameStruct {}
67+
68+
public func privateLibUser(_ arg: PrivateNameStruct) {}
69+
// PRIVATELIB-PUBLIC: arg: PrivateLib.PrivateNameStruct
70+
71+
//--- PublicLib.swift
72+
73+
@_exported import PrivateLib
74+
75+
public struct PublicNameStruct {}
76+
77+
public func publicLibUser(_ arg: PrivateNameStruct) {}
78+
// PUBLICLIB-PUBLIC: arg: PublicLib.PrivateNameStruct
79+
80+
//--- ClientLib.swift
81+
82+
import PublicLib
83+
84+
public func userOfPrivate(_ argUserOfPrivate: PrivateNameStruct) {}
85+
// CLIENT-PUBLIC: argUserOfPrivate: PublicLib.PrivateNameStruct
86+
// CLIENT-PRIVATE: argUserOfPrivate: PrivateLib.PrivateNameStruct
87+
public func userOfPublic(_ argUserOfPublic: PublicNameStruct) {}
88+
// CLIENT-PUBLIC: argUserOfPublic: PublicLib.PublicNameStruct
89+
// CLIENT-PRIVATE: argUserOfPublic: PublicLib.PublicNameStruct

0 commit comments

Comments
 (0)