Skip to content

Commit afe21e4

Browse files
committed
Merge pull request #39376 from apple/es-mod-alias1
Introduce a module alias option to the frontend. Validate and convert the input to a module alias map to be used by import resolution and sema. rdar://83316886
1 parent 1038ffc commit afe21e4

File tree

7 files changed

+107
-1
lines changed

7 files changed

+107
-1
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,14 @@ ERROR(error_stdlib_module_name,none,
148148
"module name \"%0\" is reserved for the standard library"
149149
"%select{|; use -module-name flag to specify an alternate name}1",
150150
(StringRef, bool))
151-
152151
ERROR(error_stdlib_not_found,Fatal,
153152
"unable to load standard library for target '%0'", (StringRef))
153+
ERROR(error_module_alias_invalid_format,none,
154+
"invalid module alias format \"%0\"; make sure to use the format '-module-alias alias_name=underlying_name'", (StringRef))
155+
ERROR(error_module_alias_forbidden_name,none,
156+
"invalid module alias \"%0\"; make sure the alias differs from the module name, module ABI name, module link name, and a standard library name", (StringRef))
157+
ERROR(error_module_alias_duplicate,none,
158+
"duplicate module alias; the name \"%0\" is already used for a module alias or an underlying name", (StringRef))
154159

155160
ERROR(error_unable_to_load_supplementary_output_file_map, none,
156161
"unable to load supplementary output file map '%0': %1",

include/swift/Frontend/FrontendOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/Frontend/FrontendInputsAndOutputs.h"
1919
#include "swift/Frontend/InputFile.h"
2020
#include "llvm/ADT/Hashing.h"
21+
#include "llvm/ADT/StringMap.h"
2122

2223
#include <string>
2324
#include <vector>
@@ -48,6 +49,9 @@ class FrontendOptions {
4849
/// An Objective-C header to import and make implicitly visible.
4950
std::string ImplicitObjCHeaderPath;
5051

52+
/// The map of aliases and underlying names of imported or referenced modules.
53+
llvm::StringMap<StringRef> ModuleAliasMap;
54+
5155
/// The name of the module that the frontend is building.
5256
std::string ModuleName;
5357

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,11 @@ def module_name : Separate<["-"], "module-name">,
410410
def module_name_EQ : Joined<["-"], "module-name=">, Flags<[FrontendOption]>,
411411
Alias<module_name>;
412412

413+
def module_alias : Separate<["-"], "module-alias">,
414+
Flags<[FrontendOption]>,
415+
MetaVarName<"<alias_name=underlying_name>">,
416+
HelpText<"If a source file imports or references module <alias_name>, the underlying name is used for the contents of the file">;
417+
413418
def module_link_name : Separate<["-"], "module-link-name">,
414419
Flags<[FrontendOption, ModuleInterfaceOption]>,
415420
HelpText<"Library to link against when using this module">;

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@ bool ArgsToFrontendOptionsConverter::convert(
223223
if (const Arg *A = Args.getLastArg(OPT_module_link_name))
224224
Opts.ModuleLinkName = A->getValue();
225225

226+
// This must be called after computing module name, module abi name,
227+
// and module link name.
228+
if (computeModuleAliases())
229+
return true;
230+
226231
if (const Arg *A = Args.getLastArg(OPT_access_notes_path))
227232
Opts.AccessNotesPath = A->getValue();
228233

@@ -475,7 +480,65 @@ bool ArgsToFrontendOptionsConverter::setUpImmediateArgs() {
475480
return false;
476481
}
477482

483+
bool ArgsToFrontendOptionsConverter::computeModuleAliases() {
484+
auto list = Args.getAllArgValues(options::OPT_module_alias);
485+
if (!list.empty()) {
486+
auto validate = [this](StringRef value, bool allowModuleName) -> bool
487+
{
488+
if (!allowModuleName) {
489+
if (value == Opts.ModuleName ||
490+
value == Opts.ModuleABIName ||
491+
value == Opts.ModuleLinkName) {
492+
Diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value);
493+
return false;
494+
}
495+
}
496+
if (value == STDLIB_NAME) {
497+
Diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value);
498+
return false;
499+
}
500+
if (!Lexer::isIdentifier(value)) {
501+
Diags.diagnose(SourceLoc(), diag::error_bad_module_name, value, false);
502+
return false;
503+
}
504+
return true;
505+
};
506+
507+
for (auto item: list) {
508+
auto str = StringRef(item);
509+
// splits to an alias and the underlying name
510+
auto pair = str.split('=');
511+
auto lhs = pair.first;
512+
auto rhs = pair.second;
513+
514+
if (rhs.empty()) { // '=' is missing
515+
Diags.diagnose(SourceLoc(), diag::error_module_alias_invalid_format, str);
516+
return true;
517+
}
518+
if (!validate(lhs, false) || !validate(rhs, true)) {
519+
return true;
520+
}
521+
522+
// First, add the underlying name as a key to prevent it from being
523+
// used as an alias
524+
if (!Opts.ModuleAliasMap.insert({rhs, StringRef()}).second) {
525+
Diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, rhs);
526+
return true;
527+
}
528+
// Next, add the alias as a key and the underlying name as a value to the map
529+
auto underlyingName = Opts.ModuleAliasMap.find(rhs)->first();
530+
if (!Opts.ModuleAliasMap.insert({lhs, underlyingName}).second) {
531+
Diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, lhs);
532+
return true;
533+
}
534+
}
535+
}
536+
return false;
537+
}
538+
478539
bool ArgsToFrontendOptionsConverter::computeModuleName() {
540+
assert(Opts.ModuleAliasMap.empty() && "Module name must be computed before computing module aliases");
541+
479542
const Arg *A = Args.getLastArg(options::OPT_module_name);
480543
if (A) {
481544
Opts.ModuleName = A->getValue();

lib/Frontend/ArgsToFrontendOptionsConverter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class ArgsToFrontendOptionsConverter {
3737
void computeDebugTimeOptions();
3838
bool computeFallbackModuleName();
3939
bool computeModuleName();
40+
bool computeModuleAliases();
4041
bool computeMainAndSupplementaryOutputFilenames();
4142
void computeDumpScopeMapLocations();
4243
void computeHelpOptions();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
func quip() {
2+
}
3+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Tests for invalid module alias format and values.
2+
3+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias foo=bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS %s
4+
// INVALID_MODULE_ALIAS: error: invalid module alias "foo"; make sure the alias differs from the module name, module ABI name, module link name, and a standard library name
5+
6+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias Swift=Bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS1 %s
7+
// INVALID_MODULE_ALIAS1: error: invalid module alias "Swift"; make sure the alias differs from the module name, module ABI name, module link name, and a standard library name
8+
9+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias bar=bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS2 %s
10+
// INVALID_MODULE_ALIAS2: error: duplicate module alias; the name "bar" is already used for a module alias or an underlying name
11+
12+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias bar=baz -module-alias baz=cat 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS3 %s
13+
// INVALID_MODULE_ALIAS3: error: duplicate module alias; the name "baz" is already used for a module alias or an underlying name
14+
15+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS4 %s
16+
// INVALID_MODULE_ALIAS4: error: invalid module alias format "bar"; make sure to use the format '-module-alias alias_name=underlying_name'
17+
18+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias bar=c-a.t 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_NAME %s
19+
// INVALID_MODULE_NAME: error: module name "c-a.t" is not a valid identifier
20+
21+
// These should succeed.
22+
// RUN: %target-swift-frontend -emit-silgen %S/Inputs/invalid-module-alias.swift > /dev/null
23+
// RUN: %target-swift-frontend -emit-silgen -parse-as-library -module-name foo %S/Inputs/invalid-module-alias.swift -module-alias bar=cat > /dev/null
24+
// RUN: %target-swift-frontend -typecheck -parse-as-library -module-name foo %S/Inputs/invalid-module-alias.swift -module-alias bar=cat
25+

0 commit comments

Comments
 (0)