[lld/mac] reject -undefined warning and -undefined suppress with -twolevel_namespace

See discussion on https://reviews.llvm.org/D93263

-flat_namespace isn't implemented yet, and neither is -undefined dynamic,
so this makes -undefined pretty pointless in lld/MachO for now. But once
we implement -flat_namespace (which we need to do anyways to get check-llvm
to pass with lld as host linker), the code's already there.

Follow-up to https://reviews.llvm.org/D93263#2491865

Differential Revision: https://reviews.llvm.org/D96963
This commit is contained in:
Nico Weber 2021-02-18 08:48:07 -05:00
parent 559f372844
commit 28d9953af9
4 changed files with 53 additions and 12 deletions

View file

@ -30,6 +30,11 @@ struct PlatformInfo {
llvm::VersionTuple sdk;
};
enum class NamespaceKind {
twolevel,
flat,
};
enum class UndefinedSymbolTreatment {
unknown,
error,
@ -61,6 +66,7 @@ struct Configuration {
bool demangle = false;
llvm::MachO::Architecture arch;
PlatformInfo platform;
NamespaceKind namespaceKind = NamespaceKind::twolevel;
UndefinedSymbolTreatment undefinedSymbolTreatment =
UndefinedSymbolTreatment::error;
llvm::MachO::HeaderFileType outputType;

View file

@ -582,18 +582,27 @@ static void handlePlatformVersion(const opt::Arg *arg) {
static void handleUndefined(const opt::Arg *arg) {
StringRef treatmentStr = arg->getValue(0);
config->undefinedSymbolTreatment =
auto treatment =
StringSwitch<UndefinedSymbolTreatment>(treatmentStr)
.Case("error", UndefinedSymbolTreatment::error)
.Case("warning", UndefinedSymbolTreatment::warning)
.Case("suppress", UndefinedSymbolTreatment::suppress)
.Case("dynamic_lookup", UndefinedSymbolTreatment::dynamic_lookup)
.Default(UndefinedSymbolTreatment::unknown);
if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::unknown) {
if (treatment == UndefinedSymbolTreatment::unknown) {
warn(Twine("unknown -undefined TREATMENT '") + treatmentStr +
"', defaulting to 'error'");
config->undefinedSymbolTreatment = UndefinedSymbolTreatment::error;
treatment = UndefinedSymbolTreatment::error;
} else if (config->namespaceKind == NamespaceKind::twolevel &&
(treatment == UndefinedSymbolTreatment::warning ||
treatment == UndefinedSymbolTreatment::suppress)) {
if (treatment == UndefinedSymbolTreatment::warning)
error("'-undefined warning' only valid with '-flat_namespace'");
else
error("'-undefined suppress' only valid with '-flat_namespace'");
treatment = UndefinedSymbolTreatment::error;
}
config->undefinedSymbolTreatment = treatment;
}
static void warnIfDeprecatedOption(const opt::Option &opt) {
@ -760,6 +769,18 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
if (const opt::Arg *arg = args.getLastArg(OPT_static, OPT_dynamic))
config->staticLink = (arg->getOption().getID() == OPT_static);
if (const opt::Arg *arg =
args.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) {
config->namespaceKind = arg->getOption().getID() == OPT_twolevel_namespace
? NamespaceKind::twolevel
: NamespaceKind::flat;
if (config->namespaceKind == NamespaceKind::flat) {
warn("Option '" + arg->getOption().getPrefixedName() +
"' is not yet implemented. Stay tuned...");
config->namespaceKind = NamespaceKind::twolevel;
}
}
config->systemLibraryRoots = getSystemLibraryRoots(args);
config->librarySearchPaths =
getLibrarySearchPaths(args, config->systemLibraryRoots);

View file

@ -448,9 +448,12 @@ def alias_list : Separate<["-"], "alias_list">,
Flags<[HelpHidden]>,
Group<grp_resolve>;
def flat_namespace : Flag<["-"], "flat_namespace">,
HelpText<"Resolve symbols from all dylibs, both direct & transitive. Do not record source libraries: dyld must re-search at runtime and use the first definition found">,
HelpText<"Resolve symbols from all dylibs, both direct and transitive. Do not record source libraries: dyld must re-search at runtime and use the first definition found">,
Flags<[HelpHidden]>,
Group<grp_resolve>;
def twolevel_namespace : Flag<["-"], "twolevel_namespace">,
HelpText<"Make dyld look up symbols by (dylib,name) pairs (default)">,
Group<grp_resolve>;
def u : Separate<["-"], "u">,
MetaVarName<"<symbol>">,
HelpText<"Require that <symbol> be defined for the link to succeed">,
@ -1302,10 +1305,6 @@ def threaded_starts_section : Flag<["-"], "threaded_starts_section">,
HelpText<"This option is undocumented in ld64">,
Flags<[HelpHidden]>,
Group<grp_undocumented>;
def twolevel_namespace : Flag<["-"], "twolevel_namespace">,
HelpText<"This option is undocumented in ld64">,
Flags<[HelpHidden]>,
Group<grp_undocumented>;
def verbose_optimization_hints : Flag<["-"], "verbose_optimization_hints">,
HelpText<"This option is undocumented in ld64">,
Flags<[HelpHidden]>,

View file

@ -5,14 +5,29 @@
# RUN: FileCheck %s -check-prefix=UNKNOWN
# RUN: not %lld -undefined error -o /dev/null %t.o 2>&1 | \
# RUN: FileCheck %s -check-prefix=ERROR
# RUN: %no_fatal_warnings_lld -undefined warning -o /dev/null %t.o 2>&1 | \
# RUN: FileCheck %s -check-prefix=WARNING
# RUN: %lld -undefined suppress -o /dev/null %t.o 2>&1 | \
# RUN: FileCheck %s -check-prefix=SUPPRESS --allow-empty
# RUN: not %lld -undefined warning -o /dev/null %t.o 2>&1 | \
# RUN: FileCheck %s -check-prefix=INVAL-WARNING
# RUN: not %lld -undefined suppress -o /dev/null %t.o 2>&1 | \
# RUN: FileCheck %s -check-prefix=INVAL-SUPPRESS
# FIXME: Enable these -undefined checks once -flat_namespace is implemented.
# RN: %no_fatal_warnings_lld -flat_namespace -undefined warning \
# RN: -o /dev/null %t.o 2>&1 | \
# RN: FileCheck %s -check-prefix=WARNING
# RN: %lld -flat_namespace -undefined suppress -o /dev/null %t.o 2>&1 | \
# RN: FileCheck %s -check-prefix=SUPPRESS --allow-empty
# ERROR: error: undefined symbol: _bar
# ERROR-NEXT: >>> referenced by
# INVAL-WARNING: error: '-undefined warning' only valid with '-flat_namespace'
# INVAL-WARNING-NEXT: error: undefined symbol: _bar
# INVAL-SUPPRESS: error: '-undefined suppress' only valid with '-flat_namespace'
# INVAL-SUPPRESS-NEXT: error: undefined symbol: _bar
# WARNING: warning: undefined symbol: _bar
# WARNING-NEXT: >>> referenced by