ldionne created this revision.
ldionne added reviewers: arphaman, dexonsmith.
Herald added subscribers: cfe-commits, jkorous.
Herald added a project: clang.
ldionne requested review of this revision.

Currently, Clang looks for libc++ headers alongside the installation
directory of Clang, and it also adds a search path for headers in the
-isysroot. This patch roughly reverses the order so that headers are
searched for in the following order:

1. <isysroot>/usr/include/c++/v1
2. <installdir>/bin/../include/c++/v1

The benefit of doing this is that a user-installed libc++ can be picked
up when providing a custom sysroot, which doesn't work properly right
now. Furthermore, instead of always adding both search paths, we find
the first search path that exists and only add that one. Otherwise,
include_next is broken because there could be two sets of libc++ headers
on the search paths.

rdar://48638125


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D88984

Files:
  clang-tools-extra/test/clang-tidy/infrastructure/Inputs/empty-sysroot/.gitkeep
  clang-tools-extra/test/clang-tidy/infrastructure/Inputs/mock-libcxx/bin/clang
  
clang-tools-extra/test/clang-tidy/infrastructure/Inputs/mock-libcxx/include/c++/v1/mock_vector
  
clang-tools-extra/test/clang-tidy/infrastructure/Inputs/mock-toolchain-root/bin/clang
  
clang-tools-extra/test/clang-tidy/infrastructure/Inputs/mock-toolchain-root/include/c++/v1/mock_vector
  clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-mac-libcxx.cpp
  clang/lib/Driver/ToolChains/Darwin.cpp
  clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/include/c++/v1/.keep
  clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/lib/.keep
  clang/test/Driver/darwin-header-search-libcxx.cpp
  clang/test/Tooling/Inputs/empty-sysroot/.gitkeep
  clang/test/Tooling/Inputs/mock-libcxx/bin/clang
  clang/test/Tooling/Inputs/mock-libcxx/include/c++/v1/mock_vector
  clang/test/Tooling/Inputs/mock-toolchain-root/bin/clang
  clang/test/Tooling/Inputs/mock-toolchain-root/include/c++/v1/mock_vector
  clang/test/Tooling/clang-check-mac-libcxx-abspath.cpp
  clang/test/Tooling/clang-check-mac-libcxx-fixed-compilation-db.cpp
  clang/test/Tooling/clang-check-mac-libcxx-relpath.cpp

Index: clang/test/Tooling/clang-check-mac-libcxx-relpath.cpp
===================================================================
--- clang/test/Tooling/clang-check-mac-libcxx-relpath.cpp
+++ clang/test/Tooling/clang-check-mac-libcxx-relpath.cpp
@@ -1,15 +1,20 @@
-// Clang on MacOS can find libc++ living beside the installed compiler.
-// This test makes sure our libTooling-based tools emulate this properly.
+// Clang on MacOS can find libc++ living beside the installed compiler if there
+// are no headers in the sysroot. 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/
+// Install a mock toolchain root that contains a simulation of libc++.
+// RUN: cp -r %S/Inputs/mock-toolchain-root %t/mock-toolchain-root
 //
-// Pretend clang is installed beside the mock library that we provided.
-// RUN: echo '[{"directory":"%t","command":"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
+// Install a mock sysroot that doesn't contain anything, to make sure we
+// prefer the libc++ headers in the toolchain.
+// RUN: cp -r %S/Inputs/empty-sysroot %t/empty-sysroot
+//
+// RUN: echo '[{"directory":"%t","command":"mock-toolchain-root/bin/clang -isysroot %t/empty-sysroot -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"
+//
 // clang-check will produce an error code if the mock library is not found.
 // RUN: clang-check -p "%t" "%t/test.cpp"
 
