Merge pull request #12632 from DougGregor/suppress-eager-init-nscoding-availability-4.0

Suppress inference of @_staticInitializeObjCMetadata for "newer" classes
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 88c5771..2c0b9e4 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -6059,7 +6059,8 @@
 
 /// Infer the attribute tostatic-initialize the Objective-C metadata for the
 /// given class, if needed.
-static void inferStaticInitializeObjCMetadata(ClassDecl *classDecl) {
+static void inferStaticInitializeObjCMetadata(TypeChecker &tc,
+                                              ClassDecl *classDecl) {
   // If we already have the attribute, there's nothing to do.
   if (classDecl->getAttrs().hasAttribute<StaticInitializeObjCMetadataAttr>())
     return;
@@ -6071,6 +6072,22 @@
     return;
   }
 
+  // If this class isn't always available on the deployment target, don't
+  // mark it as statically initialized.
+  // FIXME: This is a workaround. The proper solution is for IRGen to
+  // only statically initializae the Objective-C metadata when running on
+  // a new-enough OS.
+  if (auto sourceFile = classDecl->getParentSourceFile()) {
+    AvailabilityContext availableInfo = AvailabilityContext::alwaysAvailable();
+    for (Decl *enclosingDecl = classDecl; enclosingDecl;
+         enclosingDecl = enclosingDecl->getDeclContext()
+                           ->getInnermostDeclarationDeclContext()) {
+      if (!tc.isDeclAvailable(enclosingDecl, SourceLoc(), sourceFile,
+                              availableInfo))
+        return;
+    }
+  }
+
   // Infer @_staticInitializeObjCMetadata.
   ASTContext &ctx = classDecl->getASTContext();
   classDecl->getAttrs().add(
@@ -6188,7 +6205,7 @@
         }
 
         // Infer @_staticInitializeObjCMetadata if needed.
-        inferStaticInitializeObjCMetadata(classDecl);
+        inferStaticInitializeObjCMetadata(*this, classDecl);
       }
     }
   }
diff --git a/test/decl/protocol/conforms/nscoding_availability_osx.swift b/test/decl/protocol/conforms/nscoding_availability_osx.swift
new file mode 100644
index 0000000..b9720cd
--- /dev/null
+++ b/test/decl/protocol/conforms/nscoding_availability_osx.swift
@@ -0,0 +1,22 @@
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -swift-version 4 %s -target x86_64-apple-macosx10.11 -verify
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -swift-version 4 %s -target x86_64-apple-macosx10.11 -dump-ast 2> %t.ast
+// RUN: %FileCheck %s < %t.ast
+
+// REQUIRES: objc_interop
+// REQUIRES: OS=macosx
+
+import Foundation
+
+// Nested classes that aren't available in our deployment target.
+@available(OSX 10.12, *)
+class CodingI : NSObject, NSCoding {
+  required init(coder: NSCoder) { }
+  func encode(coder: NSCoder) { }
+}
+
+@available(OSX 10.12, *)
+class OuterCodingJ {
+  // CHECK-NOT: class_decl "NestedJ"{{.*}}@_staticInitializeObjCMetadata
+  class NestedJ : CodingI { }
+}