[LLD] [COFF] Add a separate option for allowing duplicate weak symbols (#68077)

The MinGW mode (enabled with the flag -lldmingw) does allow duplicate
weak symbols. A test in
compiler-rt/test/profile/Windows/coverage-weak-lld.cpp does currently
enable the -lldmingw flag in an MSVC context, in order to deal with
duplicate weak symbols.

Add a new, separate, lld specific flag for enabling this. In MinGW mode,
this is enabled by default, otherwise it is disabled.

This allows making the MinGW mode more restrictive in adding libpaths
from the surrounding environment; in MinGW mode, all libpaths are passed
explicitly by the compiler driver to the linker, which is attempted in
https://reviews.llvm.org/D144084.

GitOrigin-RevId: a67ae8c0fd301a11e2a058e8035304cfc70a3e91
diff --git a/COFF/Config.h b/COFF/Config.h
index 2d5d4d6..1c338cc 100644
--- a/COFF/Config.h
+++ b/COFF/Config.h
@@ -316,6 +316,7 @@
   bool stdcallFixup = false;
   bool writeCheckSum = false;
   EmitKind emit = EmitKind::Obj;
+  bool allowDuplicateWeak = false;
 };
 
 } // namespace lld::coff
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 0fbfefd..1d9a7e4 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -2028,6 +2028,9 @@
   config->stdcallFixup =
       args.hasFlag(OPT_stdcall_fixup, OPT_stdcall_fixup_no, config->mingw);
   config->warnStdcallFixup = !args.hasArg(OPT_stdcall_fixup);
+  config->allowDuplicateWeak =
+      args.hasFlag(OPT_lld_allow_duplicate_weak,
+                   OPT_lld_allow_duplicate_weak_no, config->mingw);
 
   if (args.hasFlag(OPT_inferasanlibs, OPT_inferasanlibs_no, false))
     warn("ignoring '/inferasanlibs', this flag is not supported");
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index b66ef41..38ce29e 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -81,7 +81,7 @@
       // of another symbol emitted near the weak symbol.
       // Just use the definition from the first object file that defined
       // this weak symbol.
-      if (ctx.config.mingw)
+      if (ctx.config.allowDuplicateWeak)
         return;
       ctx.symtab.reportDuplicate(source, f);
     }
diff --git a/COFF/Options.td b/COFF/Options.td
index e7bb952..977657a 100644
--- a/COFF/Options.td
+++ b/COFF/Options.td
@@ -232,6 +232,7 @@
 def include_optional : Joined<["/", "-", "/?", "-?"], "includeoptional:">,
     HelpText<"Add symbol as undefined, but allow it to remain undefined">;
 def kill_at : F<"kill-at">;
+defm lld_allow_duplicate_weak : B_priv<"lld-allow-duplicate-weak">;
 def lldemit : P<"lldemit", "Specify output type">;
 def lldmingw : F<"lldmingw">;
 def noseh : F<"noseh">;
diff --git a/test/COFF/gnu-weak.test b/test/COFF/gnu-weak.test
index 20284d7..08e5973 100644
--- a/test/COFF/gnu-weak.test
+++ b/test/COFF/gnu-weak.test
@@ -1,4 +1,9 @@
 RUN: lld-link -lldmingw %S/Inputs/gnu-weak.o %S/Inputs/gnu-weak2.o -out:%t.exe
+RUN: lld-link -lld-allow-duplicate-weak %S/Inputs/gnu-weak.o %S/Inputs/gnu-weak2.o -out:%t.exe
+RUN: not lld-link %S/Inputs/gnu-weak.o %S/Inputs/gnu-weak2.o -out:%t.exe 2>&1 | FileCheck %s --check-prefix=DEFAULT-ERROR
+
+DEFAULT-ERROR: error: duplicate symbol: weakfunc
+
 
 GNU ld can handle several definitions of the same weak symbol, and
 unless there is a strong definition of it, it just picks the first