Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -587,8 +587,12 @@ if (Opts.POSIXThreads) Builder.defineMacro("_MT"); - if (Opts.MSCVersion != 0) - Builder.defineMacro("_MSC_VER", Twine(Opts.MSCVersion)); + if (Opts.MSCVersion != 0) { + Builder.defineMacro("_MSC_VER", Twine(Opts.MSCVersion / 100000)); + Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCVersion)); + // FIXME We cannot encode the revision information into 32-bits + Builder.defineMacro("_MSC_BUILD", Twine(1)); + } if (Opts.MicrosoftExt) { Builder.defineMacro("_MSC_EXTENSIONS"); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -20,6 +20,7 @@ #include "clang/Serialization/ASTReader.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" @@ -1191,6 +1192,55 @@ return DefaultVisibility; } +static void parseMSCVersion(LangOptions &Opts, ArgList &Args, + DiagnosticsEngine &Diags) { + decltype(Opts.MSCVersion) Version = 0; + + if (auto Arg = Args.getLastArg(OPT_fmsc_version)) { + StringRef Value = Arg->getValue(); + + // The MSC versioning scheme involves four versioning components: + // - Major + // - Minor + // - Build + // - Patch + // We accept either the old style (_MSC_VER) value, or a _MSC_FULL_VER + // value. Additionally, the value may be provided in the form of a more + // readable MM.mm.bbbbb.pp version. + // + // Unfortunately, due to the bit-width limitations, we cannot currently + // encode the value for the patch level. + + if (Value.find('.') == StringRef::npos) { + if (Value.getAsInteger(10, Version)) + Diags.Report(diag::err_drv_invalid_value) + << Arg->getAsString(Args) << Value; + } else { + bool Valid = true; + SmallVector Components; + decltype(Opts.MSCVersion) VC[4] = {0}; // MM.mm.bbbbb.pp + + Value.split(Components, ".", llvm::array_lengthof(VC)); + for (unsigned CI = 0, + CE = std::min(Components.size(), llvm::array_lengthof(VC)); + CI < CE; ++CI) { + if (Components[CI].getAsInteger(10, VC[CI])) { + Diags.Report(diag::err_drv_invalid_value) + << Arg->getAsString(Args) << Value; + Valid = false; + break; + } + } + + // FIXME we cannot encode the patch level + if (Valid) + Version = VC[0] * 10000000 + VC[1] * 100000 + VC[2]; + } + } + + Opts.MSCVersion = (Version < 100000) ? Version * 100000 : Version; +} + static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { // FIXME: Cleanup per-file based stuff. @@ -1360,7 +1410,7 @@ Opts.MSVCCompat = Args.hasArg(OPT_fms_compatibility); Opts.MicrosoftExt = Opts.MSVCCompat || Args.hasArg(OPT_fms_extensions); Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt; - Opts.MSCVersion = getLastArgIntValue(Args, OPT_fmsc_version, 0, Diags); + parseMSCVersion(Opts, Args, Diags); Opts.VtorDispMode = getLastArgIntValue(Args, OPT_vtordisp_mode_EQ, 1, Diags); Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); Index: test/Driver/msc-version.c =================================================================== --- /dev/null +++ test/Driver/msc-version.c @@ -0,0 +1,36 @@ +// RUN: %clang -target i686-windows -fms-compatibility -dM -E -