[PATCH] D109624: [clang] Make the driver not diagnose errors on nonexistent linker inputs

Nico Weber via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 10 12:00:48 PDT 2021


thakis created this revision.
thakis added a reviewer: hans.
thakis requested review of this revision.

The motivation for this change is that I noticed that
`clang-cl /winsysroot sysroot main.cc ole32.lib` emitted a
"ole32.lib not found" error, even though the linker finds it just fine when
I run `clang-cl /winsysroot sysroot main.cc /link ole32.lib`.

The same problem occurs if running `clang-cl main.cc ole32.lib` in a
non-MSVC shell.

The problem is that DiagnoseInputExistence() only looked for libs in %LIB%,
but MSVCToolChain uses much more involved techniques.

For this particular problem, we could make DiagnoseInputExistence() ask
the toolchain to see if it can find a .lib file, but in general the
driver can't know what the linker will do to find files, so it shouldn't
try. For example, if we implement PR24616, lld-link will look in the
registry to determine a good default for %LIB% if it isn't set.

This is less or a problem for the gcc driver, since .a paths there are
either passed via -l flags (which honor -L), or via a qualified path
(that doesn't honor -L) -- but for example ld.lld's --chroot flag
can also trigger this problem. Without this patch,
`clang -fuse-ld=lld -Wl,--chroot,some/dir /file.o` will complain that
`/file.o` doesn't exist, even though
`clang -fuse-ld=lld -Wl,--chroot,some/dir -Wl,/file.o` succeeds just fine.

This implements rnk's suggestion on the old bug PR27234.


https://reviews.llvm.org/D109624

Files:
  clang/lib/Driver/Driver.cpp
  clang/test/Driver/cl-inputs.c
  clang/test/Driver/cl-link.c


Index: clang/test/Driver/cl-link.c
===================================================================
--- clang/test/Driver/cl-link.c
+++ clang/test/Driver/cl-link.c
@@ -50,9 +50,12 @@
 // PR27234
 // RUN: %clang_cl /Tc%s nonexistent.obj -fuse-ld=link -### /link /libpath:somepath 2>&1 | FileCheck --check-prefix=NONEXISTENT %s
 // RUN: %clang_cl /Tc%s nonexistent.lib -fuse-ld=link -### /link /libpath:somepath 2>&1 | FileCheck --check-prefix=NONEXISTENT %s
+// RUN: %clang_cl /Tc%s nonexistent.obj -fuse-ld=link -### /winsysroot somepath 2>&1 | FileCheck --check-prefix=NONEXISTENT %s
+// RUN: %clang_cl /Tc%s nonexistent.lib -fuse-ld=link -### /winsysroot somepath 2>&1 | FileCheck --check-prefix=NONEXISTENT %s
+// RUN: %clang_cl /Tc%s nonexistent.obj -fuse-ld=link -### 2>&1 | FileCheck --check-prefix=NONEXISTENT %s
+// RUN: %clang_cl /Tc%s nonexistent.lib -fuse-ld=link -### 2>&1 | FileCheck --check-prefix=NONEXISTENT %s
 // NONEXISTENT-NOT: no such file
 // NONEXISTENT: link.exe
-// NONEXISTENT: "/libpath:somepath"
 // NONEXISTENT: nonexistent
 
 // RUN: %clang_cl /Tc%s -fuse-ld=lld -### 2>&1 | FileCheck --check-prefix=USE_LLD %s
Index: clang/test/Driver/cl-inputs.c
===================================================================
--- clang/test/Driver/cl-inputs.c
+++ clang/test/Driver/cl-inputs.c
@@ -55,13 +55,13 @@
 // LIBINPUT: "cl-test.lib"
 
 // RUN: env LIB=%S/Inputs/cl-libs %clang_cl -fuse-ld=link -### -- %s cl-test2.lib 2>&1 | FileCheck -check-prefix=LIBINPUT2 %s
-// LIBINPUT2: error: no such file or directory: 'cl-test2.lib'
+// LIBINPUT2-NOT: error: no such file or directory: 'cl-test2.lib'
 // LIBINPUT2: link.exe"
-// LIBINPUT2-NOT: "cl-test2.lib"
+// LIBINPUT2: "cl-test2.lib"
 
 // RUN: %clang_cl -fuse-ld=link -### -- %s /nonexisting.lib 2>&1 | FileCheck -check-prefix=LIBINPUT3 %s
-// LIBINPUT3: error: no such file or directory: '/nonexisting.lib'
+// LIBINPUT3-NOT: error: no such file or directory: '/nonexisting.lib'
 // LIBINPUT3: link.exe"
-// LIBINPUT3-NOT: "/nonexisting.lib"
+// LIBINPUT3: "/nonexisting.lib"
 
 void f();
Index: clang/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -2130,19 +2130,6 @@
   if (getVFS().exists(Value))
     return true;
 
-  if (IsCLMode()) {
-    if (!llvm::sys::path::is_absolute(Twine(Value)) &&
-        llvm::sys::Process::FindInEnvPath("LIB", Value, ';'))
-      return true;
-
-    if (Args.hasArg(options::OPT__SLASH_link) && Ty == types::TY_Object) {
-      // Arguments to the /link flag might cause the linker to search for object
-      // and library files in paths we don't know about. Don't error in such
-      // cases.
-      return true;
-    }
-  }
-
   if (TypoCorrect) {
     // Check if the filename is a typo for an option flag. OptTable thinks
     // that all args that are not known options and that start with / are
@@ -2162,6 +2149,31 @@
     }
   }
 
+  // Don't error on apparently non-existent linker inputs, because they
+  // can be influenced by linker flags the clang driver might not understand.
+  // Examples:
+  // - `clang -fuse-ld=lld -Wl,--chroot,some/dir /file.o` will make lld look
+  //   for some/dir/file.o
+  // - `clang-cl main.cc ole32.lib` in a a non-MSVC shell will make the driver
+  //   module look for an MSVC installation in the registry. (We could ask
+  //   the MSVCToolChain object if it can find `ole32.lib`, but the logic to
+  //   look in the registry might move into lld-link in the future so that
+  //   lld-link invocations in non-MSVC shells just work too.)
+  // - `clang-cl ... /link ...` can pass arbitrary flags to the linker,
+  //   including /libpath:, which is used to find .lib and .obj files.
+  // So do not diagnose this on the driver level. Rely on the linker diagnosing
+  // it. (If we don't end up invoking the driver, this means we'll emit a
+  // "'linker' input unused [-Wunused-command-line-argument]" warning instead
+  // of an error.)
+  //
+  // Only do this skip after the typo correction step above. `/Brepo` is treated
+  // as TY_Object, but it's clearly a typo for `/Brepro`. It seems fine to emit
+  // an error if we have a flag that's within an edit distance of 1 from a
+  // flag. (Users can use `-Wl,` or `/linker` to launder the flag past the
+  // driver in the unlikely case they run into this.)
+  if (Ty == types::TY_Object)
+    return true;
+
   Diag(clang::diag::err_drv_no_such_file) << Value;
   return false;
 }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D109624.371986.patch
Type: text/x-patch
Size: 4520 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210910/83e738a5/attachment.bin>


More information about the llvm-commits mailing list