Reorganize predefined macros for all Windows targets.

This adds an option to set the _MSC_VER macro without
recompiling. This is very useful when testing compatibility
with the Windows SDK and c++stdlib headers.

-fmsc-version=<version> (defaults to VS2003 (1300))

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116999 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 9601210..b6eb15c 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -405,6 +405,54 @@
     // FIXME: WIntType should be SignedLong
   }
 };
+
+// Windows target
+template<typename Target>
+class WindowsTargetInfo : public OSTargetInfo<Target> {
+protected:
+  virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+                            MacroBuilder &Builder) const {
+    if (Opts.CPlusPlus) {
+      if (Opts.RTTI)
+        Builder.defineMacro("_CPPRTTI");
+
+      if (Opts.Exceptions)
+        Builder.defineMacro("_CPPUNWIND");
+    }
+
+    if (!Opts.CharIsSigned)
+      Builder.defineMacro("_CHAR_UNSIGNED");
+
+    // FIXME: POSIXThreads isn't exactly the option this should be defined for,
+    //        but it works for now.
+    if (Opts.POSIXThreads)
+      Builder.defineMacro("_MT");
+      
+    if (Opts.MSCVersion != 0)
+      Builder.defineMacro("_MSC_VER", llvm::Twine(Opts.MSCVersion));
+
+    if (Opts.Microsoft) {
+      Builder.defineMacro("_MSC_EXTENSIONS");
+
+      if (Opts.CPlusPlus0x) {
+        Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED");
+        Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED");
+        Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED");
+      }
+    }
+
+    Builder.defineMacro("_INTEGRAL_MAX_BITS", "64");
+    Builder.defineMacro("_WIN32");
+  }
+
+  virtual const char *getVAListDeclaration() const {
+    return "typedef char* __builtin_va_list;";
+  }
+public:
+  WindowsTargetInfo(const std::string &triple)
+    : OSTargetInfo<Target>(triple) {}
+};
+
 } // end anonymous namespace.
 
 //===----------------------------------------------------------------------===//
@@ -1185,6 +1233,21 @@
     break;
   }
 
