[driver][darwin] Take the OS version specified in "-target" as the target
OS instead of inferring it from SDK / environment

The OS version is specified in -target should be used instead of the one in an
environment variable / SDK name.

rdar://35813850

Differential Revision: https://reviews.llvm.org/D40998

llvm-svn: 321099
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 28efa86..2114c28 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1233,6 +1233,10 @@
     llvm_unreachable("Unsupported Darwin Source Kind");
   }
 
+  static DarwinPlatform createFromTarget(llvm::Triple::OSType OS,
+                                         StringRef OSVersion, Arg *A) {
+    return DarwinPlatform(TargetArg, getPlatformFromOS(OS), OSVersion, A);
+  }
   static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform,
                                            Arg *A) {
     return DarwinPlatform(OSVersionArg, Platform, A);
@@ -1250,32 +1254,31 @@
   }
   static DarwinPlatform createFromArch(llvm::Triple::OSType OS,
                                        StringRef Value) {
-    DarwinPlatformKind Platform;
-    switch (OS) {
-    case llvm::Triple::Darwin:
-    case llvm::Triple::MacOSX:
-      Platform = DarwinPlatformKind::MacOS;
-      break;
-    case llvm::Triple::IOS:
-      Platform = DarwinPlatformKind::IPhoneOS;
-      break;
-    case llvm::Triple::TvOS:
-      Platform = DarwinPlatformKind::TvOS;
-      break;
-    case llvm::Triple::WatchOS:
-      Platform = DarwinPlatformKind::WatchOS;
-      break;
-    default:
-      llvm_unreachable("Unable to infer Darwin variant");
-    }
-    return DarwinPlatform(InferredFromArch, Platform, Value);
+    return DarwinPlatform(InferredFromArch, getPlatformFromOS(OS), Value);
   }
 
 private:
   DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, Arg *Argument)
       : Kind(Kind), Platform(Platform), Argument(Argument) {}
-  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, StringRef Value)
-      : Kind(Kind), Platform(Platform), OSVersion(Value), Argument(nullptr) {}
+  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, StringRef Value,
+                 Arg *Argument = nullptr)
+      : Kind(Kind), Platform(Platform), OSVersion(Value), Argument(Argument) {}
+
+  static DarwinPlatformKind getPlatformFromOS(llvm::Triple::OSType OS) {
+    switch (OS) {
+    case llvm::Triple::Darwin:
+    case llvm::Triple::MacOSX:
+      return DarwinPlatformKind::MacOS;
+    case llvm::Triple::IOS:
+      return DarwinPlatformKind::IPhoneOS;
+    case llvm::Triple::TvOS:
+      return DarwinPlatformKind::TvOS;
+    case llvm::Triple::WatchOS:
+      return DarwinPlatformKind::WatchOS;
+    default:
+      llvm_unreachable("Unable to infer Darwin variant");
+    }
+  }
 
   SourceKind Kind;
   DarwinPlatformKind Platform;
@@ -1449,20 +1452,15 @@
                               const Driver &TheDriver) {
   llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS;
 
-  // Set the OSTy based on -target if -arch isn't present.
-  if (Args.hasArg(options::OPT_target) && !Args.hasArg(options::OPT_arch)) {
-    OSTy = Triple.getOS();
-  } else {
-    StringRef MachOArchName = Toolchain.getMachOArchName(Args);
-    if (MachOArchName == "armv7" || MachOArchName == "armv7s" ||
-        MachOArchName == "arm64")
-      OSTy = llvm::Triple::IOS;
-    else if (MachOArchName == "armv7k")
-      OSTy = llvm::Triple::WatchOS;
-    else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
-             MachOArchName != "armv7em")
-      OSTy = llvm::Triple::MacOSX;
-  }
+  StringRef MachOArchName = Toolchain.getMachOArchName(Args);
+  if (MachOArchName == "armv7" || MachOArchName == "armv7s" ||
+      MachOArchName == "arm64")
+    OSTy = llvm::Triple::IOS;
+  else if (MachOArchName == "armv7k")
+    OSTy = llvm::Triple::WatchOS;
+  else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
+           MachOArchName != "armv7em")
+    OSTy = llvm::Triple::MacOSX;
 
   if (OSTy == llvm::Triple::UnknownOS)
     return None;
@@ -1470,6 +1468,19 @@
                                         getOSVersion(OSTy, Triple, TheDriver));
 }
 
+/// Returns the deployment target that's specified using the -target option.
+Optional<DarwinPlatform> getDeploymentTargetFromTargetArg(
+    DerivedArgList &Args, const llvm::Triple &Triple, const Driver &TheDriver) {
+  if (!Args.hasArg(options::OPT_target))
+    return None;
+  if (Triple.getOS() == llvm::Triple::Darwin ||
+      Triple.getOS() == llvm::Triple::UnknownOS)
+    return None;
+  std::string OSVersion = getOSVersion(Triple.getOS(), Triple, TheDriver);
+  return DarwinPlatform::createFromTarget(Triple.getOS(), OSVersion,
+                                          Args.getLastArg(options::OPT_target));
+}
+
 } // namespace
 
 void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
@@ -1494,24 +1505,35 @@
     }
   }
 
-  // The OS target can be specified using the -m<os>version-min argument.
+  // The OS and the version can be specified using the -target argument.
   Optional<DarwinPlatform> OSTarget =
-      getDeploymentTargetFromOSVersionArg(Args, getDriver());
-  // If no deployment target was specified on the command line, check for
-  // environment defines.
-  if (!OSTarget)
-    OSTarget =
-        getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple());
-  // If there is no command-line argument to specify the Target version and
-  // no environment variable defined, see if we can set the default based
-  // on -isysroot.
-  if (!OSTarget)
-    OSTarget = inferDeploymentTargetFromSDK(Args);
-  // If no OS targets have been specified, try to guess platform from -target
-  // or arch name and compute the version from the triple.
-  if (!OSTarget)
-    OSTarget =
-        inferDeploymentTargetFromArch(Args, *this, getTriple(), getDriver());
+      getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver());
+  if (OSTarget) {
+    // Warn about superfluous -m<os>-version-min arg.
+    Optional<DarwinPlatform> OSVersionArgTarget =
+        getDeploymentTargetFromOSVersionArg(Args, getDriver());
+    if (OSVersionArgTarget)
+      getDriver().Diag(clang::diag::warn_drv_unused_argument)
+          << OSVersionArgTarget->getAsString(Args, Opts);
+  } else {
+    // The OS target can be specified using the -m<os>version-min argument.
+    OSTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver());
+    // If no deployment target was specified on the command line, check for
+    // environment defines.
+    if (!OSTarget)
+      OSTarget =
+          getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple());
+    // If there is no command-line argument to specify the Target version and
+    // no environment variable defined, see if we can set the default based
+    // on -isysroot.
+    if (!OSTarget)
+      OSTarget = inferDeploymentTargetFromSDK(Args);
+    // If no OS targets have been specified, try to guess platform from -target
+    // or arch name and compute the version from the triple.
+    if (!OSTarget)
+      OSTarget =
+          inferDeploymentTargetFromArch(Args, *this, getTriple(), getDriver());
+  }
 
   assert(OSTarget && "Unable to infer Darwin variant");
   OSTarget->addOSVersionMinArgument(Args, Opts);