Index: clang/test/Tooling/clang-check-mac-libcxx-fixed-compilation-db.cpp
===================================================================
--- clang/test/Tooling/clang-check-mac-libcxx-fixed-compilation-db.cpp
+++ clang/test/Tooling/clang-check-mac-libcxx-fixed-compilation-db.cpp
@@ -1,18 +1,23 @@
-// Clang on MacOS can find libc++ living beside the installed compiler.
-// This test makes sure our libTooling-based tools emulate this properly with
-// fixed compilation database.
+// Clang on MacOS can find libc++ living beside the installed compiler if there
+// are no headers in the sysroot. This test makes sure our libTooling-based tools
+// emulate this properly with a fixed compilation database.
 //
 // RUN: rm -rf %t
 // RUN: mkdir %t
 //
-// Install the mock libc++ (simulates the libc++ directory structure).
-// RUN: cp -r %S/Inputs/mock-libcxx %t/
+// Install a mock toolchain root that contains a simulation of libc++.
+// RUN: cp -r %S/Inputs/mock-toolchain-root %t/mock-toolchain-root
 //
-// RUN: cp clang-check %t/mock-libcxx/bin/
+// Install a mock sysroot that doesn't contain anything, to make sure we
+// prefer the libc++ headers in the toolchain.
+// RUN: cp -r %S/Inputs/empty-sysroot %t/empty-sysroot
+//
+// RUN: cp clang-check %t/mock-toolchain-root/bin/
 // RUN: cp %s %t/test.cpp
-// RUN: "%t/mock-libcxx/bin/clang-check" -p %t %t/test.cpp -- \
+// RUN: "%t/mock-toolchain-root/bin/clang-check" -p %t %t/test.cpp -- \
 // RUN:     -stdlib=libc++ -target x86_64-apple-darwin \
-// RUN:     -ccc-install-dir %t/mock-libcxx/bin
+// RUN:     -isysroot %t/empty-sysroot \
+// RUN:     -ccc-install-dir %t/mock-toolchain-root/bin
 //
 // ^ -ccc-install-dir passed to unbreak tests on *BSD where
 //   getMainExecutable() relies on real argv[0] being passed
Index: clang/test/Tooling/clang-check-mac-libcxx-abspath.cpp
===================================================================
--- clang/test/Tooling/clang-check-mac-libcxx-abspath.cpp
+++ clang/test/Tooling/clang-check-mac-libcxx-abspath.cpp
@@ -1,15 +1,20 @@
-// Clang on MacOS can find libc++ living beside the installed compiler.
-// This test makes sure our libTooling-based tools emulate this properly.
+// Clang on MacOS can find libc++ living beside the installed compiler if there
+// are no headers in the sysroot. 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/
+// Install a mock toolchain root that contains a simulation of libc++.
+// RUN: cp -r %S/Inputs/mock-toolchain-root %t/mock-toolchain-root
 //
-// 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
+// Install a mock sysroot that doesn't contain anything, to make sure we
+// prefer the libc++ headers in the toolchain.
+// RUN: cp -r %S/Inputs/empty-sysroot %t/empty-sysroot
+//
+// RUN: echo '[{"directory":"%t","command":"%t/mock-toolchain-root/bin/clang -isysroot %t/empty-sysroot -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"
+//
 // clang-check will produce an error code if the mock library is not found.
 // RUN: clang-check -p "%t" "%t/test.cpp"
 
Index: clang/test/Tooling/Inputs/mock-libcxx/include/c++/v1/mock_vector
===================================================================
--- /dev/null
+++ clang/test/Tooling/Inputs/mock-libcxx/include/c++/v1/mock_vector
@@ -1 +0,0 @@
-class vector {};
Index: clang/test/Tooling/Inputs/mock-libcxx/bin/clang
===================================================================
--- /dev/null
+++ clang/test/Tooling/Inputs/mock-libcxx/bin/clang
@@ -1 +0,0 @@
-This file is a placeholder to keep its parent directory in git.
Index: clang/test/Driver/darwin-header-search-libcxx.cpp
===================================================================
--- clang/test/Driver/darwin-header-search-libcxx.cpp
+++ clang/test/Driver/darwin-header-search-libcxx.cpp
@@ -13,30 +13,47 @@
 // RUN:   | FileCheck --check-prefix=CHECK-LIBCXX-NONE %s
 // CHECK-LIBCXX-NONE: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
 
