Skip to content

Commit 8d28ed4

Browse files
authored
Merge pull request #76269 from xymus/public-module-name
Diagnostics: Intro the public module name concept to hide support modules from clients
2 parents c6f81cb + c70162c commit 8d28ed4

18 files changed

+210
-3
lines changed

include/swift/AST/FileUnit.h

+6
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,12 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
335335
return getParentModule()->getRealName().str();
336336
}
337337

338+
/// Returns the public facing name of this module, only if it is set
339+
/// explicitly.
340+
virtual StringRef getPublicModuleName() const {
341+
return {};
342+
}
343+
338344
SWIFT_DEBUG_DUMPER(dumpDisplayDecls());
339345
SWIFT_DEBUG_DUMPER(dumpTopLevelDecls());
340346

include/swift/AST/Module.h

+17
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@ class ModuleDecl
243243
/// Module name to use when referenced in clients module interfaces.
244244
mutable Identifier ExportAsName;
245245

246+
mutable Identifier PublicModuleName;
247+
246248
public:
247249
/// Produces the components of a given module's full name in reverse order.
248250
///
@@ -502,6 +504,21 @@ class ModuleDecl
502504
ExportAsName = name;
503505
}
504506

507+
/// Public facing name for this module in diagnostics and documentation.
508+
///
509+
/// This always returns a valid name as it defaults to the module name if
510+
/// no public module name is set.
511+
///
512+
/// If `onlyIfImported`, return the normal module name when the module
513+
/// corresponding to the public module name isn't imported. Users working
514+
/// in between both modules will then see the normal module name,
515+
/// this may be more useful for diagnostics at that level.
516+
Identifier getPublicModuleName(bool onlyIfImported) const;
517+
518+
void setPublicModuleName(Identifier name) {
519+
PublicModuleName = name;
520+
}
521+
505522
/// Retrieve the actual module name of an alias used for this module (if any).
506523
///
507524
/// For example, if '-module-alias Foo=Bar' is passed in when building the main module,

include/swift/Frontend/FrontendOptions.h

+3
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class FrontendOptions {
7070
/// Module name to use when referenced in clients module interfaces.
7171
std::string ExportAsName;
7272

73+
/// The public facing name of the module to build.
74+
std::string PublicModuleName;
75+
7376
/// Arguments which should be passed in immediate mode.
7477
std::vector<std::string> ImmediateArgv;
7578

include/swift/Option/Options.td

+3
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,9 @@ def package_name : Separate<["-"], "package-name">,
586586
def export_as : Separate<["-"], "export-as">,
587587
Flags<[FrontendOption, ModuleInterfaceOption]>,
588588
HelpText<"Module name to use when referenced in clients module interfaces">;
589+
def public_module_name : Separate<["-"], "public-module-name">,
590+
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable]>,
591+
HelpText<"Public facing module name to use in diagnostics and documentation">;
589592

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

include/swift/Serialization/SerializedModuleLoader.h

