Merge branch 'fix-legacy-implicit-includes' into release-3.14

Merge-request: !2981
diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake
index fd1d5fb..e0d2449 100644
--- a/Modules/CMakeDetermineCompilerABI.cmake
+++ b/Modules/CMakeDetermineCompilerABI.cmake
@@ -96,6 +96,12 @@
         file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
           "Parsed ${lang} implicit include dir info from above output: rv=${rv}\n${log}\n\n")
         if("${rv}" STREQUAL "done")
+          # Entries that we have been told to explicitly pass as standard include
+          # directories will not be implicitly added by the compiler.
+          if(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
+            list(REMOVE_ITEM implicit_incdirs ${CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES})
+          endif()
+
           # We parsed implicit include directories, so override the default initializer.
           set(_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT "${implicit_incdirs}")
         endif()
diff --git a/Modules/Platform/UnixPaths.cmake b/Modules/Platform/UnixPaths.cmake
index 46c24bb..97f744d 100644
--- a/Modules/Platform/UnixPaths.cmake
+++ b/Modules/Platform/UnixPaths.cmake
@@ -63,21 +63,29 @@
   /lib /lib32 /lib64 /usr/lib /usr/lib32 /usr/lib64
   )
 
+if(CMAKE_SYSROOT_COMPILE)
+  set(_cmake_sysroot_compile "${CMAKE_SYSROOT_COMPILE}")
+else()
+  set(_cmake_sysroot_compile "${CMAKE_SYSROOT}")
+endif()
+
 # Default per-language values.  These may be later replaced after
 # parsing the implicit directory information from compiler output.
 set(_CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES_INIT
   ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}
-  /usr/include
+  "${_cmake_sysroot_compile}/usr/include"
   )
 set(_CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES_INIT
   ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}
-  /usr/include
+  "${_cmake_sysroot_compile}/usr/include"
   )
 set(_CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES_INIT
   ${CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES}
-  /usr/include
+  "${_cmake_sysroot_compile}/usr/include"
   )
 
+unset(_cmake_sysroot_compile)
+
 # Enable use of lib32 and lib64 search path variants by default.
 set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS TRUE)
 set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 8090e00..8b01af1 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -920,6 +920,20 @@
     return result;
   }
 
+  // Standard include directories to be added unconditionally at the end.
+  // These are intended to simulate additional implicit include directories.
+  std::vector<std::string> userStandardDirs;
+  {
+    std::string key = "CMAKE_";
+    key += lang;
+    key += "_STANDARD_INCLUDE_DIRECTORIES";
+    std::string const value = this->Makefile->GetSafeDefinition(key);
+    cmSystemTools::ExpandListArgument(value, userStandardDirs);
+    for (std::string& usd : userStandardDirs) {
+      cmSystemTools::ConvertToUnixSlashes(usd);
+    }
+  }
+
   // Implicit include directories
   std::vector<std::string> implicitDirs;
   std::set<std::string> implicitSet;
@@ -928,24 +942,21 @@
     return (implicitSet.find(dir) == implicitSet.end());
   };
   {
-    std::string rootPath;
-    if (const char* sysrootCompile =
-          this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
-      rootPath = sysrootCompile;
-    } else {
-      rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
-    }
-    cmSystemTools::ConvertToUnixSlashes(rootPath);
-
     // Raw list of implicit include directories
-    std::vector<std::string> impDirVec;
+    // Start with "standard" directories that we unconditionally add below.
+    std::vector<std::string> impDirVec = userStandardDirs;
 
     // Load implicit include directories for this language.
     std::string key = "CMAKE_";
     key += lang;
     key += "_IMPLICIT_INCLUDE_DIRECTORIES";
     if (const char* value = this->Makefile->GetDefinition(key)) {
+      size_t const impDirVecOldSize = impDirVec.size();
       cmSystemTools::ExpandListArgument(value, impDirVec);
+      // FIXME: Use cmRange with 'advance()' when it supports non-const.
+      for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) {
+        cmSystemTools::ConvertToUnixSlashes(impDirVec[i]);
+      }
     }
 
     // The Platform/UnixPaths module used to hard-code /usr/include for C, CXX,
@@ -965,13 +976,8 @@
     }
 
     for (std::string const& i : impDirVec) {
-      std::string imd = i;
-      cmSystemTools::ConvertToUnixSlashes(imd);
-      if (!rootPath.empty() && !cmHasPrefix(imd, rootPath)) {
-        imd = rootPath + imd;
-      }
-      if (implicitSet.insert(imd).second) {
-        implicitDirs.emplace_back(std::move(imd));
+      if (implicitSet.insert(i).second) {
+        implicitDirs.emplace_back(i);
       }
     }
   }
@@ -1010,23 +1016,10 @@
   MoveSystemIncludesToEnd(result, config, lang, target);
 
   // Append standard include directories for this language.
-  {
-    std::vector<std::string> userStandardDirs;
-    {
-      std::string key = "CMAKE_";
-      key += lang;
-      key += "_STANDARD_INCLUDE_DIRECTORIES";
-      std::string const value = this->Makefile->GetSafeDefinition(key);
-      cmSystemTools::ExpandListArgument(value, userStandardDirs);
-    }
-    userDirs.reserve(userDirs.size() + userStandardDirs.size());
-    for (std::string& usd : userStandardDirs) {
-      cmSystemTools::ConvertToUnixSlashes(usd);
-      if (notImplicit(usd)) {
-        emitDir(usd);
-      }
-      userDirs.emplace_back(std::move(usd));
-    }
+  userDirs.reserve(userDirs.size() + userStandardDirs.size());
+  for (std::string& usd : userStandardDirs) {
+    emitDir(usd);
+    userDirs.emplace_back(std::move(usd));
   }
 
   // Append compiler implicit include directories