-// Check with only headers alongside the installation (those should be used,
-// but we should still add /usr/include/c++/v1 after to preserve legacy).
+// Check with only headers alongside the installation (those should be used).
 //
 // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
 // RUN:     -target x86_64-apple-darwin \
 // RUN:     -stdlib=libc++ \
 // RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
 // RUN:     --sysroot="" \
-// RUN:   | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain --check-prefix=CHECK-LIBCXX-TOOLCHAIN-1 %s
+// RUN:   | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \
+// RUN:               --check-prefix=CHECK-LIBCXX-TOOLCHAIN-1 %s
 // CHECK-LIBCXX-TOOLCHAIN-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
 // CHECK-LIBCXX-TOOLCHAIN-1: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
-// CHECK-LIBCXX-TOOLCHAIN-1: "-internal-isystem" "/usr/include/c++/v1"
+// CHECK-LIBCXX-TOOLCHAIN-1-NOT: "-internal-isystem" "/usr/include/c++/v1"
 //
 // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
 // RUN:     -target x86_64-apple-darwin \
 // RUN:     -stdlib=libc++ \
 // RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
 // RUN:     -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \
-// RUN:   | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain --check-prefix=CHECK-LIBCXX-TOOLCHAIN-2 %s
+// RUN:   | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \
+// RUN:               -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \
+// RUN:               --check-prefix=CHECK-LIBCXX-TOOLCHAIN-2 %s
 // CHECK-LIBCXX-TOOLCHAIN-2: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
 // CHECK-LIBCXX-TOOLCHAIN-2: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
+// CHECK-LIBCXX-TOOLCHAIN-2-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
+
+// Check with only headers in the sysroot (those should be used).
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN:     -target x86_64-apple-darwin \
+// RUN:     -stdlib=libc++ \
+// RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain_no_libcxx/usr/bin \
+// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
+// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
+// RUN:               -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain_no_libcxx \
+// RUN:               --check-prefix=CHECK-LIBCXX-SYSROOT-1 %s
+// CHECK-LIBCXX-SYSROOT-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-LIBCXX-SYSROOT-1: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
+// CHECK-LIBCXX-SYSROOT-1-NOT: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
 
 // Check with both headers in the sysroot and headers alongside the installation
-// (the headers in <sysroot> should be added after the toolchain headers).
+// (the headers in <sysroot> should be preferred over the toolchain headers).
 // Ensure that both -isysroot and --sysroot work, and that isysroot has precedence.
 //
 // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
@@ -44,8 +61,8 @@
 // RUN:     -stdlib=libc++ \
 // RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
-// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr \
-// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \
+// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
+// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
 // RUN:               -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \
 // RUN:               --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s
 //
@@ -54,8 +71,8 @@
 // RUN:     -stdlib=libc++ \
 // RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
-// RUN:     --sysroot %S/Inputs/basic_darwin_sdk_usr \
-// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \
+// RUN:     --sysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
+// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
 // RUN:               -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \
 // RUN:               --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s
 //
@@ -64,32 +81,46 @@
 // RUN:     -stdlib=libc++ \
 // RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
-// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr \
+// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
 // RUN:     --sysroot %S/Inputs/basic_darwin_sdk_no_libcxx \
-// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \
+// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
 // RUN:               -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \
 // RUN:               --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s
 //
 // CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
-// CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
 // CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
+// CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1-NOT: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
 
-// Make sure that using -nostdinc will drop the sysroot C++ library include
-// path, but not the toolchain one.
+// Make sure that using -nostdinc does not drop any C++ library include path.
+// This behavior is strange, but it is compatible with the legacy CC1 behavior.
 //
 // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
 // RUN:     -target x86_64-apple-darwin16 \
 // RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
-// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr \
+// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
 // RUN:     -stdlib=platform \
 // RUN:     -nostdinc \
-// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \
+// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
+// RUN:               -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \
+// RUN:               --check-prefix=CHECK-LIBCXX-NOSTDINC-1 %s
+// CHECK-LIBCXX-NOSTDINC-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-LIBCXX-NOSTDINC-1-NOT: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
+// CHECK-LIBCXX-NOSTDINC-1: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN:     -target x86_64-apple-darwin16 \
+// RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
+// RUN:     -resource-dir=%S/Inputs/resource_dir \
+// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \
+// RUN:     -stdlib=platform \
+// RUN:     -nostdinc \
+// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \
 // RUN:               -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \
-// RUN:               --check-prefix=CHECK-LIBCXX-NOSTDINC %s
-// CHECK-LIBCXX-NOSTDINC: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
-// CHECK-LIBCXX-NOSTDINC: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
-// CHECK-LIBCXX-NOSTDINC-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
+// RUN:               --check-prefix=CHECK-LIBCXX-NOSTDINC-2 %s
+// CHECK-LIBCXX-NOSTDINC-2: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-LIBCXX-NOSTDINC-2: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
+// CHECK-LIBCXX-NOSTDINC-2-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
 
 // Make sure that using -nostdinc++ or -nostdlib will drop both the toolchain
 // C++ include path and the sysroot one.
@@ -98,7 +129,7 @@
 // RUN:     -target x86_64-apple-darwin16 \
 // RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
-// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr \
+// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
 // RUN:     -stdlib=platform \
 // RUN:     -nostdinc++ \
 // RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \
@@ -121,3 +152,24 @@
 // CHECK-LIBCXX-NOSTDLIBINC: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
 // CHECK-LIBCXX-NOSTDLIBINC-NOT: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
 // CHECK-LIBCXX-NOSTDLIBINC-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
