For Linux/gnu compatibility, preinclude <stdc-predef.h> if the file is available

As reported in llvm bugzilla 32377.
Here’s a patch to add preinclude of stdc-predef.h.

The gcc documentation says “On GNU/Linux, <stdc-predef.h> is pre-included.” See https://gcc.gnu.org/gcc-4.8/porting_to.html;

The preinclude is inhibited with –ffreestanding.

Basically I fixed the failing test cases by adding –ffreestanding which inhibits this behavior.

I fixed all the failing tests, including some in extra/test, there's a separate patch for that which is linked here

Note: this is a recommit after a test failure took down the original (r318669)

Patch By: mibintc
Differential Revision: https://reviews.llvm.org/D34158

llvm-svn: 320391
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index 765c057..b494bc7 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -64,7 +64,7 @@
     .Cases("-internal-externc-isystem", "-iprefix", true)
     .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
     .Cases("-isysroot", "-I", "-F", "-resource-dir", true)
-    .Cases("-iframework", "-include-pch", true)
+    .Cases("-iframework", "-include-pch", "-fsystem-include-if-exists", true)
     .Default(false);
   if (IsInclude)
     return HaveCrashVFS ? false : true;
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 1301cdf..5c36973 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -710,6 +710,8 @@
   addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
 
   addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
+
+  AddGnuIncludeArgs(DriverArgs, CC1Args);
 }
 
 static std::string DetectLibcxxIncludePath(StringRef base) {
@@ -748,6 +750,16 @@
   return "";
 }
 
+void Linux::AddGnuIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                              llvm::opt::ArgStringList &CC1Args) const {
+  if (!DriverArgs.hasArg(options::OPT_ffreestanding)) {
+    // For gcc compatibility, clang will preinclude <stdc-predef.h>
+    // -ffreestanding suppresses this behavior.
+    CC1Args.push_back("-fsystem-include-if-exists");
+    CC1Args.push_back("stdc-predef.h");
+  }
+}
+
 void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
                                      llvm::opt::ArgStringList &CC1Args) const {
   // We need a detected GCC installation on Linux to provide libstdc++'s
diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h
index 9778c18..8b7e2e2 100644
--- a/clang/lib/Driver/ToolChains/Linux.h
+++ b/clang/lib/Driver/ToolChains/Linux.h
@@ -31,6 +31,8 @@
   void addLibStdCxxIncludePaths(
       const llvm::opt::ArgList &DriverArgs,
       llvm::opt::ArgStringList &CC1Args) const override;
+  void AddGnuIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                          llvm::opt::ArgStringList &CC1Args) const;
   void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
                           llvm::opt::ArgStringList &CC1Args) const override;
   void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 2ebdc2a..60802da 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2611,6 +2611,10 @@
   for (const Arg *A : Args.filtered(OPT_chain_include))
     Opts.ChainedIncludes.emplace_back(A->getValue());
 
+  // Add the ordered list of -fsystem-include-if-exists.
+  for (const Arg *A : Args.filtered(OPT_fsystem_include_if_exists))
+    Opts.FSystemIncludeIfExists.emplace_back(A->getValue());
+
   for (const Arg *A : Args.filtered(OPT_remap_file)) {
     std::pair<StringRef, StringRef> Split = StringRef(A->getValue()).split(';');
 
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index d398904..45760ae 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -70,6 +70,15 @@
   Builder.append(Twine("#include \"") + File + "\"");
 }
 
+/// AddImplicitSystemIncludeIfExists - Add an implicit system \#include of the 
+/// specified file to the predefines buffer: precheck with __has_include.
+static void AddImplicitSystemIncludeIfExists(MacroBuilder &Builder, 
+                                             StringRef File) {
+  Builder.append(Twine("#if __has_include( <") + File + ">)");
+  Builder.append(Twine("#include <") + File + ">");
+  Builder.append(Twine("#endif"));
+}
+
 static void AddImplicitIncludeMacros(MacroBuilder &Builder, StringRef File) {
   Builder.append(Twine("#__include_macros \"") + File + "\"");
   // Marker token to stop the __include_macros fetch loop.
@@ -1133,6 +1142,13 @@
   if (!PP.getLangOpts().AsmPreprocessor)
     Builder.append("# 1 \"<built-in>\" 2");
 
+  // Process -fsystem-include-if-exists directives.
+  for (unsigned i = 0, 
+       e = InitOpts.FSystemIncludeIfExists.size(); i != e; ++i) {
+    const std::string &Path = InitOpts.FSystemIncludeIfExists[i];
+    AddImplicitSystemIncludeIfExists(Builder, Path);
+  }
+
   // If -imacros are specified, include them now.  These are processed before
   // any -include directives.
   for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i)