+  if (Opts.Microsoft && PointerWidth == 32) {
+    Builder.defineMacro("_M_IX86", "600");
+
+    switch (SSELevel) {
+    case SSE2:
+      Builder.defineMacro("_M_IX86_FP", llvm::Twine(2));
+      break;
+    case SSE1:
+      Builder.defineMacro("_M_IX86_FP", llvm::Twine(1));
+      break;
+    default:
+      Builder.defineMacro("_M_IX86_FP", llvm::Twine(0));
+    }
+  }
+
   // Each case falls through to the previous one here.
   switch (AMD3DNowLevel) {
   case AMD3DNowAthlon:
@@ -1325,49 +1388,19 @@
 
 namespace {
 // x86-32 Windows target
-class WindowsX86_32TargetInfo : public X86_32TargetInfo {
+class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> {
 public:
   WindowsX86_32TargetInfo(const std::string& triple)
-    : X86_32TargetInfo(triple) {
+    : WindowsTargetInfo<X86_32TargetInfo>(triple) {
     TLSSupported = false;
     WCharType = UnsignedShort;
     DoubleAlign = LongLongAlign = 64;
+    LongDoubleWidth = 64;
+    LongDoubleFormat = &llvm::APFloat::IEEEdouble;
     DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
                         "i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-"
                         "v128:128:128-a0:0:64-f80:32:32-n8:16:32";
   }
-  virtual void getTargetDefines(const LangOptions &Opts,
-                                MacroBuilder &Builder) const {
-    X86_32TargetInfo::getTargetDefines(Opts, Builder);
-    // This list is based off of the the list of things MingW defines
-    Builder.defineMacro("_WIN32");
-    DefineStd(Builder, "WIN32", Opts);
-    DefineStd(Builder, "WINNT", Opts);
-    Builder.defineMacro("_X86_");
-  }
-};
-} // end anonymous namespace
-
-namespace {
-
-// x86-32 Windows Visual Studio target
-class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
-public:
-  VisualStudioWindowsX86_32TargetInfo(const std::string& triple)
-    : WindowsX86_32TargetInfo(triple) {
-    LongDoubleWidth = 64;
-    LongDoubleFormat = &llvm::APFloat::IEEEdouble;
-  }
-  virtual void getTargetDefines(const LangOptions &Opts,
-                                MacroBuilder &Builder) const {
-    WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
-    // The value of the following reflects processor type.
-    // 300=386, 400=486, 500=Pentium, 600=Blend (default)
-    // We lost the original triple, so we use the default.
-    Builder.defineMacro("_M_IX86", "600");
-    Builder.defineMacro("_INTEGRAL_MAX_BITS", "64");
-    Builder.defineMacro("_STDCALL_SUPPORTED");
-  }
 };
 } // end anonymous namespace
 
@@ -1474,10 +1507,10 @@
 
 namespace {
 // x86-64 Windows target
-class WindowsX86_64TargetInfo : public X86_64TargetInfo {
+class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> {
 public:
   WindowsX86_64TargetInfo(const std::string& triple)
-    : X86_64TargetInfo(triple) {
+    : WindowsTargetInfo<X86_64TargetInfo>(triple) {
     TLSSupported = false;
     WCharType = UnsignedShort;
     LongWidth = LongAlign = 32;
@@ -1491,25 +1524,11 @@
   }
   virtual void getTargetDefines(const LangOptions &Opts,
                                 MacroBuilder &Builder) const {
-    X86_64TargetInfo::getTargetDefines(Opts, Builder);
-    Builder.defineMacro("_WIN64");
-    DefineStd(Builder, "WIN64", Opts);
-  }
-};
-} // end anonymous namespace
+    WindowsTargetInfo<X86_64TargetInfo>::getTargetDefines(Opts, Builder);
 
-namespace {
-// x86-64 Windows Visual Studio target
-class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo {
-public:
-  VisualStudioWindowsX86_64TargetInfo(const std::string& triple)
-    : WindowsX86_64TargetInfo(triple) {
-  }
-  virtual void getTargetDefines(const LangOptions &Opts,
-                                MacroBuilder &Builder) const {
-    WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+    Builder.defineMacro("_WIN64");
     Builder.defineMacro("_M_X64");
-    Builder.defineMacro("_INTEGRAL_MAX_BITS", "64");
+    Builder.defineMacro("_M_AMD64");
   }
   virtual const char *getVAListDeclaration() const {
     return "typedef char* __builtin_va_list;";
@@ -2523,7 +2542,7 @@
     case llvm::Triple::MinGW32:
       return new MinGWX86_32TargetInfo(T);
     case llvm::Triple::Win32:
-      return new VisualStudioWindowsX86_32TargetInfo(T);
+      return new WindowsX86_32TargetInfo(T);
     case llvm::Triple::Haiku:
       return new HaikuX86_32TargetInfo(T);
     default:
@@ -2551,7 +2570,7 @@
     case llvm::Triple::MinGW64:
       return new MinGWX86_64TargetInfo(T);
     case llvm::Triple::Win32:   // This is what Triple.h supports now.
-      return new VisualStudioWindowsX86_64TargetInfo(T);
+      return new WindowsX86_64TargetInfo(T);
     default:
       return new X86_64TargetInfo(T);
     }
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index d4ba92c..021c7cb 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1314,6 +1314,18 @@
                    getToolChain().getTriple().getOS() == llvm::Triple::Win32))
     CmdArgs.push_back("-fms-extensions");
 
+  // -fmsc-version=1300 is default.
+  if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
+                   getToolChain().getTriple().getOS() == llvm::Triple::Win32) ||
+      Args.hasArg(options::OPT_fmsc_version)) {
+    llvm::StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version);
+    if (msc_ver.empty())
+      CmdArgs.push_back("-fmsc-version=1300");
+    else
+      CmdArgs.push_back(Args.MakeArgString("-fmsc-version=" + msc_ver));
+  }
+
+
   // -fborland-extensions=0 is default.
   if (Args.hasFlag(options::OPT_fborland_extensions,
                    options::OPT_fno_borland_extensions, false))
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b7ad08b..3ed859a 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -529,6 +529,8 @@
     Res.push_back("-fgnu-keywords");
   if (Opts.Microsoft)
     Res.push_back("-fms-extensions");
+  if (Opts.MSCVersion != 0)
+    Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion));
   if (Opts.Borland)
     Res.push_back("-fborland-extensions");
   if (Opts.ObjCNonFragileABI)
@@ -1334,6 +1336,7 @@
                                    !Opts.AsmPreprocessor);
   Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
   Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
+  Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
   Opts.Borland = Args.hasArg(OPT_fborland_extensions);
   Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
   Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index ada41b4..4461703 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -74,6 +74,7 @@
   PARSE_LANGOPT_BENIGN(HexFloats);
   PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99);
   PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions);
+  PARSE_LANGOPT_BENIGN(MSCVersion);
   PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus);
   PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x);
   PARSE_LANGOPT_BENIGN(CXXOperatorName);
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index d0e4802..4d0ec99 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -828,6 +828,8 @@
   Record.push_back(LangOpts.HexFloats);  // C99 Hexadecimal float constants.
   Record.push_back(LangOpts.C99);  // C99 Support
   Record.push_back(LangOpts.Microsoft);  // Microsoft extensions.
+  // LangOpts.MSCVersion is ignored because all it does it set a macro, which is
+  // already saved elsewhere.
   Record.push_back(LangOpts.CPlusPlus);  // C++ Support
   Record.push_back(LangOpts.CPlusPlus0x);  // C++0x Support
   Record.push_back(LangOpts.CXXOperatorNames);  // Treat C++ operator names as keywords.