Change the driver's logic about Objective-C runtimes:  abstract out a
structure to hold inferred information, then propagate each invididual
bit down to -cc1.  Separate the bits of "supports weak" and "has a native
ARC runtime";  make the latter a CodeGenOption.

The tool chain is still driving this decision, because it's the place that
has the required deployment target information on Darwin, but at least it's
better-factored now.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134453 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index 7f34796..0678a25 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -189,7 +189,7 @@
   CInvok->getDiagnosticOpts().ErrorLimit = 0;
   CInvok->getDiagnosticOpts().Warnings.push_back(
                                             "error=arc-unsafe-retained-assign");
-  CInvok->getLangOpts().ObjCNoAutoRefCountRuntime = !HasARCRuntime(origCI);
+  CInvok->getLangOpts().ObjCRuntimeHasWeak = HasARCRuntime(origCI);
 
   return CInvok.take();
 }
diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp
index ba55627..97695cb 100644
--- a/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -98,12 +98,12 @@
         BlocksAttr *attr = var->getAttr<BlocksAttr>();
         if(!attr)
           continue;
-        bool hasARCRuntime = !Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime;
+        bool hasWeak = Pass.Ctx.getLangOptions().ObjCRuntimeHasWeak;
         SourceManager &SM = Pass.Ctx.getSourceManager();
         Transaction Trans(Pass.TA);
         Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()),
                             "__block",
