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,34 @@ } } + // 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 linker, 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.) + // + // Don't do this skip in clang-cl mode for inputs that start with a '/' -- + // else we'd pass options like /libpath: through to the linker silently. + if (Ty == types::TY_Object && !(IsCLMode() && Value.startswith("/"))) + return true; + Diag(clang::diag::err_drv_no_such_file) << Value; return false; } Index: clang/test/Driver/cl-inputs.c =================================================================== --- clang/test/Driver/cl-inputs.c +++ clang/test/Driver/cl-inputs.c @@ -55,9 +55,9 @@ // 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' Index: clang/test/Driver/cl-link.c =================================================================== --- clang/test/Driver/cl-link.c +++ clang/test/Driver/cl-link.c @@ -47,12 +47,20 @@ // DEBUG: link.exe // DEBUG: "-debug" +// Don't pass through /libpath: if it's not after a /link flag: +// RUN: %clang_cl /Tc%s /libpath:foo -fuse-ld=link -### /link /libpath:bar 2>&1 | FileCheck --check-prefix=LIBPATH %s +// LIBPATH: error: no such file or directory: '/libpath:foo' +// LIBPATH: libpath:bar + // 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/unknown-arg.c =================================================================== --- clang/test/Driver/unknown-arg.c +++ clang/test/Driver/unknown-arg.c @@ -10,6 +10,8 @@ // RUN: FileCheck %s --check-prefix=CL-DID-YOU-MEAN // RUN: %clang_cl /Brepo -### -- %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=CL-DID-YOU-MEAN-SLASH +// RUN: %clang_cl /Brepo -### /Tc%s /link 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CL-DID-YOU-MEAN-SLASH // RUN: not %clang_cl -cake-is-lie -%0 -%d -HHHH -munknown-to-clang-option -print-stats -funknown-to-clang-option -c -Werror=unknown-argument -### -- %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=CL-ERROR // RUN: not %clang_cl -helo -Werror=unknown-argument -### -- %s 2>&1 | \