Index: include/clang/Lex/HeaderSearchOptions.h =================================================================== --- include/clang/Lex/HeaderSearchOptions.h +++ include/clang/Lex/HeaderSearchOptions.h @@ -108,6 +108,11 @@ /// etc.). std::string ResourceDir; + /// Compiler install dir as detected by the Driver. + /// Only used to add include dirs for libc++ on Darwin. Please avoid relying + /// on this field for other purposes. + std::string InstallDir; + /// The directory used for the module cache. std::string ModuleCachePath; Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1773,6 +1773,7 @@ if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0); Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); + Opts.InstallDir = Opts.ResourceDir; // Canonicalize -fmodules-cache-path before storing it. SmallString<128> P(Args.getLastArgValue(OPT_fmodules_cache_path)); Index: lib/Frontend/CreateInvocationFromCommandLine.cpp =================================================================== --- lib/Frontend/CreateInvocationFromCommandLine.cpp +++ lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -11,17 +11,18 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/Utils.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" -#include "clang/Driver/Action.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" using namespace clang; using namespace llvm::opt; @@ -102,5 +103,8 @@ CCArgs.size(), *Diags)) return nullptr; + // Patch up the install dir, so we find the same standard library as the + // original compiler on MacOS. + CI->getHeaderSearchOpts().InstallDir = TheDriver.getInstalledDir(); return CI; } Index: lib/Frontend/InitHeaderSearch.cpp =================================================================== --- lib/Frontend/InitHeaderSearch.cpp +++ lib/Frontend/InitHeaderSearch.cpp @@ -476,14 +476,9 @@ if (triple.isOSDarwin()) { // On Darwin, libc++ may be installed alongside the compiler in // include/c++/v1. - if (!HSOpts.ResourceDir.empty()) { - // Remove version from foo/lib/clang/version - StringRef NoVer = llvm::sys::path::parent_path(HSOpts.ResourceDir); - // Remove clang from foo/lib/clang - StringRef Lib = llvm::sys::path::parent_path(NoVer); - // Remove lib from foo/lib - SmallString<128> P = llvm::sys::path::parent_path(Lib); - + if (!HSOpts.InstallDir.empty()) { + // Get from foo/bin to foo. + SmallString<128> P(llvm::sys::path::parent_path(HSOpts.InstallDir)); // Get foo/include/c++/v1 llvm::sys::path::append(P, "include", "c++", "v1"); AddUnmappedPath(P, CXXSystem, false); Index: lib/Tooling/Tooling.cpp =================================================================== --- lib/Tooling/Tooling.cpp +++ lib/Tooling/Tooling.cpp @@ -323,6 +323,9 @@ Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(), Input.release()); } + // Patch up the install dir, so we find the same standard library as the + // original compiler on MacOS. + Invocation->getHeaderSearchOpts().InstallDir = Driver->getInstalledDir(); return runInvocation(BinaryName, Compilation.get(), std::move(Invocation), std::move(PCHContainerOps)); } Index: test/Tooling/Inputs/mock-libcxx/include/c++/v1/mock_vector =================================================================== --- /dev/null +++ test/Tooling/Inputs/mock-libcxx/include/c++/v1/mock_vector @@ -0,0 +1 @@ +class vector {}; Index: test/Tooling/clang-check-mac-libcxx.cpp =================================================================== --- /dev/null +++ test/Tooling/clang-check-mac-libcxx.cpp @@ -0,0 +1,16 @@ +// Clang on MacOS can find libc++ living beside the installed compiler. +// This test makes sure our libTooling-based tools emulate this properly. +// +// RUN: rm -rf %t +// RUN: mkdir %t +// +// Install the mock libc++ (simulates the libc++ directory structure). +// RUN: cp -r %S/Inputs/mock-libcxx %t/ +// +// Pretend clang is installed beside the mock library that we provided. +// RUN: echo '[{"directory":"%t","command":"%t/mock-libcxx/bin/clang++ -stdlib=libc++ -target x86_64-apple-darwin -c test.cpp","file":"test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json +// RUN: cp "%s" "%t/test.cpp" +// RUN: clang-check -p "%t" "%t/test.cpp" + +#include +vector v;