-                            hasARCRuntime ? "__weak" : "__unsafe_unretained");
+                            hasWeak ? "__weak" : "__unsafe_unretained");
       }
 
     }
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index e0009ac..0efc4c0 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -112,7 +112,7 @@
   }
 
   void applyWeak(PropData &prop) {
-    assert(!Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime);
+    assert(Pass.Ctx.getLangOptions().ObjCRuntimeHasWeak);
 
     Transaction Trans(Pass.TA);
     Pass.TA.insert(prop.IvarD->getLocation(), "__weak "); 
@@ -157,7 +157,7 @@
     // There is a "error: existing ivar for assign property must be
     // __unsafe_unretained"; fix it.
 
-    if (Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime) {
+    if (!Pass.Ctx.getLangOptions().ObjCRuntimeHasWeak) {
       // We will just add __unsafe_unretained to the ivar.
       Transaction Trans(Pass.TA);
       Pass.TA.insert(ivarD->getLocation(), "__unsafe_unretained ");
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index db9873b..d8ce1f4 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -1311,7 +1311,7 @@
 
   // In -fobjc-no-arc-runtime, emit weak references to the runtime
   // support library.
-  if (CGM.getLangOptions().ObjCNoAutoRefCountRuntime)
+  if (!CGM.getCodeGenOpts().ObjCRuntimeHasARC)
     if (llvm::Function *f = dyn_cast<llvm::Function>(fn))
       f->setLinkage(llvm::Function::ExternalWeakLinkage);
 
@@ -2457,13 +2457,7 @@
 
   // Keep track of the current cleanup stack depth.
   RunCleanupsScope Scope(*this);
-  const llvm::Triple Triple = getContext().Target.getTriple();
-  if (CGM.getLangOptions().ObjCAutoRefCount ||
-      (CGM.isTargetDarwin() && 
-       ((Triple.getArch() == llvm::Triple::x86_64 && 
-         !Triple.isMacOSXVersionLT(10,7,0))
-        || (Triple.getEnvironmentName() == "iphoneos" && 
-            !Triple.isOSVersionLT(5,0))))) {
+  if (CGM.getCodeGenOpts().ObjCRuntimeHasARC) {
     llvm::Value *token = EmitObjCAutoreleasePoolPush();
     EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token);
   } else {
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 2657faa..e15e402 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -13,6 +13,7 @@
 #include "clang/Driver/ArgList.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/ObjCRuntime.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/ToolChain.h"
 
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index cbbbc5c..0cce517 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -15,7 +15,9 @@
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/HostInfo.h"
+#include "clang/Driver/ObjCRuntime.h"
 #include "clang/Driver/Options.h"
+#include "llvm/Support/ErrorHandling.h"
 
 using namespace clang::driver;
 
@@ -47,6 +49,23 @@
   return false;
 }
 
+void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const {
+  switch (runtime.getKind()) {
+  case ObjCRuntime::NeXT:
+    // Assume a minimal NeXT runtime.
+    runtime.HasARC = false;
+    runtime.HasWeak = false;
+    return;
+
+  case ObjCRuntime::GNU:
+    // Assume a maximal GNU runtime.
+    runtime.HasARC = true;
+    runtime.HasWeak = true;
+    return;
+  }
+  llvm_unreachable("invalid runtime kind!");
+}
+
 /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
 //
 // FIXME: tblgen this.
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index b4501ac..68ebc1b 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -19,6 +19,7 @@
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/HostInfo.h"
+#include "clang/Driver/ObjCRuntime.h"
 #include "clang/Driver/OptTable.h"
 #include "clang/Driver/Option.h"
 #include "clang/Driver/Options.h"
@@ -74,8 +75,7 @@
   return true;
 }
 
-/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
-bool Darwin::HasARCRuntime() const {
+bool Darwin::hasARCRuntime() const {
   // FIXME: Remove this once there is a proper way to detect an ARC runtime
   // for the simulator.
   switch (ARCRuntimeForSimulator) {
@@ -93,6 +93,14 @@
     return !isMacosxVersionLT(10, 7);
 }
 
+/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
+void Darwin::configureObjCRuntime(ObjCRuntime &runtime) const {
+  if (runtime.getKind() != ObjCRuntime::NeXT)
+    return ToolChain::configureObjCRuntime(runtime);
+
+  runtime.HasARC = runtime.HasWeak = hasARCRuntime();
+}
+
 // FIXME: Can we tablegen this?
 static const char *GetArmArchForMArch(llvm::StringRef Value) {
   if (Value == "armv6k")
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 9ed0dc2..d68016b 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -80,6 +80,8 @@
   /// initialized.
   std::string MacosxVersionMin;
 
+  bool hasARCRuntime() const;
+
 private:
   void AddDeploymentTarget(DerivedArgList &Args) const;
 
@@ -184,7 +186,7 @@
 
   virtual bool HasNativeLLVMSupport() const;
 
-  virtual bool HasARCRuntime() const;
+  virtual void configureObjCRuntime(ObjCRuntime &runtime) const;
 
   virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
                                         const char *BoundArch) const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 4e70c5c..d0fd914 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -17,6 +17,7 @@
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/Job.h"
 #include "clang/Driver/HostInfo.h"
+#include "clang/Driver/ObjCRuntime.h"
 #include "clang/Driver/Option.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/ToolChain.h"
@@ -1600,47 +1601,6 @@
                     options::OPT_fno_lax_vector_conversions))
     CmdArgs.push_back("-fno-lax-vector-conversions");
 
-  // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
-  // NOTE: This logic is duplicated in ToolChains.cpp.
-  bool ARC = isObjCAutoRefCount(Args);
-  if (ARC) {
-    CmdArgs.push_back("-fobjc-arc");
-
-    // Certain deployment targets don't have runtime support.
-    if (!getToolChain().HasARCRuntime())
-      CmdArgs.push_back("-fobjc-no-arc-runtime");
-
-    // Allow the user to enable full exceptions code emission.
-    // We define off for Objective-CC, on for Objective-C++.
-    if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
-                     options::OPT_fno_objc_arc_exceptions,
-                     /*default*/ types::isCXX(InputType)))
-      CmdArgs.push_back("-fobjc-arc-exceptions");
-  }
-
-  // -fobjc-infer-related-result-type is the default, except in the Objective-C
-  // rewriter.
-  if (IsRewriter)
-    CmdArgs.push_back("-fno-objc-infer-related-result-type");
-  
-  // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
-  // takes precedence.
-  const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
-  if (!GCArg)
-    GCArg = Args.getLastArg(options::OPT_fobjc_gc);
-  if (GCArg) {
-    if (ARC) {
-      D.Diag(clang::diag::err_drv_objc_gc_arr)
-        << GCArg->getAsString(Args);
-    } else if (getToolChain().SupportsObjCGC()) {
-      GCArg->render(Args, CmdArgs);
-    } else {
-      // FIXME: We should move this to a hard error.
-      D.Diag(clang::diag::warn_drv_objc_gc_unsupported)
-        << GCArg->getAsString(Args);
-    }
-  }
-
   if (Args.getLastArg(options::OPT_fapple_kext))
     CmdArgs.push_back("-fapple-kext");
 