+2
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@ class SerializedASTFile final : public LoadedFile {
531531

532532
virtual StringRef getExportedModuleName() const override;
533533

534+
virtual StringRef getPublicModuleName() const override;
535+
534536
ValueDecl *getMainDecl() const override;
535537

536538
bool hasEntryPoint() const override;

include/swift/Serialization/Validation.h

+4
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class ExtendedValidationInfo {
129129
StringRef ModuleABIName;
130130
StringRef ModulePackageName;
131131
StringRef ExportAsName;
132+
StringRef PublicModuleName;
132133
CXXStdlibKind CXXStdlib;
133134
struct {
134135
unsigned ArePrivateImportsEnabled : 1;
@@ -230,6 +231,9 @@ class ExtendedValidationInfo {
230231
StringRef getModulePackageName() const { return ModulePackageName; }
231232
void setModulePackageName(StringRef name) { ModulePackageName = name; }
232233

234+
StringRef getPublicModuleName() const { return PublicModuleName; }
235+
void setPublicModuleName(StringRef name) { PublicModuleName = name; }
236+
233237
StringRef getExportAsName() const { return ExportAsName; }
234238
void setExportAsName(StringRef name) { ExportAsName = name; }
235239

lib/AST/DiagnosticEngine.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,9 @@ static void formatDiagnosticArgument(StringRef Modifier,
847847
// Figure out the name we want to print.
848848
DeclName name;
849849
if (includeName) {
850-
if (auto VD = dyn_cast<ValueDecl>(D))
850+
if (auto MD = dyn_cast<ModuleDecl>(D))
851+
name = MD->getPublicModuleName(/*onlyIfImported=*/true);
852+
else if (auto VD = dyn_cast<ValueDecl>(D))
851853
name = VD->getName();
852854
else if (auto PGD = dyn_cast<PrecedenceGroupDecl>(D))
853855
name = PGD->getName();
@@ -1419,7 +1421,9 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
14191421
// build the name of the buffer.
14201422
SmallVector<StringRef, 4> nameComponents;
14211423
while (dc) {
1422-
nameComponents.push_back(cast<ModuleDecl>(dc)->getName().str());
1424+
auto publicName = cast<ModuleDecl>(dc)->
1425+
getPublicModuleName(/*onlyIfImported*/true);
1426+
nameComponents.push_back(publicName.str());
14231427
dc = dc->getParent();
14241428
}
14251429

lib/AST/Module.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -1922,6 +1922,19 @@ ImportedModule::removeDuplicates(SmallVectorImpl<ImportedModule> &imports) {
19221922
imports.erase(last, imports.end());
19231923
}
19241924

1925+
Identifier ModuleDecl::getPublicModuleName(bool onlyIfImported) const {
1926+
if (!PublicModuleName.empty()) {
1927+
if (!onlyIfImported)
1928+
return PublicModuleName;
1929+
1930+
bool publicModuleIsImported =
1931+
getASTContext().getModuleByIdentifier(PublicModuleName);
1932+
if (publicModuleIsImported)
1933+
return PublicModuleName;
1934+
}
1935+
return getName();
1936+
}
1937+
19251938
Identifier ModuleDecl::getRealName() const {
19261939
// This will return the real name for an alias (if used) or getName()
19271940
return getASTContext().getRealModuleName(getName());

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ bool ArgsToFrontendOptionsConverter::convert(
288288
Opts.ExportAsName = exportAs;
289289
}
290290

291+
if (const Arg *A = Args.getLastArg(OPT_public_module_name))
292+
Opts.PublicModuleName = A->getValue();
293+
291294
// This must be called after computing module name, module abi name,
292295
// and module link name. If computing module aliases is unsuccessful,
293296
// return early.

lib/Frontend/Frontend.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,10 @@ ModuleDecl *CompilerInstance::getMainModule() const {
14651465
MainModule->setExportAsName(getASTContext().getIdentifier(
14661466
Invocation.getFrontendOptions().ExportAsName));
14671467
}
1468+
if (!Invocation.getFrontendOptions().PublicModuleName.empty()) {
1469+
MainModule->setPublicModuleName(getASTContext().getIdentifier(
1470+
Invocation.getFrontendOptions().PublicModuleName));
1471+
}
14681472
if (Invocation.getFrontendOptions().EnableLibraryEvolution)
14691473
MainModule->setResilienceStrategy(ResilienceStrategy::Resilient);
14701474
if (Invocation.getLangOptions().isSwiftVersionAtLeast(6))

lib/Serialization/ModuleFile.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1398,3 +1398,7 @@ StringRef SerializedASTFile::getExportedModuleName() const {
13981398
return name;
13991399
return FileUnit::getExportedModuleName();
14001400
}
1401+
1402+
StringRef SerializedASTFile::getPublicModuleName() const {
1403+
return File.getPublicModuleName();
1404+
}

lib/Serialization/ModuleFile.h

+4
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,10 @@ class ModuleFile
587587
return Core->ModuleExportAsName;
588588
}
589589

590+
StringRef getPublicModuleName() const {
591+
return Core->PublicModuleName;
592+
}
593+
590594
/// The ABI name of the module.
591595
StringRef getModuleABIName() const {
592596
return Core->ModuleABIName;

lib/Serialization/ModuleFileSharedCore.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
209209
case options_block::SERIALIZE_PACKAGE_ENABLED:
210210
extendedInfo.setSerializePackageEnabled(true);
211211
break;
212+
case options_block::PUBLIC_MODULE_NAME:
213+
extendedInfo.setPublicModuleName(blobData);
214+
break;
212215
default:
213216
// Unknown options record, possibly for use by a future version of the
214217
// module format.
@@ -1474,6 +1477,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
14741477
ModuleABIName = extInfo.getModuleABIName();
14751478
ModulePackageName = extInfo.getModulePackageName();
14761479
ModuleExportAsName = extInfo.getExportAsName();
1480+
PublicModuleName = extInfo.getPublicModuleName();
14771481

14781482
hasValidControlBlock = true;
14791483
break;

lib/Serialization/ModuleFileSharedCore.h

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ModuleFileSharedCore {
100100
/// Module name to use when referenced in clients module interfaces.
101101
StringRef ModuleExportAsName;
102102

103+
/// Name to use in public facing diagnostics and documentation.
104+
StringRef PublicModuleName;
105+
103106
/// \c true if this module has incremental dependency information.
104107
bool HasIncrementalInfo = false;
105108

lib/Serialization/ModuleFormat.h

+7-1
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 = 888; // Value generics
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 889; // public-module-name
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -959,6 +959,7 @@ namespace options_block {
959959
ALLOW_NON_RESILIENT_ACCESS,
960960
SERIALIZE_PACKAGE_ENABLED,
961961
CXX_STDLIB_KIND,
962+
PUBLIC_MODULE_NAME,
962963
};
963964

964965
using SDKPathLayout = BCRecordLayout<
@@ -1054,6 +1055,11 @@ namespace options_block {
10541055
using SerializePackageEnabled = BCRecordLayout<
10551056
SERIALIZE_PACKAGE_ENABLED
10561057
>;
1058+
1059+
using PublicModuleNameLayout = BCRecordLayout<
1060+
PUBLIC_MODULE_NAME,
1061+
BCBlob
1062+
>;
10571063
}
10581064

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

lib/Serialization/Serialization.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,13 @@ void Serializer::writeHeader() {
11261126
ExportAs.emit(ScratchRecord, M->getExportAsName().str());
11271127
}
11281128

1129+
Identifier publicModuleName =
1130+
M->getPublicModuleName(/*onlyIfImported=*/false);
1131+
if (publicModuleName != M->getName()) {
1132+
options_block::PublicModuleNameLayout PublicModuleName(Out);
1133+
PublicModuleName.emit(ScratchRecord, publicModuleName.str());
1134+
}
1135+
11291136
if (M->isConcurrencyChecked()) {
11301137
options_block::IsConcurrencyCheckedLayout IsConcurrencyChecked(Out);
11311138
IsConcurrencyChecked.emit(ScratchRecord);

lib/Serialization/SerializedModuleLoader.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
992992
M.setSerializePackageEnabled();
993993
if (!loadedModuleFile->getModuleABIName().empty())
994994
M.setABIName(Ctx.getIdentifier(loadedModuleFile->getModuleABIName()));
995+
if (!loadedModuleFile->getPublicModuleName().empty())
996+
M.setPublicModuleName(Ctx.getIdentifier(loadedModuleFile->getPublicModuleName()));
995997
if (loadedModuleFile->isConcurrencyChecked())
996998
M.setIsConcurrencyChecked();
997999
if (loadedModuleFile->hasCxxInteroperability()) {

test/Sema/public-module-name.swift

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file --leading-lines %s %t
3+
4+
/// Build the libraries.
5+
// RUN: %target-swift-frontend %t/LibCore.swift \
6+
// RUN: -emit-module-path %t/LibCore.swiftmodule \
7+
// RUN: -emit-module-interface-path %t/LibCore.swiftinterface \
8+
// RUN: -enable-library-evolution -swift-version 6 \
9+
// RUN: -public-module-name Lib
10+
// RUN: %target-swift-typecheck-module-from-interface(%t/LibCore.swiftinterface)
11+
12+
// RUN: %target-swift-frontend %t/LibMiddle.swift -I %t \
13+
// RUN: -emit-module-path %t/LibMiddle.swiftmodule \
14+
// RUN: -emit-module-interface-path %t/LibMiddle.swiftinterface \
15+
// RUN: -enable-library-evolution -swift-version 6 \
16+
// RUN: -public-module-name Lib
17+
// RUN: %target-swift-typecheck-module-from-interface(%t/LibMiddle.swiftinterface) -I %t
18+
19+
// RUN: %target-swift-frontend %t/Lib.swift -I %t \
20+
// RUN: -emit-module-path %t/Lib.swiftmodule \
21+
// RUN: -emit-module-interface-path %t/Lib.swiftinterface \
22+
// RUN: -enable-library-evolution -swift-version 6
23+
// RUN: %target-swift-typecheck-module-from-interface(%t/Lib.swiftinterface) -I %t
24+
25+
// RUN: %target-swift-frontend %t/LibUnrelated.swift -I %t \
26+
// RUN: -emit-module-path %t/LibUnrelated.swiftmodule \
27+
// RUN: -enable-library-evolution -swift-version 6
28+
29+
/// Check flag in swiftinterface
30+
// RUN: cat %t/LibCore.swiftinterface | %FileCheck --check-prefix=CHECK-FLAG %s
31+
// RUN: cat %t/LibMiddle.swiftinterface | %FileCheck --check-prefix=CHECK-FLAG %s
32+
// CHECK-FLAG: swift-module-flags-ignorable:
33+
// CHECK-SAME-FLAG: -public-module-name Lib
34+
35+
/// Build clients against binary swiftmodules.
36+
/// First errors in files, then diagnostics in other files.
37+
// RUN: %target-swift-frontend -typecheck %t/ClientPublic.swift -o %t -I %t \
38+
// RUN: -enable-library-evolution -swift-version 6 \
39+
// RUN: -verify
40+
// RUN: not %target-swift-frontend -typecheck %t/ClientPublic.swift -o %t -I %t \
41+
// RUN: -enable-library-evolution -swift-version 6 \
42+
// RUN: -diagnostic-style llvm \
43+
// RUN: 2>&1 | %FileCheck %t/ClientPublic.swift
44+
45+
// RUN: %target-swift-frontend -typecheck %t/ClientMiddle.swift -o %t -I %t \
46+
// RUN: -enable-library-evolution -swift-version 6 \
47+
// RUN: -verify
48+
// RUN: not %target-swift-frontend -typecheck %t/ClientMiddle.swift -o %t -I %t \
49+
// RUN: -enable-library-evolution -swift-version 6 \
50+
// RUN: 2>&1 | %FileCheck %t/ClientMiddle.swift
51+
52+
/// Test more diagnostics referencing modules.
53+
// RUN: %target-swift-frontend -typecheck %t/ClientAccessLevelOnImports.swift -o %t -I %t \
54+
// RUN: -enable-library-evolution -swift-version 6 \
55+
// RUN: -verify
56+
57+
/// Build client against textual swiftinterfaces.
58+
// RUN: rm %t/LibCore.swiftmodule %t/LibMiddle.swiftmodule %t/Lib.swiftmodule
59+
// RUN: %target-swift-frontend -typecheck %t/ClientPublic.swift -I %t \
60+
// RUN: -enable-library-evolution -swift-version 6 \
61+
// RUN: -verify
62+
// RUN: not %target-swift-frontend -typecheck %t/ClientPublic.swift -o %t -I %t \
63+
// RUN: -enable-library-evolution -swift-version 6 \
64+
// RUN: -diagnostic-style llvm \
65+
// RUN: 2>&1 | %FileCheck %t/ClientPublic.swift
66+
67+
// RUN: %target-swift-frontend -typecheck %t/ClientMiddle.swift -o %t -I %t \
68+
// RUN: -enable-library-evolution -swift-version 6 \
69+
// RUN: -verify
70+
// RUN: not %target-swift-frontend -typecheck %t/ClientMiddle.swift -o %t -I %t \
71+
// RUN: -enable-library-evolution -swift-version 6 \
72+
// RUN: 2>&1 | %FileCheck %t/ClientMiddle.swift
73+
74+
// RUN: %target-swift-frontend -typecheck %t/ClientAccessLevelOnImports.swift -o %t -I %t \
75+
// RUN: -enable-library-evolution -swift-version 6 \
76+
// RUN: -verify
77+
78+
//--- LibCore.swift
79+
public func ambiguous() {}
80+
public func coreFunc() {}
81+
82+
//--- LibMiddle.swift
83+
import LibCore
84+
public func ambiguous() {}
85+
86+
//--- Lib.swift
87+
@_exported import LibCore
88+
@_exported import LibMiddle
89+
90+
//--- LibUnrelated.swift
91+
public func ambiguous() {}
92+
93+
//--- ClientPublic.swift
94+
import Lib
95+
import LibUnrelated
96+
97+
ambiguous() // expected-error {{ambiguous use of 'ambiguous()'}}
98+
// CHECK-NOT: LibCore
99+
// CHECK-NOT: LibMiddle
100+
// CHECK: LibUnrelated.ambiguous:1:13: note: found this candidate in module 'LibUnrelated'
101+
// CHECK: Lib.ambiguous:1:13: note: found this candidate in module 'Lib'
102+
// CHECK: Lib.ambiguous:1:13: note: found this candidate in module 'Lib'
103+
104+
//--- ClientMiddle.swift
105+
import LibCore
106+
import LibMiddle
107+
108+
ambiguous() // expected-error {{ambiguous use of 'ambiguous()'}}
109+
// CHECK: LibCore.ambiguous:1:13: note: found this candidate in module 'LibCore'
110+
// CHECK: LibMiddle.ambiguous:1:13: note: found this candidate in module 'LibMiddle'
111+
112+
//--- ClientAccessLevelOnImports.swift
113+
internal import Lib // expected-note {{global function 'coreFunc()' imported as 'internal' from 'Lib' here}}
114+
115+
@inlinable
116+
public func foo() {
117+
coreFunc() // expected-error {{global function 'coreFunc()' is internal and cannot be referenced from an '@inlinable' function}}
118+
}

0 commit comments

Comments
 (0)