+
+// Make sure we explain that we considered a path but didn't add it when it
+// doesn't exist.
+//
+// RUN: %clang -no-canonical-prefixes %s -fsyntax-only -v 2>&1 \
+// RUN:     -target x86_64-apple-darwin \
+// RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \
+// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \
+// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \
+// RUN:               --check-prefix=CHECK-LIBCXX-MISSING-SYSROOT %s
+// CHECK-LIBCXX-MISSING-SYSROOT: ignoring nonexistent directory "[[SYSROOT]]/usr/include/c++/v1"
+//
+// RUN: %clang -no-canonical-prefixes %s -fsyntax-only -v 2>&1 \
+// RUN:     -target x86_64-apple-darwin \
+// RUN:     -ccc-install-dir %S/Inputs/basic_darwin_toolchain_no_libcxx/usr/bin \
+// RUN:     -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \
+// RUN:   | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \
+// RUN:               -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain_no_libcxx \
+// RUN:               --check-prefix=CHECK-LIBCXX-MISSING-BOTH %s
+// CHECK-LIBCXX-MISSING-BOTH: ignoring nonexistent directory "[[SYSROOT]]/usr/include/c++/v1"
+// CHECK-LIBCXX-MISSING-BOTH: ignoring nonexistent directory "[[TOOLCHAIN]]/usr/bin/../include/c++/v1"
Index: clang/lib/Driver/ToolChains/Darwin.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Darwin.cpp
+++ clang/lib/Driver/ToolChains/Darwin.cpp
@@ -2020,21 +2020,38 @@
 
   switch (GetCXXStdlibType(DriverArgs)) {
   case ToolChain::CST_Libcxx: {
-    // On Darwin, libc++ is installed alongside the compiler in
-    // include/c++/v1, so get from '<install>/bin' to '<install>/include/c++/v1'.
-    {
-      llvm::SmallString<128> P = llvm::StringRef(getDriver().getInstalledDir());
-      // Note that P can be relative, so we have to '..' and not parent_path.
-      llvm::sys::path::append(P, "..", "include", "c++", "v1");
-      addSystemInclude(DriverArgs, CC1Args, P);
+    // On Darwin, libc++ can be installed in one of the following two places:
+    // 1. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1
+    // 2. Alongside the compiler in         <install>/include/c++/v1
+    //
+    // The precendence of paths is as listed above, i.e. we take the first path
+    // that exists. Also note that we never include libc++ twice -- we take the
+    // first path that exists and don't send the other paths to CC1 (otherwise
+    // include_next could break).
+
+    // Check for (1)
+    llvm::SmallString<128> SysrootUsr = Sysroot;
+    llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1");
+    if (getVFS().exists(SysrootUsr)) {
+      addSystemInclude(DriverArgs, CC1Args, SysrootUsr);
+      return;
+    } else if (DriverArgs.hasArg(options::OPT_v)) {
+      llvm::errs() << "ignoring nonexistent directory \"" << SysrootUsr << "\"\n";
     }
-    // Also add <sysroot>/usr/include/c++/v1 unless -nostdinc is used,
-    // to match the legacy behavior in CC1.
-    if (!DriverArgs.hasArg(options::OPT_nostdinc)) {
-      llvm::SmallString<128> P = Sysroot;
-      llvm::sys::path::append(P, "usr", "include", "c++", "v1");
-      addSystemInclude(DriverArgs, CC1Args, P);
+
+    // Otherwise, check for (2)
+    // Get from '<install>/bin' to '<install>/include/c++/v1'.
+    // Note that InstallBin can be relative, so we use '..' instead of parent_path.
+    llvm::SmallString<128> InstallBin = llvm::StringRef(getDriver().getInstalledDir()); // <install>/bin
+    llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");
+    if (getVFS().exists(InstallBin)) {
+      addSystemInclude(DriverArgs, CC1Args, InstallBin);
+      return;
+    } else if (DriverArgs.hasArg(options::OPT_v)) {
+      llvm::errs() << "ignoring nonexistent directory \"" << InstallBin << "\"\n";
     }
+
+    // Otherwise, don't add any path.
     break;
   }
 
Index: clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-mac-libcxx.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-mac-libcxx.cpp
+++ clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-mac-libcxx.cpp
@@ -1,14 +1,18 @@
-// Clang on MacOS can find libc++ living beside the installed compiler.
-// This test makes sure clang-tidy emulates this properly.
+// Clang on MacOS can find libc++ living beside the installed compiler if there
+// are no headers in the sysroot. This test makes sure our clang-tidy emulates
+// 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/
+// Install a mock toolchain root that contains a simulation of libc++.
+// RUN: cp -r %S/Inputs/mock-toolchain-root %t/mock-toolchain-root
 //
-// Pretend clang is installed beside the mock library that we provided.
-// RUN: echo '[{"directory":"%t","command":"%t/mock-libcxx/bin/clang++ -stdlib=libc++ -std=c++11 -target x86_64-apple-darwin -c test.cpp","file":"test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
+// Install a mock sysroot that doesn't contain anything, to make sure we
+// prefer the libc++ headers in the toolchain.
+// RUN: cp -r %S/Inputs/empty-sysroot %t/empty-sysroot
+//
+// RUN: echo '[{"directory":"%t","command":"%t/mock-toolchain-root/bin/clang -isysroot %t/empty-sysroot -stdlib=libc++ -std=c++11 -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-tidy -header-filter='.*' -system-headers -checks='-*,modernize-use-using'  "%t/test.cpp" | FileCheck %s
 // CHECK: mock_vector:{{[0-9]+}}:{{[0-9]+}}: warning: use 'using' instead of 'typedef'
Index: clang-tools-extra/test/clang-tidy/infrastructure/Inputs/mock-libcxx/include/c++/v1/mock_vector
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/infrastructure/Inputs/mock-libcxx/include/c++/v1/mock_vector
@@ -1,2 +0,0 @@
-class vector {};
-typedef vector* vector_ptr;
Index: clang-tools-extra/test/clang-tidy/infrastructure/Inputs/mock-libcxx/bin/clang
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/infrastructure/Inputs/mock-libcxx/bin/clang
@@ -1 +0,0 @@
-This file is a placeholder to keep its parent directory in git.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D88984: P... Louis Dionne via Phabricator via cfe-commits

Reply via email to