@@ -1805,17 +1765,23 @@
                    false))
     CmdArgs.push_back("-fgnu89-inline");
 
-  // -fnext-runtime defaults to on Darwin and when rewriting Objective-C, and is
-  // -the -cc1 default.
-  bool NeXTRuntimeIsDefault =
-    IsRewriter || getToolChain().getTriple().getOS() == llvm::Triple::Darwin;
-  if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
-                    NeXTRuntimeIsDefault))
-    CmdArgs.push_back("-fgnu-runtime");
-
   // -fobjc-nonfragile-abi=0 is default.
+  ObjCRuntime objCRuntime;
   unsigned objcABIVersion = 0;
   if (types::isObjC(InputType)) {
+    bool NeXTRuntimeIsDefault
+      = (IsRewriter || getToolChain().getTriple().isOSDarwin());
+    if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
+                     NeXTRuntimeIsDefault))
+      objCRuntime.setKind(ObjCRuntime::NeXT);
+    else
+      objCRuntime.setKind(ObjCRuntime::GNU);
+    getToolChain().configureObjCRuntime(objCRuntime);
+    if (objCRuntime.HasARC)
+      CmdArgs.push_back("-fobjc-runtime-has-arc");
+    if (objCRuntime.HasWeak)
+      CmdArgs.push_back("-fobjc-runtime-has-weak");
+
     // Compute the Objective-C ABI "version" to use. Version numbers are
     // slightly confusing for historical reasons:
     //   1 - Traditional "fragile" ABI
@@ -1890,6 +1856,43 @@
 #endif
   }
 
+  // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
+  // NOTE: This logic is duplicated in ToolChains.cpp.
+  bool ARC = isObjCAutoRefCount(Args);
+  if (ARC) {
+    CmdArgs.push_back("-fobjc-arc");
+
+    // Allow the user to enable full exceptions code emission.
+    // We define off for Objective-CC, on for Objective-C++.
+    if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
+                     options::OPT_fno_objc_arc_exceptions,
+                     /*default*/ types::isCXX(InputType)))
+      CmdArgs.push_back("-fobjc-arc-exceptions");
+  }
+
+  // -fobjc-infer-related-result-type is the default, except in the Objective-C
+  // rewriter.
+  if (IsRewriter)
+    CmdArgs.push_back("-fno-objc-infer-related-result-type");
+  
+  // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
+  // takes precedence.
+  const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
+  if (!GCArg)
+    GCArg = Args.getLastArg(options::OPT_fobjc_gc);
+  if (GCArg) {
+    if (ARC) {
+      D.Diag(clang::diag::err_drv_objc_gc_arr)
+        << GCArg->getAsString(Args);
+    } else if (getToolChain().SupportsObjCGC()) {
+      GCArg->render(Args, CmdArgs);
+    } else {
+      // FIXME: We should move this to a hard error.
+      D.Diag(clang::diag::warn_drv_objc_gc_unsupported)
+        << GCArg->getAsString(Args);
+    }
+  }
+
   // Add exception args.
   addExceptionArgs(Args, InputType, getToolChain().getTriple(),
                    KernelOrKext, IsRewriter, objcABIVersion, CmdArgs);
@@ -3237,8 +3240,12 @@
   // In ARC, if we don't have runtime support, link in the runtime
   // stubs.  We have to do this *before* adding any of the normal
   // linker inputs so that its initializer gets run first.
-  if (!getDarwinToolChain().HasARCRuntime() && isObjCAutoRefCount(Args))
-    getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
+  if (isObjCAutoRefCount(Args)) {
+    ObjCRuntime runtime;
+    getDarwinToolChain().configureObjCRuntime(runtime);
+    if (!runtime.HasARC)
+      getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
+  }
 
   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
 
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 12e51a6..31c8643 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -123,6 +123,8 @@
     Res.push_back("-dwarf-debug-flags");
     Res.push_back(Opts.DwarfDebugFlags);
   }
+  if (Opts.ObjCRuntimeHasARC)
+    Res.push_back("-fobjc-runtime-has-arc");
   if (Opts.EmitGcovArcs)
     Res.push_back("-femit-coverage-data");
   if (Opts.EmitGcovNotes)
@@ -690,8 +692,8 @@
   }
   if (Opts.ObjCAutoRefCount)
     Res.push_back("-fobjc-arc");
-  if (Opts.ObjCNoAutoRefCountRuntime)
-    Res.push_back("-fobjc-no-arc-runtime");
+  if (Opts.ObjCRuntimeHasWeak)
+    Res.push_back("-fobjc-runtime-has-weak");
   if (!Opts.ObjCInferRelatedResultType)
     Res.push_back("-fno-objc-infer-related-result-type");
   
@@ -976,6 +978,7 @@
 
   Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
   Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
+  Opts.ObjCRuntimeHasARC = Args.hasArg(OPT_fobjc_runtime_has_arc);
   Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
   Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
   Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
@@ -1532,10 +1535,11 @@
       Opts.ObjCAutoRefCount = 1;
       if (!Args.hasArg(OPT_fobjc_nonfragile_abi))
         Diags.Report(diag::err_arc_nonfragile_abi);
-      if (Args.hasArg(OPT_fobjc_no_arc_runtime))
-        Opts.ObjCNoAutoRefCountRuntime = 1;
     }
 
+    if (Args.hasArg(OPT_fobjc_runtime_has_weak))
+      Opts.ObjCRuntimeHasWeak = 1;
+
     if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
       Opts.ObjCInferRelatedResultType = 0;
   }
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index b07fb43..9428cd5 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -250,7 +250,7 @@
         << "}\n"
         << "\n";
       
-    if (!LangOpts.ObjCNoAutoRefCountRuntime) {
+    if (LangOpts.ObjCRuntimeHasWeak) {
       Out << "template <class _Tp>\n"
           << "inline __attribute__ ((__visibility__(\"hidden\"),"
           << "__always_inline__))\n"
@@ -318,7 +318,7 @@
         << "};\n"
         << "\n";
       
-    if (!LangOpts.ObjCNoAutoRefCountRuntime) {
+    if (LangOpts.ObjCRuntimeHasWeak) {
       Out << "template<typename _Tp>\n"
           << "struct __is_scalar<__attribute__((objc_ownership(weak))) _Tp> {\n"
           << "  enum { __value = 0 };\n"
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index d7c4def..f1d0371 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -596,7 +596,7 @@
            .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
            .Case("objc_arc", LangOpts.ObjCAutoRefCount)
            .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount && 
-                 !LangOpts.ObjCNoAutoRefCountRuntime)
+                 LangOpts.ObjCRuntimeHasWeak)
            .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
            .Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
            .Case("ownership_holds", true)
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 012e256..b47d627 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -592,7 +592,7 @@
           PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
         }
         else if (kind & ObjCPropertyDecl::OBJC_PR_weak) {
-          if (getLangOptions().ObjCNoAutoRefCountRuntime) {
+          if (!getLangOptions().ObjCRuntimeHasWeak) {
             Diag(PropertyLoc, diag::err_arc_weak_no_runtime);
             Diag(property->getLocation(), diag::note_property_declare);
           }
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 3f211da..1418422 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -3191,9 +3191,9 @@
     type = S.Context.getAttributedType(AttributedType::attr_objc_ownership,
                                        origType, type);
 
-  // Forbid __weak if we don't have a runtime.
+  // Forbid __weak if the runtime doesn't support it.
   if (lifetime == Qualifiers::OCL_Weak &&
-      S.getLangOptions().ObjCNoAutoRefCountRuntime) {
+      !S.getLangOptions().ObjCRuntimeHasWeak) {
 
     // Actually, delay this until we know what we're parsing.
     if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {