Merge pull request #8554 from palimondo/CheckResultsWithConditionalMessage

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2ce6f8f..3939944 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,48 @@
 Swift 4.0
 ---------
 
+* [SE-0138](https://github.com/apple/swift-evolution/blob/master/proposals/0138-unsaferawbufferpointer.md#amendment-to-normalize-the-slice-type):
+
+  Slicing a raw buffer no longer results in the same raw buffer
+  type. Specifically, `Unsafe[Mutable]BufferPointer.SubSequence` now has type
+  `[Mutable]RandomAccessSlice<Unsafe[Mutable]RawBufferPointer>`. Therefore,
+  indexing into a raw buffer slice is no longer zero-based. This is required for
+  raw buffers to fully conform to generic `Collection`. Changing the slice type
+  resulted in the following behavioral changes:
+
+  Passing a region within buffer to another function that takes a buffer can no
+  longer be done via subscript:
+
+  Incorrect: `takesRawBuffer(buffer[i..<j])`
+
+  This now requires explicit initialization, using a `rebasing:` initializer,
+  which converts from a slice to a zero-based `Unsafe[Mutable]RawBufferPointer`:
+
+  Correct: `takesRawBuffer(UnsafeRawBufferPointer(rebasing: buffer[i..<j]))`
+
+  Subscript assignment directly from a buffer no longer compiles:
+
+  Incorrect: `buffer[n..<m] = smaller_buffer`
+
+  This now requires creation of a slice from the complete source buffer:
+
+  Correct: `buffer[n..<m] = smaller_buffer.suffix(from: 0)`
+
+  `UnsafeRawBufferPointer`'s slice type no longer has a nonmutating subscript
+  setter. So assigning into a mutable `let` buffer no longer compiles:
+
+  ```
+  let slice = buffer[n..<m]
+  slice[i..<j] = buffer[k..<l]
+  ```
+
+  The assigned buffer slice now needs to be a `var`.
+
+  ```
+  var slice = buffer[n..<m]
+  slice[i..<j] = buffer[k..<l]
+  ```
+
 * [SR-1529](https://bugs.swift.org/browse/SR-1529):
 
   Covariant method overrides are now fully supported, fixing many crashes
@@ -46,7 +88,8 @@
 
     // 'where' becomes a superclass
     override func sleep(where: Bed) {}
-  }```
+  }
+  ```
 
 * [SE-0148][]:
 
diff --git a/apinotes/CMakeLists.txt b/apinotes/CMakeLists.txt
index 002f55c..5fe73a7 100644
--- a/apinotes/CMakeLists.txt
+++ b/apinotes/CMakeLists.txt
@@ -38,6 +38,7 @@
   QuickLook
   SafariServices
   SceneKit
+  ScriptingBridge
   SpriteKit
   StoreKit
   TVMLKit
diff --git a/apinotes/Foundation.apinotes b/apinotes/Foundation.apinotes
index 75c9e50..0c475fd 100644
--- a/apinotes/Foundation.apinotes
+++ b/apinotes/Foundation.apinotes
@@ -5,6 +5,7 @@
   SwiftBridge: AffineTransform
 - Name: NSArray
   SwiftBridge: Swift.Array
+  SwiftImportAsNonGeneric: true
   Methods:
   - Selector: 'pathsMatchingExtensions:'
     SwiftName: pathsMatchingExtensions(_:)
@@ -12,6 +13,15 @@
   - Selector: 'filteredArrayUsingPredicate:'
     SwiftName: filtered(using:)
     MethodKind: Instance
+- Name: NSMutableArray
+  SwiftImportAsNonGeneric: true
+  Methods:
+  - Selector: 'removeObjectIdenticalTo:inRange:'
+    SwiftName: removeObject(identicalTo:in:)
+    MethodKind: Instance
+  - Selector: 'removeObjectIdenticalTo:'
+    SwiftName: removeObject(identicalTo:)
+    MethodKind: Instance
 - Name: NSCachedURLResponse
   SwiftName: CachedURLResponse
 - Name: NSCharacterSet
@@ -51,6 +61,8 @@
   - Selector: 'hasMemberInPlane:'
     SwiftName: hasMemberInPlane(_:)
     MethodKind: Instance
+- Name: NSCountedSet
+  SwiftImportAsNonGeneric: true
 - Name: NSData
   SwiftBridge: Data
   Methods:
@@ -85,6 +97,8 @@
   SwiftBridge: DateComponents
 - Name: NSDateInterval
   SwiftBridge: DateInterval
+- Name: NSEnumerator
+  SwiftImportAsNonGeneric: true
 - Name: NSError
   SwiftBridge: Swift.Error
   Methods:
@@ -93,12 +107,18 @@
     MethodKind: Class
 - Name: NSDictionary
   SwiftBridge: Swift.Dictionary
+  SwiftImportAsNonGeneric: true
+- Name: NSMutableDictionary
+  SwiftImportAsNonGeneric: true
 - Name: NSSet
   SwiftBridge: Swift.Set
+  SwiftImportAsNonGeneric: true
   Methods:
   - Selector: 'filteredSetUsingPredicate:'
     SwiftName: filtered(using:)
     MethodKind: Instance
+- Name: NSMutableSet
+  SwiftImportAsNonGeneric: true
 - Name: NSString
   SwiftBridge: Swift.String
   Methods:
@@ -313,14 +333,7 @@
     MethodKind: Instance
 - Name: NSMeasurement
   SwiftBridge: Measurement
-- Name: NSMutableArray
-  Methods:
-  - Selector: 'removeObjectIdenticalTo:inRange:'
-    SwiftName: removeObject(identicalTo:in:)
-    MethodKind: Instance
-  - Selector: 'removeObjectIdenticalTo:'
-    SwiftName: removeObject(identicalTo:)
-    MethodKind: Instance
+  SwiftImportAsNonGeneric: true
 - Name: NSMutableData
   Methods:
   - Selector: 'appendBytes:length:'
@@ -445,6 +458,7 @@
   - Name: unsignedIntegerValue
     SwiftName: uintValue
 - Name: NSOrderedSet
+  SwiftImportAsNonGeneric: true
   Methods:
   - Selector: 'enumerateObjectsWithOptions:usingBlock:'
     SwiftName: enumerateObjects(options:using:)
@@ -470,6 +484,8 @@
   - Selector: 'indexOfObjectWithOptions:passingTest:'
     SwiftName: index(_:ofObjectPassingTest:)
     MethodKind: Instance
+- Name: NSMutableOrderedSet
+  SwiftImportAsNonGeneric: true
 - Name: NSTask
   SwiftName: Process
   Methods:
@@ -932,6 +948,7 @@
   SwiftName: ValueTransformer
 - Name: NSDirectoryEnumerator
   SwiftName: FileManager.DirectoryEnumerator
+  SwiftImportAsNonGeneric: true
 - Name: NSDimension
   SwiftName: Dimension
 - Name: NSUnit
diff --git a/apinotes/ScriptingBridge.apinotes b/apinotes/ScriptingBridge.apinotes
new file mode 100644
index 0000000..a02ce24
--- /dev/null
+++ b/apinotes/ScriptingBridge.apinotes
@@ -0,0 +1,5 @@
+---
+Name: ScriptingBridge
+Classes:
+- Name: SBElementArray
+  SwiftImportAsNonGeneric: true
diff --git a/apinotes/XCTest.apinotes b/apinotes/XCTest.apinotes
index ae19634..1332195 100644
--- a/apinotes/XCTest.apinotes
+++ b/apinotes/XCTest.apinotes
@@ -18,6 +18,7 @@
     MethodKind: Instance
     SwiftName: 'matching(identifier:)'
 - Name: XCTestCase
+  SwiftObjCMembers: true
   Methods:
   - Selector: 'waitForExpectationsWithTimeout:handler:'
     MethodKind: Instance
diff --git a/benchmark/single-source/DictTest.swift b/benchmark/single-source/DictTest.swift
index 52f9734..d93bb6f 100644
--- a/benchmark/single-source/DictTest.swift
+++ b/benchmark/single-source/DictTest.swift
@@ -157,7 +157,7 @@
     return value.hashValue
   }
 
-  static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
+  static func ==(lhs: Box, rhs: Box) -> Bool {
     return lhs.value == rhs.value
   }
 }
diff --git a/benchmark/single-source/DictTest2.swift b/benchmark/single-source/DictTest2.swift
index 98bfc5f..f5b2273 100644
--- a/benchmark/single-source/DictTest2.swift
+++ b/benchmark/single-source/DictTest2.swift
@@ -37,7 +37,7 @@
   CheckResults(res == ref_result, "Incorrect results in Dictionary2: \(res) != \(ref_result)")
 }
 
-class Box<T : Hashable> : Hashable where T : Equatable {
+class Box<T : Hashable> : Hashable {
   var value: T
 
   init(_ v: T) {
@@ -48,7 +48,7 @@
     return value.hashValue
   }
 
-  static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
+  static func ==(lhs: Box, rhs: Box) -> Bool {
     return lhs.value == rhs.value
   }
 }
diff --git a/benchmark/single-source/DictTest3.swift b/benchmark/single-source/DictTest3.swift
index ac2feb9..0ecbb80 100644
--- a/benchmark/single-source/DictTest3.swift
+++ b/benchmark/single-source/DictTest3.swift
@@ -54,13 +54,10 @@
   var hashValue: Int {
     return value.hashValue
   }
-}
-
-extension Box : Equatable {
-}
-
-func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
-  return lhs.value == rhs.value
+  
+  static func ==(lhs: Box, rhs: Box) -> Bool {
+    return lhs.value == rhs.value
+  }
 }
 
 @inline(never)
diff --git a/benchmark/single-source/DictionaryRemove.swift b/benchmark/single-source/DictionaryRemove.swift
index 044fb32..a35df73 100644
--- a/benchmark/single-source/DictionaryRemove.swift
+++ b/benchmark/single-source/DictionaryRemove.swift
@@ -53,7 +53,7 @@
     return value.hashValue
   }
 
-  static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
+  static func ==(lhs: Box, rhs: Box) -> Bool {
     return lhs.value == rhs.value
   }
 }
diff --git a/benchmark/single-source/DictionarySwap.swift b/benchmark/single-source/DictionarySwap.swift
index 7ab3edf..5072368 100644
--- a/benchmark/single-source/DictionarySwap.swift
+++ b/benchmark/single-source/DictionarySwap.swift
@@ -56,7 +56,7 @@
     return value.hashValue
   }
 
-  static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
+  static func ==(lhs: Box, rhs: Box) -> Bool {
     return lhs.value == rhs.value
   }
 }
diff --git a/benchmark/single-source/RGBHistogram.swift b/benchmark/single-source/RGBHistogram.swift
index 52a6c83..d0957f6 100644
--- a/benchmark/single-source/RGBHistogram.swift
+++ b/benchmark/single-source/RGBHistogram.swift
@@ -124,7 +124,7 @@
     return value.hashValue
   }
 
-  static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
+  static func ==(lhs: Box, rhs: Box) -> Bool {
     return lhs.value == rhs.value
   }
 }
diff --git a/benchmark/single-source/SetTests.swift b/benchmark/single-source/SetTests.swift
index b5521f3..7db9eb8 100644
--- a/benchmark/single-source/SetTests.swift
+++ b/benchmark/single-source/SetTests.swift
@@ -115,7 +115,7 @@
     return value.hashValue
   }
 
-  static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
+  static func ==(lhs: Box, rhs: Box) -> Bool {
     return lhs.value == rhs.value
   }
 }
diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index 9357225..805bffc 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -265,6 +265,10 @@
         "-I${SWIFT_ANDROID_NDK_PATH}/sources/android/support/include")
   endif()
 
+  if(SWIFT_RUNTIME_ENABLE_COW_EXISTENTIALS)
+    list(APPEND result "-DSWIFT_RUNTIME_ENABLE_COW_EXISTENTIALS=1")
+  endif()
+
   set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE)
 endfunction()
 
@@ -1544,6 +1548,11 @@
           endif()
         endif()
 
+        # Add PrivateFrameworks, rdar://28466433
+        if(SWIFTLIB_IS_SDK_OVERLAY)
+          list(APPEND swiftlib_swift_compile_flags_all "-Fsystem" "${SWIFT_SDK_${sdk}_PATH}/System/Library/PrivateFrameworks/")
+        endif()
+
         # Add this library variant.
         _add_swift_library_single(
           ${VARIANT_NAME}
diff --git a/cmake/modules/SwiftHandleGybSources.cmake b/cmake/modules/SwiftHandleGybSources.cmake
index 9941f3a..116bc8d 100644
--- a/cmake/modules/SwiftHandleGybSources.cmake
+++ b/cmake/modules/SwiftHandleGybSources.cmake
@@ -46,6 +46,17 @@
 
   get_filename_component(dir "${GYB_SINGLE_OUTPUT}" DIRECTORY)
   get_filename_component(basename "${GYB_SINGLE_OUTPUT}" NAME)
+
+  # Handle foo.gyb in pattern ``gyb.expand('foo.gyb'`` as a dependency
+  set(gyb_expand_deps "")
+  file(READ "${GYB_SINGLE_SOURCE}" gyb_file)
+  string(REGEX MATCHALL "\\\$\{[\r\n\t ]*gyb.expand\\\([\r\n\t ]*[\'\"]([^\'\"]*)[\'\"]" gyb_expand_matches "${gyb_file}")
+  foreach(match ${gyb_expand_matches})
+    string(REGEX MATCH "[\'\"]\([^\'\"]*\)[\'\"]" gyb_dep "${match}")
+    list(APPEND gyb_expand_deps "${CMAKE_MATCH_1}")
+  endforeach()
+  list(REMOVE_DUPLICATES gyb_expand_deps)
+
   add_custom_command_target(
       dependency_target
       COMMAND
@@ -59,7 +70,7 @@
       COMMAND
           "${CMAKE_COMMAND}" -E remove "${GYB_SINGLE_OUTPUT}.tmp"
       OUTPUT "${GYB_SINGLE_OUTPUT}"
-      DEPENDS "${gyb_tool_source}" "${GYB_SINGLE_DEPENDS}" "${GYB_SINGLE_SOURCE}"
+      DEPENDS "${gyb_tool_source}" "${GYB_SINGLE_DEPENDS}" "${GYB_SINGLE_SOURCE}" "${gyb_expand_deps}"
       COMMENT "Generating ${basename} from ${GYB_SINGLE_SOURCE} ${GYB_SINGLE_COMMENT}"
       WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
       SOURCES "${GYB_SINGLE_SOURCE}"
diff --git a/cmake/modules/SwiftSource.cmake b/cmake/modules/SwiftSource.cmake
index 8548fbc..f5f9c9f 100644
--- a/cmake/modules/SwiftSource.cmake
+++ b/cmake/modules/SwiftSource.cmake
@@ -272,6 +272,10 @@
     list(APPEND swift_flags "-autolink-force-load")
   endif()
 
+  if (SWIFTFILE_IS_STDLIB_CORE OR SWIFTFILE_IS_SDK_OVERLAY)
+    list(APPEND swift_flags "-warn-swift3-objc-inference")
+  endif()
+
   list(APPEND swift_flags ${SWIFT_EXPERIMENTAL_EXTRA_FLAGS})
 
   if(SWIFTFILE_OPT_FLAGS)
diff --git a/docs/Android.md b/docs/Android.md
index c024088..b9fb5c9 100644
--- a/docs/Android.md
+++ b/docs/Android.md
@@ -118,7 +118,7 @@
     -target armv7-none-linux-androideabi \                                       # Targeting android-armv7.
     -sdk /path/to/android-ndk-r14/platforms/android-21/arch-arm \                # Use the same NDK path and API version as you used to build the stdlib in the previous step.
     -L /path/to/android-ndk-r14/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a \   # Link the Android NDK's libc++ and libgcc.
-    -L /path/to/android-ndk-r14/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9 \
+    -L /path/to/android-ndk-r14/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x \
     hello.swift
 ```
 
diff --git a/docs/GenericsManifesto.md b/docs/GenericsManifesto.md
index 1b7aabd..4db5bee 100644
--- a/docs/GenericsManifesto.md
+++ b/docs/GenericsManifesto.md
@@ -511,13 +511,13 @@
 }
 
 extension P {
-  func foo() { print("P.foo()")
-  func bar() { print("P.bar()")
+  func foo() { print("P.foo()") }
+  func bar() { print("P.bar()") }
 }
 
 struct X : P {
-  func foo() { print("X.foo()")
-  func bar() { print("X.bar()")
+  func foo() { print("X.foo()") }
+  func bar() { print("X.bar()") }
 }
 
 let x = X()
diff --git a/docs/HighLevelSILOptimizations.rst b/docs/HighLevelSILOptimizations.rst
index 3178b4c..54e538f 100644
--- a/docs/HighLevelSILOptimizations.rst
+++ b/docs/HighLevelSILOptimizations.rst
@@ -207,6 +207,18 @@
   Read the array capacity from the storage descriptor. The semantics
   are identical to ``get_count`` except for the meaning of the return value.
 
+array.append_element(newElement: Element)
+
+  Appends a single element to the array. No elements are read.
+  The operation is itself guarded by ``make_mutable``.
+  In contrast to other semantics operations, this operation is allowed to be
+  inlined in the early stages of the compiler.
+
+array.append_contentsOf(contentsOf newElements: S)
+
+  Appends all elements from S, which is a Sequence. No elements are read.
+  The operation is itself guarded by ``make_mutable``.
+
 array.make_mutable()
 
   This operation guards mutating operations that don't already imply
diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h
index bde650b..2b3b9b1 100644
--- a/include/swift/AST/ASTContext.h
+++ b/include/swift/AST/ASTContext.h
@@ -450,7 +450,10 @@
 
   /// Retrieve the declaration of Swift.==(Int, Int) -> Bool.
   FuncDecl *getEqualIntDecl() const;
-  
+
+  /// Retrieve the declaration of Array.append(element:)
+  FuncDecl *getArrayAppendElementDecl() const;
+
   /// Retrieve the declaration of Swift._unimplementedInitializer.
   FuncDecl *getUnimplementedInitializerDecl(LazyResolver *resolver) const;
 
diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def
index 5b4e156..0a7b396 100644
--- a/include/swift/AST/Attr.def
+++ b/include/swift/AST/Attr.def
@@ -92,7 +92,7 @@
                  OnClass | OnFunc | OnVar | OnSubscript|DeclModifier, 2)
 
 DECL_ATTR(objc, ObjC,
-          OnFunc | OnClass | OnProtocol | OnVar | OnSubscript |
+          OnFunc | OnClass | OnProtocol | OnExtension | OnVar | OnSubscript |
           OnConstructor | OnDestructor | OnEnum | OnEnumElement, 3)
 
 SIMPLE_DECL_ATTR(required, Required,
@@ -158,7 +158,7 @@
 SIMPLE_DECL_ATTR(noescape, NoEscape, OnParam, 29)
 
 SIMPLE_DECL_ATTR(nonobjc, NonObjC,
-                 OnFunc | OnVar | OnSubscript | OnConstructor, 30)
+                 OnExtension | OnFunc | OnVar | OnSubscript | OnConstructor, 30)
 
 SIMPLE_DECL_ATTR(_fixed_layout, FixedLayout,
                  OnVar | OnClass | OnStruct | OnEnum | UserInaccessible, 31)
@@ -171,6 +171,8 @@
           OnConstructor | OnFunc | AllowMultipleAttributes | LongAttribute
           | UserInaccessible, 33)
 
+SIMPLE_DECL_ATTR(objcMembers, ObjCMembers, OnClass, 34)
+
 // Non-serialized attributes.
 
 SIMPLE_DECL_ATTR(mutating, Mutating, OnFunc | DeclModifier | NotSerialized,
diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h
index a2146ac..6b44d35 100644
--- a/include/swift/AST/Attr.h
+++ b/include/swift/AST/Attr.h
@@ -197,8 +197,12 @@
 
     /// Whether the name is implicit, produced as the result of caching.
     unsigned ImplicitName : 1;
+
+    /// Whether the @objc was inferred using Swift 3's deprecated inference
+    /// rules.
+    unsigned Swift3Inferred : 1;
   };
-  enum { NumObjCAttrBits = NumDeclAttrBits + 2 };
+  enum { NumObjCAttrBits = NumDeclAttrBits + 3 };
   static_assert(NumObjCAttrBits <= 32, "fits in an unsigned");
 
   class AccessibilityAttrBitFields {
@@ -716,6 +720,7 @@
   {
     ObjCAttrBits.HasTrailingLocationInfo = false;
     ObjCAttrBits.ImplicitName = implicitName;
+    ObjCAttrBits.Swift3Inferred = false;
 
     if (name) {
       NameData = name->getOpaqueValue();
@@ -823,6 +828,18 @@
     ObjCAttrBits.ImplicitName = implicit;
   }
 
+  /// Determine whether this attribute was inferred based on Swift 3's
+  /// deprecated @objc inference rules.
+  bool isSwift3Inferred() const {
+    return ObjCAttrBits.Swift3Inferred;
+  }
+
+  /// Set whether this attribute was inferred based on Swift 3's deprecated
+  /// @objc inference rules.
+  void setSwift3Inferred(bool inferred = true) {
+    ObjCAttrBits.Swift3Inferred = inferred;
+  }
+
   /// Clear the name of this entity.
   void clearName() {
     NameData = nullptr;
diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def
index 7caa7ac..d11efc5 100644
--- a/include/swift/AST/Builtins.def
+++ b/include/swift/AST/Builtins.def
@@ -488,6 +488,9 @@
 // getObjCTypeEncoding has type <T> T.Type -> RawPointer
 BUILTIN_MISC_OPERATION(GetObjCTypeEncoding, "getObjCTypeEncoding", "n", Special)
 
+// Swift3ImplicitObjCEntrypoint has type () -> ()
+BUILTIN_MISC_OPERATION(Swift3ImplicitObjCEntrypoint, "swift3ImplicitObjCEntrypoint", "", Special)
+
 #undef BUILTIN_MISC_OPERATION
 
 /// Builtins for instrumentation added by sanitizers during SILGen.
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 16bc277..36ce501 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -4974,7 +4974,10 @@
   
   /// True if the declaration is forced to be statically dispatched.
   bool hasForcedStaticDispatch() const;
-  
+
+  /// Get the interface type of this decl and remove the Self context.
+  Type getMethodInterfaceType() const;
+
   using DeclContext::operator new;
   using Decl::getASTContext;
 };
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index 655399f..11f8256 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -208,10 +208,6 @@
 ERROR(enum_case_dot_prefix,none,
       "extraneous '.' in enum 'case' declaration", ())
 
-ERROR(protocol_associatedtype_where_swift_3,none,
-      "where clauses on %0 are fragile; use '-swift-version 4' to experiment.", (StringRef))
-
-
 // Variable getters/setters
 ERROR(static_var_decl_global_scope,none,
       "%select{%error|static properties|class properties}0 may only be declared on a type",
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index b0b1fab..5743b67 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -415,6 +415,10 @@
 ERROR(expr_keypath_non_objc_property,none,
       "argument of '#keyPath' refers to non-'@objc' property %0",
       (DeclName))
+WARNING(expr_keypath_swift3_objc_inference,none,
+        "argument of '#keyPath' refers to property %0 in %1 that depends on "
+        "'@objc' attribute inference deprecated in Swift 4",
+        (DeclName, Identifier))
 ERROR(stdlib_anyobject_not_found,none,
       "broken standard library: cannot find 'AnyObject' protocol", ())
 ERROR(expr_keypath_type_of_property,none,
@@ -463,6 +467,10 @@
 NOTE(make_decl_objc,none,
      "add '@objc' to expose this %0 to Objective-C",
      (DescriptiveDeclKind))
+WARNING(expr_selector_swift3_objc_inference,none,
+        "argument of '#selector' refers to %0 %1 in %2 that depends on "
+        "'@objc' attribute inference deprecated in Swift 4",
+        (DescriptiveDeclKind, DeclName, Identifier))
 
 // Selectors-as-string-literals.
 WARNING(selector_literal_invalid,none,
@@ -1067,6 +1075,8 @@
 ERROR(optional_attribute_missing_explicit_objc,none,
       "'optional' requirements are an Objective-C compatibility feature; add '@objc'",
       ())
+ERROR(objcmembers_attribute_nonclass,none,
+      "'@objcMembers' attribute can only be applied to a class", ())
 ERROR(optional_attribute_initializer,none,
       "'optional' cannot be applied to an initializer", ())
 ERROR(unavailable_method_non_objc_protocol,none,
@@ -1111,6 +1121,11 @@
 NOTE(variadic_superclass_init_here,none,
      "variadic superclass initializer defined here", ())
 
+WARNING(expr_dynamic_lookup_swift3_objc_inference,none,
+        "reference to %0 %1 of %2 depends on '@objc' attribute inference "
+        "deprecated in Swift 4",
+        (DescriptiveDeclKind, DeclName, Identifier))
+
 // Alignment attribute
 ERROR(alignment_not_power_of_two,none,
       "alignment value must be a power of two", ())
@@ -1784,6 +1799,10 @@
 ERROR(open_decl_cannot_be_final,none,
       "%0 cannot be declared both 'final' and 'open'", (DescriptiveDeclKind))
 
+WARNING(override_swift3_objc_inference,none,
+        "override of %0 %1 from extension of %2 depends on deprecated "
+        "inference of '@objc'",
+        (DescriptiveDeclKind, DeclName, Identifier))
 
 // Inheritance
 ERROR(duplicate_inheritance,none,
@@ -2964,13 +2983,16 @@
       "@objc can only be used with members of classes, @objc protocols, and "
       "concrete extensions of classes", ())
 ERROR(invalid_objc_decl,none,
-      "only classes, protocols, methods, initializers, properties, and "
-      "subscript declarations can be declared @objc", ())
+      "only classes (and their extensions), protocols, methods, initializers, "
+      "properties, and subscript declarations can be declared @objc", ())
 ERROR(invalid_objc_swift_rooted_class,none,
       "only classes that inherit from NSObject can be declared @objc", ())
 ERROR(invalid_nonobjc_decl,none,
       "only methods, initializers, properties and subscript declarations can "
       "be declared @nonobjc", ())
+ERROR(invalid_nonobjc_extension,none,
+      "only extensions of classes can be declared @nonobjc", ())
+
 ERROR(objc_in_extension_context,none,
       "members of constrained extensions cannot be declared @objc", ())
 ERROR(objc_in_generic_extension,none,
@@ -2979,6 +3001,18 @@
       "operator methods cannot be declared @objc", ())
 ERROR(objc_operator_proto, none,
       "@objc protocols may not have operator requirements", ())
+WARNING(objc_inference_swift3_dynamic,none,
+        "inference of '@objc' for 'dynamic' members is deprecated", ())
+WARNING(objc_inference_swift3_objc_derived,none,
+        "inference of '@objc' for members of Objective-C-derived classes is "
+        "deprecated", ())
+
+NOTE(objc_inference_swift3_addobjc,none,
+     "add `@objc` to continue exposing an Objective-C entry point (Swift 3 "
+     "behavior)", ())
+NOTE(objc_inference_swift3_addnonobjc,none,
+     "add `@nonobjc` to suppress the Objective-C entry point (Swift 4 "
+     "behavior)", ())
 
 ERROR(objc_for_generic_class,none,
       "generic subclasses of '@objc' classes cannot have an explicit '@objc' "
@@ -2991,6 +3025,11 @@
       "'@objc' setter for non-'@objc' property", ())
 ERROR(objc_setter_for_nonobjc_subscript,none,
       "'@objc' setter for non-'@objc' subscript", ())
+WARNING(accessor_swift3_objc_inference,none,
+        "%select{%0 %1|%1}2 with '@objc' %select{getter|setter}3 depends on "
+        "deprecated inference of '@objc'",
+        (DescriptiveDeclKind, DeclName, bool, bool))
+
 ERROR(objc_enum_generic,none,
       "'@objc' enum cannot be generic", ())
 ERROR(objc_name_req_nullary,none,
@@ -3014,8 +3053,11 @@
 ERROR(objc_enum_case_multi,none,
       "'@objc' enum case declaration defines multiple enum cases with the same Objective-C name", ())
 
+ERROR(objc_extension_not_class,none,
+      "'@objc' can only be applied to an extension of a class", ())
+
 // If you change this, also change enum ObjCReason
-#define OBJC_ATTR_SELECT "select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement}"
+#define OBJC_ATTR_SELECT "select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}"
 
 ERROR(objc_invalid_on_var,none,
       "property cannot be %" OBJC_ATTR_SELECT "0 "
@@ -3221,6 +3263,12 @@
 ERROR(dynamic_with_final,none,
       "a declaration cannot be both 'final' and 'dynamic'",
       ())
+ERROR(dynamic_with_nonobjc,none,
+      "a declaration cannot be both '@nonobjc' and 'dynamic'",
+      ())
+ERROR(dynamic_requires_objc,none,
+      "'dynamic' %0 %1 must also be '@objc'",
+      (DescriptiveDeclKind, DeclName))
 
 //------------------------------------------------------------------------------
 // @available
diff --git a/include/swift/AST/GenericEnvironment.h b/include/swift/AST/GenericEnvironment.h
index cba8da9..6d4104d 100644
--- a/include/swift/AST/GenericEnvironment.h
+++ b/include/swift/AST/GenericEnvironment.h
@@ -142,8 +142,6 @@
   };
   friend class QueryArchetypeToInterfaceSubstitutions;
 
-  void populateParentMap(SubstitutionMap &subMap) const;
-
 public:
   GenericSignature *getGenericSignature() const {
     return Signature;
diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h
index 151d46c..e2000a8 100644
--- a/include/swift/AST/GenericSignature.h
+++ b/include/swift/AST/GenericSignature.h
@@ -134,8 +134,6 @@
   /// Retrieve the generic signature builder for the given generic signature.
   GenericSignatureBuilder *getGenericSignatureBuilder(ModuleDecl &mod);
 
-  void populateParentMap(SubstitutionMap &subMap) const;
-
   friend class ArchetypeType;
 
 public:
@@ -287,6 +285,9 @@
   /// must conform.
   ConformsToArray getConformsTo(Type type, ModuleDecl &mod);
 
+  /// Determine whether the given dependent type conforms to this protocol.
+  bool conformsToProtocol(Type type, ProtocolDecl *proto, ModuleDecl &mod);
+
   /// Determine whether the given dependent type is equal to a concrete type.
   bool isConcreteType(Type type, ModuleDecl &mod);
 
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index 9b0f120..8f93fc1 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -191,6 +191,16 @@
   GenericSignatureBuilder(const GenericSignatureBuilder &) = delete;
   GenericSignatureBuilder &operator=(const GenericSignatureBuilder &) = delete;
 
+  /// When a particular requirement cannot be resolved due to, e.g., a
+  /// currently-unresolvable or nested type, this routine should be
+  /// called to record the unresolved requirement to be reconsidered later.
+  ///
+  /// \returns false, which is used elsewhere to indicate "no failure".
+  bool recordUnresolvedRequirement(RequirementKind kind,
+                                   UnresolvedType lhs,
+                                   RequirementRHS rhs,
+                                   FloatingRequirementSource source);
+
   /// Retrieve the constraint source conformance for the superclass constraint
   /// of the given potential archetype (if present) to the given protocol.
   ///
@@ -222,7 +232,8 @@
   /// called with the two types that don't match (\c Bar<T> and \c Baz for the
   /// previous example).
   bool
-  addSameTypeRequirement(ResolvedType paOrT1, ResolvedType paOrT2,
+  addSameTypeRequirementDirect(
+                         ResolvedType paOrT1, ResolvedType paOrT2,
                          FloatingRequirementSource Source,
                          llvm::function_ref<void(Type, Type)> diagnoseMismatch);
 
@@ -230,8 +241,8 @@
   /// (output of GenericSignatureBuilder::resolve).
   ///
   /// The two types must not be incompatible concrete types.
-  bool addSameTypeRequirement(ResolvedType paOrT1, ResolvedType paOrT2,
-                              FloatingRequirementSource Source);
+  bool addSameTypeRequirementDirect(ResolvedType paOrT1, ResolvedType paOrT2,
+                                    FloatingRequirementSource Source);
 
   /// \brief Add a new same-type requirement between two unresolved types.
   ///
@@ -260,9 +271,18 @@
 private:
   /// \brief Add a new superclass requirement specifying that the given
   /// potential archetype has the given type as an ancestor.
-  bool addSuperclassRequirement(PotentialArchetype *T,
-                                Type Superclass,
-                                const RequirementSource *Source);
+  bool addSuperclassRequirementDirect(PotentialArchetype *T,
+                                      Type Superclass,
+                                      const RequirementSource *Source);
+
+  /// \brief Add a new type requirement specifying that the given
+  /// type conforms-to or is a superclass of the second type.
+  bool addTypeRequirement(UnresolvedType subject,
+                          UnresolvedType constraint,
+                          FloatingRequirementSource source,
+                          Type dependentType,
+                          llvm::SmallPtrSetImpl<ProtocolDecl *> *visited
+                            = nullptr);
 
   /// \brief Add a new conformance requirement specifying that the given
   /// potential archetypes are equivalent.
@@ -285,6 +305,23 @@
       Type T1, Type T2, FloatingRequirementSource Source,
       llvm::function_ref<void(Type, Type)> diagnoseMismatch);
 
+  /// \brief Add a new layout requirement directly on the potential archetype.
+  ///
+  /// \returns true if this requirement makes the set of requirements
+  /// inconsistent, in which case a diagnostic will have been issued.
+  bool addLayoutRequirementDirect(PotentialArchetype *PAT,
+                                  LayoutConstraint Layout,
+                                  const RequirementSource *Source);
+
+  /// Add a new layout requirement to the subject.
+  ///
+  /// FIXME: The "dependent type" is the subject type pre-substitution. We
+  /// should be able to compute this!
+  bool addLayoutRequirement(UnresolvedType subject,
+                            LayoutConstraint layout,
+                            FloatingRequirementSource source,
+                            Type dependentType);
+
   /// Add the requirements placed on the given type parameter
   /// to the given potential archetype.
   ///
@@ -379,15 +416,6 @@
                       const SubstitutionMap *subMap,
                       llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
 
-  /// \brief Add a new requirement.
-  ///
-  /// \returns true if this requirement makes the set of requirements
-  /// inconsistent, in which case a diagnostic will have been issued.
-
-  bool addLayoutRequirement(PotentialArchetype *PAT,
-                            LayoutConstraint Layout,
-                            const RequirementSource *Source);
-
   /// \brief Add all of a generic signature's parameters and requirements.
   void addGenericSignature(GenericSignature *sig);
 
@@ -547,13 +575,12 @@
 
   /// \brief Resolve the given type as far as this Builder knows how.
   ///
-  /// This returns either a non-typealias potential archetype or a Type, if \c
-  /// type is concrete.
-  // FIXME: the hackTypeFromGenericTypeAlias is just temporarily patching over
-  // problems with generic typealiases (see the comment on the ResolvedType
-  // function)
-  ResolvedType resolve(UnresolvedType type,
-                       bool hackTypeFromGenericTypeAlias = false);
+  /// If successful, this returns either a non-typealias potential archetype
+  /// or a Type, if \c type is concrete.
+  /// If the type cannot be resolved, e.g., because it is "too" recursive
+  /// given the source, returns \c None.
+  Optional<ResolvedType> resolve(UnresolvedType type,
+                                 FloatingRequirementSource source);
 
   /// \brief Dump all of the requirements, both specified and inferred.
   LLVM_ATTRIBUTE_DEPRECATED(
@@ -1051,6 +1078,9 @@
 
   /// Retrieve the source location for this requirement.
   SourceLoc getLoc() const;
+
+  /// Whether this is an explicitly-stated requirement.
+  bool isExplicit() const;
 };
 
 class GenericSignatureBuilder::PotentialArchetype {
diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h
index 0d5e808..7dc6219 100644
--- a/include/swift/AST/IRGenOptions.h
+++ b/include/swift/AST/IRGenOptions.h
@@ -209,6 +209,12 @@
       return OutputKind == IRGenOutputKind::LLVMAssembly;
     }
   }
+
+  /// Return a hash code of any components from these options that should
+  /// contribute to a Swift Bridging PCH hash.
+  llvm::hash_code getPCHHashComponents() const {
+    return llvm::hash_value(0);
+  }
 };
 
 } // end namespace swift
diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h
index 275ef9e..079396e 100644
--- a/include/swift/AST/LazyResolver.h
+++ b/include/swift/AST/LazyResolver.h
@@ -52,11 +52,6 @@
   virtual void resolveWitness(const NormalProtocolConformance *conformance,
                               ValueDecl *requirement) = 0;
 
-  /// Resolve an inherited conformance.
-  virtual ProtocolConformance *resolveInheritedConformance(
-                                 const NormalProtocolConformance *conformance,
-                                 ProtocolDecl *inherited) = 0;
-
   /// Resolve the accessibility of a value.
   ///
   /// It does no type-checking.
@@ -127,12 +122,6 @@
     Principal.resolveWitness(conformance, requirement);
   }
 
-  ProtocolConformance *resolveInheritedConformance(
-                         const NormalProtocolConformance *conformance,
-                         ProtocolDecl *inherited) override {
-    return Principal.resolveInheritedConformance(conformance, inherited);
-  }
-
   void resolveAccessibility(ValueDecl *VD) override {
     Principal.resolveAccessibility(VD);
   }
diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h
index a2952cd..8486681 100644
--- a/include/swift/AST/NameLookup.h
+++ b/include/swift/AST/NameLookup.h
@@ -37,7 +37,32 @@
 /// UnqualifiedLookupResult - One result of unqualified lookup.
 struct UnqualifiedLookupResult {
 private:
+
+  /// The declaration through where we find Value. For instance,
+  ///
+  /// class BaseClass {
+  ///   func foo() {}
+  /// }
+  ///
+  /// class DerivedClass : BaseClass {
+  ///   func bar() {}
+  /// }
+  ///
+  /// When finding foo() from the body of DerivedClass, Base is DerivedClass.
+  ///
+  /// Another example:
+  ///
+  /// class BaseClass {
+  ///   func bar() {}
+  ///   func foo() {}
+  /// }
+  ///
+  /// When finding bar() from the function body of foo(), Base is the implicit
+  /// self parameter in foo().
   ValueDecl *Base;
+
+  /// The declaration corresponds to the given name; i.e. the decl we are
+  /// looking up.
   ValueDecl *Value;
 
 public:
diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h
index b8ed6c4..b851830 100644
--- a/include/swift/AST/ProtocolConformance.h
+++ b/include/swift/AST/ProtocolConformance.h
@@ -18,7 +18,7 @@
 
 #include "swift/AST/ConcreteDeclRef.h"
 #include "swift/AST/Decl.h"
-#include "swift/AST/Substitution.h"
+#include "swift/AST/SubstitutionList.h"
 #include "swift/AST/Type.h"
 #include "swift/AST/Types.h"
 #include "swift/AST/TypeAlignments.h"
@@ -48,16 +48,11 @@
 /// Map from non-type requirements to the corresponding conformance witnesses.
 typedef llvm::DenseMap<ValueDecl *, Witness> WitnessMap;
 
-/// Map from associated type requirements to the corresponding substitution,
-/// which captures the replacement type along with any conformances it requires.
-typedef llvm::DenseMap<AssociatedTypeDecl *, std::pair<Substitution, TypeDecl*>>
+/// Map from associated type requirements to the corresponding type and
+/// the type declaration that was used to satisfy the requirement.
+typedef llvm::DenseMap<AssociatedTypeDecl *, std::pair<Type, TypeDecl*>>
   TypeWitnessMap;
 
-/// Map from a directly-inherited protocol to its corresponding protocol
-/// conformance.
-typedef llvm::DenseMap<ProtocolDecl *, ProtocolConformance *>
-  InheritedConformanceMap;
-
 /// Describes the kind of protocol conformance structure used to encode
 /// conformance.
 enum class ProtocolConformanceKind {
@@ -101,7 +96,6 @@
   
   /// \brief The interface type that conforms to the protocol.
   Type ConformingInterfaceType;
-  
 
 protected:
   ProtocolConformance(ProtocolConformanceKind kind, Type conformingType,
@@ -149,21 +143,21 @@
   bool hasTypeWitness(AssociatedTypeDecl *assocType,
                       LazyResolver *resolver = nullptr) const;
 
-  /// Retrieve the type witness substitution for the given associated type.
-  const Substitution &getTypeWitness(AssociatedTypeDecl *assocType,
-                                     LazyResolver *resolver) const;
+  /// Retrieve the type witness for the given associated type.
+  Type getTypeWitness(AssociatedTypeDecl *assocType,
+                      LazyResolver *resolver) const;
 
-  /// Retrieve the type witness substitution and type decl (if one exists)
+  /// Retrieve the type witness and type decl (if one exists)
   /// for the given associated type.
-  std::pair<const Substitution &, TypeDecl *>
-  getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType,
-                             LazyResolver *resolver) const;
+  std::pair<Type, TypeDecl *>
+  getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
+                        LazyResolver *resolver) const;
 
   /// Apply the given function object to each type witness within this
   /// protocol conformance.
   ///
   /// The function object should accept an \c AssociatedTypeDecl* for the
-  /// requirement followed by the \c Substitution for the witness and a
+  /// requirement followed by the \c Type for the witness and a
   /// (possibly null) \c TypeDecl* that explicitly declared the type.
   /// It should return true to indicate an early exit.
   ///
@@ -180,7 +174,7 @@
       if (!resolver && !hasTypeWitness(assocTypeReq))
         continue;
 
-      const auto &TWInfo = getTypeWitnessSubstAndDecl(assocTypeReq, resolver);
+      const auto &TWInfo = getTypeWitnessAndDecl(assocTypeReq, resolver);
       if (f(assocTypeReq, TWInfo.first, TWInfo.second))
         return true;
     }
@@ -226,10 +220,6 @@
   /// Retrieve the protocol conformance for the inherited protocol.
   ProtocolConformance *getInheritedConformance(ProtocolDecl *protocol) const;
 
-  /// Retrieve the complete set of protocol conformances for directly inherited
-  /// protocols.
-  const InheritedConformanceMap &getInheritedConformances() const;
-
   /// Given a dependent type expressed in terms of the self parameter,
   /// map it into the context of this conformance.
   Type getAssociatedType(Type assocType,
@@ -266,7 +256,11 @@
   /// Determine whether the witness for the given requirement
   /// is either the default definition or was otherwise deduced.
   bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const;
-  
+
+  /// Returns true if this conformance has a layout that is known to all
+  /// consumers, based on the type/protocol involved in it.
+  bool hasFixedLayout() const;
+
   // Make vanilla new/delete illegal for protocol conformances.
   void *operator new(size_t bytes) = delete;
   void operator delete(void *data) SWIFT_DELETE_OPERATOR_DELETED;
@@ -340,14 +334,9 @@
   /// the declarations that satisfy those requirements.
   mutable WitnessMap Mapping;
 
-  /// The mapping from associated type requirements to their substitutions.
+  /// The mapping from associated type requirements to their types.
   mutable TypeWitnessMap TypeWitnesses;
 
-  /// \brief The mapping from any directly-inherited protocols over to the
-  /// protocol conformance structures that indicate how the given type meets
-  /// the requirements of those protocols.
-  InheritedConformanceMap InheritedMapping;
-
   /// Conformances that satisfy each of conformance requirements of the
   /// requirement signature of the protocol.
   ArrayRef<ProtocolConformanceRef> SignatureConformances;
@@ -436,11 +425,11 @@
     return ContextAndInvalid.getPointer().dyn_cast<AbstractStorageDecl *>();
   }
   
-  /// Retrieve the type witness substitution and type decl (if one exists)
+  /// Retrieve the type witness and type decl (if one exists)
   /// for the given associated type.
-  std::pair<const Substitution &, TypeDecl *>
-  getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType,
-                             LazyResolver *resolver) const;
+  std::pair<Type, TypeDecl *>
+  getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
+                        LazyResolver *resolver) const;
 
   /// Determine whether the protocol conformance has a type witness for the
   /// given associated type.
@@ -449,8 +438,7 @@
 
   /// Set the type witness for the given associated type.
   /// \param typeDecl the type decl the witness type came from, if one exists.
-  void setTypeWitness(AssociatedTypeDecl *assocType,
-                      const Substitution &substitution,
+  void setTypeWitness(AssociatedTypeDecl *assocType, Type type,
                       TypeDecl *typeDecl) const;
 
   /// Given that the requirement signature of the protocol directly states
@@ -479,28 +467,6 @@
   /// Set the witness for the given requirement.
   void setWitness(ValueDecl *requirement, Witness witness) const;
 
-  /// Retrieve the protocol conformances directly-inherited protocols.
-  const InheritedConformanceMap &getInheritedConformances() const {
-    return InheritedMapping;
-  }
-
-  /// Determine whether the protocol conformance has a particular inherited
-  /// conformance.
-  ///
-  /// Only usable on incomplete or invalid protocol conformances.
-  bool hasInheritedConformance(ProtocolDecl *proto) const {
-    return InheritedMapping.count(proto) > 0;
-  }
-
-  /// Set the given inherited conformance.
-  void setInheritedConformance(ProtocolDecl *proto,
-                               ProtocolConformance *conformance) {
-    assert(InheritedMapping.count(proto) == 0 &&
-           "Already recorded inherited conformance");
-    assert(!isComplete() && "Conformance already complete?");
-    InheritedMapping[proto] = conformance;
-  }
-
   /// Retrieve the protocol conformances that satisfy the requirements of the
   /// protocol, which line up with the conformance constraints in the
   /// protocol's requirement signature.
@@ -515,7 +481,7 @@
   /// Determine whether the witness for the given type requirement
   /// is the default definition.
   bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
-    return getTypeWitnessSubstAndDecl(requirement, nullptr)
+    return getTypeWitnessAndDecl(requirement, nullptr)
         .second->isImplicit();
   }
 
@@ -603,21 +569,16 @@
   bool hasTypeWitness(AssociatedTypeDecl *assocType,
                       LazyResolver *resolver = nullptr) const;
 
-  /// Retrieve the type witness substitution and type decl (if one exists)
+  /// Retrieve the type witness and type decl (if one exists)
   /// for the given associated type.
-  std::pair<const Substitution &, TypeDecl *>
-  getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType,
-                             LazyResolver *resolver) const;
+  std::pair<Type, TypeDecl *>
+  getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
+                        LazyResolver *resolver) const;
 
   /// Retrieve the value witness corresponding to the given requirement.
   Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const;
 
 
-  /// Retrieve the protocol conformances directly-inherited protocols.
-  const InheritedConformanceMap &getInheritedConformances() const {
-    return GenericConformance->getInheritedConformances();
-  }
-
   /// Given that the requirement signature of the protocol directly states
   /// that the given dependent type must conform to the given protocol,
   /// return its associated conformance.
@@ -709,12 +670,12 @@
     return InheritedConformance->hasTypeWitness(assocType, resolver);
   }
 
-  /// Retrieve the type witness substitution and type decl (if one exists)
+  /// Retrieve the type witness and type decl (if one exists)
   /// for the given associated type.
-  std::pair<const Substitution &, TypeDecl *>
-  getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType,
-                             LazyResolver *resolver) const {
-    return InheritedConformance->getTypeWitnessSubstAndDecl(assocType,resolver);
+  std::pair<Type, TypeDecl *>
+  getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
+                        LazyResolver *resolver) const {
+    return InheritedConformance->getTypeWitnessAndDecl(assocType, resolver);
   }
 
   /// Retrieve the value witness corresponding to the given requirement.
@@ -730,11 +691,6 @@
   getAssociatedConformance(Type assocType, ProtocolDecl *protocol,
                            LazyResolver *resolver = nullptr) const;
 
-  /// Retrieve the protocol conformances directly-inherited protocols.
-  const InheritedConformanceMap &getInheritedConformances() const {
-    return InheritedConformance->getInheritedConformances();
-  }
-
   /// Determine whether the witness for the given requirement
   /// is either the default definition or was otherwise deduced.
   bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
diff --git a/include/swift/AST/Requirement.h b/include/swift/AST/Requirement.h
index 650c0ef..7165ca7 100644
--- a/include/swift/AST/Requirement.h
+++ b/include/swift/AST/Requirement.h
@@ -98,15 +98,14 @@
       return None;
 
     switch (getKind()) {
+    case RequirementKind::Conformance:
+    case RequirementKind::Superclass:
     case RequirementKind::SameType: {
       auto newSecond = getSecondType().subst(std::forward<Args>(args)...);
       if (!newSecond)
         return None;
       return Requirement(getKind(), newFirst, newSecond);
     }
-    case RequirementKind::Conformance:
-    case RequirementKind::Superclass:
-      return Requirement(getKind(), newFirst, getSecondType());
     case RequirementKind::Layout:
       return Requirement(getKind(), newFirst, getLayoutConstraint());
     }
diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h
index 68eb468..c18bfad 100644
--- a/include/swift/AST/SILOptions.h
+++ b/include/swift/AST/SILOptions.h
@@ -19,6 +19,7 @@
 #define SWIFT_AST_SILOPTIONS_H
 
 #include "swift/Basic/Sanitizers.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/StringRef.h"
 #include <string>
 #include <climits>
@@ -56,6 +57,11 @@
   /// Controls how to perform SIL linking.
   LinkingMode LinkMode = LinkNormal;
 
+  /// Controls whether to pull in SIL from partial modules during the
+  /// merge modules step. Could perhaps be merged with the link mode
+  /// above but the interactions between all the flags are tricky.
+  bool MergePartialModules = false;
+
   /// Remove all runtime assertions during optimizations.
   bool RemoveRuntimeAsserts = false;
 
@@ -140,8 +146,16 @@
   /// Emit checks to trap at run time when the law of exclusivity is violated.
   bool EnforceExclusivityDynamic = false;
 
+  /// Enable the mandatory semantic arc optimizer.
+  bool EnableMandatorySemanticARCOpts = false;
+
   SILOptions() : Sanitize(SanitizerKind::None) {}
 
+  /// Return a hash code of any components from these options that should
+  /// contribute to a Swift Bridging PCH hash.
+  llvm::hash_code getPCHHashComponents() const {
+    return llvm::hash_value(0);
+  }
 };
 
 } // end namespace swift
diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h
index 4e596b7..2755d37 100644
--- a/include/swift/AST/SearchPathOptions.h
+++ b/include/swift/AST/SearchPathOptions.h
@@ -13,6 +13,8 @@
 #ifndef SWIFT_AST_SEARCHPATHOPTIONS_H
 #define SWIFT_AST_SEARCHPATHOPTIONS_H
 
+#include "llvm/ADT/Hashing.h"
+
 #include <string>
 #include <vector>
 
@@ -67,6 +69,26 @@
 
   /// Don't look in for compiler-provided modules.
   bool SkipRuntimeLibraryImportPath = false;
+
+  /// Return a hash code of any components from these options that should
+  /// contribute to a Swift Bridging PCH hash.
+  llvm::hash_code getPCHHashComponents() const {
+    using llvm::hash_value;
+    using llvm::hash_combine;
+    auto Code = hash_value(SDKPath);
+    for (auto Import : ImportSearchPaths) {
+      Code = hash_combine(Code, Import);
+    }
+    for (const auto &FrameworkPath : FrameworkSearchPaths) {
+      Code = hash_combine(Code, FrameworkPath.Path);
+    }
+    for (auto LibraryPath : LibrarySearchPaths) {
+      Code = hash_combine(Code, LibraryPath);
+    }
+    Code = hash_combine(Code, RuntimeResourcePath);
+    Code = hash_combine(Code, RuntimeLibraryImportPath);
+    return Code;
+  }
 };
 
 }
diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h
index 7385abb..083c1f3 100644
--- a/include/swift/AST/SubstitutionMap.h
+++ b/include/swift/AST/SubstitutionMap.h
@@ -51,39 +51,29 @@
 };
 
 class SubstitutionMap {
-  using ParentType = std::pair<CanType, AssociatedTypeDecl *>;
+  /// The generic signature for which we are performing substitutions.
+  GenericSignature *genericSig;
 
   // FIXME: Switch to a more efficient representation.
   llvm::DenseMap<SubstitutableType *, Type> subMap;
   llvm::DenseMap<TypeBase *, SmallVector<ProtocolConformanceRef, 1>>
     conformanceMap;
-  llvm::DenseMap<TypeBase *, SmallVector<ParentType, 1>> parentMap;
-
-  // Call the given function for each parent of the given type. The
-  // function \c fn should return an \c Optional<T>. \c forEachParent() will
-  // return the first non-empty \C Optional<T> returned by \c fn.
-  template<typename T>
-  Optional<T> forEachParent(
-                CanType type,
-                llvm::SmallPtrSetImpl<CanType> &visitedParents,
-                llvm::function_ref<Optional<T>(CanType,
-                                               AssociatedTypeDecl *)> fn) const;
-
-  // Call the given function for each conformance of the given type. The
-  // function \c fn should return an \c Optional<T>. \c forEachConformance()
-  // will return the first non-empty \C Optional<T> returned by \c fn.
-  template<typename T>
-  Optional<T> forEachConformance(
-                  CanType type,
-                  llvm::SmallPtrSetImpl<CanType> &visitedParents,
-                  llvm::function_ref<Optional<T>(ProtocolConformanceRef)> fn)
-                const;
 
 public:
+  SubstitutionMap()
+    : SubstitutionMap(static_cast<GenericSignature *>(nullptr)) { }
+
+  SubstitutionMap(GenericSignature *genericSig)
+    : genericSig(genericSig) { }
+
+  SubstitutionMap(GenericEnvironment *genericEnv);
+
+  /// Retrieve the generic signature describing the environment in which
+  /// substitutions occur.
+  GenericSignature *getGenericSignature() const { return genericSig; }
+
   Optional<ProtocolConformanceRef>
-  lookupConformance(
-                CanType type, ProtocolDecl *proto,
-                llvm::SmallPtrSetImpl<CanType> *visitedParents = nullptr) const;
+  lookupConformance(CanType type, ProtocolDecl *proto) const;
 
   bool empty() const {
     return subMap.empty();
@@ -179,8 +169,6 @@
 
   void addSubstitution(CanSubstitutableType type, Type replacement);
   void addConformance(CanType type, ProtocolConformanceRef conformance);
-  void addParent(CanType type, CanType parent,
-                 AssociatedTypeDecl *assocType);
 };
 
 } // end namespace swift
diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h
index 83a53c1..bcfab9b 100644
--- a/include/swift/AST/Type.h
+++ b/include/swift/AST/Type.h
@@ -350,9 +350,7 @@
   static bool isReferenceTypeImpl(CanType type, bool functionsCount);
   static bool isExistentialTypeImpl(CanType type);
   static bool isAnyExistentialTypeImpl(CanType type);
-  static bool isExistentialTypeImpl(CanType type,
-                                    SmallVectorImpl<ProtocolDecl*> &protocols);
-  static bool isAnyExistentialTypeImpl(CanType type,
+  static void getExistentialTypeProtocolsImpl(CanType type,
                                     SmallVectorImpl<ProtocolDecl*> &protocols);
   static void getAnyExistentialTypeProtocolsImpl(CanType type,
                                     SmallVectorImpl<ProtocolDecl*> &protocols);
@@ -404,19 +402,16 @@
     return isExistentialTypeImpl(*this);
   }
 
-  /// Is this type existential?
-  bool isExistentialType(SmallVectorImpl<ProtocolDecl *> &protocols) {
-    return isExistentialTypeImpl(*this, protocols);
-  }
-
   /// Is this type an existential or an existential metatype?
   bool isAnyExistentialType() const {
     return isAnyExistentialTypeImpl(*this);
   }
 
-  /// Is this type an existential or an existential metatype?
-  bool isAnyExistentialType(SmallVectorImpl<ProtocolDecl *> &protocols) {
-    return isAnyExistentialTypeImpl(*this, protocols);
+  /// Given that this type is an existential, return its
+  /// protocols in a canonical order.
+  void getExistentialTypeProtocols(
+                                SmallVectorImpl<ProtocolDecl *> &protocols) {
+    return getExistentialTypeProtocolsImpl(*this, protocols);
   }
 
   /// Given that this type is any kind of existential, return its
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index fe3e04f..b1e7cfa 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -576,22 +576,9 @@
   /// bound.
   bool isClassExistentialType();
 
-  /// isExistentialType - Determines whether this type is an existential type,
-  /// whose real (runtime) type is unknown but which is known to conform to
-  /// some set of protocols. Protocol and protocol-conformance types are
-  /// existential types.
-  ///
-  /// \param Protocols If the type is an existential type, this vector is
-  /// populated with the set of protocols
-  bool isExistentialType(SmallVectorImpl<ProtocolDecl *> &Protocols);
-
-  /// isAnyExistentialType - Determines whether this type is any kind of
-  /// existential type: a protocol type, a protocol composition type, or
-  /// an existential metatype.
-  ///
-  /// \param protocols If the type is an existential type, this vector is
-  /// populated with the set of protocols.
-  bool isAnyExistentialType(SmallVectorImpl<ProtocolDecl *> &protocols);
+  /// Given that this type is an existential type, produce
+  /// its list of protocols.
+  void getExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protocols);
 
   /// Given that this type is any kind of existential type, produce
   /// its list of protocols.
@@ -2088,11 +2075,6 @@
     return get(T, repr, T->getASTContext());
   }
 
-  /// Return the canonicalized list of protocols.
-  void getAnyExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protos) {
-    getInstanceType()->getAnyExistentialTypeProtocols(protos);
-  }
-
   // Implement isa/cast/dyncast/etc.
   static bool classof(const TypeBase *T) {
     return T->getKind() == TypeKind::ExistentialMetatype;
@@ -2112,9 +2094,6 @@
                                         MetatypeRepresentation repr) {
     return CanExistentialMetatypeType(ExistentialMetatypeType::get(type, repr));
   }
-  void getAnyExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protocols) {
-    getInstanceType().getAnyExistentialTypeProtocols(protocols);
-  }
 END_CAN_TYPE_WRAPPER(ExistentialMetatypeType, AnyMetatypeType)
   
 /// ModuleType - This is the type given to a module value, e.g. the "Builtin" in
@@ -3625,10 +3604,6 @@
   /// True if only classes may conform to the protocol.
   bool requiresClass() const;
 
-  void getAnyExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protos) {
-    protos.push_back(getDecl());
-  }
-  
   // Implement isa/cast/dyncast/etc.
   static bool classof(const TypeBase *T) {
     return T->getKind() == TypeKind::Protocol;
@@ -3665,9 +3640,6 @@
                RecursiveTypeProperties properties);
 };
 BEGIN_CAN_TYPE_WRAPPER(ProtocolType, NominalType)
-  void getAnyExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protos) {
-    getPointer()->getAnyExistentialTypeProtocols(protos);
-  }
 END_CAN_TYPE_WRAPPER(ProtocolType, NominalType)
 
 /// ProtocolCompositionType - A type that composes some number of protocols
@@ -3727,11 +3699,6 @@
   CanTypeArrayRef getProtocols() const {
     return CanTypeArrayRef(getPointer()->getProtocols());
   }
-  void getAnyExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protos) {
-    for (CanType proto : getProtocols()) {
-      cast<ProtocolType>(proto).getAnyExistentialTypeProtocols(protos);
-    }
-  }
 END_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
 
 /// LValueType - An l-value is a handle to a physical object.  The
diff --git a/include/swift/Basic/DiagnosticOptions.h b/include/swift/Basic/DiagnosticOptions.h
index a7db91b..5f5cd78 100644
--- a/include/swift/Basic/DiagnosticOptions.h
+++ b/include/swift/Basic/DiagnosticOptions.h
@@ -49,6 +49,13 @@
 
   /// Treat all warnings as errors
   bool WarningsAsErrors = false;
+
+  /// Return a hash code of any components from these options that should
+  /// contribute to a Swift Bridging PCH hash.
+  llvm::hash_code getPCHHashComponents() const {
+    // Nothing here that contributes anything significant when emitting the PCH.
+    return llvm::hash_value(0);
+  }
 };
 
 } // end namespace swift
diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h
index 3d686ab..e010da6 100644
--- a/include/swift/Basic/LangOptions.h
+++ b/include/swift/Basic/LangOptions.h
@@ -22,9 +22,12 @@
 #include "swift/Basic/Version.h"
 #include "clang/Basic/VersionTuple.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Support/raw_ostream.h"
 #include <string>
 #include <vector>
 
@@ -194,6 +197,14 @@
     /// will be used in editor. This usually leads to more aggressive fixit.
     bool DiagnosticsEditorMode = false;
 
+    /// Whether to enable Swift 3 @objc inference, e.g., for members of
+    /// Objective-C-derived classes and 'dynamic' members.
+    bool EnableSwift3ObjCInference = false;
+
+    /// Warn about cases where Swift 3 would infer @objc but later versions
+    /// of Swift do not.
+    bool WarnSwift3ObjCInference = false;
+
     /// Sets the target we are building for and updates platform conditions
     /// to match.
     ///
@@ -270,6 +281,17 @@
       PlatformConditionKind Kind, StringRef Value,
       std::vector<StringRef> &suggestions);
 
+    /// Return a hash code of any components from these options that should
+    /// contribute to a Swift Bridging PCH hash.
+    llvm::hash_code getPCHHashComponents() const {
+      auto code = llvm::hash_value(Target.str());
+      SmallString<16> Scratch;
+      llvm::raw_svector_ostream OS(Scratch);
+      OS << EffectiveLanguageVersion;
+      code = llvm::hash_combine(code, OS.str());
+      return code;
+    }
+
   private:
     llvm::SmallVector<std::pair<PlatformConditionKind, std::string>,
                       NumPlatformConditionKind>
diff --git a/include/swift/Basic/Mangler.h b/include/swift/Basic/Mangler.h
index de11ddd..f0fc399 100644
--- a/include/swift/Basic/Mangler.h
+++ b/include/swift/Basic/Mangler.h
@@ -64,6 +64,9 @@
   /// If enabled, non-ASCII names are encoded in modified Punycode.
   bool UsePunycode = true;
 
+  /// If enabled, repeated entities are mangled using substitutions ('A...').
+  bool UseSubstitutions = true;
+
   /// A helpful little wrapper for an integer value that should be mangled
   /// in a particular, compressed value.
   class Index {
@@ -109,10 +112,12 @@
   void appendIdentifier(StringRef ident);
 
   void addSubstitution(const void *ptr) {
-    Substitutions[ptr] = Substitutions.size() + StringSubstitutions.size();
+    if (UseSubstitutions)
+      Substitutions[ptr] = Substitutions.size() + StringSubstitutions.size();
   }
   void addSubstitution(StringRef Str) {
-    StringSubstitutions[Str] = Substitutions.size() + StringSubstitutions.size();
+    if (UseSubstitutions)
+      StringSubstitutions[Str] = Substitutions.size() + StringSubstitutions.size();
   }
 
   bool tryMangleSubstitution(const void *ptr);
diff --git a/include/swift/Basic/STLExtras.h b/include/swift/Basic/STLExtras.h
index 4739c0f..41d1e9c 100644
--- a/include/swift/Basic/STLExtras.h
+++ b/include/swift/Basic/STLExtras.h
@@ -706,6 +706,11 @@
   return is_sorted_and_uniqued(C.begin(), C.end());
 }
 
+template <typename Container, typename OutputIterator>
+inline void copy(const Container &C, OutputIterator iter) {
+  std::copy(C.begin(), C.end(), iter);
+}
+
 //===----------------------------------------------------------------------===//
 //                              Function Traits
 //===----------------------------------------------------------------------===//
diff --git a/include/swift/Basic/Statistic.h b/include/swift/Basic/Statistic.h
index c51b6a2..e89dea1 100644
--- a/include/swift/Basic/Statistic.h
+++ b/include/swift/Basic/Statistic.h
@@ -13,7 +13,9 @@
 #ifndef SWIFT_BASIC_STATISTIC_H
 #define SWIFT_BASIC_STATISTIC_H
 
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Statistic.h"
+#include "swift/Basic/Timer.h"
 
 #define SWIFT_FUNC_STAT                                                 \
   do {                                                                  \
@@ -22,4 +24,85 @@
     ++FStat;                                                            \
   } while (0)
 
+// Helper class designed to consolidate reporting of LLVM statistics and timers
+// across swift compilations that typically invoke many drivers, each running
+// many frontends. Additionally collects some cheap "always-on" statistics,
+// beyond those that are (compile-time) parametrized by -DLLVM_ENABLE_STATS
+// (LLVM's stats are global and involve some amount of locking and mfences).
+//
+// Assumes it's given a process name and target name (the latter used as
+// decoration for its self-timer), and a directory to collect stats into, then:
+//
+//  - On construction:
+//    - Calls llvm::EnableStatistics(/*PrintOnExit=*/false)
+//    - Calls swift::enableCompilationTimers()
+//    - Starts an llvm::NamedRegionTimer for this process
+//
+//  - On destruction:
+//    - Add any standard always-enabled stats about the process as a whole
+//    - Opens $dir/stats-$timestamp-$name-$random.json for writing
+//    - Calls llvm::PrintStatisticsJSON(ostream) and/or its own writer
+//
+// Generally we make one of these per-process: either early in the life of the
+// driver, or early in the life of the frontend.
+
+namespace swift {
+
+class UnifiedStatsReporter {
+
+public:
+  struct AlwaysOnDriverCounters
+  {
+    size_t NumDriverJobsRun;
+    size_t NumDriverJobsSkipped;
+
+    size_t DriverDepCascadingTopLevel;
+    size_t DriverDepCascadingDynamic;
+    size_t DriverDepCascadingNominal;
+    size_t DriverDepCascadingMember;
+    size_t DriverDepCascadingExternal;
+
+    size_t DriverDepTopLevel;
+    size_t DriverDepDynamic;
+    size_t DriverDepNominal;
+    size_t DriverDepMember;
+    size_t DriverDepExternal;
+  };
+
+  struct AlwaysOnFrontendCounters
+  {
+    size_t NumSILGenFunctions;
+    size_t NumSILGenVtables;
+    size_t NumSILGenWitnessTables;
+    size_t NumSILGenDefaultWitnessTables;
+    size_t NumSILGenGlobalVariables;
+
+    size_t NumSILOptFunctions;
+    size_t NumSILOptVtables;
+    size_t NumSILOptWitnessTables;
+    size_t NumSILOptDefaultWitnessTables;
+    size_t NumSILOptGlobalVariables;
+  };
+
+private:
+  SmallString<128> Filename;
+  std::unique_ptr<llvm::NamedRegionTimer> Timer;
+
+  std::unique_ptr<AlwaysOnDriverCounters> DriverCounters;
+  std::unique_ptr<AlwaysOnFrontendCounters> FrontendCounters;
+
+  void publishAlwaysOnStatsToLLVM();
+  void printAlwaysOnStatsAndTimers(llvm::raw_ostream &OS);
+
+public:
+  UnifiedStatsReporter(StringRef ProgramName,
+                       StringRef TargetName,
+                       StringRef Directory);
+  ~UnifiedStatsReporter();
+
+  AlwaysOnDriverCounters &getDriverCounters();
+  AlwaysOnFrontendCounters &getFrontendCounters();
+};
+
+}
 #endif // SWIFT_BASIC_STATISTIC_H
diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h
index 8600a02..263941a 100644
--- a/include/swift/ClangImporter/ClangImporter.h
+++ b/include/swift/ClangImporter/ClangImporter.h
@@ -31,6 +31,7 @@
   class CodeGenOptions;
   class Decl;
   class DependencyCollector;
+  class DiagnosticConsumer;
   class EnumConstantDecl;
   class EnumDecl;
   class MacroInfo;
@@ -44,6 +45,7 @@
 
 namespace swift {
 class ASTContext;
+class CompilerInvocation;
 class ClangImporterOptions;
 class ClangModuleUnit;
 class ClangNode;
@@ -78,14 +80,19 @@
   /// \param ctx The ASTContext into which the module will be imported.
   /// The ASTContext's SearchPathOptions will be used for the Clang importer.
   ///
-  /// \param clangImporterOpts The options to use for the Clang importer.
+  /// \param importerOpts The options to use for the Clang importer.
+  ///
+  /// \param swiftPCHHash A hash of Swift's various options in a compiler
+  /// invocation, used to create a unique Bridging PCH if requested.
   ///
   /// \param tracker The object tracking files this compilation depends on.
   ///
   /// \returns a new Clang module importer, or null (with a diagnostic) if
   /// an error occurred.
   static std::unique_ptr<ClangImporter>
-  create(ASTContext &ctx, const ClangImporterOptions &clangImporterOpts,
+  create(ASTContext &ctx,
+         const ClangImporterOptions &importerOpts,
+         std::string swiftPCHHash = "",
          DependencyTracker *tracker = nullptr);
 
   ClangImporter(const ClangImporter &) = delete;
@@ -234,7 +241,14 @@
   /// replica.
   ///
   /// \sa clang::GeneratePCHAction
-  bool emitBridgingPCH(StringRef headerPath, StringRef outputPCHPath);
+  bool emitBridgingPCH(StringRef headerPath,
+                       StringRef outputPCHPath,
+                       clang::DiagnosticConsumer *Diags = nullptr);
+
+  /// Returns true if a clang CompilerInstance can successfully read in a PCH,
+  /// assuming it exists, with the current options. This can be used to find out
+  /// if we need to persist a PCH for later reuse.
+  bool canReadPCH(StringRef PCHFilename);
 
   const clang::Module *getClangOwningModule(ClangNode Node) const;
   bool hasTypedef(const clang::Decl *typeDecl) const;
@@ -291,6 +305,13 @@
 
   DeclName importName(const clang::NamedDecl *D,
                       clang::DeclarationName givenName);
+
+  Optional<std::string>
+  getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
+                 const std::string &SwiftPCHHash);
+  Optional<std::string>
+  getPCHFilename(const ClangImporterOptions &ImporterOptions,
+                 const std::string &SwiftPCHHash);
 };
 
 ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,
diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h
index 8f893b1..222c79e 100644
--- a/include/swift/ClangImporter/ClangImporterOptions.h
+++ b/include/swift/ClangImporter/ClangImporterOptions.h
@@ -13,6 +13,8 @@
 #ifndef SWIFT_CLANGIMPORTER_CLANGIMPORTEROPTIONS_H
 #define SWIFT_CLANGIMPORTER_CLANGIMPORTEROPTIONS_H
 
+#include "llvm/ADT/Hashing.h"
+
 #include <string>
 #include <vector>
 
@@ -43,7 +45,7 @@
   std::string PrecompiledHeaderOutputDir;
 
   /// \see Mode
-  enum class Modes {
+  enum class Modes : uint8_t {
     /// Set up Clang for importing modules into Swift and generating IR from
     /// Swift code.
     Normal,
@@ -84,6 +86,28 @@
 
   /// When set, don't look for or load adapter modules.
   bool DisableAdapterModules = false;
+
+  /// Return a hash code of any components from these options that should
+  /// contribute to a Swift Bridging PCH hash.
+  llvm::hash_code getPCHHashComponents() const {
+    using llvm::hash_value;
+    using llvm::hash_combine;
+
+    auto Code = hash_value(ModuleCachePath);
+    // ExtraArgs ignored - already considered in Clang's module hashing.
+    Code = hash_combine(Code, OverrideResourceDir);
+    Code = hash_combine(Code, TargetCPU);
+    Code = hash_combine(Code, BridgingHeader);
+    Code = hash_combine(Code, PrecompiledHeaderOutputDir);
+    Code = hash_combine(Code, static_cast<uint8_t>(Mode));
+    Code = hash_combine(Code, DetailedPreprocessingRecord);
+    Code = hash_combine(Code, ImportForwardDeclarations);
+    Code = hash_combine(Code, InferImportAsMember);
+    Code = hash_combine(Code, DisableSwiftBridgeAttr);
+    Code = hash_combine(Code, DisableModulesValidateSystemHeaders);
+    Code = hash_combine(Code, DisableAdapterModules);
+    return Code;
+  }
 };
 
 } // end namespace swift
diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h
index cc42bf6..e71b604 100644
--- a/include/swift/Demangling/Demangler.h
+++ b/include/swift/Demangling/Demangler.h
@@ -99,7 +99,7 @@
     // Do we have enough space in the current slab?
     if (CurPtr + ObjectSize > End) {
       // No. We have to malloc a new slab.
-      // We doulbe the slab size for each allocated slab.
+      // We double the slab size for each allocated slab.
       SlabSize = std::max(SlabSize * 2, ObjectSize + alignof(T));
       size_t AllocSize = sizeof(Slab) + SlabSize;
       Slab *newSlab = (Slab *)malloc(AllocSize);
@@ -125,8 +125,8 @@
 
   /// Tries to enlarge the \p Capacity of an array of \p Objects.
   ///
-  /// If \p Objects is allcoated at the end of the current slab and the slab
-  /// has enough free space, the \p Capacity is simpliy enlarged and no new
+  /// If \p Objects is allocated at the end of the current slab and the slab
+  /// has enough free space, the \p Capacity is simply enlarged and no new
   /// allocation needs to be done.
   /// Otherwise a new array of objects is allocated and \p Objects is set to the
   /// new memory address.
@@ -171,7 +171,7 @@
 
   /// Creates a node of kind \p K with a \p Text payload.
   ///
-  /// The \p Text string must be already allocted with the Factory and therefore
+  /// The \p Text string must be already allocated with the Factory and therefore
   /// it is _not_ copied.
   NodePointer createNodeWithAllocatedText(Node::Kind K, llvm::StringRef Text);
 
@@ -184,7 +184,7 @@
 
   /// Creates a node of kind \p K with a \p Text payload.
   ///
-  /// The \p Text string is already allocted with the Factory and therefore
+  /// The \p Text string is already allocated with the Factory and therefore
   /// it is _not_ copied.
   NodePointer createNode(Node::Kind K, const CharVector &Text);
   
@@ -212,7 +212,7 @@
 
   Vector() { }
 
-  /// Construct a vector with an inital capacity.
+  /// Construct a vector with an initial capacity.
   explicit Vector(NodeFactory &Factory, size_t InitialCapacity) {
     init(Factory, InitialCapacity);
   }
@@ -455,6 +455,8 @@
 
   NodePointer demangleObjCTypeName();
 
+  void dump();
+
 public:
   Demangler() {}
   
diff --git a/include/swift/Driver/Compilation.h b/include/swift/Driver/Compilation.h
index ad43cbf..d207911 100644
--- a/include/swift/Driver/Compilation.h
+++ b/include/swift/Driver/Compilation.h
@@ -21,6 +21,7 @@
 #include "swift/Driver/Util.h"
 #include "swift/Basic/ArrayRefView.h"
 #include "swift/Basic/LLVM.h"
+#include "swift/Basic/Statistic.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Chrono.h"
@@ -134,6 +135,9 @@
   /// execute.
   bool ShowDriverTimeCompilation;
 
+  /// When non-null, record various high-level counters to this.
+  std::unique_ptr<UnifiedStatsReporter> Stats;
+
   /// When true, dumps information about why files are being scheduled to be
   /// rebuilt.
   bool ShowIncrementalBuildDecisions = false;
@@ -156,7 +160,8 @@
               bool EnableIncrementalBuild = false,
               bool SkipTaskExecution = false,
               bool SaveTemps = false,
-              bool ShowDriverTimeCompilation = false);
+              bool ShowDriverTimeCompilation = false,
+              std::unique_ptr<UnifiedStatsReporter> Stats = nullptr);
   ~Compilation();
 
   ArrayRefView<std::unique_ptr<const Job>, const Job *, Compilation::unwrap>
diff --git a/include/swift/Driver/DependencyGraph.h b/include/swift/Driver/DependencyGraph.h
index c01cb20..2148cf2 100644
--- a/include/swift/Driver/DependencyGraph.h
+++ b/include/swift/Driver/DependencyGraph.h
@@ -33,6 +33,8 @@
 
 namespace swift {
 
+class UnifiedStatsReporter;
+
 /// The non-templated implementation of DependencyGraph.
 ///
 /// \see DependencyGraph
@@ -65,12 +67,14 @@
   class MarkTracerImpl {
     class Entry;
     llvm::DenseMap<const void *, SmallVector<Entry, 4>> Table;
+    UnifiedStatsReporter *Stats;
 
     friend class DependencyGraphImpl;
   protected:
-    MarkTracerImpl();
+    explicit MarkTracerImpl(UnifiedStatsReporter *Stats);
     ~MarkTracerImpl();
-
+    void countStatsForNodeMarking(const OptionSet<DependencyKind> &Kind,
+                                  bool Cascading) const;
     void printPath(raw_ostream &out, const void *item,
                    llvm::function_ref<void(const void *)> printItem) const;
   };
@@ -223,7 +227,8 @@
   /// This is intended to be a debugging aid.
   class MarkTracer : public MarkTracerImpl {
   public:
-    MarkTracer() = default;
+    explicit MarkTracer(UnifiedStatsReporter *Stats)
+      : MarkTracerImpl(Stats) {}
 
     /// Dump the path that led to \p node.
     void printPath(raw_ostream &out, T node,
diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h
index be74fea..e9fcf8d 100644
--- a/include/swift/Frontend/Frontend.h
+++ b/include/swift/Frontend/Frontend.h
@@ -292,6 +292,11 @@
   bool isDelayedFunctionBodyParsing() const {
     return FrontendOpts.DelayedFunctionBodyParsing;
   }
+
+  /// Retrieve a module hash string that is suitable for uniquely
+  /// identifying the conditions under which the module was built, for use
+  /// in generating a cached PCH file for the bridging header.
+  std::string getPCHHash() const;
 };
 
 /// A class which manages the state and execution of the compiler.
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 35de401..765e4cb 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -14,6 +14,7 @@
 #define SWIFT_FRONTEND_FRONTENDOPTIONS_H
 
 #include "swift/AST/Module.h"
+#include "llvm/ADT/Hashing.h"
 
 #include <string>
 #include <vector>
@@ -192,6 +193,9 @@
   /// \sa swift::SharedTimer
   bool DebugTimeCompilation = false;
 
+  /// The path to which we should output statistics files.
+  std::string StatsOutputDir;
+
   /// Indicates whether function body parsing should be delayed
   /// until the end of all files.
   bool DelayedFunctionBodyParsing = false;
@@ -302,6 +306,12 @@
     OutputFilenames.clear();
     OutputFilenames.push_back(FileName);
   }
+
+  /// Return a hash code of any components from these options that should
+  /// contribute to a Swift Bridging PCH hash.
+  llvm::hash_code getPCHHashComponents() const {
+    return llvm::hash_value(0);
+  }
 };
 
 }
diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h
index feee5d6..b78b942 100644
--- a/include/swift/IDE/Utils.h
+++ b/include/swift/IDE/Utils.h
@@ -306,7 +306,7 @@
   unsigned commonPartsCount(DeclNameViewer &Other) const;
 };
 
-/// This provide a utility for writing to an underlying string buffer mulitiple
+/// This provide a utility for writing to an underlying string buffer multiple
 /// string pieces and retrieve them later when the underlying buffer is stable.
 class DelayedStringRetriever : public raw_ostream {
     SmallVectorImpl<char> &OS;
diff --git a/include/swift/IRGen/LinkEntity.h b/include/swift/IRGen/Linking.h
similarity index 88%
rename from include/swift/IRGen/LinkEntity.h
rename to include/swift/IRGen/Linking.h
index f84cfb1..2027923 100644
--- a/include/swift/IRGen/LinkEntity.h
+++ b/include/swift/IRGen/Linking.h
@@ -1,4 +1,4 @@
-//===--- LinkEntity.h - Named declarations ----------------------*- C++ -*-===//
+//===--- Linking.h - Named declarations and how to link to them -*- C++ -*-===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -10,22 +10,40 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef SWIFT_IRGEN_LINKENTITY_H
-#define SWIFT_IRGEN_LINKENTITY_H
+#ifndef SWIFT_IRGEN_LINKING_H
+#define SWIFT_IRGEN_LINKING_H
 
-#include "swift/AST/Types.h"
 #include "swift/AST/Decl.h"
 #include "swift/AST/ProtocolConformance.h"
+#include "swift/AST/Types.h"
 #include "swift/IRGen/ValueWitness.h"
-#include "swift/SIL/SILModule.h"
 #include "swift/SIL/SILFunction.h"
 #include "swift/SIL/SILGlobalVariable.h"
+#include "swift/SIL/SILModule.h"
 #include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/IR/GlobalValue.h"
+
+namespace llvm {
+class Triple;
+}
 
 namespace swift {
 namespace irgen {
 class IRGenModule;
 
+/// Determine if the triple uses the DLL storage.
+bool useDllStorage(const llvm::Triple &triple);
+
+class UniversalLinkageInfo {
+public:
+  bool IsELFObject, UseDLLStorage, HasMultipleIGMs, IsWholeModule;
+
+  UniversalLinkageInfo(IRGenModule &IGM);
+
+  UniversalLinkageInfo(const llvm::Triple &triple, bool hasMultipleIGMs,
+                       bool isWholeModule);
+};
+
 /// Selector for type metadata symbol kinds.
 enum class TypeMetadataAddress {
   AddressPoint,
@@ -75,7 +93,7 @@
     /// A function.
     /// The pointer is a FuncDecl*.
     Function,
-    
+
     /// The offset to apply to a witness table or metadata object
     /// in order to find the information for a declaration.  The
     /// pointer is a ValueDecl*.
@@ -99,7 +117,7 @@
     /// The nominal type descriptor for a nominal type.
     /// The pointer is a NominalTypeDecl*.
     NominalTypeDescriptor,
-    
+
     /// The protocol descriptor for a protocol type.
     /// The pointer is a ProtocolDecl*.
     ProtocolDescriptor,
@@ -113,7 +131,7 @@
 
     /// A SIL function. The pointer is a SILFunction*.
     SILFunction,
-    
+
     /// A SIL global variable. The pointer is a SILGlobalVariable*.
     SILGlobalVariable,
 
@@ -134,7 +152,7 @@
     /// The instantiation function for a generic protocol witness table.
     /// The secondary pointer is a ProtocolConformance*.
     GenericProtocolWitnessTableInstantiationFunction,
-    
+
     /// A function which returns the type metadata for the associated type
     /// of a protocol.  The secondary pointer is a ProtocolConformance*.
     /// The index of the associated type declaration is stored in the data.
@@ -187,7 +205,7 @@
     /// A foreign type metadata candidate.
     /// The pointer is a canonical TypeBase*.
     ForeignTypeMetadataCandidate,
-    
+
     /// A reflection metadata descriptor for a builtin or imported type.
     ReflectionBuiltinDescriptor,
 
@@ -215,7 +233,7 @@
   static bool isTypeKind(Kind k) {
     return k >= Kind::ProtocolWitnessTableLazyAccessFunction;
   }
-  
+
   static bool isProtocolConformanceKind(Kind k) {
     return (k >= Kind::DirectProtocolWitnessTable &&
             k <= Kind::ProtocolWitnessTableLazyCacheVariable);
@@ -409,13 +427,13 @@
     entity.setForType(Kind::ForeignTypeMetadataCandidate, type);
     return entity;
   }
-  
+
   static LinkEntity forNominalTypeDescriptor(NominalTypeDecl *decl) {
     LinkEntity entity;
     entity.setForDecl(Kind::NominalTypeDescriptor, decl);
     return entity;
   }
-  
+
   static LinkEntity forProtocolDescriptor(ProtocolDecl *decl) {
     LinkEntity entity;
     entity.setForDecl(Kind::ProtocolDescriptor, decl);
@@ -444,7 +462,7 @@
     entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILFunction));
     return entity;
   }
-  
+
   static LinkEntity forSILGlobalVariable(SILGlobalVariable *G) {
     LinkEntity entity;
     entity.Pointer = G;
@@ -452,7 +470,7 @@
     entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILGlobalVariable));
     return entity;
   }
-  
+
   static LinkEntity
   forDirectProtocolWitnessTable(const ProtocolConformance *C) {
     LinkEntity entity;
@@ -553,7 +571,7 @@
   void mangle(llvm::raw_ostream &out) const;
   void mangle(SmallVectorImpl<char> &buffer) const;
   std::string mangleAsString() const;
-  SILLinkage getLinkage(IRGenModule &IGM, ForDefinition_t isDefinition) const;
+  SILLinkage getLinkage(ForDefinition_t isDefinition) const;
 
   /// Returns true if this function or global variable is potentially defined
   /// in a different module.
@@ -563,7 +581,7 @@
   /// Returns true if this function or global variable may be inlined into
   /// another module.
   ///
-  bool isFragile(IRGenModule &IGM) const;
+  bool isFragile(ForDefinition_t isDefinition) const;
 
   const ValueDecl *getDecl() const {
     assert(isDeclKind(getKind()));
@@ -656,36 +674,79 @@
 #undef LINKENTITY_GET_FIELD
 #undef LINKENTITY_SET_FIELD
 };
+
+/// Encapsulated information about the linkage of an entity.
+class LinkInfo {
+  LinkInfo() = default;
+
+  llvm::SmallString<32> Name;
+  llvm::GlobalValue::LinkageTypes Linkage;
+  llvm::GlobalValue::VisibilityTypes Visibility;
+  llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass;
+  ForDefinition_t ForDefinition;
+
+public:
+  /// Compute linkage information for the given
+  static LinkInfo get(const UniversalLinkageInfo &linkInfo,
+                      ModuleDecl *swiftModule, const LinkEntity &entity,
+                      ForDefinition_t forDefinition);
+
+  static LinkInfo get(IRGenModule &IGM, const LinkEntity &entity,
+                      ForDefinition_t forDefinition);
+
+  StringRef getName() const {
+    return Name.str();
+  }
+  llvm::GlobalValue::LinkageTypes getLinkage() const {
+    return Linkage;
+  }
+  llvm::GlobalValue::VisibilityTypes getVisibility() const {
+    return Visibility;
+  }
+  llvm::GlobalValue::DLLStorageClassTypes getDLLStorage() const {
+    return DLLStorageClass;
+  }
+
+  bool isForDefinition() const {
+    return ForDefinition;
+  }
+  bool isUsed() const {
+    return ForDefinition && isUsed(Linkage, Visibility, DLLStorageClass);
+  }
+
+  static bool isUsed(llvm::GlobalValue::LinkageTypes Linkage,
+                     llvm::GlobalValue::VisibilityTypes Visibility,
+                     llvm::GlobalValue::DLLStorageClassTypes DLLStorage);
+};
 }
 }
 
 /// Allow LinkEntity to be used as a key for a DenseMap.
- template <> struct llvm::DenseMapInfo<swift::irgen::LinkEntity> {
-   typedef swift::irgen::LinkEntity LinkEntity;
-   static LinkEntity getEmptyKey() {
-     LinkEntity entity;
-     entity.Pointer = nullptr;
-     entity.SecondaryPointer = nullptr;
-     entity.Data = 0;
-     return entity;
-   }
-   static LinkEntity getTombstoneKey() {
-     LinkEntity entity;
-     entity.Pointer = nullptr;
-     entity.SecondaryPointer = nullptr;
-     entity.Data = 1;
-     return entity;
-   }
-   static unsigned getHashValue(const LinkEntity &entity) {
-     return DenseMapInfo<void*>::getHashValue(entity.Pointer)
-       ^ DenseMapInfo<void*>::getHashValue(entity.SecondaryPointer)
-       ^ entity.Data;
-   }
-   static bool isEqual(const LinkEntity &LHS, const LinkEntity &RHS) {
-     return LHS.Pointer == RHS.Pointer &&
-       LHS.SecondaryPointer == RHS.SecondaryPointer &&
-       LHS.Data == RHS.Data;
-   }
- };
+template <> struct llvm::DenseMapInfo<swift::irgen::LinkEntity> {
+  typedef swift::irgen::LinkEntity LinkEntity;
+  static LinkEntity getEmptyKey() {
+    LinkEntity entity;
+    entity.Pointer = nullptr;
+    entity.SecondaryPointer = nullptr;
+    entity.Data = 0;
+    return entity;
+  }
+  static LinkEntity getTombstoneKey() {
+    LinkEntity entity;
+    entity.Pointer = nullptr;
+    entity.SecondaryPointer = nullptr;
+    entity.Data = 1;
+    return entity;
+  }
+  static unsigned getHashValue(const LinkEntity &entity) {
+    return DenseMapInfo<void *>::getHashValue(entity.Pointer) ^
+           DenseMapInfo<void *>::getHashValue(entity.SecondaryPointer) ^
+           entity.Data;
+  }
+  static bool isEqual(const LinkEntity &LHS, const LinkEntity &RHS) {
+    return LHS.Pointer == RHS.Pointer &&
+           LHS.SecondaryPointer == RHS.SecondaryPointer && LHS.Data == RHS.Data;
+  }
+};
 
 #endif
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index 13dd289..22c7a71 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -250,6 +250,9 @@
 def enable_sil_ownership : Flag<["-"], "enable-sil-ownership">,
   HelpText<"Enable the SIL Ownership Model">;
 
+def disable_mandatory_semantic_arc_opts : Flag<["-"], "disable-mandatory-semantic-arc-opts">,
+  HelpText<"Disable the mandatory semantic arc optimizer">;
+
 def assume_parsing_unqualified_ownership_sil : Flag<["-"], "assume-parsing-unqualified-ownership-sil">,
   HelpText<"Assume unqualified SIL ownership when parsing SIL">;
 
@@ -275,6 +278,15 @@
   Flag<["-"], "enable-infer-import-as-member">,
   HelpText<"Infer when a global could be imported as a member">;
 
+def enable_swift3_objc_inference : Flag<["-"], "enable-swift3-objc-inference">,
+  Flags<[FrontendOption, HelpHidden]>,
+HelpText<"Enable Swift 3's @objc inference rules for NSObject-derived classes and 'dynamic' members (emulates Swift 3 behavior)">;
+
+def disable_swift3_objc_inference :
+  Flag<["-"], "disable-swift3-objc-inference">,
+  Flags<[FrontendOption, HelpHidden]>,
+  HelpText<"Disable Swift 3's @objc inference rules for NSObject-derived classes and 'dynamic' members (emulates Swift 4 behavior)">;
+
 def warn_long_function_bodies : Separate<["-"], "warn-long-function-bodies">,
   MetaVarName<"<n>">,
   HelpText<"Warns when type-checking a function takes longer than <n> ms">;
@@ -312,6 +324,9 @@
   MetaVarName<"<50>">,
   HelpText<"Controls the aggressiveness of performance inlining">;
 
+def sil_merge_partial_modules : Flag<["-"], "sil-merge-partial-modules">,
+  HelpText<"Merge SIL from all partial swiftmodules into the final module">;
+
 def sil_link_all : Flag<["-"], "sil-link-all">,
   HelpText<"Link all SIL functions">;
 
diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td
index 2101d5a..6a99fe4 100644
--- a/include/swift/Option/Options.td
+++ b/include/swift/Option/Options.td
@@ -191,6 +191,9 @@
 def driver_time_compilation : Flag<["-"], "driver-time-compilation">,
   Flags<[NoInteractiveOption,DoesNotAffectIncrementalBuild]>,
   HelpText<"Prints the total time it took to execute all compilation tasks">;
+def stats_output_dir: Separate<["-"], "stats-output-dir">,
+  Flags<[FrontendOption, HelpHidden]>,
+  HelpText<"Directory to write unified compilation-statistics files to">;
 
 def emit_dependencies : Flag<["-"], "emit-dependencies">,
   Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
@@ -268,6 +271,10 @@
   Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
   HelpText<"Continue building, even after errors are encountered">;
 
+def warn_swift3_objc_inference : Flag<["-"], "warn-swift3-objc-inference">,
+  Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
+  HelpText<"Warn about deprecated @objc inference in Swift 3">;
+
 // Platform options.
 def enable_app_extension : Flag<["-"], "application-extension">,
   Flags<[FrontendOption, NoInteractiveOption]>,
diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h
index 8b6497b..572a0cd 100644
--- a/include/swift/Runtime/Debug.h
+++ b/include/swift/Runtime/Debug.h
@@ -93,6 +93,10 @@
 extern void
 fatalError(uint32_t flags, const char *format, ...);
 
+/// swift::warning() emits a warning from the runtime.
+extern void
+warning(uint32_t flags, const char *format, ...);
+
 // swift_dynamicCastFailure halts using fatalError()
 // with a description of a failed cast's types.
 LLVM_ATTRIBUTE_NORETURN
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index f38650d..9e8a360 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -1207,6 +1207,13 @@
          ARGS(ObjCClassPtrTy),
          ATTRS(NoUnwind))
 
+// void swift_objc_swift3ImplicitObjCEntrypoint(id self, SEL selector)
+FUNCTION(Swift3ImplicitObjCEntrypoint, swift_objc_swift3ImplicitObjCEntrypoint,
+         DefaultCC,
+         RETURNS(VoidTy),
+         ARGS(ObjCPtrTy, ObjCSELTy),
+         ATTRS(NoUnwind))
+
 #endif
 
 #undef RETURNS
diff --git a/include/swift/SIL/OwnershipChecker.h b/include/swift/SIL/OwnershipChecker.h
new file mode 100644
index 0000000..2cebdd5
--- /dev/null
+++ b/include/swift/SIL/OwnershipChecker.h
@@ -0,0 +1,53 @@
+//===--- OwnershipChecker.h -----------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_SIL_OWNERSHIPCHECKER_H
+#define SWIFT_SIL_OWNERSHIPCHECKER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+namespace swift {
+
+class SILBasicBlock;
+class SILInstruction;
+class SILModule;
+class SILValue;
+class TransitivelyUnreachableBlocksInfo;
+
+/// This class is a higher level interface to the ownership checker meant for
+/// use with SILPasses. It uses the actual checker as an internal PImpl detail
+/// so types/etc do not leak.
+struct OwnershipChecker {
+  /// The module that we are in.
+  SILModule &Mod;
+
+  /// A cache of unreachable function blocks that we use to determine if we can
+  /// ignore "leaks".
+  const TransitivelyUnreachableBlocksInfo &TUB;
+
+  /// The list of regular users from the last run of the checker.
+  llvm::SmallVector<SILInstruction *, 16> RegularUsers;
+
+  /// The list of regular users from the last run of the checker.
+  llvm::SmallVector<SILInstruction *, 16> LifetimeEndingUsers;
+
+  /// The live blocks for the SILValue we processed. This can be used to
+  /// determine if a block is in the "live" region of our SILInstruction.
+  llvm::SmallPtrSet<SILBasicBlock *, 32> LiveBlocks;
+
+  bool checkValue(SILValue Value);
+};
+
+} // end swift namespace
+
+#endif
diff --git a/include/swift/SIL/Projection.h b/include/swift/SIL/Projection.h
index 86973a1..c42274d 100644
--- a/include/swift/SIL/Projection.h
+++ b/include/swift/SIL/Projection.h
@@ -681,9 +681,7 @@
   void verify(SILModule &M);
 
   raw_ostream &print(raw_ostream &OS, SILModule &M);
-  raw_ostream &printProjections(raw_ostream &OS, SILModule &M) const;
   void dump(SILModule &M);
-  void dumpProjections(SILModule &M) const;
 };
 
 /// Returns the hashcode for the new projection path.
diff --git a/include/swift/SIL/SILBasicBlock.h b/include/swift/SIL/SILBasicBlock.h
index ee8bd11..5ed29e1 100644
--- a/include/swift/SIL/SILBasicBlock.h
+++ b/include/swift/SIL/SILBasicBlock.h
@@ -28,6 +28,7 @@
 class SILArgument;
 class SILPHIArgument;
 class SILFunctionArgument;
+class SILPrintContext;
 
 class SILBasicBlock :
 public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock> {
@@ -335,6 +336,9 @@
   /// Pretty-print the SILBasicBlock with the designated stream.
   void print(llvm::raw_ostream &OS) const;
 
+  /// Pretty-print the SILBasicBlock with the designated stream and context.
+  void print(llvm::raw_ostream &OS, SILPrintContext &Ctx) const;
+
   void printAsOperand(raw_ostream &OS, bool PrintType = true);
 
   /// getSublistAccess() - returns pointer to member of instruction list
diff --git a/include/swift/SIL/SILDebugScope.h b/include/swift/SIL/SILDebugScope.h
index cc8fa21..cb75ee8 100644
--- a/include/swift/SIL/SILDebugScope.h
+++ b/include/swift/SIL/SILDebugScope.h
@@ -46,82 +46,28 @@
   /// An optional chain of inlined call sites.
   ///
   /// If this scope is inlined, this points to a special "scope" that
-  /// holds only the location of the call site. The parent scope will be
-  /// the scope of the inlined call site.
-  ///
-  /// Note that compared to the inlinedAt chain in llvm::DILocation
-  /// SILDebugScope represents an inline tree.
+  /// holds the location of the call site.
   const SILDebugScope *InlinedCallSite;
 
   SILDebugScope(SILLocation Loc, SILFunction *SILFn,
                 const SILDebugScope *ParentScope = nullptr,
-                const SILDebugScope *InlinedCallSite = nullptr)
-      : Loc(Loc), InlinedCallSite(InlinedCallSite) {
-    if (ParentScope)
-      Parent = ParentScope;
-    else {
-      assert(SILFn && "no parent provided");
-      Parent = SILFn;
-    }
-  }
+                const SILDebugScope *InlinedCallSite = nullptr);
 
   /// Create a scope for an artificial function.
-  SILDebugScope(SILLocation Loc)
-      : Loc(Loc), InlinedCallSite(nullptr) {}
-
-  /// Create an inlined version of CalleeScope.
-  SILDebugScope(const SILDebugScope *CallSiteScope,
-                const SILDebugScope *CalleeScope)
-    : Loc(CalleeScope->Loc), Parent(CalleeScope),
-        InlinedCallSite(CallSiteScope) {
-    assert(CallSiteScope && CalleeScope);
-    if (InlinedCallSite)
-      assert(!InlinedCallSite->InlinedCallSite &&
-             "a call site scope cannot have an inlined call site");
-  }
+  SILDebugScope(SILLocation Loc);
 
   /// Return the function this scope originated from before being inlined.
-  SILFunction *getInlinedFunction() const {
-    if (Parent.isNull())
-      return nullptr;
+  SILFunction *getInlinedFunction() const;
 
-    const SILDebugScope *Scope = this;
-    while (Scope->Parent.is<const SILDebugScope *>())
-      Scope = Scope->Parent.get<const SILDebugScope *>();
-    assert(Scope->Parent.is<SILFunction *>() && "orphaned scope");
-    return Scope->Parent.get<SILFunction *>();
-  }
-
-  /// Return this scope without inline information.
-  const SILDebugScope *getInlinedScope() const {
-    return InlinedCallSite ? Parent.get<const SILDebugScope*>() : this;
-  }
-  
   /// Return the parent function of this scope. If the scope was
   /// inlined this recursively returns the function it was inlined
   /// into.
-  SILFunction *getParentFunction() const {
-    if (InlinedCallSite)
-      return InlinedCallSite->Parent.get<const SILDebugScope *>()
-          ->getParentFunction();
-    if (auto *ParentScope = Parent.dyn_cast<const SILDebugScope *>())
-      return ParentScope->getParentFunction();
-    return Parent.get<SILFunction *>();
-  }
+  SILFunction *getParentFunction() const;
 
-  typedef SmallVector<const SILDebugScope *, 8> InlineScopeList;
-  static void flatten(const SILDebugScope *DS, InlineScopeList &List);
-
-  // Return a flattened representation of the inline scope tree that
-  // is equivalent to the reversed inlined-at chain.
-  InlineScopeList flattenedInlineTree() const {
-    InlineScopeList List;
-    flatten(this, List);
-    return List;
-  }
-
+#ifndef NDEBUG
   void dump(SourceManager &SM, llvm::raw_ostream &OS = llvm::errs(),
             unsigned Indent = 0) const;
+#endif
 };
 
 #ifndef NDEBUG
diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h
index 81c236c..169674f 100644
--- a/include/swift/SIL/SILFunction.h
+++ b/include/swift/SIL/SILFunction.h
@@ -32,9 +32,6 @@
 class ASTContext;
 class SILInstruction;
 class SILModule;
-namespace Lowering {
-class TypeLowering;
-} // namespace Lowering
 
 enum IsBare_t { IsNotBare, IsBare };
 enum IsTransparent_t { IsNotTransparent, IsTransparent };
@@ -603,10 +600,6 @@
     GenericEnv = env;
   }
 
-  /// Returns the type lowering for the \p Type given the generic signature of
-  /// the current function.
-  const Lowering::TypeLowering &getTypeLowering(SILType Type) const;
-
   /// Map the given type, which is based on an interface SILFunctionType and may
   /// therefore be dependent, to a type based on the context archetypes of this
   /// SILFunction.
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index c029d20..c624922 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -4501,7 +4501,7 @@
 /// An unsafe conversion in between ownership kinds.
 ///
 /// This is used today in destructors where due to objective-c legacy
-/// constraints, we need to be able to convert a guaranteed paramter to an owned
+/// constraints, we need to be able to convert a guaranteed parameter to an owned
 /// parameter.
 class UncheckedOwnershipConversionInst
     : public UnaryInstructionBase<ValueKind::UncheckedOwnershipConversionInst> {
diff --git a/include/swift/SIL/SILLocation.h b/include/swift/SIL/SILLocation.h
index cc240fa..7b7ab4e 100644
--- a/include/swift/SIL/SILLocation.h
+++ b/include/swift/SIL/SILLocation.h
@@ -410,9 +410,12 @@
   SourceLoc getSourceLoc() const;
   SourceLoc getStartSourceLoc() const;
   SourceLoc getEndSourceLoc() const;
-  
   SourceRange getSourceRange() const {
-    return { getStartSourceLoc(), getEndSourceLoc() };
+    return {getStartSourceLoc(), getEndSourceLoc()};
+  }
+  DebugLoc getDebugInfoLoc() const {
+    assert(isDebugInfoLoc());
+    return Loc.DebugInfoLoc;
   }
 
   /// Fingerprint a DebugLoc for use in a DenseMap.
diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h
index 97598c0..3d23411 100644
--- a/include/swift/SIL/SILModule.h
+++ b/include/swift/SIL/SILModule.h
@@ -200,6 +200,9 @@
   /// optimizations can assume that they see the whole module.
   bool wholeModule;
 
+  /// True if this SILModule is being completely serialized.
+  bool WholeModuleSerialized;
+
   /// The options passed into this SILModule.
   SILOptions &Options;
 
@@ -210,7 +213,7 @@
   // Intentionally marked private so that we need to use 'constructSIL()'
   // to construct a SILModule.
   SILModule(ModuleDecl *M, SILOptions &Options, const DeclContext *associatedDC,
-            bool wholeModule);
+            bool wholeModule, bool wholeModuleSerialized);
 
   SILModule(const SILModule&) = delete;
   void operator=(const SILModule&) = delete;
@@ -275,10 +278,12 @@
 
   /// \brief Create and return an empty SIL module that we can
   /// later parse SIL bodies directly into, without converting from an AST.
-  static std::unique_ptr<SILModule> createEmptyModule(ModuleDecl *M,
-                                                      SILOptions &Options,
-                                                      bool WholeModule = false) {
-    return std::unique_ptr<SILModule>(new SILModule(M, Options, M, WholeModule));
+  static std::unique_ptr<SILModule>
+  createEmptyModule(ModuleDecl *M, SILOptions &Options,
+                    bool WholeModule = false,
+                    bool WholeModuleSerialized = false) {
+    return std::unique_ptr<SILModule>(
+        new SILModule(M, Options, M, WholeModule, WholeModuleSerialized));
   }
 
   /// Get the Swift module associated with this SIL module.
@@ -306,6 +311,9 @@
     return wholeModule;
   }
 
+  /// Returns true if everything in this SILModule is being serialized.
+  bool isWholeModuleSerialized() const { return WholeModuleSerialized; }
+
   SILOptions &getOptions() const { return Options; }
 
   using iterator = FunctionListType::iterator;
@@ -459,6 +467,10 @@
   /// Link in all VTables in the module.
   void linkAllVTables();
 
+  /// Link all definitions in all segments that are logically part of
+  /// the same AST module.
+  void linkAllFromCurrentModule();
+
   /// \brief Return the declaration of a utility function that can,
   /// but needn't, be shared between modules.
   SILFunction *getOrCreateSharedFunction(SILLocation loc,
diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def
index 472efe0..8221f00 100644
--- a/include/swift/SIL/SILNodes.def
+++ b/include/swift/SIL/SILNodes.def
@@ -202,7 +202,7 @@
 
   // Metatypes
   INST(MetatypeInst, SILInstruction, metatype, None, DoesNotRelease)
-  INST(ValueMetatypeInst, SILInstruction, value_metatype, None, DoesNotRelease)
+  INST(ValueMetatypeInst, SILInstruction, value_metatype, MayRead, DoesNotRelease)
   INST(ExistentialMetatypeInst, SILInstruction, existential_metatype, MayRead, DoesNotRelease)
   INST(ObjCProtocolInst, SILInstruction, objc_protocol, None, DoesNotRelease)
 
diff --git a/include/swift/SIL/SILPrintContext.h b/include/swift/SIL/SILPrintContext.h
index 20cbe52..df63da5 100644
--- a/include/swift/SIL/SILPrintContext.h
+++ b/include/swift/SIL/SILPrintContext.h
@@ -13,6 +13,8 @@
 #ifndef SWIFT_SIL_PRINTCONTEXT_H
 #define SWIFT_SIL_PRINTCONTEXT_H
 
+#include "swift/SIL/SILDebugScope.h"
+#include "swift/SIL/SILValue.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -21,10 +23,42 @@
 class SILDebugScope;
 class SILInstruction;
 class SILFunction;
+class SILBasicBlock;
 
 /// Used as context for the SIL print functions.
 class SILPrintContext {
+public:
+  struct ID {
+    enum ID_Kind { SILBasicBlock, SILUndef, SSAValue } Kind;
+    unsigned Number;
+
+    // A stable ordering of ID objects.
+    bool operator<(ID Other) const {
+      if (unsigned(Kind) < unsigned(Other.Kind))
+        return true;
+      if (Number < Other.Number)
+        return true;
+      return false;
+    }
+
+    void print(raw_ostream &OS);
+  };
+
 protected:
+  // Cache block and value identifiers for this function. This is useful in
+  // general for identifying entities, not just emitting textual SIL.
+  //
+  // TODO: It would be more discplined for the caller to provide a function
+  // context. That way it would be impossible for IDs to change meaning within
+  // the caller's scope.
+  struct SILPrintFunctionContext {
+    const SILFunction *F = nullptr;
+    llvm::DenseMap<const SILBasicBlock *, unsigned> BlocksToIDMap;
+    llvm::DenseMap<const ValueBase *, unsigned> ValueToIDMap;
+  };
+
+  SILPrintFunctionContext FuncCtx;
+
   llvm::raw_ostream &OutStream;
 
   llvm::DenseMap<const SILDebugScope *, unsigned> ScopeToIDMap;
@@ -42,6 +76,11 @@
 
   virtual ~SILPrintContext();
 
+  SILPrintFunctionContext &getFuncContext(const SILFunction *F);
+
+  // Initialized block IDs from the order provided in `blocks`.
+  void initBlockIDs(ArrayRef<const SILBasicBlock *> Blocks);
+
   /// Returns the output stream for printing.
   llvm::raw_ostream &OS() const { return OutStream; }
 
@@ -51,6 +90,10 @@
   /// Returns true if verbose SIL should be printed.
   bool printVerbose() const { return Verbose; }
 
+  SILPrintContext::ID getID(const SILBasicBlock *Block);
+
+  SILPrintContext::ID getID(SILValue V);
+
   /// Returns true if the \p Scope has and ID assigned.
   bool hasScopeID(const SILDebugScope *Scope) const {
     return ScopeToIDMap.count(Scope) != 0;
@@ -74,6 +117,8 @@
   virtual void printInstructionCallBack(const SILInstruction *I);
 };
 
+raw_ostream &operator<<(raw_ostream &OS, SILPrintContext::ID i);
+
 } // end namespace swift
 
 #endif /* SWIFT_SIL_PRINTCONTEXT_H */
diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h
index f21e166..3d82399 100644
--- a/include/swift/SIL/SILValue.h
+++ b/include/swift/SIL/SILValue.h
@@ -174,6 +174,7 @@
   bool use_empty() const { return FirstUse == nullptr; }
 
   using use_iterator = ValueBaseUseIterator;
+  using use_range = iterator_range<use_iterator>;
 
   inline use_iterator use_begin() const;
   inline use_iterator use_end() const;
@@ -181,13 +182,17 @@
   /// Returns a range of all uses, which is useful for iterating over all uses.
   /// To ignore debug-info instructions use swift::getNonDebugUses instead
   /// (see comment in DebugUtils.h).
-  inline iterator_range<use_iterator> getUses() const;
+  inline use_range getUses() const;
 
   /// Returns true if this value has exactly one use.
   /// To ignore debug-info instructions use swift::hasOneNonDebugUse instead
   /// (see comment in DebugUtils.h).
   inline bool hasOneUse() const;
 
+  /// Returns .some(single user) if this value has a single user. Returns .none
+  /// otherwise.
+  inline Operand *getSingleUse() const;
+
   /// Pretty-print the value.
   void dump() const;
   void print(raw_ostream &OS) const;
@@ -499,6 +504,23 @@
   if (I == E) return false;
   return ++I == E;
 }
+inline Operand *ValueBase::getSingleUse() const {
+  auto I = use_begin(), E = use_end();
+
+  // If we have no elements, return nullptr.
+  if (I == E) return nullptr;
+
+  // Otherwise, grab the first element and then increment.
+  Operand *Op = *I;
+  ++I;
+
+  // If the next element is not the end list, then return nullptr. We do not
+  // have one user.
+  if (I != E) return nullptr;
+
+  // Otherwise, the element that we accessed.
+  return Op;
+}
 
 /// A constant-size list of the operands of an instruction.
 template <unsigned N> class FixedOperandList {
diff --git a/lib/SIL/TransitivelyUnreachableBlocks.h b/include/swift/SIL/TransitivelyUnreachableBlocks.h
similarity index 100%
rename from lib/SIL/TransitivelyUnreachableBlocks.h
rename to include/swift/SIL/TransitivelyUnreachableBlocks.h
diff --git a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
index bd4e6be..9d8c067 100644
--- a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
+++ b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
@@ -196,6 +196,7 @@
   SILFunction *F;
   RCIdentityFunctionInfo *RCFI;
   ExitKind Kind;
+  ArrayRef<SILArgumentConvention> ArgumentConventions;
   llvm::SmallMapVector<SILArgument *, ReleaseList, 8> ArgInstMap;
 
   /// Set to true if we found some releases but not all for the argument.
@@ -221,6 +222,10 @@
   /// arguments. 
   void collectMatchingReleases(SILBasicBlock *BB);
 
+  /// Walk the function and find all the destroy_addr instructions that match
+  /// to function arguments. 
+  void collectMatchingDestroyAddresses(SILBasicBlock *BB);
+
   /// For every argument in the function, check to see whether all epilogue
   /// releases are found. Clear all releases for the argument if not all 
   /// epilogue releases are found.
@@ -228,9 +233,12 @@
 
 public:
   /// Finds matching releases in the return block of the function \p F.
-  ConsumedArgToEpilogueReleaseMatcher(RCIdentityFunctionInfo *RCFI,
-                                      SILFunction *F,
-                                      ExitKind Kind = ExitKind::Return);
+  ConsumedArgToEpilogueReleaseMatcher(
+      RCIdentityFunctionInfo *RCFI,
+      SILFunction *F,
+      ArrayRef<SILArgumentConvention> ArgumentConventions =
+          {SILArgumentConvention::Direct_Owned},
+      ExitKind Kind = ExitKind::Return);
 
   /// Finds matching releases in the provided block \p BB.
   void findMatchingReleases(SILBasicBlock *BB);
diff --git a/include/swift/SILOptimizer/Analysis/Analysis.h b/include/swift/SILOptimizer/Analysis/Analysis.h
index a62b7d4..ac1a1d2 100644
--- a/include/swift/SILOptimizer/Analysis/Analysis.h
+++ b/include/swift/SILOptimizer/Analysis/Analysis.h
@@ -168,6 +168,12 @@
     /// meant to be overridden by subclasses.
     virtual void verify(AnalysisTy *A) const {}
 
+    void deleteAllAnalysisProviders() {
+      for (auto D : Storage)
+        delete D.second;
+      Storage.clear();
+    }
+
   public:
     /// Returns an analysis provider for a specific function \p F.
     AnalysisTy *get(SILFunction *F) {
@@ -183,7 +189,7 @@
 
     /// Invalidate all information in this analysis.
     virtual void invalidate() override {
-      Storage.clear();
+      deleteAllAnalysisProviders();
     }
 
     /// Helper function to remove the analysis data for a function.
@@ -216,8 +222,7 @@
 
     FunctionAnalysisBase() {}
     virtual ~FunctionAnalysisBase() {
-      for (auto D : Storage)
-        delete D.second;
+      deleteAllAnalysisProviders();
     }
     FunctionAnalysisBase(AnalysisKind K) : SILAnalysis(K), Storage() {}
     FunctionAnalysisBase(const FunctionAnalysisBase &) = delete;
diff --git a/include/swift/SILOptimizer/Analysis/ArraySemantic.h b/include/swift/SILOptimizer/Analysis/ArraySemantic.h
index bd27138..f1bc730 100644
--- a/include/swift/SILOptimizer/Analysis/ArraySemantic.h
+++ b/include/swift/SILOptimizer/Analysis/ArraySemantic.h
@@ -34,8 +34,12 @@
   kMakeMutable,
   kMutateUnknown,
   kWithUnsafeMutableBufferPointer,
+  kAppendContentsOf,
+  kAppendElement,
   // The following two semantic function kinds return the result @owned
-  // instead of operating on self passed as parameter.
+  // instead of operating on self passed as parameter. If you are adding
+  // a function, and it has a self parameter, make sure that it is defined
+  // before this comment.
   kArrayInit,
   kArrayUninitialized
 };
@@ -131,6 +135,12 @@
   /// Returns true on success, false otherwise.
   bool replaceByValue(SILValue V);
 
+  /// Replace a call to append(contentsOf: ) with a series of
+  /// append(element: ) calls.
+  bool replaceByAppendingValues(SILModule &M, SILFunction *AppendFn,
+                                const llvm::SmallVectorImpl<SILValue> &Vals,
+                                ArrayRef<Substitution> Subs);
+
   /// Hoist the call to the insert point.
   void hoist(SILInstruction *InsertBefore, DominanceInfo *DT) {
     hoistOrCopy(InsertBefore, DT, false);
@@ -152,6 +162,9 @@
 
   /// Could this array be backed by an NSArray.
   bool mayHaveBridgedObjectElementType() const;
+  
+  /// Can this function be inlined by the early inliner.
+  bool canInlineEarly() const;
 
 protected:
   /// Validate the signature of this call.
diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def
index 8e66137..3706e26 100644
--- a/include/swift/SILOptimizer/PassManager/Passes.def
+++ b/include/swift/SILOptimizer/PassManager/Passes.def
@@ -251,6 +251,8 @@
      "Use pre-specialized functions")
 PASS(ValueOwnershipKindDumper, "value-ownership-kind-dumper",
      "Print the value ownership kind of all ValueBase in a SILModule")
+PASS(SemanticARCOpts, "semantic-arc-opts",
+     "Pass for performing semantic ARC optimizations")
 PASS(BugReducerTester, "bug-reducer-tester",
      "Utility pass for testing sil-bug-reducer. Asserts when visits an apply that calls a specific function")
 PASS_RANGE(AllPasses, AADumper, BugReducerTester)
diff --git a/include/swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h b/include/swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h
index c886035..4e25561 100644
--- a/include/swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h
+++ b/include/swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h
@@ -36,7 +36,7 @@
   SILFunctionArgument *Arg;
 
   /// Parameter Info.
-  SILParameterInfo PInfo;
+  Optional<SILParameterInfo> PInfo;
 
   /// The original index of this argument.
   unsigned Index;
@@ -78,11 +78,17 @@
   /// have access to the original argument's state if we modify the argument
   /// when optimizing.
   ArgumentDescriptor(SILFunctionArgument *A)
-      : Arg(A), PInfo(A->getKnownParameterInfo()), Index(A->getIndex()),
+      : Arg(A),
+        PInfo(A->getKnownParameterInfo()),
+        Index(A->getIndex()),
         Decl(A->getDecl()), IsEntirelyDead(false), Explode(false),
         OwnedToGuaranteed(false), IsIndirectResult(A->isIndirectResult()),
         CalleeRelease(), CalleeReleaseInThrowBlock(),
-        ProjTree(A->getModule(), A->getType()) {}
+        ProjTree(A->getModule(), A->getType()) {
+        if(!A->isIndirectResult()) {
+           PInfo = Arg->getKnownParameterInfo();
+        }
+  }
 
   ArgumentDescriptor(const ArgumentDescriptor &) = delete;
   ArgumentDescriptor(ArgumentDescriptor &&) = default;
@@ -95,7 +101,15 @@
   }
 
   bool canOptimizeLiveArg() const {
-    return Arg->getType().isObject();
+    if (Arg->getType().isObject())
+      return true;
+    // @in arguments of generic types can be processed.
+    if (Arg->getType().getSwiftRValueType()->hasArchetype() &&
+        Arg->getType().isAddress() &&
+        (Arg->hasConvention(SILArgumentConvention::Indirect_In) ||
+         Arg->hasConvention(SILArgumentConvention::Indirect_In_Guaranteed)))
+      return true;
+    return false;
   }
 
   /// Return true if it's both legal and a good idea to explode this argument.
diff --git a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h
index f9049f7..177d531 100644
--- a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h
+++ b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h
@@ -169,10 +169,12 @@
   }
 
   /// Print the LSBase.
-  virtual void print(SILModule *Mod) { 
-    llvm::outs() << Base;
-    Path.getValue().print(llvm::outs(), *Mod);
+  virtual void print(llvm::raw_ostream &os, SILModule *Mod) { 
+    os << Base;
+    Path.getValue().print(os, *Mod);
   }
+
+  virtual void dump(SILModule *Mod) { print(llvm::dbgs(), Mod); }
 };
 
 static inline llvm::hash_code hash_value(const LSBase &S) {
@@ -255,12 +257,12 @@
     return Path.getValue().createExtract(Base, Inst, true);
   }
 
-  void print(SILModule *Mod) {
+  void print(llvm::raw_ostream &os, SILModule *Mod) {
     if (CoveringValue) {
-      llvm::outs() << "Covering Value";
+      os << "Covering Value";
       return;
     }
-    LSBase::print(Mod);
+    LSBase::print(os, Mod);
   }
 
   /// Expand this SILValue to all individual fields it contains.
diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h
index 872cc65..9617b05 100644
--- a/include/swift/SILOptimizer/Utils/Local.h
+++ b/include/swift/SILOptimizer/Utils/Local.h
@@ -277,6 +277,11 @@
 
   /// Returns the last use of the value in the live block \p BB.
   SILInstruction *findLastUserInBlock(SILBasicBlock *BB);
+
+  /// Returns true if the value is alive at the begin of block \p BB.
+  bool isAliveAtBeginOfBlock(SILBasicBlock *BB) {
+    return LiveBlocks.count(BB) && BB != DefValue->getParentBlock();
+  }
 };
 
 /// Base class for BB cloners.
diff --git a/include/swift/SILOptimizer/Utils/SILInliner.h b/include/swift/SILOptimizer/Utils/SILInliner.h
index a1cbe59..f88769e 100644
--- a/include/swift/SILOptimizer/Utils/SILInliner.h
+++ b/include/swift/SILOptimizer/Utils/SILInliner.h
@@ -51,7 +51,7 @@
              CloneCollector::CallbackType Callback = nullptr)
       : TypeSubstCloner<SILInliner>(To, From, ApplySubs,
                                     OpenedArchetypesTracker, true),
-        IKind(IKind), CalleeEntryBB(nullptr), CallSiteScope(nullptr),
+        IKind(IKind), CalleeEntryBB(nullptr),
         Callback(Callback) {
   }
 
@@ -114,7 +114,7 @@
   /// Alternatively, it can be the SIL file location of the call site (in case
   /// of SIL-to-SIL transformations).
   Optional<SILLocation> Loc;
-  const SILDebugScope *CallSiteScope;
+  const SILDebugScope *CallSiteScope = nullptr;
   SILFunction *CalleeFunction;
   llvm::SmallDenseMap<const SILDebugScope *,
                       const SILDebugScope *> InlinedScopeCache;
diff --git a/include/swift/SILOptimizer/Utils/StackNesting.h b/include/swift/SILOptimizer/Utils/StackNesting.h
index 9b4c41c..105ae28 100644
--- a/include/swift/SILOptimizer/Utils/StackNesting.h
+++ b/include/swift/SILOptimizer/Utils/StackNesting.h
@@ -143,7 +143,8 @@
   ///
   /// Returns true if any deallocations were inserted.
   bool insertDeallocs(const BitVector &AliveBefore, const BitVector &AliveAfter,
-                      SILInstruction *InsertionPoint);
+                      SILInstruction *InsertionPoint,
+                      Optional<SILLocation> Location);
 
   /// Modifies the SIL to end up with a correct stack nesting.
   ///
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index af9ec03..1b1189d 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,7 @@
 /// in source control, you should also update the comment to briefly
 /// describe what change you made. The content of this comment isn't important;
 /// it just ensures a conflict if two people change the module format.
-const uint16_t VERSION_MINOR = 328; // Last change: fragile => serialized
+const uint16_t VERSION_MINOR = 331; // Last change: type witness substitutions
 
 using DeclID = PointerEmbeddedInt<unsigned, 31>;
 using DeclIDField = BCFixed<31>;
@@ -1135,7 +1135,6 @@
     DeclContextIDField, // the decl that provided this conformance
     BCVBR<5>, // value mapping count
     BCVBR<5>, // type mapping count
-    BCVBR<5>, // inherited conformances count
     BCArray<DeclIDField>
     // The array contains archetype-value pairs, then type declarations.
     // Inherited conformances follow, then the substitution records for the
@@ -1354,6 +1353,7 @@
   using ObjCDeclAttrLayout = BCRecordLayout<
     ObjC_DECL_ATTR,
     BCFixed<1>, // implicit flag
+    BCFixed<1>, // Swift 3 inferred
     BCFixed<1>, // implicit name flag
     BCVBR<4>,   // # of arguments (+1) or zero if no name
     BCArray<IdentifierIDField>
diff --git a/include/swift/Serialization/SerializedSILLoader.h b/include/swift/Serialization/SerializedSILLoader.h
index bbecd10..8401628 100644
--- a/include/swift/Serialization/SerializedSILLoader.h
+++ b/include/swift/Serialization/SerializedSILLoader.h
@@ -112,6 +112,12 @@
 
   /// Deserialize all SILFunctions, VTables, and WitnessTables for
   /// a given Module.
+  ///
+  /// If PrimaryFile is nullptr, all definitions are brought in with
+  /// definition linkage.
+  ///
+  /// Otherwise, definitions not in the primary file are brought in
+  /// with external linkage.
   void getAllForModule(Identifier Mod, FileUnit *PrimaryFile);
 
   /// Deserialize all SILFunctions in all SILModules.
diff --git a/include/swift/Syntax/DeclSyntax.h b/include/swift/Syntax/DeclSyntax.h
index e5031b3..f659676 100644
--- a/include/swift/Syntax/DeclSyntax.h
+++ b/include/swift/Syntax/DeclSyntax.h
@@ -614,7 +614,7 @@
   /// between the parameter type and the default value.
   FunctionParameterSyntax withEqualToken(RC<TokenSyntax> NewEqualToken) const;
 
-  /// Return the expresion for the default value of the parameter, if there
+  /// Return the expression for the default value of the parameter, if there
   /// is one.
   llvm::Optional<ExprSyntax> getDefaultValue() const;
 
@@ -712,7 +712,7 @@
   /// Return the left parenthesis '(' token enclosing the parameter list.
   RC<TokenSyntax> getLeftParenToken() const;
 
-  /// Return a FunctionSignatureSyntax with the given left parentesis '(' token
+  /// Return a FunctionSignatureSyntax with the given left parenthesis '(' token
   /// enclosing the parameter list.
   FunctionSignatureSyntax
   withLeftParenToken(RC<TokenSyntax> NewLeftParen) const;
@@ -727,7 +727,7 @@
   /// Return the right parenthesis ')' token enclosing the parameter list.
   RC<TokenSyntax> getRightParenToken() const;
 
-  /// Return a FunctionSignatureSyntax with the given right parentesis ')' token
+  /// Return a FunctionSignatureSyntax with the given right parenthesis ')' token
   /// enclosing the parameter list.
   FunctionSignatureSyntax
   withRightParenToken(RC<TokenSyntax> NewRightParen) const;
diff --git a/include/swift/Syntax/ExprSyntax.h b/include/swift/Syntax/ExprSyntax.h
index 1dfbf14..7fe0c02 100644
--- a/include/swift/Syntax/ExprSyntax.h
+++ b/include/swift/Syntax/ExprSyntax.h
@@ -10,7 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file defines the interface for expresion-specific syntax nodes,
+// This file defines the interface for expression-specific syntax nodes,
 // such as 
 //
 //===----------------------------------------------------------------------===//
diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h
index bf740b7..5cfec5c 100644
--- a/include/swift/TBDGen/TBDGen.h
+++ b/include/swift/TBDGen/TBDGen.h
@@ -17,7 +17,8 @@
 namespace swift {
 class FileUnit;
 
-void enumeratePublicSymbols(FileUnit *module, llvm::StringSet<> &symbols);
+void enumeratePublicSymbols(FileUnit *module, llvm::StringSet<> &symbols,
+                            bool hasMultipleIRGenThreads, bool isWholeModule);
 } // end namespace swift
 
 #endif
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index ee2c042..31825c6 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -162,6 +162,9 @@
   /// func ==(Int, Int) -> Bool
   FuncDecl *EqualIntDecl = nullptr;
 
+  /// func append(Element) -> void
+  FuncDecl *ArrayAppendElementDecl = nullptr;
+
   /// func _unimplementedInitializer(className: StaticString).
   FuncDecl *UnimplementedInitializerDecl = nullptr;
 
@@ -886,6 +889,56 @@
   return nullptr;
 }
 
+FuncDecl *ASTContext::getArrayAppendElementDecl() const {
+  if (Impl.ArrayAppendElementDecl)
+    return Impl.ArrayAppendElementDecl;
+
+  auto AppendFunctions = getArrayDecl()->lookupDirect(getIdentifier("append"));
+
+  for (auto CandidateFn : AppendFunctions) {
+    auto FnDecl = dyn_cast<FuncDecl>(CandidateFn);
+    auto Attrs = FnDecl->getAttrs();
+    for (auto *A : Attrs.getAttributes<SemanticsAttr, false>()) {
+      if (A->Value != "array.append_element")
+        continue;
+
+      auto ParamLists = FnDecl->getParameterLists();
+      if (ParamLists.size() != 2)
+        return nullptr;
+      if (ParamLists[0]->size() != 1)
+        return nullptr;
+
+      InOutType *SelfInOutTy =
+        ParamLists[0]->get(0)->getInterfaceType()->getAs<InOutType>();
+      if (!SelfInOutTy)
+        return nullptr;
+
+      BoundGenericStructType *SelfGenericStructTy =
+        SelfInOutTy->getObjectType()->getAs<BoundGenericStructType>();
+      if (!SelfGenericStructTy)
+        return nullptr;
+      if (SelfGenericStructTy->getDecl() != getArrayDecl())
+        return nullptr;
+
+      if (ParamLists[1]->size() != 1)
+        return nullptr;
+      GenericTypeParamType *ElementType = ParamLists[1]->get(0)->
+                             getInterfaceType()->getAs<GenericTypeParamType>();
+      if (!ElementType)
+        return nullptr;
+      if (ElementType->getName() != getIdentifier("Element"))
+        return nullptr;
+
+      if (!FnDecl->getResultInterfaceType()->isVoid())
+        return nullptr;
+
+      Impl.ArrayAppendElementDecl = FnDecl;
+      return FnDecl;
+    }
+  }
+  return nullptr;
+}
+
 FuncDecl *
 ASTContext::getUnimplementedInitializerDecl(LazyResolver *resolver) const {
   if (Impl.UnimplementedInitializerDecl)
@@ -3403,7 +3456,7 @@
 
   llvm::SmallVector<ProtocolDecl *, 4> conformsTo;
   assert(existential->isExistentialType());
-  existential->getAnyExistentialTypeProtocols(conformsTo);
+  existential->getExistentialTypeProtocols(conformsTo);
   Type superclass = existential->getSuperclass(nullptr);
 
   auto arena = AllocationArena::Permanent;
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index 4bfe930..5825fec 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -303,6 +303,7 @@
     // Don't use word-substitutions and punycode encoding.
     MaxNumWords = 0;
     UsePunycode = false;
+    UseSubstitutions = false;
     Buffer << "_Tt";
     bool isProto = false;
     if (isa<ClassDecl>(Nominal)) {
@@ -1484,7 +1485,7 @@
   // This can result in getting the same mangled string for different
   // DependentMemberTypes. This is not a problem but re-mangling might do more
   // aggressive substitutions, which means that the re-mangled name may differ
-  // from the the original mangled name.
+  // from the original mangled name.
   // FIXME: We ought to be able to get to the generic signature from a
   // dependent type, but can't yet. Shouldn't need this side channel.
 
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index e97015b..3bb224d 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -337,6 +337,17 @@
         }
       }
     };
+
+    auto handleExtension = [&](ExtensionDecl *E, bool Synthesized) {
+      if (shouldPrint(E, Options)) {
+        auto Pair = isApplicable(E, Synthesized);
+        if (Pair.first) {
+          InfoMap->insert({E, Pair.first});
+          MergeInfoMap.insert({E, Pair.second});
+        }
+      }
+    };
+
     for (auto TL : Target->getInherited()) {
       if (!isEnumRawType(Target, TL))
         addTypeLocNominal(TL);
@@ -345,13 +356,7 @@
       NominalTypeDecl* Back = Unhandled.back();
       Unhandled.pop_back();
       for (ExtensionDecl *E : Back->getExtensions()) {
-        if (!shouldPrint(E, Options))
-          continue;
-        auto Pair = isApplicable(E, /*Synthesized*/true);
-        if (Pair.first) {
-          InfoMap->insert({E, Pair.first});
-          MergeInfoMap.insert({E, Pair.second});
-        }
+        handleExtension(E, true);
         for (auto TL : Back->getInherited()) {
           if (!isEnumRawType(Target, TL))
             addTypeLocNominal(TL);
@@ -361,12 +366,10 @@
 
     // Merge with actual extensions.
     for (auto *E : Target->getExtensions()) {
-      if (!shouldPrint(E, Options))
-        continue;
-      auto Pair = isApplicable(E, /*Synthesized*/false);
-      if (Pair.first) {
-        InfoMap->insert({E, Pair.first});
-        MergeInfoMap.insert({E, Pair.second});
+      handleExtension(E, false);
+      for (auto *Conf : E->getLocalConformances()) {
+        for (auto E : Conf->getProtocol()->getExtensions())
+          handleExtension(E, true);
       }
     }
 
diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp
index c851382..1974c3a 100644
--- a/lib/AST/ASTVerifier.cpp
+++ b/lib/AST/ASTVerifier.cpp
@@ -1045,9 +1045,17 @@
         abort();
       }
 
-      SmallVector<ProtocolDecl*, 2> protocols;
-      if (!srcTy->isExistentialType(protocols)
-          || protocols.size() != 1
+      if (!srcTy->isExistentialType()) {
+        Out << "ProtocolMetatypeToObject with non-existential metatype:\n";
+        E->print(Out);
+        Out << "\n";
+        abort();
+      }
+
+      SmallVector<ProtocolDecl*, 1> protocols;
+      srcTy->getExistentialTypeProtocols(protocols);
+
+      if (protocols.size() != 1
           || !protocols[0]->isObjC()) {
         Out << "ProtocolMetatypeToObject with non-ObjC-protocol metatype:\n";
         E->print(Out);
@@ -1903,7 +1911,7 @@
         protocolTypes.push_back(proto->getDeclaredType());
       SmallVector<ProtocolDecl *, 4> canonicalProtocols;
       ProtocolCompositionType::get(Ctx, protocolTypes)
-        ->isExistentialType(canonicalProtocols);
+        ->getExistentialTypeProtocols(canonicalProtocols);
       if (nominalProtocols != canonicalProtocols) {
         dumpRef(decl);
         Out << " doesn't have a complete set of protocols\n";
@@ -2008,8 +2016,7 @@
 
           // Make sure that the replacement type only uses archetypes allowed
           // in the context where the normal conformance exists.
-          auto replacementType
-            = normal->getTypeWitness(assocType, nullptr).getReplacement();
+          auto replacementType = normal->getTypeWitness(assocType, nullptr);
           Verifier(M, normal->getDeclContext())
             .verifyChecked(replacementType);
           continue;
diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp
index e80bc66..0685c04 100644
--- a/lib/AST/Attr.cpp
+++ b/lib/AST/Attr.cpp
@@ -624,6 +624,7 @@
   }
 
   ObjCAttrBits.ImplicitName = false;
+  ObjCAttrBits.Swift3Inferred = false;
 }
 
 ObjCAttr *ObjCAttr::create(ASTContext &Ctx, Optional<ObjCSelector> name,
@@ -700,7 +701,9 @@
 }
 
 ObjCAttr *ObjCAttr::clone(ASTContext &context) const {
-  return new (context) ObjCAttr(getName(), isNameImplicit());
+  auto attr = new (context) ObjCAttr(getName(), isNameImplicit());
+  attr->setSwift3Inferred(isSwift3Inferred());
+  return attr;
 }
 
 AvailableAttr *
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index d024526..ee1da99 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -1762,6 +1762,9 @@
 
   case BuiltinValueKind::TSanInoutAccess:
     return getTSanInoutAccess(Context, Id);
+
+  case BuiltinValueKind::Swift3ImplicitObjCEntrypoint:
+    return getBuiltinFunction(Id, {}, TupleType::getEmpty(Context));
   }
 
   llvm_unreachable("bad builtin value!");
diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp
index 51810ec..7df7e94 100644
--- a/lib/AST/ConformanceLookupTable.cpp
+++ b/lib/AST/ConformanceLookupTable.cpp
@@ -1110,7 +1110,7 @@
         continue;
 
       conf->forEachTypeWitness(resolver, [&](const AssociatedTypeDecl *assoc,
-                                             const Substitution &subst,
+                                             Type type,
                                              TypeDecl *typeDecl) -> bool {
         if (typeDecl == member)
           reqs.push_back(const_cast<AssociatedTypeDecl*>(assoc));
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 51962f3..ad4d501 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2316,8 +2316,10 @@
 }
 
 Type AbstractTypeParamDecl::getSuperclass() const {
-  auto *dc = getDeclContext();
-  auto contextTy = dc->mapTypeIntoContext(getDeclaredInterfaceType());
+  auto *genericEnv = getDeclContext()->getGenericEnvironmentOfContext();
+  assert(genericEnv != nullptr && "Too much circularity");
+
+  auto contextTy = genericEnv->mapTypeIntoContext(getDeclaredInterfaceType());
   if (auto *archetype = contextTy->getAs<ArchetypeType>())
     return archetype->getSuperclass();
 
@@ -2327,8 +2329,10 @@
 
 ArrayRef<ProtocolDecl *>
 AbstractTypeParamDecl::getConformingProtocols() const {
-  auto *dc = getDeclContext();
-  auto contextTy = dc->mapTypeIntoContext(getDeclaredInterfaceType());
+  auto *genericEnv = getDeclContext()->getGenericEnvironmentOfContext();
+  assert(genericEnv != nullptr && "Too much circularity");
+
+  auto contextTy = genericEnv->mapTypeIntoContext(getDeclaredInterfaceType());
   if (auto *archetype = contextTy->getAs<ArchetypeType>())
     return archetype->getConformsTo();
 
@@ -2446,6 +2450,10 @@
 }
 
 bool ClassDecl::inheritsSuperclassInitializers(LazyResolver *resolver) {
+  // Get a resolver from the ASTContext if we don't have one already.
+  if (resolver == nullptr)
+    resolver = getASTContext().getLazyResolver();
+
   // Check whether we already have a cached answer.
   switch (static_cast<StoredInheritsSuperclassInits>(
             ClassDeclBits.InheritsSuperclassInits)) {
@@ -2486,8 +2494,10 @@
       return false;
 
     // Resolve this initializer, if needed.
-    if (!ctor->hasInterfaceType())
+    if (!ctor->hasInterfaceType()) {
+      assert(resolver && "Should have a resolver here");
       resolver->resolveDeclSignature(ctor);
+    }
 
     // Ignore any stub implementations.
     if (ctor->hasStubImplementation())
@@ -2720,8 +2730,9 @@
     for (auto inherited : getInherited()) {
       SmallPtrSet<ProtocolDecl *, 4> known;
       if (auto type = inherited.getType()) {
-        SmallVector<ProtocolDecl *, 4> protocols;
-        if (type->isExistentialType(protocols)) {
+        if (type->isExistentialType()) {
+          SmallVector<ProtocolDecl *, 4> protocols;
+          type->getExistentialTypeProtocols(protocols);
           for (auto proto : protocols) {
             if (known.insert(proto).second)
               result.push_back(proto);
@@ -4290,6 +4301,14 @@
   llvm_unreachable("Invalid parameter index");
 }
 
+Type AbstractFunctionDecl::getMethodInterfaceType() const {
+  assert(getDeclContext()->isTypeContext());
+  auto Ty = getInterfaceType();
+  if (Ty->hasError())
+    return ErrorType::get(getASTContext());
+  return Ty->castTo<AnyFunctionType>()->getResult();
+}
+
 bool AbstractFunctionDecl::argumentNameIsAPIByDefault() const {
   // Initializers have argument labels.
   if (isa<ConstructorDecl>(this))
diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp
index 2938047..64313ae 100644
--- a/lib/AST/GenericEnvironment.cpp
+++ b/lib/AST/GenericEnvironment.cpp
@@ -342,58 +342,9 @@
   return getGenericSignature()->getASTContext().AllocateCopy(result);
 }
 
-void GenericEnvironment::populateParentMap(SubstitutionMap &subMap) const {
-  for (auto reqt : getGenericSignature()->getRequirements()) {
-    if (reqt.getKind() != RequirementKind::SameType)
-      continue;
-
-    auto first = reqt.getFirstType();
-    auto second = reqt.getSecondType();
-
-    auto archetype = first.subst(
-        QueryInterfaceTypeSubstitutions(this),
-        MakeAbstractConformanceForGenericType())
-      ->getAs<ArchetypeType>();
-    if (!archetype)
-      continue;
-
-#ifndef NDEBUG
-    auto secondArchetype = second.subst(
-        QueryInterfaceTypeSubstitutions(this),
-        MakeAbstractConformanceForGenericType())
-      ->getAs<ArchetypeType>();
-    assert(secondArchetype == archetype);
-#endif
-
-    if (auto *firstMemTy = first->getAs<DependentMemberType>()) {
-      auto parent = firstMemTy->getBase().subst(
-        QueryInterfaceTypeSubstitutions(this),
-        MakeAbstractConformanceForGenericType())
-          ->getAs<ArchetypeType>();
-      if (parent && archetype->getParent() != parent) {
-        subMap.addParent(CanType(archetype),
-                         CanType(parent),
-                         firstMemTy->getAssocType());
-      }
-    }
-
-    if (auto *secondMemTy = second->getAs<DependentMemberType>()) {
-      auto parent = secondMemTy->getBase().subst(
-        QueryInterfaceTypeSubstitutions(this),
-        MakeAbstractConformanceForGenericType())
-          ->getAs<ArchetypeType>();
-      if (parent && archetype->getParent() != parent) {
-        subMap.addParent(CanType(archetype),
-                         CanType(parent),
-                         secondMemTy->getAssocType());
-      }
-    }
-  }
-}
-
 SubstitutionMap GenericEnvironment::
 getSubstitutionMap(SubstitutionList subs) const {
-  SubstitutionMap result;
+  SubstitutionMap result(const_cast<GenericEnvironment *>(this));
 
   getGenericSignature()->enumeratePairedRequirements(
     [&](Type depTy, ArrayRef<Requirement> reqts) -> bool {
@@ -419,7 +370,6 @@
 
   assert(subs.empty() && "did not use all substitutions?!");
 
-  populateParentMap(result);
   result.verify();
   return result;
 }
@@ -428,7 +378,7 @@
 GenericEnvironment::
 getSubstitutionMap(TypeSubstitutionFn subs,
                    GenericSignature::LookupConformanceFn lookupConformance) const {
-  SubstitutionMap subMap;
+  SubstitutionMap subMap(const_cast<GenericEnvironment *>(this));
 
   getGenericSignature()->enumeratePairedRequirements(
     [&](Type depTy, ArrayRef<Requirement> reqs) -> bool {
@@ -459,7 +409,6 @@
       return false;
     });
 
-  populateParentMap(subMap);
   subMap.verify();
   return subMap;
 }
diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp
index 0d3e63a..234db00 100644
--- a/lib/AST/GenericSignature.cpp
+++ b/lib/AST/GenericSignature.cpp
@@ -377,34 +377,9 @@
   return enumerateGenericParamsUpToDependentType(CanType());
 }
 
-void GenericSignature::populateParentMap(SubstitutionMap &subMap) const {
-  for (auto reqt : getRequirements()) {
-    if (reqt.getKind() != RequirementKind::SameType)
-      continue;
-
-    auto first = reqt.getFirstType();
-    auto second = reqt.getSecondType();
-
-    if (!first->isTypeParameter() || !second->isTypeParameter())
-      continue;
-
-    if (auto *firstMemTy = first->getAs<DependentMemberType>()) {
-      subMap.addParent(second->getCanonicalType(),
-                       firstMemTy->getBase()->getCanonicalType(),
-                       firstMemTy->getAssocType());
-    }
-
-    if (auto *secondMemTy = second->getAs<DependentMemberType>()) {
-      subMap.addParent(first->getCanonicalType(),
-                       secondMemTy->getBase()->getCanonicalType(),
-                       secondMemTy->getAssocType());
-    }
-  }
-}
-
 SubstitutionMap
 GenericSignature::getSubstitutionMap(SubstitutionList subs) const {
-  SubstitutionMap result;
+  SubstitutionMap result(const_cast<GenericSignature *>(this));
 
   enumeratePairedRequirements(
     [&](Type depTy, ArrayRef<Requirement> reqts) -> bool {
@@ -423,7 +398,6 @@
     });
 
   assert(subs.empty() && "did not use all substitutions?!");
-  populateParentMap(result);
   result.verify();
   return result;
 }
@@ -432,7 +406,7 @@
 GenericSignature::
 getSubstitutionMap(TypeSubstitutionFn subs,
                    GenericSignature::LookupConformanceFn lookupConformance) const {
-  SubstitutionMap subMap;
+  SubstitutionMap subMap(const_cast<GenericSignature *>(this));
 
   // Enumerate all of the requirements that require substitution.
   enumeratePairedRequirements([&](Type depTy, ArrayRef<Requirement> reqs) {
@@ -458,7 +432,6 @@
     return false;
   });
 
-  populateParentMap(subMap);
   subMap.verify();
   return subMap;
 }
@@ -581,6 +554,28 @@
   return result;
 }
 
+bool GenericSignature::conformsToProtocol(Type type, ProtocolDecl *proto,
+                                          ModuleDecl &mod) {
+  // FIXME: Deal with concrete conformances here?
+  if (!type->isTypeParameter()) return false;
+
+  auto &builder = *getGenericSignatureBuilder(mod);
+  auto pa = builder.resolveArchetype(type);
+  if (!pa) return false;
+
+  pa = pa->getRepresentative();
+
+  // FIXME: Deal with concrete conformances here?
+  if (pa->isConcreteType()) return false;
+
+  // Check whether the representative conforms to this protocol.
+  if (auto equivClass = pa->getEquivalenceClassIfPresent())
+    if (equivClass->conformsTo.count(proto) > 0)
+      return true;
+
+  return false;
+}
+
 /// Determine whether the given dependent type is equal to a concrete type.
 bool GenericSignature::isConcreteType(Type type, ModuleDecl &mod) {
   return bool(getConcreteType(type, mod));
@@ -819,7 +814,7 @@
       // If this step was computed via the requirement signature, add it
       // directly.
       if (source->usesRequirementSignature) {
-        // Add this step along the path, which involes looking for the
+        // Add this step along the path, which involves looking for the
         // conformance we want (\c conformingProto) within the protocol
         // described by this source.
 
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index 81c958d..c6773f6 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -430,7 +430,7 @@
     totalSizeToAlloc<ProtocolDecl *, WrittenRequirementLoc>(               \
                                            NumProtocolDecls,               \
                                            WrittenReq.isNull()? 0 : 1);    \
-  void *mem = malloc(size);                                                \
+  void *mem = ::operator new(size);                                        \
   auto result = new (mem) RequirementSource ConstructorArgs;               \
   builder.Impl->RequirementSources.InsertNode(result, insertPos);          \
   return result
@@ -829,6 +829,49 @@
   return SourceLoc();
 }
 
+bool FloatingRequirementSource::isExplicit() const {
+  switch (kind) {
+  case Explicit:
+    return true;
+
+  case Inferred:
+    return false;
+
+  case AbstractProtocol:
+    switch (storage.get<const RequirementSource *>()->kind) {
+    case RequirementSource::RequirementSignatureSelf:
+      return true;
+
+    case RequirementSource::Concrete:
+    case RequirementSource::Explicit:
+    case RequirementSource::Inferred:
+    case RequirementSource::NestedTypeNameMatch:
+    case RequirementSource::Parent:
+    case RequirementSource::ProtocolRequirement:
+    case RequirementSource::Superclass:
+      return false;
+    }
+
+  case Resolved:
+    switch (storage.get<const RequirementSource *>()->kind) {
+    case RequirementSource::Explicit:
+      return true;
+
+    case RequirementSource::ProtocolRequirement:
+      return storage.get<const RequirementSource *>()->parent->kind
+        == RequirementSource::RequirementSignatureSelf;
+
+    case RequirementSource::Inferred:
+    case RequirementSource::RequirementSignatureSelf:
+    case RequirementSource::Concrete:
+    case RequirementSource::NestedTypeNameMatch:
+    case RequirementSource::Parent:
+    case RequirementSource::Superclass:
+      return false;
+    }
+  }
+}
+
 GenericSignatureBuilder::PotentialArchetype::~PotentialArchetype() {
   for (const auto &nested : NestedTypes) {
     for (auto pa : nested.second) {
@@ -959,6 +1002,15 @@
   return false;
 }
 
+bool GenericSignatureBuilder::recordUnresolvedRequirement(
+                                         RequirementKind kind,
+                                         UnresolvedType lhs,
+                                         RequirementRHS rhs,
+                                         FloatingRequirementSource source) {
+  // FIXME: Drop the requirement for now. Nothing depends on this.
+  return false;
+}
+
 const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
                       GenericSignatureBuilder::PotentialArchetype *pa,
                       ProtocolDecl *proto) {
@@ -1004,14 +1056,6 @@
     return ResolvedType(t);
   }
 
-  // FIXME: this probably shouldn't exist, the potential archetype modelling of
-  // generic typealiases is fundamentally broken (aka they're not modelled at
-  // all), but some things with them mostly work, so we just maintain that,
-  // despite this causing crashes and weird behavior.
-  static ResolvedType forConcreteTypeFromGenericTypeAlias(Type t) {
-    return ResolvedType(t);
-  }
-
   static ResolvedType forPotentialArchetype(PotentialArchetype *pa) {
     return ResolvedType(pa);
   }
@@ -1026,6 +1070,9 @@
   PotentialArchetype *getPotentialArchetype() const {
     return paOrT.dyn_cast<PotentialArchetype *>();
   }
+
+  bool isType() const { return paOrT.is<Type>(); }
+  bool isPotentialArchetype() const { return paOrT.is<PotentialArchetype *>(); }
 };
 
 /// If there is a same-type requirement to be added for the given nested type
@@ -1043,8 +1090,7 @@
   // Dig out the type witness.
   auto superConformance = superSource->getProtocolConformance();
   auto concreteType =
-    superConformance->getTypeWitness(assocType, builder.getLazyResolver())
-      .getReplacement();
+    superConformance->getTypeWitness(assocType, builder.getLazyResolver());
   if (!concreteType) return;
 
   // Add the same-type constraint.
@@ -1348,9 +1394,9 @@
 
   Type witnessType;
   if (conformance.isConcrete()) {
-    witnessType = conformance.getConcrete()
-                      ->getTypeWitness(assocType, builder.getLazyResolver())
-                      .getReplacement();
+    witnessType =
+      conformance.getConcrete()
+        ->getTypeWitness(assocType, builder.getLazyResolver());
   } else {
     witnessType = DependentMemberType::get(concreteParent, assocType);
   }
@@ -1622,9 +1668,9 @@
         type = type.subst(subMap, SubstFlags::UseErrorType);
 
         builder.addSameTypeRequirement(
-                           ResolvedType::forNewTypeAlias(resultPA),
-                           builder.resolve(type),
-                           RequirementSource::forNestedTypeNameMatch(resultPA));
+                         UnresolvedType(resultPA),
+                         UnresolvedType(type),
+                         RequirementSource::forNestedTypeNameMatch(resultPA));
       }
     }
 
@@ -1984,6 +2030,13 @@
   if (!Impl)
     return;
 
+  SmallVector<RequirementSource *, 4> requirementSources;
+  for (auto &reqSource : Impl->RequirementSources)
+    requirementSources.push_back(&reqSource);
+  Impl->RequirementSources.clear();
+  for (auto reqSource : requirementSources)
+    delete reqSource;
+
   for (auto PA : Impl->PotentialArchetypes)
     delete PA;
 }
@@ -2022,14 +2075,13 @@
 }
 
 auto GenericSignatureBuilder::resolve(UnresolvedType paOrT,
-                                      bool hackTypeFromGenericTypeAlias)
-    -> ResolvedType {
+                                      FloatingRequirementSource source)
+    -> Optional<ResolvedType> {
   auto pa = paOrT.dyn_cast<PotentialArchetype *>();
   if (auto type = paOrT.dyn_cast<Type>()) {
+    // FIXME: Limit the resolution of the archetype based on the source.
     pa = resolveArchetype(type);
     if (!pa) {
-      if (hackTypeFromGenericTypeAlias)
-        return ResolvedType::forConcreteTypeFromGenericTypeAlias(type);
       return ResolvedType::forConcreteType(type);
     }
   }
@@ -2133,6 +2185,13 @@
   if (!PAT->addConformance(Proto, Source, *this))
     return false;
 
+  // FIXME: Ad hoc recursion breaking.
+  if (Visited.count(Proto)) {
+    markPotentialArchetypeRecursive(PAT, Proto, Source);
+    return true;
+  }
+
+
   // Add the requirement to the representative.
   auto T = PAT->getRepresentative();
 
@@ -2214,7 +2273,7 @@
   return false;
 }
 
-bool GenericSignatureBuilder::addLayoutRequirement(
+bool GenericSignatureBuilder::addLayoutRequirementDirect(
                                              PotentialArchetype *PAT,
                                              LayoutConstraint Layout,
                                              const RequirementSource *Source) {
@@ -2236,6 +2295,40 @@
   return false;
 }
 
+bool GenericSignatureBuilder::addLayoutRequirement(
+                                             UnresolvedType subject,
+                                             LayoutConstraint layout,
+                                             FloatingRequirementSource source,
+                                             Type dependentType) {
+  // Resolve the subject.
+  auto resolvedSubject = resolve(subject, source);
+  if (!resolvedSubject) {
+    return recordUnresolvedRequirement(RequirementKind::Layout, subject,
+                                       layout, source);
+  }
+
+  // If this layout constraint applies to a concrete type, we can fully
+  // resolve it now.
+  if (resolvedSubject->isType()) {
+    // If a layout requirement was explicitly written on a concrete type,
+    // complain.
+    if (source.isExplicit() && source.getLoc().isValid()) {
+      Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
+                     0, TypeLoc::withoutLoc(resolvedSubject->getType()), 0);
+      return true;
+    }
+
+    // FIXME: Check whether the layout constraint makes sense for this
+    // concrete type!
+
+    return false;
+  }
+
+  auto pa = resolvedSubject->getPotentialArchetype();
+  return addLayoutRequirementDirect(pa, layout,
+                                    source.getSource(pa, dependentType));
+}
+
 bool GenericSignatureBuilder::updateSuperclass(
                                            PotentialArchetype *T,
                                            Type superclass,
@@ -2273,7 +2366,7 @@
     // Presence of a superclass constraint implies a _Class layout
     // constraint.
     auto layoutReqSource = source->viaSuperclass(*this, nullptr);
-    addLayoutRequirement(T,
+    addLayoutRequirementDirect(T,
                          LayoutConstraint::getLayoutConstraint(
                              superclass->getClassOrBoundGenericClass()->isObjC()
                                  ? LayoutConstraintKind::Class
@@ -2306,7 +2399,7 @@
   return false;
 }
 
-bool GenericSignatureBuilder::addSuperclassRequirement(
+bool GenericSignatureBuilder::addSuperclassRequirementDirect(
                                             PotentialArchetype *T,
                                             Type superclass,
                                             const RequirementSource *source) {
@@ -2318,6 +2411,120 @@
   return updateSuperclass(T, superclass, source);
 }
 
+/// Map an unresolved type to a requirement right-hand-side.
+static GenericSignatureBuilder::RequirementRHS
+toRequirementRHS(GenericSignatureBuilder::UnresolvedType unresolved) {
+  if (auto pa = unresolved.dyn_cast<PotentialArchetype *>())
+    return pa;
+
+  return unresolved.dyn_cast<Type>();
+}
+
+bool GenericSignatureBuilder::addTypeRequirement(
+                             UnresolvedType subject,
+                             UnresolvedType constraint,
+                             FloatingRequirementSource source,
+                             Type dependentType,
+                             llvm::SmallPtrSetImpl<ProtocolDecl *> *visited) {
+  // Make sure we always have a "visited" set to pass down.
+  SmallPtrSet<ProtocolDecl *, 4> visitedSet;
+  if (!visited)
+    visited = &visitedSet;
+
+  // Resolve the constraint.
+  auto resolvedConstraint = resolve(constraint, source);
+  if (!resolvedConstraint) {
+    return recordUnresolvedRequirement(RequirementKind::Conformance, subject,
+                                       toRequirementRHS(constraint), source);
+  }
+
+  // The right-hand side needs to be concrete.
+  if (auto constraintPA = resolvedConstraint->getPotentialArchetype()) {
+    // The constraint type isn't a statically-known constraint.
+    if (source.getLoc().isValid()) {
+      auto constraintType =
+        constraintPA->getDependentType(Impl->GenericParams,
+                                       /*allowUnresolved=*/true);
+      Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
+                     1, TypeLoc::withoutLoc(constraintType), 0);
+    }
+
+    return true;
+  }
+
+  // Check whether we have a reasonable constraint type at all.
+  auto constraintType = resolvedConstraint->getType();
+  assert(constraintType && "Missing constraint type?");
+  if (!constraintType->isExistentialType() &&
+      !constraintType->getClassOrBoundGenericClass()) {
+    if (source.getLoc().isValid() && !constraintType->hasError()) {
+      Type subjectType = subject.dyn_cast<Type>();
+      if (!subjectType)
+        subjectType = subject.get<PotentialArchetype *>()
+                        ->getDependentType(Impl->GenericParams,
+                                           /*allowUnresolved=*/true);
+
+      Diags.diagnose(source.getLoc(), diag::requires_conformance_nonprotocol,
+                     TypeLoc::withoutLoc(subjectType),
+                     TypeLoc::withoutLoc(constraintType));
+    }
+
+    return true;
+  }
+
+  // Resolve the subject. If we can't, delay the constraint.
+  auto resolvedSubject = resolve(subject, source);
+  if (!resolvedSubject) {
+    auto recordedKind =
+      constraintType->isExistentialType()
+        ? RequirementKind::Conformance
+        : RequirementKind::Superclass;
+    return recordUnresolvedRequirement(recordedKind, subject, constraintType,
+                                       source);
+  }
+
+  // If the resolved subject is a type, we can probably perform diagnostics
+  // here.
+  if (resolvedSubject->isType()) {
+    // One cannot explicitly write a constraint on a concrete type.
+    if (source.isExplicit()) {
+      if (source.getLoc().isValid()) {
+        Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
+                       0, TypeLoc::withoutLoc(resolvedSubject->getType()), 0);
+      }
+
+      return true;
+    }
+
+    // FIXME: Check the constraint now.
+    return false;
+  }
+
+  auto subjectPA = resolvedSubject->getPotentialArchetype();
+  assert(subjectPA && "No potential archetype?");
+
+  auto resolvedSource = source.getSource(subjectPA, dependentType);
+
+  // Protocol requirements.
+  if (constraintType->isExistentialType()) {
+    // FIXME: "Class" or arbitrary layout requirements.
+    SmallVector<ProtocolDecl *, 4> protocols;
+    (void)constraintType->getExistentialTypeProtocols(protocols);
+    bool anyErrors = false;
+    for (auto proto : protocols) {
+      if (addConformanceRequirement(subjectPA, proto, resolvedSource,
+                                    *visited))
+        anyErrors = true;
+    }
+
+    return anyErrors;
+  }
+
+  // Superclass constraint.
+  return addSuperclassRequirementDirect(subjectPA, constraintType,
+                                        resolvedSource);
+}
+
 void GenericSignatureBuilder::PotentialArchetype::addSameTypeConstraint(
                                              PotentialArchetype *otherPA,
                                              const RequirementSource *source) {
@@ -2556,26 +2763,46 @@
                                              UnresolvedType paOrT1,
                                              UnresolvedType paOrT2,
                                              FloatingRequirementSource source) {
-  return addSameTypeRequirement(resolve(paOrT1), resolve(paOrT2), source);
+  return addSameTypeRequirement(paOrT1, paOrT2, source,
+                                [&](Type type1, Type type2) {
+      Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
+                     type1, type2);
+    });
 }
+
 bool GenericSignatureBuilder::addSameTypeRequirement(
     UnresolvedType paOrT1, UnresolvedType paOrT2,
     FloatingRequirementSource source,
     llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
-  return addSameTypeRequirement(resolve(paOrT1), resolve(paOrT2), source,
-                                diagnoseMismatch);
+
+  auto resolved1 = resolve(paOrT1, source);
+  if (!resolved1) {
+    return recordUnresolvedRequirement(RequirementKind::SameType, paOrT1,
+                                       toRequirementRHS(paOrT2), source);
+  }
+
+  auto resolved2 = resolve(paOrT2, source);
+  if (!resolved2) {
+    return recordUnresolvedRequirement(RequirementKind::SameType, paOrT1,
+                                       toRequirementRHS(paOrT2), source);
+  }
+
+  return addSameTypeRequirementDirect(*resolved1, *resolved2, source,
+                                      diagnoseMismatch);
 }
-bool GenericSignatureBuilder::addSameTypeRequirement(ResolvedType paOrT1,
-                                                     ResolvedType paOrT2,
-                                                     FloatingRequirementSource source) {
-  return addSameTypeRequirement(paOrT1, paOrT2, source,
-                                [&](Type type1, Type type2) {
+
+bool GenericSignatureBuilder::addSameTypeRequirementDirect(
+                                           ResolvedType paOrT1,
+                                           ResolvedType paOrT2,
+                                           FloatingRequirementSource source) {
+  return addSameTypeRequirementDirect(paOrT1, paOrT2, source,
+                                      [&](Type type1, Type type2) {
     Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
                    type1, type2);
   });
 }
 
-bool GenericSignatureBuilder::addSameTypeRequirement(
+bool GenericSignatureBuilder::addSameTypeRequirementDirect(
     ResolvedType paOrT1, ResolvedType paOrT2, FloatingRequirementSource source,
     llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
   auto pa1 = paOrT1.getPotentialArchetype();
@@ -2664,30 +2891,8 @@
     };
 
     // Protocol requirement.
-    if (auto protocolType = inheritedType->getAs<ProtocolType>()) {
-      if (visited.count(protocolType->getDecl())) {
-        markPotentialArchetypeRecursive(
-                            pa, protocolType->getDecl(),
-                            getFloatingSource().getSource(pa, dependentType));
-
-        return true;
-      }
-
-      return addConformanceRequirement(
-                             pa, protocolType->getDecl(),
-                             getFloatingSource().getSource(pa, dependentType),
-                             visited);
-    }
-
-    // Superclass requirement.
-    if (inheritedType->getClassOrBoundGenericClass()) {
-      return addSuperclassRequirement(
-                            pa, inheritedType,
-                            getFloatingSource().getSource(pa, dependentType));
-    }
-
-    // Note: anything else is an error, to be diagnosed later.
-    return false;
+    return addTypeRequirement(pa, inheritedType, getFloatingSource(),
+                              dependentType, &visited);
   });
 }
 
@@ -2707,65 +2912,30 @@
     return t;
   };
 
-
   switch (Req->getKind()) {
-  case RequirementReprKind::LayoutConstraint: {
-    // FIXME: Need to do something here.
-    PotentialArchetype *PA = resolveArchetype(subst(Req->getSubject()));
-    if (!PA) {
-      // FIXME: Poor location information.
-      // FIXME: Delay diagnostic until after type validation?
-      Diags.diagnose(Req->getColonLoc(), diag::requires_not_suitable_archetype,
-                     0, Req->getSubjectLoc(), 0);
-      return true;
-    }
+  case RequirementReprKind::LayoutConstraint:
+    return addLayoutRequirement(subst(Req->getSubject()),
+                                Req->getLayoutConstraint(),
+                                source, Req->getSubject());
 
-    if (addLayoutRequirement(PA, Req->getLayoutConstraint(),
-                             source.getSource(PA, Req->getSubject())))
-      return true;
-
-    return false;
-  }
-
-  case RequirementReprKind::TypeConstraint: {
-    PotentialArchetype *PA = resolveArchetype(subst(Req->getSubject()));
-    if (!PA) {
-      // FIXME: Poor location information.
-      // FIXME: Delay diagnostic until after type validation?
-      Diags.diagnose(Req->getColonLoc(), diag::requires_not_suitable_archetype,
-                     0, Req->getSubjectLoc(), 0);
-      return true;
-    }
-
-    // Check whether this is a supertype requirement.
-    if (Req->getConstraint()->getClassOrBoundGenericClass()) {
-      return addSuperclassRequirement(PA, subst(Req->getConstraint()),
-                                      source.getSource(PA, Req->getSubject()));
-    }
-
-    SmallVector<ProtocolDecl *, 4> ConformsTo;
-    if (!Req->getConstraint()->isExistentialType(ConformsTo)) {
-      // FIXME: Diagnose this failure here, rather than over in type-checking.
-      return true;
-    }
-
-    // Add each of the protocols.
-    for (auto Proto : ConformsTo)
-      if (addConformanceRequirement(PA, Proto,
-                                    source.getSource(PA, Req->getSubject())))
-        return true;
-
-    return false;
-  }
+  case RequirementReprKind::TypeConstraint:
+    return addTypeRequirement(subst(Req->getSubject()),
+                              subst(Req->getConstraint()),
+                              source, Req->getSubject());
 
   case RequirementReprKind::SameType:
     // Require that at least one side of the requirement contain a type
     // parameter.
     if (!Req->getFirstType()->hasTypeParameter() &&
         !Req->getSecondType()->hasTypeParameter()) {
-      Diags.diagnose(Req->getEqualLoc(), diag::requires_no_same_type_archetype)
-        .highlight(Req->getFirstTypeLoc().getSourceRange())
-        .highlight(Req->getSecondTypeLoc().getSourceRange());
+      if (!Req->getFirstType()->hasError() &&
+          !Req->getSecondType()->hasError()) {
+        Diags.diagnose(Req->getEqualLoc(),
+                       diag::requires_no_same_type_archetype)
+          .highlight(Req->getFirstTypeLoc().getSourceRange())
+          .highlight(Req->getSecondTypeLoc().getSourceRange());
+      }
+
       return true;
     }
 
@@ -2799,49 +2969,18 @@
 
 
   switch (req.getKind()) {
-  case RequirementKind::Superclass: {
-    // FIXME: Diagnose this.
-    PotentialArchetype *pa = resolveArchetype(subst(req.getFirstType()));
-    if (!pa) return false;
+  case RequirementKind::Superclass:
+  case RequirementKind::Conformance:
+    return addTypeRequirement(subst(req.getFirstType()),
+                              subst(req.getSecondType()),
+                              source, req.getFirstType(),
+                              &Visited);
 
-    assert(req.getSecondType()->getClassOrBoundGenericClass());
-    return addSuperclassRequirement(pa, req.getSecondType(),
-                                    source.getSource(pa, req.getFirstType()));
-  }
-
-  case RequirementKind::Layout: {
-    // FIXME: Diagnose this.
-    PotentialArchetype *pa = resolveArchetype(subst(req.getFirstType()));
-    if (!pa) return false;
-
-    return addLayoutRequirement(pa, req.getLayoutConstraint(),
-                                source.getSource(pa, req.getFirstType()));
-  }
-
-  case RequirementKind::Conformance: {
-    // FIXME: Diagnose this.
-    PotentialArchetype *pa = resolveArchetype(subst(req.getFirstType()));
-    if (!pa) return false;
-
-    SmallVector<ProtocolDecl *, 4> conformsTo;
-    (void)req.getSecondType()->isExistentialType(conformsTo);
-
-    // Add each of the protocols.
-    for (auto proto : conformsTo) {
-      if (Visited.count(proto)) {
-        markPotentialArchetypeRecursive(
-                                    pa, proto,
-                                    source.getSource(pa, req.getFirstType()));
-        continue;
-      }
-      if (addConformanceRequirement(pa, proto,
-                                    source.getSource(pa, req.getFirstType()),
-                                    Visited))
-        return true;
-    }
-
-    return false;
-  }
+  case RequirementKind::Layout:
+    return addLayoutRequirement(subst(req.getFirstType()),
+                                req.getLayoutConstraint(),
+                                source,
+                                req.getFirstType());
 
   case RequirementKind::SameType:
     return addSameTypeRequirement(
@@ -3522,11 +3661,11 @@
     // Skip non-derived constraints.
     if (!constraint.source->isDerivedRequirement()) continue;
 
-    sameTypeDFS(constraint.value, component, paToComponent);
+    auto newAnchor = sameTypeDFS(constraint.value, component, paToComponent);
 
     // If this type is better than the anchor, use it for the anchor.
-    if (compareDependentTypes(&constraint.value, &anchor) < 0)
-      anchor = constraint.value;
+    if (compareDependentTypes(&newAnchor, &anchor) < 0)
+      anchor = newAnchor;
   }
 
   return anchor;
@@ -4092,11 +4231,10 @@
       // If this equivalence class is bound to a concrete type, equate the
       // anchor with a concrete type.
       if (Type concreteType = rep->getConcreteType()) {
-        // If the parent of this anchor is also in the equivalence class,
-        // don't create a requirement... it's covered by the "parent"
-        // relationship.
+        // If the parent of this anchor is also a concrete type, don't
+        // create a requirement.
         if (!archetype->isGenericParam() &&
-            archetype->getParent()->getRepresentative() == rep)
+            archetype->getParent()->isConcreteType())
           continue;
 
         auto source =
diff --git a/lib/AST/LayoutConstraint.cpp b/lib/AST/LayoutConstraint.cpp
index 24cd5a6..f1949e9 100644
--- a/lib/AST/LayoutConstraint.cpp
+++ b/lib/AST/LayoutConstraint.cpp
@@ -178,43 +178,43 @@
      E(/* RefCountedObject*/ RefCountedObject),
      E(/* NativeRefCountedObject */ NativeRefCountedObject)},
 
-    // Initiaze the row for TrivialOfExactSize.
+    // Initialize the row for TrivialOfExactSize.
     {E(/* UnknownLayout */ TrivialOfExactSize),
      E(/* TrivialOfExactSize */ TrivialOfExactSize), MERGE_CONFLICT,
      E(/* Trivial */ TrivialOfExactSize), MERGE_CONFLICT, MERGE_CONFLICT,
      MERGE_CONFLICT, MERGE_CONFLICT},
 
-    // Initiaze the row for TrivialOfAtMostSize.
+    // Initialize the row for TrivialOfAtMostSize.
     {E(/* UnknownLayout */ TrivialOfAtMostSize), MERGE_CONFLICT,
      E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize),
      E(/* Trivial */ TrivialOfAtMostSize), MERGE_CONFLICT, MERGE_CONFLICT,
      MERGE_CONFLICT, MERGE_CONFLICT},
 
-    // Initiaze the row for Trivial.
+    // Initialize the row for Trivial.
     {E(/* UnknownLayout */ Trivial),
      E(/* TrivialOfExactSize */ TrivialOfExactSize),
      E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize), E(/* Trivial */ Trivial),
      MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
 
-    // Initiaze the row for Class.
+    // Initialize the row for Class.
     {E(/* UnknownLayout*/ Class), MERGE_CONFLICT, MERGE_CONFLICT,
      MERGE_CONFLICT, E(/* Class */ Class), E(/* NativeClass */ NativeClass),
      E(/* RefCountedObject */ Class),
      E(/* NativeRefCountedObject */ NativeClass)},
 
-    // Initiaze the row for NativeClass.
+    // Initialize the row for NativeClass.
     {E(/* UnknownLayout */ NativeClass), MERGE_CONFLICT, MERGE_CONFLICT,
      MERGE_CONFLICT, E(/* Class */ NativeClass),
      E(/* NativeClass */ NativeClass), E(/* RefCountedObject */ NativeClass),
      E(/* NativeRefCountedObject */ NativeClass)},
 
-    // Initiaze the row for RefCountedObject.
+    // Initialize the row for RefCountedObject.
     {E(/* UnknownLayout */ RefCountedObject), MERGE_CONFLICT, MERGE_CONFLICT,
      MERGE_CONFLICT, E(/* Class */ Class), E(/* NativeClass */ NativeClass),
      E(/* RefCountedObject */ RefCountedObject),
      E(/* NativeRefCountedObject */ NativeRefCountedObject)},
 
-    // Initiaze the row for NativeRefCountedObject.
+    // Initialize the row for NativeRefCountedObject.
     {E(/* UnknownLayout */ NativeRefCountedObject), MERGE_CONFLICT,
      MERGE_CONFLICT, MERGE_CONFLICT, E(/* Class */ NativeClass),
      E(/* NativeClass */ NativeClass),
@@ -253,7 +253,7 @@
   if (!RHS->getAlignment())
     return LHS;
 
-  // Check if fixed_size_layout.alignment is a multple of
+  // Check if fixed_size_layout.alignment is a multiple of
   // at_most_size_layout.alignment.
   if (LHS->getAlignment() && LHS->getAlignment() % RHS->getAlignment() == 0)
     return LHS;
diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp
index 967bece..d380778 100644
--- a/lib/AST/Module.cpp
+++ b/lib/AST/Module.cpp
@@ -606,7 +606,7 @@
   // itself.
   if (type->isExistentialType()) {
     SmallVector<ProtocolDecl *, 4> protocols;
-    type->getAnyExistentialTypeProtocols(protocols);
+    type->getExistentialTypeProtocols(protocols);
 
     // Due to an IRGen limitation, witness tables cannot be passed from an
     // existential to an archetype parameter, so for now we restrict this to
diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp
index b9971af..306c45e 100644
--- a/lib/AST/NameLookup.cpp
+++ b/lib/AST/NameLookup.cpp
@@ -575,13 +575,7 @@
         // FIXME: We shouldn't need to compute a type to perform this lookup.
         Type lookupType = dc->getSelfTypeInContext();
 
-        // FIXME: Hack to deal with missing 'Self' archetypes.
-        if (!lookupType) {
-          if (auto proto = dc->getAsProtocolOrProtocolExtensionContext())
-            lookupType = proto->getDeclaredType();
-        }
-
-        if (!lookupType || lookupType->hasError()) continue;
+        if (lookupType->hasError()) continue;
 
         // Perform lookup into the type.
         NLOptions options = NL_UnqualifiedDefault;
@@ -686,12 +680,6 @@
 
           if (AFD->getDeclContext()->isTypeContext()) {
             ExtendedType = AFD->getDeclContext()->getSelfTypeInContext();
-            // FIXME: Hack to deal with missing 'Self' archetypes.
-            if (!ExtendedType)
-              if (auto *PD = AFD->getDeclContext()
-                      ->getAsProtocolOrProtocolExtensionContext())
-                ExtendedType = PD->getDeclaredType();
-
             BaseDecl = AFD->getImplicitSelfDecl();
             MetaBaseDecl = AFD->getDeclContext()
                 ->getAsNominalTypeOrNominalTypeExtensionContext();
@@ -782,8 +770,8 @@
           if (IgnoreAccessControl)
             options |= NL_IgnoreAccessibility;
 
-          if (!ExtendedType)
-            ExtendedType = ErrorType::get(Ctx);
+          if (ExtendedType->hasError())
+            continue;
 
           SmallVector<ValueDecl *, 4> Lookup;
           DC->lookupQualified(ExtendedType, Name, options, TypeResolver, Lookup);
@@ -1181,6 +1169,8 @@
 TinyPtrVector<ValueDecl *> NominalTypeDecl::lookupDirect(
                                                   DeclName name,
                                                   bool ignoreNewExtensions) {
+  (void)getMembers();
+
   // Make sure we have the complete list of members (in this nominal and in all
   // extensions).
   if (!ignoreNewExtensions) {
@@ -1188,8 +1178,6 @@
       (void)E->getMembers();
   }
 
-  (void)getMembers();
-
   prepareLookupTable(ignoreNewExtensions);
 
   // Look for the declarations with this name.
@@ -1317,9 +1305,6 @@
   using namespace namelookup;
   assert(decls.empty() && "additive lookup not supported");
 
-  if (type->hasError())
-    return false;
-
   auto checkLookupCascading = [this, options]() -> Optional<bool> {
     switch (static_cast<unsigned>(options & NL_KnownDependencyMask)) {
     case 0:
@@ -1398,15 +1383,12 @@
   llvm::SmallPtrSet<NominalTypeDecl *, 4> visited;
 
   // Handle nominal types.
-  bool wantProtocolMembers = false;
+  bool wantProtocolMembers = (options & NL_ProtocolMembers);
   bool wantLookupInAllClasses = false;
   if (auto nominal = type->getAnyNominal()) {
     visited.insert(nominal);
     stack.push_back(nominal);
     
-    wantProtocolMembers = (options & NL_ProtocolMembers) &&
-                          !isa<ProtocolDecl>(nominal);
-
     // If we want dynamic lookup and we're searching in the
     // AnyObject protocol, note this for later.
     if (options & NL_DynamicLookup) {
@@ -1428,9 +1410,6 @@
       if (auto superclassDecl = superclassTy->getAnyNominal()) {
         if (visited.insert(superclassDecl).second) {
           stack.push_back(superclassDecl);
-
-          wantProtocolMembers = (options & NL_ProtocolMembers) &&
-                                !isa<ProtocolDecl>(superclassDecl);
         }
       }
     }
@@ -1438,17 +1417,16 @@
   // Handle protocol compositions.
   else if (auto compositionTy = type->getAs<ProtocolCompositionType>()) {
     SmallVector<ProtocolDecl *, 4> protocols;
-    if (compositionTy->isExistentialType(protocols)) {
-      for (auto proto : protocols) {
-        if (visited.insert(proto).second) {
-          stack.push_back(proto);
+    compositionTy->getExistentialTypeProtocols(protocols);
+    for (auto proto : protocols) {
+      if (visited.insert(proto).second) {
+        stack.push_back(proto);
 
-          // If we want dynamic lookup and this is the AnyObject
-          // protocol, note this for later.
-          if ((options & NL_DynamicLookup) &&
-              proto->isSpecificProtocol(KnownProtocolKind::AnyObject))
-            wantLookupInAllClasses = true;
-        }
+        // If we want dynamic lookup and this is the AnyObject
+        // protocol, note this for later.
+        if ((options & NL_DynamicLookup) &&
+            proto->isSpecificProtocol(KnownProtocolKind::AnyObject))
+          wantLookupInAllClasses = true;
       }
     }
   } else {
diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp
index 07a922f..9d7af93 100644
--- a/lib/AST/ProtocolConformance.cpp
+++ b/lib/AST/ProtocolConformance.cpp
@@ -153,7 +153,9 @@
     return ProtocolConformanceRef(lookupResults.front());
   }
 
-  llvm_unreachable("Invalid conformance substitution");
+  // FIXME: Rip this out once ConformanceAccessPaths are plumbed through
+  auto *M = proto->getParentModule();
+  return *M->lookupConformance(substType, proto, nullptr);
 }
 
 Type
@@ -187,7 +189,7 @@
   if (!concrete->hasTypeWitness(assocType, resolver)) {
     return nullptr;
   }
-  return concrete->getTypeWitness(assocType, resolver).getReplacement();
+  return concrete->getTypeWitness(assocType, resolver);
 }
 
 void *ProtocolConformance::operator new(size_t bytes, ASTContext &context,
@@ -237,17 +239,15 @@
   CONFORMANCE_SUBCLASS_DISPATCH(hasTypeWitness, (assocType, resolver));
 }
 
-std::pair<const Substitution &, TypeDecl *>
-ProtocolConformance::getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType,
+std::pair<Type, TypeDecl *>
+ProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
                                                 LazyResolver *resolver) const {
-  CONFORMANCE_SUBCLASS_DISPATCH(getTypeWitnessSubstAndDecl,
-                                (assocType, resolver))
+  CONFORMANCE_SUBCLASS_DISPATCH(getTypeWitnessAndDecl, (assocType, resolver))
 }
 
-const Substitution &
-ProtocolConformance::getTypeWitness(AssociatedTypeDecl *assocType, 
-                                    LazyResolver *resolver) const {
-  return getTypeWitnessSubstAndDecl(assocType, resolver).first;
+Type ProtocolConformance::getTypeWitness(AssociatedTypeDecl *assocType,
+                                         LazyResolver *resolver) const {
+  return getTypeWitnessAndDecl(assocType, resolver).first;
 }
 
 Witness ProtocolConformance::getWitness(ValueDecl *requirement,
@@ -255,11 +255,6 @@
   CONFORMANCE_SUBCLASS_DISPATCH(getWitness, (requirement, resolver))
 }
 
-const InheritedConformanceMap &
-ProtocolConformance::getInheritedConformances() const {
-  CONFORMANCE_SUBCLASS_DISPATCH(getInheritedConformances, ())
-}
-
 /// Determine whether the witness for the given requirement
 /// is either the default definition or was otherwise deduced.
 bool ProtocolConformance::
@@ -267,6 +262,18 @@
   CONFORMANCE_SUBCLASS_DISPATCH(usesDefaultDefinition, (requirement))
 }
 
+bool ProtocolConformance::hasFixedLayout() const {
+  // A conformance/witness table has fixed layout if type has a fixed layout in
+  // all resilience domains, and the conformance is externally visible.
+  if (auto nominal = getInterfaceType()->getAnyNominal())
+    if (nominal->hasFixedLayout() &&
+        getProtocol()->getEffectiveAccess() >= Accessibility::Public &&
+        nominal->getEffectiveAccess() >= Accessibility::Public)
+      return true;
+
+  return false;
+}
+
 GenericEnvironment *ProtocolConformance::getGenericEnvironment() const {
   switch (getKind()) {
   case ProtocolConformanceKind::Inherited:
@@ -368,10 +375,9 @@
   return false;
 }
 
-std::pair<const Substitution &, TypeDecl *>
-NormalProtocolConformance::getTypeWitnessSubstAndDecl(
-                      AssociatedTypeDecl *assocType, 
-                      LazyResolver *resolver) const {
+std::pair<Type, TypeDecl *>
+NormalProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
+                                                 LazyResolver *resolver) const {
   if (Resolver)
     resolveLazyInfo();
 
@@ -386,15 +392,14 @@
   return known->second;
 }
 
-void NormalProtocolConformance::setTypeWitness(
-       AssociatedTypeDecl *assocType,
-       const Substitution &substitution,
-       TypeDecl *typeDecl) const {
+void NormalProtocolConformance::setTypeWitness(AssociatedTypeDecl *assocType,
+                                               Type type,
+                                               TypeDecl *typeDecl) const {
   assert(getProtocol() == cast<ProtocolDecl>(assocType->getDeclContext()) &&
          "associated type in wrong protocol");
   assert(TypeWitnesses.count(assocType) == 0 && "Type witness already known");
   assert((!isComplete() || isInvalid()) && "Conformance already complete?");
-  TypeWitnesses[assocType] = std::make_pair(substitution, typeDecl);
+  TypeWitnesses[assocType] = std::make_pair(type, typeDecl);
 }
 
 Type ProtocolConformance::getAssociatedType(Type assocType,
@@ -426,7 +431,7 @@
   auto memberType = cast<DependentMemberType>(type);
   if (memberType.getBase()->isEqual(proto->getProtocolSelfType()) &&
       memberType->getAssocType()->getProtocol() == proto)
-    return getTypeWitness(memberType->getAssocType(), nullptr).getReplacement();
+    return getTypeWitness(memberType->getAssocType(), nullptr);
 #endif
 
   // General case: consult the substitution map.
@@ -473,6 +478,8 @@
                                                 LazyResolver *resolver) const {
   assert(assocType->isTypeParameter() &&
          "associated type must be a type parameter");
+  assert(!getSignatureConformances().empty() &&
+         "signature conformances not yet computed");
 
   unsigned conformanceIndex = 0;
   for (auto &reqt :
@@ -551,8 +558,8 @@
          GenericConformance->hasTypeWitness(assocType, resolver);
 }
 
-std::pair<const Substitution &, TypeDecl *>
-SpecializedProtocolConformance::getTypeWitnessSubstAndDecl(
+std::pair<Type, TypeDecl *>
+SpecializedProtocolConformance::getTypeWitnessAndDecl(
                       AssociatedTypeDecl *assocType, 
                       LazyResolver *resolver) const {
   // If we've already created this type witness, return it.
@@ -568,49 +575,24 @@
       genericEnv->getSubstitutionMap(GenericSubstitutions);
 
   auto genericWitnessAndDecl
-    = GenericConformance->getTypeWitnessSubstAndDecl(assocType, resolver);
+    = GenericConformance->getTypeWitnessAndDecl(assocType, resolver);
 
   auto &genericWitness = genericWitnessAndDecl.first;
   auto *typeDecl = genericWitnessAndDecl.second;
 
   // Apply the substitution we computed above
   auto specializedType
-    = genericWitness.getReplacement().subst(substitutionMap);
+    = genericWitness.subst(substitutionMap);
   if (!specializedType)
-    specializedType = ErrorType::get(genericWitness.getReplacement());
+    specializedType = ErrorType::get(genericWitness);
 
   // If the type witness was unchanged, just copy it directly.
-  if (specializedType.getPointer() == genericWitness.getReplacement().getPointer()) {
+  if (specializedType.getPointer() == genericWitness.getPointer()) {
     TypeWitnesses[assocType] = genericWitnessAndDecl;
     return TypeWitnesses[assocType];
   }
 
-  auto conformingDC = getDeclContext();
-  auto conformingModule = conformingDC->getParentModule();
-
-  // Gather the conformances for the type witness. These should never fail.
-  // FIXME: We should just be able to use the SubstitutionMap from above,
-  // but we have no way to force inherited conformances to be filled in
-  // through that mechanism.
-  SmallVector<ProtocolConformanceRef, 4> conformances;
-  for (auto proto : assocType->getConformingProtocols()) {
-    auto conforms = conformingModule->lookupConformance(specializedType, proto,
-                                                        resolver);
-    assert((conforms ||
-            specializedType->isTypeVariableOrMember() ||
-            specializedType->isTypeParameter() ||
-            specializedType->hasError()) &&
-           "Improperly checked substitution");
-    conformances.push_back(conforms ? *conforms 
-                                    : ProtocolConformanceRef(proto));
-  }
-
-  // Form the substitution.
-  auto &ctx = assocType->getASTContext();
-  TypeWitnesses[assocType] = std::make_pair(
-                        Substitution{specializedType,
-                                     ctx.AllocateCopy(conformances)},
-                        typeDecl);
+  TypeWitnesses[assocType] = std::make_pair(specializedType, typeDecl);
   return TypeWitnesses[assocType];
 }
 
@@ -645,9 +627,22 @@
 InheritedProtocolConformance::getAssociatedConformance(Type assocType,
                          ProtocolDecl *protocol,
                          LazyResolver *resolver) const {
-  // FIXME: Substitute!
-  return InheritedConformance->getAssociatedConformance(assocType, protocol,
-                                                        resolver);
+  auto underlying =
+    InheritedConformance->getAssociatedConformance(assocType, protocol,
+                                                   resolver);
+
+
+  // If the conformance is for Self, return an inherited conformance.
+  if (underlying.isConcrete() &&
+      assocType->isEqual(getProtocol()->getSelfInterfaceType())) {
+    auto subclassType = getType();
+    ASTContext &ctx = subclassType->getASTContext();
+    return ProtocolConformanceRef(
+             ctx.getInheritedConformance(subclassType,
+                                         underlying.getConcrete()));
+  }
+
+  return underlying;
 }
 
 const NormalProtocolConformance *
@@ -759,64 +754,9 @@
 
 ProtocolConformance *
 ProtocolConformance::getInheritedConformance(ProtocolDecl *protocol) const {
-  auto &C = getProtocol()->getASTContext();
-  // Preserve specialization and class inheritance through this operation by
-  // reapplying them to the conformance we find.
-  switch (getKind()) {
-  case ProtocolConformanceKind::Specialized: {
-    auto spec = cast<SpecializedProtocolConformance>(this);
-    auto inherited = spec->getGenericConformance()
-      ->getInheritedConformance(protocol);
-    assert(inherited->getType()->isEqual(spec->getGenericConformance()->getType())
-           && "inherited conformance doesn't match type?!");
-    
-    auto subs = spec->getGenericSubstitutions();
-    auto *conformingDC = spec->getDeclContext();
-    auto *env = conformingDC->getGenericEnvironmentOfContext();
-    auto subMap = env->getSubstitutionMap(subs);
-
-    auto r = inherited->subst(getType(),
-                              QuerySubstitutionMap{subMap},
-                              LookUpConformanceInSubstitutionMap(subMap));
-    assert(getType()->isEqual(r->getType())
-           && "substitution didn't produce conformance for same type?!");
-    return r;
-  }
-
-  case ProtocolConformanceKind::Inherited: {
-    auto classInherited = cast<InheritedProtocolConformance>(this);
-    auto protoInherited = classInherited->getInheritedConformance()
-      ->getInheritedConformance(protocol);
-    assert(protoInherited->getType()->isEqual(
-                           classInherited->getInheritedConformance()->getType())
-           && "inherited conformance doesn't match type?!");
-    return C.getInheritedConformance(classInherited->getType(),
-                                     protoInherited);
-  }
-
-  case ProtocolConformanceKind::Normal:
-    // For a normal conformance, do the inheritance lookup.
-    break;
-  }
-
-  // Search for the inherited conformance among our immediate parents.
-  auto &inherited = getInheritedConformances();
-  auto known = inherited.find(protocol);
-  if (known != inherited.end())
-    return known->second;
-
-  // If not there, the inherited conformance must be available through one of
-  // our parents.
-  for (auto &inheritedMapping : inherited)
-    if (inheritedMapping.first->inheritsFrom(protocol))
-      return inheritedMapping.second->getInheritedConformance(protocol);
-
-  // The conformance must not be complete; resolve the inherited conformance
-  // and try again.
-  assert(!isComplete() && "Missing inherited mapping in conformance");
-  assert(C.getLazyResolver() && "Need a lazy resolver");
-  return C.getLazyResolver()->resolveInheritedConformance(
-    getRootNormalConformance(), protocol);
+  auto result =
+    getAssociatedConformance(getProtocol()->getSelfInterfaceType(), protocol);
+  return result.isConcrete() ? result.getConcrete() : nullptr;
 }
 
 #pragma mark Protocol conformance lookup
diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp
index 251b236..6321424 100644
--- a/lib/AST/SubstitutionMap.cpp
+++ b/lib/AST/SubstitutionMap.cpp
@@ -22,9 +22,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "swift/AST/ASTContext.h"
 #include "swift/AST/SubstitutionMap.h"
+#include "swift/AST/ASTContext.h"
 #include "swift/AST/Decl.h"
+#include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/Module.h"
 #include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/Types.h"
@@ -32,6 +33,9 @@
 
 using namespace swift;
 
+SubstitutionMap::SubstitutionMap(GenericEnvironment *genericEnv)
+  : SubstitutionMap(genericEnv->getGenericSignature()) { }
+
 bool SubstitutionMap::hasArchetypes() const {
   for (auto &entry : subMap)
     if (entry.second->hasArchetype())
@@ -64,152 +68,105 @@
 
 void SubstitutionMap::
 addSubstitution(CanSubstitutableType type, Type replacement) {
+  assert(!(type->isTypeParameter() && !getGenericSignature()) &&
+         "type parameter substitution map without generic signature");
   auto result = subMap.insert(std::make_pair(type, replacement));
   assert(result.second || result.first->second->isEqual(replacement));
   (void) result;
 }
 
-template<typename T>
-Optional<T> SubstitutionMap::forEachParent(
-              CanType type,
-              llvm::SmallPtrSetImpl<CanType> &visitedParents,
-              llvm::function_ref<Optional<T>(CanType,
-                                             AssociatedTypeDecl *)> fn) const {
-  // If we've already visited the parents of this type, stop.
-  if (!visitedParents.insert(type).second)
-    return None;
-
-  auto foundParents = parentMap.find(type.getPointer());
-  if (foundParents != parentMap.end()) {
-    for (auto parent : foundParents->second) {
-      if (auto result = fn(parent.first, parent.second))
-        return result;
-    }
-  }
-
-  if (auto archetypeType = dyn_cast<ArchetypeType>(type))
-    if (auto *parent = archetypeType->getParent())
-      return fn(CanType(parent), archetypeType->getAssocType());
-
-  if (auto memberType = dyn_cast<DependentMemberType>(type))
-    return fn(CanType(memberType->getBase()), memberType->getAssocType());
-
-  return None;
-}
-
-template<typename T>
-Optional<T> SubstitutionMap::forEachConformance(
-              CanType type,
-              llvm::SmallPtrSetImpl<CanType> &visitedParents,
-              llvm::function_ref<Optional<T>(ProtocolConformanceRef)> fn) const{
-  // Check for conformances for the type that apply to the original
-  // substituted archetype.
-  auto foundReplacement = conformanceMap.find(type.getPointer());
-  if (foundReplacement != conformanceMap.end()) {
-    for (auto conformance : foundReplacement->second) {
-      if (auto found = fn(conformance))
-        return found;
-    }
-  }
-
-  // Local function to performance a (recursive) search for an associated type
-  // of the given name in the given conformance and all inherited conformances.
-  std::function<Optional<T>(ProtocolConformanceRef, DeclName,
-                                 llvm::SmallPtrSetImpl<ProtocolDecl *> &)>
-    searchInConformance;
-  searchInConformance =
-      [&](ProtocolConformanceRef conformance,
-          DeclName associatedTypeName,
-          llvm::SmallPtrSetImpl<ProtocolDecl *> &visited) -> Optional<T> {
-    // Only visit a particular protocol once.
-    auto proto = conformance.getRequirement();
-    if (!visited.insert(proto).second) return None;
-
-    // Check whether this protocol has an associated type with the
-    // same name as the one we're looking for.
-    AssociatedTypeDecl *protoAssocType = nullptr;
-    for (auto member : proto->lookupDirect(associatedTypeName)) {
-      protoAssocType = dyn_cast<AssociatedTypeDecl>(member);
-      if (protoAssocType) break;
-    }
-
-    if (protoAssocType) {
-      if (conformance.isAbstract()) {
-        for (auto assocProto : protoAssocType->getConformingProtocols()) {
-          if (auto found = fn(ProtocolConformanceRef(assocProto)))
-            return found;
-        }
-      } else {
-        auto sub = conformance.getConcrete()->getTypeWitnessSubstAndDecl(
-                                           protoAssocType, nullptr).first;
-        for (auto subConformance : sub.getConformances()) {
-          if (auto found = fn(subConformance))
-            return found;
-        }
-      }
-    }
-
-    // Search inherited conformances.
-    for (auto inherited : proto->getInheritedProtocols()) {
-      if (auto found = searchInConformance(conformance.getInherited(inherited),
-                                           associatedTypeName,
-                                           visited))
-        return found;
-    }
-    return None;
-  };
-
-  // Check if we have conformances from one of our parent types.
-  return forEachParent<ProtocolConformanceRef>(type, visitedParents,
-      [&](CanType parent, AssociatedTypeDecl *assocType)
-         -> Optional<ProtocolConformanceRef> {
-    return forEachConformance<T>(parent, visitedParents,
-        [&](ProtocolConformanceRef conformance) -> Optional<T> {
-      llvm::SmallPtrSet<ProtocolDecl *, 4> visited;
-      return searchInConformance(conformance, assocType->getFullName(),
-                                 visited);
-    });
-  });
-}
-
 Optional<ProtocolConformanceRef>
-SubstitutionMap::lookupConformance(
-                         CanType type, ProtocolDecl *proto,
-                         llvm::SmallPtrSetImpl<CanType> *visitedParents) const {
-  // Local function to either record an abstract conformance or return a
-  // concrete conformance. This allows us to check multiple parents and
-  // find the most specific conformance that applies.
-  Optional<ProtocolConformanceRef> abstractConformance;
-  auto recordOrReturn = [&](ProtocolConformanceRef conformance)
-      -> Optional<ProtocolConformanceRef> {
-    if (conformance.isAbstract()) {
-      if (!abstractConformance)
-        abstractConformance = conformance;
+SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
+  // If we have an archetype, map out of the context so we can compute a
+  // conformance access path.
+  GenericEnvironment *genericEnv = nullptr;
+  if (auto archetype = type->getAs<ArchetypeType>()) {
+    genericEnv = archetype->getGenericEnvironment();
+    type = genericEnv->mapTypeOutOfContext(type)->getCanonicalType();
+  }
+
+  // Error path: if we don't have a type parameter, there is no conformance.
+  // FIXME: Query concrete conformances in the generic signature?
+  if (!type->isTypeParameter())
+    return None;
+
+  // Retrieve the starting conformance from the conformance map.
+  auto getInitialConformance =
+    [&](Type type, ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
+      // We're working relative to a generic environment, map into that
+      // context before looking into the conformance map.
+      if (genericEnv)
+        type = genericEnv->mapTypeIntoContext(type);
+
+      auto known = conformanceMap.find(type->getCanonicalType().getPointer());
+      if (known == conformanceMap.end())
+        return None;
+
+      for (auto conformance : known->second) {
+        if (conformance.getRequirement() == proto)
+          return conformance;
+      }
 
       return None;
+    };
+
+  auto genericSig = getGenericSignature();
+  auto &mod = *proto->getModuleContext();
+
+  // HACK: Deal with AnyObject conformances, which get magically dropped in
+  // frustrating ways.
+  // FIXME: This hack dies with AnyObject-as-a-protocol.
+  if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject) &&
+      genericSig->requiresClass(type, mod))
+    return ProtocolConformanceRef(proto);
+
+  // If the type doesn't conform to this protocol, fail.
+  if (!genericSig->conformsToProtocol(type, proto, mod))
+    return None;
+
+  auto canonType = genericSig->getCanonicalTypeInContext(type, mod);
+  auto accessPath =
+    genericSig->getConformanceAccessPath(canonType, proto, mod);
+
+  // Fall through because we cannot yet evaluate an access path.
+  Optional<ProtocolConformanceRef> conformance;
+  for (const auto &step : accessPath) {
+    // For the first step, grab the initial conformance.
+    if (!conformance) {
+      conformance = getInitialConformance(step.first, step.second);
+      if (!conformance)
+        return None;
+
+      continue;
     }
 
-    return conformance;
-  };
+    // If we've hit an abstract conformance, everything from here on out is
+    // abstract.
+    // FIXME: This may not always be true, but it holds for now.
+    if (conformance->isAbstract())
+      return ProtocolConformanceRef(proto);
 
-  llvm::SmallPtrSet<CanType, 4> visitedParentsStored;
-  if (!visitedParents)
-    visitedParents = &visitedParentsStored;
+    // For the second step, we're looking into the requirement signature for
+    // this protocol.
+    auto concrete = conformance->getConcrete();
+    auto normal = concrete->getRootNormalConformance();
 
-  auto concreteConformance =
-    forEachConformance<ProtocolConformanceRef>(type, *visitedParents,
-        [&](ProtocolConformanceRef conformance)
-          -> Optional<ProtocolConformanceRef> {
-      if (conformance.getRequirement() == proto)
-        return recordOrReturn(conformance);
+    // If we haven't set the signature conformances yet, force the issue now.
+    if (normal->getSignatureConformances().empty()) {
+      auto lazyResolver = canonType->getASTContext().getLazyResolver();
+      lazyResolver->resolveTypeWitness(normal, nullptr);
 
-      if (conformance.getRequirement()->inheritsFrom(proto))
-        return recordOrReturn(conformance.getInherited(proto));
+      // Error case: the conformance is broken, so we cannot handle this
+      // substitution.
+      if (normal->getSignatureConformances().empty())
+        return None;
+    }
 
-       return None;
-    });
+    // Get the associated conformance.
+    conformance = concrete->getAssociatedConformance(step.first, step.second);
+  }
 
-  return concreteConformance ? concreteConformance : abstractConformance;
+  return conformance;
 }
 
 void SubstitutionMap::
@@ -217,13 +174,6 @@
   conformanceMap[type.getPointer()].push_back(conformance);
 }
 
-void SubstitutionMap::
-addParent(CanType type, CanType parent, AssociatedTypeDecl *assocType) {
-  assert(type && parent && assocType);
-  parentMap[type.getPointer()].push_back(std::make_pair(parent, assocType));
-}
-
-
 SubstitutionMap SubstitutionMap::subst(const SubstitutionMap &subMap) const {
   return subst(QuerySubstitutionMap{subMap},
                LookUpConformanceInSubstitutionMap(subMap));
@@ -437,6 +387,9 @@
 }
 
 void SubstitutionMap::dump(llvm::raw_ostream &out) const {
+  out << "Generic signature: ";
+  getGenericSignature()->print(out);
+  out << "\n";
   out << "Substitutions:\n";
   for (const auto &sub : subMap) {
     out.indent(2);
@@ -460,24 +413,6 @@
                });
     out << "]\n";
   }
-
-  out << "\nParent map:\n";
-  for (const auto &parent : parentMap) {
-    out.indent(2);
-    parent.first->print(out);
-    out << " -> [";
-    interleave(parent.second.begin(), parent.second.end(),
-               [&](SubstitutionMap::ParentType parentType) {
-                 parentType.first->print(out);
-                 out << " @ ";
-                 out << parentType.second->getProtocol()->getName().str()
-                     << "." << parentType.second->getName().str();
-               },
-               [&] {
-                 out << ", ";
-               });
-    out << "]\n";
-  }
 }
 
 void SubstitutionMap::dump() const {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 523e36e..647be73 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -207,37 +207,9 @@
   return getCanonicalType().isAnyClassReferenceType();
 }
 
-bool TypeBase::isAnyExistentialType(SmallVectorImpl<ProtocolDecl*> &protocols) {
-  return getCanonicalType().isAnyExistentialType(protocols);
-}
-
-bool CanType::isAnyExistentialTypeImpl(CanType type,
-                                       SmallVectorImpl<ProtocolDecl*> &protocols) {
-  if (auto metatype = dyn_cast<ExistentialMetatypeType>(type)) {
-    metatype.getInstanceType().getAnyExistentialTypeProtocols(protocols);
-    return true;
-  }
-  return isExistentialTypeImpl(type, protocols);
-}
-
-bool TypeBase::isExistentialType(SmallVectorImpl<ProtocolDecl *> &protocols) {
-  return getCanonicalType().isExistentialType(protocols);
-}
-
-bool CanType::isExistentialTypeImpl(CanType type,
-                                    SmallVectorImpl<ProtocolDecl*> &protocols) {
-  if (auto proto = dyn_cast<ProtocolType>(type)) {
-    proto.getAnyExistentialTypeProtocols(protocols);
-    return true;
-  }
-  
-  if (auto comp = dyn_cast<ProtocolCompositionType>(type)) {
-    comp.getAnyExistentialTypeProtocols(protocols);
-    return true;
-  }
-
-  assert(!type.isExistentialType());
-  return false;
+void TypeBase::getExistentialTypeProtocols(
+                                   SmallVectorImpl<ProtocolDecl*> &protocols) {
+  getCanonicalType().getExistentialTypeProtocols(protocols);
 }
 
 void TypeBase::getAnyExistentialTypeProtocols(
@@ -245,19 +217,29 @@
   getCanonicalType().getAnyExistentialTypeProtocols(protocols);
 }
 
-void CanType::getAnyExistentialTypeProtocolsImpl(CanType type,
+void CanType::getExistentialTypeProtocolsImpl(CanType type,
                                    SmallVectorImpl<ProtocolDecl*> &protocols) {
   if (auto proto = dyn_cast<ProtocolType>(type)) {
-    proto.getAnyExistentialTypeProtocols(protocols);
+    protocols.push_back(proto->getDecl());
   } else if (auto comp = dyn_cast<ProtocolCompositionType>(type)) {
-    comp.getAnyExistentialTypeProtocols(protocols);
-  } else if (auto metatype = dyn_cast<ExistentialMetatypeType>(type)) {
-    metatype.getAnyExistentialTypeProtocols(protocols);
+    auto protos = comp.getProtocols();
+    for (auto proto : protos)
+      proto.getExistentialTypeProtocols(protocols);
   } else {
     llvm_unreachable("type was not any kind of existential type!");
   }
 }
 
+void CanType::getAnyExistentialTypeProtocolsImpl(CanType type,
+                                   SmallVectorImpl<ProtocolDecl*> &protocols) {
+  if (auto metatype = dyn_cast<ExistentialMetatypeType>(type)) {
+      metatype.getInstanceType().getAnyExistentialTypeProtocols(protocols);
+      return;
+  }
+
+  type.getExistentialTypeProtocols(protocols);
+}
+
 bool TypeBase::isObjCExistentialType() {
   return getCanonicalType().isObjCExistentialType();
 }
@@ -266,7 +248,7 @@
   if (!type.isExistentialType()) return false;
 
   SmallVector<ProtocolDecl *, 4> protocols;
-  type.getAnyExistentialTypeProtocols(protocols);
+  type.getExistentialTypeProtocols(protocols);
 
   // Must have at least one protocol to be class-bounded.
   if (protocols.empty())
@@ -558,10 +540,14 @@
 }
 
 bool TypeBase::isExistentialWithError() {
+  auto canTy = getCanonicalType();
+
+  if (!canTy.isExistentialType()) return false;
+
   // FIXME: Compute this as a bit in TypeBase so this operation isn't
   // overly expensive.
   SmallVector<ProtocolDecl *, 4> protocols;
-  if (!getCanonicalType()->isExistentialType(protocols)) return false;
+  canTy.getExistentialTypeProtocols(protocols);
 
   auto errorProto =
     getASTContext().getProtocol(KnownProtocolKind::Error);
@@ -2688,14 +2674,6 @@
   return getDecl()->requiresClass();
 }
 
-void ProtocolCompositionType::getAnyExistentialTypeProtocols(
-                                   SmallVectorImpl<ProtocolDecl *> &protos) {
-  // The canonical type for a protocol composition canonicalizes the
-  // order of the protocols.
-  auto canonical = cast<ProtocolCompositionType>(getCanonicalType());
-  canonical.getAnyExistentialTypeProtocols(protos);
-}
-
 bool ProtocolCompositionType::requiresClass() const {
   for (Type t : getProtocols()) {
     if (const ProtocolType *proto = t->getAs<ProtocolType>()) {
@@ -2840,8 +2818,8 @@
         !conformance->getConcrete()->hasTypeWitness(assocType, nullptr))
       return failed();
 
-    auto witness = conformance->getConcrete()
-        ->getTypeWitness(assocType, resolver).getReplacement();
+    auto witness =
+      conformance->getConcrete()->getTypeWitness(assocType, resolver);
 
     // This is a hacky feature allowing code completion to migrate to
     // using Type::subst() without changing output.
@@ -2875,7 +2853,17 @@
 LookUpConformanceInSubstitutionMap::operator()(CanType dependentType,
                                        Type conformingReplacementType,
                                        ProtocolType *conformedProtocol) const {
-  return Subs.lookupConformance(dependentType, conformedProtocol->getDecl());
+  auto result = Subs.lookupConformance(dependentType, conformedProtocol->getDecl());
+  if ((result && result->isConcrete()) ||
+      conformingReplacementType->hasError() ||
+      conformingReplacementType->isTypeParameter())
+    return result;
+
+  // FIXME: Rip this out once ConformanceAccessPaths are plumbed through
+  auto *M = conformedProtocol->getDecl()->getParentModule();
+  return M->lookupConformance(conformingReplacementType,
+                              conformedProtocol->getDecl(),
+                              nullptr);
 }
 
 Optional<ProtocolConformanceRef>
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 936e1fa..c007c7b 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -83,6 +83,7 @@
   Program.cpp
   QuotedString.cpp
   SourceLoc.cpp
+  Statistic.cpp
   StringExtras.cpp
   TaskQueue.cpp
   ThreadSafeRefCounted.cpp
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index 93ec8a9..d648b4a 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -18,6 +18,7 @@
 #include "swift/Basic/LangOptions.h"
 #include "swift/Basic/Range.h"
 #include "swift/Config.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/raw_ostream.h"
 #include <limits.h>
diff --git a/lib/Basic/Statistic.cpp b/lib/Basic/Statistic.cpp
new file mode 100644
index 0000000..d902d59
--- /dev/null
+++ b/lib/Basic/Statistic.cpp
@@ -0,0 +1,191 @@
+//===--- Statistic.cpp - Swift unified stats reporting --------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/Basic/Statistic.h"
+#include "swift/Driver/DependencyGraph.h"
+#include "swift/SIL/SILModule.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+#include <chrono>
+
+namespace swift {
+using namespace llvm;
+using namespace llvm::sys;
+
+static std::string
+makeFileName(StringRef ProcessName) {
+  std::string tmp;
+  raw_string_ostream stream(tmp);
+  auto now = std::chrono::system_clock::now();
+  stream << "stats"
+         << "-" << now.time_since_epoch().count()
+         << "-" << ProcessName
+         << "-" << Process::GetRandomNumber()
+         << ".json";
+  return stream.str();
+}
+
+UnifiedStatsReporter::UnifiedStatsReporter(StringRef ProgramName,
+                                           StringRef TargetName,
+                                           StringRef Directory)
+  : Filename(Directory),
+    Timer(make_unique<NamedRegionTimer>(TargetName, "Building Target",
+                                        ProgramName, "Running Program"))
+{
+  path::append(Filename, makeFileName(ProgramName));
+  EnableStatistics(/*PrintOnExit=*/false);
+  SharedTimer::enableCompilationTimers();
+}
+
+UnifiedStatsReporter::AlwaysOnDriverCounters &
+UnifiedStatsReporter::getDriverCounters()
+{
+  if (!DriverCounters)
+    DriverCounters = make_unique<AlwaysOnDriverCounters>();
+  return *DriverCounters;
+}
+
+UnifiedStatsReporter::AlwaysOnFrontendCounters &
+UnifiedStatsReporter::getFrontendCounters()
+{
+  if (!FrontendCounters)
+    FrontendCounters = make_unique<AlwaysOnFrontendCounters>();
+  return *FrontendCounters;
+}
+
+#define PUBLISH_STAT(C,TY,NAME)                               \
+  do {                                                        \
+    static Statistic Stat = {TY, #NAME, #NAME, {0}, false};   \
+    Stat += (C).NAME;                                         \
+  } while(0)
+
+void
+UnifiedStatsReporter::publishAlwaysOnStatsToLLVM() {
+  if (FrontendCounters) {
+    auto &C = getFrontendCounters();
+    PUBLISH_STAT(C, "SILModule", NumSILGenFunctions);
+    PUBLISH_STAT(C, "SILModule", NumSILGenVtables);
+    PUBLISH_STAT(C, "SILModule", NumSILGenWitnessTables);
+    PUBLISH_STAT(C, "SILModule", NumSILGenDefaultWitnessTables);
+    PUBLISH_STAT(C, "SILModule", NumSILGenGlobalVariables);
+
+    PUBLISH_STAT(C, "SILModule", NumSILOptFunctions);
+    PUBLISH_STAT(C, "SILModule", NumSILOptVtables);
+    PUBLISH_STAT(C, "SILModule", NumSILOptWitnessTables);
+    PUBLISH_STAT(C, "SILModule", NumSILOptDefaultWitnessTables);
+    PUBLISH_STAT(C, "SILModule", NumSILOptGlobalVariables);
+  }
+  if (DriverCounters) {
+    auto &C = getDriverCounters();
+    PUBLISH_STAT(C, "Driver", NumDriverJobsRun);
+    PUBLISH_STAT(C, "Driver", NumDriverJobsSkipped);
+
+    PUBLISH_STAT(C, "Driver", DriverDepCascadingTopLevel);
+    PUBLISH_STAT(C, "Driver", DriverDepCascadingDynamic);
+    PUBLISH_STAT(C, "Driver", DriverDepCascadingNominal);
+    PUBLISH_STAT(C, "Driver", DriverDepCascadingMember);
+    PUBLISH_STAT(C, "Driver", DriverDepCascadingExternal);
+
+    PUBLISH_STAT(C, "Driver", DriverDepTopLevel);
+    PUBLISH_STAT(C, "Driver", DriverDepDynamic);
+    PUBLISH_STAT(C, "Driver", DriverDepNominal);
+    PUBLISH_STAT(C, "Driver", DriverDepMember);
+    PUBLISH_STAT(C, "Driver", DriverDepExternal);
+  }
+}
+
+#define PRINT_STAT(OS,DELIM,C,TY,NAME)                   \
+  do {                                                   \
+    OS << DELIM << "\t\"" TY "." #NAME "\": " << C.NAME; \
+    delim = ",\n";                                       \
+  } while(0)
+
+void
+UnifiedStatsReporter::printAlwaysOnStatsAndTimers(raw_ostream &OS) {
+  // Adapted from llvm::PrintStatisticsJSON
+  OS << "{\n";
+  const char *delim = "";
+  if (FrontendCounters) {
+    auto &C = getFrontendCounters();
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenFunctions);
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenVtables);
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenWitnessTables);
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenDefaultWitnessTables);
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenGlobalVariables);
+
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptFunctions);
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptVtables);
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptWitnessTables);
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptDefaultWitnessTables);
+    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptGlobalVariables);
+  }
+  if (DriverCounters) {
+    auto &C = getDriverCounters();
+    PRINT_STAT(OS, delim, C, "Driver", NumDriverJobsRun);
+    PRINT_STAT(OS, delim, C, "Driver", NumDriverJobsSkipped);
+
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingTopLevel);
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingDynamic);
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingNominal);
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingMember);
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingExternal);
+
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepTopLevel);
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepDynamic);
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepNominal);
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepMember);
+    PRINT_STAT(OS, delim, C, "Driver", DriverDepExternal);
+  }
+  // Print timers.
+  TimerGroup::printAllJSONValues(OS, delim);
+  OS << "\n}\n";
+  OS.flush();
+}
+
+UnifiedStatsReporter::~UnifiedStatsReporter()
+{
+  // NB: Timer needs to be Optional<> because it needs to be destructed early;
+  // LLVM will complain about double-stopping a timer if you tear down a
+  // NamedRegionTimer after printing all timers. The printing routines were
+  // designed with more of a global-scope, run-at-process-exit in mind, which
+  // we're repurposing a bit here.
+  Timer.reset();
+
+  std::error_code EC;
+  raw_fd_ostream ostream(Filename, EC, fs::F_Append | fs::F_Text);
+  if (EC)
+    return;
+
+  // We change behaviour here depending on whether -DLLVM_ENABLE_STATS and/or
+  // assertions were on in this build; this is somewhat subtle, but turning on
+  // all stats for all of LLVM and clang is a bit more expensive and intrusive
+  // than we want to be in release builds.
+  //
+  //  - If enabled: we copy all of our "always-on" local stats into LLVM's
+  //    global statistics list, and ask LLVM to manage the printing of them.
+  //
+  //  - If disabled: we still have our "always-on" local stats to write, and
+  //    LLVM's global _timers_ were still enabled (they're runtime-enabled, not
+  //    compile-time) so we sequence printing our own stats and LLVM's timers
+  //    manually.
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
+  publishAlwaysOnStatsToLLVM();
+  PrintStatisticsJSON(ostream);
+#else
+  printAlwaysOnStatsAndTimers(ostream);
+#endif
+}
+
+} // namespace swift
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index 94c66aa..de72345 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -145,27 +145,44 @@
     ASTContext &Ctx;
     ClangImporter &Importer;
     ClangImporter::Implementation &Impl;
+    const ClangImporterOptions &ImporterOpts;
+    std::string SwiftPCHHash;
   public:
     explicit ParsingAction(ASTContext &ctx,
                            ClangImporter &importer,
-                           ClangImporter::Implementation &impl)
-      : Ctx(ctx), Importer(importer), Impl(impl) {}
+                           ClangImporter::Implementation &impl,
+                           const ClangImporterOptions &importerOpts,
+                           std::string swiftPCHHash)
+      : Ctx(ctx), Importer(importer), Impl(impl), ImporterOpts(importerOpts),
+        SwiftPCHHash(swiftPCHHash) {}
     std::unique_ptr<clang::ASTConsumer>
     CreateASTConsumer(clang::CompilerInstance &CI, StringRef InFile) override {
       return llvm::make_unique<HeaderParsingASTConsumer>(Impl);
     }
-    bool BeginSourceFileAction(CompilerInstance &CI,
+    bool BeginSourceFileAction(clang::CompilerInstance &CI,
                                StringRef Filename) override {
       // Prefer frameworks over plain headers.
       // We add search paths here instead of when building the initial invocation
       // so that (a) we use the same code as search paths for imported modules,
       // and (b) search paths are always added after -Xcc options.
       SearchPathOptions &searchPathOpts = Ctx.SearchPathOpts;
-      for (const auto &framepath : searchPathOpts.FrameworkSearchPaths)
+      for (const auto &framepath : searchPathOpts.FrameworkSearchPaths) {
         Importer.addSearchPath(framepath.Path, /*isFramework*/true,
                                framepath.IsSystem);
-      for (auto path : searchPathOpts.ImportSearchPaths)
+      }
+
+      for (auto path : searchPathOpts.ImportSearchPaths) {
         Importer.addSearchPath(path, /*isFramework*/false, /*isSystem=*/false);
+      }
+
+      auto PCH = Importer.getOrCreatePCH(ImporterOpts, SwiftPCHHash);
+      if (PCH.hasValue()) {
+        Impl.getClangInstance()->getPreprocessorOpts().ImplicitPCHInclude =
+            PCH.getValue();
+        Impl.IsReadingBridgingPCH = true;
+        Impl.setSinglePCHImport(PCH.getValue());
+      }
+
       return true;
     }
   };
@@ -692,11 +709,73 @@
     llvm::itostr(ctx.LangOpts.EffectiveLanguageVersion[0]));
 }
 
+bool ClangImporter::canReadPCH(StringRef PCHFilename) {
+  return clang::ASTReader::isAcceptableASTFile(PCHFilename,
+    Impl.Instance->getFileManager(),
+    Impl.Instance->getPCHContainerReader(),
+    Impl.Instance->getLangOpts(),
+    Impl.Instance->getTargetOpts(),
+    Impl.Instance->getPreprocessorOpts(),
+    Impl.Instance->getSpecificModuleCachePath());
+}
+
+Optional<std::string>
+ClangImporter::getPCHFilename(const ClangImporterOptions &ImporterOptions,
+                              const std::string &SwiftPCHHash) {
+  if (llvm::sys::path::extension(ImporterOptions.BridgingHeader)
+        .endswith(PCH_EXTENSION)) {
+    return ImporterOptions.BridgingHeader;
+  }
+
+  const auto &BridgingHeader = ImporterOptions.BridgingHeader;
+  const auto &PCHOutputDir = ImporterOptions.PrecompiledHeaderOutputDir;
+  if (SwiftPCHHash.empty() || BridgingHeader.empty() || PCHOutputDir.empty()) {
+    return None;
+  }
+
+  SmallString<256> PCHBasename { llvm::sys::path::filename(BridgingHeader) };
+  llvm::sys::path::replace_extension(PCHBasename, "");
+  PCHBasename.append("-swift_");
+  PCHBasename.append(SwiftPCHHash);
+  PCHBasename.append("-clang_");
+  PCHBasename.append(getClangModuleHash());
+  llvm::sys::path::replace_extension(PCHBasename, ".pch");
+  SmallString<256> PCHFilename { PCHOutputDir };
+  llvm::sys::path::append(PCHFilename, PCHBasename);
+  return PCHFilename.str().str();
+}
+
+
+Optional<std::string>
+ClangImporter::getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
+                              const std::string &SwiftPCHHash) {
+  auto PCHFilename = getPCHFilename(ImporterOptions, SwiftPCHHash);
+  if (!PCHFilename.hasValue()) {
+    return None;
+  }
+  if (!canReadPCH(PCHFilename.getValue())) {
+    SmallString<256> Message;
+    llvm::raw_svector_ostream OS(Message);
+    auto Diags = new clang::TextDiagnosticPrinter {
+      llvm::errs(),
+      &Impl.Instance->getDiagnosticOpts()
+    };
+    auto FailedToEmit = emitBridgingPCH(ImporterOptions.BridgingHeader,
+                                        PCHFilename.getValue(),
+                                        Diags);
+    if (FailedToEmit) {
+      return None;
+    }
+  }
+
+  return PCHFilename.getValue();
+}
+
 std::unique_ptr<ClangImporter>
 ClangImporter::create(ASTContext &ctx,
                       const ClangImporterOptions &importerOpts,
+                      std::string swiftPCHHash,
                       DependencyTracker *tracker) {
-
   std::unique_ptr<ClangImporter> importer{
     new ClangImporter(ctx, importerOpts, tracker)
   };
@@ -718,7 +797,7 @@
   addCommonInvocationArguments(invocationArgStrs, ctx, importerOpts);
 
   if (importerOpts.DumpClangDiagnostics) {
-    llvm::errs() << "clang '";
+    llvm::errs() << "'";
     interleave(invocationArgStrs,
                [](StringRef arg) { llvm::errs() << arg; },
                [] { llvm::errs() << "' '"; });
@@ -731,6 +810,7 @@
 
   if (llvm::sys::path::extension(importerOpts.BridgingHeader).endswith(
         PCH_EXTENSION)) {
+    importer->Impl.setSinglePCHImport(importerOpts.BridgingHeader);
     importer->Impl.IsReadingBridgingPCH = true;
     if (tracker) {
       // Currently ignoring dependency on bridging .pch files because they are
@@ -751,8 +831,9 @@
     new ClangDiagnosticConsumer(importer->Impl, *diagnosticOpts,
                                 importerOpts.DumpClangDiagnostics)
   };
-  auto clangDiags = CompilerInstance::createDiagnostics(diagnosticOpts.get(),
-                                                        diagClient.release());
+  auto clangDiags =
+      clang::CompilerInstance::createDiagnostics(diagnosticOpts.get(),
+                                                 diagClient.release());
 
   // Create a new Clang compiler invocation.
   importer->Impl.Invocation =
@@ -794,7 +875,8 @@
       llvm::make_unique<clang::ObjectFilePCHContainerWriter>());
   PCHContainerOperations->registerReader(
       llvm::make_unique<clang::ObjectFilePCHContainerReader>());
-  importer->Impl.Instance.reset(new CompilerInstance(PCHContainerOperations));
+  importer->Impl.Instance.reset(
+      new clang::CompilerInstance(PCHContainerOperations));
   auto &instance = *importer->Impl.Instance;
   if (tracker)
     instance.addDependencyCollector(tracker->getClangCollector());
@@ -804,7 +886,9 @@
 
   // Create the associated action.
   importer->Impl.Action.reset(new ParsingAction(ctx, *importer,
-                                                importer->Impl));
+                                                importer->Impl,
+                                                importerOpts,
+                                                swiftPCHHash));
   auto *action = importer->Impl.Action.get();
 
   // Execute the action. We effectively inline most of
@@ -934,6 +1018,7 @@
     bool trackParsedSymbols,
     std::unique_ptr<llvm::MemoryBuffer> sourceBuffer,
     bool implicitImport) {
+
   // Don't even try to load the bridging header if the Clang AST is in a bad
   // state. It could cause a crash.
   auto &clangDiags = getClangASTContext().getDiagnostics();
@@ -1061,6 +1146,11 @@
     return importBridgingHeader(header, adapter, diagLoc, false, true);
   }
 
+  // If we've made it to here, this is some header other than the bridging
+  // header, which means we can no longer rely on one file's modification time
+  // to invalid code completion caches. :-(
+  Impl.setSinglePCHImport(None);
+
   if (!cachedContents.empty() && cachedContents.back() == '\0')
     cachedContents = cachedContents.drop_back();
   std::unique_ptr<llvm::MemoryBuffer> sourceBuffer{
@@ -1082,6 +1172,7 @@
     Impl.handleDeferredImports();
     return false;
   }
+
   clang::FileManager &fileManager = Impl.Instance->getFileManager();
   const clang::FileEntry *headerFile = fileManager.getFile(header,
                                                            /*OpenFile=*/true);
@@ -1152,7 +1243,8 @@
 
 bool
 ClangImporter::emitBridgingPCH(StringRef headerPath,
-                               StringRef outputPCHPath) {
+                               StringRef outputPCHPath,
+                               clang::DiagnosticConsumer *Diags) {
   auto invocation = std::make_shared<clang::CompilerInvocation>
     (clang::CompilerInvocation(*Impl.Invocation));
   invocation->getFrontendOpts().DisableFree = false;
@@ -1165,8 +1257,12 @@
   clang::CompilerInstance emitInstance(
     Impl.Instance->getPCHContainerOperations());
   emitInstance.setInvocation(std::move(invocation));
-  emitInstance.createDiagnostics(&Impl.Instance->getDiagnosticClient(),
-                                 false);
+
+  auto ReusingDiags = Diags == nullptr;
+  if (ReusingDiags) {
+    Diags = &Impl.Instance->getDiagnosticClient();
+  }
+  emitInstance.createDiagnostics(Diags, /*ShouldOwnDiags=*/!ReusingDiags);
 
   clang::FileManager &fileManager = Impl.Instance->getFileManager();
   emitInstance.setFileManager(&fileManager);
@@ -2446,8 +2542,13 @@
 }
 
 StringRef ClangModuleUnit::getFilename() const {
-  if (!clangModule)
-    return "<imports>";
+  if (!clangModule) {
+    StringRef SinglePCH = owner.getSinglePCHImport();
+    if (SinglePCH.empty())
+      return "<imports>";
+    else
+      return SinglePCH;
+  }
   if (const clang::FileEntry *F = clangModule->getASTFile())
     if (!F->getName().empty())
       return F->getName();
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index c2aaa76..fbe9249 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -30,9 +30,11 @@
 #include "swift/AST/NameLookup.h"
 #include "swift/AST/ParameterList.h"
 #include "swift/AST/Pattern.h"
+#include "swift/AST/PrettyStackTrace.h"
 #include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/Stmt.h"
 #include "swift/AST/Types.h"
+#include "swift/Basic/PrettyStackTrace.h"
 #include "swift/ClangImporter/ClangModule.h"
 #include "swift/Parse/Lexer.h"
 #include "swift/Config.h"
@@ -996,7 +998,7 @@
                                                        clang::VK_RValue,
                                                        clang::OK_Ordinary,
                                                        clang::SourceLocation(),
-                                                       /*fpContractable=*/ false);
+                                                       clang::FPOptions());
     
     cSetterDecl->setBody(cSetterExpr);
 
@@ -1711,16 +1713,35 @@
 /// Whether we should suppress importing the Objective-C generic type params
 /// of this class as Swift generic type params.
 static bool
-shouldSuppressGenericParamsImport(const clang::ObjCInterfaceDecl *decl) {
-  while (decl) {
-    StringRef name = decl->getName();
-    if (name == "NSArray" || name == "NSDictionary" || name == "NSSet" ||
-        name == "NSOrderedSet" || name == "NSEnumerator" ||
-        name == "NSMeasurement") {
-      return true;
+shouldSuppressGenericParamsImport(const LangOptions &langOpts,
+                                  const clang::ObjCInterfaceDecl *decl) {
+  if (decl->hasAttr<clang::SwiftImportAsNonGenericAttr>())
+    return true;
+
+  // FIXME: This check is only necessary to keep things working even without
+  // the SwiftImportAsNonGeneric API note. Once we can guarantee that that
+  // attribute is present in all contexts, we can remove this check.
+  auto isFromFoundationModule = [](const clang::Decl *decl) -> bool {
+    Optional<clang::Module *> module = getClangSubmoduleForDecl(decl);
+    if (!module)
+      return false;
+    return module.getValue()->getTopLevelModuleName() == "Foundation";
+  };
+
+  if (langOpts.isSwiftVersion3() || isFromFoundationModule(decl)) {
+    // In Swift 3 we used a hardcoded list of declarations, and made all of
+    // their subclasses drop their generic parameters when imported.
+    while (decl) {
+      StringRef name = decl->getName();
+      if (name == "NSArray" || name == "NSDictionary" || name == "NSSet" ||
+          name == "NSOrderedSet" || name == "NSEnumerator" ||
+          name == "NSMeasurement") {
+        return true;
+      }
+      decl = decl->getSuperClass();
     }
-    decl = decl->getSuperClass();
   }
+
   return false;
 }
 
@@ -3063,10 +3084,12 @@
 
     Decl *importGlobalAsInitializer(const clang::FunctionDecl *decl,
                                     DeclName name, DeclContext *dc,
-                                    CtorInitializerKind initKind);
+                                    CtorInitializerKind initKind,
+                                    Optional<ImportedName> correctSwiftName);
 
     Decl *importGlobalAsMethod(const clang::FunctionDecl *decl, DeclName name,
-                               DeclContext *dc, Optional<unsigned> selfIdx);
+                               DeclContext *dc, Optional<unsigned> selfIdx,
+                               Optional<ImportedName> correctSwiftName);
 
     /// Create an implicit property given the imported name of one of
     /// the accessors.
@@ -3116,16 +3139,16 @@
 
       DeclName name = owningStorage ? DeclName() : importedName.getDeclName();
       if (importedName.importAsMember()) {
-        assert(!correctSwiftName && "Swift 2 didn't support import-as-member!");
-
         // Handle initializers.
         if (name.getBaseName() == Impl.SwiftContext.Id_init)
           return importGlobalAsInitializer(decl, name, dc,
-                                           importedName.getInitKind());
+                                           importedName.getInitKind(),
+                                           correctSwiftName);
 
         // Everything else is a method.
         return importGlobalAsMethod(decl, name, dc,
-                                    importedName.getSelfIndex());
+                                    importedName.getSelfIndex(),
+                                    correctSwiftName);
       }
 
       // Import the function type. If we have parameters, make sure their names
@@ -4323,32 +4346,44 @@
       // Check whether there is a function with the same name as this
       // property. If so, suppress the property; the user will have to use
       // the methods directly, to avoid ambiguities.
-      auto containerTy = dc->getDeclaredTypeInContext();
-      VarDecl *overridden = nullptr;
-      SmallVector<ValueDecl *, 2> lookup;
-      dc->lookupQualified(containerTy, name,
-                          NL_QualifiedDefault | NL_KnownNoDependency,
-                          Impl.getTypeResolver(), lookup);
-      for (auto result : lookup) {
-        if (isa<FuncDecl>(result) &&
-            result->isInstanceMember() == decl->isInstanceProperty() &&
-            result->getFullName().getArgumentNames().empty())
-          return nullptr;
+      Type containerTy = dc->getDeclaredInterfaceType();
+      Type lookupContextTy = containerTy;
+      if (auto *classDecl = dyn_cast<ClassDecl>(dc)) {
+        // If we're importing into the primary @interface for something, as
+        // opposed to an extension, make sure we don't try to load any
+        // categories...by just looking into the super type.
+        lookupContextTy = classDecl->getSuperclass();
+      }
 
-        if (auto var = dyn_cast<VarDecl>(result)) {
-          // If the selectors of the getter match in Objective-C, we have an
-          // override.
-          if (var->isInstanceMember() == decl->isInstanceProperty() &&
-              var->getObjCGetterSelector() ==
-                Impl.importSelector(decl->getGetterName()))
-            overridden = var;
+      VarDecl *overridden = nullptr;
+      if (lookupContextTy) {
+        SmallVector<ValueDecl *, 2> lookup;
+        dc->lookupQualified(lookupContextTy, name,
+                            NL_QualifiedDefault | NL_KnownNoDependency,
+                            Impl.getTypeResolver(), lookup);
+        for (auto result : lookup) {
+          if (isa<FuncDecl>(result) &&
+              result->isInstanceMember() == decl->isInstanceProperty() &&
+              result->getFullName().getArgumentNames().empty())
+            return nullptr;
+
+          if (auto var = dyn_cast<VarDecl>(result)) {
+            // If the selectors of the getter match in Objective-C, we have an
+            // override.
+            if (var->isInstanceMember() == decl->isInstanceProperty() &&
+                var->getObjCGetterSelector() ==
+                  Impl.importSelector(decl->getGetterName()))
+              overridden = var;
+          }
         }
       }
 
       if (overridden) {
         const DeclContext *overrideContext = overridden->getDeclContext();
-        if (overrideContext != dc &&
-            overrideContext->getDeclaredTypeInContext()->isEqual(containerTy)) {
+        // It's okay to compare interface types directly because Objective-C
+        // does not have constrained extensions.
+        if (overrideContext != dc && overridden->hasClangNode() &&
+            overrideContext->getDeclaredInterfaceType()->isEqual(containerTy)) {
           // We've encountered a redeclaration of the property.
           // HACK: Just update the original declaration instead of importing a
           // second property.
@@ -4672,12 +4707,8 @@
     }
   }
 
-  // Import the declaration context where this name will go. Note that
-  // this is the "natural" context for the declaration, without
-  // import-as-member inference or swift_name tricks.
-  EffectiveClangContext effectiveContext(
-      decl->getDeclContext()->getRedeclContext());
-  auto dc = Impl.importDeclContextOf(decl, effectiveContext);
+  auto dc = Impl.importDeclContextOf(decl,
+                                     compatibilityName.getEffectiveContext());
   if (!dc)
     return nullptr;
 
@@ -4695,6 +4726,53 @@
   return alias;
 }
 
+static bool inheritanceListContainsProtocol(ArrayRef<TypeLoc> inherited,
+                                            const ProtocolDecl *proto) {
+  return llvm::any_of(inherited, [proto](TypeLoc type) -> bool {
+    if (!type.getType()->isExistentialType())
+      return false;
+    SmallVector<ProtocolDecl *, 8> protos;
+    type.getType()->getExistentialTypeProtocols(protos);
+    return ProtocolType::visitAllProtocols(protos,
+                                           [proto](const ProtocolDecl *next) {
+      return next == proto;
+    });
+  });
+}
+
+static bool conformsToProtocolInOriginalModule(NominalTypeDecl *nominal,
+                                               const ProtocolDecl *proto,
+                                               ModuleDecl *foundationModule,
+                                               LazyResolver *resolver) {
+  if (resolver)
+    resolver->resolveInheritanceClause(nominal);
+  if (inheritanceListContainsProtocol(nominal->getInherited(), proto))
+    return true;
+
+  // Only consider extensions from the original module...or from an overlay
+  // or the Swift half of a mixed-source framework.
+  const DeclContext *containingFile = nominal->getModuleScopeContext();
+  ModuleDecl *originalModule = containingFile->getParentModule();
+
+  ModuleDecl *adapterModule = nullptr;
+  if (auto *clangUnit = dyn_cast<ClangModuleUnit>(containingFile))
+    adapterModule = clangUnit->getAdapterModule();
+
+  for (ExtensionDecl *extension : nominal->getExtensions()) {
+    ModuleDecl *extensionModule = extension->getParentModule();
+    if (extensionModule != originalModule && extensionModule != adapterModule &&
+        extensionModule != foundationModule) {
+      continue;
+    }
+    if (resolver)
+      resolver->resolveInheritanceClause(extension);
+    if (inheritanceListContainsProtocol(extension->getInherited(), proto))
+      return true;
+  }
+
+  return false;
+}
+
 Decl *
 SwiftDeclConverter::importSwiftNewtype(const clang::TypedefNameDecl *decl,
                                        clang::SwiftNewtypeAttr *newtypeAttr,
@@ -4779,9 +4857,11 @@
     if (!proto)
       return;
 
-    SmallVector<ProtocolConformance *, 1> conformances;
-    if (computedNominal->lookupConformance(computedNominal->getParentModule(),
-                                           proto, conformances)) {
+    // Break circularity by only looking for declared conformances in the
+    // original module, or possibly its adapter.
+    if (conformsToProtocolInOriginalModule(computedNominal, proto,
+                                           Impl.tryLoadFoundationModule(),
+                                           Impl.getTypeResolver())) {
       protocols.push_back(proto);
       synthesizedProtocols.push_back(kind);
     }
@@ -4972,10 +5052,12 @@
   return structDecl;
 }
 
-Decl *
-SwiftDeclConverter::importGlobalAsInitializer(const clang::FunctionDecl *decl,
-                                               DeclName name, DeclContext *dc,
-                                               CtorInitializerKind initKind) {
+Decl *SwiftDeclConverter::importGlobalAsInitializer(
+    const clang::FunctionDecl *decl,
+    DeclName name,
+    DeclContext *dc,
+    CtorInitializerKind initKind,
+    Optional<ImportedName> correctSwiftName) {
   // TODO: Should this be an error? How can this come up?
   assert(dc->isTypeContext() && "cannot import as member onto non-type");
 
@@ -5042,12 +5124,17 @@
   result->setInterfaceType(allocType);
 
   finishFuncDecl(decl, result);
+  if (correctSwiftName)
+    markAsVariant(result, *correctSwiftName);
   return result;
 }
 
-Decl *SwiftDeclConverter::importGlobalAsMethod(const clang::FunctionDecl *decl,
-                                                DeclName name, DeclContext *dc,
-                                                Optional<unsigned> selfIdx) {
+Decl *SwiftDeclConverter::importGlobalAsMethod(
+    const clang::FunctionDecl *decl,
+    DeclName name,
+    DeclContext *dc,
+    Optional<unsigned> selfIdx,
+    Optional<ImportedName> correctSwiftName) {
   if (dc->getAsProtocolOrProtocolExtensionContext() && !selfIdx) {
     // FIXME: source location...
     Impl.SwiftContext.Diags.diagnose({}, diag::swift_name_protocol_static,
@@ -5124,6 +5211,8 @@
     result->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
 
   finishFuncDecl(decl, result);
+  if (correctSwiftName)
+    markAsVariant(result, *correctSwiftName);
   return result;
 }
 
@@ -5529,7 +5618,9 @@
                             ->getResult()
                             ->castTo<AnyFunctionType>()
                             ->getInput();
-  for (auto other : ownerNominal->lookupDirect(importedName.getDeclName())) {
+  bool ignoreNewExtensions = isa<ClassDecl>(dc);
+  for (auto other : ownerNominal->lookupDirect(importedName.getDeclName(),
+                                               ignoreNewExtensions)) {
     auto ctor = dyn_cast<ConstructorDecl>(other);
     if (!ctor || ctor->isInvalid() ||
         ctor->getAttrs().isUnavailable(Impl.SwiftContext) ||
@@ -6133,7 +6224,7 @@
   if (!typeParamList) {
     return nullptr;
   }
-  if (shouldSuppressGenericParamsImport(decl)) {
+  if (shouldSuppressGenericParamsImport(Impl.SwiftContext.LangOpts, decl)) {
     return nullptr;
   }
   assert(typeParamList->size() > 0);
@@ -6698,13 +6789,29 @@
   if (AnyUnavailable)
     return;
 
-  // Ban NSInvocation.
   if (auto ID = dyn_cast<clang::ObjCInterfaceDecl>(ClangDecl)) {
+    // Ban NSInvocation.
     if (ID->getName() == "NSInvocation") {
       auto attr = AvailableAttr::createPlatformAgnostic(C, "");
       MappedDecl->getAttrs().add(attr);
       return;
     }
+
+    // Map Clang's swift_objc_members attribute to @objcMembers.
+    if (ID->hasAttr<clang::SwiftObjCMembersAttr>()) {
+      if (!MappedDecl->getAttrs().hasAttribute<ObjCMembersAttr>()) {
+        auto attr = new (C) ObjCMembersAttr(/*implicit=*/true);
+        MappedDecl->getAttrs().add(attr);
+      }
+    }
+
+    // Infer @objcMembers on XCTestCase.
+    if (ID->getName() == "XCTestCase") {
+      if (!MappedDecl->getAttrs().hasAttribute<ObjCMembersAttr>()) {
+        auto attr = new (C) ObjCMembersAttr(/*implicit=*/true);
+        MappedDecl->getAttrs().add(attr);
+      }
+    }
   }
 
   // Ban CFRelease|CFRetain|CFAutorelease(CFTypeRef) as well as custom ones
@@ -6977,8 +7084,6 @@
                                                      /*resolver=*/nullptr);
     assert(inheritedConformance && inheritedConformance->isConcrete() &&
            "inherited conformance not found");
-    conformance->setInheritedConformance(inherited,
-                                         inheritedConformance->getConcrete());
   }
 
   // Collect conformances for the requirement signature.
@@ -7495,6 +7600,15 @@
     auto table = findLookupTable(topLevelModule);
     if (!table) return;
 
+    StringRef traceName;
+    if (topLevelModule)
+      traceName = topLevelModule->getTopLevelModuleName();
+    else
+      traceName = "(bridging header)";
+    PrettyStackTraceStringAction trace("loading import-as-members from",
+                                       traceName);
+    PrettyStackTraceDecl trace2("...for", nominal);
+
     // Dig out the effective Clang context for this nominal type.
     auto effectiveClangContext = getEffectiveClangContext(nominal);
     if (!effectiveClangContext) return;
@@ -7560,6 +7674,23 @@
     auto ext = cast<ExtensionDecl>(D);
     DC = ext;
     IDC = ext;
+
+
+    // If the base is also imported from Clang, load its members first.
+    const NominalTypeDecl *base = ext->getExtendedType()->getAnyNominal();
+    if (auto *clangBase = base->getClangDecl()) {
+      base->loadAllMembers();
+
+      // Sanity check: make sure we don't jump over to a category /while/
+      // loading the original class's members. Right now we only check if this
+      // happens on the first member.
+      if (auto *clangContainer = dyn_cast<clang::ObjCContainerDecl>(clangBase)){
+        if (!clangContainer->decls_empty()) {
+          assert(!base->getMembers().empty() &&
+                 "can't load extension members before base has finished");
+        }
+      }
+    }
   }
 
   ImportingEntityRAII Importing(*this);
diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h
index c5be503..ec6b02c 100644
--- a/lib/ClangImporter/ImporterImpl.h
+++ b/lib/ClangImporter/ImporterImpl.h
@@ -29,6 +29,7 @@
 #include "swift/AST/Type.h"
 #include "swift/AST/ForeignErrorConvention.h"
 #include "swift/Basic/StringExtras.h"
+#include "swift/Strings.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclVisitor.h"
 #include "clang/Basic/IdentifierTable.h"
@@ -40,6 +41,7 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Support/Path.h"
 #include <set>
 
 namespace llvm {
@@ -386,6 +388,10 @@
   llvm::DenseMap<std::pair<ObjCSelector, char>, unsigned>
     ActiveSelectors;
 
+  clang::CompilerInstance *getClangInstance() {
+    return Instance.get();
+  }
+
 private:
   /// \brief Generation number that is used for crude versioning.
   ///
@@ -532,6 +538,11 @@
   /// after having set up a suitable Clang instance.
   std::unique_ptr<importer::NameImporter> nameImporter = nullptr;
 
+  /// If there is a single .PCH file imported into the __ObjC module, this
+  /// is the filename of that PCH. When other files are imported, this should
+  /// be llvm::None.
+  Optional<std::string> SinglePCHImport = None;
+
 public:
   importer::NameImporter &getNameImporter() {
     assert(nameImporter && "haven't finished initialization");
@@ -1158,6 +1169,24 @@
 
   /// Dump the Swift-specific name lookup tables we generate.
   void dumpSwiftLookupTables();
+
+  void setSinglePCHImport(Optional<std::string> PCHFilename) {
+    if (PCHFilename.hasValue()) {
+      assert(llvm::sys::path::extension(PCHFilename.getValue())
+                 .endswith(PCH_EXTENSION) &&
+             "Single PCH imported filename doesn't have .pch extension!");
+    }
+    SinglePCHImport = PCHFilename;
+  }
+
+  /// If there was is a single .pch bridging header without other imported
+  /// files, we can provide the PCH filename for declaration caching,
+  /// especially in code completion.
+  StringRef getSinglePCHImport() const {
+    if (SinglePCHImport.hasValue())
+      return *SinglePCHImport;
+    return StringRef();
+  }
 };
 
 namespace importer {
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index 68a9a21..80fbeaa 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -905,6 +905,10 @@
       BoundParent = createWithChildren(Node::Kind::Extension,
                                        Context->getFirstChild(),
                                        BoundParent);
+      if (Context->getNumChildren() == 3) {
+        // Add the generic signature of the extension context.
+        addChild(BoundParent, Context->getChild(2));
+      }
     } else {
       BoundParent = demangleBoundGenericArgs(Context, TypeLists, TypeListIdx);
     }
diff --git a/lib/Demangling/NodeDumper.cpp b/lib/Demangling/NodeDumper.cpp
index 5f2f453..be2929d 100644
--- a/lib/Demangling/NodeDumper.cpp
+++ b/lib/Demangling/NodeDumper.cpp
@@ -1,4 +1,4 @@
-//===--- NodeDumper.cpp - Swift Demangling Node Dumper --------------------===//
+//===--- NodeDumper.cpp - Swift Demangling Debug Dump Functions -----------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "swift/Demangling/Demangle.h"
+#include "swift/Demangling/Demangler.h"
 #include <cstdio>
 
 using namespace swift;
@@ -58,3 +59,14 @@
   std::string TreeStr = getNodeTreeAsString(this);
   fputs(TreeStr.c_str(), stderr);
 }
+
+void Demangler::dump() {
+  for (unsigned Idx = 0; Idx < NodeStack.size(); ++Idx) {
+    fprintf(stderr, "NodeStack[%u] at position %zd:\n", Idx, NodeStack[Idx].Pos);
+    NodeStack[Idx].Node->dump();
+    fprintf(stderr, "\n");
+  }
+  fprintf(stderr, "Position = %zd:\n%.*s\n%*s\n", Pos,
+          (int)Text.size(), Text.data(), (int)Pos + 1, "^");
+}
+
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 5e22af5..aec1355 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -1784,6 +1784,10 @@
       NodePointer result = Factory.createNode(Node::Kind::Extension);
       result->addChild(node->getFirstChild(), Factory);
       result->addChild(getUnspecialized(parent, Factory), Factory);
+      if (node->getNumChildren() == 3) {
+        // Add the generic signature of the extension.
+        result->addChild(node->getChild(2), Factory);
+      }
       return result;
     }
     default:
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 7ae5be6..1a43f8b 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -15,6 +15,7 @@
 #include "swift/AST/DiagnosticEngine.h"
 #include "swift/AST/DiagnosticsDriver.h"
 #include "swift/Basic/Program.h"
+#include "swift/Basic/Statistic.h"
 #include "swift/Basic/TaskQueue.h"
 #include "swift/Basic/Version.h"
 #include "swift/Basic/type_traits.h"
@@ -92,7 +93,8 @@
                          bool EnableIncrementalBuild,
                          bool SkipTaskExecution,
                          bool SaveTemps,
-                         bool ShowDriverTimeCompilation)
+                         bool ShowDriverTimeCompilation,
+                         std::unique_ptr<UnifiedStatsReporter> StatsReporter)
   : Diags(Diags), Level(Level), RawInputArgs(std::move(InputArgs)),
     TranslatedArgs(std::move(TranslatedArgs)), 
     InputFilesWithTypes(std::move(InputsWithTypes)), ArgsHash(ArgsHash),
@@ -101,7 +103,8 @@
     SkipTaskExecution(SkipTaskExecution),
     EnableIncrementalBuild(EnableIncrementalBuild),
     SaveTemps(SaveTemps),
-    ShowDriverTimeCompilation(ShowDriverTimeCompilation) {
+    ShowDriverTimeCompilation(ShowDriverTimeCompilation),
+    Stats(std::move(StatsReporter)) {
 };
 
 static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags);
@@ -229,7 +232,13 @@
                      << ": " << LogJob(Cmd) << "\n";
       }
       FinishedCommands.insert(Cmd);
-
+      if (Comp.Stats) {
+          auto &D = Comp.Stats->getDriverCounters();
+          if (Skipped)
+            D.NumDriverJobsSkipped++;
+          else
+            D.NumDriverJobsRun++;
+      }
       auto BlockedIter = BlockingCommands.find(Cmd);
       if (BlockedIter != BlockingCommands.end()) {
         auto AllBlocked = std::move(BlockedIter->second);
@@ -466,12 +475,14 @@
     }
 
   public:
-    PerformJobsState(Compilation &Comp) : Comp(Comp) {
+    PerformJobsState(Compilation &Comp)
+      : Comp(Comp),
+        ActualIncrementalTracer(Comp.Stats.get()) {
       if (Comp.SkipTaskExecution)
         TQ.reset(new DummyTaskQueue(Comp.NumberOfParallelCommands));
       else
         TQ.reset(new TaskQueue(Comp.NumberOfParallelCommands));
-      if (Comp.ShowIncrementalBuildDecisions)
+      if (Comp.ShowIncrementalBuildDecisions || Comp.Stats)
         IncrementalTracer = &ActualIncrementalTracer;
     }
 
diff --git a/lib/Driver/DependencyGraph.cpp b/lib/Driver/DependencyGraph.cpp
index 7643397..4852425 100644
--- a/lib/Driver/DependencyGraph.cpp
+++ b/lib/Driver/DependencyGraph.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "swift/Basic/Statistic.h"
 #include "swift/Driver/DependencyGraph.h"
 #include "swift/Demangling/Demangle.h"
 #include "llvm/ADT/SmallString.h"
@@ -41,7 +42,8 @@
   DependencyMaskTy KindMask;
 };
 
-DependencyGraphImpl::MarkTracerImpl::MarkTracerImpl() = default;
+DependencyGraphImpl::MarkTracerImpl::MarkTracerImpl(UnifiedStatsReporter *Stats)
+  : Stats(Stats) {}
 DependencyGraphImpl::MarkTracerImpl::~MarkTracerImpl() = default;
 
 using LoadResult = DependencyGraphImpl::LoadResult;
@@ -350,6 +352,7 @@
 
         MutableArrayRef<MarkTracerImpl::Entry> newReason;
         if (tracer) {
+          tracer->countStatsForNodeMarking(intersectingKinds, isCascading);
           newReason = {scratchAlloc.Allocate(reason.size()+1), reason.size()+1};
           std::uninitialized_copy(reason.begin(), reason.end(),
                                   newReason.begin());
@@ -393,6 +396,38 @@
   }
 }
 
+void DependencyGraphImpl::MarkTracerImpl::countStatsForNodeMarking(
+  const OptionSet<DependencyKind> &Kind, bool IsCascading) const {
+
+  if (!Stats)
+    return;
+
+  auto &D = Stats->getDriverCounters();
+  if (IsCascading) {
+    if (Kind & DependencyKind::TopLevelName)
+      D.DriverDepCascadingTopLevel++;
+    if (Kind & DependencyKind::DynamicLookupName)
+      D.DriverDepCascadingDynamic++;
+    if (Kind & DependencyKind::NominalType)
+      D.DriverDepCascadingNominal++;
+    if (Kind & DependencyKind::NominalTypeMember)
+      D.DriverDepCascadingMember++;
+    if (Kind & DependencyKind::NominalTypeMember)
+      D.DriverDepCascadingExternal++;
+  } else {
+    if (Kind & DependencyKind::TopLevelName)
+      D.DriverDepTopLevel++;
+    if (Kind & DependencyKind::DynamicLookupName)
+      D.DriverDepDynamic++;
+    if (Kind & DependencyKind::NominalType)
+      D.DriverDepNominal++;
+    if (Kind & DependencyKind::NominalTypeMember)
+      D.DriverDepMember++;
+    if (Kind & DependencyKind::NominalTypeMember)
+      D.DriverDepExternal++;
+  }
+}
+
 void DependencyGraphImpl::MarkTracerImpl::printPath(
     raw_ostream &out,
     const void *item,
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 1fde07a..ecd2576 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -25,6 +25,7 @@
 #include "swift/Basic/TaskQueue.h"
 #include "swift/Basic/Version.h"
 #include "swift/Basic/Range.h"
+#include "swift/Basic/Statistic.h"
 #include "swift/Driver/Action.h"
 #include "swift/Driver/Compilation.h"
 #include "swift/Driver/Job.h"
@@ -554,6 +555,14 @@
   if (Diags.hadAnyError())
     return nullptr;
 
+  std::unique_ptr<UnifiedStatsReporter> StatsReporter;
+  if (const Arg *A =
+      ArgList->getLastArgNoClaim(options::OPT_stats_output_dir)) {
+    StatsReporter = llvm::make_unique<UnifiedStatsReporter>("swift-driver",
+                                                            OI.ModuleName,
+                                                            A->getValue());
+  }
+
   assert(OI.CompilerOutputType != types::ID::TY_INVALID &&
          "buildOutputInfo() must set a valid output type!");
   
@@ -655,7 +664,8 @@
                                                  Incremental,
                                                  DriverSkipExecution,
                                                  SaveTemps,
-                                                 ShowDriverTimeCompilation));
+                                                 ShowDriverTimeCompilation,
+                                                 std::move(StatsReporter)));
 
   buildJobs(Actions, OI, OFM.get(), *TC, *C);
 
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index ff94b81..008a9db 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -139,6 +139,7 @@
   inputArgs.AddLastArg(arguments, options::OPT_parse_stdlib);
   inputArgs.AddLastArg(arguments, options::OPT_resource_dir);
   inputArgs.AddLastArg(arguments, options::OPT_solver_memory_threshold);
+  inputArgs.AddLastArg(arguments, options::OPT_warn_swift3_objc_inference);
   inputArgs.AddLastArg(arguments, options::OPT_suppress_warnings);
   inputArgs.AddLastArg(arguments, options::OPT_profile_generate);
   inputArgs.AddLastArg(arguments, options::OPT_profile_coverage_mapping);
@@ -147,6 +148,7 @@
   inputArgs.AddLastArg(arguments, options::OPT_sanitize_coverage_EQ);
   inputArgs.AddLastArg(arguments, options::OPT_swift_version);
   inputArgs.AddLastArg(arguments, options::OPT_enforce_exclusivity_EQ);
+  inputArgs.AddLastArg(arguments, options::OPT_stats_output_dir);
 
   // Pass on any build config options
   inputArgs.AddAllArgs(arguments, options::OPT_D);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 2ccb201..409adf7 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -187,6 +187,9 @@
   Opts.DebugTimeExpressionTypeChecking |=
     Args.hasArg(OPT_debug_time_expression_type_checking);
   Opts.DebugTimeCompilation |= Args.hasArg(OPT_debug_time_compilation);
+  if (const Arg *A = Args.getLastArg(OPT_stats_output_dir)) {
+    Opts.StatsOutputDir = A->getValue();
+  }
 
   Opts.ValidateTBDAgainstIR |= Args.hasArg(OPT_validate_tbd_against_ir);
 
@@ -955,6 +958,12 @@
   }
 
   Opts.EnableAppExtensionRestrictions |= Args.hasArg(OPT_enable_app_extension);
+  Opts.WarnSwift3ObjCInference |= Args.hasArg(OPT_warn_swift3_objc_inference);
+
+  Opts.EnableSwift3ObjCInference =
+    Args.hasFlag(OPT_enable_swift3_objc_inference,
+                 OPT_disable_swift3_objc_inference,
+                 Opts.isSwiftVersion3());
 
   llvm::Triple Target = Opts.Target;
   StringRef TargetArg;
@@ -1209,6 +1218,9 @@
       llvm_unreachable("Unknown SIL linking option!");
   }
 
+  if (Args.hasArg(OPT_sil_merge_partial_modules))
+    Opts.MergePartialModules = true;
+
   // Parse the optimization level.
   if (const Arg *A = Args.getLastArg(OPT_O_Group)) {
     if (A->getOption().matches(OPT_Onone)) {
@@ -1284,6 +1296,8 @@
   Opts.EnableSILOwnership |= Args.hasArg(OPT_enable_sil_ownership);
   Opts.AssumeUnqualifiedOwnershipWhenParsing
     |= Args.hasArg(OPT_assume_parsing_unqualified_ownership_sil);
+  Opts.EnableMandatorySemanticARCOpts |=
+      !Args.hasArg(OPT_disable_mandatory_semantic_arc_opts);
 
   if (Args.hasArg(OPT_debug_on_sil)) {
     // Derive the name of the SIL file for debugging from
@@ -1571,7 +1585,6 @@
   return false;
 }
 
-
 serialization::Status
 CompilerInvocation::loadFromSerializedAST(StringRef data) {
   serialization::ExtendedValidationInfo extendedInfo;
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index 64cae61..8d5efd5 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -27,6 +27,7 @@
 #include "swift/Parse/Lexer.h"
 #include "swift/SIL/SILModule.h"
 #include "swift/Serialization/SerializedModuleLoader.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Support/CommandLine.h"
@@ -35,11 +36,27 @@
 
 using namespace swift;
 
+std::string CompilerInvocation::getPCHHash() const {
+  using llvm::hash_code;
+  using llvm::hash_value;
+  using llvm::hash_combine;
+
+  auto Code = hash_value(LangOpts.getPCHHashComponents());
+  Code = hash_combine(Code, FrontendOpts.getPCHHashComponents());
+  Code = hash_combine(Code, ClangImporterOpts.getPCHHashComponents());
+  Code = hash_combine(Code, SearchPathOpts.getPCHHashComponents());
+  Code = hash_combine(Code, DiagnosticOpts.getPCHHashComponents());
+  Code = hash_combine(Code, SILOpts.getPCHHashComponents());
+  Code = hash_combine(Code, IRGenOpts.getPCHHashComponents());
+
+  return llvm::APInt(64, Code).toString(36, /*Signed=*/false);
+}
+
 void CompilerInstance::createSILModule(bool WholeModule) {
   assert(MainModule && "main module not created yet");
-  TheSILModule = SILModule::createEmptyModule(getMainModule(),
-                                              Invocation.getSILOptions(),
-                                              WholeModule);
+  TheSILModule = SILModule::createEmptyModule(
+      getMainModule(), Invocation.getSILOptions(), WholeModule,
+      Invocation.getFrontendOptions().SILSerializeAll);
 }
 
 void CompilerInstance::setPrimarySourceFile(SourceFile *SF) {
@@ -103,6 +120,7 @@
   // knowledge.
   auto clangImporter =
     ClangImporter::create(*Context, Invocation.getClangImporterOptions(),
+                          Invocation.getPCHHash(),
                           DepTracker);
   if (!clangImporter) {
     Diagnostics.diagnose(SourceLoc(), diag::error_clang_importer_create_fail);
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 4df0d76..c492ab6 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -38,6 +38,7 @@
 #include "swift/Basic/FileSystem.h"
 #include "swift/Basic/LLVMContext.h"
 #include "swift/Basic/SourceManager.h"
+#include "swift/Basic/Statistic.h"
 #include "swift/Basic/Timer.h"
 #include "swift/Frontend/DiagnosticVerifier.h"
 #include "swift/Frontend/Frontend.h"
@@ -325,6 +326,28 @@
   LLVM_BUILTIN_TRAP;
 }
 
+static void countStatsPostSILGen(UnifiedStatsReporter &Stats,
+                                 const SILModule& Module) {
+  auto &C = Stats.getFrontendCounters();
+  // FIXME: calculate these in constant time, via the dense maps.
+  C.NumSILGenFunctions = Module.getFunctionList().size();
+  C.NumSILGenVtables = Module.getVTableList().size();
+  C.NumSILGenWitnessTables = Module.getWitnessTableList().size();
+  C.NumSILGenDefaultWitnessTables = Module.getDefaultWitnessTableList().size();
+  C.NumSILGenGlobalVariables = Module.getSILGlobalList().size();
+}
+
+static void countStatsPostSILOpt(UnifiedStatsReporter &Stats,
+                                 const SILModule& Module) {
+  auto &C = Stats.getFrontendCounters();
+  // FIXME: calculate these in constant time, via the dense maps.
+  C.NumSILOptFunctions = Module.getFunctionList().size();
+  C.NumSILOptVtables = Module.getVTableList().size();
+  C.NumSILOptWitnessTables = Module.getWitnessTableList().size();
+  C.NumSILOptDefaultWitnessTables = Module.getDefaultWitnessTableList().size();
+  C.NumSILOptGlobalVariables = Module.getSILGlobalList().size();
+}
+
 /// Performs the compile requested by the user.
 /// \param Instance Will be reset after performIRGeneration when the verifier
 ///                 mode is NoVerify and there were no errors.
@@ -333,7 +356,8 @@
                            CompilerInvocation &Invocation,
                            ArrayRef<const char *> Args,
                            int &ReturnValue,
-                           FrontendObserver *observer) {
+                           FrontendObserver *observer,
+                           UnifiedStatsReporter *Stats) {
   FrontendOptions opts = Invocation.getFrontendOptions();
   FrontendOptions::ActionType Action = opts.RequestedAction;
 
@@ -343,7 +367,8 @@
     auto clangImporter = static_cast<ClangImporter *>(
       Instance->getASTContext().getClangModuleLoader());
     return clangImporter->emitBridgingPCH(
-      Invocation.getInputFilenames()[0], opts.getSingleOutputFilename());
+      Invocation.getInputFilenames()[0],
+      opts.getSingleOutputFilename());
   }
 
   IRGenOptions &IRGenOpts = Invocation.getIRGenOptions();
@@ -525,7 +550,9 @@
   }
 
   if (Action == FrontendOptions::EmitTBD) {
-    return writeTBD(Instance->getMainModule(), opts.getSingleOutputFilename());
+    auto hasMultipleIRGenThreads = Invocation.getSILOptions().NumThreads > 1;
+    return writeTBD(Instance->getMainModule(), hasMultipleIRGenThreads,
+                    opts.getSingleOutputFilename());
   }
 
   assert(Action >= FrontendOptions::EmitSILGen &&
@@ -551,6 +578,9 @@
   if (observer) {
     observer->performedSILGeneration(*SM);
   }
+  if (Stats) {
+    countStatsPostSILGen(*Stats, *SM);
+  }
 
   // We've been told to emit SIL after SILGen, so write it now.
   if (Action == FrontendOptions::EmitSILGen) {
@@ -598,8 +628,11 @@
   if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll)
     performSILLinking(SM.get(), true);
 
+  if (Invocation.getSILOptions().MergePartialModules)
+    SM->linkAllFromCurrentModule();
+
   {
-    SharedTimer timer("SIL verification (pre-optimization)");
+    SharedTimer timer("SIL verification, pre-optimization");
     SM->verify();
   }
 
@@ -624,9 +657,12 @@
   if (observer) {
     observer->performedSILOptimization(*SM);
   }
+  if (Stats) {
+    countStatsPostSILOpt(*Stats, *SM);
+  }
 
   {
-    SharedTimer timer("SIL verification (post-optimization)");
+    SharedTimer timer("SIL verification, post-optimization");
     SM->verify();
   }
 
@@ -761,10 +797,15 @@
   }
 
   if (opts.ValidateTBDAgainstIR) {
-    bool validationError =
-        PrimarySourceFile ? validateTBD(PrimarySourceFile, *IRModule)
-                          : validateTBD(Instance->getMainModule(), *IRModule);
-    if (validationError)
+    auto hasMultipleIRGenThreads = Invocation.getSILOptions().NumThreads > 1;
+    bool error;
+    if (PrimarySourceFile)
+      error =
+          validateTBD(PrimarySourceFile, *IRModule, hasMultipleIRGenThreads);
+    else
+      error = validateTBD(Instance->getMainModule(), *IRModule,
+                          hasMultipleIRGenThreads);
+    if (error)
       return true;
   }
 
@@ -973,6 +1014,23 @@
     llvm::EnableStatistics();
   }
 
+  const std::string &StatsOutputDir =
+      Invocation.getFrontendOptions().StatsOutputDir;
+  std::unique_ptr<UnifiedStatsReporter> StatsReporter;
+  if (!StatsOutputDir.empty()) {
+    auto &opts = Invocation.getFrontendOptions();
+    std::string TargetName = opts.ModuleName;
+    if (opts.PrimaryInput.hasValue() &&
+        opts.PrimaryInput.getValue().isFilename()) {
+      auto Index = opts.PrimaryInput.getValue().Index;
+      TargetName += ".";
+      TargetName += llvm::sys::path::filename(opts.InputFilenames[Index]);
+    }
+    StatsReporter = llvm::make_unique<UnifiedStatsReporter>("swift-frontend",
+                                                            TargetName,
+                                                            StatsOutputDir);
+  }
+
   const DiagnosticOptions &diagOpts = Invocation.getDiagnosticOptions();
   if (diagOpts.VerifyMode != DiagnosticOptions::NoVerify) {
     enableDiagnosticVerifier(Instance->getSourceMgr());
@@ -995,7 +1053,8 @@
 
   int ReturnValue = 0;
   bool HadError =
-    performCompile(Instance, Invocation, Args, ReturnValue, observer);
+    performCompile(Instance, Invocation, Args, ReturnValue, observer,
+                   StatsReporter.get());
 
   if (!HadError) {
     Mangle::printManglingStats();
diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp
index c300e24..aa9c374 100644
--- a/lib/FrontendTool/ReferenceDependencies.cpp
+++ b/lib/FrontendTool/ReferenceDependencies.cpp
@@ -88,12 +88,14 @@
   if (!inheritedType.getType())
     return true;
 
-  SmallVector<ProtocolDecl *, 2> protocols;
-  if (!inheritedType.getType()->isAnyExistentialType(protocols)) {
+  if (!inheritedType.getType()->isExistentialType()) {
     // Be conservative. We don't know how to deal with other extended types.
     return false;
   }
 
+  SmallVector<ProtocolDecl *, 2> protocols;
+  inheritedType.getType()->getExistentialTypeProtocols(protocols);
+
   return std::all_of(protocols.begin(), protocols.end(), declIsPrivate);
 }
 
diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp
index f214362..58af820 100644
--- a/lib/FrontendTool/TBD.cpp
+++ b/lib/FrontendTool/TBD.cpp
@@ -38,7 +38,8 @@
   return sorted;
 }
 
-bool swift::writeTBD(ModuleDecl *M, StringRef OutputFilename) {
+bool swift::writeTBD(ModuleDecl *M, bool hasMultipleIRGenThreads,
+                     StringRef OutputFilename) {
   std::error_code EC;
   llvm::raw_fd_ostream OS(OutputFilename, EC, llvm::sys::fs::F_None);
   if (EC) {
@@ -48,7 +49,8 @@
   }
   llvm::StringSet<> symbols;
   for (auto file : M->getFiles())
-    enumeratePublicSymbols(file, symbols);
+    enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
+                           /*isWholeModule=*/true);
 
   // Ensure the order is stable.
   for (auto &symbol : sortSymbols(symbols)) {
@@ -103,17 +105,21 @@
   return error;
 }
 
-bool swift::validateTBD(ModuleDecl *M, llvm::Module &IRModule) {
+bool swift::validateTBD(ModuleDecl *M, llvm::Module &IRModule,
+                        bool hasMultipleIRGenThreads) {
   llvm::StringSet<> symbols;
   for (auto file : M->getFiles())
-    enumeratePublicSymbols(file, symbols);
+    enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
+                           /*isWholeModule=*/true);
 
   return validateSymbolSet(M->getASTContext().Diags, symbols, IRModule);
 }
 
-bool swift::validateTBD(FileUnit *file, llvm::Module &IRModule) {
+bool swift::validateTBD(FileUnit *file, llvm::Module &IRModule,
+                        bool hasMultipleIRGenThreads) {
   llvm::StringSet<> symbols;
-  enumeratePublicSymbols(file, symbols);
+  enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
+                         /*isWholeModule=*/false);
 
   return validateSymbolSet(file->getParentModule()->getASTContext().Diags,
                            symbols, IRModule);
diff --git a/lib/FrontendTool/TBD.h b/lib/FrontendTool/TBD.h
index 343cef7..c6d96d7 100644
--- a/lib/FrontendTool/TBD.h
+++ b/lib/FrontendTool/TBD.h
@@ -20,10 +20,14 @@
 namespace swift {
 class ModuleDecl;
 class FileUnit;
+class FrontendOptions;
 
-bool writeTBD(ModuleDecl *M, llvm::StringRef OutputFilename);
-bool validateTBD(ModuleDecl *M, llvm::Module &IRModule);
-bool validateTBD(FileUnit *M, llvm::Module &IRModule);
+bool writeTBD(ModuleDecl *M, bool hasMultipleIRGenThreads,
+              llvm::StringRef OutputFilename);
+bool validateTBD(ModuleDecl *M, llvm::Module &IRModule,
+                 bool hasMultipleIRGenThreads);
+bool validateTBD(FileUnit *M, llvm::Module &IRModule,
+                 bool hasMultipleIRGenThreads);
 }
 
 #endif
diff --git a/lib/IDE/CMakeLists.txt b/lib/IDE/CMakeLists.txt
index 02b3c2b..a4b39a5 100644
--- a/lib/IDE/CMakeLists.txt
+++ b/lib/IDE/CMakeLists.txt
@@ -15,5 +15,5 @@
     swiftClangImporter
     swiftParse
     swiftSema
-    swiftAST)
+    swiftIndex)
 
diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp
index 39b9de2..c4a6cc4 100644
--- a/lib/IDE/CodeCompletion.cpp
+++ b/lib/IDE/CodeCompletion.cpp
@@ -2036,8 +2036,7 @@
         if (Conformance && Conformance->isConcrete()) {
           return Conformance->getConcrete()
               ->getTypeWitness(const_cast<AssociatedTypeDecl *>(ATD),
-                               TypeResolver.get())
-              .getReplacement();
+                               TypeResolver.get());
         }
       }
     }
diff --git a/lib/IDE/IDETypeChecking.cpp b/lib/IDE/IDETypeChecking.cpp
index 6b3130e..2c3f25c 100644
--- a/lib/IDE/IDETypeChecking.cpp
+++ b/lib/IDE/IDETypeChecking.cpp
@@ -18,6 +18,13 @@
 
 using namespace swift;
 
+static Type getContextFreeInterfaceType(ValueDecl *VD) {
+  if (auto AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
+    return AFD->getMethodInterfaceType();
+  }
+  return VD->getInterfaceType();
+}
+
 ArrayRef<ValueDecl*> swift::
 canDeclProvideDefaultImplementationFor(ValueDecl* VD,
                                 llvm::SmallVectorImpl<ValueDecl*> &Scractch) {
@@ -37,10 +44,11 @@
     resolveValueMember(*P->getInnermostDeclContext(),
                        P->getDeclaredInterfaceType(), VD->getFullName());
 
+  auto VDType = getContextFreeInterfaceType(VD);
   for (auto Mem : LookupResult.getMemberDecls(InterestedMemberKind::All)) {
     if (auto Pro = dyn_cast<ProtocolDecl>(Mem->getDeclContext())) {
       if (Mem->isProtocolRequirement() &&
-          Mem->getInterfaceType()->isEqual(VD->getInterfaceType())) {
+          getContextFreeInterfaceType(Mem)->isEqual(VDType)) {
         // We find a protocol requirement VD can provide default
         // implementation for.
         Scractch.push_back(Mem);
diff --git a/lib/IRGen/DebugTypeInfo.cpp b/lib/IRGen/DebugTypeInfo.cpp
index 82804c7..6d07f3e 100644
--- a/lib/IRGen/DebugTypeInfo.cpp
+++ b/lib/IRGen/DebugTypeInfo.cpp
@@ -30,8 +30,6 @@
                              Alignment align)
     : DeclCtx(DC), GenericEnv(GE), Type(Ty.getPointer()),
       StorageType(StorageTy), size(size), align(align) {
-  assert((!isArchetype() || (isArchetype() && DC)) &&
-         "archetype without a declcontext");
   assert(StorageType && "StorageType is a nullptr");
   assert(align.getValue() != 0);
 }
diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp
index 3a6e112..47c8b94 100644
--- a/lib/IRGen/GenArchetype.cpp
+++ b/lib/IRGen/GenArchetype.cpp
@@ -17,17 +17,18 @@
 #include "GenArchetype.h"
 
 #include "swift/AST/ASTContext.h"
-#include "swift/AST/Types.h"
 #include "swift/AST/Decl.h"
 #include "swift/AST/GenericEnvironment.h"
+#include "swift/AST/Types.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/SILValue.h"
 #include "swift/SIL/TypeLowering.h"
 #include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
 #include "llvm/IR/Constant.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
 
 #include "EnumPayload.h"
 #include "Explosion.h"
@@ -43,7 +44,6 @@
 #include "IRGenDebugInfo.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
-#include "Linking.h"
 #include "ProtocolInfo.h"
 #include "ResilientTypeInfo.h"
 #include "TypeInfo.h"
diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp
index 9f1fd8b..c95e616 100644
--- a/lib/IRGen/GenBuiltin.cpp
+++ b/lib/IRGen/GenBuiltin.cpp
@@ -850,5 +850,24 @@
     return;
   }
 
+  if (Builtin.ID == BuiltinValueKind::Swift3ImplicitObjCEntrypoint) {
+    llvm::Value *args[2];
+    auto argIter = IGF.CurFn->arg_begin();
+
+    // self
+    args[0] = &*argIter++;
+    if (args[0]->getType() != IGF.IGM.ObjCPtrTy)
+      args[0] = IGF.Builder.CreateBitCast(args[0], IGF.IGM.ObjCPtrTy);
+
+    // _cmd
+    args[1] = &*argIter;
+    if (args[1]->getType() != IGF.IGM.ObjCSELTy)
+      args[1] = IGF.Builder.CreateBitCast(args[1], IGF.IGM.ObjCSELTy);
+
+    IGF.Builder.CreateCall(IGF.IGM.getSwift3ImplicitObjCEntrypointFn(), args);
+    return;
+  }
+
+
   llvm_unreachable("IRGen unimplemented for this builtin!");
 }
diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp
index c3e876a0..466d3db 100644
--- a/lib/IRGen/GenClass.cpp
+++ b/lib/IRGen/GenClass.cpp
@@ -18,8 +18,8 @@
 
 #include "swift/ABI/Class.h"
 #include "swift/ABI/MetadataValues.h"
-#include "swift/AST/AttrKind.h"
 #include "swift/AST/ASTContext.h"
+#include "swift/AST/AttrKind.h"
 #include "swift/AST/Decl.h"
 #include "swift/AST/IRGenOptions.h"
 #include "swift/AST/Module.h"
@@ -27,14 +27,15 @@
 #include "swift/AST/PrettyStackTrace.h"
 #include "swift/AST/TypeMemberVisitor.h"
 #include "swift/AST/Types.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/SILModule.h"
 #include "swift/SIL/SILType.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/IR/CallSite.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/Support/raw_ostream.h"
-#include "llvm/IR/CallSite.h"
 
 #include "ConstantBuilder.h"
 #include "Explosion.h"
@@ -48,7 +49,6 @@
 #include "IRGenModule.h"
 #include "GenHeap.h"
 #include "HeapTypeInfo.h"
-#include "Linking.h"
 #include "MemberAccessStrategy.h"
 
 
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index e4bd09f..da1eabb 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -27,34 +27,35 @@
 #include "swift/AST/TypeMemberVisitor.h"
 #include "swift/AST/Types.h"
 #include "swift/ClangImporter/ClangModule.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/FormalLinkage.h"
 #include "swift/SIL/SILDebugScope.h"
 #include "swift/SIL/SILModule.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/GlobalDecl.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/IR/GlobalAlias.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/TypeBuilder.h"
 #include "llvm/IR/Value.h"
-#include "llvm/IR/GlobalAlias.h"
-#include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Compiler.h"
-#include "llvm/Support/Path.h"
 #include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Path.h"
 
 #include "ConstantBuilder.h"
 #include "Explosion.h"
 #include "FixedTypeInfo.h"
 #include "GenCall.h"
 #include "GenClass.h"
+#include "GenDecl.h"
+#include "GenMeta.h"
 #include "GenObjC.h"
 #include "GenOpaque.h"
-#include "GenMeta.h"
 #include "GenType.h"
 #include "IRGenDebugInfo.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
-#include "Linking.h"
 
 using namespace swift;
 using namespace irgen;
@@ -329,10 +330,11 @@
     NewProto = Builder.CreateCall(objc_allocateProtocol, protocolName);
     
     // Add the parent protocols.
+    //
+    // FIXME: Look at the requirement signature instead.
     for (auto inherited : proto->getInherited()) {
       SmallVector<ProtocolDecl*, 4> protocols;
-      if (!inherited.getType()->isAnyExistentialType(protocols))
-        continue;
+      inherited.getType()->getExistentialTypeProtocols(protocols);
       for (auto parentProto : protocols) {
         if (!parentProto->isObjC())
           continue;
@@ -611,14 +613,14 @@
         protos.insert(proto.first);
       
       llvm::SmallVector<ProtocolDecl*, 4> protoInitOrder;
-      
+
+      // FIXME: Use the requirement signature instead.
       std::function<void(ProtocolDecl*)> orderProtocol
         = [&](ProtocolDecl *proto) {
           // Recursively put parents first.
           for (auto &inherited : proto->getInherited()) {
             SmallVector<ProtocolDecl*, 4> parents;
-            if (!inherited.getType()->isAnyExistentialType(parents))
-              continue;
+            inherited.getType()->getExistentialTypeProtocols(parents);
             for (auto parent : parents)
               orderProtocol(parent);
           }
@@ -1078,24 +1080,47 @@
   llvm_unreachable("bad formal linkage");
 }
 
-static SILLinkage getConformanceLinkage(IRGenModule &IGM,
-                                        const ProtocolConformance *conf) {
-  if (auto wt = IGM.getSILModule().lookUpWitnessTable(conf,
-                                               /*deserializeLazily*/ false)) {
-    return wt->getLinkage();
-  } else {
-    return SILLinkage::PublicExternal;
-  }
-}
+SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
+  // For when `this` is a protocol conformance of some kind.
+  auto getLinkageAsConformance = [&] {
+    return getLinkageForProtocolConformance(
+        getProtocolConformance()->getRootNormalConformance(), forDefinition);
+  };
 
-SILLinkage LinkEntity::getLinkage(IRGenModule &IGM,
-                                  ForDefinition_t forDefinition) const {
   switch (getKind()) {
   // Most type metadata depend on the formal linkage of their type.
-  case Kind::ValueWitnessTable:
-    return getSILLinkage(getTypeLinkage(getType()), forDefinition);
+  case Kind::ValueWitnessTable: {
+    auto type = getType();
+
+    // Builtin types, (), () -> () and so on are in the runtime.
+    if (!type.getAnyNominal())
+      return getSILLinkage(FormalLinkage::PublicUnique, forDefinition);
+
+    // Imported types.
+    if (getTypeMetadataAccessStrategy(type) ==
+          MetadataAccessStrategy::NonUniqueAccessor)
+      return SILLinkage::Shared;
+
+    // Everything else is only referenced inside its module.
+    return SILLinkage::Private;
+  }
+
+  case Kind::TypeMetadataLazyCacheVariable: {
+    auto type = getType();
+
+    // Imported types, non-primitive structural types.
+    if (getTypeMetadataAccessStrategy(type) ==
+          MetadataAccessStrategy::NonUniqueAccessor)
+      return SILLinkage::Shared;
+
+    // Everything else is only referenced inside its module.
+    return SILLinkage::Private;
+  }
 
   case Kind::TypeMetadata:
+    if (isMetadataPattern())
+      return SILLinkage::Private;
+
     switch (getMetadataAddress()) {
     case TypeMetadataAddress::FullMetadata:
       // The full metadata object is private to the containing module.
@@ -1114,8 +1139,7 @@
     return SILLinkage::Shared;
 
   case Kind::TypeMetadataAccessFunction:
-  case Kind::TypeMetadataLazyCacheVariable:
-    switch (getTypeMetadataAccessStrategy(IGM, getType())) {
+    switch (getTypeMetadataAccessStrategy(getType())) {
     case MetadataAccessStrategy::PublicUniqueAccessor:
       return getSILLinkage(FormalLinkage::PublicUnique, forDefinition);
     case MetadataAccessStrategy::HiddenUniqueAccessor:
@@ -1143,13 +1167,12 @@
 
   case Kind::DirectProtocolWitnessTable:
   case Kind::ProtocolWitnessTableAccessFunction:
-    return getConformanceLinkage(IGM, getProtocolConformance());
+    return getLinkageAsConformance();
 
   case Kind::ProtocolWitnessTableLazyAccessFunction:
   case Kind::ProtocolWitnessTableLazyCacheVariable:
     if (getTypeLinkage(getType()) == FormalLinkage::Private ||
-        getConformanceLinkage(IGM, getProtocolConformance())
-          == SILLinkage::Private) {
+        getLinkageAsConformance() == SILLinkage::Private) {
       return SILLinkage::Private;
     } else {
       return SILLinkage::Shared;
@@ -1175,8 +1198,7 @@
       return SILLinkage::Shared;
     return SILLinkage::Private;
   case Kind::ReflectionAssociatedTypeDescriptor:
-    if (getConformanceLinkage(IGM, getProtocolConformance())
-          == SILLinkage::Shared)
+    if (getLinkageAsConformance() == SILLinkage::Shared)
       return SILLinkage::Shared;
     return SILLinkage::Private;
   case Kind::ReflectionSuperclassDescriptor:
@@ -1254,7 +1276,7 @@
   llvm_unreachable("bad link entity kind");
 }
 
-bool LinkEntity::isFragile(IRGenModule &IGM) const {
+bool LinkEntity::isFragile(ForDefinition_t isDefinition) const {
   switch (getKind()) {
     case Kind::SILFunction:
       return getSILFunction()->isSerialized();
@@ -1275,16 +1297,15 @@
       break;
   }
   if (isProtocolConformanceKind(getKind())) {
-    if (SILWitnessTable *wt = IGM.getSILModule().lookUpWitnessTable(
-                                            getProtocolConformance(), false)) {
-      SILLinkage L = wt->getLinkage();
-      // We don't deserialize the fragile attribute correctly. But we know that
-      // if the witness table was deserialized (= available externally) and it's
-      // not public, it must be fragile.
-      if (swift::isAvailableExternally(L) && !hasPublicVisibility(L))
-        return true;
-      return wt->isSerialized();
-    }
+    auto conformance = getProtocolConformance();
+
+    auto conformanceModule = conformance->getDeclContext()->getParentModule();
+    auto isCompletelySerialized = conformanceModule->getResilienceStrategy() ==
+                                  ResilienceStrategy::Fragile;
+
+    // The conformance is fragile if it is in a -sil-serialize-all module, or
+    // has a fully publicly determined layout.
+    return isCompletelySerialized || conformance->hasFixedLayout();
   }
   return false;
 }
@@ -1292,31 +1313,27 @@
 static std::tuple<llvm::GlobalValue::LinkageTypes,
                   llvm::GlobalValue::VisibilityTypes,
                   llvm::GlobalValue::DLLStorageClassTypes>
-getIRLinkage(IRGenModule &IGM, SILLinkage linkage, bool isFragile,
-             bool isSILOnly, ForDefinition_t isDefinition,
+getIRLinkage(const UniversalLinkageInfo &info, SILLinkage linkage,
+             bool isFragile, bool isSILOnly, ForDefinition_t isDefinition,
              bool isWeakImported) {
 #define RESULT(LINKAGE, VISIBILITY, DLL_STORAGE)                               \
   std::make_tuple(llvm::GlobalValue::LINKAGE##Linkage,                         \
                   llvm::GlobalValue::VISIBILITY##Visibility,                   \
                   llvm::GlobalValue::DLL_STORAGE##StorageClass)
 
-  const auto ObjFormat = IGM.TargetInfo.OutputObjectFormat;
-  bool IsELFObject = ObjFormat == llvm::Triple::ELF;
-  bool UseDLLStorage = IGM.useDllStorage();
-
   // Use protected visibility for public symbols we define on ELF.  ld.so
   // doesn't support relative relocations at load time, which interferes with
   // our metadata formats.  Default visibility should suffice for other object
   // formats.
   llvm::GlobalValue::VisibilityTypes PublicDefinitionVisibility =
-      IsELFObject ? llvm::GlobalValue::ProtectedVisibility
-                  : llvm::GlobalValue::DefaultVisibility;
+      info.IsELFObject ? llvm::GlobalValue::ProtectedVisibility
+                       : llvm::GlobalValue::DefaultVisibility;
   llvm::GlobalValue::DLLStorageClassTypes ExportedStorage =
-      UseDLLStorage ? llvm::GlobalValue::DLLExportStorageClass
-                    : llvm::GlobalValue::DefaultStorageClass;
+      info.UseDLLStorage ? llvm::GlobalValue::DLLExportStorageClass
+                         : llvm::GlobalValue::DefaultStorageClass;
   llvm::GlobalValue::DLLStorageClassTypes ImportedStorage =
-      UseDLLStorage ? llvm::GlobalValue::DLLImportStorageClass
-                    : llvm::GlobalValue::DefaultStorageClass;
+      info.UseDLLStorage ? llvm::GlobalValue::DLLImportStorageClass
+                         : llvm::GlobalValue::DefaultStorageClass;
 
   if (isFragile) {
     // Fragile functions/globals must be visible from outside, regardless of
@@ -1328,10 +1345,13 @@
       linkage = SILLinkage::Public;
       break;
 
-    case SILLinkage::Public:
-    case SILLinkage::Shared:
     case SILLinkage::HiddenExternal:
     case SILLinkage::PrivateExternal:
+      linkage = SILLinkage::PublicExternal;
+      break;
+
+    case SILLinkage::Public:
+    case SILLinkage::Shared:
     case SILLinkage::PublicExternal:
     case SILLinkage::SharedExternal:
       break;
@@ -1351,8 +1371,7 @@
     // TODO: In non-whole-module-opt the generated swiftmodules are "linked" and
     // this strips all serialized transparent functions. So we have to code-gen
     // transparent functions in non-whole-module-opt.
-    if (isSILOnly && !IGM.IRGen.hasMultipleIGMs() &&
-        IGM.getSILModule().isWholeModule())
+    if (isSILOnly && !info.HasMultipleIGMs && info.IsWholeModule)
       return RESULT(Internal, Default, Default);
     return std::make_tuple(llvm::GlobalValue::ExternalLinkage,
                            PublicDefinitionVisibility, ExportedStorage);
@@ -1367,7 +1386,7 @@
   case SILLinkage::Private:
     // In case of multiple llvm modules (in multi-threaded compilation) all
     // private decls must be visible from other files.
-    if (IGM.IRGen.hasMultipleIGMs())
+    if (info.HasMultipleIGMs)
       return RESULT(External, Hidden, Default);
     return RESULT(Internal, Default, Default);
 
@@ -1408,10 +1427,11 @@
                                        const LinkEntity &entity) {
   // TODO: there are probably cases where we can avoid redoing the
   // entire linkage computation.
+  UniversalLinkageInfo linkInfo(IGM);
   auto linkage =
-      getIRLinkage(IGM, entity.getLinkage(IGM, ForDefinition),
-                   entity.isFragile(IGM), entity.isSILOnly(), ForDefinition,
-                   entity.isWeakImported(IGM.getSwiftModule()));
+      getIRLinkage(linkInfo, entity.getLinkage(ForDefinition),
+                   entity.isFragile(ForDefinition), entity.isSILOnly(),
+                   ForDefinition, entity.isWeakImported(IGM.getSwiftModule()));
   global->setLinkage(std::get<0>(linkage));
   global->setVisibility(std::get<1>(linkage));
   global->setDLLStorageClass(std::get<2>(linkage));
@@ -1430,14 +1450,20 @@
 
 LinkInfo LinkInfo::get(IRGenModule &IGM, const LinkEntity &entity,
                        ForDefinition_t isDefinition) {
+  return LinkInfo::get(IGM, IGM.getSwiftModule(), entity, isDefinition);
+}
+
+LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo,
+                       ModuleDecl *swiftModule, const LinkEntity &entity,
+                       ForDefinition_t isDefinition) {
   LinkInfo result;
 
   entity.mangle(result.Name);
 
   std::tie(result.Linkage, result.Visibility, result.DLLStorageClass) =
-      getIRLinkage(IGM, entity.getLinkage(IGM, isDefinition),
-                   entity.isFragile(IGM), entity.isSILOnly(), isDefinition,
-                   entity.isWeakImported(IGM.getSwiftModule()));
+      getIRLinkage(linkInfo, entity.getLinkage(isDefinition),
+                   entity.isFragile(isDefinition), entity.isSILOnly(),
+                   isDefinition, entity.isWeakImported(swiftModule));
 
   result.ForDefinition = isDefinition;
 
@@ -1449,27 +1475,31 @@
 }
 
 /// Get or create an LLVM function with these linkage rules.
-llvm::Function *LinkInfo::createFunction(IRGenModule &IGM,
-                                         llvm::FunctionType *fnType,
-                                         llvm::CallingConv::ID cc,
-                                         const llvm::AttributeSet &attrs,
-                                         llvm::Function *insertBefore) {
-  llvm::Function *existing = IGM.Module.getFunction(getName());
+llvm::Function *swift::irgen::createFunction(IRGenModule &IGM,
+                                             LinkInfo &linkInfo,
+                                             llvm::FunctionType *fnType,
+                                             llvm::CallingConv::ID cc,
+                                             const llvm::AttributeSet &attrs,
+                                             llvm::Function *insertBefore) {
+  auto name = linkInfo.getName();
+
+  llvm::Function *existing = IGM.Module.getFunction(name);
   if (existing) {
     if (isPointerTo(existing->getType(), fnType))
       return cast<llvm::Function>(existing);
 
     IGM.error(SourceLoc(),
-              "program too clever: function collides with existing symbol "
-                + getName());
+              "program too clever: function collides with existing symbol " +
+                  name);
 
     // Note that this will implicitly unique if the .unique name is also taken.
-    existing->setName(getName() + ".unique");
+    existing->setName(name + ".unique");
   }
 
-  llvm::Function *fn = llvm::Function::Create(fnType, getLinkage(), getName());
-  fn->setVisibility(getVisibility());
-  fn->setDLLStorageClass(getDLLStorage());
+  llvm::Function *fn =
+      llvm::Function::Create(fnType, linkInfo.getLinkage(), name);
+  fn->setVisibility(linkInfo.getVisibility());
+  fn->setDLLStorageClass(linkInfo.getDLLStorage());
   fn->setCallingConv(cc);
 
   if (insertBefore) {
@@ -1491,8 +1521,7 @@
   // Exclude "main", because it should naturally be used, and because adding it
   // to llvm.used leaves a dangling use when the REPL attempts to discard
   // intermediate mains.
-  if (isUsed() &&
-      getName() != SWIFT_ENTRY_POINT_FUNCTION) {
+  if (linkInfo.isUsed() && name != SWIFT_ENTRY_POINT_FUNCTION) {
     IGM.addUsedGlobal(fn);
   }
 
@@ -1512,42 +1541,41 @@
 }
 
 /// Get or create an LLVM global variable with these linkage rules.
-llvm::GlobalVariable *LinkInfo::createVariable(IRGenModule &IGM,
-                                               llvm::Type *storageType,
-                                               Alignment alignment,
-                                               DebugTypeInfo DbgTy,
-                                               Optional<SILLocation> DebugLoc,
-                                               StringRef DebugName) {
-  llvm::GlobalValue *existingValue = IGM.Module.getNamedGlobal(getName());
+llvm::GlobalVariable *swift::irgen::createVariable(
+    IRGenModule &IGM, LinkInfo &linkInfo, llvm::Type *storageType,
+    Alignment alignment, DebugTypeInfo DbgTy, Optional<SILLocation> DebugLoc,
+    StringRef DebugName) {
+  auto name = linkInfo.getName();
+  llvm::GlobalValue *existingValue = IGM.Module.getNamedGlobal(name);
   if (existingValue) {
     auto existingVar = dyn_cast<llvm::GlobalVariable>(existingValue);
     if (existingVar && isPointerTo(existingVar->getType(), storageType))
       return existingVar;
 
     IGM.error(SourceLoc(),
-              "program too clever: variable collides with existing symbol "
-                + getName());
+              "program too clever: variable collides with existing symbol " +
+                  name);
 
     // Note that this will implicitly unique if the .unique name is also taken.
-    existingValue->setName(getName() + ".unique");
+    existingValue->setName(name + ".unique");
   }
 
   auto var = new llvm::GlobalVariable(IGM.Module, storageType,
-                                      /*constant*/ false, getLinkage(),
-                                      /*initializer*/ nullptr, getName());
-  var->setVisibility(getVisibility());
-  var->setDLLStorageClass(getDLLStorage());
+                                      /*constant*/ false, linkInfo.getLinkage(),
+                                      /*initializer*/ nullptr, name);
+  var->setVisibility(linkInfo.getVisibility());
+  var->setDLLStorageClass(linkInfo.getDLLStorage());
   var->setAlignment(alignment.getValue());
 
   // Everything externally visible is considered used in Swift.
   // That mostly means we need to be good at not marking things external.
-  if (isUsed()) {
+  if (linkInfo.isUsed()) {
     IGM.addUsedGlobal(var);
   }
 
-  if (IGM.DebugInfo && !DbgTy.isNull() && ForDefinition)
+  if (IGM.DebugInfo && !DbgTy.isNull() && linkInfo.isForDefinition())
     IGM.DebugInfo->emitGlobalVariableDeclaration(
-        var, DebugName.empty() ? getName() : DebugName, getName(), DbgTy,
+        var, DebugName.empty() ? name : DebugName, name, DbgTy,
         var->hasInternalLinkage(), DebugLoc);
 
   return var;
@@ -1690,15 +1718,15 @@
       DebugTypeInfo::getGlobal(var, storageType, fixedSize, fixedAlignment);
   if (var->getDecl()) {
     // If we have the VarDecl, use it for more accurate debugging information.
-    gvar = link.createVariable(*this, storageType, fixedAlignment,
-                               DbgTy, SILLocation(var->getDecl()),
-                               var->getDecl()->getName().str());
+    gvar = createVariable(*this, link, storageType, fixedAlignment, DbgTy,
+                          SILLocation(var->getDecl()),
+                          var->getDecl()->getName().str());
   } else {
     Optional<SILLocation> loc;
     if (var->hasLocation())
       loc = var->getLocation();
-    gvar = link.createVariable(*this, storageType, fixedAlignment,
-                               DbgTy, loc, var->getName());
+    gvar = createVariable(*this, link, storageType, fixedAlignment, DbgTy, loc,
+                          var->getName());
   }
   
   // Set the alignment from the TypeInfo.
@@ -1820,7 +1848,7 @@
     attrs = attrs.addAttribute(fnType->getContext(),
                 llvm::AttributeSet::FunctionIndex, llvm::Attribute::ReadOnly);
   }
-  fn = link.createFunction(*this, fnType, cc, attrs, insertBefore);
+  fn = createFunction(*this, link, fnType, cc, attrs, insertBefore);
 
   // If we have an order number for this function, set it up as appropriate.
   if (hasOrderNumber) {
@@ -1962,7 +1990,7 @@
   if (!definitionType) definitionType = defaultType;
 
   // Create the variable.
-  auto var = link.createVariable(*this, definitionType, alignment, DbgTy);
+  auto var = createVariable(*this, link, definitionType, alignment, DbgTy);
 
   // Install the concrete definition if we have one.
   if (definition && definition.hasInit()) {
@@ -2442,7 +2470,7 @@
 
   auto fnType = llvm::FunctionType::get(TypeMetadataPtrTy, false);
   LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
-  entry = link.createFunction(*this, fnType, DefaultCC, llvm::AttributeSet());
+  entry = createFunction(*this, link, fnType, DefaultCC, llvm::AttributeSet());
   return entry;
 }
 
@@ -2467,7 +2495,7 @@
 
   auto fnType = llvm::FunctionType::get(TypeMetadataPtrTy, genericArgs, false);
   LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
-  entry = link.createFunction(*this, fnType, DefaultCC, llvm::AttributeSet());
+  entry = createFunction(*this, link, fnType, DefaultCC, llvm::AttributeSet());
   return entry;
 }
 
@@ -2784,7 +2812,7 @@
       cast<llvm::PointerType>(getValueWitnessTy(index))
         ->getElementType());
   LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
-  entry = link.createFunction(*this, fnType, DefaultCC, llvm::AttributeSet());
+  entry = createFunction(*this, link, fnType, DefaultCC, llvm::AttributeSet());
   return entry;
 }
 
@@ -2817,7 +2845,7 @@
 
   // Otherwise, we need to create it.
   LinkInfo link = LinkInfo::get(IGM, entity, forDefinition);
-  auto addr = link.createVariable(IGM, type, alignment);
+  auto addr = createVariable(IGM, link, type, alignment);
   addr->setConstant(true);
 
   entry = addr;
@@ -3119,7 +3147,7 @@
                                           Int8PtrPtrTy },
                                         /*varargs*/ false);
   LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
-  entry = link.createFunction(*this, fnType, DefaultCC, llvm::AttributeSet());
+  entry = createFunction(*this, link, fnType, DefaultCC, llvm::AttributeSet());
   return entry;
 }
 
@@ -3167,7 +3195,7 @@
   }
 
   LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
-  entry = link.createFunction(*this, fnType, DefaultCC, llvm::AttributeSet());
+  entry = createFunction(*this, link, fnType, DefaultCC, llvm::AttributeSet());
   return entry;
 }
 
@@ -3189,7 +3217,7 @@
     = llvm::FunctionType::get(WitnessTablePtrTy, false);
 
   LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
-  entry = link.createFunction(*this, fnType, DefaultCC, llvm::AttributeSet());
+  entry = createFunction(*this, link, fnType, DefaultCC, llvm::AttributeSet());
   return entry;
 }
 
@@ -3240,7 +3268,7 @@
 
   auto fnType = getAssociatedTypeMetadataAccessFunctionTy();
   LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
-  entry = link.createFunction(*this, fnType, DefaultCC, llvm::AttributeSet());
+  entry = createFunction(*this, link, fnType, DefaultCC, llvm::AttributeSet());
   return entry;
 }
 
@@ -3263,7 +3291,7 @@
 
   auto fnType = getAssociatedTypeWitnessTableAccessFunctionTy();
   LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
-  entry = link.createFunction(*this, fnType, DefaultCC, llvm::AttributeSet());
+  entry = createFunction(*this, link, fnType, DefaultCC, llvm::AttributeSet());
   return entry;
 }
 
diff --git a/lib/IRGen/GenDecl.h b/lib/IRGen/GenDecl.h
new file mode 100644
index 0000000..b9c2dba
--- /dev/null
+++ b/lib/IRGen/GenDecl.h
@@ -0,0 +1,52 @@
+//===--- GenDecl.h - Swift IR generation for some decl ----------*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file provides the private interface to some decl emission code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_IRGEN_GENDECL_H
+#define SWIFT_IRGEN_GENDECL_H
+
+#include "llvm/IR/CallingConv.h"
+#include "DebugTypeInfo.h"
+#include "IRGen.h"
+
+namespace llvm {
+  class AttributeSet;
+  class Function;
+  class FunctionType;
+}
+namespace swift {
+namespace irgen {
+  class IRGenModule;
+  class LinkInfo;
+
+  llvm::Function *createFunction(IRGenModule &IGM,
+                                 LinkInfo &linkInfo,
+                                 llvm::FunctionType *fnType,
+                                 llvm::CallingConv::ID cc,
+                                 const llvm::AttributeSet &attrs,
+                                 llvm::Function *insertBefore = nullptr);
+
+
+  llvm::GlobalVariable *createVariable(IRGenModule &IGM,
+                                       LinkInfo &linkInfo,
+                                       llvm::Type *objectType,
+                                       Alignment alignment,
+                                       DebugTypeInfo DebugType=DebugTypeInfo(),
+                                       Optional<SILLocation> DebugLoc = None,
+                                       StringRef DebugName = StringRef());
+}
+}
+
+#endif
diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp
index b2b27dd..fd9c70e 100644
--- a/lib/IRGen/GenExistential.cpp
+++ b/lib/IRGen/GenExistential.cpp
@@ -20,13 +20,14 @@
 #include "swift/AST/Decl.h"
 #include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/Types.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/SILValue.h"
 #include "swift/SIL/TypeLowering.h"
 #include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
 
 #include "EnumPayload.h"
 #include "Explosion.h"
@@ -43,7 +44,6 @@
 #include "IRGenDebugInfo.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
-#include "Linking.h"
 #include "NonFixedTypeInfo.h"
 #include "ProtocolInfo.h"
 #include "TypeInfo.h"
@@ -141,14 +141,6 @@
     IRGenModule &IGM, OpaqueExistentialLayout existLayout,
     llvm::Type *existContainerPointerTy);
 
-static llvm::Constant *getInitWithTakeBoxedOpaqueExistentialBufferFunction(
-    IRGenModule &IGM, OpaqueExistentialLayout existLayout,
-    llvm::Type *existContainerPointerTy);
-
-static llvm::Constant *getInitWithCopyBoxedOpaqueExistentialBufferFunction(
-    IRGenModule &IGM, OpaqueExistentialLayout existLayout,
-    llvm::Type *existContainerPointerTy);
-
 static llvm::Constant *
 getProjectBoxedOpaqueExistentialFunction(IRGenFunction &IGF,
                                          OpenedExistentialAccess accessKind,
@@ -1486,7 +1478,7 @@
 TypeConverter::convertProtocolCompositionType(ProtocolCompositionType *T) {
   // Find the canonical protocols.  There might not be any.
   SmallVector<ProtocolDecl*, 4> protocols;
-  T->getAnyExistentialTypeProtocols(protocols);
+  T->getExistentialTypeProtocols(protocols);
 
   return createExistentialTypeInfo(IGM, CanType(T), protocols);
 }
@@ -1649,7 +1641,7 @@
                           std::function<void (unsigned, llvm::Value*)> body) {
   // Collect the conformances that need witness tables.
   SmallVector<ProtocolDecl*, 2> destProtocols;
-  destType.getAnyExistentialTypeProtocols(destProtocols);
+  destType.getExistentialTypeProtocols(destProtocols);
 
   SmallVector<ProtocolConformanceRef, 2> witnessConformances;
   assert(destProtocols.size() == conformances.size() &&
@@ -1670,23 +1662,14 @@
   }
 }
 
-#ifndef NDEBUG
-static bool _isError(SILType baseTy) {
-  llvm::SmallVector<ProtocolDecl*, 1> protos;
-  return baseTy.getSwiftRValueType()->isExistentialType(protos)
-    && protos.size() == 1
-    && protos[0]->getKnownProtocolKind()
-    && *protos[0]->getKnownProtocolKind() == KnownProtocolKind::Error;
-}
-#endif
-
 /// Project the address of the value inside a boxed existential container.
 ContainedAddress irgen::emitBoxedExistentialProjection(IRGenFunction &IGF,
                                               Explosion &base,
                                               SILType baseTy,
                                               CanType projectedType) {
   // TODO: Non-ErrorType boxed existentials.
-  assert(_isError(baseTy));
+  assert(baseTy.canUseExistentialRepresentation(
+           IGF.getSILModule(), ExistentialRepresentation::Boxed, Type()));
   
   // Get the reference to the existential box.
   llvm::Value *box = base.claimNext();
@@ -1738,7 +1721,8 @@
                                   CanType formalSrcType,
                                 ArrayRef<ProtocolConformanceRef> conformances) {
   // TODO: Non-Error boxed existentials.
-  assert(_isError(destType));
+  assert(destType.canUseExistentialRepresentation(
+           IGF.getSILModule(), ExistentialRepresentation::Boxed, Type()));
 
   auto &destTI = IGF.getTypeInfo(destType).as<ErrorExistentialTypeInfo>();
   auto srcMetadata = IGF.emitTypeMetadataRef(formalSrcType);
@@ -1777,7 +1761,8 @@
                                                       SILType containerType,
                                                       CanType valueType) {
   // TODO: Non-Error boxed existentials.
-  assert(_isError(containerType));
+  assert(containerType.canUseExistentialRepresentation(
+           IGF.getSILModule(), ExistentialRepresentation::Boxed, Type()));
 
   auto box = container.claimNext();
   auto srcMetadata = IGF.emitTypeMetadataRef(valueType);
@@ -1811,20 +1796,21 @@
                                ArrayRef<ProtocolConformanceRef> conformances) {
   // As a special case, an Error existential can be represented as a
   // reference to an already existing NSError or CFError instance.
-  SmallVector<ProtocolDecl*, 4> protocols;
-  
-  if (outType.getSwiftRValueType()->isExistentialType(protocols)
-      && protocols.size() == 1) {
-    switch (getSpecialProtocolID(protocols[0])) {
-    case SpecialProtocol::Error: {
-      // Bitcast the incoming class reference to Error.
-      out.add(IGF.Builder.CreateBitCast(instance, IGF.IGM.ErrorPtrTy));
-      return;
-    }
+  if (outType.getSwiftRValueType().isExistentialType()) {
+    SmallVector<ProtocolDecl*, 4> protocols;
+    outType.getSwiftRValueType().getExistentialTypeProtocols(protocols);
+    if (protocols.size() == 1) {
+      switch (getSpecialProtocolID(protocols[0])) {
+      case SpecialProtocol::Error: {
+        // Bitcast the incoming class reference to Error.
+        out.add(IGF.Builder.CreateBitCast(instance, IGF.IGM.ErrorPtrTy));
+        return;
+      }
 
-    case SpecialProtocol::AnyObject:
-    case SpecialProtocol::None:
-      break;
+      case SpecialProtocol::AnyObject:
+      case SpecialProtocol::None:
+        break;
+      }
     }
   }
   
@@ -1954,7 +1940,8 @@
 void irgen::emitMetatypeOfBoxedExistential(IRGenFunction &IGF, Explosion &value,
                                            SILType type, Explosion &out) {
   // TODO: Non-Error boxed existentials.
-  assert(_isError(type));
+  assert(type.canUseExistentialRepresentation(
+           IGF.getSILModule(), ExistentialRepresentation::Boxed, Type()));
 
   // Get the reference to the existential box.
   llvm::Value *box = value.claimNext();
@@ -2789,112 +2776,3 @@
         }
       }, true /*noinline*/);
 }
-
-static llvm::Constant *getInitWithTakeBoxedOpaqueExistentialBufferFunction(
-    IRGenModule &IGM, OpaqueExistentialLayout existLayout,
-    llvm::Type *existContainerPointerTy) {
-
-  llvm::Type *argTys[] = {existContainerPointerTy, existContainerPointerTy};
-
-  llvm::SmallString<40> fnName;
-  llvm::raw_svector_ostream(fnName)
-      << "__swift_initWithTake_boxed_opaque_existential_"
-      << existLayout.getNumTables();
-
-  return IGM.getOrCreateHelperFunction(
-      fnName, IGM.VoidTy, argTys, [&](IRGenFunction &IGF) {
-        auto &Builder = IGF.Builder;
-        auto it = IGF.CurFn->arg_begin();
-        Address dest(&*(it++), existLayout.getAlignment(IGM));
-        Address src(&*(it++), existLayout.getAlignment(IGM));
-        auto *metadata = existLayout.loadMetadataRef(IGF, src);
-        auto srcBuffer = existLayout.projectExistentialBuffer(IGF, src);
-        auto destBuffer = existLayout.projectExistentialBuffer(IGF, dest);
-        // Is the value stored inline?
-        //
-        llvm::Value *isInline, *flags;
-        std::tie(isInline, flags) = emitLoadOfIsInline(IGF, metadata);
-        auto *inlineBB = IGF.createBasicBlock("inline");
-        auto *outlineBB = IGF.createBasicBlock("outline");
-        Builder.CreateCondBr(isInline, inlineBB, outlineBB);
-
-        Builder.emitBlock(inlineBB);
-        {
-          ConditionalDominanceScope domScope(IGF);
-          emitInitializeWithTakeCall(IGF, metadata,
-                                     castToOpaquePtr(IGF, destBuffer),
-                                     castToOpaquePtr(IGF, srcBuffer));
-          Builder.CreateRetVoid();
-        }
-
-        Builder.emitBlock(outlineBB);
-        {
-          ConditionalDominanceScope domScope(IGF);
-
-          // destBuffer[0] = srcBuffer[0]
-          auto *srcReferenceAddr = Builder.CreateBitCast(
-              srcBuffer.getAddress(), IGM.RefCountedPtrTy->getPointerTo());
-          auto *reference =
-              Builder.CreateLoad(srcReferenceAddr, srcBuffer.getAlignment());
-          auto *destReferenceAddr = Builder.CreateBitCast(
-              destBuffer.getAddress(), IGM.RefCountedPtrTy->getPointerTo());
-          IGF.Builder.CreateStore(
-              reference,
-              Address(destReferenceAddr, existLayout.getAlignment(IGF.IGM)));
-          Builder.CreateRetVoid();
-        }
-
-      }, true /*noinline*/);
-}
-
-static llvm::Constant *getInitWithCopyBoxedOpaqueExistentialBufferFunction(
-    IRGenModule &IGM, OpaqueExistentialLayout existLayout,
-    llvm::Type *existContainerPointerTy) {
-
-  llvm::Type *argTys[] = {existContainerPointerTy, existContainerPointerTy};
-
-  llvm::SmallString<40> fnName;
-  llvm::raw_svector_ostream(fnName)
-      << "__swift_initWithCopy_boxed_opaque_existential_"
-      << existLayout.getNumTables();
-  return IGM.getOrCreateHelperFunction(
-      fnName, IGM.VoidTy, argTys,
-      [&](IRGenFunction &IGF) {
-        auto &Builder = IGF.Builder;
-        auto it = IGF.CurFn->arg_begin();
-        Address dest(&*(it++), existLayout.getAlignment(IGM));
-        Address src(&*(it++), existLayout.getAlignment(IGM));
-        auto *metadata = existLayout.loadMetadataRef(IGF, src);
-        auto srcBuffer = existLayout.projectExistentialBuffer(IGF, src);
-        auto destBuffer = existLayout.projectExistentialBuffer(IGF, dest);
-        // Is the value stored inline?
-        //
-        llvm::Value *isInline, *flags;
-        std::tie(isInline, flags) = emitLoadOfIsInline(IGF, metadata);
-        auto *inlineBB = IGF.createBasicBlock("inline");
-        auto *outlineBB = IGF.createBasicBlock("outline");
-        Builder.CreateCondBr(isInline, inlineBB, outlineBB);
-
-        Builder.emitBlock(inlineBB);
-        {
-          ConditionalDominanceScope domScope(IGF);
-          emitInitializeWithCopyCall(IGF, metadata,
-                                     castToOpaquePtr(IGF, destBuffer),
-                                     castToOpaquePtr(IGF, srcBuffer));
-          Builder.CreateRetVoid();
-        }
-
-        Builder.emitBlock(outlineBB);
-        {
-          ConditionalDominanceScope domScope(IGF);
-
-          // destBuffer[0] = srcBuffer[0]
-          // swift_retain(srcBuffer[0])
-          initBufferWithCopyOfReference(IGF, existLayout, destBuffer,
-                                        srcBuffer);
-          Builder.CreateRetVoid();
-        }
-
-      },
-      true /*noinline*/);
-}
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index af2e97a..86df3bc 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -14,43 +14,44 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "swift/ABI/MetadataValues.h"
 #include "swift/AST/ASTContext.h"
 #include "swift/AST/CanTypeVisitor.h"
 #include "swift/AST/Decl.h"
 #include "swift/AST/IRGenOptions.h"
 #include "swift/AST/SubstitutionMap.h"
 #include "swift/AST/Types.h"
+#include "swift/IRGen/Linking.h"
+#include "swift/Runtime/Metadata.h"
 #include "swift/SIL/FormalLinkage.h"
 #include "swift/SIL/SILModule.h"
 #include "swift/SIL/TypeLowering.h"
-#include "swift/Runtime/Metadata.h"
-#include "swift/ABI/MetadataValues.h"
-#include "llvm/IR/InlineAsm.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Module.h"
-#include "llvm/ADT/SmallString.h"
 
 #include "Address.h"
 #include "Callee.h"
 #include "ClassMetadataLayout.h"
 #include "ConstantBuilder.h"
-#include "FixedTypeInfo.h"
-#include "GenClass.h"
-#include "GenPoly.h"
-#include "GenValueWitness.h"
-#include "GenArchetype.h"
-#include "GenStruct.h"
-#include "HeapTypeInfo.h"
-#include "IRGenModule.h"
-#include "IRGenDebugInfo.h"
-#include "Linking.h"
-#include "ScalarTypeInfo.h"
-#include "StructMetadataLayout.h"
-#include "StructLayout.h"
 #include "EnumMetadataLayout.h"
+#include "FixedTypeInfo.h"
+#include "GenArchetype.h"
+#include "GenClass.h"
+#include "GenDecl.h"
+#include "GenPoly.h"
+#include "GenStruct.h"
+#include "GenValueWitness.h"
+#include "HeapTypeInfo.h"
+#include "IRGenDebugInfo.h"
 #include "IRGenMangler.h"
+#include "IRGenModule.h"
+#include "ScalarTypeInfo.h"
+#include "StructLayout.h"
+#include "StructMetadataLayout.h"
 
 #include "GenMeta.h"
 
@@ -473,8 +474,7 @@
   return false;
 }
 
-static bool hasRequiredTypeMetadataAccessFunction(IRGenModule &IGM,
-                                                  NominalTypeDecl *typeDecl) {
+static bool hasRequiredTypeMetadataAccessFunction(NominalTypeDecl *typeDecl) {
   // This needs to be kept in sync with getTypeMetadataStrategy.
 
   if (isa<ProtocolDecl>(typeDecl))
@@ -496,8 +496,7 @@
 
 /// Return the standard access strategy for getting a non-dependent
 /// type metadata object.
-MetadataAccessStrategy
-irgen::getTypeMetadataAccessStrategy(IRGenModule &IGM, CanType type) {
+MetadataAccessStrategy irgen::getTypeMetadataAccessStrategy(CanType type) {
   // We should not be emitting accessors for partially-substituted
   // generic types.
   assert(!type->hasArchetype());
@@ -919,7 +918,7 @@
       
     llvm::Value *emitExistentialTypeMetadata(CanType type) {
       SmallVector<ProtocolDecl*, 2> protocols;
-      type.getAnyExistentialTypeProtocols(protocols);
+      type.getExistentialTypeProtocols(protocols);
       
       // Collect references to the protocol descriptors.
       auto descriptorArrayTy
@@ -1422,7 +1421,7 @@
 getRequiredTypeMetadataAccessFunction(IRGenModule &IGM,
                                       NominalTypeDecl *theDecl,
                                       ForDefinition_t shouldDefine) {
-  if (!hasRequiredTypeMetadataAccessFunction(IGM, theDecl))
+  if (!hasRequiredTypeMetadataAccessFunction(theDecl))
     return nullptr;
 
   if (theDecl->isGenericContext()) {
@@ -1436,10 +1435,9 @@
 /// Force a public metadata access function into existence if necessary
 /// for the given type.
 template <class BuilderTy>
-static void maybeEmitNominalTypeMetadataAccessFunction(IRGenModule &IGM,
-                                                NominalTypeDecl *theDecl,
+static void maybeEmitNominalTypeMetadataAccessFunction(NominalTypeDecl *theDecl,
                                                        BuilderTy &builder) {
-  if (!hasRequiredTypeMetadataAccessFunction(IGM, theDecl))
+  if (!hasRequiredTypeMetadataAccessFunction(theDecl))
     return;
 
   builder.createMetadataAccessFunction();
@@ -1476,7 +1474,7 @@
     return emitDirectTypeMetadataRef(*this, type);
   }
 
-  switch (getTypeMetadataAccessStrategy(IGM, type)) {
+  switch (getTypeMetadataAccessStrategy(type)) {
   case MetadataAccessStrategy::PublicUniqueAccessor:
   case MetadataAccessStrategy::HiddenUniqueAccessor:
   case MetadataAccessStrategy::PrivateAccessor:
@@ -1496,7 +1494,7 @@
   assert(!type->hasArchetype() &&
          "cannot create global function to return dependent type metadata");
 
-  switch (getTypeMetadataAccessStrategy(IGM, type)) {
+  switch (getTypeMetadataAccessStrategy(type)) {
   case MetadataAccessStrategy::PublicUniqueAccessor:
   case MetadataAccessStrategy::HiddenUniqueAccessor:
   case MetadataAccessStrategy::PrivateAccessor:
@@ -1935,11 +1933,13 @@
 
       // Reference storage types with witness tables need open-coded layouts.
       // TODO: Maybe we could provide prefabs for 1 witness table.
-      SmallVector<ProtocolDecl*, 2> protocols;
-      if (referent.isAnyExistentialType(protocols))
+      if (referent.isExistentialType()) {
+        SmallVector<ProtocolDecl*, 2> protocols;
+        referent.getExistentialTypeProtocols(protocols);
         for (auto *proto : protocols)
           if (IGF.getSILTypes().protocolRequiresWitnessTable(proto))
             return visitType(type);
+      }
 
       // Unmanaged references are plain pointers with extra inhabitants,
       // which look like thick metatypes.
@@ -4010,14 +4010,14 @@
     isPattern = true;
     canBeConstant = false;
 
-    maybeEmitNominalTypeMetadataAccessFunction(IGM, classDecl, builder);
+    maybeEmitNominalTypeMetadataAccessFunction(classDecl, builder);
   } else {
     ClassMetadataBuilder builder(IGM, classDecl, init, layout, fieldLayout);
     builder.layout();
     isPattern = false;
     canBeConstant = builder.canBeConstant();
 
-    maybeEmitNominalTypeMetadataAccessFunction(IGM, classDecl, builder);
+    maybeEmitNominalTypeMetadataAccessFunction(classDecl, builder);
   }
 
   CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
@@ -4939,14 +4939,14 @@
     isPattern = true;
     canBeConstant = false;
 
-    maybeEmitNominalTypeMetadataAccessFunction(IGM, structDecl, builder);
+    maybeEmitNominalTypeMetadataAccessFunction(structDecl, builder);
   } else {
     StructMetadataBuilder builder(IGM, structDecl, init);
     builder.layout();
     isPattern = false;
     canBeConstant = builder.canBeConstant();
 
-    maybeEmitNominalTypeMetadataAccessFunction(IGM, structDecl, builder);
+    maybeEmitNominalTypeMetadataAccessFunction(structDecl, builder);
   }
 
   CanType declaredType = structDecl->getDeclaredType()->getCanonicalType();
@@ -5118,14 +5118,14 @@
     isPattern = true;
     canBeConstant = false;
 
-    maybeEmitNominalTypeMetadataAccessFunction(IGM, theEnum, builder);
+    maybeEmitNominalTypeMetadataAccessFunction(theEnum, builder);
   } else {
     EnumMetadataBuilder builder(IGM, theEnum, init);
     builder.layout();
     isPattern = false;
     canBeConstant = builder.canBeConstant();
 
-    maybeEmitNominalTypeMetadataAccessFunction(IGM, theEnum, builder);
+    maybeEmitNominalTypeMetadataAccessFunction(theEnum, builder);
   }
 
   CanType declaredType = theEnum->getDeclaredType()->getCanonicalType();
@@ -5458,8 +5458,8 @@
   
   // Create the global variable.
   LinkInfo link = LinkInfo::get(*this, entity, ForDefinition);
-  auto var = link.createVariable(*this, definition.getType(),
-                                 getPointerAlignment());
+  auto var =
+      createVariable(*this, link, definition.getType(), getPointerAlignment());
   definition.installInGlobal(var);
   
   // Apply the offset.
diff --git a/lib/IRGen/GenMeta.h b/lib/IRGen/GenMeta.h
index c6da205..e9b5be9 100644
--- a/lib/IRGen/GenMeta.h
+++ b/lib/IRGen/GenMeta.h
@@ -290,9 +290,8 @@
   bool isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type);
 
   /// Determine how the given type metadata should be accessed.
-  MetadataAccessStrategy getTypeMetadataAccessStrategy(IRGenModule &IGM,
-                                                       CanType type);
-  
+  MetadataAccessStrategy getTypeMetadataAccessStrategy(CanType type);
+
   /// Return the address of a function that will return type metadata 
   /// for the given non-dependent type.
   llvm::Function *getOrCreateTypeMetadataAccessFunction(IRGenModule &IGM,
diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp
index 50f4439..d0b7864 100644
--- a/lib/IRGen/GenObjC.cpp
+++ b/lib/IRGen/GenObjC.cpp
@@ -26,12 +26,13 @@
 
 #include "swift/AST/Decl.h"
 #include "swift/AST/IRGenOptions.h"
-#include "swift/ClangImporter/ClangImporter.h"
 #include "swift/AST/Types.h"
+#include "swift/ClangImporter/ClangImporter.h"
+#include "swift/Demangling/ManglingMacros.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/SILModule.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/DeclObjC.h"
-#include "swift/Demangling/ManglingMacros.h"
 
 #include "CallEmission.h"
 #include "ConstantBuilder.h"
@@ -47,7 +48,6 @@
 #include "IRGenDebugInfo.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
-#include "Linking.h"
 #include "NativeConventionSchema.h"
 #include "ScalarTypeInfo.h"
 #include "StructLayout.h"
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 74253c5..c9d7228 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -33,6 +33,7 @@
 #include "swift/AST/Decl.h"
 #include "swift/AST/IRGenOptions.h"
 #include "swift/AST/SubstitutionMap.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/SILDeclRef.h"
 #include "swift/SIL/SILModule.h"
 #include "swift/SIL/SILValue.h"
@@ -61,7 +62,6 @@
 #include "IRGenDebugInfo.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
-#include "Linking.h"
 #include "MetadataPath.h"
 #include "NecessaryBindings.h"
 #include "ProtocolInfo.h"
@@ -837,12 +837,13 @@
   if (isResilientConformance(conformance))
     return true;
 
-  // Check whether any of the inherited protocols are dependent.
-  for (auto &entry : conformance->getInheritedConformances()) {
-    if (isDependentConformance(IGM, entry.second->getRootNormalConformance(),
-                               expansion)) {
+  // Check whether any of the inherited conformances are dependent.
+  for (auto inherited : conformance->getProtocol()->getInheritedProtocols()) {
+    if (isDependentConformance(IGM,
+                               conformance->getInheritedConformance(inherited)
+                                 ->getRootNormalConformance(),
+                               expansion))
       return true;
-    }
   }
 
   // If the conforming type isn't dependent, the below check is never true.
@@ -851,10 +852,10 @@
 
   // Check whether any of the associated types are dependent.
   if (conformance->forEachTypeWitness(nullptr,
-        [&](AssociatedTypeDecl *requirement, const Substitution &sub,
+        [&](AssociatedTypeDecl *requirement, Type type,
             TypeDecl *explicitDecl) -> bool {
           // RESILIENCE: this could be an opaque conformance
-          return sub.getReplacement()->hasArchetype();
+          return type->hasArchetype();
        })) {
     return true;
   }
@@ -1123,12 +1124,11 @@
 
       SILEntries = SILEntries.slice(1);
 
-      const Substitution &sub =
-        Conformance.getTypeWitness(requirement, nullptr);
+      CanType associate =
+        Conformance.getTypeWitness(requirement, nullptr)->getCanonicalType();
 
       // This type will be expressed in terms of the archetypes
       // of the conforming context.
-      CanType associate = sub.getReplacement()->getCanonicalType();
       assert(!associate->hasTypeParameter());
 
       llvm::Constant *metadataAccessFunction =
diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp
index 9fb9c03..f21ef3c 100644
--- a/lib/IRGen/GenReflection.cpp
+++ b/lib/IRGen/GenReflection.cpp
@@ -19,20 +19,21 @@
 #include "swift/AST/PrettyStackTrace.h"
 #include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/SubstitutionMap.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/Reflection/MetadataSourceBuilder.h"
 #include "swift/Reflection/Records.h"
 #include "swift/SIL/SILModule.h"
 
 #include "ConstantBuilder.h"
 #include "GenClass.h"
+#include "GenDecl.h"
 #include "GenEnum.h"
 #include "GenHeap.h"
 #include "GenProto.h"
 #include "GenType.h"
-#include "IRGenModule.h"
-#include "Linking.h"
-#include "LoadableTypeInfo.h"
 #include "IRGenMangler.h"
+#include "IRGenModule.h"
+#include "LoadableTypeInfo.h"
 
 using namespace swift;
 using namespace irgen;
@@ -252,7 +253,7 @@
 
       auto init = B.finishAndCreateFuture();
 
-      var = info.createVariable(IGM, init.getType(), Alignment(4));
+      var = createVariable(IGM, info, init.getType(), Alignment(4));
       var->setConstant(true);
       init.installInGlobal(var);
 
@@ -889,11 +890,11 @@
   SmallVector<std::pair<StringRef, CanType>, 2> AssociatedTypes;
 
   auto collectTypeWitness = [&](const AssociatedTypeDecl *AssocTy,
-                                const Substitution &Sub,
+                                Type Replacement,
                                 const TypeDecl *TD) -> bool {
 
     auto Subst = Conformance->getDeclContext()->mapTypeOutOfContext(
-        Sub.getReplacement());
+        Replacement);
 
     AssociatedTypes.push_back({
       AssocTy->getNameStr(),
diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp
index 6349a10..e9644bb 100644
--- a/lib/IRGen/GenStruct.cpp
+++ b/lib/IRGen/GenStruct.cpp
@@ -21,6 +21,7 @@
 #include "swift/AST/IRGenOptions.h"
 #include "swift/AST/Pattern.h"
 #include "swift/AST/SubstitutionMap.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/SILModule.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Function.h"
@@ -34,7 +35,6 @@
 #include "GenType.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
-#include "Linking.h"
 #include "IndirectTypeInfo.h"
 #include "MemberAccessStrategy.h"
 #include "NonFixedTypeInfo.h"
diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp
index 03d2b2d..a5c52eb 100644
--- a/lib/IRGen/GenType.cpp
+++ b/lib/IRGen/GenType.cpp
@@ -20,6 +20,7 @@
 #include "swift/AST/IRGenOptions.h"
 #include "swift/AST/PrettyStackTrace.h"
 #include "swift/AST/Types.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/SILModule.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/ADT/SmallString.h"
@@ -38,7 +39,6 @@
 #include "GenOpaque.h"
 #include "HeapTypeInfo.h"
 #include "IndirectTypeInfo.h"
-#include "Linking.h"
 #include "ProtocolInfo.h"
 #include "ReferenceTypeInfo.h"
 #include "ScalarTypeInfo.h"
diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp
index 8a19dbd..d75eb4f 100644
--- a/lib/IRGen/GenValueWitness.cpp
+++ b/lib/IRGen/GenValueWitness.cpp
@@ -23,6 +23,7 @@
 
 #include "swift/AST/ASTContext.h"
 #include "swift/AST/Types.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/TypeLowering.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/raw_ostream.h"
@@ -37,7 +38,6 @@
 #include "IRGenDebugInfo.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
-#include "Linking.h"
 #include "StructLayout.h"
 #include "TypeInfo.h"
 
diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp
index 8b37a65..bd63430 100644
--- a/lib/IRGen/IRGenDebugInfo.cpp
+++ b/lib/IRGen/IRGenDebugInfo.cpp
@@ -18,7 +18,6 @@
 #include "IRGenDebugInfo.h"
 #include "GenOpaque.h"
 #include "GenType.h"
-#include "Linking.h"
 #include "swift/AST/Expr.h"
 #include "swift/AST/IRGenOptions.h"
 #include "swift/AST/ASTMangler.h"
@@ -30,6 +29,7 @@
 #include "swift/Basic/Version.h"
 #include "swift/Demangling/ManglingMacros.h"
 #include "swift/ClangImporter/ClangImporter.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/SILArgument.h"
 #include "swift/SIL/SILBasicBlock.h"
 #include "swift/SIL/SILDebugScope.h"
@@ -190,7 +190,7 @@
 
 /// Use the SM to figure out the actual line/column of a SourceLoc.
 template <typename WithLoc>
-SILLocation::DebugLoc getDebugLoc(SourceManager &SM, WithLoc *S,
+SILLocation::DebugLoc getDebugLoc(IRGenDebugInfo &DI, WithLoc *S,
                                   bool End = false) {
   SILLocation::DebugLoc L;
   if (S == nullptr)
@@ -203,22 +203,37 @@
     // the module.
     return getDeserializedLoc(S);
 
-  return SILLocation::decode(Loc, SM);
+  return DI.decodeSourceLoc(Loc);
 }
 
-/// Return the start of the location's source range.
-static SILLocation::DebugLoc getStartLocation(Optional<SILLocation> OptLoc,
-                                              SourceManager &SM) {
-  if (!OptLoc) return {};
-  return SILLocation::decode(OptLoc->getStartSourceLoc(), SM);
+SILLocation::DebugLoc
+IRGenDebugInfo::getStartLocation(Optional<SILLocation> OptLoc) {
+  if (!OptLoc)
+    return {};
+  return decodeSourceLoc(OptLoc->getStartSourceLoc());
 }
 
-/// Return the debug location from a SILLocation.
-static SILLocation::DebugLoc getDebugLocation(Optional<SILLocation> OptLoc,
-                                              SourceManager &SM) {
+SILLocation::DebugLoc
+IRGenDebugInfo::decodeSourceLoc(SourceLoc SL) {
+  auto &Cached = DebugLocCache[SL.getOpaquePointerValue()];
+  if (Cached.Filename.empty())
+    Cached = SILLocation::decode(SL, SM);
+  return Cached;
+}
+
+SILLocation::DebugLoc
+IRGenDebugInfo::decodeDebugLoc(SILLocation Loc) {
+  if (Loc.isDebugInfoLoc())
+    return Loc.getDebugInfoLoc();
+  return decodeSourceLoc(Loc.getDebugSourceLoc());
+}
+
+SILLocation::DebugLoc
+IRGenDebugInfo::getDebugLocation(Optional<SILLocation> OptLoc) {
   if (!OptLoc || OptLoc->isInPrologue())
     return {};
-  return OptLoc->decodeDebugLoc(SM);
+
+  return decodeDebugLoc(*OptLoc);
 }
 
 
@@ -239,34 +254,37 @@
   return false;
 }
 
+/// Both the code that is used to set up a closure object and the
+/// (beginning of) the closure itself has the AbstractClosureExpr as
+/// location. We are only interested in the latter case and want to
+/// ignore the setup code.
+///
+/// callWithClosure(
+///  { // <-- a breakpoint here should only stop inside of the closure.
+///    foo();
+///  })
+///
+/// The actual closure has a closure expression as scope.
+static bool shouldIgnoreAbstractClosure(Optional<SILLocation> Loc,
+                                        const SILDebugScope *DS) {
+  return Loc && isAbstractClosure(*Loc) && DS && !isAbstractClosure(DS->Loc) &&
+         !Loc->is<ImplicitReturnLocation>();
+}
+
 llvm::MDNode *IRGenDebugInfo::createInlinedAt(const SILDebugScope *DS) {
-  llvm::MDNode *InlinedAt = nullptr;
-  if (DS) {
-    // The inlined-at chain, starting with the innermost (noninlined) scope.
-    auto Scopes = DS->flattenedInlineTree();
+  auto *CS = DS->InlinedCallSite;
+  if (!CS)
+    return nullptr;
 
-    // See if we share a common prefix with the last chain of inline scopes.
-    unsigned N = 0;
-    while (N < LastInlineChain.size() && N < Scopes.size() &&
-           LastInlineChain[N].first == Scopes[N])
-      InlinedAt = LastInlineChain[N++].second;
-    LastInlineChain.resize(N);
+  auto CachedInlinedAt = InlinedAtCache.find(CS);
+  if (CachedInlinedAt != InlinedAtCache.end())
+    return cast<llvm::MDNode>(CachedInlinedAt->second);
 
-    // Construct the new suffix.
-    for (; N < Scopes.size(); ++N) {
-      auto *CS = Scopes[N];
-      // In SIL the inlined-at information is part of the scopes, in
-      // LLVM IR it is part of the location. Transforming the inlined-at
-      // SIL scope to a location means skipping the inlined-at scope.
-      auto *Parent = CS->Parent.get<const SILDebugScope *>();
-      auto *ParentScope = getOrCreateScope(Parent);
-      auto L = CS->Loc.decodeDebugLoc(SM);
-      InlinedAt = llvm::DebugLoc::get(L.Line, L.Column, ParentScope, InlinedAt);
-
-      // Cache the suffix.
-      LastInlineChain.push_back({CS, llvm::TrackingMDNodeRef(InlinedAt)});
-    }
-  }
+  auto L = decodeDebugLoc(CS->Loc);
+  auto Scope = getOrCreateScope(CS->Parent.dyn_cast<const SILDebugScope *>());
+  auto InlinedAt =
+      llvm::DebugLoc::get(L.Line, L.Column, Scope, createInlinedAt(CS));
+  InlinedAtCache.insert({CS, llvm::TrackingMDNodeRef(InlinedAt.getAsMDNode())});
   return InlinedAt;
 }
 
@@ -299,13 +317,26 @@
 void IRGenDebugInfo::setCurrentLoc(IRBuilder &Builder, const SILDebugScope *DS,
                                    Optional<SILLocation> Loc) {
   assert(DS && "empty scope");
-  // Inline info is emitted as part of the location below; extract the
-  // original scope here.
-  auto *Scope = getOrCreateScope(DS->getInlinedScope());
+  auto *Scope = getOrCreateScope(DS);
   if (!Scope)
     return;
 
-  auto L = getDebugLocation(Loc, SM);
+  SILFunction *Fn = DS->getInlinedFunction();
+  SILLocation::DebugLoc L;
+
+  if (shouldIgnoreAbstractClosure(Loc, DS) || (Fn && Fn->isThunk())) {
+    // Reuse the last source location if we are still in the same
+    // scope to get a more contiguous line table.
+    // Otherwise use a line 0 artificial location.
+    if (DS == LastScope)
+      L = LastDebugLoc;
+    else
+      L.Filename = LastDebugLoc.Filename;
+  } else {
+    // Decode the location.
+    L = getDebugLocation(Loc);
+  }
+
   auto *File = getOrCreateFile(L.Filename);
   if (File->getFilename() != Scope->getFilename()) {
     // We changed files in the middle of a scope. This happens, for
@@ -314,31 +345,7 @@
     auto File = getOrCreateFile(L.Filename);
     Scope = DBuilder.createLexicalBlockFile(Scope, File);
   }
-
-  // Both the code that is used to set up a closure object and the
-  // (beginning of) the closure itself has the AbstractClosureExpr as
-  // location. We are only interested in the latter case and want to
-  // ignore the setup code.
-  //
-  // callWithClosure(
-  //  { // <-- a breakpoint here should only stop inside of the closure.
-  //    foo();
-  //  })
-  //
-  // The actual closure has a closure expression as scope.
-  if (Loc && isAbstractClosure(*Loc) && DS && !isAbstractClosure(DS->Loc) &&
-      !Loc->is<ImplicitReturnLocation>())
-    L.Line = L.Column = 0;
-
-  if (auto *Fn = DS->getInlinedFunction())
-    if (Fn->isThunk())
-      L.Line = L.Column = 0;
-
-  // Reuse the last source location if we are still in the same
-  // scope to get a more contiguous line table.
-  if (L.Line == 0 && DS == LastScope)
-    L = LastDebugLoc;
-
+  
   // FIXME: Enable this assertion.
   //assert(lineNumberIsSane(Builder, L.Line) &&
   //       "-Onone, but line numbers are not monotonically increasing within bb");
@@ -349,8 +356,6 @@
   assert(((!InlinedAt) || (InlinedAt && Scope)) && "inlined w/o scope");
   assert(parentScopesAreSane(DS) && "parent scope sanity check failed");
   auto DL = llvm::DebugLoc::get(L.Line, L.Column, Scope, InlinedAt);
-  // TODO: Write a strongly-worded letter to the person that came up
-  // with a pair of functions spelled "get" and "Set".
   Builder.SetCurrentDebugLocation(DL);
 }
 
@@ -364,7 +369,7 @@
     return MainFile;
 
   // Try to find it in the cache first.
-  auto CachedScope = ScopeCache.find(DS);
+  auto CachedScope = ScopeCache.find(LocalScope(DS));
   if (CachedScope != ScopeCache.end())
     return cast<llvm::DIScope>(CachedScope->second);
 
@@ -376,7 +381,7 @@
     if (!FnScope)
       SILFn->setDebugScope(DS);
 
-    auto CachedScope = ScopeCache.find(FnScope);
+    auto CachedScope = ScopeCache.find(LocalScope(FnScope));
     if (CachedScope != ScopeCache.end())
       return cast<llvm::DIScope>(CachedScope->second);
 
@@ -388,7 +393,7 @@
     auto *SP = emitFunction(*SILFn, Fn);
 
     // Cache it.
-    ScopeCache[DS] = llvm::TrackingMDNodeRef(SP);
+    ScopeCache[LocalScope(DS)] = llvm::TrackingMDNodeRef(SP);
     return SP;
   }
 
@@ -400,13 +405,12 @@
     return Parent;
 
   assert(DS->Parent && "lexical block must have a parent subprogram");
-  auto L = getStartLocation(DS->Loc, SM);
+  auto L = getStartLocation(DS->Loc);
   llvm::DIFile *File = getOrCreateFile(L.Filename);
   auto *DScope = DBuilder.createLexicalBlock(Parent, File, L.Line, L.Column);
 
   // Cache it.
-  ScopeCache[DS] = llvm::TrackingMDNodeRef(DScope);
-
+  ScopeCache[LocalScope(DS)] = llvm::TrackingMDNodeRef(DScope);
   return DScope;
 }
 
@@ -549,7 +553,7 @@
       return DITy;
 
     // Create a Forward-declared type.
-    auto Loc = getDebugLoc(SM, NTD);
+    auto Loc = getDebugLoc(*this, NTD);
     auto File = getOrCreateFile(Loc.Filename);
     auto Line = Loc.Line;
     auto FwdDecl = DBuilder.createReplaceableCompositeType(
@@ -630,7 +634,7 @@
 IRGenDebugInfo::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
                              SILFunctionTypeRepresentation Rep, SILType SILTy,
                              DeclContext *DeclCtx, GenericEnvironment *GE) {
-  auto Cached = ScopeCache.find(DS);
+  auto Cached = ScopeCache.find(LocalScope(DS));
   if (Cached != ScopeCache.end()) {
     auto SP = cast<llvm::DISubprogram>(Cached->second);
     // If we created the DISubprogram for a forward declaration,
@@ -666,10 +670,10 @@
   // thunk helpers, where DS->Loc is an arbitrary location of whichever use
   // was emitted first.
   if (DS && (!SILFn || (!SILFn->isBare() && !SILFn->isThunk()))) {
-    L = DS->Loc.decodeDebugLoc(SM);
+    L = decodeDebugLoc(DS->Loc);
     ScopeLine = L.Line;
     if (!DS->Loc.isDebugInfoLoc())
-      L = SILLocation::decode(DS->Loc.getSourceLoc(), SM);
+      L = decodeSourceLoc(DS->Loc.getSourceLoc());
   }
 
   auto Line = L.Line;
@@ -740,7 +744,7 @@
   if (!DS)
     return nullptr;
 
-  ScopeCache[DS] = llvm::TrackingMDNodeRef(SP);
+  ScopeCache[LocalScope(DS)] = llvm::TrackingMDNodeRef(SP);
   return SP;
 }
 
@@ -757,7 +761,7 @@
     return;
   }
   auto DIMod = getOrCreateModule({D->getModulePath(), M});
-  auto L = getDebugLoc(SM, D);
+  auto L = getDebugLoc(*this, D);
   DBuilder.createImportedModule(getOrCreateFile(L.Filename), DIMod, L.Line);
 }
 
@@ -891,12 +895,17 @@
   if (Opts.DebugInfoKind <= IRGenDebugInfoKind::LineTables)
     return;
 
+  // Currently, the DeclContext is needed to mangle archetypes. Bail out if it's
+  // missing.
+  if (DbgTy.Type->hasArchetype() && !DbgTy.DeclCtx)
+    return;
+
   if (!DbgTy.size)
     DbgTy.size = getStorageSize(IGM.DataLayout, Storage);
 
   auto *Scope = dyn_cast<llvm::DILocalScope>(getOrCreateScope(DS));
   assert(Scope && "variable has no local scope");
-  auto Loc = getDebugLoc(SM, VarDecl);
+  auto Loc = getDebugLoc(*this, VarDecl);
 
   // FIXME: this should be the scope of the type's declaration.
   // If this is an argument, attach it to the current function scope.
@@ -1022,7 +1031,7 @@
     // would confuse both the user and LLDB.
     return;
 
-  auto L = getStartLocation(Loc, SM);
+  auto L = getStartLocation(Loc);
   auto File = getOrCreateFile(L.Filename);
 
   // Emit it as global variable of the current module.
@@ -1473,7 +1482,7 @@
   case TypeKind::Struct: {
     auto *StructTy = BaseTy->castTo<StructType>();
     auto *Decl = StructTy->getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     auto *File = getOrCreateFile(L.Filename);
     if (Opts.DebugInfoKind > IRGenDebugInfoKind::ASTTypes)
       return createStructType(DbgTy, Decl, StructTy, Scope, File, L.Line,
@@ -1491,7 +1500,7 @@
     // used to differentiate them from C++ and ObjC classes.
     auto *ClassTy = BaseTy->castTo<ClassType>();
     auto *Decl = ClassTy->getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     if (auto *ClangDecl = Decl->getClangDecl()) {
       auto ClangSrcLoc = ClangDecl->getLocStart();
       clang::SourceManager &ClangSM =
@@ -1531,7 +1540,7 @@
     auto *ProtocolTy = BaseTy->castTo<ProtocolType>();
     auto *Decl = ProtocolTy->getDecl();
     // FIXME: (LLVM branch) This should probably be a DW_TAG_interface_type.
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     auto File = getOrCreateFile(L.Filename);
     return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName,
                               File, L.Line, SizeInBits, AlignInBits, Flags,
@@ -1540,7 +1549,7 @@
 
   case TypeKind::ProtocolComposition: {
     auto *Decl = DbgTy.getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     auto File = getOrCreateFile(L.Filename);
 
     // FIXME: emit types
@@ -1553,7 +1562,7 @@
   case TypeKind::UnboundGeneric: {
     auto *UnboundTy = BaseTy->castTo<UnboundGenericType>();
     auto *Decl = UnboundTy->getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0));
     return createPointerSizedStruct(Scope,
                                     Decl ? Decl->getNameStr() : MangledName,
@@ -1563,7 +1572,7 @@
   case TypeKind::BoundGenericStruct: {
     auto *StructTy = BaseTy->castTo<BoundGenericStructType>();
     auto *Decl = StructTy->getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName,
                               File, L.Line, SizeInBits, AlignInBits, Flags,
                               MangledName);
@@ -1572,7 +1581,7 @@
   case TypeKind::BoundGenericClass: {
     auto *ClassTy = BaseTy->castTo<BoundGenericClassType>();
     auto *Decl = ClassTy->getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     // TODO: We may want to peek at Decl->isObjC() and set this
     // attribute accordingly.
     assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0));
@@ -1608,7 +1617,7 @@
 
   case TypeKind::Archetype: {
     auto *Archetype = BaseTy->castTo<ArchetypeType>();
-    auto L = getDebugLoc(SM, Archetype->getAssocType());
+    auto L = getDebugLoc(*this, Archetype->getAssocType());
     auto Superclass = Archetype->getSuperclass();
     auto DerivedFrom = Superclass.isNull()
                            ? nullptr
@@ -1645,7 +1654,7 @@
   case TypeKind::Metatype: {
     // Metatypes are (mostly) singleton type descriptors, often without storage.
     Flags |= llvm::DINode::FlagArtificial;
-    auto L = getDebugLoc(SM, DbgTy.getDecl());
+    auto L = getDebugLoc(*this, DbgTy.getDecl());
     auto File = getOrCreateFile(L.Filename);
     return DBuilder.createStructType(
         Scope, MangledName, File, L.Line, SizeInBits, AlignInBits, Flags,
@@ -1667,7 +1676,7 @@
   case TypeKind::Enum: {
     auto *EnumTy = BaseTy->castTo<EnumType>();
     auto *Decl = EnumTy->getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     auto *File = getOrCreateFile(L.Filename);
     if (Opts.DebugInfoKind > IRGenDebugInfoKind::ASTTypes)
       return createEnumType(DbgTy, Decl, MangledName, Scope, File, L.Line,
@@ -1680,7 +1689,7 @@
   case TypeKind::BoundGenericEnum: {
     auto *EnumTy = BaseTy->castTo<BoundGenericEnumType>();
     auto *Decl = EnumTy->getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     auto *File = getOrCreateFile(L.Filename);
     if (Opts.DebugInfoKind > IRGenDebugInfoKind::ASTTypes)
       return createEnumType(DbgTy, Decl, MangledName, Scope, File, L.Line,
@@ -1709,7 +1718,7 @@
   case TypeKind::WeakStorage: {
     auto *ReferenceTy = cast<ReferenceStorageType>(BaseTy);
     auto CanTy = ReferenceTy->getReferentType();
-    auto L = getDebugLoc(SM, DbgTy.getDecl());
+    auto L = getDebugLoc(*this, DbgTy.getDecl());
     auto File = getOrCreateFile(L.Filename);
     return DBuilder.createTypedef(getOrCreateDesugaredType(CanTy, DbgTy),
                                   MangledName, File, L.Line, File);
@@ -1721,7 +1730,7 @@
 
     auto *NameAliasTy = cast<NameAliasType>(BaseTy);
     auto *Decl = NameAliasTy->getDecl();
-    auto L = getDebugLoc(SM, Decl);
+    auto L = getDebugLoc(*this, Decl);
     auto AliasedTy = NameAliasTy->getSinglyDesugaredType();
     auto File = getOrCreateFile(L.Filename);
     // For NameAlias types, the DeclContext for the aliasED type is
diff --git a/lib/IRGen/IRGenDebugInfo.h b/lib/IRGen/IRGenDebugInfo.h
index 80f3395..2d72b97 100644
--- a/lib/IRGen/IRGenDebugInfo.h
+++ b/lib/IRGen/IRGenDebugInfo.h
@@ -61,14 +61,24 @@
   llvm::DIBuilder DBuilder;
   IRGenModule &IGM;
 
-  // Various caches.
-  llvm::DenseMap<const SILDebugScope *, llvm::TrackingMDNodeRef> ScopeCache;
+  /// Used for caching SILDebugScopes without inline information.
+  typedef std::pair<const void *, void *> LocalScopeHash;
+  struct LocalScope : public LocalScopeHash {
+    LocalScope(const SILDebugScope *DS)
+        : LocalScopeHash({DS->Loc.getOpaquePointerValue(),
+                          DS->Parent.getOpaqueValue()}) {}
+  };
+
+  /// Various caches.
+  /// @{
+  llvm::DenseMap<LocalScopeHash, llvm::TrackingMDNodeRef> ScopeCache;
+  llvm::DenseMap<const SILDebugScope *, llvm::TrackingMDNodeRef> InlinedAtCache;
   llvm::DenseMap<llvm::StringRef, llvm::TrackingMDNodeRef> DIFileCache;
+  llvm::DenseMap<const void *, SILLocation::DebugLoc> DebugLocCache;
   llvm::DenseMap<TypeBase *, llvm::TrackingMDNodeRef> DITypeCache;
   llvm::StringMap<llvm::TrackingMDNodeRef> DIModuleCache;
   TrackingDIRefMap DIRefMap;
-  std::vector<std::pair<const SILDebugScope *, llvm::TrackingMDNodeRef>>
-      LastInlineChain;
+  /// @}
 
   /// A list of replaceable fwddecls that need to be RAUWed at the end.
   std::vector<std::pair<TypeBase *, llvm::TrackingMDRef>> ReplaceMap;
@@ -207,7 +217,17 @@
   /// Return the DIBuilder.
   llvm::DIBuilder &getBuilder() { return DBuilder; }
 
+  /// Decode (and cache) a SourceLoc.
+  SILLocation::DebugLoc decodeSourceLoc(SourceLoc SL);
 private:
+  /// Decode (and cache) a SILLocation.
+  SILLocation::DebugLoc decodeDebugLoc(SILLocation Loc);
+  /// Return the debug location from a SILLocation.
+  SILLocation::DebugLoc getDebugLocation(Optional<SILLocation> OptLoc);
+  /// Return the start of the location's source range.
+  SILLocation::DebugLoc getStartLocation(Optional<SILLocation> OptLoc);
+
+
   StringRef BumpAllocatedString(const char *Data, size_t Length);
   StringRef BumpAllocatedString(std::string S);
   StringRef BumpAllocatedString(StringRef S);
diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp
index de85637..0b91a76 100644
--- a/lib/IRGen/IRGenFunction.cpp
+++ b/lib/IRGen/IRGenFunction.cpp
@@ -17,6 +17,7 @@
 
 #include "swift/AST/IRGenOptions.h"
 #include "swift/Basic/SourceLoc.h"
+#include "swift/IRGen/Linking.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Function.h"
 #include "llvm/Support/raw_ostream.h"
@@ -25,7 +26,6 @@
 #include "IRGenDebugInfo.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
-#include "Linking.h"
 #include "LoadableTypeInfo.h"
 
 using namespace swift;
diff --git a/lib/IRGen/IRGenMangler.cpp b/lib/IRGen/IRGenMangler.cpp
index f467660..7ead960 100644
--- a/lib/IRGen/IRGenMangler.cpp
+++ b/lib/IRGen/IRGenMangler.cpp
@@ -77,7 +77,7 @@
 std::string IRGenMangler::
 mangleProtocolForLLVMTypeName(ProtocolCompositionType *type) {
   SmallVector<ProtocolDecl *, 4> protocols;
-  type->getAnyExistentialTypeProtocols(protocols);
+  type->getExistentialTypeProtocols(protocols);
 
   if (protocols.empty()) {
     Buffer << "Any";
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index f96eba6..d5cb9aa 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -21,6 +21,7 @@
 #include "swift/Basic/Dwarf.h"
 #include "swift/Demangling/ManglingMacros.h"
 #include "swift/ClangImporter/ClangImporter.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/Runtime/RuntimeFnWrappersGen.h"
 #include "swift/Runtime/Config.h"
 #include "clang/AST/ASTContext.h"
@@ -48,7 +49,6 @@
 #include "GenType.h"
 #include "IRGenModule.h"
 #include "IRGenDebugInfo.h"
-#include "Linking.h"
 
 #include <initializer_list>
 
@@ -119,11 +119,6 @@
   return ClangCodeGen;
 }
 
-/// A helper for determining if the triple uses the DLL storage
-static bool useDllStorage(const llvm::Triple &Triple) {
-  return Triple.isOSBinFormatCOFF() && !Triple.isOSCygMing();
-}
-
 IRGenModule::IRGenModule(IRGenerator &irgen,
                          std::unique_ptr<llvm::TargetMachine> &&target,
                          SourceFile *SF, llvm::LLVMContext &LLVMContext,
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index 543803d..d780d8c 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -4553,7 +4553,7 @@
   auto srcType = i->getLoweredConcreteType();
   auto &srcTI = getTypeInfo(srcType);
 
-  // Allocate a COW box for the value if neceesary.
+  // Allocate a COW box for the value if necessary.
   if (getSILModule().getOptions().UseCOWExistentials) {
     auto *genericEnv = CurSILFn->getGenericEnvironment();
     setLoweredAddress(i, emitAllocateBoxedOpaqueExistentialBuffer(
@@ -4603,7 +4603,7 @@
                                               swift::DeinitExistentialAddrInst *i) {
   Address container = getLoweredAddress(i->getOperand());
 
-  // Deallocate the COW box for the value if neceesary.
+  // Deallocate the COW box for the value if necessary.
   if (getSILModule().getOptions().UseCOWExistentials) {
     emitDeallocateBoxedOpaqueExistentialBuffer(
         *this, i->getOperand()->getType(), container);
diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp
index 6a09b7b..d26a1e7 100644
--- a/lib/IRGen/Linking.cpp
+++ b/lib/IRGen/Linking.cpp
@@ -14,19 +14,36 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "Linking.h"
+#include "swift/IRGen/Linking.h"
 #include "IRGenMangler.h"
-#include "llvm/Support/raw_ostream.h"
+#include "IRGenModule.h"
 #include "swift/ClangImporter/ClangImporter.h"
 #include "swift/SIL/SILGlobalVariable.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclObjC.h"
+#include "llvm/ADT/Triple.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace swift;
 using namespace irgen;
 
+bool swift::irgen::useDllStorage(const llvm::Triple &triple) {
+  return triple.isOSBinFormatCOFF() && !triple.isOSCygMing();
+}
+
+UniversalLinkageInfo::UniversalLinkageInfo(IRGenModule &IGM)
+    : UniversalLinkageInfo(IGM.Triple, IGM.IRGen.hasMultipleIGMs(),
+                           IGM.getSILModule().isWholeModule()) {}
+
+UniversalLinkageInfo::UniversalLinkageInfo(const llvm::Triple &triple,
+                                           bool hasMultipleIGMs,
+                                           bool isWholeModule)
+    : IsELFObject(triple.isOSBinFormatELF()),
+      UseDLLStorage(useDllStorage(triple)), HasMultipleIGMs(hasMultipleIGMs),
+      IsWholeModule(isWholeModule) {}
+
 /// Mangle this entity into the given buffer.
 void LinkEntity::mangle(SmallVectorImpl<char> &buffer) const {
   llvm::raw_svector_ostream stream(buffer);
diff --git a/lib/IRGen/Linking.h b/lib/IRGen/Linking.h
deleted file mode 100644
index 042f029..0000000
--- a/lib/IRGen/Linking.h
+++ /dev/null
@@ -1,95 +0,0 @@
-//===--- Linking.h - Common declarations for link information ---*- C++ -*-===//
-//
-// This source file is part of the Swift.org open source project
-//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
-// Licensed under Apache License v2.0 with Runtime Library Exception
-//
-// See https://swift.org/LICENSE.txt for license information
-// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines structures and routines used when creating global
-// entities that are placed in the LLVM module, potentially with
-// external linkage.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SWIFT_IRGEN_LINKING_H
-#define SWIFT_IRGEN_LINKING_H
-
-#include "swift/IRGen/LinkEntity.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/IR/CallingConv.h"
-#include "llvm/IR/GlobalValue.h"
-#include "DebugTypeInfo.h"
-#include "IRGen.h"
-#include "IRGenModule.h"
-#include "swift/IRGen/ValueWitness.h"
-
-namespace llvm {
-  class AttributeSet;
-  class Value;
-  class FunctionType;
-}
-
-namespace swift {  
-namespace irgen {
-class IRGenModule;
-
-/// Encapsulated information about the linkage of an entity.
-class LinkInfo {
-  LinkInfo() = default;
-
-  llvm::SmallString<32> Name;
-  llvm::GlobalValue::LinkageTypes Linkage;
-  llvm::GlobalValue::VisibilityTypes Visibility;
-  llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass;
-  ForDefinition_t ForDefinition;
-
-public:
-  /// Compute linkage information for the given 
-  static LinkInfo get(IRGenModule &IGM, const LinkEntity &entity,
-                      ForDefinition_t forDefinition);
-
-  StringRef getName() const {
-    return Name.str();
-  }
-  llvm::GlobalValue::LinkageTypes getLinkage() const {
-    return Linkage;
-  }
-  llvm::GlobalValue::VisibilityTypes getVisibility() const {
-    return Visibility;
-  }
-  llvm::GlobalValue::DLLStorageClassTypes getDLLStorage() const {
-    return DLLStorageClass;
-  }
-
-  llvm::Function *createFunction(IRGenModule &IGM,
-                                 llvm::FunctionType *fnType,
-                                 llvm::CallingConv::ID cc,
-                                 const llvm::AttributeSet &attrs,
-                                 llvm::Function *insertBefore = nullptr);
-
-
-  llvm::GlobalVariable *createVariable(IRGenModule &IGM,
-                                  llvm::Type *objectType,
-                                  Alignment alignment,
-                                  DebugTypeInfo DebugType=DebugTypeInfo(),
-                                  Optional<SILLocation> DebugLoc = None,
-                                  StringRef DebugName = StringRef());
-
-  bool isUsed() const {
-    return ForDefinition && isUsed(Linkage, Visibility, DLLStorageClass);
-  }
-
-  static bool isUsed(llvm::GlobalValue::LinkageTypes Linkage,
-                     llvm::GlobalValue::VisibilityTypes Visibility,
-                     llvm::GlobalValue::DLLStorageClassTypes DLLStorage);
-};
-
-} // end namespace irgen
-} // end namespace swift
-
-#endif
diff --git a/lib/IRGen/MetadataPath.h b/lib/IRGen/MetadataPath.h
index dbd111c..001cae0 100644
--- a/lib/IRGen/MetadataPath.h
+++ b/lib/IRGen/MetadataPath.h
@@ -109,7 +109,7 @@
         return OperationCost::Call;
 
       case Kind::Impossible:
-        llvm_unreachable("cannot compute cost of an imposible path");
+        llvm_unreachable("cannot compute cost of an impossible path");
       }
       llvm_unreachable("bad path component");
     }
diff --git a/lib/LLVMPasses/LLVMMergeFunctions.cpp b/lib/LLVMPasses/LLVMMergeFunctions.cpp
index 9561246..cb41c06 100644
--- a/lib/LLVMPasses/LLVMMergeFunctions.cpp
+++ b/lib/LLVMPasses/LLVMMergeFunctions.cpp
@@ -782,20 +782,31 @@
 
 /// Returns true if the \p OpIdx's constant operand in the current instruction
 /// does differ in any of the functions in \p FInfos.
+///
+/// But it accepts the case where all operands refer to their containing
+/// functions (in case of self recursive functions).
 bool SwiftMergeFunctions::constsDiffer(const FunctionInfos &FInfos,
                                        unsigned OpIdx) {
   Constant *CommonConst = nullptr;
+  bool matching = true;
+  bool selfReferencing = true;
 
   for (const FunctionInfo &FI : FInfos) {
     Value *Op = FI.CurrentInst->getOperand(OpIdx);
     if (Constant *C = dyn_cast<Constant>(Op)) {
+      if (C != FI.F)
+        selfReferencing = false;
+
       if (!CommonConst) {
         CommonConst = C;
       } else if (C != CommonConst) {
-        return true;
+        matching = false;
       }
+      if (!selfReferencing && !matching)
+        return true;
     }
   }
+  assert(selfReferencing || matching);
   return false;
 }
 
@@ -903,6 +914,7 @@
       assert(!isInEquivalenceClass(&*Iter->second));
       Iter->second->F = nullptr;
       FuncEntries.erase(Iter);
+      DEBUG(dbgs() << "    Erase " << OrigFunc->getName() << '\n');
       OrigFunc->eraseFromParent();
     } else {
       // Otherwise we need a thunk which calls the merged function.
@@ -1062,8 +1074,15 @@
     // Add the new parameters.
     for (const ParamInfo &PI : Params) {
       assert(ParamIdx < NewFuncTy->getNumParams());
-      NewArgs.push_back(PI.Values[FuncIdx]);
-      OldParamTypes.push_back(PI.Values[FuncIdx]->getType());
+      Constant *ArgValue = PI.Values[FuncIdx];
+
+      // Check if it's a self referencing function. We must not use the old
+      // function pointer as argument.
+      if (ArgValue == Old)
+        ArgValue = New;
+
+      NewArgs.push_back(ArgValue);
+      OldParamTypes.push_back(ArgValue->getType());
       ++ParamIdx;
     }
 
@@ -1080,6 +1099,7 @@
     CI->replaceAllUsesWith(NewCI);
     CI->eraseFromParent();
   }
+  assert(Old->use_empty() && "should have replaced all uses of old function");
   return Old->hasLocalLinkage();
 }
 
diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp
index efbf5f1..e72f465 100644
--- a/lib/Parse/ParseGeneric.cpp
+++ b/lib/Parse/ParseGeneric.cpp
@@ -393,11 +393,5 @@
     }
   }
 
-  if (Context.isSwiftVersion3()) {
-    diagnose(whereLoc, diag::protocol_associatedtype_where_swift_3,
-             isProtocol ? "protocols" : "associated types");
-    // There's nothing to see here, move along.
-    trailingWhere = nullptr;
-  }
   return ParserStatus();
 }
diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp
index 0cac9ed..63564ac 100644
--- a/lib/Parse/ParseSIL.cpp
+++ b/lib/Parse/ParseSIL.cpp
@@ -1516,9 +1516,7 @@
 collectExistentialConformances(Parser &P, CanType conformingType, SourceLoc loc,
                                CanType protocolType) {
   SmallVector<ProtocolDecl *, 2> protocols;
-  bool isExistential = protocolType->isAnyExistentialType(protocols);
-  assert(isExistential);
-  (void)isExistential;
+  protocolType.getExistentialTypeProtocols(protocols);
   if (protocols.empty())
     return {};
 
@@ -4041,7 +4039,7 @@
 
     ArrayRef<ProtocolConformanceRef> conformances
       = collectExistentialConformances(P, formalConcreteType, TyLoc,
-                            ExistentialTy.getSwiftRValueType());
+                                       baseExType);
     
     ResultVal = B.createInitExistentialMetatype(InstLoc, Val, ExistentialTy,
                                                 conformances);
diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp
index 3eb4ae7..5c2a295 100644
--- a/lib/PrintAsObjC/PrintAsObjC.cpp
+++ b/lib/PrintAsObjC/PrintAsObjC.cpp
@@ -517,7 +517,7 @@
 
     Optional<ForeignErrorConvention> errorConvention
       = AFD->getForeignErrorConvention();
-    Type rawMethodTy = AFD->getInterfaceType()->castTo<AnyFunctionType>()->getResult();
+    Type rawMethodTy = AFD->getMethodInterfaceType();
     auto methodTy = rawMethodTy->castTo<FunctionType>();
     auto resultTy = getForeignResultType(AFD, methodTy, errorConvention);
 
@@ -632,6 +632,13 @@
       appendAvailabilityAttribute(AFD);
     }
 
+    if (isa<FuncDecl>(AFD) && cast<FuncDecl>(AFD)->isAccessor()) {
+      printSwift3ObjCDeprecatedInference(
+                              cast<FuncDecl>(AFD)->getAccessorStorageDecl());
+    } else {
+      printSwift3ObjCDeprecatedInference(AFD);
+    }
+
     os << ";\n";
   }
 
@@ -803,7 +810,33 @@
       }
     }
   }
-    
+
+  void printSwift3ObjCDeprecatedInference(ValueDecl *VD) {
+    auto attr = VD->getAttrs().getAttribute<ObjCAttr>();
+    if (!attr || !attr->isSwift3Inferred())
+      return;
+
+    os << " SWIFT_DEPRECATED_MSG(\"Swift ";
+    if (isa<VarDecl>(VD))
+      os << "property";
+    else if (isa<SubscriptDecl>(VD))
+      os << "subscript";
+    else if (isa<ConstructorDecl>(VD))
+      os << "initializer";
+    else
+      os << "method";
+    os << " '";
+    auto nominal =
+      VD->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
+    printEncodedString(nominal->getName().str(), /*includeQuotes=*/false);
+    os << ".";
+    SmallString<32> scratch;
+    printEncodedString(VD->getFullName().getString(scratch),
+                       /*includeQuotes=*/false);
+    os << "' uses '@objc' inference deprecated in Swift 4; add '@objc' to "
+       <<   "provide an Objective-C entrypoint\")";
+  }
+
   void visitFuncDecl(FuncDecl *FD) {
     if (FD->getDeclContext()->isTypeContext())
       printAbstractFunctionAsMethod(FD, FD->isStatic());
@@ -966,6 +999,8 @@
       print(ty, OTK_None, objCName);
     }
 
+    printSwift3ObjCDeprecatedInference(VD);
+
     os << ";";
     if (VD->isStatic()) {
       os << ")\n";
diff --git a/lib/SIL/CMakeLists.txt b/lib/SIL/CMakeLists.txt
index b1217bd..defd7d6 100644
--- a/lib/SIL/CMakeLists.txt
+++ b/lib/SIL/CMakeLists.txt
@@ -13,6 +13,7 @@
   SILBasicBlock.cpp
   SILBuilder.cpp
   SILCoverageMap.cpp
+  SILDebugScope.cpp
   SILDeclRef.cpp
   SILDefaultWitnessTable.cpp
   SILFunction.cpp
@@ -32,6 +33,7 @@
   SILVTable.cpp
   SILWitnessTable.cpp
   TypeLowering.cpp
+  ValueOwnershipKindClassifier.cpp
   LINK_LIBRARIES
     swiftSerialization
     swiftSema
diff --git a/lib/SIL/LoopInfo.cpp b/lib/SIL/LoopInfo.cpp
index ae2cae5..416ffb6 100644
--- a/lib/SIL/LoopInfo.cpp
+++ b/lib/SIL/LoopInfo.cpp
@@ -76,6 +76,9 @@
     return false;
   }
 
+  if (isa<ThrowInst>(I))
+    return false;
+
   assert(I->isTriviallyDuplicatable() &&
     "Code here must match isTriviallyDuplicatable in SILInstruction");
   return true;
diff --git a/lib/SIL/Projection.cpp b/lib/SIL/Projection.cpp
index 8d69dda..57e2828 100644
--- a/lib/SIL/Projection.cpp
+++ b/lib/SIL/Projection.cpp
@@ -531,87 +531,59 @@
 }
 
 raw_ostream &ProjectionPath::print(raw_ostream &os, SILModule &M) {
-  // Match how the memlocation print tests expect us to print projection paths.
-  //
-  // TODO: It sort of sucks having to print these bottom up computationally. We
-  // should really change the test so that prints out the path elements top
-  // down the path, rather than constructing all of these intermediate paths.
-  for (unsigned i : reversed(indices(Path))) {
-    SILType IterType = getDerivedType(i, M);
-    auto &IterProj = Path[i];
-    os << "Address Projection Type: ";
+  os << "Projection Path [";
+  SILType IterType = getBaseType();
+  for (const Projection &IterProj : Path) {
+    SILType BaseType = IterType;
+    IterType = IterProj.getType(IterType, M);
+
+    os << BaseType.getAddressType() << "\n  ";
+
     if (IterProj.isNominalKind()) {
-      auto *Decl = IterProj.getVarDecl(IterType);
-      IterType = IterProj.getType(IterType, M);
-      os << IterType.getAddressType() << "\n";
-      os << "Field Type: ";
+      auto *Decl = IterProj.getVarDecl(BaseType);
+      os << "Field: ";
       Decl->print(os);
-      os << "\n";
+      os << " of: ";
       continue;
     }
 
     if (IterProj.getKind() == ProjectionKind::Tuple) {
-      IterType = IterProj.getType(IterType, M);
-      os << IterType.getAddressType() << "\n";
-      os << "Index: ";
-      os << IterProj.getIndex() << "\n";
+      os << "Index: " << IterProj.getIndex() << " into: ";
       continue;
     }
 
+    if (IterProj.getKind() == ProjectionKind::BitwiseCast) {
+      os << "BitwiseCast to: ";
+      continue;
+    }
+    if (IterProj.getKind() == ProjectionKind::Index) {
+      os << "Index: " << IterProj.getIndex() << " into: ";
+      continue;
+    }
+    if (IterProj.getKind() == ProjectionKind::Upcast) {
+      os << "UpCast to: ";
+      continue;
+    }
+    if (IterProj.getKind() == ProjectionKind::RefCast) {
+      os << "RefCast to: ";
+      continue;
+    }
     if (IterProj.getKind() == ProjectionKind::Box) {
-      os << "Box: ";
+      os << " Box over: ";
       continue;
     }
-
-    llvm_unreachable("Can not print this projection kind");
-  }
-
-// Migrate the tests to this format eventually.
-#if 0
-  os << "(Projection Path [";
-  SILType NextType = BaseType;
-  os << NextType;
-  for (const Projection &P : Path) {
-    os << ", ";
-    NextType = P.getType(NextType, M);
-    os << NextType;
-  }
-  os << "]";
-#endif
-  return os;
-}
-
-raw_ostream &ProjectionPath::printProjections(raw_ostream &os, SILModule &M) const {
-  // Match how the memlocation print tests expect us to print projection paths.
-  //
-  // TODO: It sort of sucks having to print these bottom up computationally. We
-  // should really change the test so that prints out the path elements top
-  // down the path, rather than constructing all of these intermediate paths.
-  for (unsigned i : reversed(indices(Path))) {
-    auto &IterProj = Path[i];
-    if (IterProj.isNominalKind()) {
-      os << "Field Type: " << IterProj.getIndex() << "\n";
+    if (IterProj.getKind() == ProjectionKind::TailElems) {
+      os << " TailElems of: ";
       continue;
     }
-
-    if (IterProj.getKind() == ProjectionKind::Tuple) {
-      os << "Index: " << IterProj.getIndex() << "\n";
-      continue;
-    }
-
-    llvm_unreachable("Can not print this projection kind");
+    os << "<unexpected projection> into: ";
   }
-
+  os << IterType.getAddressType() << "]\n";
   return os;
 }
 
 void ProjectionPath::dump(SILModule &M) {
-  print(llvm::outs(), M);
-  llvm::outs() << "\n";
-}
-
-void ProjectionPath::dumpProjections(SILModule &M) const {
-  printProjections(llvm::outs(), M);
+  print(llvm::dbgs(), M);
 }
 
 void ProjectionPath::verify(SILModule &M) {
diff --git a/lib/SIL/SILDebugScope.cpp b/lib/SIL/SILDebugScope.cpp
new file mode 100644
index 0000000..aa01d93
--- /dev/null
+++ b/lib/SIL/SILDebugScope.cpp
@@ -0,0 +1,57 @@
+//===--- SILDebugScope.h - DebugScopes for SIL code -------------*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// This file defines a container for scope information used to
+/// generate debug info.
+///
+//===----------------------------------------------------------------------===//
+
+#include "swift/SIL/SILDebugScope.h"
+#include "swift/SIL/SILFunction.h"
+
+using namespace swift;
+
+SILDebugScope::SILDebugScope(SILLocation Loc, SILFunction *SILFn,
+                             const SILDebugScope *ParentScope ,
+                             const SILDebugScope *InlinedCallSite)
+    : Loc(Loc), InlinedCallSite(InlinedCallSite) {
+  if (ParentScope)
+    Parent = ParentScope;
+  else {
+    assert(SILFn && "no parent provided");
+    Parent = SILFn;
+  }
+}
+
+SILDebugScope::SILDebugScope(SILLocation Loc)
+    : Loc(Loc), InlinedCallSite(nullptr) {}
+
+SILFunction *SILDebugScope::getInlinedFunction() const {
+  if (Parent.isNull())
+    return nullptr;
+
+  const SILDebugScope *Scope = this;
+  while (Scope->Parent.is<const SILDebugScope *>())
+    Scope = Scope->Parent.get<const SILDebugScope *>();
+  assert(Scope->Parent.is<SILFunction *>() && "orphaned scope");
+  return Scope->Parent.get<SILFunction *>();
+}
+
+SILFunction *SILDebugScope::getParentFunction() const {
+  if (InlinedCallSite)
+    return InlinedCallSite->getParentFunction();
+  if (auto *ParentScope = Parent.dyn_cast<const SILDebugScope *>())
+    return ParentScope->getParentFunction();
+  return Parent.get<SILFunction *>();
+}
diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp
index 5280add..4560e36 100644
--- a/lib/SIL/SILDeclRef.cpp
+++ b/lib/SIL/SILDeclRef.cpp
@@ -415,19 +415,23 @@
 }
 
 SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
-  // Anonymous functions have shared linkage.
-  // FIXME: This should really be the linkage of the parent function.
-  if (getAbstractClosureExpr())
-    return SILLinkage::Shared;
-  
+  if (getAbstractClosureExpr()) {
+    if (isSerialized())
+      return SILLinkage::Shared;
+    return SILLinkage::Private;
+  }
+
   // Native function-local declarations have shared linkage.
   // FIXME: @objc declarations should be too, but we currently have no way
   // of marking them "used" other than making them external. 
   ValueDecl *d = getDecl();
   DeclContext *moduleContext = d->getDeclContext();
   while (!moduleContext->isModuleScopeContext()) {
-    if (!isForeign && moduleContext->isLocalContext())
-      return SILLinkage::Shared;
+    if (!isForeign && moduleContext->isLocalContext()) {
+      if (isSerialized())
+        return SILLinkage::Shared;
+      return SILLinkage::Private;
+    }
     moduleContext = moduleContext->getParent();
   }
 
diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp
index 16bbb6d..dbb2a72 100644
--- a/lib/SIL/SILFunction.cpp
+++ b/lib/SIL/SILFunction.cpp
@@ -462,11 +462,3 @@
   ForwardingSubs = env->getForwardingSubstitutions();
   return *ForwardingSubs;
 }
-
-const TypeLowering &SILFunction::getTypeLowering(SILType InputType) const {
-  CanSILFunctionType FuncType = getLoweredFunctionType();
-  auto &TypeConverter = getModule().Types;
-  GenericContextScope GCS(TypeConverter, FuncType->getGenericSignature());
-  const TypeLowering &Result = TypeConverter.getTypeLowering(InputType);
-  return Result;
-}
diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp
index 1ae2f21..21c5867 100644
--- a/lib/SIL/SILInstruction.cpp
+++ b/lib/SIL/SILInstruction.cpp
@@ -992,6 +992,9 @@
 /// additional handling. It is important to know this information when
 /// you perform such optimizations like e.g. jump-threading.
 bool SILInstruction::isTriviallyDuplicatable() const {
+  if (isa<ThrowInst>(this))
+    return false;
+
   if (isa<AllocStackInst>(this) || isa<DeallocStackInst>(this)) {
     return false;
   }
diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp
index 1bc41f6..fb2f262 100644
--- a/lib/SIL/SILModule.cpp
+++ b/lib/SIL/SILModule.cpp
@@ -77,12 +77,12 @@
 };
 
 SILModule::SILModule(ModuleDecl *SwiftModule, SILOptions &Options,
-                     const DeclContext *associatedDC,
-                     bool wholeModule)
-  : TheSwiftModule(SwiftModule), AssociatedDeclContext(associatedDC),
-    Stage(SILStage::Raw), Callback(new SILModule::SerializationCallback()),
-    wholeModule(wholeModule), Options(Options), Types(*this) {
-}
+                     const DeclContext *associatedDC, bool wholeModule,
+                     bool wholeModuleSerialized)
+    : TheSwiftModule(SwiftModule), AssociatedDeclContext(associatedDC),
+      Stage(SILStage::Raw), Callback(new SILModule::SerializationCallback()),
+      wholeModule(wholeModule), WholeModuleSerialized(wholeModuleSerialized),
+      Options(Options), Types(*this) {}
 
 SILModule::~SILModule() {
   // Decrement ref count for each SILGlobalVariable with static initializers.
@@ -568,6 +568,11 @@
   return Visitor.hasFunction(Name);
 }
 
+void SILModule::linkAllFromCurrentModule() {
+  getSILLoader()->getAllForModule(getSwiftModule()->getName(),
+                                  /*PrimaryFile=*/nullptr);
+}
+
 void SILModule::linkAllWitnessTables() {
   getSILLoader()->getAllWitnessTables();
 }
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index e80a7d3..bbb21a4 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -12,7 +12,6 @@
 
 #define DEBUG_TYPE "sil-ownership-verifier"
 
-#include "TransitivelyUnreachableBlocks.h"
 #include "swift/AST/ASTContext.h"
 #include "swift/AST/AnyFunctionRef.h"
 #include "swift/AST/Decl.h"
@@ -21,9 +20,11 @@
 #include "swift/AST/Types.h"
 #include "swift/Basic/Range.h"
 #include "swift/Basic/STLExtras.h"
+#include "swift/Basic/TransformArrayRef.h"
 #include "swift/ClangImporter/ClangModule.h"
 #include "swift/SIL/Dominance.h"
 #include "swift/SIL/DynamicCasts.h"
+#include "swift/SIL/OwnershipChecker.h"
 #include "swift/SIL/PrettyStackTrace.h"
 #include "swift/SIL/Projection.h"
 #include "swift/SIL/SILBuiltinVisitor.h"
@@ -33,6 +34,7 @@
 #include "swift/SIL/SILOpenedArchetypesTracker.h"
 #include "swift/SIL/SILVTable.h"
 #include "swift/SIL/SILVisitor.h"
+#include "swift/SIL/TransitivelyUnreachableBlocks.h"
 #include "swift/SIL/TypeLowering.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/PostOrderIterator.h"
@@ -43,10 +45,6 @@
 
 using namespace swift;
 
-// The verifier is basically all assertions, so don't compile it with NDEBUG to
-// prevent release builds from triggering spurious unused variable warnings.
-#ifndef NDEBUG
-
 // This is an option to put the SILOwnershipVerifier in testing mode. This
 // causes the following:
 //
@@ -219,6 +217,35 @@
 
 namespace {
 
+struct ErrorBehaviorKind {
+  enum inner_t {
+    Invalid = 0,
+    ReturnFalse = 1,
+    PrintMessage = 2,
+    Assert = 4,
+    PrintMessageAndReturnFalse = PrintMessage | ReturnFalse,
+    PrintMessageAndAssert = PrintMessage | Assert,
+  } Value;
+
+  ErrorBehaviorKind() : Value(Invalid) {}
+  ErrorBehaviorKind(inner_t Inner) : Value(Inner) { assert(Value != Invalid); }
+
+  bool shouldAssert() const {
+    assert(Value != Invalid);
+    return Value & Assert;
+  }
+
+  bool shouldPrintMessage() const {
+    assert(Value != Invalid);
+    return Value & PrintMessage;
+  }
+
+  bool shouldReturnFalse() const {
+    assert(Value != Invalid);
+    return Value & ReturnFalse;
+  }
+};
+
 struct OwnershipUseCheckerResult {
   bool HasCompatibleOwnership;
   bool ShouldCheckForDataflowViolations;
@@ -227,9 +254,12 @@
 class OwnershipCompatibilityUseChecker
     : public SILInstructionVisitor<OwnershipCompatibilityUseChecker,
                                    OwnershipUseCheckerResult> {
+public:
+private:
   SILModule &Mod;
   const Operand &Op;
   SILValue BaseValue;
+  ErrorBehaviorKind ErrorBehavior;
 
 public:
   /// Create a new OwnershipCompatibilityUseChecker.
@@ -240,8 +270,9 @@
   /// of where one would want to do this is in the case of value projections
   /// like struct_extract.
   OwnershipCompatibilityUseChecker(SILModule &M, const Operand &Op,
-                                   SILValue BaseValue)
-      : Mod(M), Op(Op), BaseValue(BaseValue) {
+                                   SILValue BaseValue,
+                                   ErrorBehaviorKind ErrorBehavior)
+      : Mod(M), Op(Op), BaseValue(BaseValue), ErrorBehavior(ErrorBehavior) {
     assert((BaseValue == Op.get() ||
             BaseValue.getOwnershipKind() == ValueOwnershipKind::Guaranteed) &&
            "Guaranteed values are the only values allowed to have subobject");
@@ -274,6 +305,21 @@
     return getOwnershipKind() == ValueOwnershipKind::Trivial;
   }
 
+  /// Depending on our initialization, either return false or call Func and
+  /// throw an error.
+  bool handleError(llvm::function_ref<void()> &&MessagePrinterFunc) const {
+    if (ErrorBehavior.shouldPrintMessage()) {
+      MessagePrinterFunc();
+    }
+
+    if (ErrorBehavior.shouldReturnFalse()) {
+      return false;
+    }
+
+    assert(ErrorBehavior.shouldAssert() && "At this point, we should assert");
+    llvm_unreachable("triggering standard assertion failure routine");
+  }
+
   OwnershipUseCheckerResult visitForwardingInst(SILInstruction *I,
                                                 ArrayRef<Operand> Ops);
   OwnershipUseCheckerResult visitForwardingInst(SILInstruction *I) {
@@ -292,14 +338,13 @@
   bool check(SILInstruction *User) {
     auto Result = visit(User);
     if (!Result.HasCompatibleOwnership) {
-      llvm::errs() << "Function: '" << User->getFunction()->getName() << "'\n"
-                   << "Have operand with incompatible ownership?!\n"
-                   << "Value: " << *getValue() << "BaseValue: " << *BaseValue
-                   << "User: " << *User << "Conv: " << getOwnershipKind()
-                   << "\n\n";
-      if (IsSILOwnershipVerifierTestingEnabled)
-        return false;
-      llvm_unreachable("triggering standard assertion failure routine");
+      return handleError([&]() {
+        llvm::errs() << "Function: '" << User->getFunction()->getName() << "'\n"
+                     << "Have operand with incompatible ownership?!\n"
+                     << "Value: " << *getValue() << "BaseValue: " << *BaseValue
+                     << "User: " << *User << "Conv: " << getOwnershipKind()
+                     << "\n\n";
+      });
     }
 
     assert((!Result.ShouldCheckForDataflowViolations ||
@@ -1095,6 +1140,7 @@
 CONSTANT_OWNERSHIP_BUILTIN(Trivial, false, ZExt)
 CONSTANT_OWNERSHIP_BUILTIN(Trivial, false, ZExtOrBitCast)
 CONSTANT_OWNERSHIP_BUILTIN(Trivial, false, ZeroInitializer)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, false, Swift3ImplicitObjCEntrypoint)
 #undef CONSTANT_OWNERSHIP_BUILTIN
 
 // Builtins that should be lowered to SIL instructions so we should never see
@@ -1157,7 +1203,12 @@
 
 namespace {
 
+// TODO: This class uses a bunch of global state like variables. It should be
+// refactored into a large state object that is used by functions.
 class SILValueOwnershipChecker {
+  /// The result of performing the check.
+  llvm::Optional<bool> Result;
+
   /// The module that we are in.
   SILModule &Mod;
 
@@ -1168,47 +1219,92 @@
   /// The value whose ownership we will check.
   SILValue Value;
 
-  // The worklist that we will use for our iterative reachability query.
+  /// The action that the checker should perform on detecting an error.
+  ErrorBehaviorKind ErrorBehavior;
+
+  /// The worklist that we will use for our iterative reachability query.
   llvm::SmallVector<SILBasicBlock *, 32> Worklist;
 
-  // The set of blocks with lifetime ending uses.
+  /// The set of blocks with lifetime ending uses.
   llvm::SmallPtrSet<SILBasicBlock *, 8> BlocksWithLifetimeEndingUses;
 
-  // The set of blocks with non-lifetime ending uses and the associated
-  // non-lifetime ending use SILInstruction.
+  /// The set of blocks with non-lifetime ending uses and the associated
+  /// non-lifetime ending use SILInstruction.
   llvm::SmallDenseMap<SILBasicBlock *, GeneralizedUser, 8>
       BlocksWithNonLifetimeEndingUses;
 
-  // The blocks that we have already visited.
-  llvm::SmallPtrSet<SILBasicBlock *, 32> VisitedBlocks;
+  /// The blocks that we have already visited.
+  llvm::SmallPtrSet<SILBasicBlock *, 32> &VisitedBlocks;
 
-  // A list of successor blocks that we must visit by the time the algorithm
-  // terminates.
+  /// A list of successor blocks that we must visit by the time the algorithm
+  /// terminates.
   llvm::SmallPtrSet<SILBasicBlock *, 8> SuccessorBlocksThatMustBeVisited;
 
+  /// The list of lifetime ending users that we found. Only valid if check is
+  /// successful.
+  llvm::SmallVector<GeneralizedUser, 16> LifetimeEndingUsers;
+
+  /// The list of non lifetime ending users that we found. Only valid if check
+  /// is successful.
+  llvm::SmallVector<GeneralizedUser, 16> RegularUsers;
+
 public:
-  SILValueOwnershipChecker(SILModule &M,
-                           const TransitivelyUnreachableBlocksInfo &TUB,
-                           SILValue V)
-      : Mod(M), TUB(TUB), Value(V) {}
+  SILValueOwnershipChecker(
+      SILModule &M, const TransitivelyUnreachableBlocksInfo &TUB, SILValue V,
+      ErrorBehaviorKind ErrorBehavior,
+      llvm::SmallPtrSet<SILBasicBlock *, 32> &VisitedBlocks)
+      : Result(), Mod(M), TUB(TUB), Value(V), ErrorBehavior(ErrorBehavior),
+        VisitedBlocks(VisitedBlocks) {
+    assert(Value && "Can not initialize a checker with an empty SILValue");
+  }
 
   ~SILValueOwnershipChecker() = default;
   SILValueOwnershipChecker(SILValueOwnershipChecker &) = delete;
   SILValueOwnershipChecker(SILValueOwnershipChecker &&) = delete;
 
-  void check() {
+  bool check() {
+    if (Result.hasValue())
+      return Result.getValue();
+
     DEBUG(llvm::dbgs() << "Verifying ownership of: " << *Value);
-    // First check that our uses have coherent ownership. If after evaluating
-    // the ownership we do not need to check dataflow (due to performs
-    // ValueOwnershipKind::None), then bail.
-    if (!checkUses())
-      return;
-    checkDataflow();
+    Result = checkUses() && checkDataflow();
+
+    return Result.getValue();
+  }
+
+  using user_array_transform = std::function<SILInstruction *(GeneralizedUser)>;
+  using user_array = TransformArrayRef<user_array_transform>;
+
+  /// A function that returns a range of lifetime ending users found for the
+  /// given value.
+  user_array getLifetimeEndingUsers() const {
+    assert(Result.hasValue() && "Can not call until check() is called");
+    assert(Result.getValue() && "Can not call if check() returned false");
+
+    user_array_transform Transform(
+        [](GeneralizedUser User) -> SILInstruction * {
+          return User.getInst();
+        });
+    return user_array(ArrayRef<GeneralizedUser>(LifetimeEndingUsers),
+                      Transform);
+  }
+
+  /// A function that returns a range of regular (i.e. "non lifetime ending")
+  /// users found for the given value.
+  user_array getRegularUsers() const {
+    assert(Result.hasValue() && "Can not call until check() is called");
+    assert(Result.getValue() && "Can not call if check() returned false");
+
+    user_array_transform Transform(
+        [](GeneralizedUser User) -> SILInstruction * {
+          return User.getInst();
+        });
+    return user_array(ArrayRef<GeneralizedUser>(RegularUsers), Transform);
   }
 
 private:
   bool checkUses();
-  void checkDataflow();
+  bool checkDataflow();
   void checkDataflowEndConditions();
   void
   gatherUsers(llvm::SmallVectorImpl<GeneralizedUser> &LifetimeEndingUsers,
@@ -1235,6 +1331,28 @@
   bool checkValueWithoutLifetimeEndingUses();
 
   bool checkFunctionArgWithoutLifetimeEndingUses(SILFunctionArgument *Arg);
+
+  bool isGuaranteedFunctionArgWithLifetimeEndingUses(
+      SILFunctionArgument *Arg,
+      const llvm::SmallVectorImpl<GeneralizedUser> &LifetimeEndingUsers) const;
+  bool isSubobjectProjectionWithLifetimeEndingUses(
+      SILValue Value,
+      const llvm::SmallVectorImpl<GeneralizedUser> &LifetimeEndingUsers) const;
+
+  /// Depending on our initialization, either return false or call Func and
+  /// throw an error.
+  bool handleError(llvm::function_ref<void()> &&MessagePrinterFunc) const {
+    if (ErrorBehavior.shouldPrintMessage()) {
+      MessagePrinterFunc();
+    }
+
+    if (ErrorBehavior.shouldReturnFalse()) {
+      return false;
+    }
+
+    assert(ErrorBehavior.shouldAssert() && "At this point, we should assert");
+    llvm_unreachable("triggering standard assertion failure routine");
+  }
 };
 
 } // end anonymous namespace
@@ -1253,13 +1371,14 @@
   // First check if our lifetime ending user is a cond_br. In such a case, we
   // always consider the non-lifetime ending use to be a use after free.
   if (LifetimeEndingUser.isCondBranchUser()) {
-    llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
-                 << "Found use after free?!\n"
-                 << "Value: " << *Value
-                 << "Consuming User: " << *LifetimeEndingUser
-                 << "Non Consuming User: " << *Iter->second << "Block: bb"
-                 << UserBlock->getDebugID() << "\n\n";
-    return true;
+    return !handleError([&]() {
+      llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
+                   << "Found use after free?!\n"
+                   << "Value: " << *Value
+                   << "Consuming User: " << *LifetimeEndingUser
+                   << "Non Consuming User: " << *Iter->second << "Block: bb"
+                   << UserBlock->getDebugID() << "\n\n";
+    });
   }
 
   // Ok. At this point, we know that our lifetime ending user is not a cond
@@ -1278,13 +1397,14 @@
                    [&NonLifetimeEndingUser](const SILInstruction &I) -> bool {
                      return NonLifetimeEndingUser == &I;
                    }) != UserBlock->end()) {
-    llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
-                 << "Found use after free?!\n"
-                 << "Value: " << *Value
-                 << "Consuming User: " << *LifetimeEndingUser
-                 << "Non Consuming User: " << *Iter->second << "Block: bb"
-                 << UserBlock->getDebugID() << "\n\n";
-    return true;
+    return !handleError([&] {
+      llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
+                   << "Found use after free?!\n"
+                   << "Value: " << *Value
+                   << "Consuming User: " << *LifetimeEndingUser
+                   << "Non Consuming User: " << *Iter->second << "Block: bb"
+                   << UserBlock->getDebugID() << "\n\n";
+    });
   }
 
   // Erase the use since we know that it is properly joint post-dominated.
@@ -1299,14 +1419,14 @@
       !BlocksWithLifetimeEndingUses.count(UserBlock))
     return false;
 
-  llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
-               << "Found over consume?!\n"
-               << "Value: " << *Value;
-  if (LifetimeEndingUser.hasValue())
-    llvm::errs() << "User: " << *LifetimeEndingUser.getValue();
-  llvm::errs() << "Block: bb" << UserBlock->getDebugID() << "\n\n";
-
-  return true;
+  return !handleError([&] {
+    llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
+                 << "Found over consume?!\n"
+                 << "Value: " << *Value;
+    if (LifetimeEndingUser.hasValue())
+      llvm::errs() << "User: " << *LifetimeEndingUser.getValue();
+    llvm::errs() << "Block: bb" << UserBlock->getDebugID() << "\n\n";
+  });
 }
 
 void SILValueOwnershipChecker::gatherUsers(
@@ -1348,7 +1468,8 @@
     if (User->isTypeDependentOperand(*Op))
       continue;
 
-    if (OwnershipCompatibilityUseChecker(Mod, *Op, Value).check(User)) {
+    if (OwnershipCompatibilityUseChecker(Mod, *Op, Value, ErrorBehavior)
+            .check(User)) {
       DEBUG(llvm::dbgs() << "        Lifetime Ending User: " << *User);
       if (auto *CBI = dyn_cast<CondBranchInst>(User)) {
         addCondBranchToList(LifetimeEndingUsers, CBI, Op->getOperandNumber());
@@ -1450,13 +1571,11 @@
   if (TUB.isUnreachable(Arg->getParent()))
     return true;
 
-  llvm::errs() << "Function: '" << Arg->getFunction()->getName() << "'\n"
-               << "    Owned function parameter without life "
-                  "ending uses!\n"
-               << "Value: " << *Arg << '\n';
-  if (IsSILOwnershipVerifierTestingEnabled)
-    return true;
-  llvm_unreachable("triggering standard assertion failure routine");
+  return !handleError([&] {
+    llvm::errs() << "Function: '" << Arg->getFunction()->getName() << "'\n"
+                 << "    Owned function parameter without life ending uses!\n"
+                 << "Value: " << *Arg << '\n';
+  });
 }
 
 bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() {
@@ -1490,50 +1609,48 @@
   }
 
   if (!isValueAddressOrTrivial(Value, Mod)) {
-    llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
-                 << "Non trivial values, non address values, and non "
-                    "guaranteed function args must have at least one "
-                    "lifetime ending use?!\n"
-                 << "Value: " << *Value << '\n';
-    if (IsSILOwnershipVerifierTestingEnabled)
-      return true;
-    llvm_unreachable("triggering standard assertion failure routine");
+    return !handleError([&] {
+      llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
+                   << "Non trivial values, non address values, and non "
+                      "guaranteed function args must have at least one "
+                      "lifetime ending use?!\n"
+                   << "Value: " << *Value << '\n';
+    });
   }
 
   return true;
 }
 
-static bool isGuaranteedFunctionArgWithLifetimeEndingUses(
+bool SILValueOwnershipChecker::isGuaranteedFunctionArgWithLifetimeEndingUses(
     SILFunctionArgument *Arg,
-    const llvm::SmallVectorImpl<GeneralizedUser> &LifetimeEndingUsers) {
+    const llvm::SmallVectorImpl<GeneralizedUser> &LifetimeEndingUsers) const {
   if (Arg->getOwnershipKind() != ValueOwnershipKind::Guaranteed)
     return true;
 
-  llvm::errs() << "    Function: '" << Arg->getFunction()->getName() << "'\n"
-               << "    Guaranteed function parameter with life ending uses!\n"
-               << "    Value: " << *Arg;
-  for (const auto &U : LifetimeEndingUsers) {
-    llvm::errs() << "    Lifetime Ending User: " << *U;
-  }
-  llvm::errs() << '\n';
-  if (IsSILOwnershipVerifierTestingEnabled)
-    return false;
-  llvm_unreachable("triggering standard assertion failure routine");
+  return handleError([&] {
+    llvm::errs() << "    Function: '" << Arg->getFunction()->getName() << "'\n"
+                 << "    Guaranteed function parameter with life ending uses!\n"
+                 << "    Value: " << *Arg;
+    for (const auto &U : LifetimeEndingUsers) {
+      llvm::errs() << "    Lifetime Ending User: " << *U;
+    }
+    llvm::errs() << '\n';
+  });
 }
 
-static bool isSubobjectProjectionWithLifetimeEndingUses(
+bool SILValueOwnershipChecker::isSubobjectProjectionWithLifetimeEndingUses(
     SILValue Value,
-    const llvm::SmallVectorImpl<GeneralizedUser> &LifetimeEndingUsers) {
-  llvm::errs() << "    Function: '" << Value->getFunction()->getName() << "'\n"
-               << "    Subobject projection with life ending uses!\n"
-               << "    Value: " << *Value;
-  for (const auto &U : LifetimeEndingUsers) {
-    llvm::errs() << "    Lifetime Ending User: " << *U;
-  }
-  llvm::errs() << '\n';
-  if (IsSILOwnershipVerifierTestingEnabled)
-    return false;
-  llvm_unreachable("triggering standard assertion failure routine");
+    const llvm::SmallVectorImpl<GeneralizedUser> &LifetimeEndingUsers) const {
+  return handleError([&] {
+    llvm::errs() << "    Function: '" << Value->getFunction()->getName()
+                 << "'\n"
+                 << "    Subobject projection with life ending uses!\n"
+                 << "    Value: " << *Value;
+    for (const auto &U : LifetimeEndingUsers) {
+      llvm::errs() << "    Lifetime Ending User: " << *U;
+    }
+    llvm::errs() << '\n';
+  });
 }
 
 bool SILValueOwnershipChecker::checkUses() {
@@ -1544,9 +1661,7 @@
   // 1. Verify that none of the uses are in the same block. This would be an
   // overconsume so in this case we assert.
   // 2. Verify that the uses are compatible with our ownership convention.
-  llvm::SmallVector<GeneralizedUser, 16> LifetimeEndingUsers;
-  llvm::SmallVector<GeneralizedUser, 16> NonLifetimeEndingUsers;
-  gatherUsers(LifetimeEndingUsers, NonLifetimeEndingUsers);
+  gatherUsers(LifetimeEndingUsers, RegularUsers);
 
   // We can only have no lifetime ending uses if we have:
   //
@@ -1592,7 +1707,7 @@
   // BlocksWithNonLifetimeEndingUses map. While we do this, if we have multiple
   // uses in the same block, we only accept the last use since from a liveness
   // perspective that is all we care about.
-  uniqueNonLifetimeEndingUsers(NonLifetimeEndingUsers);
+  uniqueNonLifetimeEndingUsers(RegularUsers);
 
   // Finally, we go through each one of our lifetime ending users performing the
   // following operation:
@@ -1612,16 +1727,12 @@
     // If the block does over consume, we either assert or return false. We only
     // return false when debugging.
     if (doesBlockDoubleConsume(UserBlock, User, true)) {
-      if (IsSILOwnershipVerifierTestingEnabled)
-        return false;
-      llvm_unreachable("triggering standard assertion failure routine");
+      return handleError([] {});
     }
 
     // Then check if the given block has a use after free.
     if (doesBlockContainUseAfterFree(User, UserBlock)) {
-      if (IsSILOwnershipVerifierTestingEnabled)
-        return false;
-      llvm_unreachable("triggering standard assertion failure routine");
+      return handleError([] {});
     }
 
     // If this user is in the same block as the value, do not visit
@@ -1661,9 +1772,7 @@
     // Make sure that the predecessor is not in our
     // BlocksWithLifetimeEndingUses list.
     if (doesBlockDoubleConsume(PredBlock, User)) {
-      if (IsSILOwnershipVerifierTestingEnabled)
-        return false;
-      llvm_unreachable("triggering standard assertion failure routine");
+      return handleError([] {});
     }
 
     if (!VisitedBlocks.insert(PredBlock).second)
@@ -1674,7 +1783,7 @@
   return true;
 }
 
-void SILValueOwnershipChecker::checkDataflow() {
+bool SILValueOwnershipChecker::checkDataflow() {
   DEBUG(llvm::dbgs() << "    Beginning to check dataflow constraints\n");
   // Until the worklist is empty...
   while (!Worklist.empty()) {
@@ -1734,9 +1843,7 @@
     // 2. We add the predecessor to the worklist if we have not visited it yet.
     for (auto *PredBlock : BB->getPredecessorBlocks()) {
       if (doesBlockDoubleConsume(PredBlock)) {
-        if (IsSILOwnershipVerifierTestingEnabled)
-          return;
-        llvm_unreachable("triggering standard assertion failure routine");
+        return handleError([] {});
       }
 
       if (VisitedBlocks.count(PredBlock)) {
@@ -1751,39 +1858,37 @@
   // Make sure that we visited all successor blocks that we needed to visit to
   // make sure we didn't leak.
   if (!SuccessorBlocksThatMustBeVisited.empty()) {
-    llvm::errs()
-        << "Function: '" << Value->getFunction()->getName() << "'\n"
-        << "Error! Found a leak due to a consuming post-dominance failure!\n"
-        << "    Value: " << *Value << "    Post Dominating Failure Blocks:\n";
-    for (auto *BB : SuccessorBlocksThatMustBeVisited) {
-      llvm::errs() << "        bb" << BB->getDebugID();
-    }
-    llvm::errs() << '\n';
-    if (IsSILOwnershipVerifierTestingEnabled)
-      return;
-    llvm_unreachable("triggering standard assertion failure routine");
+    return handleError([&] {
+      llvm::errs()
+          << "Function: '" << Value->getFunction()->getName() << "'\n"
+          << "Error! Found a leak due to a consuming post-dominance failure!\n"
+          << "    Value: " << *Value << "    Post Dominating Failure Blocks:\n";
+      for (auto *BB : SuccessorBlocksThatMustBeVisited) {
+        llvm::errs() << "        bb" << BB->getDebugID();
+      }
+      llvm::errs() << '\n';
+    });
   }
 
   // Make sure that we do not have any lifetime ending uses left to visit. If we
   // do, then these non lifetime ending uses must be outside of our "alive"
   // blocks implying a use-after free.
   if (!BlocksWithNonLifetimeEndingUses.empty()) {
-    llvm::errs()
-        << "Function: '" << Value->getFunction()->getName() << "'\n"
-        << "Found use after free due to unvisited non lifetime ending uses?!\n"
-        << "Value: " << *Value << "    Remaining Users:\n";
-    for (auto &Pair : BlocksWithNonLifetimeEndingUses) {
-      llvm::errs() << "User:" << *Pair.second << "Block: bb"
-                   << Pair.first->getDebugID() << "\n";
-    }
-    llvm::errs() << "\n";
-    if (IsSILOwnershipVerifierTestingEnabled)
-      return;
-    llvm_unreachable("triggering standard assertion failure routine");
+    return handleError([&] {
+      llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
+                   << "Found use after free due to unvisited non lifetime "
+                      "ending uses?!\n"
+                   << "Value: " << *Value << "    Remaining Users:\n";
+      for (auto &Pair : BlocksWithNonLifetimeEndingUses) {
+        llvm::errs() << "User:" << *Pair.second << "Block: bb"
+                     << Pair.first->getDebugID() << "\n";
+      }
+      llvm::errs() << "\n";
+    });
   }
-}
 
-#endif
+  return true;
+}
 
 //===----------------------------------------------------------------------===//
 //                           Top Level Entrypoints
@@ -1811,11 +1916,18 @@
   if (isa<TermInst>(this))
     return;
 
+  ErrorBehaviorKind ErrorBehavior;
+  if (IsSILOwnershipVerifierTestingEnabled) {
+    ErrorBehavior = ErrorBehaviorKind::PrintMessageAndReturnFalse;
+  } else {
+    ErrorBehavior = ErrorBehaviorKind::PrintMessageAndAssert;
+  }
   auto *Self = const_cast<SILInstruction *>(this);
   for (const Operand &Op : getAllOperands()) {
     if (isTypeDependentOperand(Op))
       continue;
-    OwnershipCompatibilityUseChecker(getModule(), Op, Op.get()).check(Self);
+    OwnershipCompatibilityUseChecker(getModule(), Op, Op.get(), ErrorBehavior)
+        .check(Self);
   }
 #endif
 }
@@ -1838,12 +1950,54 @@
   if (F->hasUnqualifiedOwnership())
     return;
 
+  ErrorBehaviorKind ErrorBehavior;
+  if (IsSILOwnershipVerifierTestingEnabled) {
+    ErrorBehavior = ErrorBehaviorKind::PrintMessageAndReturnFalse;
+  } else {
+    ErrorBehavior = ErrorBehaviorKind::PrintMessageAndAssert;
+  }
+  llvm::SmallPtrSet<SILBasicBlock *, 32> LiveBlocks;
   if (TUB) {
-    SILValueOwnershipChecker(Mod, *TUB, *this).check();
+    SILValueOwnershipChecker(Mod, *TUB, *this, ErrorBehavior, LiveBlocks)
+        .check();
   } else {
     PostOrderFunctionInfo NewPOFI((*this)->getFunction());
     TransitivelyUnreachableBlocksInfo TUB(NewPOFI);
-    SILValueOwnershipChecker(Mod, TUB, *this).check();
+    SILValueOwnershipChecker(Mod, TUB, *this, ErrorBehavior, LiveBlocks)
+        .check();
   }
 #endif
 }
+
+bool OwnershipChecker::checkValue(SILValue Value) {
+  RegularUsers.clear();
+  LifetimeEndingUsers.clear();
+  LiveBlocks.clear();
+
+  // If we are SILUndef, just bail. SILUndef can pair with anything. Any uses of
+  // the SILUndef will make sure that the matching checks out.
+  if (isa<SILUndef>(Value))
+    return false;
+
+  // Since we do not have SILUndef, we now know that getFunction() should return
+  // a real function. Assert in case this assumption is no longer true.
+  SILFunction *F = Value->getFunction();
+  assert(F && "Instructions and arguments should have a function");
+
+  // If the given function has unqualified ownership, there is nothing further
+  // to verify.
+  if (F->hasUnqualifiedOwnership())
+    return false;
+
+  ErrorBehaviorKind ErrorBehavior(ErrorBehaviorKind::ReturnFalse);
+  SILValueOwnershipChecker Checker(Mod, TUB, Value, ErrorBehavior, LiveBlocks);
+  if (!Checker.check()) {
+    return false;
+  }
+
+  // TODO: Make this more efficient.
+  copy(Checker.getRegularUsers(), std::back_inserter(RegularUsers));
+  copy(Checker.getLifetimeEndingUsers(),
+       std::back_inserter(LifetimeEndingUsers));
+  return true;
+}
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 6521a64..e6fc383 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -48,6 +48,7 @@
 
 
 using namespace swift;
+using ID = SILPrintContext::ID;
 
 llvm::cl::opt<bool>
 SILPrintNoColor("sil-print-no-color", llvm::cl::init(""),
@@ -64,22 +65,6 @@
                     Demangle::DemangleOptions::SimplifiedUIDemangleOptions());
 }
 
-struct ID {
-  enum ID_Kind {
-    SILBasicBlock, SILUndef, SSAValue
-  } Kind;
-  unsigned Number;
-
-  // A stable ordering of ID objects.
-  bool operator<(ID Other) const {
-    if (unsigned(Kind) < unsigned(Other.Kind))
-      return true;
-    if (Number < Other.Number)
-      return true;
-    return false;
-  }
-};
-
 enum SILColorKind {
   SC_Type,
 };
@@ -125,17 +110,24 @@
 };
 } // end anonymous namespace
 
-static raw_ostream &operator<<(raw_ostream &OS, ID i) {
-  SILColor C(OS, i.Kind);
-  switch (i.Kind) {
-  case ID::SILUndef: OS << "undef"; return OS;
+void SILPrintContext::ID::print(raw_ostream &OS) {
+  SILColor C(OS, Kind);
+  switch (Kind) {
+  case ID::SILUndef:
+    OS << "undef";
+    return;
   case ID::SILBasicBlock: OS << "bb"; break;
   case ID::SSAValue: OS << '%'; break;
   }
-  OS << i.Number;
+  OS << Number;
+}
 
+namespace swift {
+raw_ostream &operator<<(raw_ostream &OS, SILPrintContext::ID i) {
+  i.print(OS);
   return OS;
 }
+}
 
 /// IDAndType - Used when a client wants to print something like "%0 : $Int".
 struct SILValuePrinterInfo {
@@ -400,9 +392,6 @@
   SILValue subjectValue;
   unsigned LastBufferID;
 
-  llvm::DenseMap<const SILBasicBlock *, unsigned> BlocksToIDMap;
-  llvm::DenseMap<const ValueBase *, unsigned> ValueToIDMap;
-
   // Printers for the underlying stream.
 #define SIMPLE_PRINTER(TYPE) \
   SILPrinter &operator<<(TYPE value) { \
@@ -455,13 +444,11 @@
     PrintState.ASTOptions.PrintForSIL = true;
   }
 
-  ID getID(const SILBasicBlock *B);
-  ID getID(SILValue V);
   SILValuePrinterInfo getIDAndType(SILValue V) {
-    return { getID(V), V->getType() };
+    return {Ctx.getID(V), V->getType()};
   }
   SILValuePrinterInfo getIDAndTypeAndOwnership(SILValue V) {
-    return {getID(V), V->getType(), V.getOwnershipKind()};
+    return {Ctx.getID(V), V->getType(), V.getOwnershipKind()};
   }
 
   //===--------------------------------------------------------------------===//
@@ -474,9 +461,7 @@
       std::copy(po_begin(UnsafeF), po_end(UnsafeF),
                 std::back_inserter(RPOT));
       std::reverse(RPOT.begin(), RPOT.end());
-      // Initialize IDs so our IDs are in RPOT as well. This is a hack.
-      for (unsigned Index : indices(RPOT))
-        BlocksToIDMap[RPOT[Index]] = Index;
+      Ctx.initBlockIDs(RPOT);
       interleave(RPOT,
                  [&](SILBasicBlock *B) { print(B); },
                  [&] { *this << '\n'; });
@@ -495,7 +480,7 @@
     for (SILValue V : BB->getArguments()) {
       if (V->use_empty())
         continue;
-      *this << "// " << getID(V);
+      *this << "// " << Ctx.getID(V);
       PrintState.OS.PadToColumn(50);
       *this << "// user";
       if (std::next(V->use_begin()) != V->use_end())
@@ -504,7 +489,7 @@
 
       llvm::SmallVector<ID, 32> UserIDs;
       for (auto *Op : V->getUses())
-        UserIDs.push_back(getID(Op->getUser()));
+        UserIDs.push_back(Ctx.getID(Op->getUser()));
 
       // Display the user ids sorted to give a stable use order in the
       // printer's output if we are asked to do so. This makes diffing large
@@ -551,7 +536,9 @@
     printBlockArgumentUses(BB);
 
     // Then print the name of our block, the arguments, and the block colon.
-    *this << getID(BB); printBlockArguments(BB); *this << ":";
+    *this << Ctx.getID(BB);
+    printBlockArguments(BB);
+    *this << ":";
 
     if (!BB->pred_empty()) {
       PrintState.OS.PadToColumn(50);
@@ -560,7 +547,7 @@
 
       llvm::SmallVector<ID, 32> PredIDs;
       for (auto *BBI : BB->getPredecessorBlocks())
-        PredIDs.push_back(getID(BBI));
+        PredIDs.push_back(Ctx.getID(BBI));
 
       // Display the pred ids sorted to give a stable use order in the printer's
       // output if we are asked to do so. This makes diffing large sections of
@@ -592,7 +579,7 @@
     PrintState.OS.PadToColumn(50);
     *this << "// type-defs: ";
     interleave(TypeDepOps,
-               [&](const Operand &op) { *this << getID(op.get()); },
+               [&](const Operand &op) { *this << Ctx.getID(op.get()); },
                [&] { *this << ", "; });
     return true;
   }
@@ -611,7 +598,7 @@
       *this << "// ";
     }
     if (!V->hasValue()) {
-      *this << "id: " << getID(V);
+      *this << "id: " << Ctx.getID(V);
       return true;
     }
 
@@ -625,7 +612,7 @@
 
     llvm::SmallVector<ID, 32> UserIDs;
     for (auto *Op : V->getUses())
-      UserIDs.push_back(getID(Op->getUser()));
+      UserIDs.push_back(Ctx.getID(Op->getUser()));
 
     // If we are asked to, display the user ids sorted to give a stable use
     // order in the printer's output. This makes diffing large sections of SIL
@@ -744,27 +731,24 @@
         *this << ":in_prologue";
     }
 
-    // Print inlined-at location, if any.
-    if (DS) {
-      SILFunction *InlinedF = DS->getInlinedFunction();
-      auto InlineScopes = DS->flattenedInlineTree();
-      for (auto *CS : reversed(InlineScopes)) {
-        *this << ": ";
-        if (InlinedF) {
-          *this << demangleSymbol(InlinedF->getName());
-        } else {
-          *this << '?';
-        }
-        *this << " perf_inlined_at ";
-        auto CallSite = CS->Loc;
-        if (!CallSite.isNull() && CallSite.isASTNode())
-          CallSite.getSourceLoc().print(
-            PrintState.OS, M.getASTContext().SourceMgr, LastBufferID);
-        else
-          *this << "?";
+    if (!DS)
+      return;
 
-        InlinedF = CS->getInlinedFunction();
-      }
+    // Print inlined-at location, if any.
+    const SILDebugScope *CS = DS;
+    while ((CS = CS->InlinedCallSite)) {
+      *this << ": ";
+      if (auto *InlinedF = CS->getInlinedFunction())
+        *this << demangleSymbol(InlinedF->getName());
+      else
+        *this << '?';
+      *this << " perf_inlined_at ";
+      auto CallSite = CS->Loc;
+      if (!CallSite.isNull() && CallSite.isASTNode())
+        CallSite.getSourceLoc().print(
+            PrintState.OS, M.getASTContext().SourceMgr, LastBufferID);
+      else
+        *this << "?";
     }
   }
 
@@ -796,7 +780,7 @@
 
     // Print result.
     if (V->hasValue()) {
-      ID Name = getID(V);
+      ID Name = Ctx.getID(V);
       *this << Name << " = ";
     }
 
@@ -831,12 +815,11 @@
   
   void printInContext(SILValue V) {
     subjectValue = V;
-    
+
     auto sortByID = [&](SILValue a, SILValue b) {
-      return getID(a).Number < getID(b).Number;
+      return Ctx.getID(a).Number < Ctx.getID(b).Number;
     };
 
-    
     if (auto *I = dyn_cast<SILInstruction>(V)) {
       auto operands = map<SmallVector<SILValue,4>>(I->getAllOperands(),
                                                    [](Operand const &o) {
@@ -865,7 +848,7 @@
 
   void visitSILArgument(SILArgument *A) {
     // This should really only happen during debugging.
-    *this << "argument of " << getID(A->getParent()) << " : "
+    *this << "argument of " << Ctx.getID(A->getParent()) << " : "
           << A->getType();
   }
 
@@ -938,25 +921,25 @@
   void visitApplyInst(ApplyInst *AI) {
     if (AI->isNonThrowing())
       *this << "[nothrow] ";
-    *this << getID(AI->getCallee());
+    *this << Ctx.getID(AI->getCallee());
     printSubstitutions(AI->getSubstitutions());
     *this << '(';
     interleave(AI->getArguments(),
-               [&](const SILValue &arg) { *this << getID(arg); },
+               [&](const SILValue &arg) { *this << Ctx.getID(arg); },
                [&] { *this << ", "; });
     *this << ") : " << AI->getCallee()->getType();
   }
 
   void visitTryApplyInst(TryApplyInst *AI) {
-    *this << getID(AI->getCallee());
+    *this << Ctx.getID(AI->getCallee());
     printSubstitutions(AI->getSubstitutions());
     *this << '(';
     interleave(AI->getArguments(),
-               [&](const SILValue &arg) { *this << getID(arg); },
+               [&](const SILValue &arg) { *this << Ctx.getID(arg); },
                [&] { *this << ", "; });
     *this << ") : " << AI->getCallee()->getType();
-    *this << ", normal " << getID(AI->getNormalBB());
-    *this << ", error " << getID(AI->getErrorBB());
+    *this << ", normal " << Ctx.getID(AI->getNormalBB());
+    *this << ", error " << Ctx.getID(AI->getErrorBB());
   }
 
   void visitPartialApplyInst(PartialApplyInst *CI) {
@@ -976,11 +959,11 @@
     case ParameterConvention::Indirect_InoutAliasable:
       llvm_unreachable("unexpected callee convention!");
     }
-    *this << getID(CI->getCallee());
+    *this << Ctx.getID(CI->getCallee());
     printSubstitutions(CI->getSubstitutions());
     *this << '(';
     interleave(CI->getArguments(),
-               [&](const SILValue &arg) { *this << getID(arg); },
+               [&](const SILValue &arg) { *this << Ctx.getID(arg); },
                [&] { *this << ", "; });
     *this << ") : " << CI->getCallee()->getType();
   }
@@ -1094,19 +1077,19 @@
   }
 
   void visitStoreInst(StoreInst *SI) {
-    *this << getID(SI->getSrc()) << " to ";
+    *this << Ctx.getID(SI->getSrc()) << " to ";
     printStoreOwnershipQualifier(SI->getOwnershipQualifier());
     *this << getIDAndType(SI->getDest());
   }
 
   void visitStoreBorrowInst(StoreBorrowInst *SI) {
-    *this << getID(SI->getSrc()) << " to ";
+    *this << Ctx.getID(SI->getSrc()) << " to ";
     *this << getIDAndType(SI->getDest());
   }
 
   void visitEndBorrowInst(EndBorrowInst *EBI) {
-    *this << getID(EBI->getBorrowedValue()) << " from "
-          << getID(EBI->getOriginalValue()) << " : "
+    *this << Ctx.getID(EBI->getBorrowedValue()) << " from "
+          << Ctx.getID(EBI->getOriginalValue()) << " : "
           << EBI->getBorrowedValue()->getType() << ", "
           << EBI->getOriginalValue()->getType();
   }
@@ -1116,7 +1099,7 @@
   }
 
   void visitAssignInst(AssignInst *AI) {
-    *this << getID(AI->getSrc()) << " to " << getIDAndType(AI->getDest());
+    *this << Ctx.getID(AI->getSrc()) << " to " << getIDAndType(AI->getDest());
   }
 
   void visitMarkUninitializedInst(MarkUninitializedInst *MU) {
@@ -1133,14 +1116,14 @@
     *this << getIDAndType(MU->getOperand());
   }
   void visitMarkUninitializedBehaviorInst(MarkUninitializedBehaviorInst *MU) {
-    *this << getID(MU->getInitStorageFunc());
+    *this << Ctx.getID(MU->getInitStorageFunc());
     printSubstitutions(MU->getInitStorageSubstitutions());
-    *this << '(' << getID(MU->getStorage()) << ") : "
-          << MU->getInitStorageFunc()->getType() << ", "
-          << getID(MU->getSetterFunc());
+    *this << '(' << Ctx.getID(MU->getStorage())
+          << ") : " << MU->getInitStorageFunc()->getType() << ", "
+          << Ctx.getID(MU->getSetterFunc());
     printSubstitutions(MU->getSetterSubstitutions());
-    *this << '(' << getID(MU->getSelf()) << ") : "
-          << MU->getSetterFunc()->getType();
+    *this << '(' << Ctx.getID(MU->getSelf())
+          << ") : " << MU->getSetterFunc()->getType();
   }
   void visitMarkFunctionEscapeInst(MarkFunctionEscapeInst *MFE) {
     interleave(MFE->getElements(),
@@ -1164,7 +1147,7 @@
     *this << getIDAndType(LI->getOperand());
   }
   void visitStoreUnownedInst(StoreUnownedInst *SI) {
-    *this << getID(SI->getSrc()) << " to ";
+    *this << Ctx.getID(SI->getSrc()) << " to ";
     if (SI->isInitializationOfDest())
       *this << "[initialization] ";
     *this << getIDAndType(SI->getDest());
@@ -1176,7 +1159,7 @@
     *this << getIDAndType(LI->getOperand());
   }
   void visitStoreWeakInst(StoreWeakInst *SI) {
-    *this << getID(SI->getSrc()) << " to ";
+    *this << Ctx.getID(SI->getSrc()) << " to ";
     if (SI->isInitializationOfDest())
       *this << "[initialization] ";
     *this << getIDAndType(SI->getDest());
@@ -1185,7 +1168,7 @@
   void visitCopyAddrInst(CopyAddrInst *CI) {
     if (CI->isTakeOfSrc())
       *this << "[take] ";
-    *this << getID(CI->getSrc()) << " to ";
+    *this << Ctx.getID(CI->getSrc()) << " to ";
     if (CI->isInitializationOfDest())
       *this << "[initialization] ";
     *this << getIDAndType(CI->getDest());
@@ -1204,15 +1187,15 @@
   void visitCheckedCastBranchInst(CheckedCastBranchInst *CI) {
     if (CI->isExact())
       *this << "[exact] ";
-    *this << getIDAndType(CI->getOperand())
-       << " to " << CI->getCastType() << ", "
-       << getID(CI->getSuccessBB()) << ", " << getID(CI->getFailureBB());
+    *this << getIDAndType(CI->getOperand()) << " to " << CI->getCastType()
+          << ", " << Ctx.getID(CI->getSuccessBB()) << ", "
+          << Ctx.getID(CI->getFailureBB());
   }
 
   void visitCheckedCastValueBranchInst(CheckedCastValueBranchInst *CI) {
     *this << getIDAndType(CI->getOperand()) << " to " << CI->getCastType()
-          << ", " << getID(CI->getSuccessBB()) << ", "
-          << getID(CI->getFailureBB());
+          << ", " << Ctx.getID(CI->getSuccessBB()) << ", "
+          << Ctx.getID(CI->getFailureBB());
   }
 
   void visitUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *CI) {
@@ -1232,8 +1215,9 @@
     *this << getCastConsumptionKindName(CI->getConsumptionKind()) << ' '
           << CI->getSourceType() << " in " << getIDAndType(CI->getSrc())
           << " to " << CI->getTargetType() << " in "
-          << getIDAndType(CI->getDest()) << ", " << getID(CI->getSuccessBB())
-          << ", " << getID(CI->getFailureBB());
+          << getIDAndType(CI->getDest()) << ", "
+          << Ctx.getID(CI->getSuccessBB()) << ", "
+          << Ctx.getID(CI->getFailureBB());
   }
 
   void printUncheckedConversionInst(ConversionInst *CI, SILValue operand) {
@@ -1396,7 +1380,7 @@
       // Otherwise, print the type, then each value.
       *this << TI->getType() << " (";
       interleave(TI->getElements(),
-                 [&](const SILValue &V){ *this << getID(V); },
+                 [&](const SILValue &V) { *this << Ctx.getID(V); },
                  [&] { *this << ", "; });
       *this << ')';
     }
@@ -1548,7 +1532,7 @@
   }
   void visitInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *IBSHI) {
     *this << getIDAndType(IBSHI->getBlockStorage()) << ", invoke "
-          << getID(IBSHI->getInvokeFunction());
+          << Ctx.getID(IBSHI->getInvokeFunction());
     printSubstitutions(IBSHI->getSubstitutions());
     *this << " : " << IBSHI->getInvokeFunction()->getType()
           << ", type " << IBSHI->getType();
@@ -1679,10 +1663,10 @@
       SILValue value;
       SILBasicBlock *dest;
       std::tie(value, dest) = SII->getCase(i);
-      *this << ", case " << getID(value) << ": " << getID(dest);
+      *this << ", case " << Ctx.getID(value) << ": " << Ctx.getID(dest);
     }
     if (SII->hasDefault())
-      *this << ", default " << getID(SII->getDefaultBB());
+      *this << ", default " << Ctx.getID(SII->getDefaultBB());
   }
   
   void printSwitchEnumInst(SwitchEnumInstBase *SOI) {
@@ -1692,10 +1676,10 @@
       SILBasicBlock *dest;
       std::tie(elt, dest) = SOI->getCase(i);
       *this << ", case " << SILDeclRef(elt, SILDeclRef::Kind::EnumElement)
-         << ": " << getID(dest);
+            << ": " << Ctx.getID(dest);
     }
     if (SOI->hasDefault())
-      *this << ", default " << getID(SOI->getDefaultBB());
+      *this << ", default " << Ctx.getID(SOI->getDefaultBB());
   }
   
   void visitSwitchEnumInst(SwitchEnumInst *SOI) {
@@ -1713,10 +1697,10 @@
       SILValue result;
       std::tie(elt, result) = SEI->getCase(i);
       *this << ", case " << SILDeclRef(elt, SILDeclRef::Kind::EnumElement)
-         << ": " << getID(result);
+            << ": " << Ctx.getID(result);
     }
     if (SEI->hasDefault())
-      *this << ", default " << getID(SEI->getDefaultResult());
+      *this << ", default " << Ctx.getID(SEI->getDefaultResult());
 
     *this << " : " << SEI->getType();
   }
@@ -1735,19 +1719,18 @@
       SILValue casevalue;
       SILValue result;
       std::tie(casevalue, result) = SVI->getCase(i);
-      *this << ", case " << getID(casevalue)
-         << ": " << getID(result);
+      *this << ", case " << Ctx.getID(casevalue) << ": " << Ctx.getID(result);
     }
     if (SVI->hasDefault())
-      *this << ", default " << getID(SVI->getDefaultResult());
+      *this << ", default " << Ctx.getID(SVI->getDefaultResult());
 
     *this << " : " << SVI->getType();
   }
   
   void visitDynamicMethodBranchInst(DynamicMethodBranchInst *DMBI) {
     *this << getIDAndType(DMBI->getOperand()) << ", " << DMBI->getMember()
-          << ", " << getID(DMBI->getHasMethodBB()) << ", "
-          << getID(DMBI->getNoMethodBB());
+          << ", " << Ctx.getID(DMBI->getHasMethodBB()) << ", "
+          << Ctx.getID(DMBI->getNoMethodBB());
   }
 
   void printBranchArgs(OperandValueArrayRef args) {
@@ -1761,47 +1744,27 @@
   }
   
   void visitBranchInst(BranchInst *UBI) {
-    *this << getID(UBI->getDestBB());
+    *this << Ctx.getID(UBI->getDestBB());
     printBranchArgs(UBI->getArgs());
   }
 
   void visitCondBranchInst(CondBranchInst *CBI) {
-    *this << getID(CBI->getCondition()) << ", " << getID(CBI->getTrueBB());
+    *this << Ctx.getID(CBI->getCondition()) << ", "
+          << Ctx.getID(CBI->getTrueBB());
     printBranchArgs(CBI->getTrueArgs());
-    *this << ", " << getID(CBI->getFalseBB());
+    *this << ", " << Ctx.getID(CBI->getFalseBB());
     printBranchArgs(CBI->getFalseArgs());
   }
 };
 } // end anonymous namespace
 
-ID SILPrinter::getID(const SILBasicBlock *Block) {
-  // Lazily initialize the Blocks-to-IDs mapping.
-  if (BlocksToIDMap.empty()) {
-    unsigned idx = 0;
-    for (const SILBasicBlock &B : *Block->getParent())
-      BlocksToIDMap[&B] = idx++;
-  }
-
-  ID R = { ID::SILBasicBlock, BlocksToIDMap[Block] };
-  return R;
-}
-
-ID SILPrinter::getID(SILValue V) {
-  if (isa<SILUndef>(V))
-    return { ID::SILUndef, 0 };
-
-  // Lazily initialize the instruction -> ID mapping.
-  if (ValueToIDMap.empty()) {
-    V->getParentBlock()->getParent()->numberValues(ValueToIDMap);
-  }
-
-  ID R = { ID::SSAValue, ValueToIDMap[V] };
-  return R;
+static void printBlockID(raw_ostream &OS, SILBasicBlock *bb) {
+  SILPrintContext Ctx(OS);
+  OS << Ctx.getID(bb);
 }
 
 void SILBasicBlock::printAsOperand(raw_ostream &OS, bool PrintType) {
-  SILPrintContext Ctx(OS);
-  OS << SILPrinter(Ctx).getID(this);
+  printBlockID(OS, this);
 }
 
 //===----------------------------------------------------------------------===//
@@ -1828,6 +1791,10 @@
   SILPrinter(Ctx).print(this);
 }
 
+void SILBasicBlock::print(raw_ostream &OS, SILPrintContext &Ctx) const {
+  SILPrinter(Ctx).print(this);
+}
+
 /// Pretty-print the SILFunction to errs.
 void SILFunction::dump(bool Verbose) const {
   SILPrintContext Ctx(llvm::errs(), Verbose);
@@ -2440,17 +2407,7 @@
   print(llvm::errs());
 }
 
-void SILDebugScope::flatten(const SILDebugScope *DS,
-                            SILDebugScope::InlineScopeList &List) {
-  if (DS) {
-    if (auto *CS = DS->InlinedCallSite) {
-      flatten(CS->Parent.dyn_cast<const SILDebugScope *>(), List);
-      List.push_back(CS);
-    }
-    flatten(DS->Parent.dyn_cast<const SILDebugScope *>(), List);
-  }
-}
-
+#ifndef NDEBUG
 void SILDebugScope::dump(SourceManager &SM, llvm::raw_ostream &OS,
                          unsigned Indent) const {
   OS << "{\n";
@@ -2478,6 +2435,7 @@
   }
   OS << "}\n";
 }
+#endif
 
 void SILSpecializeAttr::print(llvm::raw_ostream &OS) const {
   SILPrintContext Ctx(OS);
@@ -2519,8 +2477,68 @@
 // SILPrintContext members
 //===----------------------------------------------------------------------===//
 
+SILPrintContext::SILPrintFunctionContext &
+SILPrintContext::getFuncContext(const SILFunction *F) {
+  if (F != FuncCtx.F) {
+    FuncCtx.BlocksToIDMap.clear();
+    FuncCtx.ValueToIDMap.clear();
+    FuncCtx.F = F;
+  }
+  return FuncCtx;
+}
+
 SILPrintContext::~SILPrintContext() {
 }
 
 void SILPrintContext::printInstructionCallBack(const SILInstruction *I) {
 }
+
+void SILPrintContext::initBlockIDs(ArrayRef<const SILBasicBlock *> Blocks) {
+  if (Blocks.empty())
+    return;
+
+  auto funcCtx = getFuncContext(Blocks[0]->getParent());
+
+  // Initialize IDs so our IDs are in RPOT as well. This is a hack.
+  for (unsigned Index : indices(Blocks))
+    funcCtx.BlocksToIDMap[Blocks[Index]] = Index;
+}
+
+ID SILPrintContext::getID(const SILBasicBlock *Block) {
+  auto funcCtx = getFuncContext(Block->getParent());
+
+  // Lazily initialize the Blocks-to-IDs mapping.
+  // If we are asked to emit sorted SIL, print out our BBs in RPOT order.
+  if (funcCtx.BlocksToIDMap.empty()) {
+    if (sortSIL()) {
+      std::vector<SILBasicBlock *> RPOT;
+      auto *UnsafeF = const_cast<SILFunction *>(Block->getParent());
+      std::copy(po_begin(UnsafeF), po_end(UnsafeF), std::back_inserter(RPOT));
+      std::reverse(RPOT.begin(), RPOT.end());
+      // Initialize IDs so our IDs are in RPOT as well. This is a hack.
+      for (unsigned Index : indices(RPOT))
+        funcCtx.BlocksToIDMap[RPOT[Index]] = Index;
+    } else {
+      unsigned idx = 0;
+      for (const SILBasicBlock &B : *Block->getParent())
+        funcCtx.BlocksToIDMap[&B] = idx++;
+    }
+  }
+  ID R = {ID::SILBasicBlock, funcCtx.BlocksToIDMap[Block]};
+  return R;
+}
+
+ID SILPrintContext::getID(SILValue V) {
+  if (isa<SILUndef>(V))
+    return {ID::SILUndef, 0};
+
+  auto funcCtx = getFuncContext(V->getFunction());
+
+  // Lazily initialize the instruction -> ID mapping.
+  if (funcCtx.ValueToIDMap.empty()) {
+    V->getParentBlock()->getParent()->numberValues(funcCtx.ValueToIDMap);
+  }
+
+  ID R = {ID::SSAValue, funcCtx.ValueToIDMap[V]};
+  return R;
+}
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index 6a271cd..e26b593 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -487,11 +487,13 @@
   if (is<ExistentialMetatypeType>())
     return ExistentialRepresentation::Metatype;
   
-  // Get the list of existential constraints. If the type isn't existential,
-  // then there is no representation.
-  if (!getSwiftRValueType()->isAnyExistentialType(protocols))
+  // If the type isn't existential, then there is no representation.
+  if (!isExistentialType())
     return ExistentialRepresentation::None;
-  
+
+  // Get the list of existential constraints.
+  getSwiftRValueType()->getExistentialTypeProtocols(protocols);
+
   // The (uncomposed) Error existential uses a special boxed representation.
   if (isErrorExistential(protocols)) {
     // NSError or CFError references can be adopted directly as Error
@@ -502,7 +504,7 @@
       return ExistentialRepresentation::Boxed;
     }
   }
-  
+
   // A class-constrained protocol composition can adopt the conforming
   // class reference directly.
   for (auto proto : protocols) {
@@ -525,9 +527,11 @@
   case ExistentialRepresentation::Class:
   case ExistentialRepresentation::Boxed: {
     // Look at the protocols to see what representation is appropriate.
-    SmallVector<ProtocolDecl *, 4> protocols;
-    if (!getSwiftRValueType()->isAnyExistentialType(protocols))
+    if (!getSwiftRValueType().isExistentialType())
       return false;
+    SmallVector<ProtocolDecl *, 4> protocols;
+    getSwiftRValueType().getExistentialTypeProtocols(protocols);
+
     // The (uncomposed) Error existential uses a special boxed
     // representation. It can also adopt class references of bridged error types
     // directly.
diff --git a/lib/SIL/SILValue.cpp b/lib/SIL/SILValue.cpp
index 6dcf8f5..0c87609 100644
--- a/lib/SIL/SILValue.cpp
+++ b/lib/SIL/SILValue.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "swift/SIL/SILValue.h"
+#include "ValueOwnershipKindClassifier.h"
 #include "swift/SIL/SILArgument.h"
 #include "swift/SIL/SILBuiltinVisitor.h"
 #include "swift/SIL/SILInstruction.h"
@@ -157,635 +158,8 @@
   Value = Result.getValue();
 }
 
-//===----------------------------------------------------------------------===//
-//                 Instruction ValueOwnershipKind Computation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class ValueOwnershipKindVisitor
-    : public SILVisitor<ValueOwnershipKindVisitor,
-                        ValueOwnershipKind> {
-
-public:
-  ValueOwnershipKindVisitor() = default;
-  ~ValueOwnershipKindVisitor() = default;
-  ValueOwnershipKindVisitor(const ValueOwnershipKindVisitor &) = delete;
-  ValueOwnershipKindVisitor(ValueOwnershipKindVisitor &&) = delete;
-
-  ValueOwnershipKind visitForwardingInst(SILInstruction *I,
-                                         ArrayRef<Operand> Ops);
-  ValueOwnershipKind visitForwardingInst(SILInstruction *I) {
-    return visitForwardingInst(I, I->getAllOperands());
-  }
-
-  ValueOwnershipKind visitValueBase(ValueBase *V) {
-    llvm_unreachable("unimplemented method on ValueBaseOwnershipVisitor");
-  }
-#define VALUE(Id, Parent) ValueOwnershipKind visit##Id(Id *ID);
-#include "swift/SIL/SILNodes.def"
-};
-
-} // end anonymous namespace
-
-#define CONSTANT_OWNERSHIP_INST(OWNERSHIP, INST)                               \
-  ValueOwnershipKind ValueOwnershipKindVisitor::visit##INST##Inst(   \
-      INST##Inst *Arg) {                                                       \
-    assert(Arg->hasValue() && "Expected to have a result");                    \
-    if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) {        \
-      assert((Arg->getType().isAddress() ||                                    \
-              Arg->getType().isTrivial(Arg->getModule())) &&                   \
-             "Trivial ownership requires a trivial type or an address");       \
-    }                                                                          \
-    return ValueOwnershipKind::OWNERSHIP;                                      \
-  }
-CONSTANT_OWNERSHIP_INST(Guaranteed, BeginBorrow)
-CONSTANT_OWNERSHIP_INST(Guaranteed, LoadBorrow)
-CONSTANT_OWNERSHIP_INST(Owned, AllocBox)
-CONSTANT_OWNERSHIP_INST(Owned, AllocExistentialBox)
-CONSTANT_OWNERSHIP_INST(Owned, AllocRef)
-CONSTANT_OWNERSHIP_INST(Owned, AllocRefDynamic)
-CONSTANT_OWNERSHIP_INST(Trivial, AllocValueBuffer)
-CONSTANT_OWNERSHIP_INST(Owned, CopyBlock)
-CONSTANT_OWNERSHIP_INST(Owned, CopyValue)
-CONSTANT_OWNERSHIP_INST(Owned, CopyUnownedValue)
-CONSTANT_OWNERSHIP_INST(Owned, LoadUnowned)
-CONSTANT_OWNERSHIP_INST(Owned, LoadWeak)
-CONSTANT_OWNERSHIP_INST(Owned, PartialApply)
-CONSTANT_OWNERSHIP_INST(Owned, StrongPin)
-CONSTANT_OWNERSHIP_INST(Owned, ThinToThickFunction)
-CONSTANT_OWNERSHIP_INST(Owned, InitExistentialOpaque)
-CONSTANT_OWNERSHIP_INST(Owned, UnconditionalCheckedCastValue)
-
-// One would think that these /should/ be unowned. In truth they are owned since
-// objc metatypes do not go through the retain/release fast path. In their
-// implementations of retain/release nothing happens, so this is safe.
-//
-// You could even have an optimization that just always removed retain/release
-// operations on these objects.
-CONSTANT_OWNERSHIP_INST(Owned, ObjCExistentialMetatypeToObject)
-CONSTANT_OWNERSHIP_INST(Owned, ObjCMetatypeToObject)
-
-// All addresses have trivial ownership. The values stored at the address may
-// not though.
-CONSTANT_OWNERSHIP_INST(Trivial, AddressToPointer)
-CONSTANT_OWNERSHIP_INST(Trivial, AllocStack)
-CONSTANT_OWNERSHIP_INST(Trivial, BindMemory)
-CONSTANT_OWNERSHIP_INST(Trivial, BeginAccess)
-CONSTANT_OWNERSHIP_INST(Trivial, BridgeObjectToWord)
-CONSTANT_OWNERSHIP_INST(Trivial, ClassMethod)
-CONSTANT_OWNERSHIP_INST(Trivial, DynamicMethod)
-CONSTANT_OWNERSHIP_INST(Trivial, ExistentialMetatype)
-CONSTANT_OWNERSHIP_INST(Trivial, FloatLiteral)
-CONSTANT_OWNERSHIP_INST(Trivial, FunctionRef)
-CONSTANT_OWNERSHIP_INST(Trivial, GlobalAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, IndexAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, IndexRawPointer)
-CONSTANT_OWNERSHIP_INST(Trivial, InitBlockStorageHeader)
-CONSTANT_OWNERSHIP_INST(Trivial, InitEnumDataAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, InitExistentialAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, InitExistentialMetatype)
-CONSTANT_OWNERSHIP_INST(Trivial, IntegerLiteral)
-CONSTANT_OWNERSHIP_INST(Trivial, IsNonnull)
-CONSTANT_OWNERSHIP_INST(Trivial, IsUnique)
-CONSTANT_OWNERSHIP_INST(Trivial, IsUniqueOrPinned)
-CONSTANT_OWNERSHIP_INST(Trivial, MarkFunctionEscape)
-CONSTANT_OWNERSHIP_INST(Trivial, MarkUninitializedBehavior)
-CONSTANT_OWNERSHIP_INST(Trivial, Metatype)
-CONSTANT_OWNERSHIP_INST(Trivial, ObjCProtocol)           // Is this right?
-CONSTANT_OWNERSHIP_INST(Trivial, ObjCToThickMetatype)
-CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialBox)
-CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialMetatype)
-CONSTANT_OWNERSHIP_INST(Trivial, PointerToAddress)
-CONSTANT_OWNERSHIP_INST(Trivial, PointerToThinFunction)
-CONSTANT_OWNERSHIP_INST(Trivial, ProjectBlockStorage)
-CONSTANT_OWNERSHIP_INST(Trivial, ProjectBox)
-CONSTANT_OWNERSHIP_INST(Trivial, ProjectExistentialBox)
-CONSTANT_OWNERSHIP_INST(Trivial, ProjectValueBuffer)
-CONSTANT_OWNERSHIP_INST(Trivial, RefElementAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, RefTailAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, RefToRawPointer)
-CONSTANT_OWNERSHIP_INST(Trivial, RefToUnmanaged)
-CONSTANT_OWNERSHIP_INST(Trivial, SelectEnumAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, StringLiteral)
-CONSTANT_OWNERSHIP_INST(Trivial, StructElementAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, SuperMethod)
-CONSTANT_OWNERSHIP_INST(Trivial, TailAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, ThickToObjCMetatype)
-CONSTANT_OWNERSHIP_INST(Trivial, ThinFunctionToPointer)
-CONSTANT_OWNERSHIP_INST(Trivial, TupleElementAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, UncheckedAddrCast)
-CONSTANT_OWNERSHIP_INST(Trivial, UncheckedRefCastAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, UncheckedTakeEnumDataAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, UncheckedTrivialBitCast)
-CONSTANT_OWNERSHIP_INST(Trivial, UnconditionalCheckedCastAddr)
-CONSTANT_OWNERSHIP_INST(Trivial, ValueMetatype)
-CONSTANT_OWNERSHIP_INST(Trivial, WitnessMethod)
-CONSTANT_OWNERSHIP_INST(Trivial, StoreBorrow)
-// TODO: It would be great to get rid of these.
-CONSTANT_OWNERSHIP_INST(Unowned, RawPointerToRef)
-CONSTANT_OWNERSHIP_INST(Unowned, RefToUnowned)
-CONSTANT_OWNERSHIP_INST(Unowned, UnmanagedToRef)
-CONSTANT_OWNERSHIP_INST(Unowned, UnownedToRef)
-#undef CONSTANT_OWNERSHIP_INST
-
-#define CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(OWNERSHIP, INST)                    \
-  ValueOwnershipKind ValueOwnershipKindVisitor::visit##INST##Inst(             \
-      INST##Inst *I) {                                                         \
-    if (I->getType().isTrivial(I->getModule())) {                              \
-      return ValueOwnershipKind::Trivial;                                      \
-    }                                                                          \
-    return ValueOwnershipKind::OWNERSHIP;                                      \
-  }
-CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, StructExtract)
-CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, TupleExtract)
-#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
-
-// These are instructions that do not have any result, so we should never reach
-// this point in the code since we need a SILValue to compute
-// ValueOwnershipKind. We define methods so that all instructions have a method
-// on the visitor (causing the compiler to warn if a new instruction is added
-// within a method being added).
-#define NO_RESULT_OWNERSHIP_INST(INST)                                         \
-  ValueOwnershipKind ValueOwnershipKindVisitor::visit##INST##Inst(   \
-      INST##Inst *I) {                                                         \
-    assert(!I->hasValue() && "Expected an instruction without a result");      \
-    llvm_unreachable("Instruction without a result can not have ownership");   \
-  }
-NO_RESULT_OWNERSHIP_INST(DeallocStack)
-NO_RESULT_OWNERSHIP_INST(DeallocRef)
-NO_RESULT_OWNERSHIP_INST(DeallocPartialRef)
-NO_RESULT_OWNERSHIP_INST(DeallocValueBuffer)
-NO_RESULT_OWNERSHIP_INST(DeallocBox)
-NO_RESULT_OWNERSHIP_INST(DeallocExistentialBox)
-NO_RESULT_OWNERSHIP_INST(EndAccess)
-NO_RESULT_OWNERSHIP_INST(EndBorrow)
-NO_RESULT_OWNERSHIP_INST(EndBorrowArgument)
-NO_RESULT_OWNERSHIP_INST(Store)
-NO_RESULT_OWNERSHIP_INST(StoreWeak)
-NO_RESULT_OWNERSHIP_INST(StoreUnowned)
-NO_RESULT_OWNERSHIP_INST(Assign)
-NO_RESULT_OWNERSHIP_INST(DebugValue)
-NO_RESULT_OWNERSHIP_INST(DebugValueAddr)
-NO_RESULT_OWNERSHIP_INST(CopyAddr)
-NO_RESULT_OWNERSHIP_INST(DestroyAddr)
-NO_RESULT_OWNERSHIP_INST(StrongRetain)
-NO_RESULT_OWNERSHIP_INST(StrongRelease)
-NO_RESULT_OWNERSHIP_INST(StrongRetainUnowned)
-NO_RESULT_OWNERSHIP_INST(StrongUnpin)
-NO_RESULT_OWNERSHIP_INST(UnmanagedRetainValue)
-NO_RESULT_OWNERSHIP_INST(UnmanagedReleaseValue)
-NO_RESULT_OWNERSHIP_INST(UnmanagedAutoreleaseValue)
-NO_RESULT_OWNERSHIP_INST(UnownedRetain)
-NO_RESULT_OWNERSHIP_INST(UnownedRelease)
-NO_RESULT_OWNERSHIP_INST(RetainValue)
-NO_RESULT_OWNERSHIP_INST(ReleaseValue)
-NO_RESULT_OWNERSHIP_INST(SetDeallocating)
-NO_RESULT_OWNERSHIP_INST(AutoreleaseValue)
-NO_RESULT_OWNERSHIP_INST(FixLifetime)
-NO_RESULT_OWNERSHIP_INST(DestroyValue)
-NO_RESULT_OWNERSHIP_INST(AllocGlobal)
-NO_RESULT_OWNERSHIP_INST(InjectEnumAddr)
-NO_RESULT_OWNERSHIP_INST(DeinitExistentialAddr)
-NO_RESULT_OWNERSHIP_INST(DeinitExistentialOpaque)
-NO_RESULT_OWNERSHIP_INST(CondFail)
-NO_RESULT_OWNERSHIP_INST(EndLifetime)
-
-// Terminators. These do not produce SILValue, so they do not have a
-// ValueOwnershipKind. They do have ownership implications in terms of the
-// SILArguments that they feed into. But that code is in SILArgument.
-NO_RESULT_OWNERSHIP_INST(Unreachable)
-NO_RESULT_OWNERSHIP_INST(Return)
-NO_RESULT_OWNERSHIP_INST(Throw)
-NO_RESULT_OWNERSHIP_INST(TryApply)
-NO_RESULT_OWNERSHIP_INST(Branch)
-NO_RESULT_OWNERSHIP_INST(CondBranch)
-NO_RESULT_OWNERSHIP_INST(SwitchValue)
-NO_RESULT_OWNERSHIP_INST(SwitchEnum)
-NO_RESULT_OWNERSHIP_INST(SwitchEnumAddr)
-NO_RESULT_OWNERSHIP_INST(DynamicMethodBranch)
-NO_RESULT_OWNERSHIP_INST(CheckedCastBranch)
-NO_RESULT_OWNERSHIP_INST(CheckedCastValueBranch)
-NO_RESULT_OWNERSHIP_INST(CheckedCastAddrBranch)
-#undef NO_RESULT_OWNERSHIP_INST
-
-// For a forwarding instruction, we loop over all operands and make sure that
-// all non-trivial values have the same ownership.
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitForwardingInst(SILInstruction *I,
-                                               ArrayRef<Operand> Ops) {
-  // A forwarding inst without operands must be trivial.
-  if (Ops.empty())
-    return ValueOwnershipKind::Trivial;
-
-  // Find the first index where we have a trivial value.
-  auto Iter =
-    find_if(Ops,
-            [&I](const Operand &Op) -> bool {
-              if (I->isTypeDependentOperand(Op))
-                return false;
-              return Op.get().getOwnershipKind() != ValueOwnershipKind::Trivial;
-            });
-  // All trivial.
-  if (Iter == Ops.end()) {
-    return ValueOwnershipKind::Trivial;
-  }
-
-  // See if we have any Any. If we do, just return that for now.
-  if (any_of(Ops,
-             [&I](const Operand &Op) -> bool {
-               if (I->isTypeDependentOperand(Op))
-                 return false;
-               return Op.get().getOwnershipKind() == ValueOwnershipKind::Any;
-             }))
-    return ValueOwnershipKind::Any;
-  unsigned Index = std::distance(Ops.begin(), Iter);
-
-  ValueOwnershipKind Base = Ops[Index].get().getOwnershipKind();
-
-  for (const Operand &Op : Ops.slice(Index+1)) {
-    if (I->isTypeDependentOperand(Op))
-      continue;
-    auto OpKind = Op.get().getOwnershipKind();
-    if (OpKind.merge(ValueOwnershipKind::Trivial))
-      continue;
-
-    auto MergedValue = Base.merge(OpKind.Value);
-    if (!MergedValue.hasValue()) {
-      // If we have mismatched SILOwnership and sil ownership is not enabled,
-      // just return Any for staging purposes. If SILOwnership is enabled, then
-      // we must assert!
-      if (!I->getModule().getOptions().EnableSILOwnership) {
-        return ValueOwnershipKind::Any;
-      }
-      llvm_unreachable("Forwarding inst with mismatching ownership kinds?!");
-    }
-  }
-
-  return Base;
-}
-
-#define FORWARDING_OWNERSHIP_INST(INST)                                        \
-  ValueOwnershipKind ValueOwnershipKindVisitor::visit##INST##Inst(   \
-      INST##Inst *I) {                                                         \
-    assert(I->hasValue() && "Expected to have a value");                       \
-    return visitForwardingInst(I);                                             \
-  }
-FORWARDING_OWNERSHIP_INST(BridgeObjectToRef)
-FORWARDING_OWNERSHIP_INST(ConvertFunction)
-FORWARDING_OWNERSHIP_INST(InitExistentialRef)
-FORWARDING_OWNERSHIP_INST(OpenExistentialRef)
-FORWARDING_OWNERSHIP_INST(OpenExistentialOpaque)
-FORWARDING_OWNERSHIP_INST(RefToBridgeObject)
-FORWARDING_OWNERSHIP_INST(SelectValue)
-FORWARDING_OWNERSHIP_INST(Struct)
-FORWARDING_OWNERSHIP_INST(Tuple)
-FORWARDING_OWNERSHIP_INST(UncheckedRefCast)
-FORWARDING_OWNERSHIP_INST(UnconditionalCheckedCast)
-FORWARDING_OWNERSHIP_INST(Upcast)
-FORWARDING_OWNERSHIP_INST(MarkUninitialized)
-FORWARDING_OWNERSHIP_INST(UncheckedEnumData)
-#undef FORWARDING_OWNERSHIP_INST
-
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitSelectEnumInst(SelectEnumInst *SEI) {
-  // We handle this specially, since a select enum forwards only its case
-  // values. We drop the first element since that is the condition element.
-  return visitForwardingInst(SEI, SEI->getAllOperands().drop_front());
-}
-
-ValueOwnershipKind ValueOwnershipKindVisitor::visitUncheckedBitwiseCastInst(
-    UncheckedBitwiseCastInst *UBCI) {
-  ValueOwnershipKind OpOwnership = UBCI->getOperand().getOwnershipKind();
-  bool ResultTypeIsTrivial = UBCI->getType().isTrivial(UBCI->getModule());
-
-  // First check if our operand has a trivial value ownership kind...
-  if (OpOwnership == ValueOwnershipKind::Trivial) {
-    // If we do have a trivial value ownership kind, see if our result type is
-    // trivial or non-trivial. If it is trivial, then we have trivial
-    // ownership. Otherwise, we have unowned ownership since from an ownership
-    // perspective, the value has instantaneously come into existence and
-    // nothing has taken ownership of it.
-    if (ResultTypeIsTrivial) {
-      return ValueOwnershipKind::Trivial;
-    }
-    return ValueOwnershipKind::Unowned;
-  }
-
-  // If our operand has non-trivial ownership, but our result does, then of
-  // course the result has trivial ownership.
-  if (ResultTypeIsTrivial) {
-    return ValueOwnershipKind::Trivial;
-  }
-
-  // Otherwise, we forward our ownership.
-  return visitForwardingInst(UBCI);
-}
-
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitUncheckedOwnershipConversionInst(
-    UncheckedOwnershipConversionInst *I) {
-  return I->getConversionOwnershipKind();
-}
-
-// An enum without payload is trivial. One with non-trivial payload is
-// forwarding.
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitEnumInst(EnumInst *EI) {
-  if (!EI->hasOperand())
-    return ValueOwnershipKind::Trivial;
-  return visitForwardingInst(EI);
-}
-
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitSILUndef(SILUndef *Arg) {
-  return ValueOwnershipKind::Any;
-}
-
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitSILPHIArgument(SILPHIArgument *Arg) {
-  return Arg->getOwnershipKind();
-}
-
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitSILFunctionArgument(SILFunctionArgument *Arg) {
-  return Arg->getOwnershipKind();
-}
-
-// This is a forwarding instruction through only one of its arguments.
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitMarkDependenceInst(MarkDependenceInst *MDI) {
-  return MDI->getValue().getOwnershipKind();
-}
-
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitApplyInst(ApplyInst *AI) {
-  SILModule &M = AI->getModule();
-  bool IsTrivial = AI->getType().isTrivial(M);
-  SILFunctionConventions fnConv(AI->getSubstCalleeType(), M);
-  auto Results = fnConv.getDirectSILResults();
-  // No results => empty tuple result => Trivial.
-  if (Results.empty() || IsTrivial)
-    return ValueOwnershipKind::Trivial;
-
-  CanGenericSignature Sig = AI->getSubstCalleeType()->getGenericSignature();
-  // Find the first index where we have a trivial value.
-  auto Iter = find_if(Results, [&M, &Sig](const SILResultInfo &Info) -> bool {
-    return Info.getOwnershipKind(M, Sig) != ValueOwnershipKind::Trivial;
-  });
-  // If we have all trivial, then we must be trivial.
-  if (Iter == Results.end())
-    return ValueOwnershipKind::Trivial;
-
-  ValueOwnershipKind Base = Iter->getOwnershipKind(M, Sig);
-
-  for (const SILResultInfo &ResultInfo :
-       SILFunctionConventions::DirectSILResultRange(next(Iter),
-                                                    Results.end())) {
-    auto RKind = ResultInfo.getOwnershipKind(M, Sig);
-    if (RKind.merge(ValueOwnershipKind::Trivial))
-      continue;
-
-    auto MergedValue = Base.merge(RKind.Value);
-    if (!MergedValue.hasValue()) {
-      llvm_unreachable("Forwarding inst with mismatching ownership kinds?!");
-    }
-  }
-
-  return Base;
-}
-
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitLoadInst(LoadInst *LI) {
-  switch (LI->getOwnershipQualifier()) {
-  case LoadOwnershipQualifier::Take:
-  case LoadOwnershipQualifier::Copy:
-    return ValueOwnershipKind::Owned;
-  case LoadOwnershipQualifier::Unqualified:
-    return ValueOwnershipKind::Any;
-  case LoadOwnershipQualifier::Trivial:
-    return ValueOwnershipKind::Trivial;
-  }
-
-  llvm_unreachable("Unhandled LoadOwnershipQualifier in switch.");
-}
-
 ValueOwnershipKind SILValue::getOwnershipKind() const {
   // Once we have multiple return values, this must be changed.
-  return ValueOwnershipKindVisitor().visit(const_cast<ValueBase *>(Value));
-}
-
-//===----------------------------------------------------------------------===//
-//                   Builtin OwnershipValueKind Computation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-struct ValueOwnershipKindBuiltinVisitor
-    : SILBuiltinVisitor<ValueOwnershipKindBuiltinVisitor, ValueOwnershipKind> {
-
-  ValueOwnershipKind visitLLVMIntrinsic(BuiltinInst *BI,
-                                        llvm::Intrinsic::ID ID) {
-    // LLVM intrinsics do not traffic in ownership, so if we have a result, it
-    // must be trivial.
-    assert(BI->hasValue() && "Can only get here if we have a SILValue");
-    assert(BI->getType().isTrivial(BI->getModule()) &&
-           "LLVM intrinsics should always be trivial");
-    return ValueOwnershipKind::Trivial;
-  }
-
-#define BUILTIN(ID, NAME, ATTRS)                                               \
-  ValueOwnershipKind visit##ID(BuiltinInst *BI, StringRef Attr);
-#include "swift/AST/Builtins.def"
-};
-
-} // end anonymous namespace
-
-#define CONSTANT_OWNERSHIP_BUILTIN(OWNERSHIP, ID)                              \
-  ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID(              \
-      BuiltinInst *BI, StringRef Attr) {                                       \
-    assert(BI->hasValue() && "Expected to have type");                         \
-    if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) {        \
-      assert(BI->getType().isTrivial(BI->getModule()) &&                       \
-             "Only trivial types can have trivial ownership");                 \
-    } else {                                                                   \
-      assert(!BI->getType().isTrivial(BI->getModule()) &&                      \
-             "Only non trivial types can have non trivial ownership");         \
-    }                                                                          \
-    return ValueOwnershipKind::OWNERSHIP;                                      \
-  }
-CONSTANT_OWNERSHIP_BUILTIN(Owned, Take)
-CONSTANT_OWNERSHIP_BUILTIN(Owned, TryPin)
-// This returns a value at +1 that is destroyed strictly /after/ the
-// UnsafeGuaranteedEnd. This provides the guarantee that we want.
-CONSTANT_OWNERSHIP_BUILTIN(Owned, UnsafeGuaranteed)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, AShr)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Add)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, And)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, AssumeNonNegative)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, BitCast)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ExactSDiv)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ExactUDiv)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FAdd)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OEQ)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OGE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OGT)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OLE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OLT)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ONE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UEQ)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UGE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UGT)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ULE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ULT)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UNE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FDiv)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FMul)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FNeg)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPExt)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPToSI)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPToUI)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPTrunc)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FRem)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FSub)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_EQ)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_NE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SGE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SGT)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SLE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SLT)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_UGE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_UGT)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_ULE)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_ULT)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToPtr)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, LShr)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Load)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadRaw)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadInvariant)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Mul)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Or)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, PtrToInt)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SAddOver)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SDiv)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SExt)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SExtOrBitCast)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SIToFP)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SMulOver)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SRem)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SSubOver)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Shl)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Sub)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Trunc)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, TruncOrBitCast)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, UAddOver)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, UDiv)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, UIToFP)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, UMulOver)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, URem)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, USubOver)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Xor)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ZExt)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ZExtOrBitCast)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ORD)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UNO)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToUnknownObject)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastFromUnknownObject)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToNativeObject)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, UnsafeCastToNativeObject)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastFromNativeObject)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToBridgeObject)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastReferenceFromBridgeObject)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, CastBitPatternFromBridgeObject)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, BridgeToRawPointer)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, BridgeFromRawPointer)
-CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastReference)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, AddressOf)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, GepRaw)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Gep)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, GetTailAddr)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, OnFastPath)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique_native)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned_native)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, BindMemory)
-CONSTANT_OWNERSHIP_BUILTIN(Owned, AllocWithTailElems)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ProjectTailElems)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsOptionalType)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Sizeof)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Strideof)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsPOD)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Alignof)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, AllocRaw)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, AssertConf)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToSCheckedTrunc)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToSCheckedTrunc)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToUCheckedTrunc)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToUCheckedTrunc)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SUCheckedConversion)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, USCheckedConversion)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToFPWithOverflow)
-
-// This is surprising, Builtin.unreachable returns a "Never" value which is
-// trivially typed.
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Unreachable)
-
-/// AtomicRMW has type (Builtin.RawPointer, T) -> T. But it provides overloads
-/// for integer or rawpointer, so it should be trivial.
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, AtomicRMW)
-
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, CondUnreachable)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, UnsafeGuaranteedEnd)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, GetObjCTypeEncoding)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, CanBeObjCClass)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, WillThrow)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, StaticReport)
-
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, DestroyArray)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, CopyArray)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, TakeArrayFrontToBack)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, TakeArrayBackToFront)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, UnexpectedError)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, ErrorInMain)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, DeallocRaw)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Fence)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Retain)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Release)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, CondFail)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, FixLifetime)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Autorelease)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Unpin)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Destroy)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Assign)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Init)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, AtomicStore)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, Once)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, TSanInoutAccess)
-
-#undef CONSTANT_OWNERSHIP_BUILTIN
-
-// Check all of these...
-#define UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ID)                             \
-  ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID(              \
-      BuiltinInst *BI, StringRef Attr) {                                       \
-    if (BI->getType().isTrivial(BI->getModule())) {                            \
-      return ValueOwnershipKind::Trivial;                                      \
-    }                                                                          \
-    return ValueOwnershipKind::Unowned;                                        \
-  }
-UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ReinterpretCast)
-UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(CmpXChg)
-UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(AtomicLoad)
-UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ExtractElement)
-UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(InsertElement)
-UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ZeroInitializer)
-#undef UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT
-
-ValueOwnershipKind
-ValueOwnershipKindVisitor::visitBuiltinInst(BuiltinInst *BI) {
-  // For now, just conservatively say builtins are None. We need to use a
-  // builtin in here to guarantee correctness.
-  return ValueOwnershipKindBuiltinVisitor().visit(BI);
+  sil::ValueOwnershipKindClassifier Classifier;
+  return Classifier.visit(const_cast<ValueBase *>(Value));
 }
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index ae2d1b0..5fd13c2 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -11,7 +11,6 @@
 //===----------------------------------------------------------------------===//
 
 #define DEBUG_TYPE "sil-verifier"
-#include "TransitivelyUnreachableBlocks.h"
 #include "swift/AST/ASTContext.h"
 #include "swift/AST/AnyFunctionRef.h"
 #include "swift/AST/Decl.h"
@@ -31,6 +30,7 @@
 #include "swift/SIL/SILOpenedArchetypesTracker.h"
 #include "swift/SIL/SILVTable.h"
 #include "swift/SIL/SILVisitor.h"
+#include "swift/SIL/TransitivelyUnreachableBlocks.h"
 #include "swift/SIL/TypeLowering.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/PostOrderIterator.h"
@@ -1131,8 +1131,25 @@
                                     "result of function_ref");
     require(!fnType->getExtInfo().hasContext(),
             "function_ref should have a context-free function result");
+
+    // Note: in SingleFunction mode, we relax some of these checks because
+    // we may not have linked everything yet.
+
+    SILFunction *RefF = FRI->getReferencedFunction();
+
+    // A direct reference to a shared_external declaration is an error; we
+    // should have deserialized a body.
+    if (RefF->isExternalDeclaration()) {
+      require(SingleFunction ||
+              !hasSharedVisibility(RefF->getLinkage()) ||
+              RefF->hasForeignBody(),
+              "external declarations of SILFunctions with shared visibility is "
+              "not allowed");
+    }
+
+    // A direct reference to a non-public or shared but not fragile function
+    // from a fragile function is an error.
     if (F.isSerialized()) {
-      SILFunction *RefF = FRI->getReferencedFunction();
       require((SingleFunction && RefF->isExternalDeclaration()) ||
               RefF->hasValidLinkageForFragileRef(),
               "function_ref inside fragile function cannot "
@@ -1539,6 +1556,17 @@
     require(I->getType() == boxTy->getFieldType(F.getModule(),
                                                 I->getFieldIndex()),
             "project_box result should be address of boxed type");
+
+    // If we have a mark_uninitialized as a user, the mark_uninitialized must be
+    // our only user. This is a requirement that is asserted by allocbox to
+    // stack. This check just embeds the requirement into the IR.
+    require(I->hasOneUse() ||
+            none_of(I->getUses(),
+                    [](Operand *Op) -> bool {
+                      return isa<MarkUninitializedInst>(Op->getUser());
+                    }),
+            "project_box with more than one user when a user is a "
+            "mark_uninitialized");
   }
 
   void checkProjectExistentialBoxInst(ProjectExistentialBoxInst *PEBI) {
@@ -2580,6 +2608,9 @@
             "init_existential_metatype result must match representation of "
             "operand");
 
+    while(auto metatypeType = resultType.is<ExistentialMetatypeType>())
+      resultType = resultType.getMetatypeInstanceType(F.getModule());
+
     checkExistentialProtocolConformances(resultType, I->getConformances());
     verifyOpenedArchetype(I, MetaTy.getInstanceType());
   }
@@ -2587,7 +2618,7 @@
   void checkExistentialProtocolConformances(SILType resultType,
                                 ArrayRef<ProtocolConformanceRef> conformances) {
     SmallVector<ProtocolDecl*, 4> protocols;
-    resultType.getSwiftRValueType().isAnyExistentialType(protocols);
+    resultType.getSwiftRValueType().getExistentialTypeProtocols(protocols);
 
     require(conformances.size() == protocols.size(),
             "init_existential instruction must have the "
@@ -3912,9 +3943,6 @@
 
       assert(F->isAvailableExternally() &&
              "external declaration of internal SILFunction not allowed");
-      assert(!hasSharedVisibility(F->getLinkage()) &&
-             "external declarations of SILFunctions with shared visibility is not "
-             "allowed");
       // If F is an external declaration, there is nothing further to do,
       // return.
       return;
@@ -4037,15 +4065,20 @@
 
   auto *protocol = getConformance()->getProtocol();
 
-  // Currently all witness tables have public conformances, thus witness tables
-  // should not reference SILFunctions without public/public_external linkage.
-  // FIXME: Once we support private conformances, update this.
   for (const Entry &E : getEntries())
     if (E.getKind() == SILWitnessTable::WitnessKind::Method) {
       SILFunction *F = E.getMethodWitness().Witness;
       if (F) {
-        assert(!isLessVisibleThan(F->getLinkage(), getLinkage()) &&
-               "Witness tables should not reference less visible functions.");
+        // If a SILWitnessTable is going to be serialized, it must only
+        // reference public or serializable functions.
+        if (isSerialized()) {
+          assert((!isLessVisibleThan(F->getLinkage(), getLinkage()) ||
+                  (F->isSerialized() &&
+                   hasSharedVisibility(F->getLinkage()))) &&
+                 "Fragile witness tables should not reference "
+                 "less visible functions.");
+        }
+
         assert(F->getLoweredFunctionType()->getRepresentation() ==
                SILFunctionTypeRepresentation::WitnessMethod &&
                "Witnesses must have witness_method representation.");
@@ -4069,9 +4102,12 @@
       continue;
 
     SILFunction *F = E.getWitness();
+    // FIXME
+    #if 0
     assert(!isLessVisibleThan(F->getLinkage(), getLinkage()) &&
            "Default witness tables should not reference "
            "less visible functions.");
+    #endif
     assert(F->getLoweredFunctionType()->getRepresentation() ==
            SILFunctionTypeRepresentation::WitnessMethod &&
            "Default witnesses must have witness_method representation.");
diff --git a/lib/SIL/ValueOwnershipKindClassifier.cpp b/lib/SIL/ValueOwnershipKindClassifier.cpp
new file mode 100644
index 0000000..df55fff
--- /dev/null
+++ b/lib/SIL/ValueOwnershipKindClassifier.cpp
@@ -0,0 +1,609 @@
+//===--- ValueOwnershipKindClassifier.cpp ---------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "ValueOwnershipKindClassifier.h"
+#include "swift/SIL/SILBuiltinVisitor.h"
+#include "swift/SIL/SILModule.h"
+
+using namespace swift;
+using namespace sil;
+
+#define CONSTANT_OWNERSHIP_INST(OWNERSHIP, INST)                               \
+  ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst(          \
+      INST##Inst *Arg) {                                                       \
+    assert(Arg->hasValue() && "Expected to have a result");                    \
+    if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) {        \
+      assert((Arg->getType().isAddress() ||                                    \
+              Arg->getType().isTrivial(Arg->getModule())) &&                   \
+             "Trivial ownership requires a trivial type or an address");       \
+    }                                                                          \
+    return ValueOwnershipKind::OWNERSHIP;                                      \
+  }
+CONSTANT_OWNERSHIP_INST(Guaranteed, BeginBorrow)
+CONSTANT_OWNERSHIP_INST(Guaranteed, LoadBorrow)
+CONSTANT_OWNERSHIP_INST(Owned, AllocBox)
+CONSTANT_OWNERSHIP_INST(Owned, AllocExistentialBox)
+CONSTANT_OWNERSHIP_INST(Owned, AllocRef)
+CONSTANT_OWNERSHIP_INST(Owned, AllocRefDynamic)
+CONSTANT_OWNERSHIP_INST(Trivial, AllocValueBuffer)
+CONSTANT_OWNERSHIP_INST(Owned, CopyBlock)
+CONSTANT_OWNERSHIP_INST(Owned, CopyValue)
+CONSTANT_OWNERSHIP_INST(Owned, CopyUnownedValue)
+CONSTANT_OWNERSHIP_INST(Owned, LoadUnowned)
+CONSTANT_OWNERSHIP_INST(Owned, LoadWeak)
+CONSTANT_OWNERSHIP_INST(Owned, PartialApply)
+CONSTANT_OWNERSHIP_INST(Owned, StrongPin)
+CONSTANT_OWNERSHIP_INST(Owned, ThinToThickFunction)
+CONSTANT_OWNERSHIP_INST(Owned, InitExistentialOpaque)
+CONSTANT_OWNERSHIP_INST(Owned, UnconditionalCheckedCastValue)
+
+// One would think that these /should/ be unowned. In truth they are owned since
+// objc metatypes do not go through the retain/release fast path. In their
+// implementations of retain/release nothing happens, so this is safe.
+//
+// You could even have an optimization that just always removed retain/release
+// operations on these objects.
+CONSTANT_OWNERSHIP_INST(Owned, ObjCExistentialMetatypeToObject)
+CONSTANT_OWNERSHIP_INST(Owned, ObjCMetatypeToObject)
+
+// All addresses have trivial ownership. The values stored at the address may
+// not though.
+CONSTANT_OWNERSHIP_INST(Trivial, AddressToPointer)
+CONSTANT_OWNERSHIP_INST(Trivial, AllocStack)
+CONSTANT_OWNERSHIP_INST(Trivial, BindMemory)
+CONSTANT_OWNERSHIP_INST(Trivial, BeginAccess)
+CONSTANT_OWNERSHIP_INST(Trivial, BridgeObjectToWord)
+CONSTANT_OWNERSHIP_INST(Trivial, ClassMethod)
+CONSTANT_OWNERSHIP_INST(Trivial, DynamicMethod)
+CONSTANT_OWNERSHIP_INST(Trivial, ExistentialMetatype)
+CONSTANT_OWNERSHIP_INST(Trivial, FloatLiteral)
+CONSTANT_OWNERSHIP_INST(Trivial, FunctionRef)
+CONSTANT_OWNERSHIP_INST(Trivial, GlobalAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, IndexAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, IndexRawPointer)
+CONSTANT_OWNERSHIP_INST(Trivial, InitBlockStorageHeader)
+CONSTANT_OWNERSHIP_INST(Trivial, InitEnumDataAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, InitExistentialAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, InitExistentialMetatype)
+CONSTANT_OWNERSHIP_INST(Trivial, IntegerLiteral)
+CONSTANT_OWNERSHIP_INST(Trivial, IsNonnull)
+CONSTANT_OWNERSHIP_INST(Trivial, IsUnique)
+CONSTANT_OWNERSHIP_INST(Trivial, IsUniqueOrPinned)
+CONSTANT_OWNERSHIP_INST(Trivial, MarkFunctionEscape)
+CONSTANT_OWNERSHIP_INST(Trivial, MarkUninitializedBehavior)
+CONSTANT_OWNERSHIP_INST(Trivial, Metatype)
+CONSTANT_OWNERSHIP_INST(Trivial, ObjCProtocol) // Is this right?
+CONSTANT_OWNERSHIP_INST(Trivial, ObjCToThickMetatype)
+CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialBox)
+CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialMetatype)
+CONSTANT_OWNERSHIP_INST(Trivial, PointerToAddress)
+CONSTANT_OWNERSHIP_INST(Trivial, PointerToThinFunction)
+CONSTANT_OWNERSHIP_INST(Trivial, ProjectBlockStorage)
+CONSTANT_OWNERSHIP_INST(Trivial, ProjectBox)
+CONSTANT_OWNERSHIP_INST(Trivial, ProjectExistentialBox)
+CONSTANT_OWNERSHIP_INST(Trivial, ProjectValueBuffer)
+CONSTANT_OWNERSHIP_INST(Trivial, RefElementAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, RefTailAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, RefToRawPointer)
+CONSTANT_OWNERSHIP_INST(Trivial, RefToUnmanaged)
+CONSTANT_OWNERSHIP_INST(Trivial, SelectEnumAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, StringLiteral)
+CONSTANT_OWNERSHIP_INST(Trivial, StructElementAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, SuperMethod)
+CONSTANT_OWNERSHIP_INST(Trivial, TailAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, ThickToObjCMetatype)
+CONSTANT_OWNERSHIP_INST(Trivial, ThinFunctionToPointer)
+CONSTANT_OWNERSHIP_INST(Trivial, TupleElementAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, UncheckedAddrCast)
+CONSTANT_OWNERSHIP_INST(Trivial, UncheckedRefCastAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, UncheckedTakeEnumDataAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, UncheckedTrivialBitCast)
+CONSTANT_OWNERSHIP_INST(Trivial, UnconditionalCheckedCastAddr)
+CONSTANT_OWNERSHIP_INST(Trivial, ValueMetatype)
+CONSTANT_OWNERSHIP_INST(Trivial, WitnessMethod)
+CONSTANT_OWNERSHIP_INST(Trivial, StoreBorrow)
+// TODO: It would be great to get rid of these.
+CONSTANT_OWNERSHIP_INST(Unowned, RawPointerToRef)
+CONSTANT_OWNERSHIP_INST(Unowned, RefToUnowned)
+CONSTANT_OWNERSHIP_INST(Unowned, UnmanagedToRef)
+CONSTANT_OWNERSHIP_INST(Unowned, UnownedToRef)
+#undef CONSTANT_OWNERSHIP_INST
+
+#define CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(OWNERSHIP, INST)                    \
+  ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst(          \
+      INST##Inst *I) {                                                         \
+    if (I->getType().isTrivial(I->getModule())) {                              \
+      return ValueOwnershipKind::Trivial;                                      \
+    }                                                                          \
+    return ValueOwnershipKind::OWNERSHIP;                                      \
+  }
+CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, StructExtract)
+CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, TupleExtract)
+#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
+
+// These are instructions that do not have any result, so we should never reach
+// this point in the code since we need a SILValue to compute
+// ValueOwnershipKind. We define methods so that all instructions have a method
+// on the visitor (causing the compiler to warn if a new instruction is added
+// within a method being added).
+#define NO_RESULT_OWNERSHIP_INST(INST)                                         \
+  ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst(          \
+      INST##Inst *I) {                                                         \
+    assert(!I->hasValue() && "Expected an instruction without a result");      \
+    llvm_unreachable("Instruction without a result can not have ownership");   \
+  }
+NO_RESULT_OWNERSHIP_INST(DeallocStack)
+NO_RESULT_OWNERSHIP_INST(DeallocRef)
+NO_RESULT_OWNERSHIP_INST(DeallocPartialRef)
+NO_RESULT_OWNERSHIP_INST(DeallocValueBuffer)
+NO_RESULT_OWNERSHIP_INST(DeallocBox)
+NO_RESULT_OWNERSHIP_INST(DeallocExistentialBox)
+NO_RESULT_OWNERSHIP_INST(EndAccess)
+NO_RESULT_OWNERSHIP_INST(EndBorrow)
+NO_RESULT_OWNERSHIP_INST(EndBorrowArgument)
+NO_RESULT_OWNERSHIP_INST(Store)
+NO_RESULT_OWNERSHIP_INST(StoreWeak)
+NO_RESULT_OWNERSHIP_INST(StoreUnowned)
+NO_RESULT_OWNERSHIP_INST(Assign)
+NO_RESULT_OWNERSHIP_INST(DebugValue)
+NO_RESULT_OWNERSHIP_INST(DebugValueAddr)
+NO_RESULT_OWNERSHIP_INST(CopyAddr)
+NO_RESULT_OWNERSHIP_INST(DestroyAddr)
+NO_RESULT_OWNERSHIP_INST(StrongRetain)
+NO_RESULT_OWNERSHIP_INST(StrongRelease)
+NO_RESULT_OWNERSHIP_INST(StrongRetainUnowned)
+NO_RESULT_OWNERSHIP_INST(StrongUnpin)
+NO_RESULT_OWNERSHIP_INST(UnmanagedRetainValue)
+NO_RESULT_OWNERSHIP_INST(UnmanagedReleaseValue)
+NO_RESULT_OWNERSHIP_INST(UnmanagedAutoreleaseValue)
+NO_RESULT_OWNERSHIP_INST(UnownedRetain)
+NO_RESULT_OWNERSHIP_INST(UnownedRelease)
+NO_RESULT_OWNERSHIP_INST(RetainValue)
+NO_RESULT_OWNERSHIP_INST(ReleaseValue)
+NO_RESULT_OWNERSHIP_INST(SetDeallocating)
+NO_RESULT_OWNERSHIP_INST(AutoreleaseValue)
+NO_RESULT_OWNERSHIP_INST(FixLifetime)
+NO_RESULT_OWNERSHIP_INST(DestroyValue)
+NO_RESULT_OWNERSHIP_INST(AllocGlobal)
+NO_RESULT_OWNERSHIP_INST(InjectEnumAddr)
+NO_RESULT_OWNERSHIP_INST(DeinitExistentialAddr)
+NO_RESULT_OWNERSHIP_INST(DeinitExistentialOpaque)
+NO_RESULT_OWNERSHIP_INST(CondFail)
+NO_RESULT_OWNERSHIP_INST(EndLifetime)
+
+// Terminators. These do not produce SILValue, so they do not have a
+// ValueOwnershipKind. They do have ownership implications in terms of the
+// SILArguments that they feed into. But that code is in SILArgument.
+NO_RESULT_OWNERSHIP_INST(Unreachable)
+NO_RESULT_OWNERSHIP_INST(Return)
+NO_RESULT_OWNERSHIP_INST(Throw)
+NO_RESULT_OWNERSHIP_INST(TryApply)
+NO_RESULT_OWNERSHIP_INST(Branch)
+NO_RESULT_OWNERSHIP_INST(CondBranch)
+NO_RESULT_OWNERSHIP_INST(SwitchValue)
+NO_RESULT_OWNERSHIP_INST(SwitchEnum)
+NO_RESULT_OWNERSHIP_INST(SwitchEnumAddr)
+NO_RESULT_OWNERSHIP_INST(DynamicMethodBranch)
+NO_RESULT_OWNERSHIP_INST(CheckedCastBranch)
+NO_RESULT_OWNERSHIP_INST(CheckedCastValueBranch)
+NO_RESULT_OWNERSHIP_INST(CheckedCastAddrBranch)
+#undef NO_RESULT_OWNERSHIP_INST
+
+// For a forwarding instruction, we loop over all operands and make sure that
+// all non-trivial values have the same ownership.
+ValueOwnershipKind
+ValueOwnershipKindClassifier::visitForwardingInst(SILInstruction *I,
+                                                  ArrayRef<Operand> Ops) {
+  // A forwarding inst without operands must be trivial.
+  if (Ops.empty())
+    return ValueOwnershipKind::Trivial;
+
+  // Find the first index where we have a trivial value.
+  auto Iter = find_if(Ops, [&I](const Operand &Op) -> bool {
+    if (I->isTypeDependentOperand(Op))
+      return false;
+    return Op.get().getOwnershipKind() != ValueOwnershipKind::Trivial;
+  });
+  // All trivial.
+  if (Iter == Ops.end()) {
+    return ValueOwnershipKind::Trivial;
+  }
+
+  // See if we have any Any. If we do, just return that for now.
+  if (any_of(Ops, [&I](const Operand &Op) -> bool {
+        if (I->isTypeDependentOperand(Op))
+          return false;
+        return Op.get().getOwnershipKind() == ValueOwnershipKind::Any;
+      }))
+    return ValueOwnershipKind::Any;
+  unsigned Index = std::distance(Ops.begin(), Iter);
+
+  ValueOwnershipKind Base = Ops[Index].get().getOwnershipKind();
+
+  for (const Operand &Op : Ops.slice(Index + 1)) {
+    if (I->isTypeDependentOperand(Op))
+      continue;
+    auto OpKind = Op.get().getOwnershipKind();
+    if (OpKind.merge(ValueOwnershipKind::Trivial))
+      continue;
+
+    auto MergedValue = Base.merge(OpKind.Value);
+    if (!MergedValue.hasValue()) {
+      // If we have mismatched SILOwnership and sil ownership is not enabled,
+      // just return Any for staging purposes. If SILOwnership is enabled, then
+      // we must assert!
+      if (!I->getModule().getOptions().EnableSILOwnership) {
+        return ValueOwnershipKind::Any;
+      }
+      llvm_unreachable("Forwarding inst with mismatching ownership kinds?!");
+    }
+  }
+
+  return Base;
+}
+
+#define FORWARDING_OWNERSHIP_INST(INST)                                        \
+  ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst(          \
+      INST##Inst *I) {                                                         \
+    assert(I->hasValue() && "Expected to have a value");                       \
+    return visitForwardingInst(I);                                             \
+  }
+FORWARDING_OWNERSHIP_INST(BridgeObjectToRef)
+FORWARDING_OWNERSHIP_INST(ConvertFunction)
+FORWARDING_OWNERSHIP_INST(InitExistentialRef)
+FORWARDING_OWNERSHIP_INST(OpenExistentialRef)
+FORWARDING_OWNERSHIP_INST(OpenExistentialOpaque)
+FORWARDING_OWNERSHIP_INST(RefToBridgeObject)
+FORWARDING_OWNERSHIP_INST(SelectValue)
+FORWARDING_OWNERSHIP_INST(Struct)
+FORWARDING_OWNERSHIP_INST(Tuple)
+FORWARDING_OWNERSHIP_INST(UncheckedRefCast)
+FORWARDING_OWNERSHIP_INST(UnconditionalCheckedCast)
+FORWARDING_OWNERSHIP_INST(Upcast)
+FORWARDING_OWNERSHIP_INST(MarkUninitialized)
+FORWARDING_OWNERSHIP_INST(UncheckedEnumData)
+#undef FORWARDING_OWNERSHIP_INST
+
+ValueOwnershipKind
+ValueOwnershipKindClassifier::visitSelectEnumInst(SelectEnumInst *SEI) {
+  // We handle this specially, since a select enum forwards only its case
+  // values. We drop the first element since that is the condition element.
+  return visitForwardingInst(SEI, SEI->getAllOperands().drop_front());
+}
+
+ValueOwnershipKind ValueOwnershipKindClassifier::visitUncheckedBitwiseCastInst(
+    UncheckedBitwiseCastInst *UBCI) {
+  ValueOwnershipKind OpOwnership = UBCI->getOperand().getOwnershipKind();
+  bool ResultTypeIsTrivial = UBCI->getType().isTrivial(UBCI->getModule());
+
+  // First check if our operand has a trivial value ownership kind...
+  if (OpOwnership == ValueOwnershipKind::Trivial) {
+    // If we do have a trivial value ownership kind, see if our result type is
+    // trivial or non-trivial. If it is trivial, then we have trivial
+    // ownership. Otherwise, we have unowned ownership since from an ownership
+    // perspective, the value has instantaneously come into existence and
+    // nothing has taken ownership of it.
+    if (ResultTypeIsTrivial) {
+      return ValueOwnershipKind::Trivial;
+    }
+    return ValueOwnershipKind::Unowned;
+  }
+
+  // If our operand has non-trivial ownership, but our result does, then of
+  // course the result has trivial ownership.
+  if (ResultTypeIsTrivial) {
+    return ValueOwnershipKind::Trivial;
+  }
+
+  // Otherwise, we forward our ownership.
+  return visitForwardingInst(UBCI);
+}
+
+ValueOwnershipKind
+ValueOwnershipKindClassifier::visitUncheckedOwnershipConversionInst(
+    UncheckedOwnershipConversionInst *I) {
+  return I->getConversionOwnershipKind();
+}
+
+// An enum without payload is trivial. One with non-trivial payload is
+// forwarding.
+ValueOwnershipKind ValueOwnershipKindClassifier::visitEnumInst(EnumInst *EI) {
+  if (!EI->hasOperand())
+    return ValueOwnershipKind::Trivial;
+  return visitForwardingInst(EI);
+}
+
+ValueOwnershipKind ValueOwnershipKindClassifier::visitSILUndef(SILUndef *Arg) {
+  return ValueOwnershipKind::Any;
+}
+
+ValueOwnershipKind
+ValueOwnershipKindClassifier::visitSILPHIArgument(SILPHIArgument *Arg) {
+  return Arg->getOwnershipKind();
+}
+
+ValueOwnershipKind ValueOwnershipKindClassifier::visitSILFunctionArgument(
+    SILFunctionArgument *Arg) {
+  return Arg->getOwnershipKind();
+}
+
+// This is a forwarding instruction through only one of its arguments.
+ValueOwnershipKind
+ValueOwnershipKindClassifier::visitMarkDependenceInst(MarkDependenceInst *MDI) {
+  return MDI->getValue().getOwnershipKind();
+}
+
+ValueOwnershipKind ValueOwnershipKindClassifier::visitApplyInst(ApplyInst *AI) {
+  SILModule &M = AI->getModule();
+  bool IsTrivial = AI->getType().isTrivial(M);
+  SILFunctionConventions fnConv(AI->getSubstCalleeType(), M);
+  auto Results = fnConv.getDirectSILResults();
+  // No results => empty tuple result => Trivial.
+  if (Results.empty() || IsTrivial)
+    return ValueOwnershipKind::Trivial;
+
+  CanGenericSignature Sig = AI->getSubstCalleeType()->getGenericSignature();
+  // Find the first index where we have a trivial value.
+  auto Iter = find_if(Results, [&M, &Sig](const SILResultInfo &Info) -> bool {
+    return Info.getOwnershipKind(M, Sig) != ValueOwnershipKind::Trivial;
+  });
+  // If we have all trivial, then we must be trivial.
+  if (Iter == Results.end())
+    return ValueOwnershipKind::Trivial;
+
+  ValueOwnershipKind Base = Iter->getOwnershipKind(M, Sig);
+
+  for (const SILResultInfo &ResultInfo :
+       SILFunctionConventions::DirectSILResultRange(next(Iter),
+                                                    Results.end())) {
+    auto RKind = ResultInfo.getOwnershipKind(M, Sig);
+    if (RKind.merge(ValueOwnershipKind::Trivial))
+      continue;
+
+    auto MergedValue = Base.merge(RKind.Value);
+    if (!MergedValue.hasValue()) {
+      llvm_unreachable("Forwarding inst with mismatching ownership kinds?!");
+    }
+  }
+
+  return Base;
+}
+
+ValueOwnershipKind ValueOwnershipKindClassifier::visitLoadInst(LoadInst *LI) {
+  switch (LI->getOwnershipQualifier()) {
+  case LoadOwnershipQualifier::Take:
+  case LoadOwnershipQualifier::Copy:
+    return ValueOwnershipKind::Owned;
+  case LoadOwnershipQualifier::Unqualified:
+    return ValueOwnershipKind::Any;
+  case LoadOwnershipQualifier::Trivial:
+    return ValueOwnershipKind::Trivial;
+  }
+
+  llvm_unreachable("Unhandled LoadOwnershipQualifier in switch.");
+}
+
+//===----------------------------------------------------------------------===//
+//                   Builtin OwnershipValueKind Computation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+struct ValueOwnershipKindBuiltinVisitor
+    : SILBuiltinVisitor<ValueOwnershipKindBuiltinVisitor, ValueOwnershipKind> {
+
+  ValueOwnershipKind visitLLVMIntrinsic(BuiltinInst *BI,
+                                        llvm::Intrinsic::ID ID) {
+    // LLVM intrinsics do not traffic in ownership, so if we have a result, it
+    // must be trivial.
+    assert(BI->hasValue() && "Can only get here if we have a SILValue");
+    assert(BI->getType().isTrivial(BI->getModule()) &&
+           "LLVM intrinsics should always be trivial");
+    return ValueOwnershipKind::Trivial;
+  }
+
+#define BUILTIN(ID, NAME, ATTRS)                                               \
+  ValueOwnershipKind visit##ID(BuiltinInst *BI, StringRef Attr);
+#include "swift/AST/Builtins.def"
+};
+
+} // end anonymous namespace
+
+#define CONSTANT_OWNERSHIP_BUILTIN(OWNERSHIP, ID)                              \
+  ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID(              \
+      BuiltinInst *BI, StringRef Attr) {                                       \
+    assert(BI->hasValue() && "Expected to have type");                         \
+    if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) {        \
+      assert(BI->getType().isTrivial(BI->getModule()) &&                       \
+             "Only trivial types can have trivial ownership");                 \
+    } else {                                                                   \
+      assert(!BI->getType().isTrivial(BI->getModule()) &&                      \
+             "Only non trivial types can have non trivial ownership");         \
+    }                                                                          \
+    return ValueOwnershipKind::OWNERSHIP;                                      \
+  }
+CONSTANT_OWNERSHIP_BUILTIN(Owned, Take)
+CONSTANT_OWNERSHIP_BUILTIN(Owned, TryPin)
+// This returns a value at +1 that is destroyed strictly /after/ the
+// UnsafeGuaranteedEnd. This provides the guarantee that we want.
+CONSTANT_OWNERSHIP_BUILTIN(Owned, UnsafeGuaranteed)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, AShr)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Add)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, And)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, AssumeNonNegative)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, BitCast)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ExactSDiv)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ExactUDiv)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FAdd)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OEQ)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OGE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OGT)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OLE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OLT)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ONE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UEQ)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UGE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UGT)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ULE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ULT)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UNE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FDiv)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FMul)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FNeg)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPExt)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPToSI)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPToUI)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPTrunc)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FRem)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FSub)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_EQ)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_NE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SGE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SGT)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SLE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SLT)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_UGE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_UGT)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_ULE)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_ULT)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToPtr)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, LShr)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Load)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadRaw)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadInvariant)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Mul)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Or)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, PtrToInt)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SAddOver)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SDiv)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SExt)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SExtOrBitCast)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SIToFP)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SMulOver)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SRem)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SSubOver)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Shl)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Sub)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Trunc)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, TruncOrBitCast)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, UAddOver)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, UDiv)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, UIToFP)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, UMulOver)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, URem)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, USubOver)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Xor)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ZExt)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ZExtOrBitCast)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ORD)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UNO)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToUnknownObject)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastFromUnknownObject)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToNativeObject)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, UnsafeCastToNativeObject)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastFromNativeObject)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToBridgeObject)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastReferenceFromBridgeObject)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, CastBitPatternFromBridgeObject)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, BridgeToRawPointer)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, BridgeFromRawPointer)
+CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastReference)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, AddressOf)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, GepRaw)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Gep)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, GetTailAddr)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, OnFastPath)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique_native)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned_native)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, BindMemory)
+CONSTANT_OWNERSHIP_BUILTIN(Owned, AllocWithTailElems)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ProjectTailElems)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsOptionalType)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Sizeof)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Strideof)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsPOD)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Alignof)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, AllocRaw)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, AssertConf)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToSCheckedTrunc)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToSCheckedTrunc)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToUCheckedTrunc)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToUCheckedTrunc)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, SUCheckedConversion)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, USCheckedConversion)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToFPWithOverflow)
+
+// This is surprising, Builtin.unreachable returns a "Never" value which is
+// trivially typed.
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Unreachable)
+
+/// AtomicRMW has type (Builtin.RawPointer, T) -> T. But it provides overloads
+/// for integer or rawpointer, so it should be trivial.
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, AtomicRMW)
+
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, CondUnreachable)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, UnsafeGuaranteedEnd)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, GetObjCTypeEncoding)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, CanBeObjCClass)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, WillThrow)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, StaticReport)
+
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, DestroyArray)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, CopyArray)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, TakeArrayFrontToBack)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, TakeArrayBackToFront)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, UnexpectedError)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, ErrorInMain)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, DeallocRaw)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Fence)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Retain)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Release)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, CondFail)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, FixLifetime)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Autorelease)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Unpin)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Destroy)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Assign)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Init)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, AtomicStore)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Once)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, TSanInoutAccess)
+CONSTANT_OWNERSHIP_BUILTIN(Trivial, Swift3ImplicitObjCEntrypoint)
+
+#undef CONSTANT_OWNERSHIP_BUILTIN
+
+// Check all of these...
+#define UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ID)                             \
+  ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID(              \
+      BuiltinInst *BI, StringRef Attr) {                                       \
+    if (BI->getType().isTrivial(BI->getModule())) {                            \
+      return ValueOwnershipKind::Trivial;                                      \
+    }                                                                          \
+    return ValueOwnershipKind::Unowned;                                        \
+  }
+UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ReinterpretCast)
+UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(CmpXChg)
+UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(AtomicLoad)
+UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ExtractElement)
+UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(InsertElement)
+UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ZeroInitializer)
+#undef UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT
+
+ValueOwnershipKind
+ValueOwnershipKindClassifier::visitBuiltinInst(BuiltinInst *BI) {
+  // For now, just conservatively say builtins are None. We need to use a
+  // builtin in here to guarantee correctness.
+  return ValueOwnershipKindBuiltinVisitor().visit(BI);
+}
diff --git a/lib/SIL/ValueOwnershipKindClassifier.h b/lib/SIL/ValueOwnershipKindClassifier.h
new file mode 100644
index 0000000..7fe59a8
--- /dev/null
+++ b/lib/SIL/ValueOwnershipKindClassifier.h
@@ -0,0 +1,46 @@
+//===--- ValueOwnershipKindClassifier.h -----------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_SIL_VALUEOWNERSHIPKINDCLASSIFIER_H
+#define SWIFT_SIL_VALUEOWNERSHIPKINDCLASSIFIER_H
+
+#include "swift/SIL/SILVisitor.h"
+
+namespace swift {
+namespace sil {
+
+class ValueOwnershipKindClassifier
+    : public SILVisitor<ValueOwnershipKindClassifier, ValueOwnershipKind> {
+
+public:
+  ValueOwnershipKindClassifier() = default;
+  ~ValueOwnershipKindClassifier() = default;
+  ValueOwnershipKindClassifier(const ValueOwnershipKindClassifier &) = delete;
+  ValueOwnershipKindClassifier(ValueOwnershipKindClassifier &&) = delete;
+
+  ValueOwnershipKind visitForwardingInst(SILInstruction *I,
+                                         ArrayRef<Operand> Ops);
+  ValueOwnershipKind visitForwardingInst(SILInstruction *I) {
+    return visitForwardingInst(I, I->getAllOperands());
+  }
+
+  ValueOwnershipKind visitValueBase(ValueBase *V) {
+    llvm_unreachable("unimplemented method on ValueBaseOwnershipVisitor");
+  }
+#define VALUE(Id, Parent) ValueOwnershipKind visit##Id(Id *ID);
+#include "swift/SIL/SILNodes.def"
+};
+
+} // end namespace sil
+} // end namespace swift
+
+#endif
diff --git a/lib/SILGen/Cleanup.cpp b/lib/SILGen/Cleanup.cpp
index eaa1799..88e24bf 100644
--- a/lib/SILGen/Cleanup.cpp
+++ b/lib/SILGen/Cleanup.cpp
@@ -276,3 +276,9 @@
   llvm::errs() << "CLEANUP DEPTH: " << handle.getDepth() << "\n";
   stackCleanup.dump(SGF);
 }
+
+void CleanupManager::checkIterator(CleanupHandle handle) const {
+#ifndef NDEBUG
+  stack.checkIterator(handle);
+#endif
+}
diff --git a/lib/SILGen/Cleanup.h b/lib/SILGen/Cleanup.h
index 4ffd947..2c523b3 100644
--- a/lib/SILGen/Cleanup.h
+++ b/lib/SILGen/Cleanup.h
@@ -209,6 +209,9 @@
 
   /// Dump the given cleanup handle if it is on the current stack.
   void dump(CleanupHandle handle) const;
+
+  /// Verify that the given cleanup handle is valid.
+  void checkIterator(CleanupHandle handle) const;
 };
 
 /// An RAII object that allows the state of a cleanup to be
diff --git a/lib/SILGen/FormalEvaluation.cpp b/lib/SILGen/FormalEvaluation.cpp
index b14d0df..8c9fa5b 100644
--- a/lib/SILGen/FormalEvaluation.cpp
+++ b/lib/SILGen/FormalEvaluation.cpp
@@ -23,6 +23,26 @@
 
 void FormalAccess::_anchor() {}
 
+void FormalAccess::verify(SILGenFunction &SGF) const {
+#ifndef NDEBUG
+  // If this access was already finished, continue. This can happen if an
+  // owned formal access was forwarded.
+  if (isFinished()) {
+    assert(getKind() == FormalAccess::Owned &&
+           "Only owned formal accesses should be forwarded.");
+    // We can not check that our cleanup is actually dead since the cleanup
+    // may have been popped at this point and the stack may have new values.
+    return;
+  }
+
+  assert(!isFinished() && "Can not finish a formal access cleanup "
+         "twice");
+
+  // Now try to look up the cleanup handle of the formal access.
+  SGF.Cleanups.checkIterator(getCleanup());
+#endif
+}
+
 //===----------------------------------------------------------------------===//
 //                      Shared Borrow Formal Evaluation
 //===----------------------------------------------------------------------===//
@@ -141,6 +161,24 @@
   context.pop(savedDepth.getValue());
 }
 
+void FormalEvaluationScope::verify() const {
+  // Check to see if there is anything going on here.
+  auto &context = SGF.FormalEvalContext;
+  using iterator = FormalEvaluationContext::iterator;
+
+  iterator unwrappedSavedDepth = context.find(savedDepth.getValue());
+  iterator iter = context.begin();
+  if (iter == unwrappedSavedDepth)
+    return;
+
+  // Then working down the stack until we visit unwrappedSavedDepth...
+  for (; iter != unwrappedSavedDepth; ++iter) {
+    // Grab the next evaluation verify that we can successfully access this
+    // formal access.
+    (*iter).verify(SGF);
+  }
+}
+
 //===----------------------------------------------------------------------===//
 //                         Formal Evaluation Context
 //===----------------------------------------------------------------------===//
diff --git a/lib/SILGen/FormalEvaluation.h b/lib/SILGen/FormalEvaluation.h
index 66a0a51..92b6a8f 100644
--- a/lib/SILGen/FormalEvaluation.h
+++ b/lib/SILGen/FormalEvaluation.h
@@ -65,6 +65,8 @@
 
   bool isFinished() const { return finished; }
 
+  void verify(SILGenFunction &SGF) const;
+
 protected:
   virtual void finishImpl(SILGenFunction &SGF) = 0;
 };
@@ -202,6 +204,10 @@
   FormalEvaluationScope(FormalEvaluationScope &&o);
   FormalEvaluationScope &operator=(FormalEvaluationScope &&o) = delete;
 
+  /// Verify that we can successfully access all of the inner lexical scopes
+  /// that would be popped by this scope.
+  void verify() const;
+
 private:
   void popImpl();
 };
diff --git a/lib/SILGen/Initialization.h b/lib/SILGen/Initialization.h
index 1096c05..5a939b9 100644
--- a/lib/SILGen/Initialization.h
+++ b/lib/SILGen/Initialization.h
@@ -47,9 +47,9 @@
 ///
 /// This interface supports four ways to receive the initializing value:
 ///
-///   - If getAddressForInPlaceInitialization() returns non-null, the
-///     initializing value may be created directly in that location.
-///     It is legal to call getAddressForInPlaceInitialization()
+///   - If canPerformInPlaceInitialization() return true,
+///     getAddressForInPlaceInitialization may be called.
+///     It is not legal to call getAddressForInPlaceInitialization
 ///     multiple times.
 ///
 ///   - If canSplitIntoTupleElements() returns true, getTupleElements may
@@ -77,29 +77,26 @@
   Initialization() {}
   virtual ~Initialization() {}
 
-  /// Return true if this initialization is a simple address in memory.
-  virtual bool isSingleBuffer() const {
+  /// Return true if this initialization supports in-place initialization.
+  ///
+  /// This method must return consistently both before and after
+  /// initialization begins.
+  virtual bool canPerformInPlaceInitialization() const {
     return false;
   }
 
-   /// If this initialization represents a single contiguous buffer, return the
-  /// SILValue of that buffer's address. If not, returns an invalid SILValue.
-  virtual SILValue getAddressOrNull() const = 0;
-  
-  /// Returns the address of the single contiguous buffer represented by this
-  /// initialization. Once the address has been stored to,
-  /// finishInitialization must be called.
-  SILValue getAddress() const {
-    SILValue address = getAddressOrNull();
-    assert(address && "initialization does not represent a single buffer");
-    return address;
+  /// A hack that should be removed relating to the initialization of
+  /// global values.
+  virtual bool isInPlaceInitializationOfGlobal() const {
+    llvm_unreachable("didn't implement isInPlaceInitializationOfGlobal");
   }
   
-  
-  /// If this initialization has an address we can directly emit into, return
-  /// it.  Otherwise, return a null SILValue.
-  virtual SILValue getAddressForInPlaceInitialization() const {
-    return SILValue();
+  /// Begin an in-place initialization, given that
+  /// canPerformInPlaceInitialization() returned true.
+  virtual SILValue
+  getAddressForInPlaceInitialization(SILGenFunction &SGF, SILLocation loc) {
+    llvm_unreachable("Must implement if getAddressForInPlaceInitialization "
+                     "returns true");
   }
   
   /// Return true if we can get the addresses of elements with the
@@ -165,14 +162,15 @@
 public:
   SingleBufferInitialization() {}
   
-  bool isSingleBuffer() const override {
+  bool canPerformInPlaceInitialization() const override {
     return true;
   }
 
-  // SingleBufferInitializations always have an address.
-  SILValue getAddressForInPlaceInitialization() const override {
-    return getAddress();
-  }
+  // SingleBufferInitializations must always implement this method.
+  SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+                                              SILLocation loc) override = 0;
+
+  bool isInPlaceInitializationOfGlobal() const override = 0;
   
   bool canSplitIntoTupleElements() const override {
     return true;
@@ -184,7 +182,8 @@
 
   void copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,
                            ManagedValue value, bool isInit) override {
-    copyOrInitValueIntoSingleBuffer(SGF, loc, value, isInit, getAddress());
+    auto address = getAddressForInPlaceInitialization(SGF, loc);
+    copyOrInitValueIntoSingleBuffer(SGF, loc, value, isInit, address);
   }
 
   /// Overriders must call this.
@@ -209,14 +208,20 @@
   /// The physical address of the global.
   SILValue address;
   
-  virtual void anchor() const;
 public:
   KnownAddressInitialization(SILValue address) : address(address) {}
   
-  SILValue getAddressOrNull() const override {
+  SILValue getAddress() const {
     return address;
   }
 
+  SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+                                              SILLocation loc) override {
+    return address;
+  }
+
+  bool isInPlaceInitializationOfGlobal() const override;
+
   void finishUninitialized(SILGenFunction &SGF) override {}
 };
 
@@ -234,7 +239,8 @@
     TemporaryInitialization::finishInitialization(SGF);
   }
 
-  SILValue getAddressOrNull() const override {
+  SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+                                              SILLocation loc) override {
     return Addr;
   }
 
@@ -242,6 +248,8 @@
     return Addr;
   }
 
+  bool isInPlaceInitializationOfGlobal() const override;
+
   /// Returns the cleanup corresponding to the value of the temporary.
   CleanupHandle getInitializedCleanup() const { return Cleanup; }
 
@@ -260,14 +268,7 @@
   SmallVector<InitializationPtr, 4> SubInitializations;
     
   TupleInitialization() {}
-    
-  SILValue getAddressOrNull() const override {
-    if (SubInitializations.size() == 1)
-      return SubInitializations[0]->getAddressOrNull();
-    else
-      return SILValue();
-  }
-    
+
   bool canSplitIntoTupleElements() const override {
     return true;
   }
diff --git a/lib/SILGen/LValue.h b/lib/SILGen/LValue.h
index 494edbf..b5cc235 100644
--- a/lib/SILGen/LValue.h
+++ b/lib/SILGen/LValue.h
@@ -343,6 +343,7 @@
                          CanType substFormalType);
 
   static LValue forAddress(ManagedValue address,
+                           Optional<SILAccessEnforcement> enforcement,
                            AbstractionPattern origFormalType,
                            CanType substFormalType);
 
diff --git a/lib/SILGen/RValue.cpp b/lib/SILGen/RValue.cpp
index b5b7425..f33eeba 100644
--- a/lib/SILGen/RValue.cpp
+++ b/lib/SILGen/RValue.cpp
@@ -365,13 +365,12 @@
   
   bool implodeTuple = false;
 
-  if (auto Address = init->getAddressOrNull()) {
-    if (isa<GlobalAddrInst>(Address) &&
-        SGF.getTypeLowering(type).getLoweredType().isTrivial(SGF.SGM.M)) {
-      // Implode tuples in initialization of globals if they are
-      // of trivial types.
-      implodeTuple = true;
-    }
+  if (init->canPerformInPlaceInitialization() &&
+      init->isInPlaceInitializationOfGlobal() &&
+      SGF.getTypeLowering(type).getLoweredType().isTrivial(SGF.SGM.M)) {
+    // Implode tuples in initialization of globals if they are
+    // of trivial types.
+    implodeTuple = true;
   }
   
   // If we can satisfy the tuple type by breaking up the aggregate
diff --git a/lib/SILGen/ResultPlan.cpp b/lib/SILGen/ResultPlan.cpp
index 6ee2a47..53eb0e7 100644
--- a/lib/SILGen/ResultPlan.cpp
+++ b/lib/SILGen/ResultPlan.cpp
@@ -40,8 +40,9 @@
     return RValue();
   }
   void
-  gatherIndirectResultAddrs(SmallVectorImpl<SILValue> &outList) const override {
-    outList.emplace_back(init->getAddressForInPlaceInitialization());
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const override {
+    outList.emplace_back(init->getAddressForInPlaceInitialization(SGF, loc));
   }
 };
 
@@ -122,7 +123,8 @@
   }
 
   void
-  gatherIndirectResultAddrs(SmallVectorImpl<SILValue> &outList) const override {
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const override {
     if (!temporary)
       return;
     outList.emplace_back(temporary->getAddress());
@@ -157,8 +159,9 @@
   }
 
   void
-  gatherIndirectResultAddrs(SmallVectorImpl<SILValue> &outList) const override {
-    subPlan->gatherIndirectResultAddrs(outList);
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const override {
+    subPlan->gatherIndirectResultAddrs(SGF, loc, outList);
   }
 };
 
@@ -184,8 +187,9 @@
   }
 
   void
-  gatherIndirectResultAddrs(SmallVectorImpl<SILValue> &outList) const override {
-    subPlan->gatherIndirectResultAddrs(outList);
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const override {
+    subPlan->gatherIndirectResultAddrs(SGF, loc, outList);
   }
 };
 
@@ -223,9 +227,10 @@
   }
 
   void
-  gatherIndirectResultAddrs(SmallVectorImpl<SILValue> &outList) const override {
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const override {
     for (const auto &eltPlan : eltPlans) {
-      eltPlan->gatherIndirectResultAddrs(outList);
+      eltPlan->gatherIndirectResultAddrs(SGF, loc, outList);
     }
   }
 };
@@ -275,9 +280,10 @@
   }
 
   void
-  gatherIndirectResultAddrs(SmallVectorImpl<SILValue> &outList) const override {
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const override {
     for (const auto &eltPlan : eltPlans) {
-      eltPlan->gatherIndirectResultAddrs(outList);
+      eltPlan->gatherIndirectResultAddrs(SGF, loc, outList);
     }
   }
 };
@@ -324,6 +330,7 @@
 
     // Create the appropriate pointer type.
     lvalue = LValue::forAddress(ManagedValue::forLValue(errorTemp),
+                                /*TODO: enforcement*/ None,
                                 AbstractionPattern(errorType), errorType);
   }
 
@@ -333,8 +340,9 @@
   }
 
   void
-  gatherIndirectResultAddrs(SmallVectorImpl<SILValue> &outList) const override {
-    subPlan->gatherIndirectResultAddrs(outList);
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const override {
+    subPlan->gatherIndirectResultAddrs(SGF, loc, outList);
   }
 
   Optional<std::pair<ManagedValue, ManagedValue>>
@@ -421,17 +429,13 @@
   // Otherwise, grab the next result.
   auto result = allResults.pop_back_val();
 
-  SILValue initAddr;
-  if (init) {
-    initAddr = init->getAddressForInPlaceInitialization();
-
-    // If the result is indirect, and we have an address to emit into, and
-    // there are no abstraction differences, then just do it.
-    if (initAddr && SGF.silConv.isSILIndirect(result) &&
-        !initAddr->getType().hasAbstractionDifference(
+  // If the result is indirect, and we have an address to emit into, and
+  // there are no abstraction differences, then just do it.
+  if (init && init->canPerformInPlaceInitialization() &&
+      SGF.silConv.isSILIndirect(result) &&
+      !SGF.getLoweredType(substType).getAddressType().hasAbstractionDifference(
             calleeTypeInfo.getOverrideRep(), result.getSILStorageType())) {
-      return ResultPlanPtr(new InPlaceInitializationResultPlan(init));
-    }
+    return ResultPlanPtr(new InPlaceInitializationResultPlan(init));
   }
 
   // Otherwise, we need to:
diff --git a/lib/SILGen/ResultPlan.h b/lib/SILGen/ResultPlan.h
index e2f0cb5..0a72d6e 100644
--- a/lib/SILGen/ResultPlan.h
+++ b/lib/SILGen/ResultPlan.h
@@ -42,7 +42,8 @@
   virtual ~ResultPlan() = default;
 
   virtual void
-  gatherIndirectResultAddrs(SmallVectorImpl<SILValue> &outList) const = 0;
+  gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
+                            SmallVectorImpl<SILValue> &outList) const = 0;
 
   virtual Optional<std::pair<ManagedValue, ManagedValue>>
   emitForeignErrorArgument(SILGenFunction &SGF, SILLocation loc) {
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index d603cd1..4a57124 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -927,7 +927,12 @@
   emitOrDelayFunction(*this, constant, [this,constant,arg](SILFunction *f) {
     preEmitFunction(constant, arg, f, arg);
     PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f);
-    SILGenFunction(*this, *f).emitGeneratorFunction(constant, arg);
+    SILGenFunction SGF(*this, *f);
+    // Override location for #file, #line etc. to an invalid one so that we
+    // don't put extra strings into the default argument generator function that
+    // is not going to be ever used anyway.
+    SGF.overrideLocationForMagicIdentifiers = SourceLoc();
+    SGF.emitGeneratorFunction(constant, arg);
     postEmitFunction(constant, f);
   });
 }
@@ -1405,7 +1410,8 @@
     DC = mod;
   }
 
-  std::unique_ptr<SILModule> M(new SILModule(mod, options, DC, isWholeModule));
+  std::unique_ptr<SILModule> M(
+      new SILModule(mod, options, DC, isWholeModule, makeModuleFragile));
   SILGenModule SGM(*M, mod, makeModuleFragile);
 
   if (SF) {
diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h
index d8beee5..eaf6b3b 100644
--- a/lib/SILGen/SILGen.h
+++ b/lib/SILGen/SILGen.h
@@ -317,6 +317,7 @@
   /// Emit a protocol witness entry point.
   SILFunction *emitProtocolWitness(ProtocolConformance *conformance,
                                    SILLinkage linkage,
+                                   IsSerialized_t isSerialized,
                                    SILDeclRef requirement,
                                    SILDeclRef witnessRef,
                                    IsFreeFunctionWitness_t isFree,
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 562b199..12fa88b 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -645,8 +645,8 @@
       // Be sure not to consume the cleanup for an inout argument.
       auto selfLV = ManagedValue::forLValue(address.getValue());
       selfValue = ArgumentSource(loc,
-                    LValue::forAddress(selfLV, AbstractionPattern(formalTy),
-                                       formalTy));
+                    LValue::forAddress(selfLV, None,
+                                       AbstractionPattern(formalTy), formalTy));
     } else {
       selfValue = ArgumentSource(loc, RValue(SGF, loc, formalTy, address));
     }
@@ -1705,7 +1705,7 @@
 
   // Create the result plan.
   SmallVector<SILValue, 4> indirectResultAddrs;
-  resultPlan->gatherIndirectResultAddrs(indirectResultAddrs);
+  resultPlan->gatherIndirectResultAddrs(*this, loc, indirectResultAddrs);
 
   // If the function returns an inner pointer, we'll need to lifetime-extend
   // the 'self' parameter.
@@ -1744,12 +1744,8 @@
   }
 
   // If there's a foreign error parameter, fill it in.
-  Optional<FormalEvaluationScope> errorTempWriteback;
   ManagedValue errorTemp;
   if (auto foreignError = calleeTypeInfo.foreignError) {
-    // Error-temporary emission may need writeback.
-    errorTempWriteback.emplace(*this);
-
     unsigned errorParamIndex =
         calleeTypeInfo.foreignError->getErrorParameterIndex();
 
@@ -1850,9 +1846,6 @@
   // TODO: maybe this should happen after managing the result if it's
   // not a result-checking convention?
   if (auto foreignError = calleeTypeInfo.foreignError) {
-    // Force immediate writeback to the error temporary.
-    errorTempWriteback.reset();
-
     bool doesNotThrow = (options & ApplyOptions::DoesNotThrow);
     emitForeignErrorCheck(loc, directResults, errorTemp,
                           doesNotThrow, *foreignError);
@@ -1960,7 +1953,7 @@
 
   llvm_unreachable("ran out of null arguments before we ran out of inouts");
 
- done:
+done:
 
   // Check to see if we have multiple inout arguments which obviously
   // alias.  Note that we could do this in a later SILDiagnostics pass
@@ -2507,7 +2500,7 @@
             .getAsSingleValue(SGF, arg.getKnownRValueLocation());
           assert(address.isLValue());
           auto substObjectType = cast<InOutType>(substType).getObjectType();
-          return LValue::forAddress(address,
+          return LValue::forAddress(address, None,
                                     AbstractionPattern(substObjectType),
                                     substObjectType);
         } else {
@@ -3265,10 +3258,15 @@
         SGF.Cleanups.setCleanupState(initCleanup, CleanupState::Active);
   }
 
-  SILValue getAddressOrNull() const override {
+  SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+                                              SILLocation loc) override {
     return addr;
   }
 
+  bool isInPlaceInitializationOfGlobal() const override {
+    return false;
+  }
+
   ManagedValue getManagedBox() const {
     return ManagedValue(box, initCleanup);
   }
@@ -3644,6 +3642,8 @@
     }
 
     RValue apply(SGFContext C = SGFContext()) {
+      initialWritebackScope.verify();
+
       assert(!applied && "already applied!");
 
       applied = true;
@@ -3664,12 +3664,12 @@
                                 foreignError, foreignSelf, uncurryLevel, C);
 
       // End of the initial writeback scope.
+      initialWritebackScope.verify();
       initialWritebackScope.pop();
 
       // Then handle the remaining call sites.
       result = applyRemainingCallSites(std::move(result), formalType,
                                        foreignSelf, foreignError, C);
-
       return result;
     }
 
@@ -4231,9 +4231,10 @@
                         apply.AssumedPlusZeroSelf);
 
   // Apply 'self' if provided.
-  if (apply.SelfParam)
+  if (apply.SelfParam) {
     emission.addCallSite(RegularLocation(e), std::move(apply.SelfParam),
                          apply.SelfType->getCanonicalType(), /*throws*/ false);
+  }
 
   // Apply arguments from call sites, innermost to outermost.
   for (auto site = apply.CallSites.rbegin(), end = apply.CallSites.rend();
@@ -4246,7 +4247,8 @@
 }
 
 RValue SILGenFunction::emitApplyExpr(Expr *e, SGFContext c) {
-  return prepareApplyExpr(*this, e).apply(c);
+  CallEmission emission = prepareApplyExpr(*this, e);
+  return emission.apply(c);
 }
 
 RValue
@@ -4738,7 +4740,7 @@
     // FIXME: this assumes that there's never meaningful reabstraction of self
     // arguments.
     return ArgumentSource(
-        loc, LValue::forAddress(base, AbstractionPattern(baseFormalType),
+        loc, LValue::forAddress(base, None, AbstractionPattern(baseFormalType),
                                 baseFormalType));
   }
 
@@ -4785,7 +4787,8 @@
       // Drop the cleanup if we have one.
       auto baseLV = ManagedValue::forLValue(base.getValue());
       return ArgumentSource(
-          loc, LValue::forAddress(baseLV, AbstractionPattern(baseFormalType),
+          loc, LValue::forAddress(baseLV, None,
+                                  AbstractionPattern(baseFormalType),
                                   baseFormalType));
     }
   }
diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp
index 52020f0..927c779 100644
--- a/lib/SILGen/SILGenBridging.cpp
+++ b/lib/SILGen/SILGenBridging.cpp
@@ -51,8 +51,7 @@
   auto objcTypeReq = SGF.SGM.getBridgedObjectiveCTypeRequirement(loc);
   if (!objcTypeReq) return None;
 
-  Type objcType =
-      conformance->getTypeWitness(objcTypeReq, nullptr).getReplacement();
+  Type objcType = conformance->getTypeWitness(objcTypeReq, nullptr);
   assert(objcType);
 
   // Create a reference to the witness.
@@ -1031,6 +1030,29 @@
         emitTemporaryAllocation(loc, substConv.getSingleSILResultType()));
   }
 
+  // If the '@objc' was inferred due to deprecated rules,
+  // emit a Builtin.swift3ImplicitObjCEntrypoint().
+  //
+  // However, don't do so for 'dynamic' members, which must use Objective-C
+  // dispatch and therefore create many false positives.
+  if (thunk.hasDecl()) {
+    auto decl = thunk.getDecl();
+
+    // For an accessor, look at the storage declaration's attributes.
+    if (auto func = dyn_cast<FuncDecl>(decl)) {
+      if (func->isAccessor())
+        decl = func->getAccessorStorageDecl();
+    }
+
+    if (auto attr = decl->getAttrs().getAttribute<ObjCAttr>()) {
+      if (attr->isSwift3Inferred() &&
+          !decl->getAttrs().hasAttribute<DynamicAttr>()) {
+        B.createBuiltin(loc, getASTContext().getIdentifier("swift3ImplicitObjCEntrypoint"),
+            getModule().Types.getEmptyTupleType(), { }, { });
+      }
+    }
+  }
+
   // Now, enter a cleanup used for bridging the arguments. Note that if we
   // have an indirect result, it must be outside of this scope, otherwise
   // we will deallocate it too early.
diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp
index 03cead5..4c69ab8 100644
--- a/lib/SILGen/SILGenBuilder.cpp
+++ b/lib/SILGen/SILGenBuilder.cpp
@@ -209,7 +209,7 @@
 
 ManagedValue SILGenBuilder::createCopyValue(SILLocation loc,
                                             ManagedValue originalValue) {
-  auto &lowering = getFunction().getTypeLowering(originalValue.getType());
+  auto &lowering = SGF.getTypeLowering(originalValue.getType());
   return createCopyValue(loc, originalValue, lowering);
 }
 
@@ -314,7 +314,7 @@
 
 ManagedValue SILGenBuilder::createLoadBorrow(SILLocation loc,
                                              ManagedValue base) {
-  if (getFunction().getTypeLowering(base.getType()).isTrivial()) {
+  if (SGF.getTypeLowering(base.getType()).isTrivial()) {
     auto *i = SILBuilder::createLoad(loc, base.getValue(),
                                      LoadOwnershipQualifier::Trivial);
     return ManagedValue::forUnmanaged(i);
@@ -326,7 +326,7 @@
 
 ManagedValue SILGenBuilder::createFormalAccessLoadBorrow(SILLocation loc,
                                                          ManagedValue base) {
-  if (getFunction().getTypeLowering(base.getType()).isTrivial()) {
+  if (SGF.getTypeLowering(base.getType()).isTrivial()) {
     auto *i = SILBuilder::createLoad(loc, base.getValue(),
                                      LoadOwnershipQualifier::Trivial);
     return ManagedValue::forUnmanaged(i);
@@ -342,7 +342,7 @@
 SILGenBuilder::createFormalAccessCopyValue(SILLocation loc,
                                            ManagedValue originalValue) {
   SILType ty = originalValue.getType();
-  const auto &lowering = getFunction().getTypeLowering(ty);
+  const auto &lowering = SGF.getTypeLowering(ty);
   if (lowering.isTrivial())
     return originalValue;
 
@@ -372,7 +372,7 @@
     SGFContext context, std::function<void (SILValue)> rvalueEmitter) {
   // If we have a single-buffer "emit into" initialization, use that for the
   // result.
-  SILValue address = context.getAddressForInPlaceInitialization();
+  SILValue address = context.getAddressForInPlaceInitialization(SGF, loc);
 
   // If we couldn't emit into the Initialization, emit into a temporary
   // allocation.
@@ -384,8 +384,7 @@
 
   // If we have a single-buffer "emit into" initialization, use that for the
   // result.
-  if (context.getAddressForInPlaceInitialization()) {
-    context.getEmitInto()->finishInitialization(SGF);
+  if (context.finishInPlaceInitialization(SGF)) {
     return ManagedValue::forInContext();
   }
 
@@ -402,7 +401,7 @@
     SGFContext context, std::function<void(SILValue)> rvalueEmitter) {
   // If we have a single-buffer "emit into" initialization, use that for the
   // result.
-  SILValue address = context.getAddressForInPlaceInitialization();
+  SILValue address = context.getAddressForInPlaceInitialization(SGF, loc);
 
   // If we couldn't emit into the Initialization, emit into a temporary
   // allocation.
@@ -414,8 +413,7 @@
 
   // If we have a single-buffer "emit into" initialization, use that for the
   // result.
-  if (context.getAddressForInPlaceInitialization()) {
-    context.getEmitInto()->finishInitialization(SGF);
+  if (context.finishInPlaceInitialization(SGF)) {
     return ManagedValue::forInContext();
   }
 
@@ -460,7 +458,7 @@
 }
 
 ManagedValue SILGenBuilder::createLoadTake(SILLocation loc, ManagedValue v) {
-  auto &lowering = getFunction().getTypeLowering(v.getType());
+  auto &lowering = SGF.getTypeLowering(v.getType());
   return createLoadTake(loc, v, lowering);
 }
 
@@ -476,7 +474,7 @@
 }
 
 ManagedValue SILGenBuilder::createLoadCopy(SILLocation loc, ManagedValue v) {
-  auto &lowering = getFunction().getTypeLowering(v.getType());
+  auto &lowering = SGF.getTypeLowering(v.getType());
   return createLoadCopy(loc, v, lowering);
 }
 
@@ -575,7 +573,7 @@
 ManagedValue SILGenBuilder::createOptionalSome(SILLocation loc,
                                                ManagedValue arg) {
   CleanupCloner cloner(*this, arg);
-  auto &argTL = getFunction().getTypeLowering(arg.getType());
+  auto &argTL = SGF.getTypeLowering(arg.getType());
   SILType optionalType = arg.getType().wrapAnyOptionalType(getFunction());
   if (argTL.isLoadable() || !SGF.silConv.useLoweredAddresses()) {
     SILValue someValue =
@@ -588,7 +586,7 @@
   ArgumentSource argValue(loc, std::move(rvalue));
   SGF.emitInjectOptionalValueInto(
       loc, std::move(argValue), tempResult,
-      getFunction().getTypeLowering(tempResult->getType()));
+      SGF.getTypeLowering(tempResult->getType()));
   return ManagedValue::forUnmanaged(tempResult);
 }
 
@@ -601,7 +599,7 @@
 
   SILValue tempResult = SGF.emitTemporaryAllocation(loc, type);
   SGF.emitInjectOptionalNothingInto(loc, tempResult,
-                                    SGF.F.getTypeLowering(type));
+                                    SGF.getTypeLowering(type));
   return ManagedValue::forUnmanaged(tempResult);
 }
 
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index 8933d00..5d17ebf 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -309,7 +309,7 @@
   assert(noOptResultTy);
 
   // Create a temporary for the output optional.
-  auto &resultTL = F.getTypeLowering(resultTy);
+  auto &resultTL = getTypeLowering(resultTy);
 
   // If the result is address-only, we need to return something in memory,
   // otherwise the result is the BBArgument in the merge point.
@@ -329,7 +329,7 @@
         // transforming the underlying type instead of the optional type. This
         // ensures that we use the more efficient non-generic code paths when
         // possible.
-        if (F.getTypeLowering(input.getType()).isAddressOnly() &&
+        if (getTypeLowering(input.getType()).isAddressOnly() &&
             silConv.useLoweredAddresses()) {
           auto *someDecl = B.getASTContext().getOptionalSomeDecl();
           input = B.createUncheckedTakeEnumDataAddr(
@@ -695,7 +695,7 @@
                                             *this));
           ManagedValue mv = F(SGFContext(init.get()));
           if (!mv.isInContext()) {
-            mv.forwardInto(*this, loc, init->getAddress());
+            init->copyOrInitValueInto(*this, loc, mv, /*init*/ true);
             init->finishInitialization(*this);
           }
         });
@@ -888,14 +888,12 @@
     return entry.Value;
   }
 
-  // If the context wants us to initialize a buffer, copy there instead
+  // If the context has an initialization a buffer, copy there instead
   // of making a temporary allocation.
   if (auto I = C.getEmitInto()) {
-    if (SILValue address = I->getAddressForInPlaceInitialization()) {
-      entry.Value.copyInto(*this, address, loc);
-      I->finishInitialization(*this);
-      return ManagedValue::forInContext();
-    }
+    I->copyOrInitValueInto(*this, loc, entry.Value, /*init*/ false);
+    I->finishInitialization(*this);
+    return ManagedValue::forInContext();
   }
 
   // Otherwise, copy the value into a temporary.
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index 7818ed2..3da5b9c 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -17,13 +17,9 @@
 #include "Scope.h"
 #include "SwitchCaseFullExpr.h"
 #include "swift/AST/ASTMangler.h"
-#include "swift/AST/ASTMangler.h"
 #include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/Module.h"
-#include "swift/AST/Module.h"
 #include "swift/AST/NameLookup.h"
-#include "swift/AST/NameLookup.h"
-#include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/ProtocolConformance.h"
 #include "swift/SIL/FormalLinkage.h"
 #include "swift/SIL/PrettyStackTrace.h"
@@ -48,8 +44,6 @@
   public:
     BlackHoleInitialization() {}
 
-    SILValue getAddressOrNull() const override { return SILValue(); }
-
     bool canSplitIntoTupleElements() const override {
       return true;
     }
@@ -162,8 +156,9 @@
 splitIntoTupleElements(SILGenFunction &gen, SILLocation loc, CanType type,
                        SmallVectorImpl<InitializationPtr> &buf) {
   assert(SplitCleanups.empty() && "getting sub-initializations twice?");
-  return splitSingleBufferIntoTupleElements(gen, loc, type, getAddress(), buf,
-                                            SplitCleanups);
+  auto address = getAddressForInPlaceInitialization(gen, loc);
+  return splitSingleBufferIntoTupleElements(gen, loc, type, address,
+                                            buf, SplitCleanups);
 }
 
 MutableArrayRef<InitializationPtr>
@@ -218,7 +213,12 @@
     gen.Cleanups.forwardCleanup(eltCleanup);
 }
 
-void KnownAddressInitialization::anchor() const {
+bool KnownAddressInitialization::isInPlaceInitializationOfGlobal() const {
+  return isa<GlobalAddrInst>(address);
+}
+
+bool TemporaryInitialization::isInPlaceInitializationOfGlobal() const {
+  return isa<GlobalAddrInst>(Addr);
 }
 
 void TemporaryInitialization::finishInitialization(SILGenFunction &gen) {
@@ -412,9 +412,18 @@
     assert(DidFinish && "did not call VarInit::finishInitialization!");
   }
 
-  SILValue getAddressOrNull() const override {
+  SILValue getAddress() const {
     assert(SGF.VarLocs.count(decl) && "did not emit var?!");
-    return SGF.VarLocs[decl].value;
+    return SGF.VarLocs[decl].value;    
+  }
+
+  SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+                                              SILLocation loc) override {
+    return getAddress();
+  }
+
+  bool isInPlaceInitializationOfGlobal() const override {
+    return isa<GlobalAddrInst>(getAddress());
   }
 
   void finishUninitialized(SILGenFunction &gen) override {
@@ -503,13 +512,21 @@
   }
 
   bool hasAddress() const { return (bool)address; }
+
+  bool canPerformInPlaceInitialization() const override {
+    return hasAddress();
+  }
+
+  bool isInPlaceInitializationOfGlobal() const override {
+    return isa<GlobalAddrInst>(address);
+  }
   
-  // SingleBufferInitializations always have an address.
-  SILValue getAddressForInPlaceInitialization() const override {
+  SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+                                              SILLocation loc) override {
     // Emit into the buffer that 'let's produce for address-only values if
     // we have it.
-    if (hasAddress()) return address;
-    return SILValue();
+    assert(hasAddress());
+    return address;
   }
 
   /// Return true if we can get the addresses of elements with the
@@ -526,15 +543,12 @@
   splitIntoTupleElements(SILGenFunction &gen, SILLocation loc, CanType type,
                          SmallVectorImpl<InitializationPtr> &buf) override {
     assert(SplitCleanups.empty());
+    auto address = getAddressForInPlaceInitialization(gen, loc);
     return SingleBufferInitialization
-       ::splitSingleBufferIntoTupleElements(gen, loc, type, getAddress(), buf,
+       ::splitSingleBufferIntoTupleElements(gen, loc, type, address, buf,
                                             SplitCleanups);
   }
 
-  SILValue getAddressOrNull() const override {
-    return address;
-  }
-
   void bindValue(SILValue value, SILGenFunction &gen) {
     assert(!gen.VarLocs.count(vd) && "Already emitted this vardecl?");
     // If we're binding an address to this let value, then we can use it as an
@@ -560,7 +574,7 @@
     // buffer value.
     if (hasAddress())
       return SingleBufferInitialization::
-        copyOrInitValueIntoSingleBuffer(gen, loc, value, isInit, getAddress());
+        copyOrInitValueIntoSingleBuffer(gen, loc, value, isInit, address);
     
     // Otherwise, we bind the value.
     if (isInit) {
@@ -605,19 +619,19 @@
   InitializationPtr VarInit;
 public:
   ReferenceStorageInitialization(InitializationPtr &&subInit)
-    : VarInit(std::move(subInit)) {}
-
-  SILValue getAddressOrNull() const override { return SILValue(); }
-
+    : VarInit(std::move(subInit)) {
+    assert(VarInit->canPerformInPlaceInitialization());
+  }
 
   void copyOrInitValueInto(SILGenFunction &gen, SILLocation loc,
                            ManagedValue value, bool isInit) override {
+    auto address = VarInit->getAddressForInPlaceInitialization(gen, loc);
     // If this is not an initialization, copy the value before we translateIt,
     // translation expects a +1 value.
     if (isInit)
-      value.forwardInto(gen, loc, VarInit->getAddress());
+      value.forwardInto(gen, loc, address);
     else
-      value.copyInto(gen, VarInit->getAddress(), loc);
+      value.copyInto(gen, address, loc);
   }
 
   void finishUninitialized(SILGenFunction &gen) override {
@@ -644,8 +658,6 @@
 
   JumpDest getFailureDest() const { return failureDest; }
 
-  SILValue getAddressOrNull() const override { return SILValue(); }
-
   void copyOrInitValueInto(SILGenFunction &gen, SILLocation loc,
                            ManagedValue value, bool isInit) override = 0;
 
@@ -1467,7 +1479,7 @@
 SILGenFunction::emitFormalAccessManagedBufferWithCleanup(SILLocation loc,
                                                          SILValue addr) {
   assert(InWritebackScope && "Must be in formal evaluation scope");
-  auto &lowering = F.getTypeLowering(addr->getType());
+  auto &lowering = getTypeLowering(addr->getType());
   if (lowering.isTrivial())
     return ManagedValue::forUnmanaged(addr);
 
@@ -1482,7 +1494,7 @@
 SILGenFunction::emitFormalAccessManagedRValueWithCleanup(SILLocation loc,
                                                          SILValue value) {
   assert(InWritebackScope && "Must be in formal evaluation scope");
-  auto &lowering = F.getTypeLowering(value->getType());
+  auto &lowering = getTypeLowering(value->getType());
   if (lowering.isTrivial())
     return ManagedValue::forUnmanaged(value);
 
diff --git a/lib/SILGen/SILGenDestructor.cpp b/lib/SILGen/SILGenDestructor.cpp
index 94fab0d..afa484c 100644
--- a/lib/SILGen/SILGenDestructor.cpp
+++ b/lib/SILGen/SILGenDestructor.cpp
@@ -150,7 +150,7 @@
   //
   // This means that the lifetime of self can not be modeled statically in a
   // deallocating deinit without analyzing the body of the destroying deinit
-  // (something that violates semantic sil). Thus we add an artifical destroy of
+  // (something that violates semantic sil). Thus we add an artificial destroy of
   // self before the actual destroy of self so that the verifier can understand
   // that self is being properly balanced.
   B.createEndLifetime(loc, initialSelfValue);
diff --git a/lib/SILGen/SILGenDynamicCast.cpp b/lib/SILGen/SILGenDynamicCast.cpp
index baf1c31..3b60443 100644
--- a/lib/SILGen/SILGenDynamicCast.cpp
+++ b/lib/SILGen/SILGenDynamicCast.cpp
@@ -224,11 +224,8 @@
                                         const TypeLowering &origTargetTL,
                                         SGFContext ctx) {
       if (!hasAbstraction) {
-        if (auto emitInto = ctx.getEmitInto()) {
-          if (SILValue addr = emitInto->getAddressOrNull()) {
-            return addr;
-          }
-        }
+        if (auto address = ctx.getAddressForInPlaceInitialization(SGF, Loc))
+          return address;
       }
 
       return SGF.emitTemporaryAllocation(Loc, origTargetTL.getLoweredType());
@@ -239,12 +236,8 @@
                                         const TypeLowering &origTargetTL,
                                         SGFContext ctx) {
       if (!hasAbstraction) {
-        if (auto emitInto = ctx.getEmitInto()) {
-          if (emitInto->getAddressOrNull()) {
-            emitInto->finishInitialization(SGF);
-            return ManagedValue::forInContext();
-          }
-        }
+        if (ctx.finishInPlaceInitialization(SGF))
+          return ManagedValue::forInContext();
       }
 
       ManagedValue result;
@@ -481,12 +474,11 @@
     SILValue createAbstractResultBuffer(bool hasAbstraction,
                                         const TypeLowering &origTargetTL,
                                         SGFContext ctx) {
+      // Note that the conditions here must exactly match the criteria in
+      // finishFromResultBuffer.
       if (!hasAbstraction) {
-        if (auto emitInto = ctx.getEmitInto()) {
-          if (SILValue addr = emitInto->getAddressOrNull()) {
-            return addr;
-          }
-        }
+        if (auto address = ctx.getAddressForInPlaceInitialization(SGF, Loc))
+          return address;
       }
 
       return SGF.emitTemporaryAllocation(Loc, origTargetTL.getLoweredType());
@@ -497,13 +489,11 @@
                                         AbstractionPattern abstraction,
                                         const TypeLowering &origTargetTL,
                                         SGFContext ctx) {
+      // Note that the conditions here must exactly match the criteria in
+      // createAbstractResultBuffer.
       if (!hasAbstraction) {
-        if (auto emitInto = ctx.getEmitInto()) {
-          if (emitInto->getAddressOrNull()) {
-            emitInto->finishInitialization(SGF);
-            return ManagedValue::forInContext();
-          }
-        }
+        if (ctx.finishInPlaceInitialization(SGF))
+          return ManagedValue::forInContext();
       }
 
       ManagedValue result;
@@ -713,7 +703,7 @@
   Optional<TemporaryInitialization> resultObjectTemp;
   SGFContext resultObjectCtx;
   if ((resultTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) ||
-      (C.getEmitInto() && C.getEmitInto()->getAddressOrNull())) {
+      (C.getEmitInto() && C.getEmitInto()->canPerformInPlaceInitialization())) {
     SILType resultTy = resultTL.getLoweredType();
     resultBuffer = SGF.getBufferForExprResult(loc, resultTy, C);
     resultObjectBuffer =
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 329ad5f..dc556d9 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -50,7 +50,7 @@
 
 ManagedValue SILGenFunction::emitManagedRetain(SILLocation loc,
                                                SILValue v) {
-  auto &lowering = F.getTypeLowering(v->getType());
+  auto &lowering = getTypeLowering(v->getType());
   return emitManagedRetain(loc, v, lowering);
 }
 
@@ -70,7 +70,7 @@
 }
 
 ManagedValue SILGenFunction::emitManagedLoadCopy(SILLocation loc, SILValue v) {
-  auto &lowering = F.getTypeLowering(v->getType());
+  auto &lowering = getTypeLowering(v->getType());
   return emitManagedLoadCopy(loc, v, lowering);
 }
 
@@ -88,7 +88,7 @@
 
 ManagedValue SILGenFunction::emitManagedLoadBorrow(SILLocation loc,
                                                    SILValue v) {
-  auto &lowering = F.getTypeLowering(v->getType());
+  auto &lowering = getTypeLowering(v->getType());
   return emitManagedLoadBorrow(loc, v, lowering);
 }
 
@@ -108,7 +108,7 @@
 
 ManagedValue SILGenFunction::emitManagedStoreBorrow(SILLocation loc, SILValue v,
                                                     SILValue addr) {
-  auto &lowering = F.getTypeLowering(v->getType());
+  auto &lowering = getTypeLowering(v->getType());
   return emitManagedStoreBorrow(loc, v, addr, lowering);
 }
 
@@ -127,7 +127,7 @@
 
 ManagedValue SILGenFunction::emitManagedBeginBorrow(SILLocation loc,
                                                     SILValue v) {
-  auto &lowering = F.getTypeLowering(v->getType());
+  auto &lowering = getTypeLowering(v->getType());
   return emitManagedBeginBorrow(loc, v, lowering);
 }
 
@@ -212,7 +212,7 @@
                                                        SILValue v) {
   if (v.getOwnershipKind() == ValueOwnershipKind::Guaranteed)
     return ManagedValue::forUnmanaged(v);
-  auto &lowering = F.getTypeLowering(v->getType());
+  auto &lowering = getTypeLowering(v->getType());
   return emitFormalEvaluationManagedBeginBorrow(loc, v, lowering);
 }
 
@@ -232,7 +232,7 @@
 ManagedValue
 SILGenFunction::emitFormalEvaluationManagedBorrowedRValueWithCleanup(
     SILLocation loc, SILValue original, SILValue borrowed) {
-  auto &lowering = F.getTypeLowering(original->getType());
+  auto &lowering = getTypeLowering(original->getType());
   return emitFormalEvaluationManagedBorrowedRValueWithCleanup(
       loc, original, borrowed, lowering);
 }
@@ -264,7 +264,7 @@
                                                      SILValue borrowed) {
   assert(original->getType().getObjectType() ==
          borrowed->getType().getObjectType());
-  auto &lowering = F.getTypeLowering(original->getType());
+  auto &lowering = getTypeLowering(original->getType());
   return emitManagedBorrowedRValueWithCleanup(original, borrowed, lowering);
 }
 
@@ -287,7 +287,7 @@
 }
 
 ManagedValue SILGenFunction::emitManagedRValueWithCleanup(SILValue v) {
-  auto &lowering = F.getTypeLowering(v->getType());
+  auto &lowering = getTypeLowering(v->getType());
   return emitManagedRValueWithCleanup(v, lowering);
 }
 
@@ -305,7 +305,7 @@
 }
 
 ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v) {
-  auto &lowering = F.getTypeLowering(v->getType());
+  auto &lowering = getTypeLowering(v->getType());
   return emitManagedBufferWithCleanup(v, lowering);
 }
 
@@ -541,7 +541,7 @@
 
   void emit(SILGenFunction &gen, CleanupLocation) override {
     gen.emitSemanticStore(loc, value, lvalueAddress,
-                          gen.F.getTypeLowering(lvalueAddress->getType()),
+                          gen.getTypeLowering(lvalueAddress->getType()),
                           IsInitialization);
   }
 
@@ -570,7 +570,7 @@
                                                          SGFContext C) {
   assert(SelfInitDelegationState != SILGenFunction::NormalSelf &&
          "This should never be called unless we are in a delegation sequence");
-  assert(F.getTypeLowering(addr->getType()).isLoadable() &&
+  assert(getTypeLowering(addr->getType()).isLoadable() &&
          "Make sure that we are not dealing with semantic rvalues");
 
   // If we are currently in the WillSharedBorrowSelf state, then we know that
@@ -595,7 +595,7 @@
   // If we are in WillExclusiveBorrowSelf, then we need to perform an exclusive
   // borrow (i.e. a load take) and then move to DidExclusiveBorrowSelf.
   if (SelfInitDelegationState == SILGenFunction::WillExclusiveBorrowSelf) {
-    const auto &typeLowering = F.getTypeLowering(addr->getType());
+    const auto &typeLowering = getTypeLowering(addr->getType());
     SelfInitDelegationState = SILGenFunction::DidExclusiveBorrowSelf;
     SILValue self =
         emitLoad(loc, addr, typeLowering, C, IsTake, false).forward(*this);
@@ -1092,7 +1092,7 @@
 
   // If we have a single-buffer "emit into" initialization, use that for the
   // result.
-  if (SILValue address = C.getAddressForInPlaceInitialization())
+  if (SILValue address = C.getAddressForInPlaceInitialization(*this, loc))
     return address;
   
   // If we couldn't emit into the Initialization, emit into a temporary
@@ -1105,10 +1105,8 @@
                           SGFContext C) {
   // If we have a single-buffer "emit into" initialization, use that for the
   // result.
-  if (C.getAddressForInPlaceInitialization()) {
-    C.getEmitInto()->finishInitialization(*this);
+  if (C.finishInPlaceInitialization(*this))
     return ManagedValue::forInContext();
-  }
   
   // Add a cleanup for the temporary we allocated.
   if (bufferTL.isTrivial())
@@ -1152,7 +1150,8 @@
   auto &optTL = SGF.getTypeLowering(E->getType());
 
   Initialization *optInit = C.getEmitInto();
-  bool usingProvidedContext = optInit && optInit->isSingleBuffer();
+  bool usingProvidedContext =
+    optInit && optInit->canPerformInPlaceInitialization();
 
   // Form the optional using address operations if the type is address-only or
   // if we already have an address to use.
@@ -1180,7 +1179,7 @@
   SILValue branchArg;
   if (isByAddress) {
     assert(optInit);
-    SILValue optAddr = optInit->getAddress();
+    SILValue optAddr = optInit->getAddressForInPlaceInitialization(SGF, E);
     SGF.emitInjectOptionalValueInto(E, E->getSubExpr(), optAddr, optTL);
   } else {
     ManagedValue subExprValue = SGF.emitRValueAsSingleValue(E->getSubExpr());
@@ -1228,7 +1227,8 @@
   catchCleanups.pop();
 
   if (isByAddress) {
-    SGF.emitInjectOptionalNothingInto(E, optInit->getAddress(), optTL);
+    SGF.emitInjectOptionalNothingInto(E,
+                    optInit->getAddressForInPlaceInitialization(SGF, E), optTL);
     SGF.B.createBranch(E, contBB);
   } else {
     auto branchArg = SGF.getOptionalNoneValue(E, optTL);
@@ -1871,13 +1871,12 @@
 
     bool implodeTuple = false;
 
-    if (auto Address = I->getAddressOrNull()) {
-      if (isa<GlobalAddrInst>(Address) &&
-          SGF.getTypeLowering(type).getLoweredType().isTrivial(SGF.SGM.M)) {
-        // Implode tuples in initialization of globals if they are
-        // of trivial types.
-        implodeTuple = true;
-      }
+    if (I->canPerformInPlaceInitialization() &&
+        I->isInPlaceInitializationOfGlobal() &&
+        SGF.getTypeLowering(type).getLoweredType().isTrivial(SGF.SGM.M)) {
+      // Implode tuples in initialization of globals if they are
+      // of trivial types.
+      implodeTuple = true;
     }
 
     if (!implodeTuple && I->canSplitIntoTupleElements()) {
@@ -3239,11 +3238,6 @@
   };
 } // end anonymous namespace
 
-// Return an initialization address we can emit directly into.
-static SILValue getAddressForInPlaceInitialization(const Initialization *I) {
-  return I ? I->getAddressForInPlaceInitialization() : SILValue();
-}
-
 /// emitOptimizedOptionalEvaluation - Look for cases where we can short-circuit
 /// evaluation of an OptionalEvaluationExpr by pattern matching the AST.
 ///
@@ -3270,38 +3264,13 @@
   auto *BO = dyn_cast<BindOptionalExpr>(IIO->getSubExpr()
                                         ->getSemanticsProvidingExpr());
   if (!BO || BO->getDepth() != 0) return false;
-  
-  // If the subexpression type is exactly the same, then just peephole the
-  // whole thing away.
-  if (BO->getSubExpr()->getType()->isEqual(E->getType())) {
-    if (optInit)
-      SGF.emitExprInto(BO->getSubExpr(), optInit);
-    else
-      LoadableResult=SGF.emitRValueAsSingleValue(BO->getSubExpr()).forward(SGF);
-    return true;
-  }
-  
-  OptionalTypeKind Kind = OTK_None; (void)Kind;
-  assert(BO->getSubExpr()->getType()->getAnyOptionalObjectType(Kind)
-         ->isEqual(E->getType()->getAnyOptionalObjectType(Kind)));
-  
-  // If we're not emitting into memory (which happens both because the type is
-  // address only or because we have a contextual memory location to
-  // initialize).
-  if (optInit == nullptr) {
+
+  // SIL defines away abstraction differences between T? and T!,
+  // so we can just emit the sub-initialization normally.
+  if (optInit)
+    SGF.emitExprInto(BO->getSubExpr(), optInit);
+  else
     LoadableResult = SGF.emitRValueAsSingleValue(BO->getSubExpr()).forward(SGF);
-    return true;
-  }
-  
-  // If this is an address-only case, get the address of the buffer we want the
-  // result in, then cast the address of it to the right type, then emit into
-  // it.
-  SILValue optAddr = getAddressForInPlaceInitialization(optInit);
-  assert(optAddr && "Caller should have provided a buffer");
-  
-  KnownAddressInitialization subInit(optAddr);
-  SGF.emitExprInto(BO->getSubExpr(), &subInit);
-  optInit->finishInitialization(SGF);
   return true;
 }
 
@@ -3310,7 +3279,8 @@
   auto &optTL = SGF.getTypeLowering(E->getType());
 
   Initialization *optInit = C.getEmitInto();
-  bool usingProvidedContext = optInit && optInit->isSingleBuffer();
+  bool usingProvidedContext =
+    optInit && optInit->canPerformInPlaceInitialization();
 
   // Form the optional using address operations if the type is address-only or
   // if we already have an address to use.
@@ -3318,42 +3288,66 @@
                       SGF.silConv.useLoweredAddresses());
 
   std::unique_ptr<TemporaryInitialization> optTemp;
-  if (!usingProvidedContext && isByAddress) {
+  if (!isByAddress) {
+    // If the caller produced a context for us, but we're not going
+    // to use it, make sure we don't.
+    optInit = nullptr;
+  } else if (!usingProvidedContext) {
     // Allocate the temporary for the Optional<T> if we didn't get one from the
     // context.  This needs to happen outside of the cleanups scope we're about
     // to push.
     optTemp = SGF.emitTemporary(E, optTL);
     optInit = optTemp.get();
-  } else if (!usingProvidedContext) {
-    // If the caller produced a context for us, but we can't use it, then don't.
-    optInit = nullptr;
   }
+  assert(isByAddress == (optInit != nullptr));
+
+  // Acquire the address to emit into outside of the cleanups scope.
+  SILValue optAddr;
+  if (isByAddress)
+    optAddr = optInit->getAddressForInPlaceInitialization(SGF, E);
 
   // Enter a cleanups scope.
   FullExpr scope(SGF.Cleanups, E);
 
+  // Inside of the cleanups scope, create a new initialization to
+  // emit into optAddr.
+  std::unique_ptr<TemporaryInitialization> normalInit;
+  if (isByAddress) {
+    normalInit = SGF.useBufferAsTemporary(optAddr, optTL);
+  }
+
   // Install a new optional-failure destination just outside of the
   // cleanups scope.
   SILBasicBlock *failureBB = SGF.createBasicBlock();
   RestoreOptionalFailureDest restoreFailureDest(SGF,
                     JumpDest(failureBB, SGF.Cleanups.getCleanupsDepth(), E));
 
-  SILValue NormalArgument = nullptr;
-  if (emitOptimizedOptionalEvaluation(E, NormalArgument, optInit, *this)) {
+  SILValue normalArgument = nullptr;
+  if (emitOptimizedOptionalEvaluation(E, normalArgument,
+                                      normalInit.get(), *this)) {
     // Already emitted code for this.
-  } else if (isByAddress) {
+  } else if (normalInit) {
     // Emit the operand into the temporary.
-    SGF.emitExprInto(E->getSubExpr(), optInit);
+    SGF.emitExprInto(E->getSubExpr(), normalInit.get());
   } else {
-    NormalArgument = SGF.emitRValueAsSingleValue(E->getSubExpr()).forward(SGF);
+    normalArgument = SGF.emitRValueAsSingleValue(E->getSubExpr()).forward(SGF);
   }
 
+  assert(isByAddress == (normalArgument == nullptr) &&
+         "shouldn't have emitted as scalar in this case");
+
   // We fell out of the normal result, which generated a T? as either
-  // a scalar in NormalArgument or directly into optInit.
+  // a scalar in normalArgument or directly into normalInit.
+
+  // If we're using by-address initialization, we must've emitted into
+  // normalInit.  Forward its cleanup before popping the scope.
+  if (isByAddress) {
+    normalInit->getManagedAddress().forward(SGF);
+    normalInit.reset(); // Make sure we don't use this anymore.
+  }
 
   // This concludes the conditional scope.
   scope.pop();
-
   
   // In the usual case, the code will have emitted one or more branches to the
   // failure block.  However, if the body is simple enough, we can end up with
@@ -3362,34 +3356,41 @@
   if (failureBB->pred_empty()) {
     // Remove the dead failureBB.
     failureBB->eraseFromParent();
-    
-    // The value we provide is the one we've already got.
-    if (!isByAddress && NormalArgument)
-      return RValue(SGF, E,
-                    SGF.emitManagedRValueWithCleanup(NormalArgument, optTL));
 
-    // If we emitted into the provided context, we're done.
+    // Just re-manage normalArgument if we're not using address-based IRGen.
+    if (!isByAddress)
+      return RValue(SGF, E,
+                    SGF.emitManagedRValueWithCleanup(normalArgument, optTL));
+
+    // Otherwise, we must have emitted into normalInit, which means that,
+    // now that we're out of the cleanups scope, we need to finish optInit.
+    optInit->finishInitialization(SGF);
+
+    // If optInit came from the SGFContext, then we've successfully emitted
+    // into that.
     if (usingProvidedContext)
       return RValue();
 
+    // Otherwise, we must have emitted into optTemp.
     return RValue(SGF, E, optTemp->getManagedAddress());
   }
   
-  
+  // Okay, we do have uses of the failure block, so we'll need to merge
+  // control paths.
+
   SILBasicBlock *contBB = SGF.createBasicBlock();
 
   // Branch to the continuation block.
-  if (NormalArgument)
-    SGF.B.createBranch(E, contBB, NormalArgument);
-  else
+  if (isByAddress)
     SGF.B.createBranch(E, contBB);
+  else
+    SGF.B.createBranch(E, contBB, normalArgument);
 
-  // If control branched to the failure block, inject .None into the
-  // result type.
+  // In the failure block, inject nil into the result.
   SGF.B.emitBlock(failureBB);
 
   if (isByAddress) {
-    SGF.emitInjectOptionalNothingInto(E, optInit->getAddress(), optTL);
+    SGF.emitInjectOptionalNothingInto(E, optAddr, optTL);
     SGF.B.createBranch(E, contBB);
   } else {
     auto branchArg = SGF.getOptionalNoneValue(E, optTL);
@@ -3400,16 +3401,20 @@
   SGF.B.emitBlock(contBB);
 
   // If this was done in SSA registers, then the value is provided as an
-  // argument to the block.
+  // argument to the block; manage it and return.
   if (!isByAddress) {
     auto arg = contBB->createPHIArgument(optTL.getLoweredType(),
                                          ValueOwnershipKind::Owned);
     return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(arg, optTL));
   }
+
+  // Otherwise, we need to manage the value in optInit.
+  optInit->finishInitialization(SGF);
   
   // If we emitted into the provided context, we're done.
-  if (usingProvidedContext)
+  if (usingProvidedContext) {
     return RValue();
+  }
   
   assert(optTemp);
   return RValue(SGF, E, optTemp->getManagedAddress());
diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp
index d1ded2d..3b1f91e 100644
--- a/lib/SILGen/SILGenFunction.cpp
+++ b/lib/SILGen/SILGenFunction.cpp
@@ -631,11 +631,6 @@
   RegularLocation Loc(value);
   Loc.markAutoGenerated();
 
-  // Override location for #file, #line etc. to an invalid one so that we
-  // don't put extra strings into the default argument generator function that
-  // is not going to be ever used anyway.
-  overrideLocationForMagicIdentifiers = SourceLoc();
-
   auto *dc = function.getDecl()->getInnermostDeclContext();
   auto interfaceType = dc->mapTypeOutOfContext(value->getType());
   emitProlog({}, interfaceType, dc, false);
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index fba3c6a..30bd808 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -110,15 +110,34 @@
     return state.getPointer();
   }
 
-  /// If we have an emit into, return the address of the emit into. Otherwise,
-  /// return an empty SILValue.
-  SILValue getAddressForInPlaceInitialization() const {
+  /// Try to get the address of the emit-into initialization if we can.
+  /// Otherwise, return an empty SILValue.
+  ///
+  /// Note that, if this returns a non-empty address, the caller must
+  /// finish the emit-into initialization.
+  SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
+                                              SILLocation loc) const {
     if (auto *init = getEmitInto()) {
-      return init->getAddressForInPlaceInitialization();
+      if (init->canPerformInPlaceInitialization())
+        return init->getAddressForInPlaceInitialization(SGF, loc);
     }
     return SILValue();
   }
 
+  /// If getAddressForInPlaceInitialization did (or would have)
+  /// returned a non-null address, finish the initialization and
+  /// return true.  Otherwise, return false.
+  bool finishInPlaceInitialization(SILGenFunction &SGF) const {
+    if (auto *init = getEmitInto()) {
+      if (init->canPerformInPlaceInitialization()) {
+        init->finishInitialization(SGF);
+        return true;
+      }
+    }
+
+    return false;
+  }
+
   /// Return true if a ManagedValue producer is allowed to return at
   /// +0, given that it cannot guarantee that the value will be valid
   /// until the end of the current evaluation.
@@ -505,6 +524,10 @@
     return SGM.Types.getConstantInfo(constant);
   }
 
+  Optional<SILAccessEnforcement> getStaticEnforcement(VarDecl *var = nullptr);
+  Optional<SILAccessEnforcement> getDynamicEnforcement(VarDecl *var = nullptr);
+  Optional<SILAccessEnforcement> getUnknownEnforcement(VarDecl *var = nullptr);
+
   SourceManager &getSourceManager() { return SGM.M.getASTContext().SourceMgr; }
 
   /// Push a new debug scope and set its parent pointer.
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index c33d7ed..b21cc7a 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -107,6 +107,35 @@
   };
 }
 
+static bool shouldUseUnsafeEnforcement(VarDecl *var) {
+  return false; // TODO
+}
+
+Optional<SILAccessEnforcement>
+SILGenFunction::getStaticEnforcement(VarDecl *var) {
+  if (getOptions().EnforceExclusivityStatic)
+    return SILAccessEnforcement::Static;
+  return None;
+}
+
+Optional<SILAccessEnforcement>
+SILGenFunction::getDynamicEnforcement(VarDecl *var) {
+  if (getOptions().EnforceExclusivityDynamic) {
+    if (var && shouldUseUnsafeEnforcement(var))
+      return SILAccessEnforcement::Unsafe;
+    return SILAccessEnforcement::Dynamic;
+  }
+  return None;
+}
+
+Optional<SILAccessEnforcement>
+SILGenFunction::getUnknownEnforcement(VarDecl *var) {
+  if (getOptions().EnforceExclusivityStatic ||
+      getOptions().EnforceExclusivityDynamic)
+    return SILAccessEnforcement::Unknown;
+  return None;
+}
+
 /// SILGenLValue - An ASTVisitor for building logical lvalues.
 class LLVM_LIBRARY_VISIBILITY SILGenLValue
   : public Lowering::ExprVisitor<SILGenLValue, LValue, AccessKind>
@@ -314,6 +343,44 @@
 }
 
 namespace {
+  /// A helper class for creating writebacks associated with l-value
+  /// components that don't really need them.
+  class WritebackPseudoComponent : public LogicalPathComponent {
+  protected:
+    WritebackPseudoComponent(const LValueTypeData &typeData)
+      : LogicalPathComponent(typeData, WritebackPseudoKind) {}
+
+  public:
+    AccessKind getBaseAccessKind(SILGenFunction &SGF,
+                                 AccessKind accessKind) const override {
+      llvm_unreachable("called getBaseAccessKind on pseudo-component");
+    }
+    std::unique_ptr<LogicalPathComponent>
+    clone(SILGenFunction &SGF, SILLocation l) const override {
+      llvm_unreachable("called clone on pseudo-component");
+    }
+
+    RValue get(SILGenFunction &SGF, SILLocation loc,
+               ManagedValue base, SGFContext c) && override {
+      llvm_unreachable("called get on a pseudo-component");
+    }
+    void set(SILGenFunction &SGF, SILLocation loc,
+             RValue &&value, ManagedValue base) && override {
+      llvm_unreachable("called set on a pseudo-component");
+    }
+    ManagedValue getMaterialized(SILGenFunction &SGF, SILLocation loc,
+                                 ManagedValue base,
+                                 AccessKind accessKind) && override {
+      llvm_unreachable("called getMaterialized on a pseudo-component");
+    }
+
+    void diagnoseWritebackConflict(LogicalPathComponent *rhs,
+                                   SILLocation loc1, SILLocation loc2,
+                                   SILGenFunction &SGF) override {
+      // do nothing
+    }
+  };
+
   class RefElementComponent : public PhysicalPathComponent {
     VarDecl *Field;
     SILType SubstFieldType;
@@ -450,15 +517,38 @@
     }
   };
 
+  class EndAccessPseudoComponent : public WritebackPseudoComponent {
+  public:
+    EndAccessPseudoComponent(const LValueTypeData &typeData)
+      : WritebackPseudoComponent(typeData) {}
+
+  private:
+    void writeback(SILGenFunction &SGF, SILLocation loc,
+                   ManagedValue base,
+                   MaterializedLValue materialized,
+                   bool isFinal) override {
+      assert(base.isLValue());
+      SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
+    }
+
+    void print(raw_ostream &OS) const override {
+      OS << "EndAccessPseudoComponent";
+    }
+  };
+
   /// A physical path component which returns a literal address.
   class ValueComponent : public PhysicalPathComponent {
     ManagedValue Value;
+    Optional<SILAccessEnforcement> Enforcement;
     bool IsRValue;
   public:
-    ValueComponent(ManagedValue value, LValueTypeData typeData,
+    ValueComponent(ManagedValue value,
+                   Optional<SILAccessEnforcement> enforcement,
+                   LValueTypeData typeData,
                    bool isRValue = false) :
       PhysicalPathComponent(typeData, ValueKind),
       Value(value),
+      Enforcement(enforcement),
       IsRValue(isRValue) {
         assert(IsRValue || value.getType().isAddress());
     }
@@ -466,7 +556,34 @@
     ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
                         AccessKind accessKind) && override {
       assert(!base && "value component must be root of lvalue path");
-      return Value;
+
+      if (!Enforcement)
+        return Value;
+
+      assert(Value.isLValue() && "nonlvalue has enforcement?");
+      auto silAccessKind = [&] {
+        switch (accessKind) {
+        case AccessKind::Read:
+          return SILAccessKind::Read;
+        case AccessKind::Write:
+        case AccessKind::ReadWrite:
+          return SILAccessKind::Modify;
+        }
+      }();
+
+      // Enter the access.
+      auto accessedValue =
+        SGF.B.createBeginAccess(loc, Value.getValue(),
+                                silAccessKind, *Enforcement);
+      auto accessedMV = ManagedValue::forLValue(accessedValue);
+
+      // Push a writeback to end it.
+      std::unique_ptr<LogicalPathComponent>
+        component(new EndAccessPseudoComponent(getTypeData()));
+      pushWriteback(SGF, loc, std::move(component), accessedMV,
+                    MaterializedLValue());
+
+      return ManagedValue::forLValue(accessedValue);
     }
 
     bool isRValue() const override {
@@ -1065,41 +1182,12 @@
     }
   };
 
-  class UnpinPseudoComponent : public LogicalPathComponent {
+  class UnpinPseudoComponent : public WritebackPseudoComponent {
   public:
     UnpinPseudoComponent(const LValueTypeData &typeData)
-      : LogicalPathComponent(typeData, WritebackPseudoKind) {}
+      : WritebackPseudoComponent(typeData) {}
 
   private:
-    AccessKind getBaseAccessKind(SILGenFunction &SGF,
-                                 AccessKind accessKind) const override {
-      llvm_unreachable("called getBaseAccessKind on pseudo-component");
-    }
-    std::unique_ptr<LogicalPathComponent>
-    clone(SILGenFunction &SGF, SILLocation l) const override {
-      llvm_unreachable("called clone on pseudo-component");
-    }
-
-    RValue get(SILGenFunction &SGF, SILLocation loc,
-               ManagedValue base, SGFContext c) && override {
-      llvm_unreachable("called get on a pseudo-component");
-    }
-    void set(SILGenFunction &SGF, SILLocation loc,
-             RValue &&value, ManagedValue base) && override {
-      llvm_unreachable("called set on a pseudo-component");
-    }
-    ManagedValue getMaterialized(SILGenFunction &SGF, SILLocation loc,
-                                 ManagedValue base,
-                                 AccessKind accessKind) && override {
-      llvm_unreachable("called getMaterialized on a pseudo-component");
-    }
-
-    void diagnoseWritebackConflict(LogicalPathComponent *rhs,
-                                   SILLocation loc1, SILLocation loc2,
-                                   SILGenFunction &SGF) override {
-      // do nothing
-    }
-
     void writeback(SILGenFunction &SGF, SILLocation loc,
                    ManagedValue base,
                    MaterializedLValue materialized,
@@ -1358,11 +1446,12 @@
                                              value.getValue());
 
   LValue lv;
-  lv.add<ValueComponent>(value, typeData, /*isRValue=*/true);
+  lv.add<ValueComponent>(value, None, typeData, /*isRValue=*/true);
   return lv;
 }
 
 LValue LValue::forAddress(ManagedValue address,
+                          Optional<SILAccessEnforcement> enforcement,
                           AbstractionPattern origFormalType,
                           CanType substFormalType) {
   assert(address.isLValue());
@@ -1371,7 +1460,7 @@
   };
 
   LValue lv;
-  lv.add<ValueComponent>(address, typeData);
+  lv.add<ValueComponent>(address, enforcement, typeData);
   return lv;
 }
 
@@ -1521,7 +1610,7 @@
     CanType formalType = getSubstFormalRValueType(e);
     auto typeData = getValueTypeData(formalType, rv.getValue());
     LValue lv;
-    lv.add<ValueComponent>(rv, typeData, /*isRValue=*/true);
+    lv.add<ValueComponent>(rv, None, typeData, /*isRValue=*/true);
     return lv;
   }
 
@@ -1602,7 +1691,21 @@
     assert(address.isLValue() &&
            "physical lvalue decl ref must evaluate to an address");
     auto typeData = getPhysicalStorageTypeData(SGF.SGM, var, formalRValueType);
-    lv.add<ValueComponent>(address, typeData);
+
+    Optional<SILAccessEnforcement> enforcement;
+    if (!var->isLet()) {
+      if (var->getDeclContext()->isLocalContext()) {
+        enforcement = SGF.getUnknownEnforcement(var);
+      } else if (var->getDeclContext()->isModuleScopeContext()) {
+        enforcement = SGF.getDynamicEnforcement(var);
+      } else {
+        assert(var->getDeclContext()->isTypeContext() &&
+               !var->isInstanceMember());
+        enforcement = SGF.getDynamicEnforcement(var);
+      }
+    }
+
+    lv.add<ValueComponent>(address, enforcement, typeData);
 
     if (address.getType().is<ReferenceStorageType>())
       lv.add<OwnershipComponent>(typeData);
@@ -1626,7 +1729,8 @@
   address = SGF.B.createMarkUninitialized(e, address,
                                           MarkUninitializedInst::Var);
   LValue lv;
-  lv.add<ValueComponent>(SGF.emitManagedBufferWithCleanup(address), typeData);
+  lv.add<ValueComponent>(SGF.emitManagedBufferWithCleanup(address),
+                         None, typeData);
   return lv;
 }
 
@@ -1656,7 +1760,7 @@
 
     // Open up the existential.
     LValue lv;
-    lv.add<ValueComponent>(existentialAddr, existentialLV.getTypeData());
+    lv.add<ValueComponent>(existentialAddr, None, existentialLV.getTypeData());
     lv.add<OpenOpaqueExistentialComponent>(
       cast<ArchetypeType>(opened->getOpenedArchetype()->getCanonicalType()));
     return lv;
@@ -1670,7 +1774,7 @@
 
   RegularLocation loc(e);
   LValue lv;
-  lv.add<ValueComponent>(entry.Value.borrow(SGF, loc),
+  lv.add<ValueComponent>(entry.Value.borrow(SGF, loc), None,
                          getValueTypeData(SGF, e));
   return lv;
 }
@@ -1792,7 +1896,7 @@
     assert(addr != SGF.VarLocs.end() && addr->second.value);
     Path.clear();
     add<ValueComponent>(ManagedValue::forUnmanaged(addr->second.value),
-                        typeData);
+                        None, typeData);
   // For member variables, this access is done w.r.t. a base computation that
   // was already emitted.  This member is accessed off of it.
   } else if (strategy == AccessStrategy::Addressor) {
@@ -1952,7 +2056,7 @@
   ManagedValue valueAddr =
     getAddressOfOptionalValue(SGF, e, optAddr, valueTypeData);
   LValue valueLV;
-  valueLV.add<ValueComponent>(valueAddr, valueTypeData);
+  valueLV.add<ValueComponent>(valueAddr, None, valueTypeData);
   return valueLV;
 }
 
@@ -1981,7 +2085,8 @@
                                                  base.getValue());
 
   // Refer to 'self' as the base of the lvalue.
-  lv.add<ValueComponent>(base, baseTypeData, /*isRValue=*/!base.isLValue());
+  lv.add<ValueComponent>(base, None, baseTypeData,
+                         /*isRValue=*/!base.isLValue());
 
   auto substFormalType = ivar->getInterfaceType().subst(subMap)
     ->getCanonicalType();
@@ -2551,12 +2656,11 @@
   // lvalue into the destination.
   if (!src.isPhysical())
     return skipPeephole();
-  auto destAddr = dest->getAddressOrNull();
-  if (!destAddr)
+  if (!dest->canPerformInPlaceInitialization())
     return skipPeephole();
-  if (src.getTypeOfRValue().getSwiftRValueType()
-        != destAddr->getType().getSwiftRValueType())
-    return skipPeephole();
+  auto destAddr = dest->getAddressForInPlaceInitialization(*this, loc);
+  assert(src.getTypeOfRValue().getSwiftRValueType()
+           == destAddr->getType().getSwiftRValueType());
   
   auto srcAddr = emitAddressOfLValue(loc, std::move(src), AccessKind::Read)
                    .getUnmanagedValue();
diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp
index daf44f4..add01fc 100644
--- a/lib/SILGen/SILGenMaterializeForSet.cpp
+++ b/lib/SILGen/SILGenMaterializeForSet.cpp
@@ -359,7 +359,7 @@
          emitter.WitnessStorage->hasAddressors()))
       emitter.TheAccessSemantics = AccessSemantics::DirectToStorage;
     else if (emitter.WitnessStorage->hasClangNode() ||
-             emitter.WitnessStorage->getAttrs().hasAttribute<NSManagedAttr>())
+             emitter.WitnessStorage->isDynamic())
       emitter.TheAccessSemantics = AccessSemantics::Ordinary;
     else
       emitter.TheAccessSemantics = AccessSemantics::DirectToAccessor;
@@ -433,7 +433,7 @@
       else {
         if (!self.isLValue())
           self = ManagedValue::forLValue(self.getValue());
-        return LValue::forAddress(self, selfPattern, SubstSelfType);
+        return LValue::forAddress(self, None, selfPattern, SubstSelfType);
       }
     }
 
diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp
index ab44d50..aeb49c2 100644
--- a/lib/SILGen/SILGenPattern.cpp
+++ b/lib/SILGen/SILGenPattern.cpp
@@ -2292,7 +2292,7 @@
       pattern->forEachVariable([&](VarDecl *V) {
         if (!V->hasName())
           return;
-        block->createPHIArgument(SGF.VarLocs[V].value->getType(),
+        block->createPHIArgument(SGF.getLoweredType(V->getType()),
                                  ValueOwnershipKind::Owned, V);
       });
     }
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index 5f22750..d83f4c8 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -164,7 +164,7 @@
   assert(!fromType->isAnyExistentialType());
   
   SmallVector<ProtocolDecl *, 4> protocols;
-  toType->getAnyExistentialTypeProtocols(protocols);
+  toType->getExistentialTypeProtocols(protocols);
   
   SmallVector<ProtocolConformanceRef, 4> conformances;
   for (auto proto : protocols) {
diff --git a/lib/SILGen/SILGenProfiling.cpp b/lib/SILGen/SILGenProfiling.cpp
index ea3e28f..d24d937 100644
--- a/lib/SILGen/SILGenProfiling.cpp
+++ b/lib/SILGen/SILGenProfiling.cpp
@@ -641,7 +641,7 @@
       assignCounter(E);
     } else if (auto *IE = dyn_cast<IfExpr>(E)) {
       CounterExpr &ThenCounter = assignCounter(IE->getThenExpr());
-      if (Parent.isNull())
+      if (RegionStack.empty())
         assignCounter(IE->getElseExpr());
       else
         assignCounter(IE->getElseExpr(),
diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp
index d2aeab1..549de94 100644
--- a/lib/SILGen/SILGenStmt.cpp
+++ b/lib/SILGen/SILGenStmt.cpp
@@ -253,7 +253,6 @@
                               SmallVectorImpl<CleanupHandle> &cleanups)
       : Storage(storage), Cleanups(cleanups) {}
 
-    SILValue getAddressOrNull() const override { return SILValue(); }
     void copyOrInitValueInto(SILGenFunction &gen, SILLocation loc,
                              ManagedValue value, bool isInit) override {
       Storage = value.getValue();
diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp
index c23259f..0f69eb8 100644
--- a/lib/SILGen/SILGenThunk.cpp
+++ b/lib/SILGen/SILGenThunk.cpp
@@ -14,7 +14,7 @@
 // referenced from code, such as dynamic thunks, curry thunks, native to foreign
 // thunks and foreign to native thunks.
 //
-// VTable thunks and witness thunks can be found in SILGenType.cpp, and and the
+// VTable thunks and witness thunks can be found in SILGenType.cpp, and the
 // meat of the bridging thunk implementation is in SILGenBridging.cpp, and
 // re-abstraction thunks are in SILGenPoly.cpp.
 //
diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp
index e80448d..e4a8473 100644
--- a/lib/SILGen/SILGenType.cpp
+++ b/lib/SILGen/SILGenType.cpp
@@ -312,6 +312,7 @@
   NormalProtocolConformance *Conformance;
   std::vector<SILWitnessTable::Entry> Entries;
   SILLinkage Linkage;
+  IsSerialized_t Serialized;
 
   SILGenConformance(SILGenModule &SGM, NormalProtocolConformance *C)
     // We only need to emit witness tables for base NormalProtocolConformances.
@@ -319,9 +320,18 @@
       Linkage(getLinkageForProtocolConformance(Conformance,
                                                ForDefinition))
   {
-    // Not all protocols use witness tables.
-    if (!Lowering::TypeConverter::protocolRequiresWitnessTable(
-        Conformance->getProtocol()))
+    auto *proto = Conformance->getProtocol();
+
+    Serialized = IsNotSerialized;
+
+    // Serialize the witness table if we're serializing everything with
+    // -sil-serialize-all, or if the conformance itself thinks it should be.
+    if (SGM.makeModuleFragile || Conformance->hasFixedLayout())
+      Serialized = IsSerialized;
+
+    // Not all protocols use witness tables; in this case we just skip
+    // all of emit() below completely.
+    if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto))
       Conformance = nullptr;
   }
 
@@ -333,19 +343,6 @@
     auto *proto = Conformance->getProtocol();
     visitProtocolDecl(proto);
 
-    // Serialize the witness table in two cases:
-    // 1) We're serializing everything
-    // 2) The type has a fixed layout in all resilience domains, and the
-    //    conformance is externally visible
-    IsSerialized_t isSerialized = IsNotSerialized;
-    if (SGM.makeModuleFragile)
-      isSerialized = IsSerialized;
-    if (auto nominal = Conformance->getInterfaceType()->getAnyNominal())
-      if (nominal->hasFixedLayout() &&
-          proto->getEffectiveAccess() >= Accessibility::Public &&
-          nominal->getEffectiveAccess() >= Accessibility::Public)
-        isSerialized = IsSerialized;
-
     // Check if we already have a declaration or definition for this witness
     // table.
     if (auto *wt = SGM.M.lookUpWitnessTable(Conformance, false)) {
@@ -358,7 +355,7 @@
 
       // If we have a declaration, convert the witness table to a definition.
       if (wt->isDeclaration()) {
-        wt->convertToDefinition(Entries, isSerialized);
+        wt->convertToDefinition(Entries, Serialized);
 
         // Since we had a declaration before, its linkage should be external,
         // ensure that we have a compatible linkage for sanity. *NOTE* we are ok
@@ -375,19 +372,14 @@
     }
 
     // Otherwise if we have no witness table yet, create it.
-    return SILWitnessTable::create(SGM.M, Linkage, isSerialized,
+    return SILWitnessTable::create(SGM.M, Linkage, Serialized,
                                    Conformance, Entries);
   }
 
   void addOutOfLineBaseProtocol(ProtocolDecl *baseProtocol) {
     assert(Lowering::TypeConverter::protocolRequiresWitnessTable(baseProtocol));
 
-    auto foundBaseConformance
-      = Conformance->getInheritedConformances().find(baseProtocol);
-    assert(foundBaseConformance != Conformance->getInheritedConformances().end()
-           && "no inherited conformance for base protocol");
-
-    auto conformance = foundBaseConformance->second;
+    auto conformance = Conformance->getInheritedConformance(baseProtocol);
 
     Entries.push_back(SILWitnessTable::BaseProtocolWitness{
       baseProtocol,
@@ -427,20 +419,44 @@
       return;
     }
 
+    auto witnessLinkage = witnessRef.getLinkage(ForDefinition);
+    auto witnessSerialized = Serialized;
+    if (witnessSerialized &&
+        !hasPublicVisibility(witnessLinkage) &&
+        !hasSharedVisibility(witnessLinkage)) {
+      // FIXME: This should not happen, but it looks like visibility rules
+      // for extension members are slightly bogus.
+      //
+      // We allow a 'public' member of an extension to witness a public
+      // protocol requirement, even if the extended type is not public;
+      // then SILGen gives the member private linkage, ignoring the more
+      // visible accessibility it was given in the AST.
+      witnessLinkage = SILLinkage::Public;
+      witnessSerialized = (SGM.makeModuleFragile
+                           ? IsSerialized
+                           : IsNotSerialized);
+    } else {
+      // This is the "real" rule; the above case should go away once we
+      // figure out what's going on.
+      witnessLinkage = (witnessSerialized
+                        ? SILLinkage::Shared
+                        : SILLinkage::Private);
+    }
+
     SILFunction *witnessFn =
-      SGM.emitProtocolWitness(Conformance, Linkage, requirementRef, witnessRef,
-                              isFree, witness);
+      SGM.emitProtocolWitness(Conformance, witnessLinkage, witnessSerialized,
+                              requirementRef, witnessRef, isFree, witness);
     Entries.push_back(
                     SILWitnessTable::MethodWitness{requirementRef, witnessFn});
   }
 
   void addAssociatedType(AssociatedTypeDecl *td) {
     // Find the substitution info for the witness type.
-    const auto &witness = Conformance->getTypeWitness(td, /*resolver=*/nullptr);
+    Type witness = Conformance->getTypeWitness(td, /*resolver=*/nullptr);
 
     // Emit the record for the type itself.
     Entries.push_back(SILWitnessTable::AssociatedTypeWitness{td,
-                                witness.getReplacement()->getCanonicalType()});    
+                                                witness->getCanonicalType()});
   }
 
   void addAssociatedConformance(CanType dependentType, ProtocolDecl *protocol) {
@@ -540,6 +556,7 @@
 SILFunction *
 SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
                                   SILLinkage linkage,
+                                  IsSerialized_t isSerialized,
                                   SILDeclRef requirement,
                                   SILDeclRef witnessRef,
                                   IsFreeFunctionWitness_t isFree,
@@ -637,14 +654,6 @@
   if (witnessRef.isAlwaysInline())
     InlineStrategy = AlwaysInline;
 
-  IsSerialized_t isSerialized = IsNotSerialized;
-  if (makeModuleFragile)
-    isSerialized = IsSerialized;
-  if (witnessRef.isSerialized() &&
-      (hasSharedVisibility(linkage) ||
-       hasPublicVisibility(linkage)))
-    isSerialized = IsSerialized;
-
   auto *f = M.createFunction(
       linkage, nameBuffer, witnessSILFnType,
       genericEnv, SILLocation(witnessRef.getDecl()),
@@ -742,7 +751,9 @@
                  SILDeclRef witnessRef,
                  IsFreeFunctionWitness_t isFree,
                  Witness witness) {
-    SILFunction *witnessFn = SGM.emitProtocolWitness(nullptr, Linkage,
+    SILFunction *witnessFn = SGM.emitProtocolWitness(nullptr,
+                                                     SILLinkage::Private,
+                                                     IsNotSerialized,
                                                      requirementRef, witnessRef,
                                                      isFree, witness);
     auto entry = SILDefaultWitnessTable::Entry(requirementRef, witnessFn);
diff --git a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
index c81a439..b6563ef 100644
--- a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
@@ -664,10 +664,13 @@
 //                          Owned Argument Utilities
 //===----------------------------------------------------------------------===//
 
-ConsumedArgToEpilogueReleaseMatcher::
-ConsumedArgToEpilogueReleaseMatcher(RCIdentityFunctionInfo *RCFI,
-                                    SILFunction *F, ExitKind Kind)
-   : F(F), RCFI(RCFI), Kind(Kind), ProcessedBlock(nullptr) {
+ConsumedArgToEpilogueReleaseMatcher::ConsumedArgToEpilogueReleaseMatcher(
+    RCIdentityFunctionInfo *RCFI,
+    SILFunction *F,
+    ArrayRef<SILArgumentConvention> ArgumentConventions,
+    ExitKind Kind)
+    : F(F), RCFI(RCFI), Kind(Kind), ArgumentConventions(ArgumentConventions),
+      ProcessedBlock(nullptr) {
   recompute();
 }
 
@@ -770,6 +773,52 @@
   }
 }
 
+/// Check if a given argument convention is in the list
+/// of possible argument conventions.
+static bool
+isOneOfConventions(SILArgumentConvention Convention,
+                   ArrayRef<SILArgumentConvention> ArgumentConventions) {
+  for (auto ArgumentConvention : ArgumentConventions) {
+    if (Convention == ArgumentConvention)
+      return true;
+  }
+  return false;
+}
+
+void
+ConsumedArgToEpilogueReleaseMatcher::
+collectMatchingDestroyAddresses(SILBasicBlock *BB) {
+  // Check if we can find destory_addr for each @in argument.
+  SILFunction::iterator AnotherEpilogueBB =
+      (Kind == ExitKind::Return) ? F->findThrowBB() : F->findReturnBB();
+  for (auto Arg : F->begin()->getFunctionArguments()) {
+    if (Arg->isIndirectResult())
+      continue;
+    if (Arg->getArgumentConvention() != SILArgumentConvention::Indirect_In)
+      continue;
+    bool HasDestroyAddrOutsideEpilogueBB = false;
+    // This is an @in argument. Check if there are any destroy_addr
+    // instructions for it.
+    for (auto Use : getNonDebugUses(Arg)) {
+      auto User = Use->getUser();
+      if (!isa<DestroyAddrInst>(User))
+        continue;
+      // Do not take into account any uses in the other
+      // epilogue BB.
+      if (AnotherEpilogueBB != F->end() &&
+          User->getParent() == &*AnotherEpilogueBB)
+        continue;
+      if (User->getParent() != BB )
+        HasDestroyAddrOutsideEpilogueBB = true;
+      ArgInstMap[Arg].push_back(dyn_cast<SILInstruction>(User));
+    }
+
+    // Don't know how to handle destroy_addr outside of the epilogue.
+    if (HasDestroyAddrOutsideEpilogueBB)
+      ArgInstMap.erase(Arg);
+  }
+}
+
 void
 ConsumedArgToEpilogueReleaseMatcher::
 collectMatchingReleases(SILBasicBlock *BB) {
@@ -789,7 +838,14 @@
   // 3. A release that is mapped to an argument which already has a release
   // that overlaps with this release. This release for sure is not the final
   // release.
+  bool IsTrackingInArgs = isOneOfConventions(SILArgumentConvention::Indirect_In,
+                                             ArgumentConventions);
+
   for (auto II = std::next(BB->rbegin()), IE = BB->rend(); II != IE; ++II) {
+    if (IsTrackingInArgs && isa<DestroyAddrInst>(*II)) {
+      // It is probably a destroy addr for an @in argument.
+      continue;
+    }
     // If we do not have a release_value or strong_release. We can continue
     if (!isa<ReleaseValueInst>(*II) && !isa<StrongReleaseInst>(*II)) {
 
@@ -825,13 +881,14 @@
     // we could make this more general by allowing for intervening non-arg
     // releases in the sense that we do not allow for race conditions in between
     // destructors.
-    if (!Arg->hasConvention(SILArgumentConvention::Direct_Owned))
+    if (!Arg ||
+        !isOneOfConventions(Arg->getArgumentConvention(), ArgumentConventions))
       break;
 
-    // Ok, we have a release on a SILArgument that is direct owned. Attempt to
-    // put it into our arc opts map. If we already have it, we have exited the
-    // return value sequence so break. Otherwise, continue looking for more arc
-    // operations.
+    // Ok, we have a release on a SILArgument that has a consuming convention.
+    // Attempt to put it into our arc opts map. If we already have it, we have
+    // exited the return value sequence so break. Otherwise, continue looking
+    // for more arc operations.
     auto Iter = ArgInstMap.find(Arg);
     if (Iter == ArgInstMap.end()) {
       ArgInstMap[Arg].push_back(Target);
@@ -843,13 +900,19 @@
     //
     // If we are seeing a redundant release we have exited the return value
     // sequence, so break.
-    if (isRedundantRelease(Iter->second, Arg, OrigOp)) 
-      break;
+    if (!isa<DestroyAddrInst>(Target))
+      if (isRedundantRelease(Iter->second, Arg, OrigOp)) 
+        break;
     
     // We've seen part of this base, but this is a part we've have not seen.
     // Record it. 
     Iter->second.push_back(Target);
   }
+
+  if (IsTrackingInArgs) {
+    // Find destory_addr for each @in argument.
+    collectMatchingDestroyAddresses(BB);
+  }
 }
 
 void
@@ -948,7 +1011,8 @@
     UseBlocks.insert(BB);
 
     // Try to speed up the trivial case of single release/dealloc.
-    if (isa<StrongReleaseInst>(User) || isa<DeallocBoxInst>(User)) {
+    if (isa<StrongReleaseInst>(User) || isa<DeallocBoxInst>(User) ||
+        isa<DestroyValueInst>(User)) {
       if (!seenRelease)
         OneRelease = User;
       else
diff --git a/lib/SILOptimizer/Analysis/ArraySemantic.cpp b/lib/SILOptimizer/Analysis/ArraySemantic.cpp
index a0f8ce3..68eb9be 100644
--- a/lib/SILOptimizer/Analysis/ArraySemantic.cpp
+++ b/lib/SILOptimizer/Analysis/ArraySemantic.cpp
@@ -162,7 +162,10 @@
             .Case("array.get_element_address",
                   ArrayCallKind::kGetElementAddress)
             .Case("array.mutate_unknown", ArrayCallKind::kMutateUnknown)
-            .Case("array.withUnsafeMutableBufferPointer", ArrayCallKind::kWithUnsafeMutableBufferPointer)
+            .Case("array.withUnsafeMutableBufferPointer",
+                  ArrayCallKind::kWithUnsafeMutableBufferPointer)
+            .Case("array.append_contentsOf", ArrayCallKind::kAppendContentsOf)
+            .Case("array.append_element", ArrayCallKind::kAppendElement)
             .Default(ArrayCallKind::kNone);
     if (Tmp != ArrayCallKind::kNone) {
       assert(Kind == ArrayCallKind::kNone && "Multiple array semantic "
@@ -562,6 +565,21 @@
   return true;
 }
 
+bool swift::ArraySemanticsCall::canInlineEarly() const {
+  switch (getKind()) {
+    default:
+      return false;
+    case ArrayCallKind::kAppendContentsOf:
+    case ArrayCallKind::kAppendElement:
+      // append(Element) calls other semantics functions. Therefore it's
+      // important that it's inlined by the early inliner (which is before all
+      // the array optimizations). Also, this semantics is only used to lookup
+      // Array.append(Element), so inlining it does not prevent any other
+      // optimization.
+      return true;
+  }
+}
+
 SILValue swift::ArraySemanticsCall::getInitializationCount() const {
   if (getKind() == ArrayCallKind::kArrayUninitialized) {
     // Can be either a call to _adoptStorage or _allocateUninitialized.
@@ -675,3 +693,55 @@
   removeCall();
   return true;
 }
+
+bool swift::ArraySemanticsCall::replaceByAppendingValues(
+    SILModule &M, SILFunction *AppendFn, const SmallVectorImpl<SILValue> &Vals,
+    ArrayRef<Substitution> Subs) {
+  assert(getKind() == ArrayCallKind::kAppendContentsOf &&
+         "Must be an append_contentsOf call");
+  assert(AppendFn && "Must provide an append SILFunction");
+
+  // We only handle loadable types.
+  if (any_of(Vals, [&M](SILValue V) -> bool {
+        return !V->getType().isLoadable(M);
+      }))
+    return false;
+  
+  CanSILFunctionType AppendFnTy = AppendFn->getLoweredFunctionType();
+  SILValue ArrRef = SemanticsCall->getArgument(1);
+  SILBuilderWithScope Builder(SemanticsCall);
+  auto Loc = SemanticsCall->getLoc();
+  auto *FnRef = Builder.createFunctionRef(Loc, AppendFn);
+  auto FnTy = FnRef->getType();
+
+  for (SILValue V : Vals) {
+    auto SubTy = V->getType();
+    auto &ValLowering = Builder.getModule().getTypeLowering(SubTy);
+    auto CopiedVal = ValLowering.emitCopyValue(Builder, Loc, V);
+    auto *AllocStackInst = Builder.createAllocStack(Loc, SubTy);
+
+    ValLowering.emitStoreOfCopy(Builder, Loc, CopiedVal, AllocStackInst,
+                                IsInitialization_t::IsInitialization);
+
+    SILValue Args[] = {AllocStackInst, ArrRef};
+    Builder.createApply(Loc, FnRef, FnTy.substGenericArgs(M, Subs),
+                        FnTy.castTo<SILFunctionType>()->getAllResultsType(), Subs,
+                        Args, false);
+    Builder.createDeallocStack(Loc, AllocStackInst);
+    if (!isConsumedParameter(AppendFnTy->getParameters()[0].getConvention())) {
+      ValLowering.emitDestroyValue(Builder, Loc, CopiedVal);
+    }
+  }
+  CanSILFunctionType AppendContentsOfFnTy =
+    SemanticsCall->getReferencedFunction()->getLoweredFunctionType();
+  if (AppendContentsOfFnTy->getParameters()[0].getConvention() ==
+        ParameterConvention::Direct_Owned) {
+    SILValue SrcArray = SemanticsCall->getArgument(0);
+    Builder.createReleaseValue(SemanticsCall->getLoc(), SrcArray,
+                               Builder.getDefaultAtomicity());
+  }
+
+  removeCall();
+
+  return true;
+}
diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
index f114f9c..a9d30f9 100644
--- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
@@ -1818,9 +1818,16 @@
   if (ConGraph->isUsePoint(UsePoint, Node))
     return true;
 
-  if (hasReferenceSemantics(V->getType())) {
-    // Check if the object "content", i.e. a pointer to one of its stored
-    // properties, can escape to the called function.
+  if (isPointer(V)) {
+    // Check if the object "content" can escape to the called function.
+    // This will catch cases where V is a reference and a pointer to a stored
+    // property escapes.
+    // It's also important in case of a pointer assignment, e.g.
+    //    V = V1
+    //    apply(V1)
+    // In this case the apply is only a use-point for V1 and V1's content node.
+    // As V1's content node is the same as V's content node, we also make the
+    // check for the content node.
     CGNode *ContentNode = ConGraph->getContentNode(Node);
     if (ContentNode->escapesInsideFunction(false))
       return true;
diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp
index 119e348..5eabb35 100644
--- a/lib/SILOptimizer/IPO/CapturePromotion.cpp
+++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp
@@ -211,14 +211,16 @@
 
   void visitDebugValueAddrInst(DebugValueAddrInst *Inst);
   void visitStrongReleaseInst(StrongReleaseInst *Inst);
+  void visitDestroyValueInst(DestroyValueInst *Inst);
   void visitStructElementAddrInst(StructElementAddrInst *Inst);
   void visitLoadInst(LoadInst *Inst);
+  void visitLoadBorrowInst(LoadBorrowInst *Inst);
   void visitProjectBoxInst(ProjectBoxInst *Inst);
 
   SILFunction *Orig;
   IndicesSet &PromotableIndices;
-  llvm::DenseMap<SILArgument*, SILValue> BoxArgumentMap;
-  llvm::DenseMap<ProjectBoxInst*, SILValue> ProjectBoxArgumentMap;
+  llvm::DenseMap<SILArgument *, SILValue> BoxArgumentMap;
+  llvm::DenseMap<ProjectBoxInst *, SILValue> ProjectBoxArgumentMap;
 };
 } // end anonymous namespace
 
@@ -324,6 +326,11 @@
 
   DEBUG(llvm::dbgs() << "Preparing New Args!\n");
 
+  auto fnTy = F->getLoweredFunctionType();
+
+  auto &Types = F->getModule().Types;
+  Lowering::GenericContextScope scope(Types, fnTy->getGenericSignature());
+
   // For each parameter in the old function...
   for (unsigned Index : indices(Parameters)) {
     auto &param = Parameters[Index];
@@ -350,8 +357,7 @@
     assert(paramBoxTy->getLayout()->getFields().size() == 1
            && "promoting compound box not implemented yet");
     auto paramBoxedTy = paramBoxTy->getFieldType(F->getModule(), 0);
-    auto &paramTL = F->getModule().Types.getTypeLowering(paramBoxedTy);
-
+    auto &paramTL = Types.getTypeLowering(paramBoxedTy);
     ParameterConvention convention;
     if (paramTL.isFormallyPassedIndirectly()) {
       convention = ParameterConvention::Indirect_In;
@@ -437,36 +443,45 @@
   // Create arguments for the entry block
   SILBasicBlock *OrigEntryBB = &*Orig->begin();
   SILBasicBlock *ClonedEntryBB = Cloned->createBasicBlock();
+  getBuilder().setInsertionPoint(ClonedEntryBB);
+
   unsigned ArgNo = 0;
   auto I = OrigEntryBB->args_begin(), E = OrigEntryBB->args_end();
-  while (I != E) {
-    if (PromotableIndices.count(ArgNo)) {
-      // Handle the case of a promoted capture argument.
-      auto BoxTy = (*I)->getType().castTo<SILBoxType>();
-      assert(BoxTy->getLayout()->getFields().size() == 1
-             && "promoting compound box not implemented");
-      auto BoxedTy = BoxTy->getFieldType(Cloned->getModule(),0).getObjectType();
-      SILValue MappedValue =
-          ClonedEntryBB->createFunctionArgument(BoxedTy, (*I)->getDecl());
-      BoxArgumentMap.insert(std::make_pair(*I, MappedValue));
-      
-      // Track the projections of the box.
-      for (auto *Use : (*I)->getUses()) {
-        if (auto Proj = dyn_cast<ProjectBoxInst>(Use->getUser())) {
-          ProjectBoxArgumentMap.insert(std::make_pair(Proj, MappedValue));
-        }
-      }
-    } else {
+  for (; I != E; ++ArgNo, ++I) {
+    if (!PromotableIndices.count(ArgNo)) {
       // Otherwise, create a new argument which copies the original argument
       SILValue MappedValue = ClonedEntryBB->createFunctionArgument(
           (*I)->getType(), (*I)->getDecl());
       ValueMap.insert(std::make_pair(*I, MappedValue));
+      continue;
     }
-    ++ArgNo;
-    ++I;
+
+    // Handle the case of a promoted capture argument.
+    auto BoxTy = (*I)->getType().castTo<SILBoxType>();
+    assert(BoxTy->getLayout()->getFields().size() == 1 &&
+           "promoting compound box not implemented");
+    auto BoxedTy = BoxTy->getFieldType(Cloned->getModule(), 0).getObjectType();
+    SILValue MappedValue =
+        ClonedEntryBB->createFunctionArgument(BoxedTy, (*I)->getDecl());
+
+    // If SIL ownership is enabled, we need to perform a borrow here if we have
+    // a non-trivial value. We know that our value is not written to and it does
+    // not escape. The use of a borrow enforces this.
+    if (Cloned->hasQualifiedOwnership() &&
+        MappedValue.getOwnershipKind() != ValueOwnershipKind::Trivial) {
+      SILLocation Loc(const_cast<ValueDecl *>((*I)->getDecl()));
+      MappedValue = getBuilder().createBeginBorrow(Loc, MappedValue);
+    }
+    BoxArgumentMap.insert(std::make_pair(*I, MappedValue));
+
+    // Track the projections of the box.
+    for (auto *Use : (*I)->getUses()) {
+      if (auto Proj = dyn_cast<ProjectBoxInst>(Use->getUser())) {
+        ProjectBoxArgumentMap.insert(std::make_pair(Proj, MappedValue));
+      }
+    }
   }
 
-  getBuilder().setInsertionPoint(ClonedEntryBB);
   BBMap.insert(std::make_pair(OrigEntryBB, ClonedEntryBB));
   // Recursively visit original BBs in depth-first preorder, starting with the
   // entry block, cloning all instructions other than terminators.
@@ -503,6 +518,9 @@
 /// normally.
 void
 ClosureCloner::visitStrongReleaseInst(StrongReleaseInst *Inst) {
+  assert(
+      Inst->getFunction()->hasUnqualifiedOwnership() &&
+      "Should not see strong release in a function with qualified ownership");
   SILValue Operand = Inst->getOperand();
   if (SILArgument *A = dyn_cast<SILArgument>(Operand)) {
     auto I = BoxArgumentMap.find(A);
@@ -520,8 +538,43 @@
   SILCloner<ClosureCloner>::visitStrongReleaseInst(Inst);
 }
 
-/// \brief Handle a struct_element_addr instruction during cloning of a closure;
-/// if its operand is the promoted address argument then ignore it, otherwise it
+/// \brief Handle a destroy_value instruction during cloning of a closure; if
+/// it is a strong release of a promoted box argument, then it is replaced with
+/// a destroy_value of the new object type argument, otherwise it is handled
+/// normally.
+void ClosureCloner::visitDestroyValueInst(DestroyValueInst *Inst) {
+  SILValue Operand = Inst->getOperand();
+  if (SILArgument *A = dyn_cast<SILArgument>(Operand)) {
+    auto I = BoxArgumentMap.find(A);
+    if (I != BoxArgumentMap.end()) {
+      // Releases of the box arguments get replaced with an end_borrow,
+      // destroy_value of the new object type argument.
+      SILFunction &F = getBuilder().getFunction();
+      auto &typeLowering = F.getModule().getTypeLowering(I->second->getType());
+      SILBuilderWithPostProcess<ClosureCloner, 1> B(this, Inst);
+
+      SILValue Value = I->second;
+
+      // If ownership is enabled, then we must emit a begin_borrow for any
+      // non-trivial value.
+      if (F.hasQualifiedOwnership() &&
+          Value.getOwnershipKind() != ValueOwnershipKind::Trivial) {
+        auto *BBI = cast<BeginBorrowInst>(Value);
+        Value = BBI->getOperand();
+        B.createEndBorrow(Inst->getLoc(), BBI, Value);
+      }
+
+      typeLowering.emitDestroyValue(B, Inst->getLoc(), Value);
+      return;
+    }
+  }
+
+  SILCloner<ClosureCloner>::visitDestroyValueInst(Inst);
+}
+
+/// Handle a struct_element_addr instruction during cloning of a closure.
+///
+/// If its operand is the promoted address argument then ignore it, otherwise it
 /// is handled normally.
 void
 ClosureCloner::visitStructElementAddrInst(StructElementAddrInst *Inst) {
@@ -545,37 +598,87 @@
   SILCloner<ClosureCloner>::visitProjectBoxInst(I);
 }
 
-/// \brief Handle a load instruction during cloning of a closure; the two
-/// relevant cases are a direct load from a promoted address argument or a load
-/// of a struct_element_addr of a promoted address argument.
-void
-ClosureCloner::visitLoadInst(LoadInst *Inst) {
-  SILValue Operand = Inst->getOperand();
+/// \brief Handle a load_borrow instruction during cloning of a closure.
+///
+/// The two relevant cases are a direct load from a promoted address argument or
+/// a load of a struct_element_addr of a promoted address argument.
+void ClosureCloner::visitLoadBorrowInst(LoadBorrowInst *LI) {
+  assert(LI->getFunction()->hasQualifiedOwnership() &&
+         "We should only see a load borrow in ownership qualified SIL");
+  SILValue Operand = LI->getOperand();
   if (auto *A = dyn_cast<ProjectBoxInst>(Operand)) {
     auto I = ProjectBoxArgumentMap.find(A);
     if (I != ProjectBoxArgumentMap.end()) {
       // Loads of the address argument get eliminated completely; the uses of
       // the loads get mapped to uses of the new object type argument.
-      ValueMap.insert(std::make_pair(Inst, I->second));
+      //
+      // We assume that the value is already guaranteed.
+      assert(I->second.getOwnershipKind() == ValueOwnershipKind::Guaranteed &&
+             "Expected out argument value to be guaranteed");
+      ValueMap.insert(std::make_pair(LI, I->second));
       return;
     }
-  } else if (auto *SEAI = dyn_cast<StructElementAddrInst>(Operand)) {
-    if (auto *A = dyn_cast<ProjectBoxInst>(SEAI->getOperand())) {
-      auto I = ProjectBoxArgumentMap.find(A);
-      if (I != ProjectBoxArgumentMap.end()) {
-        // Loads of a struct_element_addr of an argument get replaced with
-        // struct_extract of the new object type argument.
-        SILBuilderWithPostProcess<ClosureCloner, 1> B(this, Inst);
-        SILValue V = B.emitStructExtract(Inst->getLoc(), I->second,
-                                         SEAI->getField(),
-                                         Inst->getType());
-        ValueMap.insert(std::make_pair(Inst, V));
-        return;
-      }
-    }
   }
 
-  SILCloner<ClosureCloner>::visitLoadInst(Inst);
+  SILCloner<ClosureCloner>::visitLoadBorrowInst(LI);
+  return;
+}
+
+/// \brief Handle a load instruction during cloning of a closure.
+///
+/// The two relevant cases are a direct load from a promoted address argument or
+/// a load of a struct_element_addr of a promoted address argument.
+void ClosureCloner::visitLoadInst(LoadInst *LI) {
+  SILValue Operand = LI->getOperand();
+  if (auto *A = dyn_cast<ProjectBoxInst>(Operand)) {
+    auto I = ProjectBoxArgumentMap.find(A);
+    if (I != ProjectBoxArgumentMap.end()) {
+      // Loads of the address argument get eliminated completely; the uses of
+      // the loads get mapped to uses of the new object type argument.
+      //
+      // If we are compiling with SIL ownership, we need to take different
+      // behaviors depending on the type of load. Specifically, if we have a
+      // load [copy], then we need to add a copy_value here. If we have a take
+      // or trivial, we just propagate the value through.
+      SILValue Value = I->second;
+      if (A->getFunction()->hasQualifiedOwnership() &&
+          LI->getOwnershipQualifier() == LoadOwnershipQualifier::Copy) {
+        Value = getBuilder().createCopyValue(LI->getLoc(), Value);
+      }
+      ValueMap.insert(std::make_pair(LI, Value));
+      return;
+    }
+    SILCloner<ClosureCloner>::visitLoadInst(LI);
+    return;
+  }
+
+  auto *SEAI = dyn_cast<StructElementAddrInst>(Operand);
+  if (!SEAI) {
+    SILCloner<ClosureCloner>::visitLoadInst(LI);
+    return;
+  }
+
+  auto *PBI = dyn_cast<ProjectBoxInst>(SEAI->getOperand());
+  if (!PBI) {
+    SILCloner<ClosureCloner>::visitLoadInst(LI);
+    return;
+  }
+
+  auto I = ProjectBoxArgumentMap.find(PBI);
+  if (I == ProjectBoxArgumentMap.end()) {
+    SILCloner<ClosureCloner>::visitLoadInst(LI);
+    return;
+  }
+
+  // Loads of a struct_element_addr of an argument get replaced with a
+  // struct_extract of the new passed in value. The value should be borrowed
+  // already.
+  SILBuilderWithPostProcess<ClosureCloner, 1> B(this, LI);
+  assert(B.getFunction().hasUnqualifiedOwnership() ||
+         I->second.getOwnershipKind() == ValueOwnershipKind::Guaranteed);
+  SILValue V = B.emitStructExtract(LI->getLoc(), I->second, SEAI->getField(),
+                                   LI->getType());
+  ValueMap.insert(std::make_pair(LI, V));
 }
 
 static SILArgument *getBoxFromIndex(SILFunction *F, unsigned Index) {
@@ -589,14 +692,15 @@
 /// for the address of the box's contents), return true if the closure is known
 /// not to mutate the captured variable.
 static bool
-isNonmutatingCapture(SILArgument *BoxArg) {
+isNonMutatingCapture(SILArgument *BoxArg) {
   SmallVector<ProjectBoxInst*, 2> Projections;
   
   // Conservatively do not allow any use of the box argument other than a
   // strong_release or projection, since this is the pattern expected from
   // SILGen.
   for (auto *O : BoxArg->getUses()) {
-    if (isa<StrongReleaseInst>(O->getUser()))
+    if (isa<StrongReleaseInst>(O->getUser()) ||
+        isa<DestroyValueInst>(O->getUser()))
       continue;
     
     if (auto Projection = dyn_cast<ProjectBoxInst>(O->getUser())) {
@@ -621,79 +725,309 @@
             return false;
         continue;
       }
-      if (!isa<LoadInst>(O->getUser())
-          && !isa<DebugValueAddrInst>(O->getUser())
-          && !isa<MarkFunctionEscapeInst>(O->getUser()))
+      if (!isa<LoadInst>(O->getUser()) &&
+          !isa<DebugValueAddrInst>(O->getUser()) &&
+          !isa<MarkFunctionEscapeInst>(O->getUser())) {
         return false;
+      }
     }
   }
 
   return true;
 }
 
+namespace {
+
+class NonEscapingUserVisitor
+    : public SILInstructionVisitor<NonEscapingUserVisitor, bool> {
+  llvm::SmallVector<Operand *, 32> Worklist;
+  llvm::SmallVectorImpl<SILInstruction *> &Mutations;
+  NullablePtr<Operand> CurrentOp;
+
+public:
+  NonEscapingUserVisitor(Operand *Op,
+                         llvm::SmallVectorImpl<SILInstruction *> &Mutations)
+      : Worklist(), Mutations(Mutations), CurrentOp() {
+    Worklist.push_back(Op);
+  }
+
+  NonEscapingUserVisitor(const NonEscapingUserVisitor &) = delete;
+  NonEscapingUserVisitor &operator=(const NonEscapingUserVisitor &) = delete;
+  NonEscapingUserVisitor(NonEscapingUserVisitor &&) = delete;
+  NonEscapingUserVisitor &operator=(NonEscapingUserVisitor &&) = delete;
+
+  bool compute() {
+    while (!Worklist.empty()) {
+      CurrentOp = Worklist.pop_back_val();
+      SILInstruction *User = CurrentOp.get()->getUser();
+
+      // Ignore type dependent operands.
+      if (User->isTypeDependentOperand(*(CurrentOp.get())))
+        continue;
+
+      // Then visit the specific user. This routine returns true if the value
+      // does not escape. In such a case, continue.
+      if (visit(User)) {
+        continue;
+      }
+
+      return false;
+    }
+
+    return true;
+  }
+
+  /// Visit a random value base.
+  ///
+  /// These are considered to be escapes.
+  bool visitValueBase(ValueBase *V) {
+    DEBUG(llvm::dbgs() << "    FAIL! Have unknown escaping user: " << *V);
+    return false;
+  }
+
+#define ALWAYS_NON_ESCAPING_INST(INST)                                         \
+  bool visit##INST##Inst(INST##Inst *V) { return true; }
+  // Marking the boxed value as escaping is OK. It's just a DI annotation.
+  ALWAYS_NON_ESCAPING_INST(MarkFunctionEscape)
+  // These remaining instructions are ok and don't count as mutations.
+  ALWAYS_NON_ESCAPING_INST(StrongRetain)
+  ALWAYS_NON_ESCAPING_INST(Load)
+  ALWAYS_NON_ESCAPING_INST(StrongRelease)
+  ALWAYS_NON_ESCAPING_INST(DestroyValue)
+#undef ALWAYS_NON_ESCAPING_INST
+
+  bool visitDeallocBoxInst(DeallocBoxInst *DBI) {
+    Mutations.push_back(DBI);
+    return true;
+  }
+
+  bool visitApplyInst(ApplyInst *AI) {
+    auto argIndex = CurrentOp.get()->getOperandNumber() - 1;
+    SILFunctionConventions substConv(AI->getSubstCalleeType(), AI->getModule());
+    auto convention = substConv.getSILArgumentConvention(argIndex);
+    if (!convention.isIndirectConvention()) {
+      DEBUG(llvm::dbgs() << "    FAIL! Found non indirect apply user: " << *AI);
+      return false;
+    }
+    Mutations.push_back(AI);
+    return true;
+  }
+
+  /// Add the Operands of a transitive use instruction to the worklist.
+  void addUserOperandsToWorklist(SILInstruction *I) {
+    for (auto *User : I->getUses()) {
+      Worklist.push_back(User);
+    }
+  }
+
+  /// This is separate from the normal copy value handling since we are matching
+  /// the old behavior of non-top-level uses not being able to have partial
+  /// apply and project box uses.
+  struct detail {
+  enum IsMutating_t {
+    IsNotMutating = 0,
+    IsMutating = 1,
+  };
+  };
+#define RECURSIVE_INST_VISITOR(MUTATING, INST)    \
+  bool visit##INST##Inst(INST##Inst *I) {         \
+    if (bool(detail::MUTATING)) {                 \
+      Mutations.push_back(I);                     \
+    }                                             \
+    addUserOperandsToWorklist(I);                 \
+    return true;                                  \
+  }
+  // *NOTE* It is important that we do not have copy_value here. The reason why
+  // is that we only want to handle copy_value directly of the alloc_box without
+  // going through any other instructions. This protects our optimization later
+  // on.
+  //
+  // Additionally, copy_value is not a valid use of any of the instructions that
+  // we allow through.
+  //
+  // TODO: Can we ever hit copy_values here? If we do, we may be missing
+  // opportunities.
+  RECURSIVE_INST_VISITOR(IsNotMutating, StructElementAddr)
+  RECURSIVE_INST_VISITOR(IsNotMutating, TupleElementAddr)
+  RECURSIVE_INST_VISITOR(IsNotMutating, InitEnumDataAddr)
+  RECURSIVE_INST_VISITOR(IsNotMutating, OpenExistentialAddr)
+  RECURSIVE_INST_VISITOR(IsMutating   , UncheckedTakeEnumDataAddr)
+#undef RECURSIVE_INST_VISITOR
+
+  bool visitCopyAddrInst(CopyAddrInst *CAI) {
+    if (CurrentOp.get()->getOperandNumber() == 1 || CAI->isTakeOfSrc())
+      Mutations.push_back(CAI);
+    return true;
+  }
+
+  bool visitStoreInst(StoreInst *SI) {
+    if (CurrentOp.get()->getOperandNumber() != 1) {
+      DEBUG(llvm::dbgs() << "    FAIL! Found store of pointer: " << *SI);
+      return false;
+    }
+    Mutations.push_back(SI);
+    return true;
+  }
+
+  bool visitAssignInst(AssignInst *AI) {
+    if (CurrentOp.get()->getOperandNumber() != 1) {
+      DEBUG(llvm::dbgs() << "    FAIL! Found store of pointer: " << *AI);
+      return false;
+    }
+    Mutations.push_back(AI);
+    return true;
+  }
+};
+
+} // end anonymous namespace
+
+namespace {
+
+struct EscapeMutationScanningState {
+  /// The list of mutations that we found while checking for escapes.
+  llvm::SmallVector<SILInstruction *, 8> Mutations;
+
+  /// A flag that we use to ensure that we only ever see 1 project_box on an
+  /// alloc_box.
+  bool SawProjectBoxInst;
+
+  /// The global partial_apply -> index map.
+  llvm::DenseMap<PartialApplyInst *, unsigned> &IM;
+};
+
+} // end anonymous namespace
+
 /// \brief Given a use of an alloc_box instruction, return true if the use
 /// definitely does not allow the box to escape; also, if the use is an
 /// instruction which possibly mutates the contents of the box, then add it to
 /// the Mutations vector.
-static bool
-isNonescapingUse(Operand *O, SmallVectorImpl<SILInstruction*> &Mutations) {
-  auto *U = O->getUser();
-  if (U->isTypeDependentOperand(*O))
-    return true;
-  // Marking the boxed value as escaping is OK. It's just a DI annotation.
-  if (isa<MarkFunctionEscapeInst>(U))
-    return true;
-  
-  // A store or assign is ok if the alloc_box is the destination.
-  if (isa<StoreInst>(U) || isa<AssignInst>(U)) {
-    if (O->getOperandNumber() != 1)
-      return false;
-    Mutations.push_back(cast<SILInstruction>(U));
-    return true;
-  }
-  // copy_addr is ok, but counts as a mutation if the use is as the
-  // destination or the copy_addr is a take.
-  if (auto *CAI = dyn_cast<CopyAddrInst>(U)) {
-    if (O->getOperandNumber() == 1 || CAI->isTakeOfSrc())
-      Mutations.push_back(CAI);
-    return true;
-  }
-  // Recursively see through struct_element_addr, tuple_element_addr, and
-  // open_existential_addr instructions.
-  if (isa<StructElementAddrInst>(U) || isa<TupleElementAddrInst>(U) ||
-      isa<InitEnumDataAddrInst>(U) ||
-      isa<OpenExistentialAddrInst>(U) || isa<UncheckedTakeEnumDataAddrInst>(U)) {
-    // UncheckedTakeEnumDataAddr is additionally a mutation.
-    if (isa<UncheckedTakeEnumDataAddrInst>(U))
-      Mutations.push_back(U);
-    
-    for (auto *UO : U->getUses())
-      if (!isNonescapingUse(UO, Mutations))
-        return false;
-    return true;
-  }
-  // An apply is ok if the argument is used as an inout parameter or an
-  // indirect return, but counts as a possible mutation in both cases.
-  if (auto *AI = dyn_cast<ApplyInst>(U)) {
-    auto argIndex = O->getOperandNumber()-1;
-    SILFunctionConventions substConv(AI->getSubstCalleeType(), AI->getModule());
-    auto convention = substConv.getSILArgumentConvention(argIndex);
-    if (convention.isIndirectConvention()) {
-      Mutations.push_back(AI);
-      return true;
-    }
+static bool isNonEscapingUse(Operand *InitialOp,
+                             EscapeMutationScanningState &State) {
+  return NonEscapingUserVisitor(InitialOp, State.Mutations).compute();
+}
+
+bool isPartialApplyNonEscapingUser(Operand *CurrentOp, PartialApplyInst *PAI,
+                                   EscapeMutationScanningState &State) {
+  DEBUG(llvm::dbgs() << "    Found partial: " << *PAI);
+
+  unsigned OpNo = CurrentOp->getOperandNumber();
+  assert(OpNo != 0 && "Alloc box used as callee of partial apply?");
+
+  // If we've already seen this partial apply, then it means the same alloc
+  // box is being captured twice by the same closure, which is odd and
+  // unexpected: bail instead of trying to handle this case.
+  if (State.IM.count(PAI)) {
+    DEBUG(llvm::dbgs() << "        FAIL! Already seen.\n");
     return false;
   }
-  // These instructions are ok but count as mutations.
-  if (isa<DeallocBoxInst>(U)) {
-    Mutations.push_back(cast<SILInstruction>(U));
-    return true;
+
+  SILModule &M = PAI->getModule();
+  auto closureType = PAI->getType().castTo<SILFunctionType>();
+  SILFunctionConventions closureConv(closureType, M);
+
+  // Calculate the index into the closure's argument list of the captured
+  // box pointer (the captured address is always the immediately following
+  // index so is not stored separately);
+  unsigned Index = OpNo - 1 + closureConv.getNumSILArguments();
+
+  auto *Fn = PAI->getReferencedFunction();
+  if (!Fn || !Fn->isDefinition()) {
+    DEBUG(llvm::dbgs() << "        FAIL! Not a direct function definition "
+                          "reference.\n");
+    return false;
   }
-  // These remaining instructions are ok and don't count as mutations.
-  if (isa<StrongRetainInst>(U) || isa<StrongReleaseInst>(U) ||
-      isa<LoadInst>(U))
-    return true;
-  return false;
+
+  SILArgument *BoxArg = getBoxFromIndex(Fn, Index);
+
+  // For now, return false is the address argument is an address-only type,
+  // since we currently handle loadable types only.
+  // TODO: handle address-only types
+  auto BoxTy = BoxArg->getType().castTo<SILBoxType>();
+  assert(BoxTy->getLayout()->getFields().size() == 1 &&
+         "promoting compound box not implemented yet");
+  if (BoxTy->getFieldType(M, 0).isAddressOnly(M)) {
+    DEBUG(llvm::dbgs() << "        FAIL! Box is an address only argument!\n");
+    return false;
+  }
+
+  // Verify that this closure is known not to mutate the captured value; if
+  // it does, then conservatively refuse to promote any captures of this
+  // value.
+  if (!isNonMutatingCapture(BoxArg)) {
+    DEBUG(llvm::dbgs() << "        FAIL: Have a mutating capture!\n");
+    return false;
+  }
+
+  // Record the index and continue.
+  DEBUG(llvm::dbgs()
+        << "        Partial apply does not escape, may be optimizable!\n");
+  DEBUG(llvm::dbgs() << "        Index: " << Index << "\n");
+  State.IM.insert(std::make_pair(PAI, Index));
+  return true;
+}
+
+static bool isProjectBoxNonEscapingUse(ProjectBoxInst *PBI,
+                                       EscapeMutationScanningState &State) {
+  DEBUG(llvm::dbgs() << "    Found project box: " << *PBI);
+
+  // Check for mutations of the address component.
+  SILValue Addr = PBI;
+
+  // If the AllocBox is used by a mark_uninitialized, scan the MUI for
+  // interesting uses.
+  if (Addr->hasOneUse()) {
+    SILInstruction *SingleAddrUser = Addr->use_begin()->getUser();
+    if (isa<MarkUninitializedInst>(SingleAddrUser))
+      Addr = SILValue(SingleAddrUser);
+  }
+
+  for (Operand *AddrOp : Addr->getUses()) {
+    if (!isNonEscapingUse(AddrOp, State)) {
+      DEBUG(llvm::dbgs() << "    FAIL! Has escaping user of addr:"
+                         << *AddrOp->getUser());
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool scanUsesForEscapesAndMutations(Operand *Op,
+                                           EscapeMutationScanningState &State) {
+  if (auto *PAI = dyn_cast<PartialApplyInst>(Op->getUser())) {
+    return isPartialApplyNonEscapingUser(Op, PAI, State);
+  }
+
+  if (auto *PBI = dyn_cast<ProjectBoxInst>(Op->getUser())) {
+    // It is assumed in later code that we will only have 1 project_box. This
+    // can be seen since there is no code for reasoning about multiple
+    // boxes. Just put in the restriction so we are consistent.
+    if (State.SawProjectBoxInst)
+      return false;
+    State.SawProjectBoxInst = true;
+    return isProjectBoxNonEscapingUse(PBI, State);
+  }
+
+  // Given a top level copy value use, check all of its user operands as if
+  // they were apart of the use list of the base operand.
+  //
+  // This is because even though we are copying the box, a copy of the box is
+  // just a retain + bitwise copy of the pointer. This has nothing to do with
+  // whether or not the address escapes in some way.
+  //
+  // This is a separate code path from the non escaping user visitor check since
+  // we want to be more conservative around non-top level copies (i.e. a copy
+  // derived from a projection like instruction). In fact such a thing may not
+  // even make any sense!
+  if (auto *CVI = dyn_cast<CopyValueInst>(Op->getUser())) {
+    return all_of(CVI->getUses(), [&State](Operand *CopyOp) -> bool {
+      return scanUsesForEscapesAndMutations(CopyOp, State);
+    });
+  }
+
+  // Verify that this use does not otherwise allow the alloc_box to
+  // escape.
+  return isNonEscapingUse(Op, State);
 }
 
 /// \brief Examine an alloc_box instruction, returning true if at least one
@@ -702,78 +1036,21 @@
 /// argument list is added to IM.
 static bool
 examineAllocBoxInst(AllocBoxInst *ABI, ReachabilityInfo &RI,
-                    llvm::DenseMap<PartialApplyInst*, unsigned> &IM) {
-  SmallVector<SILInstruction*, 32> Mutations;
-  
+                    llvm::DenseMap<PartialApplyInst *, unsigned> &IM) {
+  DEBUG(llvm::dbgs() << "Visiting alloc box: " << *ABI);
+  EscapeMutationScanningState State{{}, false, IM};
+
   // Scan the box for interesting uses.
-  for (Operand *O : ABI->getUses()) {
-    if (auto *PAI = dyn_cast<PartialApplyInst>(O->getUser())) {
-      unsigned OpNo = O->getOperandNumber();
-      assert(OpNo != 0 && "Alloc box used as callee of partial apply?");
-
-      // If we've already seen this partial apply, then it means the same alloc
-      // box is being captured twice by the same closure, which is odd and
-      // unexpected: bail instead of trying to handle this case.
-      if (IM.count(PAI))
-        return false;
-
-      SILModule &M = PAI->getModule();
-      auto closureType = PAI->getType().castTo<SILFunctionType>();
-      SILFunctionConventions closureConv(closureType, M);
-
-      // Calculate the index into the closure's argument list of the captured
-      // box pointer (the captured address is always the immediately following
-      // index so is not stored separately);
-      unsigned Index = OpNo - 1 + closureConv.getNumSILArguments();
-
-      auto *Fn = PAI->getReferencedFunction();
-      if (!Fn || !Fn->isDefinition())
-        return false;
-
-      SILArgument *BoxArg = getBoxFromIndex(Fn, Index);
-
-      // For now, return false is the address argument is an address-only type,
-      // since we currently handle loadable types only.
-      // TODO: handle address-only types
-      auto BoxTy = BoxArg->getType().castTo<SILBoxType>();
-      assert(BoxTy->getLayout()->getFields().size() == 1
-             && "promoting compound box not implemented yet");
-      if (BoxTy->getFieldType(M, 0).isAddressOnly(M))
-        return false;
-
-      // Verify that this closure is known not to mutate the captured value; if
-      // it does, then conservatively refuse to promote any captures of this
-      // value.
-      if (!isNonmutatingCapture(BoxArg))
-        return false;
-
-      // Record the index and continue.
-      IM.insert(std::make_pair(PAI, Index));
-      continue;
-    }
-    if (auto *PBI = dyn_cast<ProjectBoxInst>(O->getUser())) {
-      // Check for mutations of the address component.
-      SILValue Addr = PBI;
-      // If the AllocBox is used by a mark_uninitialized, scan the MUI for
-      // interesting uses.
-      if (Addr->hasOneUse()) {
-        SILInstruction *SingleAddrUser = Addr->use_begin()->getUser();
-        if (isa<MarkUninitializedInst>(SingleAddrUser))
-          Addr = SILValue(SingleAddrUser);
-      }
-
-      for (Operand *AddrOp : Addr->getUses()) {
-        if (!isNonescapingUse(AddrOp, Mutations))
-          return false;
-      }
-      continue;
-    }
-    // Verify that this use does not otherwise allow the alloc_box to
-    // escape.
-    if (!isNonescapingUse(O, Mutations))
-      return false;
+  if (any_of(ABI->getUses(), [&State](Operand *Op) {
+        return !scanUsesForEscapesAndMutations(Op, State);
+      })) {
+    DEBUG(llvm::dbgs()
+          << "Found an escaping use! Can not optimize this alloc box?!\n");
+    return false;
   }
 
+  DEBUG(llvm::dbgs() << "We can optimize this alloc box!\n");
+
   // Helper lambda function to determine if instruction b is strictly after
   // instruction a, assuming both are in the same basic block.
   auto isAfter = [](SILInstruction *a, SILInstruction *b) {
@@ -788,8 +1065,10 @@
     return false;
   };
 
+  DEBUG(llvm::dbgs()
+        << "Checking for any mutations that invalidate captures...\n");
   // Loop over all mutations to possibly invalidate captures.
-  for (auto *I : Mutations) {
+  for (auto *I : State.Mutations) {
     auto Iter = IM.begin();
     while (Iter != IM.end()) {
       auto *PAI = Iter->first;
@@ -798,6 +1077,8 @@
       // block is after the partial_apply.
       if (RI.isReachable(PAI->getParent(), I->getParent()) ||
           (PAI->getParent() == I->getParent() && isAfter(PAI, I))) {
+        DEBUG(llvm::dbgs() << "    Invalidating: " << *PAI);
+        DEBUG(llvm::dbgs() << "    Because of user: " << *I);
         auto Prev = Iter++;
         IM.erase(Prev);
         continue;
@@ -805,10 +1086,13 @@
       ++Iter;
     }
     // If there are no valid captures left, then stop.
-    if (IM.empty())
+    if (IM.empty()) {
+      DEBUG(llvm::dbgs() << "    Ran out of valid captures... bailing!\n");
       return false;
+    }
   }
 
+  DEBUG(llvm::dbgs() << "    We can optimize this box!\n");
   return true;
 }
 
@@ -838,6 +1122,66 @@
   return cloner.getCloned();
 }
 
+/// For an alloc_box or iterated copy_value alloc_box, get or create the
+/// project_box for the copy or original alloc_box.
+///
+/// There are two possible case here:
+///
+/// 1. It could be an alloc box.
+/// 2. It could be an iterated copy_value from an alloc_box.
+///
+/// Some important constraints from our initial safety condition checks:
+///
+/// 1. We only see a project_box paired with an alloc_box. e.x.:
+///
+///       (project_box (alloc_box)).
+///
+/// 2. We only see a mark_uninitialized when paired with an (alloc_box,
+///    project_box). e.x.:
+///
+///       (mark_uninitialized (project_box (alloc_box)))
+///
+/// The asserts are to make sure that if the initial safety condition check
+/// is changed, this code is changed as well.
+static SILValue getOrCreateProjectBoxHelper(SILValue PartialOperand) {
+  // If we have a copy_value, just create a project_box on the copy and return.
+  if (auto *CVI = dyn_cast<CopyValueInst>(PartialOperand)) {
+    SILBuilder B(std::next(CVI->getIterator()));
+    return B.createProjectBox(CVI->getLoc(), CVI, 0);
+  }
+
+  // Otherwise, handle the alloc_box case.
+  auto *ABI = cast<AllocBoxInst>(PartialOperand);
+  // Load and copy from the address value, passing the result as an argument
+  // to the new closure.
+  //
+  // *NOTE* This code assumes that we only have one project box user. We
+  // enforce this with the assert below.
+  assert(count_if(ABI->getUses(), [](Operand *Op) -> bool {
+           return isa<ProjectBoxInst>(Op->getUser());
+         }) == 1);
+
+  // If the address is marked uninitialized, load through the mark, so
+  // that DI can reason about it.
+  for (Operand *BoxValueUse : ABI->getUses()) {
+    auto *PBI = dyn_cast<ProjectBoxInst>(BoxValueUse->getUser());
+    if (!PBI)
+      continue;
+
+    auto *OptIter = PBI->getSingleUse();
+    if (!OptIter)
+      continue;
+
+    if (!isa<MarkUninitializedInst>(OptIter->getUser()))
+      continue;
+
+    return OptIter->getUser();
+  }
+
+  // Otherwise, just return a project_box.
+  return getOrCreateProjectBox(ABI, 0);
+}
+
 /// \brief Given a partial_apply instruction and a set of promotable indices,
 /// clone the closure with the promoted captures and replace the partial_apply
 /// with a partial_apply of the new closure, fixing up reference counting as
@@ -863,54 +1207,44 @@
   // Populate the argument list for a new partial_apply instruction, taking into
   // consideration any captures.
   auto CalleeFunctionTy = PAI->getCallee()->getType().castTo<SILFunctionType>();
-  SILFunctionConventions calleeConv(CalleeFunctionTy, M);
-  auto CalleePInfo = CalleeFunctionTy->getParameters();
+  auto SubstCalleeFunctionTy = CalleeFunctionTy;
+  if (PAI->hasSubstitutions())
+    SubstCalleeFunctionTy =
+        CalleeFunctionTy->substGenericArgs(M, PAI->getSubstitutions());
+  SILFunctionConventions calleeConv(SubstCalleeFunctionTy, M);
+  auto CalleePInfo = SubstCalleeFunctionTy->getParameters();
   SILFunctionConventions paConv(PAI->getType().castTo<SILFunctionType>(), M);
   unsigned FirstIndex = paConv.getNumSILArguments();
   unsigned OpNo = 1, OpCount = PAI->getNumOperands();
   SmallVector<SILValue, 16> Args;
   auto NumIndirectResults = calleeConv.getNumIndirectSILResults();
-  while (OpNo != OpCount) {
+  for (; OpNo != OpCount; ++OpNo) {
     unsigned Index = OpNo - 1 + FirstIndex;
-    if (PromotableIndices.count(Index)) {
-      SILValue BoxValue = PAI->getOperand(OpNo);
-      AllocBoxInst *ABI = cast<AllocBoxInst>(BoxValue);
-
-      SILParameterInfo CPInfo = CalleePInfo[Index - NumIndirectResults];
-      assert(calleeConv.getSILType(CPInfo) == BoxValue->getType()
-             && "SILType of parameter info does not match type of parameter");
-      // Cleanup the captured argument.
-      releasePartialApplyCapturedArg(B, PAI->getLoc(), BoxValue,
-                                     CPInfo);
-
-      // Load and copy from the address value, passing the result as an argument
-      // to the new closure.
-      SILValue Addr;
-      for (Operand *BoxUse : ABI->getUses()) {
-        auto *PBI = dyn_cast<ProjectBoxInst>(BoxUse->getUser());
-          // If the address is marked uninitialized, load through the mark, so
-          // that DI can reason about it.
-        if (PBI && PBI->hasOneUse()) {
-          SILInstruction *PBIUser = PBI->use_begin()->getUser();
-          if (isa<MarkUninitializedInst>(PBIUser))
-            Addr = PBIUser;
-          break;
-        }
-      }
-      // We only reuse an existing project_box if it directly follows the
-      // alloc_box. This makes sure that the project_box dominates the
-      // partial_apply.
-      if (!Addr)
-        Addr = getOrCreateProjectBox(ABI, 0);
-
-      auto &typeLowering = M.getTypeLowering(Addr->getType());
-      Args.push_back(
-        typeLowering.emitLoadOfCopy(B, PAI->getLoc(), Addr, IsNotTake));
-      ++NumCapturesPromoted;
-    } else {
+    if (!PromotableIndices.count(Index)) {
       Args.push_back(PAI->getOperand(OpNo));
+      continue;
     }
-    ++OpNo;
+
+    // First the grab the box and projected_box for the box value.
+    //
+    // *NOTE* Box may be a copy_value.
+    SILValue Box = PAI->getOperand(OpNo);
+    SILValue Addr = getOrCreateProjectBoxHelper(Box);
+
+    auto &typeLowering = M.getTypeLowering(Addr->getType());
+    Args.push_back(
+        typeLowering.emitLoadOfCopy(B, PAI->getLoc(), Addr, IsNotTake));
+
+    // Cleanup the captured argument.
+    //
+    // *NOTE* If we initially had a box, then this is on the actual
+    // alloc_box. Otherwise, it is on the specific iterated copy_value that we
+    // started with.
+    SILParameterInfo CPInfo = CalleePInfo[Index - NumIndirectResults];
+    assert(calleeConv.getSILType(CPInfo) == Box->getType() &&
+           "SILType of parameter info does not match type of parameter");
+    releasePartialApplyCapturedArg(B, PAI->getLoc(), Box, CPInfo);
+    ++NumCapturesPromoted;
   }
 
   auto SubstFnTy = FnTy.substGenericArgs(M, PAI->getSubstitutions());
@@ -949,31 +1283,38 @@
           for (auto &IndexPair : IndexMap)
             Map[IndexPair.first].insert(IndexPair.second);
         }
+        DEBUG(llvm::dbgs() << "\n");
       }
     }
   }
 }
 
 namespace {
+
 class CapturePromotionPass : public SILModuleTransform {
   /// The entry point to the transformation.
   void run() override {
     SmallVector<SILFunction*, 128> Worklist;
-    for (auto &F : *getModule())
+    for (auto &F : *getModule()) {
       processFunction(&F, Worklist);
+    }
 
-    while (!Worklist.empty())
+    while (!Worklist.empty()) {
       processFunction(Worklist.pop_back_val(), Worklist);
+    }
   }
 
   void processFunction(SILFunction *F, SmallVectorImpl<SILFunction*> &Worklist);
 
   StringRef getName() override { return "Capture Promotion"; }
 };
+
 } // end anonymous namespace
 
 void CapturePromotionPass::processFunction(SILFunction *F,
                                       SmallVectorImpl<SILFunction*> &Worklist) {
+  DEBUG(llvm::dbgs() << "******** Performing Capture Promotion on: "
+                     << F->getName() << "********\n");
   // This is a map from each partial apply to a set of indices of promotable
   // box variables.
   PartialApplyIndicesMap IndicesMap;
diff --git a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp
index 8e76604..961306a 100644
--- a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp
+++ b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp
@@ -489,6 +489,8 @@
   case ArrayCallKind::kWithUnsafeMutableBufferPointer:
   case ArrayCallKind::kArrayInit:
   case ArrayCallKind::kArrayUninitialized:
+  case ArrayCallKind::kAppendContentsOf:
+  case ArrayCallKind::kAppendElement:
     return false;
   }
 
@@ -825,6 +827,8 @@
   case ArrayCallKind::kWithUnsafeMutableBufferPointer:
   case ArrayCallKind::kArrayInit:
   case ArrayCallKind::kArrayUninitialized:
+  case ArrayCallKind::kAppendContentsOf:
+  case ArrayCallKind::kAppendElement:
     return true;
   }
 
diff --git a/lib/SILOptimizer/Mandatory/CMakeLists.txt b/lib/SILOptimizer/Mandatory/CMakeLists.txt
index 24ff2f0..c26c8a1 100644
--- a/lib/SILOptimizer/Mandatory/CMakeLists.txt
+++ b/lib/SILOptimizer/Mandatory/CMakeLists.txt
@@ -8,4 +8,5 @@
   Mandatory/MandatoryInlining.cpp
   Mandatory/PredictableMemOpt.cpp
   Mandatory/ConstantPropagation.cpp
+  Mandatory/SemanticARCOpts.cpp
   PARENT_SCOPE)
diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
index ef3e7fe..f672de8 100644
--- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
+++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
@@ -18,6 +18,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/SaveAndRestore.h"
 #include "llvm/ADT/StringExtras.h"
+
 using namespace swift;
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp b/lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp
index 300b73df..d25ffc1 100644
--- a/lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp
+++ b/lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp
@@ -14,9 +14,12 @@
 #include "swift/SILOptimizer/PassManager/Passes.h"
 #include "swift/SILOptimizer/PassManager/Transforms.h"
 #include "swift/SIL/SILVisitor.h"
+#include "llvm/ADT/Statistic.h"
 
 using namespace swift;
 
+STATISTIC(NumInstsEliminated, "Number of instructions eliminated");
+
 namespace {
 
 struct GuaranteedARCOptsVisitor
@@ -47,6 +50,7 @@
       if (CA->getSrc() == Operand && !CA->isTakeOfSrc()) {
         CA->setIsTakeOfSrc(IsTake);
         DAI->eraseFromParent();
+        NumInstsEliminated += 2;
         return true;
       }
     }
@@ -107,6 +111,7 @@
   // Release on a functionref is a noop.
   if (isa<FunctionRefInst>(Operand)) {
     SRI->eraseFromParent();
+    ++NumInstsEliminated;
     return true;
   }
 
@@ -121,6 +126,7 @@
       if (SRA->getOperand() == Operand) {
         SRA->eraseFromParent();
         SRI->eraseFromParent();
+        NumInstsEliminated += 2;
         return true;
       }
       // Skip past unrelated retains.
@@ -148,6 +154,7 @@
         CVI->replaceAllUsesWith(CVI->getOperand());
         CVI->eraseFromParent();
         DVI->eraseFromParent();
+        NumInstsEliminated += 2;
         return true;
       }
       // Skip past unrelated retains.
@@ -174,6 +181,7 @@
       if (SRA->getOperand() == Operand) {
         SRA->eraseFromParent();
         RVI->eraseFromParent();
+        NumInstsEliminated += 2;
         return true;
       }
       // Skip past unrelated retains.
diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
index 80767e1..6de006d 100644
--- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
+++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
@@ -100,7 +100,10 @@
     auto *Inst = cast<SILInstruction>(Pointer);
     if (auto *PBI = dyn_cast<ProjectBoxInst>(Inst)) {
       Pointer = PBI->getOperand();
-    } else if (auto *TEAI = dyn_cast<TupleElementAddrInst>(Inst)) {
+      continue;
+    }
+
+    if (auto *TEAI = dyn_cast<TupleElementAddrInst>(Inst)) {
       SILType TT = TEAI->getOperand()->getType();
       
       // Keep track of what subelement is being referenced.
@@ -108,7 +111,10 @@
         SubEltNumber += getNumSubElements(TT.getTupleElementType(i), M);
       }
       Pointer = TEAI->getOperand();
-    } else if (auto *SEAI = dyn_cast<StructElementAddrInst>(Inst)) {
+      continue;
+    }
+
+    if (auto *SEAI = dyn_cast<StructElementAddrInst>(Inst)) {
       SILType ST = SEAI->getOperand()->getType();
       
       // Keep track of what subelement is being referenced.
@@ -119,12 +125,14 @@
       }
       
       Pointer = SEAI->getOperand();
-    } else {
-      assert((isa<InitExistentialAddrInst>(Inst) || isa<InjectEnumAddrInst>(Inst))&&
-             "Unknown access path instruction");
-      // Cannot promote loads and stores from within an existential projection.
-      return ~0U;
+      continue;
     }
+
+    
+    assert((isa<InitExistentialAddrInst>(Inst) || isa<InjectEnumAddrInst>(Inst))&&
+           "Unknown access path instruction");
+    // Cannot promote loads and stores from within an existential projection.
+    return ~0U;
   }
 }
 
diff --git a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp
new file mode 100644
index 0000000..3d2ed46
--- /dev/null
+++ b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp
@@ -0,0 +1,174 @@
+//===--- SemanticARCOpts.cpp ----------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "sil-semantic-arc-opts"
+#include "swift/SIL/OwnershipChecker.h"
+#include "swift/SIL/SILArgument.h"
+#include "swift/SIL/SILInstruction.h"
+#include "swift/SIL/TransitivelyUnreachableBlocks.h"
+#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
+#include "swift/SILOptimizer/PassManager/Passes.h"
+#include "swift/SILOptimizer/PassManager/Transforms.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+
+using namespace swift;
+
+STATISTIC(NumEliminatedInsts, "number of removed instructions");
+
+static bool optimizeGuaranteedArgument(SILArgument *Arg,
+                                       OwnershipChecker &Checker) {
+  bool MadeChange = false;
+
+  // Gather all copy_value users of Arg.
+  llvm::SmallVector<CopyValueInst *, 4> Worklist;
+  for (auto *Op : Arg->getUses()) {
+    if (auto *CVI = dyn_cast<CopyValueInst>(Op->getUser())) {
+      Worklist.push_back(CVI);
+    }
+  }
+
+  // Then until we run out of copies...
+  while (!Worklist.empty()) {
+    auto *CVI = Worklist.pop_back_val();
+
+    // Quickly see if copy has only one use and that use is a destroy_value. In
+    // such a case, we can always eliminate both the copy and the destroy.
+    if (auto *Op = CVI->getSingleUse()) {
+      if (auto *DVI = dyn_cast<DestroyValueInst>(Op->getUser())) {
+        DVI->eraseFromParent();
+        CVI->eraseFromParent();
+        NumEliminatedInsts += 2;
+        continue;
+      }
+    }
+
+    // Ok, now run the checker on the copy value. If it fails, then we just
+    // continue.
+    if (!Checker.checkValue(CVI))
+      continue;
+
+    // Otherwise, lets do a quick check on what the checker thinks the lifetime
+    // ending and non-lifetime ending users. To be conservative, we bail unless
+    // each lifetime ending use is a destroy_value and if each non-lifetime
+    // ending use is one of the following instructions:
+    //
+    // 1. copy_value.
+    // 2. begin_borrow.
+    // 3. end_borrow.
+    if (!all_of(Checker.LifetimeEndingUsers, [](SILInstruction *I) -> bool {
+          return isa<DestroyValueInst>(I);
+        }))
+      continue;
+
+    // Extra copy values that we should visit recursively.
+    llvm::SmallVector<CopyValueInst *, 8> NewCopyInsts;
+    llvm::SmallVector<SILInstruction *, 8> NewBorrowInsts;
+    if (!all_of(Checker.RegularUsers, [&](SILInstruction *I) -> bool {
+          if (auto *CVI = dyn_cast<CopyValueInst>(I)) {
+            NewCopyInsts.push_back(CVI);
+            return true;
+          }
+
+          if (!isa<BeginBorrowInst>(I) && !isa<EndBorrowInst>(I))
+            return false;
+
+          NewBorrowInsts.push_back(I);
+          return true;
+        }))
+      continue;
+
+    // Ok! we can remove the copy_value, destroy_values!
+    MadeChange = true;
+    CVI->replaceAllUsesWith(CVI->getOperand());
+    CVI->eraseFromParent();
+    ++NumEliminatedInsts;
+
+    while (!Checker.LifetimeEndingUsers.empty()) {
+      Checker.LifetimeEndingUsers.pop_back_val()->eraseFromParent();
+      ++NumEliminatedInsts;
+    }
+
+    // Then add the copy_values that were users of our original copy value to
+    // the worklist.
+    while (!NewCopyInsts.empty()) {
+      Worklist.push_back(NewCopyInsts.pop_back_val());
+    }
+
+    // Then remove any begin/end borrow that we found. These are unneeded since
+    // the lifetime guarantee from the argument exists above and beyond said
+    // scope.
+    while (!NewBorrowInsts.empty()) {
+      SILInstruction *I = NewBorrowInsts.pop_back_val();
+      if (auto *BBI = dyn_cast<BeginBorrowInst>(I)) {
+        // Any copy_value that is used by the begin borrow is added to the
+        // worklist.
+        for (auto *BBIUse : BBI->getUses()) {
+          if (auto *BBIUseCopyValue =
+                  dyn_cast<CopyValueInst>(BBIUse->getUser())) {
+            Worklist.push_back(BBIUseCopyValue);
+          }
+        }
+        BBI->replaceAllUsesWith(BBI->getOperand());
+        BBI->eraseFromParent();
+        ++NumEliminatedInsts;
+        continue;
+      }
+
+      // This is not necessary, but it does add a check.
+      auto *EBI = cast<EndBorrowInst>(I);
+      EBI->eraseFromParent();
+      ++NumEliminatedInsts;
+    }
+  }
+
+  return MadeChange;
+}
+
+//===----------------------------------------------------------------------===//
+//                            Top Level Entrypoint
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+struct SemanticARCOpts : SILFunctionTransform {
+  void run() override {
+    bool MadeChange = false;
+    SILFunction *F = getFunction();
+
+    auto *PO = PM->getAnalysis<PostOrderAnalysis>()->get(F);
+    TransitivelyUnreachableBlocksInfo TUB(*PO);
+    OwnershipChecker Checker{F->getModule(), TUB, {}, {}, {}};
+
+    // First as a special case, handle guaranteed SIL function arguments.
+    //
+    // The reason that this is special is that we do not need to consider the
+    // end of the borrow scope since the end of the function is the end of the
+    // borrow scope.
+    for (auto *Arg : F->getArguments()) {
+      if (Arg->getOwnershipKind() != ValueOwnershipKind::Guaranteed)
+        continue;
+      MadeChange |= optimizeGuaranteedArgument(Arg, Checker);
+    }
+
+    if (MadeChange) {
+      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
+    }
+  }
+
+  StringRef getName() override { return "Semantic ARC Opts"; }
+};
+
+} // end anonymous namespace
+
+SILTransform *swift::createSemanticARCOpts() { return new SemanticARCOpts(); }
diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp
index 57be946..9672806 100644
--- a/lib/SILOptimizer/PassManager/PassPipeline.cpp
+++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp
@@ -71,10 +71,16 @@
   P.addOwnershipModelEliminator();
 }
 
-static void addMandatoryOptPipeline(SILPassPipelinePlan &P) {
+static void addMandatoryOptPipeline(SILPassPipelinePlan &P,
+                                    const SILOptions &Options) {
   P.startPipeline("Guaranteed Passes");
+  if (Options.EnableMandatorySemanticARCOpts) {
+    P.addSemanticARCOpts();
+  }
   P.addCapturePromotion();
   P.addAllocBoxToStack();
+
+  P.addOwnershipModelEliminator();
   P.addNoReturnFolding();
   P.addDefiniteInitialization();
 
@@ -104,11 +110,8 @@
     return P;
   }
 
-  // Lower all ownership instructions right after SILGen for now.
-  addOwnershipModelEliminatorPipeline(P);
-
   // Otherwise run the rest of diagnostics.
-  addMandatoryOptPipeline(P);
+  addMandatoryOptPipeline(P, Options);
 
   if (SILViewGuaranteedCFG) {
     addCFGPrinterPipeline(P, "SIL View Guaranteed CFG");
@@ -212,6 +215,14 @@
   // Promote stack allocations to values.
   P.addMem2Reg();
 
+  // Cleanup, which is important if the inliner has restarted the pass pipeline.
+  P.addPerformanceConstantPropagation();
+  P.addSimplifyCFG();
+  P.addSILCombine();
+
+  // Mainly for Array.append(contentsOf) optimization.
+  P.addArrayElementPropagation();
+  
   // Run the devirtualizer, specializer, and inliner. If any of these
   // makes a change we'll end up restarting the function passes on the
   // current function (after optimizing any new callees).
diff --git a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp
index ec94f50..fc03897 100644
--- a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp
+++ b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp
@@ -1055,7 +1055,9 @@
     if (Kind == Release) {
       // TODO: we should consider Throw block as well, or better we should
       // abstract the Return block or Throw block away in the matcher.
-      ConsumedArgToEpilogueReleaseMatcher ERM(RCFI, F, 
+      SILArgumentConvention Conv[] = {SILArgumentConvention::Direct_Owned};
+      ConsumedArgToEpilogueReleaseMatcher ERM(RCFI, F,
+            Conv,
             ConsumedArgToEpilogueReleaseMatcher::ExitKind::Return);
 
       ReleaseCodeMotionContext RelCM(BPA, F, PO, AA, RCFI, 
diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
index a1b9089..d76b49f 100644
--- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
+++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
@@ -81,13 +81,21 @@
   return false;
 }
 
-// Walk backwards in BB looking for strong_release or dealloc_box of
-// the given value, and add it to Releases.
+static SILValue stripOffCopyValue(SILValue V) {
+  while (auto *CVI = dyn_cast<CopyValueInst>(V)) {
+    V = CVI->getOperand();
+  }
+  return V;
+}
+
+// Walk backwards in BB looking for strong_release, destroy_value, or
+// dealloc_box of the given value, and add it to releases.
 static bool addLastRelease(SILValue V, SILBasicBlock *BB,
                            llvm::SmallVectorImpl<SILInstruction*> &Releases) {
   for (auto I = BB->rbegin(); I != BB->rend(); ++I) {
-    if (isa<StrongReleaseInst>(*I) || isa<DeallocBoxInst>(*I)) {
-      if (I->getOperand(0) != V)
+    if (isa<StrongReleaseInst>(*I) || isa<DeallocBoxInst>(*I) ||
+        isa<DestroyValueInst>(*I)) {
+      if (stripOffCopyValue(I->getOperand(0)) != V)
         continue;
 
       Releases.push_back(&*I);
@@ -114,8 +122,10 @@
   // We'll treat this like a liveness problem where the alloc_box is
   // the def. Each block that has a use of the owning pointer has the
   // value live-in unless it is the block with the alloc_box.
-  for (auto UI : ABI->getUses()) {
-    auto *User = UI->getUser();
+  llvm::SmallVector<Operand *, 32> Worklist(ABI->use_begin(), ABI->use_end());
+  while (!Worklist.empty()) {
+    auto *Op = Worklist.pop_back_val();
+    auto *User = Op->getUser();
     auto *BB = User->getParent();
 
     if (isa<ProjectBoxInst>(User))
@@ -127,8 +137,18 @@
     // Also keep track of the blocks with uses.
     UseBlocks.insert(BB);
 
+    // If we have a copy value, add its uses to the work list and continue.
+    //
+    // We are actually performing multiple operations here. We are eliminating
+    // copies of the box and the box itself.
+    if (auto *CVI = dyn_cast<CopyValueInst>(User)) {
+      std::copy(CVI->use_begin(), CVI->use_end(), std::back_inserter(Worklist));
+      continue;
+    }
+
     // Try to speed up the trivial case of single release/dealloc.
-    if (isa<StrongReleaseInst>(User) || isa<DeallocBoxInst>(User)) {
+    if (isa<StrongReleaseInst>(User) || isa<DeallocBoxInst>(User) ||
+        isa<DestroyValueInst>(User)) {
       if (!seenRelease)
         OneRelease = User;
       else
@@ -162,10 +182,9 @@
   auto *User = UI->getUser();
 
   // These instructions do not cause the address to escape.
-  if (isa<DebugValueInst>(User) ||
-      isa<DebugValueAddrInst>(User) ||
-      isa<StrongReleaseInst>(User) ||
-      isa<StrongRetainInst>(User))
+  if (isa<DebugValueInst>(User) || isa<DebugValueAddrInst>(User) ||
+      isa<StrongReleaseInst>(User) || isa<StrongRetainInst>(User) ||
+      isa<DestroyValueInst>(User))
     return false;
 
   if (auto *Store = dyn_cast<StoreInst>(User)) {
@@ -180,41 +199,52 @@
 }
 
 static bool partialApplyEscapes(SILValue V, bool examineApply) {
-  SILModuleConventions modConv(*V->getModule());
-  for (auto UI : V->getUses()) {
-    auto *User = UI->getUser();
+  SILModuleConventions ModConv(*V->getModule());
+  llvm::SmallVector<Operand *, 32> Worklist(V->use_begin(), V->use_end());
+  while (!Worklist.empty()) {
+    auto *Op = Worklist.pop_back_val();
 
     // These instructions do not cause the address to escape.
-    if (!useCaptured(UI))
+    if (!useCaptured(Op))
       continue;
 
-    if (auto apply = dyn_cast<ApplyInst>(User)) {
+    auto *User = Op->getUser();
+
+    // If we have a copy_value, the copy value does not cause an escape, but its
+    // uses might do so... so add the copy_value's uses to the worklist and
+    // continue.
+    if (auto *Copy = dyn_cast<CopyValueInst>(User)) {
+      std::copy(Copy->use_begin(), Copy->use_end(),
+                std::back_inserter(Worklist));
+      continue;
+    }
+
+    if (auto *Apply = dyn_cast<ApplyInst>(User)) {
       // Applying a function does not cause the function to escape.
-      if (UI->getOperandNumber() == 0)
+      if (Op->getOperandNumber() == 0)
         continue;
 
       // apply instructions do not capture the pointer when it is passed
       // indirectly
-      if (apply->getArgumentConvention(UI->getOperandNumber() - 1)
+      if (Apply->getArgumentConvention(Op->getOperandNumber() - 1)
               .isIndirectConvention())
         continue;
 
       // Optionally drill down into an apply to see if the operand is
       // captured in or returned from the apply.
-      if (examineApply && !partialApplyArgumentEscapes(UI))
+      if (examineApply && !partialApplyArgumentEscapes(Op))
         continue;
     }
 
     // partial_apply instructions do not allow the pointer to escape
     // when it is passed indirectly, unless the partial_apply itself
     // escapes
-    if (auto partialApply = dyn_cast<PartialApplyInst>(User)) {
-      auto args = partialApply->getArguments();
-      auto params = partialApply->getSubstCalleeType()
-        ->getParameters();
-      params = params.slice(params.size() - args.size(), args.size());
-      if (modConv.isSILIndirect(params[UI->getOperandNumber() - 1])) {
-        if (partialApplyEscapes(partialApply, /*examineApply = */ true))
+    if (auto *PartialApply = dyn_cast<PartialApplyInst>(User)) {
+      auto Args = PartialApply->getArguments();
+      auto Params = PartialApply->getSubstCalleeType()->getParameters();
+      Params = Params.slice(Params.size() - Args.size(), Args.size());
+      if (ModConv.isSILIndirect(Params[Op->getOperandNumber() - 1])) {
+        if (partialApplyEscapes(PartialApply, /*examineApply = */ true))
           return true;
         continue;
       }
@@ -343,24 +373,32 @@
   // Scan all of the uses of the retain count value, collecting all
   // the releases and validating that we don't have an unexpected
   // user.
-  for (auto UI : Box->getUses()) {
-    auto *User = UI->getUser();
+  llvm::SmallVector<Operand *, 32> Worklist(Box->use_begin(), Box->use_end());
+  while (!Worklist.empty()) {
+    auto *Op = Worklist.pop_back_val();
+    auto *User = Op->getUser();
 
     // Retains and releases are fine. Deallocs are fine if we're not
     // examining a function that the alloc_box was passed into.
     // Projections are fine as well.
     if (isa<StrongRetainInst>(User) || isa<StrongReleaseInst>(User) ||
-        isa<ProjectBoxInst>(User) ||
+        isa<ProjectBoxInst>(User) || isa<DestroyValueInst>(User) ||
         (!inAppliedFunction && isa<DeallocBoxInst>(User)))
       continue;
 
+    // If we have a copy_value, visit the users of the copy_value.
+    if (auto *CVI = dyn_cast<CopyValueInst>(User)) {
+      std::copy(CVI->use_begin(), CVI->use_end(), std::back_inserter(Worklist));
+      continue;
+    }
+
     // For partial_apply, if we've been asked to examine the body, the
     // uses of the argument are okay there, and the partial_apply
     // itself cannot escape, then everything is fine.
     if (auto *PAI = dyn_cast<PartialApplyInst>(User))
-      if (examinePartialApply && checkPartialApplyBody(UI) &&
+      if (examinePartialApply && checkPartialApplyBody(Op) &&
           !partialApplyEscapes(PAI, /* examineApply = */ true)) {
-        LocalPromotedOperands.push_back(UI);
+        LocalPromotedOperands.push_back(Op);
         continue;
       }
 
@@ -368,7 +406,7 @@
   }
 
   PromotedOperands.append(LocalPromotedOperands.begin(),
-                         LocalPromotedOperands.end());
+                          LocalPromotedOperands.end());
   return nullptr;
 }
 
@@ -394,12 +432,28 @@
   return true;
 }
 
+static void replaceProjectBoxUsers(AllocBoxInst *ABI, AllocStackInst *ASI) {
+  llvm::SmallVector<Operand *, 8> Worklist(ABI->use_begin(), ABI->use_end());
+  while (!Worklist.empty()) {
+    auto *Op = Worklist.pop_back_val();
+    if (auto *PBI = dyn_cast<ProjectBoxInst>(Op->getUser())) {
+      PBI->replaceAllUsesWith(ASI);
+      continue;
+    }
+
+    auto *CVI = dyn_cast<CopyValueInst>(Op->getUser());
+    if (!CVI)
+      continue;
+    std::copy(CVI->use_begin(), CVI->use_end(), std::back_inserter(Worklist));
+  }
+}
+
 /// rewriteAllocBoxAsAllocStack - Replace uses of the alloc_box with a
 /// new alloc_stack, but do not delete the alloc_box yet.
 static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
   DEBUG(llvm::dbgs() << "*** Promoting alloc_box to stack: " << *ABI);
 
-  llvm::SmallVector<SILInstruction*, 4> FinalReleases;
+  llvm::SmallVector<SILInstruction *, 4> FinalReleases;
   if (!getFinalReleases(ABI, FinalReleases))
     return false;
 
@@ -415,23 +469,20 @@
 
   // Replace all uses of the address of the box's contained value with
   // the address of the stack location.
-  for (Operand *Use : ABI->getUses()) {
-    if (auto *PBI = dyn_cast<ProjectBoxInst>(Use->getUser())) {
-      PBI->replaceAllUsesWith(ASI);
-    }
-  }
+  replaceProjectBoxUsers(ABI, ASI);
 
   // Check to see if the alloc_box was used by a mark_uninitialized instruction.
   // If so, any uses of the pointer result need to keep using the MUI, not the
   // alloc_stack directly.  If we don't do this, DI will miss the uses.
   SILValue PointerResult = ASI;
-  for (auto UI : ASI->getUses())
+  for (auto UI : ASI->getUses()) {
     if (auto *MUI = dyn_cast<MarkUninitializedInst>(UI->getUser())) {
       assert(ASI->hasOneUse() &&
              "alloc_stack used by mark_uninitialized, but not exclusively!");
       PointerResult = MUI;
       break;
     }
+  }
 
   assert(ABI->getBoxType()->getLayout()->getFields().size() == 1
          && "promoting multi-field box not implemented");
@@ -452,10 +503,25 @@
   // Remove any retain and release instructions.  Since all uses of project_box
   // are gone, this only walks through uses of the box itself (the retain count
   // pointer).
-  while (!ABI->use_empty()) {
-    auto *User = (*ABI->use_begin())->getUser();
+  llvm::SmallVector<SILInstruction *, 8> Worklist;
+  std::transform(ABI->use_begin(), ABI->use_end(), std::back_inserter(Worklist),
+                 [](Operand *Op) -> SILInstruction * { return Op->getUser(); });
+  while (!Worklist.empty()) {
+    auto *User = Worklist.pop_back_val();
+
+    if (isa<CopyValueInst>(User)) {
+      std::transform(
+          User->use_begin(), User->use_end(), std::back_inserter(Worklist),
+          [](Operand *Op) -> SILInstruction * { return Op->getUser(); });
+      User->replaceAllUsesWith(
+          SILUndef::get(User->getType(), User->getModule()));
+      User->eraseFromParent();
+      continue;
+    }
+
     assert(isa<StrongReleaseInst>(User) || isa<StrongRetainInst>(User) ||
-           isa<DeallocBoxInst>(User) || isa<ProjectBoxInst>(User));
+           isa<DeallocBoxInst>(User) || isa<ProjectBoxInst>(User) ||
+           isa<DestroyValueInst>(User));
 
     User->eraseFromParent();
   }
@@ -468,7 +534,7 @@
 /// \brief A SILCloner subclass which clones a closure function while
 /// promoting some of its box parameters to stack addresses.
 class PromotedParamCloner : public SILClonerWithScopes<PromotedParamCloner> {
-  public:
+public:
   friend class SILVisitor<PromotedParamCloner>;
   friend class SILCloner<PromotedParamCloner>;
 
@@ -480,21 +546,23 @@
 
   SILFunction *getCloned() { return &getBuilder().getFunction(); }
 
-  private:
-    static SILFunction *initCloned(SILFunction *Orig, IsSerialized_t Serialized,
-                                   ArgIndexList &PromotedArgIndices,
-                                   llvm::StringRef ClonedName);
+private:
+  static SILFunction *initCloned(SILFunction *Orig, IsSerialized_t Serialized,
+                                 ArgIndexList &PromotedArgIndices,
+                                 llvm::StringRef ClonedName);
 
-    void visitStrongReleaseInst(StrongReleaseInst *Inst);
-    void visitStrongRetainInst(StrongRetainInst *Inst);
-    void visitProjectBoxInst(ProjectBoxInst *Inst);
+  void visitStrongReleaseInst(StrongReleaseInst *Inst);
+  void visitDestroyValueInst(DestroyValueInst *Inst);
+  void visitStrongRetainInst(StrongRetainInst *Inst);
+  void visitCopyValueInst(CopyValueInst *Inst);
+  void visitProjectBoxInst(ProjectBoxInst *Inst);
 
-    SILFunction *Orig;
-    ArgIndexList &PromotedArgIndices;
+  SILFunction *Orig;
+  ArgIndexList &PromotedArgIndices;
 
-    // The values in the original function that are promoted to stack
-    // references.
-    llvm::SmallSet<SILValue, 4> PromotedParameters;
+  // The values in the original function that are promoted to stack
+  // references.
+  llvm::SmallSet<SILValue, 4> PromotedParameters;
 };
 } // end anonymous namespace
 
@@ -644,6 +712,24 @@
   SILCloner<PromotedParamCloner>::visitStrongReleaseInst(Inst);
 }
 
+/// \brief Handle a strong_release instruction during cloning of a closure; if
+/// it is a strong release of a promoted box argument, then it is replaced with
+/// a ReleaseValue of the new object type argument, otherwise it is handled
+/// normally.
+void PromotedParamCloner::visitDestroyValueInst(DestroyValueInst *Inst) {
+  // If we are a destroy of a promoted parameter, just drop the instruction. We
+  // look through copy_value to preserve current behavior.
+  SILInstruction *Tmp = Inst;
+  while (auto *CopyOp = dyn_cast<CopyValueInst>(Tmp->getOperand(0))) {
+    Tmp = CopyOp;
+  }
+
+  if (PromotedParameters.count(Tmp->getOperand(0)))
+    return;
+
+  SILCloner<PromotedParamCloner>::visitDestroyValueInst(Inst);
+}
+
 void
 PromotedParamCloner::visitStrongRetainInst(StrongRetainInst *Inst) {
   // If it's a retain of a promoted parameter, just drop the instruction.
@@ -653,8 +739,19 @@
   SILCloner<PromotedParamCloner>::visitStrongRetainInst(Inst);
 }
 
-void
-PromotedParamCloner::visitProjectBoxInst(ProjectBoxInst *Inst) {
+void PromotedParamCloner::visitCopyValueInst(CopyValueInst *CVI) {
+  // If it's a copy of a promoted parameter, just drop the instruction.
+  auto *Tmp = CVI;
+  while (auto *CopyOp = dyn_cast<CopyValueInst>(Tmp->getOperand())) {
+    Tmp = CopyOp;
+  }
+  if (PromotedParameters.count(Tmp->getOperand()))
+    return;
+
+  SILCloner<PromotedParamCloner>::visitCopyValueInst(CVI);
+}
+
+void PromotedParamCloner::visitProjectBoxInst(ProjectBoxInst *Inst) {
   // If it's a projection of a promoted parameter, drop the instruction.
   // Its uses will be replaced by the promoted address.
   // and replace its uses with
@@ -707,36 +804,15 @@
       continue;
     }
 
-    // If this argument is promoted, it is a box that we're
-    // turning into an address because we've proven we can
-    // keep this value on the stack. The partial_apply had ownership
-    // of this box so we must now release it explicitly when the
-    // partial_apply is released.
-    auto box = cast<AllocBoxInst>(O.get());
-
-    // If the box address has a MUI, route accesses through it so DI still
-    // works.
-    SILInstruction *promoted = nullptr;
-    int numAddrUses = 0;
-    for (Operand *BoxUse : box->getUses()) {
-      if (auto *PBI = dyn_cast<ProjectBoxInst>(BoxUse->getUser())) {
-        for (auto PBIUse : PBI->getUses()) {
-          numAddrUses++;
-          if (auto MUI = dyn_cast<MarkUninitializedInst>(PBIUse->getUser()))
-            promoted = MUI;
-        }
-      }
-    }
-    assert((!promoted || numAddrUses == 1) &&
-           "box value used by mark_uninitialized but not exclusively!");
-    
-    // We only reuse an existing project_box if it directly follows the
-    // alloc_box. This makes sure that the project_box dominates the
-    // partial_apply.
-    if (!promoted)
-      promoted = getOrCreateProjectBox(box, 0);
-
-    Args.push_back(promoted);
+    // If this argument is promoted, it is a box that we're turning into an
+    // address because we've proven we can keep this value on the stack. The
+    // partial_apply had ownership of this box so we must now release it
+    // explicitly when the partial_apply is released.
+    SILInstruction *Box = cast<SILInstruction>(O.get());
+    assert((isa<AllocBoxInst>(Box) || isa<CopyValueInst>(Box)) &&
+           "Expected either an alloc box or a copy of an alloc box");
+    SILBuilder B(Box);
+    Args.push_back(B.createProjectBox(Box->getLoc(), Box, 0));
 
     if (PAFrontier.empty()) {
       ValueLifetimeAnalysis VLA(PartialApply);
@@ -746,10 +822,11 @@
                                     "to release the returned function");
     }
 
-    // Insert releases after each point where the partial_apply becomes dead.
+    // Insert destroys of the box at each point where the partial_apply becomes
+    // dead.
     for (SILInstruction *FrontierInst : PAFrontier) {
       SILBuilderWithScope Builder(FrontierInst);
-      Builder.emitStrongReleaseAndFold(PartialApply->getLoc(), O.get());
+      Builder.createDestroyValue(PartialApply->getLoc(), Box);
     }
   }
 
diff --git a/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp b/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp
index 1303fc0..01f23f8 100644
--- a/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp
+++ b/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp
@@ -11,7 +11,9 @@
 //===----------------------------------------------------------------------===//
 #define DEBUG_TYPE "array-element-propagation"
 
-#include "llvm/ADT/SetVector.h"
+#include "swift/AST/NameLookup.h"
+#include "swift/AST/ParameterList.h"
+#include "swift/AST/GenericEnvironment.h"
 #include "swift/SIL/SILBasicBlock.h"
 #include "swift/SIL/SILInstruction.h"
 #include "swift/SIL/DebugUtils.h"
@@ -23,12 +25,14 @@
 using namespace swift;
 
 /// Propagate the elements of array values to calls of the array's get_element
-/// method.
+/// method, and replace calls of append(contentsOf:) with append(element:).
 ///
 /// Array literal construction and array initialization of array values
 /// associates element values with the array value. These values can be
 /// propagated to the get_element method if we can prove that the array value
-/// has not changed until reading the array value's element.
+/// has not changed until reading the array value's element. These values can
+/// also be used to replace append(contentsOf:) with multiple append(element:)
+/// calls.
 ///
 /// Propagation of the elements of one array allocation.
 ///
@@ -42,53 +46,71 @@
 ///   The stores on the returned array element buffer pointer.
 ///
 namespace {
+
+/// Utility class for analysis array literal initializations.
+///
+/// Array literals are initialized by allocating an array buffer, and storing
+/// the elements into it.
+/// This class analysis all the code which does the array literal
+/// initialization. It also collects uses of the array, like getElement calls
+/// and append(contentsOf) calls.
 class ArrayAllocation {
-  /// The array allocation call.
-  ApplyInst *Alloc;
   /// The array value returned by the allocation call.
   SILValue ArrayValue;
 
-  /// The pointer to the returned array element buffer pointer.
-  SILValue ElementBuffer;
-
-  // The calls to Array get_element that use this array allocation.
+  /// The calls to Array get_element that use this array allocation.
   llvm::SmallSetVector<ApplyInst *, 16> GetElementCalls;
+
+  /// The calls to Array append_contentsOf that use this array allocation.
+  llvm::SmallVector<ApplyInst *, 4> AppendContentsOfCalls;
+
+  /// A map of Array indices to element values
   llvm::DenseMap<uint64_t, SILValue> ElementValueMap;
 
-  // Array get_element calls and their matching array element value for later
-  // replacement.
-  llvm::SmallVectorImpl<std::pair<ApplyInst *, SILValue>> &ReplacementMap;
-
-  ArrayAllocation(
-      ApplyInst *AI,
-      llvm::SmallVectorImpl<std::pair<ApplyInst *, SILValue>> &Replacements)
-      : Alloc(AI), ReplacementMap(Replacements) {}
-
-  bool findValueReplacements();
-  bool isInitializationWithKnownElements();
-  bool mapInitializationStores();
-  bool analyzeArrayValueUses();
+  bool mapInitializationStores(SILValue ElementBuffer);
   bool recursivelyCollectUses(ValueBase *Def);
-  bool collectForwardableValues();
+  bool replacementsAreValid();
+
+  // After approx. this many elements, it's faster to use append(contentsOf:)
+  static constexpr unsigned APPEND_CONTENTSOF_REPLACEMENT_VALUES_MAX = 6;
 
 public:
 
-  /// Find a set of get_element calls that can be replace by the initialization
-  /// value of the array allocation call.
-  ///
-  /// Returns true if an access can be replaced. The replacements are stored in
-  /// the \p ReplacementMap.
-  static bool findValueReplacements(
-      ApplyInst *Inst,
-      llvm::SmallVectorImpl<std::pair<ApplyInst *, SILValue>> &Replacements) {
-    return ArrayAllocation(Inst, Replacements).findValueReplacements();
-  }
-};
-} // end anonymous namespace
+  /// Specifies the value with which a get-element call can be replaced.
+  struct GetElementReplacement {
+    ApplyInst *GetElementCall;
+    SILValue Replacement;
+  };
 
+  /// Specifies the set of elements with which a append-contentof call can be
+  /// replaced.
+  struct AppendContentOfReplacement {
+    ApplyInst *AppendContentOfCall;
+    llvm::SmallVector<SILValue, 4> ReplacementValues;
+    SILValue Array;
+  };
+
+  ArrayAllocation() {}
+
+  /// Analyzes an array allocation call.
+  ///
+  /// Returns true if \p Alloc is the allocation of an array literal (or a
+  /// similar pattern) and the array values can be used to replace get_element
+  /// or append(contentof) calls.
+  bool analyze(ApplyInst *Alloc);
+
+  /// Gets the list of get_element calls which can be replaced.
+  void getGetElementReplacements(
+    llvm::SmallVectorImpl<GetElementReplacement> &Replacements);
+
+  /// Gets the list of append(contentof) calls which can be replaced by a
+  /// set of values.
+  void getAppendContentOfReplacements(
+    llvm::SmallVectorImpl<AppendContentOfReplacement> &Replacements);
+};
 
 /// Map the indices of array element initialization stores to their values.
-bool ArrayAllocation::mapInitializationStores() {
+bool ArrayAllocation::mapInitializationStores(SILValue ElementBuffer) {
   assert(ElementBuffer &&
          "Must have identified an array element storage pointer");
 
@@ -148,44 +170,18 @@
   return !ElementValueMap.empty();
 }
 
-/// Check that we have an array initialization call with known elements.
-///
-/// The returned array value is known not to be aliased since it was just
-/// allocated.
-bool ArrayAllocation::isInitializationWithKnownElements() {
-  ArraySemanticsCall Uninitialized(Alloc, "array.uninitialized");
-  if (Uninitialized &&
-      (ArrayValue = Uninitialized.getArrayValue()) &&
-      (ElementBuffer = Uninitialized.getArrayElementStoragePointer()))
-    return mapInitializationStores();
+bool ArrayAllocation::replacementsAreValid() {
+  unsigned ElementCount = ElementValueMap.size();
 
-  return false;
-}
-
-/// Propagate the elements of an array literal to get_element method calls on
-/// the same array.
-///
-/// We have to prove that the array value is not changed in between the
-/// creation and the method call to get_element.
-bool ArrayAllocation::findValueReplacements() {
-  if (!isInitializationWithKnownElements())
+  if (ElementCount > APPEND_CONTENTSOF_REPLACEMENT_VALUES_MAX)
     return false;
 
-  // The array value was stored or has escaped.
-  if (!analyzeArrayValueUses())
-    return false;
+  // Bail if elements aren't contiguous
+  for (unsigned i = 0; i < ElementCount; ++i)
+    if (!ElementValueMap.count(i))
+      return false;
 
-  // No count users.
-  if (GetElementCalls.empty())
-    return false;
-
-  return collectForwardableValues();
-}
-
-/// Collect all get_element users and check that there are no escapes or uses
-/// that could change the array value.
-bool ArrayAllocation::analyzeArrayValueUses() {
-  return recursivelyCollectUses(ArrayValue);
+  return true;
 }
 
 /// Recursively look at all uses of this definition. Abort if the array value
@@ -206,10 +202,16 @@
 
     // Check array semantic calls.
     ArraySemanticsCall ArrayOp(User);
-    if (ArrayOp && ArrayOp.doesNotChangeArray()) {
-      if (ArrayOp.getKind() == ArrayCallKind::kGetElement)
+    if (ArrayOp) {
+      if (ArrayOp.getKind() == ArrayCallKind::kAppendContentsOf) {
+        AppendContentsOfCalls.push_back(ArrayOp);
+        continue;
+      } else if (ArrayOp.getKind() == ArrayCallKind::kGetElement) {
         GetElementCalls.insert(ArrayOp);
-      continue;
+        continue;
+      } else if (ArrayOp.doesNotChangeArray()) {
+        continue;
+      }
     }
 
     // An operation that escapes or modifies the array value.
@@ -218,9 +220,32 @@
   return true;
 }
 
-/// Look at the get_element calls and match them to values by index.
-bool ArrayAllocation::collectForwardableValues() {
-  bool FoundForwardableValue = false;
+bool ArrayAllocation::analyze(ApplyInst *Alloc) {
+  ArraySemanticsCall Uninitialized(Alloc, "array.uninitialized");
+  if (!Uninitialized)
+    return false;
+
+  ArrayValue = Uninitialized.getArrayValue();
+  if (!ArrayValue)
+    return false;
+
+  SILValue ElementBuffer = Uninitialized.getArrayElementStoragePointer();
+  if (!ElementBuffer)
+    return false;
+
+  // Figure out all stores to the array.
+  if (!mapInitializationStores(ElementBuffer))
+    return false;
+
+  // Check if the array value was stored or has escaped.
+  if (!recursivelyCollectUses(ArrayValue))
+    return false;
+
+  return true;
+}
+
+void ArrayAllocation::getGetElementReplacements(
+                   llvm::SmallVectorImpl<GetElementReplacement> &Replacements) {
   for (auto *GetElementCall : GetElementCalls) {
     ArraySemanticsCall GetElement(GetElementCall);
     assert(GetElement.getKind() == ArrayCallKind::kGetElement);
@@ -235,19 +260,29 @@
     if (EltValueIt == ElementValueMap.end())
       continue;
 
-    ReplacementMap.push_back(
-        std::make_pair(GetElementCall, EltValueIt->second));
-    FoundForwardableValue = true;
+    Replacements.push_back({GetElementCall, EltValueIt->second});
   }
-  return FoundForwardableValue;
+}
+
+void ArrayAllocation::getAppendContentOfReplacements(
+              llvm::SmallVectorImpl<AppendContentOfReplacement> &Replacements) {
+  if (AppendContentsOfCalls.empty())
+    return;
+  if (!replacementsAreValid())
+    return;
+
+  llvm::SmallVector<SILValue, 4> ElementValueVector;
+  for (unsigned i = 0; i < ElementValueMap.size(); ++i)
+    ElementValueVector.push_back(ElementValueMap[i]);
+
+  for (auto *Call : AppendContentsOfCalls)
+    Replacements.push_back({Call, ElementValueVector, ArrayValue});
 }
 
 // =============================================================================
 //                                 Driver
 // =============================================================================
 
-namespace {
-
 class ArrayElementPropagation : public SILFunctionTransform {
 public:
   ArrayElementPropagation() {}
@@ -256,30 +291,83 @@
     return "Array Element Propagation";
   }
 
+  bool replaceAppendCalls(
+                  ArrayRef<ArrayAllocation::AppendContentOfReplacement> Repls) {
+    auto &Fn = *getFunction();
+    auto &M = Fn.getModule();
+    auto &Ctx = M.getASTContext();
+
+    if (Repls.empty())
+      return false;
+
+    DEBUG(llvm::dbgs() << "Array append contentsOf calls replaced in "
+                       << Fn.getName() << " (" << Repls.size() << ")\n");
+
+    auto *AppendFnDecl = Ctx.getArrayAppendElementDecl();
+    if (!AppendFnDecl)
+      return false;
+
+    auto Mangled = SILDeclRef(AppendFnDecl, SILDeclRef::Kind::Func).mangle();
+    auto *AppendFn = M.findFunction(Mangled, SILLinkage::PublicExternal);
+    if (!AppendFn)
+      return false;
+    
+    for (const ArrayAllocation::AppendContentOfReplacement &Repl : Repls) {
+      ArraySemanticsCall AppendContentsOf(Repl.AppendContentOfCall);
+      assert(AppendContentsOf && "Must be AppendContentsOf call");
+      
+      SILType ArrayType = Repl.Array->getType();
+      auto *NTD = ArrayType.getSwiftRValueType()->getAnyNominal();
+      SubstitutionMap ArraySubMap = ArrayType.getSwiftRValueType()
+        ->getContextSubstitutionMap(M.getSwiftModule(), NTD);
+      
+      GenericSignature *Sig = NTD->getGenericSignature();
+      assert(Sig && "Array type must have generic signature");
+      SmallVector<Substitution, 4> Subs;
+      Sig->getSubstitutions(ArraySubMap, Subs);
+      
+      AppendContentsOf.replaceByAppendingValues(M, AppendFn,
+                                                Repl.ReplacementValues, Subs);
+    }
+    return true;
+  }
+
   void run() override {
     auto &Fn = *getFunction();
 
-    bool Changed = false;
-
     // Propagate the elements an of array value to its users.
-    SmallVector<std::pair<ApplyInst *, SILValue>, 16> ValueReplacements;
+    llvm::SmallVector<ArrayAllocation::GetElementReplacement, 16>
+      GetElementReplacements;
+    llvm::SmallVector<ArrayAllocation::AppendContentOfReplacement, 4>
+      AppendContentsOfReplacements;
+
     for (auto &BB :Fn) {
       for (auto &Inst : BB) {
-        if (auto *Apply = dyn_cast<ApplyInst>(&Inst))
-          Changed |=
-              ArrayAllocation::findValueReplacements(Apply, ValueReplacements);
+        if (auto *Apply = dyn_cast<ApplyInst>(&Inst)) {
+          ArrayAllocation ALit;
+          if (ALit.analyze(Apply)) {
+            ALit.getGetElementReplacements(GetElementReplacements);
+            ALit.getAppendContentOfReplacements(AppendContentsOfReplacements);
+          }
+        }
       }
     }
-    DEBUG(if (Changed) {
+
+    DEBUG(if (!GetElementReplacements.empty()) {
       llvm::dbgs() << "Array elements replaced in " << Fn.getName() << " ("
-                   << ValueReplacements.size() << ")\n";
+                   << GetElementReplacements.size() << ")\n";
     });
+    
+    bool Changed = false;
+    
     // Perform the actual replacement of the get_element call by its value.
-    for (auto &Repl : ValueReplacements) {
-      ArraySemanticsCall GetElement(Repl.first);
-      GetElement.replaceByValue(Repl.second);
+    for (ArrayAllocation::GetElementReplacement &Repl : GetElementReplacements) {
+      ArraySemanticsCall GetElement(Repl.GetElementCall);
+      Changed |= GetElement.replaceByValue(Repl.Replacement);
     }
 
+    Changed |= replaceAppendCalls(AppendContentsOfReplacements);
+
     if (Changed) {
       PM->invalidateAnalysis(
           &Fn, SILAnalysis::InvalidationKind::CallsAndInstructions);
diff --git a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp
index d322414..cc8d58f 100644
--- a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp
+++ b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp
@@ -139,8 +139,6 @@
   case ValueKind::RetainValueInst:
   case ValueKind::DeallocStackInst:
   case ValueKind::CondFailInst:
-  case ValueKind::IsUniqueInst:
-  case ValueKind::IsUniqueOrPinnedInst:
   case ValueKind::FixLifetimeInst:
     return true;
   default:
diff --git a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
index a2b5897..089fbd9 100644
--- a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
+++ b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
@@ -271,6 +271,13 @@
       Changed = true;
     }
 
+    // Check if generic signature of the function could be changed by
+    // removed some unused generic arguments.
+    if (F->getLoweredFunctionType()->isPolymorphic() &&
+        createOptimizedSILFunctionType() != F->getLoweredFunctionType()) {
+      Changed = true;
+    }
+
     // Create the specialized function and invalidate the old function.
     if (Changed) {
       createFunctionSignatureOptimizedFunction();
@@ -364,7 +371,8 @@
 computeOptimizedArgInterface(ArgumentDescriptor &AD, SILParameterInfoList &Out) {
   // If this argument is live, but we cannot optimize it.
   if (!AD.canOptimizeLiveArg()) {
-    Out.push_back(AD.PInfo);
+    if (AD.PInfo.hasValue())
+      Out.push_back(AD.PInfo.getValue());
     return;
   }
 
@@ -391,9 +399,17 @@
       }
 
       // Ty is not trivial, pass it through as the original calling convention.
-      SILParameterInfo NewInfo(Ty.getSwiftRValueType(), AD.OwnedToGuaranteed ? 
-                               ParameterConvention::Direct_Guaranteed : 
-                               AD.PInfo.getConvention());
+      auto ParameterConvention = AD.PInfo.getValue().getConvention();
+      if (AD.OwnedToGuaranteed) {
+        if (ParameterConvention == ParameterConvention::Direct_Owned)
+          ParameterConvention = ParameterConvention::Direct_Guaranteed;
+        else if (ParameterConvention == ParameterConvention::Indirect_In)
+          ParameterConvention = ParameterConvention::Indirect_In_Guaranteed;
+        else {
+          llvm_unreachable("Unknown parameter convention transformation");
+        }
+      }
+      SILParameterInfo NewInfo(Ty.getSwiftRValueType(), ParameterConvention);
       Out.push_back(NewInfo);
     }
     return;
@@ -404,18 +420,135 @@
   // parameter, change the parameter to @guaranteed and continue...
   if (AD.OwnedToGuaranteed) {
     ++NumOwnedConvertedToGuaranteed;
-    SILParameterInfo NewInfo(AD.PInfo.getType(),
-                             ParameterConvention::Direct_Guaranteed);
+    auto ParameterConvention = AD.PInfo.getValue().getConvention();
+    if (ParameterConvention == ParameterConvention::Direct_Owned)
+      ParameterConvention = ParameterConvention::Direct_Guaranteed;
+    else if (ParameterConvention == ParameterConvention::Indirect_In)
+      ParameterConvention = ParameterConvention::Indirect_In_Guaranteed;
+    else {
+      llvm_unreachable("Unknown parameter convention transformation");
+    }
+
+    SILParameterInfo NewInfo(AD.PInfo.getValue().getType(),
+                             ParameterConvention);
     Out.push_back(NewInfo);
     return;
   }
 
   // Otherwise just propagate through the parameter info.
-  Out.push_back(AD.PInfo);
+  Out.push_back(AD.PInfo.getValue());
+}
+
+/// Collect all archetypes used by a function.
+static bool usesGenerics(SILFunction *F,
+                         ArrayRef<SILParameterInfo> InterfaceParams,
+                         ArrayRef<SILResultInfo> InterfaceResults) {
+  CanSILFunctionType FTy = F->getLoweredFunctionType();
+  auto HasGenericSignature = FTy->getGenericSignature() != nullptr;
+  if (!HasGenericSignature)
+    return false;
+
+  bool UsesGenerics = false;
+
+  auto FindArchetypesAndGenericTypes = [&UsesGenerics](Type Ty) {
+    if (Ty.findIf([](Type Ty) -> bool {
+          return (Ty->hasTypeParameter() || Ty->hasArchetype());
+        }))
+      UsesGenerics = true;
+  };
+
+  for (auto Param : InterfaceParams) {
+    Param.getType().visit(FindArchetypesAndGenericTypes);
+  }
+
+  for (auto Result : InterfaceResults) {
+    Result.getType().visit(FindArchetypesAndGenericTypes);
+  }
+
+  if (UsesGenerics)
+    return UsesGenerics;
+
+  for (auto &BB : *F) {
+    for (auto &I : BB) {
+      for (auto Arg : BB.getArguments()) {
+        if (&BB != &*F->begin()) {
+          // Scan types of all BB arguments. Ignore the entry BB, because
+          // it is handled in a special way.
+           Arg->getType().getSwiftRValueType().visit(FindArchetypesAndGenericTypes);
+           if (UsesGenerics)
+             return UsesGenerics;
+        }
+      }
+      // Scan types of all operands.
+      for (auto &Op : I.getAllOperands()) {
+        Op.get()->getType().getSwiftRValueType().visit(FindArchetypesAndGenericTypes);
+      }
+      // Scan all substitutions of apply instructions.
+      if (auto AI = ApplySite::isa(&I)) {
+        auto Subs = AI.getSubstitutions();
+        for (auto Sub : Subs) {
+          Sub.getReplacement().visit(FindArchetypesAndGenericTypes);
+        }
+      }
+      // Scan all substitutions of builtin instructions.
+      if (auto *BI = dyn_cast<BuiltinInst>(&I)) {
+        auto Subs = BI->getSubstitutions();
+        for (auto Sub : Subs) {
+          Sub.getReplacement().visit(FindArchetypesAndGenericTypes);
+        }
+      }
+
+      // Scan the result type of the instruction.
+      if (I.getType()) {
+        I.getType().getSwiftRValueType().visit(FindArchetypesAndGenericTypes);
+      }
+
+      if (UsesGenerics)
+        return UsesGenerics;
+    }
+  }
+  return UsesGenerics;
+}
+
+// Map the parameter, result and error types out of context to get the interface
+// type.
+static void
+mapInterfaceTypes(SILFunction *F,
+                  MutableArrayRef<SILParameterInfo> InterfaceParams,
+                  MutableArrayRef<SILResultInfo> InterfaceResults,
+                  Optional<SILResultInfo> &InterfaceErrorResult) {
+
+  for (auto &Param : InterfaceParams) {
+    if (!Param.getType()->hasArchetype())
+      continue;
+    Param = SILParameterInfo(
+      F->mapTypeOutOfContext(Param.getType())->getCanonicalType(),
+      Param.getConvention());
+  }
+
+  for (auto &Result : InterfaceResults) {
+    if (!Result.getType()->hasArchetype())
+      continue;
+    auto InterfaceResult = Result.getWithType(
+        F->mapTypeOutOfContext(Result.getType())->getCanonicalType());
+    Result = InterfaceResult;
+  }
+
+  if (InterfaceErrorResult.hasValue()) {
+    if (InterfaceErrorResult.getValue().getType()->hasArchetype()) {
+      InterfaceErrorResult = SILResultInfo(
+          F->mapTypeOutOfContext(InterfaceErrorResult.getValue().getType())
+              ->getCanonicalType(),
+          InterfaceErrorResult.getValue().getConvention());
+    }
+  }
 }
 
 CanSILFunctionType FunctionSignatureTransform::createOptimizedSILFunctionType() {
   CanSILFunctionType FTy = F->getLoweredFunctionType();
+  auto ExpectedFTy = F->getLoweredType().castTo<SILFunctionType>();
+  auto HasGenericSignature = FTy->getGenericSignature() != nullptr;
+
   // The only way that we modify the arity of function parameters is here for
   // dead arguments. Doing anything else is unsafe since by definition non-dead
   // arguments will have SSA uses in the function. We would need to be smarter
@@ -444,15 +577,59 @@
     InterfaceResults.push_back(InterfaceResult);
   }
 
+  bool UsesGenerics = false;
+  if (HasGenericSignature) {
+    // Not all of the generic type parameters are used by the function
+    // parameters.
+    // Check which of the generic type parameters are not used and check if they
+    // are used anywhere in the function body. If this is not the case, we can
+    // remove the unused generic type parameters from the generic signature.
+    // This makes the code both smaller and faster, because no implicit
+    // parameters for type metadata and conformances need to be passed to the
+    // callee at the LLVM IR level.
+    // TODO: Implement a more precise analysis, so that we can eliminate only
+    // those generic parameters which are not used.
+    UsesGenerics = usesGenerics(F, InterfaceParams, InterfaceResults);
+
+    // The set of used archetypes is complete now.
+    if (!UsesGenerics) {
+      // None of the generic type parameters are used.
+      DEBUG(llvm::dbgs() << "None of generic parameters are used by "
+                         << F->getName() << "\n";
+            llvm::dbgs() << "Interface params:\n";
+            for (auto Param : InterfaceParams) {
+              Param.getType().dump();
+            }
+
+            llvm::dbgs()
+            << "Interface results:\n";
+            for (auto Result : InterfaceResults) {
+              Result.getType().dump();
+            });
+    }
+  }
+
   // Don't use a method representation if we modified self.
   auto ExtInfo = FTy->getExtInfo();
   if (shouldModifySelfArgument) {
     ExtInfo = ExtInfo.withRepresentation(SILFunctionTypeRepresentation::Thin);
   }
 
-  return SILFunctionType::get(FTy->getGenericSignature(), ExtInfo,
+  Optional<SILResultInfo> InterfaceErrorResult;
+  if (ExpectedFTy->hasErrorResult()) {
+    InterfaceErrorResult = ExpectedFTy->getErrorResult();
+  }
+
+  // Map the parameter, result and error types out of context to get the
+  // proper interface type. This is required for generic functions.
+  mapInterfaceTypes(F, InterfaceParams, InterfaceResults, InterfaceErrorResult);
+
+  GenericSignature *GenericSig =
+      UsesGenerics ? FTy->getGenericSignature() : nullptr;
+
+  return SILFunctionType::get(GenericSig, ExtInfo,
                               FTy->getCalleeConvention(), InterfaceParams,
-                              InterfaceResults, FTy->getOptionalErrorResult(),
+                              InterfaceResults, InterfaceErrorResult,
                               F->getModule().getASTContext());
 }
 
@@ -466,12 +643,19 @@
 
   DEBUG(llvm::dbgs() << "  -> create specialized function " << Name << "\n");
 
-  NewF = M.createFunction(linkage, Name, createOptimizedSILFunctionType(),
-                          F->getGenericEnvironment(), F->getLocation(),
-                          F->isBare(), F->isTransparent(), F->isSerialized(),
-                          F->isThunk(), F->getClassVisibility(),
-                          F->getInlineStrategy(), F->getEffectsKind(), nullptr,
-                          F->getDebugScope());
+  auto NewFTy = createOptimizedSILFunctionType();
+  GenericEnvironment *NewFGenericEnv;
+  if (NewFTy->getGenericSignature()) {
+    NewFGenericEnv = F->getGenericEnvironment();
+  } else {
+    NewFGenericEnv = nullptr;
+  }
+
+  NewF = M.createFunction(
+      linkage, Name, NewFTy, NewFGenericEnv, F->getLocation(), F->isBare(),
+      F->isTransparent(), F->isSerialized(), F->isThunk(),
+      F->getClassVisibility(), F->getInlineStrategy(), F->getEffectsKind(),
+      nullptr, F->getDebugScope());
   if (F->hasUnqualifiedOwnership()) {
     NewF->setUnqualifiedOwnership();
   }
@@ -490,6 +674,15 @@
   ArgumentExplosionFinalizeOptimizedFunction();
   DeadArgumentFinalizeOptimizedFunction();
 
+  // Update the ownership kinds of function entry BB arguments.
+
+  for (auto Arg : NewF->begin()->getFunctionArguments()) {
+    SILType MappedTy = Arg->getType();
+    auto Ownershipkind =
+        ValueOwnershipKind(M, MappedTy, Arg->getArgumentConvention());
+    Arg->setOwnershipKind(Ownershipkind);
+  }
+
   // Create the thunk body !
   F->setThunk(IsThunk);
   // The thunk now carries the information on how the signature is
@@ -514,11 +707,23 @@
     addThunkArgument(ArgDesc, Builder, ThunkBody, ThunkArgs);
   }
 
-  // We are ignoring generic functions and functions with out parameters for
-  // now.
   SILValue ReturnValue;
   SILType LoweredType = NewF->getLoweredType();
   SILType ResultType = NewF->getConventions().getSILResultType();
+  auto GenCalleeType = NewF->getLoweredFunctionType();
+  auto SubstCalleeSILType = LoweredType;
+  ArrayRef<Substitution> Subs;
+  // Handle generic functions.
+  if (GenCalleeType->isPolymorphic()) {
+    // Produce a substitutions list and a set of substituted SIL types
+    // required for creating a new SIL function.
+    Subs = F->getForwardingSubstitutions();
+    auto SubstCalleeType =
+        GenCalleeType->substGenericArgs(M, Subs);
+    SubstCalleeSILType = SILType::getPrimitiveObjectType(SubstCalleeType);
+    SILFunctionConventions Conv(SubstCalleeType, M);
+    ResultType = Conv.getSILResultType();
+  }
   auto FunctionTy = LoweredType.castTo<SILFunctionType>();
   if (FunctionTy->hasErrorResult()) {
     // We need a try_apply to call a function with an error result.
@@ -531,15 +736,15 @@
         SILType::getPrimitiveObjectType(FunctionTy->getErrorResult().getType());
     auto *ErrorArg =
         ErrorBlock->createPHIArgument(Error, ValueOwnershipKind::Owned);
-    Builder.createTryApply(Loc, FRI, LoweredType, SubstitutionList(),
+    Builder.createTryApply(Loc, FRI, SubstCalleeSILType, Subs,
                            ThunkArgs, NormalBlock, ErrorBlock);
 
     Builder.setInsertionPoint(ErrorBlock);
     Builder.createThrow(Loc, ErrorArg);
     Builder.setInsertionPoint(NormalBlock);
   } else {
-    ReturnValue = Builder.createApply(Loc, FRI, LoweredType, ResultType,
-                                      SubstitutionList(), ThunkArgs,
+    ReturnValue = Builder.createApply(Loc, FRI, SubstCalleeSILType, ResultType,
+                                      Subs, ThunkArgs,
                                       false);
   }
 
@@ -552,6 +757,7 @@
 
   // Do the last bit work to finalize the thunk.
   OwnedToGuaranteedFinalizeThunkFunction(Builder, F);
+
   assert(F->getDebugScope()->Parent != NewF->getDebugScope()->Parent);
 }
 
@@ -562,10 +768,15 @@
   // Did we decide we should optimize any parameter?
   bool SignatureOptimize = false;
   auto Args = F->begin()->getFunctionArguments();
-
+  auto OrigShouldModifySelfArgument = shouldModifySelfArgument;
   // Analyze the argument information.
   for (unsigned i = 0, e = Args.size(); i != e; ++i) {
     ArgumentDescriptor &A = ArgumentDescList[i];
+    if (!A.PInfo.hasValue()) {
+      // It is not an argument. It could be an indirect result. 
+      continue;
+    }
+
     if (!A.canOptimizeLiveArg()) {
       continue;
     }
@@ -578,6 +789,32 @@
         shouldModifySelfArgument = true;
     }
   }
+
+  if (F->getLoweredFunctionType()->isPolymorphic()) {
+    // If the set of dead arguments contains only type arguments,
+    // don't remove them, because it would produce a slower code
+    // for generic functions.
+    bool HasNonTypeDeadArguments = false;
+    for (auto &AD : ArgumentDescList) {
+      if (AD.IsEntirelyDead &&
+          !isa<AnyMetatypeType>(AD.Arg->getType().getSwiftRValueType())) {
+        HasNonTypeDeadArguments = true;
+        break;
+      }
+    }
+
+    if (!HasNonTypeDeadArguments) {
+      for (auto &AD : ArgumentDescList) {
+        if (AD.IsEntirelyDead) {
+          AD.IsEntirelyDead = false;
+          break;
+        }
+      }
+      shouldModifySelfArgument = OrigShouldModifySelfArgument;
+      SignatureOptimize = false;
+    }
+  }
+
   return SignatureOptimize;
 }
 
@@ -609,9 +846,13 @@
   // argument.
   //
   // TODO: The return block and throw block should really be abstracted away.
-  ConsumedArgToEpilogueReleaseMatcher ArgToReturnReleaseMap(RCIA->get(F), F);
+  SILArgumentConvention ArgumentConventions[] = {
+      SILArgumentConvention::Direct_Owned, SILArgumentConvention::Indirect_In};
+  ConsumedArgToEpilogueReleaseMatcher ArgToReturnReleaseMap(
+      RCIA->get(F), F, ArgumentConventions);
   ConsumedArgToEpilogueReleaseMatcher ArgToThrowReleaseMap(
-      RCIA->get(F), F, ConsumedArgToEpilogueReleaseMatcher::ExitKind::Throw);
+      RCIA->get(F), F, ArgumentConventions,
+      ConsumedArgToEpilogueReleaseMatcher::ExitKind::Throw);
 
   // Did we decide we should optimize any parameter?
   bool SignatureOptimize = false;
@@ -625,7 +866,10 @@
 
     // See if we can find a ref count equivalent strong_release or release_value
     // at the end of this function if our argument is an @owned parameter.
-    if (A.hasConvention(SILArgumentConvention::Direct_Owned)) {
+    // See if we can find a destroy_addr at the end of this function if our
+    // argument is an @in parameter.
+    if (A.hasConvention(SILArgumentConvention::Direct_Owned) ||
+        A.hasConvention(SILArgumentConvention::Indirect_In)) {
       auto Releases = ArgToReturnReleaseMap.getReleasesForArgument(A.Arg);
       if (!Releases.empty()) {
         // If the function has a throw block we must also find a matching
@@ -653,7 +897,9 @@
   auto fnConv = F->getConventions();
   // For now, only do anything if there's a single direct result.
   if (fnConv.getNumDirectSILResults() != 1)
-    return false; 
+    return false;
+  if (!fnConv.getIndirectSILResults().empty())
+    return false;
 
   bool SignatureOptimize = false;
   if (ResultDescList[0].hasConvention(ResultConvention::Owned)) {
@@ -662,7 +908,8 @@
       return false;
     auto &RI = ResultDescList[0];
     // We have an @owned return value, find the epilogue retains now.
-    auto Retains = EA->get(F)->computeEpilogueARCInstructions(EpilogueARCContext::EpilogueARCKind::Retain, RV); 
+    auto Retains = EA->get(F)->computeEpilogueARCInstructions(
+        EpilogueARCContext::EpilogueARCKind::Retain, RV);
     // We do not need to worry about the throw block, as the return value is only
     // going to be used in the return block/normal block of the try_apply
     // instruction.
@@ -723,6 +970,22 @@
   }
 }
 
+static void createArgumentRelease(SILBuilder &Builder, ArgumentDescriptor &AD) {
+  auto &F = Builder.getFunction();
+  if (AD.PInfo->getConvention() == ParameterConvention::Direct_Owned) {
+    Builder.createReleaseValue(RegularLocation(SourceLoc()),
+                               F.getArguments()[AD.Index],
+                               Builder.getDefaultAtomicity());
+    return;
+  }
+  if (AD.PInfo->getConvention() == ParameterConvention::Indirect_In) {
+    Builder.createDestroyAddr(RegularLocation(SourceLoc()),
+                              F.getArguments()[AD.Index]);
+    return;
+  }
+  llvm_unreachable("Parameter convention is not supported");
+}
+
 /// Set up epilogue work for the thunk arguments based in the given argument.
 /// Default implementation simply passes it through.
 void
@@ -730,7 +993,7 @@
 OwnedToGuaranteedAddArgumentRelease(ArgumentDescriptor &AD, SILBuilder &Builder,
                                     SILFunction *F) {
   // If we have any arguments that were consumed but are now guaranteed,
-  // insert a release_value.
+  // insert a releasing RC instruction.
   if (!AD.OwnedToGuaranteed) {
     return;
   }
@@ -738,21 +1001,15 @@
   SILInstruction *Call = findOnlyApply(F);
   if (isa<ApplyInst>(Call)) {
     Builder.setInsertionPoint(&*std::next(SILBasicBlock::iterator(Call)));
-    Builder.createReleaseValue(RegularLocation(SourceLoc()),
-                               F->getArguments()[AD.Index],
-                               Builder.getDefaultAtomicity());
+    createArgumentRelease(Builder, AD);
   } else {
     SILBasicBlock *NormalBB = dyn_cast<TryApplyInst>(Call)->getNormalBB();
     Builder.setInsertionPoint(&*NormalBB->begin());
-    Builder.createReleaseValue(RegularLocation(SourceLoc()),
-                               F->getArguments()[AD.Index],
-                               Builder.getDefaultAtomicity());
+    createArgumentRelease(Builder, AD);
 
     SILBasicBlock *ErrorBB = dyn_cast<TryApplyInst>(Call)->getErrorBB();
     Builder.setInsertionPoint(&*ErrorBB->begin());
-    Builder.createReleaseValue(RegularLocation(SourceLoc()),
-                               F->getArguments()[AD.Index],
-                               Builder.getDefaultAtomicity());
+    createArgumentRelease(Builder, AD);
   }
 }
 
@@ -760,8 +1017,8 @@
 FunctionSignatureTransform::
 OwnedToGuaranteedAddResultRelease(ResultDescriptor &RD, SILBuilder &Builder,
                                   SILFunction *F) {
- // If we have any result that were consumed but are now guaranteed,
-  // insert a release_value.
+  // If we have any result that were consumed but are now guaranteed,
+  // insert a releasing RC instruction.
   if (!RD.OwnedToGuaranteed) {
     return;
   }
@@ -786,7 +1043,8 @@
   // Did we decide we should optimize any parameter?
   bool SignatureOptimize = false;
   auto Args = F->begin()->getFunctionArguments();
-  ConsumedArgToEpilogueReleaseMatcher ArgToReturnReleaseMap(RCIA->get(F), F);
+  ConsumedArgToEpilogueReleaseMatcher ArgToReturnReleaseMap(
+    RCIA->get(F), F, {SILArgumentConvention::Direct_Owned});
 
   // Analyze the argument information.
   for (unsigned i = 0, e = Args.size(); i != e; ++i) {
@@ -796,6 +1054,10 @@
       continue;
     }
 
+    // Explosion of generic parameters is not supported yet.
+    if (A.Arg->getType().getSwiftRValueType()->hasArchetype())
+      continue;
+
     A.ProjTree.computeUsesAndLiveness(A.Arg);
     A.Explode = A.shouldExplode(ArgToReturnReleaseMap);
 
diff --git a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
index bf774de..b7056d4 100644
--- a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
+++ b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
@@ -79,6 +79,7 @@
   bool visitUnmanagedAutoreleaseValueInst(UnmanagedAutoreleaseValueInst *UAVI);
   bool visitCheckedCastBranchInst(CheckedCastBranchInst *CBI);
   bool visitSwitchEnumInst(SwitchEnumInst *SWI);
+  bool visitProjectBoxInst(ProjectBoxInst *PBI);
 };
 
 } // end anonymous namespace
@@ -246,37 +247,100 @@
   return true;
 }
 
+// Since we are threading through copies, we may have situations like:
+//
+// let x = alloc_box $Foo
+// let y = project_box x
+// let z = mark_uninitialized y
+// ... use z ...
+//
+// let y2 = project_box x
+//
+// let x2 = copy_value x
+// let y3 = project_box y
+//
+// We need to move project_box like y2 and y3 to go through z so that DI can
+// reason about them.
+//
+// Once DI is updated for ownership, this can go away.
+bool OwnershipModelEliminatorVisitor::visitProjectBoxInst(ProjectBoxInst *PBI) {
+  // First if our operand is already a mark_uninitialized, then we do not need
+  // to do anything.
+  auto *Use = PBI->getSingleUse();
+  if (Use && isa<MarkUninitializedInst>(Use->getUser())) {
+    return false;
+  }
+
+  // Otherwise, lets try to find the alloc_box.
+  SILValue BoxValue = PBI->getOperand();
+  while (auto *CVI = dyn_cast<CopyValueInst>(BoxValue)) {
+    BoxValue = CVI->getOperand();
+  }
+
+  // We were unable to find the alloc_box. This must be an indirect enum box
+  // pattern.
+  auto *ABI = dyn_cast<AllocBoxInst>(BoxValue);
+  if (!ABI)
+    return false;
+
+  // See if we can find (mark_uninitialized (project_box))
+  SILValue MUI;
+  for (auto *Use : ABI->getUses()) {
+    auto *BoxProjection = dyn_cast<ProjectBoxInst>(Use->getUser());
+    if (!BoxProjection)
+      continue;
+    auto *Op = BoxProjection->getSingleUse();
+    if (!Op || !isa<MarkUninitializedInst>(Op->getUser()))
+      continue;
+    MUI = SILValue(Op->getUser());
+    break;
+  }
+
+  // If we did not find a mark uninitialized inst, then this is not the pattern
+  // that we are looking for.
+  if (!MUI)
+    return false;
+
+  // Ok, we found it. Replace all uses of this project box with the
+  // mark_uninitialized and then erase it.
+  PBI->replaceAllUsesWith(MUI);
+  PBI->eraseFromParent();
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 //                           Top Level Entry Point
 //===----------------------------------------------------------------------===//
 
 namespace {
 
-struct OwnershipModelEliminator : SILFunctionTransform {
+struct OwnershipModelEliminator : SILModuleTransform {
   void run() override {
-    SILFunction *F = getFunction();
+    for (auto &F : *getModule()) {
+      // Set F to have unqualified ownership.
+      F.setUnqualifiedOwnership();
 
-    // Set F to have unqualified ownership.
-    F->setUnqualifiedOwnership();
+      bool MadeChange = false;
+      SILBuilder B(F);
+      OwnershipModelEliminatorVisitor Visitor(B);
 
-    bool MadeChange = false;
-    SILBuilder B(*F);
-    OwnershipModelEliminatorVisitor Visitor(B);
+      for (auto &BB : F) {
+        for (auto II = BB.begin(), IE = BB.end(); II != IE;) {
+          // Since we are going to be potentially removing instructions, we need
+          // to make sure to increment our iterator before we perform any
+          // visits.
+          SILInstruction *I = &*II;
+          ++II;
 
-    for (auto &BB : *F) {
-      for (auto II = BB.begin(), IE = BB.end(); II != IE;) {
-        // Since we are going to be potentially removing instructions, we need
-        // to make sure to grab out instruction and increment first.
-        SILInstruction *I = &*II;
-        ++II;
-
-        MadeChange |= Visitor.visit(I);
+          MadeChange |= Visitor.visit(I);
+        }
       }
-    }
 
-    if (MadeChange) {
-      invalidateAnalysis(
-          SILAnalysis::InvalidationKind::BranchesAndInstructions);
+      if (MadeChange) {
+        auto InvalidKind =
+            SILAnalysis::InvalidationKind::BranchesAndInstructions;
+        invalidateAnalysis(&F, InvalidKind);
+      }
     }
   }
 
diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
index badf82a..da0c39b 100644
--- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
+++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
@@ -104,8 +104,11 @@
     /// increasing the code size.
     TrivialFunctionThreshold = 18,
 
-    /// Configuration for the caller block limit.
-    BlockLimitDenominator = 10000,
+    /// Configuration for the "soft" caller block limit.
+    BlockLimitDenominator = 3000,
+
+    /// No inlining is done if the caller has more than this number of blocks.
+    OverallCallerBlockLimit = 400,
 
     /// The assumed execution length of a function call.
     DefaultApplyLength = 10
@@ -227,7 +230,9 @@
   // attribute if the inliner is asked not to inline them.
   if (Callee->hasSemanticsAttrs() || Callee->hasEffectsKind()) {
     if (WhatToInline == InlineSelection::NoSemanticsAndGlobalInit) {
-      return nullptr;
+      ArraySemanticsCall ASC(AI.getInstruction());
+      if (!ASC.canInlineEarly())
+        return nullptr;
     }
     // The "availability" semantics attribute is treated like global-init.
     if (Callee->hasSemanticsAttrs() &&
@@ -564,8 +569,13 @@
 
   SILFunction *Callee = AI.getReferencedFunction();
 
-  if (Callee->getInlineStrategy() == AlwaysInline)
+  if (Callee->getInlineStrategy() == AlwaysInline) {
+    DEBUG(
+      dumpCaller(AI.getFunction());
+      llvm::dbgs() << "    always-inline decision " <<Callee->getName() << '\n';
+    );
     return true;
+  }
 
   return isProfitableToInline(AI, CallerWeight, callerTracker, NumCallerBlocks);
 }
@@ -696,6 +706,9 @@
           InitialCandidates.push_back(AI);
       }
     }
+    if (NumCallerBlocks > OverallCallerBlockLimit)
+      break;
+
     domOrder.pushChildrenIf(block, [&] (SILBasicBlock *child) {
       if (CBI.isSlowPath(block, child)) {
         // Handle cold blocks separately.
diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
index c0a89ce..27440a8 100644
--- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
+++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
@@ -400,6 +400,10 @@
   /// Returns a *single* forwardable SILValue for the given LSLocation right
   /// before the InsertPt instruction.
   SILValue reduceValuesAtEndOfBlock(RLEContext &Ctx, LSLocation &L);
+
+#ifndef NDEBUG
+  void dump(RLEContext &Ctx);
+#endif
 };
 
 } // end anonymous namespace
@@ -477,6 +481,10 @@
   /// walked, i.e. when the we generate the genset and killset.
   llvm::DenseSet<SILBasicBlock *> BBWithLoads;
 
+#ifndef NDEBUG
+  SILPrintContext printCtx;
+#endif
+
 public:
   RLEContext(SILFunction *F, SILPassManager *PM, AliasAnalysis *AA,
              TypeExpansionAnalysis *TE, PostOrderFunctionInfo *PO,
@@ -489,6 +497,8 @@
   /// Entry point to redundant load elimination.
   bool run();
 
+  SILFunction *getFunction() const { return Fn; }
+
   /// Use a set of ad hoc rules to tell whether we should run a pessimistic
   /// one iteration data flow on the function.
   ProcessKind getProcessFunctionKind(unsigned LoadCount, unsigned StoreCount);
@@ -714,6 +724,8 @@
   // forwardable values are recorded in the function.
   //
   RedundantLoads[I] = TheForwardingValue;
+
+  DEBUG(llvm::dbgs() << "FORWARD " << TheForwardingValue << "  to" << *I);
   return true;
 }
 
@@ -1065,9 +1077,11 @@
   // that it and its operands cannot alias a load we have visited,
   // invalidate that load.
   if (Inst->mayWriteToMemory()) {
+    DEBUG(llvm::dbgs() << "WRITE " << *Inst);
     processUnknownWriteInst(Ctx, Inst, Kind);
     return;
   }
+  DEBUG(llvm::dbgs() << "READ " << *Inst);
 }
 
 RLEContext::ProcessKind
@@ -1121,6 +1135,39 @@
   return ProcessKind::ProcessMultipleIterations;
 }
 
+#ifndef NDEBUG
+void BlockState::dump(RLEContext &Ctx) {
+  for (unsigned i = 0; i < LocationNum; ++i) {
+    if (!isTrackingLocation(ForwardSetMax, i))
+      continue;
+
+    llvm::dbgs() << "Loc #" << i << ":" << (BBGenSet[i] ? " Gen" : "")
+                 << (BBKillSet[i] ? " Kill" : "");
+    if (!ForwardSetIn.empty() && ForwardSetIn.test(i)) {
+      llvm::dbgs() << " IN ";
+      ValueTableMap::const_iterator inIter = ForwardValIn.find(i);
+      if (inIter != ForwardValIn.end()) {
+        if (SILValue base = Ctx.getValue(inIter->second).getBase())
+          llvm::dbgs() << base;
+        else
+          llvm::dbgs() << "no base";
+      }
+    }
+    if (!ForwardSetOut.empty() && ForwardSetOut.test(i)) {
+      llvm::dbgs() << " OUT ";
+      ValueTableMap::const_iterator outIter = ForwardValOut.find(i);
+      if (outIter != ForwardValOut.end()) {
+        if (SILValue base = Ctx.getValue(outIter->second).getBase())
+          llvm::dbgs() << base;
+        else
+          llvm::dbgs() << "no base";
+      }
+    }
+    llvm::dbgs() << "\n";
+  }
+}
+#endif
+
 //===----------------------------------------------------------------------===//
 //                          RLEContext Implementation
 //===----------------------------------------------------------------------===//
@@ -1128,7 +1175,12 @@
 RLEContext::RLEContext(SILFunction *F, SILPassManager *PM, AliasAnalysis *AA,
                        TypeExpansionAnalysis *TE, PostOrderFunctionInfo *PO,
                        EpilogueARCFunctionInfo *EAFI)
-    : Fn(F), PM(PM), AA(AA), TE(TE), PO(PO), EAFI(EAFI) {
+    : Fn(F), PM(PM), AA(AA), TE(TE), PO(PO), EAFI(EAFI)
+#ifndef NDEBUG
+      ,
+      printCtx(llvm::dbgs(), /*Verbose=*/false, /*Sorted=*/true)
+#endif
+{
 }
 
 LSLocation &RLEContext::getLocation(const unsigned index) {
@@ -1306,6 +1358,10 @@
 
 void RLEContext::processBasicBlocksForGenKillSet() {
   for (SILBasicBlock *BB : PO->getReversePostOrder()) {
+    DEBUG(llvm::dbgs() << "PROCESS " << printCtx.getID(BB)
+                       << " for Gen/Kill:\n";
+          BB->print(llvm::dbgs(), printCtx));
+
     BlockState &S = getBlockState(BB);
 
     // Compute the AvailSetMax at the beginning of the basic block.
@@ -1327,6 +1383,7 @@
 
       S.processInstructionWithKind(*this, &*I, RLEKind::ComputeAvailGenKillSet);
     }
+    DEBUG(S.dump(*this));
   }
 }
 
@@ -1345,6 +1402,8 @@
   }
   while (!WorkList.empty()) {
     SILBasicBlock *BB = WorkList.pop_back_val();
+    DEBUG(llvm::dbgs() << "PROCESS " << printCtx.getID(BB)
+                       << " with Gen/Kill.\n");
     HandledBBs.erase(BB);
 
     // Intersection.
@@ -1361,11 +1420,15 @@
         WorkList.push_back(X);
       }
     }
+    DEBUG(Forwarder.dump(*this));
   }
 }
 
 void RLEContext::processBasicBlocksForAvailValue() {
   for (SILBasicBlock *BB : PO->getReversePostOrder()) {
+    DEBUG(llvm::dbgs() << "PROCESS " << printCtx.getID(BB)
+                       << " for available.\n");
+
     BlockState &Forwarder = getBlockState(BB);
 
     // Merge the predecessors. After merging, BlockState now contains
@@ -1382,11 +1445,15 @@
     // the available BitVector here as they should have been initialized and
     // stabilized in the processBasicBlocksWithGenKillSet.
     Forwarder.updateForwardValOut();
+
+    DEBUG(Forwarder.dump(*this));
   }
 }
 
 void RLEContext::processBasicBlocksForRLE(bool Optimistic) {
   for (SILBasicBlock *BB : PO->getReversePostOrder()) {
+    DEBUG(llvm::dbgs() << "PROCESS " << printCtx.getID(BB) << " for RLE.\n");
+
     // If we know this is not a one iteration function which means its
     // forward sets have been computed and converged, 
     // and this basic block does not even have LoadInsts, there is no point
@@ -1402,6 +1469,8 @@
     // beginning of the basic block along all paths.
     Forwarder.mergePredecessorAvailSetAndValue(*this);
 
+    DEBUG(Forwarder.dump(*this));
+
     // Perform the actual redundant load elimination.
     Forwarder.processBasicBlockWithKind(*this, RLEKind::PerformRLE);
 
@@ -1478,6 +1547,11 @@
                           BBToProcess.find(&B) != BBToProcess.end());
   }
 
+  DEBUG(for (unsigned i = 0; i < LocationVault.size(); ++i) {
+    llvm::dbgs() << "LSLocation #" << i;
+    getLocation(i).print(llvm::dbgs(), &Fn->getModule());
+  });
+
   if (Optimistic)
     runIterativeRLE();
 
diff --git a/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp b/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp
index c221654..7a81adf 100644
--- a/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp
+++ b/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp
@@ -165,7 +165,7 @@
 
         llvm::outs() << "#" << Counter++ << II;
         for (auto &Loc : Locs) {
-          Loc.print(&Fn.getModule());
+          Loc.print(llvm::outs(), &Fn.getModule());
         }
         Locs.clear();
       }
@@ -219,7 +219,7 @@
         LSLocation::reduce(L, &Fn.getModule(), SLocs);
         llvm::outs() << "#" << Counter++ << II;
         for (auto &Loc : SLocs) {
-          Loc.print(&Fn.getModule());
+          Loc.print(llvm::outs(), &Fn.getModule());
         }
         L.reset();
         Locs.clear();
diff --git a/lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp b/lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp
index 24f8da3..e088889 100644
--- a/lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp
+++ b/lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp
@@ -18,9 +18,16 @@
 #include "swift/SIL/DebugUtils.h"
 #include "swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h"
 #include "swift/SILOptimizer/Utils/Local.h"
+#include "llvm/Support/CommandLine.h"
 
 using namespace swift;
 
+/// Set to true to enable the support for partial specialization.
+llvm::cl::opt<bool> FSOEnableGenerics(
+  "sil-fso-enable-generics", llvm::cl::init(true),
+    llvm::cl::desc("Support function signature optimization "
+                   "of generic functions"));
+
 bool swift::hasNonTrivialNonDebugUse(SILArgument *Arg) {
   llvm::SmallVector<SILInstruction *, 8> Worklist;
   llvm::SmallPtrSet<SILInstruction *, 8> SeenInsts;
@@ -92,7 +99,7 @@
     return false;
 
   // For now ignore generic functions to keep things simple...
-  if (F->getLoweredFunctionType()->isPolymorphic())
+  if (!FSOEnableGenerics && F->getLoweredFunctionType()->isPolymorphic())
     return false;
 
   // Make sure F has a linkage that we can optimize.
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index a47db34..6733440 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -50,7 +50,7 @@
 // Compute the width and the depth of a type.
 // We compute both, because some pathological test-cases result in very
 // wide types and some others result in very deep types. It is important
-// to bail as soon as we hit the threshold on any of both dimentions to
+// to bail as soon as we hit the threshold on any of both dimensions to
 // prevent compiler hangs and crashes.
 static std::pair<unsigned, unsigned> getTypeDepthAndWidth(Type t) {
   unsigned Depth = 0;
@@ -653,6 +653,10 @@
   OriginalF = OrigF;
   ConvertIndirectToDirect = true;
 
+  // FIXME: All of the below initialization is then redone by
+  // specializeConcreteSubstitutions(), but there are still a
+  // couple of callers that aren't using the new API.
+
   SILModule &M = OrigF->getModule();
   auto &Ctx = M.getASTContext();
 
@@ -731,11 +735,8 @@
   auto OrigGenericSig = Callee->getLoweredFunctionType()->getGenericSignature();
   auto OrigGenericEnv = Callee->getGenericEnvironment();
 
-  SubstitutionMap InterfaceSubs;
   // Get the original substitution map.
-  if (Callee->getLoweredFunctionType()->getGenericSignature())
-    InterfaceSubs = Callee->getLoweredFunctionType()->getGenericSignature()
-      ->getSubstitutionMap(ParamSubs);
+  auto InterfaceSubs = OrigGenericSig->getSubstitutionMap(ParamSubs);
 
   // This is a workaround for the rdar://30610428
   if (!EnablePartialSpecialization) {
@@ -750,7 +751,7 @@
   // Build a set of requirements.
   SmallVector<Requirement, 4> Requirements;
 
-  for (auto DP : OrigGenericSig->getGenericParams()) {
+  for (auto DP : OrigGenericSig->getSubstitutableParams()) {
     auto Replacement = Type(DP).subst(InterfaceSubs);
     if (Replacement->hasArchetype())
       continue;
@@ -883,7 +884,7 @@
     DEBUG(llvm::dbgs() << "\n\nRe-mapping the requirement:\n"; reqReq.dump());
 
     auto first = reqReq.getFirstType();
-    // Is this generic generic type equivalent to a concrete type?
+    // Is this generic type equivalent to a concrete type?
     if (first->hasTypeParameter() &&
         !GenSig->getCanonicalTypeInContext(first, *SM)->hasTypeParameter())
       continue;
@@ -1379,7 +1380,7 @@
   computeCallerInterfaceToSpecializedInterfaceMap(CallerGenericSig);
 
   // Add generic parameters that will come from the callee.
-  // Introduce a new generic parameter in the new new generic signature
+  // Introduce a new generic parameter in the new generic signature
   // for each generic parameter from the callee.
   createGenericParamsForCalleeGenericParams(CalleeGenericSig, CallerGenericEnv);
 
@@ -1402,13 +1403,13 @@
 // - For all other substitutions that are considered for partial specialization,
 // it collects first the archetypes used in the replacements. Then for each such
 // archetype A a new generic parameter T' introduced.
-// - If there is a substitution for type T and this substitution is execluded
+// - If there is a substitution for type T and this substitution is excluded
 // from partial specialization (e.g. because it is impossible or would result
 // in a less efficient code), then a new generic parameter T' is introduced,
 // which does not get any additional, more specific requirements based on the
 // substitutions.
 //
-// After all generic parameters are added accoriding to the rules above,
+// After all generic parameters are added according to the rules above,
 // the requirements of the callee's signature are re-mapped by re-formulating
 // them in terms of the newly introduced generic parameters. In case a remapped
 // requirement does not contain any generic types, it can be omitted, because
@@ -1435,7 +1436,7 @@
   auto CalleeGenericSig = CalleeFnTy->getGenericSignature();
 
   // Used naming convention:
-  // Caller - the function containg the provided apply instruction.
+  // Caller - the function containing the provided apply instruction.
   // Callee - the callee of the provided apply instruction.
   // Specialized - the specialized callee which is being created.
 
@@ -1446,7 +1447,7 @@
 
   FunctionSignaturePartialSpecializer FSPS(M);
 
-  // Get the parially specialized generic signature and generic environment.
+  // Get the partially specialized generic signature and generic environment.
   auto GenPair = FSPS.createSpecializedGenericSignature(
       CallerGenericSig, CallerGenericEnv, CalleeGenericSig, ParamSubs);
 
@@ -1645,17 +1646,7 @@
 getCalleeSubstFunctionType(SILValue Callee, SubstitutionList Subs) {
   // Create a substituted callee type.
   auto CanFnTy = Callee->getType().castTo<SILFunctionType>();
-  auto CalleeSubstFnTy = CanFnTy;
-
-  if (CanFnTy->isPolymorphic() && !Subs.empty()) {
-    CalleeSubstFnTy = CanFnTy->substGenericArgs(*Callee->getModule(), Subs);
-    assert(!CalleeSubstFnTy->isPolymorphic() &&
-           "Substituted callee type should not be polymorphic");
-    assert(!CalleeSubstFnTy->hasTypeParameter() &&
-           "Substituted callee type should not have type parameters");
-  }
-
-  return CalleeSubstFnTy;
+  return CanFnTy->substGenericArgs(*Callee->getModule(), Subs);
 }
 
 // Create a new apply based on an old one, but with a different
diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp
index 485f4c9..ae983ab 100644
--- a/lib/SILOptimizer/Utils/Local.cpp
+++ b/lib/SILOptimizer/Utils/Local.cpp
@@ -407,30 +407,19 @@
 }
 
 SILLinkage swift::getSpecializedLinkage(SILFunction *F, SILLinkage L) {
-  switch (L) {
-  case SILLinkage::Public:
-  case SILLinkage::PublicExternal:
-  case SILLinkage::Shared:
-  case SILLinkage::SharedExternal:
-  case SILLinkage::Hidden:
-  case SILLinkage::HiddenExternal:
-    // Specializations of public or hidden symbols can be shared by all TUs
-    // that specialize the definition.
-    // Treat stdlib_binary_only specially. We don't serialize the body of
-    // stdlib_binary_only functions so we can't mark them as Shared (making
-    // their visibility in the dylib hidden).
-    return F->hasSemanticsAttr("stdlib_binary_only") ? SILLinkage::Public
-                                                     : SILLinkage::Shared;
-
-  case SILLinkage::Private:
-  case SILLinkage::PrivateExternal:
-    // Specializations of private symbols should remain so.
-    // TODO: maybe PrivateExternals should get SharedExternal (these are private
-    // functions from the stdlib which are specialized in another module).
+  if (hasPrivateVisibility(L) &&
+      !F->isSerialized()) {
+    // Specializations of private symbols should remain so, unless
+    // they were serialized, which can only happen when specializing
+    // definitions from a standard library built with -sil-serialize-all.
     return SILLinkage::Private;
   }
 
-  llvm_unreachable("Unhandled SILLinkage in switch.");
+  // Treat stdlib_binary_only specially. We don't serialize the body of
+  // stdlib_binary_only functions so we can't mark them as Shared (making
+  // their visibility in the dylib hidden).
+  return F->hasSemanticsAttr("stdlib_binary_only") ? SILLinkage::Public
+                                                   : SILLinkage::Shared;
 }
 
 /// Remove all instructions in the body of \p BB in safe manner by using
@@ -894,6 +883,8 @@
   switch (I->getKind()) {
   case ValueKind::StrongRetainInst:
   case ValueKind::StrongReleaseInst:
+  case ValueKind::CopyValueInst:
+  case ValueKind::DestroyValueInst:
   case ValueKind::RetainValueInst:
   case ValueKind::ReleaseValueInst:
   case ValueKind::DebugValueInst:
@@ -923,6 +914,12 @@
 
   // Otherwise, we need to destroy the argument.
   if (Arg->getType().isObject()) {
+    // If we have qualified ownership, we should just emit a destroy value.
+    if (Arg->getFunction()->hasQualifiedOwnership()) {
+      Callbacks.CreatedNewInst(Builder.createDestroyValue(Loc, Arg));
+      return;
+    }
+
     if (Arg->getType().hasReferenceSemantics()) {
       auto U = Builder.emitStrongRelease(Loc, Arg);
       if (U.isNull())
@@ -1085,7 +1082,7 @@
     bool LiveInSucc = false;
     bool DeadInSucc = false;
     for (const SILSuccessor &Succ : BB->getSuccessors()) {
-      if (LiveBlocks.count(Succ)) {
+      if (isAliveAtBeginOfBlock(Succ)) {
         LiveInSucc = true;
       } else {
         DeadInSucc = true;
@@ -1108,7 +1105,7 @@
       // The value is not live in some of the successor blocks.
       LiveOutBlocks.insert(BB);
       for (const SILSuccessor &Succ : BB->getSuccessors()) {
-        if (!LiveBlocks.count(Succ)) {
+        if (!isAliveAtBeginOfBlock(Succ)) {
           // It's an "exit" edge from the lifetime region.
           FrontierBlocks.insert(Succ);
         }
@@ -1170,7 +1167,7 @@
     // live at the end of BB and therefore Inst is definitely in the lifetime
     // region (Note that we don't check in upward direction against the value's
     // definition).
-    if (LiveBlocks.count(Succ))
+    if (isAliveAtBeginOfBlock(Succ))
       return true;
   }
   // The value is live in the block but not at the end of the block. Check if
diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp
index 8ab3184..6ca3dc0 100644
--- a/lib/SILOptimizer/Utils/SILInliner.cpp
+++ b/lib/SILOptimizer/Utils/SILInliner.cpp
@@ -71,10 +71,10 @@
     // Performance inlining. Construct a proper inline scope pointing
     // back to the call site.
     CallSiteScope = new (F.getModule())
-      SILDebugScope(AI.getLoc(), &F, AIScope);
-    assert(CallSiteScope->getParentFunction() == &F);
+        SILDebugScope(AI.getLoc(), nullptr, AIScope, AIScope->InlinedCallSite);
   }
   assert(CallSiteScope && "call site has no scope");
+  assert(CallSiteScope->getParentFunction() == &F);
 
   // Increment the ref count for the inlined function, so it doesn't
   // get deleted before we can emit abstract debug info for it.
@@ -198,20 +198,22 @@
 
 const SILDebugScope *
 SILInliner::getOrCreateInlineScope(const SILDebugScope *CalleeScope) {
-  assert(CalleeScope);
+  if (!CalleeScope)
+    return CallSiteScope;
   auto it = InlinedScopeCache.find(CalleeScope);
   if (it != InlinedScopeCache.end())
     return it->second;
 
-  auto InlineScope = new (getBuilder().getFunction().getModule())
-      SILDebugScope(CallSiteScope, CalleeScope);
-  assert(CallSiteScope->Parent == InlineScope->InlinedCallSite->Parent);
-
-  InlinedScopeCache.insert({CalleeScope, InlineScope});
-  return InlineScope;
+  auto &M = getBuilder().getFunction().getModule();
+  auto InlinedAt =
+      getOrCreateInlineScope(CalleeScope->InlinedCallSite);
+  auto *InlinedScope = new (M) SILDebugScope(
+      CalleeScope->Loc, CalleeScope->Parent.dyn_cast<SILFunction *>(),
+      CalleeScope->Parent.dyn_cast<const SILDebugScope *>(), InlinedAt);
+  InlinedScopeCache.insert({CalleeScope, InlinedScope});
+  return InlinedScope;
 }
 
-
 //===----------------------------------------------------------------------===//
 //                                 Cost Model
 //===----------------------------------------------------------------------===//
diff --git a/lib/SILOptimizer/Utils/StackNesting.cpp b/lib/SILOptimizer/Utils/StackNesting.cpp
index f6f6e1a..0840fce 100644
--- a/lib/SILOptimizer/Utils/StackNesting.cpp
+++ b/lib/SILOptimizer/Utils/StackNesting.cpp
@@ -119,7 +119,8 @@
             // More locations are alive around the StackInst's location.
             // Update the AlivaLocs bitset, which contains all those alive
             // locations.
-            assert(Bits.test(BitNr) && "no dealloc found for alloc stack");
+            assert((Bits.test(BitNr) || (!BI.ExitReachable && !Bits.any()))
+                   && "no dealloc found for alloc stack");
             StackLocs[BitNr].AliveLocs = Bits;
             changed = true;
             isNested = true;
@@ -147,15 +148,15 @@
 }
 
 static SILInstruction *createDealloc(SILInstruction *Alloc,
-                                     SILInstruction *InsertionPoint) {
+                                     SILInstruction *InsertionPoint,
+                                     SILLocation Location) {
   SILBuilder B(InsertionPoint);
   switch (Alloc->getKind()) {
     case ValueKind::AllocStackInst:
-      return B.createDeallocStack(InsertionPoint->getLoc(), Alloc);
+      return B.createDeallocStack(Location, Alloc);
     case ValueKind::AllocRefInst:
       assert(cast<AllocRefInst>(Alloc)->canAllocOnStack());
-      return B.createDeallocRef(InsertionPoint->getLoc(), Alloc,
-                                /*canBeOnStack*/true);
+      return B.createDeallocRef(Location, Alloc, /*canBeOnStack*/true);
     default:
       llvm_unreachable("unknown stack allocation");
   }
@@ -163,7 +164,8 @@
 
 bool StackNesting::insertDeallocs(const BitVector &AliveBefore,
                                   const BitVector &AliveAfter,
-                                  SILInstruction *InsertionPoint) {
+                                  SILInstruction *InsertionPoint,
+                                  Optional<SILLocation> Location) {
   if (!AliveBefore.test(AliveAfter))
     return false;
 
@@ -174,7 +176,9 @@
   for (int LocNr = AliveBefore.find_first(); LocNr >= 0;
        LocNr = AliveBefore.find_next(LocNr)) {
     if (!AliveAfter.test(LocNr)) {
-      InsertionPoint = createDealloc(StackLocs[LocNr].Alloc, InsertionPoint);
+      SILInstruction *Alloc = StackLocs[LocNr].Alloc;
+      InsertionPoint = createDealloc(Alloc, InsertionPoint,
+                   Location.hasValue() ? Location.getValue() : Alloc->getLoc());
       changesMade = true;
     }
   }
@@ -233,7 +237,7 @@
         CFGChanged = true;
       }
       InstChanged |= insertDeallocs(Bits, SuccBI->AliveStackLocsAtEntry,
-                                    &InsertionBlock->front());
+                                    &InsertionBlock->front(), None);
     }
 
     // Insert/remove deallocations inside blocks.
@@ -247,6 +251,7 @@
       } else if (StackInst->isDeallocatingStack()) {
         // Handle deallocations.
         auto *AllocInst = cast<SILInstruction>(StackInst->getOperand(0));
+        SILLocation Loc = StackInst->getLoc();
         int BitNr = StackLoc2BitNumbers.lookup(AllocInst);
         SILInstruction *InsertionPoint = &*std::next(StackInst->getIterator());
         if (Bits.test(BitNr)) {
@@ -263,7 +268,7 @@
         // Insert deallocations for all locations which are not alive after
         // StackInst but _are_ alive at the StackInst.
         InstChanged |= insertDeallocs(StackLocs[BitNr].AliveLocs, Bits,
-                                      InsertionPoint);
+                                      InsertionPoint, Loc);
         Bits |= StackLocs[BitNr].AliveLocs;
       }
     }
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index 6b8855b..14dffb8 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -32,29 +32,6 @@
 using namespace swift;
 using namespace constraints;
 
-/// \brief Get a substitution corresponding to the type witness.
-/// Inspired by ProtocolConformance::getTypeWitnessByName.
-const Substitution *
-getTypeWitnessByName(ProtocolConformance *conformance,
-                     Identifier name,
-                     LazyResolver *resolver) {
-  // Find the named requirement.
-  AssociatedTypeDecl *assocType = nullptr;
-  auto members = conformance->getProtocol()->lookupDirect(name);
-  for (auto member : members) {
-    assocType = dyn_cast<AssociatedTypeDecl>(member);
-    if (assocType)
-      break;
-  }
-
-  if (!assocType)
-    return nullptr;
-
-  assert(conformance && "Missing conformance information");
-  return &conformance->getTypeWitness(assocType, resolver);
-}
-
-
 /// \brief Retrieve the fixed type for the given type variable.
 Type Solution::getFixedType(TypeVariableType *typeVar) const {
   auto knownBinding = typeBindings.find(typeVar);
@@ -76,7 +53,7 @@
     return false;
 
   SmallVector<ProtocolDecl *, 2> protocols;
-  existential->isExistentialType(protocols);
+  existential->getExistentialTypeProtocols(protocols);
   return protocols.size() == 1 &&
          protocols[0]->isSpecificProtocol(KnownProtocolKind::AnyObject);
 }
@@ -910,6 +887,25 @@
 
         closeExistential(ref, locator, /*force=*/openedExistential);
 
+        // If this attribute was inferred based on deprecated Swift 3 rules,
+        // complain.
+        if (auto attr = member->getAttrs().getAttribute<ObjCAttr>()) {
+          if (attr->isSwift3Inferred() &&
+              !tc.Context.LangOpts.WarnSwift3ObjCInference) {
+            tc.diagnose(memberLoc,
+                        diag::expr_dynamic_lookup_swift3_objc_inference,
+                        member->getDescriptiveKind(),
+                        member->getFullName(),
+                        member->getDeclContext()
+                          ->getAsNominalTypeOrNominalTypeExtensionContext()
+                          ->getName());
+            tc.diagnose(member, diag::make_decl_objc,
+                        member->getDescriptiveKind())
+              .fixItInsert(member->getAttributeInsertionLoc(false),
+                           "@objc ");
+          }
+        }
+
         return ref;
       }
 
@@ -3772,6 +3768,11 @@
           return E;
         }
 
+        if (cs.getType(subExpr)->isLValueType()) {
+          // Treat this like a read of the property.
+          cs.propagateLValueAccessKind(subExpr, AccessKind::Read);
+        }
+
         // Check that we requested a property getter or setter.
         switch (E->getSelectorKind()) {
         case ObjCSelectorExpr::Method: {
@@ -3856,6 +3857,22 @@
           .fixItInsert(foundDecl->getAttributeInsertionLoc(false),
                        "@objc ");
         return E;
+      } else if (auto attr = foundDecl->getAttrs().getAttribute<ObjCAttr>()) {
+        // If this attribute was inferred based on deprecated Swift 3 rules,
+        // complain.
+        if (attr->isSwift3Inferred() &&
+            !tc.Context.LangOpts.WarnSwift3ObjCInference) {
+          tc.diagnose(E->getLoc(), diag::expr_selector_swift3_objc_inference,
+                      foundDecl->getDescriptiveKind(), foundDecl->getFullName(),
+                      foundDecl->getDeclContext()
+                        ->getAsNominalTypeOrNominalTypeExtensionContext()
+                        ->getName())
+            .highlight(subExpr->getSourceRange());
+          tc.diagnose(foundDecl, diag::make_decl_objc,
+                      foundDecl->getDescriptiveKind())
+            .fixItInsert(foundDecl->getAttributeInsertionLoc(false),
+                         "@objc ");
+        }
       }
 
       // Note which method we're referencing.
@@ -4626,7 +4643,7 @@
 collectExistentialConformances(TypeChecker &tc, Type fromType, Type toType,
                                DeclContext *DC) {
   SmallVector<ProtocolDecl *, 4> protocols;
-  toType->getAnyExistentialTypeProtocols(protocols);
+  toType->getExistentialTypeProtocols(protocols);
 
   SmallVector<ProtocolConformanceRef, 4> conformances;
   for (auto proto : protocols) {
@@ -4806,6 +4823,49 @@
   return false;
 }
 
+static unsigned computeCallLevel(
+    ConstraintSystem &cs, ConcreteDeclRef callee,
+    llvm::PointerUnion<ApplyExpr *, ExprRewriter::LevelTy> applyOrLevel) {
+  using LevelTy = ExprRewriter::LevelTy;
+
+  if (applyOrLevel.is<LevelTy>()) {
+    // Level specified by caller.
+    return applyOrLevel.get<LevelTy>();
+  }
+
+  // If we do not have a callee, return a level of 0.
+  if (!callee) {
+    return 0;
+  }
+
+  // Determine the level based on the application itself.
+  auto *apply = applyOrLevel.get<ApplyExpr *>();
+
+  // Only calls to members of types can have level > 0.
+  auto calleeDecl = callee.getDecl();
+  if (!calleeDecl->getDeclContext()->isTypeContext()) {
+    return 0;
+  }
+
+  // Level 1 if we're not applying "self".
+  if (auto *call = dyn_cast<CallExpr>(apply)) {
+    if (!calleeDecl->isInstanceMember() ||
+        !isReferenceToMetatypeMember(cs, call->getDirectCallee())) {
+      return 1;
+    }
+    return 0;
+  }
+
+  // Level 1 if we have an operator.
+  if (isa<PrefixUnaryExpr>(apply) || isa<PostfixUnaryExpr>(apply) ||
+      isa<BinaryExpr>(apply)) {
+    return 1;
+  }
+
+  // Otherwise, we have a normal application.
+  return 0;
+}
+
 Expr *ExprRewriter::coerceCallArguments(
     Expr *arg, Type paramType,
     llvm::PointerUnion<ApplyExpr *, LevelTy> applyOrLevel,
@@ -4853,29 +4913,7 @@
     findCalleeDeclRef(cs, solution, cs.getConstraintLocator(locator));
 
   // Determine the level,
-  unsigned level = 0;
-  if (applyOrLevel.is<LevelTy>()) {
-    // Level specified by caller.
-    level = applyOrLevel.get<LevelTy>();
-  } else if (callee) {
-    // Determine the level based on the application itself.
-    auto apply = applyOrLevel.get<ApplyExpr *>();
-
-    // Only calls to members of types can have level > 0.
-    auto calleeDecl = callee.getDecl();
-    if (calleeDecl->getDeclContext()->isTypeContext()) {
-      // Level 1 if we're not applying "self".
-      if (auto call = dyn_cast<CallExpr>(apply)) {
-        if (!calleeDecl->isInstanceMember() ||
-            !isReferenceToMetatypeMember(cs, call->getDirectCallee()))
-          level = 1;
-      } else if (isa<PrefixUnaryExpr>(apply) ||
-                 isa<PostfixUnaryExpr>(apply) ||
-                 isa<BinaryExpr>(apply)) {
-        level = 1;
-      }
-    }
-  }
+  unsigned level = computeCallLevel(cs, callee, applyOrLevel);
 
   // Determine the parameter bindings.
   auto params = decomposeParamType(paramType, callee.getDecl(), level);
@@ -7016,6 +7054,9 @@
   }
 
   case FixKind::ForceDowncast: {
+    if (auto *paren = dyn_cast<ParenExpr>(affected))
+      affected = paren->getSubExpr();
+
     auto fromType = solution.simplifyType(getType(affected))
                       ->getRValueObjectType();
     Type toType = solution.simplifyType(fix.first.getTypeArgument(*this));
@@ -7038,7 +7079,7 @@
       insertAfter += ")";
     }
     insertAfter += useAs ? " as " : " as! ";
-    insertAfter += toType.getString();
+    insertAfter += toType->getWithoutParens()->getString();
     if (needsParensOutside)
       insertAfter += ")";
     
diff --git a/lib/Sema/CSPropagate.cpp b/lib/Sema/CSPropagate.cpp
index 3e38591..d171303 100644
--- a/lib/Sema/CSPropagate.cpp
+++ b/lib/Sema/CSPropagate.cpp
@@ -15,13 +15,255 @@
 //===----------------------------------------------------------------------===//
 #include "ConstraintGraph.h"
 #include "ConstraintSystem.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Debug.h"
+
 using namespace swift;
 using namespace constraints;
 
+// Find the disjunction of bind overload constraints related to this
+// applicable function constraint, if it exists.
+Constraint *
+getBindOverloadDisjunction(ConstraintSystem &CS, Constraint *applicableFn) {
+  assert(applicableFn->getKind() == ConstraintKind::ApplicableFunction
+         && "Expected ApplicableFunction disjunction!");
+  auto *tyvar = applicableFn->getSecondType()->getAs<TypeVariableType>();
+  assert(tyvar && "Expected type variable!");
+
+  Constraint *found = nullptr;
+  for (auto *constraint : CS.getConstraintGraph()[tyvar].getConstraints()) {
+    if (constraint->getKind() == ConstraintKind::Disjunction) {
+      found = constraint;
+      break;
+    }
+  }
+
+  if (!found)
+    return nullptr;
+
+#if !defined(NDEBUG)
+  for (auto *constraint : CS.getConstraintGraph()[tyvar].getConstraints()) {
+    if (constraint == found)
+      continue;
+
+    assert(constraint->getKind() != ConstraintKind::Disjunction
+           && "Type variable is involved in more than one disjunction!");
+  }
+#endif
+
+  // Verify the disjunction consists of BindOverload constraints.
+  assert(found->getNestedConstraints().front()->getKind() ==
+         ConstraintKind::BindOverload);
+
+  return found;
+}
+
+// Simplify the active constraints, collecting any new applicable
+// function constraints we find along the way, and bailing if we fail
+// to simplify a constraint successfully.
+bool ConstraintSystem::simplifyForConstraintPropagation() {
+  while (!ActiveConstraints.empty()) {
+    auto *constraint = &ActiveConstraints.front();
+    ActiveConstraints.pop_front();
+
+    assert(constraint->isActive()
+           && "Expected constraints to be active?");
+    assert(!constraint->isDisabled() && "Unexpected disabled constraint!");
+
+    bool failed = false;
+
+    // Simplify this constraint.
+    switch (simplifyConstraint(*constraint)) {
+    case SolutionKind::Error:
+      failed = true;
+      LLVM_FALLTHROUGH;
+
+    case SolutionKind::Solved:
+      solverState->retireConstraint(constraint);
+      CG.removeConstraint(constraint);
+      break;
+
+    case SolutionKind::Unsolved:
+      InactiveConstraints.push_back(constraint);
+      break;
+    }
+
+    constraint->setActive(false);
+
+    if (failed)
+      return true;
+  }
+
+  return false;
+}
+
+// Gather the applicable function constraints associated with a
+// particular typevar, but do not include the one that is passed in
+// since that is the constraint that we're starting from.
+void ConstraintSystem::gatherNeighboringApplicableFunctionConstraints(
+    Constraint *applicableFn,
+    SmallVectorImpl<Constraint *> &otherApplicableFn) {
+
+  auto *tyvar = applicableFn->getSecondType()->getAs<TypeVariableType>();
+  assert(tyvar && "Expected type variable!");
+
+  SmallVector<Constraint *, 8> neighbors;
+  CG.gatherConstraints(tyvar, neighbors,
+                       ConstraintGraph::GatheringKind::AllMentions);
+
+  for (auto *constraint : neighbors) {
+    if (constraint->getKind() != ConstraintKind::ApplicableFunction ||
+        constraint == applicableFn)
+      continue;
+
+    otherApplicableFn.push_back(constraint);
+  }
+}
+
+// Test a bind overload constraint to see if it is consistent with the
+// rest of the constraint system.
+bool ConstraintSystem::isBindOverloadConsistent(
+    Constraint *bindConstraint, Constraint *applicableFn,
+    llvm::SetVector<Constraint *> &workList, bool topLevel) {
+
+  // Set up a scope that will be torn down when we're done testing
+  // this constraint.
+  ConstraintSystem::SolverScope scope(*this);
+
+  assert(applicableFn->getKind() == ConstraintKind::ApplicableFunction
+         && "Expected an ApplicableFunction constraint!");
+  assert(bindConstraint->getKind() == ConstraintKind::BindOverload
+         && "Expected a BindOverload constraint!");
+
+  switch (simplifyConstraint(*bindConstraint)) {
+  case ConstraintSystem::SolutionKind::Error:
+    solverState->retireConstraint(bindConstraint);
+    solverState->addGeneratedConstraint(bindConstraint);
+    return false;
+  case ConstraintSystem::SolutionKind::Solved: {
+    solverState->retireConstraint(bindConstraint);
+    solverState->addGeneratedConstraint(bindConstraint);
+
+    if (simplifyForConstraintPropagation())
+      return false;
+
+    if (!topLevel)
+      return true;
+
+    // Test the applicable function constraints that neighbor the bind
+    // overload constraint.
+    SmallVector<Constraint *, 8> otherApplicableFn;
+    gatherNeighboringApplicableFunctionConstraints(applicableFn,
+                                                   otherApplicableFn);
+
+    for (auto *constraint : otherApplicableFn)
+      if (!isApplicableFunctionConsistent(constraint, workList,
+                                          /* topLevel = */ false))
+        return false;
+
+    return true;
+  }
+
+  case ConstraintSystem::SolutionKind::Unsolved:
+    InactiveConstraints.push_back(bindConstraint);
+    CG.addConstraint(bindConstraint);
+    solverState->addGeneratedConstraint(bindConstraint);
+    return true;
+  }
+}
+
+// Test an applicable function constraint by testing all of the bind
+// overload constraints in the related disjunction. If we cannot find
+// a related disjunction, or if all the constraints in that
+// disjunction are inconsistent with the system, we'll return false.
+bool ConstraintSystem::isApplicableFunctionConsistent(
+    Constraint *applicableFn, llvm::SetVector<Constraint *> &workList,
+    bool topLevel) {
+
+  // Set up a scope that will be torn down when we're done testing
+  // this constraint.
+  ConstraintSystem::SolverScope scope(*this);
+
+  auto *disjunction = getBindOverloadDisjunction(*this, applicableFn);
+  if (!disjunction)
+    return true;
+
+  auto insertPt = InactiveConstraints.erase(disjunction);
+  CG.removeConstraint(disjunction);
+
+  bool foundConsistent = false;
+  for (auto *bindConstraint : disjunction->getNestedConstraints()) {
+    assert(bindConstraint->getKind() == ConstraintKind::BindOverload
+           && "Expected a BindOverload constraint!");
+
+    if (bindConstraint->isDisabled())
+      continue;
+
+    if (!isBindOverloadConsistent(bindConstraint, applicableFn, workList,
+                                  topLevel)) {
+      if (topLevel) {
+        bindConstraint->setDisabled();
+
+        // Queue up other constraints that may be affected by disabling
+        // this one.
+        SmallVector<Constraint *, 8> otherApplicableFn;
+        gatherNeighboringApplicableFunctionConstraints(applicableFn,
+                                                       otherApplicableFn);
+
+        for (auto *constraint : otherApplicableFn)
+          workList.insert(constraint);
+      }
+    } else {
+      foundConsistent = true;
+
+      // If we find any bind overload that works when we're testing
+      // the "other" applicable function constraints, we know there is
+      // some working solution and can stop.
+      if (!topLevel)
+        break;
+    }
+  }
+
+  CG.addConstraint(disjunction);
+  InactiveConstraints.insert(insertPt, disjunction);
+
+  // If none of the nested constraints works, we know there is no
+  // solution to this constraint system, otherwise, there may be.
+  return foundConsistent;
+}
+
+// Do a form of constraint propagation consisting of examining
+// applicable function constraints and their associated disjunction of
+// bind overload constraints. Disable bind overload constraints in the
+// disjunction if they are inconsistent with the rest of the
+// constraint system. By doing this we can eliminate a lot of the work
+// that we'll perform in the constraint solver.
 bool ConstraintSystem::propagateConstraints() {
+  assert(!failedConstraint && "Unexpected failed constraint!");
   assert(getActiveConstraints().empty() && "Expected no active constraints!");
 
+  // Queue an initial set of ApplicableFunction constraints to process.
+  llvm::SetVector<Constraint *> workList;
+  for (auto &constraint : getConstraints()) {
+    if (constraint.getKind() != ConstraintKind::ApplicableFunction)
+      continue;
+
+    workList.insert(&constraint);
+  }
+
+  // Process all constraints in the work list, adding new elements as
+  // we process them.
+  while (!workList.empty()) {
+    auto *constraint = workList.pop_back_val();
+
+    assert(constraint->getKind() == ConstraintKind::ApplicableFunction
+           && "Expected ApplicableFunction constraint on work list!");
+
+    if (!isApplicableFunctionConsistent(constraint, workList,
+                                        /* topLevel = */ true))
+      return true;
+  }
+
   return false;
 }
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index b0fd113f..7594a81 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1177,11 +1177,11 @@
     }
   }
 
-  if (!type2->isAnyExistentialType())
+  if (!type2->isExistentialType())
     return SolutionKind::Error;
 
   SmallVector<ProtocolDecl *, 4> protocols;
-  type2->getAnyExistentialTypeProtocols(protocols);
+  type2->getExistentialTypeProtocols(protocols);
 
   for (auto proto : protocols) {
     switch (simplifyConformsToConstraint(type1, proto, kind, locator,
diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp
index 145754b..4498e65 100644
--- a/lib/Sema/CSSolver.cpp
+++ b/lib/Sema/CSSolver.cpp
@@ -1173,22 +1173,30 @@
   // If we're supposed to add optional supertype bindings, do so now.
   if (addOptionalSupertypeBindings) {
     for (unsigned i : indices(result.Bindings)) {
-      // Only interested in supertype bindings.
       auto &binding = result.Bindings[i];
-      if (binding.Kind != AllowedBindingKind::Supertypes) continue;
+      bool wrapInOptional = false;
+        
+      if (binding.Kind == AllowedBindingKind::Supertypes) {
+        // If the type doesn't conform to ExpressibleByNilLiteral,
+        // produce an optional of that type as a potential binding. We
+        // overwrite the binding in place because the non-optional type
+        // will fail to type-check against the nil-literal conformance.
+        auto nominalBindingDecl = binding.BindingType->getAnyNominal();
+        bool conformsToExprByNilLiteral = false;
+        if (nominalBindingDecl) {
+          SmallVector<ProtocolConformance *, 2> conformances;
+          conformsToExprByNilLiteral = nominalBindingDecl->lookupConformance(
+                                         cs.DC->getParentModule(),
+                                         cs.getASTContext().getProtocol(
+                                           KnownProtocolKind::ExpressibleByNilLiteral),
+                                         conformances);
+        }
+        wrapInOptional = !conformsToExprByNilLiteral;
+      } else if (binding.isDefaultableBinding() && binding.BindingType->isAny()) {
+        wrapInOptional = true;
+      }
 
-      // If the type doesn't conform to ExpressibleByNilLiteral,
-      // produce an optional of that type as a potential binding. We
-      // overwrite the binding in place because the non-optional type
-      // will fail to type-check against the nil-literal conformance.
-      auto nominalBindingDecl = binding.BindingType->getAnyNominal();
-      if (!nominalBindingDecl) continue;
-      SmallVector<ProtocolConformance *, 2> conformances;
-      if (!nominalBindingDecl->lookupConformance(
-            cs.DC->getParentModule(),
-            cs.getASTContext().getProtocol(
-              KnownProtocolKind::ExpressibleByNilLiteral),
-            conformances)) {
+      if (wrapInOptional) {
         binding.BindingType = OptionalType::get(binding.BindingType);
       }
     }
@@ -2432,10 +2440,10 @@
   // FIXME: This heuristic isn't great, but it helped somewhat for
   // overload sets.
   auto disjunction = disjunctions[0];
-  auto bestSize = disjunction->getNestedConstraints().size();
+  auto bestSize = disjunction->countActiveNestedConstraints();
   if (bestSize > 2) {
     for (auto contender : llvm::makeArrayRef(disjunctions).slice(1)) {
-      unsigned newSize = contender->getNestedConstraints().size();
+      unsigned newSize = contender->countActiveNestedConstraints();
       if (newSize < bestSize) {
         bestSize = newSize;
         disjunction = contender;
@@ -2446,6 +2454,11 @@
     }
   }
 
+  // If there are no active constraints in the disjunction, there is
+  // no solution.
+  if (bestSize == 0)
+    return true;
+
   // Remove this disjunction constraint from the list.
   auto afterDisjunction = InactiveConstraints.erase(disjunction);
   CG.removeConstraint(disjunction);
@@ -2456,6 +2469,16 @@
   auto constraints = disjunction->getNestedConstraints();
   for (auto index : indices(constraints)) {
     auto constraint = constraints[index];
+    if (constraint->isDisabled()) {
+      if (TC.getLangOpts().DebugConstraintSolver) {
+        auto &log = getASTContext().TypeCheckerDebug->getStream();
+        log.indent(solverState->depth)
+          << "(skipping ";
+        constraint->print(log, &TC.Context.SourceMgr);
+        log << '\n';
+      }
+      continue;
+    }
 
     // We already have a solution; check whether we should
     // short-circuit the disjunction.
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index 3bff267..ac9d23c 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -848,6 +848,11 @@
 /// Add a materializeForSet accessor to the given declaration.
 static FuncDecl *addMaterializeForSet(AbstractStorageDecl *storage,
                                       TypeChecker &TC) {
+  if (TC.Context.getOptionalDecl() == nullptr) {
+    TC.diagnose(storage->getStartLoc(), diag::optional_intrinsics_not_found);
+    return nullptr;
+  }
+
   auto materializeForSet = createMaterializeForSetPrototype(
       storage, storage->getSetter(), TC);
   addMemberToContextIfNeeded(materializeForSet, storage->getDeclContext(),
@@ -888,6 +893,8 @@
   // the members list.
   addMemberToContextIfNeeded(Get, VD->getDeclContext(), VD);
   addMemberToContextIfNeeded(Set, VD->getDeclContext(), Get);
+
+  maybeAddMaterializeForSet(VD, TC);
 }
 
 /// The specified AbstractStorageDecl was just found to satisfy a
@@ -1648,23 +1655,20 @@
   if (!storage->getSetter()) return;
 
   // We only need materializeForSet in type contexts.
-  NominalTypeDecl *container = storage->getDeclContext()
-      ->getAsNominalTypeOrNominalTypeExtensionContext();
-  if (!container) return;
+  auto *dc = storage->getDeclContext();
+  if (!dc->isTypeContext())
+    return;
 
   // Requirements of ObjC protocols don't need this.
-  if (auto protocol = dyn_cast<ProtocolDecl>(container)) {
-    if (protocol->isObjC()) return;
+  if (auto protoDecl = dyn_cast<ProtocolDecl>(dc))
+    if (protoDecl->isObjC())
+      return;
 
-  // Types imported by Clang don't need this, because we can
+  // Members of structs imported by Clang don't need this, because we can
   // synthesize it later.
-  } else {
-    assert(isa<NominalTypeDecl>(container));
-    if (container->hasClangNode()) return;
-  }
-
-  // @NSManaged properties don't need this.
-  if (storage->getAttrs().hasAttribute<NSManagedAttr>()) return;
+  if (auto structDecl = dyn_cast<StructDecl>(dc))
+    if (structDecl->hasClangNode())
+      return;
 
   addMaterializeForSet(storage, TC);
 }
diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp
index 4442630..a6e70dc 100644
--- a/lib/Sema/Constraint.cpp
+++ b/lib/Sema/Constraint.cpp
@@ -31,7 +31,8 @@
                        ConstraintLocator *locator, 
                        ArrayRef<TypeVariableType *> typeVars)
   : Kind(kind), HasRestriction(false), HasFix(false), IsActive(false),
-    RememberChoice(false), IsFavored(false), NumTypeVariables(typeVars.size()),
+    IsDisabled(false), RememberChoice(false), IsFavored(false),
+    NumTypeVariables(typeVars.size()),
     Nested(constraints), Locator(locator)
 {
   assert(kind == ConstraintKind::Disjunction);
@@ -43,8 +44,8 @@
                        ConstraintLocator *locator,
                        ArrayRef<TypeVariableType *> typeVars)
   : Kind(Kind), HasRestriction(false), HasFix(false), IsActive(false),
-    RememberChoice(false), IsFavored(false), NumTypeVariables(typeVars.size()),
-    Types { First, Second }, Locator(locator)
+    IsDisabled(false), RememberChoice(false), IsFavored(false),
+    NumTypeVariables(typeVars.size()), Types { First, Second }, Locator(locator)
 {
   switch (Kind) {
   case ConstraintKind::Bind:
@@ -100,8 +101,9 @@
                        ConstraintLocator *locator,
                        ArrayRef<TypeVariableType *> typeVars)
   : Kind(kind), HasRestriction(false), HasFix(false), IsActive(false),
-    RememberChoice(false), IsFavored(false), NumTypeVariables(typeVars.size()),
-    Member { first, second, member, useDC }, Locator(locator)
+    IsDisabled(false), RememberChoice(false), IsFavored(false),
+    NumTypeVariables(typeVars.size()), Member { first, second, member, useDC },
+    Locator(locator)
 {
   assert(kind == ConstraintKind::ValueMember ||
          kind == ConstraintKind::UnresolvedValueMember);
@@ -117,7 +119,7 @@
                        ConstraintLocator *locator,
                        ArrayRef<TypeVariableType *> typeVars)
   : Kind(ConstraintKind::BindOverload),
-    HasRestriction(false), HasFix(false), IsActive(false),
+    HasRestriction(false), HasFix(false), IsActive(false), IsDisabled(false),
     RememberChoice(false), IsFavored(false), NumTypeVariables(typeVars.size()),
     Overload{type, choice, useDC}, Locator(locator)
 { 
@@ -129,7 +131,7 @@
                        Type first, Type second, ConstraintLocator *locator,
                        ArrayRef<TypeVariableType *> typeVars)
     : Kind(kind), Restriction(restriction),
-      HasRestriction(true), HasFix(false), IsActive(false),
+      HasRestriction(true), HasFix(false), IsActive(false), IsDisabled(false),
       RememberChoice(false), IsFavored(false), NumTypeVariables(typeVars.size()),
       Types{ first, second }, Locator(locator)
 {
@@ -143,7 +145,7 @@
                        ArrayRef<TypeVariableType *> typeVars)
   : Kind(kind), FixData(fix.getData()), TheFix(fix.getKind()),
     HasRestriction(false), HasFix(true),
-    IsActive(false), RememberChoice(false), IsFavored(false),
+    IsActive(false), IsDisabled(false), RememberChoice(false), IsFavored(false),
     NumTypeVariables(typeVars.size()),
     Types{ first, second }, Locator(locator)
 {
@@ -216,7 +218,11 @@
     Out << ":";
 
     interleave(getNestedConstraints(),
-               [&](Constraint *constraint) { constraint->print(Out, sm); },
+               [&](Constraint *constraint) {
+                 if (isDisabled())
+                   Out << "[disabled] ";
+                 constraint->print(Out, sm);
+               },
                [&] { Out << " or "; });
     return;
   }
diff --git a/lib/Sema/Constraint.h b/lib/Sema/Constraint.h
index 1a11394..79b3d6d 100644
--- a/lib/Sema/Constraint.h
+++ b/lib/Sema/Constraint.h
@@ -307,6 +307,10 @@
   /// Whether this constraint is currently active, i.e., stored in the worklist.
   unsigned IsActive : 1;
 
+  /// Was this constraint was determined to be inconsistent with the
+  /// constraint graph during constraint propagation?
+  unsigned IsDisabled : 1;
+
   /// Whether the choice of this disjunction should be recorded in the
   /// solver state.
   unsigned RememberChoice : 1;
@@ -465,8 +469,20 @@
   bool isActive() const { return IsActive; }
 
   /// Set whether this constraint is active or not.
-  void setActive(bool active) { IsActive = active; }
-  
+  void setActive(bool active) {
+    assert(!isDisabled() && "Cannot activate a constraint that is disabled!");
+    IsActive = active;
+  }
+
+  /// Whether this constraint is active, i.e., in the worklist.
+  bool isDisabled() const { return IsDisabled; }
+
+  /// Set whether this constraint is active or not.
+  void setDisabled() {
+    assert(!isActive() && "Cannot disable constraint marked as active!");
+    IsDisabled = true;
+  }
+
   /// Mark or retrieve whether this constraint should be favored in the system.
   void setFavored() { IsFavored = true; }
   bool isFavored() const { return IsFavored; }
@@ -588,6 +604,15 @@
     return Nested;
   }
 
+  unsigned countActiveNestedConstraints() const {
+    unsigned count = 0;
+    for (auto *constraint : Nested)
+      if (!constraint->isDisabled())
+        count++;
+
+    return count;
+  }
+
   /// Retrieve the overload choice for an overload-binding constraint.
   OverloadChoice getOverloadChoice() const {
     assert(Kind == ConstraintKind::BindOverload);
diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index d52d87b..076de8a 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -189,8 +189,7 @@
 getDynamicResultSignature(ValueDecl *decl) {
   if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
     // Handle functions.
-    auto type =
-      decl->getInterfaceType()->castTo<AnyFunctionType>()->getResult();
+    auto type = func->getMethodInterfaceType();
     return std::make_tuple(func->isStatic(), func->getObjCSelector(),
                            type->getCanonicalType());
   }
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index 82babc1..4b9edbf 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -33,6 +33,7 @@
 #include "swift/AST/TypeCheckerDebugConsumer.h"
 #include "llvm/ADT/ilist.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
@@ -2360,8 +2361,19 @@
   /// \param expr The expression to find reductions for.
   void shrink(Expr *expr);
 
- public:
+  void gatherNeighboringApplicableFunctionConstraints(
+      Constraint *applicableFn,
+      SmallVectorImpl<Constraint *> &otherApplicableFn);
+  bool simplifyForConstraintPropagation();
+  bool isBindOverloadConsistent(Constraint *bindConstraint,
+                                Constraint *applicableFn,
+                                llvm::SetVector<Constraint *> &workList,
+                                bool topLevel);
+  bool isApplicableFunctionConsistent(Constraint *applicableFn,
+                                      llvm::SetVector<Constraint *> &workList,
+                                      bool topLevel);
 
+public:
   /// \brief Solve the system of constraints generated from provided expression.
   ///
   /// \param expr The expression to generate constraints from.
diff --git a/lib/Sema/ITCDecl.cpp b/lib/Sema/ITCDecl.cpp
index 430e43a..9ba5be4 100644
--- a/lib/Sema/ITCDecl.cpp
+++ b/lib/Sema/ITCDecl.cpp
@@ -255,8 +255,9 @@
 
     // Collect existential types.
     // FIXME: We'd prefer to keep what the user wrote here.
-    SmallVector<ProtocolDecl *, 4> protocols;
-    if (inherited.getType()->isExistentialType(protocols)) {
+    if (inherited.getType()->isExistentialType()) {
+      SmallVector<ProtocolDecl *, 4> protocols;
+      inherited.getType()->getExistentialTypeProtocols(protocols);
       for (auto inheritedProtocol: protocols) {
         if (inheritedProtocol == protocol ||
             inheritedProtocol->inheritsFrom(protocol)) {
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index 3671153..967999d 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -234,6 +234,7 @@
   void visitSetterAccessibilityAttr(SetterAccessibilityAttr *attr);
   bool visitAbstractAccessibilityAttr(AbstractAccessibilityAttr *attr);
   void visitSILStoredAttr(SILStoredAttr *attr);
+  void visitObjCMembersAttr(ObjCMembersAttr *attr);
 };
 } // end anonymous namespace
 
@@ -293,6 +294,10 @@
   // Members cannot be both dynamic and final.
   if (D->getAttrs().hasAttribute<FinalAttr>())
     return diagnoseAndRemoveAttr(attr, diag::dynamic_with_final);
+
+  // Members cannot be both dynamic and @nonobjc.
+  if (D->getAttrs().hasAttribute<NonObjCAttr>())
+    return diagnoseAndRemoveAttr(attr, diag::dynamic_with_nonobjc);
 }
 
 
@@ -629,6 +634,10 @@
   }
 }
 
+void AttributeEarlyChecker::visitObjCMembersAttr(ObjCMembersAttr *attr) {
+  if (!isa<ClassDecl>(D))
+    return diagnoseAndRemoveAttr(attr, diag::objcmembers_attribute_nonclass);
+}
 
 void TypeChecker::checkDeclAttributesEarly(Decl *D) {
   // Don't perform early attribute validation more than once.
@@ -745,6 +754,7 @@
     IGNORED_ATTR(Testable)
     IGNORED_ATTR(WarnUnqualifiedAccess)
     IGNORED_ATTR(ShowInInterface)
+    IGNORED_ATTR(ObjCMembers)
 #undef IGNORED_ATTR
 
   void visitAvailableAttr(AvailableAttr *attr);
@@ -832,7 +842,7 @@
 void AttributeChecker::visitIBActionAttr(IBActionAttr *attr) {
   // IBActions instance methods must have type Class -> (...) -> ().
   auto *FD = cast<FuncDecl>(D);
-  Type CurriedTy = FD->getInterfaceType()->castTo<AnyFunctionType>()->getResult();
+  Type CurriedTy = FD->getMethodInterfaceType();
   Type ResultTy = CurriedTy->castTo<AnyFunctionType>()->getResult();
   if (!ResultTy->isEqual(TupleType::getEmpty(TC.Context))) {
     TC.diagnose(D, diag::invalid_ibaction_result, ResultTy);
diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp
index b3de2ca..eaa504e 100644
--- a/lib/Sema/TypeCheckAvailability.cpp
+++ b/lib/Sema/TypeCheckAvailability.cpp
@@ -1676,7 +1676,7 @@
     diag.fixItReplace(referenceRange, baseReplace);
   }
 
-  if (!dyn_cast_or_null<CallExpr>(call))
+  if (!call || !isa<CallExpr>(call))
     return;
 
   const Expr *argExpr = call->getArg();
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index 30e1853..070f793 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -3319,10 +3319,8 @@
 
   bool toArchetype = toType->is<ArchetypeType>();
   bool fromArchetype = fromType->is<ArchetypeType>();
-  SmallVector<ProtocolDecl*, 2> toProtocols;
-  bool toExistential = toType->isExistentialType(toProtocols);
-  SmallVector<ProtocolDecl*, 2> fromProtocols;
-  bool fromExistential = fromType->isExistentialType(fromProtocols);
+  bool toExistential = toType->isExistentialType();
+  bool fromExistential = fromType->isExistentialType();
   
   // If we're doing a metatype cast, it can only be existential if we're
   // casting to/from the existential metatype. 'T.self as P.Protocol'
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 0faf100..ed5e2bd 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -241,9 +241,40 @@
   ITC.satisfy(requestTypeCheckRawType(enumDecl));
 }
 
+void TypeChecker::validateWhereClauses(ProtocolDecl *protocol) {
+  ProtocolRequirementTypeResolver resolver(protocol);
+  TypeResolutionOptions options;
+
+  if (auto whereClause = protocol->getTrailingWhereClause()) {
+    DeclContext *lookupDC = protocol;
+    for (auto &req : whereClause->getRequirements()) {
+      // FIXME: handle error?
+      (void)validateRequirement(whereClause->getWhereLoc(), req,
+                                lookupDC, options, &resolver);
+    }
+  }
+
+  for (auto member : protocol->getMembers()) {
+    if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
+      if (auto whereClause = assocType->getTrailingWhereClause()) {
+        DeclContext *lookupDC = assocType->getDeclContext();
+
+        for (auto &req : whereClause->getRequirements()) {
+          if (!validateRequirement(whereClause->getWhereLoc(), req,
+                                   lookupDC, options, &resolver))
+            // FIXME handle error?
+            continue;
+        }
+      }
+    }
+  }
+}
+
 void TypeChecker::resolveInheritedProtocols(ProtocolDecl *protocol) {
   IterativeTypeChecker ITC(*this);
   ITC.satisfy(requestInheritedProtocols(protocol));
+
+  validateWhereClauses(protocol);
 }
 
 void TypeChecker::resolveInheritanceClause(
@@ -412,7 +443,7 @@
     // protocols.
     if (inheritedTy->isExistentialType()) {
       SmallVector<ProtocolDecl *, 4> protocols;
-      inheritedTy->isExistentialType(protocols);
+      inheritedTy->getExistentialTypeProtocols(protocols);
 
       allProtocols.insert(protocols.begin(), protocols.end());
       continue;
@@ -2285,6 +2316,23 @@
   }
 }
 
+/// Whether this declaration is a member of a class extension marked @objc.
+static bool isMemberOfObjCClassExtension(const ValueDecl *VD) {
+  auto ext = dyn_cast<ExtensionDecl>(VD->getDeclContext());
+  if (!ext) return false;
+
+  return ext->getAsClassOrClassExtensionContext() &&
+    ext->getAttrs().hasAttribute<ObjCAttr>();
+}
+
+/// Whether this declaration is a member of a class with the `@objcMembers`
+/// attribute.
+static bool isMemberOfObjCMembersClass(const ValueDecl *VD) {
+  auto classDecl = VD->getDeclContext()->getAsClassOrClassExtensionContext();
+  if (!classDecl) return false;
+
+  return classDecl->getAttrs().hasAttribute<ObjCMembersAttr>();
+}
 /// Figure out if a declaration should be exported to Objective-C.
 static Optional<ObjCReason> shouldMarkAsObjC(TypeChecker &TC,
                                              const ValueDecl *VD,
@@ -2296,42 +2344,104 @@
   bool isMemberOfObjCProtocol =
       protocolContext && protocolContext->isObjC();
 
+  // Local function to determine whether we can implicitly infer @objc.
+  auto canInferImplicitObjC = [&] {
+    if (VD->isInvalid())
+      return false;
+    if (VD->isOperator())
+      return false;
+
+    // Implicitly generated declarations are not @objc, except for constructors.
+    if (!allowImplicit && VD->isImplicit())
+      return false;
+
+    if (VD->getFormalAccess() <= Accessibility::FilePrivate)
+      return false;
+
+    return true;
+  };
+
   // explicitly declared @objc.
   if (VD->getAttrs().hasAttribute<ObjCAttr>())
     return ObjCReason::ExplicitlyObjC;
-  // dynamic, @IBOutlet, @IBAction, and @NSManaged imply @objc.
-  else if (VD->getAttrs().hasAttribute<DynamicAttr>())
-    return ObjCReason::ExplicitlyDynamic;
-  else if (VD->getAttrs().hasAttribute<IBOutletAttr>())
+  // @IBOutlet, @IBAction, @IBInspectable, @NSManaged, and @GKInspectable
+  // imply @objc.
+  if (VD->getAttrs().hasAttribute<IBOutletAttr>())
     return ObjCReason::ExplicitlyIBOutlet;
-  else if (VD->getAttrs().hasAttribute<IBActionAttr>())
+  if (VD->getAttrs().hasAttribute<IBActionAttr>())
     return ObjCReason::ExplicitlyIBAction;
-  else if (VD->getAttrs().hasAttribute<NSManagedAttr>())
+  if (VD->getAttrs().hasAttribute<IBInspectableAttr>())
+    return ObjCReason::ExplicitlyIBInspectable;
+  if (VD->getAttrs().hasAttribute<GKInspectableAttr>())
+    return ObjCReason::ExplicitlyGKInspectable;
+  if (VD->getAttrs().hasAttribute<NSManagedAttr>())
     return ObjCReason::ExplicitlyNSManaged;
   // A member of an @objc protocol is implicitly @objc.
-  else if (isMemberOfObjCProtocol)
+  if (isMemberOfObjCProtocol)
     return ObjCReason::MemberOfObjCProtocol;
   // A @nonobjc is not @objc, even if it is an override of an @objc, so check
   // for @nonobjc first.
-  else if (VD->getAttrs().hasAttribute<NonObjCAttr>())
+  if (VD->getAttrs().hasAttribute<NonObjCAttr>() ||
+      (isa<ExtensionDecl>(VD->getDeclContext()) &&
+       cast<ExtensionDecl>(VD->getDeclContext())->getAttrs()
+        .hasAttribute<NonObjCAttr>()))
     return None;
+  if (isMemberOfObjCClassExtension(VD))
+    return ObjCReason::MemberOfObjCExtension;
+  if (isMemberOfObjCMembersClass(VD) && canInferImplicitObjC())
+    return ObjCReason::MemberOfObjCMembersClass;
   // An override of an @objc declaration is implicitly @objc.
-  else if (VD->getOverriddenDecl() && VD->getOverriddenDecl()->isObjC())
+  if (VD->getOverriddenDecl() && VD->getOverriddenDecl()->isObjC())
     return ObjCReason::OverridesObjC;
   // A witness to an @objc protocol requirement is implicitly @objc.
-  else if (VD->getDeclContext()->getAsClassOrClassExtensionContext() &&
-           !TC.findWitnessedObjCRequirements(
-             VD,
-             /*anySingleRequirement=*/true).empty())
+  if (VD->getDeclContext()->getAsClassOrClassExtensionContext() &&
+      !TC.findWitnessedObjCRequirements(VD,
+                                        /*anySingleRequirement=*/true).empty())
     return ObjCReason::WitnessToObjC;
-  else if (VD->isInvalid())
+
+  // Infer '@objc' for 'dynamic' members.
+  if (auto attr = VD->getAttrs().getAttribute<DynamicAttr>()) {
+    // For implicit 'dynamic', just infer '@objc' implicitly.
+    if (attr->isImplicit())
+      return ObjCReason::ImplicitlyObjC;
+
+    bool isAccessor =
+      isa<FuncDecl>(VD) && cast<FuncDecl>(VD)->isGetterOrSetter();
+
+    // Under Swift 3's @objc inference rules, 'dynamic' infers '@objc'.
+    if (TC.Context.LangOpts.EnableSwift3ObjCInference) {
+      // If we've been asked to warn about deprecated @objc inference, do so
+      // now.
+      if (TC.Context.LangOpts.WarnSwift3ObjCInference && !isAccessor) {
+        TC.diagnose(VD, diag::objc_inference_swift3_dynamic)
+          .highlight(attr->getLocation())
+          .fixItInsert(VD->getAttributeInsertionLoc(/*forModifier=*/false),
+                      "@objc ");
+      }
+
+      return ObjCReason::ExplicitlyDynamic;
+    }
+
+    // Complain that 'dynamic' requires '@objc', but (quietly) infer @objc
+    // anyway for better recovery.
+    TC.diagnose(VD, diag::dynamic_requires_objc,
+                VD->getDescriptiveKind(), VD->getFullName())
+      .highlight(attr->getRange())
+      .fixItInsert(VD->getAttributeInsertionLoc(/*forModifier=*/false),
+                   "@objc ");
+
+    return ObjCReason::ImplicitlyObjC;
+  }
+
+  // If we aren't provided Swift 3's @objc inference rules, we're done.
+  if (!TC.Context.LangOpts.EnableSwift3ObjCInference)
     return None;
-  else if (VD->isOperator())
-    return None;
-  // Implicitly generated declarations are not @objc, except for constructors.
-  else if (!allowImplicit && VD->isImplicit())
-    return None;
-  else if (VD->getFormalAccess() <= Accessibility::FilePrivate)
+
+  // Infer '@objc' for valid, non-implicit, non-operator, members of classes
+  // (and extensions thereof) whose class hierarchies originate in Objective-C,
+  // e.g., which derive from NSObject, so long as the members have internal
+  // access or greater.
+  if (!canInferImplicitObjC())
     return None;
 
   // If this declaration is part of a class with implicitly @objc members,
@@ -2343,8 +2453,10 @@
     if (classDecl->isForeign())
       return None;
 
-    if (classDecl->checkObjCAncestry() != ObjCClassKind::NonObjC)
-      return ObjCReason::DoNotDiagnose;
+    if (classDecl->checkObjCAncestry() != ObjCClassKind::NonObjC) {
+      return VD->isImplicit() ? ObjCReason::ImplicitlyObjC
+                              : ObjCReason::MemberOfObjCSubclass;
+    }
   }
 
   return None;
@@ -2621,7 +2733,7 @@
   // could be overridden by @nonobjc. If we see a @nonobjc and we are trying
   // to add an @objc for whatever reason, diagnose an error.
   if (auto *attr = D->getAttrs().getAttribute<NonObjCAttr>()) {
-    if (*isObjC == ObjCReason::DoNotDiagnose)
+    if (!shouldDiagnoseObjCReason(*isObjC))
       isObjC = ObjCReason::ImplicitlyObjC;
 
     TC.diagnose(D->getStartLoc(), diag::nonobjc_not_allowed,
@@ -2722,6 +2834,29 @@
       sourceFile->ObjCMethods[method->getObjCSelector()].push_back(method);
     }
   }
+
+  // Special handling for Swift 3 @objc inference rules that are no longer
+  // present in later versions of Swift.
+  if (*isObjC == ObjCReason::MemberOfObjCSubclass) {
+    // If we've been asked to unconditionally warn about these deprecated
+    // @objc inference rules, do so now. However, we don't warn about
+    // accessors---just the main storage dclarations.
+    if (TC.Context.LangOpts.WarnSwift3ObjCInference &&
+        !(isa<FuncDecl>(D) && cast<FuncDecl>(D)->isGetterOrSetter())) {
+      TC.diagnose(D, diag::objc_inference_swift3_objc_derived);
+      TC.diagnose(D, diag::objc_inference_swift3_addobjc)
+        .fixItInsert(D->getAttributeInsertionLoc(/*forModifier=*/false),
+                     "@objc ");
+      TC.diagnose(D, diag::objc_inference_swift3_addnonobjc)
+        .fixItInsert(D->getAttributeInsertionLoc(/*forModifier=*/false),
+                     "@nonobjc ");
+    }
+
+    // Mark the attribute as having used Swift 3 inference, or create an
+    // implicit @objc for that purpose.
+    auto attr = D->getAttrs().getAttribute<ObjCAttr>();
+    attr->setSwift3Inferred();
+  }
 }
 
 namespace {
@@ -3047,10 +3182,7 @@
     auto inherited = TC.conformsToProtocol(behaviorSelf, refinedProto, dc,
                                            ConformanceCheckFlags::Used,
                                            blameLoc);
-    if (inherited && inherited->isConcrete()) {
-      conformance->setInheritedConformance(refinedProto,
-                                           inherited->getConcrete());
-    } else {
+    if (!inherited || !inherited->isConcrete()) {
       // Add some notes that the conformance is behavior-driven.
       TC.diagnose(behavior->getLoc(),
                   diag::self_conformance_required_by_property_behavior,
@@ -3117,7 +3249,7 @@
       // FIXME: Maybe we should synthesize an implicit TypeAliasDecl? We
       // really don't want the behavior conformances to show up in the
       // enclosing namespace though.
-      conformance->setTypeWitness(assocTy, valueSub, /*typeDecl*/ nullptr);
+      conformance->setTypeWitness(assocTy, propTy, /*typeDecl*/ nullptr);
     }
   next_requirement:;
   }
@@ -4420,33 +4552,7 @@
 
     if (!IsSecondPass) {
       checkUnsupportedNestedType(PD);
-
-      ProtocolRequirementTypeResolver resolver(PD);
-      TypeResolutionOptions options;
-
-      if (auto whereClause = PD->getTrailingWhereClause()) {
-        DeclContext *lookupDC = PD;
-        for (auto &req : whereClause->getRequirements()) {
-          // FIXME: handle error?
-          (void)TC.validateRequirement(whereClause->getWhereLoc(), req,
-                                       lookupDC, options, &resolver);
-        }
-      }
-
-      for (auto member : PD->getMembers()) {
-        if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
-          if (auto whereClause = assocType->getTrailingWhereClause()) {
-            DeclContext *lookupDC = assocType->getDeclContext();
-
-            for (auto &req : whereClause->getRequirements()) {
-              if (!TC.validateRequirement(whereClause->getWhereLoc(), req,
-                                          lookupDC, options, &resolver))
-                // FIXME handle error?
-                continue;
-            }
-          }
-        }
-      }
+      TC.validateWhereClauses(PD);
     }
 
     if (IsSecondPass) {
@@ -4978,10 +5084,8 @@
       ProtocolDecl *protocolContext = dyn_cast<ProtocolDecl>(
           FD->getDeclContext());
       if (protocolContext && FD->isAccessor()) {
-        // Don't complain about accessors in protocols.  We will emit a
-        // diagnostic about the property itself.
         if (isObjC)
-          isObjC = ObjCReason::DoNotDiagnose;
+          isObjC = ObjCReason::Accessor;
       }
 
       if (FD->isGetterOrSetter()) {
@@ -4997,8 +5101,26 @@
 
         if (storage->getAttrs().hasAttribute<NonObjCAttr>())
           isObjC = None;
-        else if (!isObjC && storage->isObjC())
-          isObjC = ObjCReason::DoNotDiagnose;
+        else if (storage->isObjC()) {
+          if (!isObjC) {
+            // Make this accessor @objc because its property is @objc.
+            isObjC = ObjCReason::Accessor;
+          } else {
+            // If @objc on the storage declaration was inferred using a
+            // deprecated rule, but this accessor is @objc in its own right,
+            // complain.
+            auto storageObjCAttr = storage->getAttrs().getAttribute<ObjCAttr>();
+            if (storageObjCAttr->isSwift3Inferred() &&
+                shouldDiagnoseObjCReason(*isObjC)) {
+              TC.diagnose(storage, diag::accessor_swift3_objc_inference,
+                          storage->getDescriptiveKind(), storage->getFullName(),
+                          isa<SubscriptDecl>(storage), FD->isSetter())
+                .fixItInsert(storage->getAttributeInsertionLoc(
+                                                      /*forModifier=*/false),
+                             "@objc ");
+            }
+          }
+        }
 
         // If the storage is dynamic, propagate to this accessor.
         if (isObjC && storage->isDynamic() && !FD->isDynamic())
@@ -5933,7 +6055,6 @@
     UNINTERESTING_ATTR(NSApplicationMain)
     UNINTERESTING_ATTR(NSCopying)
     UNINTERESTING_ATTR(NSManaged)
-    UNINTERESTING_ATTR(ObjC)
     UNINTERESTING_ATTR(ObjCBridged)
     UNINTERESTING_ATTR(Optional)
     UNINTERESTING_ATTR(Override)
@@ -5968,6 +6089,8 @@
     UNINTERESTING_ATTR(WarnUnqualifiedAccess)
     UNINTERESTING_ATTR(DiscardableResult)
 
+    UNINTERESTING_ATTR(ObjCMembers)
+
 #undef UNINTERESTING_ATTR
 
     void visitAvailableAttr(AvailableAttr *attr) {
@@ -6021,6 +6144,41 @@
         Override->getAttrs().add(
                                 new (TC.Context) DynamicAttr(/*implicit*/true));
     }
+
+    void visitObjCAttr(ObjCAttr *attr) {
+      // Checking for overrides of declarations that are implicitly @objc
+      // and occur in class extensions, because overriding will no longer be
+      // possible under the Swift 4 rules.
+
+      // We only care about the storage declaration.
+      if (auto func = dyn_cast<FuncDecl>(Override)) {
+        if (func->isAccessor()) return;
+      }
+
+      // If @objc was explicit or handles elsewhere, nothing to do.
+      if (!attr->isSwift3Inferred()) return;
+
+      // When warning about all deprecated @objc inference rules,
+      // we only need to do this check if we have implicit 'dynamic'.
+      if (TC.Context.LangOpts.WarnSwift3ObjCInference) {
+        if (auto dynamicAttr = Base->getAttrs().getAttribute<DynamicAttr>())
+          if (!dynamicAttr->isImplicit()) return;
+      }
+
+      // The overridden declaration needs to be in an extension.
+      if (!isa<ExtensionDecl>(Base->getDeclContext())) return;
+
+      // Complain.
+      TC.diagnose(Override, diag::override_swift3_objc_inference,
+                  Override->getDescriptiveKind(),
+                  Override->getFullName(),
+                  Base->getDeclContext()
+                    ->getAsNominalTypeOrNominalTypeExtensionContext()
+                    ->getName());
+      TC.diagnose(Base, diag::make_decl_objc, Base->getDescriptiveKind())
+        .fixItInsert(Base->getAttributeInsertionLoc(false),
+                     "@objc ");
+    }
   };
 
   /// Determine whether overriding the given declaration requires a keyword.
@@ -7109,8 +7267,8 @@
 
     validateAttributes(*this, D);
 
-    // Mark a class as @objc. This must happen before checking its members.
     if (auto CD = dyn_cast<ClassDecl>(nominal)) {
+      // Mark a class as @objc. This must happen before checking its members.
       Optional<ObjCReason> isObjC = shouldMarkClassAsObjC(*this, CD);
       markAsObjC(*this, CD, isObjC);
 
@@ -7120,6 +7278,14 @@
            CD->getSuperclass()->getClassOrBoundGenericClass()
              ->requiresStoredPropertyInits()))
         CD->setRequiresStoredPropertyInits(true);
+
+      // Inherit @objcMembers.
+      if (auto superclass = CD->getSuperclassDecl()) {
+        if (superclass->getAttrs().hasAttribute<ObjCMembersAttr>() &&
+            !CD->getAttrs().hasAttribute<ObjCMembersAttr>()) {
+          CD->getAttrs().add(new (Context) ObjCMembersAttr(/*implicit=*/true));
+        }
+      }
     }
 
     if (auto *ED = dyn_cast<EnumDecl>(nominal)) {
@@ -8254,6 +8420,9 @@
     if (isa<ClassDecl>(D) ||
         isa<ProtocolDecl>(D)) {
       /* ok */
+    } else if (auto Ext = dyn_cast<ExtensionDecl>(D)) {
+      if (!Ext->getAsClassOrClassExtensionContext())
+        error = diag::objc_extension_not_class;
     } else if (auto ED = dyn_cast<EnumDecl>(D)) {
       if (ED->isGenericContext())
         error = diag::objc_enum_generic;
@@ -8351,7 +8520,8 @@
   }
 
   if (auto nonObjcAttr = Attrs.getAttribute<NonObjCAttr>()) {
-    // Only methods, properties, subscripts and constructors can be NonObjC.
+    // Only extensions of classes; methods, properties, subscripts
+    // and constructors can be NonObjC.
     // The last three are handled automatically by generic attribute
     // validation -- for the first one, we have to check FuncDecls
     // ourselves.
@@ -8365,6 +8535,11 @@
       error = diag::invalid_nonobjc_decl;
     }
 
+    if (auto ext = dyn_cast<ExtensionDecl>(D)) {
+      if (!ext->getAsClassOrClassExtensionContext())
+        error = diag::invalid_nonobjc_extension;
+    }
+
     if (error) {
       TC.diagnose(D->getStartLoc(), *error)
         .fixItRemove(nonObjcAttr->getRangeWithAt());
diff --git a/lib/Sema/TypeCheckExprObjC.cpp b/lib/Sema/TypeCheckExprObjC.cpp
index c57b325..c4f05bd 100644
--- a/lib/Sema/TypeCheckExprObjC.cpp
+++ b/lib/Sema/TypeCheckExprObjC.cpp
@@ -302,6 +302,20 @@
             .fixItInsert(var->getAttributeInsertionLoc(false),
                          "@objc ");
         }
+      } else if (auto attr = var->getAttrs().getAttribute<ObjCAttr>()) {
+        // If this attribute was inferred based on deprecated Swift 3 rules,
+        // complain.
+        if (attr->isSwift3Inferred() &&
+            !Context.LangOpts.WarnSwift3ObjCInference) {
+          diagnose(componentNameLoc, diag::expr_keypath_swift3_objc_inference,
+                   var->getFullName(),
+                   var->getDeclContext()
+                    ->getAsNominalTypeOrNominalTypeExtensionContext()
+                   ->getName());
+          diagnose(var, diag::make_decl_objc, var->getDescriptiveKind())
+            .fixItInsert(var->getAttributeInsertionLoc(false),
+                         "@objc ");
+        }
       } else {
         // FIXME: Warn about non-KVC-compliant getter/setter names?
       }
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index d57325c..2f8dd9f 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -158,7 +158,20 @@
 }
 
 bool ProtocolRequirementTypeResolver::areSameType(Type type1, Type type2) {
-  return type1->isEqual(type2);
+  if (type1->isEqual(type2))
+    return true;
+
+  // If both refer to associated types with the same name, they'll implicitly
+  // be considered equivalent.
+  auto depMem1 = type1->getAs<DependentMemberType>();
+  if (!depMem1) return false;
+
+  auto depMem2 = type2->getAs<DependentMemberType>();
+  if (!depMem2) return false;
+
+  if (depMem1->getName() != depMem2->getName()) return false;
+
+  return areSameType(depMem1->getBase(), depMem2->getBase());
 }
 
 void ProtocolRequirementTypeResolver::recordParamType(ParamDecl *decl,
@@ -354,51 +367,37 @@
     // Validate the types.
     if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) {
       req.setInvalid();
-      return true;
     }
 
     if (validateType(req.getConstraintLoc(), lookupDC, options, resolver)) {
       req.setInvalid();
-      return true;
     }
 
-    // FIXME: Feels too early to perform this check.
-    if (!req.getConstraint()->isExistentialType() &&
-        !req.getConstraint()->getClassOrBoundGenericClass()) {
-      diagnose(whereLoc, diag::requires_conformance_nonprotocol,
-               req.getSubjectLoc(), req.getConstraintLoc());
-      req.getConstraintLoc().setInvalidType(Context);
-      req.setInvalid();
-      return true;
-    }
-    return false;
+    return req.isInvalid();
   }
 
   case RequirementReprKind::LayoutConstraint: {
     // Validate the types.
     if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) {
       req.setInvalid();
-      return true;
     }
 
     if (req.getLayoutConstraintLoc().isNull()) {
       req.setInvalid();
-      return true;
     }
-    return false;
+    return req.isInvalid();
   }
 
   case RequirementReprKind::SameType: {
     if (validateType(req.getFirstTypeLoc(), lookupDC, options, resolver)) {
       req.setInvalid();
-      return true;
     }
 
     if (validateType(req.getSecondTypeLoc(), lookupDC, options, resolver)) {
       req.setInvalid();
-      return true;
     }
-    return false;
+
+    return req.isInvalid();
   }
   }
 
@@ -616,33 +615,129 @@
 
   auto *decl = cast<ValueDecl>(dc->getInnermostDeclarationDeclContext());
 
-  // Collect all generic params referenced in parameter types,
-  // return type or requirements.
-  SmallPtrSet<GenericTypeParamDecl *, 4> referencedGenericParams;
+  // A helper class to collect referenced generic type parameters
+  // and dependent memebr types.
+  class ReferencedGenericTypeWalker : public TypeWalker {
+    SmallPtrSet<CanType, 4> ReferencedGenericParams;
 
-  auto visitorFn = [&referencedGenericParams](Type t) {
-    if (auto *paramTy = t->getAs<GenericTypeParamType>())
-      referencedGenericParams.insert(paramTy->getDecl());
+  public:
+    ReferencedGenericTypeWalker() {}
+    Action walkToTypePre(Type ty) override {
+      // Find generic parameters or dependent member types.
+      // Once such a type is found, don't recurse into its children.
+      if (!ty->hasTypeParameter())
+        return Action::SkipChildren;
+      if (ty->isTypeParameter()) {
+        ReferencedGenericParams.insert(ty->getCanonicalType());
+        return Action::SkipChildren;
+      }
+      return Action::Continue;
+    }
+
+    SmallPtrSet<CanType, 4> &getReferencedGenericParams() {
+      return ReferencedGenericParams;
+    }
   };
 
+  // Collect all generic params referenced in parameter types and
+  // return type.
+  ReferencedGenericTypeWalker paramsAndResultWalker;
   auto *funcTy = decl->getInterfaceType()->castTo<GenericFunctionType>();
-  funcTy->getInput().visit(visitorFn);
-  funcTy->getResult().visit(visitorFn);
+  funcTy->getInput().walk(paramsAndResultWalker);
+  funcTy->getResult().walk(paramsAndResultWalker);
 
-  auto requirements = sig->getRequirements();
-  for (auto req : requirements) {
+  // Set of generic params referenced in parameter types,
+  // return type or requirements.
+  auto &referencedGenericParams =
+      paramsAndResultWalker.getReferencedGenericParams();
+
+  // Check if at least one of the generic params in the requirment refers
+  // to an already referenced generic parameter. If this is the case,
+  // then the other type is also considered as referenced, because
+  // it is used to put requirements on the first type.
+  auto reqTypesVisitor = [&referencedGenericParams](Requirement req) -> bool {
+    Type first;
+    Type second;
+
     switch (req.getKind()) {
-      case RequirementKind::SameType:
-      case RequirementKind::Superclass:
-        req.getSecondType().visit(visitorFn);
-        LLVM_FALLTHROUGH;
+    case RequirementKind::Superclass:
+    case RequirementKind::SameType:
+      second = req.getSecondType();
+      LLVM_FALLTHROUGH;
 
-      case RequirementKind::Conformance:
-      case RequirementKind::Layout:
-        req.getFirstType().visit(visitorFn);
+    case RequirementKind::Conformance:
+    case RequirementKind::Layout:
+      first = req.getFirstType();
+      break;
+    }
+
+    // Collect generic parameter types refereced by types used in a requirement.
+    ReferencedGenericTypeWalker walker;
+    if (first && first->hasTypeParameter())
+      first.walk(walker);
+    if (second && second->hasTypeParameter())
+      second.walk(walker);
+    auto &genericParamsUsedByRequirementTypes =
+        walker.getReferencedGenericParams();
+
+    // If at least one of the collected generic types or a root generic
+    // parameter of dependent member types is known to be referenced by
+    // parameter types, return types or other types known to be "referenced",
+    // then all the types used in the requirement are considered to be
+    // referenced, because they are used to defined something that is known
+    // to be referenced.
+    bool foundNewReferencedGenericParam = false;
+    if (std::any_of(genericParamsUsedByRequirementTypes.begin(),
+                    genericParamsUsedByRequirementTypes.end(),
+                    [&referencedGenericParams](CanType t) {
+                      assert(t->isTypeParameter());
+                      return referencedGenericParams.find(
+                                 t->getRootGenericParam()
+                                     ->getCanonicalType()) !=
+                             referencedGenericParams.end();
+                    })) {
+      std::for_each(genericParamsUsedByRequirementTypes.begin(),
+                    genericParamsUsedByRequirementTypes.end(),
+                    [&referencedGenericParams,
+                     &foundNewReferencedGenericParam](CanType t) {
+                      // Add only generic type parameters, but ignore any
+                      // dependent member types, because requirement
+                      // on a dependent member type does not provide enough
+                      // information to infer the base generic type
+                      // parameter.
+                      if (!t->is<GenericTypeParamType>())
+                        return;
+                      if (referencedGenericParams.insert(t).second)
+                        foundNewReferencedGenericParam = true;
+                    });
+    }
+    return foundNewReferencedGenericParam;
+  };
+
+  ArrayRef<Requirement> requirements;
+
+  auto FindReferencedGenericParamsInRequirements = [&requirements, sig, &reqTypesVisitor] {
+    requirements = sig->getRequirements();
+    // Try to find new referenced generic parameter types in requirements until
+    // we reach a fix point. We need to iterate until a fix point, because we
+    // may have e.g. chains of same-type requirements like:
+    // not-yet-referenced-T1 == not-yet-referenced-T2.DepType2,
+    // not-yet-referenced-T2 == not-yet-referenced-T3.DepType3,
+    // not-yet-referenced-T3 == referenced-T4.DepType4.
+    // When we process the first of these requirements, we don't know yet that
+    // T2
+    // will be referenced, because T3 will be referenced,
+    // because T3 == T4.DepType4.
+    while (true) {
+      bool foundNewReferencedGenericParam = false;
+      for (auto req : requirements) {
+        if (reqTypesVisitor(req))
+          foundNewReferencedGenericParam = true;
+      }
+      if (!foundNewReferencedGenericParam)
         break;
     }
-  }
+  };
 
   // Find the depth of the function's own generic parameters.
   unsigned fnGenericParamsDepth = genericParams->getDepth();
@@ -653,7 +748,18 @@
     auto *paramDecl = genParam->getDecl();
     if (paramDecl->getDepth() != fnGenericParamsDepth)
       continue;
-    if (!referencedGenericParams.count(paramDecl)) {
+    if (!referencedGenericParams.count(genParam->getCanonicalType())) {
+      // Lazily search for generic params that are indirectly used in the
+      // function signature. Do it only if there is a generic parameter
+      // that is not known to be referenced yet.
+      if (requirements.empty()) {
+        FindReferencedGenericParamsInRequirements();
+        // Nothing to do if this generic parameter is considered to be
+        // referenced after analyzing the requirements from the generic
+        // signature.
+        if (referencedGenericParams.count(genParam->getCanonicalType()))
+          continue;
+      }
       // Produce an error that this generic parameter cannot be bound.
       TC.diagnose(paramDecl->getLoc(), diag::unreferenced_generic_parameter,
                   paramDecl->getNameStr());
@@ -1143,11 +1249,7 @@
     Type rawSecondType, secondType;
     if (kind != RequirementKind::Layout) {
       rawSecondType = rawReq.getSecondType();
-      secondType = req->getSecondType().subst(substitutions, conformances);
-      if (!secondType) {
-        valid = false;
-        continue;
-      }
+      secondType = req->getSecondType();
     }
 
     if (listener && !listener->shouldCheck(kind, firstType, secondType))
diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp
index e641a87..63e54c7 100644
--- a/lib/Sema/TypeCheckNameLookup.cpp
+++ b/lib/Sema/TypeCheckNameLookup.cpp
@@ -152,7 +152,7 @@
         ValueDecl *witness = nullptr;
         auto concrete = conformance->getConcrete();
         if (auto assocType = dyn_cast<AssociatedTypeDecl>(found)) {
-          witness = concrete->getTypeWitnessSubstAndDecl(assocType, &TC)
+          witness = concrete->getTypeWitnessAndDecl(assocType, &TC)
             .second;
         } else if (found->isProtocolRequirement()) {
           witness = concrete->getWitness(found, &TC).getDecl();
@@ -414,8 +414,7 @@
 
       // Use the type witness.
       auto concrete = conformance->getConcrete();
-      Type memberType =
-        concrete->getTypeWitness(assocType, this).getReplacement();
+      Type memberType = concrete->getTypeWitness(assocType, this);
       assert(memberType && "Missing type witness?");
 
       // If we haven't seen this type result yet, add it to the result set.
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 2cad7cc..dd67c2d 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -1728,6 +1728,9 @@
     /// Whether we've already complained about problems with this conformance.
     bool AlreadyComplained = false;
 
+    /// Whether we checked the requirement signature already.
+    bool CheckedRequirementSignature = false;
+
     /// Retrieve the associated types that are referenced by the given
     /// requirement with a base of 'Self'.
     ArrayRef<AssociatedTypeDecl *> getReferencedAssociatedTypes(ValueDecl *req);
@@ -2039,11 +2042,7 @@
       TC.conformsToProtocol(T, InheritedProto, DC,
                             ConformanceCheckFlags::Used,
                             ComplainLoc);
-      if (InheritedConformance && InheritedConformance->isConcrete()) {
-        if (!conformance->hasInheritedConformance(InheritedProto))
-          conformance->setInheritedConformance(InheritedProto,
-                                           InheritedConformance->getConcrete());
-      } else {
+      if (!InheritedConformance || !InheritedConformance->isConcrete()) {
         // Recursive call already diagnosed this problem, but tack on a note
         // to establish the relationship.
         if (ComplainLoc.isValid()) {
@@ -2131,8 +2130,7 @@
       if (member->getBase()->isEqual(selfTy)) {
         // FIXME: Could handle inherited conformances here.
         if (conformance->hasTypeWitness(member->getAssocType()))
-          return conformance->getTypeWitness(member->getAssocType(), nullptr)
-                   .getReplacement();
+          return conformance->getTypeWitness(member->getAssocType(), nullptr);
       }
     }
 
@@ -2273,9 +2271,8 @@
   for (auto member : conformance->getProtocol()->getMembers()) {
     if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
       if (conformance->usesDefaultDefinition(assocType)) {
-        auto &witness = conformance->getTypeWitness(assocType, nullptr);
-        addAssocTypeDeductionString(withAssocTypes, assocType,
-                                    witness.getReplacement());
+        Type witness = conformance->getTypeWitness(assocType, nullptr);
+        addAssocTypeDeductionString(withAssocTypes, assocType, witness);
       }
     }
   }
@@ -2375,35 +2372,7 @@
   }
 }
 
-/// Compute the substitution for the given archetype and its replacement
-/// type.
-static Substitution getArchetypeSubstitution(TypeChecker &tc,
-                                             DeclContext *dc,
-                                             ArrayRef<ProtocolDecl *> protocols,
-                                             Type replacement) {
-  assert(!replacement->isTypeParameter() && "Can't be dependent");
-  SmallVector<ProtocolConformanceRef, 4> conformances;
-
-  bool isError = replacement->hasError();
-
-  for (auto proto : protocols) {
-    auto conformance = tc.conformsToProtocol(replacement, proto, dc, None);
-    assert((conformance || isError) &&
-           "Conformance should already have been verified");
-    (void)isError;
-    if (conformance)
-      conformances.push_back(*conformance);
-    else
-      conformances.push_back(ProtocolConformanceRef(proto));
-  }
-
-  return Substitution{
-    replacement,
-    tc.Context.AllocateCopy(conformances),
-  };
-}
-
-ArrayRef<AssociatedTypeDecl *> 
+ArrayRef<AssociatedTypeDecl *>
 ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) {
   // Check whether we've already cached this information.
   auto known = ReferencedAssociatedTypes.find(req);
@@ -2479,7 +2448,7 @@
 
   // If we already recoded this type witness, there's nothing to do.
   if (Conformance->hasTypeWitness(assocType)) {
-    assert(Conformance->getTypeWitness(assocType, nullptr).getReplacement()
+    assert(Conformance->getTypeWitness(assocType, nullptr)
              ->isEqual(type) && "Conflicting type witness deductions");
     return;
   }
@@ -2580,11 +2549,7 @@
   }
 
   // Record the type witness.
-  auto protocols = assocType->getConformingProtocols();
-  Conformance->setTypeWitness(
-      assocType,
-      getArchetypeSubstitution(TC, DC, protocols, type),
-      typeDecl);
+  Conformance->setTypeWitness(assocType, type, typeDecl);
 }
 
 bool swift::
@@ -2779,8 +2744,7 @@
   // If any of the type witnesses was erroneous, don't bother to check
   // this value witness: it will fail.
   for (auto assocType : getReferencedAssociatedTypes(requirement)) {
-    if (Conformance->getTypeWitness(assocType, nullptr).getReplacement()
-          ->hasError()) {
+    if (Conformance->getTypeWitness(assocType, nullptr)->hasError()) {
       return ResolveWitnessResult::ExplicitFailed;
     }
   }
@@ -3480,8 +3444,8 @@
       // witness completely.
       if (!allUnresolved.count(result.first)) {
         auto existingWitness =
-        Conformance->getTypeWitness(result.first, nullptr)
-        .getReplacement();
+          Conformance->getTypeWitness(result.first, nullptr);
+
         // If the deduced type contains an irreducible
         // DependentMemberType, that indicates a dependency
         // on another associated type we haven't deduced,
@@ -3905,7 +3869,7 @@
     switch (reqt.getKind()) {
     case RequirementKind::Conformance: {
       SmallVector<ProtocolDecl*, 4> protos;
-      reqt.getSecondType()->getAnyExistentialTypeProtocols(protos);
+      reqt.getSecondType()->getExistentialTypeProtocols(protos);
       
       for (auto proto : protos) {
         insertProtocol(proto);
@@ -3942,7 +3906,7 @@
     switch (reqt.getKind()) {
     case RequirementKind::Conformance: {
       SmallVector<ProtocolDecl*, 4> protos;
-      reqt.getSecondType()->getAnyExistentialTypeProtocols(protos);
+      reqt.getSecondType()->getExistentialTypeProtocols(protos);
       
       for (auto proto : protos) {
         removeProtocol(proto);
@@ -3990,6 +3954,12 @@
 void ConformanceChecker::resolveTypeWitnesses() {
   llvm::SetVector<AssociatedTypeDecl *> unresolvedAssocTypes;
 
+  SWIFT_DEFER {
+    // Resolution attempts to have the witnesses be correct by construction, but
+    // this isn't guaranteed, so let's double check.
+    ensureRequirementsAreSatisfied();
+  };
+
   // Track when we are checking type witnesses.
   ProtocolConformanceState initialState = Conformance->getState();
   Conformance->setState(ProtocolConformanceState::CheckingTypeWitnesses);
@@ -4075,8 +4045,8 @@
         if (!archetype)
           continue;
         if (Conformance->hasTypeWitness(assocType)) {
-          substitutions[archetype]
-            = Conformance->getTypeWitness(assocType, nullptr).getReplacement();
+          substitutions[archetype] =
+            Conformance->getTypeWitness(assocType, nullptr);
         } else {
           auto known = typeWitnesses.begin(assocType);
           if (known != typeWitnesses.end())
@@ -4399,7 +4369,6 @@
   };
   findSolutions(0);
 
-
   // Go make sure that type declarations that would act as witnesses
   // did not get injected while we were performing checks above. This
   // can happen when two associated types in different protocols have
@@ -4745,8 +4714,7 @@
   // If any of the type witnesses was erroneous, don't bother to check
   // this value witness: it will fail.
   for (auto assocType : getReferencedAssociatedTypes(requirement)) {
-    if (Conformance->getTypeWitness(assocType, nullptr).getReplacement()
-          ->hasError()) {
+    if (Conformance->getTypeWitness(assocType, nullptr)->hasError()) {
       Conformance->setInvalid();
       return;
     }
@@ -4841,16 +4809,11 @@
   if (normalConf->isIncomplete())
     TC.UsedConformances.insert(normalConf);
 
-  // Mark each type witness conformance as used.
-  conformance->forEachTypeWitness(nullptr, [&](AssociatedTypeDecl *assocType,
-                                               Substitution sub,
-                                               TypeDecl *witness) -> bool {
-    for (auto nestedConformance : sub.getConformances())
-      if (nestedConformance.isConcrete())
-        addUsedConformances(nestedConformance.getConcrete(), visited);
-
-    return false;
-  });
+  // Mark each conformance in the signature as used.
+  for (auto sigConformance : normalConf->getSignatureConformances()) {
+    if (sigConformance.isConcrete())
+      addUsedConformances(sigConformance.getConcrete(), visited);
+  }
 }
 
 void ConformanceChecker::addUsedConformances(ProtocolConformance *conformance) {
@@ -4866,6 +4829,11 @@
     return;
   }
 
+  if (CheckedRequirementSignature)
+    return;
+
+  CheckedRequirementSignature = true;
+
   auto reqSig = proto->getRequirementSignature();
 
   auto substitutions = SubstitutionMap::getProtocolSubstitutions(
@@ -4886,7 +4854,9 @@
       // FIXME: maybe this should be the conformance's type
       proto->getDeclaredInterfaceType(), reqSig,
       QuerySubstitutionMap{substitutions},
-      LookUpConformanceInSubstitutionMap{substitutions}, nullptr,
+      LookUpConformanceInModule(
+        Conformance->getDeclContext()->getParentModule()),
+      nullptr,
       ConformanceCheckFlags::Used, &listener);
 
   // If there were no errors, record the conformances.
@@ -4922,10 +4892,6 @@
   // Diagnose missing type witnesses for now.
   diagnoseMissingWitnesses(Kind);
 
-  // Resolution attempts to have the witnesses be correct by construction, but
-  // this isn't guaranteed, so let's double check.
-  ensureRequirementsAreSatisfied();
-
   // Ensure the conforming type is used.
   //
   // FIXME: This feels like the wrong place for this, but if we don't put
@@ -5235,7 +5201,7 @@
   // contain the protocol.
   if (T->isExistentialType()) {
     SmallVector<ProtocolDecl *, 4> protocols;
-    T->getAnyExistentialTypeProtocols(protocols);
+    T->getExistentialTypeProtocols(protocols);
 
     for (auto P : protocols) {
       // Special case -- any class-bound protocol can be passed as an
@@ -5306,14 +5272,9 @@
     }
   }
 
-  // When debugging, compute the conformance access path for each requirement.
-  // This acts as an assertion that the path itself makes sense.
-#ifndef NDEBUG
-  bool computeConformanceAccessPath = true;
-#else
-  bool computeConformanceAccessPath = Context.LangOpts.DebugGenericSignatures;
-#endif
-  if (computeConformanceAccessPath &&
+  // When requested, print the conformance access path used to find this
+  // conformance.
+  if (Context.LangOpts.DebugGenericSignatures &&
       InExpression && T->is<ArchetypeType>() && lookupResult->isAbstract() &&
       !T->castTo<ArchetypeType>()->isOpenedExistential() &&
       !T->castTo<ArchetypeType>()->requiresClass() &&
@@ -5327,13 +5288,11 @@
 
       // Debugging aid: display the conformance access path for archetype
       // conformances.
-      if (Context.LangOpts.DebugGenericSignatures) {
-        llvm::errs() << "Conformance access path for ";
-        T.print(llvm::errs());
-        llvm::errs() << ": " << Proto->getName() << " is ";
-        path.print(llvm::errs());
-        llvm::errs() << "\n";
-      }
+      llvm::errs() << "Conformance access path for ";
+      T.print(llvm::errs());
+      llvm::errs() << ": " << Proto->getName() << " is ";
+      path.print(llvm::errs());
+      llvm::errs() << "\n";
     }
   }
 
@@ -5353,8 +5312,9 @@
         return ConformsToProtocolResult::unsatisfiedDependency();
     }
 
-    SmallVector<ProtocolDecl *, 2> protos;
-    if (T->isExistentialType(protos)) {
+    if (T->isExistentialType()) {
+      SmallVector<ProtocolDecl *, 2> protos;
+      T->getExistentialTypeProtocols(protos);
       bool anyUnsatisfied = false;
       for (auto *proto : protos) {
         if ((*unsatisfiedDependency)(requestInheritedProtocols(proto)))
@@ -6182,7 +6142,10 @@
                        *this, 
                        const_cast<NormalProtocolConformance*>(conformance),
                        MissingWitnesses);
-  checker.resolveSingleTypeWitness(assocType);
+  if (!assocType)
+    checker.resolveTypeWitnesses();
+  else
+    checker.resolveSingleTypeWitness(assocType);
 }
 
 void TypeChecker::resolveWitness(const NormalProtocolConformance *conformance,
@@ -6195,19 +6158,6 @@
   checker.resolveSingleWitness(requirement);
 }
 
-ProtocolConformance *TypeChecker::resolveInheritedConformance(
-       const NormalProtocolConformance *conformance,
-       ProtocolDecl *inherited) {
-  auto inheritedConformance =
-    conformsToProtocol(conformance->getType(), inherited,
-                       conformance->getDeclContext(),
-                       ConformanceCheckFlags::InExpression);
-  if (inheritedConformance && inheritedConformance->isConcrete())
-    return inheritedConformance->getConcrete();
-
-  return nullptr;
-}
-
 ValueDecl *TypeChecker::deriveProtocolRequirement(DeclContext *DC,
                                                   NominalTypeDecl *TypeDecl,
                                                   ValueDecl *Requirement) {
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index 66be449..a672b89 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -3046,7 +3046,7 @@
 static void diagnoseFunctionParamNotRepresentable(
     TypeChecker &TC, const AbstractFunctionDecl *AFD, unsigned NumParams,
     unsigned ParamIndex, const ParamDecl *P, ObjCReason Reason) {
-  if (Reason == ObjCReason::DoNotDiagnose)
+  if (!shouldDiagnoseObjCReason(Reason))
     return;
 
   if (NumParams == 1) {
@@ -3072,7 +3072,7 @@
                                            ObjCReason Reason) {
   // If you change this function, you must add or modify a test in PrintAsObjC.
 
-  bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
+  bool Diagnose = shouldDiagnoseObjCReason(Reason);
 
   bool IsObjC = true;
   unsigned NumParams = PL->size();
@@ -3081,7 +3081,7 @@
     
     // Swift Varargs are not representable in Objective-C.
     if (param->isVariadic()) {
-      if (Diagnose && Reason != ObjCReason::DoNotDiagnose) {
+      if (Diagnose && shouldDiagnoseObjCReason(Reason)) {
         TC.diagnose(param->getStartLoc(), diag::objc_invalid_on_func_variadic,
                     getObjCDiagnosticAttrKind(Reason))
           .highlight(param->getSourceRange());
@@ -3168,7 +3168,7 @@
 static bool checkObjCWithGenericParams(TypeChecker &TC,
                                        const AbstractFunctionDecl *AFD,
                                        ObjCReason Reason) {
-  bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
+  bool Diagnose = shouldDiagnoseObjCReason(Reason);
 
   if (AFD->getGenericParams()) {
     // Diagnose this problem, if asked to.
@@ -3189,7 +3189,7 @@
 static bool checkObjCInForeignClassContext(TypeChecker &TC,
                                            const ValueDecl *VD,
                                            ObjCReason Reason) {
-  bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
+  bool Diagnose = shouldDiagnoseObjCReason(Reason);
 
   auto type = VD->getDeclContext()->getDeclaredInterfaceType();
   if (!type)
@@ -3257,7 +3257,7 @@
 
   // If you change this function, you must add or modify a test in PrintAsObjC.
 
-  bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
+  bool Diagnose = shouldDiagnoseObjCReason(Reason);
 
   if (checkObjCInForeignClassContext(*this, AFD, Reason))
     return false;
@@ -3589,7 +3589,7 @@
   }
   bool Result = T->isRepresentableIn(ForeignLanguage::ObjectiveC,
                                      VD->getDeclContext());
-  bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
+  bool Diagnose = shouldDiagnoseObjCReason(Reason);
 
   if (Result && checkObjCInExtensionContext(*this, VD, Diagnose))
     return false;
@@ -3620,7 +3620,7 @@
                                         ObjCReason Reason) {
   // If you change this function, you must add or modify a test in PrintAsObjC.
 
-  bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
+  bool Diagnose = shouldDiagnoseObjCReason(Reason);
 
   if (checkObjCInForeignClassContext(*this, SD, Reason))
     return false;
@@ -3710,8 +3710,9 @@
   }
 
   // Special diagnostic for protocols and protocol compositions.
-  SmallVector<ProtocolDecl *, 4> Protocols;
-  if (T->isExistentialType(Protocols)) {
+  if (T->isExistentialType()) {
+    SmallVector<ProtocolDecl *, 4> Protocols;
+    T->getExistentialTypeProtocols(Protocols);
     if (Protocols.empty()) {
       // Any is not @objc.
       diagnose(TypeRange.Start, diag::not_objc_empty_protocol_composition);
@@ -3829,8 +3830,9 @@
       type.findIf([&](Type type) -> bool {
         if (T->isInvalid())
           return false;
-        SmallVector<ProtocolDecl*, 2> protocols;
-        if (type->isExistentialType(protocols)) {
+        if (type->isExistentialType()) {
+          SmallVector<ProtocolDecl*, 2> protocols;
+          type->getExistentialTypeProtocols(protocols);
           for (auto *proto : protocols) {
             if (proto->existentialTypeSupported(&TC))
               continue;
diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp
index 160969b..7163f6e 100644
--- a/lib/Sema/TypeChecker.cpp
+++ b/lib/Sema/TypeChecker.cpp
@@ -714,13 +714,14 @@
 
     typeCheckFunctionsAndExternalDecls(TC);
   }
-  MyTC.reset();
 
   // Checking that benefits from having the whole module available.
   if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking)) {
     performWholeModuleTypeChecking(SF);
   }
 
+  MyTC.reset();
+
   // Verify that we've checked types correctly.
   SF.ASTStage = SourceFile::TypeChecked;
 
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index ebf4007..3400160 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -515,24 +515,90 @@
 /// Should only affect diagnostics. If you change this enum, also change
 /// the OBJC_ATTR_SELECT macro in DiagnosticsSema.def.
 enum class ObjCReason {
-  DoNotDiagnose,
+  /// Has the '@cdecl' attribute.
   ExplicitlyCDecl,
+  /// Has the 'dynamic' modifier.
   ExplicitlyDynamic,
+  /// Has an explicit '@objc' attribute.
   ExplicitlyObjC,
+  /// Has an explicit '@IBOutlet' attribute.
   ExplicitlyIBOutlet,
+  /// Has an explicit '@IBAction' attribute.
   ExplicitlyIBAction,
+  /// Has an explicit '@NSManaged' attribute.
   ExplicitlyNSManaged,
+  /// Is a member of an @objc protocol.
   MemberOfObjCProtocol,
+  /// Implicitly-introduced @objc.
   ImplicitlyObjC,
+  /// Is an override of an @objc member.
   OverridesObjC,
+  /// Is a witness to an @objc protocol requirement.
   WitnessToObjC,
+  /// Has an explicit '@IBInspectable' attribute.
+  ExplicitlyIBInspectable,
+  /// Has an explicit '@GKInspectable' attribute.
+  ExplicitlyGKInspectable,
+  /// Is it a member of an @objc extension of a class.
+  MemberOfObjCExtension,
+  /// Is it a member of an @objcMembers class.
+  MemberOfObjCMembersClass,
+  /// A member of an Objective-C-defined class or subclass.
+  MemberOfObjCSubclass,
+  /// An accessor to a property.
+  Accessor,
 };
 
+/// Determine whether we should diagnose conflicts due to inferring @objc
+/// with this particular reason.
+static inline bool shouldDiagnoseObjCReason(ObjCReason reason) {
+  switch(reason) {
+  case ObjCReason::ExplicitlyCDecl:
+  case ObjCReason::ExplicitlyDynamic:
+  case ObjCReason::ExplicitlyObjC:
+  case ObjCReason::ExplicitlyIBOutlet:
+  case ObjCReason::ExplicitlyIBAction:
+  case ObjCReason::ExplicitlyNSManaged:
+  case ObjCReason::MemberOfObjCProtocol:
+  case ObjCReason::OverridesObjC:
+  case ObjCReason::WitnessToObjC:
+  case ObjCReason::ImplicitlyObjC:
+  case ObjCReason::ExplicitlyIBInspectable:
+  case ObjCReason::ExplicitlyGKInspectable:
+  case ObjCReason::MemberOfObjCExtension:
+    return true;
+
+  case ObjCReason::MemberOfObjCSubclass:
+  case ObjCReason::MemberOfObjCMembersClass:
+  case ObjCReason::Accessor:
+    return false;
+  }
+}
+
 /// Return the %select discriminator for the OBJC_ATTR_SELECT macro used to
 /// complain about the correct attribute during @objc inference.
-static inline unsigned getObjCDiagnosticAttrKind(ObjCReason Reason) {
-  assert(Reason != ObjCReason::DoNotDiagnose);
-  return static_cast<unsigned>(Reason) - 1;
+static inline unsigned getObjCDiagnosticAttrKind(ObjCReason reason) {
+  switch (reason) {
+  case ObjCReason::ExplicitlyCDecl:
+  case ObjCReason::ExplicitlyDynamic:
+  case ObjCReason::ExplicitlyObjC:
+  case ObjCReason::ExplicitlyIBOutlet:
+  case ObjCReason::ExplicitlyIBAction:
+  case ObjCReason::ExplicitlyNSManaged:
+  case ObjCReason::MemberOfObjCProtocol:
+  case ObjCReason::OverridesObjC:
+  case ObjCReason::WitnessToObjC:
+  case ObjCReason::ImplicitlyObjC:
+  case ObjCReason::ExplicitlyIBInspectable:
+  case ObjCReason::ExplicitlyGKInspectable:
+  case ObjCReason::MemberOfObjCExtension:
+    return static_cast<unsigned>(reason);
+
+  case ObjCReason::MemberOfObjCSubclass:
+  case ObjCReason::MemberOfObjCMembersClass:
+  case ObjCReason::Accessor:
+    llvm_unreachable("should not diagnose this @objc reason");
+  }
 }
 
 /// Flags that control protocol conformance checking.
@@ -1278,6 +1344,10 @@
   /// Resolve the inherited protocols of a given protocol.
   void resolveInheritedProtocols(ProtocolDecl *protocol) override;
 
+  /// Validate a protocol's where clause, along with the where clauses of
+  /// its associated types.
+  void validateWhereClauses(ProtocolDecl *protocol);
+
   /// Resolve the types in the inheritance clause of the given
   /// declaration context, which will be a nominal type declaration or
   /// extension declaration.
@@ -1971,9 +2041,6 @@
                           AssociatedTypeDecl *assocType) override;
   void resolveWitness(const NormalProtocolConformance *conformance,
                       ValueDecl *requirement) override;
-  ProtocolConformance *resolveInheritedConformance(
-                         const NormalProtocolConformance *conformance,
-                         ProtocolDecl *inherited) override;
 
   bool isCIntegerType(const DeclContext *DC, Type T);
   bool isRepresentableInObjC(const AbstractFunctionDecl *AFD,
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index f749c7a..e2d6164 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -696,7 +696,7 @@
 
   DeclID protoID;
   DeclContextID contextID;
-  unsigned valueCount, typeCount, inheritedCount;
+  unsigned valueCount, typeCount;
   ArrayRef<uint64_t> rawIDs;
   SmallVector<uint64_t, 16> scratch;
 
@@ -707,7 +707,7 @@
   }
   NormalProtocolConformanceLayout::readRecord(scratch, protoID,
                                               contextID, valueCount,
-                                              typeCount, inheritedCount,
+                                              typeCount,
                                               rawIDs);
 
   ASTContext &ctx = getContext();
@@ -741,24 +741,10 @@
   }
   conformance->setSignatureConformances(reqConformances);
 
-  // Read inherited conformances.
-  InheritedConformanceMap inheritedConformances;
-  while (inheritedCount--) {
-    auto inheritedRef = readConformance(DeclTypeCursor);
-    assert(inheritedRef.isConcrete());
-    auto inherited = inheritedRef.getConcrete();
-    inheritedConformances[inherited->getProtocol()] = inherited;
-  }
-
   // If the conformance is complete, we're done.
   if (conformance->isComplete())
     return conformance;
 
-  // Record the inherited conformance.
-  if (conformance->getInheritedConformances().empty())
-    for (auto inherited : inheritedConformances)
-      conformance->setInheritedConformance(inherited.first, inherited.second);
-
   conformance->setState(ProtocolConformanceState::Complete);
   conformance->setLazyLoader(this, offset);
   return conformance;
@@ -2377,10 +2363,12 @@
       case decls_block::ObjC_DECL_ATTR: {
         bool isImplicit;
         bool isImplicitName;
+        bool isSwift3Inferred;
         uint64_t numArgs;
         ArrayRef<uint64_t> rawPieceIDs;
         serialization::decls_block::ObjCDeclAttrLayout::readRecord(
-          scratch, isImplicit, isImplicitName, numArgs, rawPieceIDs);
+          scratch, isImplicit, isSwift3Inferred, isImplicitName, numArgs,
+          rawPieceIDs);
 
         SmallVector<Identifier, 4> pieces;
         for (auto pieceID : rawPieceIDs)
@@ -2392,6 +2380,7 @@
           Attr = ObjCAttr::create(ctx, ObjCSelector(ctx, numArgs-1, pieces),
                                   isImplicitName);
         Attr->setImplicit(isImplicit);
+        cast<ObjCAttr>(Attr)->setSwift3Inferred(isSwift3Inferred);
         break;
       }
 
@@ -4346,7 +4335,7 @@
 
   DeclID protoID;
   DeclContextID contextID;
-  unsigned valueCount, typeCount, inheritedCount;
+  unsigned valueCount, typeCount;
   ArrayRef<uint64_t> rawIDs;
   SmallVector<uint64_t, 16> scratch;
 
@@ -4356,7 +4345,7 @@
          "registered lazy loader incorrectly");
   NormalProtocolConformanceLayout::readRecord(scratch, protoID,
                                               contextID, valueCount,
-                                              typeCount, inheritedCount,
+                                              typeCount,
                                               rawIDs);
 
   // Skip requirement signature conformances.
@@ -4367,10 +4356,6 @@
     }
   }
 
-  // Skip trailing inherited conformances.
-  while (inheritedCount--)
-    (void)readConformance(DeclTypeCursor);
-
   ArrayRef<uint64_t>::iterator rawIDIter = rawIDs.begin();
 
   while (valueCount--) {
@@ -4445,10 +4430,9 @@
     // FIXME: We don't actually want to allocate an archetype here; we just
     // want to get an access path within the protocol.
     auto first = cast<AssociatedTypeDecl>(getDecl(*rawIDIter++));
-    auto second = cast_or_null<TypeDecl>(getDecl(*rawIDIter++));
-    auto third = maybeReadSubstitution(DeclTypeCursor);
-    assert(third.hasValue());
-    typeWitnesses[first] = std::make_pair(*third, second);
+    auto second = getType(*rawIDIter++);
+    auto third = cast_or_null<TypeDecl>(getDecl(*rawIDIter++));
+    typeWitnesses[first] = std::make_pair(second, third);
   }
   assert(rawIDIter <= rawIDs.end() && "read too much");
 
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 4711c30..104ad9f 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -1256,16 +1256,6 @@
   unsigned numValueWitnesses = 0;
   unsigned numTypeWitnesses = 0;
 
-  // Collect the set of protocols inherited by this conformance.
-  SmallVector<ProtocolDecl *, 8> inheritedProtos;
-  for (auto inheritedMapping : conformance->getInheritedConformances()) {
-    inheritedProtos.push_back(inheritedMapping.first);
-  }
-
-  // Sort the protocols so that we get a deterministic ordering.
-  llvm::array_pod_sort(inheritedProtos.begin(), inheritedProtos.end(),
-                       ProtocolType::compareProtocols);
-
   conformance->forEachValueWitness(nullptr,
     [&](ValueDecl *req, Witness witness) {
       data.push_back(addDeclRef(req));
@@ -1300,16 +1290,14 @@
 
   conformance->forEachTypeWitness(/*resolver=*/nullptr,
                                   [&](AssociatedTypeDecl *assocType,
-                                      const Substitution &witness,
-                                      TypeDecl *typeDecl) {
+                                      Type type, TypeDecl *typeDecl) {
     data.push_back(addDeclRef(assocType));
+    data.push_back(addTypeRef(type));
     data.push_back(addDeclRef(typeDecl));
-    // The substitution record is serialized later.
     ++numTypeWitnesses;
     return false;
   });
 
-  unsigned numInheritedConformances = inheritedProtos.size();
   unsigned abbrCode
     = DeclTypeAbbrCodes[NormalProtocolConformanceLayout::Code];
   auto ownerID = addDeclContextRef(conformance->getDeclContext());
@@ -1317,19 +1305,12 @@
                                               addDeclRef(protocol), ownerID,
                                               numValueWitnesses,
                                               numTypeWitnesses,
-                                              numInheritedConformances,
                                               data);
 
   // Write requirement signature conformances.
   for (auto reqConformance : conformance->getSignatureConformances())
     writeConformance(reqConformance, DeclTypeAbbrCodes);
   
-  // Write inherited conformances.
-  for (auto inheritedProto : inheritedProtos) {
-    writeConformance(conformance->getInheritedConformance(inheritedProto),
-                     DeclTypeAbbrCodes);
-  }
-
   conformance->forEachValueWitness(nullptr,
                                    [&](ValueDecl *req, Witness witness) {
    // Bail out early for simple witnesses.
@@ -1357,14 +1338,6 @@
                         ? witness.getSyntheticEnvironment()
                         : nullptr);
   });
-
-  conformance->forEachTypeWitness(/*resolver=*/nullptr,
-                                  [&](AssociatedTypeDecl *assocType,
-                                      const Substitution &witness,
-                                      TypeDecl *typeDecl) {
-    writeSubstitutions(witness, DeclTypeAbbrCodes);
-    return false;
-  });
 }
 
 void
@@ -2075,7 +2048,8 @@
     }
     auto abbrCode = DeclTypeAbbrCodes[ObjCDeclAttrLayout::Code];
     ObjCDeclAttrLayout::emitRecord(Out, ScratchRecord, abbrCode,
-                                   theAttr->isImplicit(), 
+                                   theAttr->isImplicit(),
+                                   theAttr->isSwift3Inferred(),
                                    theAttr->isNameImplicit(), numArgs, pieces);
     return;
   }
@@ -4525,7 +4499,7 @@
 
   bool hadError = withOutputFile(getContext(DC), options.OutputPath,
                                  [&](raw_ostream &out) {
-    SharedTimer timer("Serialization (swiftmodule)");
+    SharedTimer timer("Serialization, swiftmodule");
     Serializer::writeToStream(out, DC, M, options);
   });
   if (hadError)
@@ -4534,7 +4508,7 @@
   if (options.DocOutputPath && options.DocOutputPath[0] != '\0') {
     (void)withOutputFile(getContext(DC), options.DocOutputPath,
                          [&](raw_ostream &out) {
-      SharedTimer timer("Serialization (swiftdoc)");
+      SharedTimer timer("Serialization, swiftdoc");
       Serializer::writeDocToStream(out, DC, options.GroupInfoPath,
                                    getContext(DC));
     });
diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp
index 39a9979..ed4fa6d 100644
--- a/lib/TBDGen/TBDGen.cpp
+++ b/lib/TBDGen/TBDGen.cpp
@@ -20,12 +20,14 @@
 #include "swift/AST/ASTVisitor.h"
 #include "swift/AST/Module.h"
 #include "swift/Basic/LLVM.h"
-#include "swift/IRGen/LinkEntity.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/FormalLinkage.h"
 #include "swift/SIL/SILDeclRef.h"
+#include "swift/SIL/TypeLowering.h"
 #include "llvm/ADT/StringSet.h"
 
 using namespace swift;
+using namespace swift::irgen;
 using StringSet = llvm::StringSet<>;
 
 static bool isPrivateDecl(ValueDecl *VD) {
@@ -35,26 +37,38 @@
 namespace {
 class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
   StringSet &Symbols;
+  const UniversalLinkageInfo &UniversalLinkInfo;
+  ModuleDecl *SwiftModule;
 
   void addSymbol(StringRef name) {
-    assert(Symbols.insert(name).second && "already inserted");
+    auto isNewValue = Symbols.insert(name).second;
+    (void)isNewValue;
+    assert(isNewValue && "already inserted");
+  }
+
+  void addSymbol(LinkEntity entity) {
+    auto linkage =
+        LinkInfo::get(UniversalLinkInfo, SwiftModule, entity, ForDefinition);
+
+    auto externallyVisible =
+        llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) &&
+        linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility;
+
+    if (externallyVisible)
+      addSymbol(linkage.getName());
   }
 
   void visitValueTypeDecl(NominalTypeDecl *NTD) {
     assert(isa<StructDecl>(NTD) || isa<EnumDecl>(NTD));
-    if (isPrivateDecl(NTD))
-      return;
-
-    auto declaredType = NTD->getDeclaredType()->getCanonicalType();
-
-    auto vwt = irgen::LinkEntity::forValueWitnessTable(declaredType);
-    addSymbol(vwt.mangleAsString());
-
     visitNominalTypeDecl(NTD);
   }
 
 public:
-  TBDGenVisitor(StringSet &symbols) : Symbols(symbols) {}
+  TBDGenVisitor(StringSet &symbols,
+                const UniversalLinkageInfo &universalLinkInfo,
+                ModuleDecl *swiftModule)
+      : Symbols(symbols), UniversalLinkInfo(universalLinkInfo),
+        SwiftModule(swiftModule) {}
 
   void visitMembers(Decl *D) {
     SmallVector<Decl *, 4> members;
@@ -86,45 +100,40 @@
   void visitNominalTypeDecl(NominalTypeDecl *NTD) {
     auto declaredType = NTD->getDeclaredType()->getCanonicalType();
 
-    auto ntDescriptor = irgen::LinkEntity::forNominalTypeDescriptor(NTD);
-    addSymbol(ntDescriptor.mangleAsString());
+    addSymbol(LinkEntity::forNominalTypeDescriptor(NTD));
 
-    auto tmd = irgen::LinkEntity::forTypeMetadata(
-        declaredType, irgen::TypeMetadataAddress::AddressPoint,
-        /*isPattern=*/false);
-    addSymbol(tmd.mangleAsString());
-    auto tmda = irgen::LinkEntity::forTypeMetadataAccessFunction(declaredType);
-    addSymbol(tmda.mangleAsString());
+    addSymbol(LinkEntity::forTypeMetadata(declaredType,
+                                          TypeMetadataAddress::AddressPoint,
+                                          /*isPattern=*/false));
+    addSymbol(LinkEntity::forTypeMetadataAccessFunction(declaredType));
 
-    if (isPrivateDecl(NTD))
-      return;
+    // There are symbols associated with any protocols this type conforms to.
+    for (auto conformance : NTD->getLocalConformances()) {
+      auto needsWTable = Lowering::TypeConverter::protocolRequiresWitnessTable(
+          conformance->getProtocol());
+      if (!needsWTable)
+        continue;
+
+      addSymbol(LinkEntity::forDirectProtocolWitnessTable(conformance));
+      addSymbol(LinkEntity::forProtocolWitnessTableAccessFunction(conformance));
+    }
 
     visitMembers(NTD);
   }
   void visitClassDecl(ClassDecl *CD) {
-    if (isPrivateDecl(CD))
-      return;
-
-    auto declaredType = CD->getDeclaredType()->getCanonicalType();
-
-    auto tmlcv =
-        irgen::LinkEntity::forTypeMetadataLazyCacheVariable(declaredType);
-    addSymbol(tmlcv.mangleAsString());
-
     visitNominalTypeDecl(CD);
   }
 
   void visitStructDecl(StructDecl *SD) { visitValueTypeDecl(SD); }
   void visitEnumDecl(EnumDecl *ED) { visitValueTypeDecl(ED); }
   void visitProtocolDecl(ProtocolDecl *PD) {
-    if (isPrivateDecl(PD))
-      return;
-
-    auto pDescriptor = irgen::LinkEntity::forProtocolDescriptor(PD);
-    addSymbol(pDescriptor.mangleAsString());
+    addSymbol(LinkEntity::forProtocolDescriptor(PD));
 
     // There's no relevant information about members of a protocol at individual
     // protocols, each conforming type has to handle them individually.
+
+    // FIXME: Eventually we might allow nominal type members of protocols.
+    // Should just visit that here or at least assert that there aren't any.
   }
 
   void visitVarDecl(VarDecl *VD);
@@ -151,11 +160,16 @@
   visitMembers(VD);
 }
 
-void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols) {
+void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols,
+                                   bool hasMultipleIRGenThreads,
+                                   bool isWholeModule) {
+  UniversalLinkageInfo linkInfo(file->getASTContext().LangOpts.Target,
+                                hasMultipleIRGenThreads, isWholeModule);
+
   SmallVector<Decl *, 16> decls;
   file->getTopLevelDecls(decls);
 
-  TBDGenVisitor visitor(symbols);
+  TBDGenVisitor visitor(symbols, linkInfo, file->getParentModule());
   for (auto d : decls)
     visitor.visit(d);
 }
diff --git a/stdlib/private/StdlibCollectionUnittest/CheckCollectionInstance.swift.gyb b/stdlib/private/StdlibCollectionUnittest/CheckCollectionInstance.swift.gyb
index a4d23ef..c1598be 100644
--- a/stdlib/private/StdlibCollectionUnittest/CheckCollectionInstance.swift.gyb
+++ b/stdlib/private/StdlibCollectionUnittest/CheckCollectionInstance.swift.gyb
@@ -269,9 +269,57 @@
 %   ('Expected: Collection',  'Expected.Iterator.Element',  'Expected'),
 %   ('Element'             ,  'Element'                  ,  'Array<Element>')]:
 
+// Top-level check for Collection instances. Alias for checkForwardCollection.
+// Checks all slices: O(n^2).
+public func checkCollection<${genericParam}, C : Collection>(
+  _ expected: ${Expected},
+  _ collection: C,
+  ${TRACE},
+  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
+  sameValue: (${Element}, ${Element}) -> Bool
+) where C.Iterator.Element == ${Element},
+  // FIXME(ABI) (Associated Types with where clauses): these constraints should be applied to
+  // associated types of Collection.
+  C.Indices.Iterator.Element == C.Index,
+  C.SubSequence : Collection,
+  C.SubSequence.Iterator.Element == ${Element},
+  C.SubSequence.Indices.Iterator.Element == C.Index,
+  C.SubSequence.Index == C.Index {
+
+  checkForwardCollection(expected, collection, message(),
+    stackTrace: stackTrace, showFrame: showFrame, file: file, line: line,
+    resiliencyChecks: resiliencyChecks,
+    sameValue: sameValue)
+}
+
 %   for Traversal in TRAVERSALS:
 %     TraversalCollection = collectionForTraversal(Traversal)
 
+// Calls check${Traversal}Collection with default `sameValue`.
+public func check${Traversal}Collection<
+  ${genericParam}, C : ${TraversalCollection}
+>(
+  _ expected: ${Expected}, _ collection: C,
+  ${TRACE},
+  resiliencyChecks: CollectionMisuseResiliencyChecks = .all
+) where
+  C.Iterator.Element == ${Element},
+  C.Indices.Iterator.Element == C.Index,
+  C.SubSequence : ${TraversalCollection},
+  C.SubSequence.Iterator.Element == ${Element},
+  C.SubSequence.Indices.Iterator.Element == C.Index,
+  C.SubSequence.Index == C.Index,
+  ${Element} : Equatable {
+
+  check${Traversal}Collection(
+    expected, collection, ${trace},
+    resiliencyChecks: resiliencyChecks) { $0 == $1 }
+}
+
+// Top-Level check for all ${TraversalCollection} semantics on a single
+// instance. This constrains SubSequence associated types in order to check
+// slice semantics.
+// Checks all slices: O(n^2).
 public func check${Traversal}Collection<
   ${genericParam}, C : ${TraversalCollection}
 >(
@@ -281,6 +329,44 @@
   sameValue: (${Element}, ${Element}) -> Bool
 ) where
   C.Iterator.Element == ${Element},
+  // FIXME(ABI) (Associated Types with where clauses): these constraints should be applied to
+  // associated types of Collection.
+  C.Indices.Iterator.Element == C.Index,
+  C.SubSequence : ${TraversalCollection},
+  C.SubSequence.Iterator.Element == ${Element},
+  C.SubSequence.Index == C.Index,
+  C.SubSequence.Indices.Iterator.Element == C.Index {
+
+  checkOneLevelOf${Traversal}Collection(expected, collection, ${trace},
+    resiliencyChecks: resiliencyChecks, sameValue: sameValue)
+
+  // Avoid validation of all possible (n^2) slices on large collection.
+  // Test cases should call checkOneLevelOf${Traversal}Collection instead.
+  expectLT(expected.count, 30)
+
+  _checkSliceableWith${Traversal}Index(expected, collection, ${trace},
+    resiliencyChecks: resiliencyChecks, sameValue: sameValue)
+}
+
+// Helper for check${Traversal}Collection. Check that instance of `C`,
+// `collection`, upholds the semantics of `${TraversalCollection}`,
+// non-recursively. This does not check subsequences. It may be called for each
+// subsequence without combinatorial explosion. Also, since recursive protocol
+// contraints are not supported, our second level of checks cannot depend on the
+// associated type properties of SubSequence.
+//
+// Checks all slices: O(n^2).
+public func checkOneLevelOf${Traversal}Collection<
+  ${genericParam}, C : ${TraversalCollection}
+>(
+  _ expected: ${Expected}, _ collection: C,
+  ${TRACE},
+  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
+  sameValue: (${Element}, ${Element}) -> Bool
+) where
+  C.Iterator.Element == ${Element},
+  // FIXME(ABI) (Associated Types with where clauses): these constraints should be applied to
+  // associated types of Collection.
   C.Indices.Iterator.Element == C.Index {
 
   // A `Collection` is a multi-pass `Sequence`.
@@ -290,6 +376,10 @@
       resiliencyChecks: resiliencyChecks, sameValue: sameValue)
   }
 
+  //===------------------------------------------------------------------===//
+  // Check Index semantics
+  //===------------------------------------------------------------------===//
+
   let succ = { collection.index(after: $0) }
 %     if Traversal != 'Forward':
   let pred = { collection.index(before: $0) }
@@ -356,9 +446,14 @@
 
   let expectedArray = Array(expected)
 
+  // Check `count`.
   expectEqual(
     expectedArray.count.toIntMax(), collection.count.toIntMax(), ${trace})
 
+  //===------------------------------------------------------------------===//
+  // Check Iteration behavior.
+  //===------------------------------------------------------------------===//
+
   for _ in 0..<3 {
     do {
       let startIndex = collection.startIndex
@@ -414,7 +509,7 @@
           expectedArray[i], collection[index], ${trace}, sameValue: sameValue)
       }
 
-%       end
+%       end # Traversal == "Bidirectional"
 
     } // end of `if expectedArray.count >= 2`
 
@@ -440,65 +535,59 @@
   // FIXME: more checks for bidirectional and random access collections.
 }
 
-public func check${Traversal}Collection<
-  ${genericParam}, C : ${TraversalCollection}
+// Helper for check${Traversal}Collection to check Slices.
+//
+// Checks all slices: O(n^2).
+internal func _checkSliceableWith${Traversal}Index<
+${genericParam}, S : ${TraversalCollection}
 >(
-  _ expected: ${Expected}, _ collection: C,
-  ${TRACE},
-  resiliencyChecks: CollectionMisuseResiliencyChecks = .all
-) where
-  C.Iterator.Element == ${Element},
-  C.Indices.Iterator.Element == C.Index,
-  ${Element} : Equatable {
-
-  check${Traversal}Collection(
-    expected, collection, ${trace},
-    resiliencyChecks: resiliencyChecks) { $0 == $1 }
-}
-
-%   end
-
-// FIXME: merge into checkCollection()
-public func checkSliceableWithBidirectionalIndex<
-  ${genericParam}, S : BidirectionalCollection
->(
-  _ expected: ${Expected}, _ sliceable: S, ${TRACE}
+  _ expected: ${Expected}, _ sliceable: S, ${TRACE},
+  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
+  sameValue: (${Element}, ${Element}) -> Bool
 ) where
   S.Iterator.Element == ${Element},
-  S.Indices.Iterator.Element == S.Index,
-  S.SubSequence : BidirectionalCollection,
+  S.SubSequence : ${TraversalCollection},
   S.SubSequence.Iterator.Element == ${Element},
-  S.SubSequence.Indices.Iterator.Element == S.SubSequence.Index,
-  ${Element} : Equatable {
-
-  // A `Sliceable` is a `Collection`.
-  checkBidirectionalCollection(expected, sliceable, ${trace})
+  S.SubSequence.Index == S.Index,
+  S.SubSequence.Indices.Iterator.Element == S.Index {
 
   let expectedArray = Array(expected)
 
   let succ = { sliceable.index(after: $0) }
+%       if Traversal != "Forward":
   let pred = { sliceable.index(before: $0) }
+%       end
 
   var start = sliceable.startIndex
   for startNumericIndex in 0...expectedArray.count {
+%       if Traversal != "Forward":
     if start != sliceable.endIndex {
       start = succ(start)
       start = pred(start)
       start = succ(start)
       start = pred(start)
     }
+%       end
     var end = start
     for endNumericIndex in startNumericIndex...expectedArray.count {
+%       if Traversal != "Forward":
       if end != sliceable.endIndex {
         end = succ(end)
         end = pred(end)
         end = succ(end)
         end = pred(end)
       }
+%       end
       let expectedSlice = expectedArray[startNumericIndex..<endNumericIndex]
       let slice = sliceable[start..<end]
+      // For every possible slice, verify that the slice's bounds are identical
+      // to the indices used to form the slice.
+      expectEqual(start, slice.startIndex)
+      expectEqual(end, slice.endIndex)
 
-      checkBidirectionalCollection(expectedSlice, slice, ${trace})
+      checkOneLevelOf${Traversal}Collection(expectedSlice, slice, ${trace},
+        resiliencyChecks: resiliencyChecks,
+        sameValue: sameValue)
 
       if end != sliceable.endIndex {
         end = succ(end)
@@ -510,9 +599,13 @@
   }
 }
 
-% end
+%   end # Traversal
 
+% end # genericParam, Elements, Expected
 
+// Check RangeReplaceableCollection using a factory.
+//
+// Note: This does not invoke other collection tests.
 public func checkRangeReplaceable<C, N>(
   _ makeCollection: @escaping () -> C,
   _ makeNewValues: (Int) -> N
@@ -574,13 +667,3 @@
     }
   }
 }
-
-public func checkCollection<C : Collection, Expected : Collection>(
-  _ subject: C,
-  expected: Expected,
-  ${TRACE},
-  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
-  sameValue: (Expected.Iterator.Element, Expected.Iterator.Element) -> Bool
-) where C.Iterator.Element == Expected.Iterator.Element {
-}
-
diff --git a/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb b/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb
index a7aa073..1dada79 100644
--- a/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb
+++ b/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb
@@ -120,85 +120,85 @@
 
   // Slice to the full extent.
   SubscriptRangeTest(
-    expected: [ 1010 ],
-    collection: [ 1010 ],
+    expected: [1010],
+    collection: [1010],
     bounds: 0..<1,
     count: 1),
   SubscriptRangeTest(
-    expected: [ 1010, 2020, 3030 ],
-    collection: [ 1010, 2020, 3030 ],
+    expected: [1010, 2020, 3030],
+    collection: [1010, 2020, 3030],
     bounds: 0..<3,
     count: 3),
   SubscriptRangeTest(
-    expected: [ 1010, 2020, 3030, 4040, 5050 ],
-    collection: [ 1010, 2020, 3030, 4040, 5050 ],
+    expected: [1010, 2020, 3030, 4040, 5050],
+    collection: [1010, 2020, 3030, 4040, 5050],
     bounds: 0..<5,
     count: 5),
 
   // Slice an empty prefix.
   SubscriptRangeTest(
     expected: [],
-    collection: [ 1010, 2020, 3030 ],
+    collection: [1010, 2020, 3030],
     bounds: 0..<0,
     count: 3),
 
   // Slice a prefix.
   SubscriptRangeTest(
-    expected: [ 1010, 2020 ],
-    collection: [ 1010, 2020, 3030 ],
+    expected: [1010, 2020],
+    collection: [1010, 2020, 3030],
     bounds: 0..<2,
     count: 3),
   SubscriptRangeTest(
-    expected: [ 1010, 2020 ],
-    collection: [ 1010, 2020, 3030, 4040, 5050 ],
+    expected: [1010, 2020],
+    collection: [1010, 2020, 3030, 4040, 5050],
     bounds: 0..<2,
     count: 5),
 
   // Slice an empty suffix.
   SubscriptRangeTest(
     expected: [],
-    collection: [ 1010, 2020, 3030 ],
+    collection: [1010, 2020, 3030],
     bounds: 3..<3,
     count: 3),
 
   // Slice a suffix.
   SubscriptRangeTest(
-    expected: [ 2020, 3030 ],
-    collection: [ 1010, 2020, 3030 ],
+    expected: [2020, 3030],
+    collection: [1010, 2020, 3030],
     bounds: 1..<3,
     count: 3),
   SubscriptRangeTest(
-    expected: [ 4040, 5050 ],
-    collection: [ 1010, 2020, 3030, 4040, 5050 ],
+    expected: [4040, 5050],
+    collection: [1010, 2020, 3030, 4040, 5050],
     bounds: 3..<5,
     count: 5),
 
   // Slice an empty range in the middle.
   SubscriptRangeTest(
     expected: [],
-    collection: [ 1010, 2020, 3030 ],
+    collection: [1010, 2020, 3030],
     bounds: 1..<1,
     count: 3),
   SubscriptRangeTest(
     expected: [],
-    collection: [ 1010, 2020, 3030 ],
+    collection: [1010, 2020, 3030],
     bounds: 2..<2,
     count: 3),
 
   // Slice the middle part.
   SubscriptRangeTest(
-    expected: [ 2020 ],
-    collection: [ 1010, 2020, 3030 ],
+    expected: [2020],
+    collection: [1010, 2020, 3030],
     bounds: 1..<2,
     count: 3),
   SubscriptRangeTest(
-    expected: [ 3030 ],
-    collection: [ 1010, 2020, 3030, 4040 ],
-    bounds: 3..<4,
+    expected: [3030],
+    collection: [1010, 2020, 3030, 4040],
+    bounds: 2..<3,
     count: 4),
   SubscriptRangeTest(
-    expected: [ 2020, 3030, 4040 ],
-    collection: [ 1010, 2020, 3030, 4040, 5050, 6060 ],
+    expected: [2020, 3030, 4040],
+    collection: [1010, 2020, 3030, 4040, 5050, 6060],
     bounds: 1..<4,
     count: 6),
 ]
@@ -690,8 +690,8 @@
         // TODO: swift-3-indexing-model: uncomment the following.
         // FIXME: improve checkForwardCollection to check the SubSequence type.
         checkCollection(
-          slice,
           expected: test.expected.map(wrapValue),
+          slice,
           resiliencyChecks: .none) {
           extractValue($0).value == extractValue($1).value
         }
diff --git a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
index ae6ad0c..51d3b6d 100644
--- a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
+++ b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
@@ -158,6 +158,10 @@
   expectEqualTest(expected.3, actual.3, ${trace}, showFrame: false) {$0 == $1}
 }
 
+public func expectEqualReference(_ expected: AnyObject?, _ actual: AnyObject?, ${TRACE}) {
+  expectEqualTest(expected, actual, ${trace}, showFrame: false) {$0 === $1}
+}
+
 public func expectationFailure(
   _ reason: String,
   trace message: String,
diff --git a/stdlib/public/SDK/AppKit/AppKit.swift b/stdlib/public/SDK/AppKit/AppKit.swift
index 8327a12..5740076 100644
--- a/stdlib/public/SDK/AppKit/AppKit.swift
+++ b/stdlib/public/SDK/AppKit/AppKit.swift
@@ -71,6 +71,7 @@
 }
 
 extension NSColor : _ExpressibleByColorLiteral {
+  @nonobjc
   public required convenience init(colorLiteralRed red: Float, green: Float,
                                    blue: Float, alpha: Float) {
     self.init(srgbRed: CGFloat(red), green: CGFloat(green),
@@ -85,6 +86,7 @@
     self.init(named: name)
   }
 
+  @nonobjc
   public required convenience init(imageLiteralResourceName name: String) {
     self.init(failableImageLiteral: name)
   }
diff --git a/stdlib/public/SDK/AppKit/NSError.swift b/stdlib/public/SDK/AppKit/NSError.swift
index 3d35f94..8351200 100644
--- a/stdlib/public/SDK/AppKit/NSError.swift
+++ b/stdlib/public/SDK/AppKit/NSError.swift
@@ -33,7 +33,7 @@
   public static var serviceMalformedServiceDictionary: CocoaError.Code {
     return CocoaError.Code(rawValue: 66564)
   }
-  public static var serviceMiscellaneous: CocoaError.Code {
+  public static var serviceMiscellaneousError: CocoaError.Code {
     return CocoaError.Code(rawValue: 66800)
   }
   public static var sharingServiceNotConfigured: CocoaError.Code {
@@ -71,8 +71,8 @@
   public static var serviceMalformedServiceDictionaryError: CocoaError.Code {
     return CocoaError.Code(rawValue: 66564)
   }
-  @available(*, deprecated, renamed: "serviceMiscellaneous")
-  public static var serviceMiscellaneousError: CocoaError.Code {
+  @available(*, deprecated, renamed: "serviceMiscellaneousError")
+  public static var serviceMiscellaneous: CocoaError.Code {
     return CocoaError.Code(rawValue: 66800)
   }
   @available(*, deprecated, renamed: "sharingServiceNotConfigured")
diff --git a/stdlib/public/SDK/CloudKit/CMakeLists.txt b/stdlib/public/SDK/CloudKit/CMakeLists.txt
index a8243d3..2a4ab81 100644
--- a/stdlib/public/SDK/CloudKit/CMakeLists.txt
+++ b/stdlib/public/SDK/CloudKit/CMakeLists.txt
@@ -6,7 +6,7 @@
 
   SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
   LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
-  TARGET_SDKS ALL_APPLE_PLATFORMS
+  TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR WATCHOS WATCHOS_SIMULATOR
 
   # The dependency on the 'os' module only appears in particular Apple-internal
   # configurations, but it causes no harm to specify it unconditionally.
diff --git a/stdlib/public/SDK/CoreAudio/CMakeLists.txt b/stdlib/public/SDK/CoreAudio/CMakeLists.txt
index b3f8c66..d438ab8 100644
--- a/stdlib/public/SDK/CoreAudio/CMakeLists.txt
+++ b/stdlib/public/SDK/CoreAudio/CMakeLists.txt
@@ -7,7 +7,7 @@
 
   SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
   LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
-  TARGET_SDKS ALL_APPLE_PLATFORMS
+  TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR WATCHOS WATCHOS_SIMULATOR
   SWIFT_MODULE_DEPENDS_OSX Darwin Dispatch ObjectiveC # auto-updated
   SWIFT_MODULE_DEPENDS_IOS Darwin Dispatch ObjectiveC # auto-updated
   SWIFT_MODULE_DEPENDS_TVOS Darwin Dispatch ObjectiveC # auto-updated
diff --git a/stdlib/public/SDK/Foundation/Boxing.swift b/stdlib/public/SDK/Foundation/Boxing.swift
index 6cc11a3..fe7c9ec 100644
--- a/stdlib/public/SDK/Foundation/Boxing.swift
+++ b/stdlib/public/SDK/Foundation/Boxing.swift
@@ -68,158 +68,3 @@
     case Immutable(Unmanaged<ImmutableType>)
     case Mutable(Unmanaged<MutableType>)
 }
-
-internal protocol _SwiftNativeFoundationType : class {
-    associatedtype ImmutableType : NSObject
-    associatedtype MutableType : NSObject, NSMutableCopying
-    var __wrapped : _MutableUnmanagedWrapper<ImmutableType, MutableType> { get }
-    
-    init(unmanagedImmutableObject: Unmanaged<ImmutableType>)
-    init(unmanagedMutableObject: Unmanaged<MutableType>)
-    
-    func mutableCopy(with zone : NSZone?) -> Any
-    
-    var hashValue: Int { get }
-    var description: String { get }
-    var debugDescription: String { get }
-    
-    func releaseWrappedObject()
-}
-
-extension _SwiftNativeFoundationType {
-    
-    @inline(__always)
-    func _mapUnmanaged<ReturnType>(_ whatToDo : (ImmutableType) throws -> ReturnType) rethrows -> ReturnType {
-        defer { _fixLifetime(self) }
-
-        switch __wrapped {
-        case .Immutable(let i):
-            return try i._withUnsafeGuaranteedRef {
-                _onFastPath()
-                return try whatToDo($0)
-            }
-        case .Mutable(let m):
-            return try m._withUnsafeGuaranteedRef {
-                _onFastPath()
-                return try whatToDo(_unsafeReferenceCast($0, to: ImmutableType.self))
-            }
-        }
-    }
-
-    func releaseWrappedObject() {
-        switch __wrapped {
-        case .Immutable(let i):
-            i.release()
-        case .Mutable(let m):
-            m.release()
-        }
-    }
-    
-    func mutableCopy(with zone : NSZone?) -> Any {
-        return _mapUnmanaged { $0.mutableCopy() }
-    }
-    
-    var hashValue: Int {
-        return _mapUnmanaged { return $0.hashValue }
-    }
-    
-    var description: String {
-        return _mapUnmanaged { return $0.description }
-    }
-    
-    var debugDescription: String {
-        return _mapUnmanaged { return $0.debugDescription }
-    }
-    
-    func isEqual(_ other: AnyObject) -> Bool {
-        return _mapUnmanaged { return $0.isEqual(other) }
-    }
-}
-
-internal protocol _MutablePairBoxing {
-    associatedtype WrappedSwiftNSType : _SwiftNativeFoundationType
-    var _wrapped :  WrappedSwiftNSType { get set }
-}
-
-extension _MutablePairBoxing {
-    @inline(__always)
-    func _mapUnmanaged<ReturnType>(_ whatToDo : (WrappedSwiftNSType.ImmutableType) throws -> ReturnType) rethrows -> ReturnType {
-        // We are using Unmanaged. Make sure that the owning container class
-        // 'self' is guaranteed to be alive by extending the lifetime of 'self'
-        // to the end of the scope of this function.
-        // Note: At the time of this writing using withExtendedLifetime here
-        // instead of _fixLifetime causes different ARC pair matching behavior
-        // foiling optimization. This is why we explicitly use _fixLifetime here
-        // instead.
-        defer { _fixLifetime(self) }
-
-        let unmanagedHandle = Unmanaged.passUnretained(_wrapped)
-        let wrapper = unmanagedHandle._withUnsafeGuaranteedRef { $0.__wrapped }
-        switch wrapper {
-        case .Immutable(let i):
-            return try i._withUnsafeGuaranteedRef {
-                return try whatToDo($0)
-            }
-        case .Mutable(let m):
-            return try m._withUnsafeGuaranteedRef {
-                return try whatToDo(_unsafeReferenceCast($0, to: WrappedSwiftNSType.ImmutableType.self))
-            }
-        }
-    }
-
-    @inline(__always)
-    mutating func _applyUnmanagedMutation<ReturnType>(_ whatToDo : (WrappedSwiftNSType.MutableType) throws -> ReturnType) rethrows -> ReturnType {
-        // We are using Unmanaged. Make sure that the owning container class
-        // 'self' is guaranteed to be alive by extending the lifetime of 'self'
-        // to the end of the scope of this function.
-        // Note: At the time of this writing using withExtendedLifetime here
-        // instead of _fixLifetime causes different ARC pair matching behavior
-        // foiling optimization. This is why we explicitly use _fixLifetime here
-        // instead.
-        defer { _fixLifetime(self) }
-
-        var unique = true
-        let _unmanagedHandle = Unmanaged.passUnretained(_wrapped)
-        let wrapper = _unmanagedHandle._withUnsafeGuaranteedRef { $0.__wrapped }
-
-        // This check is done twice because: <rdar://problem/24939065> Value kept live for too long causing uniqueness check to fail
-        switch wrapper {
-        case .Immutable(_):
-            break
-        case .Mutable(_):
-            unique = isKnownUniquelyReferenced(&_wrapped)
-        }
-
-        switch wrapper {
-        case .Immutable(let i):
-            // We need to become mutable; by creating a new instance we also become unique
-            let copy = Unmanaged.passRetained(i._withUnsafeGuaranteedRef {
-                return _unsafeReferenceCast($0.mutableCopy(), to: WrappedSwiftNSType.MutableType.self) }
-            )
-
-            // Be sure to set the var before calling out; otherwise references to the struct in the closure may be looking at the old value
-            _wrapped = WrappedSwiftNSType(unmanagedMutableObject: copy)
-            return try copy._withUnsafeGuaranteedRef {
-                _onFastPath()
-                return try whatToDo($0)
-            }
-        case .Mutable(let m):
-            // Only create a new box if we are not uniquely referenced
-            if !unique {
-                let copy = Unmanaged.passRetained(m._withUnsafeGuaranteedRef {
-                    return _unsafeReferenceCast($0.mutableCopy(), to: WrappedSwiftNSType.MutableType.self)
-                    })
-                _wrapped = WrappedSwiftNSType(unmanagedMutableObject: copy)
-                return try copy._withUnsafeGuaranteedRef {
-                    _onFastPath()
-                    return try whatToDo($0)
-                }
-            } else {
-                return try m._withUnsafeGuaranteedRef {
-                    _onFastPath()
-                    return try whatToDo($0)
-                }
-            }
-        }
-    }
-}
diff --git a/stdlib/public/SDK/Foundation/CharacterSet.swift b/stdlib/public/SDK/Foundation/CharacterSet.swift
index c2dc27b..f100ddb 100644
--- a/stdlib/public/SDK/Foundation/CharacterSet.swift
+++ b/stdlib/public/SDK/Foundation/CharacterSet.swift
@@ -12,110 +12,385 @@
 
 @_exported import Foundation // Clang module
 import CoreFoundation
+import _SwiftCoreFoundationOverlayShims
 
-private func _utfRangeToNSRange(_ inRange : Range<UnicodeScalar>) -> NSRange {
-    return NSMakeRange(Int(inRange.lowerBound.value), Int(inRange.upperBound.value - inRange.lowerBound.value))
+private func _utfRangeToCFRange(_ inRange : Range<UnicodeScalar>) -> CFRange {
+    return CFRange(
+        location: Int(inRange.lowerBound.value),
+        length: Int(inRange.upperBound.value - inRange.lowerBound.value))
 }
 
-private func _utfRangeToNSRange(_ inRange : ClosedRange<UnicodeScalar>) -> NSRange {
-    return NSMakeRange(Int(inRange.lowerBound.value), Int(inRange.upperBound.value - inRange.lowerBound.value + 1))
+private func _utfRangeToCFRange(_ inRange : ClosedRange<UnicodeScalar>) -> CFRange {
+    return CFRange(
+        location: Int(inRange.lowerBound.value),
+        length: Int(inRange.upperBound.value - inRange.lowerBound.value + 1))
 }
 
-internal final class _SwiftNSCharacterSet : _SwiftNativeNSCharacterSet, _SwiftNativeFoundationType {
-    internal typealias ImmutableType = NSCharacterSet
-    internal typealias MutableType = NSMutableCharacterSet
-    
-    var __wrapped : _MutableUnmanagedWrapper<ImmutableType, MutableType>
-    
-    init(immutableObject: AnyObject) {
-        // Take ownership.
-        __wrapped = .Immutable(Unmanaged.passRetained(_unsafeReferenceCast(immutableObject, to: ImmutableType.self)))
+// MARK: -
+
+fileprivate final class _CharacterSetStorage : Hashable {
+    fileprivate enum Backing {
+        case immutable(CFCharacterSet)
+        case mutable(CFMutableCharacterSet)
     }
     
-    init(mutableObject: AnyObject) {
-        // Take ownership.
-        __wrapped = .Mutable(Unmanaged.passRetained(_unsafeReferenceCast(mutableObject, to: MutableType.self)))
+    fileprivate var _backing : Backing
+   
+    @nonobjc 
+    init(immutableReference r : CFCharacterSet) {
+        _backing = .immutable(r)
+    }
+
+    @nonobjc
+    init(mutableReference r : CFMutableCharacterSet) {
+        _backing = .mutable(r)
     }
     
-    internal required init(unmanagedImmutableObject: Unmanaged<ImmutableType>) {
-        // Take ownership.
-        __wrapped = .Immutable(unmanagedImmutableObject)
+    // MARK: -
+    
+    fileprivate var hashValue : Int {
+        switch _backing {
+        case .immutable(let cs):
+            return Int(CFHash(cs))
+        case .mutable(let cs):
+            return Int(CFHash(cs))
+        }
+    }
+    
+    fileprivate static func ==(_ lhs : _CharacterSetStorage, _ rhs : _CharacterSetStorage) -> Bool {
+        switch (lhs._backing, rhs._backing) {
+        case (.immutable(let cs1), .immutable(let cs2)):
+            return CFEqual(cs1, cs2)
+        case (.immutable(let cs1), .mutable(let cs2)):
+            return CFEqual(cs1, cs2)
+        case (.mutable(let cs1), .immutable(let cs2)):
+            return CFEqual(cs1, cs2)
+        case (.mutable(let cs1), .mutable(let cs2)):
+            return CFEqual(cs1, cs2)
+        }
+    }
+    
+    // MARK: -
+    
+    fileprivate func mutableCopy() -> _CharacterSetStorage {
+        switch _backing {
+        case .immutable(let cs):
+            return _CharacterSetStorage(mutableReference: CFCharacterSetCreateMutableCopy(nil, cs))
+        case .mutable(let cs):
+            return _CharacterSetStorage(mutableReference: CFCharacterSetCreateMutableCopy(nil, cs))
+        }
+    }
+
+    
+    // MARK: Immutable Functions
+    
+    fileprivate var bitmapRepresentation : Data {
+        switch _backing {
+        case .immutable(let cs):
+            return CFCharacterSetCreateBitmapRepresentation(nil, cs) as Data
+        case .mutable(let cs):
+            return CFCharacterSetCreateBitmapRepresentation(nil, cs) as Data
+        }
+    }
+    
+    fileprivate func hasMember(inPlane plane: UInt8) -> Bool {
+        switch _backing {
+        case .immutable(let cs):
+            return CFCharacterSetHasMemberInPlane(cs, CFIndex(plane))
+        case .mutable(let cs):
+            return CFCharacterSetHasMemberInPlane(cs, CFIndex(plane))
+        }
+    }
+    
+    // MARK: Mutable functions
+    
+    fileprivate func insert(charactersIn range: Range<UnicodeScalar>) {
+        switch _backing {
+        case .immutable(let cs):
+            let r = CFCharacterSetCreateMutableCopy(nil, cs)!
+            CFCharacterSetAddCharactersInRange(r, _utfRangeToCFRange(range))
+            _backing = .mutable(r)
+        case .mutable(let cs):
+            CFCharacterSetAddCharactersInRange(cs, _utfRangeToCFRange(range))
+        }
+    }
+    
+    fileprivate func insert(charactersIn range: ClosedRange<UnicodeScalar>) {
+        switch _backing {
+        case .immutable(let cs):
+            let r = CFCharacterSetCreateMutableCopy(nil, cs)!
+            CFCharacterSetAddCharactersInRange(r, _utfRangeToCFRange(range))
+            _backing = .mutable(r)
+        case .mutable(let cs):
+            CFCharacterSetAddCharactersInRange(cs, _utfRangeToCFRange(range))
+        }
+    }
+    
+    fileprivate func remove(charactersIn range: Range<UnicodeScalar>) {
+        switch _backing {
+        case .immutable(let cs):
+            let r = CFCharacterSetCreateMutableCopy(nil, cs)!
+            CFCharacterSetRemoveCharactersInRange(r, _utfRangeToCFRange(range))
+            _backing = .mutable(r)
+        case .mutable(let cs):
+            CFCharacterSetRemoveCharactersInRange(cs, _utfRangeToCFRange(range))
+        }
+    }
+    
+    fileprivate func remove(charactersIn range: ClosedRange<UnicodeScalar>) {
+        switch _backing {
+        case .immutable(let cs):
+            let r = CFCharacterSetCreateMutableCopy(nil, cs)!
+            CFCharacterSetRemoveCharactersInRange(r, _utfRangeToCFRange(range))
+            _backing = .mutable(r)
+        case .mutable(let cs):
+            CFCharacterSetRemoveCharactersInRange(cs, _utfRangeToCFRange(range))
+        }
+    }
+    
+    fileprivate func insert(charactersIn string: String) {
+        switch _backing {
+        case .immutable(let cs):
+            let r = CFCharacterSetCreateMutableCopy(nil, cs)!
+            CFCharacterSetAddCharactersInString(r, string as CFString)
+            _backing = .mutable(r)
+        case .mutable(let cs):
+            CFCharacterSetAddCharactersInString(cs, string as CFString)
+        }
+    }
+    
+    fileprivate func remove(charactersIn string: String) {
+        switch _backing {
+        case .immutable(let cs):
+            let r = CFCharacterSetCreateMutableCopy(nil, cs)!
+            CFCharacterSetRemoveCharactersInString(r, string as CFString)
+            _backing = .mutable(r)
+        case .mutable(let cs):
+            CFCharacterSetRemoveCharactersInString(cs, string as CFString)
+        }
+    }
+    
+    fileprivate func invert() {
+        switch _backing {
+        case .immutable(let cs):
+            let r = CFCharacterSetCreateMutableCopy(nil, cs)!
+            CFCharacterSetInvert(r)
+            _backing = .mutable(r)
+        case .mutable(let cs):
+            CFCharacterSetInvert(cs)
+        }
+    }
+    
+    // -----
+    // MARK: -
+    // MARK: SetAlgebraType
+    
+    @discardableResult
+    fileprivate func insert(_ character: UnicodeScalar) -> (inserted: Bool, memberAfterInsert: UnicodeScalar) {
+        insert(charactersIn: character..<UnicodeScalar(character.value + 1)!)
+        // TODO: This should probably return the truth, but figuring it out requires two calls into NSCharacterSet
+        return (true, character)
+    }
+    
+    @discardableResult
+    fileprivate func update(with character: UnicodeScalar) -> UnicodeScalar? {
+        insert(character)
+        // TODO: This should probably return the truth, but figuring it out requires two calls into NSCharacterSet
+        return character
+    }
+    
+    @discardableResult
+    fileprivate func remove(_ character: UnicodeScalar) -> UnicodeScalar? {
+        // TODO: Add method to CFCharacterSet to do this in one call
+        let result : UnicodeScalar? = contains(character) ? character : nil
+        remove(charactersIn: character..<UnicodeScalar(character.value + 1)!)
+        return result
+    }
+    
+    fileprivate func contains(_ member: UnicodeScalar) -> Bool {
+        switch _backing {
+        case .immutable(let cs):
+            return CFCharacterSetIsLongCharacterMember(cs, member.value)
+        case .mutable(let cs):
+            return CFCharacterSetIsLongCharacterMember(cs, member.value)
+        }
+    }
+    
+    // MARK: -
+    // Why do these return CharacterSet instead of CharacterSetStorage?
+    // We want to keep the knowledge of if the returned value happened to contain a mutable or immutable CFCharacterSet as close to the creation of that instance as possible
+    
+
+    // When the underlying collection does not have a method to return new CharacterSets with changes applied, so we will copy and apply here
+    private static func _apply(_ lhs : _CharacterSetStorage, _ rhs : _CharacterSetStorage, _ f : (CFMutableCharacterSet, CFCharacterSet) -> ()) -> CharacterSet {
+        let copyOfMe : CFMutableCharacterSet
+        switch lhs._backing {
+        case .immutable(let cs):
+            copyOfMe = CFCharacterSetCreateMutableCopy(nil, cs)!
+        case .mutable(let cs):
+            copyOfMe = CFCharacterSetCreateMutableCopy(nil, cs)!
+        }
         
-        super.init()
-    }
-    
-    internal required init(unmanagedMutableObject: Unmanaged<MutableType>) {
-        // Take ownership.
-        __wrapped = .Mutable(unmanagedMutableObject)
+        switch rhs._backing {
+        case .immutable(let cs):
+            f(copyOfMe, cs)
+        case .mutable(let cs):
+            f(copyOfMe, cs)
+        }
         
-        super.init()
+        return CharacterSet(_uncopiedStorage: _CharacterSetStorage(mutableReference: copyOfMe))
     }
     
-    deinit {
-        releaseWrappedObject()
+    private func _applyMutation(_ other : _CharacterSetStorage, _ f : (CFMutableCharacterSet, CFCharacterSet) -> ()) {
+        switch _backing {
+        case .immutable(let cs):
+            let r = CFCharacterSetCreateMutableCopy(nil, cs)!
+            switch other._backing {
+            case .immutable(let otherCs):
+                f(r, otherCs)
+            case .mutable(let otherCs):
+                f(r, otherCs)
+            }
+            _backing = .mutable(r)
+        case .mutable(let cs):
+            switch other._backing {
+            case .immutable(let otherCs):
+                f(cs, otherCs)
+            case .mutable(let otherCs):
+                f(cs, otherCs)
+            }
+        }
+
+    }
+    
+    fileprivate var inverted : CharacterSet {
+        switch _backing {
+        case .immutable(let cs):
+            return CharacterSet(_uncopiedStorage: _CharacterSetStorage(immutableReference: CFCharacterSetCreateInvertedSet(nil, cs)))
+        case .mutable(let cs):
+            // Even if input is mutable, the result is immutable
+            return CharacterSet(_uncopiedStorage: _CharacterSetStorage(immutableReference: CFCharacterSetCreateInvertedSet(nil, cs)))
+        }
     }
 
-    @objc(copyWithZone:)
-    func copy(with zone: NSZone? = nil) -> Any {
-        return _mapUnmanaged { $0.copy(with: zone) }
+    fileprivate func union(_ other: _CharacterSetStorage) -> CharacterSet {
+        return _CharacterSetStorage._apply(self, other, CFCharacterSetUnion)
     }
-
-    @objc(mutableCopyWithZone:)
-    func mutableCopy(with zone: NSZone? = nil) -> Any {
-        return _mapUnmanaged { $0.mutableCopy(with: zone) }
+    
+    fileprivate func formUnion(_ other: _CharacterSetStorage) {
+        _applyMutation(other, CFCharacterSetUnion)
     }
-
-    @objc
-    public var classForCoder: AnyClass {
-        return NSCharacterSet.self
+    
+    fileprivate func intersection(_ other: _CharacterSetStorage) -> CharacterSet {
+        return _CharacterSetStorage._apply(self, other, CFCharacterSetIntersect)
+    }
+    
+    fileprivate func formIntersection(_ other: _CharacterSetStorage) {
+        _applyMutation(other, CFCharacterSetIntersect)
+    }
+    
+    fileprivate func subtracting(_ other: _CharacterSetStorage) -> CharacterSet {
+        return intersection(other.inverted._storage)
+    }
+    
+    fileprivate func subtract(_ other: _CharacterSetStorage) {
+        _applyMutation(other.inverted._storage, CFCharacterSetIntersect)
+    }
+    
+    fileprivate func symmetricDifference(_ other: _CharacterSetStorage) -> CharacterSet {
+        return union(other).subtracting(intersection(other))
+    }
+    
+    fileprivate func formSymmetricDifference(_ other: _CharacterSetStorage) {
+        // This feels like cheating
+        _backing = symmetricDifference(other)._storage._backing
+    }
+    
+    fileprivate func isSuperset(of other: _CharacterSetStorage) -> Bool {
+        switch _backing {
+        case .immutable(let cs):
+            switch other._backing {
+            case .immutable(let otherCs):
+                return CFCharacterSetIsSupersetOfSet(cs, otherCs)
+            case .mutable(let otherCs):
+                return CFCharacterSetIsSupersetOfSet(cs, otherCs)
+            }
+        case .mutable(let cs):
+            switch other._backing {
+            case .immutable(let otherCs):
+                return CFCharacterSetIsSupersetOfSet(cs, otherCs)
+            case .mutable(let otherCs):
+                return CFCharacterSetIsSupersetOfSet(cs, otherCs)
+            }
+        }
+    }
+    
+    // MARK: -
+    
+    fileprivate var description: String {
+        switch _backing {
+        case .immutable(let cs):
+            return CFCopyDescription(cs) as String
+        case .mutable(let cs):
+            return CFCopyDescription(cs) as String
+        }
+    }
+    
+    fileprivate var debugDescription: String {
+        return description
+    }
+    
+    // MARK: -
+    
+    public func bridgedReference() -> NSCharacterSet {
+        switch _backing {
+        case .immutable(let cs):
+            return cs as NSCharacterSet
+        case .mutable(let cs):
+            return cs as NSCharacterSet
+        }
     }
 }
 
+// MARK: -
+
 /**
  A `CharacterSet` represents a set of Unicode-compliant characters. Foundation types use `CharacterSet` to group characters together for searching operations, so that they can find any of a particular set of characters during a search.
  
  This type provides "copy-on-write" behavior, and is also bridged to the Objective-C `NSCharacterSet` class.
 */
-public struct CharacterSet : ReferenceConvertible, Equatable, Hashable, SetAlgebra, _MutablePairBoxing {
+public struct CharacterSet : ReferenceConvertible, Equatable, Hashable, SetAlgebra {
     public typealias ReferenceType = NSCharacterSet
-
-    internal typealias SwiftNSWrapping = _SwiftNSCharacterSet
-    internal typealias ImmutableType = SwiftNSWrapping.ImmutableType
-    internal typealias MutableType = SwiftNSWrapping.MutableType
     
-    internal var _wrapped : _SwiftNSCharacterSet
+    fileprivate var _storage : _CharacterSetStorage
     
     // MARK: Init methods
     
-    fileprivate init(_bridged characterSet: NSCharacterSet) {
-        // We must copy the input because it might be mutable; just like storing a value type in ObjC
-        _wrapped = _SwiftNSCharacterSet(immutableObject: characterSet.copy() as AnyObject)
-    }
-    
     /// Initialize an empty instance.
     public init() {
-        _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet())
+        // It's unlikely that we are creating an empty character set with no intention to mutate it
+        _storage = _CharacterSetStorage(mutableReference: CFCharacterSetCreateMutable(nil))
     }
     
     /// Initialize with a range of integers.
     ///
     /// It is the caller's responsibility to ensure that the values represent valid `UnicodeScalar` values, if that is what is desired.
     public init(charactersIn range: Range<UnicodeScalar>) {
-        _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet(range: _utfRangeToNSRange(range)))
+        _storage = _CharacterSetStorage(immutableReference: CFCharacterSetCreateWithCharactersInRange(nil, _utfRangeToCFRange(range)))
     }
 
     /// Initialize with a closed range of integers.
     ///
     /// It is the caller's responsibility to ensure that the values represent valid `UnicodeScalar` values, if that is what is desired.
     public init(charactersIn range: ClosedRange<UnicodeScalar>) {
-        _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet(range: _utfRangeToNSRange(range)))
+        _storage = _CharacterSetStorage(immutableReference: CFCharacterSetCreateWithCharactersInRange(nil, _utfRangeToCFRange(range)))
     }
 
     /// Initialize with the characters in the given string.
     ///
     /// - parameter string: The string content to inspect for characters.
     public init(charactersIn string: String) {
-        _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet(charactersIn: string))
+        _storage = _CharacterSetStorage(immutableReference: CFCharacterSetCreateWithCharactersInString(nil, string as CFString))
     }
     
     /// Initialize with a bitmap representation.
@@ -123,7 +398,7 @@
     /// This method is useful for creating a character set object with data from a file or other external data source.
     /// - parameter data: The bitmap representation.
     public init(bitmapRepresentation data: Data) {
-        _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet(bitmapRepresentation: data))
+        _storage = _CharacterSetStorage(immutableReference: CFCharacterSetCreateWithBitmapRepresentation(nil, data as CFData))
     }
     
     /// Initialize with the contents of a file.
@@ -131,152 +406,163 @@
     /// Returns `nil` if there was an error reading the file.
     /// - parameter file: The file to read.
     public init?(contentsOfFile file: String) {
-        if let interior = NSCharacterSet(contentsOfFile: file) {
-            _wrapped = _SwiftNSCharacterSet(immutableObject: interior)
-        } else {
+        do {
+            let data = try Data(contentsOf: URL(fileURLWithPath: file), options: .mappedIfSafe)
+            _storage = _CharacterSetStorage(immutableReference: CFCharacterSetCreateWithBitmapRepresentation(nil, data as CFData))
+        } catch {
             return nil
         }
     }
 
-    public var hashValue: Int {
-        return _mapUnmanaged { $0.hashValue }
+    fileprivate init(_bridged characterSet: NSCharacterSet) {
+        _storage = _CharacterSetStorage(immutableReference: characterSet.copy() as! CFCharacterSet)
     }
     
-    private init(reference: NSCharacterSet) {
-        _wrapped = _SwiftNSCharacterSet(immutableObject: reference)
+    fileprivate init(_uncopiedImmutableReference characterSet: CFCharacterSet) {
+        _storage = _CharacterSetStorage(immutableReference: characterSet)
+    }
+
+    fileprivate init(_uncopiedStorage : _CharacterSetStorage) {
+        _storage = _uncopiedStorage
+    }
+
+    fileprivate init(_builtIn: CFCharacterSetPredefinedSet) {
+        _storage = _CharacterSetStorage(immutableReference: CFCharacterSetGetPredefined(_builtIn))
     }
     
     // MARK: Static functions
     
     /// Returns a character set containing the characters in Unicode General Category Cc and Cf.
     public static var controlCharacters : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.controlCharacters as NSCharacterSet)
+        return CharacterSet(_builtIn: .control)
     }
     
     /// Returns a character set containing the characters in Unicode General Category Zs and `CHARACTER TABULATION (U+0009)`.
     public static var whitespaces : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.whitespaces as NSCharacterSet)
+        return CharacterSet(_builtIn: .whitespace)
     }
     
     /// Returns a character set containing characters in Unicode General Category Z*, `U+000A ~ U+000D`, and `U+0085`.
     public static var whitespacesAndNewlines : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.whitespacesAndNewlines as NSCharacterSet)
+        return CharacterSet(_builtIn: .whitespaceAndNewline)
     }
     
     /// Returns a character set containing the characters in the category of Decimal Numbers.
     public static var decimalDigits : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.decimalDigits as NSCharacterSet)
+        return CharacterSet(_builtIn: .decimalDigit)
     }
     
     /// Returns a character set containing the characters in Unicode General Category L* & M*.
     public static var letters : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.letters as NSCharacterSet)
+        return CharacterSet(_builtIn: .letter)
     }
     
     /// Returns a character set containing the characters in Unicode General Category Ll.
     public static var lowercaseLetters : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.lowercaseLetters as NSCharacterSet)
+        return CharacterSet(_builtIn: .lowercaseLetter)
     }
     
     /// Returns a character set containing the characters in Unicode General Category Lu and Lt.
     public static var uppercaseLetters : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.uppercaseLetters as NSCharacterSet)
+        return CharacterSet(_builtIn: .uppercaseLetter)
     }
     
     /// Returns a character set containing the characters in Unicode General Category M*.
     public static var nonBaseCharacters : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.nonBaseCharacters as NSCharacterSet)
+        return CharacterSet(_builtIn: .nonBase)
     }
     
     /// Returns a character set containing the characters in Unicode General Categories L*, M*, and N*.
     public static var alphanumerics : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.alphanumerics as NSCharacterSet)
+        return CharacterSet(_builtIn: .alphaNumeric)
     }
     
     /// Returns a character set containing individual Unicode characters that can also be represented as composed character sequences (such as for letters with accents), by the definition of "standard decomposition" in version 3.2 of the Unicode character encoding standard.
     public static var decomposables : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.decomposables as NSCharacterSet)
+        return CharacterSet(_builtIn: .decomposable)
     }
     
     /// Returns a character set containing values in the category of Non-Characters or that have not yet been defined in version 3.2 of the Unicode standard.
     public static var illegalCharacters : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.illegalCharacters as NSCharacterSet)
+        return CharacterSet(_builtIn: .illegal)
     }
     
     @available(*, unavailable, renamed: "punctuationCharacters")
     public static var punctuation : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.punctuationCharacters as NSCharacterSet)
+        return CharacterSet(_builtIn: .punctuation)
     }
 
     /// Returns a character set containing the characters in Unicode General Category P*.
     public static var punctuationCharacters : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.punctuationCharacters as NSCharacterSet)
+        return CharacterSet(_builtIn: .punctuation)
     }
     
     /// Returns a character set containing the characters in Unicode General Category Lt.
     public static var capitalizedLetters : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.capitalizedLetters as NSCharacterSet)
+        return CharacterSet(_builtIn: .capitalizedLetter)
     }
     
     /// Returns a character set containing the characters in Unicode General Category S*.
     public static var symbols : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.symbols as NSCharacterSet)
+        return CharacterSet(_builtIn: .symbol)
     }
     
     /// Returns a character set containing the newline characters (`U+000A ~ U+000D`, `U+0085`, `U+2028`, and `U+2029`).
     public static var newlines : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.newlines as NSCharacterSet)
+        return CharacterSet(_builtIn: .newline)
     }
     
     // MARK: Static functions, from NSURL
-
+    
     /// Returns the character set for characters allowed in a user URL subcomponent.
     public static var urlUserAllowed : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.urlUserAllowed as NSCharacterSet)
+        return CharacterSet(_uncopiedImmutableReference: _CFURLComponentsGetURLUserAllowedCharacterSet() as NSCharacterSet)
     }
     
     /// Returns the character set for characters allowed in a password URL subcomponent.
     public static var urlPasswordAllowed : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.urlPasswordAllowed as NSCharacterSet)
+        return CharacterSet(_uncopiedImmutableReference: _CFURLComponentsGetURLPasswordAllowedCharacterSet() as NSCharacterSet)
     }
     
     /// Returns the character set for characters allowed in a host URL subcomponent.
     public static var urlHostAllowed : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.urlHostAllowed as NSCharacterSet)
+        return CharacterSet(_uncopiedImmutableReference: _CFURLComponentsGetURLHostAllowedCharacterSet() as NSCharacterSet)
     }
     
     /// Returns the character set for characters allowed in a path URL component.
     public static var urlPathAllowed : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.urlPathAllowed as NSCharacterSet)
+        return CharacterSet(_uncopiedImmutableReference: _CFURLComponentsGetURLPathAllowedCharacterSet() as NSCharacterSet)
     }
     
     /// Returns the character set for characters allowed in a query URL component.
     public static var urlQueryAllowed : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.urlQueryAllowed as NSCharacterSet)
+        return CharacterSet(_uncopiedImmutableReference: _CFURLComponentsGetURLQueryAllowedCharacterSet() as NSCharacterSet)
     }
     
     /// Returns the character set for characters allowed in a fragment URL component.
     public static var urlFragmentAllowed : CharacterSet {
-        return CharacterSet(reference: NSCharacterSet.urlFragmentAllowed as NSCharacterSet)
+        return CharacterSet(_uncopiedImmutableReference: _CFURLComponentsGetURLFragmentAllowedCharacterSet() as NSCharacterSet)
     }
     
     // MARK: Immutable functions
     
     /// Returns a representation of the `CharacterSet` in binary format.
+    @nonobjc
     public var bitmapRepresentation: Data {
-        return _mapUnmanaged { $0.bitmapRepresentation }
+        return _storage.bitmapRepresentation
     }
     
     /// Returns an inverted copy of the receiver.
+    @nonobjc
     public var inverted : CharacterSet {
-        return _mapUnmanaged { $0.inverted }
+        return _storage.inverted
     }
     
     /// Returns true if the `CharacterSet` has a member in the specified plane.
     ///
     /// This method makes it easier to find the plane containing the members of the current character set. The Basic Multilingual Plane (BMP) is plane 0.
     public func hasMember(inPlane plane: UInt8) -> Bool {
-        return _mapUnmanaged { $0.hasMemberInPlane(plane) }
+        return _storage.hasMember(inPlane: plane)
     }
     
     // MARK: Mutable functions
@@ -285,55 +571,60 @@
     ///
     /// It is the caller's responsibility to ensure that the values represent valid `UnicodeScalar` values, if that is what is desired.
     public mutating func insert(charactersIn range: Range<UnicodeScalar>) {
-        let nsRange = _utfRangeToNSRange(range)
-        _applyUnmanagedMutation {
-          $0.addCharacters(in: nsRange)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
+        _storage.insert(charactersIn: range)
     }
 
     /// Insert a closed range of integer values in the `CharacterSet`.
     ///
     /// It is the caller's responsibility to ensure that the values represent valid `UnicodeScalar` values, if that is what is desired.
     public mutating func insert(charactersIn range: ClosedRange<UnicodeScalar>) {
-        let nsRange = _utfRangeToNSRange(range)
-        _applyUnmanagedMutation {
-            $0.addCharacters(in: nsRange)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
+        _storage.insert(charactersIn: range)
     }
 
     /// Remove a range of integer values from the `CharacterSet`.
     public mutating func remove(charactersIn range: Range<UnicodeScalar>) {
-        let nsRange = _utfRangeToNSRange(range)
-        _applyUnmanagedMutation {
-            $0.removeCharacters(in: nsRange)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
+        _storage.remove(charactersIn: range)
     }
 
     /// Remove a closed range of integer values from the `CharacterSet`.
     public mutating func remove(charactersIn range: ClosedRange<UnicodeScalar>) {
-        let nsRange = _utfRangeToNSRange(range)
-        _applyUnmanagedMutation {
-            $0.removeCharacters(in: nsRange)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
+        _storage.remove(charactersIn: range)
     }
 
     /// Insert the values from the specified string into the `CharacterSet`.
     public mutating func insert(charactersIn string: String) {
-        _applyUnmanagedMutation {
-            $0.addCharacters(in: string)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
+        _storage.insert(charactersIn: string)
     }
     
     /// Remove the values from the specified string from the `CharacterSet`.
     public mutating func remove(charactersIn string: String) {
-        _applyUnmanagedMutation {
-            $0.removeCharacters(in: string)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
+        _storage.remove(charactersIn: string)
     }
     
     /// Invert the contents of the `CharacterSet`.
     public mutating func invert() {
-        _applyUnmanagedMutation { $0.invert() }
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
+        }
+        _storage.invert()
     }
     
     // -----
@@ -345,12 +636,10 @@
     /// `UnicodeScalar` values are available on `Swift.String.UnicodeScalarView`.
     @discardableResult
     public mutating func insert(_ character: UnicodeScalar) -> (inserted: Bool, memberAfterInsert: UnicodeScalar) {
-        let nsRange = NSMakeRange(Int(character.value), 1)
-        _applyUnmanagedMutation {
-            $0.addCharacters(in: nsRange)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
-        // TODO: This should probably return the truth, but figuring it out requires two calls into NSCharacterSet
-        return (true, character)
+        return _storage.insert(character)
     }
 
     /// Insert a `UnicodeScalar` representation of a character into the `CharacterSet`.
@@ -358,12 +647,10 @@
     /// `UnicodeScalar` values are available on `Swift.String.UnicodeScalarView`.
     @discardableResult
     public mutating func update(with character: UnicodeScalar) -> UnicodeScalar? {
-        let nsRange = NSMakeRange(Int(character.value), 1)
-        _applyUnmanagedMutation {
-            $0.addCharacters(in: nsRange)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
-        // TODO: This should probably return the truth, but figuring it out requires two calls into NSCharacterSet
-        return character
+        return _storage.update(with: character)
     }
 
     
@@ -372,61 +659,59 @@
     /// `UnicodeScalar` values are available on `Swift.String.UnicodeScalarView`.
     @discardableResult
     public mutating func remove(_ character: UnicodeScalar) -> UnicodeScalar? {
-        // TODO: Add method to NSCharacterSet to do this in one call
-        let result : UnicodeScalar? = contains(character) ? character : nil
-        let r = NSMakeRange(Int(character.value), 1)
-        _applyUnmanagedMutation {
-            $0.removeCharacters(in: r)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
-        return result
+        return _storage.remove(character)
     }
     
     /// Test for membership of a particular `UnicodeScalar` in the `CharacterSet`.
     public func contains(_ member: UnicodeScalar) -> Bool {
-        return _mapUnmanaged { $0.longCharacterIsMember(member.value) }
+        return _storage.contains(member)
     }
     
     /// Returns a union of the `CharacterSet` with another `CharacterSet`.
     public func union(_ other: CharacterSet) -> CharacterSet {
-        // The underlying collection does not have a method to return new CharacterSets with changes applied, so we will copy and apply here
-        var result = self
-        result.formUnion(other)
-        return result
+        return _storage.union(other._storage)
     }
     
     /// Sets the value to a union of the `CharacterSet` with another `CharacterSet`.
     public mutating func formUnion(_ other: CharacterSet) {
-        _applyUnmanagedMutation { $0.formUnion(with: other) }
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
+        }
+        _storage.formUnion(other._storage)
     }
     
     /// Returns an intersection of the `CharacterSet` with another `CharacterSet`.
     public func intersection(_ other: CharacterSet) -> CharacterSet {
-        // The underlying collection does not have a method to return new CharacterSets with changes applied, so we will copy and apply here
-        var result = self
-        result.formIntersection(other)
-        return result
+        return _storage.intersection(other._storage)
     }
     
     /// Sets the value to an intersection of the `CharacterSet` with another `CharacterSet`.
     public mutating func formIntersection(_ other: CharacterSet) {
-        _applyUnmanagedMutation {
-            $0.formIntersection(with: other)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
         }
+        _storage.formIntersection(other._storage)
     }
 
     /// Returns a `CharacterSet` created by removing elements in `other` from `self`.
     public func subtracting(_ other: CharacterSet) -> CharacterSet {
-        return intersection(other.inverted)
+        return _storage.subtracting(other._storage)
     }
 
     /// Sets the value to a `CharacterSet` created by removing elements in `other` from `self`.
     public mutating func subtract(_ other: CharacterSet) {
-        self = subtracting(other)
+        if !isKnownUniquelyReferenced(&_storage) {
+            _storage = _storage.mutableCopy()
+        }
+        _storage.subtract(other._storage)
     }
 
     /// Returns an exclusive or of the `CharacterSet` with another `CharacterSet`.
     public func symmetricDifference(_ other: CharacterSet) -> CharacterSet {
-        return union(other).subtracting(intersection(other))
+        return _storage.symmetricDifference(other._storage)
     }
     
     /// Sets the value to an exclusive or of the `CharacterSet` with another `CharacterSet`.
@@ -436,12 +721,18 @@
     
     /// Returns true if `self` is a superset of `other`.
     public func isSuperset(of other: CharacterSet) -> Bool {
-        return _mapUnmanaged { $0.isSuperset(of: other) }
+        return _storage.isSuperset(of: other._storage)
+    }
+
+    // MARK: -
+    
+    public var hashValue: Int {
+        return _storage.hashValue
     }
 
     /// Returns true if the two `CharacterSet`s are equal.
     public static func ==(lhs : CharacterSet, rhs: CharacterSet) -> Bool {
-        return lhs._wrapped.isEqual(rhs as NSCharacterSet)
+        return lhs._storage == rhs._storage
     }
 }
 
@@ -454,7 +745,7 @@
     
     @_semantics("convertToObjectiveC")
     public func _bridgeToObjectiveC() -> NSCharacterSet {
-        return unsafeBitCast(_wrapped, to: NSCharacterSet.self)
+        return _storage.bridgedReference()
     }
     
     public static func _forceBridgeFromObjectiveC(_ input: NSCharacterSet, result: inout CharacterSet?) {
@@ -474,11 +765,11 @@
 
 extension CharacterSet : CustomStringConvertible, CustomDebugStringConvertible {
     public var description: String {
-        return _mapUnmanaged { $0.description }
+        return _storage.description
     }
 
     public var debugDescription: String {
-        return _mapUnmanaged { $0.debugDescription }
+        return _storage.debugDescription
     }
 }
 
@@ -490,44 +781,3 @@
     }
 }
 
-extension _SwiftNSCharacterSet {
-    
-    // Stubs
-    // -----
-    
-    // Immutable
-    
-    @objc(bitmapRepresentation)
-    var bitmapRepresentation: Data {
-        return _mapUnmanaged { $0.bitmapRepresentation }
-    }
-    
-    @objc(invertedSet)
-    var inverted : CharacterSet {
-        return _mapUnmanaged { $0.inverted }
-    }
-    
-    @objc(hasMemberInPlane:)
-    func hasMember(inPlane plane: UInt8) -> Bool {
-        return _mapUnmanaged { $0.hasMemberInPlane(plane) }
-    }
-    
-    @objc(characterIsMember:)
-    func characterIsMember(_ member: unichar) -> Bool {
-        return _mapUnmanaged { $0.characterIsMember(member) }
-    }
-    
-    @objc(longCharacterIsMember:)
-    func longCharacterIsMember(_ member: UTF32Char) -> Bool {
-        return _mapUnmanaged { $0.longCharacterIsMember(member) }
-    }
-    
-    @objc(isSupersetOfSet:)
-    func isSuperset(of other: CharacterSet) -> Bool {
-        return _mapUnmanaged {
-            // this is a work around for <rdar://problem/27768939>
-            return CFCharacterSetIsSupersetOfSet($0 as CFCharacterSet, (other as NSCharacterSet).copy() as! CFCharacterSet)
-        }
-    }
-    
-}
diff --git a/stdlib/public/SDK/Foundation/Data.swift b/stdlib/public/SDK/Foundation/Data.swift
index 49636cb..32815d9 100644
--- a/stdlib/public/SDK/Foundation/Data.swift
+++ b/stdlib/public/SDK/Foundation/Data.swift
@@ -350,11 +350,11 @@
     
     // fast-path for appending directly from another data storage
     @inline(__always)
-    public func append(_ otherData: _DataStorage) {
+    public func append(_ otherData: _DataStorage, startingAt start: Int) {
         let otherLength = otherData.length
         if otherLength == 0 { return }
         if let bytes = otherData.bytes {
-            append(bytes, length: otherLength)
+            append(bytes.advanced(by: start), length: otherLength)
         }
     }
     
@@ -1089,7 +1089,7 @@
     /// - warning: The byte pointer argument should not be stored and used outside of the lifetime of the call to the closure.
     @inline(__always)
     public func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType {
-        let bytes =  _backing.bytes ?? UnsafeRawPointer(bitPattern: 0xBAD0)!
+        let bytes =  _backing.bytes?.advanced(by: _sliceRange.lowerBound) ?? UnsafeRawPointer(bitPattern: 0xBAD0)!
         let contentPtr = bytes.bindMemory(to: ContentType.self, capacity: count / MemoryLayout<ContentType>.stride)
         return try body(contentPtr)
     }
@@ -1104,7 +1104,7 @@
         if !isKnownUniquelyReferenced(&_backing) {
             _backing = _backing.mutableCopy(_sliceRange)
         }
-        let mutableBytes = _backing.mutableBytes ?? UnsafeMutableRawPointer(bitPattern: 0xBAD0)!
+        let mutableBytes = _backing.mutableBytes?.advanced(by: _sliceRange.lowerBound) ?? UnsafeMutableRawPointer(bitPattern: 0xBAD0)!
         let contentPtr = mutableBytes.bindMemory(to: ContentType.self, capacity: count / MemoryLayout<ContentType>.stride)
         return try body(UnsafeMutablePointer(contentPtr))
     }
@@ -1126,7 +1126,7 @@
     @inline(__always)
     private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: NSRange) {
         if range.length == 0 { return }
-        memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: range.location + _sliceRange.lowerBound), range.length)
+        memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: range.location), range.length)
     }
     
     /// Copy a subset of the contents of the data to a pointer.
@@ -1256,7 +1256,7 @@
         if !isKnownUniquelyReferenced(&_backing) {
             _backing = _backing.mutableCopy(_sliceRange)
         }
-        _backing.append(other._backing)
+        _backing.append(other._backing, startingAt: other._sliceRange.lowerBound)
         _sliceRange = _sliceRange.lowerBound..<(_sliceRange.upperBound + other.count)
     }
     
@@ -1274,15 +1274,6 @@
     }
     
     @inline(__always)
-    public mutating func append(_ other: MutableRangeReplaceableRandomAccessSlice<Data>) {
-        let count = other.count
-        if count == 0 { return }
-        other.base.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
-            append(bytes, count: count)
-        }
-    }
-    
-    @inline(__always)
     public mutating func append<S : Sequence>(contentsOf newElements: S) where S.Iterator.Element == Iterator.Element {
         let estimatedCount = newElements.underestimatedCount
         var idx = count
@@ -1337,12 +1328,27 @@
         if !isKnownUniquelyReferenced(&_backing) {
             _backing = _backing.mutableCopy(_sliceRange)
         }
-        data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
+        let resultingLength = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Int in
             let currentLength = _backing.length
             _backing.replaceBytes(in: nsRange, with: bytes, length: cnt)
-            let resultingLength = currentLength - nsRange.length + cnt
-            _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
+            return currentLength - nsRange.length + cnt
         }
+        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
+    }
+    
+    @inline(__always)
+    public mutating func replaceSubrange(_ subrange: CountableRange<Index>, with data: Data) {
+        let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
+        let cnt = data.count
+        if !isKnownUniquelyReferenced(&_backing) {
+            _backing = _backing.mutableCopy(_sliceRange)
+        }
+        let resultingLength = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Int in
+            let currentLength = _backing.length
+            _backing.replaceBytes(in: nsRange, with: bytes, length: cnt)
+            return currentLength - nsRange.length + cnt
+        }
+        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
     }
     
     /// Replace a region of bytes in the data with new bytes from a buffer.
@@ -1489,9 +1495,7 @@
     public subscript(index: Index) -> UInt8 {
         @inline(__always)
         get {
-            return withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UInt8 in
-                return bytes.advanced(by: index).pointee
-            }
+            return _backing.bytes!.advanced(by: _sliceRange.lowerBound + index).assumingMemoryBound(to: UInt8.self).pointee
         }
         @inline(__always)
         set {
@@ -1513,6 +1517,39 @@
         }
     }
     
+    public subscript(bounds: CountableRange<Index>) -> Data {
+        @inline(__always)
+        get {
+            return Data(backing: _backing, range: bounds.lowerBound..<bounds.upperBound)
+        }
+        @inline(__always)
+        set {
+            replaceSubrange(bounds, with: newValue)
+        }
+    }
+    
+    public subscript(bounds: ClosedRange<Index>) -> Data {
+        @inline(__always)
+        get {
+            return Data(backing: _backing, range: bounds.lowerBound..<bounds.upperBound)
+        }
+        @inline(__always)
+        set {
+            replaceSubrange(bounds.lowerBound..<bounds.upperBound, with: newValue)
+        }
+    }
+    
+    public subscript(bounds: CountableClosedRange<Index>) -> Data {
+        @inline(__always)
+        get {
+            return Data(backing: _backing, range: bounds.lowerBound..<bounds.upperBound)
+        }
+        @inline(__always)
+        set {
+            replaceSubrange(bounds.lowerBound..<bounds.upperBound, with: newValue)
+        }
+    }
+    
     
     /// The start `Index` in the data.
     public var startIndex: Index {
diff --git a/stdlib/public/SDK/Foundation/FileManager.swift b/stdlib/public/SDK/Foundation/FileManager.swift
index e34d4f2..2eef296 100644
--- a/stdlib/public/SDK/Foundation/FileManager.swift
+++ b/stdlib/public/SDK/Foundation/FileManager.swift
@@ -43,6 +43,7 @@
     }
 
     @available(OSX 10.6, iOS 4.0, *)
+    @nonobjc
     public func enumerator(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = [], errorHandler handler: ((URL, Error) -> Bool)? = nil) -> FileManager.DirectoryEnumerator? {
         return __NSFileManagerEnumeratorAtURL(self, url, keys, mask, { (url, error) in
             var errorResult = true
diff --git a/stdlib/public/SDK/Foundation/IndexSet.swift b/stdlib/public/SDK/Foundation/IndexSet.swift
index 6ceed0f..f74d88e 100644
--- a/stdlib/public/SDK/Foundation/IndexSet.swift
+++ b/stdlib/public/SDK/Foundation/IndexSet.swift
@@ -41,52 +41,6 @@
     }
 }
 
-// We currently cannot use this mechanism because NSIndexSet is not abstract; it has its own ivars and therefore subclassing it using the same trick as NSData, etc. does not work.
-
-/*
-private final class _SwiftNSIndexSet : _SwiftNativeNSIndexSet, _SwiftNativeFoundationType {
-    public typealias ImmutableType = NSIndexSet
-    public typealias MutableType = NSMutableIndexSet
-
-    var __wrapped : _MutableUnmanagedWrapper<ImmutableType, MutableType>
-
-    init(immutableObject: AnyObject) {
-      // Take ownership.
-      __wrapped = .Immutable(
-        Unmanaged.passRetained(
-          _unsafeReferenceCast(immutableObject, to: ImmutableType.self)))
-
-      super.init()
-    }
-
-    init(mutableObject: AnyObject) {
-      // Take ownership.
-      __wrapped = .Mutable(
-       Unmanaged.passRetained(
-         _unsafeReferenceCast(mutableObject, to: MutableType.self)))
-      super.init()
-    }
-
-    public required init(unmanagedImmutableObject: Unmanaged<ImmutableType>) {
-      // Take ownership.
-      __wrapped = .Immutable(unmanagedImmutableObject)
-
-      super.init()
-    }
-
-    public required init(unmanagedMutableObject: Unmanaged<MutableType>) {
-      // Take ownership.
-      __wrapped = .Mutable(unmanagedMutableObject)
-
-      super.init()
-    }
-
-    deinit {
-      releaseWrappedObject()
-    }
-}
-*/
-
 /// Manages a `Set` of integer values, which are commonly used as an index type in Cocoa API.
 ///
 /// The range of valid integer values is 0..<INT_MAX-1. Anything outside this range is an error.
diff --git a/stdlib/public/SDK/Foundation/NSDate.swift b/stdlib/public/SDK/Foundation/NSDate.swift
index d1f776f..a69ef73 100644
--- a/stdlib/public/SDK/Foundation/NSDate.swift
+++ b/stdlib/public/SDK/Foundation/NSDate.swift
@@ -13,6 +13,7 @@
 @_exported import Foundation // Clang module
 
 extension NSDate : CustomPlaygroundQuickLookable {
+  @nonobjc
   var summary: String {
     let df = DateFormatter()
     df.dateStyle = .medium
diff --git a/stdlib/public/SDK/Foundation/NSError.swift b/stdlib/public/SDK/Foundation/NSError.swift
index 7f6dbc9..a4c091b 100644
--- a/stdlib/public/SDK/Foundation/NSError.swift
+++ b/stdlib/public/SDK/Foundation/NSError.swift
@@ -303,11 +303,17 @@
 // or CFError is used as an Error existential.
 
 extension NSError : Error {
+  @nonobjc
   public var _domain: String { return domain }
+
+  @nonobjc
   public var _code: Int { return code }
+
+  @nonobjc
   public var _userInfo: AnyObject? { return userInfo as NSDictionary }
 
   /// The "embedded" NSError is itself.
+  @nonobjc
   public func _getEmbeddedNSError() -> AnyObject? {
     return self
   }
diff --git a/stdlib/public/SDK/Foundation/NSNumber.swift.gyb b/stdlib/public/SDK/Foundation/NSNumber.swift.gyb
index 036b3c0..1354430 100644
--- a/stdlib/public/SDK/Foundation/NSNumber.swift.gyb
+++ b/stdlib/public/SDK/Foundation/NSNumber.swift.gyb
@@ -281,16 +281,19 @@
     ExpressibleByBooleanLiteral
 {
   /// Create an instance initialized to `value`.
+  @nonobjc
   public required convenience init(integerLiteral value: Int) {
     self.init(value: value)
   }
 
   /// Create an instance initialized to `value`.
+  @nonobjc
   public required convenience init(floatLiteral value: Double) {
     self.init(value: value)
   }
 
   /// Create an instance initialized to `value`.
+  @nonobjc
   public required convenience init(booleanLiteral value: Bool) {
     self.init(value: value)
   }
diff --git a/stdlib/public/SDK/Foundation/NSStringAPI.swift b/stdlib/public/SDK/Foundation/NSStringAPI.swift
index 1131be1..6186046 100644
--- a/stdlib/public/SDK/Foundation/NSStringAPI.swift
+++ b/stdlib/public/SDK/Foundation/NSStringAPI.swift
@@ -14,6 +14,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+@_exported import Foundation // Clang module
+
 // Open Issues
 // ===========
 //
@@ -391,11 +393,7 @@
   /// Returns an array containing substrings from the `String`
   /// that have been divided by characters in a given set.
   public func components(separatedBy separator: CharacterSet) -> [String] {
-    // FIXME: two steps due to <rdar://16971181>
-    let nsa = _ns.components(separatedBy: separator) as NSArray
-    // Since this function is effectively a bridge thunk, use the
-    // bridge thunk semantics for the NSArray conversion
-    return nsa as! [String]
+    return _ns.components(separatedBy: separator)
   }
 
 
@@ -404,10 +402,7 @@
   /// Returns an array containing substrings from the `String`
   /// that have been divided by a given separator.
   public func components(separatedBy separator: String) -> [String] {
-    let nsa = _ns.components(separatedBy: separator) as NSArray
-    // Since this function is effectively a bridge thunk, use the
-    // bridge thunk semantics for the NSArray conversion
-    return nsa as! [String]
+    return _ns.components(separatedBy: separator)
   }
 
   // - (const char *)cStringUsingEncoding:(NSStringEncoding)encoding
diff --git a/stdlib/public/SDK/ObjectiveC/CMakeLists.txt b/stdlib/public/SDK/ObjectiveC/CMakeLists.txt
index 847ad34..acd74eb 100644
--- a/stdlib/public/SDK/ObjectiveC/CMakeLists.txt
+++ b/stdlib/public/SDK/ObjectiveC/CMakeLists.txt
@@ -4,7 +4,8 @@
 add_swift_library(swiftObjectiveC ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
   ObjectiveC.swift
 
-  SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
+  SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}" "-Xfrontend"
+                      "-disable-objc-attr-requires-foundation-module"
   LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
 
   SWIFT_MODULE_DEPENDS_OSX Darwin # auto-updated
diff --git a/stdlib/public/SDK/ObjectiveC/ObjectiveC.swift b/stdlib/public/SDK/ObjectiveC/ObjectiveC.swift
index a5110d9..782efc3 100644
--- a/stdlib/public/SDK/ObjectiveC/ObjectiveC.swift
+++ b/stdlib/public/SDK/ObjectiveC/ObjectiveC.swift
@@ -220,6 +220,7 @@
   /// - Note: the hash value is not guaranteed to be stable across
   ///   different invocations of the same program.  Do not persist the
   ///   hash value across program runs.
+  @objc
   open var hashValue: Int {
     return hash
   }
diff --git a/stdlib/public/SDK/SceneKit/CMakeLists.txt b/stdlib/public/SDK/SceneKit/CMakeLists.txt
index 63633bb..704215d 100644
--- a/stdlib/public/SDK/SceneKit/CMakeLists.txt
+++ b/stdlib/public/SDK/SceneKit/CMakeLists.txt
@@ -6,7 +6,7 @@
 
   SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
   LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
-  TARGET_SDKS ALL_APPLE_PLATFORMS
+  TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR WATCHOS WATCHOS_SIMULATOR
   SWIFT_MODULE_DEPENDS_OSX Darwin AppKit CoreData CoreGraphics CoreImage Dispatch Foundation GLKit IOKit ObjectiveC QuartzCore simd XPC # auto-updated
   SWIFT_MODULE_DEPENDS_IOS Darwin CoreGraphics CoreImage Dispatch Foundation GLKit ObjectiveC QuartzCore simd UIKit # auto-updated
   SWIFT_MODULE_DEPENDS_TVOS Darwin CoreGraphics CoreImage Dispatch Foundation GLKit ObjectiveC QuartzCore simd UIKit # auto-updated
diff --git a/stdlib/public/SDK/SceneKit/SceneKit.swift.gyb b/stdlib/public/SDK/SceneKit/SceneKit.swift.gyb
index 2b34bba..dcdc888 100644
--- a/stdlib/public/SDK/SceneKit/SceneKit.swift.gyb
+++ b/stdlib/public/SDK/SceneKit/SceneKit.swift.gyb
@@ -187,12 +187,15 @@
 @available(iOS, introduced: 8.0)
 @available(OSX, introduced: 10.8)
 extension SCNGeometrySource {
+  @nonobjc
   public convenience init(vertices: [SCNVector3]) {
     self.init(vertices: UnsafePointer(vertices), count: vertices.count)
   }
+  @nonobjc
   public convenience init(normals: [SCNVector3]) {
     self.init(normals: UnsafePointer(normals), count: normals.count)
   }
+  @nonobjc
   public convenience init(textureCoordinates: [CGPoint]) {
     self.init(textureCoordinates: UnsafePointer(textureCoordinates), count: textureCoordinates.count)
   }
diff --git a/stdlib/public/SDK/SpriteKit/CMakeLists.txt b/stdlib/public/SDK/SpriteKit/CMakeLists.txt
index 8174db7..b2d2556 100644
--- a/stdlib/public/SDK/SpriteKit/CMakeLists.txt
+++ b/stdlib/public/SDK/SpriteKit/CMakeLists.txt
@@ -7,7 +7,7 @@
 
   SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
   LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
-  TARGET_SDKS ALL_APPLE_PLATFORMS
+  TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR WATCHOS WATCHOS_SIMULATOR
   SWIFT_MODULE_DEPENDS_OSX Darwin AppKit CoreData CoreGraphics CoreImage Dispatch Foundation GLKit IOKit ObjectiveC QuartzCore simd XPC # auto-updated
   SWIFT_MODULE_DEPENDS_IOS Darwin CoreGraphics CoreImage Dispatch Foundation GLKit ObjectiveC QuartzCore simd UIKit # auto-updated
   SWIFT_MODULE_DEPENDS_TVOS Darwin CoreGraphics CoreImage Dispatch Foundation GLKit ObjectiveC QuartzCore simd UIKit # auto-updated
diff --git a/stdlib/public/SwiftShims/CFCharacterSetShims.h b/stdlib/public/SwiftShims/CFCharacterSetShims.h
new file mode 100644
index 0000000..293b6e0
--- /dev/null
+++ b/stdlib/public/SwiftShims/CFCharacterSetShims.h
@@ -0,0 +1,26 @@
+//===--- CFCharacterSetShims.h - CoreFoundation declarations for CF hashing functions ------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+CF_IMPLICIT_BRIDGING_ENABLED
+CF_EXTERN_C_BEGIN
+_Pragma("clang assume_nonnull begin")
+
+CF_EXPORT CFCharacterSetRef _CFURLComponentsGetURLUserAllowedCharacterSet();
+CF_EXPORT CFCharacterSetRef _CFURLComponentsGetURLPasswordAllowedCharacterSet();
+CF_EXPORT CFCharacterSetRef _CFURLComponentsGetURLHostAllowedCharacterSet();
+CF_EXPORT CFCharacterSetRef _CFURLComponentsGetURLPathAllowedCharacterSet();
+CF_EXPORT CFCharacterSetRef _CFURLComponentsGetURLQueryAllowedCharacterSet();
+CF_EXPORT CFCharacterSetRef _CFURLComponentsGetURLFragmentAllowedCharacterSet();
+
+_Pragma("clang assume_nonnull end")
+CF_EXTERN_C_END
+CF_IMPLICIT_BRIDGING_DISABLED
diff --git a/stdlib/public/SwiftShims/CFHashingShims.h b/stdlib/public/SwiftShims/CFHashingShims.h
new file mode 100644
index 0000000..7083aef
--- /dev/null
+++ b/stdlib/public/SwiftShims/CFHashingShims.h
@@ -0,0 +1,41 @@
+//===--- CFHashingShims.h - CoreFoundation declarations for CF hashing functions ------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+CF_IMPLICIT_BRIDGING_ENABLED
+CF_EXTERN_C_BEGIN
+_Pragma("clang assume_nonnull begin")
+
+
+#define _CF_HASHFACTOR 2654435761U
+
+CF_INLINE CFHashCode __CFHashInt(long i) {
+    return ((i > 0) ? (CFHashCode)(i) : (CFHashCode)(-i)) * _CF_HASHFACTOR;
+}
+
+CF_INLINE CFHashCode __CFHashDouble(double d) {
+    double dInt;
+    if (d < 0) d = -d;
+    dInt = floor(d+0.5);
+    CFHashCode integralHash = _CF_HASHFACTOR * (CFHashCode)fmod(dInt, (double)ULONG_MAX);
+    return (CFHashCode)(integralHash + (CFHashCode)((d - dInt) * ULONG_MAX));
+}
+
+CF_EXPORT CFHashCode CFHashBytes(uint8_t *_Nullable bytes, long len);
+
+
+CF_INLINE CFHashCode __CFHashBytes(uint8_t *_Nullable bytes, long len) {
+    return CFHashBytes(bytes, len);
+}
+
+_Pragma("clang assume_nonnull end")
+CF_EXTERN_C_END
+CF_IMPLICIT_BRIDGING_DISABLED
diff --git a/stdlib/public/SwiftShims/CMakeLists.txt b/stdlib/public/SwiftShims/CMakeLists.txt
index 0056473..717ea6f 100644
--- a/stdlib/public/SwiftShims/CMakeLists.txt
+++ b/stdlib/public/SwiftShims/CMakeLists.txt
@@ -22,6 +22,8 @@
   XPCOverlayShims.h
 
   CoreFoundationOverlayShims.h
+  CFCharacterSetShims.h
+  CFHashingShims.h
 
   FoundationOverlayShims.h
   FoundationShimSupport.h
diff --git a/stdlib/public/SwiftShims/CoreFoundationOverlayShims.h b/stdlib/public/SwiftShims/CoreFoundationOverlayShims.h
index 71bd578..ee1ed60 100644
--- a/stdlib/public/SwiftShims/CoreFoundationOverlayShims.h
+++ b/stdlib/public/SwiftShims/CoreFoundationOverlayShims.h
@@ -1,4 +1,4 @@
-//===------------------------------------------------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -17,32 +17,5 @@
 /// calling convention, availability or any other facet of facilities offered in this file. If you use
 /// anything from here and your app breaks, expect any bug to be marked as "behaves correctly".
 
-CF_IMPLICIT_BRIDGING_ENABLED
-CF_EXTERN_C_BEGIN
-_Pragma("clang assume_nonnull begin")
-
-
-#define _CF_HASHFACTOR 2654435761U
-
-CF_INLINE CFHashCode __CFHashInt(long i) {
-    return ((i > 0) ? (CFHashCode)(i) : (CFHashCode)(-i)) * _CF_HASHFACTOR;
-}
-
-CF_INLINE CFHashCode __CFHashDouble(double d) {
-    double dInt;
-    if (d < 0) d = -d;
-    dInt = floor(d+0.5);
-    CFHashCode integralHash = _CF_HASHFACTOR * (CFHashCode)fmod(dInt, (double)ULONG_MAX);
-    return (CFHashCode)(integralHash + (CFHashCode)((d - dInt) * ULONG_MAX));
-}
-
-CF_EXPORT CFHashCode CFHashBytes(uint8_t *_Nullable bytes, long len);
-
-
-CF_INLINE CFHashCode __CFHashBytes(uint8_t *_Nullable bytes, long len) {
-    return CFHashBytes(bytes, len);
-}
-
-_Pragma("clang assume_nonnull end")
-CF_EXTERN_C_END
-CF_IMPLICIT_BRIDGING_DISABLED
+#import "CFCharacterSetShims.h"
+#import "CFHashingShims.h"
diff --git a/stdlib/public/core/Arrays.swift.gyb b/stdlib/public/core/Arrays.swift.gyb
index 5ea4f50..4adcefa 100644
--- a/stdlib/public/core/Arrays.swift.gyb
+++ b/stdlib/public/core/Arrays.swift.gyb
@@ -1411,6 +1411,7 @@
   ///   bridged `NSArray` instance as its storage, the efficiency is
   ///   unspecified.
   @_inlineable
+  @_semantics("array.append_element")
   public mutating func append(_ newElement: Element) {
     _makeUniqueAndReserveCapacityIfNotUnique()
     let oldCount = _getCount()
@@ -1433,6 +1434,7 @@
   ///
   /// - Complexity: O(*n*), where *n* is the length of the resulting array.
   @_inlineable
+  @_semantics("array.append_contentsOf")
   public mutating func append<S : Sequence>(contentsOf newElements: S)
     where S.Iterator.Element == Element {
 
diff --git a/stdlib/public/core/ContiguousArrayBuffer.swift b/stdlib/public/core/ContiguousArrayBuffer.swift
index a7e19bf..daa8f0f 100644
--- a/stdlib/public/core/ContiguousArrayBuffer.swift
+++ b/stdlib/public/core/ContiguousArrayBuffer.swift
@@ -25,6 +25,7 @@
 
   @_inlineable
   @_versioned
+  @nonobjc
   init(_doNotCallMe: ()) {
     _sanityCheckFailure("creating instance of _EmptyArrayStorage")
   }
@@ -40,6 +41,7 @@
 
   @_inlineable
   @_versioned
+  @nonobjc
   override func _getNonVerbatimBridgedCount() -> Int {
     return 0
   }
@@ -121,6 +123,7 @@
   /// - Precondition: `Element` is bridged non-verbatim.
   @_inlineable
   @_versioned
+  @nonobjc
   override internal func _getNonVerbatimBridgedCount() -> Int {
     _sanityCheck(
       !_isBridgedVerbatimToObjectiveC(Element.self),
diff --git a/stdlib/public/core/Hashable.swift b/stdlib/public/core/Hashable.swift
index 918b8c4..7dac092 100644
--- a/stdlib/public/core/Hashable.swift
+++ b/stdlib/public/core/Hashable.swift
@@ -56,7 +56,7 @@
 ///
 ///     extension GridPoint: Hashable {
 ///         var hashValue: Int {
-///             return x.hashValue ^ y.hashValue
+///             return x.hashValue ^ y.hashValue &* 16777619
 ///         }
 ///
 ///         static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
@@ -64,12 +64,16 @@
 ///         }
 ///     }
 ///
-/// The `hashValue` property in this example combines the hash values of a grid
-/// point's `x` and `y` values using the bitwise XOR operator (`^`). The `^`
-/// operator is one way to combine two integer values into a single value.
+/// The `hashValue` property in this example combines the hash value of a grid
+/// point's `x` property with the hash value of its `y` property multiplied by
+/// a prime constant.
 ///
-/// - Note: Set and dictionary performance depends on hash values that minimize
-///   collisions for their associated element and key types, respectively.
+/// - Note: The example given above is a reasonably good hash function for a
+///   simple type. If you're writing a hash function for a custom type, choose
+///   a hashing algorithm that is appropriate for kinds of data your type
+///   comprises. Set and dictionary performance depends on hash values that
+///   minimize collisions for their associated element and key types,
+///   respectively.
 ///
 /// Now that `GridPoint` conforms to the `Hashable` protocol, you can create a
 /// set of previously tapped grid points.
diff --git a/stdlib/public/core/HashedCollections.swift.gyb b/stdlib/public/core/HashedCollections.swift.gyb
index 703535f..313426e 100644
--- a/stdlib/public/core/HashedCollections.swift.gyb
+++ b/stdlib/public/core/HashedCollections.swift.gyb
@@ -2495,17 +2495,23 @@
   _SwiftNativeNS${Self}, _NS${Self}Core
 {
   internal typealias RawStorage = _RawNative${Self}Storage
-  
+
+  @nonobjc
   internal final var capacity: Int
+
   internal final var count: Int
 
   internal final var initializedEntries: _UnsafeBitMap
+
+  @nonobjc
   internal final var keys: UnsafeMutableRawPointer
 % if Self == 'Dictionary':
+  @nonobjc
   internal final var values: UnsafeMutableRawPointer
 % end
 
   // This API is unsafe and needs a `_fixLifetime` in the caller.
+  @nonobjc
   internal final
   var _initializedHashtableEntriesBitMapBuffer: UnsafeMutablePointer<UInt> {
     return UnsafeMutablePointer(Builtin.projectTailElems(self, UInt.self))
@@ -2514,6 +2520,7 @@
   /// The empty singleton that is used for every single Dictionary that is
   /// created without any elements. The contents of the storage should never
   /// be mutated.
+  @nonobjc
   internal static var empty: RawStorage {
     return Builtin.bridgeFromRawPointer(
       Builtin.addressof(&_swiftEmpty${Self}Storage))
@@ -2521,6 +2528,7 @@
 
   // This type is made with allocWithTailElems, so no init is ever called.
   // But we still need to have an init to satisfy the compiler.
+  @nonobjc
   internal init(_doNotCallMe: ()) {
     _sanityCheckFailure("Only create this by using the `empty` singleton")
   }
@@ -2533,6 +2541,7 @@
   /// Get the NSEnumerator implementation for self.
   /// _HashableTypedNative${Self}Storage overloads this to give 
   /// _NativeSelfNSEnumerator proper type parameters.
+  @objc
   func enumerator() -> _NSEnumerator {
     return _Native${Self}NSEnumerator<${AnyTypeParameters}>(
         _Native${Self}Buffer(_storage: self))
@@ -2646,6 +2655,7 @@
 
   // This type is made with allocWithTailElems, so no init is ever called.
   // But we still need to have an init to satisfy the compiler.
+  @nonobjc
   override internal init(_doNotCallMe: ()) {
     _sanityCheckFailure("Only create this by calling Buffer's inits")
   }
@@ -2680,6 +2690,7 @@
 
   // This type is made with allocWithTailElems, so no init is ever called.
   // But we still need to have an init to satisfy the compiler.
+  @nonobjc
   override internal init(_doNotCallMe: ()) {
     _sanityCheckFailure("Only create this by calling Buffer's inits'")
   }
@@ -2744,6 +2755,7 @@
     return stored
   }
 
+  @nonobjc
   internal func getObjectFor(_ aKey: AnyObject) -> AnyObject? {
     guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self)
     else { return nil }
@@ -3479,6 +3491,7 @@
   internal typealias Value = Element
 %end
 
+  @nonobjc
   internal init(minimumCapacity: Int = 2) {
     nativeBuffer = NativeBuffer(minimumCapacity: minimumCapacity)
     super.init()
@@ -3493,6 +3506,7 @@
   // operations on it.
   //
   // Do not access this property directly.
+  @nonobjc
   internal var _heapStorageBridged_DoNotUse: AnyObject?
 
   /// The unbridged elements.
@@ -3584,12 +3598,14 @@
 
   /// Returns the pointer to the stored property, which contains bridged
   /// ${Self} elements.
+  @nonobjc
   internal var _heapStorageBridgedPtr: UnsafeMutablePointer<AnyObject?> {
     return _getUnsafePointerToStoredProperties(self).assumingMemoryBound(
       to: Optional<AnyObject>.self)
   }
 
   /// The buffer for bridged ${Self} elements, if present.
+  @nonobjc
   internal var _bridgedStorage:
     BridgedBuffer.RawStorage? {
     get {
@@ -3601,6 +3617,7 @@
   }
 
   /// Attach a buffer for bridged ${Self} elements.
+  @nonobjc
   internal func _initializeHeapStorageBridged(_ newStorage: AnyObject) {
     _stdlib_atomicInitializeARCRef(
       object: _heapStorageBridgedPtr, desired: newStorage)
@@ -3611,6 +3628,7 @@
     return BridgedBuffer(_storage: _bridgedStorage!)
   }
 
+  @nonobjc
   internal func bridgeEverything() {
     if _fastPath(_bridgedStorage != nil) {
       return
@@ -3643,6 +3661,7 @@
 
 %if Self == 'Dictionary':
 
+  @nonobjc
   internal func bridgedAllKeysAndValues(
     _ objects: UnsafeMutablePointer<AnyObject>?,
     _ keys: UnsafeMutablePointer<AnyObject>?
@@ -3693,6 +3712,7 @@
     return nativeBuffer.count
   }
 
+  @nonobjc
   internal func bridgingObjectForKey(_ aKey: AnyObject)
     -> AnyObject? {
     guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self)
@@ -3707,6 +3727,7 @@
     return nil
   }
 
+  @objc
   internal func enumerator() -> _NSEnumerator {
     bridgeEverything()
     return _Native${Self}NSEnumerator<${AnyTypeParameters}>(bridgedBuffer)
diff --git a/stdlib/public/core/Runtime.swift.gyb b/stdlib/public/core/Runtime.swift.gyb
index 1fa8d38..4a097fd 100644
--- a/stdlib/public/core/Runtime.swift.gyb
+++ b/stdlib/public/core/Runtime.swift.gyb
@@ -492,13 +492,7 @@
 // FIXME(ABI)#60 : move into the Foundation overlay and remove 'open'
 @objc @_swift_native_objc_runtime_base(_SwiftNativeNSDataBase)
 open class _SwiftNativeNSData {
-  public init() {}
-}
-
-// FIXME(ABI)#61 : move into the Foundation overlay and remove 'open'
-@objc @_swift_native_objc_runtime_base(_SwiftNativeNSCharacterSetBase)
-open class _SwiftNativeNSCharacterSet {
-  public init() {}
+  @objc public init() {}
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/stdlib/public/core/StringBridge.swift b/stdlib/public/core/StringBridge.swift
index ab5158b..afd3de2 100644
--- a/stdlib/public/core/StringBridge.swift
+++ b/stdlib/public/core/StringBridge.swift
@@ -214,19 +214,22 @@
     super.init()
   }
 
+	@objc
   init(coder aDecoder: AnyObject) {
     _sanityCheckFailure("init(coder:) not implemented for _NSContiguousString")
   }
 
+	@objc
   func length() -> Int {
     return _core.count
   }
 
+	@objc
   func characterAtIndex(_ index: Int) -> UInt16 {
     return _core[index]
   }
 
-  @inline(__always) // Performance: To save on reference count operations.
+  @objc @inline(__always) // Performance: To save on reference count operations.
   func getCharacters(
     _ buffer: UnsafeMutablePointer<UInt16>,
     range aRange: _SwiftNSRange) {
@@ -255,20 +258,20 @@
   //
   // Implement sub-slicing without adding layers of wrapping
   //
-  func substringFromIndex(_ start: Int) -> _NSContiguousString {
+  @objc func substringFromIndex(_ start: Int) -> _NSContiguousString {
     return _NSContiguousString(_core[Int(start)..<Int(_core.count)])
   }
 
-  func substringToIndex(_ end: Int) -> _NSContiguousString {
+  @objc func substringToIndex(_ end: Int) -> _NSContiguousString {
     return _NSContiguousString(_core[0..<Int(end)])
   }
 
-  func substringWithRange(_ aRange: _SwiftNSRange) -> _NSContiguousString {
+  @objc func substringWithRange(_ aRange: _SwiftNSRange) -> _NSContiguousString {
     return _NSContiguousString(
       _core[Int(aRange.location)..<Int(aRange.location + aRange.length)])
   }
 
-  func copy() -> AnyObject {
+  @objc func copy() -> AnyObject {
     // Since this string is immutable we can just return ourselves.
     return self
   }
diff --git a/stdlib/public/core/SwiftNativeNSArray.swift b/stdlib/public/core/SwiftNativeNSArray.swift
index c318c20..1c2c6cd 100644
--- a/stdlib/public/core/SwiftNativeNSArray.swift
+++ b/stdlib/public/core/SwiftNativeNSArray.swift
@@ -148,15 +148,18 @@
   //
   // Do not access this property directly.
   @_versioned
+  @nonobjc
   internal var _heapBufferBridged_DoNotUse: AnyObject?
 
   // When this class is allocated inline, this property can become a
   // computed one.
   @_versioned
+  @nonobjc
   internal let _nativeStorage: _ContiguousArrayStorageBase
 
   @_inlineable
   @_versioned
+  @nonobjc
   internal var _heapBufferBridgedPtr: UnsafeMutablePointer<AnyObject?> {
     return _getUnsafePointerToStoredProperties(self).assumingMemoryBound(
       to: Optional<AnyObject>.self)
@@ -175,6 +178,7 @@
   }
 
   @_versioned
+  @nonobjc
   internal init(_nativeStorage: _ContiguousArrayStorageBase) {
     self._nativeStorage = _nativeStorage
   }
@@ -271,6 +275,7 @@
   @_versioned
   final var countAndCapacity: _ArrayBody
 
+  @nonobjc
   init(_doNotCallMeBase: ()) {
     _sanityCheckFailure("creating instance of _ContiguousArrayStorageBase")
   }
@@ -300,6 +305,7 @@
   }
 
   @_versioned
+  @nonobjc
   internal func _getNonVerbatimBridgedCount() -> Int {
     _sanityCheckFailure(
       "Concrete subclasses must implement _getNonVerbatimBridgedCount")
diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb
index f9d7e3b..418afd7 100644
--- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb
+++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb
@@ -276,6 +276,45 @@
     _end = start.map { $0 + count }
   }
 
+%  if not Mutable:
+  /// Creates a buffer over the same memory as the given buffer slice.
+  ///
+  /// The new buffer will represent the same region of memory as the slice,
+  /// but it's indices will be rebased to zero. Given:
+  ///
+  ///   let slice = buffer[n..<m]
+  ///   let rebased = UnsafeBufferPointer(rebasing: slice)
+  ///
+  /// One may assume `rebased.startIndex == 0` and `rebased[0] == slice[n]`.
+  ///
+  /// - Parameter slice: the raw buffer slice to rebase.
+  @_inlineable
+  public init(rebasing slice: RandomAccessSlice<UnsafeBufferPointer<Element>>) {
+    self.init(start: slice.base.baseAddress! + slice.startIndex,
+      count: slice.count)
+  }
+%  end # !mutable
+
+  /// Creates a buffer over the same memory as the given buffer slice.
+  ///
+  /// The new buffer will represent the same region of memory as the slice,
+  /// but it's indices will be rebased to zero. Given:
+  ///
+  ///   let slice = buffer[n..<m]
+  ///   let rebased = UnsafeBufferPointer(rebasing: slice)
+  ///
+  /// One may assume `rebased.startIndex == 0` and `rebased[0] == slice[n]`.
+  ///
+  /// - Parameter slice: the buffer slice to rebase.
+  @_inlineable
+  public init(
+    rebasing slice:
+    MutableRandomAccessSlice<UnsafeMutableBufferPointer<Element>>
+  ) {
+    self.init(start: slice.base.baseAddress! + slice.startIndex,
+      count: slice.count)
+  }
+
   /// Returns an iterator over the elements of this buffer.
   ///
   /// - Returns: An iterator over the elements of this buffer.
diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
index 6a09383..6b05fd9 100644
--- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
+++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
@@ -23,7 +23,7 @@
 /// uniqueness checks and release mode bounds checks. Bounds checks are always
 /// performed in debug mode.
 ///
-% if mutable:
+%  if mutable:
 /// An `${Self}` instance is a view of the raw bytes in a region of memory.
 /// Each byte in memory is viewed as a `UInt8` value independent of the type
 /// of values held in that memory. Reading from and writing to memory through
@@ -37,7 +37,7 @@
 /// - `load(fromByteOffset:as:)`
 /// - `storeBytes(of:toByteOffset:as:)`
 /// - `copyBytes(from:count:)`
-% else:
+%  else:
 /// An `${Self}` instance is a view of the raw bytes in a region of memory.
 /// Each byte in memory is viewed as a `UInt8` value independent of the type
 /// of values held in that memory. Reading from memory through a raw buffer is
@@ -46,7 +46,7 @@
 /// In addition to its collection interface, an `${Self}` instance also supports
 /// the `load(fromByteOffset:as:)` method provided by `UnsafeRawPointer`,
 /// including bounds checks in debug mode.
-% end
+%  end
 ///
 /// To access the underlying memory through typed operations, the memory must
 /// be bound to a trivial type.
@@ -102,7 +102,7 @@
 
   public typealias Index = Int
   public typealias IndexDistance = Int
-  public typealias SubSequence = ${Self}
+  public typealias SubSequence = ${Mutable}RandomAccessSlice<${Self}>
 
   /// An iterator over the bytes viewed by a raw buffer pointer.
   @_fixed_layout
@@ -353,6 +353,44 @@
   }
 %  end # !mutable
 
+%  if not mutable:
+  /// Creates a raw buffer over the same memory as the given raw buffer slice.
+  ///
+  /// The new raw buffer will represent the same region of memory as the slice,
+  /// but it's indices will be rebased to zero. Given:
+  ///
+  ///   let slice = buffer[n..<m]
+  ///   let rebased = UnsafeRawBufferPointer(rebasing: slice)
+  ///
+  /// One may assume `rebased.startIndex == 0` and `rebased[0] == slice[n]`.
+  ///
+  /// - Parameter slice: the raw buffer slice to rebase.
+  @_inlineable
+  public init(rebasing slice: RandomAccessSlice<UnsafeRawBufferPointer>) {
+    self.init(start: slice.base.baseAddress! + slice.startIndex,
+      count: slice.count)
+  }
+%  end # !mutable
+
+  /// Creates a raw buffer over the same memory as the given raw buffer slice.
+  ///
+  /// The new raw buffer will represent the same region of memory as the slice,
+  /// but it's indices will be rebased to zero. Given:
+  ///
+  ///   let slice = buffer[n..<m]
+  ///   let rebased = UnsafeRawBufferPointer(rebasing: slice)
+  ///
+  /// One may assume `rebased.startIndex == 0` and `rebased[0] == slice[n]`.
+  ///
+  /// - Parameter slice: the raw buffer slice to rebase.
+  @_inlineable
+  public init(
+    rebasing slice: MutableRandomAccessSlice<UnsafeMutableRawBufferPointer>
+  ) {
+    self.init(start: slice.base.baseAddress! + slice.startIndex,
+      count: slice.count)
+  }
+
   /// Always zero, which is the index of the first byte in a
   /// nonempty buffer.
   @_inlineable
@@ -403,13 +441,13 @@
   /// - Parameter bounds: The range of byte offsets to access. The upper and
   ///   lower bounds of the range must be in the range `0...count`.
   @_inlineable
-  public subscript(bounds: Range<Int>) -> Unsafe${Mutable}RawBufferPointer {
+  public subscript(
+    bounds: Range<Int>
+  ) -> ${Mutable}RandomAccessSlice<Unsafe${Mutable}RawBufferPointer> {
     get {
       _debugPrecondition(bounds.lowerBound >= startIndex)
       _debugPrecondition(bounds.upperBound <= endIndex)
-      return Unsafe${Mutable}RawBufferPointer(
-        start: baseAddress.map { $0 + bounds.lowerBound },
-        count: bounds.count)
+      return ${Mutable}RandomAccessSlice(base: self, bounds: bounds)
     }
 %  if mutable:
     nonmutating set {
@@ -419,7 +457,7 @@
 
       if newValue.count > 0 {
         (baseAddress! + bounds.lowerBound).copyBytes(
-          from: newValue.baseAddress!,
+          from: newValue.base.baseAddress! + newValue.startIndex,
           count: newValue.count)
       }
     }
@@ -525,6 +563,26 @@
   }
 }
 
+extension ${Self} {
+  @available(*, unavailable, message:
+    "use 'Unsafe${Mutable}RawBufferPointer(rebasing:)' to convert a slice into a zero-based raw buffer.")
+  public subscript(bounds: Range<Int>) -> ${Self} {
+    get { return ${Self}(start: nil, count: 0) }
+%  if mutable:
+    nonmutating set {}
+%  end # mutable
+  }
+
+%  if mutable:
+  @available(*, unavailable, message:
+    "use 'UnsafeRawBufferPointer(rebasing:)' to convert a slice into a zero-based raw buffer.")
+  public subscript(bounds: Range<Int>) -> UnsafeRawBufferPointer {
+    get { return UnsafeRawBufferPointer(start: nil, count: 0) }
+    nonmutating set {}
+  }
+%  end # mutable
+}
+
 % end # for mutable
 
 /// Invokes the given closure with a mutable buffer pointer covering the raw
diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp
index 6927f28..5f24d8f 100644
--- a/stdlib/public/runtime/Errors.cpp
+++ b/stdlib/public/runtime/Errors.cpp
@@ -264,6 +264,21 @@
   abort();
 }
 
+// Report a warning to system console and stderr.
+void
+swift::warning(uint32_t flags, const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+
+  char *log;
+  swift_vasprintf(&log, format, args);
+
+  reportNow(flags, log);
+
+  free(log);
+}
+
 // Crash when a deleted method is called by accident.
 SWIFT_RUNTIME_EXPORT
 LLVM_ATTRIBUTE_NORETURN
diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm
index 7d2b323..635ab27 100644
--- a/stdlib/public/runtime/SwiftObject.mm
+++ b/stdlib/public/runtime/SwiftObject.mm
@@ -1359,6 +1359,52 @@
   return swift_class_getInstanceExtents(c);
 }
 
+SWIFT_CC(swift)
+SWIFT_RUNTIME_EXPORT
+void swift_objc_swift3ImplicitObjCEntrypoint(id self, SEL selector) {
+  // Figure out how much reporting we want by querying the environment
+  // variable SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT. We have four
+  // levels:
+  //
+  //   0: Don't report anything
+  //   1: Complain about uses of implicit @objc entrypoints.
+  //   2: Complain about uses of implicit @objc entrypoints, with backtraces
+  //      if possible.
+  //   3: Complain about uses of implicit @objc entrypoints, with backtraces
+  //      if possible, then abort().
+  //
+  // The actual reportLevel is stored as the above values +1, so that
+  // 0 indicates we have not yet checked. It's fine to race through here.
+  static int storedReportLevel = 0;
+  if (storedReportLevel == 0) {
+    auto reportLevelStr = getenv("SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT");
+    if (reportLevelStr &&
+        reportLevelStr[0] >= '0' && reportLevelStr[0] <= '3' &&
+        reportLevelStr[1] == 0)
+      storedReportLevel = (reportLevelStr[0] - '0') + 1;
+    else
+      storedReportLevel = 1;
+  }
+
+  int reportLevel = storedReportLevel - 1;
+  if (reportLevel < 1) return;
+
+  // Report the error.
+  uint32_t flags = 0;
+  if (reportLevel >= 2)
+    flags |= 1 << 0; // Backtrace
+  bool isInstanceMethod = !class_isMetaClass(object_getClass(self));
+  void (*reporter)(uint32_t, const char *, ...) =
+    reportLevel > 2 ? swift::fatalError : swift::warning;
+  reporter(
+    flags,
+    "***Swift runtime: entrypoint %c[%s %s] generated by implicit @objc "
+    "inference is deprecated and will be removed in Swift 4\n",
+    isInstanceMethod ? '-' : '+',
+    class_getName([self class]),
+    sel_getName(selector));
+}
+
 #endif
 
 const ClassMetadata *swift::getRootSuperclass() {
diff --git a/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb b/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
index 95a1e73..a252255 100644
--- a/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
+++ b/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
@@ -47,7 +47,7 @@
 
 using namespace swift;
 
-% for Class in ('Array', 'Dictionary', 'Set', 'String', 'Enumerator', 'Data', 'CharacterSet', 'IndexSet'):
+% for Class in ('Array', 'Dictionary', 'Set', 'String', 'Enumerator', 'Data', 'IndexSet'):
 SWIFT_RUNTIME_STDLIB_INTERFACE
 @interface _SwiftNativeNS${Class}Base : NS${Class}
 {
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
index 605dedc..6e51558 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
@@ -1,5 +1,7 @@
 Name: APINotesFrameworkTest
 Classes:
+  - Name: A
+    SwiftObjCMembers: true
   - Name: TestProperties
     Properties:
       - Name: accessorsOnly
@@ -82,6 +84,8 @@
           - Name: accessorsOnlyRenamedRetypedClass
             PropertyKind:    Class
             SwiftImportAsAccessors: true
+      - Name: NewlyGenericSub
+        SwiftImportAsNonGeneric: true
     Protocols:
       - Name: ProtoWithVersionedUnavailableMember
         Methods:
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
index cf454b8..eefdfa3 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
@@ -15,8 +15,13 @@
 -(nonnull id)methodWithA:(nonnull id)a;
 @end
 
+__attribute__((objc_root_class))
+@interface Base
+@end
+
 #endif // __OBJC__
 
+#import <APINotesFrameworkTest/Classes.h>
 #import <APINotesFrameworkTest/ImportAsMember.h>
 #import <APINotesFrameworkTest/Properties.h>
 #import <APINotesFrameworkTest/Protocols.h>
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Classes.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Classes.h
new file mode 100644
index 0000000..6b76fd9
--- /dev/null
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Classes.h
@@ -0,0 +1,9 @@
+#ifdef __OBJC__
+#pragma clang assume_nonnull begin
+
+@interface NewlyGenericSub<Element> : Base
++ (Element)defaultElement;
+@end
+
+#pragma clang assume_nonnull end
+#endif // __OBJC__
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Properties.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Properties.h
index 9d21bde..5aa9464 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Properties.h
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Properties.h
@@ -1,10 +1,6 @@
 #ifdef __OBJC__
 #pragma clang assume_nonnull begin
 
-__attribute__((objc_root_class))
-@interface Base
-@end
-
 @interface TestProperties: Base
 @property (nonatomic, readwrite, retain) id accessorsOnly;
 @property (nonatomic, readwrite, retain, class) id accessorsOnlyForClass;
diff --git a/test/APINotes/basic.swift b/test/APINotes/basic.swift
index 84f25f0..5e894cf 100644
--- a/test/APINotes/basic.swift
+++ b/test/APINotes/basic.swift
@@ -1,7 +1,17 @@
-// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules -F %S/Inputs/custom-frameworks -verify-ignore-unknown
+// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules -F %S/Inputs/custom-frameworks
 import APINotesTest
 import APINotesFrameworkTest
 
+#if _runtime(_ObjC)
+extension A {
+  func implicitlyObjC() { }
+}
+
+func testSelectors(a: AnyObject) {
+  a.implicitlyObjC?()  // okay: would complain without SwiftObjCMembers
+}
+#endif
+
 func testSwiftName() {
   moveTo(x: 0, y: 0, z: 0)
   moveTo(0, 0, 0) // expected-error{{missing argument labels 'x:y:z:' in call}}
@@ -23,9 +33,3 @@
   jumpTo(x: 0, y: 0, z: 0)
   jumpTo(0, 0, 0) // expected-error{{missing argument labels 'x:y:z:' in call}}
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'ANTGlobalValue' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'PointStruct' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'real_t' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'RectStruct' was obsoleted in Swift 3
diff --git a/test/APINotes/versioned-objc.swift b/test/APINotes/versioned-objc.swift
index 4ff367c..5e511f6 100644
--- a/test/APINotes/versioned-objc.swift
+++ b/test/APINotes/versioned-objc.swift
@@ -13,4 +13,14 @@
   func requirement() -> Any? { return nil }
 }
 
+func testNonGeneric() {
+  // CHECK-DIAGS-3:[[@LINE+1]]:{{[0-9]+}}: error: cannot convert value of type 'Any' to specified type 'Int'
+  let _: Int = NewlyGenericSub.defaultElement()
+  // CHECK-DIAGS-4:[[@LINE-1]]:{{[0-9]+}}: error: generic parameter 'Element' could not be inferred
+
+  // CHECK-DIAGS-3:[[@LINE+1]]:{{[0-9]+}}: error: cannot specialize non-generic type 'NewlyGenericSub'
+  let _: Int = NewlyGenericSub<Base>.defaultElement()
+  // CHECK-DIAGS-4:[[@LINE-1]]:{{[0-9]+}}: error: cannot convert value of type 'Base' to specified type 'Int'
+}
+
 let unrelatedDiagnostic: Int = nil
diff --git a/test/APINotes/versioned.swift b/test/APINotes/versioned.swift
index 2acc130..c5c8c30 100644
--- a/test/APINotes/versioned.swift
+++ b/test/APINotes/versioned.swift
@@ -63,5 +63,5 @@
 
   // CHECK-DIAGS-4-NOT: versioned.swift:[[@LINE+1]]:
   _ = Outer.Inner()
-  // CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:7: error: type 'Outer' has no member 'Inner'
+  // CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:13: error: 'Inner' has been renamed to 'InnerInSwift4'
 }
diff --git a/test/ClangImporter/Inputs/MoreSwiftNewtypes_conformances.swift b/test/ClangImporter/Inputs/MoreSwiftNewtypes_conformances.swift
new file mode 100644
index 0000000..9f1263f
--- /dev/null
+++ b/test/ClangImporter/Inputs/MoreSwiftNewtypes_conformances.swift
@@ -0,0 +1,41 @@
+// Helper for newtype_conformance.swift
+
+@_exported import MoreSwiftNewtypes
+import Foundation
+
+extension UnbridgedNonNSObject: Equatable /* but not Hashable */ {
+  public static func ==(lhs: UnbridgedNonNSObject, rhs: UnbridgedNonNSObject) -> Bool { return true }
+}
+
+// Pick something other than "Equatable" to test that we're not just looking at
+// immediately inherited protocols.
+protocol EquatablePlus: Equatable {}
+
+public struct BridgedValue : EquatablePlus /* but not Hashable */ {
+  public static func ==(lhs: BridgedValue, rhs: BridgedValue) -> Bool { return true }
+}
+
+extension BridgedValue: _ObjectiveCBridgeable {
+  public func _bridgeToObjectiveC() -> BridgedNonNSObject {
+    return BridgedNonNSObject()
+  }
+
+  public static func _forceBridgeFromObjectiveC(
+    _ x: BridgedNonNSObject,
+    result: inout BridgedValue?) {
+  }
+
+  public static func _conditionallyBridgeFromObjectiveC(
+    _ x: BridgedNonNSObject,
+    result: inout BridgedValue?
+  ) -> Bool {
+    return true
+  }
+
+  public static func _unconditionallyBridgeFromObjectiveC(_ source: BridgedNonNSObject?)
+      -> BridgedValue {
+    var result: BridgedValue?
+    _forceBridgeFromObjectiveC(source!, result: &result)
+    return result!
+  }
+}
diff --git a/test/ClangImporter/Inputs/MoreSwiftNewtypes_tests.swift b/test/ClangImporter/Inputs/MoreSwiftNewtypes_tests.swift
new file mode 100644
index 0000000..e3dc6d4
--- /dev/null
+++ b/test/ClangImporter/Inputs/MoreSwiftNewtypes_tests.swift
@@ -0,0 +1,24 @@
+// Helper for newtype_conformance.swift
+
+@_exported import MoreSwiftNewtypes
+
+func acceptEquatable<T: Equatable>(_: T) {}
+
+func testEquatable(wrappedRef: WrappedRef, wrappedValue: WrappedValue) {
+  acceptEquatable(wrappedRef)
+  acceptEquatable(wrappedValue)
+}
+
+
+func intIfNonHashable<T>(_: T) -> Int { return 0 }
+func intIfNonHashable<T: Hashable>(_: T) -> Bool { return false }
+
+func testNotHashable(wrappedRef: WrappedRef, wrappedValue: WrappedValue) {
+  let refResult = intIfNonHashable(wrappedRef)
+  let _: Int = refResult
+  let valueResult = intIfNonHashable(wrappedValue)
+  let _: Int = valueResult
+
+  let baselineResult = intIfNonHashable(0)
+  let _: Bool = baselineResult
+}
diff --git a/test/ClangImporter/Inputs/custom-modules/MoreSwiftNewtypes.h b/test/ClangImporter/Inputs/custom-modules/MoreSwiftNewtypes.h
new file mode 100644
index 0000000..70dc731
--- /dev/null
+++ b/test/ClangImporter/Inputs/custom-modules/MoreSwiftNewtypes.h
@@ -0,0 +1,16 @@
+@import Foundation;
+
+__attribute__((objc_root_class))
+@interface Base
+- (instancetype)init;
+@end
+
+@interface UnbridgedNonNSObject : Base
+@end
+
+__attribute__((swift_bridge("BridgedValue")))
+@interface BridgedNonNSObject : Base
+@end
+
+typedef UnbridgedNonNSObject *WrappedRef __attribute__((swift_wrapper(struct)));
+typedef BridgedNonNSObject *WrappedValue __attribute__((swift_wrapper(struct)));
diff --git a/test/ClangImporter/Inputs/custom-modules/ObjCParseExtras.h b/test/ClangImporter/Inputs/custom-modules/ObjCParseExtras.h
index f4cdbe4..1ab243a 100644
--- a/test/ClangImporter/Inputs/custom-modules/ObjCParseExtras.h
+++ b/test/ClangImporter/Inputs/custom-modules/ObjCParseExtras.h
@@ -26,6 +26,20 @@
 + (void)classRef:(id)obj doSomething:(SEL)selector;
 @end
 
+@interface PropertyAndMethodCollisionInOneClass
+- (void)object;
++ (void)classRef;
+@property (getter=getObject) id object;
+@property (class,getter=getClassRef) id classRef;
+@end
+
+@interface PropertyAndMethodReverseCollisionInOneClass
+@property (getter=getObject) id object;
+@property (class,getter=getClassRef) id classRef;
+- (void)object;
++ (void)classRef;
+@end
+
 @protocol PropertyProto
 @property id protoProp;
 @property(readonly) id protoPropRO;
diff --git a/test/ClangImporter/Inputs/custom-modules/module.map b/test/ClangImporter/Inputs/custom-modules/module.map
index f1a16a5..dc18119 100644
--- a/test/ClangImporter/Inputs/custom-modules/module.map
+++ b/test/ClangImporter/Inputs/custom-modules/module.map
@@ -69,6 +69,10 @@
   header "this-header-does-not-exist.h"
 }
 
+module MoreSwiftNewtypes {
+  header "MoreSwiftNewtypes.h"
+}
+
 module Newtype {
   header "Newtype.h"
 }
diff --git a/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/Headers/PrivatelyReadwrite.h b/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/Headers/PrivatelyReadwrite.h
new file mode 100644
index 0000000..261bba6
--- /dev/null
+++ b/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/Headers/PrivatelyReadwrite.h
@@ -0,0 +1,55 @@
+__attribute__((objc_root_class))
+@interface Base
+- (nonnull instancetype)init;
+@end
+
+@interface GenericClass<T>: Base
+@end
+
+@interface PropertiesInit : Base
+@property (readonly, nonnull) Base *readwriteChange;
+@property (readonly, nonnull) Base *nullabilityChange;
+@property (readonly, nonnull) GenericClass<Base *> *missingGenerics;
+@property (readonly, nonnull) Base *typeChange;
+@end
+
+@interface PropertiesNoInit : Base
+@property (readonly, nonnull) Base *readwriteChange;
+@property (readonly, nonnull) Base *nullabilityChange;
+@property (readonly, nonnull) GenericClass<Base *> *missingGenerics;
+@property (readonly, nonnull) Base *typeChange;
+@end
+
+@interface PropertiesInitGeneric<T> : Base
+@property (readonly, nonnull) Base *readwriteChange;
+@property (readonly, nonnull) Base *nullabilityChange;
+@property (readonly, nonnull) GenericClass<Base *> *missingGenerics;
+@property (readonly, nonnull) Base *typeChange;
+@end
+
+@interface PropertiesNoInitGeneric<T> : Base
+@property (readonly, nonnull) Base *readwriteChange;
+@property (readonly, nonnull) Base *nullabilityChange;
+@property (readonly, nonnull) GenericClass<Base *> *missingGenerics;
+@property (readonly, nonnull) Base *typeChange;
+@end
+
+@interface PropertiesInitCategory : Base
+@end
+
+@interface PropertiesInitCategory (Category)
+@property (readonly, nonnull) Base *readwriteChange;
+@property (readonly, nonnull) Base *nullabilityChange;
+@property (readonly, nonnull) GenericClass<Base *> *missingGenerics;
+@property (readonly, nonnull) Base *typeChange;
+@end
+
+@interface PropertiesNoInitCategory : Base
+@end
+
+@interface PropertiesNoInitCategory (Category)
+@property (readonly, nonnull) Base *readwriteChange;
+@property (readonly, nonnull) Base *nullabilityChange;
+@property (readonly, nonnull) GenericClass<Base *> *missingGenerics;
+@property (readonly, nonnull) Base *typeChange;
+@end
diff --git a/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/Modules/module.modulemap b/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/Modules/module.modulemap
new file mode 100644
index 0000000..133cb19
--- /dev/null
+++ b/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/Modules/module.modulemap
@@ -0,0 +1,7 @@
+framework module PrivatelyReadwrite {
+  umbrella header "PrivatelyReadwrite.h"
+  module * {
+    export *
+  }
+  exclude header "Private.h"
+}
diff --git a/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/PrivateHeaders/Private.h b/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/PrivateHeaders/Private.h
new file mode 100644
index 0000000..8f9609a
--- /dev/null
+++ b/test/ClangImporter/Inputs/frameworks/PrivatelyReadwrite.framework/PrivateHeaders/Private.h
@@ -0,0 +1,46 @@
+#import <PrivatelyReadwrite/PrivatelyReadwrite.h>
+
+@interface PrivateSubclass : Base
+@end
+
+@interface PropertiesInit ()
+@property (readwrite, nonnull) Base *readwriteChange;
+@property (readwrite, nullable) Base *nullabilityChange;
+@property (readwrite, nonnull) GenericClass *missingGenerics;
+@property (readwrite, nonnull) PrivateSubclass *typeChange;
+@end
+
+@interface PropertiesNoInit ()
+@property (readwrite, nonnull) Base *readwriteChange;
+@property (readwrite, nullable) Base *nullabilityChange;
+@property (readwrite, nonnull) GenericClass *missingGenerics;
+@property (readwrite, nonnull) PrivateSubclass *typeChange;
+@end
+
+@interface PropertiesInitGeneric<T> ()
+@property (readwrite, nonnull) Base *readwriteChange;
+@property (readwrite, nullable) Base *nullabilityChange;
+@property (readwrite, nonnull) GenericClass *missingGenerics;
+@property (readwrite, nonnull) PrivateSubclass *typeChange;
+@end
+
+@interface PropertiesNoInitGeneric<T> ()
+@property (readwrite, nonnull) Base *readwriteChange;
+@property (readwrite, nullable) Base *nullabilityChange;
+@property (readwrite, nonnull) GenericClass *missingGenerics;
+@property (readwrite, nonnull) PrivateSubclass *typeChange;
+@end
+
+@interface PropertiesInitCategory ()
+@property (readwrite, nonnull) Base *readwriteChange;
+@property (readwrite, nullable) Base *nullabilityChange;
+@property (readwrite, nonnull) GenericClass *missingGenerics;
+@property (readwrite, nonnull) PrivateSubclass *typeChange;
+@end
+
+@interface PropertiesNoInitCategory ()
+@property (readwrite, nonnull) Base *readwriteChange;
+@property (readwrite, nullable) Base *nullabilityChange;
+@property (readwrite, nonnull) GenericClass *missingGenerics;
+@property (readwrite, nonnull) PrivateSubclass *typeChange;
+@end
diff --git a/test/ClangImporter/MixedSource/import-mixed-framework.swift b/test/ClangImporter/MixedSource/import-mixed-framework.swift
index 72f6222..f72be73 100644
--- a/test/ClangImporter/MixedSource/import-mixed-framework.swift
+++ b/test/ClangImporter/MixedSource/import-mixed-framework.swift
@@ -6,7 +6,7 @@
 // RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -F %t -typecheck %s
 
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t/Mixed.framework/Modules/Mixed.swiftmodule/%target-swiftmodule-name %S/Inputs/mixed-framework/Mixed.swift -import-underlying-module -F %t -module-name Mixed -disable-objc-attr-requires-foundation-module
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -F %t -typecheck %s -verify -verify-ignore-unknown
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -F %t -typecheck %s -verify
 
 // XFAIL: linux
 
@@ -35,6 +35,3 @@
   obj.protoMethod()
   _ = obj.protoProperty
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'SwiftClassWithCustomName' was obsoleted in Swift 3
diff --git a/test/ClangImporter/SceneKit_test.swift b/test/ClangImporter/SceneKit_test.swift
index 8b1c4fc..007da76 100644
--- a/test/ClangImporter/SceneKit_test.swift
+++ b/test/ClangImporter/SceneKit_test.swift
@@ -1,4 +1,4 @@
-// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
+// RUN: %target-typecheck-verify-swift
 
 // REQUIRES: objc_interop
 // REQUIRES: OS=macosx
@@ -235,48 +235,3 @@
   program.handleBinding(ofBufferNamed: "str", frequency: bufferFrequency,
                         handler: bufferBindingBlock)
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'SCNGeometrySourceSemantic' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNLightType' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNLightingModel' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNParticleProperty' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsShapeOption' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsShapeType' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsTestOption' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsTestSearchMode' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneAttribute' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceAnimationImportPolicy' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceLoadingOption' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNViewOption' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNHitTestFirstFoundOnlyKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNHitTestSortResultsKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNHitTestClipToZRangeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNHitTestBackFaceCullingKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNHitTestBoundingBoxOnlyKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNHitTestIgnoreChildNodesKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNHitTestRootNodeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNHitTestIgnoreHiddenNodesKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsShapeTypeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsShapeKeepAsCompoundKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsShapeScaleKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsTestCollisionBitMaskKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsTestSearchModeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPhysicsTestBackfaceCullingKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneStartTimeAttributeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneEndTimeAttributeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneFrameRateAttributeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneUpAxisAttributeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceCreateNormalsIfAbsentKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceCheckConsistencyKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceFlattenSceneKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceUseSafeModeKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceAssetDirectoryURLsKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceOverrideAssetURLsKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceStrictConformanceKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceConvertUnitsToMetersKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceConvertToYUpKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNSceneSourceAnimationImportPolicyKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPreferredRenderingAPIKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPreferredDeviceKey' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'SCNPreferLowPowerDeviceKey' was obsoleted in Swift 3
diff --git a/test/ClangImporter/attr-swift_name_renaming.swift b/test/ClangImporter/attr-swift_name_renaming.swift
index ff65255..802657e 100644
--- a/test/ClangImporter/attr-swift_name_renaming.swift
+++ b/test/ClangImporter/attr-swift_name_renaming.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -Xcc -w -typecheck -verify -verify-ignore-unknown %s
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -Xcc -w -typecheck -verify %s
 
 // XFAIL: linux
 
@@ -51,14 +51,3 @@
   Foo.accepts() {}
   Foo.accepts {}
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'ColorType' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: did you mean 'Overslept'?
-// <unknown>:0: error: unexpected note produced: did you mean 'TooHard'?
-// <unknown>:0: error: unexpected note produced: 'my_int_t' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'acceptsClosure' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'acceptsClosure' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'acceptsClosureStatic' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'acceptsClosureStatic' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'acceptsClosureStatic' was obsoleted in Swift 3
diff --git a/test/ClangImporter/attr-swift_private.swift b/test/ClangImporter/attr-swift_private.swift
index 1e99cbd..28af166 100644
--- a/test/ClangImporter/attr-swift_private.swift
+++ b/test/ClangImporter/attr-swift_private.swift
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t && mkdir -p %t
 // RUN: %build-clang-importer-objc-overlays
 
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -I %S/Inputs/custom-modules -typecheck %s -verify -verify-ignore-unknown
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -I %S/Inputs/custom-modules -typecheck %s -verify
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -I %S/Inputs/custom-modules -emit-ir %s -D IRGEN | %FileCheck %s
 
 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk-nosource -I %t) -I %S/Inputs/custom-modules -print-module -source-filename="%s" -module-to-print SwiftPrivateAttr > %t.txt
@@ -139,9 +139,3 @@
   let _ = Foo.__foo // expected-error{{'__foo' has been replaced by 'init(__:)'}}
 }
 #endif
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: '__PrivCFTypeRef' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: '__PrivCFSubRef' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: '__fooWithOneArg' has been explicitly marked unavailable here
-// <unknown>:0: error: unexpected note produced: '__foo' has been explicitly marked unavailable here
diff --git a/test/ClangImporter/availability.swift b/test/ClangImporter/availability.swift
index df101c7..97a8f05 100644
--- a/test/ClangImporter/availability.swift
+++ b/test/ClangImporter/availability.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -I %S/Inputs/custom-modules %s -verify-ignore-unknown
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -I %S/Inputs/custom-modules %s
 
 // REQUIRES: objc_interop
 
@@ -115,8 +115,3 @@
   _ = NSClothingStyle.hipster
   _ = NSClothingStyleOfficeCasual // expected-error{{'NSClothingStyleOfficeCasual' has been renamed to 'NSClothingStyle.semiFormal'}} {{7-34=NSClothingStyle.semiFormal}}
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected warning produced: imported declaration 'dispatch_sync' could not be mapped to 'DispatchQueue.sync(self:execute:)'
-// <unknown>:0: error: unexpected note produced: 'NSConnectionDidDieNotification' has been explicitly marked unavailable here
-// <unknown>:0: error: unexpected note produced: 'CGColorCreateGenericGray' was obsoleted in Swift 3
diff --git a/test/ClangImporter/cf.swift b/test/ClangImporter/cf.swift
index a51f8cb..d0bf265 100644
--- a/test/ClangImporter/cf.swift
+++ b/test/ClangImporter/cf.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -import-cf-types -I %S/Inputs/custom-modules %s -verify-ignore-unknown
+// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -import-cf-types -I %S/Inputs/custom-modules %s
 
 // REQUIRES: objc_interop
 
@@ -160,7 +160,3 @@
 @objc protocol ObjCProto {}
 extension CCRefrigerator: ObjCProto {} // expected-error {{Core Foundation class 'CCRefrigerator' cannot conform to @objc protocol 'ObjCProto' because Core Foundation types are not classes in Objective-C}}
 extension CCRefrigerator: SwiftProto {}
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'CCFridgeRef' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'NotAProblemRef' was obsoleted in Swift 3
diff --git a/test/ClangImporter/newtype_conformance.swift b/test/ClangImporter/newtype_conformance.swift
index 5dd60ce..6ef73e3 100644
--- a/test/ClangImporter/newtype_conformance.swift
+++ b/test/ClangImporter/newtype_conformance.swift
@@ -1,12 +1,15 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules %s
+// RUN: rm -rf %t && mkdir -p %t
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules -primary-file %S/Inputs/MoreSwiftNewtypes_conformances.swift %S/Inputs/MoreSwiftNewtypes_tests.swift -module-name MoreSwiftNewtypes
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules %S/Inputs/MoreSwiftNewtypes_conformances.swift -primary-file %S/Inputs/MoreSwiftNewtypes_tests.swift -module-name MoreSwiftNewtypes
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -I %S/Inputs/custom-modules -o %t %S/Inputs/MoreSwiftNewtypes_conformances.swift %S/Inputs/MoreSwiftNewtypes_tests.swift -module-name MoreSwiftNewtypes
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules -I %t %s -verify
+
 // REQUIRES: objc_interop
 
-// This test can't use '-verify' mode, because the potential error wouldn't
-// belong to any file.
-// e.g.:
-//   <unknown>:0: error: type 'NSNotification.Name' does not conform to protocol 'Comparable'
-
 import Foundation
+import MoreSwiftNewtypes
 
 func acceptEquatable<T: Equatable>(_: T) {}
 func acceptHashable<T: Hashable>(_: T) {}
@@ -26,3 +29,11 @@
   _ = x >= y
   _ = x as NSString
 }
+
+
+func testCustomWrappers(wrappedRef: WrappedRef, wrappedValue: WrappedValue) {
+  acceptEquatable(wrappedRef)
+  acceptEquatable(wrappedValue)
+  acceptHashable(wrappedRef) // expected-error {{does not conform to expected type 'Hashable'}}
+  acceptHashable(wrappedValue) // expected-error {{does not conform to expected type 'Hashable'}}
+}
diff --git a/test/ClangImporter/objc_bridging_generics.swift b/test/ClangImporter/objc_bridging_generics.swift
index fb68e17..54b77b2 100644
--- a/test/ClangImporter/objc_bridging_generics.swift
+++ b/test/ClangImporter/objc_bridging_generics.swift
@@ -108,7 +108,7 @@
   }
   // Doesn't use 'T', since its metadata isn't necessary to erase to AnyObject
   // or to existential metatype
-  func doesntUseGenericParam5(_ x: T, _ y: T.Type) -> T {
+  @objc func doesntUseGenericParam5(_ x: T, _ y: T.Type) -> T {
     _ = y as AnyObject.Type
     _ = y as Any.Type
     _ = y as AnyObject
@@ -143,10 +143,10 @@
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
   func usesGenericParamJ() -> [(T, T)]? {} // expected-note{{used here}}
 
-  static func doesntUseGenericParam() {}
-  static func doesntUseGenericParam2() -> Self {}
+  @objc static func doesntUseGenericParam() {}
+  @objc static func doesntUseGenericParam2() -> Self {}
   // Doesn't technically use 'T', since it's type-erased at runtime
-  static func doesntUseGenericParam3() -> GenericClass<T> {}
+  @objc static func doesntUseGenericParam3() -> GenericClass<T> {}
 
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
   static func usesGenericParamC(_ x: [(T, T)]?) {} // expected-note{{used here}}
@@ -175,12 +175,12 @@
 func swiftFunction<T: Animal>(x: T) {}
 
 extension AnimalContainer {
-  func doesntUseGenericParam1(_ x: T, _ y: T.Type) {
+  @objc func doesntUseGenericParam1(_ x: T, _ y: T.Type) {
     _ = #selector(x.another)
     _ = #selector(y.create)
   }
 
-  func doesntUseGenericParam2(_ x: T, _ y: T.Type) {
+  @objc func doesntUseGenericParam2(_ x: T, _ y: T.Type) {
     let a = x.another()
     _ = a.another()
     _ = x.another().another()
@@ -193,7 +193,7 @@
     x.eat(a)
   }
 
-  func doesntUseGenericParam3(_ x: T, _ y: T.Type) {
+  @objc func doesntUseGenericParam3(_ x: T, _ y: T.Type) {
     let sup: Animal = x
     sup.eat(x)
     _ = x.buddy
@@ -201,7 +201,7 @@
     x[0] = x
   }
 
-  func doesntUseGenericParam4(_ x: T, _ y: T.Type) {
+  @objc func doesntUseGenericParam4(_ x: T, _ y: T.Type) {
     _ = type(of: x).apexPredator.another()
     type(of: x).apexPredator = x
 
@@ -290,7 +290,7 @@
 }
 
 extension PettableContainer {
-  func doesntUseGenericParam(_ x: T, _ y: T.Type) {
+  @objc func doesntUseGenericParam(_ x: T, _ y: T.Type) {
     // TODO: rdar://problem/27796375--allocating entry points are emitted as
     // true generics.
     // _ = type(of: x).init(fur: x).other()
diff --git a/test/ClangImporter/objc_diags.swift b/test/ClangImporter/objc_diags.swift
index ffcfbde..815c39c 100644
--- a/test/ClangImporter/objc_diags.swift
+++ b/test/ClangImporter/objc_diags.swift
@@ -6,5 +6,5 @@
 
 func instanceMethod(_ b: B) {
   b.method(1, 2.5) // expected-error {{argument labels '(_:, _:)' do not match any available overloads}}
-  // expected-note @-1 {{overloads for 'method' exist with these partially matching parameter lists: (Int32, onExtB: Double), (Int32, with: Float), (Int32, withFloat: Float), (Int32, onExtA: Double), (Int32, onCat1: Double), (Int32, with: Double), (Int32, withDouble: Double)}}
+  // expected-note @-1 {{overloads for 'method' exist with these partially matching parameter lists: (Int32, with: Float), (Int32, withFloat: Float), (Int32, onExtB: Double), (Int32, with: Double), (Int32, withDouble: Double), (Int32, onExtA: Double), (Int32, onCat1: Double)}}
 }
diff --git a/test/ClangImporter/objc_factory_method.swift b/test/ClangImporter/objc_factory_method.swift
index fb3bfc5..bb9c1bb 100644
--- a/test/ClangImporter/objc_factory_method.swift
+++ b/test/ClangImporter/objc_factory_method.swift
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t && mkdir -p %t
 // RUN: %build-clang-importer-objc-overlays
 
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -target x86_64-apple-macosx10.51 -typecheck %s -verify -verify-ignore-unknown
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -target x86_64-apple-macosx10.51 -typecheck %s -verify
 
 // REQUIRES: OS=macosx
 // REQUIRES: objc_interop
@@ -108,10 +108,3 @@
   _ = NSURLRequest.requestWithString("http://www.llvm.org") // expected-error{{'requestWithString' has been replaced by 'init(string:)'}}
   _ = NSURLRequest.URLRequestWithURL(url as URL) // expected-error{{'URLRequestWithURL' has been replaced by 'init(url:)'}}
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'hiveWithQueen' has been explicitly marked unavailable here
-// <unknown>:0: error: unexpected note produced: 'decimalNumberWithMantissa(_:exponent:isNegative:)' has been explicitly marked unavailable here
-// <unknown>:0: error: unexpected note produced: 'URLWithString' has been explicitly marked unavailable here
-// <unknown>:0: error: unexpected note produced: 'requestWithString' has been explicitly marked unavailable here
-// <unknown>:0: error: unexpected note produced: 'URLRequestWithURL' has been explicitly marked unavailable here
diff --git a/test/ClangImporter/objc_implicit_with.swift b/test/ClangImporter/objc_implicit_with.swift
index 1aeebb4..3eced3b 100644
--- a/test/ClangImporter/objc_implicit_with.swift
+++ b/test/ClangImporter/objc_implicit_with.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -verify -verify-ignore-unknown
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -verify
 
 // REQUIRES: objc_interop
 
@@ -62,6 +62,3 @@
   let prot = NSCoding.self
   _ = NSXPCInterface(with: prot) // not "protocol:"
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'hiveWithQueen' has been explicitly marked unavailable here
diff --git a/test/ClangImporter/objc_init.swift b/test/ClangImporter/objc_init.swift
index a421ee7..13ea4c7 100644
--- a/test/ClangImporter/objc_init.swift
+++ b/test/ClangImporter/objc_init.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules %s -verify -verify-ignore-unknown
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules %s -verify
 
 // REQUIRES: objc_interop
 // REQUIRES: OS=macosx
@@ -171,6 +171,3 @@
   procInfo = ProcessInfo.processInfo // okay
   return procInfo
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'NSProcessInfo' was obsoleted in Swift 3
diff --git a/test/ClangImporter/objc_parse.swift b/test/ClangImporter/objc_parse.swift
index a3a8321..d4bfd8b 100644
--- a/test/ClangImporter/objc_parse.swift
+++ b/test/ClangImporter/objc_parse.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules %s -verify -verify-ignore-unknown
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules %s -verify
 
 // REQUIRES: objc_interop
 
@@ -403,6 +403,23 @@
   _ = value
 }
 
+func testPropertyAndMethodCollisionInOneClass(
+  obj: PropertyAndMethodCollisionInOneClass,
+  rev: PropertyAndMethodReverseCollisionInOneClass
+) {
+  obj.object = nil
+  obj.object()
+
+  type(of: obj).classRef = nil
+  type(of: obj).classRef()
+
+  rev.object = nil
+  rev.object()
+
+  type(of: rev).classRef = nil
+  type(of: rev).classRef()
+}
+
 func testSubscriptAndPropertyRedeclaration(_ obj: SubscriptAndProperty) {
   _ = obj.x
   obj.x = 5
@@ -612,6 +629,3 @@
   @objc func intNewtype(a: MyInt) {}
   @objc func intNewtypeOptional(a: MyInt?) {} // expected-error {{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: did you mean 'makingHoney'?
diff --git a/test/ClangImporter/objc_redeclared_properties_incompatible.swift b/test/ClangImporter/objc_redeclared_properties_incompatible.swift
new file mode 100644
index 0000000..2f81a1b
--- /dev/null
+++ b/test/ClangImporter/objc_redeclared_properties_incompatible.swift
@@ -0,0 +1,103 @@
+// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks %s 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-PUBLIC %s
+
+// RUN: echo '#import <PrivatelyReadwrite/Private.h>' > %t.h
+// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -import-objc-header %t.h %s 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-pch -F %S/Inputs/frameworks -o %t.pch %t.h
+// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -import-objc-header %t.pch %s 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s
+
+// REQUIRES: objc_interop
+
+import PrivatelyReadwrite
+
+// In the original bug, it made a difference whether the type was instantiated;
+// it resulted in members being imported in a different order.
+func testWithInitializer() {
+  let obj = PropertiesInit()
+
+  let _: Int = obj.nullabilityChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  let _: Int = obj.missingGenerics
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
+
+  let _: Int = obj.typeChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  obj.readwriteChange = Base() // CHECK-PRIVATE-NOT: [[@LINE]]:{{.+}}: error
+  // CHECK-PUBLIC: [[@LINE-1]]:23: error: cannot assign to property: 'readwriteChange' is a get-only property
+}
+
+func testWithoutInitializer(obj: PropertiesNoInit) {
+  let _: Int = obj.nullabilityChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  let _: Int = obj.missingGenerics
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
+
+  let _: Int = obj.typeChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  obj.readwriteChange = Base() // CHECK-PRIVATE-NOT: [[@LINE]]:{{.+}}: error
+  // CHECK-PUBLIC: [[@LINE-1]]:23: error: cannot assign to property: 'readwriteChange' is a get-only property
+}
+
+func testGenericWithInitializer() {
+  let obj = PropertiesInitGeneric<Base>()
+
+  let _: Int = obj.nullabilityChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  let _: Int = obj.missingGenerics
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
+
+  let _: Int = obj.typeChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  obj.readwriteChange = Base() // CHECK-PRIVATE-NOT: [[@LINE]]:{{.+}}: error
+  // CHECK-PUBLIC: [[@LINE-1]]:23: error: cannot assign to property: 'readwriteChange' is a get-only property
+}
+
+func testGenericWithoutInitializer(obj: PropertiesNoInitGeneric<Base>) {
+  let _: Int = obj.nullabilityChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  let _: Int = obj.missingGenerics
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
+
+  let _: Int = obj.typeChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  obj.readwriteChange = Base() // CHECK-PRIVATE-NOT: [[@LINE]]:{{.+}}: error
+  // CHECK-PUBLIC: [[@LINE-1]]:23: error: cannot assign to property: 'readwriteChange' is a get-only property
+}
+
+func testCategoryWithInitializer() {
+  let obj = PropertiesInitCategory()
+
+  let _: Int = obj.nullabilityChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  let _: Int = obj.missingGenerics
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
+
+  let _: Int = obj.typeChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  obj.readwriteChange = Base() // CHECK-PRIVATE-NOT: [[@LINE]]:{{.+}}: error
+  // CHECK-PUBLIC: [[@LINE-1]]:23: error: cannot assign to property: 'readwriteChange' is a get-only property
+}
+
+func testCategoryWithoutInitializer(obj: PropertiesNoInitCategory) {
+  let _: Int = obj.nullabilityChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  let _: Int = obj.missingGenerics
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
+
+  let _: Int = obj.typeChange
+  // CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
+
+  obj.readwriteChange = Base() // CHECK-PRIVATE-NOT: [[@LINE]]:{{.+}}: error
+  // CHECK-PUBLIC: [[@LINE-1]]:23: error: cannot assign to property: 'readwriteChange' is a get-only property
+}
diff --git a/test/ClangImporter/protocol-member-renaming.swift b/test/ClangImporter/protocol-member-renaming.swift
index 17ba8b7..e1c83f0 100644
--- a/test/ClangImporter/protocol-member-renaming.swift
+++ b/test/ClangImporter/protocol-member-renaming.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -typecheck -import-objc-header %S/Inputs/protocol-member-renaming.h -verify %s -verify-ignore-unknown
+// RUN: %target-swift-frontend -typecheck -import-objc-header %S/Inputs/protocol-member-renaming.h -verify %s
 
 // REQUIRES: objc_interop
 
@@ -16,6 +16,3 @@
   // Note the argument label that causes this not to match the requirement.
   func doTheThing(object: Any) {} // no-warning
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'foo(_:willConsumeObject:)' was obsoleted in Swift 3
diff --git a/test/ClangImporter/swift2_warnings.swift b/test/ClangImporter/swift2_warnings.swift
index 063bd29..cb209eb 100644
--- a/test/ClangImporter/swift2_warnings.swift
+++ b/test/ClangImporter/swift2_warnings.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %S/../IDE/Inputs/custom-modules) -emit-sil -I %S/Inputs/custom-modules %s -verify -verify-ignore-unknown
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %S/../IDE/Inputs/custom-modules) -emit-sil -I %S/Inputs/custom-modules %s -verify
 
 // REQUIRES: objc_interop
 
@@ -104,25 +104,3 @@
     case .Quince: return // expected-error {{'Quince' has been renamed to 'quince'}} {{11-17=quince}}
   }
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'NSProgressReporting' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'NSPostingStyle' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'NSPostingStyle' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'NSOperation' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'indexOfObject' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'makingHoney' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: did you mean 'NSXMLInvalidKind'?
-// <unknown>:0: error: unexpected note produced: did you mean 'NSXMLInvalidKind'?
-// <unknown>:0: error: unexpected note produced: 'EnableQuince' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'EnableMince' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1GlobalVar' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1CreateSimple' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1Invert' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1InvertInPlace' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1Rotate' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1StaticMethod()' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1GetRadius' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1SetRadius' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'Mince' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'Quince' was obsoleted in Swift 3
diff --git a/test/Constraints/array_literal.swift b/test/Constraints/array_literal.swift
index fe64443..6a3414e 100644
--- a/test/Constraints/array_literal.swift
+++ b/test/Constraints/array_literal.swift
@@ -121,7 +121,7 @@
 class B : A { }
 class C : A { }
 
-/// Check for defaulting the element type to 'Any'.
+/// Check for defaulting the element type to 'Any' / 'Any?'.
 func defaultToAny(i: Int, s: String) {
   let a1 = [1, "a", 3.5]
   // expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
@@ -129,24 +129,39 @@
 
   let a2: Array = [1, "a", 3.5]
   // expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
-
   let _: Int = a2  // expected-error{{value of type '[Any]'}}
+  
+  let a3 = [1, "a", nil, 3.5]
+  // expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
+  let _: Int = a3 // expected-error{{value of type '[Any?]'}}
+  
+  let a4: Array = [1, "a", nil, 3.5]
+  // expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
+  let _: Int = a4 // expected-error{{value of type '[Any?]'}}
 
-  let a3 = []
+  let a5 = []
   // expected-error@-1{{empty collection literal requires an explicit type}}
-
-  let _: Int = a3 // expected-error{{value of type '[Any]'}}
+  let _: Int = a5 // expected-error{{value of type '[Any]'}}
 
   let _: [Any] = [1, "a", 3.5]
   let _: [Any] = [1, "a", [3.5, 3.7, 3.9]]
   let _: [Any] = [1, "a", [3.5, "b", 3]]
+  
+  let _: [Any?] = [1, "a", nil, 3.5]
+  let _: [Any?] = [1, "a", nil, [3.5, 3.7, 3.9]]
+  let _: [Any?] = [1, "a", nil, [3.5, "b", nil]]
 
-  let a4 = [B(), C()]
-  let _: Int = a4 // expected-error{{value of type '[A]'}}
+  let a6 = [B(), C()]
+  let _: Int = a6 // expected-error{{value of type '[A]'}}
 }
 
 /// Check handling of 'nil'.
-func joinWithNil(s: String) {
+protocol Proto1 {}
+protocol Proto2 {}
+struct Nilable: ExpressibleByNilLiteral {
+	init(nilLiteral: ()) {}
+}
+func joinWithNil<T>(s: String, a: Any, t: T, m: T.Type, p: Proto1 & Proto2, arr: [Int], opt: Int?, iou: Int!, n: Nilable) {
   let a1 = [s, nil]
   let _: Int = a1 // expected-error{{value of type '[String?]'}}
 
@@ -158,6 +173,72 @@
 
   let a4 = [nil, "hello"]
   let _: Int = a4 // expected-error{{value of type '[String?]'}}
+  
+  let a5 = [(s, s), nil]
+  let _: Int = a5 // expected-error{{value of type '[(String, String)?]'}}
+  
+  let a6 = [nil, (s, s)]
+  let _: Int = a6 // expected-error{{value of type '[(String, String)?]'}}
+  
+  let a7 = [("hello", "world"), nil]
+  let _: Int = a7 // expected-error{{value of type '[(String, String)?]'}}
+  
+  let a8 = [nil, ("hello", "world")]
+  let _: Int = a8 // expected-error{{value of type '[(String, String)?]'}}
+  
+  let a9 = [{ $0 * 2 }, nil]
+  let _: Int = a9 // expected-error{{value of type '[((Int) -> Int)?]'}}
+  
+  let a10 = [nil, { $0 * 2 }]
+  let _: Int = a10 // expected-error{{value of type '[((Int) -> Int)?]'}}
+  
+  let a11 = [a, nil]
+  let _: Int = a11 // expected-error{{value of type '[Any?]'}}
+  
+  let a12 = [nil, a]
+  let _: Int = a12 // expected-error{{value of type '[Any?]'}}
+  
+  let a13 = [t, nil]
+  let _: Int = a13 // expected-error{{value of type '[T?]'}}
+  
+  let a14 = [nil, t]
+  let _: Int = a14 // expected-error{{value of type '[T?]'}}
+  
+  let a15 = [m, nil]
+  let _: Int = a15 // expected-error{{value of type '[T.Type?]'}}
+  
+  let a16 = [nil, m]
+  let _: Int = a16 // expected-error{{value of type '[T.Type?]'}}
+  
+  let a17 = [p, nil]
+  let _: Int = a17 // expected-error{{value of type '[(Proto1 & Proto2)?]'}}
+  
+  let a18 = [nil, p]
+  let _: Int = a18 // expected-error{{value of type '[(Proto1 & Proto2)?]'}}
+  
+  let a19 = [arr, nil]
+  let _: Int = a19 // expected-error{{value of type '[[Int]?]'}}
+  
+  let a20 = [nil, arr]
+  let _: Int = a20 // expected-error{{value of type '[[Int]?]'}}
+  
+  let a21 = [opt, nil]
+  let _: Int = a21 // expected-error{{value of type '[Int?]'}}
+  
+  let a22 = [nil, opt]
+  let _: Int = a22 // expected-error{{value of type '[Int?]'}}
+  
+  let a23 = [iou, nil]
+  let _: Int = a23 // expected-error{{value of type '[Int?]'}}
+  
+  let a24 = [nil, iou]
+  let _: Int = a24 // expected-error{{value of type '[Int?]'}}
+  
+  let a25 = [n, nil]
+  let _: Int = a25 // expected-error{{value of type '[Nilable]'}}
+  
+  let a26 = [nil, n]
+  let _: Int = a26 // expected-error{{value of type '[Nilable]'}}
 }
 
 struct OptionSetLike : ExpressibleByArrayLiteral {
diff --git a/test/Constraints/dictionary_literal.swift b/test/Constraints/dictionary_literal.swift
index aa8afea..5c9c0e8 100644
--- a/test/Constraints/dictionary_literal.swift
+++ b/test/Constraints/dictionary_literal.swift
@@ -72,6 +72,11 @@
   // expected-error@-1{{heterogeneous collection literal could only be inferred to 'Dictionary<String, Any>'; add explicit type annotation if this is intentional}}{{46-46= as Dictionary<String, Any>}}
 
   let _: [String : Any] = ["a" : 1, "b" : 2.5, "c" : "hello"]
+  
+  let _ = ["a" : 1, "b" : nil, "c" : "hello"]
+  // expected-error@-1{{heterogeneous collection literal could only be inferred to 'Dictionary<String, Any?>' (aka 'Dictionary<String, Optional<Any>>'); add explicit type annotation if this is intentional}}{{46-46= as Dictionary<String, Any?>}}
+  
+  let _: [String : Any?] = ["a" : 1, "b" : nil, "c" : "hello"]
 
   let d2 = [:]
   // expected-error@-1{{empty collection literal requires an explicit type}}
diff --git a/test/Constraints/dynamic_lookup.swift b/test/Constraints/dynamic_lookup.swift
index 25f099d..0e13502 100644
--- a/test/Constraints/dynamic_lookup.swift
+++ b/test/Constraints/dynamic_lookup.swift
@@ -235,7 +235,7 @@
 // looked-up dynamically through AnyObject are treated as conforming
 // to the protocols they are supposed to conform to.
 class NSObjDerived1 : NSObject {
-  var everything: [Any] = []
+  @objc var everything: [Any] = []
 }
 
 class NSObjDerived2 : NSObject {
diff --git a/test/Constraints/existential_metatypes.swift b/test/Constraints/existential_metatypes.swift
index 652d2c1..2034837 100644
--- a/test/Constraints/existential_metatypes.swift
+++ b/test/Constraints/existential_metatypes.swift
@@ -46,7 +46,7 @@
 class HairDryer {}
 
 let a: Toaster.Type.Protocol = Toaster.Type.self
-let b: Any.Type.Type = Toaster.Type.self
+let b: Any.Type.Type = Toaster.Type.self // expected-error {{cannot convert value of type 'Toaster.Type.Protocol' to specified type 'Any.Type.Type'}}
 let c: Any.Type.Protocol = Toaster.Type.self // expected-error {{cannot convert value of type 'Toaster.Type.Protocol' to specified type 'Any.Type.Protocol'}}
 let d: Toaster.Type.Type = WashingMachine.Type.self
 let e: Any.Type.Type = WashingMachine.Type.self
diff --git a/test/Constraints/optional.swift b/test/Constraints/optional.swift
index db7f254..3186b89 100644
--- a/test/Constraints/optional.swift
+++ b/test/Constraints/optional.swift
@@ -120,7 +120,12 @@
   voidOptional(optNoop)
 }
 
-func testTernaryWithNil(b: Bool, s: String, i: Int) {
+protocol Proto1 {}
+protocol Proto2 {}
+struct Nilable: ExpressibleByNilLiteral {
+	init(nilLiteral: ()) {}
+}
+func testTernaryWithNil<T>(b: Bool, s: String, i: Int, a: Any, t: T, m: T.Type, p: Proto1 & Proto2, arr: [Int], opt: Int?, iou: Int!, n: Nilable) {
   let t1 = b ? s : nil
   let _: Double = t1 // expected-error{{value of type 'String?'}}
   let t2 = b ? nil : i
@@ -129,6 +134,50 @@
   let _: Double = t3 // expected-error{{value of type 'String?'}}
   let t4 = b ? nil : 1
   let _: Double = t4 // expected-error{{value of type 'Int?'}}
+  let t5 = b ? (s, i) : nil
+  let _: Double = t5 // expected-error{{value of type '(String, Int)?}}
+  let t6 = b ? nil : (i, s)
+  let _: Double = t6 // expected-error{{value of type '(Int, String)?}}
+  let t7 = b ? ("hello", 1) : nil
+  let _: Double = t7 // expected-error{{value of type '(String, Int)?}}
+  let t8 = b ? nil : (1, "hello")
+  let _: Double = t8 // expected-error{{value of type '(Int, String)?}}
+  let t9 = b ? { $0 * 2 } : nil
+  let _: Double = t9 // expected-error{{value of type '((Int) -> Int)?}}
+  let t10 = b ? nil : { $0 * 2 }
+  let _: Double = t10 // expected-error{{value of type '((Int) -> Int)?}}
+  let t11 = b ? a : nil
+  let _: Double = t11 // expected-error{{value of type 'Any?'}}
+  let t12 = b ? nil : a
+  let _: Double = t12 // expected-error{{value of type 'Any?'}}
+  let t13 = b ? t : nil
+  let _: Double = t13 // expected-error{{value of type 'T?'}}
+  let t14 = b ? nil : t
+  let _: Double = t14 // expected-error{{value of type 'T?'}}
+  let t15 = b ? m : nil
+  let _: Double = t15 // expected-error{{value of type 'T.Type?'}}
+  let t16 = b ? nil : m
+  let _: Double = t16 // expected-error{{value of type 'T.Type?'}}
+  let t17 = b ? p : nil
+  let _: Double = t17 // expected-error{{value of type '(Proto1 & Proto2)?'}}
+  let t18 = b ? nil : p
+  let _: Double = t18 // expected-error{{value of type '(Proto1 & Proto2)?'}}
+  let t19 = b ? arr : nil
+  let _: Double = t19 // expected-error{{value of type '[Int]?'}}
+  let t20 = b ? nil : arr
+  let _: Double = t20 // expected-error{{value of type '[Int]?'}}
+  let t21 = b ? opt : nil
+  let _: Double = t21 // expected-error{{value of type 'Int?'}}
+  let t22 = b ? nil : opt
+  let _: Double = t22 // expected-error{{value of type 'Int?'}}
+  let t23 = b ? iou : nil
+  let _: Double = t23 // expected-error{{value of type 'Int?'}}
+  let t24 = b ? nil : iou
+  let _: Double = t24 // expected-error{{value of type 'Int?'}}
+  let t25 = b ? n : nil
+  let _: Double = t25 // expected-error{{value of type 'Nilable'}}
+  let t26 = b ? nil : n
+  let _: Double = t26 // expected-error{{value of type 'Nilable'}}
 }
 
 // inference with IUOs
diff --git a/test/DebugInfo/autoclosure.swift b/test/DebugInfo/autoclosure.swift
index 98e9043..2f690f8 100644
--- a/test/DebugInfo/autoclosure.swift
+++ b/test/DebugInfo/autoclosure.swift
@@ -21,7 +21,7 @@
 func call_me(_ input: Int64) -> Void {
 // rdar://problem/14627460
 // An autoclosure should have a line number in the debug info and a scope line of 0.
-// CHECK-DAG: !DISubprogram({{.*}}linkageName: "_T011autoclosure7call_meys5Int64VFSbyXKfu_",{{.*}} line: [[@LINE+3]],{{.*}} isLocal: false, isDefinition: true
+// CHECK-DAG: !DISubprogram({{.*}}linkageName: "_T011autoclosure7call_meys5Int64VFSbyXKfu_",{{.*}} line: [[@LINE+3]],{{.*}} isLocal: true, isDefinition: true
 // But not in the line table.
 // CHECK-DAG: ![[DBG]] = !DILocation(line: [[@LINE+1]],
   if input != 0 &&&&& ( get_truth (input * 2 + 1) > 0 ) {
diff --git a/test/DebugInfo/closure-args.swift b/test/DebugInfo/closure-args.swift
index 86c1f14..5be6820 100644
--- a/test/DebugInfo/closure-args.swift
+++ b/test/DebugInfo/closure-args.swift
@@ -10,7 +10,7 @@
     var out_only = 2013
 
     var backward_ptr  =
-    // CHECK: define linkonce_odr hidden {{.*}} i1 @_T04mainAAyyFSbSS_SStcfU_(
+    // CHECK: define internal {{.*}} i1 @_T04mainAAyyFSbSS_SStcfU_(
     // CHECK: %[[RANDOM_STR_ADDR:.*]] = alloca %TSS*, align {{(4|8)}}
     // CHECK: store %TSS* %{{.*}}, %TSS** %[[RANDOM_STR_ADDR]], align {{(4|8)}}
     // CHECK-NEXT: call void @llvm.dbg.declare(metadata %TSS** %[[RANDOM_STR_ADDR]], metadata !{{.*}}, metadata !{{[0-9]+}}), !dbg
diff --git a/test/DebugInfo/inlinedAt.swift b/test/DebugInfo/inlinedAt.swift
index 8a207f3..2d781ea 100644
--- a/test/DebugInfo/inlinedAt.swift
+++ b/test/DebugInfo/inlinedAt.swift
@@ -51,3 +51,4 @@
 // CHECK-SAME:                  inlinedAt: ![[L2:.*]])
 // CHECK: ![[L2]] = !DILocation(line: 203, column: 13, scope: ![[G_SCOPE]],
 // CHECK-SAME:                  inlinedAt: ![[L3]])
+
diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt
index 3fb5591..bddd3cc 100644
--- a/test/Demangle/Inputs/manglings.txt
+++ b/test/Demangle/Inputs/manglings.txt
@@ -248,4 +248,5 @@
 _T0s10DictionaryV3t17E6Index2V1loiSbAEyxq__G_AGtFZ ---> static (extension in t17):Swift.Dictionary.Index2.< infix ((extension in t17):[A : B].Index2, (extension in t17):[A : B].Index2) -> Swift.Bool
 _T08mangling14varargsVsArrayySaySiG3arrd_SS1ntF ---> mangling.varargsVsArray (arr : Swift.Int..., n : Swift.String) -> ()
 _T08mangling14varargsVsArrayySaySiG3arrd_tF ---> mangling.varargsVsArray (arr : Swift.Int...) -> ()
-                                                                                                                           
+_T0s13_UnicodeViewsVss22RandomAccessCollectionRzs0A8EncodingR_11SubSequence_5IndexQZAFRtzsAcERpzAE_AEQZAIRSs15UnsignedInteger8Iterator_7ElementRPzAE_AlMQZANRS13EncodedScalar_AlMQY_AORSr0_lE13CharacterViewVyxq__G ---> (extension in Swift):Swift._UnicodeViews<A, B><A, B where A: Swift.RandomAccessCollection, B: Swift.UnicodeEncoding, A.Index == A.SubSequence.Index, A.SubSequence: Swift.RandomAccessCollection, A.SubSequence == A.SubSequence.SubSequence, A.Iterator.Element: Swift.UnsignedInteger, A.Iterator.Element == A.SubSequence.Iterator.Element, A.SubSequence.Iterator.Element == B.EncodedScalar.Iterator.Element>.CharacterView
+
diff --git a/test/Frontend/Inputs/sil-merge-partial-modules-other.swift b/test/Frontend/Inputs/sil-merge-partial-modules-other.swift
new file mode 100644
index 0000000..57ac38b
--- /dev/null
+++ b/test/Frontend/Inputs/sil-merge-partial-modules-other.swift
@@ -0,0 +1,14 @@
+@inline(__always)
+func internalFunction() {}
+
+@_versioned
+func versionedFunction() {}
+
+public protocol Shape {
+  func draw()
+  var area: Float { get }
+}
+
+public class ShapeManager {
+  public func manage() {}
+}
diff --git a/test/Frontend/sil-merge-partial-modules.swift b/test/Frontend/sil-merge-partial-modules.swift
new file mode 100644
index 0000000..5c04756
--- /dev/null
+++ b/test/Frontend/sil-merge-partial-modules.swift
@@ -0,0 +1,77 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// RUN: %target-swift-frontend -emit-module -primary-file %s %S/Inputs/sil-merge-partial-modules-other.swift -module-name test -enable-resilience -o %t/partial.a.swiftmodule
+// RUN: %target-swift-frontend -emit-module %s -primary-file %S/Inputs/sil-merge-partial-modules-other.swift -module-name test -enable-resilience -o %t/partial.b.swiftmodule
+
+// RUN: %target-swift-frontend -emit-module %t/partial.a.swiftmodule %t/partial.b.swiftmodule -module-name test -enable-resilience -sil-merge-partial-modules -disable-diagnostic-passes -disable-sil-perf-optzns -o %t/test.swiftmodule
+
+// RUN: %target-sil-opt %t/test.swiftmodule -disable-sil-linking > %t/dump.sil
+// RUN: %FileCheck %s < %t/dump.sil
+// RUN: %FileCheck %s --check-prefix=NEGATIVE < %t/dump.sil
+
+public func publicFunction() {
+  internalFunction()
+}
+
+@_inlineable
+public func inlineableFunction() {
+  let fn = { versionedFunction() }
+
+  fn()
+}
+
+@_fixed_layout
+public struct Rectangle : Shape {
+  @_inlineable
+  public func draw() {
+    publicFunction()
+  }
+
+  public var area: Float { return 10.0 }
+}
+
+public struct Circle : Shape {
+  public func draw() {}
+
+  public var area: Float { return 22.0 / 7 }
+}
+
+public class CircleManager : ShapeManager {
+  public override func manage() {}
+}
+
+// FIXME: Why is the definition order totally random?
+
+// CHECK-LABEL: sil shared [serialized] @_T04test18inlineableFunctionyyFyycfU_ : $@convention(thin) () -> () {
+// CHECK: function_ref @_T04test17versionedFunctionyyF
+// CHECK: }
+
+// CHECK-LABEL: sil @_T04test17versionedFunctionyyF : $@convention(thin) () -> ()
+
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @_T04test9RectangleVAA5ShapeA2aDP4drawyyFTW : $@convention(witness_method) (@in_guaranteed Rectangle) -> () {
+// CHECK: function_ref @_T04test14publicFunctionyyF
+// CHECK: }
+
+// CHECK-LABEL: sil [serialized] @_T04test18inlineableFunctionyyF : $@convention(thin) () -> () {
+// CHECK: function_ref @_T04test18inlineableFunctionyyFyycfU_
+// CHECK: }
+
+// CHECK-LABEL: sil @_T04test14publicFunctionyyF : $@convention(thin) () -> ()
+
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @_T04test9RectangleVAA5ShapeA2aDP4areaSffgTW : $@convention(witness_method) (@in_guaranteed Rectangle) -> Float {
+// CHECK: function_ref @_T04test9RectangleV4areaSffg
+// CHECK: }
+
+// CHECK-LABEL: sil @_T04test9RectangleV4areaSffg : $@convention(method) (Rectangle) -> Float
+
+// CHECK-LABEL: sil_witness_table [serialized] Rectangle: Shape module test {
+// CHECK-LABEL:   method #Shape.draw!1: <Self where Self : Shape> (Self) -> () -> () : @_T04test9RectangleVAA5ShapeA2aDP4drawyyFTW
+// CHECK-LABEL:   method #Shape.area!getter.1: <Self where Self : Shape> (Self) -> () -> Float : @_T04test9RectangleVAA5ShapeA2aDP4areaSffgTW
+// CHECK-LABEL: }
+
+// NEGATIVE-NOT: sil {{.*}}internalFunction
+
+// NEGATIVE-NOT: sil_witness_table {{.*}}Circle: Shape
+
+// NEGATIVE-NOT: sil_vtable
diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift
index b0d3830..291b507 100644
--- a/test/Generics/associated_type_typo.swift
+++ b/test/Generics/associated_type_typo.swift
@@ -15,18 +15,18 @@
 protocol P4 { }
 
 // expected-error@+1{{'T' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{30-35=Assoc}}
-func typoAssoc1<T : P1>(x: T.assoc) { } 
+func typoAssoc1<T : P1>(x: T.assoc, _: T) { } 
 
-// expected-error@+2{{'T' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{43-48=Assoc}}
-// expected-error@+1{{'U' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{54-59=Assoc}}
-func typoAssoc2<T : P1, U : P1>() where T.assoc == U.assoc {}
+// expected-error@+2{{'T' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{53-58=Assoc}}
+// expected-error@+1{{'U' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{64-69=Assoc}}
+func typoAssoc2<T : P1, U : P1>(_: T, _: U) where T.assoc == U.assoc {}
 
 // CHECK-GENERIC-LABEL: .typoAssoc2
 // CHECK-GENERIC: Generic signature: <T, U where T : P1, U : P1, T.Assoc == U.Assoc>
 
 // expected-error@+3{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{42-47=Assoc}}
 // expected-error@+2{{'U.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{19-24=Assoc}}
-func typoAssoc3<T : P2, U : P2>()
+func typoAssoc3<T : P2, U : P2>(t: T, u: U)
   where U.AssocP2.assoc : P3,  T.AssocP2.assoc : P4,
         T.AssocP2 == U.AssocP2 {}
 
diff --git a/test/Generics/associated_type_where_clause.swift b/test/Generics/associated_type_where_clause.swift
index 203d325..e53d4cd 100644
--- a/test/Generics/associated_type_where_clause.swift
+++ b/test/Generics/associated_type_where_clause.swift
@@ -135,3 +135,25 @@
 	associatedtype P2 where P2 == P1, P2 == X
 	// expected-warning@-1{{redundant same-type constraint 'Self.P2' == 'X'}}
 }
+
+// Lookup of same-named associated types aren't ambiguous in this context.
+protocol P1 {
+  associatedtype A
+}
+
+protocol P2: P1 {
+  associatedtype A
+  associatedtype B where A == B
+}
+
+protocol P3: P1 {
+  associatedtype A
+}
+
+protocol P4 {
+  associatedtype A
+}
+
+protocol P5: P3, P4 {
+  associatedtype B where B == A?
+}
diff --git a/test/Generics/function_decls.swift b/test/Generics/function_decls.swift
index 2f6ae64..74d012a 100644
--- a/test/Generics/function_decls.swift
+++ b/test/Generics/function_decls.swift
@@ -28,3 +28,52 @@
 protocol P { associatedtype A }
 
 func f12<T : P>(x: T) -> T.A<Int> {} //expected-error{{cannot specialize non-generic type 'T.A'}}{{29-34=}}
+
+public protocol Q {
+    associatedtype AT1
+    associatedtype AT2
+}
+
+public protocol R {
+  associatedtype I
+}
+
+public class C {
+}
+
+// Check that all generic params except for V can be inferred, because
+// they are directly or indirectly used to declare function's arguments.
+// In particular, T and U are considered to be used, because E is explicitly
+// used and there is a requirement E.I == (T, U)
+//expected-error@+1{{generic parameter 'V' is not used in function signature}}
+public func expectEqualSequence<E : R, A : R, T : Q, U : Q, V : Q>(
+  _ expected: E, _ actual: A
+) where
+  E.I == A.I,
+  E.I == (T, U) {
+}
+
+// Check that all generic params can be inferred, because
+// they are directly or indirectly used to declare function's arguments.
+// The only generic param that is used explicitly is T6.
+// All others are inferred from it step-by-step through the chain of
+// requirements.
+func foo<T1:Q, T2:Q, T3:Q, T4:Q, T5:Q, T6:Q> (x: T6)
+  where T1.AT1 == T2.AT1, T1 == T6.AT2, T2 == T3.AT1, T3 == T4.AT1, T4 == T5.AT2, T5 == T6.AT1 {
+}
+
+// Check that all generic params except for T1 and T2 can be inferred, because
+// they are directly or indirectly used to declare function's arguments.
+//expected-error@+2{{generic parameter 'T1' is not used in function signature}}
+//expected-error@+1{{generic parameter 'T2' is not used in function signature}}
+func boo<T1, T2:Q, T3:Q, T4:Q, T5:Q, T6:Q> (x: T6)
+  where T1:Q, T2:C, T3 == T4.AT1, T4 == T5.AT2, T5 == T6.AT1 {
+}
+
+// At the first glance U seems to be explicitly used for declaring a parameter d.
+// But in fact, the declaration of d uses the associated type U.A. This is not
+// enough to infer the type of U at any of the baz's call-sites.
+// Therefore we should reject this declaration.
+//expected-error@+1{{generic parameter 'U' is not used in function signature}}
+func baz<U:P>(_ d: U.A) {
+}
diff --git a/test/Generics/function_defs.swift b/test/Generics/function_defs.swift
index 5160f86..29e4a92 100644
--- a/test/Generics/function_defs.swift
+++ b/test/Generics/function_defs.swift
@@ -244,7 +244,7 @@
 
 func recursiveSameType
        <T : GeneratesMetaAssoc1, U : GeneratesMetaAssoc2, V : GeneratesAssoc1>
-       (_ t: T, u: U)
+       (_ t: T, u: U, v: V)
   where T.MetaAssoc1 == V.Assoc1, V.Assoc1 == U.MetaAssoc2
 {
   t.get().accept(t.get().makeIterator())
@@ -295,5 +295,5 @@
 
 func badTypeConformance2<T>(_: T) where T.Blarg : EqualComparable { } // expected-error{{'Blarg' is not a member type of 'T'}}
 
-func badSameType<T, U : GeneratesAnElement, V>(_ : T)
+func badSameType<T, U : GeneratesAnElement, V>(_ : T, _ : U)
   where T == U.Element, U.Element == V {} // expected-error{{same-type requirement makes generic parameters 'T' and 'V' equivalent}}
diff --git a/test/Generics/generic_types.swift b/test/Generics/generic_types.swift
index 1e0ce3d..24933ea 100644
--- a/test/Generics/generic_types.swift
+++ b/test/Generics/generic_types.swift
@@ -241,3 +241,4 @@
 // expected-error@-2 {{inheritance from non-protocol, non-class type 'T.A'}}
 
 enum X7<T> where X7.X : G { case X } // expected-error{{enum element 'X' is not a member type of 'X7<T>'}}
+// expected-error@-1{{use of undeclared type 'G'}}
diff --git a/test/Generics/invalid.swift b/test/Generics/invalid.swift
index 7bc051f..99e7955 100644
--- a/test/Generics/invalid.swift
+++ b/test/Generics/invalid.swift
@@ -7,9 +7,11 @@
 
 class dalet where A : B {} // expected-error {{'where' clause cannot be attached to a non-generic declaration}}
 
-protocol he where A : B { // expected-error {{where clauses on protocols are fragile; use '-swift-version 4' to experiment.}}
+protocol he where A : B { // expected-error 2 {{use of undeclared type 'A'}}
+  // expected-error@-1 {{use of undeclared type 'B'}}
 
-  associatedtype vav where A : B // expected-error {{where clauses on associated types are fragile; use '-swift-version 4' to experiment.}}
+  associatedtype vav where A : B // expected-error{{use of undeclared type 'A'}}
+  // expected-error@-1 {{use of undeclared type 'B'}}
 }
 
 
@@ -89,3 +91,13 @@
     }
   }
 }
+
+// Crash with missing types in requirements.
+protocol P1 {
+  associatedtype A where A == ThisTypeDoesNotExist
+  // expected-error@-1{{use of undeclared type 'ThisTypeDoesNotExist'}}
+  associatedtype B where ThisTypeDoesNotExist == B
+  // expected-error@-1{{use of undeclared type 'ThisTypeDoesNotExist'}}
+  associatedtype C where ThisTypeDoesNotExist == ThisTypeDoesNotExist
+  // expected-error@-1 2{{use of undeclared type 'ThisTypeDoesNotExist'}}
+}
diff --git a/test/Generics/protocol_where_clause.swift b/test/Generics/protocol_where_clause.swift
index 01b3308..b7e7686 100644
--- a/test/Generics/protocol_where_clause.swift
+++ b/test/Generics/protocol_where_clause.swift
@@ -12,7 +12,7 @@
 extension Float: Foo {}
 
 protocol Parent {
-    associatedtype T
+  associatedtype T
 }
 func needsParent<X: Parent>(_: X.Type) {}
 struct ConcreteParent: Parent { typealias T = Int }
@@ -20,7 +20,7 @@
 struct ConcreteParentNonFoo2: Parent { typealias T = Float }
 
 protocol SecondParent {
-    associatedtype U
+  associatedtype U
 }
 struct ConcreteSecondParent: SecondParent { typealias U = Int }
 struct ConcreteSecondParent2: SecondParent { typealias U = Int }
@@ -29,44 +29,40 @@
 protocol Conforms: Parent where T: Foo {}
 extension Conforms { func foo(_: T) {} }
 func needsConforms<X: Conforms>(_: X.Type) {
-    needsFoo(X.T.self)
+  needsFoo(X.T.self)
 }
 struct ConcreteConforms: Conforms {
-    typealias T = Int
+  typealias T = Int
 }
 struct BadConcreteConforms: Conforms {
-    // expected-error@-1 {{type 'BadConcreteConforms.T' (aka 'String') does not conform to protocol 'Foo'}}
-    typealias T = String
+  // expected-error@-1 {{type 'BadConcreteConforms.T' (aka 'String') does not conform to protocol 'Foo'}}
+  typealias T = String
 }
 
 protocol SameType: Parent, SecondParent where T == U { }
 func needsSameTypeProtocol<X: SameType>(_: X.Type) {
-    needsSameType(X.T.self, X.U.self)
+  needsSameType(X.T.self, X.U.self)
 }
 struct ConcreteSameType: SameType {
-    typealias T = Int
-    typealias U = Int
+  typealias T = Int
+  typealias U = Int
 }
 struct BadConcreteSameType: SameType { // expected-error{{'SameType' requires the types 'BadConcreteSameType.T' (aka 'Int') and 'BadConcreteSameType.U' (aka 'Float') be equivalent}}
 	// expected-note@-1{{requirement specified as 'Self.T' == 'Self.U' [with Self = BadConcreteSameType]}}
-    typealias T = Int
-    typealias U = Float
+  typealias T = Int
+  typealias U = Float
 }
 
+// <rdar://problem/31041997> Some where-clause requirements aren't checked on conforming types
 protocol NestedConforms: SecondParent where U: Parent, U.T: Foo2 {}
 func needsNestedConforms<X: NestedConforms>(_: X.Type) {
-    needsParent(X.U.self)
-    needsFoo2(X.U.T.self)
+  needsParent(X.U.self)
+  needsFoo2(X.U.T.self)
 }
 struct ConcreteNestedConforms: NestedConforms {
-    typealias U = ConcreteParent
+  typealias U = ConcreteParent
 }
-// FIXME: this should hit "type 'BadConcreteNestedConforms.U.T' (aka 'Float')
-// does not conform to protocol 'Foo2'", but the SubstitutionMap used in
-// ensureRequirementsAreSatified can't find the conformance of Self.U: Parent
-// because it only looks for the conformances implied directly by a protocol's
-// associated types. SubstitutionMap should use the requirement
-// signature/conformance access path.
 struct BadConcreteNestedConforms: NestedConforms {
-    typealias U = ConcreteParentNonFoo2
+  // expected-error@-1 {{type 'ConcreteParentNonFoo2.T' (aka 'Float') does not conform to protocol 'Foo2'}}
+  typealias U = ConcreteParentNonFoo2
 }
diff --git a/test/IDE/Inputs/custom-modules/ImportAsMember.apinotes b/test/IDE/Inputs/custom-modules/ImportAsMember.apinotes
index 2c976ae..e6f05c5 100644
--- a/test/IDE/Inputs/custom-modules/ImportAsMember.apinotes
+++ b/test/IDE/Inputs/custom-modules/ImportAsMember.apinotes
@@ -4,10 +4,26 @@
   SwiftName: Struct1.newApiNoteVar
 - Name: IAMStruct1APINoteVarInSwift4
   SwiftName: Struct1.apiNoteVarInSwift4
+Functions:
+- Name: IAMStruct1APINoteFunction
+  SwiftName: "Struct1.newApiNoteMethod()"
+- Name: IAMStruct1APINoteCreateFunction
+  SwiftName: "Struct1.init(newLabel:)"
+Typedefs:
+- Name: IAMStruct1APINoteType
+  SwiftName: Struct1.NewApiNoteType
 SwiftVersions:
 - Version: 3
   Globals:
   - Name: IAMStruct1APINoteVar
     SwiftName: Struct1.oldApiNoteVar
   - Name: IAMStruct1APINoteVarInSwift4
-    SwiftName: IAMStruct1APINoteVarInSwift4
\ No newline at end of file
+    SwiftName: IAMStruct1APINoteVarInSwift4
+  Functions:
+  - Name: IAMStruct1APINoteFunction
+    SwiftName: "Struct1.oldApiNoteMethod()"
+  - Name: IAMStruct1APINoteCreateFunction
+    SwiftName: "Struct1.init(oldLabel:)"
+  Typedefs:
+  - Name: IAMStruct1APINoteType
+    SwiftName: Struct1.OldApiNoteType
diff --git a/test/IDE/Inputs/custom-modules/ImportAsMemberAPINotes.h b/test/IDE/Inputs/custom-modules/ImportAsMemberAPINotes.h
index 6fa3352..6827f1f 100644
--- a/test/IDE/Inputs/custom-modules/ImportAsMemberAPINotes.h
+++ b/test/IDE/Inputs/custom-modules/ImportAsMemberAPINotes.h
@@ -6,4 +6,9 @@
 extern double IAMStruct1APINoteVar;
 extern double IAMStruct1APINoteVarInSwift4;
 
+extern void IAMStruct1APINoteFunction(void);
+extern struct IAMStruct1 IAMStruct1APINoteCreateFunction(int);
+
+typedef double IAMStruct1APINoteType;
+
 #endif // IMPORT_AS_MEMBER_B_H
diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift
index 6d55e6b..a6815ca 100644
--- a/test/IDE/complete_decl_attribute.swift
+++ b/test/IDE/complete_decl_attribute.swift
@@ -58,12 +58,13 @@
 @#^KEYWORD3^#
 class C {}
 
-// KEYWORD3:                  Begin completions, 7 items
+// KEYWORD3:                  Begin completions, 8 items
 // KEYWORD3-NEXT:             Keyword/None:                       available[#Class Attribute#]; name=available{{$}}
 // KEYWORD3-NEXT:             Keyword/None:                       objc[#Class Attribute#]; name=objc{{$}}
 // KEYWORD3-NEXT:             Keyword/None:                       IBDesignable[#Class Attribute#]; name=IBDesignable{{$}}
 // KEYWORD3-NEXT:             Keyword/None:                       UIApplicationMain[#Class Attribute#]; name=UIApplicationMain{{$}}
 // KEYWORD3-NEXT:             Keyword/None:                       requires_stored_property_inits[#Class Attribute#]; name=requires_stored_property_inits{{$}}
+// KEYWORD3-NEXT:             Keyword/None:                       objcMembers[#Class Attribute#]; name=objcMembers{{$}}
 // KEYWORD3-NEXT:             Keyword/None:                       NSApplicationMain[#Class Attribute#]; name=NSApplicationMain{{$}}
 // KEYWORD3-NEXT:             Keyword/None:                       objc_non_lazy_realization[#Class Attribute#]; name=objc_non_lazy_realization{{$}}
 // KEYWORD3-NEXT:             End completions
@@ -85,7 +86,7 @@
 
 @#^KEYWORD_LAST^#
 
-// KEYWORD_LAST:                  Begin completions, 20 items
+// KEYWORD_LAST:                  Begin completions, 21 items
 // KEYWORD_LAST-NEXT:             Keyword/None:                       available[#Declaration Attribute#]; name=available{{$}}
 // KEYWORD_LAST-NEXT:             Keyword/None:                       objc[#Declaration Attribute#]; name=objc{{$}}
 // KEYWORD_LAST-NEXT:             Keyword/None:                       noreturn[#Declaration Attribute#]; name=noreturn{{$}}
@@ -101,6 +102,7 @@
 // KEYWORD_LAST-NEXT:             Keyword/None:                       autoclosure[#Declaration Attribute#]; name=autoclosure{{$}}
 // KEYWORD_LAST-NEXT:             Keyword/None:                       noescape[#Declaration Attribute#]; name=noescape{{$}}
 // KEYWORD_LAST-NEXT:             Keyword/None:                       nonobjc[#Declaration Attribute#]; name=nonobjc{{$}}
+// KEYWORD_LAST-NEXT:             Keyword/None:                       objcMembers[#Declaration Attribute#]; name=objcMembers{{$}}
 // KEYWORD_LAST-NEXT:             Keyword/None:                       NSApplicationMain[#Declaration Attribute#]; name=NSApplicationMain{{$}}
 // KEYWORD_LAST-NEXT:             Keyword/None:                       objc_non_lazy_realization[#Declaration Attribute#]; name=objc_non_lazy_realization{{$}}
 // KEYWORD_LAST-NEXT:             Keyword/None:                       warn_unqualified_access[#Declaration Attribute#]; name=warn_unqualified_access
diff --git a/test/IDE/complete_with_header_import.swift b/test/IDE/complete_with_header_import.swift
index 41d9086..2da9189 100644
--- a/test/IDE/complete_with_header_import.swift
+++ b/test/IDE/complete_with_header_import.swift
@@ -1,5 +1,9 @@
 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TOP -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TOP
 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TYPE
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %target-swift-ide-test -code-completion -pch-output-dir %t -source-filename %s -code-completion-token=TOP -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TOP
+// RUN: %target-swift-ide-test -code-completion -pch-output-dir %t -source-filename %s -code-completion-token=TYPE -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TYPE
+// RUN: stat %t/*.pch
 
 // REQUIRES: objc_interop
 
diff --git a/test/IDE/import_as_member.swift b/test/IDE/import_as_member.swift
index 0b05739..33ba6da 100644
--- a/test/IDE/import_as_member.swift
+++ b/test/IDE/import_as_member.swift
@@ -7,6 +7,8 @@
 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -I %t -I %S/Inputs/custom-modules -print-module -source-filename %s -module-to-print=ImportAsMember.APINotes -swift-version 3 -always-argument-labels | %FileCheck %s -check-prefix=PRINT-APINOTES-3 -strict-whitespace
 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -I %t -I %S/Inputs/custom-modules -print-module -source-filename %s -module-to-print=ImportAsMember.APINotes -swift-version 4 -always-argument-labels | %FileCheck %s -check-prefix=PRINT-APINOTES-4 -strict-whitespace
 
+// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules
+
 // PRINT: struct Struct1 {
 // PRINT-NEXT:   var x: Double
 // PRINT-NEXT:   var y: Double
@@ -60,9 +62,24 @@
 // PRINT-APINOTES-3-NEXT:   var newApiNoteVar: Double
 // PRINT-APINOTES-3-NEXT:   @available(swift, introduced: 4, renamed: "IAMStruct1APINoteVarInSwift4")
 // PRINT-APINOTES-3-NEXT:   var apiNoteVarInSwift4: Double
+// PRINT-APINOTES-3-NEXT:   static func oldApiNoteMethod()
+// PRINT-APINOTES-3-NEXT:   @available(swift, introduced: 4, renamed: "Struct1.oldApiNoteMethod()")
+// PRINT-APINOTES-3-NEXT:   static func newApiNoteMethod()
+// PRINT-APINOTES-3-NEXT:   init(oldLabel _: Int32)
+// PRINT-APINOTES-3-NEXT:   @available(swift, introduced: 4, renamed: "Struct1.init(oldLabel:)")
+// PRINT-APINOTES-3-NEXT:   init(newLabel _: Int32)
+// PRINT-APINOTES-3-NEXT:   typealias OldApiNoteType = Double
+// PRINT-APINOTES-3-NEXT:   @available(swift, introduced: 4, renamed: "Struct1.OldApiNoteType")
+// PRINT-APINOTES-3-NEXT:   typealias NewApiNoteType = Struct1.OldApiNoteType
 // PRINT-APINOTES-3-NEXT: }
 // PRINT-APINOTES-3-NOT: @available
-// PRINT-APINOTES-3: var IAMStruct1APINoteVarInSwift4: Double
+// PRINT-APINOTES-3:     var IAMStruct1APINoteVarInSwift4: Double
+// PRINT-APINOTES-3:     @available(swift, obsoleted: 3, renamed: "Struct1.oldApiNoteMethod()")
+// PRINT-APINOTES-3-NEXT: func IAMStruct1APINoteFunction()
+// PRINT-APINOTES-3:     @available(swift, obsoleted: 3, renamed: "Struct1.init(oldLabel:)")
+// PRINT-APINOTES-3-NEXT: func IAMStruct1APINoteCreateFunction(_ _: Int32) -> Struct1
+// PRINT-APINOTES-3:      @available(swift, obsoleted: 3, renamed: "Struct1.OldApiNoteType")
+// PRINT-APINOTES-3-NEXT: typealias IAMStruct1APINoteType = Struct1.OldApiNoteType
 
 // PRINT-APINOTES-4:      @available(swift, obsoleted: 3, renamed: "Struct1.newApiNoteVar")
 // PRINT-APINOTES-4-NEXT: var IAMStruct1APINoteVar: Double
@@ -71,11 +88,24 @@
 // PRINT-APINOTES-4-NEXT:   @available(swift, obsoleted: 4, renamed: "Struct1.newApiNoteVar")
 // PRINT-APINOTES-4-NEXT:   var oldApiNoteVar: Double
 // PRINT-APINOTES-4-NEXT:   var apiNoteVarInSwift4: Double
+// PRINT-APINOTES-4-NEXT:   static func newApiNoteMethod()
+// PRINT-APINOTES-4-NEXT:   @available(swift, obsoleted: 4, renamed: "Struct1.newApiNoteMethod()")
+// PRINT-APINOTES-4-NEXT:   static func oldApiNoteMethod()
+// PRINT-APINOTES-4-NEXT:   init(newLabel _: Int32)
+// PRINT-APINOTES-4-NEXT:   @available(swift, obsoleted: 4, renamed: "Struct1.init(newLabel:)")
+// PRINT-APINOTES-4-NEXT:   init(oldLabel _: Int32)
+// PRINT-APINOTES-4-NEXT:   typealias NewApiNoteType = Double
+// PRINT-APINOTES-4-NEXT:   @available(swift, obsoleted: 4, renamed: "Struct1.NewApiNoteType")
+// PRINT-APINOTES-4-NEXT:   typealias OldApiNoteType = Struct1.NewApiNoteType
 // PRINT-APINOTES-4-NEXT: }
 // PRINT-APINOTES-4:      @available(swift, obsoleted: 4, renamed: "Struct1.apiNoteVarInSwift4")
 // PRINT-APINOTES-4-NEXT: var IAMStruct1APINoteVarInSwift4: Double
-
-// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules -verify-ignore-unknown
+// PRINT-APINOTES-4:     @available(swift, obsoleted: 3, renamed: "Struct1.newApiNoteMethod()")
+// PRINT-APINOTES-4-NEXT: func IAMStruct1APINoteFunction()
+// PRINT-APINOTES-4:     @available(swift, obsoleted: 3, renamed: "Struct1.init(newLabel:)")
+// PRINT-APINOTES-4-NEXT: func IAMStruct1APINoteCreateFunction(_ _: Int32) -> Struct1
+// PRINT-APINOTES-4:      @available(swift, obsoleted: 3, renamed: "Struct1.NewApiNoteType")
+// PRINT-APINOTES-4-NEXT: typealias IAMStruct1APINoteType = Struct1.NewApiNoteType
 
 import ImportAsMember.A
 import ImportAsMember.B
@@ -105,8 +135,3 @@
 
 // Global properties
 currentStruct1.x += 1.5
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1CreateSimple' declared here
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1GlobalVar' was obsoleted in Swift 3
-// <unknown>:0: error: unexpected note produced: 'IAMStruct1CreateSimple' was obsoleted in Swift 3
diff --git a/test/IDE/newtype.swift b/test/IDE/newtype.swift
index b09c0bc..97e37a4 100644
--- a/test/IDE/newtype.swift
+++ b/test/IDE/newtype.swift
@@ -3,7 +3,7 @@
 // RUN: %build-clang-importer-objc-overlays
 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk-nosource) -I %t -I %S/Inputs/custom-modules -print-module -source-filename %s -module-to-print=Newtype -skip-unavailable > %t.printed.A.txt
 // RUN: %FileCheck %s -check-prefix=PRINT -strict-whitespace < %t.printed.A.txt
-// RUN: %target-typecheck-verify-swift -sdk %clang-importer-sdk -I %S/Inputs/custom-modules -I %t -verify-ignore-unknown
+// RUN: %target-typecheck-verify-swift -sdk %clang-importer-sdk -I %S/Inputs/custom-modules -I %t
 // REQUIRES: objc_interop
 
 // PRINT-LABEL: struct ErrorDomain : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable {
@@ -180,6 +180,3 @@
 	let _ = NSMyContextName
 	  // expected-error@-1{{'NSMyContextName' has been renamed to 'NSSomeContext.Name.myContextName'}} {{10-25=NSSomeContext.Name.myContextName}}
 }
-
-// FIXME: Remove -verify-ignore-unknown.
-// <unknown>:0: error: unexpected note produced: 'NSMyContextName' was obsoleted in Swift 3
diff --git a/test/IDE/print_synthesized_extensions.swift b/test/IDE/print_synthesized_extensions.swift
index ffb8c31..4994281 100644
--- a/test/IDE/print_synthesized_extensions.swift
+++ b/test/IDE/print_synthesized_extensions.swift
@@ -14,6 +14,7 @@
 // RUN: %FileCheck %s -check-prefix=CHECK11 < %t.syn.txt
 // RUN: %FileCheck %s -check-prefix=CHECK12 < %t.syn.txt
 // RUN: %FileCheck %s -check-prefix=CHECK13 < %t.syn.txt
+// RUN: %FileCheck %s -check-prefix=CHECK14 < %t.syn.txt
 
 public protocol P1 {
   associatedtype T1
@@ -223,6 +224,13 @@
   public func f1(t: T1) -> T1 { return t }
 }
 
+public struct S13 {}
+
+extension S13 : P5 {
+  public typealias T1 = Int
+  public func foo1() {}
+}
+
 // CHECK1: <synthesized>extension <ref:Struct>S1</ref> where T : <ref:Protocol>P2</ref> {
 // CHECK1-NEXT:     <decl:Func>public func <loc>p2member()</loc></decl>
 // CHECK1-NEXT:     <decl:Func>public func <loc>ef1(<decl:Param>t: T</decl>)</loc></decl>
@@ -311,3 +319,12 @@
 // CHECK13-NEXT:   <decl:Func>public func <loc>nomergeFunc(<decl:Param>t: <ref:GenericTypeParam>Self</ref>.T1</decl>)</loc> -> <ref:GenericTypeParam>Self</ref>.T1</decl>
 // CHECK13-NEXT:   <decl:Func>public func <loc>f1(<decl:Param>t: <ref:GenericTypeParam>Self</ref>.T1</decl>)</loc> -> <ref:GenericTypeParam>Self</ref>.T1</decl>
 // CHECK13-NEXT:  }</decl>
+
+// CHECK14: <decl:Struct>public struct <loc>S13</loc> {</decl>
+// CHECK14-NEXT: <decl:Func>/// This is picked
+// CHECK14-NEXT:     public func <loc>foo2()</loc></decl>
+// CHECK14-NEXT: <decl:Func>/// This is picked
+// CHECK14-NEXT:     public func <loc>foo3()</loc></decl>
+// CHECK14-NEXT: <decl:Func>/// This is picked
+// CHECK14-NEXT:     public func <loc>foo4()</loc></decl>
+// CHECK14-NEXT: }</synthesized>
diff --git a/test/IDE/print_types.swift b/test/IDE/print_types.swift
index 974c546..dba1c03 100644
--- a/test/IDE/print_types.swift
+++ b/test/IDE/print_types.swift
@@ -134,7 +134,7 @@
 // FULL:          ConstructorRefCallExpr:[[@LINE-7]] '''GenericStruct<A, B>''' () -> swift_ide_test.GenericStruct<A, B>
 }
 
-func testInGenericFunc2<T : QuxProtocol, U : QuxProtocol>() where T.Qux == U.Qux {}
-// CHECK: FuncDecl '''testInGenericFunc2''' <T, U where T : QuxProtocol, U : QuxProtocol, T.Qux == U.Qux> () -> (){{$}}
-// FULL:  FuncDecl '''testInGenericFunc2''' <T, U where T : QuxProtocol, U : QuxProtocol, T.Qux == U.Qux> () -> (){{$}}
+func testInGenericFunc2<T : QuxProtocol, U : QuxProtocol>(_: T, _: U) where T.Qux == U.Qux {}
+// CHECK: FuncDecl '''testInGenericFunc2''' <T, U where T : QuxProtocol, U : QuxProtocol, T.Qux == U.Qux> (T, U) -> (){{$}}
+// FULL:  FuncDecl '''testInGenericFunc2''' <T, U where T : QuxProtocol, U : QuxProtocol, T.Qux == U.Qux> (T, U) -> (){{$}}
 
diff --git a/test/IRGen/access_control.sil b/test/IRGen/access_control.sil
index bcb81a9..38a472d 100644
--- a/test/IRGen/access_control.sil
+++ b/test/IRGen/access_control.sil
@@ -4,23 +4,23 @@
 import Swift
 
 public struct PublicStruct { var x: Int }
-// CHECK: @_T014access_control12PublicStructVWV = {{(protected )?}}constant
+// CHECK: @_T014access_control12PublicStructVWV = internal constant
 // CHECK: @_T014access_control12PublicStructVMn = {{(protected )?}}constant
 // CHECK: @_T014access_control12PublicStructVMf = internal constant
 
 internal struct InternalStruct { var x: Int }
-// CHECK: @_T014access_control14InternalStructVWV = hidden constant
+// CHECK: @_T014access_control14InternalStructVWV = internal constant
 // CHECK: @_T014access_control14InternalStructVMn = hidden constant
 // CHECK: @_T014access_control14InternalStructVMf = internal constant
 
 private struct PrivateStruct { var x: Int }
-// CHECK: @_T014access_control13PrivateStruct33_8F630B0A1EEF3ED34B761E3ED76C95A8LLVWV = hidden constant
+// CHECK: @_T014access_control13PrivateStruct33_8F630B0A1EEF3ED34B761E3ED76C95A8LLVWV = internal constant
 // CHECK: @_T014access_control13PrivateStruct33_8F630B0A1EEF3ED34B761E3ED76C95A8LLVMn = hidden constant
 // CHECK: @_T014access_control13PrivateStruct33_8F630B0A1EEF3ED34B761E3ED76C95A8LLVMf = internal constant
 
 func local() {
   struct LocalStruct { var x: Int }
-  // CHECK: @_T014access_control5localyyF11LocalStructL_VWV = hidden constant
+  // CHECK: @_T014access_control5localyyF11LocalStructL_VWV = internal constant
   // CHECK: @_T014access_control5localyyF11LocalStructL_VMn = hidden constant
   // CHECK: @_T014access_control5localyyF11LocalStructL_VMf = internal constant
 }
diff --git a/test/IRGen/c_globals.swift b/test/IRGen/c_globals.swift
index e73becd..731d8aa 100644
--- a/test/IRGen/c_globals.swift
+++ b/test/IRGen/c_globals.swift
@@ -20,7 +20,7 @@
   var f: Float = 0
   var i: CInt = 0
   var s: UnsafePointer<CChar>! = nil
-  // CHECK-LABEL: define linkonce_odr hidden swiftcc void @_T09c_globals17testCaptureGlobalyyFyycfU_{{.*}} {
+  // CHECK-LABEL: define internal swiftcc void @_T09c_globals17testCaptureGlobalyyFyycfU_{{.*}} {
   blackHole({ () -> Void in
     // CHECK: @staticFloat
     // CHECK: @staticInt
diff --git a/test/IRGen/class_is_module.swift b/test/IRGen/class_is_module.swift
new file mode 100644
index 0000000..306ed6d
--- /dev/null
+++ b/test/IRGen/class_is_module.swift
@@ -0,0 +1,11 @@
+// RUN: %target-swift-frontend -module-name=Hello -emit-ir %s | %FileCheck %s
+// REQUIRES: OS=macosx
+
+// Check if we mangle the objc runtime name correctly if a class has the same name as the module.
+
+class Hello {}
+
+// CHECK-DAG: _METACLASS_DATA__TtC5Hello5Hello
+// CHECK-DAG: c"_TtC5Hello5Hello\00"
+// CHECK-DAG: _DATA__TtC5Hello5Hello
+
diff --git a/test/IRGen/closure.swift b/test/IRGen/closure.swift
index 4fe4c9b..492d908 100644
--- a/test/IRGen/closure.swift
+++ b/test/IRGen/closure.swift
@@ -11,7 +11,7 @@
 }
 
 // -- Closure entry point
-// CHECK: define linkonce_odr hidden swiftcc i64 @_T07closure1aS2icSi1i_tFS2icfU_(i64, i64)
+// CHECK: define internal swiftcc i64 @_T07closure1aS2icSi1i_tFS2icfU_(i64, i64)
 
 protocol Ordinable {
   func ord() -> Int
@@ -26,7 +26,7 @@
 // CHECK: }
 
 // -- Closure entry point
-// CHECK: define linkonce_odr hidden swiftcc i64 @_T07closure1bS2icx3seq_tAA9OrdinableRzlFS2icfU_(i64, %swift.refcounted*, %swift.type* %T, i8** %T.Ordinable) {{.*}} {
+// CHECK: define internal swiftcc i64 @_T07closure1bS2icx3seq_tAA9OrdinableRzlFS2icfU_(i64, %swift.refcounted*, %swift.type* %T, i8** %T.Ordinable) {{.*}} {
 
 // -- partial_apply stub
 // CHECK: define internal swiftcc i64 @_T07closure1bS2icx3seq_tAA9OrdinableRzlFS2icfU_TA(i64, %swift.refcounted* swiftself) {{.*}} {
diff --git a/test/IRGen/dependent_reabstraction.swift b/test/IRGen/dependent_reabstraction.swift
index a1d9aa9..6dd8224 100644
--- a/test/IRGen/dependent_reabstraction.swift
+++ b/test/IRGen/dependent_reabstraction.swift
@@ -8,7 +8,7 @@
 }
 
 struct X<Y> : A {
-  // CHECK-LABEL: define hidden swiftcc void @_T023dependent_reabstraction1XVyxGAA1AAAlAaEP1by1BQzFTW(%swift.type** noalias nocapture dereferenceable({{.*}}), %T23dependent_reabstraction1XV* noalias nocapture swiftself, %swift.type* %Self, i8** %SelfWitnessTable)
+  // CHECK-LABEL: define internal swiftcc void @_T023dependent_reabstraction1XVyxGAA1AAAlAaEP1by1BQzFTW(%swift.type** noalias nocapture dereferenceable({{.*}}), %T23dependent_reabstraction1XV* noalias nocapture swiftself, %swift.type* %Self, i8** %SelfWitnessTable)
   func b(_ b: X.Type) {
     let x: Any = b
     markUsed(b as X.Type)
diff --git a/test/IRGen/dllexport.swift b/test/IRGen/dllexport.swift
index b0ea8e6..416ef22 100644
--- a/test/IRGen/dllexport.swift
+++ b/test/IRGen/dllexport.swift
@@ -27,8 +27,6 @@
 // CHECK-DAG: @_T09dllexport2ciAA1cCv = dllexport global %T9dllexport1cC* null, align 4
 // CHECK-DAG: @_T09dllexport1pMp = dllexport constant %swift.protocol
 // CHECK-DAG: @_T09dllexport1cCMn = dllexport constant
-// CHECK-DAG: @_T09dllexport1cCML = dllexport global %swift.type* null, align 4
-// CHECK-DAG: @_T09dllexport1dCML = dllexport global %swift.type* null, align 4
 // CHECK-DAG: @_T09dllexport1cCN = dllexport alias %swift.type
 // CHECK-DAG: @_T09dllexport1dCN = dllexport alias %swift.type, bitcast ({{.*}})
 // CHECK-DAG-OPT: @_T09dllexport1dC1m33_C57BA610BA35E21738CC992438E660E9LLyyF = dllexport alias void (), void ()* @_swift_dead_method_stub
diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil
index ac579588..39cb8c5 100644
--- a/test/IRGen/enum.sil
+++ b/test/IRGen/enum.sil
@@ -122,7 +122,7 @@
 // CHECK:   i32 1, i32 0
 // CHECK: }>
 
-// CHECK: @_T04enum16DynamicSingletonOMP = hidden global <{ {{.*}}, [26 x i8*] }> <{
+// CHECK: @_T04enum16DynamicSingletonOMP = internal global <{ {{.*}}, [26 x i8*] }> <{
 // CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSingleton
 // CHECK:   @_T04enum16DynamicSingletonOMn
 // CHECK:   i8* null
@@ -131,7 +131,7 @@
 
 // -- No-payload enums have extra inhabitants in
 //    their value witness table.
-// CHECK: @_T04enum10NoPayloadsOWV = hidden constant [26 x i8*] [
+// CHECK: @_T04enum10NoPayloadsOWV = internal constant [26 x i8*] [
 // -- ...
 // -- size
 // CHECK:   i8* inttoptr ([[WORD:i32|i64]] 1 to i8*),
@@ -149,7 +149,7 @@
 
 // -- Single-payload enums take unused extra inhabitants from their payload
 //    as their own.
-// CHECK: @_T04enum19SinglePayloadNestedOWV = hidden constant [26 x i8*] [
+// CHECK: @_T04enum19SinglePayloadNestedOWV = internal constant [26 x i8*] [
 // -- ...
 // -- size
 // CHECK:   i8* inttoptr ([[WORD]] 1 to i8*),
@@ -166,13 +166,13 @@
 // CHECK: ]
 
 
-// CHECK: @_T04enum20DynamicSinglePayloadOMP = hidden global <{ {{.*}}, [26 x i8*] }> <{
+// CHECK: @_T04enum20DynamicSinglePayloadOMP = internal global <{ {{.*}}, [26 x i8*] }> <{
 // CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSinglePayload
 // CHECK:   i8* null
 // CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum20DynamicSinglePayloadOwxs to i8*)
 // CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum20DynamicSinglePayloadOwxg to i8*)
 
-// CHECK: @_T04enum18MultiPayloadNestedOWV = hidden constant [26 x i8*] [
+// CHECK: @_T04enum18MultiPayloadNestedOWV = internal constant [26 x i8*] [
 // CHECK:   i8* inttoptr ([[WORD]] 9 to i8*),
 // CHECK:   i8* inttoptr ([[WORD]] 16 to i8*)
 // CHECK: ]
diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil
index 6791a92..11156f3 100644
--- a/test/IRGen/enum_value_semantics.sil
+++ b/test/IRGen/enum_value_semantics.sil
@@ -94,7 +94,7 @@
 }
 
 
-// CHECK-LABEL: @_T020enum_value_semantics20SinglePayloadTrivialOWV = hidden constant [26 x i8*] [
+// CHECK-LABEL: @_T020enum_value_semantics20SinglePayloadTrivialOWV = internal constant [26 x i8*] [
 // CHECK:   i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*),
 // CHECK:   i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy9_8 to i8*),
 // CHECK:   i8* bitcast (i8* (i8*, %swift.type*)* @__swift_noop_self_return to i8*),
@@ -133,7 +133,7 @@
 // CHECK-SAME: }>
 
 
-// CHECK-LABEL: @_T020enum_value_semantics23SinglePayloadNontrivialOWV = hidden constant [26 x i8*] [
+// CHECK-LABEL: @_T020enum_value_semantics23SinglePayloadNontrivialOWV = internal constant [26 x i8*] [
 // CHECK:   i8* bitcast (void ([24 x i8]*, %swift.type*)* @_T020enum_value_semantics23SinglePayloadNontrivialOwXX to i8*),
 // CHECK:   i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @_T020enum_value_semantics23SinglePayloadNontrivialOwCP to i8*),
 // CHECK:   i8* bitcast (i8* (i8*, %swift.type*)* @__swift_noop_self_return to i8*),
@@ -175,7 +175,7 @@
 // CHECK-SAME: }>
 
 
-// CHECK-LABEL: @_T020enum_value_semantics18GenericFixedLayoutOMP = hidden global <{{[{].*\* [}]}}> <{
+// CHECK-LABEL: @_T020enum_value_semantics18GenericFixedLayoutOMP = internal global <{{[{].*\* [}]}}> <{
 // CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_GenericFixedLayout
 // CHECK:   i32 48, i16 1, i16 8,
 // CHECK:   [16 x i8*] zeroinitializer,
diff --git a/test/IRGen/field_type_vectors.sil b/test/IRGen/field_type_vectors.sil
index 6e493ba..9908a8c 100644
--- a/test/IRGen/field_type_vectors.sil
+++ b/test/IRGen/field_type_vectors.sil
@@ -12,7 +12,7 @@
 
 // CHECK-LABEL: @_T018field_type_vectors3BarVMn = hidden constant
 // CHECK:         %swift.type** (%swift.type*)* [[BAR_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
-// CHECK-LABEL: @_T018field_type_vectors3BarVMP = hidden global
+// CHECK-LABEL: @_T018field_type_vectors3BarVMP = internal global
 // -- There should be 5 words between the address point and the field type
 //    vector slot, with type %swift.type**
 // CHECK:         i64, i64, i64, i64, %swift.type*, %swift.type**
@@ -22,7 +22,7 @@
 
 // CHECK-LABEL: @_T018field_type_vectors3BasVMn = hidden constant
 // CHECK:         %swift.type** (%swift.type*)* [[BAS_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
-// CHECK-LABEL: @_T018field_type_vectors3BasVMP = hidden global
+// CHECK-LABEL: @_T018field_type_vectors3BasVMP = internal global
 // -- There should be 7 words between the address point and the field type
 //    vector slot, with type %swift.type**
 // CHECK:         i64, i64, i64, i64, i64, %swift.type*, %swift.type*, %swift.type**
@@ -33,7 +33,7 @@
 
 // CHECK-LABEL: @_T018field_type_vectors3ZimCMn = hidden constant
 // CHECK:         %swift.type** (%swift.type*)* [[ZIM_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
-// CHECK-LABEL: @_T018field_type_vectors3ZimCMP = hidden global
+// CHECK-LABEL: @_T018field_type_vectors3ZimCMP = internal global
 // -- There should be 14 words between the address point and the field type
 //    vector slot, with type %swift.type**
 // CHECK:         i64, %swift.type*, %swift.opaque*, %swift.opaque*, i64, i32, i32, i32, i16, i16, i32, i32, i64, i8*, %swift.type*, %swift.type*, i8*, i64, i64, i64, %swift.type**
@@ -48,7 +48,7 @@
 
 // CHECK-LABEL: @_T018field_type_vectors4ZangCMn = hidden constant
 // CHECK:         %swift.type** (%swift.type*)* [[ZANG_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
-// CHECK-LABEL: @_T018field_type_vectors4ZangCMP = hidden global
+// CHECK-LABEL: @_T018field_type_vectors4ZangCMP = internal global
 // -- There should be 16 words between the address point and the field type
 //    vector slot, with type %swift.type**
 // CHECK:         i64, %swift.type*, %swift.opaque*, %swift.opaque*, i64, i32, i32, i32, i16, i16, i32, i32, i64, i8*, %swift.type*, %swift.type*, i8*, i64, i64, i64, %swift.type*, i64, %swift.type**
diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil
index bcd191e..d5ef36b 100644
--- a/test/IRGen/generic_classes.sil
+++ b/test/IRGen/generic_classes.sil
@@ -27,7 +27,7 @@
 // --       generic parameter count, primary count, witness table counts
 // CHECK:   i32 1, i32 1, i32 0
 // CHECK: }
-// CHECK: @_T015generic_classes11RootGenericCMP = hidden global
+// CHECK: @_T015generic_classes11RootGenericCMP = internal global
 // --       template fill function
 // CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_RootGeneric
 // --       nominal type descriptor
@@ -84,7 +84,7 @@
 // CHECK:   {{.*}}* @_T015generic_classes14RootNonGenericCMn
 // CHECK: }>
 
-// CHECK: @_T015generic_classes015GenericInheritsC0CMP = hidden global
+// CHECK: @_T015generic_classes015GenericInheritsC0CMP = internal global
 // --       template fill function
 // CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_GenericInheritsGeneric
 // --       RootGeneric vtable
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index 71182c5..33a52d9 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -26,7 +26,7 @@
 // --       generic parameter count, primary counts; generic parameter witness counts
 // CHECK:   i32 1, i32 1, i32 0
 // CHECK: }>
-// CHECK: @_T015generic_structs13SingleDynamicVMP = hidden global <{ {{.*}} }> <{
+// CHECK: @_T015generic_structs13SingleDynamicVMP = internal global <{ {{.*}} }> <{
 // -- template header
 // CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_SingleDynamic,
 // CHECK:   i32 240, i16 1, i16 8, [{{[0-9]+}} x i8*] zeroinitializer,
@@ -68,7 +68,7 @@
 // CHECK-SAME: i32 4, i32 2, i32 0
 // CHECK-SAME: }>
 
-// CHECK: @_T015generic_structs23DynamicWithRequirementsVMP = hidden global <{ {{.*}} }> <{
+// CHECK: @_T015generic_structs23DynamicWithRequirementsVMP = internal global <{ {{.*}} }> <{
 // -- field offset vector; generic parameter vector
 // CHECK:   i64 0, i64 0, %swift.type* null, %swift.type* null, i8** null, i8** null,
 // CHECK: }>
diff --git a/test/IRGen/generic_types.swift b/test/IRGen/generic_types.swift
index 38145ba..0bcfc5b 100644
--- a/test/IRGen/generic_types.swift
+++ b/test/IRGen/generic_types.swift
@@ -10,7 +10,7 @@
 // CHECK: [[C:%T13generic_types1CC]] = type
 // CHECK: [[D:%T13generic_types1DC]] = type
 
-// CHECK-LABEL: @_T013generic_types1ACMP = hidden global
+// CHECK-LABEL: @_T013generic_types1ACMP = internal global
 // CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_A,
 // CHECK-native-SAME: i32 160,
 // CHECK-objc-SAME:   i32 344,
@@ -36,7 +36,7 @@
 // CHECK-SAME:   void (%swift.opaque*, [[A]]*)* @_T013generic_types1AC3run{{[_0-9a-zA-Z]*}}F
 // CHECK-SAME:   %T13generic_types1AC* (i64, %T13generic_types1AC*)* @_T013generic_types1ACACyxGSi1y_tcfc
 // CHECK-SAME: }
-// CHECK-LABEL: @_T013generic_types1BCMP = hidden global
+// CHECK-LABEL: @_T013generic_types1BCMP = internal global
 // CHECK-SAME:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_B,
 // CHECK-native-SAME: i32 152,
 // CHECK-objc-SAME:   i32 336,
@@ -60,7 +60,7 @@
 // CHECK-SAME:   i32 16,
 // CHECK-SAME:   %swift.type* null
 // CHECK-SAME: }
-// CHECK-LABEL: @_T013generic_types1CCMP = hidden global
+// CHECK-LABEL: @_T013generic_types1CCMP = internal global
 // CHECK-SAME:   void ([[C]]*)* @_T013generic_types1CCfD,
 // CHECK-SAME:   i8** @_T0BoWV,
 // CHECK-SAME:   i64 0,
@@ -71,7 +71,7 @@
 // CHECK-SAME:   i64 1,
 // CHECK-SAME:   void (%swift.opaque*, [[A]]*)* @_T013generic_types1AC3run{{[_0-9a-zA-Z]*}}F
 // CHECK-SAME: }
-// CHECK-LABEL: @_T013generic_types1DCMP = hidden global
+// CHECK-LABEL: @_T013generic_types1DCMP = internal global
 // CHECK-SAME:   void ([[D]]*)* @_T013generic_types1DCfD,
 // CHECK-SAME:   i8** @_T0BoWV,
 // CHECK-SAME:   i64 0,
diff --git a/test/IRGen/indirect_enum.sil b/test/IRGen/indirect_enum.sil
index 63c7617..5976fd3 100644
--- a/test/IRGen/indirect_enum.sil
+++ b/test/IRGen/indirect_enum.sil
@@ -2,8 +2,8 @@
 
 import Swift
 
-// CHECK-64: @_T013indirect_enum5TreeAOWV = hidden constant {{.*}} i8* inttoptr ([[WORD:i64]] 8 to i8*), i8* inttoptr (i64 2162695 to i8*), i8* inttoptr (i64 8 to i8*)
-// CHECK-32: @_T013indirect_enum5TreeAOWV = hidden constant {{.*}} i8* inttoptr ([[WORD:i32]] 4 to i8*), i8* inttoptr (i32 2162691 to i8*), i8* inttoptr (i32 4 to i8*)
+// CHECK-64: @_T013indirect_enum5TreeAOWV = internal constant {{.*}} i8* inttoptr ([[WORD:i64]] 8 to i8*), i8* inttoptr (i64 2162695 to i8*), i8* inttoptr (i64 8 to i8*)
+// CHECK-32: @_T013indirect_enum5TreeAOWV = internal constant {{.*}} i8* inttoptr ([[WORD:i32]] 4 to i8*), i8* inttoptr (i32 2162691 to i8*), i8* inttoptr (i32 4 to i8*)
 
 // CHECK-LABEL: define{{( protected)?}} private %swift.type** @get_field_types_TreeA
 // -- Leaf(T)
diff --git a/test/IRGen/local_types.swift b/test/IRGen/local_types.swift
index 92d21be..5dce78c 100644
--- a/test/IRGen/local_types.swift
+++ b/test/IRGen/local_types.swift
@@ -9,14 +9,14 @@
 import local_types_helper
 
 public func singleFunc() {
-  // CHECK-DAG: @_T011local_types10singleFuncyyF06SingleD6StructL_VWV = hidden constant
+  // CHECK-DAG: @_T011local_types10singleFuncyyF06SingleD6StructL_VWV = internal constant
   struct SingleFuncStruct {
     let i: Int
   }
 }
 
 public let singleClosure: () -> () = {
-  // CHECK-DAG: @_T011local_types13singleClosureyycvfiyycfU_06SingleD6StructL_VWV = hidden constant
+  // CHECK-DAG: @_T011local_types13singleClosureyycvfiyycfU_06SingleD6StructL_VWV = internal constant
   struct SingleClosureStruct {
     let i: Int
   }
@@ -24,7 +24,7 @@
 
 public struct PatternStruct {
   public var singlePattern: Int = ({
-    // CHECK-DAG: @_T011local_types13PatternStructV06singleC0SivfiSiycfU_06SinglecD0L_VWV = hidden constant
+    // CHECK-DAG: @_T011local_types13PatternStructV06singleC0SivfiSiycfU_06SinglecD0L_VWV = internal constant
     struct SinglePatternStruct {
       let i: Int
     }
@@ -33,7 +33,7 @@
 }
 
 public func singleDefaultArgument(i: Int = {
-  // CHECK-DAG: @_T011local_types21singleDefaultArgumentySi1i_tFfA_SiycfU_06SingledE6StructL_VWV = hidden constant
+  // CHECK-DAG: @_T011local_types21singleDefaultArgumentySi1i_tFfA_SiycfU_06SingledE6StructL_VWV = internal constant
   struct SingleDefaultArgumentStruct {
     let i: Int
   }
diff --git a/test/IRGen/metadata_dominance.swift b/test/IRGen/metadata_dominance.swift
index 87607be..909a65c 100644
--- a/test/IRGen/metadata_dominance.swift
+++ b/test/IRGen/metadata_dominance.swift
@@ -79,6 +79,6 @@
 // The protocol witness for metadata_dominance.P.makeFoo () -> metadata_dominance.Foo in
 // conformance metadata_dominance.Foo : metadata_dominance.P should not use the Self type
 // as the type of the object to be created. It should dynamically obtain the type.
-// CHECK-OPT-LABEL: define hidden swiftcc %T18metadata_dominance3FooC* @_T018metadata_dominance3FooCAA1PA2aDP04makeC0ACyFTW
+// CHECK-OPT-LABEL: define internal swiftcc %T18metadata_dominance3FooC* @_T018metadata_dominance3FooCAA1PA2aDP04makeC0ACyFTW
 // CHECK-OPT-NOT: tail call noalias %swift.refcounted* @swift_rt_swift_allocObject(%swift.type* %Self
 
diff --git a/test/IRGen/objc_class_export.swift b/test/IRGen/objc_class_export.swift
index 4db1a24..20a3a1f 100644
--- a/test/IRGen/objc_class_export.swift
+++ b/test/IRGen/objc_class_export.swift
@@ -75,19 +75,19 @@
 }
 
 @objc class Foo {
-  var x = 0
-  class func create() -> Foo {
+  @objc var x = 0
+  @objc class func create() -> Foo {
     return Foo()
   }
 
-  func drawInRect(dirty dirty: NSRect) {
+  @objc func drawInRect(dirty dirty: NSRect) {
   }
   // CHECK: define internal void @_T017objc_class_export3FooC10drawInRectySC6NSRectV5dirty_tFTo([[OPAQUE:%.*]]*, i8*, [[NSRECT]]* byval align 8) unnamed_addr {{.*}} {
   // CHECK:   [[CAST:%[a-zA-Z0-9]+]] = bitcast [[OPAQUE]]* %0 to [[FOO]]*
   // CHECK:   call swiftcc void @_T017objc_class_export3FooC10drawInRectySC6NSRectV5dirty_tF(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [[FOO]]* swiftself [[CAST]])
   // CHECK: }
 
-  func bounds() -> NSRect {
+  @objc func bounds() -> NSRect {
     return NSRect(origin: NSPoint(x: 0, y: 0), 
                   size: NSSize(width: 0, height: 0))
   }
@@ -95,7 +95,7 @@
   // CHECK:   [[CAST:%[a-zA-Z0-9]+]] = bitcast [[OPAQUE4]]* %1 to [[FOO]]*
   // CHECK:   call swiftcc { double, double, double, double } @_T017objc_class_export3FooC6boundsSC6NSRectVyF([[FOO]]* swiftself [[CAST]])
 
-  func convertRectToBacking(r r: NSRect) -> NSRect {
+  @objc func convertRectToBacking(r r: NSRect) -> NSRect {
     return r
   }
   // CHECK: define internal void @_T017objc_class_export3FooC20convertRectToBackingSC6NSRectVAF1r_tFTo([[NSRECT]]* noalias nocapture sret, [[OPAQUE5:%.*]]*, i8*, [[NSRECT]]* byval align 8) unnamed_addr {{.*}} {
diff --git a/test/IRGen/objc_deprecated_objc_thunks.swift b/test/IRGen/objc_deprecated_objc_thunks.swift
new file mode 100644
index 0000000..f00a172
--- /dev/null
+++ b/test/IRGen/objc_deprecated_objc_thunks.swift
@@ -0,0 +1,15 @@
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir -disable-objc-attr-requires-foundation-module | %FileCheck %s
+
+// REQUIRES: CPU=x86_64
+// REQUIRES: objc_interop
+
+import Foundation
+
+class ObjCSubclass : NSObject {
+  func foo() { }
+}
+
+// CHECK-LABEL: define hidden void @_T0016objc_deprecated_A7_thunks12ObjCSubclassC3fooyyFTo(%0*, i8*)
+// CHECK: entry:
+// CHECK: [[SELF:%[0-9]+]] = bitcast %0* %0 to %objc_object*
+// CHECK-NEXT: call void @swift_objc_swift3ImplicitObjCEntrypoint(%objc_object* [[SELF]], i8* %1)
\ No newline at end of file
diff --git a/test/IRGen/objc_generic_protocol_conformance.swift b/test/IRGen/objc_generic_protocol_conformance.swift
index 0c40544..ceea933 100644
--- a/test/IRGen/objc_generic_protocol_conformance.swift
+++ b/test/IRGen/objc_generic_protocol_conformance.swift
@@ -9,5 +9,5 @@
 
 extension Foo: P {}
 
-// SIL-LABEL: sil hidden [transparent] [thunk] @_T0So3FooCyxG33objc_generic_protocol_conformance1PADs9AnyObjectRzlAdEP3fooyyFTW {{.*}} @pseudogeneric
-// IR-LABEL: define hidden swiftcc void @_T0So3FooCyxG33objc_generic_protocol_conformance1PADs9AnyObjectRzlAdEP3fooyyFTW(%TSo3FooC** noalias nocapture swiftself dereferenceable({{4|8}}), %swift.type*{{( %Self)?}}, i8**{{( %SelfWitnessTable)?}})
+// SIL-LABEL: sil private [transparent] [thunk] @_T0So3FooCyxG33objc_generic_protocol_conformance1PADs9AnyObjectRzlAdEP3fooyyFTW {{.*}} @pseudogeneric
+// IR-LABEL: define internal swiftcc void @_T0So3FooCyxG33objc_generic_protocol_conformance1PADs9AnyObjectRzlAdEP3fooyyFTW(%TSo3FooC** noalias nocapture swiftself dereferenceable({{4|8}}), %swift.type*{{( %Self)?}}, i8**{{( %SelfWitnessTable)?}})
diff --git a/test/IRGen/protocol_resilience.sil b/test/IRGen/protocol_resilience.sil
index 14a1664..2bf79b5 100644
--- a/test/IRGen/protocol_resilience.sil
+++ b/test/IRGen/protocol_resilience.sil
@@ -52,7 +52,7 @@
 
 // Witness table for conformance with resilient associated type
 
-// CHECK: @_T019protocol_resilience26ConformsWithResilientAssocVAA03HaseF0AAWP = {{(protected )?}}constant [2 x i8*] [
+// CHECK: @_T019protocol_resilience26ConformsWithResilientAssocVAA03HaseF0AAWP = {{(protected )?}}hidden constant [2 x i8*] [
 // CHECK-SAME:   i8* bitcast (%swift.type* ()* @_T019protocol_resilience23ResilientConformingTypeVMa to i8*),
 // CHECK-SAME:   i8* bitcast (i8** ()* @_T019protocol_resilience23ResilientConformingTypeV010resilient_A005OtherC8ProtocolAAWa to i8*)
 // CHECK-SAME: ]
@@ -383,6 +383,6 @@
 
 // Fragile conformance -- no runtime calls needed
 
-// CHECK-LABEL: define{{( protected)?}} i8** @_T019protocol_resilience16ConformingStructVAA17ResilientProtocolAAWa()
+// CHECK-LABEL: define{{( protected)?}} hidden i8** @_T019protocol_resilience16ConformingStructVAA17ResilientProtocolAAWa()
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    ret i8** getelementptr inbounds ([8 x i8*], [8 x i8*]* @_T019protocol_resilience16ConformingStructVAA17ResilientProtocolAAWP, i32 0, i32 0)
diff --git a/test/IRGen/struct_layout.sil b/test/IRGen/struct_layout.sil
index a25f432..69be487 100644
--- a/test/IRGen/struct_layout.sil
+++ b/test/IRGen/struct_layout.sil
@@ -9,9 +9,9 @@
 // 64: %T4main14Rdar15410780_CV = type <{ %TSSSg }>
 // 64: %TSSSg = type <{ [24 x i8], [1 x i8] }>
 
-// 64: @_T04main14Rdar15410780_AVWV = hidden constant {{.*}} (i64 257
-// 64: @_T04main14Rdar15410780_BVWV = hidden constant {{.*}} (i64 258
-// 64: @_T04main14Rdar15410780_CVWV = hidden constant {{.*}} (i64 25
+// 64: @_T04main14Rdar15410780_AVWV = internal constant {{.*}} (i64 257
+// 64: @_T04main14Rdar15410780_BVWV = internal constant {{.*}} (i64 258
+// 64: @_T04main14Rdar15410780_CVWV = internal constant {{.*}} (i64 25
 
 
 // 32: %T4main14Rdar15410780_AV = type <{ i2048, %Ts4Int8V }>
@@ -20,9 +20,9 @@
 // 32: %T4main14Rdar15410780_CV = type <{ %TSSSg }>
 // 32: %TSSSg = type <{ [12 x i8], [1 x i8] }>
 
-// 32: @_T04main14Rdar15410780_AVWV = hidden constant {{.*}} (i32 257
-// 32: @_T04main14Rdar15410780_BVWV = hidden constant {{.*}} (i32 258
-// 32: @_T04main14Rdar15410780_CVWV = hidden constant {{.*}} (i32 13
+// 32: @_T04main14Rdar15410780_AVWV = internal constant {{.*}} (i32 257
+// 32: @_T04main14Rdar15410780_BVWV = internal constant {{.*}} (i32 258
+// 32: @_T04main14Rdar15410780_CVWV = internal constant {{.*}} (i32 13
 
 
 // <rdar://problem/15410780>
diff --git a/test/IRGen/type_layout.swift b/test/IRGen/type_layout.swift
index fe847b2..7c6241b 100644
--- a/test/IRGen/type_layout.swift
+++ b/test/IRGen/type_layout.swift
@@ -16,7 +16,7 @@
 @_alignment(4)
 struct CommonLayout { var x,y,z,w: Int8 }
 
-// CHECK:       @_T011type_layout14TypeLayoutTestVMP = hidden global {{.*}} @create_generic_metadata_TypeLayoutTest
+// CHECK:       @_T011type_layout14TypeLayoutTestVMP = internal global {{.*}} @create_generic_metadata_TypeLayoutTest
 // CHECK:       define private %swift.type* @create_generic_metadata_TypeLayoutTest
 struct TypeLayoutTest<T> {
   // -- dynamic layout, projected from metadata
diff --git a/test/IRGen/type_layout_objc.swift b/test/IRGen/type_layout_objc.swift
index 748b586..240a08c 100644
--- a/test/IRGen/type_layout_objc.swift
+++ b/test/IRGen/type_layout_objc.swift
@@ -20,7 +20,7 @@
 @_alignment(4)
 struct CommonLayout { var x,y,z,w: Int8 }
 
-// CHECK:       @_T016type_layout_objc14TypeLayoutTestVMP = hidden global {{.*}} @create_generic_metadata_TypeLayoutTest
+// CHECK:       @_T016type_layout_objc14TypeLayoutTestVMP = internal global {{.*}} @create_generic_metadata_TypeLayoutTest
 // CHECK:       define private %swift.type* @create_generic_metadata_TypeLayoutTest
 struct TypeLayoutTest<T> {
   // -- dynamic layout, projected from metadata
diff --git a/test/IRGen/type_layout_reference_storage.swift b/test/IRGen/type_layout_reference_storage.swift
index 5c7f182..65ede45 100644
--- a/test/IRGen/type_layout_reference_storage.swift
+++ b/test/IRGen/type_layout_reference_storage.swift
@@ -4,7 +4,7 @@
 protocol P: class {}
 protocol Q: class {}
 
-// CHECK: @_T029type_layout_reference_storage26ReferenceStorageTypeLayoutVMP = hidden global {{.*}} @create_generic_metadata_ReferenceStorageTypeLayout
+// CHECK: @_T029type_layout_reference_storage26ReferenceStorageTypeLayoutVMP = internal global {{.*}} @create_generic_metadata_ReferenceStorageTypeLayout
 // CHECK: define private %swift.type* @create_generic_metadata_ReferenceStorageTypeLayout
 struct ReferenceStorageTypeLayout<T> {
   var z: T
diff --git a/test/IRGen/type_layout_reference_storage_objc.swift b/test/IRGen/type_layout_reference_storage_objc.swift
index 1fb59d6..f6db95b 100644
--- a/test/IRGen/type_layout_reference_storage_objc.swift
+++ b/test/IRGen/type_layout_reference_storage_objc.swift
@@ -8,7 +8,7 @@
 @objc protocol Q {}
 protocol NonObjC: class {}
 
-// CHECK: @_T034type_layout_reference_storage_objc26ReferenceStorageTypeLayoutVMP = hidden global {{.*}} @create_generic_metadata_ReferenceStorageTypeLayout
+// CHECK: @_T034type_layout_reference_storage_objc26ReferenceStorageTypeLayoutVMP = internal global {{.*}} @create_generic_metadata_ReferenceStorageTypeLayout
 // CHECK: define private %swift.type* @create_generic_metadata_ReferenceStorageTypeLayout
 struct ReferenceStorageTypeLayout<T> {
   var z: T
diff --git a/test/Index/roles.swift b/test/Index/roles.swift
index dd75f6b..f989ba3 100644
--- a/test/Index/roles.swift
+++ b/test/Index/roles.swift
@@ -338,23 +338,41 @@
   func fooCommon()
   func foo1()
   func foo2()
+  func foo3(a : Int)
+  func foo3(a : String)
 }
 
 protocol ProtDerived : ProtRoot {
   func fooCommon()
   func bar1()
   func bar2()
+  func bar3(_ : Int)
+  func bar3(_ : String)
 }
 
 extension ProtDerived {
   func fooCommon() {}
-  // CHECK: 350:8 | instance-method/Swift | fooCommon() | s:14swift_ide_test11ProtDerivedPAAE9fooCommonyyF | Def,RelChild,RelOver | rel: 2
+  // CHECK: 354:8 | instance-method/Swift | fooCommon() | s:14swift_ide_test11ProtDerivedPAAE9fooCommonyyF | Def,RelChild,RelOver | rel: 3
   // CHECK-NEXT: RelOver | instance-method/Swift | fooCommon() | s:14swift_ide_test11ProtDerivedP9fooCommonyyF
+  // CHECK-NEXT: RelOver | instance-method/Swift | fooCommon() | s:14swift_ide_test8ProtRootP9fooCommonyyF
 
   func foo1() {}
-  // FIXME: This should override foo1 from ProtRoot.
+  // CHECK: 359:8 | instance-method/Swift | foo1() | s:14swift_ide_test11ProtDerivedPAAE4foo1yyF | Def,RelChild,RelOver | rel: 2
+  // CHECK-NEXT: RelOver | instance-method/Swift | foo1() | s:14swift_ide_test8ProtRootP4foo1yyF
 
   func bar1() {}
-  // CHECK: 357:8 | instance-method/Swift | bar1() | s:14swift_ide_test11ProtDerivedPAAE4bar1yyF | Def,RelChild,RelOver | rel: 2
+  // CHECK: 363:8 | instance-method/Swift | bar1() | s:14swift_ide_test11ProtDerivedPAAE4bar1yyF | Def,RelChild,RelOver | rel: 2
   // CHECK-NEXT: RelOver | instance-method/Swift | bar1() | s:14swift_ide_test11ProtDerivedP4bar1yyF
+
+  func foo3(a : Int) {}
+  // CHECK: 367:8 | instance-method/Swift | foo3(a:) | s:14swift_ide_test11ProtDerivedPAAE4foo3ySi1a_tF | Def,RelChild,RelOver | rel: 2
+  // CHECK-NEXT: RelOver | instance-method/Swift | foo3(a:) | s:14swift_ide_test8ProtRootP4foo3ySi1a_tF
+
+  func foo3(a : String) {}
+  // CHECK: 371:8 | instance-method/Swift | foo3(a:) | s:14swift_ide_test11ProtDerivedPAAE4foo3ySS1a_tF | Def,RelChild,RelOver | rel: 2
+  // CHECK-NEXT: RelOver | instance-method/Swift | foo3(a:) | s:14swift_ide_test8ProtRootP4foo3ySS1a_tF
+
+  func bar3(_ : Int) {}
+  // CHECK: 375:8 | instance-method/Swift | bar3(_:) | s:14swift_ide_test11ProtDerivedPAAE4bar3ySiF | Def,RelChild,RelOver | rel: 2
+  // CHECK-NEXT: RelOver | instance-method/Swift | bar3(_:) | s:14swift_ide_test11ProtDerivedP4bar3ySiF
 }
diff --git a/test/Inputs/clang-importer-sdk/swift-modules/Foundation.swift b/test/Inputs/clang-importer-sdk/swift-modules/Foundation.swift
index 68ee75c..34d8874 100644
--- a/test/Inputs/clang-importer-sdk/swift-modules/Foundation.swift
+++ b/test/Inputs/clang-importer-sdk/swift-modules/Foundation.swift
@@ -351,7 +351,7 @@
 }
 
 extension NSDictionary {
-  public subscript(_: Any) -> Any? {
+  @objc public subscript(_: Any) -> Any? {
     @objc(_swift_objectForKeyedSubscript:)
     get { fatalError() }
   }
diff --git a/test/Inputs/clang-importer-sdk/usr/include/Foundation.h b/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
index 95ce3b8..1117d44 100644
--- a/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
+++ b/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
@@ -257,6 +257,9 @@
 @interface NSURL : NSObject
 - (instancetype)URLWithString:(NSString *)URLString;
 + (instancetype)URLWithString:(NSString *)URLString;
+- (BOOL)getResourceValue:(out id _Nullable *)value
+                  forKey:(NSString *)key
+                   error:(out NSError *_Nullable *)error;
 @end
 
 @interface NSAttributedString : NSString
diff --git a/test/Inputs/comment_to_something_conversion.swift b/test/Inputs/comment_to_something_conversion.swift
index 893553f..85b339a 100644
--- a/test/Inputs/comment_to_something_conversion.swift
+++ b/test/Inputs/comment_to_something_conversion.swift
@@ -10,12 +10,12 @@
 // CHECK: {{.*}}DocCommentAsXML=[<Class file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>A010_AttachToEntities</Name><USR>c:objc(cs)A010_AttachToEntities</USR><Declaration>@objc public class A010_AttachToEntities</Declaration><Abstract><Para>Aaa.  A010.  Bbb.</Para></Abstract></Class>]
 
 /// Aaa.  init().
-public init() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>init()</Name><USR>c:objc(cs)A010_AttachToEntities(im)init</USR><Declaration>public init()</Declaration><Abstract><Para>Aaa.  init().</Para></Abstract></Function>]
+@objc public init() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>init()</Name><USR>c:objc(cs)A010_AttachToEntities(im)init</USR><Declaration>@objc public init()</Declaration><Abstract><Para>Aaa.  init().</Para></Abstract></Function>]
 
 /// Aaa.  subscript(i: Int).
-public subscript(i: Int) -> Int {
-// CHECK: {{.*}}DocCommentAsXML=[<Other file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>subscript(_:)</Name><USR>s:14swift_ide_test21A010_AttachToEntitiesC9subscriptS2ici</USR><Declaration>public subscript(i: Int) -&gt; Int { get set }</Declaration><Abstract><Para>Aaa.  subscript(i: Int).</Para></Abstract></Other>]
+@objc public subscript(i: Int) -> Int {
+// CHECK: {{.*}}DocCommentAsXML=[<Other file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>subscript(_:)</Name><USR>s:14swift_ide_test21A010_AttachToEntitiesC9subscriptS2ici</USR><Declaration>@objc public subscript(i: Int) -&gt; Int { get set }</Declaration><Abstract><Para>Aaa.  subscript(i: Int).</Para></Abstract></Other>]
     get {
 // CHECK: {{.*}}DocCommentAsXML=none
       return 0
@@ -26,12 +26,12 @@
 // CHECK: {{.*}}DocCommentAsXML=none
 
 /// Aaa.  v1.
-public var v1: Int = 0
-// CHECK: {{.*}}DocCommentAsXML=[<Other file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>v1</Name><USR>c:objc(cs)A010_AttachToEntities(py)v1</USR><Declaration>public var v1: Int</Declaration><Abstract><Para>Aaa.  v1.</Para></Abstract></Other>]
+@objc public var v1: Int = 0
+// CHECK: {{.*}}DocCommentAsXML=[<Other file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>v1</Name><USR>c:objc(cs)A010_AttachToEntities(py)v1</USR><Declaration>@objc public var v1: Int</Declaration><Abstract><Para>Aaa.  v1.</Para></Abstract></Other>]
 
 /// Aaa.  v2.
-public class var v2: Int { return 0 }
-// CHECK: {{.*}}DocCommentAsXML=[<Other file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>v2</Name><USR>c:objc(cs)A010_AttachToEntities(cpy)v2</USR><Declaration>public class var v2: Int { get }</Declaration><Abstract><Para>Aaa.  v2.</Para></Abstract></Other>]
+@objc public class var v2: Int { return 0 }
+// CHECK: {{.*}}DocCommentAsXML=[<Other file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>v2</Name><USR>c:objc(cs)A010_AttachToEntities(cpy)v2</USR><Declaration>@objc public class var v2: Int { get }</Declaration><Abstract><Para>Aaa.  v2.</Para></Abstract></Other>]
 // CHECK: {{.*}}DocCommentAsXML=none
 }
 
@@ -58,8 +58,8 @@
   ///
   /// LEVEL TWO
   /// ---------
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)ATXHeaders(im)f0</USR><Declaration>public func f0()</Declaration><Discussion><rawHTML><![CDATA[<h1>]]></rawHTML>LEVEL ONE<rawHTML><![CDATA[</h1>]]></rawHTML><rawHTML><![CDATA[<h2>]]></rawHTML>LEVEL TWO<rawHTML><![CDATA[</h2>]]></rawHTML></Discussion></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)ATXHeaders(im)f0</USR><Declaration>@objc public func f0()</Declaration><Discussion><rawHTML><![CDATA[<h1>]]></rawHTML>LEVEL ONE<rawHTML><![CDATA[</h1>]]></rawHTML><rawHTML><![CDATA[<h2>]]></rawHTML>LEVEL TWO<rawHTML><![CDATA[</h2>]]></rawHTML></Discussion></Function>]
 }
 
 @objc public class AutomaticLink {
@@ -67,8 +67,8 @@
   /// And now for a URL.
   ///
   /// <http://developer.apple.com/swift/>
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)AutomaticLink(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>And now for a URL.</Para></Abstract><Discussion><Para><Link href="http://developer.apple.com/swift/">http://developer.apple.com/swift/</Link></Para></Discussion></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)AutomaticLink(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>And now for a URL.</Para></Abstract><Discussion><Para><Link href="http://developer.apple.com/swift/">http://developer.apple.com/swift/</Link></Para></Discussion></Function>]
 }
 
 @objc public class BlockQuote {
@@ -78,40 +78,40 @@
   /// > Bbb.
   ///
   /// > Ccc.
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)BlockQuote(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>Aaa.</Para></Abstract><Discussion><Para>Bbb.</Para><Para>Ccc.</Para></Discussion></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)BlockQuote(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>Aaa.</Para></Abstract><Discussion><Para>Bbb.</Para><Para>Ccc.</Para></Discussion></Function>]
 }
 
 @objc public class Brief {
 // CHECK: {{.*}}DocCommentAsXML=none
   /// Aaa.
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)Brief(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>Aaa.</Para></Abstract></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)Brief(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>Aaa.</Para></Abstract></Function>]
 
   /// Aaa.
   ///
   /// Bbb.
-  public func f1() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f1()</Name><USR>c:objc(cs)Brief(im)f1</USR><Declaration>public func f1()</Declaration><Abstract><Para>Aaa.</Para></Abstract><Discussion><Para>Bbb.</Para></Discussion></Function>]
+  @objc public func f1() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f1()</Name><USR>c:objc(cs)Brief(im)f1</USR><Declaration>@objc public func f1()</Declaration><Abstract><Para>Aaa.</Para></Abstract><Discussion><Para>Bbb.</Para></Discussion></Function>]
 
   /// Aaa.
   ///
   ///> Bbb.
-  public func f2() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f2()</Name><USR>c:objc(cs)Brief(im)f2</USR><Declaration>public func f2()</Declaration><Abstract><Para>Aaa.</Para></Abstract><Discussion><Para>Bbb.</Para></Discussion></Function>]
+  @objc public func f2() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f2()</Name><USR>c:objc(cs)Brief(im)f2</USR><Declaration>@objc public func f2()</Declaration><Abstract><Para>Aaa.</Para></Abstract><Discussion><Para>Bbb.</Para></Discussion></Function>]
 
   /// Aaa.
   ///
   /// Bbb.
-  public func f3() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f3()</Name><USR>c:objc(cs)Brief(im)f3</USR><Declaration>public func f3()</Declaration><Abstract><Para>Aaa.</Para></Abstract><Discussion><Para>Bbb.</Para></Discussion></Function>]
+  @objc public func f3() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f3()</Name><USR>c:objc(cs)Brief(im)f3</USR><Declaration>@objc public func f3()</Declaration><Abstract><Para>Aaa.</Para></Abstract><Discussion><Para>Bbb.</Para></Discussion></Function>]
 }
 
 @objc public class ClosingComments {
 // CHECK: {{.*}}DocCommentAsXML=none
   /// Some comment. */
-  public func closingComment() {}
-// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>closingComment()</Name><USR>c:objc(cs)ClosingComments(im)closingComment</USR><Declaration>public func closingComment()</Declaration><Abstract><Para>Some comment. */</Para></Abstract></Function>]
+  @objc public func closingComment() {}
+// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>closingComment()</Name><USR>c:objc(cs)ClosingComments(im)closingComment</USR><Declaration>@objc public func closingComment()</Declaration><Abstract><Para>Some comment. */</Para></Abstract></Function>]
 }
 
 @objc public class ClosureContainer {
@@ -159,43 +159,43 @@
   ///     f0() // WOW!
   ///     f0() // WOW!
   ///     f0() // WOW!
-  public func f0() {}
-// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)CodeBlock(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>This is how you use this code.</Para></Abstract><Discussion><CodeListing language="swift"><zCodeLineNumbered><![CDATA[f0() // WOW!]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[f0() // WOW!]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[f0() // WOW!]]></zCodeLineNumbered><zCodeLineNumbered></zCodeLineNumbered></CodeListing></Discussion></Function>]
+  @objc public func f0() {}
+// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)CodeBlock(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>This is how you use this code.</Para></Abstract><Discussion><CodeListing language="swift"><zCodeLineNumbered><![CDATA[f0() // WOW!]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[f0() // WOW!]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[f0() // WOW!]]></zCodeLineNumbered><zCodeLineNumbered></zCodeLineNumbered></CodeListing></Discussion></Function>]
 }
 
 @objc public class Emphasis {
 // CHECK: {{.*}}DocCommentAsXML=none
   /// Aaa *bbb* ccc.
   /// Aaa _bbb_ ccc.
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)Emphasis(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>Aaa <emphasis>bbb</emphasis> ccc. Aaa <emphasis>bbb</emphasis> ccc.</Para></Abstract></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)Emphasis(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>Aaa <emphasis>bbb</emphasis> ccc. Aaa <emphasis>bbb</emphasis> ccc.</Para></Abstract></Function>]
 }
 
 @objc public class EmptyComments {
 // CHECK: {{.*}}DocCommentAsXML=none
 
   ///
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)EmptyComments(im)f0</USR><Declaration>public func f0()</Declaration></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)EmptyComments(im)f0</USR><Declaration>@objc public func f0()</Declaration></Function>]
 
   /// Aaa.
-  public func f1() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f1()</Name><USR>c:objc(cs)EmptyComments(im)f1</USR><Declaration>public func f1()</Declaration><Abstract><Para>Aaa.</Para></Abstract></Function>]
+  @objc public func f1() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f1()</Name><USR>c:objc(cs)EmptyComments(im)f1</USR><Declaration>@objc public func f1()</Declaration><Abstract><Para>Aaa.</Para></Abstract></Function>]
 
   /** */
-  public func f2() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f2()</Name><USR>c:objc(cs)EmptyComments(im)f2</USR><Declaration>public func f2()</Declaration></Function>]
+  @objc public func f2() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f2()</Name><USR>c:objc(cs)EmptyComments(im)f2</USR><Declaration>@objc public func f2()</Declaration></Function>]
 
   /**
    */
-  public func f3() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f3()</Name><USR>c:objc(cs)EmptyComments(im)f3</USR><Declaration>public func f3()</Declaration></Function>]
+  @objc public func f3() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f3()</Name><USR>c:objc(cs)EmptyComments(im)f3</USR><Declaration>@objc public func f3()</Declaration></Function>]
 
   /**
    * Aaa.
    */
-  public func f4() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f4()</Name><USR>c:objc(cs)EmptyComments(im)f4</USR><Declaration>public func f4()</Declaration><Abstract><Para>Aaa.</Para></Abstract></Function>]
+  @objc public func f4() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f4()</Name><USR>c:objc(cs)EmptyComments(im)f4</USR><Declaration>@objc public func f4()</Declaration><Abstract><Para>Aaa.</Para></Abstract></Function>]
 }
 
 @objc public class HasThrowingFunction {
@@ -216,8 +216,8 @@
   /// ------------------------------------
   ///
   /// The end.
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)HorizontalRules(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>Briefly.</Para></Abstract><Discussion><rawHTML><![CDATA[<hr/>]]></rawHTML><Para>The end.</Para></Discussion></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)HorizontalRules(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>Briefly.</Para></Abstract><Discussion><rawHTML><![CDATA[<hr/>]]></rawHTML><Para>The end.</Para></Discussion></Function>]
 }
 
 @objc public class ImplicitNameLink {
@@ -225,7 +225,7 @@
   /// [Apple][]
   ///
   /// [Apple]: https://www.apple.com/
-  public func f0() {}
+  @objc public func f0() {}
 }
 
 @objc public class IndentedBlockComment {
@@ -242,8 +242,8 @@
           // var y = 2
           var z = 3
   */
-  public func f1() {}
-// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f1()</Name><USR>c:objc(cs)IndentedBlockComment(im)f1</USR><Declaration>public func f1()</Declaration><Abstract><Para>Brief.</Para></Abstract><Discussion><Para>First paragraph line. Second paragraph line.</Para><Para>Now for a code sample:</Para><CodeListing language="swift"><zCodeLineNumbered><![CDATA[var x = 1]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[// var y = 2]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[var z = 3]]></zCodeLineNumbered><zCodeLineNumbered></zCodeLineNumbered></CodeListing></Discussion></Function>]
+  @objc public func f1() {}
+// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f1()</Name><USR>c:objc(cs)IndentedBlockComment(im)f1</USR><Declaration>@objc public func f1()</Declaration><Abstract><Para>Brief.</Para></Abstract><Discussion><Para>First paragraph line. Second paragraph line.</Para><Para>Now for a code sample:</Para><CodeListing language="swift"><zCodeLineNumbered><![CDATA[var x = 1]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[// var y = 2]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[var z = 3]]></zCodeLineNumbered><zCodeLineNumbered></zCodeLineNumbered></CodeListing></Discussion></Function>]
   /**
                         Hugely indented brief.
 
@@ -256,22 +256,22 @@
                             // var y = 2
                             var z = 3
   */
-  public func f2() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f2()</Name><USR>c:objc(cs)IndentedBlockComment(im)f2</USR><Declaration>public func f2()</Declaration><Abstract><Para>Hugely indented brief.</Para></Abstract><Discussion><Para>First paragraph line. Second paragraph line.</Para><Para>Now for a code sample:</Para><CodeListing language="swift"><zCodeLineNumbered><![CDATA[var x = 1]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[// var y = 2]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[var z = 3]]></zCodeLineNumbered><zCodeLineNumbered></zCodeLineNumbered></CodeListing></Discussion></Function>]
+  @objc public func f2() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f2()</Name><USR>c:objc(cs)IndentedBlockComment(im)f2</USR><Declaration>@objc public func f2()</Declaration><Abstract><Para>Hugely indented brief.</Para></Abstract><Discussion><Para>First paragraph line. Second paragraph line.</Para><Para>Now for a code sample:</Para><CodeListing language="swift"><zCodeLineNumbered><![CDATA[var x = 1]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[// var y = 2]]></zCodeLineNumbered><zCodeLineNumbered><![CDATA[var z = 3]]></zCodeLineNumbered><zCodeLineNumbered></zCodeLineNumbered></CodeListing></Discussion></Function>]
 }
 
 @objc public class InlineCode {
 // CHECK: {{.*}}DocCommentAsXML=none
   /// Aaa `bbb` ccc.
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)InlineCode(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>Aaa <codeVoice>bbb</codeVoice> ccc.</Para></Abstract></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)InlineCode(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>Aaa <codeVoice>bbb</codeVoice> ccc.</Para></Abstract></Function>]
 }
 
 @objc public class InlineLink {
 // CHECK: {{.*}}DocCommentAsXML=none
 /// Aaa [bbb](/path/to/something) ccc.
-public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)InlineLink(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>Aaa <Link href="/path/to/something">bbb</Link> ccc.</Para></Abstract></Function>]
+@objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)InlineLink(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>Aaa <Link href="/path/to/something">bbb</Link> ccc.</Para></Abstract></Function>]
 }
 
 @objc public class MultiLineBrief {
@@ -281,8 +281,8 @@
   /// Brief after softbreak.
   ///
   /// Some paragraph text.
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)MultiLineBrief(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>Brief first line. Brief after softbreak.</Para></Abstract><Discussion><Para>Some paragraph text.</Para></Discussion></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)MultiLineBrief(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>Brief first line. Brief after softbreak.</Para></Abstract><Discussion><Para>Some paragraph text.</Para></Discussion></Function>]
 }
 
 @objc public class OrderedList {
@@ -291,8 +291,8 @@
 ///
 /// 2. Bbb.
 ///    Ccc.
-public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)OrderedList(im)f0</USR><Declaration>public func f0()</Declaration><Discussion><List-Number><Item><Para>Aaa.</Para></Item><Item><Para>Bbb. Ccc.</Para></Item></List-Number></Discussion></Function>]
+@objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)OrderedList(im)f0</USR><Declaration>@objc public func f0()</Declaration><Discussion><List-Number><Item><Para>Aaa.</Para></Item><Item><Para>Bbb. Ccc.</Para></Item></List-Number></Discussion></Function>]
 }
 
 /// - parameter x: A number
@@ -304,8 +304,8 @@
 ///
 /// - parameter second: Ccc.  Ddd.
 ///   Eee.
-public func f0(_ first: Int, second: Double) {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0(_:second:)</Name><USR>c:objc(cs)ParamAndReturns(im)f0:second:</USR><Declaration>public func f0(_ first: Int, second: Double)</Declaration><Abstract><Para>Aaa.  f0.</Para></Abstract><Parameters><Parameter><Name>first</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Bbb.</Para></Discussion></Parameter><Parameter><Name>second</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Ccc.  Ddd. Eee.</Para></Discussion></Parameter></Parameters></Function>]
+@objc public func f0(_ first: Int, second: Double) {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0(_:second:)</Name><USR>c:objc(cs)ParamAndReturns(im)f0:second:</USR><Declaration>@objc public func f0(_ first: Int, second: Double)</Declaration><Abstract><Para>Aaa.  f0.</Para></Abstract><Parameters><Parameter><Name>first</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Bbb.</Para></Discussion></Parameter><Parameter><Name>second</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Ccc.  Ddd. Eee.</Para></Discussion></Parameter></Parameters></Function>]
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
 
@@ -315,8 +315,8 @@
 ///
 /// - returns: Ccc.
 ///   Ddd.
-public func f1(_ first: Int) {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f1(_:)</Name><USR>c:objc(cs)ParamAndReturns(im)f1:</USR><Declaration>public func f1(_ first: Int)</Declaration><Abstract><Para>Aaa.  f1.</Para></Abstract><Parameters><Parameter><Name>first</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Bbb.</Para></Discussion></Parameter></Parameters><ResultDiscussion><Para>Ccc. Ddd.</Para></ResultDiscussion></Function>]
+@objc public func f1(_ first: Int) {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f1(_:)</Name><USR>c:objc(cs)ParamAndReturns(im)f1:</USR><Declaration>@objc public func f1(_ first: Int)</Declaration><Abstract><Para>Aaa.  f1.</Para></Abstract><Parameters><Parameter><Name>first</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Bbb.</Para></Discussion></Parameter></Parameters><ResultDiscussion><Para>Ccc. Ddd.</Para></ResultDiscussion></Function>]
 // CHECK: {{.*}}DocCommentAsXML=none
 
 /// Aaa.  f2.
@@ -327,8 +327,8 @@
 ///
 /// - parameter third:
 ///   Bbb.
-public func f2(_ first: Int, second: Double, third: Float) {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f2(_:second:third:)</Name><USR>c:objc(cs)ParamAndReturns(im)f2:second:third:</USR><Declaration>public func f2(_ first: Int, second: Double, third: Float)</Declaration><Abstract><Para>Aaa.  f2.</Para></Abstract><Parameters><Parameter><Name>first</Name><Direction isExplicit="0">in</Direction><Discussion><Para></Para></Discussion></Parameter><Parameter><Name>second</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Aaa.</Para></Discussion></Parameter><Parameter><Name>third</Name><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb.</Para></Discussion></Parameter></Parameters></Function>]
+@objc public func f2(_ first: Int, second: Double, third: Float) {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f2(_:second:third:)</Name><USR>c:objc(cs)ParamAndReturns(im)f2:second:third:</USR><Declaration>@objc public func f2(_ first: Int, second: Double, third: Float)</Declaration><Abstract><Para>Aaa.  f2.</Para></Abstract><Parameters><Parameter><Name>first</Name><Direction isExplicit="0">in</Direction><Discussion><Para></Para></Discussion></Parameter><Parameter><Name>second</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Aaa.</Para></Discussion></Parameter><Parameter><Name>third</Name><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb.</Para></Discussion></Parameter></Parameters></Function>]
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
@@ -338,8 +338,8 @@
 /// - parameter first: Bbb.
 /// - parameter second: Ccc.
 /// - parameter third: Ddd.
-public func f3(_ first: Int, second: Double, third: Float) {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f3(_:second:third:)</Name><USR>c:objc(cs)ParamAndReturns(im)f3:second:third:</USR><Declaration>public func f3(_ first: Int, second: Double, third: Float)</Declaration><Abstract><Para>Aaa.  f3.</Para></Abstract><Parameters><Parameter><Name>first</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Bbb.</Para></Discussion></Parameter><Parameter><Name>second</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Ccc.</Para></Discussion></Parameter><Parameter><Name>third</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Ddd.</Para></Discussion></Parameter></Parameters></Function>]
+@objc public func f3(_ first: Int, second: Double, third: Float) {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f3(_:second:third:)</Name><USR>c:objc(cs)ParamAndReturns(im)f3:second:third:</USR><Declaration>@objc public func f3(_ first: Int, second: Double, third: Float)</Declaration><Abstract><Para>Aaa.  f3.</Para></Abstract><Parameters><Parameter><Name>first</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Bbb.</Para></Discussion></Parameter><Parameter><Name>second</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Ccc.</Para></Discussion></Parameter><Parameter><Name>third</Name><Direction isExplicit="0">in</Direction><Discussion><Para>Ddd.</Para></Discussion></Parameter></Parameters></Function>]
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
@@ -352,8 +352,8 @@
 ///
 /// - returns: Eee.
 ///   Fff.
-public func f4() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f4()</Name><USR>c:objc(cs)ParamAndReturns(im)f4</USR><Declaration>public func f4()</Declaration><Abstract><Para>Aaa.  f4.</Para></Abstract><ResultDiscussion><Para>Eee. Fff.</Para></ResultDiscussion></Function>]
+@objc public func f4() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f4()</Name><USR>c:objc(cs)ParamAndReturns(im)f4</USR><Declaration>@objc public func f4()</Declaration><Abstract><Para>Aaa.  f4.</Para></Abstract><ResultDiscussion><Para>Eee. Fff.</Para></ResultDiscussion></Function>]
 }
 
 @objc public class ParameterOutline{
@@ -364,8 +364,8 @@
 ///
 /// - PARAMETERS:
 ///   - z: A number
-public func f0(_ x: Int, y: Int, z: Int) {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0(_:y:z:)</Name><USR>c:objc(cs)ParameterOutline(im)f0:y:z:</USR><Declaration>public func f0(_ x: Int, y: Int, z: Int)</Declaration><Parameters><Parameter><Name>x</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter><Parameter><Name>y</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter><Parameter><Name>z</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter></Parameters></Function>]
+@objc public func f0(_ x: Int, y: Int, z: Int) {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0(_:y:z:)</Name><USR>c:objc(cs)ParameterOutline(im)f0:y:z:</USR><Declaration>@objc public func f0(_ x: Int, y: Int, z: Int)</Declaration><Parameters><Parameter><Name>x</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter><Parameter><Name>y</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter><Parameter><Name>z</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter></Parameters></Function>]
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
@@ -379,8 +379,8 @@
 ///   - y: A number
 /// - This line should also remain.
 /// - parameter z: A number
-public func f0(_ x: Int, y: Int, z: Int) {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0(_:y:z:)</Name><USR>c:objc(cs)ParameterOutlineMiddle(im)f0:y:z:</USR><Declaration>public func f0(_ x: Int, y: Int, z: Int)</Declaration><Parameters><Parameter><Name>x</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter><Parameter><Name>y</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter><Parameter><Name>z</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter></Parameters><Discussion><List-Bullet><Item><Para>This line should remain.</Para></Item><Item><Para>This line should also remain.</Para></Item></List-Bullet></Discussion></Function>]
+@objc public func f0(_ x: Int, y: Int, z: Int) {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0(_:y:z:)</Name><USR>c:objc(cs)ParameterOutlineMiddle(im)f0:y:z:</USR><Declaration>@objc public func f0(_ x: Int, y: Int, z: Int)</Declaration><Parameters><Parameter><Name>x</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter><Parameter><Name>y</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter><Parameter><Name>z</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter></Parameters><Discussion><List-Bullet><Item><Para>This line should remain.</Para></Item><Item><Para>This line should also remain.</Para></Item></List-Bullet></Discussion></Function>]
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
@@ -397,17 +397,17 @@
 @objc public class Returns {
 // CHECK: {{.*}}DocCommentAsXML=none
   /// - returns: A number
-  public func f0() -> Int {
+  @objc public func f0() -> Int {
     return 0
   }
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)Returns(im)f0</USR><Declaration>public func f0() -&gt; Int</Declaration><ResultDiscussion><Para>A number</Para></ResultDiscussion></Function>]
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)Returns(im)f0</USR><Declaration>@objc public func f0() -&gt; Int</Declaration><ResultDiscussion><Para>A number</Para></ResultDiscussion></Function>]
 }
 
 @objc public class SeparateParameters {
 // CHECK: {{.*}}DocCommentAsXML=none
   /// - Parameter x: A number
-  public func f0(_ x: Int, y: Int) {}
-// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0(_:y:)</Name><USR>c:objc(cs)SeparateParameters(im)f0:y:</USR><Declaration>public func f0(_ x: Int, y: Int)</Declaration><Parameters><Parameter><Name>x</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter></Parameters></Function>]
+  @objc public func f0(_ x: Int, y: Int) {}
+// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0(_:y:)</Name><USR>c:objc(cs)SeparateParameters(im)f0:y:</USR><Declaration>@objc public func f0(_ x: Int, y: Int)</Declaration><Parameters><Parameter><Name>x</Name><Direction isExplicit="0">in</Direction><Discussion><Para>A number</Para></Discussion></Parameter></Parameters></Function>]
 // CHECK: {{.*}}DocCommentAsXML=none
 // CHECK: {{.*}}DocCommentAsXML=none
 }
@@ -425,16 +425,16 @@
   /// ##### LEVEL FIVE
   ///
   /// ##### LEVEL SIX
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)SetextHeaders(im)f0</USR><Declaration>public func f0()</Declaration><Discussion><rawHTML><![CDATA[<h1>]]></rawHTML>LEVEL ONE<rawHTML><![CDATA[</h1>]]></rawHTML><rawHTML><![CDATA[<h2>]]></rawHTML>LEVEL TWO<rawHTML><![CDATA[</h2>]]></rawHTML><rawHTML><![CDATA[<h3>]]></rawHTML>LEVEL THREE<rawHTML><![CDATA[</h3>]]></rawHTML><rawHTML><![CDATA[<h4>]]></rawHTML>LEVEL FOUR<rawHTML><![CDATA[</h4>]]></rawHTML><rawHTML><![CDATA[<h5>]]></rawHTML>LEVEL FIVE<rawHTML><![CDATA[</h5>]]></rawHTML><rawHTML><![CDATA[<h5>]]></rawHTML>LEVEL SIX<rawHTML><![CDATA[</h5>]]></rawHTML></Discussion></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)SetextHeaders(im)f0</USR><Declaration>@objc public func f0()</Declaration><Discussion><rawHTML><![CDATA[<h1>]]></rawHTML>LEVEL ONE<rawHTML><![CDATA[</h1>]]></rawHTML><rawHTML><![CDATA[<h2>]]></rawHTML>LEVEL TWO<rawHTML><![CDATA[</h2>]]></rawHTML><rawHTML><![CDATA[<h3>]]></rawHTML>LEVEL THREE<rawHTML><![CDATA[</h3>]]></rawHTML><rawHTML><![CDATA[<h4>]]></rawHTML>LEVEL FOUR<rawHTML><![CDATA[</h4>]]></rawHTML><rawHTML><![CDATA[<h5>]]></rawHTML>LEVEL FIVE<rawHTML><![CDATA[</h5>]]></rawHTML><rawHTML><![CDATA[<h5>]]></rawHTML>LEVEL SIX<rawHTML><![CDATA[</h5>]]></rawHTML></Discussion></Function>]
 }
 
 @objc public class StrongEmphasis {
 // CHECK: {{.*}}DocCommentAsXML=none
   /// Aaa **bbb** ccc.
   /// Aaa __bbb__ ccc.
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)StrongEmphasis(im)f0</USR><Declaration>public func f0()</Declaration><Abstract><Para>Aaa <bold>bbb</bold> ccc. Aaa <bold>bbb</bold> ccc.</Para></Abstract></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)StrongEmphasis(im)f0</USR><Declaration>@objc public func f0()</Declaration><Abstract><Para>Aaa <bold>bbb</bold> ccc. Aaa <bold>bbb</bold> ccc.</Para></Abstract></Function>]
 }
 
 @objc public class UnorderedList {
@@ -447,8 +447,8 @@
   /// - Ddd.
   /// - Eee.
   ///   - Fff.
-  public func f0() {}
-// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)UnorderedList(im)f0</USR><Declaration>public func f0()</Declaration><Discussion><List-Bullet><Item><Para>Aaa.</Para></Item><Item><Para>Bbb. Ccc.</Para></Item></List-Bullet><List-Bullet><Item><Para>Ddd.</Para></Item><Item><Para>Eee.</Para><List-Bullet><Item><Para>Fff.</Para></Item></List-Bullet></Item></List-Bullet></Discussion></Function>]
+  @objc public func f0() {}
+// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:objc(cs)UnorderedList(im)f0</USR><Declaration>@objc public func f0()</Declaration><Discussion><List-Bullet><Item><Para>Aaa.</Para></Item><Item><Para>Bbb. Ccc.</Para></Item></List-Bullet><List-Bullet><Item><Para>Ddd.</Para></Item><Item><Para>Eee.</Para><List-Bullet><Item><Para>Fff.</Para></Item></List-Bullet></Item></List-Bullet></Discussion></Function>]
 }
 
 /// Brief.
diff --git a/test/Interpreter/FunctionConversion.swift b/test/Interpreter/FunctionConversion.swift
index 58611c9..ac7839e 100644
--- a/test/Interpreter/FunctionConversion.swift
+++ b/test/Interpreter/FunctionConversion.swift
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 // RUN: %target-run-simple-swift
 // REQUIRES: executable_test
+// REQUIRES: substitution_map_not_broken
 //
 
 import StdlibUnittest
diff --git a/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift b/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift
new file mode 100644
index 0000000..b59571e
--- /dev/null
+++ b/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift
@@ -0,0 +1,59 @@
+// RUN: rm -rf %t  &&  mkdir -p %t
+// RUN: %target-build-swift %s -o %t/a.out
+// RUN: %target-run %t/a.out 2>&1 | %FileCheck %s -check-prefix=CHECK_NOTHING
+// RUN: env SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=0 SIMCTL_CHILD_SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=0 %target-run %t/a.out 2>&1 | %FileCheck %s -check-prefix=CHECK_NOTHING
+
+// RUN: env SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=1 SIMCTL_CHILD_SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=2 %target-run %t/a.out > %t/level1.log 2>&1
+// RUN: %FileCheck %s -check-prefix=CHECK_WARNINGS < %t/level1.log
+
+// RUN: env SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=2 SIMCTL_CHILD_SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=2 %target-run %t/a.out > %t/level2.log 2>&1
+// RUN: %FileCheck %s -check-prefix=CHECK_WARNINGS < %t/level2.log
+
+// RUN: SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=3 SIMCTL_CHILD_SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=3 %target-run %t/a.out -expect-crash > %t/level3.log 2>&1
+// RUN: %FileCheck %s -check-prefix=CHECK_CRASH < %t/level3.log
+
+// REQUIRES: executable_test
+// REQUIRES: objc_interop
+// REQUIRES: OS=macosx
+
+import StdlibUnittest
+import Foundation
+import Darwin
+
+var DeprecatedObjCInferenceTestSuite = TestSuite("DeprecatedObjCInferenceTestSuite")
+
+class MyClass : NSObject {
+  func foo() { }
+  class func bar() { }
+}
+
+let x = MyClass()
+let fooSel = "foo"
+let barSel = "bar"
+
+var shouldCrash = CommandLine.arguments.contains("-expect-crash")
+
+DeprecatedObjCInferenceTestSuite.test("messagingObjCInference") {
+	// Note whether we're expecting to crash.
+  if shouldCrash { expectCrashLater() }
+	
+	// CHECK_NOTHING: ---Begin 
+	// CHECK_WARNINGS: ---Begin 
+	// CHECK_CRASH: ---Begin 
+	fputs("---Begin\n", stderr)
+
+	// CHECK_WARNINGS: ***Swift runtime: entrypoint -[a.MyClass foo] generated by implicit @objc inference is deprecated and will be removed in Swift 4
+	// CHECK_CRASH: ***Swift runtime: entrypoint -[a.MyClass foo] generated by implicit @objc inference is deprecated and will be removed in Swift 4
+	x.perform(Selector(fooSel))
+
+	// CHECK_WARNINGS: ***Swift runtime: entrypoint +[a.MyClass bar] generated by implicit @objc inference is deprecated and will be removed in Swift 4
+	type(of: x).perform(Selector(barSel))
+
+	// CHECK_NOTHING-NEXT: ---End 
+	// CHECK_WARNINGS: ---End 
+	// CHECK_CRASH-NOT: ---End
+	fputs("---End\n", stderr)
+}
+
+runAllTests()
+
diff --git a/test/Interpreter/objc_class_properties.swift b/test/Interpreter/objc_class_properties.swift
index 6e508c7..a880516 100644
--- a/test/Interpreter/objc_class_properties.swift
+++ b/test/Interpreter/objc_class_properties.swift
@@ -207,5 +207,36 @@
   expectNil(type.protoProp)
 }
 
+var global1: Int = 0
+
+var global2: Int = 0
+
+class Steak : NSObject {
+  @objc override var thickness: Int {
+    get { return global1 } set { global1 = newValue }
+  }
+}
+
+extension NSObject : HasThickness {
+  @objc var thickness: Int { get { return global2 } set { global2 = newValue } }
+}
+
+protocol HasThickness : class {
+  var thickness: Int { get set }
+}
+
+ClassProperties.test("dynamicOverride") {
+  // Calls NSObject.thickness
+  NSObject().thickness += 1
+
+  // Calls Steak.thickness
+  (Steak() as NSObject).thickness += 1
+  Steak().thickness += 1
+  (Steak() as HasThickness).thickness += 1
+
+  expectEqual(3, global1)
+  expectEqual(1, global2)
+}
+
 runAllTests()
 
diff --git a/test/LLVMPasses/merge_func.ll b/test/LLVMPasses/merge_func.ll
index 37b4948..5858a0f 100644
--- a/test/LLVMPasses/merge_func.ll
+++ b/test/LLVMPasses/merge_func.ll
@@ -323,3 +323,72 @@
 ; CHECK: ret i1
   ret i1 %result
 }
+
+; Check self recursive functions
+
+; CHECK-NOT: @recursive1(
+define internal void @recursive1(i32 %x, i32 %y) {
+  br i1 undef, label %bb1, label %bb2
+
+bb1:
+  call void @recursive1(i32 %x, i32 %y)
+  br label %bb2
+
+bb2:
+  ret void
+}
+
+; CHECK-LABEL: define internal void @recursive1_merged(i32, i32)
+; CHECK: call void @recursive1_merged(i32 %0, i32 %1)
+; CHECK: ret void
+define internal void @recursive2(i32 %x, i32 %y) {
+  br i1 undef, label %bb1, label %bb2
+
+bb1:
+  call void @recursive2(i32 %x, i32 %y)
+  br label %bb2
+
+bb2:
+  ret void
+}
+
+; CHECK-LABEL: define internal void @another_recursive_func_merged(i32, void (i32)*)
+; CHECK: call void %1(i32 %0)
+; CHECK: ret void
+define internal void @another_recursive_func(i32 %x) {
+  br i1 undef, label %bb1, label %bb2
+
+bb1:
+  call void @another_recursive_func(i32 %x)
+  br label %bb2
+
+bb2:
+  ret void
+}
+
+; CHECK-NOT: @not_really_recursive(
+define internal void @not_really_recursive(i32 %x) {
+  br i1 undef, label %bb1, label %bb2
+
+bb1:
+  call void @callee1(i32 %x)
+  br label %bb2
+
+bb2:
+  ret void
+}
+
+; CHECK-LABEL: define void @call_recursive_funcs(i32 %x)
+; CHECK: call void @recursive1_merged(i32 %x, i32 %x)
+; CHECK: call void @recursive1_merged(i32 %x, i32 %x)
+; CHECK: call void bitcast (void (i32, void (i32)*)* @another_recursive_func_merged to void (i32, void (i32, void (i32)*)*)*)(i32 %x, void (i32, void (i32)*)* @another_recursive_func_merged)
+; CHECK: call void @another_recursive_func_merged(i32 %x, void (i32)* @callee1)
+; CHECK: ret void
+define void @call_recursive_funcs(i32 %x) {
+  call void @recursive1(i32 %x, i32 %x)
+  call void @recursive2(i32 %x, i32 %x)
+  call void @another_recursive_func(i32 %x)
+  call void @not_really_recursive(i32 %x)
+  ret void
+}
+
diff --git a/test/Parse/pointer_conversion.swift.gyb b/test/Parse/pointer_conversion.swift.gyb
index 5b33556..0bcdc34 100644
--- a/test/Parse/pointer_conversion.swift.gyb
+++ b/test/Parse/pointer_conversion.swift.gyb
@@ -334,3 +334,12 @@
   UP(pipe)    // ok
   UP(&pipe)   // expected-error {{'&' is not allowed passing array value as 'UnsafePointer<Int32>' argument}} {{6-7=}}
 }
+
+func takesRawBuffer(_ b: UnsafeRawBufferPointer) {}
+
+// <rdar://problem/29586888> UnsafeRawBufferPointer range subscript is inconsistent with Collection.
+func f29586888(b: UnsafeRawBufferPointer) {
+  takesRawBuffer(b[1..<2]) // expected-error {{'subscript' is unavailable: use 'UnsafeRawBufferPointer(rebasing:)' to convert a slice into a zero-based raw buffer.}}
+  let slice = b[1..<2]
+  takesRawBuffer(slice) // expected-error {{cannot convert value of type 'RandomAccessSlice<UnsafeRawBufferPointer>' to expected argument type 'UnsafeRawBufferPointer'}}
+}
diff --git a/test/PrintAsObjC/any_as_id.swift b/test/PrintAsObjC/any_as_id.swift
index 86884d5..c77295b 100644
--- a/test/PrintAsObjC/any_as_id.swift
+++ b/test/PrintAsObjC/any_as_id.swift
@@ -25,44 +25,44 @@
 class AnyAsIdTest : NSObject {
 
 // CHECK-NEXT:  - (NSArray * _Nonnull)arrayOfAny:(NSArray * _Nonnull)x SWIFT_WARN_UNUSED_RESULT;
-  func arrayOfAny(_ x: [Any]) -> [Any] { return x }
+  @objc func arrayOfAny(_ x: [Any]) -> [Any] { return x }
 // CHECK-NEXT:  - (NSArray * _Nullable)arrayOfAnyPerhaps:(NSArray * _Nonnull)x SWIFT_WARN_UNUSED_RESULT;
-  func arrayOfAnyPerhaps(_ x: [Any]) -> [Any]? { return x }
+  @objc func arrayOfAnyPerhaps(_ x: [Any]) -> [Any]? { return x }
 
 // CHECK-NEXT:  - (NSDictionary * _Nonnull)dictionaryOfAny:(NSDictionary * _Nonnull)x SWIFT_WARN_UNUSED_RESULT;
-  func dictionaryOfAny(_ x: [AnyHashable: Any]) -> [AnyHashable: Any] { return x }
+  @objc func dictionaryOfAny(_ x: [AnyHashable: Any]) -> [AnyHashable: Any] { return x }
 // CHECK-NEXT:  - (void)dictionaryOfAnyKeys:(NSDictionary<id <NSCopying>, NSString *> * _Nonnull)x;
-  func dictionaryOfAnyKeys(_ x: [AnyHashable: String]) {}
+  @objc func dictionaryOfAnyKeys(_ x: [AnyHashable: String]) {}
 // CHECK-NEXT:  - (NSDictionary * _Nullable)dictionaryOfAnyMayhap:(NSDictionary * _Nonnull)x SWIFT_WARN_UNUSED_RESULT;
-  func dictionaryOfAnyMayhap(_ x: [AnyHashable: Any]) -> [AnyHashable: Any]? { return x }
+  @objc func dictionaryOfAnyMayhap(_ x: [AnyHashable: Any]) -> [AnyHashable: Any]? { return x }
 // CHECK-NEXT:  - (void)dictionaryOfAnyValues:(NSDictionary<NSString *, id> * _Nonnull)x;
-  func dictionaryOfAnyValues(_ x: [String: Any]) {}
+  @objc func dictionaryOfAnyValues(_ x: [String: Any]) {}
 
 // CHECK-NEXT:  - (id _Nonnull)getAny SWIFT_WARN_UNUSED_RESULT;
-  func getAny() -> Any { return 1 as Any }
+  @objc func getAny() -> Any { return 1 as Any }
 // CHECK-NEXT: - (id _Nullable)getAnyConstructively SWIFT_WARN_UNUSED_RESULT;
-  func getAnyConstructively() -> Any? { return Optional<Any>(1 as Any) }
+  @objc func getAnyConstructively() -> Any? { return Optional<Any>(1 as Any) }
 // CHECK-NEXT: - (id _Nullable)getAnyMaybe SWIFT_WARN_UNUSED_RESULT;
-  func getAnyMaybe() -> Any? { return nil }
+  @objc func getAnyMaybe() -> Any? { return nil }
 // CHECK-NEXT: - (id _Nullable)getAnyProbably SWIFT_WARN_UNUSED_RESULT;
-  func getAnyProbably() -> Any? { return 1 as Any }
+  @objc func getAnyProbably() -> Any? { return 1 as Any }
 
 // CHECK-NEXT:  - (id _Nonnull)passThroughAny:(id _Nonnull)x SWIFT_WARN_UNUSED_RESULT;
-  func passThroughAny(_ x: Any) -> Any { return x }
+  @objc func passThroughAny(_ x: Any) -> Any { return x }
 // CHECK-NEXT: - (id _Nullable)passThroughAnyMaybe:(id _Nullable)x SWIFT_WARN_UNUSED_RESULT;
-  func passThroughAnyMaybe(_ x: Any?) -> Any? { return x }
+  @objc func passThroughAnyMaybe(_ x: Any?) -> Any? { return x }
 
 // CHECK-NEXT: - (void)setOfAny:(NSSet * _Nonnull)x;
-  func setOfAny(_ x: Set<AnyHashable>) {}
+  @objc func setOfAny(_ x: Set<AnyHashable>) {}
 
 // CHECK-NEXT:  - (void)takesId:(id _Nonnull)x;
-  func takesId(_ x: Any) {}
+  @objc func takesId(_ x: Any) {}
 
 // CHECK-NEXT: - (id _Nonnull)unwrapAny:(id _Nullable)x SWIFT_WARN_UNUSED_RESULT;
-  func unwrapAny(_ x : Any?) -> Any { return x! }
+  @objc func unwrapAny(_ x : Any?) -> Any { return x! }
 
 // CHECK-NEXT: - (id _Nullable)wrapAny:(id _Nonnull)x SWIFT_WARN_UNUSED_RESULT;
-  func wrapAny(_ x : Any) -> Any? { return x }
+  @objc func wrapAny(_ x : Any) -> Any? { return x }
 
 // CHECK-NEXT:  - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
   /* implicit inherited init() */
@@ -70,5 +70,5 @@
 }
 // CHECK-NEXT:  @end
 
-extension NSArray { func forceToExist() {} }
+extension NSArray { @objc func forceToExist() {} }
 
diff --git a/test/PrintAsObjC/arc-conventions.swift b/test/PrintAsObjC/arc-conventions.swift
index 82c86e2..2e2346d 100644
--- a/test/PrintAsObjC/arc-conventions.swift
+++ b/test/PrintAsObjC/arc-conventions.swift
@@ -15,7 +15,7 @@
 import Foundation
 
 public class Test: NSObject {
-  public func initAllTheThings() -> AnyObject {
+  @objc public func initAllTheThings() -> AnyObject {
     print("method called")
     return "initialized" as NSString
   }
diff --git a/test/PrintAsObjC/availability.swift b/test/PrintAsObjC/availability.swift
index 355a24b..64beca3 100644
--- a/test/PrintAsObjC/availability.swift
+++ b/test/PrintAsObjC/availability.swift
@@ -51,70 +51,70 @@
 // CHECK-NEXT: - (nonnull instancetype)initWithX:(NSInteger)_ SWIFT_UNAVAILABLE;
 // CHECK-NEXT: @end
 @objc class Availability {
-    func alwaysAvailable() {}
+    @objc func alwaysAvailable() {}
 
     @available(*, unavailable)
-    func alwaysUnavailable() {}
+    @objc func alwaysUnavailable() {}
     @available(*, unavailable, message: "stuff happened")
-    func alwaysUnavailableTwo() {}
+    @objc func alwaysUnavailableTwo() {}
     @available(*, unavailable, renamed: "bar")
-    func alwaysUnavailableThree() {}
+    @objc func alwaysUnavailableThree() {}
     @available(*, unavailable, message: "whatever", renamed: "baz")
-    func alwaysUnavailableFour() {}
+    @objc func alwaysUnavailableFour() {}
 
     @available(*, deprecated)
-    func alwaysDeprecated() {}
+    @objc func alwaysDeprecated() {}
     @available(*, deprecated, message: "it's old")
-    func alwaysDeprecatedTwo() {}
+    @objc func alwaysDeprecatedTwo() {}
     @available(*, deprecated, renamed: "qux")
-    func alwaysDeprecatedThree() {}
+    @objc func alwaysDeprecatedThree() {}
     @available(*, deprecated, message: "use something else", renamed: "quux")
-    func alwaysDeprecatedFour() {}
+    @objc func alwaysDeprecatedFour() {}
 
     @available(*, deprecated, message: "one\ntwo\tthree\rfour\\ \"five\"")
-    func escapeMessage() {}
+    @objc func escapeMessage() {}
     @available(*, deprecated, message: "über")
-    func unicodeMessage() {}
+    @objc func unicodeMessage() {}
 
     @available(macOS 10.10, *)
-    func singlePlatShorthand() {}
+    @objc func singlePlatShorthand() {}
     @available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 3.0, *)
-    func multiPlatShorthand() {}
+    @objc func multiPlatShorthand() {}
 
     @available(iOS, introduced: 9.0)
-    func singlePlatIntroduced() {}
+    @objc func singlePlatIntroduced() {}
     @available(macOS, deprecated: 10.10)
-    func singlePlatDeprecated() {}
+    @objc func singlePlatDeprecated() {}
     @available(macOS, deprecated: 10.10, renamed: "flubber")
-    func singlePlatDeprecatedTwo() {}
+    @objc func singlePlatDeprecatedTwo() {}
     @available(macOS, deprecated: 10.10, message: "we changed our minds", renamed: "fozzybear")
-    func singlePlatDeprecatedThree() {}
+    @objc func singlePlatDeprecatedThree() {}
     @available(tvOS, deprecated)
-    func singlePlatDeprecatedAlways() {}
+    @objc func singlePlatDeprecatedAlways() {}
     @available(macOS, introduced: 10.7, deprecated)
-    func singlePlatDeprecatedAlwaysTwo() {}
+    @objc func singlePlatDeprecatedAlwaysTwo() {}
     @available(watchOS, unavailable)
-    func singlePlatUnavailable() {}
+    @objc func singlePlatUnavailable() {}
     @available(watchOS, introduced: 2.0, unavailable)
-    func singlePlatUnavailableTwo() {}
+    @objc func singlePlatUnavailableTwo() {}
     @available(iOS, obsoleted: 8.1)
-    func singlePlatObsoleted() {}
+    @objc func singlePlatObsoleted() {}
     @available(macOS, introduced: 10.7, deprecated: 10.9, obsoleted: 10.10)
-    func singlePlatCombined() {}
+    @objc func singlePlatCombined() {}
 
     @available(macOS, introduced: 10.6, deprecated: 10.8, obsoleted: 10.9)
     @available(iOS, introduced: 7.0, deprecated: 9.0, obsoleted: 10.0)
-    func multiPlatCombined() {}
+    @objc func multiPlatCombined() {}
 
     @available(macOSApplicationExtension, unavailable)
     @available(iOSApplicationExtension, unavailable)
     @available(tvOSApplicationExtension, unavailable)
     @available(watchOSApplicationExtension, unavailable)
-    func extensionUnavailable() {}
+    @objc func extensionUnavailable() {}
 
-    init() {}
+    @objc init() {}
     @available(macOS 10.10, *)
-    init(x _: Int) {}
+    @objc init(x _: Int) {}
 }
 
 @objc class AvailabilitySub: Availability {
diff --git a/test/PrintAsObjC/blocks.swift b/test/PrintAsObjC/blocks.swift
index fe82ddd..2886a39 100644
--- a/test/PrintAsObjC/blocks.swift
+++ b/test/PrintAsObjC/blocks.swift
@@ -23,127 +23,127 @@
 @objc class Callbacks {
   
   // CHECK-NEXT: - (void (^ _Nonnull)(void))voidBlocks:(void (^ _Nonnull)(void))input SWIFT_WARN_UNUSED_RESULT;
-  func voidBlocks(_ input: @escaping () -> ()) -> () -> () {
+  @objc func voidBlocks(_ input: @escaping () -> ()) -> () -> () {
     return input
   }
   
   // CHECK-NEXT: - (void)manyArguments:(void (^ _Nonnull)(float, float, double, double))input;
-  func manyArguments(_ input: @escaping (Float, Float, Double, Double) -> ()) {}
+  @objc func manyArguments(_ input: @escaping (Float, Float, Double, Double) -> ()) {}
 
   // CHECK-NEXT: - (void)blockTakesBlock:(void (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))input;
-  func blockTakesBlock(_ input: @escaping (() -> ()) -> ()) {}
+  @objc func blockTakesBlock(_ input: @escaping (() -> ()) -> ()) {}
   
   // CHECK-NEXT: - (void)blockReturnsBlock:(void (^ _Nonnull (^ _Nonnull)(void))(void))input;
-  func blockReturnsBlock(_ input: @escaping () -> () -> ()) {}
+  @objc func blockReturnsBlock(_ input: @escaping () -> () -> ()) {}
   
   // CHECK-NEXT: - (void)blockTakesAndReturnsBlock:(SWIFT_NOESCAPE uint8_t (^ _Nonnull (^ _Nonnull)(SWIFT_NOESCAPE uint16_t (^ _Nonnull)(int16_t)))(int8_t))input;
-  func blockTakesAndReturnsBlock(_ input:
+  @objc func blockTakesAndReturnsBlock(_ input:
     ((Int16) -> (UInt16)) ->
                 ((Int8) -> (UInt8))) {}
   
   // CHECK-NEXT: - (void)blockTakesTwoBlocksAndReturnsBlock:(SWIFT_NOESCAPE uint8_t (^ _Nonnull (^ _Nonnull)(SWIFT_NOESCAPE uint16_t (^ _Nonnull)(int16_t), SWIFT_NOESCAPE uint32_t (^ _Nonnull)(int32_t)))(int8_t))input;
-  func blockTakesTwoBlocksAndReturnsBlock(_ input:
+  @objc func blockTakesTwoBlocksAndReturnsBlock(_ input:
     ((Int16) -> (UInt16),
                  (Int32) -> (UInt32)) ->
                 ((Int8) -> (UInt8))) {}
 
   // CHECK-NEXT: - (void (^ _Nullable)(NSObject * _Nonnull))returnsBlockWithInput SWIFT_WARN_UNUSED_RESULT;
-  func returnsBlockWithInput() -> ((NSObject) -> ())? {
+  @objc func returnsBlockWithInput() -> ((NSObject) -> ())? {
     return nil
   }
   
   // CHECK-NEXT: - (void (^ _Nullable)(NSObject * _Nonnull))returnsBlockWithParenthesizedInput SWIFT_WARN_UNUSED_RESULT;
-  func returnsBlockWithParenthesizedInput() -> ((NSObject) -> ())? {
+  @objc func returnsBlockWithParenthesizedInput() -> ((NSObject) -> ())? {
     return nil
   }
   
   // CHECK-NEXT: - (void (^ _Nullable)(NSObject * _Nonnull, NSObject * _Nonnull))returnsBlockWithTwoInputs SWIFT_WARN_UNUSED_RESULT;
-  func returnsBlockWithTwoInputs() -> ((NSObject, NSObject) -> ())? {
+  @objc func returnsBlockWithTwoInputs() -> ((NSObject, NSObject) -> ())? {
     return nil
   }
 
   // CHECK-NEXT: - (void)blockWithTypealias:(NSInteger (^ _Nonnull)(NSInteger, id _Nullable))input;
-  func blockWithTypealias(_ input: @escaping (MyTuple) -> MyInt) {}
+  @objc func blockWithTypealias(_ input: @escaping (MyTuple) -> MyInt) {}
   
   // CHECK-NEXT: - (void)blockWithSimpleTypealias:(NSInteger (^ _Nonnull)(NSInteger))input;
-  func blockWithSimpleTypealias(_ input: @escaping (MyInt) -> MyInt) {}
+  @objc func blockWithSimpleTypealias(_ input: @escaping (MyInt) -> MyInt) {}
 
   // CHECK-NEXT: - (void)namedArguments:(void (^ _Nonnull)(float, float, double, double))input;
-  func namedArguments(_ input: @escaping (_ f1: Float, _ f2: Float, _ d1: Double, _ d2: Double) -> ()) {}
+  @objc func namedArguments(_ input: @escaping (_ f1: Float, _ f2: Float, _ d1: Double, _ d2: Double) -> ()) {}
   
   // CHECK-NEXT: - (void)blockTakesNamedBlock:(void (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))input;
-  func blockTakesNamedBlock(_ input: @escaping (_ block: () -> ()) -> ()) {}
+  @objc func blockTakesNamedBlock(_ input: @escaping (_ block: () -> ()) -> ()) {}
   
   // CHECK-NEXT: - (void (^ _Nullable)(NSObject * _Nonnull))returnsBlockWithNamedInput SWIFT_WARN_UNUSED_RESULT;
-  func returnsBlockWithNamedInput() -> ((_ object: NSObject) -> ())? {
+  @objc func returnsBlockWithNamedInput() -> ((_ object: NSObject) -> ())? {
     return nil
   }
 
   // CHECK-NEXT: - (void)blockWithTypealiasWithNames:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(NSInteger a, id _Nullable b))input;
-  func blockWithTypealiasWithNames(_ input: (MyNamedTuple) -> MyInt) {}
+  @objc func blockWithTypealiasWithNames(_ input: (MyNamedTuple) -> MyInt) {}
 
   // CHECK-NEXT: - (void)blockWithKeyword:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(NSInteger))_Nullable_;
-  func blockWithKeyword(_ _Nullable: (_ `class`: Int) -> Int) {}
+  @objc func blockWithKeyword(_ _Nullable: (_ `class`: Int) -> Int) {}
 
   // CHECK-NEXT: - (NSInteger (* _Nonnull)(NSInteger))functionPointers:(NSInteger (* _Nonnull)(NSInteger))input SWIFT_WARN_UNUSED_RESULT;
-  func functionPointers(_ input: @escaping @convention(c) (Int) -> Int)
+  @objc func functionPointers(_ input: @escaping @convention(c) (Int) -> Int)
       -> @convention(c) (Int) -> Int {
     return input
   }
 
   // CHECK-NEXT: - (void)blockWithBlockTypealias:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(void (^ _Nonnull)(void)))block;
-  func blockWithBlockTypealias(_ block: MyBlockWithEscapingParam) {}
+  @objc func blockWithBlockTypealias(_ block: MyBlockWithEscapingParam) {}
 
   // CHECK-NEXT: - (void)blockWithBlockTypealias2:(NSInteger (^ _Nonnull)(void (^ _Nonnull)(void)))block;
-  func blockWithBlockTypealias2(_ block: @escaping MyBlockWithEscapingParam) {}
+  @objc func blockWithBlockTypealias2(_ block: @escaping MyBlockWithEscapingParam) {}
 
   // CHECK-NEXT: - (void)blockWithBlockTypealias3:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))block;
-  func blockWithBlockTypealias3(_ block: MyBlockWithNoescapeParam) {}
+  @objc func blockWithBlockTypealias3(_ block: MyBlockWithNoescapeParam) {}
 
   // CHECK-NEXT: - (void)blockWithBlockTypealias4:(NSInteger (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))block;
-  func blockWithBlockTypealias4(_ block: @escaping MyBlockWithNoescapeParam) {}
+  @objc func blockWithBlockTypealias4(_ block: @escaping MyBlockWithNoescapeParam) {}
 
   // CHECK-NEXT: - (void)functionPointerTakesAndReturnsFunctionPointer:(NSInteger (* _Nonnull (^ _Nonnull (* _Nonnull)(NSInteger))(NSInteger))(NSInteger))input;
-  func functionPointerTakesAndReturnsFunctionPointer(
+  @objc func functionPointerTakesAndReturnsFunctionPointer(
     _ input: @escaping @convention(c) (Int) -> (Int)
                               -> @convention(c) (Int) -> Int
   ) {
   }
   
   // CHECK-NEXT: - (void (* _Nonnull)(SWIFT_NOESCAPE NSInteger (* _Nonnull)(NSInteger, NSInteger)))returnsFunctionPointerThatTakesFunctionPointer SWIFT_WARN_UNUSED_RESULT;
-  func returnsFunctionPointerThatTakesFunctionPointer() ->
+  @objc func returnsFunctionPointerThatTakesFunctionPointer() ->
     @convention(c) (_ comparator: @convention(c) (_ x: Int, _ y: Int) -> Int) -> Void {
     fatalError()
   }
 
   // CHECK-NEXT: - (NSInteger (* _Nonnull)(NSInteger))functionPointersWithName:(NSInteger (* _Nonnull)(NSInteger))input SWIFT_WARN_UNUSED_RESULT;
-  func functionPointersWithName(_ input: @escaping @convention(c) (_ value: Int) -> Int)
+  @objc func functionPointersWithName(_ input: @escaping @convention(c) (_ value: Int) -> Int)
       -> @convention(c) (_ result: Int) -> Int {
     return input
   }
 
   // CHECK-NEXT: @property (nonatomic, copy) NSInteger (^ _Nullable savedBlock)(NSInteger);
-  var savedBlock: ((Int) -> Int)?
+  @objc var savedBlock: ((Int) -> Int)?
   
   // CHECK-NEXT: @property (nonatomic, copy) NSInteger (^ _Nullable savedBlockWithName)(NSInteger);
-  var savedBlockWithName: ((_ x: Int) -> Int)?
+  @objc var savedBlockWithName: ((_ x: Int) -> Int)?
   
   // CHECK-NEXT: @property (nonatomic) NSInteger (* _Nonnull savedFunctionPointer)(NSInteger);
-  var savedFunctionPointer: @convention(c) (Int) -> Int = { $0 }
+  @objc var savedFunctionPointer: @convention(c) (Int) -> Int = { $0 }
   
   // CHECK-NEXT: @property (nonatomic) NSInteger (* _Nullable savedFunctionPointer2)(NSInteger);
-  var savedFunctionPointer2: (@convention(c) (Int) -> Int)? = { $0 }
+  @objc var savedFunctionPointer2: (@convention(c) (Int) -> Int)? = { $0 }
   
   // CHECK-NEXT: @property (nonatomic) NSInteger (* _Nonnull savedFunctionPointerWithName)(NSInteger);
-  var savedFunctionPointerWithName: @convention(c) (_ x: Int) -> Int = { $0 }
+  @objc var savedFunctionPointerWithName: @convention(c) (_ x: Int) -> Int = { $0 }
 
   // The following uses a clang keyword as the name.
   
   // CHECK-NEXT: @property (nonatomic, copy, getter=this, setter=setThis:) NSInteger (^ _Nonnull this_)(NSInteger);
-  var this: (_ block: Int) -> Int = { $0 }
+  @objc var this: (_ block: Int) -> Int = { $0 }
   
   // CHECK-NEXT: @property (nonatomic, getter=class, setter=setClass:) NSInteger (* _Nonnull class_)(NSInteger);
-  var `class`: @convention(c) (_ function: Int) -> Int = { $0 }
+  @objc var `class`: @convention(c) (_ function: Int) -> Int = { $0 }
 }
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
diff --git a/test/PrintAsObjC/classes.swift b/test/PrintAsObjC/classes.swift
index 8f0c20c..a345e6a 100644
--- a/test/PrintAsObjC/classes.swift
+++ b/test/PrintAsObjC/classes.swift
@@ -53,11 +53,11 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class BridgedTypes {
-  func dictBridge(_ x: Dictionary<NSObject, AnyObject>) -> Dictionary<NSObject, AnyObject> {
+  @objc func dictBridge(_ x: Dictionary<NSObject, AnyObject>) -> Dictionary<NSObject, AnyObject> {
     return x
   }
 
-  func setBridge(_ x: Set<NSObject>) -> Set<NSObject> {
+  @objc func setBridge(_ x: Set<NSObject>) -> Set<NSObject> {
     return x
   }
 }
@@ -70,7 +70,7 @@
 // CHECK-NEXT: @end
 @objc(CustomName)
 class ClassWithCustomName {
-  func forwardCustomName(_: ClassWithCustomName2) {}
+  @objc func forwardCustomName(_: ClassWithCustomName2) {}
 }
   
 // CHECK-LABEL: SWIFT_CLASS_NAMED("ClassWithCustomName2")
@@ -95,7 +95,7 @@
 // CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
 // CHECK-NEXT: @end
 @objc class ClassWithNSObjectProtocol : NSObjectProtocol {
-  var description: String { return "me" }
+  @objc var description: String { return "me" }
   @objc(conformsToProtocol:)
   func conforms(to _: Protocol) -> Bool { return false }
 
@@ -109,8 +109,8 @@
 // CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
 // CHECK-NEXT: @end
 class DiscardableResult : NSObject {
-  func nonDiscardable(_ x: Int) -> Int { return x }
-  @discardableResult func discardable(_ x: Int) -> Int { return x }
+  @objc func nonDiscardable(_ x: Int) -> Int { return x }
+  @discardableResult @objc func discardable(_ x: Int) -> Int { return x }
 }
 
 // CHECK-LABEL: @interface Initializers
@@ -126,23 +126,23 @@
 // CHECK-NEXT: - (nonnull instancetype)initWithEvenMoreFun OBJC_DESIGNATED_INITIALIZER;
 // CHECK-NEXT: @end
 @objc class Initializers {
-  init() {}
+  @objc init() {}
 
-  convenience init(int _: Int) { self.init() }
+  @objc convenience init(int _: Int) { self.init() }
 
-  convenience init(float f: Float) { self.init() }
-  convenience init(string s: String, boolean b: ObjCBool) { self.init() }
+  @objc convenience init(float f: Float) { self.init() }
+  @objc convenience init(string s: String, boolean b: ObjCBool) { self.init() }
 
-  convenience init?(boolean b: ObjCBool) { self.init() }
+  @objc convenience init?(boolean b: ObjCBool) { self.init() }
 
   @objc(foo_initWithInt:) convenience init(foo_int _: Int) { self.init() }
   @objc(initializeWithX:) convenience init(X _: Int) { self.init() }
 
-  init(forFun: ()) { }
+  @objc init(forFun: ()) { }
 
-  init(moreFun: ()) { }
+  @objc init(moreFun: ()) { }
 
-  init(evenMoreFun: ()) { }
+  @objc init(evenMoreFun: ()) { }
 }
 
 // CHECK-LABEL: @interface InheritedInitializers
@@ -171,7 +171,7 @@
     super.init()
   }
 
-  init(evenMoreFun: ()) { super.init() }
+  @objc init(evenMoreFun: ()) { super.init() }
 }
 
 // NEGATIVE-NOT: NotObjC
@@ -218,62 +218,62 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class Methods {
-  func test() {}
-  class func test2() {}
+  @objc func test() {}
+  @objc class func test2() {}
 
-  func testPrimitives(_ b: Bool, i: Int, f: Float, d: Double, u: UInt)
+  @objc func testPrimitives(_ b: Bool, i: Int, f: Float, d: Double, u: UInt)
     -> OpaquePointer { return OpaquePointer(bitPattern: -1)! }
-  func testString(_ s: String) {}
-  func testSelector(_ sel: Selector, boolean b: ObjCBool) {}
+  @objc func testString(_ s: String) {}
+  @objc func testSelector(_ sel: Selector, boolean b: ObjCBool) {}
 
-  func testCSignedTypes(_ a: CSignedChar, b: CShort, c: CInt, d: CLong, e: CLongLong) {}
-  func testCUnsignedTypes(_ a: CUnsignedChar, b: CUnsignedShort, c: CUnsignedInt, d: CUnsignedLong, e: CUnsignedLongLong) {}
-  func testCChars(_ basic: CChar, wchar wide: CWideChar, char16: CChar16, char32: CChar32) {}
-  func testCFloats(_ a: CFloat, b: CDouble) {}
-  func testCBool(_ a: CBool) {}
+  @objc func testCSignedTypes(_ a: CSignedChar, b: CShort, c: CInt, d: CLong, e: CLongLong) {}
+  @objc func testCUnsignedTypes(_ a: CUnsignedChar, b: CUnsignedShort, c: CUnsignedInt, d: CUnsignedLong, e: CUnsignedLongLong) {}
+  @objc func testCChars(_ basic: CChar, wchar wide: CWideChar, char16: CChar16, char32: CChar32) {}
+  @objc func testCFloats(_ a: CFloat, b: CDouble) {}
+  @objc func testCBool(_ a: CBool) {}
 
-  func testSizedSignedTypes(_ a: Int8, b: Int16, c: Int32, d: Int64) {}
-  func testSizedUnsignedTypes(_ a: UInt8, b: UInt16, c: UInt32, d: UInt64) {}
-  func testSizedFloats(_ a: Float32, b: Float64) {}
+  @objc func testSizedSignedTypes(_ a: Int8, b: Int16, c: Int32, d: Int64) {}
+  @objc func testSizedUnsignedTypes(_ a: UInt8, b: UInt16, c: UInt32, d: UInt64) {}
+  @objc func testSizedFloats(_ a: Float32, b: Float64) {}
 
-  func getDynamicSelf() -> Self { return self }
-  class func getSelf() -> Methods.Type { return self }
+  @objc func getDynamicSelf() -> Self { return self }
+  @objc class func getSelf() -> Methods.Type { return self }
 
-  func maybeGetSelf() -> Methods? { return nil }
-  class func maybeGetSelf() -> Methods.Type? { return self }
-  func uncheckedGetSelf() -> Methods! { return self }
-  class func uncheckedGetSelf() -> Methods.Type! { return self }
+  @objc func maybeGetSelf() -> Methods? { return nil }
+  @objc class func maybeGetSelf() -> Methods.Type? { return self }
+  @objc func uncheckedGetSelf() -> Methods! { return self }
+  @objc class func uncheckedGetSelf() -> Methods.Type! { return self }
 
-  class func getCustomNameType() -> ClassWithCustomName.Type {
+  @objc class func getCustomNameType() -> ClassWithCustomName.Type {
     return ClassWithCustomName.self
   }
 
-  func testParens(_ a: ((Int))) {}
+  @objc func testParens(_ a: ((Int))) {}
 
-  func testIgnoredParam(_: Int) {}
-  func testIgnoredParams(_: Int, again _: Int) {}
+  @objc func testIgnoredParam(_: Int) {}
+  @objc func testIgnoredParams(_: Int, again _: Int) {}
 
-  func testArrayBridging(_ a: [Methods]) {}
-  func testArrayBridging2(_ a: [AnyObject]) {}
-  func testArrayBridging3(_ a: [String]) {}
+  @objc func testArrayBridging(_ a: [Methods]) {}
+  @objc func testArrayBridging2(_ a: [AnyObject]) {}
+  @objc func testArrayBridging3(_ a: [String]) {}
 
-  func testDictionaryBridging(_ a: [NSObject : AnyObject]) {}
-  func testDictionaryBridging2(_ a: [NSNumber : Methods]) {}
-  func testDictionaryBridging3(_ a: [String : String]) {}
+  @objc func testDictionaryBridging(_ a: [NSObject : AnyObject]) {}
+  @objc func testDictionaryBridging2(_ a: [NSNumber : Methods]) {}
+  @objc func testDictionaryBridging3(_ a: [String : String]) {}
 
-  func testSetBridging(_ a: Set<NSObject>) {}
+  @objc func testSetBridging(_ a: Set<NSObject>) {}
 
   @IBAction func actionMethod(_: AnyObject) {}
 
-  func methodWithReservedParameterNames(_ long: AnyObject, protected: AnyObject) {}
+  @objc func methodWithReservedParameterNames(_ long: AnyObject, protected: AnyObject) {}
 
-  func honorRenames(_: ClassWithCustomName) {}
+  @objc func honorRenames(_: ClassWithCustomName) {}
 
-  func unmanaged(_: Unmanaged<AnyObject>) -> Unmanaged<Methods>? { return nil }
+  @objc func unmanaged(_: Unmanaged<AnyObject>) -> Unmanaged<Methods>? { return nil }
 
-  func initAllTheThings() {}
+  @objc func initAllTheThings() {}
   @objc(initTheOtherThings) func setUpOtherThings() {}
-  func initializeEvenMoreThings() {}
+  @objc func initializeEvenMoreThings() {}
 }
 
 typealias AliasForNSRect = NSRect
@@ -295,25 +295,25 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class MethodsWithImports {
-  func getOrigin(_ r: NSRect) -> NSPoint { return r.origin }
-  func getOriginX(_ r: AliasForNSRect) -> CGFloat { return r.origin.x }
-  func getOriginY(_ r: CGRect) -> CGFloat { return r.origin.y }
+  @objc func getOrigin(_ r: NSRect) -> NSPoint { return r.origin }
+  @objc func getOriginX(_ r: AliasForNSRect) -> CGFloat { return r.origin.x }
+  @objc func getOriginY(_ r: CGRect) -> CGFloat { return r.origin.y }
 
-  func emptyArray() -> NSArray { return NSArray() }
-  func maybeArray() -> NSArray? { return nil }
+  @objc func emptyArray() -> NSArray { return NSArray() }
+  @objc func maybeArray() -> NSArray? { return nil }
 
-  func someEnum() -> NSRuncingMode { return .mince }
-  func protocolClass() -> NSCoding.Type? { return nil }
+  @objc func someEnum() -> NSRuncingMode { return .mince }
+  @objc func protocolClass() -> NSCoding.Type? { return nil }
 
-  func zone() -> NSZone? { return nil }
+  @objc func zone() -> NSZone? { return nil }
 
-  func cf(_ x: CFTree, str: CFString, str2: CFMutableString, obj: CFAliasForType) -> CFTypeRef? { return nil }
+  @objc func cf(_ x: CFTree, str: CFString, str2: CFMutableString, obj: CFAliasForType) -> CFTypeRef? { return nil }
 
-  func appKitInImplementation() {
+  @objc func appKitInImplementation() {
     let _ : NSResponder?
   }
 
-  func returnsURL() -> NSURL? { return nil }
+  @objc func returnsURL() -> NSURL? { return nil }
 }
 
 // CHECK-LABEL: @interface MethodsWithPointers
@@ -325,16 +325,16 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class MethodsWithPointers {
-  func test(_ a: UnsafeMutablePointer<Int>) -> UnsafeMutablePointer<AnyObject> {
+  @objc func test(_ a: UnsafeMutablePointer<Int>) -> UnsafeMutablePointer<AnyObject> {
     return UnsafeMutablePointer(bitPattern: -1)!
   }
 
-  func testNested(_ a: UnsafeMutablePointer<UnsafeMutablePointer<Int>>) {}
+  @objc func testNested(_ a: UnsafeMutablePointer<UnsafeMutablePointer<Int>>) {}
 
-  func testBridging(_ a: UnsafePointer<Int>, b: UnsafeMutablePointer<Int>, c: AutoreleasingUnsafeMutablePointer<Methods>) {}
-  func testBridgingVoid(_ a: UnsafeMutableRawPointer, b: UnsafeRawPointer) {}
+  @objc func testBridging(_ a: UnsafePointer<Int>, b: UnsafeMutablePointer<Int>, c: AutoreleasingUnsafeMutablePointer<Methods>) {}
+  @objc func testBridgingVoid(_ a: UnsafeMutableRawPointer, b: UnsafeRawPointer) {}
 
-  func testBridgingOptionality(_ a: UnsafePointer<Int>?, b: UnsafeMutablePointer<Int>!, c: AutoreleasingUnsafeMutablePointer<Methods?>?) {}
+  @objc func testBridgingOptionality(_ a: UnsafePointer<Int>?, b: UnsafeMutablePointer<Int>!, c: AutoreleasingUnsafeMutablePointer<Methods?>?) {}
 }
 
 // CHECK-LABEL: @interface MyObject : NSObject
@@ -353,7 +353,7 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class MyProtocolMetaCheck {
-  func test(_ x: MyProtocolMetaOnly.Type?) {}
+  @objc func test(_ x: MyProtocolMetaOnly.Type?) {}
 }
 // CHECK-LABEL: @protocol MyProtocolMetaOnly
 // CHECK-NEXT: @end
@@ -398,18 +398,18 @@
   // CHECK-NEXT: init
   // CHECK-NEXT: @end
   @objc class Inner2 {
-    var ref: NestedMembers?
+    @objc var ref: NestedMembers?
   }
 
-  var ref2: Inner2?
-  var ref3: Inner3?
+  @objc var ref2: Inner2?
+  @objc var ref3: Inner3?
 
   // CHECK-LABEL: @interface Inner3
   // CHECK-NEXT: @property (nonatomic, strong) NestedMembers * _Nullable ref;
   // CHECK-NEXT: init
   // CHECK-NEXT: @end
   @objc class Inner3 {
-    var ref: NestedMembers?
+    @objc var ref: NestedMembers?
   }
 }
 
@@ -509,12 +509,12 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class Properties {
-  var i: Int = 1
-  var mySelf: Properties {
+  @objc var i: Int = 1
+  @objc var mySelf: Properties {
     return self
   }
-  let pi = 3.14
-  var computed: Int {
+  @objc let pi = 3.14
+  @objc var computed: Int {
     get {
       return 42
     }
@@ -523,96 +523,96 @@
     }
   }
 
-  class var shared: Properties {
+  @objc class var shared: Properties {
     get { return Properties() }
     set { }
   }
 
-  class var sharedRO: Properties {
+  @objc class var sharedRO: Properties {
     get { return Properties() }
   }
 
-  weak var weakOther: Properties?
-  unowned var unownedOther: Properties = .shared
-  unowned(unsafe) var unmanagedOther: Properties = .shared
-  var unmanagedByDecl: Unmanaged<Properties>?
+  @objc weak var weakOther: Properties?
+  @objc unowned var unownedOther: Properties = .shared
+  @objc unowned(unsafe) var unmanagedOther: Properties = .shared
+  @objc var unmanagedByDecl: Unmanaged<Properties>?
 
-  weak var weakProto: MyProtocol?
-  weak var weakCF: CFTypeRef?
-  weak var weakCFString: CFString?
+  @objc weak var weakProto: MyProtocol?
+  @objc weak var weakCF: CFTypeRef?
+  @objc weak var weakCFString: CFString?
 
   typealias CFTypeRefAlias = CFTypeRef
 
-  var strongCF: CFTypeRef?
-  var strongCFAlias: CFTypeRefAlias?
+  @objc var strongCF: CFTypeRef?
+  @objc var strongCFAlias: CFTypeRefAlias?
 
-  var anyCF: CFAliasForType?
-  var anyCF2: CFAliasForType?
+  @objc var anyCF: CFAliasForType?
+  @objc var anyCF2: CFAliasForType?
 
   @IBOutlet weak var outlet: AnyObject!
   @IBOutlet var typedOutlet: Properties!
 
-  var string = "abc"
-  var array: Array<AnyObject> = []
-  var arrayOfArrays: Array<Array<Int>> = []
-  var arrayOfBlocks: Array<@convention(block) (AnyObject, Int) -> Bool> = []
-  var arrayOfArrayOfBlocks: Array<Array<@convention(block) () -> Void>> = []
-  var dictionary: Dictionary<String, String> = [:]
-  var dictStringInt: Dictionary<String, Int> = [:]
-  var stringSet: Set<String> = []
-  var intSet: Set<Int> = []
-  var cgFloatArray: Array<CGFloat> = []
-  var rangeArray: Array<NSRange> = []
+  @objc var string = "abc"
+  @objc var array: Array<AnyObject> = []
+  @objc var arrayOfArrays: Array<Array<Int>> = []
+  @objc var arrayOfBlocks: Array<@convention(block) (AnyObject, Int) -> Bool> = []
+  @objc var arrayOfArrayOfBlocks: Array<Array<@convention(block) () -> Void>> = []
+  @objc var dictionary: Dictionary<String, String> = [:]
+  @objc var dictStringInt: Dictionary<String, Int> = [:]
+  @objc var stringSet: Set<String> = []
+  @objc var intSet: Set<Int> = []
+  @objc var cgFloatArray: Array<CGFloat> = []
+  @objc var rangeArray: Array<NSRange> = []
 
   @IBOutlet var outletCollection: [Properties]!
   @IBOutlet var outletCollectionOptional: [ClassWithCustomName]? = []
   @IBOutlet var outletCollectionAnyObject: [AnyObject]?
   @IBOutlet var outletCollectionProto: [NSObjectProtocol]?
 
-  static let staticInt = 2
-  static var staticString = "Hello"
-  static var staticDouble: Double {
+  @objc static let staticInt = 2
+  @objc static var staticString = "Hello"
+  @objc static var staticDouble: Double {
     return 2.0
   }
-  static var staticDictionary: [String: String] { return [:] }
+  @objc static var staticDictionary: [String: String] { return [:] }
 
   @objc(wobble) var wibble: Properties?
 
-  var enabled: Bool {
+  @objc var enabled: Bool {
     @objc(isEnabled) get { return true }
     @objc(setIsEnabled:) set { }
   }
 
-  var isAnimated: Bool = true
+  @objc var isAnimated: Bool = true
 
-  var register: Bool = false
-  var this: Properties { return self }
+  @objc var register: Bool = false
+  @objc var this: Properties { return self }
 
-  private(set) var privateSetter = 2
-  private(set) var privateSetterCustomNames: Bool {
+  @objc private(set) var privateSetter = 2
+  @objc private(set) var privateSetterCustomNames: Bool {
     @objc(customGetterNameForPrivateSetter) get { return true }
     @objc(customSetterNameForPrivateSetter:) set {}
   }
 
-  static private(set) var privateSetter = 2
-  class private(set) var privateSetterCustomNames: Bool {
+  @objc static private(set) var privateSetter = 2
+  @objc class private(set) var privateSetterCustomNames: Bool {
     @objc(customGetterNameForPrivateSetter) get { return true }
     @objc(customSetterNameForPrivateSetter:) set {}
   }
-  static let sharedConstant = 2
+  @objc static let sharedConstant = 2
 
-  var initContext = 4
-  var initContextRO: Int { return 4 }
-  var getterIsInit: Bool {
+  @objc var initContext = 4
+  @objc var initContextRO: Int { return 4 }
+  @objc var getterIsInit: Bool {
     @objc(initGetter) get { return true }
     set {}
   }
-  var setterIsInit: Bool {
+  @objc var setterIsInit: Bool {
     get { return true }
     @objc(initSetter:) set {}
   }
 
-  var customValueTypeProp: URL?
+  @objc var customValueTypeProp: URL?
 }
 
 // CHECK-LABEL: @interface PropertiesOverridden
@@ -648,11 +648,11 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class Subscripts1 {
-  subscript (i: Int) -> Subscripts1 {
+  @objc subscript (i: Int) -> Subscripts1 {
     return self
   }
 
-  subscript (o: Subscripts1) -> Subscripts1 {
+  @objc subscript (o: Subscripts1) -> Subscripts1 {
     return self
   }
 }
@@ -666,7 +666,7 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class Subscripts2 {
-  subscript (i: Int16) -> Subscripts2 {
+  @objc subscript (i: Int16) -> Subscripts2 {
     get {
       return self
     }
@@ -675,7 +675,7 @@
     }
   }
 
-  subscript (o: NSObject) -> NSObject {
+  @objc subscript (o: NSObject) -> NSObject {
     get {
       return o
     }
@@ -685,7 +685,7 @@
   }
 
   // <rdar://problem/17165953> Swift: lazy property reflects back into Objective-C with two properties, one for underlying storage
-  lazy var cardPaths : [String] = []
+  @objc lazy var cardPaths : [String] = []
 }
 
 // CHECK-LABEL: @interface Subscripts3
@@ -693,7 +693,7 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class Subscripts3 {
-  subscript (_: CUnsignedLong) -> Subscripts3 {
+  @objc subscript (_: CUnsignedLong) -> Subscripts3 {
     return self
   }
 
@@ -712,14 +712,14 @@
 // CHECK-NEXT: - (nullable instancetype)initAndReturnError:(NSError * _Nullable * _Nullable)error fn:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(NSInteger))fn OBJC_DESIGNATED_INITIALIZER;
 // CHECK-NEXT: @end
 @objc class Throwing1 {
-  func method1() throws { }
-  func method2() throws -> Throwing1 { return self }
-  func method3(_ x: Int) throws -> [String] { return [] }
-  func method4() throws -> Self { return self }
+  @objc func method1() throws { }
+  @objc func method2() throws -> Throwing1 { return self }
+  @objc func method3(_ x: Int) throws -> [String] { return [] }
+  @objc func method4() throws -> Self { return self }
 
-  init() throws { }
-  init(string: String) throws { }
-  init(fn: (Int) -> Int) throws { }
+  @objc init() throws { }
+  @objc init(string: String) throws { }
+  @objc init(fn: (Int) -> Int) throws { }
 }
 
 @objc class Spoon: Fungible {}
@@ -736,7 +736,7 @@
   @objc func fungibleContainerWithAliases(_ x: FungibleContainer<Dipper>?) -> FungibleContainer<FungibleObject> { fatalError("") }
 
   // CHECK: - (void)referenceSingleGenericClass:(SingleImportedObjCGeneric<id> * _Nullable)_;
-  func referenceSingleGenericClass(_: SingleImportedObjCGeneric<AnyObject>?) {}
+  @objc func referenceSingleGenericClass(_: SingleImportedObjCGeneric<AnyObject>?) {}
 }
 // CHECK: @end
 
diff --git a/test/PrintAsObjC/depends-on-swift-framework.swift b/test/PrintAsObjC/depends-on-swift-framework.swift
index 082e395..148ca8c 100644
--- a/test/PrintAsObjC/depends-on-swift-framework.swift
+++ b/test/PrintAsObjC/depends-on-swift-framework.swift
@@ -25,7 +25,7 @@
 // CHECK-LABEL: @interface Test
 public class Test: NSObject {
   // CHECK: - (void)testSimpleTypealias:(id <Fungible> _Nonnull)_;
-  func testSimpleTypealias(_: AliasForFungible) {}
+  @objc func testSimpleTypealias(_: AliasForFungible) {}
   // CHECK: - (void)testGenericTypealias:(FungibleContainer<id <Fungible>> * _Nonnull)_;
-  func testGenericTypealias(_: FungibleContainer<AliasForFungible>) {}
+  @objc func testGenericTypealias(_: FungibleContainer<AliasForFungible>) {}
 } // CHECK: @end
diff --git a/test/PrintAsObjC/dispatch.swift b/test/PrintAsObjC/dispatch.swift
index 40282b8..613fab9 100644
--- a/test/PrintAsObjC/dispatch.swift
+++ b/test/PrintAsObjC/dispatch.swift
@@ -11,6 +11,6 @@
 // CHECK-LABEL: @interface Test : NSObject{{$}}
 public class Test : NSObject { 
   // CHECK-NEXT: - (void)thank:(dispatch_queue_t _Nonnull)queue;
-  public func thank(_ queue: DispatchQueue) {}
+  @objc public func thank(_ queue: DispatchQueue) {}
   // CHECK-NEXT: init
 } // CHECK-NEXT: @end
diff --git a/test/PrintAsObjC/extensions.swift b/test/PrintAsObjC/extensions.swift
index 0811a9f..160a414 100644
--- a/test/PrintAsObjC/extensions.swift
+++ b/test/PrintAsObjC/extensions.swift
@@ -31,7 +31,7 @@
 // CHECK-DAG: @property (nonatomic, readonly) NSInteger some;
 // CHECK-NEXT: @end
 extension A2 {
-  var some: Int { return 1 }
+  @objc var some: Int { return 1 }
 }
 @objc class A2 {}
 
@@ -47,10 +47,10 @@
 // CHECK-DAG: @end
 // CHECK: @end
 extension A3 {
-  var some: Int { return 1 }
+  @objc var some: Int { return 1 }
 }
 extension A3 {
-  var more: Int { return 10 }
+  @objc var more: Int { return 10 }
 }
 
 // CHECK-LABEL: @interface A4{{$}}
@@ -88,7 +88,7 @@
 // CHECK-NEXT: - (void)foo;
 // CHECK-NEXT: @end
 extension ClassWithCustomName {
-  func foo() {}
+  @objc func foo() {}
 }
 
 // NEGATIVE-NOT: CGColor
@@ -100,7 +100,7 @@
 // CHECK-NEXT: - (void)bar;
 // CHECK-NEXT: @end
 extension GenericClass {
-  func bar() {}
+  @objc func bar() {}
 }
 
 // NEGATIVE-NOT: NotObjC
@@ -113,7 +113,7 @@
 // CHECK-DAG: @property (nonatomic, readonly) NSInteger some;
 // CHECK-NEXT: @end
 extension NSObject {
-  var some: Int { return 1 }
+  @objc var some: Int { return 1 }
 }
 
 // NEGATIVE-NOT: @class NSString;
@@ -124,10 +124,10 @@
 // CHECK-NEXT: + (NSString * _Nullable)fromColor:(NSColor * _Nonnull)color SWIFT_WARN_UNUSED_RESULT;
 // CHECK-NEXT: @end
 extension NSString {
-  func test() {}
-  class func test2() {}
+  @objc func test() {}
+  @objc class func test2() {}
 
-  class func fromColor(_ color: NSColor) -> NSString? { return nil; }
+  @objc class func fromColor(_ color: NSColor) -> NSString? { return nil; }
 }
 
 // CHECK-LABEL: @interface PettableContainer<T> (SWIFT_EXTENSION(extensions))
@@ -138,9 +138,9 @@
 // CHECK-NEXT: - (T _Nullable)extract2 SWIFT_WARN_UNUSED_RESULT;
 // CHECK-NEXT: @end
 extension PettableContainer {
-  func duplicate() -> PettableContainer { fatalError() }
-  func duplicate2() -> PettableContainer<T> { fatalError() }
-  func duplicate3() -> PettableContainer<PettableOverextendedMetaphor> { fatalError() }
-  func extract() -> T { fatalError() }
-  func extract2() -> T? { fatalError() }
+  @objc func duplicate() -> PettableContainer { fatalError() }
+  @objc func duplicate2() -> PettableContainer<T> { fatalError() }
+  @objc func duplicate3() -> PettableContainer<PettableOverextendedMetaphor> { fatalError() }
+  @objc func extract() -> T { fatalError() }
+  @objc func extract2() -> T? { fatalError() }
 }
diff --git a/test/PrintAsObjC/imported-block-typedefs.swift b/test/PrintAsObjC/imported-block-typedefs.swift
index ecb1579..0749720 100644
--- a/test/PrintAsObjC/imported-block-typedefs.swift
+++ b/test/PrintAsObjC/imported-block-typedefs.swift
@@ -29,22 +29,22 @@
   // - (void)noescapeParam3:(SWIFT_NOESCAPE BlockWithNoescapeParam _Nonnull)input;
   // - (void)noescapeParam4:(SWIFT_NOESCAPE BlockReturningBlockWithEscapingParam _Nonnull)input;
   // - (void)noescapeParam5:(SWIFT_NOESCAPE BlockReturningBlockWithNoescapeParam _Nonnull)input;
-  func noescapeParam1(_ input: PlainBlock) {}
-  func noescapeParam2(_ input: BlockWithEscapingParam) {}
-  func noescapeParam3(_ input: BlockWithNoescapeParam) {}
-  func noescapeParam4(_ input: BlockReturningBlockWithEscapingParam) {}
-  func noescapeParam5(_ input: BlockReturningBlockWithNoescapeParam) {}
+  @objc func noescapeParam1(_ input: PlainBlock) {}
+  @objc func noescapeParam2(_ input: BlockWithEscapingParam) {}
+  @objc func noescapeParam3(_ input: BlockWithNoescapeParam) {}
+  @objc func noescapeParam4(_ input: BlockReturningBlockWithEscapingParam) {}
+  @objc func noescapeParam5(_ input: BlockReturningBlockWithNoescapeParam) {}
   
   // CHECK-NEXT: - (void)escapingParam1:(PlainBlock _Nonnull)input;
   // CHECK-NEXT: - (void)escapingParam2:(BlockWithEscapingParam _Nonnull)input;
   // CHECK-NEXT: - (void)escapingParam3:(BlockWithNoescapeParam _Nonnull)input;
   // CHECK-NEXT: - (void)escapingParam4:(BlockReturningBlockWithEscapingParam _Nonnull)input;
   // CHECK-NEXT: - (void)escapingParam5:(BlockReturningBlockWithNoescapeParam _Nonnull)input;
-  func escapingParam1(_ input: @escaping PlainBlock) {}
-  func escapingParam2(_ input: @escaping BlockWithEscapingParam) {}
-  func escapingParam3(_ input: @escaping BlockWithNoescapeParam) {}
-  func escapingParam4(_ input: @escaping BlockReturningBlockWithEscapingParam) {}
-  func escapingParam5(_ input: @escaping BlockReturningBlockWithNoescapeParam) {}
+  @objc func escapingParam1(_ input: @escaping PlainBlock) {}
+  @objc func escapingParam2(_ input: @escaping BlockWithEscapingParam) {}
+  @objc func escapingParam3(_ input: @escaping BlockWithNoescapeParam) {}
+  @objc func escapingParam4(_ input: @escaping BlockReturningBlockWithEscapingParam) {}
+  @objc func escapingParam5(_ input: @escaping BlockReturningBlockWithNoescapeParam) {}
   
   // CHECK-NEXT: - (void (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))resultHasNoescapeParam1 SWIFT_WARN_UNUSED_RESULT;
   // CHECK-NEXT: - (void (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(PlainBlock _Nullable)))resultHasNoescapeParam2 SWIFT_WARN_UNUSED_RESULT;
@@ -57,22 +57,22 @@
   //  - (void (^ _Nonnull)(SWIFT_NOESCAPE BlockWithNoescapeParam _Nonnull))resultHasNoescapeParam3 SWIFT_WARN_UNUSED_RESULT;
   //  - (void (^ _Nonnull)(SWIFT_NOESCAPE BlockReturningBlockWithEscapingParam _Nonnull))resultHasNoescapeParam4 SWIFT_WARN_UNUSED_RESULT;
   //  - (void (^ _Nonnull)(SWIFT_NOESCAPE BlockReturningBlockWithNoescapeParam _Nonnull))resultHasNoescapeParam5 SWIFT_WARN_UNUSED_RESULT;
-  func resultHasNoescapeParam1() -> (PlainBlock) -> () { fatalError() }
-  func resultHasNoescapeParam2() -> (BlockWithEscapingParam) -> () { fatalError() }
-  func resultHasNoescapeParam3() -> (BlockWithNoescapeParam) -> () { fatalError() }
-  func resultHasNoescapeParam4() -> (BlockReturningBlockWithEscapingParam) -> () { fatalError() }
-  func resultHasNoescapeParam5() -> (BlockReturningBlockWithNoescapeParam) -> () { fatalError() }
+  @objc func resultHasNoescapeParam1() -> (PlainBlock) -> () { fatalError() }
+  @objc func resultHasNoescapeParam2() -> (BlockWithEscapingParam) -> () { fatalError() }
+  @objc func resultHasNoescapeParam3() -> (BlockWithNoescapeParam) -> () { fatalError() }
+  @objc func resultHasNoescapeParam4() -> (BlockReturningBlockWithEscapingParam) -> () { fatalError() }
+  @objc func resultHasNoescapeParam5() -> (BlockReturningBlockWithNoescapeParam) -> () { fatalError() }
   
   // CHECK-NEXT: - (void (^ _Nonnull)(PlainBlock _Nonnull))resultHasEscapingParam1 SWIFT_WARN_UNUSED_RESULT;
   // CHECK-NEXT: - (void (^ _Nonnull)(BlockWithEscapingParam _Nonnull))resultHasEscapingParam2 SWIFT_WARN_UNUSED_RESULT;
   // CHECK-NEXT: - (void (^ _Nonnull)(BlockWithNoescapeParam _Nonnull))resultHasEscapingParam3 SWIFT_WARN_UNUSED_RESULT;
   // CHECK-NEXT: - (void (^ _Nonnull)(BlockReturningBlockWithEscapingParam _Nonnull))resultHasEscapingParam4 SWIFT_WARN_UNUSED_RESULT;
   // CHECK-NEXT: - (void (^ _Nonnull)(BlockReturningBlockWithNoescapeParam _Nonnull))resultHasEscapingParam5 SWIFT_WARN_UNUSED_RESULT;
-  func resultHasEscapingParam1() -> (@escaping PlainBlock) -> () { fatalError() }
-  func resultHasEscapingParam2() -> (@escaping BlockWithEscapingParam) -> () { fatalError() }
-  func resultHasEscapingParam3() -> (@escaping BlockWithNoescapeParam) -> () { fatalError() }
-  func resultHasEscapingParam4() -> (@escaping BlockReturningBlockWithEscapingParam) -> () { fatalError() }
-  func resultHasEscapingParam5() -> (@escaping BlockReturningBlockWithNoescapeParam) -> () { fatalError() }
+  @objc func resultHasEscapingParam1() -> (@escaping PlainBlock) -> () { fatalError() }
+  @objc func resultHasEscapingParam2() -> (@escaping BlockWithEscapingParam) -> () { fatalError() }
+  @objc func resultHasEscapingParam3() -> (@escaping BlockWithNoescapeParam) -> () { fatalError() }
+  @objc func resultHasEscapingParam4() -> (@escaping BlockReturningBlockWithEscapingParam) -> () { fatalError() }
+  @objc func resultHasEscapingParam5() -> (@escaping BlockReturningBlockWithNoescapeParam) -> () { fatalError() }
 
 }
 // CHECK-NEXT: init
diff --git a/test/PrintAsObjC/local-types.swift b/test/PrintAsObjC/local-types.swift
index eb770ab..1e06675 100644
--- a/test/PrintAsObjC/local-types.swift
+++ b/test/PrintAsObjC/local-types.swift
@@ -49,23 +49,23 @@
 // CHECK-NEXT: @end
 
 @objc class UseForward {
-  func definedAlready(_ a: AFullyDefinedClass) {}
+  @objc func definedAlready(_ a: AFullyDefinedClass) {}
 
-  func a(_ a: ZForwardClass1) {}
-  func b() -> ZForwardClass2 { return ZForwardClass2() }
-  func c(_ c: ZForwardAlias) {}
+  @objc func a(_ a: ZForwardClass1) {}
+  @objc func b() -> ZForwardClass2 { return ZForwardClass2() }
+  @objc func c(_ c: ZForwardAlias) {}
 
-  func d(_ d: (ZForwardProtocol1)) {}
-  func e(_ e: ZForwardProtocol2.Type) {}
-  func e2(_ e: ZForwardProtocol2) {}
-  func f(_ f: (ZForwardProtocol3, ZForwardProtocol4) -> ZForwardProtocol5) {}
-  func g(_ g: ZForwardProtocol6 & ZForwardProtocol7) {}
+  @objc func d(_ d: (ZForwardProtocol1)) {}
+  @objc func e(_ e: ZForwardProtocol2.Type) {}
+  @objc func e2(_ e: ZForwardProtocol2) {}
+  @objc func f(_ f: (ZForwardProtocol3, ZForwardProtocol4) -> ZForwardProtocol5) {}
+  @objc func g(_ g: ZForwardProtocol6 & ZForwardProtocol7) {}
 
   func h(_ h: ANonObjCClass) -> ANonObjCClass.Type { return type(of: h) }
-  func i(_: ZForwardProtocol8) {}
+  @objc func i(_: ZForwardProtocol8) {}
 
-  var j: ZForwardClass3 { return ZForwardClass3() }
-  var k: ZForwardClass4.Type { return ZForwardClass4.self }
+  @objc var j: ZForwardClass3 { return ZForwardClass3() }
+  @objc var k: ZForwardClass4.Type { return ZForwardClass4.self }
 }
 
 // CHECK-NOT: @class ZForwardClass1;
@@ -77,8 +77,8 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class UseForwardAgain {
-  func a(_ a: ZForwardClass1) {}
-  func b(_ b: ZForwardProtocol1) {}
+  @objc func a(_ a: ZForwardClass1) {}
+  @objc func b(_ b: ZForwardProtocol1) {}
 }
 
 typealias ZForwardAlias = ZForwardAliasClass
@@ -91,7 +91,7 @@
 // CHECK-NEXT: init
 // CHECK-NEXT: @end
 @objc class ZForwardClass1 {
-  func circular(_ a: UseForward) {}
+  @objc func circular(_ a: UseForward) {}
 }
 @objc class ZForwardClass2 {}
 @objc class ZForwardClass3 {}
diff --git a/test/PrintAsObjC/mixed-framework.swift b/test/PrintAsObjC/mixed-framework.swift
index f7f1049..4451f59 100644
--- a/test/PrintAsObjC/mixed-framework.swift
+++ b/test/PrintAsObjC/mixed-framework.swift
@@ -23,12 +23,12 @@
 // CHECK-LABEL: @interface Dummy : NSNumber
 public class Dummy: NSNumber {
   // CHECK: - (CIntAlias)getIntAlias SWIFT_WARN_UNUSED_RESULT;
-  public func getIntAlias() -> CIntAlias {
+  @objc public func getIntAlias() -> CIntAlias {
     let result: CInt = 0
     return result
   }
 
   // FRAMEWORK: @property (nonatomic, readonly) NSInteger extraData;
   // HEADER: @property (nonatomic) NSInteger extraData;
-  public internal(set) var extraData: Int = 0
+  @objc public internal(set) var extraData: Int = 0
 } // CHECK: @end
diff --git a/test/PrintAsObjC/never.swift b/test/PrintAsObjC/never.swift
index a227cbf..8c3ebac 100644
--- a/test/PrintAsObjC/never.swift
+++ b/test/PrintAsObjC/never.swift
@@ -8,7 +8,7 @@
 // REQUIRES: objc_interop
 
 @objc public class NeverClass {
-  func doesNotReturn() -> Never { while true {} }
+  @objc func doesNotReturn() -> Never { while true {} }
 }
 
 // CHECK-LABEL: @interface NeverClass
diff --git a/test/PrintAsObjC/newtype.swift b/test/PrintAsObjC/newtype.swift
index 13d90ca..1385575 100644
--- a/test/PrintAsObjC/newtype.swift
+++ b/test/PrintAsObjC/newtype.swift
@@ -23,26 +23,26 @@
 // CHECK-LABEL: @interface TestEnumLike : NSObject
 class TestEnumLike : NSObject {
   // CHECK: - (void)takesNewtype:(EnumLikeStringWrapper _Nonnull)a;
-  func takesNewtype(_ a: EnumLikeStringWrapper) {}
+  @objc func takesNewtype(_ a: EnumLikeStringWrapper) {}
   // CHECK: - (void)takesNewtypeArray:(NSArray<EnumLikeStringWrapper> * _Nonnull)a;
-  func takesNewtypeArray(_ a: [EnumLikeStringWrapper]) {}
+  @objc func takesNewtypeArray(_ a: [EnumLikeStringWrapper]) {}
   // CHECK: - (void)takesNewtypeDictionary:(NSDictionary<EnumLikeStringWrapper, EnumLikeStringWrapper> * _Nonnull)a;
-  func takesNewtypeDictionary(_ a: [EnumLikeStringWrapper: EnumLikeStringWrapper]) {}
+  @objc func takesNewtypeDictionary(_ a: [EnumLikeStringWrapper: EnumLikeStringWrapper]) {}
   // CHECK: - (void)takesNewtypeOptional:(EnumLikeStringWrapper _Nullable)a;
-  func takesNewtypeOptional(_ a: EnumLikeStringWrapper?) {}
+  @objc func takesNewtypeOptional(_ a: EnumLikeStringWrapper?) {}
 }
 // CHECK: @end
 
 // CHECK-LABEL: @interface TestStructLike : NSObject
 class TestStructLike : NSObject {
   // CHECK: - (void)takesNewtype:(StructLikeStringWrapper _Nonnull)a;
-  func takesNewtype(_ a: StructLikeStringWrapper) {}
+  @objc func takesNewtype(_ a: StructLikeStringWrapper) {}
   // CHECK: - (void)takesNewtypeArray:(NSArray<StructLikeStringWrapper> * _Nonnull)a;
-  func takesNewtypeArray(_ a: [StructLikeStringWrapper]) {}
+  @objc func takesNewtypeArray(_ a: [StructLikeStringWrapper]) {}
   // CHECK: - (void)takesNewtypeDictionary:(NSDictionary<StructLikeStringWrapper, StructLikeStringWrapper> * _Nonnull)a;
-  func takesNewtypeDictionary(_ a: [StructLikeStringWrapper: StructLikeStringWrapper]) {}
+  @objc func takesNewtypeDictionary(_ a: [StructLikeStringWrapper: StructLikeStringWrapper]) {}
   // CHECK: - (void)takesNewtypeOptional:(StructLikeStringWrapper _Nullable)a;
-  func takesNewtypeOptional(_ a: StructLikeStringWrapper?) {}
+  @objc func takesNewtypeOptional(_ a: StructLikeStringWrapper?) {}
 }
 // CHECK: @end
 
diff --git a/test/PrintAsObjC/swift3_deprecated_objc_inference.swift b/test/PrintAsObjC/swift3_deprecated_objc_inference.swift
new file mode 100644
index 0000000..e80c84f
--- /dev/null
+++ b/test/PrintAsObjC/swift3_deprecated_objc_inference.swift
@@ -0,0 +1,46 @@
+// REQUIRES: objc_interop
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// FIXME: BEGIN -enable-source-import hackaround
+// RUN:  %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/ObjectiveC.swift
+// RUN:  %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t  %S/../Inputs/clang-importer-sdk/swift-modules/CoreGraphics.swift
+// RUN:  %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t  %S/../Inputs/clang-importer-sdk/swift-modules/Foundation.swift
+// RUN:  %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t  %S/../Inputs/clang-importer-sdk/swift-modules/AppKit.swift
+// FIXME: END -enable-source-import hackaround
+
+
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -I %S/Inputs/custom-modules -o %t %s -disable-objc-attr-requires-foundation-module -swift-version 3
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -parse-as-library %t/swift3_deprecated_objc_inference.swiftmodule -typecheck -I %S/Inputs/custom-modules -emit-objc-header-path %t/swift3_deprecated_objc_inference.h -import-objc-header %S/../Inputs/empty.h -disable-objc-attr-requires-foundation-module -swift-version 3
+// RUN: %FileCheck %s < %t/swift3_deprecated_objc_inference.h
+// RUN: %check-in-clang -I %S/Inputs/custom-modules/ %t/swift3_deprecated_objc_inference.h
+
+import Foundation
+
+// CHECK-LABEL: @interface A1{{$}}
+// CHECK-NEXT: init
+// CHECK-NEXT: @end
+@objc class A1 {
+}
+
+// CHECK-LABEL: @interface A2{{$}}
+// CHECK-NEXT: - (nonnull instancetype)initWithA2:(A2 * _Nonnull)a2 OBJC_DESIGNATED_INITIALIZER SWIFT_DEPRECATED_MSG("Swift initializer 'A2.init(a2:)' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");
+// CHECK-NEXT: - (void)foo SWIFT_DEPRECATED_MSG("Swift method 'A2.foo()' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");
+// CHECK-NEXT: + (void)bar SWIFT_DEPRECATED_MSG("Swift method 'A2.bar()' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");
+// CHECK-NEXT: @property (nonatomic, strong) A2 * _Nullable property SWIFT_DEPRECATED_MSG("Swift property 'A2.property' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");
+// CHECK-NEXT: SWIFT_CLASS_PROPERTY(@property (nonatomic, class, strong) A2 * _Nullable static_property SWIFT_DEPRECATED_MSG("Swift property 'A2.static_property' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");)
+// CHECK-NEXT: + (A2 * _Nullable)static_property SWIFT_WARN_UNUSED_RESULT SWIFT_DEPRECATED_MSG("Swift property 'A2.static_property' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");
+// CHECK-NEXT: + (void)setStatic_property:(A2 * _Nullable)value SWIFT_DEPRECATED_MSG("Swift property 'A2.static_property' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");
+// CHECK-NEXT: - (A2 * _Nonnull)objectAtIndexedSubscript:(NSInteger)i SWIFT_WARN_UNUSED_RESULT SWIFT_DEPRECATED_MSG("Swift subscript 'A2.subscript(_:)' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");
+// CHECK-NEXT: - (void)setObject:(A2 * _Nonnull)newValue atIndexedSubscript:(NSInteger)i SWIFT_DEPRECATED_MSG("Swift subscript 'A2.subscript(_:)' uses '@objc' inference deprecated in Swift 4; add '@objc' to provide an Objective-C entrypoint");
+
+// CHECK-NEXT: @end
+@objc class A2 {
+  init(a2: A2) { }
+  func foo() { }
+  class func bar() { }
+  var property: A2? = nil
+  static var static_property: A2? = nil
+  subscript (i: Int) -> A2 { get { return self } set { } }
+}
diff --git a/test/PrintAsObjC/swift_name.swift b/test/PrintAsObjC/swift_name.swift
index 31b9573..7cb766a 100644
--- a/test/PrintAsObjC/swift_name.swift
+++ b/test/PrintAsObjC/swift_name.swift
@@ -26,10 +26,10 @@
 // CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
 // CHECK-NEXT: @end
 class Test : NSObject {
-  func makeArray(_: ZZStringAlias) -> [ZZStringAlias] { return [] }
-  func usePoint(_: ZZPoint) {}
-  func useAlignment(_: ZZAlignment) {}
-  func useObjects(_: ZZClass) -> [ZZProto] { return [] }
+  @objc func makeArray(_: ZZStringAlias) -> [ZZStringAlias] { return [] }
+  @objc func usePoint(_: ZZPoint) {}
+  @objc func useAlignment(_: ZZAlignment) {}
+  @objc func useObjects(_: ZZClass) -> [ZZProto] { return [] }
 }
 
 @objc
diff --git a/test/Prototypes/CollectionTransformers.swift b/test/Prototypes/CollectionTransformers.swift
index ffe3ded..7bd99bc 100644
--- a/test/Prototypes/CollectionTransformers.swift
+++ b/test/Prototypes/CollectionTransformers.swift
@@ -11,8 +11,6 @@
 //===----------------------------------------------------------------------===//
 // RUN: %target-run-stdlib-swift
 // REQUIRES: executable_test
-// Remove XFAIL once rdar://31286125 is resolved.
-// REQUIRES: rdar31286125
 
 // FIXME: This test runs very slowly on watchOS.
 // UNSUPPORTED: OS=watchos
diff --git a/test/SILGen/auto_closures.swift b/test/SILGen/auto_closures.swift
index 0527db4..5bd2702 100644
--- a/test/SILGen/auto_closures.swift
+++ b/test/SILGen/auto_closures.swift
@@ -48,7 +48,7 @@
   // CHECK: return [[RET]] : $Bool
   // CHECK: }
 
-  // CHECK-LABEL: sil shared [transparent] @_T013auto_closures3SubC1xAA4BoolVfgAFyXKfu_ : $@convention(thin) (@owned Sub) -> Bool {
+  // CHECK-LABEL: sil private [transparent] @_T013auto_closures3SubC1xAA4BoolVfgAFyXKfu_ : $@convention(thin) (@owned Sub) -> Bool {
   // CHECK: [[SUPER:%[0-9]+]] = function_ref @_T013auto_closures4BaseC1xAA4BoolVfg : $@convention(method) (@guaranteed Base) -> Bool
   // CHECK: [[RET:%.*]] = apply [[SUPER]]({{%.*}})
   // CHECK: return [[RET]]
@@ -57,9 +57,9 @@
 
 // CHECK-LABEL: sil hidden @_T013auto_closures20closureInAutoclosureAA4BoolVAD_ADtF : $@convention(thin) (Bool, Bool) -> Bool {
 // CHECK: }
-// CHECK-LABEL: sil shared [transparent] @_T013auto_closures20closureInAutoclosureAA4BoolVAD_ADtFADyXKfu_ : $@convention(thin) (Bool, Bool) -> Bool {
+// CHECK-LABEL: sil private [transparent] @_T013auto_closures20closureInAutoclosureAA4BoolVAD_ADtFADyXKfu_ : $@convention(thin) (Bool, Bool) -> Bool {
 // CHECK: }
-// CHECK-LABEL: sil shared @_T013auto_closures20closureInAutoclosureAA4BoolVAD_ADtFADyXKfu_A2DcfU_ : $@convention(thin) (Bool, Bool) -> Bool {
+// CHECK-LABEL: sil private @_T013auto_closures20closureInAutoclosureAA4BoolVAD_ADtFADyXKfu_A2DcfU_ : $@convention(thin) (Bool, Bool) -> Bool {
 // CHECK: }
 func compareBool(_ lhs: Bool, _ rhs: Bool) -> Bool { return false_ }
 func testBool(_ x: Bool, _ pred: (Bool) -> Bool) -> Bool {
diff --git a/test/SILGen/c_function_pointers.swift b/test/SILGen/c_function_pointers.swift
index 371363a..7724353 100644
--- a/test/SILGen/c_function_pointers.swift
+++ b/test/SILGen/c_function_pointers.swift
@@ -54,8 +54,8 @@
   calls(unsupported, x) // expected-error{{C function pointer signature '(Any) -> Int' is not compatible with expected type '@convention(c) (Int) -> Int'}}
 }
 
-// CHECK-LABEL: sil shared @_T019c_function_pointers22StructWithInitializersV3fn1yyXCvfiyycfU_ : $@convention(thin) () -> () {
-// CHECK-LABEL: sil shared [thunk] @_T019c_function_pointers22StructWithInitializersV3fn1yyXCvfiyycfU_To : $@convention(c) () -> () {
+// CHECK-LABEL: sil private @_T019c_function_pointers22StructWithInitializersV3fn1yyXCvfiyycfU_ : $@convention(thin) () -> () {
+// CHECK-LABEL: sil private [thunk] @_T019c_function_pointers22StructWithInitializersV3fn1yyXCvfiyycfU_To : $@convention(c) () -> () {
 
 struct StructWithInitializers {
   let fn1: @convention(c) () -> () = {}
diff --git a/test/SILGen/capture-canonicalization.swift b/test/SILGen/capture-canonicalization.swift
index 6ecdf3d..ccf7d57 100644
--- a/test/SILGen/capture-canonicalization.swift
+++ b/test/SILGen/capture-canonicalization.swift
@@ -5,7 +5,7 @@
 
 extension Foo where T == Bar {
   func foo(x: T) -> Bar {
-    // CHECK-LABEL: sil shared @{{.*}}3foo{{.*}}4foo2{{.*}} : $@convention(thin) (Bar) -> Bar
+    // CHECK-LABEL: sil private @{{.*}}3foo{{.*}}4foo2{{.*}} : $@convention(thin) (Bar) -> Bar
     func foo2() -> Bar {
       return x
     }
diff --git a/test/SILGen/capture_inout.swift b/test/SILGen/capture_inout.swift
index a0a8558..e11e68a 100644
--- a/test/SILGen/capture_inout.swift
+++ b/test/SILGen/capture_inout.swift
@@ -8,7 +8,7 @@
 // CHECK:   [[FUNC:%.*]] = function_ref [[CLOSURE:@.*]] : $@convention(thin) (@inout_aliasable Builtin.Int64) -> Builtin.Int64
 // CHECK:   apply [[FUNC]]([[X_INOUT]])
 // CHECK: }
-// CHECK: sil shared [[CLOSURE]] : $@convention(thin) (@inout_aliasable Builtin.Int64) -> Builtin.Int64
+// CHECK: sil private [[CLOSURE]] : $@convention(thin) (@inout_aliasable Builtin.Int64) -> Builtin.Int64
 func localFoo(x: inout Int) {
   func bar() -> Int {
     return x
@@ -22,7 +22,7 @@
 // CHECK:   [[FUNC:%.*]] = function_ref [[CLOSURE:@.*]] : $@convention(thin) (@inout_aliasable Builtin.Int64) -> Builtin.Int64
 // CHECK:   apply [[FUNC]]([[X_INOUT]])
 // CHECK: }
-// CHECK: sil shared [[CLOSURE]] : $@convention(thin) (@inout_aliasable Builtin.Int64) -> Builtin.Int64
+// CHECK: sil private [[CLOSURE]] : $@convention(thin) (@inout_aliasable Builtin.Int64) -> Builtin.Int64
 func anonFoo(x: inout Int) {
   { return x }()
 }
diff --git a/test/SILGen/capture_typealias.swift b/test/SILGen/capture_typealias.swift
index e0cf13d..411bde1 100644
--- a/test/SILGen/capture_typealias.swift
+++ b/test/SILGen/capture_typealias.swift
@@ -19,4 +19,4 @@
   }
 }
 
-// CHECK: sil shared @_T017capture_typealias3fooyyFBi64_ycfU_ : $@convention(thin) () -> Builtin.Int64 {
+// CHECK: sil private @_T017capture_typealias3fooyyFBi64_ycfU_ : $@convention(thin) () -> Builtin.Int64 {
diff --git a/test/SILGen/capture_typed_boxes.swift b/test/SILGen/capture_typed_boxes.swift
index 194d211..ef111b6 100644
--- a/test/SILGen/capture_typed_boxes.swift
+++ b/test/SILGen/capture_typed_boxes.swift
@@ -4,7 +4,7 @@
   var x = x
   return { x }
 }
-// CHECK-LABEL: sil shared @_T019capture_typed_boxes3fooSiycSiFSiycfU_ : $@convention(thin) (@owned { var Int }) -> Int {
+// CHECK-LABEL: sil private @_T019capture_typed_boxes3fooSiycSiFSiycfU_ : $@convention(thin) (@owned { var Int }) -> Int {
 // CHECK:       bb0(%0 : ${ var Int }):
 
 func closure(_ f: @escaping (Int) -> Int) -> Int {
@@ -15,7 +15,7 @@
 
   return bar(0)
 }
-// CHECK-LABEL: sil shared @_T019capture_typed_boxes7closureS3icF3barL_S2iF : $@convention(thin) (Int, @owned { var @callee_owned (Int) -> Int }) -> Int {
+// CHECK-LABEL: sil private @_T019capture_typed_boxes7closureS3icF3barL_S2iF : $@convention(thin) (Int, @owned { var @callee_owned (Int) -> Int }) -> Int {
 // CHECK:       bb0(%0 : $Int, %1 : ${ var @callee_owned (Int) -> Int }):
 
 func closure_generic<T>(_ f: @escaping (T) -> T, x: T) -> T {
@@ -26,6 +26,6 @@
 
   return bar(x)
 }
-// CHECK-LABEL: sil shared @_T019capture_typed_boxes15closure_generic{{.*}} : $@convention(thin) <T> (@in T, @owned <τ_0_0> { var @callee_owned (@in τ_0_0) -> @out τ_0_0 } <T>) -> @out T {
+// CHECK-LABEL: sil private @_T019capture_typed_boxes15closure_generic{{.*}} : $@convention(thin) <T> (@in T, @owned <τ_0_0> { var @callee_owned (@in τ_0_0) -> @out τ_0_0 } <T>) -> @out T {
 // CHECK-LABEL: bb0(%0 : $*T, %1 : $*T, %2 : $<τ_0_0> { var @callee_owned (@in τ_0_0) -> @out τ_0_0 } <T>):
 
diff --git a/test/SILGen/cf.swift b/test/SILGen/cf.swift
index a2c330c..4740273 100644
--- a/test/SILGen/cf.swift
+++ b/test/SILGen/cf.swift
@@ -65,9 +65,9 @@
 
 extension CCImpedance: Impedance {}
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4real9ComponentQzfgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4real9ComponentQzfgTW
 // CHECK-LABEL: sil shared [transparent] [serializable] @_T0SC11CCImpedanceV4realSdfg
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4imag9ComponentQzfgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4imag9ComponentQzfgTW
 // CHECK-LABEL: sil shared [transparent] [serializable] @_T0SC11CCImpedanceV4imagSdfg
 
 class MyMagnetism : CCMagnetismModel {
diff --git a/test/SILGen/closure_inline_initializer.swift b/test/SILGen/closure_inline_initializer.swift
index b3c1e61..704e46d 100644
--- a/test/SILGen/closure_inline_initializer.swift
+++ b/test/SILGen/closure_inline_initializer.swift
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
 
-// CHECK-LABEL: sil shared @_T026closure_inline_initializer3FooV3fooSivfiSiycfU_
+// CHECK-LABEL: sil private @_T026closure_inline_initializer3FooV3fooSivfiSiycfU_
 
 struct Foo {
   var foo: Int = { 2 }()
diff --git a/test/SILGen/closure_self_recursion.swift b/test/SILGen/closure_self_recursion.swift
index dee5ce2..800d20e 100644
--- a/test/SILGen/closure_self_recursion.swift
+++ b/test/SILGen/closure_self_recursion.swift
@@ -3,13 +3,13 @@
 
 // CHECK-LABEL: sil @main
 
-// CHECK-LABEL: sil shared @_T03foo5recuryycfgyycfU_
+// CHECK-LABEL: sil private @_T03foo5recuryycfgyycfU_
 var recur : () -> () {
   // CHECK-LABEL: function_ref @_T03foo5recuryycfg
   return { recur() } // expected-warning {{attempting to access 'recur' within its own getter}}
 }
 
-// CHECK-LABEL: sil shared @_T03foo12recur_harderyycyyccfgyycyyccfU_
+// CHECK-LABEL: sil private @_T03foo12recur_harderyycyyccfgyycyyccfU_
 var recur_harder : (() -> ()) -> (() -> ()) {
   // CHECK-LABEL: function_ref @_T03foo12recur_harderyycyyccfg
   return { f in recur_harder(f) } // expected-warning {{attempting to access 'recur_harder' within its own getter}}
diff --git a/test/SILGen/closures.swift b/test/SILGen/closures.swift
index e58c2a4..b67bfa1 100644
--- a/test/SILGen/closures.swift
+++ b/test/SILGen/closures.swift
@@ -48,7 +48,7 @@
 }
 // CHECK:   } // end sil function '_T08closures17read_only_captureS2iF'
 
-// CHECK: sil shared @[[CAP_NAME]]
+// CHECK: sil private @[[CAP_NAME]]
 // CHECK: bb0([[XBOX:%[0-9]+]] : ${ var Int }):
 // CHECK: [[XADDR:%[0-9]+]] = project_box [[XBOX]]
 // CHECK: [[X:%[0-9]+]] = load [trivial] [[XADDR]]
@@ -90,7 +90,7 @@
 }
 // CHECK:  } // end sil function '_T08closures16write_to_captureS2iF'
 
-// CHECK: sil shared @[[SCRIB_NAME]]
+// CHECK: sil private @[[SCRIB_NAME]]
 // CHECK: bb0([[XBOX:%[0-9]+]] : ${ var Int }):
 // CHECK:   [[XADDR:%[0-9]+]] = project_box [[XBOX]]
 // CHECK:   copy_addr {{%[0-9]+}} to [[XADDR]]
@@ -137,10 +137,10 @@
 }
 // CHECK: } // end sil function '_T08closures18capture_local_funcSiycycSiF'
 
-// CHECK: sil shared @[[ALEPH_NAME:_T08closures18capture_local_funcSiycycSiF5alephL_SiyF]] : $@convention(thin) (@owned { var Int }) -> Int {
+// CHECK: sil private @[[ALEPH_NAME:_T08closures18capture_local_funcSiycycSiF5alephL_SiyF]] : $@convention(thin) (@owned { var Int }) -> Int {
 // CHECK: bb0([[XBOX:%[0-9]+]] : ${ var Int }):
 
-// CHECK: sil shared @[[BETH_NAME]] : $@convention(thin) (@owned { var Int }) -> @owned @callee_owned () -> Int {
+// CHECK: sil private @[[BETH_NAME]] : $@convention(thin) (@owned { var Int }) -> @owned @callee_owned () -> Int {
 // CHECK: bb0([[XBOX:%[0-9]+]] : ${ var Int }):
 // CHECK:   [[XBOX_PB:%.*]] = project_box [[XBOX]]
 // CHECK:   [[ALEPH_REF:%[0-9]+]] = function_ref @[[ALEPH_NAME]] : $@convention(thin) (@owned { var Int }) -> Int
@@ -168,7 +168,7 @@
   // CHECK: destroy_value [[XBOX]]
   // CHECK: return [[RET]]
 }
-// CHECK: sil shared @[[CLOSURE_NAME]]
+// CHECK: sil private @[[CLOSURE_NAME]]
 // CHECK: bb0([[XADDR:%[0-9]+]] : $*Int):
 // CHECK: [[X:%[0-9]+]] = load [trivial] [[XADDR]]
 // CHECK: return [[X]]
@@ -189,7 +189,7 @@
   // CHECK: destroy_value [[XBOX]]
   // CHECK: return [[RET]]
 }
-// CHECK: sil shared @[[CLOSURE_NAME]]
+// CHECK: sil private @[[CLOSURE_NAME]]
 // CHECK: bb0([[XADDR:%[0-9]+]] : $*Int):
 // CHECK: [[X:%[0-9]+]] = load [trivial] [[XADDR]]
 // CHECK: return [[X]]
@@ -209,7 +209,7 @@
   // CHECK: destroy_value [[XBOX]]
   // CHECK: return [[ANON_CLOSURE_APP]]
 }
-// CHECK: sil shared @[[CLOSURE_NAME]] : $@convention(thin) (Int, @owned { var Int }) -> Int
+// CHECK: sil private @[[CLOSURE_NAME]] : $@convention(thin) (Int, @owned { var Int }) -> Int
 // CHECK: bb0([[DOLLAR0:%[0-9]+]] : $Int, [[XBOX:%[0-9]+]] : ${ var Int }):
 // CHECK: [[XADDR:%[0-9]+]] = project_box [[XBOX]]
 // CHECK: [[PLUS:%[0-9]+]] = function_ref @_T0s1poiS2i_SitF{{.*}}
@@ -225,7 +225,7 @@
   // CHECK:   return [[ANON_THICK]]
   return { $0 }
 }
-// CHECK: sil shared @[[CLOSURE_NAME]] : $@convention(thin) (Int) -> Int
+// CHECK: sil private @[[CLOSURE_NAME]] : $@convention(thin) (Int) -> Int
 // CHECK: bb0([[YARG:%[0-9]+]] : $Int):
 
 // CHECK-LABEL: sil hidden @_T08closures17uncaptured_locals{{[_0-9a-zA-Z]*}}F :
@@ -268,11 +268,11 @@
     var z = { _ = T.self } ()
   }
 
-  // CHECK-LABEL: sil shared @_T08closures16SomeGenericClassCfdSiycfU_ : $@convention(thin) (@inout_aliasable Int) -> Int
+  // CHECK-LABEL: sil private @_T08closures16SomeGenericClassCfdSiycfU_ : $@convention(thin) (@inout_aliasable Int) -> Int
 
-  // CHECK-LABEL: sil shared @_T08closures16SomeGenericClassCfdSiycfU0_ : $@convention(thin) () -> Int
+  // CHECK-LABEL: sil private @_T08closures16SomeGenericClassCfdSiycfU0_ : $@convention(thin) () -> Int
 
-  // CHECK-LABEL: sil shared @_T08closures16SomeGenericClassCfdyycfU1_ : $@convention(thin) <T> () -> ()
+  // CHECK-LABEL: sil private @_T08closures16SomeGenericClassCfdyycfU1_ : $@convention(thin) <T> () -> ()
 }
 
 // This is basically testing that the constraint system ranking
@@ -284,7 +284,7 @@
   takesSomeClassGenerator({ x })
 }
 
-// CHECK-LABEL: sil shared @_T08closures20generateWithConstantyAA17SomeSpecificClassCFAA0eG0CycfU_ : $@convention(thin) (@owned SomeSpecificClass) -> @owned SomeClass {
+// CHECK-LABEL: sil private @_T08closures20generateWithConstantyAA17SomeSpecificClassCFAA0eG0CycfU_ : $@convention(thin) (@owned SomeSpecificClass) -> @owned SomeClass {
 // CHECK: bb0([[T0:%.*]] : $SomeSpecificClass):
 // CHECK:   debug_value [[T0]] : $SomeSpecificClass, let, name "x", argno 1
 // CHECK:   [[BORROWED_T0:%.*]] = begin_borrow [[T0]]
@@ -369,7 +369,7 @@
 
 // The let property needs to be captured into a temporary stack slot so that it
 // is loadable even though we capture the value.
-// CHECK-LABEL: sil shared @_T08closures18closeOverLetLValueyyFSiycfU_ : $@convention(thin) (@owned ClassWithIntProperty) -> Int {
+// CHECK-LABEL: sil private @_T08closures18closeOverLetLValueyyFSiycfU_ : $@convention(thin) (@owned ClassWithIntProperty) -> Int {
 // CHECK: bb0([[ARG:%.*]] : $ClassWithIntProperty):
 // CHECK:   [[TMP_CLASS_ADDR:%.*]] = alloc_stack $ClassWithIntProperty, let, name "a", argno 1
 // CHECK:   store [[ARG]] to [init] [[TMP_CLASS_ADDR]] : $*ClassWithIntProperty
@@ -407,7 +407,7 @@
 // CHECK: partial_apply [[CLOSURE]](%0) : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int
 
 // Check that the closure body only takes the pointer.
-// CHECK-LABEL: sil shared @_T08closures24StructWithMutatingMethodV08mutatingE0{{.*}} : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int {
+// CHECK-LABEL: sil private @_T08closures24StructWithMutatingMethodV08mutatingE0{{.*}} : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int {
 // CHECK:       bb0(%0 : $*StructWithMutatingMethod):
 
 class SuperBase {
@@ -423,7 +423,7 @@
   // CHECK:   apply [[INNER]]([[SELF_COPY]])
   // CHECK: } // end sil function '_T08closures8SuperSubC1ayyF'
   func a() {
-    // CHECK: sil shared @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> () {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> () {
     // CHECK: bb0([[ARG:%.*]] : $SuperSub):
     // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
     // CHECK:   [[CLASS_METHOD:%.*]] = class_method [[BORROWED_ARG]] : $SuperSub, #SuperSub.boom!1
@@ -452,7 +452,7 @@
   // CHECK:   = apply [[INNER]]([[SELF_COPY]])
   // CHECK: } // end sil function '_T08closures8SuperSubC1byyF'
   func b() {
-    // CHECK: sil shared @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> () {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> () {
     // CHECK: bb0([[ARG:%.*]] : $SuperSub):
     // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
     // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:_T08closures8SuperSubC1b.*]] : $@convention(thin) (@owned SuperSub) -> ()
@@ -460,7 +460,7 @@
     // CHECK:   destroy_value [[ARG]]
     // CHECK: } // end sil function '[[INNER_FUNC_1]]'
     func b1() {
-      // CHECK: sil shared @[[INNER_FUNC_2]] : $@convention(thin) (@owned SuperSub) -> () {
+      // CHECK: sil private @[[INNER_FUNC_2]] : $@convention(thin) (@owned SuperSub) -> () {
       // CHECK: bb0([[ARG:%.*]] : $SuperSub):
       // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
       // CHECK:   [[CLASS_METHOD:%.*]] = class_method [[BORROWED_ARG]] : $SuperSub, #SuperSub.boom!1
@@ -496,7 +496,7 @@
   // CHECK:   destroy_value [[PA]]
   // CHECK: } // end sil function '_T08closures8SuperSubC1cyyF'
   func c() {
-    // CHECK: sil shared @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> ()
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> ()
     // CHECK: bb0([[ARG:%.*]] : $SuperSub):
     // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
     // CHECK:   [[CLASS_METHOD:%.*]] = class_method [[BORROWED_ARG]] : $SuperSub, #SuperSub.boom!1
@@ -530,7 +530,7 @@
   // CHECK:   destroy_value [[PA]]
   // CHECK: } // end sil function '_T08closures8SuperSubC1dyyF'
   func d() {
-    // CHECK: sil shared @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> () {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> () {
     // CHECK: bb0([[ARG:%.*]] : $SuperSub):
     // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
     // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:_T08closures8SuperSubC1d.*]] : $@convention(thin) (@owned SuperSub) -> ()
@@ -538,7 +538,7 @@
     // CHECK:   destroy_value [[ARG]]
     // CHECK: } // end sil function '[[INNER_FUNC_1]]'
     let d1 = { () -> Void in
-      // CHECK: sil shared @[[INNER_FUNC_2]] : $@convention(thin) (@owned SuperSub) -> () {
+      // CHECK: sil private @[[INNER_FUNC_2]] : $@convention(thin) (@owned SuperSub) -> () {
       // CHECK: bb0([[ARG:%.*]] : $SuperSub):
       // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
       // CHECK:   [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
@@ -564,7 +564,7 @@
   // CHECK: = apply [[INNER]]([[SELF_COPY]])
   // CHECK: } // end sil function '_T08closures8SuperSubC1eyyF'
   func e() {
-    // CHECK: sil shared @[[INNER_FUNC_NAME1]] : $@convention(thin)
+    // CHECK: sil private @[[INNER_FUNC_NAME1]] : $@convention(thin)
     // CHECK: bb0([[ARG:%.*]] : $SuperSub):
     // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_NAME2:_T08closures8SuperSubC1e.*]] : $@convention(thin)
     // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
@@ -577,7 +577,7 @@
     // CHECK:   destroy_value [[ARG]]
     // CHECK: } // end sil function '[[INNER_FUNC_NAME1]]'
     func e1() {
-      // CHECK: sil shared @[[INNER_FUNC_NAME2]] : $@convention(thin)
+      // CHECK: sil private @[[INNER_FUNC_NAME2]] : $@convention(thin)
       // CHECK: bb0([[ARG:%.*]] : $SuperSub):
       // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
       // CHECK:   [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
@@ -605,7 +605,7 @@
   // CHECK:   destroy_value [[PA]]
   // CHECK: } // end sil function '_T08closures8SuperSubC1fyyF'
   func f() {
-    // CHECK: sil shared @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> () {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> () {
     // CHECK: bb0([[ARG:%.*]] : $SuperSub):
     // CHECK:   [[TRY_APPLY_AUTOCLOSURE:%.*]] = function_ref @_T0s2qqoixxSg_xyKXKtKlF : $@convention(thin) <τ_0_0> (@in Optional<τ_0_0>, @owned @callee_owned () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error)
     // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:_T08closures8SuperSubC1fyyFyycfU_yyKXKfu_]] : $@convention(thin) (@owned SuperSub) -> @error Error
@@ -617,7 +617,7 @@
     // CHECK:   destroy_value [[ARG]]
     // CHECK: } // end sil function '[[INNER_FUNC_1]]'
     let f1 = {
-      // CHECK: sil shared [transparent] @[[INNER_FUNC_2]]
+      // CHECK: sil private [transparent] @[[INNER_FUNC_2]]
       // CHECK: bb0([[ARG:%.*]] : $SuperSub):
       // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
       // CHECK:   [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
@@ -639,7 +639,7 @@
   // CHECK:   = apply [[INNER]]([[SELF_COPY]])
   // CHECK: } // end sil function '_T08closures8SuperSubC1gyyF'
   func g() {
-    // CHECK: sil shared @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> ()
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@owned SuperSub) -> ()
     // CHECK: bb0([[ARG:%.*]] : $SuperSub):
     // CHECK:   [[TRY_APPLY_FUNC:%.*]] = function_ref @_T0s2qqoixxSg_xyKXKtKlF : $@convention(thin) <τ_0_0> (@in Optional<τ_0_0>, @owned @callee_owned () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error)
     // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:_T08closures8SuperSubC1g.*]] : $@convention(thin) (@owned SuperSub) -> @error Error
@@ -651,7 +651,7 @@
     // CHECK:   destroy_value [[ARG]]
     // CHECK: } // end sil function '[[INNER_FUNC_1]]'
     func g1() {
-      // CHECK: sil shared [transparent] @[[INNER_FUNC_2]] : $@convention(thin) (@owned SuperSub) -> @error Error {
+      // CHECK: sil private [transparent] @[[INNER_FUNC_2]] : $@convention(thin) (@owned SuperSub) -> @error Error {
       // CHECK: bb0([[ARG:%.*]] : $SuperSub):
       // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
       // CHECK:   [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
@@ -706,7 +706,7 @@
 
 // -- outer closure
 // -- strong +0, unowned +1
-// CHECK: sil shared @[[OUTER_CLOSURE_FUN:_T08closures24UnownedSelfNestedCaptureC06nestedE0yyFACycycfU_]] : $@convention(thin) (@owned @sil_unowned UnownedSelfNestedCapture) -> @owned @callee_owned () -> @owned UnownedSelfNestedCapture {
+// CHECK: sil private @[[OUTER_CLOSURE_FUN:_T08closures24UnownedSelfNestedCaptureC06nestedE0yyFACycycfU_]] : $@convention(thin) (@owned @sil_unowned UnownedSelfNestedCapture) -> @owned @callee_owned () -> @owned UnownedSelfNestedCapture {
 // CHECK: bb0([[CAPTURED_SELF:%.*]] : $@sil_unowned UnownedSelfNestedCapture):
 // -- strong +0, unowned +2
 // CHECK:         [[CAPTURED_SELF_COPY:%.*]] = copy_value [[CAPTURED_SELF]] :
@@ -719,7 +719,7 @@
 
 // -- inner closure
 // -- strong +0, unowned +1
-// CHECK: sil shared @[[INNER_CLOSURE_FUN:_T08closures24UnownedSelfNestedCaptureC06nestedE0yyFACycycfU_ACycfU_]] : $@convention(thin) (@owned @sil_unowned UnownedSelfNestedCapture) -> @owned UnownedSelfNestedCapture {
+// CHECK: sil private @[[INNER_CLOSURE_FUN:_T08closures24UnownedSelfNestedCaptureC06nestedE0yyFACycycfU_ACycfU_]] : $@convention(thin) (@owned @sil_unowned UnownedSelfNestedCapture) -> @owned UnownedSelfNestedCapture {
 // CHECK: bb0([[CAPTURED_SELF:%.*]] : $@sil_unowned UnownedSelfNestedCapture):
 // -- strong +1, unowned +1
 // CHECK:         strong_retain_unowned [[CAPTURED_SELF:%.*]] :
@@ -741,7 +741,7 @@
   func swim() {}
 }
 
-// CHECK-LABEL: sil shared @_T08closures14GenericDerivedC4swimyyFyycfU_ : $@convention(thin) <Ocean> (@owned GenericDerived<Ocean>) -> ()
+// CHECK-LABEL: sil private @_T08closures14GenericDerivedC4swimyyFyycfU_ : $@convention(thin) <Ocean> (@owned GenericDerived<Ocean>) -> ()
 // CHECK: bb0([[ARG:%.*]] : $GenericDerived<Ocean>):
 // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
 // CHECK:   [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
diff --git a/test/SILGen/coverage_toplevel.swift b/test/SILGen/coverage_toplevel.swift
index 0e4042b..8e7c26b 100644
--- a/test/SILGen/coverage_toplevel.swift
+++ b/test/SILGen/coverage_toplevel.swift
@@ -14,3 +14,40 @@
 while (i < 10) {
   i += 1
 }
+
+// CHECK: sil_coverage_map{{.*}}__tlcd_line:[[@LINE+3]]:1
+// CHECK-NEXT:  [[@LINE+2]]:17 -> [[@LINE+2]]:18 : 1
+// CHECK-NEXT:  [[@LINE+1]]:21 -> [[@LINE+1]]:22 : 0
+var i2 = true ? 1 : 0;
+
+// CHECK: sil_coverage_map{{.*}}__tlcd_line:[[@LINE+4]]:1
+// CHECK-NEXT:  [[@LINE+3]]:11 -> [[@LINE+5]]:2 : 1
+// CHECK-NEXT:  [[@LINE+2]]:1 -> [[@LINE+4]]:2 : 0
+// CHECK-NEXT:  [[@LINE+3]]:2 -> [[@LINE+3]]:2 : 0
+if (true) {
+  i2 = 2
+}
+
+// Crash tests:
+
+if (true) {
+  i2 = 3
+} else {
+  i2 = 4
+}
+
+while (i2 > 0) {
+  if (true) {
+    i2 -= 1
+    continue
+  } else {
+    i2 -= 1
+    break
+  }
+}
+
+switch (1) {
+  case 0: fallthrough
+  case 1: break
+  default: break
+}
diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift
index d55fc63..d045faa 100644
--- a/test/SILGen/default_arguments.swift
+++ b/test/SILGen/default_arguments.swift
@@ -58,10 +58,10 @@
                    y: @autoclosure () -> Int = #line) { }
 // CHECK-LABEL: sil hidden @_T017default_arguments17testAutocloseFileyyF
 func testAutocloseFile() {
-  // CHECK-LABEL: sil shared [transparent] @_T017default_arguments17testAutocloseFileyyFSSyXKfu_ : $@convention(thin) () -> @owned String
+  // CHECK-LABEL: sil private [transparent] @_T017default_arguments17testAutocloseFileyyFSSyXKfu_ : $@convention(thin) () -> @owned String
   // CHECK: string_literal utf16{{.*}}default_arguments.swift
 
-  // CHECK-LABEL: sil shared [transparent] @_T017default_arguments17testAutocloseFileyyFSiyXKfu0_ : $@convention(thin) () -> Int
+  // CHECK-LABEL: sil private [transparent] @_T017default_arguments17testAutocloseFileyyFSiyXKfu0_ : $@convention(thin) () -> Int
   // CHECK: integer_literal $Builtin.Int2048, [[@LINE+1]]
   autocloseFile()
 }
@@ -92,9 +92,9 @@
 // CHECK-LABEL: sil hidden @_T017default_arguments25testCallWithMagicLiteralsyyF
 // CHECK:         string_literal utf16 "testCallWithMagicLiterals()"
 // CHECK:         string_literal utf16 "testCallWithMagicLiterals()"
-// CHECK-LABEL: sil shared @_T017default_arguments25testCallWithMagicLiteralsyyFyycfU_
+// CHECK-LABEL: sil private @_T017default_arguments25testCallWithMagicLiteralsyyFyycfU_
 // CHECK:         string_literal utf16 "testCallWithMagicLiterals()"
-// CHECK-LABEL: sil shared [transparent] @_T017default_arguments25testCallWithMagicLiteralsyyFyyXKfu_
+// CHECK-LABEL: sil private [transparent] @_T017default_arguments25testCallWithMagicLiteralsyyFyyXKfu_
 // CHECK:         string_literal utf16 "testCallWithMagicLiterals()"
 func testCallWithMagicLiterals() {
   testMagicLiterals()
@@ -262,5 +262,5 @@
   }
   bar()
 }
-// CHECK-LABEL: sil shared @_T017default_arguments27localFunctionWithDefaultArgyyF3barL_ySiSgFfA_
+// CHECK-LABEL: sil private @_T017default_arguments27localFunctionWithDefaultArgyyF3barL_ySiSgFfA_
 // CHECK-SAME: $@convention(thin) () -> Optional<Int>
diff --git a/test/SILGen/dependent_member_lowering.swift b/test/SILGen/dependent_member_lowering.swift
index 7a4e1f6..63c3a92 100644
--- a/test/SILGen/dependent_member_lowering.swift
+++ b/test/SILGen/dependent_member_lowering.swift
@@ -9,13 +9,13 @@
   typealias A = T.Type
 
   func f(_ t: T.Type) {}
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T025dependent_member_lowering3FooVyxGAA1PAAlAaEP1fy1AQzFTW : $@convention(witness_method) <τ_0_0> (@in @thick τ_0_0.Type, @in_guaranteed Foo<τ_0_0>) -> ()
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T025dependent_member_lowering3FooVyxGAA1PAAlAaEP1fy1AQzFTW : $@convention(witness_method) <τ_0_0> (@in @thick τ_0_0.Type, @in_guaranteed Foo<τ_0_0>) -> ()
   // CHECK:       bb0(%0 : $*@thick τ_0_0.Type, %1 : $*Foo<τ_0_0>):
 }
 struct Bar<T>: P {
   typealias A = (Int) -> T
 
   func f(_ t: @escaping (Int) -> T) {}
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T025dependent_member_lowering3BarVyxGAA1PAAlAaEP1fy1AQzFTW : $@convention(witness_method) <τ_0_0> (@in @callee_owned (@in Int) -> @out τ_0_0, @in_guaranteed Bar<τ_0_0>) -> ()
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T025dependent_member_lowering3BarVyxGAA1PAAlAaEP1fy1AQzFTW : $@convention(witness_method) <τ_0_0> (@in @callee_owned (@in Int) -> @out τ_0_0, @in_guaranteed Bar<τ_0_0>) -> ()
   // CHECK:       bb0(%0 : $*@callee_owned (@in Int) -> @out τ_0_0, %1 : $*Bar<τ_0_0>):
 }
diff --git a/test/SILGen/dynamic.swift b/test/SILGen/dynamic.swift
index d6ebd0a..9cb0e5c 100644
--- a/test/SILGen/dynamic.swift
+++ b/test/SILGen/dynamic.swift
@@ -89,51 +89,51 @@
 // Protocol witnesses use best appropriate dispatch
 
 // Native witnesses use vtable dispatch:
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP12nativeMethod{{[_0-9a-zA-Z]*}}FTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP12nativeMethod{{[_0-9a-zA-Z]*}}FTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.nativeMethod!1 :
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP10nativePropSifgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP10nativePropSifgTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.nativeProp!getter.1 :
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP10nativePropSifsTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP10nativePropSifsTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.nativeProp!setter.1 :
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptS2i6native_tcfgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptS2i6native_tcfgTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.subscript!getter.1 :
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptS2i6native_tcfsTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptS2i6native_tcfsTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.subscript!setter.1 :
 
 // @objc witnesses use vtable dispatch:
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP10objcMethod{{[_0-9a-zA-Z]*}}FTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP10objcMethod{{[_0-9a-zA-Z]*}}FTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.objcMethod!1 :
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP8objcPropSifgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP8objcPropSifgTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.objcProp!getter.1 :
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP8objcPropSifsTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP8objcPropSifsTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.objcProp!setter.1 :
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptSis9AnyObject_p4objc_tcfgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptSis9AnyObject_p4objc_tcfgTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.subscript!getter.1 :
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptSis9AnyObject_p4objc_tcfsTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptSis9AnyObject_p4objc_tcfsTW
 // CHECK:         class_method {{%.*}} : $Foo, #Foo.subscript!setter.1 :
 
 // Dynamic witnesses use objc dispatch:
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP0A6Method{{[_0-9a-zA-Z]*}}FTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP0A6Method{{[_0-9a-zA-Z]*}}FTW
 // CHECK:         function_ref @_T07dynamic3FooC0A6Method{{[_0-9a-zA-Z]*}}FTD
 // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @_T07dynamic3FooC0A6Method{{[_0-9a-zA-Z]*}}FTD
 // CHECK:         class_method [volatile] {{%.*}} : $Foo, #Foo.dynamicMethod!1.foreign :
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP0A4PropSifgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP0A4PropSifgTW
 // CHECK:         function_ref @_T07dynamic3FooC0A4PropSifgTD
 // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @_T07dynamic3FooC0A4PropSifgTD
 // CHECK:         class_method [volatile] {{%.*}} : $Foo, #Foo.dynamicProp!getter.1.foreign :
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP0A4PropSifsTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP0A4PropSifsTW
 // CHECK:         function_ref @_T07dynamic3FooC0A4PropSifsTD
 // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @_T07dynamic3FooC0A4PropSifsTD
 // CHECK:         class_method [volatile] {{%.*}} : $Foo, #Foo.dynamicProp!setter.1.foreign :
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptS2iAA_tcfgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptS2iAA_tcfgTW
 // CHECK:         function_ref @_T07dynamic3FooC9subscriptS2iAA_tcfgTD
 // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @_T07dynamic3FooC9subscriptS2iAA_tcfgTD
 // CHECK:         class_method [volatile] {{%.*}} : $Foo, #Foo.subscript!getter.1.foreign :
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptS2iAA_tcfsTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T07dynamic3FooCAA5ProtoA2aDP9subscriptS2iAA_tcfsTW
 // CHECK:         function_ref @_T07dynamic3FooC9subscriptS2iAA_tcfsTD
 // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @_T07dynamic3FooC9subscriptS2iAA_tcfsTD
 // CHECK:         class_method [volatile] {{%.*}} : $Foo, #Foo.subscript!setter.1.foreign :
@@ -434,7 +434,7 @@
   // CHECK:     return {{%.*}} : $Bool
   // CHECK: } // end sil function '_T07dynamic3SubC1xSbfg'
 
-  // CHECK-LABEL: sil shared [transparent] @_T07dynamic3SubC1xSbfgSbyKXKfu_ : $@convention(thin) (@owned Sub) -> (Bool, @error Error) {
+  // CHECK-LABEL: sil private [transparent] @_T07dynamic3SubC1xSbfgSbyKXKfu_ : $@convention(thin) (@owned Sub) -> (Bool, @error Error) {
   // CHECK: bb0([[VALUE:%.*]] : $Sub):
   // CHECK:     [[BORROWED_VALUE:%.*]] = begin_borrow [[VALUE]]
   // CHECK:     [[VALUE_COPY:%.*]] = copy_value [[BORROWED_VALUE]]
@@ -451,7 +451,7 @@
 public class BaseExt : NSObject {}
 
 extension BaseExt {
-  public var count: Int {
+  @objc public var count: Int {
     return 0
   }
 }
diff --git a/test/SILGen/errors.swift b/test/SILGen/errors.swift
index 205bc80..c3b0a27 100644
--- a/test/SILGen/errors.swift
+++ b/test/SILGen/errors.swift
@@ -217,7 +217,7 @@
   func check() throws
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T06errors12DoomedStructVAA0B0A2aDP5checkyyKFTW : $@convention(witness_method) (@in_guaranteed DoomedStruct) -> @error Error
+// CHECK-LABEL: sil private [transparent] [thunk] @_T06errors12DoomedStructVAA0B0A2aDP5checkyyKFTW : $@convention(witness_method) (@in_guaranteed DoomedStruct) -> @error Error
 // CHECK:      [[TEMP:%.*]] = alloc_stack $DoomedStruct
 // CHECK:      copy_addr %0 to [initialization] [[TEMP]]
 // CHECK:      [[SELF:%.*]] = load [trivial] [[TEMP]] : $*DoomedStruct
@@ -235,7 +235,7 @@
   func check() throws {}
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T06errors11DoomedClassCAA0B0A2aDP5checkyyKFTW : $@convention(witness_method) (@in_guaranteed DoomedClass) -> @error Error {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T06errors11DoomedClassCAA0B0A2aDP5checkyyKFTW : $@convention(witness_method) (@in_guaranteed DoomedClass) -> @error Error {
 // CHECK:      [[TEMP:%.*]] = alloc_stack $DoomedClass
 // CHECK:      copy_addr %0 to [initialization] [[TEMP]]
 // CHECK:      [[SELF:%.*]] = load [take] [[TEMP]] : $*DoomedClass
@@ -258,7 +258,7 @@
   func check() throws {}
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T06errors11HappyStructVAA6DoomedA2aDP5checkyyKFTW : $@convention(witness_method) (@in_guaranteed HappyStruct) -> @error Error
+// CHECK-LABEL: sil private [transparent] [thunk] @_T06errors11HappyStructVAA6DoomedA2aDP5checkyyKFTW : $@convention(witness_method) (@in_guaranteed HappyStruct) -> @error Error
 // CHECK:      [[TEMP:%.*]] = alloc_stack $HappyStruct
 // CHECK:      copy_addr %0 to [initialization] [[TEMP]]
 // CHECK:      [[SELF:%.*]] = load [trivial] [[TEMP]] : $*HappyStruct
@@ -271,7 +271,7 @@
   func check() {}
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T06errors10HappyClassCAA6DoomedA2aDP5checkyyKFTW : $@convention(witness_method) (@in_guaranteed HappyClass) -> @error Error
+// CHECK-LABEL: sil private [transparent] [thunk] @_T06errors10HappyClassCAA6DoomedA2aDP5checkyyKFTW : $@convention(witness_method) (@in_guaranteed HappyClass) -> @error Error
 // CHECK:      [[TEMP:%.*]] = alloc_stack $HappyClass
 // CHECK:      copy_addr %0 to [initialization] [[TEMP]]
 // CHECK:      [[SELF:%.*]] = load [take] [[TEMP]] : $*HappyClass
diff --git a/test/SILGen/foreign_errors.swift b/test/SILGen/foreign_errors.swift
index 5dd0aed..99c526e 100644
--- a/test/SILGen/foreign_errors.swift
+++ b/test/SILGen/foreign_errors.swift
@@ -298,3 +298,14 @@
 // CHECK-NOT: destroy_value
 // CHECK:   return {{%.+}} : $()
 // CHECK: [[ERROR_BB]]
+
+// Make sure that we do not crash when emitting the error value here.
+//
+// TODO: Add some additional filecheck tests.
+extension NSURL {
+  func resourceValue<T>(forKey key: String) -> T? {
+    var prop: AnyObject? = nil
+    _ = try? self.getResourceValue(&prop, forKey: key)
+    return prop as? T
+  }
+}
diff --git a/test/SILGen/functions.swift b/test/SILGen/functions.swift
index a219eb0..784d95b 100644
--- a/test/SILGen/functions.swift
+++ b/test/SILGen/functions.swift
@@ -391,7 +391,7 @@
 // CHECK-LABEL: sil hidden [always_inline] @_T09functions19AlwaysInlinedMemberV06alwaysC0{{[_0-9a-zA-Z]*}}F : $@convention(method) (AlwaysInlinedMember) -> () {
 
 // protocol witness for functions.AlwaysInline.alwaysInlined <A : functions.AlwaysInline>(functions.AlwaysInline.Self)() -> () in conformance functions.AlwaysInlinedMember : functions.AlwaysInline in functions
-// CHECK-LABEL: sil hidden [transparent] [thunk] [always_inline] @_T09functions19AlwaysInlinedMemberVAA0B6InlineA2aDP06alwaysC0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in_guaranteed AlwaysInlinedMember) -> () {
+// CHECK-LABEL: sil private [transparent] [thunk] [always_inline] @_T09functions19AlwaysInlinedMemberVAA0B6InlineA2aDP06alwaysC0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in_guaranteed AlwaysInlinedMember) -> () {
 struct AlwaysInlinedMember : AlwaysInline {
   @inline(__always)
   func alwaysInlined() {}
@@ -442,7 +442,7 @@
 // Despite being a noescape closure, this needs to capture 'a' by-box so it can
 // be passed to the capturing closure.closure
 // CHECK: functions.(testNoescape () -> ()).(closure #1)
-// CHECK-NEXT: sil shared @_T09functions12testNoescapeyyFyycfU_ : $@convention(thin) (@owned { var Int }) -> () {
+// CHECK-NEXT: sil private @_T09functions12testNoescapeyyFyycfU_ : $@convention(thin) (@owned { var Int }) -> () {
 
 
 
@@ -462,10 +462,10 @@
 // CHECK-LABEL: sil hidden @_T09functions13testNoescape2yyF : $@convention(thin) () -> () {
 
 // CHECK: // functions.(testNoescape2 () -> ()).(closure #1)
-// CHECK-NEXT: sil shared @_T09functions13testNoescape2yyFyycfU_ : $@convention(thin) (@owned { var Int }) -> () {
+// CHECK-NEXT: sil private @_T09functions13testNoescape2yyFyycfU_ : $@convention(thin) (@owned { var Int }) -> () {
 
 // CHECK: // functions.(testNoescape2 () -> ()).(closure #1).(closure #1)
-// CHECK-NEXT: sil shared @_T09functions13testNoescape2yyFyycfU_yycfU_ : $@convention(thin) (@owned { var Int }) -> () {
+// CHECK-NEXT: sil private @_T09functions13testNoescape2yyFyycfU_yycfU_ : $@convention(thin) (@owned { var Int }) -> () {
 
 enum PartialApplyEnumPayload<T, U> {
   case Left(T)
diff --git a/test/SILGen/generic_closures.swift b/test/SILGen/generic_closures.swift
index b84b625..52066a6 100644
--- a/test/SILGen/generic_closures.swift
+++ b/test/SILGen/generic_closures.swift
@@ -122,9 +122,9 @@
 
 // CHECK: sil hidden @_T016generic_closures018nested_closure_in_A0xxlF : $@convention(thin) <T> (@in T) -> @out T
 // CHECK:   function_ref [[OUTER_CLOSURE:@_T016generic_closures018nested_closure_in_A0xxlFxycfU_]]
-// CHECK: sil shared [[OUTER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T
+// CHECK: sil private [[OUTER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T
 // CHECK:   function_ref [[INNER_CLOSURE:@_T016generic_closures018nested_closure_in_A0xxlFxycfU_xycfU_]]
-// CHECK: sil shared [[INNER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T {
+// CHECK: sil private [[INNER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T {
 func nested_closure_in_generic<T>(_ x:T) -> T {
   return { { x }() }()
 }
@@ -291,9 +291,9 @@
   outer()
 }
 
-// CHECK-LABEL: sil shared @_T016generic_closures06mixed_A19_nongeneric_nestingyx1t_tlF5outerL_yylF : $@convention(thin) <T> () -> ()
-// CHECK-LABEL: sil shared @_T016generic_closures06mixed_A19_nongeneric_nestingyx1t_tlF5outerL_yylF6middleL_yqd__1u_tr__lF : $@convention(thin) <T><U> (@in U) -> ()
-// CHECK-LABEL: sil shared @_T016generic_closures06mixed_A19_nongeneric_nestingyx1t_tlF5outerL_yylF6middleL_yqd__1u_tr__lF5innerL_qd__yr__lF : $@convention(thin) <T><U> (@owned <τ_0_0><τ_1_0> { var τ_1_0 } <T, U>) -> @out U
+// CHECK-LABEL: sil private @_T016generic_closures06mixed_A19_nongeneric_nestingyx1t_tlF5outerL_yylF : $@convention(thin) <T> () -> ()
+// CHECK-LABEL: sil private @_T016generic_closures06mixed_A19_nongeneric_nestingyx1t_tlF5outerL_yylF6middleL_yqd__1u_tr__lF : $@convention(thin) <T><U> (@in U) -> ()
+// CHECK-LABEL: sil private @_T016generic_closures06mixed_A19_nongeneric_nestingyx1t_tlF5outerL_yylF6middleL_yqd__1u_tr__lF5innerL_qd__yr__lF : $@convention(thin) <T><U> (@owned <τ_0_0><τ_1_0> { var τ_1_0 } <T, U>) -> @out U
 
 protocol Doge {
   associatedtype Nose : NoseProtocol
@@ -307,7 +307,7 @@
 
 struct DogSnacks<A : Doggo> {}
 
-func capture_same_type_representative<Daisy: Doge, Roo: Doggo>(slobber: Roo)
+func capture_same_type_representative<Daisy: Doge, Roo: Doggo>(slobber: Roo, daisy: Daisy)
     where Roo == Daisy.Nose.Squeegee {
   var s = DogSnacks<Daisy.Nose.Squeegee>()
   _ = { _ = s }
diff --git a/test/SILGen/generic_signatures.swift b/test/SILGen/generic_signatures.swift
index 2b73a87..cd385ab 100644
--- a/test/SILGen/generic_signatures.swift
+++ b/test/SILGen/generic_signatures.swift
@@ -68,16 +68,16 @@
 
 // Test that associated types can be constrained to concrete types
 
-func concreteJungle<T where T : Fooable, T.Foo == C>() -> T.Foo {
+func concreteJungle<T where T : Fooable, T.Foo == C>(_: T) -> T.Foo {
   return C()
 }
 
-func concreteJungle<T where T : Fooable, T.Foo == C>(t: T.Foo) -> C {
+func concreteJungle<T where T : Fooable, T.Foo == C>(_: T, t: T.Foo) -> C {
   let c: C = t
   return c
 }
 
-func concreteJungle<T where T : Fooable, T.Foo == C>(f: @escaping (T.Foo) -> C) -> T.Foo {
+func concreteJungle<T where T : Fooable, T.Foo == C>(_: T, f: @escaping (T.Foo) -> C) -> T.Foo {
   let ff: (C) -> T.Foo = f
   return ff(C())
 }
diff --git a/test/SILGen/generic_witness.swift b/test/SILGen/generic_witness.swift
index 80e6a7e..10fca24 100644
--- a/test/SILGen/generic_witness.swift
+++ b/test/SILGen/generic_witness.swift
@@ -50,7 +50,7 @@
 
 extension Canvas : Medium {}
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015generic_witness6CanvasVyxGAA6MediumA2A3InkRzAA3Pen5PaintRpzlAaEP4drawy6StrokeQyd__5paint_qd__6penciltAA6PencilRd__7Texture_AHQZAMRSlFTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : Ink><τ_1_0 where τ_1_0 : Pencil, τ_0_0.Paint == τ_1_0.Stroke> (@in τ_0_0.Paint, @in τ_1_0, @in_guaranteed Canvas<τ_0_0>) -> () {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015generic_witness6CanvasVyxGAA6MediumA2A3InkRzAA3Pen5PaintRpzlAaEP4drawy6StrokeQyd__5paint_qd__6penciltAA6PencilRd__7Texture_AHQZAMRSlFTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : Ink><τ_1_0 where τ_1_0 : Pencil, τ_0_0.Paint == τ_1_0.Stroke> (@in τ_0_0.Paint, @in τ_1_0, @in_guaranteed Canvas<τ_0_0>) -> () {
 // CHECK: [[FN:%.*]] = function_ref @_T015generic_witness6CanvasV4drawy5PaintQz5paint_qd__6penciltAA6PencilRd__6StrokeQyd__AFRSlF : $@convention(method) <τ_0_0 where τ_0_0 : Ink><τ_1_0 where τ_1_0 : Pencil, τ_0_0.Paint == τ_1_0.Stroke> (@in τ_0_0.Paint, @in τ_1_0, Canvas<τ_0_0>) -> ()
 // CHECK: apply [[FN]]<τ_0_0, τ_1_0>({{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : Ink><τ_1_0 where τ_1_0 : Pencil, τ_0_0.Paint == τ_1_0.Stroke> (@in τ_0_0.Paint, @in τ_1_0, Canvas<τ_0_0>) -> ()
 // CHECK: }
diff --git a/test/SILGen/guaranteed_closure_context.swift b/test/SILGen/guaranteed_closure_context.swift
index 1321abc..4a92079 100644
--- a/test/SILGen/guaranteed_closure_context.swift
+++ b/test/SILGen/guaranteed_closure_context.swift
@@ -66,4 +66,4 @@
 
 }
 
-// CHECK: sil shared [[FN_NAME]] : $@convention(thin) (@guaranteed { var S }, @guaranteed { var C }, @guaranteed { var P }, S, @guaranteed C, @guaranteed { var P })
+// CHECK: sil private [[FN_NAME]] : $@convention(thin) (@guaranteed { var S }, @guaranteed { var C }, @guaranteed { var P }, S, @guaranteed C, @guaranteed { var P })
diff --git a/test/SILGen/guaranteed_self.swift b/test/SILGen/guaranteed_self.swift
index 6aaf9d7..2b637ec 100644
--- a/test/SILGen/guaranteed_self.swift
+++ b/test/SILGen/guaranteed_self.swift
@@ -99,7 +99,7 @@
 }
 
 // Witness thunk for nonmutating 'foo'
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Int, @in_guaranteed S) -> () {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Int, @in_guaranteed S) -> () {
 // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : $*S):
 // CHECK:         [[SELF_COPY:%.*]] = alloc_stack $S
 // CHECK:         copy_addr [[SELF_ADDR]] to [initialization] [[SELF_COPY]]
@@ -110,21 +110,21 @@
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for mutating 'bar'
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP3bar{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout S) -> () {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP3bar{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout S) -> () {
 // CHECK:       bb0([[SELF_ADDR:%.*]] : $*S):
 // CHECK-NOT:     load [[SELF_ADDR]]
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for 'bas', which is mutating in the protocol, but nonmutating
 // in the implementation
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP3bas{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout S) -> ()
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP3bas{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout S) -> ()
 // CHECK:       bb0([[SELF_ADDR:%.*]] : $*S):
 // CHECK:         [[SELF:%.*]] = load [copy] [[SELF_ADDR]]
 // CHECK:         destroy_value [[SELF]]
 // CHECK-NOT:     destroy_value [[SELF]]
 
 // Witness thunk for prop1 getter
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop1SifgTW : $@convention(witness_method) (@in_guaranteed S) -> Int
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop1SifgTW : $@convention(witness_method) (@in_guaranteed S) -> Int
 // CHECK:       bb0([[SELF_ADDR:%.*]] : $*S):
 // CHECK:         [[SELF_COPY:%.*]] = alloc_stack $S
 // CHECK:         copy_addr [[SELF_ADDR]] to [initialization] [[SELF_COPY]]
@@ -135,17 +135,17 @@
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for prop1 setter
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop1SifsTW : $@convention(witness_method) (Int, @inout S) -> () {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop1SifsTW : $@convention(witness_method) (Int, @inout S) -> () {
 // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : $*S):
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for prop1 materializeForSet
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop1SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop1SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
 // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : $*S):
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for prop2 getter
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop2SifgTW : $@convention(witness_method) (@in_guaranteed S) -> Int
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop2SifgTW : $@convention(witness_method) (@in_guaranteed S) -> Int
 // CHECK:       bb0([[SELF_ADDR:%.*]] : $*S):
 // CHECK:         [[SELF_COPY:%.*]] = alloc_stack $S
 // CHECK:         copy_addr [[SELF_ADDR]] to [initialization] [[SELF_COPY]]
@@ -156,17 +156,17 @@
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for prop2 setter
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop2SifsTW : $@convention(witness_method) (Int, @inout S) -> () {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop2SifsTW : $@convention(witness_method) (Int, @inout S) -> () {
 // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : $*S):
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for prop2 materializeForSet
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop2SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop2SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
 // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : $*S):
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for prop3 getter
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifgTW : $@convention(witness_method) (@in_guaranteed S) -> Int
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifgTW : $@convention(witness_method) (@in_guaranteed S) -> Int
 // CHECK:       bb0([[SELF_ADDR:%.*]] : $*S):
 // CHECK:         [[SELF_COPY:%.*]] = alloc_stack $S
 // CHECK:         copy_addr [[SELF_ADDR]] to [initialization] [[SELF_COPY]]
@@ -177,7 +177,7 @@
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for prop3 nonmutating setter
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifsTW : $@convention(witness_method) (Int, @in_guaranteed S) -> ()
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifsTW : $@convention(witness_method) (Int, @in_guaranteed S) -> ()
 // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : $*S):
 // CHECK:         [[SELF_COPY:%.*]] = alloc_stack $S
 // CHECK:         copy_addr [[SELF_ADDR]] to [initialization] [[SELF_COPY]]
@@ -188,7 +188,7 @@
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness thunk for prop3 nonmutating materializeForSet
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
 // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : $*S):
 // CHECK:         [[SELF:%.*]] = load [copy] [[SELF_ADDR]]
 // CHECK:         destroy_value [[SELF]]
@@ -248,7 +248,7 @@
 }
 
 // Witness for nonmutating 'foo'
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self2AOVyxGAA7FooableAAlAaEP3foo{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0> (Int, @in_guaranteed AO<τ_0_0>) -> ()
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self2AOVyxGAA7FooableAAlAaEP3foo{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0> (Int, @in_guaranteed AO<τ_0_0>) -> ()
 // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : $*AO<τ_0_0>):
 // TODO: This copy isn't necessary.
 // CHECK:         copy_addr [[SELF_ADDR]] to [initialization] [[SELF_COPY:%.*]] :
@@ -257,7 +257,7 @@
 // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
 
 // Witness for 'bar', which is mutating in protocol but nonmutating in impl
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015guaranteed_self2AOVyxGAA7FooableAAlAaEP3bar{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0> (@inout AO<τ_0_0>) -> ()
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self2AOVyxGAA7FooableAAlAaEP3bar{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0> (@inout AO<τ_0_0>) -> ()
 // CHECK:       bb0([[SELF_ADDR:%.*]] : $*AO<τ_0_0>):
 // -- NB: This copy *is* necessary, unless we're willing to assume an inout
 //        parameter is not mutably aliased.
@@ -413,7 +413,7 @@
 // correctly if we are asked to.
 // ----------------------------------------------------------------------------
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T015guaranteed_self9FakeArrayVAA8SequenceA2aDP17_constrainElement{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in FakeElement, @in_guaranteed FakeArray) -> () {
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @_T015guaranteed_self9FakeArrayVAA8SequenceA2aDP17_constrainElement{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in FakeElement, @in_guaranteed FakeArray) -> () {
 // CHECK: bb0([[ARG0_PTR:%.*]] : $*FakeElement, [[ARG1_PTR:%.*]] : $*FakeArray):
 // CHECK: [[GUARANTEED_COPY_STACK_SLOT:%.*]] = alloc_stack $FakeArray
 // CHECK: copy_addr [[ARG1_PTR]] to [initialization] [[GUARANTEED_COPY_STACK_SLOT]]
diff --git a/test/SILGen/inherited_protocol_conformance_multi_file_2.swift b/test/SILGen/inherited_protocol_conformance_multi_file_2.swift
index f95b218..cd168bd 100644
--- a/test/SILGen/inherited_protocol_conformance_multi_file_2.swift
+++ b/test/SILGen/inherited_protocol_conformance_multi_file_2.swift
@@ -48,7 +48,7 @@
 // FILE_A-NOT: sil_witness_table Thing: Equatable module main
 
 // FILE_B-NOT: sil [transparent] [thunk] @_T04main5ThingVs9EquatableAAsADP2eeoi{{[_0-9a-zA-Z]*}}FZTW
-// FILE_B: sil hidden [transparent] [thunk] @_T04main5ThingVs8HashableAAsADP9hashValueSifgTW
+// FILE_B: sil private [transparent] [thunk] @_T04main5ThingVs8HashableAAsADP9hashValueSifgTW
 // FILE_B-NOT: sil [transparent] [thunk] @_T04main5ThingVs9EquatableAAsADP2eeoi{{[_0-9a-zA-Z]*}}FZTW
 
 // FILE_B-NOT: sil_witness_table hidden Thing: Equatable module main
@@ -56,7 +56,7 @@
 // FILE_B-NOT: sil_witness_table hidden Thing: Equatable module main
 
 // FILE_C-NOT: sil [transparent] [thunk] @_T04main5ThingVs8HashableAAsADP9hashValueSifgTW
-// FILE_C: sil hidden [transparent] [thunk] @_T04main5ThingVs9EquatableAAsADP2eeoi{{[_0-9a-zA-Z]*}}FZTW
+// FILE_C: sil private [transparent] [thunk] @_T04main5ThingVs9EquatableAAsADP2eeoi{{[_0-9a-zA-Z]*}}FZTW
 // FILE_C-NOT: sil [transparent] [thunk] @_T04main5ThingVs8HashableAAsADP9hashValueSifgTW
 
 // FILE_C-NOT: sil_witness_table hidden Thing: Hashable module main
diff --git a/test/SILGen/interface_type_mangling.swift b/test/SILGen/interface_type_mangling.swift
index d1b0cdb..07d70f2 100644
--- a/test/SILGen/interface_type_mangling.swift
+++ b/test/SILGen/interface_type_mangling.swift
@@ -194,14 +194,14 @@
   typealias Tee = T
 
   var a: T
-  // CHECK-LABEL: sil shared @_T023interface_type_mangling18GenericTypeContextV09closureIndF0yqd__lF3fooL_yx_qd__tr__lF
+  // CHECK-LABEL: sil private @_T023interface_type_mangling18GenericTypeContextV09closureIndF0yqd__lF3fooL_yx_qd__tr__lF
   func closureInGenericContext<U>(_ b: U) {
     func foo(_ x: T, _ y: U) { }
 
     foo(a, b)
   }
 
-  // CHECK-LABEL: sil shared @_T023interface_type_mangling18GenericTypeContextV09closureInd8PropertyF0xfg3fooL_xylF
+  // CHECK-LABEL: sil private @_T023interface_type_mangling18GenericTypeContextV09closureInd8PropertyF0xfg3fooL_xylF
   var closureInGenericPropertyContext: T {
     func foo() -> T { }
 
diff --git a/test/SILGen/let_decls.swift b/test/SILGen/let_decls.swift
index fe4f623..bf439bf 100644
--- a/test/SILGen/let_decls.swift
+++ b/test/SILGen/let_decls.swift
@@ -41,7 +41,7 @@
 
 // The closure just returns its value, which it captured directly.
 
-// CHECK: sil shared @_T09let_decls5test2yyFSiycfU_ : $@convention(thin) (Int) -> Int
+// CHECK: sil private @_T09let_decls5test2yyFSiycfU_ : $@convention(thin) (Int) -> Int
 // CHECK: bb0(%0 : $Int):
 // CHECK:  return %0 : $Int
 
diff --git a/test/SILGen/local_captures.swift b/test/SILGen/local_captures.swift
index f1bf4a1..5599a4f 100644
--- a/test/SILGen/local_captures.swift
+++ b/test/SILGen/local_captures.swift
@@ -6,16 +6,16 @@
 // CHECK-LABEL: sil hidden @_T014local_captures10globalfuncyycyF : $@convention(thin) () -> @owned @callee_owned () -> ()
 func globalfunc() -> () -> () {
 
-	// CHECK-LABEL: sil shared @_T014local_captures10globalfuncyycyF0A4FuncL_yyF : $@convention(thin) () -> ()
+	// CHECK-LABEL: sil private @_T014local_captures10globalfuncyycyF0A4FuncL_yyF : $@convention(thin) () -> ()
 	func localFunc() {
 	}
 
-	// CHECK-LABEL: sil shared @_T014local_captures10globalfuncyycyF6callitL_yyF : $@convention(thin) () -> ()
+	// CHECK-LABEL: sil private @_T014local_captures10globalfuncyycyF6callitL_yyF : $@convention(thin) () -> ()
 	func callit() {
 		localFunc()
 	}
 
-	// CHECK-LABEL: sil shared @_T014local_captures10globalfuncyycyF5getitL_yycyF : $@convention(thin) () -> @owned @callee_owned () -> ()
+	// CHECK-LABEL: sil private @_T014local_captures10globalfuncyycyF5getitL_yycyF : $@convention(thin) () -> @owned @callee_owned () -> ()
 	func getit() -> () -> () {
 		return localFunc
 	}
diff --git a/test/SILGen/local_recursion.swift b/test/SILGen/local_recursion.swift
index 756010e..3bbca89 100644
--- a/test/SILGen/local_recursion.swift
+++ b/test/SILGen/local_recursion.swift
@@ -76,25 +76,25 @@
   f(x)
 }
 
-// CHECK: sil shared [[SELF_RECURSIVE]]
+// CHECK: sil private [[SELF_RECURSIVE]]
 // CHECK: bb0([[A:%0]] : $Int, [[X:%1]] : $Int):
 // CHECK:   [[SELF_REF:%.*]] = function_ref [[SELF_RECURSIVE]]
 // CHECK:   apply [[SELF_REF]]({{.*}}, [[X]])
 
-// CHECK: sil shared [[MUTUALLY_RECURSIVE_1]]
+// CHECK: sil private [[MUTUALLY_RECURSIVE_1]]
 // CHECK: bb0([[A:%0]] : $Int, [[Y:%1]] : $Int, [[X:%2]] : $Int):
 // CHECK:   [[MUTUALLY_RECURSIVE_REF:%.*]] = function_ref [[MUTUALLY_RECURSIVE_2:@_T015local_recursionAAySi_Si1ytF20mutually_recursive_2L_ySiF]]
 // CHECK:   apply [[MUTUALLY_RECURSIVE_REF]]({{.*}}, [[X]], [[Y]])
-// CHECK: sil shared [[MUTUALLY_RECURSIVE_2]]
+// CHECK: sil private [[MUTUALLY_RECURSIVE_2]]
 // CHECK: bb0([[B:%0]] : $Int, [[X:%1]] : $Int, [[Y:%2]] : $Int):
 // CHECK:   [[MUTUALLY_RECURSIVE_REF:%.*]] = function_ref [[MUTUALLY_RECURSIVE_1]]
 // CHECK:   apply [[MUTUALLY_RECURSIVE_REF]]({{.*}}, [[Y]], [[X]])
 
 
-// CHECK: sil shared [[TRANS_CAPTURE_1:@_T015local_recursionAAySi_Si1ytF20transitive_capture_1L_S2iF]]
+// CHECK: sil private [[TRANS_CAPTURE_1:@_T015local_recursionAAySi_Si1ytF20transitive_capture_1L_S2iF]]
 // CHECK: bb0([[A:%0]] : $Int, [[X:%1]] : $Int):
 
-// CHECK: sil shared [[TRANS_CAPTURE]]
+// CHECK: sil private [[TRANS_CAPTURE]]
 // CHECK: bb0([[B:%0]] : $Int, [[X:%1]] : $Int, [[Y:%2]] : $Int):
 // CHECK:   [[TRANS_CAPTURE_1_REF:%.*]] = function_ref [[TRANS_CAPTURE_1]]
 // CHECK:   apply [[TRANS_CAPTURE_1_REF]]({{.*}}, [[X]])
diff --git a/test/SILGen/magic_identifiers_inside_property_initializers.swift b/test/SILGen/magic_identifiers_inside_property_initializers.swift
new file mode 100644
index 0000000..9ce3b5b
--- /dev/null
+++ b/test/SILGen/magic_identifiers_inside_property_initializers.swift
@@ -0,0 +1,7 @@
+// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
+
+class Test {
+    // CHECK-LABEL: sil hidden [transparent] @_T046magic_identifiers_inside_property_initializers4TestC4fileSSvfi
+    // CHECK: string_literal utf16 "{{.*}}.swift"
+    let file = #file
+}
diff --git a/test/SILGen/mangling_private.swift b/test/SILGen/mangling_private.swift
index aa78904..776d160 100644
--- a/test/SILGen/mangling_private.swift
+++ b/test/SILGen/mangling_private.swift
@@ -53,7 +53,7 @@
   private func extPrivateMethod() {}
 }
 
-// CHECK-LABEL: sil shared @_T016mangling_private10localTypesyyF11LocalStructL_V0B6MethodyyFZ
+// CHECK-LABEL: sil private @_T016mangling_private10localTypesyyF11LocalStructL_V0B6MethodyyFZ
 
 // CHECK-LABEL: sil_vtable Sub {
 class Sub : Base {
diff --git a/test/SILGen/materializeForSet.swift b/test/SILGen/materializeForSet.swift
index 65a066b..d828b45 100644
--- a/test/SILGen/materializeForSet.swift
+++ b/test/SILGen/materializeForSet.swift
@@ -66,7 +66,7 @@
 
 extension Derived : Abstractable {}
 
-// CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction6ResultQzycfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> ()
+// CHECK: sil private [transparent] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction6ResultQzycfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> ()
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
 // CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
 // CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
@@ -81,7 +81,7 @@
 // CHECK-NEXT: tuple ()
 // CHECK-NEXT: return
 
-// CHECK: sil hidden [transparent] [thunk] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction{{[_0-9a-zA-Z]*}}fmTW
+// CHECK: sil private [transparent] [thunk] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction{{[_0-9a-zA-Z]*}}fmTW
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived):
 // CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
 // CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
@@ -106,7 +106,7 @@
 // CHECK-NEXT: end_borrow [[T0]] from %2
 // CHECK-NEXT: return [[T4]]
 
-// CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction6ResultQzycfmytfU_TW :
+// CHECK: sil private [transparent] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction6ResultQzycfmytfU_TW :
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
 // CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
 // CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
@@ -121,7 +121,7 @@
 // CHECK-NEXT: tuple ()
 // CHECK-NEXT: return
 
-// CHECK: sil hidden [transparent] [thunk] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction{{[_0-9a-zA-Z]*}}fmTW
+// CHECK: sil private [transparent] [thunk] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction{{[_0-9a-zA-Z]*}}fmTW
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived):
 // CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
 // CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
@@ -141,7 +141,7 @@
 // CHECK-NEXT: end_borrow [[T0]] from %2
 // CHECK-NEXT: return [[T4]]
 
-// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycfmZytfU_TW
+// CHECK-LABEL: sil private [transparent] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycfmZytfU_TW
 // CHECK: bb0([[ARG1:%.*]] : $Builtin.RawPointer, [[ARG2:%.*]] : $*Builtin.UnsafeValueBuffer, [[ARG3:%.*]] : $*@thick Derived.Type, [[ARG4:%.*]] : $@thick Derived.Type.Type):
 // CHECK-NEXT: [[SELF:%.*]] = load [trivial] [[ARG3]] : $*@thick Derived.Type
 // CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[SELF]] : $@thick Derived.Type to $@thick Base.Type
@@ -154,7 +154,7 @@
 // CHECK-NEXT: [[RESULT:%.*]] = tuple ()
 // CHECK-NEXT: return [[RESULT]] : $()
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycfmZTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T017materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycfmZTW
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $@thick Derived.Type):
 // CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_owned () -> @out Int
 // CHECK-NEXT: [[SELF:%.*]] = upcast %2 : $@thick Derived.Type to $@thick Base.Type
@@ -337,7 +337,7 @@
 // CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
 // CHECK: }
 
-// CHECK-LABEL:  sil hidden [transparent] [thunk] @_T017materializeForSet4BillVAA8TotalledA2aDP5totalSifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Bill) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK-LABEL:  sil private [transparent] [thunk] @_T017materializeForSet4BillVAA8TotalledA2aDP5totalSifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Bill) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
 // CHECK:        bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Bill):
 // CHECK:          [[T0:%.*]] = function_ref @_T017materializeForSet4BillV5totalSifm
 // CHECK-NEXT:     [[T1:%.*]] = apply [[T0]]([[BUFFER]], [[STORAGE]], [[SELF]])
@@ -481,7 +481,7 @@
 
 struct TuxedoPanda : Panda { }
 
-// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet11TuxedoPandaVAA0E0A2aDP1xxxcfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> ()
+// CHECK-LABEL: sil private [transparent] @_T017materializeForSet11TuxedoPandaVAA0E0A2aDP1xxxcfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> ()
 
   // FIXME: Useless re-abstractions
 
@@ -493,7 +493,7 @@
 
 // CHECK: }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T017materializeForSet11TuxedoPandaVAA0E0A2aDP1xxxcfmTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T017materializeForSet11TuxedoPandaVAA0E0A2aDP1xxxcfmTW
 
 // Call the getter:
 
diff --git a/test/SILGen/multi_file.swift b/test/SILGen/multi_file.swift
index 6e62e41..804e664 100644
--- a/test/SILGen/multi_file.swift
+++ b/test/SILGen/multi_file.swift
@@ -53,4 +53,4 @@
   }
 }
 // CHECK-LABEL: sil hidden [transparent] @_T010multi_file19HasComputedPropertyC3fooSifm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasComputedProperty) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T010multi_file19HasComputedPropertyCAA012ProtocolWithE0A2aDP3fooSifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasComputedProperty) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T010multi_file19HasComputedPropertyCAA012ProtocolWithE0A2aDP3fooSifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasComputedProperty) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
diff --git a/test/SILGen/nested-function-fragility.swift b/test/SILGen/nested-function-fragility.swift
index ec6feb7..89535e1 100644
--- a/test/SILGen/nested-function-fragility.swift
+++ b/test/SILGen/nested-function-fragility.swift
@@ -3,17 +3,17 @@
 
 // CHECK-LABEL: sil @_T04main3fooyyF
 public func foo() {
-  // CHECK-LABEL: sil shared [always_inline] @_T04main3foo{{[_0-9a-zA-Z]*}}zim
+  // CHECK-LABEL: sil private [always_inline] @_T04main3foo{{[_0-9a-zA-Z]*}}zim
   @inline(__always)
   func zim() {
-    // CHECK-LABEL: sil shared @_T04main3fooyyF3zimL_yyF4zangL_yyF
+    // CHECK-LABEL: sil private @_T04main3fooyyF3zimL_yyF4zangL_yyF
     func zang() { internalFunc() }
     internalFunc()
   }
 
-  // CHECK-LABEL: sil shared @_T04main3foo{{[_0-9a-zA-Z]*}}U_
+  // CHECK-LABEL: sil private @_T04main3foo{{[_0-9a-zA-Z]*}}U_
   let zung = {
-    // CHECK-LABEL: sil shared [always_inline] @_T04main3fooyyFyycfU_7zippityL_yyF
+    // CHECK-LABEL: sil private [always_inline] @_T04main3fooyyFyycfU_7zippityL_yyF
     @inline(__always)
     func zippity() { internalFunc() }
     internalFunc()
@@ -23,17 +23,17 @@
 // CHECK-LABEL: sil hidden [always_inline] @_T04main3baryyF
 @inline(__always)
 internal func bar() {
-  // CHECK-LABEL: sil shared [always_inline] @_T04main3baryyF3zimL_yyF
+  // CHECK-LABEL: sil private [always_inline] @_T04main3baryyF3zimL_yyF
   @inline(__always)
   func zim() {
-    // CHECK-LABEL: sil shared @_T04main3baryyF3zimL_yyF4zangL_yyF
+    // CHECK-LABEL: sil private @_T04main3baryyF3zimL_yyF4zangL_yyF
     func zang() { internalFunc() }
     internalFunc()
   }
 
-  // CHECK-LABEL: sil shared @_T04main3bar{{[_0-9a-zA-Z]*}}U_
+  // CHECK-LABEL: sil private @_T04main3bar{{[_0-9a-zA-Z]*}}U_
   let zung = {
-    // CHECK-LABEL: sil shared [always_inline] @_T04main3baryyFyycfU_7zippityL_yyF
+    // CHECK-LABEL: sil private [always_inline] @_T04main3baryyFyycfU_7zippityL_yyF
     @inline(__always)
     func zippity() { internalFunc() }
     internalFunc()
diff --git a/test/SILGen/nested_generics.swift b/test/SILGen/nested_generics.swift
index 3ca84f4..8e11a12 100644
--- a/test/SILGen/nested_generics.swift
+++ b/test/SILGen/nested_generics.swift
@@ -23,8 +23,8 @@
 
 // Generic nested inside generic
 
-struct Lunch<T : Pizza where T.Topping : CuredMeat> {
-  struct Dinner<U : HotDog where U.Condiment == Deli<Pepper>.Mustard> {
+struct Lunch<T : Pizza> where T.Topping : CuredMeat {
+  struct Dinner<U : HotDog> where U.Condiment == Deli<Pepper>.Mustard {
     let firstCourse: T
     let secondCourse: U?
 
@@ -44,7 +44,7 @@
 // CHECK-LABEL: sil hidden @_T015nested_generics5LunchV6DinnerV15coolCombinationy7ToppingQz1t_AA4DeliC7MustardOyAA6PepperV_G1utF : $@convention(method) <T where T : Pizza, T.Topping : CuredMeat><U where U : HotDog, U.Condiment == Deli<Pepper>.Mustard> (@in T.Topping, Deli<Pepper>.Mustard, @in_guaranteed Lunch<T>.Dinner<U>) -> ()
 
 // CHECK-LABEL: // nested_generics.Lunch.Dinner.(coolCombination (t : A.Topping, u : nested_generics.Deli<nested_generics.Pepper>.Mustard) -> ()).(nestedGeneric #1) <A><A1><A2, B2 where A: nested_generics.Pizza, A1: nested_generics.HotDog, A.Topping: nested_generics.CuredMeat, A1.Condiment == nested_generics.Deli<nested_generics.Pepper>.Mustard> (x : A2, y : B2) -> (A2, B2)
-// CHECK-LABEL: sil shared @_T015nested_generics5LunchV6DinnerV15coolCombinationy7ToppingQz1t_AA4DeliC7MustardOyAA6PepperV_G1utF0A7GenericL_qd0___qd0_0_tqd0__1x_qd0_0_1ytAA5PizzaRzAA6HotDogRd__AA9CuredMeatAHRQAP9CondimentRtd__r__0_lF : $@convention(thin) <T where T : Pizza, T.Topping : CuredMeat><U where U : HotDog, U.Condiment == Deli<Pepper>.Mustard><X, Y> (@in X, @in Y) -> (@out X, @out Y)
+// CHECK-LABEL: sil private @_T015nested_generics5LunchV6DinnerV15coolCombinationy7ToppingQz1t_AA4DeliC7MustardOyAA6PepperV_G1utF0A7GenericL_qd0___qd0_0_tqd0__1x_qd0_0_1ytAA5PizzaRzAA6HotDogRd__AA9CuredMeatAHRQAP9CondimentRtd__r__0_lF : $@convention(thin) <T where T : Pizza, T.Topping : CuredMeat><U where U : HotDog, U.Condiment == Deli<Pepper>.Mustard><X, Y> (@in X, @in Y) -> (@out X, @out Y)
 
 // CHECK-LABEL: // nested_generics.Lunch.Dinner.init (firstCourse : A, secondCourse : Swift.Optional<A1>, leftovers : A, transformation : (A) -> A1) -> nested_generics.Lunch<A>.Dinner<A1>
 // CHECK-LABEL: sil hidden @_T015nested_generics5LunchV6DinnerVAEyx_qd__Gx11firstCourse_qd__Sg06secondF0x9leftoversqd__xc14transformationtcfC : $@convention(method) <T where T : Pizza, T.Topping : CuredMeat><U where U : HotDog, U.Condiment == Deli<Pepper>.Mustard> (@owned T, @in Optional<U>, @owned T, @owned @callee_owned (@owned T) -> @out U, @thin Lunch<T>.Dinner<U>.Type) -> @out Lunch<T>.Dinner<U>
@@ -91,11 +91,11 @@
 extension String {
   func foo() {
     // CHECK-LABEL: // (extension in nested_generics):Swift.String.(foo () -> ()).(Cheese #1).init (material : A) -> (extension in nested_generics):Swift.String.(foo () -> ()).(Cheese #1)<A>
-    // CHECK-LABEL: sil shared @_T0SS15nested_genericsE3fooyyF6CheeseL_VADyxGx8material_tcfC
+    // CHECK-LABEL: sil private @_T0SS15nested_genericsE3fooyyF6CheeseL_VADyxGx8material_tcfC
     struct Cheese<Milk> {
       let material: Milk
     }
-    let r = Cheese(material: "cow")
+    let _ = Cheese(material: "cow")
   }
 }
 
@@ -103,12 +103,12 @@
 extension HotDogs {
   func applyRelish() {
     // CHECK-LABEL: // nested_generics.HotDogs.(applyRelish () -> ()).(Relish #1).init (material : A) -> nested_generics.HotDogs.(applyRelish () -> ()).(Relish #1)<A>
-    // CHECK-LABEL: sil shared @_T015nested_generics7HotDogsC11applyRelishyyF0F0L_VAFyxGx8material_tcfC
+    // CHECK-LABEL: sil private @_T015nested_generics7HotDogsC11applyRelishyyF0F0L_VAFyxGx8material_tcfC
 
     struct Relish<Material> {
       let material: Material
     }
-    let r = Relish(material: "pickles")
+    let _ = Relish(material: "pickles")
   }
 }
 
@@ -179,7 +179,7 @@
 // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @_T015nested_generics6PizzasV7NewYorkCyAA6PepperV_GAA7HotDogsC8AmericanVIxxr_AhLIxxd_TR : $@convention(thin) (@owned Pizzas<Pepper>.NewYork, @owned @callee_owned (@owned Pizzas<Pepper>.NewYork) -> @out HotDogs.American) -> HotDogs.American
 
 // CHECK-LABEL: // nested_generics.(calls () -> ()).(closure #1)
-// CHECK-LABEL: sil shared @_T015nested_generics5callsyyFAA7HotDogsC8AmericanVAA6PizzasV7NewYorkCyAA6PepperV_GcfU_ : $@convention(thin) (@owned Pizzas<Pepper>.NewYork) -> HotDogs.American
+// CHECK-LABEL: sil private @_T015nested_generics5callsyyFAA7HotDogsC8AmericanVAA6PizzasV7NewYorkCyAA6PepperV_GcfU_ : $@convention(thin) (@owned Pizzas<Pepper>.NewYork) -> HotDogs.American
 
 func calls() {
 
@@ -225,7 +225,7 @@
 // CHECK-LABEL: // reabstraction thunk helper from @callee_owned (@owned nested_generics.Pizzas<nested_generics.Pepper>.NewYork) -> (@unowned nested_generics.HotDogs.American) to @callee_owned (@owned nested_generics.Pizzas<nested_generics.Pepper>.NewYork) -> (@out nested_generics.HotDogs.American)
 // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @_T015nested_generics6PizzasV7NewYorkCyAA6PepperV_GAA7HotDogsC8AmericanVIxxd_AhLIxxr_TR : $@convention(thin) (@owned Pizzas<Pepper>.NewYork, @owned @callee_owned (@owned Pizzas<Pepper>.NewYork) -> HotDogs.American) -> @out HotDogs.American
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T015nested_generics9OuterRingC05InnerD0Cyx_qd__GAA30ProtocolWithGenericRequirementAAr__lAaGP6method1TQz_1UQzqd__tAK1t_AM1uqd__1vtlFTW : $@convention(witness_method) <τ_0_0><τ_1_0><τ_2_0> (@in τ_0_0, @in τ_1_0, @in τ_2_0, @in_guaranteed OuterRing<τ_0_0>.InnerRing<τ_1_0>) -> (@out τ_0_0, @out τ_1_0, @out τ_2_0) {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T015nested_generics9OuterRingC05InnerD0Cyx_qd__GAA30ProtocolWithGenericRequirementAAr__lAaGP6method1TQz_1UQzqd__tAK1t_AM1uqd__1vtlFTW : $@convention(witness_method) <τ_0_0><τ_1_0><τ_2_0> (@in τ_0_0, @in τ_1_0, @in τ_2_0, @in_guaranteed OuterRing<τ_0_0>.InnerRing<τ_1_0>) -> (@out τ_0_0, @out τ_1_0, @out τ_2_0) {
 // CHECK: bb0([[T:%[0-9]+]] : $*τ_0_0, [[U:%[0-9]+]] : $*τ_1_0, [[V:%[0-9]+]] : $*τ_2_0, [[TOut:%[0-9]+]] : $*τ_0_0, [[UOut:%[0-9]+]] : $*τ_1_0, [[VOut:%[0-9]+]] : $*τ_2_0, [[SELF:%[0-9]+]] : $*OuterRing<τ_0_0>.InnerRing<τ_1_0>):
 // CHECK:   [[SELF_COPY:%[0-9]+]] = alloc_stack $OuterRing<τ_0_0>.InnerRing<τ_1_0>
 // CHECK:   copy_addr [[SELF]] to [initialization] [[SELF_COPY]] : $*OuterRing<τ_0_0>.InnerRing<τ_1_0>
diff --git a/test/SILGen/nested_types_referencing_nested_functions.swift b/test/SILGen/nested_types_referencing_nested_functions.swift
index cc13137..d4aabcb 100644
--- a/test/SILGen/nested_types_referencing_nested_functions.swift
+++ b/test/SILGen/nested_types_referencing_nested_functions.swift
@@ -5,19 +5,19 @@
   func bar<T>(_: T) { foo() }
 
   class Foo {
-    // CHECK-LABEL: sil shared @_T0025nested_types_referencing_A10_functions3FooL_CACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
+    // CHECK-LABEL: sil private @_T0025nested_types_referencing_A10_functions3FooL_CACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
     init() {
       foo()
     }
-    // CHECK-LABEL: sil shared @_T0025nested_types_referencing_A10_functions3FooL_C3zimyyF : $@convention(method) (@guaranteed Foo) -> ()
+    // CHECK-LABEL: sil private @_T0025nested_types_referencing_A10_functions3FooL_C3zimyyF : $@convention(method) (@guaranteed Foo) -> ()
     func zim() {
       foo()
     }
-    // CHECK-LABEL: sil shared @_T0025nested_types_referencing_A10_functions3FooL_C4zangyxlF : $@convention(method) <T> (@in T, @guaranteed Foo) -> ()
+    // CHECK-LABEL: sil private @_T0025nested_types_referencing_A10_functions3FooL_C4zangyxlF : $@convention(method) <T> (@in T, @guaranteed Foo) -> ()
     func zang<T>(_ x: T) {
       bar(x)
     }
-    // CHECK-LABEL: sil shared @_T0025nested_types_referencing_A10_functions3FooL_CfD : $@convention(method) (@owned Foo) -> ()
+    // CHECK-LABEL: sil private @_T0025nested_types_referencing_A10_functions3FooL_CfD : $@convention(method) (@owned Foo) -> ()
     deinit {
       foo()
     }
diff --git a/test/SILGen/objc_bridging_any.swift b/test/SILGen/objc_bridging_any.swift
index 00e8fc7..c616fd9 100644
--- a/test/SILGen/objc_bridging_any.swift
+++ b/test/SILGen/objc_bridging_any.swift
@@ -514,7 +514,7 @@
   // CHECK-LABEL: sil hidden [thunk] @_T017objc_bridging_any12SwiftIdLoverC26methodReturningOptionalAnyypSgyFTo
   // CHECK:       function_ref @_T0s27_bridgeAnythingToObjectiveC{{.*}}F
 
-  func methodTakingAny(a: Any) {}
+  @objc func methodTakingAny(a: Any) {}
   // CHECK-LABEL: sil hidden [thunk] @_T017objc_bridging_any12SwiftIdLoverC15methodTakingAnyyyp1a_tFTo : $@convention(objc_method) (AnyObject, SwiftIdLover) -> ()
   // CHECK:     bb0([[ARG:%.*]] : $AnyObject, [[SELF:%.*]] : $SwiftIdLover):
   // CHECK-NEXT:  [[ARG_COPY:%.*]] = copy_value [[ARG]]
@@ -571,7 +571,7 @@
   // CHECK-NEXT:  destroy_addr [[ANY]]
   // CHECK-NEXT:  return [[VOID]]
 
-  func methodTakingBlockTakingAny(_: (Any) -> ()) {}
+  @objc func methodTakingBlockTakingAny(_: (Any) -> ()) {}
 
   // CHECK-LABEL: sil hidden @_T017objc_bridging_any12SwiftIdLoverC29methodReturningBlockTakingAnyyypcyF : $@convention(method) (@guaranteed SwiftIdLover) -> @owned @callee_owned (@in Any) -> ()
 
@@ -609,9 +609,9 @@
   // CHECK-NEXT:  dealloc_stack [[RESULT]]
   // CHECK-NEXT:  return [[VOID]] : $()
 
-  func methodTakingBlockTakingOptionalAny(_: (Any?) -> ()) {}
+  @objc func methodTakingBlockTakingOptionalAny(_: (Any?) -> ()) {}
 
-  func methodReturningBlockTakingAny() -> ((Any) -> ()) {}
+  @objc func methodReturningBlockTakingAny() -> ((Any) -> ()) {}
 
   // CHECK-LABEL: sil hidden @_T017objc_bridging_any12SwiftIdLoverC29methodTakingBlockReturningAnyyypycF : $@convention(method) (@owned @callee_owned () -> @out Any, @guaranteed SwiftIdLover) -> () {
 
@@ -646,9 +646,9 @@
   // CHECK-NEXT:  destroy_value [[BLOCK]]
   // CHECK-NEXT:  return [[EMPTY]]
 
-  func methodReturningBlockTakingOptionalAny() -> ((Any?) -> ()) {}
+  @objc func methodReturningBlockTakingOptionalAny() -> ((Any?) -> ()) {}
 
-  func methodTakingBlockReturningAny(_: () -> Any) {}
+  @objc func methodTakingBlockReturningAny(_: () -> Any) {}
 
   // CHECK-LABEL: sil hidden @_T017objc_bridging_any12SwiftIdLoverC020methodReturningBlockH3AnyypycyF : $@convention(method) (@guaranteed SwiftIdLover) -> @owned @callee_owned () -> @out Any
 
@@ -689,23 +689,23 @@
   // CHECK-NEXT:  dealloc_stack [[RESULT]]
   // CHECK-NEXT:  return [[BRIDGED]]
 
-  func methodTakingBlockReturningOptionalAny(_: () -> Any?) {}
+  @objc func methodTakingBlockReturningOptionalAny(_: () -> Any?) {}
 
-  func methodReturningBlockReturningAny() -> (() -> Any) {}
+  @objc func methodReturningBlockReturningAny() -> (() -> Any) {}
 
-  func methodReturningBlockReturningOptionalAny() -> (() -> Any?) {}
+  @objc func methodReturningBlockReturningOptionalAny() -> (() -> Any?) {}
   // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @_T0ypSgIxr_s9AnyObject_pSgIyBa_TR
   // CHECK: function_ref @_T0s27_bridgeAnythingToObjectiveC{{.*}}F
 
   override init() { super.init() }
-  dynamic required convenience init(any: Any) { self.init() }
-  dynamic required convenience init(anyMaybe: Any?) { self.init() }
-  dynamic var anyProperty: Any
-  dynamic var maybeAnyProperty: Any?
+  @objc dynamic required convenience init(any: Any) { self.init() }
+  @objc dynamic required convenience init(anyMaybe: Any?) { self.init() }
+  @objc dynamic var anyProperty: Any
+  @objc dynamic var maybeAnyProperty: Any?
 
   subscript(_: IndexForAnySubscript) -> Any { get {} set {} }
 
-  func methodReturningAnyOrError() throws -> Any {}
+  @objc func methodReturningAnyOrError() throws -> Any {}
 }
 
 class IndexForAnySubscript {}
diff --git a/test/SILGen/objc_deprecated_objc_thunks.swift b/test/SILGen/objc_deprecated_objc_thunks.swift
new file mode 100644
index 0000000..142ed4f
--- /dev/null
+++ b/test/SILGen/objc_deprecated_objc_thunks.swift
@@ -0,0 +1,43 @@
+// RUN: %target-swift-frontend -sdk %S/Inputs %s -I %S/Inputs -enable-source-import -emit-silgen -enable-swift3-objc-inference | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+class ObjCSubclass : NSObject {
+  // CHECK-LABEL: sil hidden [thunk] @_T0016objc_deprecated_A7_thunks12ObjCSubclassCACyt7nothing_tcfcTo : $@convention(objc_method) (@owned ObjCSubclass) -> @owned ObjCSubclass {
+  // CHECK: bb0(%0 : $ObjCSubclass):
+  // CHECK-NEXT: builtin "swift3ImplicitObjCEntrypoint"() : $()
+  init(nothing: ()) { super.init() }
+  
+  // CHECK-LABEL: sil hidden [thunk] @_T0016objc_deprecated_A7_thunks12ObjCSubclassC3fooyyFTo : $@convention(objc_method) (ObjCSubclass) -> ()
+  // CHECK: bb0(%0 : $ObjCSubclass):
+  // CHECK-NEXT: builtin "swift3ImplicitObjCEntrypoint"() : $()
+  func foo() { }
+
+  // CHECK-LABEL: sil hidden [thunk] @_T0016objc_deprecated_A7_thunks12ObjCSubclassC3barSo8NSObjectCSgfgTo : $@convention(objc_method) (ObjCSubclass) -> @autoreleased Optional<NSObject>
+  // CHECK: bb0(%0 : $ObjCSubclass):
+  // CHECK-NEXT: builtin "swift3ImplicitObjCEntrypoint"() : $()
+
+  // CHECK-LABEL: sil hidden [thunk] @_T0016objc_deprecated_A7_thunks12ObjCSubclassC3barSo8NSObjectCSgfsTo : $@convention(objc_method) (Optional<NSObject>, ObjCSubclass) -> () {
+  // CHECK: %0 : $Optional<NSObject>, %1 : $ObjCSubclass
+  // CHECK-NEXT: builtin "swift3ImplicitObjCEntrypoint"() : $()
+  var bar: NSObject? = nil
+
+  // CHECK-LABEL: sil hidden [thunk] @_T0016objc_deprecated_A7_thunks12ObjCSubclassC9subscripts9AnyObject_pSicfgTo : $@convention(objc_method) (Int, ObjCSubclass) -> @autoreleased AnyObject 
+  // CHECK: bb0(%0 : $Int, %1 : $ObjCSubclass):
+  // CHECK-NEXT: builtin "swift3ImplicitObjCEntrypoint"() : $()
+
+  // CHECK-LABEL: sil hidden [thunk] @_T0016objc_deprecated_A7_thunks12ObjCSubclassC9subscripts9AnyObject_pSicfsTo : $@convention(objc_method) (AnyObject, Int, ObjCSubclass) ->
+  // CHECK: bb0(%0 : $AnyObject, %1 : $Int, %2 : $ObjCSubclass):
+  // CHECK-NEXT: builtin "swift3ImplicitObjCEntrypoint"() : $()
+  subscript (i: Int) -> AnyObject { get { return self } set { } } 
+}
+
+extension ObjCSubclass {
+	// CHECK-LABEL: sil hidden [thunk] @_T0016objc_deprecated_A7_thunks12ObjCSubclassC13falsePositiveyyFTo : $@convention(objc_method) (ObjCSubclass) -> ()
+  // CHECK: bb0(%0 : $ObjCSubclass):
+  // CHECK-NOT: builtin "swift3ImplicitObjCEntrypoint"() : $()
+	// CHECK: return
+  func falsePositive() { }
+}
diff --git a/test/SILGen/objc_imported_generic.swift b/test/SILGen/objc_imported_generic.swift
index 8356587..b068688 100644
--- a/test/SILGen/objc_imported_generic.swift
+++ b/test/SILGen/objc_imported_generic.swift
@@ -106,7 +106,7 @@
   x.propertyArrayOfThings = y
 }
 
-// CHECK-LABEL: sil shared @_T021objc_imported_generic0C4Funcyxms9AnyObjectRzlFyycfU_ : $@convention(thin) <V where V : AnyObject> () -> () {
+// CHECK-LABEL: sil private @_T021objc_imported_generic0C4Funcyxms9AnyObjectRzlFyycfU_ : $@convention(thin) <V where V : AnyObject> () -> () {
 // CHECK:  [[INIT:%.*]] = function_ref @_T0So12GenericClassCAByxGycfC : $@convention(method) <τ_0_0 where τ_0_0 : AnyObject> (@thick GenericClass<τ_0_0>.Type) -> @owned GenericClass<τ_0_0>
 // CHECK:  [[META:%.*]] = metatype $@thick GenericClass<V>.Type
 // CHECK:  apply [[INIT]]<V>([[META]])
diff --git a/test/SILGen/objc_metatypes.swift b/test/SILGen/objc_metatypes.swift
index 59763cf..278dce7 100644
--- a/test/SILGen/objc_metatypes.swift
+++ b/test/SILGen/objc_metatypes.swift
@@ -10,7 +10,7 @@
   // CHECK-LABEL: sil hidden @_T014objc_metatypes1AC3foo{{[_0-9a-zA-Z]*}}F
 
   // CHECK-LABEL: sil hidden [thunk] @_T014objc_metatypes1AC3fooAA9ObjCClassCmAFmFTo
-  dynamic func foo(_ m: ObjCClass.Type) -> ObjCClass.Type {
+  @objc dynamic func foo(_ m: ObjCClass.Type) -> ObjCClass.Type {
     // CHECK: bb0([[M:%[0-9]+]] : $@objc_metatype ObjCClass.Type, [[SELF:%[0-9]+]] : $A):
     // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $A
     // CHECK:   [[M_AS_THICK:%[0-9]+]] = objc_to_thick_metatype [[M]] : $@objc_metatype ObjCClass.Type to $@thick ObjCClass.Type
@@ -33,9 +33,9 @@
   // CHECK:   [[BAR:%[0-9]+]] = function_ref @_T014objc_metatypes1AC3bar{{[_0-9a-zA-Z]*}}FZ
   // CHECK-NEXT:   [[RESULT:%[0-9]+]] = apply [[BAR]]([[OBJC_SELF]]) : $@convention(method) (@thick A.Type) -> ()
   // CHECK-NEXT:   return [[RESULT]] : $()
-  dynamic class func bar() { }
+  @objc dynamic class func bar() { }
 
-  dynamic func takeGizmo(_ g: Gizmo.Type) { }
+  @objc dynamic func takeGizmo(_ g: Gizmo.Type) { }
 
   // CHECK-LABEL: sil hidden @_T014objc_metatypes1AC7callFoo{{[_0-9a-zA-Z]*}}F
   func callFoo() {
diff --git a/test/SILGen/objc_ownership_conventions.swift b/test/SILGen/objc_ownership_conventions.swift
index 312ec11..214040b 100644
--- a/test/SILGen/objc_ownership_conventions.swift
+++ b/test/SILGen/objc_ownership_conventions.swift
@@ -4,7 +4,7 @@
 
 import gizmo
 
-// CHECK-LABEL: sil hidden  @_T026objc_ownership_conventions5test3So8NSObjectCyF
+// CHECK-LABEL: sil hidden @_T026objc_ownership_conventions5test3So8NSObjectCyF
 func test3() -> NSObject {
   // initializer returns at +1
   return Gizmo()
@@ -29,7 +29,7 @@
 
 
 // Normal message send with argument, no transfers.
-// CHECK-LABEL: sil hidden  @_T026objc_ownership_conventions5test5{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T026objc_ownership_conventions5test5{{[_0-9a-zA-Z]*}}F
 func test5(_ g: Gizmo) {
   var g = g
   Gizmo.inspect(g)
@@ -53,7 +53,7 @@
 // CHECK: } // end sil function '_T026objc_ownership_conventions5test5{{[_0-9a-zA-Z]*}}F'
 
 // The argument to consume is __attribute__((ns_consumed)).
-// CHECK-LABEL: sil hidden  @_T026objc_ownership_conventions5test6{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T026objc_ownership_conventions5test6{{[_0-9a-zA-Z]*}}F
 func test6(_ g: Gizmo) {
   var g = g
   Gizmo.consume(g)
@@ -79,7 +79,7 @@
 // CHECK: } // end sil function '_T026objc_ownership_conventions5test6{{[_0-9a-zA-Z]*}}F'
 
 // fork is __attribute__((ns_consumes_self)).
-// CHECK-LABEL: sil hidden  @_T026objc_ownership_conventions5test7{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T026objc_ownership_conventions5test7{{[_0-9a-zA-Z]*}}F
 func test7(_ g: Gizmo) {
   var g = g
   g.fork()
@@ -102,7 +102,7 @@
 // CHECK: } // end sil function '_T026objc_ownership_conventions5test7{{[_0-9a-zA-Z]*}}F'
 
 // clone is __attribute__((ns_returns_retained)).
-// CHECK-LABEL: sil hidden  @_T026objc_ownership_conventions5test8{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T026objc_ownership_conventions5test8{{[_0-9a-zA-Z]*}}F
 func test8(_ g: Gizmo) -> Gizmo {
   return g.clone()
   // CHECK: bb0([[G:%.*]] : $Gizmo):
@@ -117,7 +117,7 @@
   // CHECK-NEXT: return [[RESULT]]
 }
 // duplicate returns an autoreleased object at +0.
-// CHECK-LABEL: sil hidden  @_T026objc_ownership_conventions5test9{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T026objc_ownership_conventions5test9{{[_0-9a-zA-Z]*}}F
 func test9(_ g: Gizmo) -> Gizmo {
   return g.duplicate()
   // CHECK: bb0([[G:%.*]] : $Gizmo):
diff --git a/test/SILGen/objc_properties.swift b/test/SILGen/objc_properties.swift
index 54787ad..e9643b9 100644
--- a/test/SILGen/objc_properties.swift
+++ b/test/SILGen/objc_properties.swift
@@ -5,8 +5,8 @@
 import Foundation
 
 class A {
-  dynamic var prop: Int
-  dynamic var computedProp: Int {
+  @objc dynamic var prop: Int
+  @objc dynamic var computedProp: Int {
     get {
       return 5
     }
@@ -179,7 +179,7 @@
   // CHECK-NEXT: destroy_value [[SELF_COPY]] : $HasUnmanaged
   // CHECK-NEXT: return [[RESULT:%.*]]
   // CHECK: } // end sil function '_T015objc_properties12HasUnmanagedC3refs0D0Vys9AnyObject_pGSgfsTo'
-  var ref: Unmanaged<AnyObject>?
+  @objc var ref: Unmanaged<AnyObject>?
 }
 
 @_silgen_name("autoreleasing_user")
diff --git a/test/SILGen/objc_protocols.swift b/test/SILGen/objc_protocols.swift
index d5e3f5d..ca542ad 100644
--- a/test/SILGen/objc_protocols.swift
+++ b/test/SILGen/objc_protocols.swift
@@ -24,7 +24,7 @@
   func anse()
 }
 
-// CHECK-LABEL: sil hidden  @_T014objc_protocols0A8_generic{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T014objc_protocols0A8_generic{{[_0-9a-zA-Z]*}}F
 // CHECK: bb0([[THIS:%.*]] : $T):
 // -- Result of runce is autoreleased according to default objc conv
 // CHECK: [[METHOD:%.*]] = witness_method [volatile] {{\$.*}},  #NSRuncing.runce!1.foreign
diff --git a/test/SILGen/objc_super.swift b/test/SILGen/objc_super.swift
index 6ef75c3..f31b5e5 100644
--- a/test/SILGen/objc_super.swift
+++ b/test/SILGen/objc_super.swift
@@ -8,19 +8,19 @@
 // a super_method instruction.
 class Hoozit : Gizmo {
 
-  // CHECK-LABEL: sil hidden  @_T010objc_super6HoozitC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned Hoozit) -> @owned Hoozit
+  // CHECK-LABEL: sil hidden @_T010objc_super6HoozitC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned Hoozit) -> @owned Hoozit
   override init() {
     // CHECK: super_method [volatile] {{%.*}} : $Hoozit, #Gizmo.init!initializer.1.foreign
     super.init()
   }
 
-  // CHECK-LABEL: sil hidden  @_T010objc_super6HoozitC5runce{{[_0-9a-zA-Z]*}}FZ : $@convention(method) (@thick Hoozit.Type) -> ()
+  // CHECK-LABEL: sil hidden @_T010objc_super6HoozitC5runce{{[_0-9a-zA-Z]*}}FZ : $@convention(method) (@thick Hoozit.Type) -> ()
   override class func runce() {
     // CHECK: super_method [volatile] {{%.*}} : $@thick Hoozit.Type, #Gizmo.runce!1.foreign
     super.runce()
   }
 
-  // CHECK-LABEL: sil hidden  @_T010objc_super6HoozitC4frob{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed Hoozit) -> ()
+  // CHECK-LABEL: sil hidden @_T010objc_super6HoozitC4frob{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed Hoozit) -> ()
   override func frob() {
     // CHECK: super_method [volatile] {{%.*}} : $Hoozit, #Gizmo.frob!1.foreign
     super.frob()
diff --git a/test/SILGen/objc_thunks.swift b/test/SILGen/objc_thunks.swift
index de60104..5856248 100644
--- a/test/SILGen/objc_thunks.swift
+++ b/test/SILGen/objc_thunks.swift
@@ -6,7 +6,7 @@
 import ansible
 
 class Hoozit : Gizmo {
-  func typical(_ x: Int, y: Gizmo) -> Gizmo { return y }
+  @objc func typical(_ x: Int, y: Gizmo) -> Gizmo { return y }
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC7typicalSo5GizmoCSi_AF1ytFTo : $@convention(objc_method) (Int, Gizmo, Hoozit) -> @autoreleased Gizmo {
   // CHECK: bb0([[X:%.*]] : $Int, [[Y:%.*]] : $Gizmo, [[THIS:%.*]] : $Hoozit):
   // CHECK-NEXT:   [[Y_COPY:%.*]] = copy_value [[Y]]
@@ -14,10 +14,10 @@
   // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
   // CHECK-NEXT:   // function_ref objc_thunks.Hoozit.typical
   // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @_T011objc_thunks6HoozitC7typicalSo5GizmoCSi_AF1ytF : $@convention(method) (Int, @owned Gizmo, @guaranteed Hoozit) -> @owned Gizmo
-  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[X]], [[Y_COPY]], [[BORROWED_THIS_COPY]]) {{.*}} line:[[@LINE-8]]:8:auto_gen
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[X]], [[Y_COPY]], [[BORROWED_THIS_COPY]]) {{.*}} line:[[@LINE-8]]:14:auto_gen
   // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
   // CHECK-NEXT:   destroy_value [[THIS_COPY]] : $Hoozit
-  // CHECK-NEXT:   return [[RES]] : $Gizmo{{.*}} line:[[@LINE-11]]:8:auto_gen
+  // CHECK-NEXT:   return [[RES]] : $Gizmo{{.*}} line:[[@LINE-11]]:14:auto_gen
   // CHECK-NEXT: } // end sil function '_T011objc_thunks6HoozitC7typicalSo5GizmoCSi_AF1ytFTo'
 
   // NS_CONSUMES_SELF by inheritance
@@ -44,7 +44,7 @@
   // CHECK-NEXT: }
 
   // NS_RETURNS_RETAINED by family (-copy)
-  func copyFoo() -> Gizmo { return self }
+  @objc func copyFoo() -> Gizmo { return self }
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC7copyFooSo5GizmoCyFTo : $@convention(objc_method) (Hoozit) -> @owned Gizmo
   // CHECK: bb0([[THIS:%.*]] : $Hoozit):
   // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
@@ -59,7 +59,7 @@
 
   // Override the normal family conventions to make this non-consuming and
   // returning at +0.
-  func initFoo() -> Gizmo { return self }
+  @objc func initFoo() -> Gizmo { return self }
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC7initFooSo5GizmoCyFTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo
   // CHECK: bb0([[THIS:%.*]] : $Hoozit):
   // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
@@ -72,7 +72,7 @@
   // CHECK-NEXT:   return [[RES]]
   // CHECK-NEXT: }
 
-  var typicalProperty: Gizmo
+  @objc var typicalProperty: Gizmo
   // -- getter
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC15typicalPropertySo5GizmoCfgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo {
   // CHECK: bb0([[SELF:%.*]] : $Hoozit):
@@ -104,7 +104,7 @@
   // CHECK:   [[RES:%.*]] = apply [[FR]]([[VALUE_COPY]], [[BORROWED_THIS_COPY]])
   // CHECK:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
   // CHECK:   destroy_value [[THIS_COPY]]
-  // CHECK:   return [[RES]] : $(), scope {{.*}} // id: {{.*}} line:[[@LINE-32]]:7:auto_gen
+  // CHECK:   return [[RES]] : $(), scope {{.*}} // id: {{.*}} line:[[@LINE-32]]:13:auto_gen
   // CHECK: } // end sil function '_T011objc_thunks6HoozitC15typicalPropertySo5GizmoCfsTo'
 
   // CHECK-LABEL: sil hidden @_T011objc_thunks6HoozitC15typicalPropertySo5GizmoCfs
@@ -118,7 +118,7 @@
   // CHECK: } // end sil function '_T011objc_thunks6HoozitC15typicalPropertySo5GizmoCfs'
 
   // NS_RETURNS_RETAINED getter by family (-copy)
-  var copyProperty: Gizmo
+  @objc var copyProperty: Gizmo
   // -- getter
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC12copyPropertySo5GizmoCfgTo : $@convention(objc_method) (Hoozit) -> @owned Gizmo {
   // CHECK: bb0([[SELF:%.*]] : $Hoozit):
@@ -161,7 +161,7 @@
   // CHECK:   destroy_value [[ARG1]]
   // CHECK: } // end sil function '_T011objc_thunks6HoozitC12copyPropertySo5GizmoCfs'
 
-  var roProperty: Gizmo { return self }
+  @objc var roProperty: Gizmo { return self }
   // -- getter
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC10roPropertySo5GizmoCfgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo {
   // CHECK: bb0([[THIS:%.*]] : $Hoozit):
@@ -178,7 +178,7 @@
   // -- no setter
   // CHECK-NOT: sil hidden [thunk] @_T011objc_thunks6HoozitC10roPropertySo5GizmoCfsTo
 
-  var rwProperty: Gizmo {
+  @objc var rwProperty: Gizmo {
     get {
       return self
     }
@@ -201,7 +201,7 @@
   // CHECK-NEXT:   return
   // CHECK-NEXT: }
 
-  var copyRWProperty: Gizmo {
+  @objc var copyRWProperty: Gizmo {
     get {
       return self
     }
@@ -235,7 +235,7 @@
   // CHECK-NEXT:   return
   // CHECK-NEXT: }
 
-  var initProperty: Gizmo
+  @objc var initProperty: Gizmo
   // -- getter
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC12initPropertySo5GizmoCfgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo {
   // CHECK: bb0([[THIS:%.*]] : $Hoozit):
@@ -263,7 +263,7 @@
   // CHECK-NEXT:   return
   // CHECK-NEXT: }
 
-  var propComputed: Gizmo {
+  @objc var propComputed: Gizmo {
     @objc(initPropComputedGetter) get { return self }
     @objc(initPropComputedSetter:) set {}
   }
@@ -315,7 +315,7 @@
   }
 
   // Subscript
-  subscript (i: Int) -> Hoozit {
+  @objc subscript (i: Int) -> Hoozit {
   // Getter
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC9subscriptACSicfgTo : $@convention(objc_method) (Int, Hoozit) -> @autoreleased Hoozit
   // CHECK: bb0([[I:%[0-9]+]] : $Int, [[SELF:%[0-9]+]] : $Hoozit):
@@ -359,7 +359,7 @@
   // CHECK-NEXT: destroy_value [[SELF_COPY]] : $Wotsit<T>
   // CHECK-NEXT: return [[RESULT]] : $()
   // CHECK-NEXT: }
-  func plain() { }
+  @objc func plain() { }
 
   func generic<U>(_ x: U) {}
 
@@ -404,7 +404,7 @@
 // Extension initializers, properties and methods need thunks too.
 extension Hoozit {
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitCACSi3int_tcfcTo : $@convention(objc_method) (Int, @owned Hoozit) -> @owned Hoozit
-  dynamic convenience init(int i: Int) { self.init(bellsOn: i) }
+  @objc dynamic convenience init(int i: Int) { self.init(bellsOn: i) }
 
   // CHECK-LABEL: sil hidden @_T011objc_thunks6HoozitCACSd6double_tcfc : $@convention(method) (Double, @owned Hoozit) -> @owned Hoozit
   convenience init(double d: Double) { 
@@ -439,7 +439,7 @@
   // CHECK-LABEL: sil hidden [thunk] @_T011objc_thunks6HoozitC4foofyyFTo : $@convention(objc_method) (Hoozit) -> () {
 
   var extensionProperty: Int { return 0 }
-  // CHECK-LABEL: sil hidden  @_T011objc_thunks6HoozitC17extensionPropertySifg : $@convention(method) (@guaranteed Hoozit) -> Int
+  // CHECK-LABEL: sil hidden @_T011objc_thunks6HoozitC17extensionPropertySifg : $@convention(method) (@guaranteed Hoozit) -> Int
 }
 
 // Calling objc methods of subclass should go through native entry points
diff --git a/test/SILGen/objc_witnesses.swift b/test/SILGen/objc_witnesses.swift
index 6cf31a5..68261db 100644
--- a/test/SILGen/objc_witnesses.swift
+++ b/test/SILGen/objc_witnesses.swift
@@ -19,7 +19,7 @@
 }
 
 // witness for Foo.foo uses the foreign-to-native thunk:
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T0So3FooC14objc_witnesses7FooableA2cDP3foo{{[_0-9a-zA-Z]*}}FTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T0So3FooC14objc_witnesses7FooableA2cDP3foo{{[_0-9a-zA-Z]*}}FTW
 // CHECK:         function_ref @_T0So3FooC3foo{{[_0-9a-zA-Z]*}}FTO
 
 // *NOTE* We have an extra copy here for the time being right
@@ -46,7 +46,7 @@
 extension Gizmo : Bells {
 }
 
-// CHECK: sil hidden [transparent] [thunk] @_T0So5GizmoC14objc_witnesses5BellsA2cDP{{[_0-9a-zA-Z]*}}fCTW
+// CHECK: sil private [transparent] [thunk] @_T0So5GizmoC14objc_witnesses5BellsA2cDP{{[_0-9a-zA-Z]*}}fCTW
 // CHECK: bb0([[SELF:%[0-9]+]] : $*Gizmo, [[I:%[0-9]+]] : $Int, [[META:%[0-9]+]] : $@thick Gizmo.Type):
 
 // CHECK:   [[INIT:%[0-9]+]] = function_ref @_T0So5GizmoC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Int, @thick Gizmo.Type) -> @owned Optional<Gizmo>
@@ -62,7 +62,7 @@
   subscript(x: Int) -> Any { get }
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T0So7NSArrayC14objc_witnesses13SubscriptableA2cDP9subscriptypSicfgTW : $@convention(witness_method) (Int, @in_guaranteed NSArray) -> @out Any {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T0So7NSArrayC14objc_witnesses13SubscriptableA2cDP9subscriptypSicfgTW : $@convention(witness_method) (Int, @in_guaranteed NSArray) -> @out Any {
 // CHECK:         function_ref @_T0So7NSArrayC9subscriptypSicfgTO : $@convention(method) (Int, @guaranteed NSArray) -> @out Any
 // CHECK-LABEL: sil shared [serializable] [thunk] @_T0So7NSArrayC9subscriptypSicfgTO : $@convention(method) (Int, @guaranteed NSArray) -> @out Any {
 // CHECK:         class_method [volatile] {{%.*}} : $NSArray, #NSArray.subscript!getter.1.foreign
@@ -78,10 +78,10 @@
   dynamic var quantumNumber: Int = 0
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T014objc_witnesses8ElectronCAA7OrbitalA2aDP13quantumNumberSifgTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T014objc_witnesses8ElectronCAA7OrbitalA2aDP13quantumNumberSifgTW
 // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @_T014objc_witnesses8ElectronC13quantumNumberSifgTD
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T014objc_witnesses8ElectronCAA7OrbitalA2aDP13quantumNumberSifsTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T014objc_witnesses8ElectronCAA7OrbitalA2aDP13quantumNumberSifsTW
 // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @_T014objc_witnesses8ElectronC13quantumNumberSifsTD
 
 // witness is a dynamic thunk and is public:
@@ -94,5 +94,29 @@
   public dynamic var spin: Float = 0.5
 }
 
-// CHECK-LABEL: sil [transparent] [serialized] [thunk] @_T014objc_witnesses8PositronCAA6LeptonA2aDP4spinSffgTW
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @_T014objc_witnesses8PositronCAA6LeptonA2aDP4spinSffgTW
 // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @_T014objc_witnesses8PositronC4spinSffgTD
+
+// Override of property defined in @objc extension
+
+class Derived : NSObject {
+  override var valence: Int {
+    get { return 2 } set { }
+  }
+}
+
+extension NSObject : Atom {
+  var valence: Int { get { return 1 } set { } }
+}
+
+// CHECK-LABEL: sil hidden @_T0So8NSObjectC14objc_witnessesE7valenceSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout NSObject, @thick NSObject.Type) -> () {
+// CHECK: class_method [volatile] %4 : $NSObject, #NSObject.valence!setter.1.foreign
+// CHECK: }
+
+// CHECK-LABEL: sil hidden @_T0So8NSObjectC14objc_witnessesE7valenceSifm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed NSObject) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: class_method [volatile] %2 : $NSObject, #NSObject.valence!getter.1.foreign
+// CHECK: }
+
+protocol Atom : class {
+  var valence: Int { get set }
+}
diff --git a/test/SILGen/opaque_values_silgen.swift b/test/SILGen/opaque_values_silgen.swift
index efa80f3..0a4df44 100644
--- a/test/SILGen/opaque_values_silgen.swift
+++ b/test/SILGen/opaque_values_silgen.swift
@@ -311,7 +311,7 @@
 
 // Test a guaranteed opaque parameter.
 // ---
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T020opaque_values_silgen21s110___GuaranteedSelfVAA3FooA2aDP3fooyyFTW : $@convention(witness_method) (@in_guaranteed s110___GuaranteedSelf) -> () {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T020opaque_values_silgen21s110___GuaranteedSelfVAA3FooA2aDP3fooyyFTW : $@convention(witness_method) (@in_guaranteed s110___GuaranteedSelf) -> () {
 // CHECK: bb0(%0 : $s110___GuaranteedSelf):
 // CHECK:   %[[F:.*]] = function_ref @_T020opaque_values_silgen21s110___GuaranteedSelfV3fooyyF : $@convention(method) (s110___GuaranteedSelf) -> ()
 // CHECK:   apply %[[F]](%0) : $@convention(method) (s110___GuaranteedSelf) -> ()
@@ -687,7 +687,7 @@
 
 // Tests support for address only let closures under opaque value mode - they are not by-address anymore
 // ---
-// CHECK-LABEL: sil shared @_T020opaque_values_silgen21s330___addrLetClosurexxlFxycfU_xycfU_ : $@convention(thin) <T> (@in T) -> @out T {
+// CHECK-LABEL: sil private @_T020opaque_values_silgen21s330___addrLetClosurexxlFxycfU_xycfU_ : $@convention(thin) <T> (@in T) -> @out T {
 // CHECK: bb0([[ARG:%.*]] : $T):
 // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]] : $T
 // CHECK:   [[COPY_ARG:%.*]] = copy_value [[BORROWED_ARG]] : $T
diff --git a/test/SILGen/properties.swift b/test/SILGen/properties.swift
index 8d2f5c5..70d2a73 100644
--- a/test/SILGen/properties.swift
+++ b/test/SILGen/properties.swift
@@ -6,7 +6,7 @@
 func use(_: Double) {}
 func getInt() -> Int { return zero }
 
-// CHECK-LABEL: sil hidden  @{{.*}}physical_tuple_lvalue
+// CHECK-LABEL: sil hidden @{{.*}}physical_tuple_lvalue
 // CHECK: bb0(%0 : $Int):
 func physical_tuple_lvalue(_ c: Int) {
   var x : (Int, Int)
@@ -20,7 +20,7 @@
 
 func tuple_rvalue() -> (Int, Int) {}
 
-// CHECK-LABEL: sil hidden  @{{.*}}physical_tuple_rvalue
+// CHECK-LABEL: sil hidden @{{.*}}physical_tuple_rvalue
 func physical_tuple_rvalue() -> Int {
   return tuple_rvalue().1
   // CHECK: [[FUNC:%[0-9]+]] = function_ref @_T010properties12tuple_rvalue{{[_0-9a-zA-Z]*}}F
@@ -29,7 +29,7 @@
   // CHECK: return [[RET]]
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties16tuple_assignment{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties16tuple_assignment{{[_0-9a-zA-Z]*}}F
 func tuple_assignment(_ a: inout Int, b: inout Int) {
   // CHECK: bb0([[A_ADDR:%[0-9]+]] : $*Int, [[B_ADDR:%[0-9]+]] : $*Int):
   // CHECK: [[B:%[0-9]+]] = load [trivial] [[B_ADDR]]
@@ -39,7 +39,7 @@
   (a, b) = (b, a)
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties18tuple_assignment_2{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties18tuple_assignment_2{{[_0-9a-zA-Z]*}}F
 func tuple_assignment_2(_ a: inout Int, b: inout Int, xy: (Int, Int)) {
   // CHECK: bb0([[A_ADDR:%[0-9]+]] : $*Int, [[B_ADDR:%[0-9]+]] : $*Int, [[X:%[0-9]+]] : $Int, [[Y:%[0-9]+]] : $Int):
   (a, b) = xy
@@ -87,7 +87,7 @@
   subscript(i: Int) -> Float { get {} set {} }
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties22physical_struct_lvalue{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties22physical_struct_lvalue{{[_0-9a-zA-Z]*}}F
 func physical_struct_lvalue(_ c: Int) {
   var v : Val
   // CHECK: [[VADDR:%[0-9]+]] = alloc_box ${ var Val }
@@ -95,7 +95,7 @@
   // CHECK: assign %0 to [[X_1]]
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties21physical_class_lvalue{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@owned Ref, Int) -> ()
+// CHECK-LABEL: sil hidden @_T010properties21physical_class_lvalue{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@owned Ref, Int) -> ()
 // CHECK: bb0([[ARG0:%.*]] : $Ref,
  func physical_class_lvalue(_ r: Ref, a: Int) {
     r.y = a
@@ -107,7 +107,7 @@
   }
 
 
-// CHECK-LABEL: sil hidden  @_T010properties24physical_subclass_lvalue{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties24physical_subclass_lvalue{{[_0-9a-zA-Z]*}}F
 func physical_subclass_lvalue(_ r: RefSubclass, a: Int) {
   // CHECK: bb0([[ARG1:%.*]] : $RefSubclass, [[ARG2:%.*]] : $Int):
   r.y = a
@@ -131,7 +131,7 @@
 
 func struct_rvalue() -> Val {}
 
-// CHECK-LABEL: sil hidden  @_T010properties22physical_struct_rvalue{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties22physical_struct_rvalue{{[_0-9a-zA-Z]*}}F
 func physical_struct_rvalue() -> Int {
   return struct_rvalue().y
   // CHECK: [[FUNC:%[0-9]+]] = function_ref @_T010properties13struct_rvalueAA3ValVyF
@@ -145,7 +145,7 @@
 
 func class_rvalue() -> Ref {}
 
-// CHECK-LABEL: sil hidden  @_T010properties21physical_class_rvalue{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties21physical_class_rvalue{{[_0-9a-zA-Z]*}}F
 func physical_class_rvalue() -> Int {
   return class_rvalue().y
   // CHECK: [[FUNC:%[0-9]+]] = function_ref @_T010properties12class_rvalueAA3RefCyF
@@ -156,7 +156,7 @@
   // CHECK: return [[RET]]
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties18logical_struct_get{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties18logical_struct_get{{[_0-9a-zA-Z]*}}F
 func logical_struct_get() -> Int {
   return struct_rvalue().z
   // CHECK: [[GET_RVAL:%[0-9]+]] = function_ref @_T010properties13struct_rvalue{{[_0-9a-zA-Z]*}}F
@@ -166,7 +166,7 @@
   // CHECK: return [[VALUE]]
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties18logical_struct_set{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties18logical_struct_set{{[_0-9a-zA-Z]*}}F
 func logical_struct_set(_ value: inout Val, z: Int) {
   // CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z:%[0-9]+]] : $Int):
   value.z = z
@@ -175,7 +175,7 @@
   // CHECK: return
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties27logical_struct_in_tuple_set{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties27logical_struct_in_tuple_set{{[_0-9a-zA-Z]*}}F
 func logical_struct_in_tuple_set(_ value: inout (Int, Val), z: Int) {
   // CHECK: bb0([[VAL:%[0-9]+]] : $*(Int, Val), [[Z:%[0-9]+]] : $Int):
   value.1.z = z
@@ -185,7 +185,7 @@
   // CHECK: return
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties29logical_struct_in_reftype_set{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties29logical_struct_in_reftype_set{{[_0-9a-zA-Z]*}}F
 func logical_struct_in_reftype_set(_ value: inout Val, z1: Int) {
   // CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z1:%[0-9]+]] : $Int):
   value.ref.val_prop.z_tuple.1 = z1
@@ -243,12 +243,12 @@
 
 func reftype_rvalue() -> Ref {}
 
-// CHECK-LABEL: sil hidden  @_T010properties18reftype_rvalue_set{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties18reftype_rvalue_set{{[_0-9a-zA-Z]*}}F
 func reftype_rvalue_set(_ value: Val) {
   reftype_rvalue().val_prop = value
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties27tuple_in_logical_struct_set{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties27tuple_in_logical_struct_set{{[_0-9a-zA-Z]*}}F
 func tuple_in_logical_struct_set(_ value: inout Val, z1: Int) {
   // CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z1:%[0-9]+]] : $Int):
   value.z_tuple.1 = z1
@@ -273,17 +273,17 @@
 }
 
 var global_prop : Int {
-  // CHECK-LABEL: sil hidden  @_T010properties11global_prop{{[_0-9a-zA-Z]*}}fg
+  // CHECK-LABEL: sil hidden @_T010properties11global_prop{{[_0-9a-zA-Z]*}}fg
   get {
     return zero
   }
-  // CHECK-LABEL: sil hidden  @_T010properties11global_prop{{[_0-9a-zA-Z]*}}fs
+  // CHECK-LABEL: sil hidden @_T010properties11global_prop{{[_0-9a-zA-Z]*}}fs
   set {
     use(newValue)
   }
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties18logical_global_get{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties18logical_global_get{{[_0-9a-zA-Z]*}}F
 func logical_global_get() -> Int {
   return global_prop
   // CHECK: [[GET:%[0-9]+]] = function_ref @_T010properties11global_prop{{[_0-9a-zA-Z]*}}fg
@@ -291,14 +291,14 @@
   // CHECK: return [[VALUE]]
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties18logical_global_set{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties18logical_global_set{{[_0-9a-zA-Z]*}}F
 func logical_global_set(_ x: Int) {
   global_prop = x
   // CHECK: [[SET:%[0-9]+]] = function_ref @_T010properties11global_prop{{[_0-9a-zA-Z]*}}fs
   // CHECK: apply [[SET]](%0)
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties17logical_local_get{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties17logical_local_get{{[_0-9a-zA-Z]*}}F
 func logical_local_get(_ x: Int) -> Int {
   var prop : Int {
     get {
@@ -309,10 +309,10 @@
   // CHECK: apply [[GET_REF]](%0)
   return prop
 }
-// CHECK-: sil shared [[PROP_GET_CLOSURE]]
+// CHECK-: sil private [[PROP_GET_CLOSURE]]
 // CHECK: bb0(%{{[0-9]+}} : $Int):
 
-// CHECK-LABEL: sil hidden  @_T010properties26logical_local_captured_get{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties26logical_local_captured_get{{[_0-9a-zA-Z]*}}F
 func logical_local_captured_get(_ x: Int) -> Int {
   var prop : Int {
     get {
@@ -327,12 +327,12 @@
   // CHECK: [[FUNC_REF:%[0-9]+]] = function_ref @_T010properties26logical_local_captured_getS2iF0E5_propL_SiyF
   // CHECK: apply [[FUNC_REF]](%0)
 }
-// CHECK: sil shared @_T010properties26logical_local_captured_get{{.*}}fg
+// CHECK: sil private @_T010properties26logical_local_captured_get{{.*}}fg
 // CHECK: bb0(%{{[0-9]+}} : $Int):
 
 func inout_arg(_ x: inout Int) {}
 
-// CHECK-LABEL: sil hidden  @_T010properties14physical_inout{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties14physical_inout{{[_0-9a-zA-Z]*}}F
 func physical_inout(_ x: Int) {
   var x = x
   // CHECK: [[XADDR:%[0-9]+]] = alloc_box ${ var Int }
@@ -346,7 +346,7 @@
 /* TODO check writeback to more complex logical prop, check that writeback
  * reuses temporaries */
 
-// CHECK-LABEL: sil hidden  @_T010properties17val_subscript_get{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@owned Val, Int) -> Float
+// CHECK-LABEL: sil hidden @_T010properties17val_subscript_get{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@owned Val, Int) -> Float
 // CHECK: bb0([[VVAL:%[0-9]+]] : $Val, [[I:%[0-9]+]] : $Int):
 func val_subscript_get(_ v: Val, i: Int) -> Float {
   return v[i]
@@ -358,7 +358,7 @@
   // CHECK: return [[RET]]
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties17val_subscript_set{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties17val_subscript_set{{[_0-9a-zA-Z]*}}F
 // CHECK: bb0(%0 : $Val, [[I:%[0-9]+]] : $Int, [[X:%[0-9]+]] : $Float):
 func val_subscript_set(_ v: Val, i: Int, x: Float) {
   var v = v
@@ -378,27 +378,27 @@
 
   subscript(x: T) -> T { get {} set {} }
 
-  // CHECK-LABEL: sil hidden  @_T010properties7GenericV19copy_typevar_member{{[_0-9a-zA-Z]*}}F
+  // CHECK-LABEL: sil hidden @_T010properties7GenericV19copy_typevar_member{{[_0-9a-zA-Z]*}}F
   mutating
   func copy_typevar_member(_ x: Generic<T>) {
     typevar_member = x.typevar_member
   }
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties21generic_mono_phys_get{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties21generic_mono_phys_get{{[_0-9a-zA-Z]*}}F
 func generic_mono_phys_get<T>(_ g: Generic<T>) -> Int {
   return g.mono_phys
   // CHECK: struct_element_addr %{{.*}}, #Generic.mono_phys
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties20generic_mono_log_get{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties20generic_mono_log_get{{[_0-9a-zA-Z]*}}F
 func generic_mono_log_get<T>(_ g: Generic<T>) -> Int {
   return g.mono_log
   // CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @_T010properties7GenericV8mono_log{{[_0-9a-zA-Z]*}}fg
   // CHECK: apply [[GENERIC_GET_METHOD]]<
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties20generic_mono_log_set{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties20generic_mono_log_set{{[_0-9a-zA-Z]*}}F
 func generic_mono_log_set<T>(_ g: Generic<T>, x: Int) {
   var g = g
   g.mono_log = x
@@ -406,34 +406,34 @@
   // CHECK: apply [[GENERIC_SET_METHOD]]<
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties26generic_mono_subscript_get{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties26generic_mono_subscript_get{{[_0-9a-zA-Z]*}}F
 func generic_mono_subscript_get<T>(_ g: Generic<T>, i: Int) -> Float {
   return g[i]
   // CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @_T010properties7GenericV9subscript{{[_0-9a-zA-Z]*}}fg
   // CHECK: apply [[GENERIC_GET_METHOD]]<
 }
 
-// CHECK-LABEL: sil hidden  @{{.*}}generic_mono_subscript_set
+// CHECK-LABEL: sil hidden @{{.*}}generic_mono_subscript_set
 func generic_mono_subscript_set<T>(_ g: inout Generic<T>, i: Int, x: Float) {
   g[i] = x
   // CHECK: [[GENERIC_SET_METHOD:%[0-9]+]] = function_ref @_T010properties7GenericV9subscript{{[_0-9a-zA-Z]*}}fs
   // CHECK: apply [[GENERIC_SET_METHOD]]<
 }
 
-// CHECK-LABEL: sil hidden  @{{.*}}bound_generic_mono_phys_get
+// CHECK-LABEL: sil hidden @{{.*}}bound_generic_mono_phys_get
 func bound_generic_mono_phys_get(_ g: inout Generic<UnicodeScalar>, x: Int) -> Int {
   return g.mono_phys
   // CHECK: struct_element_addr %{{.*}}, #Generic.mono_phys
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties26bound_generic_mono_log_get{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties26bound_generic_mono_log_get{{[_0-9a-zA-Z]*}}F
 func bound_generic_mono_log_get(_ g: Generic<UnicodeScalar>, x: Int) -> Int {
   return g.mono_log
 // CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @_T010properties7GenericV8mono_log{{[_0-9a-zA-Z]*}}fg
   // CHECK: apply [[GENERIC_GET_METHOD]]<
 }
 
-// CHECK-LABEL: sil hidden  @_T010properties22generic_subscript_type{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010properties22generic_subscript_type{{[_0-9a-zA-Z]*}}F
 func generic_subscript_type<T>(_ g: Generic<T>, i: T, x: T) -> T {
   var g = g
   g[i] = x
diff --git a/test/SILGen/protocol_extensions.swift b/test/SILGen/protocol_extensions.swift
index 398fb67..ec5914e 100644
--- a/test/SILGen/protocol_extensions.swift
+++ b/test/SILGen/protocol_extensions.swift
@@ -69,7 +69,7 @@
 }
 
 //   (materializeForSet test from above)
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T019protocol_extensions1CCAA2P1A2aDP9subscriptS2icfmTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_extensions1CCAA2P1A2aDP9subscriptS2icfmTW
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $Int, %3 : $*C):
 // CHECK: function_ref @_T019protocol_extensions2P1PAAE9subscriptS2icfg
 // CHECK: return
diff --git a/test/SILGen/protocol_resilience.swift b/test/SILGen/protocol_resilience.swift
index dc35e52..553e5ed 100644
--- a/test/SILGen/protocol_resilience.swift
+++ b/test/SILGen/protocol_resilience.swift
@@ -30,27 +30,27 @@
 
 extension ResilientMethods {
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP14defaultWitnessyyF
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP14defaultWitnessyyF
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientMethodsPAAE14defaultWitnessyyF
   public func defaultWitness() {}
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP21anotherDefaultWitnessxSiF
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP21anotherDefaultWitnessxSiF
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientMethodsPAAE21anotherDefaultWitnessxSiF
   public func anotherDefaultWitness(_ x: Int) -> Self {}
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP32defaultWitnessWithAssociatedTypey05AssocI0QzF
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP32defaultWitnessWithAssociatedTypey05AssocI0QzF
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientMethodsPAAE32defaultWitnessWithAssociatedTypey05AssocI0QzF
   public func defaultWitnessWithAssociatedType(_ a: AssocType) {}
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP41defaultWitnessMoreAbstractThanRequirementy9AssocTypeQz_Si1btF
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP41defaultWitnessMoreAbstractThanRequirementy9AssocTypeQz_Si1btF
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientMethodsPAAE41defaultWitnessMoreAbstractThanRequirementyqd___qd_0_1btr0_lF
   public func defaultWitnessMoreAbstractThanRequirement<A, T>(_ a: A, b: T) {}
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP48defaultWitnessMoreAbstractThanGenericRequirementy9AssocTypeQz_qd__1ttlF
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP48defaultWitnessMoreAbstractThanGenericRequirementy9AssocTypeQz_qd__1ttlF
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientMethodsPAAE48defaultWitnessMoreAbstractThanGenericRequirementyqd___qd_0_1ttr0_lF
   public func defaultWitnessMoreAbstractThanGenericRequirement<A, T>(_ a: A, t: T) {}
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP20staticDefaultWitnessxSiFZ
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientMethodsP20staticDefaultWitnessxSiFZ
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientMethodsPAAE20staticDefaultWitnessxSiFZ
   public static func staticDefaultWitness(_ x: Int) -> Self {}
 
@@ -70,13 +70,13 @@
 
 extension ResilientConstructors {
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience21ResilientConstructorsPxyt7default_tcfC
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience21ResilientConstructorsPxyt7default_tcfC
 // CHECK-LABEL: sil @_T019protocol_resilience21ResilientConstructorsPAAExyt7default_tcfC
   public init(default: ()) {
     self.init(noDefault: ())
   }
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience21ResilientConstructorsPxSgyt17defaultIsOptional_tcfC
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience21ResilientConstructorsPxSgyt17defaultIsOptional_tcfC
 // CHECK-LABEL: sil @_T019protocol_resilience21ResilientConstructorsPAAExSgyt17defaultIsOptional_tcfC
   public init?(defaultIsOptional: ()) {
     self.init(noDefault: ())
@@ -110,18 +110,18 @@
 
 extension ResilientStorage {
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP19propertyWithDefaultSifg
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP19propertyWithDefaultSifg
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE19propertyWithDefaultSifg
   public var propertyWithDefault: Int {
     get { return 0 }
   }
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifg
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifg
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE26mutablePropertyWithDefaultSifg
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifs
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifs
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE26mutablePropertyWithDefaultSifs
-// CHECK-LABEL: sil [transparent] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifmytfU_
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifm
+// CHECK-LABEL: sil private [transparent] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifmytfU_
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSifm
   public var mutablePropertyWithDefault: Int {
     get { return 0 }
     set { }
@@ -132,12 +132,12 @@
     set { }
   }
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfg
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfg
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE33mutableGenericPropertyWithDefault1TQzfg
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfs
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfs
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE33mutableGenericPropertyWithDefault1TQzfs
-// CHECK-LABEL: sil [transparent] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfmytfU_
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfm
+// CHECK-LABEL: sil private [transparent] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfmytfU_
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzfm
   public var mutableGenericPropertyWithDefault: T {
     get {
       return T(default: ())
@@ -145,12 +145,12 @@
     set { }
   }
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfg
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfg
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE9subscript1TQzAFcfg
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfs
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfs
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE9subscript1TQzAFcfs
-// CHECK-LABEL: sil [transparent] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfmytfU_
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfm
+// CHECK-LABEL: sil private [transparent] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfmytfU_
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP9subscript1TQzAFcfm
   public subscript(x: T) -> T {
     get {
       return x
@@ -158,12 +158,12 @@
     set { }
   }
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifg
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifg
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE36mutatingGetterWithNonMutatingDefaultSifg
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifs
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifs
 // CHECK-LABEL: sil @_T019protocol_resilience16ResilientStoragePAAE36mutatingGetterWithNonMutatingDefaultSifs
-// CHECK-LABEL: sil [transparent] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifmytfU_
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifm
+// CHECK-LABEL: sil private [transparent] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifmytfU_
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSifm
   public var mutatingGetterWithNonMutatingDefault: Int {
     get {
       return 0
@@ -182,22 +182,22 @@
   static func <===><T : ResilientOperators>(t: T, s: Self) -> T.AssocType
 }
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience18ResilientOperatorsP3tttopyxFZ
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience18ResilientOperatorsP3tttopyxFZ
 // CHECK-LABEL: sil @_T019protocol_resilience3tttopyxlF
 public prefix func ~~~<S>(s: S) {}
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience18ResilientOperatorsP3lmgoiyx_qd__tlFZ
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience18ResilientOperatorsP3lmgoiyx_qd__tlFZ
 // CHECK-LABEL: sil @_T019protocol_resilience3lmgoiyq__xtr0_lF
 public func <*><T, S>(s: S, t: T) {}
 
 // Swap the generic parameters to make sure we don't mix up our DeclContexts
 // when mapping interface types in and out
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience18ResilientOperatorsP4lmmgoi9AssocTypeQzqd___xtlFZ
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience18ResilientOperatorsP4lmmgoi9AssocTypeQzqd___xtlFZ
 // CHECK-LABEL: sil @_T019protocol_resilience4lmmgoi9AssocTypeQzq__xtAA18ResilientOperatorsRzr0_lF
 public func <**><S : ResilientOperators, T>(t: T, s: S) -> S.AssocType {}
 
-// CHECK-LABEL: sil [transparent] [thunk] @_T019protocol_resilience18ResilientOperatorsP5leeegoi9AssocTypeQyd__qd___xtAaBRd__lFZ
+// CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience18ResilientOperatorsP5leeegoi9AssocTypeQyd__qd___xtAaBRd__lFZ
 // CHECK-LABEL: sil @_T019protocol_resilience5leeegoi9AssocTypeQzx_q_tAA18ResilientOperatorsRzAaER_r0_lF
 public func <===><T : ResilientOperators, S : ResilientOperators>(t: T, s: S) -> T.AssocType {}
 
@@ -250,7 +250,7 @@
 
 extension InternalProtocol {
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T019protocol_resilience16InternalProtocolP8defaultGyyF
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T019protocol_resilience16InternalProtocolP8defaultGyyF
   // CHECK: return
   func defaultG() {}
 }
diff --git a/test/SILGen/protocols.swift b/test/SILGen/protocols.swift
index c2353c8..d5df1de 100644
--- a/test/SILGen/protocols.swift
+++ b/test/SILGen/protocols.swift
@@ -241,7 +241,7 @@
 
 // Make sure we are generating a protocol witness that calls the class method on
 // ClassWithGetter.
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T09protocols15ClassWithGetterCAA08PropertycD0A2aDP1aSifgTW : $@convention(witness_method) (@in_guaranteed ClassWithGetter) -> Int {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T09protocols15ClassWithGetterCAA08PropertycD0A2aDP1aSifgTW : $@convention(witness_method) (@in_guaranteed ClassWithGetter) -> Int {
 // CHECK: bb0([[C:%.*]] : $*ClassWithGetter):
 // CHECK-NEXT: [[CCOPY:%.*]] = alloc_stack $ClassWithGetter
 // CHECK-NEXT: copy_addr [[C]] to [initialization] [[CCOPY]]
@@ -269,7 +269,7 @@
   }
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T09protocols21ClassWithGetterSetterCAA08PropertycdE0A2aDP1bSifgTW : $@convention(witness_method) (@in_guaranteed ClassWithGetterSetter) -> Int {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T09protocols21ClassWithGetterSetterCAA08PropertycdE0A2aDP1bSifgTW : $@convention(witness_method) (@in_guaranteed ClassWithGetterSetter) -> Int {
 // CHECK: bb0([[C:%.*]] : $*ClassWithGetterSetter):
 // CHECK-NEXT: [[CCOPY:%.*]] = alloc_stack $ClassWithGetterSetter
 // CHECK-NEXT: copy_addr [[C]] to [initialization] [[CCOPY]]
@@ -325,7 +325,7 @@
 // thunking code being too dumb but it is harmless to program
 // correctness.
 //
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T09protocols24StructWithStoredPropertyVAA0eC6GetterA2aDP1aSifgTW : $@convention(witness_method) (@in_guaranteed StructWithStoredProperty) -> Int {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T09protocols24StructWithStoredPropertyVAA0eC6GetterA2aDP1aSifgTW : $@convention(witness_method) (@in_guaranteed StructWithStoredProperty) -> Int {
 // CHECK: bb0([[C:%.*]] : $*StructWithStoredProperty):
 // CHECK-NEXT: [[CCOPY:%.*]] = alloc_stack $StructWithStoredProperty
 // CHECK-NEXT: copy_addr [[C]] to [initialization] [[CCOPY]]
@@ -355,7 +355,7 @@
   // CHECK-NEXT: return %2 : $Int
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T09protocols29StructWithStoredClassPropertyVAA0fC6GetterA2aDP1aSifgTW : $@convention(witness_method) (@in_guaranteed StructWithStoredClassProperty) -> Int {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T09protocols29StructWithStoredClassPropertyVAA0fC6GetterA2aDP1aSifgTW : $@convention(witness_method) (@in_guaranteed StructWithStoredClassProperty) -> Int {
 // CHECK: bb0([[C:%.*]] : $*StructWithStoredClassProperty):
 // CHECK-NEXT: [[CCOPY:%.*]] = alloc_stack $StructWithStoredClassProperty
 // CHECK-NEXT: copy_addr [[C]] to [initialization] [[CCOPY]]
diff --git a/test/SILGen/result_abstraction.swift b/test/SILGen/result_abstraction.swift
index f5b9056..a9de977 100644
--- a/test/SILGen/result_abstraction.swift
+++ b/test/SILGen/result_abstraction.swift
@@ -10,7 +10,7 @@
 }
 
 struct ConformsToReturnsMetatype : ReturnsMetatype {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T018result_abstraction25ConformsToReturnsMetatypeVAA0eF0A2aDP08getAssocF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout ConformsToReturnsMetatype) -> @thick S.Type
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T018result_abstraction25ConformsToReturnsMetatypeVAA0eF0A2aDP08getAssocF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout ConformsToReturnsMetatype) -> @thick S.Type
   // CHECK:         function_ref @_T018result_abstraction25ConformsToReturnsMetatypeV08getAssocF0{{[_0-9a-zA-Z]*}}F : $@convention(method) (@inout ConformsToReturnsMetatype) -> @thin S.Type
   mutating
   func getAssocMetatype() -> S.Type {
@@ -25,7 +25,7 @@
 }
 
 struct ConformsToReturnsFunction : ReturnsFunction {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T018result_abstraction25ConformsToReturnsFunctionVAA0eF0A2aDP7getFunc{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in_guaranteed ConformsToReturnsFunction) -> @owned @callee_owned (@in S) -> @out R
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T018result_abstraction25ConformsToReturnsFunctionVAA0eF0A2aDP7getFunc{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in_guaranteed ConformsToReturnsFunction) -> @owned @callee_owned (@in S) -> @out R
   // CHECK:         function_ref @_T018result_abstraction1SVAA1RVIxyd_AcEIxir_TR : $@convention(thin) (@in S, @owned @callee_owned (S) -> R) -> @out R
   func getFunc() -> (S) -> R {
     return {s in R()}
@@ -40,7 +40,7 @@
 
 struct ConformsToReturnsAssocWithMetatype : ReturnsAssoc {
   typealias Assoc = S.Type
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T018result_abstraction34ConformsToReturnsAssocWithMetatypeVAA0eF0A2aDP03getF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout ConformsToReturnsAssocWithMetatype) -> @out @thick S.Type
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T018result_abstraction34ConformsToReturnsAssocWithMetatypeVAA0eF0A2aDP03getF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout ConformsToReturnsAssocWithMetatype) -> @out @thick S.Type
   // CHECK:         function_ref @_T018result_abstraction34ConformsToReturnsAssocWithMetatypeV03getF0{{[_0-9a-zA-Z]*}}F : $@convention(method) (@inout ConformsToReturnsAssocWithMetatype) -> @thin S.Type
   mutating
   func getAssoc() -> S.Type {
@@ -50,7 +50,7 @@
 
 struct ConformsToReturnsAssocWithFunction : ReturnsAssoc {
   typealias Assoc = (S) -> R
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T018result_abstraction34ConformsToReturnsAssocWithFunctionVAA0eF0A2aDP03getF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout ConformsToReturnsAssocWithFunction) -> @out @callee_owned (@in S) -> @out R
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T018result_abstraction34ConformsToReturnsAssocWithFunctionVAA0eF0A2aDP03getF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@inout ConformsToReturnsAssocWithFunction) -> @out @callee_owned (@in S) -> @out R
   // CHECK:         function_ref @_T018result_abstraction34ConformsToReturnsAssocWithFunctionV03getF0{{[_0-9a-zA-Z]*}}F : $@convention(method) (@inout ConformsToReturnsAssocWithFunction) -> @owned @callee_owned (S) -> R
   mutating
   func getAssoc() -> (S) -> R {
diff --git a/test/SILGen/rethrows.swift b/test/SILGen/rethrows.swift
index d9380b9..8ba390d 100644
--- a/test/SILGen/rethrows.swift
+++ b/test/SILGen/rethrows.swift
@@ -32,7 +32,7 @@
 // CHECK:     [[ERROR]]([[T0:%.*]] : $Error):
 // CHECK-NEXT:  throw [[T0]]
 //   Closure.
-// CHECK-LABEL: sil shared @_T08rethrows5test1yyKFSiyKcfU_ : $@convention(thin) () -> (Int, @error Error) {
+// CHECK-LABEL: sil private @_T08rethrows5test1yyKFSiyKcfU_ : $@convention(thin) () -> (Int, @error Error) {
 // CHECK:       [[RETHROWER:%.*]] = function_ref @_T08rethrows9rethrowerS2iyKcKF : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (Int, @error Error)
 // CHECK:       [[THROWER:%.*]] = function_ref @_T08rethrows7throwerSiyKF : $@convention(thin) () -> (Int, @error Error)
 // CHECK:       [[T0:%.*]] = thin_to_thick_function [[THROWER]]
diff --git a/test/SILGen/sil_locations.swift b/test/SILGen/sil_locations.swift
index 9aa2e98..4dcf4fe 100644
--- a/test/SILGen/sil_locations.swift
+++ b/test/SILGen/sil_locations.swift
@@ -8,7 +8,7 @@
     x+=1
   }
   return x
-  // CHECK-LABEL: sil hidden  @_T013sil_locations6ifexprSiyF
+  // CHECK-LABEL: sil hidden @_T013sil_locations6ifexprSiyF
   // CHECK: apply {{.*}}, loc "{{.*}}":[[@LINE-5]]:6
   // CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-6]]:6
   // CHECK: br [[FALSE_BB]], loc "{{.*}}":[[@LINE-5]]:3
@@ -23,7 +23,7 @@
     x-=1
   }
   return x
-  // CHECK-LABEL: sil hidden  @_T013sil_locations10ifelseexprSiyF
+  // CHECK-LABEL: sil hidden @_T013sil_locations10ifelseexprSiyF
   // CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-7]]:6
   // CHECK: [[TRUE_BB]]:
   // CHECK: br bb{{[0-9]+}}, loc "{{.*}}":[[@LINE-7]]:3
@@ -40,7 +40,7 @@
     return 5
   }
   return 6
-  // CHECK-LABEL: sil hidden  @_T013sil_locations13ifexpr_returnSiyF
+  // CHECK-LABEL: sil hidden @_T013sil_locations13ifexpr_returnSiyF
   // CHECK: apply {{.*}}, loc "{{.*}}":[[@LINE-5]]:6
   // CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-6]]:6
   // CHECK: [[TRUE_BB]]:
@@ -53,7 +53,7 @@
 func ifexpr_rval() -> Int {
   var x = true ? 5 : 6
   return x
-  // CHECK-LABEL: sil hidden  @_T013sil_locations11ifexpr_rvalSiyF
+  // CHECK-LABEL: sil hidden @_T013sil_locations11ifexpr_rvalSiyF
   // CHECK: apply {{.*}}, loc "{{.*}}":[[@LINE-3]]:11
   // CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-4]]:11
   // CHECK: [[TRUE_BB]]:
@@ -62,20 +62,10 @@
   // CHECK: br bb{{[0-9]+}}({{%.*}}), loc "{{.*}}":[[@LINE-8]]:22
 }
 
-
-
-
-
-
-
-
-
-
-
 // --- Test function calls.
 func simpleDirectCallTest(_ i: Int) -> Int {
   return simpleDirectCallTest(i)
-  // CHECK-LABEL: sil hidden  @_T013sil_locations20simpleDirectCallTestS2iF
+  // CHECK-LABEL: sil hidden @_T013sil_locations20simpleDirectCallTestS2iF
   // CHECK: function_ref @_T013sil_locations20simpleDirectCallTestS2iF : {{.*}}, loc "{{.*}}":[[@LINE-2]]:10
   // CHECK: {{%.*}} apply {{%.*}} line:[[@LINE-3]]:10
 }
@@ -85,9 +75,8 @@
 }
 func useTemplateTest() -> Int {
   return templateTest(5);
-  // CHECK-LABEL: sil hidden  @_T013sil_locations15useTemplateTestSiyF
-
-  // CHECK: function_ref @_T0S2i{{[_0-9a-zA-Z]*}}fC :{{.*}}, loc "{{.*}}":87
+  // CHECK-LABEL: sil hidden @_T013sil_locations15useTemplateTestSiyF
+  // CHECK: function_ref @_T0S2i{{[_0-9a-zA-Z]*}}fC :{{.*}}, loc "{{.*}}":77
 }
 
 func foo(_ x: Int) -> Int {
@@ -95,7 +84,7 @@
     return x + y
   }
   return bar(1)
-  // CHECK-LABEL: sil hidden  @_T013sil_locations3foo{{[_0-9a-zA-Z]*}}F
+  // CHECK-LABEL: sil hidden @_T013sil_locations3foo{{[_0-9a-zA-Z]*}}F
   // CHECK: [[CLOSURE:%[0-9]+]] = function_ref {{.*}}, loc "{{.*}}":[[@LINE-2]]:10
   // CHECK: apply [[CLOSURE:%[0-9]+]]
 }
@@ -106,7 +95,7 @@
 func testMethodCall() {
   var l: LocationClass
   l.mem();
-  // CHECK-LABEL: sil hidden  @_T013sil_locations14testMethodCallyyF
+  // CHECK-LABEL: sil hidden @_T013sil_locations14testMethodCallyyF
   
   // CHECK: class_method {{.[0-9]+}} : $LocationClass, #LocationClass.mem!1 {{.*}}, loc "{{.*}}":[[@LINE-3]]:5
 }
@@ -117,7 +106,7 @@
     return
   }
   x += 1
-  // CHECK-LABEL: sil hidden  @_T013sil_locations34multipleReturnsImplicitAndExplicityyF
+  // CHECK-LABEL: sil hidden @_T013sil_locations34multipleReturnsImplicitAndExplicityyF
   // CHECK: cond_br
   // CHECK: br bb{{[0-9]+}}, loc "{{.*}}":[[@LINE-5]]:5, {{.*}}:return
   // CHECK: br bb{{[0-9]+}}, loc "{{.*}}":[[@LINE+2]]:1, {{.*}}:imp_return
@@ -126,7 +115,7 @@
 
 func simplifiedImplicitReturn() -> () {
   var y = 0 
-  // CHECK-LABEL: sil hidden  @_T013sil_locations24simplifiedImplicitReturnyyF
+  // CHECK-LABEL: sil hidden @_T013sil_locations24simplifiedImplicitReturnyyF
   // CHECK: return {{.*}}, loc "{{.*}}":[[@LINE+1]]:1, {{.*}}:imp_return
 }
 
@@ -169,9 +158,6 @@
   //
   //
   // CHECK: br {{.*}}, loc "{{.*}}":[[@LINE-13]]:6
-
-
-
 }
 
 func testFor() {
@@ -201,13 +187,11 @@
   var tt = (2, (4,5))
   var d = "foo"
   // CHECK-LABEL: sil hidden @_T013sil_locations10testTuplesyyF
-
-
-  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-6]]:11
-  // CHECK: integer_literal $Builtin.Int2048, 2, loc "{{.*}}":[[@LINE-7]]:12
-  // CHECK: integer_literal $Builtin.Int2048, 3, loc "{{.*}}":[[@LINE-8]]:14
-  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-8]]:12
-  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-9]]:16  
+  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-4]]:11
+  // CHECK: integer_literal $Builtin.Int2048, 2, loc "{{.*}}":[[@LINE-5]]:12
+  // CHECK: integer_literal $Builtin.Int2048, 3, loc "{{.*}}":[[@LINE-6]]:14
+  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-6]]:12
+  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-7]]:16  
 }
 
 // Test tuple imploding/exploding.
@@ -222,26 +206,18 @@
 func captures_tuple<T, U>(x: (T, U)) -> () -> (T, U) {
   return {x}
   // CHECK-LABEL: sil hidden @_T013sil_locations14captures_tuple{{[_0-9a-zA-Z]*}}F
+  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-3]]:27
+  // CHECK: copy_addr [take] {{.*}}, loc "{{.*}}":[[@LINE-4]]:27
+  // CHECK: function_ref {{.*}}, loc "{{.*}}":[[@LINE-4]]:10
 
-
-  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-5]]:27
-  // CHECK: copy_addr [take] {{.*}}, loc "{{.*}}":[[@LINE-6]]:27
-  // CHECK: function_ref {{.*}}, loc "{{.*}}":[[@LINE-6]]:10
-
-  
-  // CHECK-LABEL: sil shared @_T013sil_locations14captures_tuple{{.*}}fU_
-  // CHECK: copy_addr {{.*}}, loc "{{.*}}":[[@LINE-10]]:11
+  // CHECK-LABEL: sil private @_T013sil_locations14captures_tuple{{.*}}fU_
+  // CHECK: copy_addr {{.*}}, loc "{{.*}}":[[@LINE-7]]:11
 }
 
 func interpolated_string(_ x: Int, y: String) -> String {
   return "The \(x) Million Dollar \(y)"
   // CHECK-LABEL: sil hidden @_T013sil_locations19interpolated_string{{[_0-9a-zA-Z]*}}F
-
-
-
-  // CHECK: copy_value{{.*}}, loc "{{.*}}":[[@LINE-5]]:37
-
-
+  // CHECK: copy_value{{.*}}, loc "{{.*}}":[[@LINE-2]]:37
 }
 
 
diff --git a/test/SILGen/statements.swift b/test/SILGen/statements.swift
index fa43ce6..ab255e9 100644
--- a/test/SILGen/statements.swift
+++ b/test/SILGen/statements.swift
@@ -32,7 +32,7 @@
   (x, y) = (1,2)
 }
 
-// CHECK-LABEL: sil hidden  @{{.*}}assignment
+// CHECK-LABEL: sil hidden @{{.*}}assignment
 // CHECK: integer_literal $Builtin.Int2048, 42
 // CHECK: assign
 // CHECK: integer_literal $Builtin.Int2048, 57
@@ -45,7 +45,7 @@
   bar(x);
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements7if_test{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements7if_test{{[_0-9a-zA-Z]*}}F
 
 func if_else(_ x: Int, y: Bool) {
   if (y) {
@@ -56,7 +56,7 @@
   bar(x);
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements7if_else{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements7if_else{{[_0-9a-zA-Z]*}}F
 
 func nested_if(_ x: Int, y: Bool, z: Bool) {
   if (y) {
@@ -71,7 +71,7 @@
   bar(x);
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements9nested_if{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements9nested_if{{[_0-9a-zA-Z]*}}F
 
 func nested_if_merge_noret(_ x: Int, y: Bool, z: Bool) {
   if (y) {
@@ -85,7 +85,7 @@
   }
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements21nested_if_merge_noret{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements21nested_if_merge_noret{{[_0-9a-zA-Z]*}}F
 
 func nested_if_merge_ret(_ x: Int, y: Bool, z: Bool) -> Int {
   if (y) {
@@ -101,7 +101,7 @@
   return 2
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements19nested_if_merge_ret{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements19nested_if_merge_ret{{[_0-9a-zA-Z]*}}F
 
 func else_break(_ x: Int, y: Bool, z: Bool) {
   while z {
@@ -112,7 +112,7 @@
   }
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements10else_break{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements10else_break{{[_0-9a-zA-Z]*}}F
 
 func loop_with_break(_ x: Int, _ y: Bool, _ z: Bool) -> Int {
   while (x > 2) {
@@ -123,7 +123,7 @@
   }
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements15loop_with_break{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements15loop_with_break{{[_0-9a-zA-Z]*}}F
 
 func loop_with_continue(_ x: Int, y: Bool, z: Bool) -> Int {
   while (x > 2) {
@@ -136,7 +136,7 @@
   bar(x);
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements18loop_with_continue{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements18loop_with_continue{{[_0-9a-zA-Z]*}}F
 
 func do_loop_with_continue(_ x: Int, y: Bool, z: Bool) -> Int {
   repeat {
@@ -150,10 +150,10 @@
   bar(x);
 }
 
-// CHECK-LABEL: sil hidden  @_T010statements21do_loop_with_continue{{[_0-9a-zA-Z]*}}F 
+// CHECK-LABEL: sil hidden @_T010statements21do_loop_with_continue{{[_0-9a-zA-Z]*}}F 
 
 
-// CHECK-LABEL: sil hidden  @{{.*}}for_loops1
+// CHECK-LABEL: sil hidden @{{.*}}for_loops1
 func for_loops1(_ x: Int, c: Bool) {
   for i in 1..<100 {
     markUsed(i)
@@ -161,7 +161,7 @@
 
 }
 
-// CHECK-LABEL: sil hidden  @{{.*}}for_loops2
+// CHECK-LABEL: sil hidden @{{.*}}for_loops2
 func for_loops2() {
   // rdar://problem/19316670
   // CHECK: [[NEXT:%[0-9]+]] = function_ref @_T0s16IndexingIteratorV4next{{[_0-9a-zA-Z]*}}F
@@ -182,7 +182,7 @@
     return
   }
 }
-// CHECK-LABEL: sil hidden  @_T010statements11void_return{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements11void_return{{[_0-9a-zA-Z]*}}F
 // CHECK: cond_br {{%[0-9]+}}, [[BB1:bb[0-9]+]], [[BB2:bb[0-9]+]]
 // CHECK: [[BB1]]:
 // CHECK:   br [[EPILOG:bb[0-9]+]]
@@ -195,7 +195,7 @@
 func foo() {}
 
 // <rdar://problem/13549626>
-// CHECK-LABEL: sil hidden  @_T010statements14return_from_if{{[_0-9a-zA-Z]*}}F
+// CHECK-LABEL: sil hidden @_T010statements14return_from_if{{[_0-9a-zA-Z]*}}F
 func return_from_if(_ a: Bool) -> Int {
   // CHECK: bb0(%0 : $Bool):
   // CHECK: cond_br {{.*}}, [[THEN:bb[0-9]+]], [[ELSE:bb[0-9]+]]
@@ -468,10 +468,10 @@
   // CHECK: [[C1:%.*]] = function_ref @_T010statements11defer_test1yyF6
   // CHECK: apply [[C1]]
 }
-// CHECK: sil shared @_T010statements11defer_test1yyF6
+// CHECK: sil private @_T010statements11defer_test1yyF6
 // CHECK: function_ref @{{.*}}callee1yyF
 
-// CHECK: sil shared @_T010statements11defer_test1yyF6
+// CHECK: sil private @_T010statements11defer_test1yyF6
 // CHECK: function_ref @{{.*}}callee2yyF
 
 // CHECK-LABEL: sil hidden @_T010statements11defer_test2ySbF
diff --git a/test/SILGen/super.swift b/test/SILGen/super.swift
index 68c3d4b..de91646 100644
--- a/test/SILGen/super.swift
+++ b/test/SILGen/super.swift
@@ -117,14 +117,14 @@
 
 public class GenericDerived<T> : GenericBase<T> {
   public override func method() {
-    // CHECK-LABEL: sil shared @_T05super14GenericDerivedC6methodyyFyycfU_ : $@convention(thin) <T> (@owned GenericDerived<T>) -> ()
+    // CHECK-LABEL: sil private @_T05super14GenericDerivedC6methodyyFyycfU_ : $@convention(thin) <T> (@owned GenericDerived<T>) -> ()
     // CHECK: upcast {{.*}} : $GenericDerived<T> to $GenericBase<T>
     // CHECK: return
     {
       super.method()
     }()
 
-    // CHECK-LABEL: sil shared @_T05super14GenericDerivedC6methodyyF13localFunctionL_yylF : $@convention(thin) <T> (@owned GenericDerived<T>) -> ()
+    // CHECK-LABEL: sil private @_T05super14GenericDerivedC6methodyyF13localFunctionL_yylF : $@convention(thin) <T> (@owned GenericDerived<T>) -> ()
     // CHECK: upcast {{.*}} : $GenericDerived<T> to $GenericBase<T>
     // CHECK: return
 
@@ -133,7 +133,7 @@
     }
     localFunction()
 
-    // CHECK-LABEL: sil shared @_T05super14GenericDerivedC6methodyyF15genericFunctionL_yqd__r__lF : $@convention(thin) <T><U> (@in U, @owned GenericDerived<T>) -> ()
+    // CHECK-LABEL: sil private @_T05super14GenericDerivedC6methodyyF15genericFunctionL_yqd__r__lF : $@convention(thin) <T><U> (@in U, @owned GenericDerived<T>) -> ()
     // CHECK: upcast {{.*}} : $GenericDerived<T> to $GenericBase<T>
     // CHECK: return
     func genericFunction<U>(_: U) {
diff --git a/test/SILGen/switch.swift b/test/SILGen/switch.swift
index ff6e2e2..b67c7bb 100644
--- a/test/SILGen/switch.swift
+++ b/test/SILGen/switch.swift
@@ -25,7 +25,7 @@
 func f() {}
 func g() {}
 
-// CHECK-LABEL: sil hidden  @_T06switch5test1yyF
+// CHECK-LABEL: sil hidden @_T06switch5test1yyF
 func test1() {
   switch foo() {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -39,7 +39,7 @@
   b()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch5test2yyF
+// CHECK-LABEL: sil hidden @_T06switch5test2yyF
 func test2() {
   switch foo() {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -55,7 +55,7 @@
   c()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch5test3yyF
+// CHECK-LABEL: sil hidden @_T06switch5test3yyF
 func test3() {
   switch foo() {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -81,7 +81,7 @@
   c()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch5test4yyF
+// CHECK-LABEL: sil hidden @_T06switch5test4yyF
 func test4() {
   switch (foo(), bar()) {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -96,7 +96,7 @@
   b()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch5test5yyF
+// CHECK-LABEL: sil hidden @_T06switch5test5yyF
 func test5() {
   switch (foo(), bar()) {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -131,7 +131,7 @@
   d()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch5test6yyF
+// CHECK-LABEL: sil hidden @_T06switch5test6yyF
 func test6() {
   switch (foo(), bar()) {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -148,7 +148,7 @@
   c()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch5test7yyF
+// CHECK-LABEL: sil hidden @_T06switch5test7yyF
 func test7() {
   switch (foo(), bar()) {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -174,7 +174,7 @@
   // CHECK:   function_ref @_T06switch1cyyF
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch5test8yyF
+// CHECK-LABEL: sil hidden @_T06switch5test8yyF
 func test8() {
   switch (foo(), bar()) {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -247,7 +247,7 @@
   g()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch5test9yyF
+// CHECK-LABEL: sil hidden @_T06switch5test9yyF
 func test9() {
   switch (foo(), bar()) {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -282,7 +282,7 @@
   d()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch6test10yyF
+// CHECK-LABEL: sil hidden @_T06switch6test10yyF
 func test10() {
   switch (foo(), bar()) {
   // CHECK:   function_ref @_T06switch3fooSiyF
@@ -313,7 +313,7 @@
 struct Y : P { func p() {} }
 struct Z : P { func p() {} }
 
-// CHECK-LABEL: sil hidden  @_T06switch10test_isa_1yAA1P_p1p_tF
+// CHECK-LABEL: sil hidden @_T06switch10test_isa_1yAA1P_p1p_tF
 func test_isa_1(p: P) {
   // CHECK: [[PTMPBUF:%[0-9]+]] = alloc_stack $P
   // CHECK-NEXT: copy_addr %0 to [initialization] [[PTMPBUF]] : $*P
@@ -360,7 +360,7 @@
   e()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch10test_isa_2yAA1P_p1p_tF
+// CHECK-LABEL: sil hidden @_T06switch10test_isa_2yAA1P_p1p_tF
 func test_isa_2(p: P) {
   switch (p, foo()) {
   // CHECK:   checked_cast_addr_br copy_on_success P in [[P:%.*]] : $*P to X in {{%.*}} : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
@@ -648,7 +648,7 @@
   case Both(Int, String)
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch12test_union_1yAA9MaybePairO1u_tF
+// CHECK-LABEL: sil hidden @_T06switch12test_union_1yAA9MaybePairO1u_tF
 func test_union_1(u: MaybePair) {
   switch u {
   // CHECK: switch_enum [[SUBJECT:%.*]] : $MaybePair,
@@ -692,7 +692,7 @@
   e()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch12test_union_2yAA9MaybePairO1u_tF
+// CHECK-LABEL: sil hidden @_T06switch12test_union_2yAA9MaybePairO1u_tF
 func test_union_2(u: MaybePair) {
   switch u {
   // CHECK: switch_enum {{%.*}} : $MaybePair,
@@ -729,7 +729,7 @@
   d()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch12test_union_3yAA9MaybePairO1u_tF : $@convention(thin) (@owned MaybePair) -> () {
+// CHECK-LABEL: sil hidden @_T06switch12test_union_3yAA9MaybePairO1u_tF : $@convention(thin) (@owned MaybePair) -> () {
 func test_union_3(u: MaybePair) {
   // CHECK: bb0([[ARG:%.*]] : $MaybePair):
   // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
@@ -776,7 +776,7 @@
   e()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch12test_union_4yAA9MaybePairO1u_tF
+// CHECK-LABEL: sil hidden @_T06switch12test_union_4yAA9MaybePairO1u_tF
 func test_union_4(u: MaybePair) {
   switch u {
   // CHECK: switch_enum {{%.*}} : $MaybePair,
@@ -815,7 +815,7 @@
   e()
 }
 
-// CHECK-LABEL: sil hidden  @_T06switch12test_union_5yAA9MaybePairO1u_tF
+// CHECK-LABEL: sil hidden @_T06switch12test_union_5yAA9MaybePairO1u_tF
 func test_union_5(u: MaybePair) {
   switch u {
   // CHECK: switch_enum {{%.*}} : $MaybePair,
@@ -1098,3 +1098,29 @@
   // CHECK: integer_literal $Builtin.Int2048, 42
   }
 }
+
+// SR-3518
+// CHECK-LABEL: sil hidden @_T06switch43testMultiPatternsWithOuterScopeSameNamedVarySiSg4base_AC6filtertF
+func testMultiPatternsWithOuterScopeSameNamedVar(base: Int?, filter: Int?) {
+  switch(base, filter) {
+    
+  case (.some(let base), .some(let filter)):
+    // CHECK: bb2(%10 : $Int):
+    // CHECK-NEXT: debug_value %10 : $Int, let, name "base"
+    // CHECK-NEXT: debug_value %8 : $Int, let, name "filter"
+    print("both: \(base), \(filter)")
+  case (.some(let base), .none), (.none, .some(let base)):
+    // CHECK: bb3:
+    // CHECK-NEXT: debug_value %8 : $Int, let, name "base"
+    // CHECK-NEXT: br bb6(%8 : $Int)
+
+    // CHECK: bb5([[OTHER_BASE:%.*]] : $Int)
+    // CHECK-NEXT: debug_value [[OTHER_BASE]] : $Int, let, name "base"
+    // CHECK-NEXT: br bb6([[OTHER_BASE]] : $Int)
+    
+    // CHECK: bb6([[ARG:%.*]] : $Int):
+    print("single: \(base)")
+  default:
+    print("default")
+  }
+}
diff --git a/test/SILGen/switch_fallthrough.swift b/test/SILGen/switch_fallthrough.swift
index 0f54341..6bbb0b1 100644
--- a/test/SILGen/switch_fallthrough.swift
+++ b/test/SILGen/switch_fallthrough.swift
@@ -16,7 +16,7 @@
 func f() {}
 func g() {}
 
-// CHECK-LABEL: sil hidden  @_T018switch_fallthrough5test1yyF
+// CHECK-LABEL: sil hidden @_T018switch_fallthrough5test1yyF
 func test1() {
   switch foo() {
   // CHECK:   cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], {{bb[0-9]+}}
@@ -44,7 +44,7 @@
 }
 
 // Fallthrough should work even if the next case is normally unreachable
-// CHECK-LABEL: sil hidden  @_T018switch_fallthrough5test2yyF
+// CHECK-LABEL: sil hidden @_T018switch_fallthrough5test2yyF
 func test2() {
   switch foo() {
   // CHECK:   cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], {{bb[0-9]+}}
@@ -71,7 +71,7 @@
   d()
 }
 
-// CHECK-LABEL: sil hidden  @_T018switch_fallthrough5test3yyF
+// CHECK-LABEL: sil hidden @_T018switch_fallthrough5test3yyF
 func test3() {
   switch (foo(), bar()) {
   // CHECK:   cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], {{bb[0-9]+}}
diff --git a/test/SILGen/switch_var.swift b/test/SILGen/switch_var.swift
index e8a9446..e32aa94 100644
--- a/test/SILGen/switch_var.swift
+++ b/test/SILGen/switch_var.swift
@@ -108,7 +108,7 @@
   d()
 }
 
-// CHECK-LABEL: sil hidden  @_T010switch_var05test_B2_3yyF
+// CHECK-LABEL: sil hidden @_T010switch_var05test_B2_3yyF
 func test_var_3() {
   // CHECK:   function_ref @_T010switch_var3fooSiyF
   // CHECK:   function_ref @_T010switch_var3barSiyF
@@ -180,7 +180,7 @@
 struct Y : P { func p() {} }
 struct Z : P { func p() {} }
 
-// CHECK-LABEL: sil hidden  @_T010switch_var05test_B2_4yAA1P_p1p_tF
+// CHECK-LABEL: sil hidden @_T010switch_var05test_B2_4yAA1P_p1p_tF
 func test_var_4(p p: P) {
   // CHECK:   function_ref @_T010switch_var3fooSiyF
   switch (p, foo()) {
diff --git a/test/SILGen/types.swift b/test/SILGen/types.swift
index 6badf3b..b327e69 100644
--- a/test/SILGen/types.swift
+++ b/test/SILGen/types.swift
@@ -20,7 +20,7 @@
 struct S {
   var member: Int
 
-  // CHECK-LABEL: sil hidden  @{{.*}}1SV3foo{{.*}} : $@convention(method) (Int, @inout S) -> ()
+  // CHECK-LABEL: sil hidden @{{.*}}1SV3foo{{.*}} : $@convention(method) (Int, @inout S) -> ()
   mutating
   func foo(x x: Int) {
     var x = x
@@ -101,6 +101,6 @@
   }
 }
 
-// CHECK-LABEL: sil shared @_T05types1fyyF2FCL_C3zimyyF
-// CHECK-LABEL: sil shared @_T05types1gySb1b_tF2FCL_C3zimyyF
-// CHECK-LABEL: sil shared @_T05types1gySb1b_tF2FCL0_C3zimyyF
+// CHECK-LABEL: sil private @_T05types1fyyF2FCL_C3zimyyF
+// CHECK-LABEL: sil private @_T05types1gySb1b_tF2FCL_C3zimyyF
+// CHECK-LABEL: sil private @_T05types1gySb1b_tF2FCL0_C3zimyyF
diff --git a/test/SILGen/unowned.swift b/test/SILGen/unowned.swift
index fef21cb..0211f0e 100644
--- a/test/SILGen/unowned.swift
+++ b/test/SILGen/unowned.swift
@@ -113,7 +113,7 @@
   takeClosure { bC.f() }
 }
 
-// CHECK-LABEL: sil shared @_T07unowned05test_A12_let_captureyAA1CCFSiycfU_ : $@convention(thin) (@owned @sil_unowned C) -> Int {
+// CHECK-LABEL: sil private @_T07unowned05test_A12_let_captureyAA1CCFSiycfU_ : $@convention(thin) (@owned @sil_unowned C) -> Int {
 // CHECK: bb0([[ARG:%.*]] : $@sil_unowned C):
 // CHECK-NEXT:   debug_value %0 : $@sil_unowned C, let, name "bC", argno 1
 // CHECK-NEXT:   strong_retain_unowned [[ARG]] : $@sil_unowned C
diff --git a/test/SILGen/vtable_thunks_reabstraction_final.swift b/test/SILGen/vtable_thunks_reabstraction_final.swift
index c46105b..d83e074 100644
--- a/test/SILGen/vtable_thunks_reabstraction_final.swift
+++ b/test/SILGen/vtable_thunks_reabstraction_final.swift
@@ -21,7 +21,7 @@
   }
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T033vtable_thunks_reabstraction_final13NongenericSubCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T033vtable_thunks_reabstraction_final13NongenericSubCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
 // CHECK:         class_method {{%.*}} : $NongenericSub, #NongenericSub.foo!1 {{.*}}, $@convention(method) (@in Int, @guaranteed NongenericSub) -> @out Optional<Int>
 
 class GenericSub<U: AnyObject>: GenericSuper<U>, Barrable {
@@ -30,7 +30,7 @@
   }
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T033vtable_thunks_reabstraction_final10GenericSubCyxGAA8BarrableAAs9AnyObjectRzlAaEP3foo3BarQzSgAJFTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T033vtable_thunks_reabstraction_final10GenericSubCyxGAA8BarrableAAs9AnyObjectRzlAaEP3foo3BarQzSgAJFTW
 // CHECK:         class_method {{%.*}} : $GenericSub<τ_0_0>, #GenericSub.foo!1 {{.*}}, $@convention(method) <τ_0_0 where τ_0_0 : AnyObject> (@in τ_0_0, @guaranteed GenericSub<τ_0_0>) -> @out Optional<τ_0_0>
 
 class C {}
diff --git a/test/SILGen/weak.swift b/test/SILGen/weak.swift
index 914bd39..8bb51e2 100644
--- a/test/SILGen/weak.swift
+++ b/test/SILGen/weak.swift
@@ -46,7 +46,7 @@
 
 // <rdar://problem/16871284> silgen crashes on weak capture
 // CHECK: weak.(testClosureOverWeak () -> ()).(closure #1)
-// CHECK-LABEL: sil shared @_T04weak19testClosureOverWeakyyFSiycfU_ : $@convention(thin) (@owned { var @sil_weak Optional<C> }) -> Int {
+// CHECK-LABEL: sil private @_T04weak19testClosureOverWeakyyFSiycfU_ : $@convention(thin) (@owned { var @sil_weak Optional<C> }) -> Int {
 // CHECK: bb0(%0 : ${ var @sil_weak Optional<C> }):
 // CHECK-NEXT:  %1 = project_box %0
 // CHECK-NEXT:  debug_value_addr %1 : $*@sil_weak Optional<C>, var, name "bC", argno 1
diff --git a/test/SILGen/witness-init-requirement-with-base-class-init.swift b/test/SILGen/witness-init-requirement-with-base-class-init.swift
index 1832068..38288d9 100644
--- a/test/SILGen/witness-init-requirement-with-base-class-init.swift
+++ b/test/SILGen/witness-init-requirement-with-base-class-init.swift
@@ -14,9 +14,9 @@
 }
 
 class Dog: Animal, BestFriend {}
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T04main3DogCAA10BestFriendA2aDPxycfCTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T04main3DogCAA10BestFriendA2aDPxycfCTW
 // CHECK:         [[SELF:%.*]] = apply
 // CHECK:         unchecked_ref_cast [[SELF]] : $Animal to $Dog
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T04main3DogCAA10BestFriendA2aDP6createxyFZTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T04main3DogCAA10BestFriendA2aDP6createxyFZTW
 // CHECK:         [[SELF:%.*]] = apply
 // CHECK:         unchecked_ref_cast [[SELF]] : $Animal to $Dog
diff --git a/test/SILGen/witness_accessibility.swift b/test/SILGen/witness_accessibility.swift
new file mode 100644
index 0000000..bd06a6a
--- /dev/null
+++ b/test/SILGen/witness_accessibility.swift
@@ -0,0 +1,42 @@
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s
+
+public protocol P {
+  func publicRequirement()
+}
+
+protocol Q : P {
+  func internalRequirement()
+}
+
+fileprivate protocol R : Q {
+  func privateRequirement()
+}
+
+extension R {
+  public func publicRequirement() {}
+  func internalRequirement() {}
+  func privateRequirement() {}
+}
+
+public struct S : R {}
+
+// CHECK-LABEL: sil private @_T021witness_accessibility1R{{.*}}AE18privateRequirementyyF
+// CHECK-LABEL: sil private @_T021witness_accessibility1R{{.*}}E17publicRequirementyyF
+// CHECK-LABEL: sil private @_T021witness_accessibility1R{{.*}}E19internalRequirementyyF
+
+// CHECK-LABEL: sil private [transparent] [thunk] @_T021witness_accessibility1SVAA1R{{.*}}dELLP18privateRequirementyyFTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T021witness_accessibility1SVAA1QA2aDP19internalRequirementyyFTW
+
+// FIXME: This is public because of an explicit workaround for
+// the default implementation of publicRequirement() having the
+// wrong linkage.
+//
+// It should be 'shared [fragile]', but it's not clear that this
+// this makes sense either, because 'R' is private.
+
+// Perhaps the conformance S : R should be rejected, because
+// publicRequirement() is not sufficiently visible; furthermore,
+// the use of the 'public' keyword inside an extension of 'R'
+// should generate a warning, since it has no effect.
+
+// CHECK-LABEL: sil [transparent] [thunk] @_T021witness_accessibility1SVAA1PA2aDP17publicRequirementyyFTW
diff --git a/test/SILGen/witness_same_type.swift b/test/SILGen/witness_same_type.swift
index ecda1ac..2761771 100644
--- a/test/SILGen/witness_same_type.swift
+++ b/test/SILGen/witness_same_type.swift
@@ -11,7 +11,7 @@
 
 // Ensure that the protocol witness for requirements with same-type constraints
 // is set correctly. <rdar://problem/16369105>
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T017witness_same_type3FooVAA7FooableA2aDP3foo3BarQzqd__1x_tAaDRd__AGQyd__AHRSlFTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : Fooable, τ_0_0.Bar == X> (@in τ_0_0, @in_guaranteed Foo) -> @out X
+// CHECK-LABEL: sil private [transparent] [thunk] @_T017witness_same_type3FooVAA7FooableA2aDP3foo3BarQzqd__1x_tAaDRd__AGQyd__AHRSlFTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : Fooable, τ_0_0.Bar == X> (@in τ_0_0, @in_guaranteed Foo) -> @out X
 struct Foo: Fooable {
   typealias Bar = X
 
@@ -19,7 +19,7 @@
 }
 
 // rdar://problem/19049566
-// CHECK-LABEL: sil [transparent] [thunk] @_T017witness_same_type14LazySequenceOfVyxq_Gs0E0AAsAERz8Iterator_7ElementQZRs_r0_lsAEP04makeG0AFQzyFTW : $@convention(witness_method) <τ_0_0, τ_0_1 where τ_0_0 : Sequence, τ_0_1 == τ_0_0.Iterator.Element> (@in_guaranteed LazySequenceOf<τ_0_0, τ_0_1>) -> @out AnyIterator<τ_0_1>
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @_T017witness_same_type14LazySequenceOfVyxq_Gs0E0AAsAERz8Iterator_7ElementQZRs_r0_lsAEP04makeG0AFQzyFTW : $@convention(witness_method) <τ_0_0, τ_0_1 where τ_0_0 : Sequence, τ_0_1 == τ_0_0.Iterator.Element> (@in_guaranteed LazySequenceOf<τ_0_0, τ_0_1>) -> @out AnyIterator<τ_0_1>
 public struct LazySequenceOf<SS : Sequence, A where SS.Iterator.Element == A> : Sequence {
   public func makeIterator() -> AnyIterator<A> { 
     var opt: AnyIterator<A>?
diff --git a/test/SILGen/witness_single_tuple.swift b/test/SILGen/witness_single_tuple.swift
index e9ff59d..f8a1e28 100644
--- a/test/SILGen/witness_single_tuple.swift
+++ b/test/SILGen/witness_single_tuple.swift
@@ -4,7 +4,7 @@
   func runce(x: Int)
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T020witness_single_tuple3FooVAA8RuncibleA2aDP5runce{{[_0-9a-zA-Z]*}}FTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T020witness_single_tuple3FooVAA8RuncibleA2aDP5runce{{[_0-9a-zA-Z]*}}FTW
 struct Foo: Runcible {
   func runce(x: Int = 0) {}
 }
diff --git a/test/SILGen/witness_tables.swift b/test/SILGen/witness_tables.swift
index 5851efc..5931534 100644
--- a/test/SILGen/witness_tables.swift
+++ b/test/SILGen/witness_tables.swift
@@ -64,8 +64,8 @@
 // TABLE-TESTABLE-LABEL: sil_witness_table [serialized] ConformingAssoc: AssocReqt module witness_tables {
 // TABLE-ALL-NEXT:    method #AssocReqt.requiredMethod!1: {{.*}} : @_T014witness_tables15ConformingAssocVAA0D4ReqtA2aDP14requiredMethod{{[_0-9a-zA-Z]*}}FTW
 // TABLE-ALL-NEXT:  }
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables15ConformingAssocVAA0D4ReqtA2aDP14requiredMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in_guaranteed ConformingAssoc) -> ()
-// SYMBOL-TESTABLE:      sil [transparent] [thunk] @_T014witness_tables15ConformingAssocVAA0D4ReqtA2aDP14requiredMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in_guaranteed ConformingAssoc) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables15ConformingAssocVAA0D4ReqtA2aDP14requiredMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in_guaranteed ConformingAssoc) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @_T014witness_tables15ConformingAssocVAA0D4ReqtA2aDP14requiredMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in_guaranteed ConformingAssoc) -> ()
 
 struct ConformingStruct : AnyProtocol {
   typealias AssocType = SomeAssoc
@@ -89,16 +89,16 @@
 // TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:  }
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW {{.*}}: ArchetypeReqt> (@in τ_0_0, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @thick ConformingStruct.Type) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @in ConformingStruct, @thick ConformingStruct.Type) -> ()
-// SYMBOL-TESTABLE:      sil [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
-// SYMBOL-TESTABLE:      sil [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
-// SYMBOL-TESTABLE:      sil [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingStruct) -> ()
-// SYMBOL-TESTABLE:      sil [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @thick ConformingStruct.Type) -> ()
-// SYMBOL-TESTABLE:      sil [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @in ConformingStruct, @thick ConformingStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW {{.*}}: ArchetypeReqt> (@in τ_0_0, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @thick ConformingStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @in ConformingStruct, @thick ConformingStruct.Type) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @thick ConformingStruct.Type) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @_T014witness_tables16ConformingStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @in ConformingStruct, @thick ConformingStruct.Type) -> ()
 
 protocol AddressOnly {}
 
@@ -126,11 +126,11 @@
 // TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:  }
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformingAddressOnlyStruct, @in_guaranteed ConformingAddressOnlyStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformingAddressOnlyStruct, @in_guaranteed ConformingAddressOnlyStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingAddressOnlyStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingAddressOnlyStruct, @thick ConformingAddressOnlyStruct.Type) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingAddressOnlyStruct, @in ConformingAddressOnlyStruct, @thick ConformingAddressOnlyStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformingAddressOnlyStruct, @in_guaranteed ConformingAddressOnlyStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformingAddressOnlyStruct, @in_guaranteed ConformingAddressOnlyStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingAddressOnlyStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingAddressOnlyStruct, @thick ConformingAddressOnlyStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingAddressOnlyStruct, @in ConformingAddressOnlyStruct, @thick ConformingAddressOnlyStruct.Type) -> ()
 
 class ConformingClass : AnyProtocol {
   typealias AssocType = SomeAssoc
@@ -154,11 +154,11 @@
 // TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:  }
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformingClass, @in_guaranteed ConformingClass) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformingClass, @in_guaranteed ConformingClass) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingClass) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingClass, @thick ConformingClass.Type) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingClass, @in ConformingClass, @thick ConformingClass.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformingClass, @in_guaranteed ConformingClass) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformingClass, @in_guaranteed ConformingClass) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingClass) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingClass, @thick ConformingClass.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables15ConformingClassCAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingClass, @in ConformingClass, @thick ConformingClass.Type) -> ()
 
 struct ConformsByExtension {}
 extension ConformsByExtension : AnyProtocol {
@@ -183,11 +183,11 @@
 // TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:  }
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformsByExtension, @in_guaranteed ConformsByExtension) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformsByExtension, @in_guaranteed ConformsByExtension) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformsByExtension) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsByExtension, @thick ConformsByExtension.Type) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsByExtension, @in ConformsByExtension, @thick ConformsByExtension.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformsByExtension, @in_guaranteed ConformsByExtension) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformsByExtension, @in_guaranteed ConformsByExtension) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformsByExtension) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsByExtension, @thick ConformsByExtension.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsByExtension, @in ConformsByExtension, @thick ConformsByExtension.Type) -> ()
 
 extension OtherModuleStruct : AnyProtocol {
   typealias AssocType = SomeAssoc
@@ -211,11 +211,11 @@
 // TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:  }
-// SYMBOL:      sil hidden [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in OtherModuleStruct, @in_guaranteed OtherModuleStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in OtherModuleStruct, @in_guaranteed OtherModuleStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed OtherModuleStruct) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in OtherModuleStruct, @thick OtherModuleStruct.Type) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in OtherModuleStruct, @in OtherModuleStruct, @thick OtherModuleStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in OtherModuleStruct, @in_guaranteed OtherModuleStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in OtherModuleStruct, @in_guaranteed OtherModuleStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed OtherModuleStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in OtherModuleStruct, @thick OtherModuleStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T016witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in OtherModuleStruct, @in OtherModuleStruct, @thick OtherModuleStruct.Type) -> ()
 
 protocol OtherProtocol {}
 
@@ -241,11 +241,11 @@
 // TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:  }
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformsWithMoreGenericWitnesses, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformsWithMoreGenericWitnesses, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsWithMoreGenericWitnesses, @thick ConformsWithMoreGenericWitnesses.Type) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsWithMoreGenericWitnesses, @in ConformsWithMoreGenericWitnesses, @thick ConformsWithMoreGenericWitnesses.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ConformsWithMoreGenericWitnesses, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @in ConformsWithMoreGenericWitnesses, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsWithMoreGenericWitnesses, @thick ConformsWithMoreGenericWitnesses.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsWithMoreGenericWitnesses, @in ConformsWithMoreGenericWitnesses, @thick ConformsWithMoreGenericWitnesses.Type) -> ()
 
 class ConformingClassToClassProtocol : ClassProtocol {
   typealias AssocType = SomeAssoc
@@ -270,11 +270,11 @@
 // TABLE-NEXT:    method #ClassProtocol.staticMethod!1: {{.*}} : @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:    method #ClassProtocol."<~>"!1: {{.*}} : @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
 // TABLE-NEXT:  }
-// SYMBOL:  sil hidden [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @owned ConformingClassToClassProtocol, @guaranteed ConformingClassToClassProtocol) -> ()
-// SYMBOL:  sil hidden [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @owned ConformingClassToClassProtocol, @guaranteed ConformingClassToClassProtocol) -> ()
-// SYMBOL:  sil hidden [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @guaranteed ConformingClassToClassProtocol) -> ()
-// SYMBOL:  sil hidden [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@owned ConformingClassToClassProtocol, @thick ConformingClassToClassProtocol.Type) -> ()
-// SYMBOL:  sil hidden [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@owned ConformingClassToClassProtocol, @owned ConformingClassToClassProtocol, @thick ConformingClassToClassProtocol.Type) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @owned ConformingClassToClassProtocol, @guaranteed ConformingClassToClassProtocol) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in τ_0_0, @owned ConformingClassToClassProtocol, @guaranteed ConformingClassToClassProtocol) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in SomeAssoc, @in ConformingAssoc, @guaranteed ConformingClassToClassProtocol) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@owned ConformingClassToClassProtocol, @thick ConformingClassToClassProtocol.Type) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @_T014witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@owned ConformingClassToClassProtocol, @owned ConformingClassToClassProtocol, @thick ConformingClassToClassProtocol.Type) -> ()
 
 class ConformingClassToObjCProtocol : ObjCProtocol {
   @objc func method(x x: ObjCClass) {}
@@ -467,8 +467,8 @@
 //    AnyProtocol has no class bound, so its witnesses treat Self as opaque.
 //    InheritedClassProtocol has a class bound, so its witnesses treat Self as
 //    a reference value.
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables25ClassInheritedConformanceCAA0dC8ProtocolA2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@guaranteed ClassInheritedConformance) -> ()
-// SYMBOL:      sil hidden [transparent] [thunk] @_T014witness_tables25ClassInheritedConformanceCAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ClassInheritedConformance, @in_guaranteed ClassInheritedConformance) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables25ClassInheritedConformanceCAA0dC8ProtocolA2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@guaranteed ClassInheritedConformance) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @_T014witness_tables25ClassInheritedConformanceCAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Arg, @in ClassInheritedConformance, @in_guaranteed ClassInheritedConformance) -> ()
 
 struct GenericAssocType<T> : AssocReqt {
   func requiredMethod() {}
@@ -525,7 +525,7 @@
 // TABLE-LABEL: sil_witness_table hidden HasInitializerStruct: Initializer module witness_tables {
 // TABLE-NEXT:  method #Initializer.init!allocator.1: {{.*}} : @_T014witness_tables20HasInitializerStructVAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW
 // TABLE-NEXT: }
-// SYMBOL: sil hidden [transparent] [thunk] @_T014witness_tables20HasInitializerStructVAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Arg, @thick HasInitializerStruct.Type) -> @out HasInitializerStruct
+// SYMBOL: sil private [transparent] [thunk] @_T014witness_tables20HasInitializerStructVAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Arg, @thick HasInitializerStruct.Type) -> @out HasInitializerStruct
 struct HasInitializerStruct : Initializer { 
   init(arg: Arg) { }
 }
@@ -533,7 +533,7 @@
 // TABLE-LABEL: sil_witness_table hidden HasInitializerClass: Initializer module witness_tables {
 // TABLE-NEXT:  method #Initializer.init!allocator.1: {{.*}} : @_T014witness_tables19HasInitializerClassCAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW
 // TABLE-NEXT: }
-// SYMBOL: sil hidden [transparent] [thunk] @_T014witness_tables19HasInitializerClassCAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Arg, @thick HasInitializerClass.Type) -> @out HasInitializerClass
+// SYMBOL: sil private [transparent] [thunk] @_T014witness_tables19HasInitializerClassCAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Arg, @thick HasInitializerClass.Type) -> @out HasInitializerClass
 class HasInitializerClass : Initializer {
   required init(arg: Arg) { }
 }
@@ -541,7 +541,7 @@
 // TABLE-LABEL: sil_witness_table hidden HasInitializerEnum: Initializer module witness_tables {
 // TABLE-NEXT:  method #Initializer.init!allocator.1: {{.*}} : @_T014witness_tables18HasInitializerEnumOAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW
 // TABLE-NEXT: }
-// SYMBOL: sil hidden [transparent] [thunk] @_T014witness_tables18HasInitializerEnumOAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Arg, @thick HasInitializerEnum.Type) -> @out HasInitializerEnum
+// SYMBOL: sil private [transparent] [thunk] @_T014witness_tables18HasInitializerEnumOAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Arg, @thick HasInitializerEnum.Type) -> @out HasInitializerEnum
 enum HasInitializerEnum : Initializer {
   case A
 
diff --git a/test/SILGen/witnesses.swift b/test/SILGen/witnesses.swift
index 4071912..5c446f6 100644
--- a/test/SILGen/witnesses.swift
+++ b/test/SILGen/witnesses.swift
@@ -98,7 +98,7 @@
 struct ConformingStruct : X {
   mutating
   func selfTypes(x: ConformingStruct) -> ConformingStruct { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in ConformingStruct, @inout ConformingStruct) -> @out ConformingStruct {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in ConformingStruct, @inout ConformingStruct) -> @out ConformingStruct {
   // CHECK:       bb0(%0 : $*ConformingStruct, %1 : $*ConformingStruct, %2 : $*ConformingStruct):
   // CHECK-NEXT:    %3 = load [trivial] %1 : $*ConformingStruct
   // CHECK-NEXT:    // function_ref
@@ -111,7 +111,7 @@
   
   mutating
   func loadable(x: Loadable) -> Loadable { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP8loadable{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Loadable, @inout ConformingStruct) -> Loadable {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP8loadable{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Loadable, @inout ConformingStruct) -> Loadable {
   // CHECK:       bb0(%0 : $Loadable, %1 : $*ConformingStruct):
   // CHECK-NEXT:    // function_ref
   // CHECK-NEXT:    %2 = function_ref @_T09witnesses16ConformingStructV8loadable{{[_0-9a-zA-Z]*}}F : $@convention(method) (Loadable, @inout ConformingStruct) -> Loadable
@@ -121,7 +121,7 @@
   
   mutating
   func addrOnly(x: AddrOnly) -> AddrOnly { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP8addrOnly{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in AddrOnly, @inout ConformingStruct) -> @out AddrOnly {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP8addrOnly{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in AddrOnly, @inout ConformingStruct) -> @out AddrOnly {
   // CHECK:       bb0(%0 : $*AddrOnly, %1 : $*AddrOnly, %2 : $*ConformingStruct):
   // CHECK-NEXT:    // function_ref
   // CHECK-NEXT:    %3 = function_ref @_T09witnesses16ConformingStructV8addrOnly{{[_0-9a-zA-Z]*}}F : $@convention(method) (@in AddrOnly, @inout ConformingStruct) -> @out AddrOnly
@@ -132,7 +132,7 @@
   
   mutating
   func generic<C>(x: C) -> C { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0> (@in τ_0_0, @inout ConformingStruct) -> @out τ_0_0 {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0> (@in τ_0_0, @inout ConformingStruct) -> @out τ_0_0 {
   // CHECK:       bb0(%0 : $*τ_0_0, %1 : $*τ_0_0, %2 : $*ConformingStruct):
   // CHECK-NEXT:    // function_ref
   // CHECK-NEXT:    %3 = function_ref @_T09witnesses16ConformingStructV7generic{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in τ_0_0, @inout ConformingStruct) -> @out τ_0_0
@@ -142,7 +142,7 @@
   // CHECK-NEXT:  }
   mutating
   func classes<C2: Classes>(x: C2) -> C2 { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP7classes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : Classes> (@owned τ_0_0, @inout ConformingStruct) -> @owned τ_0_0 {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP7classes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : Classes> (@owned τ_0_0, @inout ConformingStruct) -> @owned τ_0_0 {
   // CHECK:       bb0(%0 : $τ_0_0, %1 : $*ConformingStruct):
   // CHECK-NEXT:    // function_ref
   // CHECK-NEXT:    %2 = function_ref @_T09witnesses16ConformingStructV7classes{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0 where τ_0_0 : Classes> (@owned τ_0_0, @inout ConformingStruct) -> @owned τ_0_0
@@ -151,7 +151,7 @@
   // CHECK-NEXT:  }
 }
 func <~>(_ x: ConformingStruct, y: ConformingStruct) -> ConformingStruct { return x }
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @in ConformingStruct, @thick ConformingStruct.Type) -> @out ConformingStruct {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16ConformingStructVAA1XA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformingStruct, @in ConformingStruct, @thick ConformingStruct.Type) -> @out ConformingStruct {
 // CHECK:       bb0([[ARG1:%.*]] : $*ConformingStruct, [[ARG2:%.*]] : $*ConformingStruct, [[ARG3:%.*]] : $*ConformingStruct, [[ARG4:%.*]] : $@thick ConformingStruct.Type):
 // CHECK-NEXT:    [[LOADED_ARG2:%.*]] = load [trivial] [[ARG2]] : $*ConformingStruct
 // CHECK-NEXT:    [[LOADED_ARG3:%.*]] = load [trivial] [[ARG3]] : $*ConformingStruct
@@ -165,7 +165,7 @@
 
 final class ConformingClass : X {
   func selfTypes(x: ConformingClass) -> ConformingClass { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses15ConformingClassCAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in ConformingClass, @inout ConformingClass) -> @out ConformingClass {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses15ConformingClassCAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in ConformingClass, @inout ConformingClass) -> @out ConformingClass {
   // CHECK:  bb0([[ARG1:%.*]] : $*ConformingClass, [[ARG2:%.*]] : $*ConformingClass, [[ARG3:%.*]] : $*ConformingClass):
   // -- load and copy_value 'self' from inout witness 'self' parameter
   // CHECK:    [[ARG3_LOADED:%.*]] = load [copy] [[ARG3]] : $*ConformingClass
@@ -185,7 +185,7 @@
 func <~>(_ x: ConformingClass, y: ConformingClass) -> ConformingClass { return x }
 
 extension ConformingClass : ClassBounded { }
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses15ConformingClassCAA0C7BoundedA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@owned ConformingClass, @guaranteed ConformingClass) -> @owned ConformingClass {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses15ConformingClassCAA0C7BoundedA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@owned ConformingClass, @guaranteed ConformingClass) -> @owned ConformingClass {
 // CHECK:  bb0([[C0:%.*]] : $ConformingClass, [[C1:%.*]] : $ConformingClass):
 // CHECK-NEXT:    [[C1_COPY:%.*]] = copy_value [[C1]]
 // CHECK-NEXT:    function_ref
@@ -202,7 +202,7 @@
 
   mutating
   func selfTypes(x: ConformingAOStruct) -> ConformingAOStruct { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses18ConformingAOStructVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in ConformingAOStruct, @inout ConformingAOStruct) -> @out ConformingAOStruct {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses18ConformingAOStructVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in ConformingAOStruct, @inout ConformingAOStruct) -> @out ConformingAOStruct {
   // CHECK:       bb0(%0 : $*ConformingAOStruct, %1 : $*ConformingAOStruct, %2 : $*ConformingAOStruct):
   // CHECK-NEXT:    // function_ref
   // CHECK-NEXT:    %3 = function_ref @_T09witnesses18ConformingAOStructV9selfTypes{{[_0-9a-zA-Z]*}}F : $@convention(method) (@in ConformingAOStruct, @inout ConformingAOStruct) -> @out ConformingAOStruct
@@ -220,7 +220,7 @@
 struct ConformsWithMoreGeneric : X, Y {
   mutating
   func selfTypes<E>(x: E) -> E { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in ConformsWithMoreGeneric, @inout ConformsWithMoreGeneric) -> @out ConformsWithMoreGeneric {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in ConformsWithMoreGeneric, @inout ConformsWithMoreGeneric) -> @out ConformsWithMoreGeneric {
   // CHECK:       bb0(%0 : $*ConformsWithMoreGeneric, %1 : $*ConformsWithMoreGeneric, %2 : $*ConformsWithMoreGeneric):
   // CHECK-NEXT:    // function_ref
   // CHECK-NEXT:    [[WITNESS_FN:%.*]] = function_ref @_T09witnesses23ConformsWithMoreGenericV9selfTypes{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
@@ -231,7 +231,7 @@
   func loadable<F>(x: F) -> F { return x }
   mutating
   func addrOnly<G>(x: G) -> G { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP8addrOnly{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in AddrOnly, @inout ConformsWithMoreGeneric) -> @out AddrOnly {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP8addrOnly{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in AddrOnly, @inout ConformsWithMoreGeneric) -> @out AddrOnly {
   // CHECK:       bb0(%0 : $*AddrOnly, %1 : $*AddrOnly, %2 : $*ConformsWithMoreGeneric):
   // CHECK-NEXT:    // function_ref
   // CHECK-NEXT:    %3 = function_ref @_T09witnesses23ConformsWithMoreGenericV8addrOnly{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
@@ -242,7 +242,7 @@
 
   mutating
   func generic<H>(x: H) -> H { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0> (@in τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0 {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0> (@in τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0 {
   // CHECK:       bb0(%0 : $*τ_0_0, %1 : $*τ_0_0, %2 : $*ConformsWithMoreGeneric):
   // CHECK-NEXT:    // function_ref
   // CHECK-NEXT:    %3 = function_ref @_T09witnesses23ConformsWithMoreGenericV7generic{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
@@ -253,7 +253,7 @@
 
   mutating
   func classes<I>(x: I) -> I { return x }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP7classes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : Classes> (@owned τ_0_0, @inout ConformsWithMoreGeneric) -> @owned τ_0_0 {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP7classes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : Classes> (@owned τ_0_0, @inout ConformsWithMoreGeneric) -> @owned τ_0_0 {
   // CHECK:       bb0(%0 : $τ_0_0, %1 : $*ConformsWithMoreGeneric):
   // CHECK-NEXT:    [[SELF_BOX:%.*]] = alloc_stack $τ_0_0
   // CHECK-NEXT:    store %0 to [init] [[SELF_BOX]] : $*τ_0_0
@@ -268,7 +268,7 @@
   // CHECK-NEXT:  }
 }
 func <~> <J: Y, K: Y>(_ x: J, y: K) -> K { return y }
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsWithMoreGeneric, @in ConformsWithMoreGeneric, @thick ConformsWithMoreGeneric.Type) -> @out ConformsWithMoreGeneric {
+// CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses23ConformsWithMoreGenericVAA1XA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method) (@in ConformsWithMoreGeneric, @in ConformsWithMoreGeneric, @thick ConformsWithMoreGeneric.Type) -> @out ConformsWithMoreGeneric {
 // CHECK:       bb0(%0 : $*ConformsWithMoreGeneric, %1 : $*ConformsWithMoreGeneric, %2 : $*ConformsWithMoreGeneric, %3 : $@thick ConformsWithMoreGeneric.Type):
 // CHECK-NEXT:    // function_ref
 // CHECK-NEXT:    [[WITNESS_FN:%.*]] = function_ref @_T09witnesses3ltgoi{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Y, τ_0_1 : Y> (@in τ_0_0, @in τ_0_1) -> @out τ_0_1
@@ -282,7 +282,7 @@
 }
 
 struct UnlabeledWitness : LabeledRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16UnlabeledWitnessVAA18LabeledRequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Loadable, @in_guaranteed UnlabeledWitness) -> ()
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16UnlabeledWitnessVAA18LabeledRequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Loadable, @in_guaranteed UnlabeledWitness) -> ()
   func method(x _: Loadable) {}
 }
 
@@ -291,7 +291,7 @@
 }
 
 struct UnlabeledSelfWitness : LabeledSelfRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses20UnlabeledSelfWitnessVAA07LabeledC11RequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in UnlabeledSelfWitness, @in_guaranteed UnlabeledSelfWitness) -> ()
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses20UnlabeledSelfWitnessVAA07LabeledC11RequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in UnlabeledSelfWitness, @in_guaranteed UnlabeledSelfWitness) -> ()
   func method(x _: UnlabeledSelfWitness) {}
 }
 
@@ -300,7 +300,7 @@
 }
 
 struct LabeledWitness : UnlabeledRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses14LabeledWitnessVAA20UnlabeledRequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Loadable, @in_guaranteed LabeledWitness) -> ()
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses14LabeledWitnessVAA20UnlabeledRequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (Loadable, @in_guaranteed LabeledWitness) -> ()
   func method(x: Loadable) {}
 }
 
@@ -309,7 +309,7 @@
 }
 
 struct LabeledSelfWitness : UnlabeledSelfRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses18LabeledSelfWitnessVAA09UnlabeledC11RequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in LabeledSelfWitness, @in_guaranteed LabeledSelfWitness) -> ()
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses18LabeledSelfWitnessVAA09UnlabeledC11RequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method) (@in LabeledSelfWitness, @in_guaranteed LabeledSelfWitness) -> ()
   func method(_ x: LabeledSelfWitness) {}
 }
 
@@ -319,9 +319,9 @@
 }
 
 struct ImmutableModel: ReadOnlyRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses14ImmutableModelVAA19ReadOnlyRequirementA2aDP4propSSfgTW : $@convention(witness_method) (@in_guaranteed ImmutableModel) -> @owned String
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses14ImmutableModelVAA19ReadOnlyRequirementA2aDP4propSSfgTW : $@convention(witness_method) (@in_guaranteed ImmutableModel) -> @owned String
   let prop: String = "a"
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses14ImmutableModelVAA19ReadOnlyRequirementA2aDP4propSSfgZTW : $@convention(witness_method) (@thick ImmutableModel.Type) -> @owned String
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses14ImmutableModelVAA19ReadOnlyRequirementA2aDP4propSSfgZTW : $@convention(witness_method) (@thick ImmutableModel.Type) -> @owned String
   static let prop: String = "b"
 }
 
@@ -338,16 +338,16 @@
 }
 
 struct NonFailableModel: FailableRequirement, NonFailableRefinement, IUOFailableRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16NonFailableModelVAA0C11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableModel.Type) -> @out Optional<NonFailableModel>
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16NonFailableModelVAA0bC10Refinement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableModel.Type) -> @out NonFailableModel
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16NonFailableModelVAA22IUOFailableRequirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableModel.Type) -> @out Optional<NonFailableModel>
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16NonFailableModelVAA0C11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableModel.Type) -> @out Optional<NonFailableModel>
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16NonFailableModelVAA0bC10Refinement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableModel.Type) -> @out NonFailableModel
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16NonFailableModelVAA22IUOFailableRequirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableModel.Type) -> @out Optional<NonFailableModel>
   init(foo: Int) {}
 }
 
 struct FailableModel: FailableRequirement, IUOFailableRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses13FailableModelVAA0B11Requirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses13FailableModelVAA0B11Requirement{{[_0-9a-zA-Z]*}}fCTW
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses13FailableModelVAA22IUOFailableRequirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses13FailableModelVAA22IUOFailableRequirement{{[_0-9a-zA-Z]*}}fCTW
   // CHECK: bb0([[SELF:%[0-9]+]] : $*Optional<FailableModel>, [[FOO:%[0-9]+]] : $Int, [[META:%[0-9]+]] : $@thick FailableModel.Type):
   // CHECK: [[FN:%.*]] = function_ref @_T09witnesses13FailableModelV{{[_0-9a-zA-Z]*}}fC
   // CHECK: [[INNER:%.*]] = apply [[FN]](
@@ -357,7 +357,7 @@
 }
 
 struct IUOFailableModel : NonFailableRefinement, IUOFailableRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16IUOFailableModelVAA21NonFailableRefinement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16IUOFailableModelVAA21NonFailableRefinement{{[_0-9a-zA-Z]*}}fCTW
   // CHECK: bb0([[SELF:%[0-9]+]] : $*IUOFailableModel, [[FOO:%[0-9]+]] : $Int, [[META:%[0-9]+]] : $@thick IUOFailableModel.Type):
   // CHECK:   [[META:%[0-9]+]] = metatype $@thin IUOFailableModel.Type
   // CHECK:   [[INIT:%[0-9]+]] = function_ref @_T09witnesses16IUOFailableModelV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Int, @thin IUOFailableModel.Type) -> Optional<IUOFailableModel>
@@ -381,16 +381,16 @@
 }
 
 final class NonFailableClassModel: FailableClassRequirement, NonFailableClassRefinement, IUOFailableClassRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses21NonFailableClassModelCAA0cD11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableClassModel.Type) -> @owned Optional<NonFailableClassModel>
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses21NonFailableClassModelCAA0bcD10Refinement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableClassModel.Type) -> @owned NonFailableClassModel
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses21NonFailableClassModelCAA011IUOFailableD11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableClassModel.Type) -> @owned Optional<NonFailableClassModel>
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses21NonFailableClassModelCAA0cD11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableClassModel.Type) -> @owned Optional<NonFailableClassModel>
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses21NonFailableClassModelCAA0bcD10Refinement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableClassModel.Type) -> @owned NonFailableClassModel
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses21NonFailableClassModelCAA011IUOFailableD11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method) (Int, @thick NonFailableClassModel.Type) -> @owned Optional<NonFailableClassModel>
   init(foo: Int) {}
 }
 
 final class FailableClassModel: FailableClassRequirement, IUOFailableClassRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses18FailableClassModelCAA0bC11Requirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses18FailableClassModelCAA0bC11Requirement{{[_0-9a-zA-Z]*}}fCTW
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses18FailableClassModelCAA011IUOFailableC11Requirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses18FailableClassModelCAA011IUOFailableC11Requirement{{[_0-9a-zA-Z]*}}fCTW
   // CHECK: [[FUNC:%.*]] = function_ref @_T09witnesses18FailableClassModelC{{[_0-9a-zA-Z]*}}fC
   // CHECK: [[INNER:%.*]] = apply [[FUNC]](%0, %1)
   // CHECK: return [[INNER]] : $Optional<FailableClassModel>
@@ -398,7 +398,7 @@
 }
 
 final class IUOFailableClassModel: NonFailableClassRefinement, IUOFailableClassRequirement {
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses21IUOFailableClassModelCAA011NonFailableC10Refinement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses21IUOFailableClassModelCAA011NonFailableC10Refinement{{[_0-9a-zA-Z]*}}fCTW
   // CHECK: bb0({{.*}}):
   // CHECK:   [[FUNC:%.*]] = function_ref @_T09witnesses21IUOFailableClassModelCSQyACGSi3foo_tcfC : $@convention(method) (Int, @thick IUOFailableClassModel.Type) -> @owned Optional<IUOFailableClassModel>
   // CHECK:   [[VALUE:%.*]] = apply [[FUNC]]({{.*}})
@@ -411,10 +411,10 @@
   // CHECK: return [[RESULT]] : $IUOFailableClassModel
   // CHECK: } // end sil function '_T09witnesses21IUOFailableClassModelCAA011NonFailableC10Refinement{{[_0-9a-zA-Z]*}}fCTW'
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses21IUOFailableClassModelCAA0bC11Requirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses21IUOFailableClassModelCAA0bC11Requirement{{[_0-9a-zA-Z]*}}fCTW
   init!(foo: Int) {}
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses21IUOFailableClassModelCAA08FailableC11Requirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses21IUOFailableClassModelCAA08FailableC11Requirement{{[_0-9a-zA-Z]*}}fCTW
   // CHECK: [[FUNC:%.*]] = function_ref @_T09witnesses21IUOFailableClassModelC{{[_0-9a-zA-Z]*}}fC
   // CHECK: [[INNER:%.*]] = apply [[FUNC]](%0, %1)
   // CHECK: return [[INNER]] : $Optional<IUOFailableClassModel>
@@ -433,12 +433,12 @@
 struct GenericParameterNameCollision<T: HasAssoc> :
     GenericParameterNameCollisionProtocol {
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses29GenericParameterNameCollisionVyxGAA0bcdE8ProtocolA2A8HasAssocRzlAaEP3fooyqd__lFTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : HasAssoc><τ_1_0> (@in τ_1_0, @in_guaranteed GenericParameterNameCollision<τ_0_0>) -> () {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses29GenericParameterNameCollisionVyxGAA0bcdE8ProtocolA2A8HasAssocRzlAaEP3fooyqd__lFTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : HasAssoc><τ_1_0> (@in τ_1_0, @in_guaranteed GenericParameterNameCollision<τ_0_0>) -> () {
   // CHECK:       bb0(%0 : $*τ_1_0, %1 : $*GenericParameterNameCollision<τ_0_0>):
   // CHECK:         apply {{%.*}}<τ_0_0, τ_1_0>
   func foo<U>(_ x: U) {}
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses29GenericParameterNameCollisionVyxGAA0bcdE8ProtocolA2A8HasAssocRzlAaEP3bary6Assoc2Qzqd__clFTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : HasAssoc><τ_1_0> (@owned @callee_owned (@in τ_1_0) -> @out τ_0_0.Assoc, @in_guaranteed GenericParameterNameCollision<τ_0_0>) -> () {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses29GenericParameterNameCollisionVyxGAA0bcdE8ProtocolA2A8HasAssocRzlAaEP3bary6Assoc2Qzqd__clFTW : $@convention(witness_method) <τ_0_0 where τ_0_0 : HasAssoc><τ_1_0> (@owned @callee_owned (@in τ_1_0) -> @out τ_0_0.Assoc, @in_guaranteed GenericParameterNameCollision<τ_0_0>) -> () {
   // CHECK:       bb0(%0 : $@callee_owned (@in τ_1_0) -> @out τ_0_0.Assoc, %1 : $*GenericParameterNameCollision<τ_0_0>):
   // CHECK:         apply {{%.*}}<τ_0_0, τ_1_0>
   func bar<V>(_ x: (V) -> T.Assoc) {}
@@ -462,7 +462,7 @@
 
   // If the witness is in a base class of the conforming class, make sure we have a bit_cast in there:
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP5widthSifmTW : {{.*}} {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP5widthSifmTW : {{.*}} {
   // CHECK: bb0({{.*}} : $Builtin.RawPointer, {{.*}} : $*Builtin.UnsafeValueBuffer, [[ARG2:%.*]] : $*PropertyRequirementWitnessFromBase):
   // CHECK-NEXT: [[ARG2_LOADED:%[0-9][0-9]*]] = load [copy] [[ARG2]]
   // CHECK-NEXT: [[CAST_ARG2_LOADED:%[0-9][0-9]*]] = upcast [[ARG2_LOADED]] : $PropertyRequirementWitnessFromBase to $PropertyRequirementBase
@@ -476,7 +476,7 @@
   // CHECK-NEXT: destroy_value [[ARG2_LOADED]]
   // CHECK-NEXT: return [[TUPLE]]
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP6heightSifmZTW : {{.*}} {
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP6heightSifmZTW : {{.*}} {
   // CHECK: [[OBJ:%.*]] = upcast %2 : $@thick PropertyRequirementWitnessFromBase.Type to $@thick PropertyRequirementBase.Type
   // CHECK: [[METH:%.*]] = function_ref @_T09witnesses23PropertyRequirementBaseC6heightSifmZ
   // CHECK-NEXT: [[RES:%.*]] = apply [[METH]]
@@ -485,7 +485,7 @@
   // CHECK-NEXT: [[TUPLE:%.*]] = tuple ([[CAR]] : {{.*}}, [[CADR]] : {{.*}})
   // CHECK-NEXT: return [[TUPLE]]
 
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP5depthSifmTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP5depthSifmTW
   // CHECK: bb0({{.*}} : $Builtin.RawPointer, {{.*}} : $*Builtin.UnsafeValueBuffer, [[ARG2:%.*]] : $*PropertyRequirementWitnessFromBase):
   // CHECK: [[ARG2_LOADED:%[0-9][0-9]*]] = load [copy] [[ARG2]]
   // CHECK: [[METH:%.*]] = class_method [[ARG2_LOADED]] : $PropertyRequirementWitnessFromBase, #PropertyRequirementWitnessFromBase.depth!materializeForSet.1
@@ -507,7 +507,7 @@
   func crash() {}
 }
 
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T09witnesses16GenericCrashableCyxGAA0C0AAlAaEP5crashyyFTW : $@convention(witness_method) <τ_0_0> (@in_guaranteed GenericCrashable<τ_0_0>) -> ()
+// CHECK-LABEL: sil private [transparent] [thunk] @_T09witnesses16GenericCrashableCyxGAA0C0AAlAaEP5crashyyFTW : $@convention(witness_method) <τ_0_0> (@in_guaranteed GenericCrashable<τ_0_0>) -> ()
 // CHECK:       bb0(%0 : $*GenericCrashable<τ_0_0>):
 // CHECK-NEXT: [[BOX:%.*]] = alloc_stack $GenericCrashable<τ_0_0>
 // CHECK-NEXT: copy_addr %0 to [initialization] [[BOX]] : $*GenericCrashable<τ_0_0>
diff --git a/test/SILGen/witnesses_class.swift b/test/SILGen/witnesses_class.swift
index ee3e9ad..55dd943 100644
--- a/test/SILGen/witnesses_class.swift
+++ b/test/SILGen/witnesses_class.swift
@@ -9,17 +9,17 @@
 class Foo: Fooable {
   
   func foo() { }
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T015witnesses_class3FooCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T015witnesses_class3FooCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
   // CHECK-NOT:     function_ref
   // CHECK:         class_method
 
   class func bar() {}
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T015witnesses_class3FooCAA7FooableA2aDP3bar{{[_0-9a-zA-Z]*}}FZTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T015witnesses_class3FooCAA7FooableA2aDP3bar{{[_0-9a-zA-Z]*}}FZTW
   // CHECK-NOT:     function_ref
   // CHECK:         class_method
 
   required init() {}
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T015witnesses_class3FooCAA7FooableA2aDP{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T015witnesses_class3FooCAA7FooableA2aDP{{[_0-9a-zA-Z]*}}fCTW
   // CHECK-NOT:     function_ref
   // CHECK:         class_method
 }
diff --git a/test/SILGen/witnesses_inheritance.swift b/test/SILGen/witnesses_inheritance.swift
index 79e086f..e478953 100644
--- a/test/SILGen/witnesses_inheritance.swift
+++ b/test/SILGen/witnesses_inheritance.swift
@@ -18,9 +18,9 @@
 // -- Derived class conforms to a refined protocol
 class Y : X, Barrable {
   func bar() {}
-  // CHECK-NOT: sil hidden [transparent] [thunk] @_T021witnesses_inheritance1YCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
+  // CHECK-NOT: sil private [transparent] [thunk] @_T021witnesses_inheritance1YCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
   class func class_bar() {}
-  // CHECK-LABEL: sil hidden [transparent] [thunk] @_T021witnesses_inheritance1YCAA8BarrableA2aDP9class_bar{{[_0-9a-zA-Z]*}}FZTW
+  // CHECK-LABEL: sil private [transparent] [thunk] @_T021witnesses_inheritance1YCAA8BarrableA2aDP9class_bar{{[_0-9a-zA-Z]*}}FZTW
 }
 
 class A : Fooable {
@@ -32,16 +32,16 @@
 
 // -- Derived class conforms to a refined protocol using its base's methods
 class B : A, Barrable {}
-// CHECK-NOT: sil hidden [transparent] [thunk] @_T021witnesses_inheritance1BCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
-// CHECK-NOT: sil hidden [transparent] [thunk] @_T021witnesses_inheritance1BCAA7FooableA2aDP9class_foo{{[_0-9a-zA-Z]*}}FZTW
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T021witnesses_inheritance1BCAA8BarrableA2aDP3bar{{[_0-9a-zA-Z]*}}FTW
+// CHECK-NOT: sil private [transparent] [thunk] @_T021witnesses_inheritance1BCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
+// CHECK-NOT: sil private [transparent] [thunk] @_T021witnesses_inheritance1BCAA7FooableA2aDP9class_foo{{[_0-9a-zA-Z]*}}FZTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T021witnesses_inheritance1BCAA8BarrableA2aDP3bar{{[_0-9a-zA-Z]*}}FTW
 // CHECK:         [[B:%.*]] = load [take] {{%.*}} : $*B
 // CHECK-NEXT:    [[A:%.*]] = upcast [[B]] : $B to $A
 // CHECK-NEXT:    [[BORROWED_A:%.*]] = begin_borrow [[A]]
 // CHECK-NEXT:    [[METH:%.*]] = class_method [[BORROWED_A]] : $A, #A.bar!1
 // CHECK-NEXT:    apply [[METH]]([[BORROWED_A]]) : $@convention(method) (@guaranteed A) -> ()
 // CHECK:         end_borrow [[BORROWED_A]] from [[A]]
-// CHECK-LABEL: sil hidden [transparent] [thunk] @_T021witnesses_inheritance1BCAA8BarrableA2aDP9class_bar{{[_0-9a-zA-Z]*}}FZTW
+// CHECK-LABEL: sil private [transparent] [thunk] @_T021witnesses_inheritance1BCAA8BarrableA2aDP9class_bar{{[_0-9a-zA-Z]*}}FZTW
 // CHECK:         upcast {{%.*}} : $@thick B.Type to $@thick A.Type
 
 // Add tests to make sure that we handle address only case correctly.
diff --git a/test/SILOptimizer/allocbox_to_stack.sil b/test/SILOptimizer/allocbox_to_stack.sil
index 385dc0f..efe9b53 100644
--- a/test/SILOptimizer/allocbox_to_stack.sil
+++ b/test/SILOptimizer/allocbox_to_stack.sil
@@ -191,8 +191,8 @@
 // CHECK:  %2 = alloc_stack $LogicValue
   copy_addr [take] %0 to [initialization] %2a : $*LogicValue
   %6 = open_existential_addr mutable_access %2a : $*LogicValue to $*@opened("01234567-89ab-cdef-0123-000000000000") LogicValue
-  %7 = witness_method $@opened("01234567-89ab-cdef-0123-000000000000") LogicValue, #LogicValue.getLogicValue!1, %6 : $*@opened("01234567-89ab-cdef-0123-000000000000") LogicValue : $@convention(witness_method) @callee_owned <T: LogicValue> (@inout T) -> Bool
-  %8 = apply %7<@opened("01234567-89ab-cdef-0123-000000000000") LogicValue>(%6) : $@convention(witness_method) @callee_owned <T: LogicValue> (@inout T) -> Bool
+  %7 = witness_method $@opened("01234567-89ab-cdef-0123-000000000000") LogicValue, #LogicValue.getLogicValue!1, %6 : $*@opened("01234567-89ab-cdef-0123-000000000000") LogicValue : $@convention(witness_method) <T: LogicValue> (@in_guaranteed T) -> Bool
+  %8 = apply %7<@opened("01234567-89ab-cdef-0123-000000000000") LogicValue>(%6) : $@convention(witness_method) <T: LogicValue> (@in_guaranteed T) -> Bool
   strong_release %2 : ${ var LogicValue }
 // CHECK:  destroy_addr %2 : $*LogicValue
 // CHECK-NEXT:  dealloc_stack %2 : $*LogicValue
@@ -760,9 +760,9 @@
 // CHECK:      bb2:
 // CHECK:        store
 // CHECK:        [[STACK2:%[0-9]+]] = alloc_stack $Bool
-// CHECK-NEXT:   dealloc_stack [[STACK2]]
-// CHECK-NEXT:   dealloc_stack [[BOX]]
-// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK-NEXT:   dealloc_stack [[STACK2]] : $*Bool, loc "testloc":27:27
+// CHECK-NEXT:   dealloc_stack [[BOX]] : $*Int, loc "testloc":27:27
+// CHECK-NEXT:   dealloc_stack [[STACK1]] : $*Bool, loc "testloc":27:27
 // CHECK:      bb3:
 // CHECK-NEXT:   tuple
 // CHECK-NEXT:   return
@@ -784,7 +784,7 @@
   %3 = load %1a : $*Int
   %as2 = alloc_stack $Bool
   strong_release %1 : ${ var Int }
-  dealloc_stack %as2 : $*Bool
+  dealloc_stack %as2 : $*Bool, loc "testloc":27:27
   br bb3
 
 bb3:
@@ -948,6 +948,37 @@
   %5 = return %r : $()
 }
 
+// CHECK-LABEL: sil @nesting_and_unreachable5
+// CHECK:      bb0(%0 : $Int):
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK:      bb1:
+// CHECK-NEXT:   {{.*}} = alloc_stack $Bool
+// CHECK-NEXT:   {{.*}} = alloc_stack $Bool
+// CHECK-NEXT:   unreachable
+// CHECK:      bb2:
+// CHECK:        store
+// CHECK:        dealloc_stack [[BOX]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+sil @nesting_and_unreachable5 : $(Int) -> () {
+bb0(%0 : $Int):
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  cond_br undef, bb1, bb2
+
+bb1:
+  %as1 = alloc_stack $Bool
+  %as2 = alloc_stack $Bool
+  unreachable
+
+bb2:
+  %2 = store %0 to %1a : $*Int
+  %3 = load %1a : $*Int
+  strong_release %1 : ${ var Int }
+  %r = tuple ()
+  %5 = return %r : $()
+}
+
 // CHECK-LABEL: sil @nesting_and_unreachable_critical_edge
 // CHECK:      bb0(%0 : $Int):
 // CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
diff --git a/test/SILOptimizer/allocbox_to_stack_not_crash_ownership.swift b/test/SILOptimizer/allocbox_to_stack_not_crash_ownership.swift
new file mode 100644
index 0000000..229e973
--- /dev/null
+++ b/test/SILOptimizer/allocbox_to_stack_not_crash_ownership.swift
@@ -0,0 +1,15 @@
+// RUN: %target-swift-frontend %s -emit-ir -verify -enable-sil-ownership
+
+// Verify we don't crash on this.
+// rdar://15595118
+infix operator ~>
+protocol Target {}
+
+func ~> <Target, Arg0, Result>(x: inout Target, f: @escaping (_: inout Target, _: Arg0) -> Result) -> (Arg0) -> Result {
+  return { f(&x, $0) } // expected-error {{escaping closures can only capture inout parameters explicitly by value}}
+}
+
+func ~> (x: inout Int, f: @escaping (_: inout Int, _: Target) -> Target) -> (Target) -> Target {
+  return { f(&x, $0) } // expected-error {{escaping closures can only capture inout parameters explicitly by value}}
+}
+
diff --git a/test/SILOptimizer/allocbox_to_stack_ownership.sil b/test/SILOptimizer/allocbox_to_stack_ownership.sil
new file mode 100644
index 0000000..8d35505
--- /dev/null
+++ b/test/SILOptimizer/allocbox_to_stack_ownership.sil
@@ -0,0 +1,1026 @@
+// RUN: %target-sil-opt -enable-sil-ownership -enable-sil-verify-all %s -allocbox-to-stack | %FileCheck %s
+
+import Builtin
+
+struct Int {
+  var _value: Builtin.Int64
+}
+
+struct Bool {
+  var _value: Builtin.Int1
+}
+
+protocol Error {}
+
+// CHECK-LABEL: sil @simple_promotion
+sil @simple_promotion : $@convention(thin) (Int) -> Int {
+bb0(%0 : @trivial $Int):
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  %2 = store %0 to [trivial] %1a : $*Int
+
+  %3 = load [trivial] %1a : $*Int
+  destroy_value %1 : ${ var Int }
+  return %3 : $Int
+// CHECK: alloc_stack
+// CHECK-NOT: alloc_box
+// CHECK-NOT: destroy_value
+// CHECK: return
+}
+
+// CHECK-LABEL: sil @double_project_box
+sil @double_project_box : $@convention(thin) (Int) -> (Int, Int) {
+bb0(%0 : @trivial $Int):
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  %2 = store %0 to [trivial] %1a : $*Int
+  %3 = load [trivial] %1a : $*Int
+
+  %1b = project_box %1 : ${ var Int }, 0
+  %3b = load [trivial] %1b : $*Int
+  destroy_value %1 : ${ var Int }
+  %r = tuple (%3 : $Int, %3b : $Int)
+  return %r : $(Int, Int)
+
+// CHECK: alloc_stack
+// CHECK-NOT: alloc_box
+// CHECK-NOT: project_box
+// CHECK-NOT: destroy_value
+// CHECK: return
+}
+// CHECK-LABEL: sil @init_var
+sil @init_var : $@convention(thin) () -> Int {
+bb0:
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  %3 = load [trivial] %1a : $*Int
+  %4 = destroy_value %1 : ${ var Int }
+  %5 = return %3 : $Int
+
+// CHECK: %0 = alloc_stack
+// CHECK-NOT: alloc_box
+// CHECK-NOT: destroy_value
+// CHECK-NOT: destroy_addr
+// CHECK: dealloc_stack %0 : $*Int
+// CHECK: return
+}
+
+// CHECK-LABEL: sil @multi_destroy_value
+sil @multi_destroy_value : $@convention(thin) () -> Int {
+bb0:
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  %2 = mark_uninitialized [rootself] %1a : $*Int
+  %3 = load [trivial] %2 : $*Int
+  %x = copy_value %1 : ${ var Int }
+  destroy_value %1 : ${ var Int }
+  br bb1
+
+bb1:
+  destroy_value %x : ${ var Int }
+  %5 = return %3 : $Int
+
+// CHECK: %0 = alloc_stack
+// CHECK: bb1:
+// CHECK: dealloc_stack %0 : $*Int
+// CHECK: return
+}
+
+struct TestStruct {
+  var Elt : Int
+}
+
+// CHECK-LABEL: sil @struct_tuple_element_addr
+sil @struct_tuple_element_addr : $@convention(thin) (Int) -> Int {
+bb1(%0 : @trivial $Int):
+// CHECK-DAG: [[STRUCT:%.*]] = alloc_stack $TestStruct
+// CHECK-DAG: [[TUPLE:%.*]] = alloc_stack $(Int, Int)
+  %1 = alloc_box ${ var TestStruct }
+  %1a = project_box %1 : ${ var TestStruct }, 0
+  %a = alloc_box ${ var (Int, Int) }
+  %aa = project_box %a : ${ var (Int, Int) }, 0
+
+  %2 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
+  %3 = store %0 to [trivial] %2 : $*Int
+
+  %b = tuple_element_addr %aa : $*(Int, Int), 0
+  %c = store %0 to [trivial] %b : $*Int
+
+  %6 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
+  %7 = load [trivial] %6 : $*Int
+  destroy_value %a : ${ var (Int, Int) }
+  destroy_value %1 : ${ var TestStruct }
+
+  %9 = return %7 : $Int
+
+// CHECK-DAG: dealloc_stack [[STRUCT]]
+// CHECK-DAG: dealloc_stack [[TUPLE]]
+// CHECK: return
+}
+
+sil @callee : $@convention(thin) (@inout Int) -> ()
+
+// CHECK-LABEL: sil @inout_nocapture
+sil @inout_nocapture : $@convention(thin) () -> Int {
+bb0:
+  // CHECK: alloc_stack
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  %6 = function_ref @callee : $@convention(thin) (@inout Int) -> ()
+  %7 = apply %6(%1a) : $@convention(thin) (@inout Int) -> ()
+  %8 = load [trivial] %1a : $*Int
+  destroy_value %1 : ${ var Int }
+  %10 = address_to_pointer %1a : $*Int to $Builtin.RawPointer
+  %11 = pointer_to_address %10 : $Builtin.RawPointer to [strict] $*Int
+  %12 = load [trivial] %11 : $*Int
+  %13 = return %8 : $Int
+  // CHECK: return
+}
+
+protocol P {
+}
+
+sil @returns_protocol : $@convention(thin) () -> @out P
+
+// CHECK-LABEL: sil @test_indirect_return
+sil @test_indirect_return : $@convention(thin) () -> () {
+bb0:
+  // CHECK: alloc_stack
+  %1 = function_ref @returns_protocol : $@convention(thin) () -> @out P
+  %2 = alloc_box ${ var P }
+  %2a = project_box %2 : ${ var P }, 0
+  %3 = apply %1(%2a) : $@convention(thin) () -> @out P
+  destroy_value %2 : ${ var P }
+  %0 = tuple ()
+  %6 = return %0 : $()
+  // CHECK: return
+}
+
+class SomeClass {}
+
+// CHECK-LABEL: sil @class_promotion
+sil @class_promotion : $@convention(thin) (@owned SomeClass) -> @owned SomeClass {
+bb0(%0 : @owned $SomeClass):
+  %1 = alloc_box ${ var SomeClass }
+  %1a = project_box %1 : ${ var SomeClass }, 0
+  store %0 to [init] %1a : $*SomeClass
+  %3 = load [take] %1a : $*SomeClass
+  destroy_value %1 : ${ var SomeClass }
+  return %3 : $SomeClass
+
+// CHECK: %1 = alloc_stack
+// CHECK-NOT: alloc_box
+// CHECK-NOT: destroy_value
+// CHECK: destroy_addr {{.*}} : $*SomeClass
+// CHECK: return
+}
+
+protocol LogicValue {
+  func getLogicValue() -> Bool
+}
+
+// CHECK-LABEL: @protocols
+sil @protocols : $@convention(thin) (@in LogicValue, @thin Bool.Type) -> Bool {
+bb0(%0 : @trivial $*LogicValue, %1 : @trivial $@thin Bool.Type):
+  %2 = alloc_box ${ var LogicValue }
+  %2a = project_box %2 : ${ var LogicValue }, 0
+// CHECK:  %2 = alloc_stack $LogicValue
+  copy_addr [take] %0 to [initialization] %2a : $*LogicValue
+  %6 = open_existential_addr mutable_access %2a : $*LogicValue to $*@opened("01234567-89ab-cdef-0123-000000000000") LogicValue
+  %7 = witness_method $@opened("01234567-89ab-cdef-0123-000000000000") LogicValue, #LogicValue.getLogicValue!1, %6 : $*@opened("01234567-89ab-cdef-0123-000000000000") LogicValue : $@convention(witness_method) <T: LogicValue> (@in_guaranteed T) -> Bool
+  %8 = apply %7<@opened("01234567-89ab-cdef-0123-000000000000") LogicValue>(%6) : $@convention(witness_method) <T: LogicValue> (@in_guaranteed T) -> Bool
+  destroy_value %2 : ${ var LogicValue }
+// CHECK:  destroy_addr %2 : $*LogicValue
+// CHECK-NEXT:  dealloc_stack %2 : $*LogicValue
+// CHECK-NEXT:  return
+  return %8 : $Bool
+}
+
+
+// Generics test, which is address-only.
+class Generic<T> {}
+
+// CHECK-LABEL: sil @dealloc_box_test
+sil @dealloc_box_test : $@convention(thin) <T> () -> () {
+bb0:  // CHECK-NEXT: bb0:
+      // CHECK-NEXT: alloc_stack
+  %1 = alloc_box $<τ_0_0> { var Generic<τ_0_0> } <T>
+  dealloc_box %1 : $<τ_0_0> { var Generic<τ_0_0> } <T>
+
+  %0 = tuple ()    // CHECK: tuple ()
+  %6 = return %0 : $()
+  // CHECK: return
+}
+
+
+enum SomeUnion {
+  case x(Int)
+  case y(SomeClass)
+}
+
+
+
+sil @_T01t9SomeUnionO1yfMS0_FCS_9SomeClassS0_ : $@convention(thin) (@owned SomeClass, @thin SomeUnion.Type) -> @owned SomeUnion
+sil @_T01t9SomeClassCCfMS0_FT_S0_ : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass
+
+// CHECK-LABEL: sil @union_test
+sil @union_test : $@convention(thin) () -> () {
+bb0:
+// CHECK: [[UNION:%.*]] = alloc_stack
+  %1 = alloc_box ${ var SomeUnion }
+  %1a = project_box %1 : ${ var SomeUnion }, 0
+  %2 = function_ref @_T01t9SomeUnionO1yfMS0_FCS_9SomeClassS0_ : $@convention(thin) (@owned SomeClass, @thin SomeUnion.Type) -> @owned SomeUnion // user: %7
+  %3 = metatype $@thin SomeUnion.Type
+  %4 = function_ref @_T01t9SomeClassCCfMS0_FT_S0_ : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass // user: %6
+  %5 = metatype $@thick SomeClass.Type
+  %6 = apply %4(%5) : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass
+  %7 = apply %2(%6, %3) : $@convention(thin) (@owned SomeClass, @thin SomeUnion.Type) -> @owned SomeUnion
+  store %7 to [init] %1a : $*SomeUnion
+  destroy_value %1 : ${ var SomeUnion }
+  %10 = tuple ()
+  return %10 : $()
+// CHECK: dealloc_stack [[UNION]]
+// CHECK:  [[T0:%.*]] = tuple ()
+// CHECK-NEXT:  return [[T0]] : $()
+}
+
+// CHECK-LABEL: sil @multiple_destroy_test
+sil @multiple_destroy_test : $@convention(thin) (Bool) -> Bool {
+bb0(%0 : @trivial $Bool):
+  %1 = alloc_box ${ var Bool }
+  %1a = project_box %1 : ${ var Bool }, 0
+  store %0 to [trivial] %1a : $*Bool
+  %2 = copy_value %1 : ${ var Bool }
+  %3 = copy_value %1 : ${ var Bool }
+  %5 = tuple ()
+  %6 = load [trivial] %1a : $*Bool
+  destroy_value %3 : ${ var Bool }
+  destroy_value %2 : ${ var Bool }
+  destroy_value %1 : ${ var Bool }
+  return %6 : $Bool
+
+  // CHECK: alloc_stack $Bool
+  // CHECK-NEXT: store
+  // CHECK-NEXT: tuple ()
+  // CHECK-NEXT: load
+  // CHECK-NEXT: dealloc_stack
+  // CHECK-NEXT: return
+}
+
+// Make sure that we can promote this box and dealloc_stack
+// on each path.
+//
+// CHECK-LABEL: sil @box_reachable_from_destroy_test
+sil @box_reachable_from_destroy_test : $@convention(thin) () -> () {
+bb0:
+  br bb1
+
+// CHECK: bb1:
+// CHECK-NEXT: alloc_stack
+bb1:
+  %1 = alloc_box ${ var Bool }
+  cond_br undef, bb2, bb3
+
+// CHECK: bb2:
+// CHECK-NEXT: dealloc_stack
+bb2:
+  destroy_value %1 : ${ var Bool }
+  br bb1
+
+// CHECK: bb3:
+// CHECK-NEXT: dealloc_stack
+bb3:
+  destroy_value %1 : ${ var Bool }
+  %2 = tuple ()
+// CHECK: return
+  return %2 : $()
+}
+
+
+
+sil @useSomeClass : $@convention(thin) (@owned SomeClass) -> ()
+
+
+// <rdar://problem/16382973> DI misses destroy_addr because allocbox_to_stack isn't preserving mark_uninitialized invariants
+// When allocbox_to_stack promotes the box, it should rewrite the multiple
+// destroy_values into destroy_addr/dealloc_stack pairs.  However, it needs to
+// make sure to use the MUI result for the destroy addr.
+
+public protocol My_Incrementable { }
+
+extension Int : My_Incrementable { }
+
+// CHECK-LABEL: sil @test_mui
+sil @test_mui : $@convention(thin) (Builtin.Int1) -> () {
+bb0(%0 : @trivial $Builtin.Int1):
+  %2 = alloc_box ${ var SomeClass }
+  %2a = project_box %2 : ${ var SomeClass }, 0
+  // CHECK: [[STACK:%[0-9]+]] = alloc_stack
+  %3 = mark_uninitialized [var] %2a : $*SomeClass
+  // CHECK: [[MUI:%[0-9]+]] = mark_uninitialized
+  cond_br %0, bb1, bb3
+
+bb1:
+  %7 = function_ref @_T01t9SomeClassCCfMS0_FT_S0_ : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass // user: %6
+  %8 = metatype $@thick SomeClass.Type
+  %9 = apply %7(%8) : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass
+
+  assign %9 to %3 : $*SomeClass
+  %11 = function_ref @useSomeClass : $@convention(thin) (@owned SomeClass) -> ()
+  %12 = load [copy] %3 : $*SomeClass
+  %14 = apply %11(%12) : $@convention(thin) (@owned SomeClass) -> ()
+
+  destroy_value %2 : ${ var SomeClass }
+  // CHECK: destroy_addr [[MUI]]
+  // CHECK-NEXT: dealloc_stack [[STACK]]
+  br bb2
+
+  // CHECK: bb2
+bb2:
+  %17 = tuple ()
+  // CHECK: return
+  return %17 : $()
+
+bb3:
+  destroy_value %2 : ${ var SomeClass }
+  // CHECK: destroy_addr [[MUI]]
+  // CHECK-NEXT: dealloc_stack [[STACK]]
+  br bb2
+}
+
+// CHECK-LABEL: sil @_T06struct5applySiSiyc1f_tF
+// struct.apply (f : () -> Swift.Int) -> Swift.Int
+sil @_T06struct5applySiSiyc1f_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> Int {
+bb0(%0 : @owned $@callee_owned () -> Int):
+  debug_value %0 : $@callee_owned () -> Int, let, name "f" // id: %1
+  %1 = copy_value %0 : $@callee_owned () -> Int     // id: %2
+  %3 = apply %1() : $@callee_owned () -> Int      // user: %5
+  destroy_value %0 : $@callee_owned () -> Int    // id: %4
+  return %3 : $Int                                // id: %5
+}
+
+// CHECK-LABEL: sil @_T06struct6escapeSiycSiyc1f_tF
+// struct.escape (f : () -> Swift.Int) -> () -> Swift.Int
+sil @_T06struct6escapeSiycSiyc1f_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> @owned @callee_owned () -> Int {
+bb0(%0 : @owned $@callee_owned () -> Int):
+  debug_value %0 : $@callee_owned () -> Int, let, name "f" // id: %1
+  return %0 : $@callee_owned () -> Int            // id: %2
+}
+
+// CHECK-LABEL: sil @_T06struct8useStackySi1t_tF
+// struct.useStack (t : Swift.Int) -> ()
+sil @_T06struct8useStackySi1t_tF : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  debug_value %0 : $Int, let, name "t" // id: %1
+  // CHECK: alloc_stack
+  %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>, var, name "s"                   // users: %3, %6, %7, %7, %9
+  %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %0 to [trivial] %2a : $*Int                        // id: %3
+  // function_ref struct.apply (f : () -> Swift.Int) -> Swift.Int
+  %4 = function_ref @_T06struct5applySiSiyc1f_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> Int // user: %8
+  // CHECK: [[FUNC:%[a-zA-Z0-9]+]] = function_ref @_T06struct8useStackySi1t_tFSiycfU_Tf0s_n
+  // function_ref struct.(useStack (t : Swift.Int) -> ()).(closure #1)
+  %5 = function_ref @_T06struct8useStackySi1t_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %7
+  %6 = copy_value %2 : $<τ_0_0> { var τ_0_0 } <Int>     // id: %6
+  // CHECK: [[PA:%[a-zA-Z0-9]+]] = partial_apply [[FUNC]]
+  %7 = partial_apply %5(%6) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %8
+  %8 = apply %4(%7) : $@convention(thin) (@owned @callee_owned () -> Int) -> Int
+  destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Int>
+  %10 = tuple ()                                  // user: %11
+  return %10 : $()                                // id: %11
+}
+
+// CHECK-LABEL: sil shared @_T06struct8useStackySi1t_tFSiycfU_Tf0s_n
+// CHECK-LABEL: sil private @_T06struct8useStackySi1t_tFSiycfU_
+// struct.(useStack (t : Swift.Int) -> ()).(closure #1)
+sil private @_T06struct8useStackySi1t_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
+bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  // function_ref Swift.++ @postfix <A : Swift._Incrementable>(x : @inout A) -> A
+  %2 = function_ref @_TFsoP2ppUs14_Incrementable__FT1xRQ__Q_ : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0 // user: %4
+  %3 = alloc_stack $Int                           // users: %4, %5, %6
+  %4 = apply %2<Int>(%3, %1) : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0
+  %5 = load [trivial] %3 : $*Int                          // user: %8
+  dealloc_stack %3 : $*Int       // id: %6
+  destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Int>      // id: %7
+  return %5 : $Int                                // id: %8
+}
+
+// Swift.++ @postfix <A : Swift._Incrementable>(x : @inout A) -> A
+sil [transparent] @_TFsoP2ppUs14_Incrementable__FT1xRQ__Q_ : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0
+
+// CHECK-LABEL: sil @_T06struct6useBoxySi1t_tF
+// struct.useBox (t : Swift.Int) -> ()
+sil @_T06struct6useBoxySi1t_tF : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  debug_value %0 : $Int, let, name "t" // id: %1
+  // CHECK: alloc_box
+  %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>, var, name "s"                   // users: %3, %6, %7, %7, %10
+  %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %0 to [trivial] %2a : $*Int                        // id: %3
+  // function_ref struct.escape (f : () -> Swift.Int) -> () -> Swift.Int
+  %4 = function_ref @_T06struct6escapeSiycSiyc1f_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> @owned @callee_owned () -> Int // user: %8
+  // function_ref struct.(useBox (t : Swift.Int) -> ()).(closure #1)
+  %5 = function_ref @_T06struct6useBoxySi1t_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %7
+  %6 = copy_value %2 : $<τ_0_0> { var τ_0_0 } <Int>     // id: %6
+  %7 = partial_apply %5(%6) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %8
+  %8 = apply %4(%7) : $@convention(thin) (@owned @callee_owned () -> Int) -> @owned @callee_owned () -> Int // user: %9
+  %9 = apply %8() : $@callee_owned () -> Int
+  destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Int>    // id: %10
+  %11 = tuple ()                                  // user: %12
+  return %11 : $()                                // id: %12
+}
+
+// CHECK-LABEL: sil private @_T06struct6useBoxySi1t_tFSiycfU_
+// struct.(useBox (t : Swift.Int) -> ()).(closure #1)
+sil private @_T06struct6useBoxySi1t_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
+bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  // function_ref Swift.++ @postfix <A : Swift._Incrementable>(x : @inout A) -> A
+  %2 = function_ref @_TFsoP2ppUs14_Incrementable__FT1xRQ__Q_ : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0 // user: %4
+  %3 = alloc_stack $Int                           // users: %4, %5, %6
+  %4 = apply %2<Int>(%3, %1) : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0
+  %5 = load [trivial] %3 : $*Int                          // user: %8
+  dealloc_stack %3 : $*Int       // id: %6
+  destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Int>      // id: %7
+  return %5 : $Int                                // id: %8
+}
+
+// CHECK-LABEL: sil @closure
+sil @closure : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
+
+// CHECK-LABEL: sil @no_final_destroy
+sil @no_final_destroy : $@convention(thin) (Int) -> Bool {
+bb0(%0 : @trivial $Int):
+  // This is not destroyed, but the unreachable makes the verifier not trip.
+  %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %0 to [trivial] %1a : $*Int
+  // function_ref main.(newFoo (Swift.Int) -> Swift.Bool).(modify #1) (())()
+  %3 = function_ref @closure : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
+  %4 = copy_value %1 : $<τ_0_0> { var τ_0_0 } <Int>
+  %5 = partial_apply %3(%4) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
+  %6 = copy_value %5 : $@callee_owned () -> ()
+  apply %6() : $@callee_owned () -> ()
+  destroy_value %5 : $@callee_owned () -> ()
+  unreachable
+}
+
+// CHECK-LABEL: sil [transparent] [serialized] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> ()
+sil [transparent] [serialized] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> () {
+// CHECK: bb0
+bb0(%0 : @owned $@callee_owned () -> @out U):
+  debug_value %0 : $@callee_owned () -> @out U
+  %1 = copy_value %0 : $@callee_owned () -> @out U
+  %3 = alloc_stack $U
+  %4 = apply %1(%3) : $@callee_owned () -> @out U
+  destroy_addr %3 : $*U
+  dealloc_stack %3 : $*U
+  destroy_value %0 : $@callee_owned () -> @out U
+  %8 = tuple ()
+// CHECK: return
+  return %8 : $()
+}
+
+// CHECK-LABEL: sil @callWithAutoclosure
+sil @callWithAutoclosure : $@convention(thin) <T where T : P> (@in T) -> () {
+// CHECK: bb0
+bb0(%0 : @trivial $*T):
+  // CHECK: debug_value_addr
+  debug_value_addr %0 : $*T
+  // CHECK: function_ref @mightApply
+  %2 = function_ref @mightApply : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
+  %3 = function_ref @closure_to_specialize : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
+  // CHECK-NOT: alloc_box
+  // CHECK: [[STACK:%[0-9a-zA-Z_]+]] = alloc_stack $T
+  %4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
+  %4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
+  // CHECK: copy_addr %0 to [initialization] [[STACK]] : $*T
+  copy_addr %0 to [initialization] %4a : $*T
+  // CHECK: [[CLOSURE:%[0-9a-zA-Z]+]] = function_ref @_T021closure_to_specializeTf0ns_n
+  // CHECK: partial_apply [[CLOSURE]]<T>([[STACK]])
+  %6 = partial_apply %3<T>(%4) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
+  %7 = apply %2<T>(%6) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
+  // CHECK: destroy_addr [[STACK]] : $*T
+  // CHECK: dealloc_stack [[STACK]] : $*T
+  destroy_addr %0 : $*T
+  %9 = tuple ()
+  // CHECK: return
+  return %9 : $()
+}
+
+// CHECK-LABEL: sil shared @_T021closure_to_specializeTf0ns_n : $@convention(thin) <T where T : P> (@inout_aliasable T) -> @out T
+sil shared @closure_to_specialize : $@convention(thin) <T where T : P> (@owned <τ_0_0> { var τ_0_0 } <T>) -> @out T {
+// CHECK: bb0
+bb0(%0 : @trivial $*T, %1 : @owned $<τ_0_0> { var τ_0_0 } <T>):
+  %2 = project_box %1 : $<τ_0_0> { var τ_0_0 } <T>, 0
+  // CHECK-NEXT: copy_addr
+  copy_addr %2 to [initialization] %0 : $*T
+  // CHECK-NOT: destroy_value
+  destroy_value %1 : $<τ_0_0> { var τ_0_0 } <T>
+  %5 = tuple ()
+  // CHECK: return
+  return %5 : $()
+}
+
+protocol Count {
+  var count: Int { get }
+}
+
+struct Q : Count {
+  var count: Int { get }
+  init()
+}
+
+struct S<T : Count> {
+  @sil_stored var t: T
+  var count: Int { get }
+  func test(i: Int) -> Bool
+  init(t: T)
+}
+
+// CHECK-LABEL: sil [noinline] @inner
+sil [noinline] @inner : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool {
+// CHECK: bb0
+bb0(%0 : @owned $@callee_owned () -> Bool):
+  debug_value %0 : $@callee_owned () -> Bool
+  %1 = copy_value %0 : $@callee_owned () -> Bool
+  %3 = apply %1() : $@callee_owned () -> Bool
+  destroy_value %0 : $@callee_owned () -> Bool
+// CHECK: return
+  return %3 : $Bool
+}
+
+// CHECK-LABEL: sil [noinline] @outer
+sil [noinline] @outer : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool {
+// CHECK: bb0
+bb0(%0 : @owned $@callee_owned () -> Bool):
+  debug_value %0 : $@callee_owned () -> Bool
+  %1 = copy_value %0 : $@callee_owned () -> Bool
+  %3 = apply %1() : $@callee_owned () -> Bool
+  destroy_value %0 : $@callee_owned () -> Bool
+// CHECK: return
+  return %3 : $Bool
+}
+
+// CHECK-LABEL: sil @get
+sil @get : $@convention(method) <T where T : Count> (@in S<T>) -> Int
+
+// CHECK-LABEL: sil shared @specialized
+sil shared @specialized : $@convention(method) (Int, @in S<Q>) -> Bool {
+// CHECK: bb0
+bb0(%0 : @trivial $Int, %1 : @trivial $*S<Q>):
+  debug_value %0 : $Int
+  debug_value_addr %1 : $*S<Q>
+  %4 = function_ref @outer : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
+  %5 = function_ref @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool
+  %6 = alloc_box $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <Q>
+  %6a = project_box %6 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <Q>, 0
+  copy_addr %1 to [initialization] %6a : $*S<Q>
+  %8 = partial_apply %5<Q>(%0, %6) : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
+  %9 = apply %4(%8) : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
+  destroy_addr %1 : $*S<Q>
+// CHECK: return
+  return %9 : $Bool
+}
+
+// CHECK-LABEL: sil @unspecialized
+sil @unspecialized : $@convention(method) <T where T : Count> (Int, @in S<T>) -> Bool {
+// CHECK: bb0
+bb0(%0 : @trivial $Int, %1 : @trivial $*S<T>):
+  debug_value %0 : $Int
+  debug_value_addr %1 : $*S<T>
+  %4 = function_ref @outer : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
+  %5 = function_ref @closure1 : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
+  %6 = alloc_box $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
+  %6a = project_box %6 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
+  copy_addr %1 to [initialization] %6a : $*S<T>
+  %8 = partial_apply %5<T>(%0, %6) : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
+  %9 = apply %4(%8) : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
+  destroy_addr %1 : $*S<T>
+// CHECK: return
+  return %9 : $Bool
+}
+
+// CHECK-LABEL: sil shared @closure1
+sil shared @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
+// CHECK: bb0
+bb0(%0 : @trivial $Int, %1 : @owned $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>):
+  %2 = project_box %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
+  %3 = function_ref @inner : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
+  %4 = function_ref @closure2 : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
+  %5 = alloc_box $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
+  %5a = project_box %5 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
+  copy_addr %2 to [initialization] %5a : $*S<T>
+  %7 = partial_apply %4<T>(%0, %5) : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
+  %8 = apply %3(%7) : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
+  destroy_value %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
+// CHECK: return
+  return %8 : $Bool
+}
+
+// CHECK-LABEL: sil shared @_T08closure2Tf0ns_n
+// CHECK: bb0
+// CHECK: return
+// CHECK-NOT: bb1
+
+// CHECK-LABEL: sil shared @closure2
+sil shared @closure2 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
+// CHECK: bb0
+bb0(%0 : @trivial $Int, %1 : @owned $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>):
+  %2 = project_box %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
+  %3 = function_ref @binary : $@convention(thin) (Int, Int) -> Bool
+  %4 = alloc_stack $S<T>
+  copy_addr %2 to [initialization] %4 : $*S<T>
+  %6 = function_ref @get : $@convention(method) <τ_0_0 where τ_0_0 : Count> (@in S<τ_0_0>) -> Int
+  %7 = apply %6<T>(%4) : $@convention(method) <τ_0_0 where τ_0_0 : Count> (@in S<τ_0_0>) -> Int
+  %8 = apply %3(%0, %7) : $@convention(thin) (Int, Int) -> Bool
+  dealloc_stack %4 : $*S<T>
+  destroy_value %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
+// CHECK: return
+  return %8 : $Bool
+}
+
+// CHECK-LABEL: sil [transparent] [serialized] @binary
+sil [transparent] [serialized] @binary : $@convention(thin) (Int, Int) -> Bool
+
+// CHECK-LABEL: sil @destroy_stack_value_after_closure
+sil @destroy_stack_value_after_closure : $@convention(thin) <T> (@in T) -> @out T {
+// CHECK: bb0
+bb0(%0 : @trivial $*T, %1 : @trivial $*T):
+  // CHECK: [[STACK:%.*]] = alloc_stack
+  // CHECK: copy_addr %1 to [initialization] [[STACK]]
+  // CHECK: [[APPLIED:%.*]] = function_ref
+  %3 = function_ref @applied : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> ()
+  %4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
+  %4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
+  copy_addr %1 to [initialization] %4a : $*T
+  // CHECK: [[PARTIAL:%.*]] = partial_apply [[APPLIED]]<T>([[STACK]])
+  %6 = partial_apply %3<T>(%4) : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> ()
+  // CHECK: debug_value [[PARTIAL]]
+  debug_value %6 : $@callee_owned () -> ()
+  // CHECK: [[COPIED_PARTIAL:%.*]] = copy_value [[PARTIAL]]
+  %7 = copy_value %6 : $@callee_owned () -> ()
+  // CHECK: apply [[COPIED_PARTIAL]]() : $@callee_owned () -> ()
+  %9 = apply %7() : $@callee_owned () -> ()
+  copy_addr %1 to [initialization] %0 : $*T
+  // CHECK: destroy_value [[PARTIAL]]
+  destroy_value %6 : $@callee_owned () -> ()
+  // CHECK: destroy_addr [[STACK]]
+  // CHECK: destroy_addr %1
+  destroy_addr %1 : $*T
+  %13 = tuple ()
+  return %13 : $()
+}
+
+sil @applied : $@convention(thin) <T> (@owned <τ_0_0> { var τ_0_0 } <T>) -> () {
+bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <T>):
+  %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <T>, 0
+  %2 = function_ref @consume : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
+  %3 = alloc_stack $T
+  copy_addr %1 to [initialization] %3 : $*T
+  %5 = apply %2<T>(%3) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
+  dealloc_stack %3 : $*T
+  destroy_value %0 : $<τ_0_0> { var τ_0_0 } <T>
+  %8 = tuple ()
+  return %8 : $()
+}
+
+sil hidden [noinline] @consume : $@convention(thin) <T> (@in T) -> () {
+bb0(%0 : @trivial $*T):
+  debug_value_addr %0 : $*T
+  destroy_addr %0 : $*T
+  %3 = tuple ()
+  return %3 : $()
+}
+
+class ThrowBaseClass {
+  required init() throws
+  init(noFail: ())
+}
+
+class ThrowDerivedClass : ThrowBaseClass {
+  //final init(failBeforeFullInitialization: Int) throws
+}
+
+sil @throwing_unwrap : $@convention(thin) (Int) -> (Int, @error Error)
+sil @fake_throwing_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error)
+
+sil hidden @try_apply_during_chaining_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) {
+// %0                                             // users: %11, %5
+// %1                                             // user: %7
+bb0(%0 : @trivial $Int, %1 : @owned $ThrowDerivedClass):
+  %2 = alloc_box ${ var ThrowDerivedClass }, let, name "self"
+  %3 = project_box %2 : ${ var ThrowDerivedClass }, 0
+  %4 = mark_uninitialized [delegatingself] %3 : $*ThrowDerivedClass
+  store %1 to [init] %4 : $*ThrowDerivedClass
+  %8 = load [take] %4 : $*ThrowDerivedClass
+  %9 = function_ref @fake_throwing_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error)
+  %10 = function_ref @throwing_unwrap : $@convention(thin) (Int) -> (Int, @error Error)
+  try_apply %10(%0) : $@convention(thin) (Int) -> (Int, @error Error), normal bb1, error bb3
+
+// %12                                            // user: %13
+bb1(%12 : @trivial $Int):                                  // Preds: bb0
+  try_apply %9(%12, %8) : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error), normal bb2, error bb4
+
+// %14                                            // user: %15
+bb2(%14 : @owned $ThrowDerivedClass):                    // Preds: bb1
+  store %14 to [init] %4 : $*ThrowDerivedClass
+  %16 = load [copy] %4 : $*ThrowDerivedClass
+  destroy_value %2 : ${ var ThrowDerivedClass }
+  return %16 : $ThrowDerivedClass
+
+// %20                                            // user: %22
+bb3(%20 : @owned $Error):                                // Preds: bb0
+  destroy_value %8 : $ThrowDerivedClass
+  br bb5(%20 : $Error)
+
+// %23                                            // user: %24
+bb4(%23 : @owned $Error):                                // Preds: bb1
+  br bb5(%23 : $Error)
+
+// %25                                            // user: %27
+bb5(%25 : @owned $Error):                                // Preds: bb4 bb3
+  destroy_value %2 : ${ var ThrowDerivedClass }
+  throw %25 : $Error
+}
+
+// CHECK-LABEL: sil @deal_with_wrong_nesting
+// CHECK:      bb0(%0 : @trivial $Int):
+// CHECK-NEXT:   [[STACK1:%[0-9]+]] = alloc_stack $Bool
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK:      bb1:
+// CHECK-NEXT:   dealloc_stack [[BOX]]
+// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK:      bb2:
+// CHECK:        store
+// CHECK:        [[STACK2:%[0-9]+]] = alloc_stack $Bool
+// CHECK-NEXT:   dealloc_stack [[STACK2]]
+// CHECK-NEXT:   dealloc_stack [[BOX]]
+// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK:      bb3:
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+sil @deal_with_wrong_nesting : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  %as1 = alloc_stack $Bool
+  %1 = alloc_box ${ var Int }
+  cond_br undef, bb1, bb2
+
+bb1:
+  destroy_value %1 : ${ var Int }
+  dealloc_stack %as1 : $*Bool
+  br bb3
+
+bb2:
+  %1a = project_box %1 : ${ var Int }, 0
+  %2 = store %0 to [trivial] %1a : $*Int
+  dealloc_stack %as1 : $*Bool
+  %3 = load [trivial] %1a : $*Int
+  %as2 = alloc_stack $Bool
+  destroy_value %1 : ${ var Int }
+  dealloc_stack %as2 : $*Bool
+  br bb3
+
+bb3:
+  %r = tuple ()
+  %5 = return %r : $()
+}
+
+// CHECK-LABEL: sil @wrong_nesting_with_alloc_ref
+// CHECK:      bb0(%0 : @trivial $Int):
+// CHECK-NEXT:   [[REF:%[0-9]+]] = alloc_ref [stack] $SomeClass
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK:        store
+// CHECK:        dealloc_stack [[BOX]]
+// CHECK-NEXT:   dealloc_ref [stack] [[REF]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+sil @wrong_nesting_with_alloc_ref : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  %as1 = alloc_ref [stack] $SomeClass
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  store %0 to [trivial] %1a : $*Int
+  dealloc_ref [stack] %as1 : $SomeClass
+  %3 = load [trivial] %1a : $*Int
+  destroy_value %1 : ${ var Int }
+  %r = tuple ()
+  %5 = return %r : $()
+}
+
+// CHECK-LABEL: sil @nesting_and_unreachable1
+// CHECK:      bb0(%0 : @trivial $Int):
+// CHECK-NEXT:   [[STACK1:%[0-9]+]] = alloc_stack $Bool
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK:      bb1:
+// CHECK-NEXT:   [[STACK2:%[0-9]+]] = alloc_stack $Bool
+// CHECK-NEXT:   dealloc_stack [[STACK2]]
+// CHECK-NEXT:   unreachable
+// CHECK:      bb2:
+// CHECK:        store
+// CHECK:        dealloc_stack [[BOX]]
+// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+sil @nesting_and_unreachable1 : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  %as1 = alloc_stack $Bool
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  cond_br undef, bb1, bb2
+
+bb1:
+  %as2 = alloc_stack $Bool
+  dealloc_stack %as2 : $*Bool
+  unreachable
+
+bb2:
+  store %0 to [trivial] %1a : $*Int
+  dealloc_stack %as1 : $*Bool
+  %3 = load [trivial] %1a : $*Int
+  destroy_value %1 : ${ var Int }
+  %r = tuple ()
+  %5 = return %r : $()
+}
+
+// CHECK-LABEL: sil @nesting_and_unreachable2
+// CHECK:      bb0(%0 : @trivial $Int):
+// CHECK-NEXT:   [[STACK1:%[0-9]+]] = alloc_stack $Bool
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK:      bb1:
+// CHECK-NEXT:   [[STACK2:%[0-9]+]] = alloc_stack $Bool
+// CHECK-NEXT:   dealloc_stack [[STACK2]]
+// CHECK-NEXT:   dealloc_stack [[BOX]]
+// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK-NEXT:   unreachable
+// CHECK:      bb2:
+// CHECK:        store
+// CHECK:        dealloc_stack [[BOX]]
+// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+sil @nesting_and_unreachable2 : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  %as1 = alloc_stack $Bool
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  cond_br undef, bb1, bb2
+
+bb1:
+  %as2 = alloc_stack $Bool
+  destroy_value %1 : ${ var Int }
+  dealloc_stack %as2 : $*Bool
+  unreachable
+
+bb2:
+  %2 = store %0 to [trivial] %1a : $*Int
+  dealloc_stack %as1 : $*Bool
+  %3 = load [trivial] %1a : $*Int
+  destroy_value %1 : ${ var Int }
+  %r = tuple ()
+  %5 = return %r : $()
+}
+
+// CHECK-LABEL: sil @nesting_and_unreachable3
+// CHECK:      bb0(%0 : @trivial $Int):
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK-NEXT:   [[STACK:%[0-9]+]] = alloc_stack $Bool
+// CHECK:      bb1:
+// CHECK-NEXT:   dealloc_stack [[STACK]]
+// CHECK-NEXT:   dealloc_stack [[BOX]]
+// CHECK-NEXT:   unreachable
+// CHECK:      bb2:
+// CHECK:        store
+// CHECK:        dealloc_stack [[STACK]]
+// CHECK-NEXT:   dealloc_stack [[BOX]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+sil @nesting_and_unreachable3 : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  %1 = alloc_box ${ var Int }
+  %as1 = alloc_stack $Bool
+  %1a = project_box %1 : ${ var Int }, 0
+  cond_br undef, bb1, bb2
+
+bb1:
+  destroy_value %1 : ${ var Int }
+  unreachable
+
+bb2:
+  store %0 to [trivial] %1a : $*Int
+  %3 = load [trivial] %1a : $*Int
+  dealloc_stack %as1 : $*Bool
+  destroy_value %1 : ${ var Int }
+  %r = tuple ()
+  %5 = return %r : $()
+}
+
+// CHECK-LABEL: sil @nesting_and_unreachable4
+// CHECK:      bb0(%0 : @trivial $Int):
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK:      bb1:
+// CHECK-NEXT:   unreachable
+// CHECK:      bb2:
+// CHECK:        store
+// CHECK:        dealloc_stack [[BOX]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+sil @nesting_and_unreachable4 : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  cond_br undef, bb1, bb2
+
+bb1:
+  unreachable
+
+bb2:
+  %2 = store %0 to [trivial] %1a : $*Int
+  %3 = load [trivial] %1a : $*Int
+  destroy_value %1 : ${ var Int }
+  %r = tuple ()
+  %5 = return %r : $()
+}
+
+// CHECK-LABEL: sil @nesting_and_unreachable5
+// CHECK:      bb0(%0 : @trivial $Int):
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK:      bb1:
+// CHECK-NEXT:   {{.*}} = alloc_stack $Bool
+// CHECK-NEXT:   {{.*}} = alloc_stack $Bool
+// CHECK-NEXT:   unreachable
+// CHECK:      bb2:
+// CHECK:        store
+// CHECK:        dealloc_stack [[BOX]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+sil @nesting_and_unreachable5 : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  %1 = alloc_box ${ var Int }
+  %1a = project_box %1 : ${ var Int }, 0
+  cond_br undef, bb1, bb2
+
+bb1:
+  %as1 = alloc_stack $Bool
+  %as2 = alloc_stack $Bool
+  unreachable
+
+bb2:
+  %2 = store %0 to [trivial] %1a : $*Int
+  %3 = load [trivial] %1a : $*Int
+  destroy_value %1 : ${ var Int }
+  %r = tuple ()
+  %5 = return %r : $()
+}
+
+// CHECK-LABEL: sil @nesting_and_unreachable_critical_edge
+// CHECK:      bb0(%0 : @trivial $Int):
+// CHECK-NEXT:   [[BOX:%[0-9]+]] = alloc_stack $Int
+// CHECK-NEXT:   [[STACK1:%[0-9]+]] = alloc_stack $Bool
+// CHECK-NEXT:   cond_br
+// CHECK:      bb1:
+// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK-NEXT:   br bb5
+// CHECK:      bb2:
+// CHECK-NEXT:   [[STACK2:%[0-9]+]] = alloc_stack $Bool
+// CHECK-NEXT:   cond_br
+// CHECK:      bb3:
+// CHECK-NEXT:   dealloc_stack [[STACK2]]
+// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK-NEXT:   br bb5
+// CHECK:      bb4:
+// CHECK:        store
+// CHECK:        dealloc_stack [[STACK2]]
+// CHECK-NEXT:   dealloc_stack [[STACK1]]
+// CHECK-NEXT:   dealloc_stack [[BOX]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+// CHECK:      bb5:
+// CHECK-NEXT:   dealloc_stack [[BOX]]
+// CHECK-NEXT:   unreachable
+sil @nesting_and_unreachable_critical_edge : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+  %1 = alloc_box ${ var Int }
+  %as1 = alloc_stack $Bool
+  %1a = project_box %1 : ${ var Int }, 0
+  cond_br undef, bb1, bb3
+
+bb1:
+  %as2 = alloc_stack $Bool
+  cond_br undef, bb2, bb3
+
+bb2:
+  %2 = store %0 to [trivial] %1a : $*Int
+  %3 = load [trivial] %1a : $*Int
+  dealloc_stack %as2 : $*Bool
+  dealloc_stack %as1 : $*Bool
+  destroy_value %1 : ${ var Int }
+  %r = tuple ()
+  %5 = return %r : $()
+
+bb3:
+  destroy_value %1 : ${ var Int }
+  unreachable
+}
+
diff --git a/test/SILOptimizer/array_contentof_opt.swift b/test/SILOptimizer/array_contentof_opt.swift
new file mode 100644
index 0000000..c3c2b19
--- /dev/null
+++ b/test/SILOptimizer/array_contentof_opt.swift
@@ -0,0 +1,52 @@
+// RUN: %target-swift-frontend -O -emit-sil  %s | %FileCheck %s
+// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib
+
+// This is an end-to-end test of the array(contentsOf) -> array(Element) optimization
+
+// CHECK-LABEL: sil @{{.*}}testInt
+// CHECK-NOT: apply
+// CHECK:        [[F:%[0-9]+]] = function_ref @_T0Sa6appendyxFSi_Tg
+// CHECK-NOT: apply
+// CHECK:        apply [[F]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+public func testInt(_ a: inout [Int]) {
+  a += [1]
+}
+
+// CHECK-LABEL: sil @{{.*}}testThreeInt
+// CHECK-NOT: apply
+// CHECK:        [[F:%[0-9]+]] = function_ref @_T0Sa6appendyxFSi_Tg
+// CHECK-NOT: apply
+// CHECK:        apply [[F]]
+// CHECK-NEXT:   apply [[F]]
+// CHECK-NEXT:   apply [[F]]
+// CHECK-NEXT:   tuple
+// CHECK-NEXT:   return
+public func testThreeInts(_ a: inout [Int]) {
+  a += [1, 2, 3]
+}
+
+// CHECK-LABEL: sil @{{.*}}testTooManyInts
+// CHECK-NOT: apply
+// CHECK:        [[F:%[0-9]+]] = function_ref @_T0Sa6appendyqd__10contentsOf_t8Iterator_7ElementQYd__Rszs8SequenceRd__lF
+// CHECK-NOT: apply
+// CHECK:        apply [[F]]
+// CHECK-NOT: apply
+// CHECK:        return
+public func testTooManyInts(_ a: inout [Int]) {
+  a += [1, 2, 3, 4, 5, 6, 7]
+}
+
+// CHECK-LABEL: sil @{{.*}}testString
+// CHECK-NOT: apply
+// CHECK:        [[F:%[0-9]+]] = function_ref @_T0Sa6appendyxFSS_Tg
+// CHECK-NOT: apply
+// CHECK:        apply [[F]]
+// CHECK-NOT: apply
+// CHECK:        tuple
+// CHECK-NEXT:   return
+public func testString(_ a: inout [String], s: String) {
+  a += [s]
+}
+
diff --git a/test/SILOptimizer/array_element_propagation.sil b/test/SILOptimizer/array_element_propagation.sil
index 9f42641..29e8221 100644
--- a/test/SILOptimizer/array_element_propagation.sil
+++ b/test/SILOptimizer/array_element_propagation.sil
@@ -31,6 +31,9 @@
 sil [_semantics "array.get_element"] @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
 sil [_semantics "array.get_element"] @getElement2 : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> MyInt
 sil @unknown_array_use : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+sil [_semantics "array.uninitialized"] @arrayAdoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin Array<MyInt>.Type) -> @owned (Array<MyInt>, UnsafeMutablePointer<MyInt>)
+sil @arrayInit : $@convention(method) (@thin Array<MyInt>.Type) -> @owned Array<MyInt>
+sil [_semantics "array.append_contentsOf"] @arrayAppendContentsOf : $@convention(method) (@owned Array<MyInt>, @inout Array<MyInt>) -> ()
 
 // CHECK-LABEL: sil @propagate01
 // CHECK:    struct $MyInt
@@ -300,3 +303,83 @@
   strong_release %25 : $Builtin.BridgeObject
   return %52 : $()
 }
+
+// CHECK-LABEL: sil @append_contentsOf_int
+// CHECK:      [[ASFUN:%.*]] = function_ref @arrayAdoptStorage
+// CHECK-NEXT: [[ARR:%.*]] = apply [[ASFUN]]
+// CHECK-NEXT: [[OWNER:%.*]] = tuple_extract [[ARR]]{{.*}}, 0
+// CHECK-NOT:    apply [[ACFUN]]
+// CHECK:      [[AEFUN:%.*]] = function_ref @_T0Sa6appendyxF
+// CHECK-NEXT: [[STACK:%.*]] = alloc_stack $MyInt
+// CHECK-NEXT: store %{{[0-9]+}} to [[STACK]]
+// CHECK-NEXT: apply [[AEFUN]]<MyInt>([[STACK]]
+// CHECK-NEXT: dealloc_stack [[STACK]]
+// CHECK-NEXT: release_value [[OWNER]]
+// CHECK:      return
+sil @append_contentsOf_int : $@convention(thin) () -> () {
+  %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject
+  %1 = integer_literal $Builtin.Int64, 1
+  %2 = struct $MyInt (%1 : $Builtin.Int64)
+  %3 = apply %0() : $@convention(thin) () -> @owned AnyObject
+  %4 = metatype $@thin Array<MyInt>.Type
+  %5 = function_ref @arrayAdoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin Array<MyInt>.Type) -> @owned (Array<MyInt>, UnsafeMutablePointer<MyInt>)
+  %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin Array<MyInt>.Type) -> @owned (Array<MyInt>, UnsafeMutablePointer<MyInt>)
+  %7 = tuple_extract %6 : $(Array<MyInt>, UnsafeMutablePointer<MyInt>), 0
+  %8 = tuple_extract %6 : $(Array<MyInt>, UnsafeMutablePointer<MyInt>), 1
+  %9 = struct_extract %8 : $UnsafeMutablePointer<MyInt>, #UnsafeMutablePointer._rawValue
+  %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt
+  %11 = integer_literal $Builtin.Int64, 27
+  %12 = struct $MyInt (%11 : $Builtin.Int64)
+  store %12 to %10 : $*MyInt
+  %13 = alloc_stack $Array<MyInt>
+  %14 = metatype $@thin Array<MyInt>.Type
+  %15 = function_ref @arrayInit : $@convention(method) (@thin Array<MyInt>.Type) -> @owned Array<MyInt>
+  %16 = apply %15(%14) : $@convention(method) (@thin Array<MyInt>.Type) -> @owned Array<MyInt>
+  store %16 to %13 : $*Array<MyInt>
+  %17 = function_ref @arrayAppendContentsOf : $@convention(method) (@owned Array<MyInt>, @inout Array<MyInt>) -> ()
+  %18 = apply %17(%7, %13) : $@convention(method) (@owned Array<MyInt>, @inout Array<MyInt>) -> ()
+  dealloc_stack %13 : $*Array<MyInt>
+  %19 = tuple ()
+  return %19 : $()
+}
+
+class Hello {
+}
+
+sil [_semantics "array.uninitialized"] @adoptStorageHello : $@convention(method) (@owned _ContiguousArrayStorage<Hello>, MyInt, @thin Array<Hello>.Type) -> (@owned Array<Hello>, UnsafeMutablePointer<Hello>)
+sil [_semantics "array.append_contentsOf"] @arrayAppendContentsOfHello : $@convention(method) (@owned Array<Hello>, @inout Array<Hello>) -> ()
+
+// CHECK-LABEL: sil @append_contentsOf_class
+// CHECK:      [[ASFUN:%.*]] = function_ref @adoptStorageHello
+// CHECK-NEXT: [[ARR:%.*]] = apply [[ASFUN]]
+// CHECK-NEXT: [[OWNER:%.*]] = tuple_extract [[ARR]]{{.*}}, 0
+// CHECK:      strong_retain %1 : $Hello
+// CHECK-NEXT: store %1 to %{{[0-9]+}} : $*Hello
+// CHECK-NOT:     apply
+// CHECK:      [[AEFUN:%.*]] = function_ref @_T0Sa6appendyxF
+// CHECK-NEXT: strong_retain %1 : $Hello
+// CHECK-NEXT: [[STACK:%.*]] = alloc_stack $Hello
+// CHECK-NEXT: store %1 to [[STACK]]
+// CHECK-NEXT: apply [[AEFUN]]<Hello>([[STACK]], %0)
+// CHECK-NEXT: dealloc_stack [[STACK]]
+// CHECK-NEXT: release_value [[OWNER]]
+// CHECK-NEXT: return
+sil @append_contentsOf_class : $@convention(thin) (@inout Array<Hello>, @owned Hello) -> @owned Hello {
+bb0(%0 : $*Array<Hello>, %1 : $Hello):
+  %4 = integer_literal $Builtin.Word, 1
+  %5 = integer_literal $Builtin.Int64, 1
+  %6 = struct $MyInt (%5 : $Builtin.Int64)
+  %7 = alloc_ref [tail_elems $Hello * %4 : $Builtin.Word] $_ContiguousArrayStorage<Hello>
+  %8 = metatype $@thin Array<Hello>.Type
+  %9 = function_ref @adoptStorageHello : $@convention(method) (@owned _ContiguousArrayStorage<Hello>, MyInt, @thin Array<Hello>.Type) -> (@owned Array<Hello>, UnsafeMutablePointer<Hello>)
+  %10 = apply %9(%7, %6, %8) : $@convention(method) (@owned _ContiguousArrayStorage<Hello>, MyInt, @thin Array<Hello>.Type) -> (@owned Array<Hello>, UnsafeMutablePointer<Hello>)
+  %11 = tuple_extract %10 : $(Array<Hello>, UnsafeMutablePointer<Hello>), 0
+  %12 = tuple_extract %10 : $(Array<Hello>, UnsafeMutablePointer<Hello>), 1
+  %13 = struct_extract %12 : $UnsafeMutablePointer<Hello>, #UnsafeMutablePointer._rawValue
+  %22 = pointer_to_address %13 : $Builtin.RawPointer to [strict] $*Hello
+  strong_retain %1 : $Hello
+  store %1 to %22 : $*Hello
+  %25 = function_ref @arrayAppendContentsOfHello : $@convention(method) (@owned Array<Hello>, @inout Array<Hello>) -> ()
+  %26 = apply %25(%11, %0) : $@convention(method) (@owned Array<Hello>, @inout Array<Hello>) -> ()
+  return %1 : $Hello
+}
diff --git a/test/SILOptimizer/bridged_casts_folding.swift b/test/SILOptimizer/bridged_casts_folding.swift
index 2394858..5ee8433 100644
--- a/test/SILOptimizer/bridged_casts_folding.swift
+++ b/test/SILOptimizer/bridged_casts_folding.swift
@@ -31,7 +31,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding29testForcedCastNStoSwiftStringSSyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0SSs21_ObjectiveCBridgeable10FoundationsAAP016_forceBridgeFromA1Cy01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0SS10FoundationE26_forceBridgeFromObjectiveCySo8NSStringC_SSSgz6resulttFZ : $@convention(method) (@owned NSString, @inout Optional<String>, @thin String.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftString() -> String {
@@ -41,7 +41,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding27testCondCastNStoSwiftStringSSSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0SSs21_ObjectiveCBridgeable10FoundationsAAP024_conditionallyBridgeFromA1CSb01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0SS10FoundationE34_conditionallyBridgeFromObjectiveCSbSo8NSStringC_SSSgz6resulttFZ : $@convention(method) (@owned NSString, @inout Optional<String>, @thin String.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftString() -> String? {
@@ -56,7 +56,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding32testForcedCastNSNumberToSwiftIntSiyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0Sis21_ObjectiveCBridgeable10FoundationsAAP016_forceBridgeFromA1Cy01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Si10FoundationE26_forceBridgeFromObjectiveCySo8NSNumberC_SiSgz6resulttFZ : $@convention(method) (@owned NSNumber, @inout Optional<Int>, @thin Int.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNSNumberToSwiftInt() -> Int {
@@ -66,7 +66,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding30testCondCastNSNumberToSwiftIntSiSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0Sis21_ObjectiveCBridgeable10FoundationsAAP024_conditionallyBridgeFromA1CSb01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Si10FoundationE34_conditionallyBridgeFromObjectiveCSbSo8NSNumberC_SiSgz6resulttFZ : $@convention(method) (@owned NSNumber, @inout Optional<Int>, @thin Int.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNSNumberToSwiftInt() -> Int? {
@@ -80,7 +80,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding35testForcedCastNSNumberToSwiftDoubleSdyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0Sds21_ObjectiveCBridgeable10FoundationsAAP016_forceBridgeFromA1Cy01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sd10FoundationE26_forceBridgeFromObjectiveCySo8NSNumberC_SdSgz6resulttFZ : $@convention(method) (@owned NSNumber, @inout Optional<Double>, @thin Double.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNSNumberToSwiftDouble() -> Double {
@@ -90,7 +90,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding33testCondCastNSNumberToSwiftDoubleSdSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0Sds21_ObjectiveCBridgeable10FoundationsAAP024_conditionallyBridgeFromA1CSb01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sd10FoundationE34_conditionallyBridgeFromObjectiveCSbSo8NSNumberC_SdSgz6resulttFZ : $@convention(method) (@owned NSNumber, @inout Optional<Double>, @thin Double.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNSNumberToSwiftDouble() -> Double? {
@@ -100,7 +100,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding38testForcedCastNSIntNumberToSwiftDoubleSdyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0Sds21_ObjectiveCBridgeable10FoundationsAAP016_forceBridgeFromA1Cy01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sd10FoundationE26_forceBridgeFromObjectiveCySo8NSNumberC_SdSgz6resulttFZ : $@convention(method) (@owned NSNumber, @inout Optional<Double>, @thin Double.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNSIntNumberToSwiftDouble() -> Double {
@@ -110,7 +110,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding36testCondCastNSIntNumberToSwiftDoubleSdSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0Sds21_ObjectiveCBridgeable10FoundationsAAP024_conditionallyBridgeFromA1CSb01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sd10FoundationE34_conditionallyBridgeFromObjectiveCSbSo8NSNumberC_SdSgz6resulttFZ : $@convention(method) (@owned NSNumber, @inout Optional<Double>, @thin Double.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNSIntNumberToSwiftDouble() -> Double? {
@@ -128,7 +128,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding31testForcedCastNStoSwiftArrayIntSaySiGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0SayxGs21_ObjectiveCBridgeable10FoundationlsABP016_forceBridgeFromA1Cy01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sa10FoundationE26_forceBridgeFromObjectiveCySo7NSArrayC_SayxGSgz6resulttFZ : $@convention(method) <τ_0_0> (@owned NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftArrayInt() -> [Int] {
@@ -138,7 +138,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding29testCondCastNStoSwiftArrayIntSaySiGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: @_T0SayxGs21_ObjectiveCBridgeable10FoundationlsABP024_conditionallyBridgeFromA1CSb01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sa10FoundationE34_conditionallyBridgeFromObjectiveCSbSo7NSArrayC_SayxGSgz6resulttFZ : $@convention(method) <τ_0_0> (@owned NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftArrayInt() -> [Int]? {
@@ -148,7 +148,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding34testForcedCastNStoSwiftArrayDoubleSaySdGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0SayxGs21_ObjectiveCBridgeable10FoundationlsABP016_forceBridgeFromA1Cy01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sa10FoundationE26_forceBridgeFromObjectiveCySo7NSArrayC_SayxGSgz6resulttFZ : $@convention(method) <τ_0_0> (@owned NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftArrayDouble() -> [Double] {
@@ -158,7 +158,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding32testCondCastNStoSwiftArrayDoubleSaySdGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0SayxGs21_ObjectiveCBridgeable10FoundationlsABP024_conditionallyBridgeFromA1CSb01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sa10FoundationE34_conditionallyBridgeFromObjectiveCSbSo7NSArrayC_SayxGSgz6resulttFZ : $@convention(method) <τ_0_0> (@owned NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftArrayDouble() -> [Double]? {
@@ -169,7 +169,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding34testForcedCastNStoSwiftArrayStringSaySSGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0SayxGs21_ObjectiveCBridgeable10FoundationlsABP016_forceBridgeFromA1Cy01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sa10FoundationE26_forceBridgeFromObjectiveCySo7NSArrayC_SayxGSgz6resulttFZ : $@convention(method) <τ_0_0> (@owned NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftArrayString() -> [String] {
@@ -179,7 +179,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding32testCondCastNStoSwiftArrayStringSaySSGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0SayxGs21_ObjectiveCBridgeable10FoundationlsABP024_conditionallyBridgeFromA1CSb01_A5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0Sa10FoundationE34_conditionallyBridgeFromObjectiveCSbSo7NSArrayC_SayxGSgz6resulttFZ : $@convention(method) <τ_0_0> (@owned NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftArrayString() -> [String]? {
@@ -197,7 +197,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding30testForcedCastNStoSwiftDictInts10DictionaryVyS2iGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0s10DictionaryVyxq_Gs21_ObjectiveCBridgeable10Foundations8HashableRzr0_lsADP016_forceBridgeFromB1Cy01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s10DictionaryV10FoundationE26_forceBridgeFromObjectiveCySo12NSDictionaryC_AByxq_GSgz6resulttFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@owned NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftDictInt() -> [Int: Int] {
@@ -207,7 +207,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding28testCondCastNStoSwiftDictInts10DictionaryVyS2iGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0s10DictionaryVyxq_Gs21_ObjectiveCBridgeable10Foundations8HashableRzr0_lsADP024_conditionallyBridgeFromB1CSb01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s10DictionaryV10FoundationE34_conditionallyBridgeFromObjectiveCSbSo12NSDictionaryC_AByxq_GSgz6resulttFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@owned NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftDictInt() -> [Int: Int]? {
@@ -217,7 +217,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding33testForcedCastNStoSwiftDictDoubles10DictionaryVyS2dGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0s10DictionaryVyxq_Gs21_ObjectiveCBridgeable10Foundations8HashableRzr0_lsADP016_forceBridgeFromB1Cy01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s10DictionaryV10FoundationE26_forceBridgeFromObjectiveCySo12NSDictionaryC_AByxq_GSgz6resulttFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@owned NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftDictDouble() -> [Double: Double] {
@@ -227,7 +227,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding31testCondCastNStoSwiftDictDoubles10DictionaryVyS2dGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0s10DictionaryVyxq_Gs21_ObjectiveCBridgeable10Foundations8HashableRzr0_lsADP024_conditionallyBridgeFromB1CSb01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s10DictionaryV10FoundationE34_conditionallyBridgeFromObjectiveCSbSo12NSDictionaryC_AByxq_GSgz6resulttFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@owned NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftDictDouble() -> [Double: Double]? {
@@ -238,7 +238,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding33testForcedCastNStoSwiftDictStrings10DictionaryVyS2SGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0s10DictionaryVyxq_Gs21_ObjectiveCBridgeable10Foundations8HashableRzr0_lsADP016_forceBridgeFromB1Cy01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s10DictionaryV10FoundationE26_forceBridgeFromObjectiveCySo12NSDictionaryC_AByxq_GSgz6resulttFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@owned NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftDictString() -> [String: String] {
@@ -248,7 +248,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding31testCondCastNStoSwiftDictStrings10DictionaryVyS2SGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0s10DictionaryVyxq_Gs21_ObjectiveCBridgeable10Foundations8HashableRzr0_lsADP024_conditionallyBridgeFromB1CSb01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s10DictionaryV10FoundationE34_conditionallyBridgeFromObjectiveCSbSo12NSDictionaryC_AByxq_GSgz6resulttFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@owned NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftDictString() -> [String: String]? {
@@ -258,7 +258,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding40testForcedCastNSDictStringtoSwiftDictInts10DictionaryVyS2iGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0s10DictionaryVyxq_Gs21_ObjectiveCBridgeable10Foundations8HashableRzr0_lsADP016_forceBridgeFromB1Cy01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s10DictionaryV10FoundationE26_forceBridgeFromObjectiveCySo12NSDictionaryC_AByxq_GSgz6resulttFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@owned NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNSDictStringtoSwiftDictInt() -> [Int: Int] {
@@ -269,7 +269,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding38testCondCastNSDictStringtoSwiftDictInts10DictionaryVyS2iGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0s10DictionaryVyxq_Gs21_ObjectiveCBridgeable10Foundations8HashableRzr0_lsADP024_conditionallyBridgeFromB1CSb01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s10DictionaryV10FoundationE34_conditionallyBridgeFromObjectiveCSbSo12NSDictionaryC_AByxq_GSgz6resulttFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@owned NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNSDictStringtoSwiftDictInt() -> [Int: Int]? {
@@ -286,7 +286,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding29testForcedCastNStoSwiftSetInts0I0VySiGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0s3SetVyxGs21_ObjectiveCBridgeable10Foundations8HashableRzlsADP016_forceBridgeFromB1Cy01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s3SetV10FoundationE26_forceBridgeFromObjectiveCySo5NSSetC_AByxGSgz6resulttFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@owned NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftSetInt() -> Set<Int> {
@@ -296,7 +296,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding27testCondCastNStoSwiftSetInts0I0VySiGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0s3SetVyxGs21_ObjectiveCBridgeable10Foundations8HashableRzlsADP024_conditionallyBridgeFromB1CSb01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s3SetV10FoundationE34_conditionallyBridgeFromObjectiveCSbSo5NSSetC_AByxGSgz6resulttFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@owned NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftSetInt() -> Set<Int>? {
@@ -306,7 +306,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding32testForcedCastNStoSwiftSetDoubles0I0VySdGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0s3SetVyxGs21_ObjectiveCBridgeable10Foundations8HashableRzlsADP016_forceBridgeFromB1Cy01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s3SetV10FoundationE26_forceBridgeFromObjectiveCySo5NSSetC_AByxGSgz6resulttFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@owned NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftSetDouble() -> Set<Double> {
@@ -316,7 +316,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding30testCondCastNStoSwiftSetDoubles0I0VySdGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0s3SetVyxGs21_ObjectiveCBridgeable10Foundations8HashableRzlsADP024_conditionallyBridgeFromB1CSb01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s3SetV10FoundationE34_conditionallyBridgeFromObjectiveCSbSo5NSSetC_AByxGSgz6resulttFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@owned NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftSetDouble() -> Set<Double>? {
@@ -327,7 +327,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding32testForcedCastNStoSwiftSetStrings0I0VySSGyF
 // CHECK-NOT: unconditional_checked
-// CHECK: function_ref @_T0s3SetVyxGs21_ObjectiveCBridgeable10Foundations8HashableRzlsADP016_forceBridgeFromB1Cy01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s3SetV10FoundationE26_forceBridgeFromObjectiveCySo5NSSetC_AByxGSgz6resulttFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@owned NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> ()
 // CHECK: return
 @inline(never)
 public func testForcedCastNStoSwiftSetString() -> Set<String> {
@@ -337,7 +337,7 @@
 
 // CHECK-LABEL: sil [noinline] @_T021bridged_casts_folding30testCondCastNStoSwiftSetStrings0I0VySSGSgyF
 // CHECK-NOT: checked_cast
-// CHECK: function_ref @_T0s3SetVyxGs21_ObjectiveCBridgeable10Foundations8HashableRzlsADP024_conditionallyBridgeFromB1CSb01_B5CTypeQz_xSgz6resulttFZTW
+// CHECK: function_ref @_T0s3SetV10FoundationE34_conditionallyBridgeFromObjectiveCSbSo5NSSetC_AByxGSgz6resulttFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@owned NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> Bool
 // CHECK: return
 @inline(never)
 public func testCondCastNStoSwiftSetString() -> Set<String>? {
diff --git a/test/SILOptimizer/caller_analysis_printer.sil b/test/SILOptimizer/caller_analysis_printer.sil
index b068baa..3d43a0c 100644
--- a/test/SILOptimizer/caller_analysis_printer.sil
+++ b/test/SILOptimizer/caller_analysis_printer.sil
@@ -43,7 +43,7 @@
   return %2 : $()
 }
 
-sil hidden  @call_bottom : $@convention(thin) () -> () {
+sil hidden @call_bottom : $@convention(thin) () -> () {
 bb0:
   %0 = tuple ()
   return %0 : $()
diff --git a/test/SILOptimizer/capture_promotion.swift b/test/SILOptimizer/capture_promotion.swift
index 838cb4d..331814f 100644
--- a/test/SILOptimizer/capture_promotion.swift
+++ b/test/SILOptimizer/capture_promotion.swift
@@ -28,5 +28,5 @@
   return { x + y.foo() + z.x }
 }
 
-// CHECK: sil shared @_T017capture_promotion05test_a1_B0SiycyFSiycfU_Tf2iii_n : $@convention(thin) (Int, @owned Foo, @owned Baz) -> Int
+// CHECK: sil private @_T017capture_promotion05test_a1_B0SiycyFSiycfU_Tf2iii_n : $@convention(thin) (Int, @owned Foo, @owned Baz) -> Int
 
diff --git a/test/SILOptimizer/capture_promotion_generic_context.sil b/test/SILOptimizer/capture_promotion_generic_context.sil
index e0550d0..2b3c8b2 100644
--- a/test/SILOptimizer/capture_promotion_generic_context.sil
+++ b/test/SILOptimizer/capture_promotion_generic_context.sil
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-sil -O %s | %FileCheck %s
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-sil -O -Xllvm -sil-fso-enable-generics=false %s | %FileCheck %s
 
 sil_stage raw
 
@@ -20,7 +20,7 @@
   return %v : $Int
 }
 
-// CHECK-LABEL: sil @call_promotable_box_from_generic
+// CHECK-LABEL: sil {{.*}}@call_promotable_box_from_generic
 // CHECK:         [[F:%.*]] = function_ref @_T014promotable_boxTf2i_n
 // CHECK:         partial_apply [[F]](
 
@@ -67,3 +67,56 @@
   %k = partial_apply %f<U>(%b) : $@convention(thin) <V> (@in V, <τ_0_0> { var τ_0_0 } <Int>) -> Int
   return %k : $@callee_owned (@in U) -> Int
 }
+
+enum E<X> {
+  case None
+  case Some(X)
+}
+
+struct R<T> {
+}
+
+// Check that the capture promotion took place and the function now
+// take argument of a type E<(R<T>) -> Builtin.Int32>, which used
+// to be a slot inside a box.
+// CHECK-LABEL: sil @_T023generic_promotable_box2Tf2nni_n : $@convention(thin) <T> (@in R<T>, @in Builtin.Int32, @owned E<(R<T>) -> Builtin.Int32>) -> () 
+// CHECK:       bb0(%0 : $*R<T>, %1 : $*Builtin.Int32, %2 : $E<(R<T>) -> Builtin.Int32>):
+// CHECK-NOT:     project_box
+// CHECK:         switch_enum %2 : $E<(R<T>) -> Builtin.Int32>
+// CHECK-NOT:     project_box
+// CHECK:       } // end sil function '_T023generic_promotable_box2Tf2nni_n'
+sil @generic_promotable_box2 : $@convention(thin) <T> (@in R<T>, @in Int, <τ_0_0> { var  E<(R<τ_0_0>) -> Int> } <T>) -> () {
+entry(%0: $*R<T>, %1 : $*Int, %b : $<τ_0_0> { var E< (R<τ_0_0>)->Int > } <T>):
+  %a = project_box %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <T>, 0
+  %e = load %a : $*E<(R<T>)->Int>
+  switch_enum %e : $E<(R<T>)->Int>, case #E.Some!enumelt.1 : bb1, default bb2
+bb1(%f : $@callee_owned (@in R<T>) -> @out Int):
+  %t = tuple ()
+  apply %f(%1, %0) : $@callee_owned (@in R<T>) -> @out Int
+  br exit
+bb2:
+  br exit
+exit:
+  %r = tuple ()
+  return %r : $()
+}
+
+// Check that alloc_box was eliminated and a specialized version of the
+// closure is invoked.
+// CHECK-LABEL: sil @call_generic_promotable_box_from_different_generic2
+// CHECK:       bb0(%0 : $*R<T>, %1 : $*E<(R<U>) -> Builtin.Int32>, %2 : $*Builtin.Int32):
+// CHECK:         %3 = load %1 : $*E<(R<U>) -> Builtin.Int32>
+// CHECK:         [[F:%.*]] = function_ref @_T023generic_promotable_box2Tf2nni_n : $@convention(thin) <τ_0_0> (@in R<τ_0_0>, @in Builtin.Int32, @owned E<(R<τ_0_0>) -> Builtin.Int32>) -> ()
+// CHECK-NEXT:    [[CLOSURE:%.*]] = partial_apply [[F]]<U>(%2, %3)
+// CHECK-NEXT:    return [[CLOSURE]]
+
+sil @call_generic_promotable_box_from_different_generic2 : $@convention(thin) <T, U: P> (@in R<T>, @in E<(R<U>)->Int>, @in Int) -> @owned @callee_owned (@in R<U>) -> () {
+entry(%0 : $*R<T>, %1 : $*E<(R<U>)->Int>, %2 : $*Int):
+  destroy_addr %0 : $*R<T>
+  %f = function_ref @generic_promotable_box2 : $@convention(thin) <V> (@in R<V>, @in Int, <τ_0_0> { var E<(R<τ_0_0>)->Int> } <V>) -> ()
+  %b = alloc_box $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <U>
+  %a = project_box %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <U>, 0
+  copy_addr [take] %1 to [initialization] %a : $*E<(R<U>)->Int>
+  %k = partial_apply %f<U>(%2, %b) : $@convention(thin) <V> (@in R<V>, @in Int, <τ_0_0> { var E<(R<τ_0_0>)->Int> } <V>) -> ()
+  return %k : $@callee_owned (@in R<U>) -> ()
+}
diff --git a/test/SILOptimizer/capture_promotion_generic_context_ownership.sil b/test/SILOptimizer/capture_promotion_generic_context_ownership.sil
new file mode 100644
index 0000000..80d9446
--- /dev/null
+++ b/test/SILOptimizer/capture_promotion_generic_context_ownership.sil
@@ -0,0 +1,127 @@
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-sil -O -Xllvm -sil-fso-enable-generics=false %s | %FileCheck %s
+
+sil_stage raw
+
+import Builtin
+
+typealias Int = Builtin.Int32
+
+// rdar://problem/28945854: When a nongeneric closure was formed inside a
+// generic function, the capture promotion pass would erroneously try to
+// apply the generic caller's substitutions to the nongeneric callee, violating
+// invariants.
+
+// CHECK-LABEL: sil @_T014promotable_boxTf2i_n : $@convention(thin) (Builtin.Int32) -> Builtin.Int32
+sil @promotable_box : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
+entry(%b : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %v = load [trivial] %a : $*Int
+  destroy_value %b : $<τ_0_0> { var τ_0_0 } <Int>
+  return %v : $Int
+}
+
+// CHECK-LABEL: sil {{.*}}@call_promotable_box_from_generic
+// CHECK:         [[F:%.*]] = function_ref @_T014promotable_boxTf2i_n
+// CHECK:         partial_apply [[F]](
+
+sil @call_promotable_box_from_generic : $@convention(thin) <T> (@in T, Int) -> @owned @callee_owned () -> Int {
+entry(%0 : @trivial $*T, %1 : @trivial $Int):
+  destroy_addr %0 : $*T
+  %f = function_ref @promotable_box : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %1 to [trivial] %a : $*Int
+  %k = partial_apply %f(%b) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  return %k : $@callee_owned () -> Int
+}
+
+protocol P {}
+
+// CHECK-LABEL: sil @_T022generic_promotable_boxTf2ni_n : $@convention(thin) <T> (@in T, Builtin.Int32) -> Builtin.Int32
+// CHECK:       bb0([[ARG0:%.*]] : @trivial $*T, [[ARG1:%.*]] : @trivial $Builtin.Int32):
+// CHECK-NEXT:    return [[ARG1]] : $Builtin.Int32
+
+sil @generic_promotable_box : $@convention(thin) <T> (@in T, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
+entry(%0 : @trivial $*T, %b : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %v = load [trivial] %a : $*Int
+  destroy_value %b : $<τ_0_0> { var τ_0_0 } <Int>
+  return %v : $Int
+}
+
+// CHECK-LABEL: sil @call_generic_promotable_box_from_different_generic
+// CHECK:       bb0([[ARG0:%.*]] : @trivial $*T, [[ARG1:%.*]] : @trivial $*U, [[ARG2:%.*]] : @trivial $Builtin.Int32):
+// CHECK-NEXT:    destroy_addr [[ARG0]] : $*T
+// CHECK-NEXT:    destroy_addr [[ARG1]] : $*U
+// CHECK:         [[F:%.*]] = function_ref @_T022generic_promotable_boxTf2ni_n : $@convention(thin) <τ_0_0> (@in τ_0_0, Builtin.Int32) -> Builtin.Int32
+// CHECK-NEXT:    [[CLOSURE:%.*]] = partial_apply [[F]]<U>([[ARG2]])
+// CHECK-NEXT:    return [[CLOSURE]]
+
+sil @call_generic_promotable_box_from_different_generic : $@convention(thin) <T, U: P> (@in T, @in U, Int) -> @owned @callee_owned (@in U) -> Int {
+entry(%0 : @trivial $*T, %1 : @trivial $*U, %2 : @trivial $Int):
+  destroy_addr %0 : $*T
+  destroy_addr %1 : $*U
+  %f = function_ref @generic_promotable_box : $@convention(thin) <V> (@in V, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %2 to [trivial] %a : $*Int
+  %k = partial_apply %f<U>(%b) : $@convention(thin) <V> (@in V, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  return %k : $@callee_owned (@in U) -> Int
+}
+
+enum E<X> {
+  case None
+  case Some(X)
+}
+
+struct R<T> {
+}
+
+// Check that the capture promotion took place and the function now
+// take argument of a type  E<(R<T>) -> Builtin.Int32>, which used
+// to be a slot inside a box.
+// CHECK-LABEL: sil @_T023generic_promotable_box2Tf2nni_n : $@convention(thin) <T> (@in R<T>, @in Builtin.Int32, @owned E<(R<T>) -> Builtin.Int32>) -> () 
+// CHECK:       bb0([[ARG0:%.*]] : @trivial $*R<T>, [[ARG1:%.*]] : @trivial $*Builtin.Int32, [[ARG2:%.*]] : @owned $E<(R<T>) -> Builtin.Int32>):
+// CHECK-NOT:     project_box
+// CHECK:         switch_enum [[ARG2]] : $E<(R<T>) -> Builtin.Int32>
+// CHECK-NOT:     project_box
+// CHECK:       } // end sil function '_T023generic_promotable_box2Tf2nni_n'
+sil @generic_promotable_box2 : $@convention(thin) <T> (@in R<T>, @in Int, @owned <τ_0_0> { var E<(R<τ_0_0>) -> Int> } <T>) -> () {
+entry(%0 : @trivial $*R<T>, %1 : @trivial $*Int, %b : @owned $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <T>):
+  %a = project_box %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <T>, 0
+  %e = load [copy] %a : $*E<(R<T>)->Int>
+  switch_enum %e : $E<(R<T>)->Int>, case #E.Some!enumelt.1 : bb1, default bb2
+
+bb1(%f : @owned $@callee_owned (@in R<T>) -> @out Int):
+  apply %f(%1, %0) : $@callee_owned (@in R<T>) -> @out Int
+  br exit
+
+bb2(%original : @owned $E<(R<T>)->Int>):
+  destroy_value %original : $E<(R<T>)->Int>
+  br exit
+
+exit:
+  destroy_value %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <T>
+  %r = tuple ()
+  return %r : $()
+}
+
+// Check that alloc_box was eliminated and a specialized version of the
+// closure is invoked.
+// CHECK-LABEL: sil @call_generic_promotable_box_from_different_generic2
+// CHECK:       bb0([[ARG0:%.*]] : @trivial $*R<T>, [[ARG1:%.*]] : @trivial $*E<(R<U>) -> Builtin.Int32>, [[ARG2:%.*]] : @trivial $*Builtin.Int32):
+// CHECK:         %3 = load [[ARG1]] : $*E<(R<U>) -> Builtin.Int32>
+// CHECK:         [[F:%.*]] = function_ref @_T023generic_promotable_box2Tf2nni_n : $@convention(thin) <τ_0_0> (@in R<τ_0_0>, @in Builtin.Int32, @owned E<(R<τ_0_0>) -> Builtin.Int32>) -> ()
+// CHECK-NEXT:    [[CLOSURE:%.*]] = partial_apply [[F]]<U>(%2, %3)
+// CHECK-NEXT:    return [[CLOSURE]]
+
+sil @call_generic_promotable_box_from_different_generic2 : $@convention(thin) <T, U: P> (@in R<T>, @in E<(R<U>)->Int>, @in Int) -> @owned @callee_owned (@in R<U>) -> () {
+entry(%0 : @trivial $*R<T>, %1 : @trivial $*E<(R<U>)->Int>, %2 : @trivial $*Int):
+  destroy_addr %0 : $*R<T>
+  %f = function_ref @generic_promotable_box2 : $@convention(thin) <V> (@in R<V>, @in Int, @owned <τ_0_0> { var E<(R<τ_0_0>)->Int> } <V>) -> ()
+  %b = alloc_box $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <U>
+  %a = project_box %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <U>, 0
+  copy_addr [take] %1 to [initialization] %a : $*E<(R<U>)->Int>
+  %k = partial_apply %f<U>(%2, %b) : $@convention(thin) <V> (@in R<V>, @in Int, @owned <τ_0_0> { var E<(R<τ_0_0>)->Int> } <V>) -> ()
+  return %k : $@callee_owned (@in R<U>) -> ()
+}
diff --git a/test/SILOptimizer/capture_promotion_ownership.sil b/test/SILOptimizer/capture_promotion_ownership.sil
new file mode 100644
index 0000000..fd7d788
--- /dev/null
+++ b/test/SILOptimizer/capture_promotion_ownership.sil
@@ -0,0 +1,328 @@
+// RUN: %target-sil-opt -enable-sil-verify-all %s -capture-promotion -enable-sil-ownership | %FileCheck %s
+
+// Check to make sure that the process of promoting closure captures results in
+// a correctly cloned and modified closure function body. This test
+// intentionally only includes one promotable closure so that there is minimal
+// ordering dependence in the checked output.
+
+sil_stage raw
+
+import Builtin
+
+struct Int {
+  var value : Builtin.Int64
+}
+
+class Foo {
+  func foo() -> Int
+}
+
+class Bar {
+}
+
+struct Baz {
+  var bar: Bar
+  var x: Int
+}
+
+sil @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
+sil @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
+sil @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz
+sil @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
+
+// CHECK-LABEL: sil @test_capture_promotion
+sil @test_capture_promotion : $@convention(thin) () -> @owned @callee_owned () -> Int {
+bb0:
+  // CHECK: [[BOX1:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Foo>
+  %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Foo>
+  %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Foo>, 0
+  %2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
+  %3 = metatype $@thick Foo.Type
+  %4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo
+  store %4 to [init] %1a : $*Foo
+
+  // CHECK: [[BOX2:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz>
+  %6 = alloc_box $<τ_0_0> { var τ_0_0 } <Baz>
+  %6a = project_box %6 : $<τ_0_0> { var τ_0_0 } <Baz>, 0
+  %7 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz
+  %8 = metatype $@thin Baz.Type
+  %9 = apply %7(%8) : $@convention(thin) (@thin Baz.Type) -> @owned Baz
+  store %9 to [init] %6a : $*Baz
+
+  // CHECK: [[BOX3:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %11 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %11a = project_box %11 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %12 = function_ref @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
+  %13 = metatype $@thin Int.Type
+  %14 = integer_literal $Builtin.Word, 3
+  %15 = apply %12(%14, %13) : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
+  store %15 to [trivial] %11a : $*Int
+
+// CHECK: [[BOX1_COPY:%.*]] = copy_value [[BOX1]]
+// CHECK: [[BOX1_COPY_PB:%.*]] = project_box [[BOX1_COPY]]
+// CHECK: [[BOX2_COPY:%.*]] = copy_value [[BOX2]]
+// CHECK: [[BOX2_COPY_PB:%.*]] = project_box [[BOX2_COPY]]
+// CHECK: [[BOX3_COPY:%.*]] = copy_value [[BOX3]]
+// CHECK: [[BOX3_COPY_PB:%.*]] = project_box [[BOX3_COPY]]
+
+// CHECK-NOT: function_ref @closure0 :
+// CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @_T08closure0Tf2iii_n
+// CHECK-NOT: function_ref @closure0 :
+
+// The Foo variable is loaded from and retained, because it is a reference type
+// CHECK-NEXT: [[LOADFOO:%.*]] = load [copy] [[BOX1_COPY_PB]] : $*Foo
+// CHECK-NEXT: destroy_value [[BOX1_COPY]]
+//
+// The Baz variable is loaded and copied, because it is a non-trivial
+// aggregate type
+// CHECK-NEXT: [[LOADBAZ:%.*]] = load [copy] [[BOX2_COPY_PB]] : $*Baz
+// CHECK-NEXT: destroy_value [[BOX2_COPY]]
+
+// The Int variable is loaded only, because it is trivial
+// CHECK-NEXT: [[LOADINT:%.*]] = load [trivial] [[BOX3_COPY_PB]] : $*Int
+// CHECK-NEXT: destroy_value [[BOX3_COPY]]
+
+// The partial apply has one value argument for each pair of arguments that was
+// previously used to capture and pass the variable by reference
+// CHECK-NEXT: {{.*}} = partial_apply [[CLOSURE_PROMOTE]]([[LOADFOO]], [[LOADBAZ]], [[LOADINT]])
+
+  %17 = function_ref @closure0 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  %18 = copy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo>
+  %19 = copy_value %6 : $<τ_0_0> { var τ_0_0 } <Baz>
+  %20 = copy_value %11 : $<τ_0_0> { var τ_0_0 } <Int>
+  %21 = partial_apply %17(%18, %19, %20) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+
+  destroy_value %11 : $<τ_0_0> { var τ_0_0 } <Int>
+  destroy_value %6 : $<τ_0_0> { var τ_0_0 } <Baz>
+  destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo>
+
+  return %21 : $@callee_owned () -> Int
+}
+
+// CHECK-LABEL: sil @test_capture_promotion_indirect
+sil @test_capture_promotion_indirect : $@convention(thin) () -> @owned @callee_owned () -> @out Int {
+bb0:
+  // CHECK: [[BOX1:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Foo>
+  %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Foo>
+  %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Foo>, 0
+  %2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
+  %3 = metatype $@thick Foo.Type
+  %4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo
+  store %4 to [init] %1a : $*Foo
+
+  // CHECK: [[BOX2:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz>
+  %6 = alloc_box $<τ_0_0> { var τ_0_0 } <Baz>
+  %6a = project_box %6 : $<τ_0_0> { var τ_0_0 } <Baz>, 0
+  %7 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz
+  %8 = metatype $@thin Baz.Type
+  %9 = apply %7(%8) : $@convention(thin) (@thin Baz.Type) -> @owned Baz
+  store %9 to [init] %6a : $*Baz
+
+  // CHECK: [[BOX3:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %11 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %11a = project_box %11 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %12 = function_ref @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
+  %13 = metatype $@thin Int.Type
+  %14 = integer_literal $Builtin.Word, 3
+  %15 = apply %12(%14, %13) : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
+  store %15 to [trivial] %11a : $*Int
+
+  // CHECK: [[BOX1_COPY:%.*]] = copy_value [[BOX1]]
+  // CHECK: [[BOX1_COPY_PB:%.*]] = project_box [[BOX1_COPY]]
+  // CHECK: [[BOX2_COPY:%.*]] = copy_value [[BOX2]]
+  // CHECK: [[BOX2_COPY_PB:%.*]] = project_box [[BOX2_COPY]]
+  // CHECK: [[BOX3_COPY:%.*]] = copy_value [[BOX3]]
+  // CHECK: [[BOX3_COPY_PB:%.*]] = project_box [[BOX3_COPY]]
+
+  // CHECK-NOT: function_ref @closure_indirect_result :
+  // CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @_T023closure_indirect_resultTf2niii_n
+  // CHECK-NOT: function_ref @closure_indirect_result :
+  %17 = function_ref @closure_indirect_result : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> @out Int
+
+  // CHECK-NEXT: [[LOADFOO:%.*]] = load [copy] [[BOX1_COPY_PB]] : $*Foo
+  // CHECK-NEXT: destroy_value [[BOX1_COPY]]
+  // CHECK-NEXT: [[LOADBAZ:%.*]] = load [copy] [[BOX2_COPY_PB]] : $*Baz
+  // CHECK-NEXT: destroy_value [[BOX2_COPY]]
+  // CHECK-NEXT: [[LOADINT:%.*]] = load [trivial] [[BOX3_COPY_PB]] : $*Int
+  // CHECK-NEXT: destroy_value [[BOX3_COPY]]
+  %18 = copy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo>
+  %19 = copy_value %6 : $<τ_0_0> { var τ_0_0 } <Baz>
+  %20 = copy_value %11 : $<τ_0_0> { var τ_0_0 } <Int>
+
+  // The partial apply has one value argument for each pair of arguments that was
+  // previously used to capture and pass the variable by reference
+  // CHECK-NEXT: {{.*}} = partial_apply [[CLOSURE_PROMOTE]]([[LOADFOO]], [[LOADBAZ]], [[LOADINT]])
+  %21 = partial_apply %17(%18, %19, %20) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> @out Int
+
+  destroy_value %11 : $<τ_0_0> { var τ_0_0 } <Int>
+  destroy_value %6 : $<τ_0_0> { var τ_0_0 } <Baz>
+  destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo>
+
+  return %21 : $@callee_owned () -> @out Int
+}
+
+// CHECK-LABEL: sil private @_T08closure0Tf2iii_n : $@convention(thin) (@owned Foo, @owned Baz, Int) -> Int {
+// CHECK: bb0([[ORIGINAL_ARG0:%.*]] : @owned $Foo, [[ORIGINAL_ARG1:%.*]] : @owned $Baz, [[ARG2:%.*]] : @trivial $Int):
+// CHECK:   [[ARG0:%.*]] = begin_borrow [[ORIGINAL_ARG0]]
+// CHECK:   [[ARG1:%.*]] = begin_borrow [[ORIGINAL_ARG1]]
+// CHECK:   [[DUMMY_FUNC:%.*]] = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
+
+// CHECK:   [[ARG0_COPY:%.*]] = copy_value [[ARG0]]
+// CHECK:   [[METHOD_FOO:%.*]] = class_method [[ARG0_COPY]] : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
+// CHECK:   [[BORROWED_ARG0_COPY:%.*]] = begin_borrow [[ARG0_COPY]]
+// CHECK:   [[APPLY_FOO:%.*]] = apply [[METHOD_FOO]]([[BORROWED_ARG0_COPY]]) : $@convention(method) (@guaranteed Foo) -> Int
+// CHECK:   end_borrow [[BORROWED_ARG0_COPY]] from [[ARG0_COPY]]
+// CHECK:   destroy_value [[ARG0_COPY]]
+
+// CHECK: [[EXTRACT_BAZ_X:%.*]] = struct_extract [[ARG1]] : $Baz, #Baz.x
+// CHECK: [[RETVAL:%.*]] = apply [[DUMMY_FUNC]]([[APPLY_FOO]], [[EXTRACT_BAZ_X]], {{.*}}) : $@convention(thin) (Int, Int, Int) -> Int
+
+// The release of %4 is removed because the Int type is trivial
+
+// The release of %2 is replaced by a release_value of the Baz argument, since
+// it is a non-trivial aggregate
+// CHECK: end_borrow [[ARG1]] from [[ORIGINAL_ARG1]]
+// CHECK: destroy_value [[ORIGINAL_ARG1]] : $Baz
+
+// The release of %0 is replaced by a strong_release of the Foo argument, since
+// it is a reference type
+// CHECK: end_borrow [[ARG0]] from [[ORIGINAL_ARG0]]
+// CHECK: destroy_value [[ORIGINAL_ARG0]]
+// CHECK: return [[RETVAL]] : $Int
+// CHECK: } // end sil function '_T08closure0Tf2iii_n'
+
+sil private @closure0 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
+bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Foo>, %2 : @owned $<τ_0_0> { var τ_0_0 } <Baz>, %4 : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Foo>, 0
+  %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } <Baz>, 0
+  %5 = project_box %4 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %6 = tuple ()
+  // function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int
+  %7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
+  %8 = load [copy] %1 : $*Foo
+  %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
+  %9 = begin_borrow %8 : $Foo
+  %11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
+  end_borrow %9 from %8 : $Foo, $Foo
+  destroy_value %8 : $Foo
+  %12 = struct_element_addr %3 : $*Baz, #Baz.x
+  %13 = load [trivial] %12 : $*Int
+  %14 = load [trivial] %5 : $*Int
+  %15 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int
+  destroy_value %4 : $<τ_0_0> { var τ_0_0 } <Int>
+  destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Baz>
+  destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Foo>
+  return %15 : $Int
+}
+
+// The closure in this function is not promotable because it mutates its argument
+
+// CHECK-LABEL: sil @test_unpromotable
+sil @test_unpromotable : $@convention(thin) () -> @owned @callee_owned () -> Int {
+bb0:
+  %0 = tuple ()
+  %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Foo>
+  %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Foo>, 0
+  %2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
+  %3 = metatype $@thick Foo.Type
+  %4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo
+  store %4 to [init] %1a : $*Foo
+  %17 = function_ref @closure1 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>) -> Int
+  %18 = copy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo>
+  // CHECK: partial_apply {{%.*}}({{%.*}})
+  %21 = partial_apply %17(%18) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>) -> Int
+  destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo>
+  return %21 : $@callee_owned () -> Int
+}
+
+sil @mutate_foo : $@convention(thin) (@inout Foo) -> ()
+
+sil private @closure1 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>) -> Int {
+bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Foo>):
+  %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Foo>, 0
+  %6 = tuple ()
+  // function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int
+  %7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
+  %8 = load [copy] %1 : $*Foo
+  %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
+  %9 = begin_borrow %8 : $Foo
+  %11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
+  end_borrow %9 from %8 : $Foo, $Foo
+  destroy_value %8 : $Foo
+  %12 = function_ref @mutate_foo : $@convention(thin) (@inout Foo) -> ()
+  %13 = apply %12(%1) : $@convention(thin) (@inout Foo) -> ()
+  destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Foo>
+  return %11 : $Int
+}
+
+sil @apply : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
+
+// CHECK-LABEL: sil @captureWithinGeneric
+sil @captureWithinGeneric : $@convention(thin) <T> (@inout Int, @inout Int) -> () {
+// CHECK: bb0
+bb0(%0 : @trivial $*Int, %1 : @trivial $*Int):
+  %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  copy_addr %0 to [initialization] %2a : $*Int
+  %4 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  copy_addr %1 to [initialization] %4a : $*Int
+  %6 = function_ref @apply : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
+  // CHECK: [[PROMOTED:%[0-9a-zA-Z]+]] = function_ref @_T027closureWithGenericSignatureTf2ni_n : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <Int>, Int) -> ()
+  %7 = function_ref @closureWithGenericSignature : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <Int>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
+  %8 = copy_value %4 : $<τ_0_0> { var τ_0_0 } <Int>
+  %9 = copy_value %2 : $<τ_0_0> { var τ_0_0 } <Int>
+  // CHECK: partial_apply [[PROMOTED]]<{{[^>]+}}>(
+  %10 = partial_apply %7<T>(%8, %9) : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <Int>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
+  %11 = apply %6(%10) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
+  copy_addr %4a to %1 : $*Int
+  destroy_value %4 : $<τ_0_0> { var τ_0_0 } <Int>
+  copy_addr %2a to %0 : $*Int
+  destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Int>
+  %16 = tuple ()
+  return %16 : $()
+}
+
+// CHECK: sil @_T027closureWithGenericSignatureTf2ni_n : $@convention(thin) <{{[^>]+}}> (@owned <τ_0_0> { var τ_0_0 } <Int>, Int) -> ()
+sil @closureWithGenericSignature : $@convention(thin) <T> (@owned <τ_0_0> { var τ_0_0 } <Int>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> () {
+bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Int>, %2 : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %4 = function_ref @_T0s1poiSiSi_SitF : $@convention(thin) (Int, Int) -> Int
+  %5 = load [trivial] %3 : $*Int
+  %6 = load [trivial] %3 : $*Int
+  %7 = apply %4(%5, %6) : $@convention(thin) (Int, Int) -> Int
+  assign %7 to %1 : $*Int
+  destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Int>
+  destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Int>
+  %11 = tuple ()
+  return %11 : $()
+}
+
+sil [transparent] [serialized] @_T0s1poiSiSi_SitF : $@convention(thin) (Int, Int) -> Int
+
+
+sil private @closure_indirect_result : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> @out Int {
+bb0(%0: @trivial $*Int, %1 : @owned $<τ_0_0> { var τ_0_0 } <Foo>, %2 : @owned $<τ_0_0> { var τ_0_0 } <Baz>, %4 : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %17 = project_box %1 : $<τ_0_0> { var τ_0_0 } <Foo>, 0
+  %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } <Baz>, 0
+  %5 = project_box %4 : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  // function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int
+  %7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
+  %8 = load [copy] %17 : $*Foo
+  %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
+  %9 = begin_borrow %8 : $Foo
+  %11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
+  end_borrow %9 from %8 : $Foo, $Foo
+  destroy_value %8 : $Foo
+  %12 = struct_element_addr %3 : $*Baz, #Baz.x
+  %13 = load [trivial] %12 : $*Int
+  %14 = load [trivial] %5 : $*Int
+  %15 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int
+  destroy_value %4 : $<τ_0_0> { var τ_0_0 } <Int>
+  destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Baz>
+  destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo>
+  store %15 to [trivial] %0 : $*Int
+  %16 = tuple()
+  return %16 : $()
+}
diff --git a/test/SILOptimizer/capture_promotion_ownership.swift b/test/SILOptimizer/capture_promotion_ownership.swift
new file mode 100644
index 0000000..0df9923
--- /dev/null
+++ b/test/SILOptimizer/capture_promotion_ownership.swift
@@ -0,0 +1,37 @@
+// RUN: %target-swift-frontend %s -enable-sil-ownership -disable-sil-linking -emit-sil -o - -verify | %FileCheck %s
+
+// NOTE: We add -disable-sil-linking to the compile line to ensure that we have
+// access to declarations for standard library types, but not definitions. This
+// ensures that we are able to safely use standard library types for this test
+// without needing the standard library to be ownership correct in its body.
+
+class Foo {
+  func foo() -> Int {
+    return 1
+  }
+}
+
+class Bar {
+}
+
+struct Baz {
+  var bar = Bar()
+  var x = 42
+}
+
+// CHECK: sil hidden @_T027capture_promotion_ownership05test_a1_B0SiycyF
+func test_capture_promotion() -> () -> Int {
+  var x : Int = 1; x = 1
+  var y : Foo = Foo(); y = Foo()
+  var z : Baz = Baz(); z = Baz()
+
+// CHECK-NOT: alloc_box
+
+// CHECK: [[CLOSURE0_PROMOTE0:%.*]] = function_ref @_T027capture_promotion_ownership05test_a1_B0SiycyFSiycfU_Tf2iii_n
+// CHECK: partial_apply [[CLOSURE0_PROMOTE0]]({{%[0-9]*}}, {{%[0-9]*}}, {{%[0-9]*}})
+
+  return { x + y.foo() + z.x }
+}
+
+// CHECK: sil private @_T027capture_promotion_ownership05test_a1_B0SiycyFSiycfU_Tf2iii_n : $@convention(thin) (Int, @owned Foo, @owned Baz) -> Int
+
diff --git a/test/SILOptimizer/cast_folding_no_bridging.sil b/test/SILOptimizer/cast_folding_no_bridging.sil
index 640a543..47dffe2 100644
--- a/test/SILOptimizer/cast_folding_no_bridging.sil
+++ b/test/SILOptimizer/cast_folding_no_bridging.sil
@@ -88,7 +88,7 @@
 // CHECK: bb0(
 // CHECK-NEXT: [[T0:%.*]] = load %1 : $*CFString
 // CHECK-NEXT: [[T1:%.*]] = unchecked_ref_cast [[T0]] : $CFString to $NSString
-// CHECK:      [[FN:%.*]] = function_ref @_T0SSs21_ObjectiveCBridgeable10FoundationsAAP024_conditionallyBridgeFromA1CSb01_A5CTypeQz_xSgz6resulttFZTW : $@convention(witness_method) (@owned NSString, @inout Optional<String>, @thick String.Type) -> Bool
+// CHECK:      [[FN:%.*]] = function_ref @_T0SS10FoundationE34_conditionallyBridgeFromObjectiveCSbSo8NSStringC_SSSgz6resulttFZ : $@convention(method) (@owned NSString, @inout Optional<String>, @thin String.Type) -> Bool
 // CHECK: apply [[FN]]([[T1]], {{.*}}, {{.*}})
 sil @testCFToSwift : $@convention(thin) (@in CFString) -> @out String {
 bb0(%0 : $*String, %1 : $*CFString):
diff --git a/test/SILOptimizer/dead_array_elim.sil b/test/SILOptimizer/dead_array_elim.sil
index e2088c0..baab325 100644
--- a/test/SILOptimizer/dead_array_elim.sil
+++ b/test/SILOptimizer/dead_array_elim.sil
@@ -216,3 +216,37 @@
   return %18 : $()
 }
 
+// CHECK-LABEL: sil @dead_array_in_single_cycle_loop
+// CHECK: bb0(%0 : $TrivialDestructor):
+// CHECK-NEXT: br bb1
+// CHECK: bb1:
+// CHECK-NEXT: strong_retain %0
+// CHECK-NEXT: strong_release %0
+// CHECK-NEXT: cond_br
+// CHECK: bb2:
+// CHECK-NEXT: tuple
+// CHECK-NEXT: return
+sil @dead_array_in_single_cycle_loop : $@convention(thin) (@guaranteed TrivialDestructor) -> () {
+bb0(%0 : $TrivialDestructor):
+  br bb1
+
+bb1:
+  %2 = integer_literal $Builtin.Word, 2
+  %3 = function_ref @allocArray : $@convention(thin) <τ_0_0> (Builtin.Word) -> @owned (Array<τ_0_0>, Builtin.RawPointer)
+  %4 = apply %3<TrivialDestructor>(%2) : $@convention(thin) <τ_0_0> (Builtin.Word) -> @owned (Array<τ_0_0>, Builtin.RawPointer)
+  %5 = tuple_extract %4 : $(Array<TrivialDestructor>, Builtin.RawPointer), 0
+  %6 = tuple_extract %4 : $(Array<TrivialDestructor>, Builtin.RawPointer), 1
+  %7 = pointer_to_address %6 : $Builtin.RawPointer to [strict] $*TrivialDestructor
+  %13 = struct_extract %5 : $Array<TrivialDestructor>, #Array._buffer
+  %14 = struct_extract %13 : $_ArrayBuffer<TrivialDestructor>, #_ArrayBuffer._storage
+  %15 = struct_extract %14 : $_BridgeStorage<_ContiguousArrayStorageBase, _NSArrayCore>, #_BridgeStorage.rawValue
+  strong_retain %0 : $TrivialDestructor
+  store %0 to %7 : $*TrivialDestructor
+  strong_release %15 : $Builtin.BridgeObject
+  cond_br undef, bb1, bb2
+
+bb2:
+  %18 = tuple ()
+  return %18 : $()
+}
+
diff --git a/test/SILOptimizer/dead_store_elim.sil b/test/SILOptimizer/dead_store_elim.sil
index 4031856..af7dcae 100644
--- a/test/SILOptimizer/dead_store_elim.sil
+++ b/test/SILOptimizer/dead_store_elim.sil
@@ -1389,3 +1389,47 @@
   %14 = tuple ()
   return %14 : $()
 }
+
+// CHECK-LABEL: test_is_unique
+// CHECK: %1 = alloc_stack
+// CHECK: store %0 to %1 
+// CHECK: is_unique
+// CHECK: return
+sil @test_is_unique : $@convention(thin) (@guaranteed AB) -> Builtin.Int1 {
+bb0(%0 : $AB):                     // Preds: bb6 bb5 bb4 bb3
+  %1 = alloc_stack $AB
+  store %0 to %1 : $*AB
+  %2 = is_unique %1 : $*AB
+  dealloc_stack %1 : $*AB
+  return %2 : $Builtin.Int1
+}
+
+// CHECK-LABEL: test_is_unique_or_pinned
+// CHECK: %1 = alloc_stack
+// CHECK: store %0 to %1 
+// CHECK: is_unique_or_pinned
+// CHECK: return
+sil @test_is_unique_or_pinned : $@convention(thin) (@guaranteed AB) -> Builtin.Int1 {
+bb0(%0 : $AB):                     // Preds: bb6 bb5 bb4 bb3
+  %1 = alloc_stack $AB
+  store %0 to %1 : $*AB
+  %2 = is_unique_or_pinned %1 : $*AB
+  dealloc_stack %1 : $*AB
+  return %2 : $Builtin.Int1
+}
+
+// CHECK-LABEL: dont_remove_store
+// CHECK: load
+// CHECK: store
+// CHECK: value_metatype
+// CHECK: return
+sil @dont_remove_store : $@convention(thin) (@in_guaranteed foo) -> () {
+bb0(%0 : $*foo):
+  %1 = alloc_stack $foo
+  %2 = load %0 : $*foo
+  store %2 to %1 : $*foo
+  %3 = value_metatype $@thick foo.Type, %1 : $*foo
+  dealloc_stack %1 : $*foo
+  %20 = tuple()
+  return %20 : $()
+}
diff --git a/test/SILOptimizer/devirt_materializeForSet.swift b/test/SILOptimizer/devirt_materializeForSet.swift
index 1ce6d48..12fdf59 100644
--- a/test/SILOptimizer/devirt_materializeForSet.swift
+++ b/test/SILOptimizer/devirt_materializeForSet.swift
@@ -3,7 +3,7 @@
 // Check that compiler does not crash on the devirtualization of materializeForSet methods
 // and produces a correct code.
 
-// CHECK-LABEL: sil [transparent] [serialized] [thunk] @_T024devirt_materializeForSet7BaseFooCAA0F0A2aDP3barSSfmTW
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @_T024devirt_materializeForSet7BaseFooCAA0F0A2aDP3barSSfmTW
 // CHECK: checked_cast_br [exact] %{{.*}} : $BaseFoo to $ChildFoo
 // CHECK: thin_function_to_pointer %{{.*}} : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout ChildFoo, @thick ChildFoo.Type) -> () to $Builtin.RawPointer
 // CHECK: enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, %{{.*}} : $Builtin.RawPointer
diff --git a/test/SILOptimizer/devirt_single_module_in_multiple_files.swift b/test/SILOptimizer/devirt_single_module_in_multiple_files.swift
index e4cdbeb..1a59059 100644
--- a/test/SILOptimizer/devirt_single_module_in_multiple_files.swift
+++ b/test/SILOptimizer/devirt_single_module_in_multiple_files.swift
@@ -6,12 +6,12 @@
   e.evaluate(1)
 }
 
-// CHECK-LABEL: sil shared @_T038devirt_single_module_in_multiple_files9EvaluatorCACycfcSiycfU_
+// CHECK-LABEL: sil private @_T038devirt_single_module_in_multiple_files9EvaluatorCACycfcSiycfU_
 // CHECK: %{{.*}} = class_method %{{.*}} : $Problem1, #Problem1.run!1 : (Problem1) -> () -> Int, $@convention(method) (@guaranteed Problem1) -> Int
 // CHECK-NEXT: apply
 // CHECK: return
 
-// CHECK-LABEL: sil shared @_T038devirt_single_module_in_multiple_files9EvaluatorCACycfcSiycfU0_
+// CHECK-LABEL: sil private @_T038devirt_single_module_in_multiple_files9EvaluatorCACycfcSiycfU0_
 // CHECK: %{{.*}} = class_method %{{.*}} : $Problem2, #Problem2.run!1 : (Problem2) -> () -> Int, $@convention(method) (@guaranteed Problem2) -> Int
 // CHECK-NEXT: apply
 // CHECK: return
diff --git a/test/SILOptimizer/devirt_specialized_inherited_interplay.swift b/test/SILOptimizer/devirt_specialized_inherited_interplay.swift
index d71b2d45..d6ead9e 100644
--- a/test/SILOptimizer/devirt_specialized_inherited_interplay.swift
+++ b/test/SILOptimizer/devirt_specialized_inherited_interplay.swift
@@ -12,13 +12,7 @@
 
 // CHECK-LABEL: sil @_T038devirt_specialized_inherited_interplay6driveryyF : $@convention(thin) () -> () {
 // CHECK: bb0:
-// CHECK: [[A3:%[0-9]+]] = alloc_ref [stack] $A3<S>
-// CHECK: [[A4:%[0-9]+]] = alloc_ref [stack] $A4<S>
-// CHECK: [[A5:%[0-9]+]] = alloc_ref [stack] $A5<S>
-// CHECK: [[B1:%[0-9]+]] = alloc_ref [stack] $B1<S>
-// CHECK: [[B2:%[0-9]+]] = alloc_ref [stack] $B2<S>
-// CHECK: [[B3:%[0-9]+]] = alloc_ref [stack] $B3<S>
-// CHECK: [[B4:%[0-9]+]] = alloc_ref [stack] $B4<S>
+// CHECK-NOT: alloc_ref
 // CHECK: [[F0:%[0-9]+]] = function_ref @unknown0 : $@convention(thin) () -> ()
 // CHECK: apply [[F0]]
 // CHECK: apply [[F0]]
@@ -45,13 +39,7 @@
 // CHECK: [[F8:%[0-9]+]] = function_ref @unknown8 :
 // CHECK: apply [[F8]]
 // CHECK: apply [[F8]]
-// CHECK: dealloc_ref [stack] [[B4]]
-// CHECK: dealloc_ref [stack] [[B3]]
-// CHECK: dealloc_ref [stack] [[B2]]
-// CHECK: dealloc_ref [stack] [[B1]]
-// CHECK: dealloc_ref [stack] [[A5]]
-// CHECK: dealloc_ref [stack] [[A4]]
-// CHECK: dealloc_ref [stack] [[A3]]
+// CHECK-NOT: dealloc_ref
 // CHECK: return
 
 @_silgen_name("unknown0")
diff --git a/test/SILOptimizer/devirt_unbound_generic.swift b/test/SILOptimizer/devirt_unbound_generic.swift
index 982fc3d..974c4ea 100644
--- a/test/SILOptimizer/devirt_unbound_generic.swift
+++ b/test/SILOptimizer/devirt_unbound_generic.swift
@@ -1,24 +1,24 @@
-// RUN: %target-swift-frontend -emit-sil -O %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-sorted-sil -emit-sil -O %s | %FileCheck %s
 
 // We used to crash on this when trying to devirtualize t.boo(a, 1),
-// because it is an "apply" with unbound generic arguments and
-// devirtualizer is not able to devirtualize unbound generic
-// invocations yet.
+// because it is an "apply" with replacement types that contain
+// archetypes, and the devirtualizer was not able to handle that
+// case correctly.
 //
 // rdar://19912272
 
 protocol P {
-   associatedtype Node
+  associatedtype Node
 }
 
 class C<T:P> {
-   typealias Node = T.Node
+  typealias Node = T.Node
 
-   func foo(_ n:Node) {
-   }
+  func foo(_ n:Node) {
+  }
 
-   func boo<S>(_ n:Node, s:S) {
-   }
+  func boo<S>(_ n:Node, s:S) {
+  }
 }
 
 func test1<T>(_ t:C<T>, a: T.Node) {
@@ -42,14 +42,25 @@
   }
 }
 
+// Check that testDevirt is specialized and uses speculative devirtualization.
+// CHECK-LABEL: sil shared [noinline] @{{.*}}testDevirt
+// CHECK: checked_cast_br [exact] %{{.*}} : $CC<Int32> to $CC<Int32>
+// CHECK: class_method
+// CHECK: }
+@inline(never)
+public func testDevirt<T>(_ c: CC<T>) -> T? {
+  return c.next()
+}
+
+
 // Check that the instance method Derived<T>.foo can be devirtualized, because Derived.foo is an internal function,
 // Derived has no subclasses and it is a WMO compilation.
-// CHECK: sil hidden [noinline] @_T022devirt_unbound_generic5test2yAA7DerivedCyxGlF
+// CHECK-LABEL: sil hidden [noinline] @_T022devirt_unbound_generic5test2yAA7DerivedCyxGlF{{.*}}
 // CHECK-NOT: class_method
 // CHECK-NOT: witness_method
 // CHECK-NOT: apply
 // CHECK: return
-// CHEC: end sil function '_T022devirt_unbound_generic5test2yAA7DerivedCyxGlF'
+// CHECK: end sil function '_T022devirt_unbound_generic5test2yAA7DerivedCyxGlF{{.*}}'
 @inline(never)
 func test2<T>(_ d: Derived<T>) {
    d.foo()
@@ -61,12 +72,12 @@
 
 // Check that the class method Derived<T>.boo can be devirtualized, because Derived.boo is an internal function,
 // Derived has no subclasses and it is a WMO compilation.
-// CHECK: sil hidden [noinline] @_T022devirt_unbound_generic5test3yAA7DerivedCyxGlF
+// CHECK: sil hidden [noinline] @_T022devirt_unbound_generic5test3yAA7DerivedCyxGlF{{.*}}
 // CHECK-NOT: class_method
 // CHECK-NOT: witness_method
 // CHECK-NOT: apply
 // CHECK: return
-// CHECK: end sil function '_T022devirt_unbound_generic5test3yAA7DerivedCyxGlF'
+// CHECK: end sil function '_T022devirt_unbound_generic5test3yAA7DerivedCyxGlF{{.*}}'
 @inline(never)
 func test3<T>(_ d: Derived<T>) {
    type(of: d).boo()
@@ -150,7 +161,7 @@
 }
 
 // Check that c.next() inside test4 gets completely devirtualized.
-// CHECK-LABEL: sil @{{.*}}test4
+// CHECK-LABEL: sil @{{.*}}test4{{.*}}
 // CHECK-NOT: class_method
 // CHECK: return
 public func test4() -> Int32? {
@@ -162,16 +173,6 @@
   return testDevirt(D<E>())
 }
 
-// Check that testDevirt is specialized and uses speculative devirtualization.
-// CHECK-LABEL: sil shared [noinline] @{{.*}}testDevirt
-// CHECK: checked_cast_br [exact] %{{.*}} : $CC<Int32> to $CC<Int32>
-// CHECK: class_method
-// CHECK: }
-@inline(never)
-public func testDevirt<T>(_ c: CC<T>) -> T? {
-  return c.next()
-}
-
 // The compiler used to crash on this code, because of
 // generic types involved in the devirtualization.
 //
diff --git a/test/SILOptimizer/functionsigopts.sil b/test/SILOptimizer/functionsigopts.sil
index 1418247..ad42d87 100644
--- a/test/SILOptimizer/functionsigopts.sil
+++ b/test/SILOptimizer/functionsigopts.sil
@@ -49,7 +49,23 @@
   var bottom : foo
 }
 
+public protocol P {
+  func foo() -> Int64
+}
+
+public protocol KlassFoo : class {
+  func bar() -> Int64
+}
+
+public class KlassBar : KlassFoo {
+  public func bar() -> Int64
+  deinit
+  init()
+}
+
 sil @use_Int : $@convention(thin) (Int) -> ()
+sil @use_Int64 : $@convention(thin) (Int64) -> ()
+sil @use_Generic : $@convention(thin) <T>(@in_guaranteed T) -> ()
 
 
 // CHECK-LABEL: sil [thunk] [always_inline] @argument_with_incomplete_epilogue_release
@@ -1479,6 +1495,212 @@
   return %9999 : $()
 }
 
+// CHECK-LABEL: sil hidden [thunk] [always_inline] @generic_owned_to_guaranteed : $@convention(thin) <T where T : KlassFoo> (@owned T) -> Int64
+// CHECK: function_ref @_T027generic_owned_to_guaranteedTf4g_n 
+// CHECK: apply
+// CHECK: release_value
+// CHECK: end sil function 'generic_owned_to_guaranteed'
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_owned_to_guaranteed_caller : $@convention(thin) <T where T : KlassFoo> (@owned T) -> Int64 
+// CHECK: function_ref @_T034generic_owned_to_guaranteed_callerTf4g_n 
+// CHECK: apply
+// CHECK: release_value
+// CHECK: end sil function 'generic_owned_to_guaranteed_caller'
+
+sil hidden [noinline] @generic_owned_to_guaranteed : $@convention(thin) <T where T : KlassFoo> (@owned T) -> Int64 {
+bb0(%0 : $T):
+  %2 = witness_method $T, #KlassFoo.bar!1 : <Self where Self : KlassFoo> (Self) -> () -> Int64 : $@convention(witness_method) <τ_0_0 where τ_0_0 : KlassFoo> (@guaranteed τ_0_0) -> Int64
+  %3 = apply %2<T>(%0) : $@convention(witness_method) <τ_0_0 where τ_0_0 : KlassFoo> (@guaranteed τ_0_0) -> Int64
+  strong_release %0 : $T
+  return %3 : $Int64
+}
+
+sil @generic_owned_to_guaranteed_caller : $@convention(thin) <T where T : KlassFoo> (@owned T) -> Int64 {
+bb0(%0 : $T):
+  %2 = function_ref @generic_owned_to_guaranteed : $@convention(thin) <τ_0_0 where τ_0_0 : KlassFoo> (@owned τ_0_0) -> Int64
+  strong_retain %0 : $T
+  %4 = apply %2<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : KlassFoo> (@owned τ_0_0) -> Int64
+  %5 = function_ref @generic_owned_to_guaranteed : $@convention(thin) <τ_0_0 where τ_0_0 : KlassFoo> (@owned τ_0_0) -> Int64
+  strong_retain %0 : $T
+  %7 = apply %5<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : KlassFoo> (@owned τ_0_0) -> Int64
+  %8 = struct_extract %4 : $Int64, #Int64._value
+  %9 = struct_extract %7 : $Int64, #Int64._value
+  %10 = integer_literal $Builtin.Int1, -1
+  %11 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %9 : $Builtin.Int64, %10 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %12 = tuple_extract %11 : $(Builtin.Int64, Builtin.Int1), 0
+  %13 = tuple_extract %11 : $(Builtin.Int64, Builtin.Int1), 1
+  cond_fail %13 : $Builtin.Int1
+  %15 = struct $Int64 (%12 : $Builtin.Int64)
+  strong_release %0 : $T
+  return %15 : $Int64
+}
+
+// CHECK-LABEL: sil hidden [thunk] [always_inline] @generic_in_to_guaranteed : $@convention(thin) <T where T : P> (@in T) -> Int64
+// CHECK: function_ref @_T024generic_in_to_guaranteedTf4g_n 
+// CHECK: apply
+// CHECK: destroy_addr
+// CHECK: end sil function 'generic_in_to_guaranteed'
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_in_to_guaranteed_caller : $@convention(thin) <T where T : P> (@in T) -> Int64 
+// CHECK: function_ref @_T031generic_in_to_guaranteed_callerTf4g_n 
+// CHECK: apply
+// CHECK: destroy_addr
+// CHECK: end sil function 'generic_in_to_guaranteed_caller'
+
+sil hidden [noinline] @generic_in_to_guaranteed : $@convention(thin) <T where T : P> (@in T) -> Int64 {
+bb0(%0 : $*T):
+  %2 = witness_method $T, #P.foo!1 : <Self where Self : P> (Self) -> () -> Int64 : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
+  %3 = apply %2<T>(%0) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
+  destroy_addr %0 : $*T
+  return %3 : $Int64
+}
+
+sil @generic_in_to_guaranteed_caller : $@convention(thin) <T where T : P> (@in T) -> Int64 {
+bb0(%0 : $*T):
+  %2 = function_ref @generic_in_to_guaranteed : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0) -> Int64
+  %3 = alloc_stack $T
+  copy_addr %0 to [initialization] %3 : $*T
+  %5 = apply %2<T>(%3) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0) -> Int64
+  dealloc_stack %3 : $*T
+  %7 = apply %2<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0) -> Int64
+  %8 = struct_extract %5 : $Int64, #Int64._value
+  %9 = struct_extract %7 : $Int64, #Int64._value
+  %10 = integer_literal $Builtin.Int1, -1
+  %11 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %9 : $Builtin.Int64, %10 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %12 = tuple_extract %11 : $(Builtin.Int64, Builtin.Int1), 0
+  %13 = tuple_extract %11 : $(Builtin.Int64, Builtin.Int1), 1
+  cond_fail %13 : $Builtin.Int1
+  %15 = struct $Int64 (%12 : $Builtin.Int64)
+  return %15 : $Int64
+}
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_func_with_dead_non_generic_arg : $@convention(thin) <T> (@owned foo, @in T) -> ()
+// CHECK: function_ref @_T0027generic_func_with_dead_non_A4_argTf4dd_n : $@convention(thin) () -> ()
+// Call the specialization which is not polymorphic.
+// CHECK: apply
+// CHECK: destroy_addr
+// CHECK: end sil function 'generic_func_with_dead_non_generic_arg'
+sil [noinline] @generic_func_with_dead_non_generic_arg : $@convention(thin) <T> (@owned foo, @in T) -> () {
+bb0(%0 : $foo, %1 : $*T):
+  destroy_addr %1 : $*T
+  %r = tuple()
+  return %r : $()
+}
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_func_with_dead_generic_arg : $@convention(thin) <T> (Int64, @in T) -> Int64
+// CHECK: function_ref @_T0023generic_func_with_dead_A4_argTf4nd_n : $@convention(thin) (Int64) -> Int64 
+// Call the specialization which is not polymorphic.
+// CHECK: apply
+// CHECK: destroy_addr
+// CHECK: end sil function 'generic_func_with_dead_generic_arg'
+sil [noinline] @generic_func_with_dead_generic_arg : $@convention(thin) <T> (Int64, @in T) -> Int64 {
+bb0(%0 : $Int64, %1 : $*T):
+  destroy_addr %1 : $*T
+  return %0 : $Int64
+}
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_func_with_unused_generic_param_and_non_generic_arg : $@convention(thin) <T> (Int64) -> Int64 
+// CHECK: function_ref @_T0025generic_func_with_unused_a15_param_and_non_A4_argTf4n_n : $@convention(thin) (Int64) -> Int64 
+// Call the specialization which is not polymorphic.
+// CHECK: apply
+// CHECK: end sil function 'generic_func_with_unused_generic_param_and_non_generic_arg'
+sil [noinline] @generic_func_with_unused_generic_param_and_non_generic_arg : $@convention(thin) <T> (Int64) -> Int64 {
+bb0(%0 : $Int64):
+  return %0 : $Int64
+}
+
+sil [noinline] @generic_func_with_unused_generic_param_and_non_generic_arg_caller : $@convention(thin) <T> (Int64) -> Int64 {
+bb0(%0 : $Int64):
+  %f = function_ref @generic_func_with_unused_generic_param_and_non_generic_arg : $@convention(thin) <T> (Int64) -> Int64 
+  %r = apply %f<T>(%0) : $@convention(thin) <T> (Int64) -> Int64 
+  return %r : $Int64
+}
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_func_with_unused_generic_param_and_dead_non_generic_arg : $@convention(thin) <T> (Int64, Int64) -> Int64
+// CHECK: function_ref @_T0025generic_func_with_unused_a20_param_and_dead_non_A4_argTf4nd_n : $@convention(thin) (Int64) -> Int64 
+// Call the specialization which is not polymorphic.
+// CHECK: apply
+// CHECK: end sil function 'generic_func_with_unused_generic_param_and_dead_non_generic_arg'
+sil [noinline] @generic_func_with_unused_generic_param_and_dead_non_generic_arg : $@convention(thin) <T> (Int64, Int64) -> Int64 {
+bb0(%0 : $Int64, %1 : $Int64):
+  return %0 : $Int64
+}
+
+sil [noinline] @generic_func_with_unused_generic_param_and_dead_non_generic_arg_caller : $@convention(thin) <T> (Int64) -> Int64 {
+bb0(%0 : $Int64):
+  %f = function_ref @generic_func_with_unused_generic_param_and_dead_non_generic_arg : $@convention(thin) <T> (Int64, Int64) -> Int64 
+  %r = apply %f<T>(%0, %0) : $@convention(thin) <T> (Int64, Int64) -> Int64 
+  return %r : $Int64
+}
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_func_with_unused_generic_param_and_dead_generic_arg : $@convention(thin) <T> (@in_guaranteed T) -> ()
+// CHECK: function_ref @_T0025generic_func_with_unused_a16_param_and_dead_A4_argTf4d_n : $@convention(thin) () -> ()
+// Call the specialization which is not polymorphic.
+// CHECK: apply
+// CHECK: end sil function 'generic_func_with_unused_generic_param_and_dead_generic_arg'
+sil [noinline] @generic_func_with_unused_generic_param_and_dead_generic_arg : $@convention(thin) <T> (@in_guaranteed T) -> () {
+bb0(%0 : $*T):
+  %r = tuple()
+  return %r : $()
+}
+
+sil [noinline] @generic_func_with_unused_generic_param_and_dead_generic_arg_caller : $@convention(thin) <T> (@in_guaranteed T) -> () {
+bb0(%0 : $*T):
+  %f = function_ref @generic_func_with_unused_generic_param_and_dead_generic_arg : $@convention(thin) <T> (@in_guaranteed T) -> () 
+  apply %f<T>(%0) : $@convention(thin) <T> (@in_guaranteed T) -> ()  
+  %r = tuple()
+  return %r : $()
+}
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_func_with_unused_generic_param_and_dead_owned_generic_arg : $@convention(thin) <T where T : KlassFoo> (@owned T) -> ()
+// CHECK: function_ref @_T0025generic_func_with_unused_a22_param_and_dead_owned_A4_argTf4d_n : $@convention(thin) () -> ()
+// Call the specialization which is not polymorphic.
+// CHECK: apply
+// CHECK: release_value %0
+// CHECK: end sil function 'generic_func_with_unused_generic_param_and_dead_owned_generic_arg'
+sil [noinline] @generic_func_with_unused_generic_param_and_dead_owned_generic_arg : $@convention(thin) <T where T: KlassFoo> (@owned T) -> () {
+bb0(%0 : $T):
+  release_value %0 : $T
+  %r = tuple()
+  return %r : $()
+}
+
+sil [noinline] @generic_func_with_unused_generic_param_and_dead_owned_generic_arg_caller : $@convention(thin) <T where T: KlassFoo> (@owned T) -> () {
+bb0(%0 : $T):
+  %f = function_ref @generic_func_with_unused_generic_param_and_dead_owned_generic_arg : $@convention(thin) <T where T: KlassFoo> (@owned T) -> () 
+  apply %f<T>(%0) : $@convention(thin) <T where T: KlassFoo> (@owned T) -> ()  
+  %r = tuple()
+  return %r : $()
+}
+
+// CHECK-LABEL: sil [thunk] [always_inline] @generic_func_with_multple_generic_args_and_dead_generic_arg : $@convention(thin) <T, S> (@in T, @in S) -> ()
+// CHECK: function_ref @_T0026generic_func_with_multple_a15_args_and_dead_A4_argTf4nd_n : $@convention(thin) <τ_0_0, τ_0_1> (@in τ_0_0) -> ()
+// Call the specialization which has only one function argument, because another one is dead
+// and was eliminated.
+// CHECK: apply
+// CHECK: end sil function 'generic_func_with_multple_generic_args_and_dead_generic_arg'
+sil [noinline] @generic_func_with_multple_generic_args_and_dead_generic_arg : $@convention(thin) <T, S> (@in T, @in S) -> () {
+bb0(%0 : $*T, %1 : $*S):
+  %f = function_ref @use_Generic : $@convention(thin) <T>(@in_guaranteed T) -> ()
+  apply %f<T>(%0) : $@convention(thin) <T>(@in_guaranteed T) -> ()
+  %r = tuple()
+  return %r : $()
+}
+
+sil [noinline] @generic_func_with_multple_generic_args_and_dead_generic_arg_caller : $@convention(thin) <T> (@in T) -> () {
+bb0(%0 : $*T):
+  %2 = alloc_stack $T
+  copy_addr %0 to [initialization] %2 : $*T
+  %4 = alloc_stack $T
+  copy_addr %0 to [initialization] %4 : $*T
+  %f = function_ref @generic_func_with_multple_generic_args_and_dead_generic_arg : $@convention(thin) <T, S> (@in T, @in S) -> ()
+  apply %f<T, T>(%2, %4) : $@convention(thin) <T, S> (@in T, @in S) -> () 
+  dealloc_stack %4 : $*T
+  dealloc_stack %2 : $*T
+  %r = tuple()
+  return %r : $()
+}
+
 // CHECK-LABEL: sil @_T036exploded_release_to_guaranteed_paramTf4gX_n
 // CHECK: bb0([[INPUT_ARG0:%[0-9]+]] : $Int):
 // CHECK-NOT: strong_release
@@ -1553,3 +1775,29 @@
 // CHECK:  tuple
 // CHECK:  return
 
+// Check that a owned-to-guaranteed has happened.
+// CHECK-LABEL: sil hidden [noinline] @_T027generic_owned_to_guaranteedTf4g_n : $@convention(thin) <T where T : KlassFoo> (@guaranteed T) -> Int64
+// CHECK-NOT: release_value 
+// CHECK-NOT: strong_release 
+// CHECK-NOT: destroy_addr 
+// CHECK: end sil function '_T027generic_owned_to_guaranteedTf4g_n'
+
+// Check that a owned-to-guaranteed has happened.
+// CHECK-LABEL: sil @_T034generic_owned_to_guaranteed_callerTf4g_n : $@convention(thin) <T where T : KlassFoo> (@guaranteed T) -> Int64
+// Call the specialized function. It should have a guaranteed param now. 
+// CHECK: function_ref @_T027generic_owned_to_guaranteedTf4g_n : $@convention(thin) <τ_0_0 where τ_0_0 : KlassFoo> (@guaranteed τ_0_0) -> Int64
+// CHECK: apply
+// CHECK: end sil function '_T034generic_owned_to_guaranteed_callerTf4g_n'
+
+// Check that a in-to-guaranteed has happened.
+// CHECK-LABEL: sil hidden [noinline] @_T024generic_in_to_guaranteedTf4g_n : $@convention(thin) <T where T : P> (@in_guaranteed T) -> Int64
+// CHECK-NOT: destroy_addr
+// CHECK: end sil function '_T024generic_in_to_guaranteedTf4g_n'
+
+// Check that a in-to-guaranteed has happened.
+// CHECK-LABEL: sil @_T031generic_in_to_guaranteed_callerTf4g_n : $@convention(thin) <T where T : P> (@in_guaranteed T) -> Int64
+// Call the specialized function. It should have a guaranteed param now. 
+// CHECK: function_ref @_T024generic_in_to_guaranteedTf4g_n : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
+// CHECK: apply
+// CHECK: end sil function '_T031generic_in_to_guaranteed_callerTf4g_n'
+
diff --git a/test/SILOptimizer/inline_thunk.swift b/test/SILOptimizer/inline_thunk.swift
index 69b4122..edbd0ed 100644
--- a/test/SILOptimizer/inline_thunk.swift
+++ b/test/SILOptimizer/inline_thunk.swift
@@ -9,7 +9,7 @@
 // CHECK: call swiftcc i32 @{{.*}}testit{{.*}}Tf{{.*}} #[[ATTR:[0-9]+]]
 // CHECK: ret
 
-// CHECK-LABEL: define hidden swiftcc i32 @{{.*}}testit{{.*}}FTW(i32
+// CHECK-LABEL: define internal swiftcc i32 @{{.*}}testit{{.*}}FTW(i32
 // CHECK: call swiftcc i32 @{{.*}}testit{{.*}}Tf{{.*}} #[[ATTR]]
 // CHECK: ret
 
diff --git a/test/SILOptimizer/inline_tryApply.sil b/test/SILOptimizer/inline_tryApply.sil
index b4de00c..c9e2fdb 100644
--- a/test/SILOptimizer/inline_tryApply.sil
+++ b/test/SILOptimizer/inline_tryApply.sil
@@ -7,10 +7,10 @@
 import SwiftShims
 
 
-//CHECK-LABEL: caller_function
+//CHECK-LABEL: sil @caller_function
 //CHECK-NOT: try_apply
 //CHECK: throw {{.*}} : $Error
-sil  @caller_function : $@convention(thin) () -> @error Error {
+sil @caller_function : $@convention(thin) () -> @error Error {
 bb0:
   // function_ref main.inner () throws -> ()
   %0 = function_ref @callee_function : $@convention(thin) () -> @error Error // user: %1
@@ -24,7 +24,7 @@
   throw %5 : $Error                           // id: %6
 }
 
-//CHECK-LABEL: callee_function
+//CHECK-LABEL: sil [always_inline] @callee_function
 //CHECK: return
 
 // main.inner () throws -> ()
diff --git a/test/SILOptimizer/lslocation_expansion.sil b/test/SILOptimizer/lslocation_expansion.sil
index f88efb7..d06ac87 100644
--- a/test/SILOptimizer/lslocation_expansion.sil
+++ b/test/SILOptimizer/lslocation_expansion.sil
@@ -103,16 +103,14 @@
 // CHECK-LABEL: @store_after_store_struct
 // CHECK: #0 store
 // CHECK-NEXT: [[RET0:%.+]] = alloc_stack
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
+// CHECK-NEXT: Projection Path [$*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK: #1 store
 // CHECK-NEXT: [[RET0:%.+]] = alloc_stack
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
+// CHECK-NEXT: Projection Path [$*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 sil @store_after_store_struct : $@convention(thin) () -> () {
   %1 = alloc_stack $S1
   %9 = integer_literal $Builtin.Int64, 0          // user: %10
@@ -130,136 +128,97 @@
 // CHECK-LABEL: @many_struct_allocs
 // CHECK: #0 store
 // CHECK-NEXT: alloc_stack $S2
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
+// CHECK-NEXT: Projection Path [$*S2
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S2
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
+// CHECK-NEXT: Projection Path [$*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK: #1 store
 // CHECK-NEXT: alloc_stack $S3
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var c: S2
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var c: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S3
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var c: S2
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var c: S2 of: $*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S3
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S3
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S3
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK: #2 store
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var c: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var y: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var y: S3 of: $*S3
+// CHECK-NEXT:   Field: var c: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var c: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var y: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var y: S3 of: $*S3
+// CHECK-NEXT:   Field: var c: S2 of: $*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var y: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var y: S3 of: $*S3
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var y: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var y: S3 of: $*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var y: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var y: S3 of: $*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var c: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var x: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var x: S3 of: $*S3
+// CHECK-NEXT:   Field: var c: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var c: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var x: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var x: S3 of: $*S3
+// CHECK-NEXT:   Field: var c: S2 of: $*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var x: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var x: S3 of: $*S3
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var x: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var x: S3 of: $*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK-NEXT: alloc_stack $S4
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Field Type: var x: S3
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var x: S3 of: $*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 sil hidden @many_struct_allocs : $@convention(thin) () -> () {
 bb0:
   %0 = alloc_stack $S2, var, name "a"                  // users: %6, %18
@@ -288,8 +247,8 @@
 // CHECK-LABEL: self_loop
 // CHECK: #0 store
 // CHECK-NEXT: alloc_stack $S5, var, name "b"{{.*}}  // users: %7, %4
-// CHECK-NEXT: Address Projection Type: $*SelfLoop
-// CHECK-NEXT: Field Type: var a: SelfLoop
+// CHECK-NEXT: Projection Path [$*S5
+// CHECK-NEXT:   Field: var a: SelfLoop of: $*SelfLoop]
 sil hidden @self_loop : $@convention(thin) () -> () {
 bb0:
   %0 = alloc_stack $S5, var, name "b"             // users: %4, %7
diff --git a/test/SILOptimizer/lslocation_reduction.sil b/test/SILOptimizer/lslocation_reduction.sil
index a41c517..5223030 100644
--- a/test/SILOptimizer/lslocation_reduction.sil
+++ b/test/SILOptimizer/lslocation_reduction.sil
@@ -103,12 +103,12 @@
 // CHECK-LABEL: @store_after_store_struct
 // CHECK: #0 store
 // CHECK-NEXT: [[RET0:%.+]] = alloc_stack
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
+// CHECK-NEXT: Projection Path [$*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int]
 // CHECK: #1 store
 // CHECK-NEXT: [[RET0:%.+]] = alloc_stack
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
+// CHECK-NEXT: Projection Path [$*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int]
 sil @store_after_store_struct : $@convention(thin) () -> () {
   %1 = alloc_stack $S1
   %9 = integer_literal $Builtin.Int64, 0          // user: %10
diff --git a/test/SILOptimizer/lslocation_type_only_expansion.sil b/test/SILOptimizer/lslocation_type_only_expansion.sil
index 1956ed9..f1f45e7 100644
--- a/test/SILOptimizer/lslocation_type_only_expansion.sil
+++ b/test/SILOptimizer/lslocation_type_only_expansion.sil
@@ -81,31 +81,24 @@
 
 // CHECK-LABEL: @test_struct_type_expansion
 // CHECK: #0  store
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
+// CHECK-NEXT: Projection Path [$*S1
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 // CHECK: #1  store
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S1
-// CHECK-NEXT: Field Type: var b: S1
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S1
-// CHECK-NEXT: Field Type: var b: S1
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
+// CHECK-NEXT: Projection Path [$*S2
+// CHECK-NEXT:   Field: var b: S1 of: $*S1
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S2
+// CHECK-NEXT:   Field: var b: S1 of: $*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 sil hidden @test_struct_type_expansion : $@convention(thin) () -> () {
 bb0:
   %0 = alloc_stack $S1, var, name "a"                   // users: %5, %12
@@ -146,32 +139,24 @@
 
 // CHECK-LABEL: test_struct_and_class_slot
 // CHECK:  #0 store
-// CHECK-NEXT: Address Projection Type: $*C1
-// CHECK-NEXT: Field Type: var b: C1
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S1
-// CHECK-NEXT: Field Type: var b: S1
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S1
-// CHECK-NEXT: Field Type: var b: S1
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*C1
-// CHECK-NEXT: Field Type: var c: C1
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var b: C1 of: $*C1]
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: S1 of: $*S1
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: S1 of: $*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S3
+// CHECK-NEXT:   Field: var c: C1 of: $*C1]
 sil hidden @test_struct_and_class_slot : $@convention(thin) () -> () {
 bb0:
   %0 = alloc_stack $S3, var, name "a"                  // users: %4, %7
@@ -190,34 +175,24 @@
 //
 // CHECK-LABEL: test_tuple
 // CHECK:  #0 store
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S1
-// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S1)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S1)
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S1
-// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S1)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S1)
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Index: 1
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S1)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S1)
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Index: 0
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S1)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S1)
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var c: (Int, Int, S1) of: $*(Int, Int, S1)
+// CHECK-NEXT:   Index: 2 into: $*S1
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var c: (Int, Int, S1) of: $*(Int, Int, S1)
+// CHECK-NEXT:   Index: 2 into: $*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var c: (Int, Int, S1) of: $*(Int, Int, S1)
+// CHECK-NEXT:   Index: 1 into: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S4
+// CHECK-NEXT:   Field: var c: (Int, Int, S1) of: $*(Int, Int, S1)
+// CHECK-NEXT:   Index: 0 into: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 sil hidden @test_tuple : $@convention(thin) () -> () {
 bb0:
   %0 = alloc_stack $S4, var, name "x"                  // users: %4, %7
@@ -234,64 +209,42 @@
 
 // CHECK-LABEL: tuple_test_with_reference
 // CHECK: #0 store
-// CHECK-NEXT: Address Projection Type: $*C1
-// CHECK-NEXT: Field Type: var b: C1
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S3)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S3)
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var b: Int
-// CHECK-NEXT: Address Projection Type: $*S1
-// CHECK-NEXT: Field Type: var b: S1
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S3)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S3)
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S1
-// CHECK-NEXT: Field Type: var b: S1
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S3)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S3)
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Field Type: var a: Int
-// CHECK-NEXT: Address Projection Type: $*S2
-// CHECK-NEXT: Field Type: var a: S2
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S3)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S3)
-// CHECK-NEXT: Address Projection Type: $*C1
-// CHECK-NEXT: Field Type: var c: C1
-// CHECK-NEXT: Address Projection Type: $*S3
-// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S3)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S3)
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Index: 1
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S3)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S3)
-// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-// CHECK-NEXT: Field Type: var value: Int64
-// CHECK-NEXT: Address Projection Type: $*Int
-// CHECK-NEXT: Index: 0
-// CHECK-NEXT: Address Projection Type: $*(Int, Int, S3)
-// CHECK-NEXT: Field Type: var c: (Int, Int, S3)
+// CHECK-NEXT: Projection Path [$*S5
+// CHECK-NEXT:   Field: var c: (Int, Int, S3) of: $*(Int, Int, S3)
+// CHECK-NEXT:   Index: 2 into: $*S3
+// CHECK-NEXT:   Field: var b: C1 of: $*C1]
+// CHECK-NEXT: Projection Path [$*S5
+// CHECK-NEXT:   Field: var c: (Int, Int, S3) of: $*(Int, Int, S3)
+// CHECK-NEXT:   Index: 2 into: $*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: S1 of: $*S1
+// CHECK-NEXT:   Field: var b: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S5
+// CHECK-NEXT:   Field: var c: (Int, Int, S3) of: $*(Int, Int, S3)
+// CHECK-NEXT:   Index: 2 into: $*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var b: S1 of: $*S1
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S5
+// CHECK-NEXT:   Field: var c: (Int, Int, S3) of: $*(Int, Int, S3)
+// CHECK-NEXT:   Index: 2 into: $*S3
+// CHECK-NEXT:   Field: var a: S2 of: $*S2
+// CHECK-NEXT:   Field: var a: Int of: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S5
+// CHECK-NEXT:   Field: var c: (Int, Int, S3) of: $*(Int, Int, S3)
+// CHECK-NEXT:   Index: 2 into: $*S3
+// CHECK-NEXT:   Field: var c: C1 of: $*C1]
+// CHECK-NEXT: Projection Path [$*S5
+// CHECK-NEXT:   Field: var c: (Int, Int, S3) of: $*(Int, Int, S3)
+// CHECK-NEXT:   Index: 1 into: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+// CHECK-NEXT: Projection Path [$*S5
+// CHECK-NEXT:   Field: var c: (Int, Int, S3) of: $*(Int, Int, S3)
+// CHECK-NEXT:   Index: 0 into: $*Int
+// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 sil hidden @tuple_test_with_reference : $@convention(thin) () -> () {
 bb0:
   %0 = alloc_stack $S5, var, name "x"                  // users: %4, %7
@@ -308,18 +261,14 @@
 
 /// CHECK-LABEL: tuple_inside_struct
 /// CHECK: #0 store
-/// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-/// CHECK-NEXT: Field Type: var value: Int64
-/// CHECK-NEXT: Address Projection Type: $*Int
-/// CHECK-NEXT: Index: 1
-/// CHECK-NEXT: Address Projection Type: $*(Int, Int)
-/// CHECK-NEXT: Field Type: var tuple: (Int, Int)
-/// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-/// CHECK-NEXT: Field Type: var value: Int64
-/// CHECK-NEXT: Address Projection Type: $*Int
-/// CHECK-NEXT: Index: 0
-/// CHECK-NEXT: Address Projection Type: $*(Int, Int)
-/// CHECK-NEXT: Field Type: var tuple: (Int, Int)
+/// CHECK-NEXT: Projection Path [$*S6
+/// CHECK-NEXT:   Field: var tuple: (Int, Int) of: $*(Int, Int)
+/// CHECK-NEXT:   Index: 1 into: $*Int
+/// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
+/// CHECK-NEXT: Projection Path [$*S6
+/// CHECK-NEXT:   Field: var tuple: (Int, Int) of: $*(Int, Int)
+/// CHECK-NEXT:   Index: 0 into: $*Int
+/// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 sil hidden @tuple_inside_struct : $@convention(thin) () -> () {
 bb0:
   %0 = alloc_stack $S6, var, name "x"                  // users: %4, %7
@@ -342,8 +291,8 @@
 /// CHECK-NOT: Int64
 /// CHECK-NOT: Int32
 /// CHECK: #1  store
-/// CHECK-NEXT: Address Projection Type: $*Builtin.Int64
-/// CHECK-NEXT: Field Type: var value: Int64
+/// CHECK-NEXT: Projection Path [$*Int
+/// CHECK-NEXT:   Field: var value: Int64 of: $*Builtin.Int64]
 sil hidden @enum_test : $@convention(thin) () -> () {
 bb0:
   %0 = alloc_stack $Example, var, name "ee"       // users: %5, %11
diff --git a/test/SILOptimizer/ownership_model_eliminator.sil b/test/SILOptimizer/ownership_model_eliminator.sil
index 1328aa2..0df8dbe 100644
--- a/test/SILOptimizer/ownership_model_eliminator.sil
+++ b/test/SILOptimizer/ownership_model_eliminator.sil
@@ -1,6 +1,6 @@
 // RUN: %target-sil-opt -enable-sil-ownership -ownership-model-eliminator %s | %FileCheck %s
 
-sil_stage canonical
+sil_stage raw
 
 import Builtin
 
@@ -228,4 +228,33 @@
 bb3:
   %9999 = tuple()
   return %9999 : $()
+}
+
+// CHECK-LABEL: sil @mark_uninitialized_project_box : $@convention(thin) () -> () {
+// CHECK: [[BOX:%.*]] = alloc_box
+// CHECK: [[PB_BOX:%.*]] = project_box [[BOX]]
+// CHECK: [[MUI:%.*]] = mark_uninitialized [var] [[PB_BOX]]
+// CHECK: store {{%.*}} to [[MUI]]
+// CHECK: load [[MUI]]
+// CHECK: load [[MUI]]
+// CHECK: strong_release [[BOX]]
+// CHECK: } // end sil function 'mark_uninitialized_project_box'
+sil @mark_uninitialized_project_box : $@convention(thin) () -> () {
+bb0:
+  %0 = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
+  %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0
+  %2 = mark_uninitialized [var] %1 : $*Builtin.Int32
+  %3 = integer_literal $Builtin.Int32, 0
+  store %3 to [trivial] %2 : $*Builtin.Int32
+
+  %4 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0
+  %5 = load [trivial] %4 : $*Builtin.Int32
+
+  %6 = copy_value %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
+  %7 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0
+  %8 = load [trivial] %7 : $*Builtin.Int32
+  destroy_value %6 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
+  destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
+  %9999 = tuple()
+  return %9999 : $()
 }
\ No newline at end of file
diff --git a/test/SILOptimizer/redundant_load_elim.sil b/test/SILOptimizer/redundant_load_elim.sil
index 150df90..91b0050 100644
--- a/test/SILOptimizer/redundant_load_elim.sil
+++ b/test/SILOptimizer/redundant_load_elim.sil
@@ -1166,3 +1166,27 @@
   return %6 : $Int
 }
 
+sil @overwrite_int : $@convention(thin) (@inout Int, Int) -> ()
+
+// CHECK-LABEL: sil @test_address_block_args
+// CHECK: bb2({{.*}}):
+// CHECK: apply
+// CHECK: [[L:%.*]] = load
+// CHECK: return [[L]]
+sil @test_address_block_args : $@convention(thin) (Int) -> Int {
+bb0(%0 : $Int):
+  %4 = alloc_stack $Int
+  store %0 to %4 : $*Int
+  cond_br undef, bb1(%4 : $*Int), bb2(%4 : $*Int)
+
+bb1(%a1 : $*Int):
+  br bb2(%a1 : $*Int)
+
+bb2(%a : $*Int):
+  %l1 = load %a : $*Int
+  %60 = function_ref @overwrite_int : $@convention(thin) (@inout Int, Int) -> ()
+  %61 = apply %60(%4, %l1) : $@convention(thin) (@inout Int, Int) -> ()
+  %r = load %a : $*Int
+  dealloc_stack %4 : $*Int
+  return %r : $Int
+} 
diff --git a/test/SILOptimizer/semantic-arc-opts.sil b/test/SILOptimizer/semantic-arc-opts.sil
new file mode 100644
index 0000000..048a283
--- /dev/null
+++ b/test/SILOptimizer/semantic-arc-opts.sil
@@ -0,0 +1,96 @@
+// RUN: %target-sil-opt -enable-sil-verify-all -enable-sil-ownership -semantic-arc-opts %s | %FileCheck %s
+
+sil_stage canonical
+
+import Builtin
+
+//////////////////
+// Declarations //
+//////////////////
+
+sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
+
+///////////
+// Tests //
+///////////
+
+// CHECK-LABEL: sil @argument_only_destroy_user_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+// CHECK-NOT: copy_value
+// CHECK-NOT: destroy_value
+sil @argument_only_destroy_user_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+bb0(%0 : @guaranteed $Builtin.NativeObject):
+  %1 = copy_value %0 : $Builtin.NativeObject
+  destroy_value %1 : $Builtin.NativeObject
+  %9999 = tuple()
+  return %9999 : $()
+}
+
+// CHECK-LABEL: sil @argument_diamond_test_case : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned Builtin.NativeObject {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Builtin.NativeObject):
+// CHECK-NEXT: [[RESULT:%.*]] = copy_value [[ARG]]
+// CHECK-NEXT: cond_br undef, [[LHSBB:bb[0-9]+]], [[RHSBB:bb[0-9]+]]
+//
+// CHECK: [[LHSBB]]:
+// CHECK-NEXT: br [[EPILOGBB:bb[0-9]+]]
+//
+// CHECK: [[RHSBB]]:
+// CHECK-NEXT: br [[EPILOGBB]]
+//
+// CHECK: [[EPILOGBB]]:
+// CHECK-NEXT: return [[RESULT]]
+sil @argument_diamond_test_case : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned Builtin.NativeObject {
+bb0(%0 : @guaranteed $Builtin.NativeObject):
+  %1 = copy_value %0 : $Builtin.NativeObject
+  %2 = copy_value %1 : $Builtin.NativeObject
+  cond_br undef, bb1, bb2
+
+bb1:
+  destroy_value %1 : $Builtin.NativeObject
+  br bb3
+
+bb2:
+  destroy_value %1 : $Builtin.NativeObject
+  br bb3
+
+bb3:
+  return %2 : $Builtin.NativeObject
+}
+
+// CHECK-LABEL: sil @argument_copy_borrow_test_case : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Builtin.NativeObject
+// CHECK-NOT: copy_value
+// CHECK-NOT: begin_borrow
+// CHECK: apply {{%.*}}([[ARG]])
+// CHECK-NOT: end_borrow
+// CHECK-NOT: destroy_value
+// CHECK: } // end sil function 'argument_copy_borrow_test_case'
+sil @argument_copy_borrow_test_case : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+bb0(%0 : @guaranteed $Builtin.NativeObject):
+  %1 = copy_value %0 : $Builtin.NativeObject
+  %2 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
+  %3 = begin_borrow %1 : $Builtin.NativeObject
+  apply %2(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
+  %4 = end_borrow %3 from %1 : $Builtin.NativeObject, $Builtin.NativeObject
+  destroy_value %1 : $Builtin.NativeObject
+  %9999 = tuple()
+  return %9999 : $()
+}
+
+// CHECK-LABEL: sil @argument_copy_of_copy : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+// CHECK: bb0
+// CHECK-NEXT: tuple
+// CHECK-NEXT: return
+// CHECK-NEXT: } // end sil function 'argument_copy_of_copy'
+sil @argument_copy_of_copy : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+bb0(%0 : @guaranteed $Builtin.NativeObject):
+  %1 = copy_value %0 : $Builtin.NativeObject
+  %2 = begin_borrow %1 : $Builtin.NativeObject
+  %3 = copy_value %2 : $Builtin.NativeObject
+  %4 = begin_borrow %3 : $Builtin.NativeObject
+  end_borrow %4 from %3 : $Builtin.NativeObject, $Builtin.NativeObject
+  destroy_value %3 : $Builtin.NativeObject
+  end_borrow %2 from %1 : $Builtin.NativeObject, $Builtin.NativeObject
+  destroy_value %1 : $Builtin.NativeObject
+  %9999 = tuple()
+  return %9999 : $()
+}
diff --git a/test/SILOptimizer/simplify_cfg.sil b/test/SILOptimizer/simplify_cfg.sil
index 21f1627..17fa10a 100644
--- a/test/SILOptimizer/simplify_cfg.sil
+++ b/test/SILOptimizer/simplify_cfg.sil
@@ -2707,3 +2707,66 @@
   return %6 : $()
 }
 
+enum TestEnum {
+  case int64(Builtin.Int64)
+  case string (Base)
+  case none
+}
+
+enum MyError : Error {
+ case a
+ case b
+ case c(TestEnum)
+}
+
+enum MyError2 : Error {
+ case o(Optional<MyError>)
+}
+
+sil @foo : $@convention(thin) (Builtin.Int64) -> Builtin.Int8
+sil @foo2 : $@convention(thin) (Builtin.Int32) -> Builtin.Int8
+
+sil @dont_thread_throw_block : $@convention(thin) (@guaranteed TestEnum) -> (Builtin.Int8, @error Error) {
+bb0(%0 : $TestEnum):
+  switch_enum %0 : $TestEnum, case #TestEnum.int64!enumelt.1: bb1,  default bb4
+
+bb1(%5 : $Builtin.Int64):
+  %7 = function_ref @foo : $@convention(thin) (Builtin.Int64) -> Builtin.Int8
+  %9 = apply %7(%5) : $@convention(thin) (Builtin.Int64) -> Builtin.Int8
+  br bb6(%9 : $Builtin.Int8)
+
+bb2(%11 : $Builtin.Int32):
+  %13 = function_ref @foo2 : $@convention(thin) (Builtin.Int32) -> Builtin.Int8
+  %15 = apply %13(%11) : $@convention(thin) (Builtin.Int32) -> Builtin.Int8
+  br bb6(%15 : $Builtin.Int8)
+
+bb4:
+  %60 = debug_value %0 : $TestEnum
+  %22 = alloc_existential_box $Error, $MyError2
+  %23 = project_existential_box $MyError2 in %22 : $Error
+  switch_enum %0 : $TestEnum, case #TestEnum.none!enumelt: bbnone, case #TestEnum.int64!enumelt.1: bb7, case #TestEnum.string!enumelt.1: bb10
+
+bbnone:
+  %tn = enum $TestEnum, #TestEnum.none!enumelt
+  %en = enum $MyError, #MyError.c!enumelt.1, %tn : $TestEnum
+br bb5(%en : $MyError)
+
+bb7(%50 : $Builtin.Int64):
+  %t = enum $TestEnum, #TestEnum.int64!enumelt.1, %50 : $Builtin.Int64
+  %e1 = enum $MyError, #MyError.c!enumelt.1, %t : $TestEnum
+  br bb5(%e1 : $MyError)
+
+bb10(%53 : $Base):
+  %t4 = enum $TestEnum, #TestEnum.string!enumelt.1, %53 : $Base
+  %e4 = enum $MyError, #MyError.c!enumelt.1, %t4 : $TestEnum
+  br bb5(%e4 : $MyError)
+
+bb5(%e : $MyError):
+  %89 = enum $Optional<MyError>, #Optional.some!enumelt.1, %e : $MyError
+  %e5 = enum $MyError2, #MyError2.o!enumelt.1, %89 : $Optional<MyError>
+  store %e5 to %23 : $*MyError2
+  throw %22 : $Error
+
+bb6(%44 : $Builtin.Int8):
+  return %44 : $Builtin.Int8
+}
diff --git a/test/SILOptimizer/specialize_unconditional_checked_cast.swift b/test/SILOptimizer/specialize_unconditional_checked_cast.swift
index 1b3a279..0c0bd83 100644
--- a/test/SILOptimizer/specialize_unconditional_checked_cast.swift
+++ b/test/SILOptimizer/specialize_unconditional_checked_cast.swift
@@ -99,6 +99,8 @@
 // CHECK-LABEL: sil shared [noinline] @_T037specialize_unconditional_checked_cast31ArchetypeToConcreteConvertUInt8{{[_0-9a-zA-Z]*}}3Not{{.*}}Tg5 : $@convention(thin) (NotUInt8) -> NotUInt8 {
 // CHECK: bb0
 // CHECK-NEXT: debug_value %0
+// TODO: the second debug_value is redundant and should be removed
+// CHECK-NEXT: debug_value %0
 // CHECK-NEXT: return %0
 
 // x -> y where y is a class but x is not.
diff --git a/test/Sanitizers/tsan-inout.swift b/test/Sanitizers/tsan-inout.swift
index b839764..c5863e9 100644
--- a/test/Sanitizers/tsan-inout.swift
+++ b/test/Sanitizers/tsan-inout.swift
@@ -19,7 +19,7 @@
 var gInThread1: () -> () = { }
 var gInThread2: () -> () = { }
 
-// Spawn two threads, run the the two passed in closures simultaneously, and
+// Spawn two threads, run the two passed in closures simultaneously, and
 // join them.
 func testRace(name: String, thread inThread1: @escaping () -> (), thread inThread2: @escaping () -> ()) {
   var thread1: pthread_t?
diff --git a/test/Sema/availability_versions.swift b/test/Sema/availability_versions.swift
index c5e1294..dd4c4dc 100644
--- a/test/Sema/availability_versions.swift
+++ b/test/Sema/availability_versions.swift
@@ -1310,7 +1310,7 @@
 
 @objc
 class X {
-  var y = Y()
+  @objc var y = Y()
 }
 
 func testForFixitWithNestedMemberRefExpr() {
diff --git a/test/Serialization/write-to-locked-dir.swift b/test/Serialization/write-to-locked-dir.swift
index 190e883..73ffccf 100644
--- a/test/Serialization/write-to-locked-dir.swift
+++ b/test/Serialization/write-to-locked-dir.swift
@@ -1,3 +1,4 @@
+// RUN: test ! -d %t || chmod +w %t
 // RUN: rm -rf %t && mkdir -p %t
 // RUN: touch %t/main.swiftmodule %t/main.swiftdoc
 // RUN: chmod -w %t
diff --git a/test/SourceKit/CursorInfo/cursor_info.swift b/test/SourceKit/CursorInfo/cursor_info.swift
index 95461ad..b55b121 100644
--- a/test/SourceKit/CursorInfo/cursor_info.swift
+++ b/test/SourceKit/CursorInfo/cursor_info.swift
@@ -78,7 +78,7 @@
 }
 
 struct S2<T, U where T == U> {
-  func foo<V, W where V == W> (_ closure: ()->()) -> ()->() { return closure }
+  func foo<V, W where V == W> (_: V, _: W, _ closure: ()->()) -> ()->() { return closure }
 }
 class C4<T, U where T == U> {}
 enum E1<T, U where T == U> {}
@@ -433,12 +433,12 @@
 // CHECK33-NEXT: <decl.struct><syntaxtype.keyword>struct</syntaxtype.keyword> <decl.name>S2</decl.name>&lt;<decl.generic_type_param usr="s:11cursor_info2S2V1Txmfp"><decl.generic_type_param.name>T</decl.generic_type_param.name></decl.generic_type_param>, <decl.generic_type_param usr="s:11cursor_info2S2V1Uq_mfp"><decl.generic_type_param.name>U</decl.generic_type_param.name></decl.generic_type_param>&gt; <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement>T == U</decl.generic_type_requirement></decl.struct>
 
 // RUN: %sourcekitd-test -req=cursor -pos=81:8 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | %FileCheck %s -check-prefix=CHECK34
-// CHECK34: source.lang.swift.decl.function.method.instance (81:8-81:50)
-// CHECK34-NEXT: foo(_:)
-// CHECK34-NEXT: s:11cursor_info2S2V3fooyycyycqd_0_Rsd__r0_lF
-// CHECK34-NEXT: <T, U, V, W where T == U, V == W> (S2<T, U>) -> (() -> ()) -> () -> ()
-// CHECK34: <Declaration>func foo&lt;V, W&gt;(_ closure: () -&gt; ()) -&gt; () -&gt; () where V == W</Declaration>
-// CHECK34-NEXT: <decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>foo</decl.name>&lt;<decl.generic_type_param usr="s:11cursor_info2S2V3fooyycyycqd_0_Rsd__r0_lF1VL_qd__mfp"><decl.generic_type_param.name>V</decl.generic_type_param.name></decl.generic_type_param>, <decl.generic_type_param usr="s:11cursor_info2S2V3fooyycyycqd_0_Rsd__r0_lF1WL_qd_0_mfp"><decl.generic_type_param.name>W</decl.generic_type_param.name></decl.generic_type_param>&gt;(<decl.var.parameter><decl.var.parameter.argument_label>_</decl.var.parameter.argument_label> <decl.var.parameter.name>closure</decl.var.parameter.name>: <decl.var.parameter.type>() -&gt; <decl.function.returntype><tuple>()</tuple></decl.function.returntype></decl.var.parameter.type></decl.var.parameter>) -&gt; <decl.function.returntype>() -&gt; <decl.function.returntype><tuple>()</tuple></decl.function.returntype></decl.function.returntype> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement>V == W</decl.generic_type_requirement></decl.function.method.instance>
+// CHECK34: source.lang.swift.decl.function.method.instance (81:8-81:62)
+// CHECK34-NEXT: foo(_:_:_:)
+// CHECK34-NEXT: s:11cursor_info2S2V3fooyycqd___qd__yyctqd_0_Rsd__r0_lF
+// CHECK34-NEXT: <T, U, V, W where T == U, V == W> (S2<T, U>) -> (V, W, () -> ()) -> () -> ()
+// CHECK34: <Declaration>func foo&lt;V, W&gt;(_: <Type usr="s:11cursor_info2S2V3fooyycqd___qd__yyctqd_0_Rsd__r0_lF1VL_qd__mfp">V</Type>, _: <Type usr="s:11cursor_info2S2V3fooyycqd___qd__yyctqd_0_Rsd__r0_lF1WL_qd_0_mfp">W</Type>, _ closure: () -&gt; ()) -&gt; () -&gt; () where V == W</Declaration>
+// CHECK34: <decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>foo</decl.name>&lt;<decl.generic_type_param usr="s:11cursor_info2S2V3fooyycqd___qd__yyctqd_0_Rsd__r0_lF1VL_qd__mfp"><decl.generic_type_param.name>V</decl.generic_type_param.name></decl.generic_type_param>, <decl.generic_type_param usr="s:11cursor_info2S2V3fooyycqd___qd__yyctqd_0_Rsd__r0_lF1WL_qd_0_mfp"><decl.generic_type_param.name>W</decl.generic_type_param.name></decl.generic_type_param>&gt;(<decl.var.parameter><decl.var.parameter.argument_label>_</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.generic_type_param usr="s:11cursor_info2S2V3fooyycqd___qd__yyctqd_0_Rsd__r0_lF1VL_qd__mfp">V</ref.generic_type_param></decl.var.parameter.type></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.argument_label>_</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.generic_type_param usr="s:11cursor_info2S2V3fooyycqd___qd__yyctqd_0_Rsd__r0_lF1WL_qd_0_mfp">W</ref.generic_type_param></decl.var.parameter.type></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.argument_label>_</decl.var.parameter.argument_label> <decl.var.parameter.name>closure</decl.var.parameter.name>: <decl.var.parameter.type>() -&gt; <decl.function.returntype><tuple>()</tuple></decl.function.returntype></decl.var.parameter.type></decl.var.parameter>) -&gt; <decl.function.returntype>() -&gt; <decl.function.returntype><tuple>()</tuple></decl.function.returntype></decl.function.returntype> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement>V == W</decl.generic_type_requirement></decl.function.method.instance>
 
 // RUN: %sourcekitd-test -req=cursor -pos=83:7 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | %FileCheck %s -check-prefix=CHECK35
 // CHECK35: source.lang.swift.decl.class (83:7-83:9)
diff --git a/test/SourceKit/CursorInfo/cursor_label.swift b/test/SourceKit/CursorInfo/cursor_label.swift
new file mode 100644
index 0000000..a15772a
--- /dev/null
+++ b/test/SourceKit/CursorInfo/cursor_label.swift
@@ -0,0 +1,15 @@
+class C1 {
+  init(cc: Int) {}
+  func foo(aa : Int) {}
+  subscript(aa : Int, bb: Int)-> Int { get { return 0 } set {}}
+}
+let c = C1(cc: 1)
+c.foo(aa : 1)
+
+// RUN: %sourcekitd-test -req=cursor -pos=2:9 %s -- %s | %FileCheck %s -check-prefix=CHECK1
+// RUN: %sourcekitd-test -req=cursor -pos=3:13 %s -- %s | %FileCheck %s -check-prefix=CHECK2
+// RUN: %sourcekitd-test -req=cursor -pos=4:24 %s -- %s | %FileCheck %s -check-prefix=CHECK3
+
+// CHECK1: PARENT OFFSET: 13
+// CHECK2: PARENT OFFSET: 37
+// CHECK3: PARENT OFFSET: 56
diff --git a/test/SourceKit/CursorInfo/rdar_30248264.swift b/test/SourceKit/CursorInfo/rdar_30248264.swift
new file mode 100644
index 0000000..010b428
--- /dev/null
+++ b/test/SourceKit/CursorInfo/rdar_30248264.swift
@@ -0,0 +1,14 @@
+// Checks that we don't crash.
+// RUN: %sourcekitd-test -req=cursor -pos=9:25 %s -- %s | %FileCheck %s
+// RUN: %sourcekitd-test -req=cursor -pos=11:13 %s -- %s | %FileCheck -check-prefix=CHECK2 %s
+
+class A {
+  static prefix func +(_:A) {}
+
+  func method() {
+    let _ = "" /*here:*/== ""
+    // CHECK: source.lang.swift.ref.function.operator.infix
+    /*here*/+A()
+    // CHECK2: source.lang.swift.ref.function.operator.prefix
+  }
+}
diff --git a/test/SourceKit/CursorInfo/rdar_30292429.swift b/test/SourceKit/CursorInfo/rdar_30292429.swift
new file mode 100644
index 0000000..352daa3
--- /dev/null
+++ b/test/SourceKit/CursorInfo/rdar_30292429.swift
@@ -0,0 +1,16 @@
+// Checks that we don't crash.
+// RUN: %sourcekitd-test -req=cursor -pos=10:17 %s -- %s | %FileCheck -check-prefix=CHECK %s
+// RUN: %sourcekitd-test -req=cursor -pos=13:22 %s -- %s | %FileCheck -check-prefix=CHECK2 %s
+
+class A {
+  var field: Bool = true
+  var items: [Int] = []
+
+  func method() {
+    if /*here:*/field {}
+    // CHECK: source.lang.swift.ref.var.instance
+
+    for _ in /*here*/items {}
+    // CHECK2: source.lang.swift.ref.var.instance
+  }
+}
diff --git a/test/SourceKit/Indexing/Inputs/index_constructors_other.swift b/test/SourceKit/Indexing/Inputs/index_constructors_other.swift
new file mode 100644
index 0000000..769b64d
--- /dev/null
+++ b/test/SourceKit/Indexing/Inputs/index_constructors_other.swift
@@ -0,0 +1,7 @@
+class DogObject : CatObject {
+  override init() {
+    super.init()
+  }
+}
+
+class CatObject : NSObject {}
diff --git a/test/SourceKit/Indexing/index_constructors.swift b/test/SourceKit/Indexing/index_constructors.swift
new file mode 100644
index 0000000..1791dba
--- /dev/null
+++ b/test/SourceKit/Indexing/index_constructors.swift
@@ -0,0 +1,10 @@
+// RUN: %sourcekitd-test -req=index %s -- %s %S/Inputs/index_constructors_other.swift | %sed_clean > %t.response
+// RUN: diff -u %s.response %t.response
+
+import Foundation
+
+class HorseObject : DogObject {
+  var name: NSString
+
+  @objc public func flip() {}
+}
diff --git a/test/SourceKit/Indexing/index_constructors.swift.response b/test/SourceKit/Indexing/index_constructors.swift.response
new file mode 100644
index 0000000..14391805
--- /dev/null
+++ b/test/SourceKit/Indexing/index_constructors.swift.response
@@ -0,0 +1,58 @@
+{
+  key.hash: <hash>,
+  key.dependencies: [
+    {
+      key.kind: source.lang.swift.import.module.swift,
+      key.name: "Swift",
+      key.filepath: Swift.swiftmodule,
+      key.hash: <hash>,
+      key.is_system: 1
+    }
+  ],
+  key.entities: [
+    {
+      key.kind: source.lang.swift.decl.class,
+      key.name: "HorseObject",
+      key.usr: "s:18index_constructors11HorseObjectC",
+      key.line: 6,
+      key.column: 7,
+      key.related: [
+        {
+          key.kind: source.lang.swift.ref.class,
+          key.name: "DogObject",
+          key.usr: "s:18index_constructors9DogObjectC",
+          key.line: 6,
+          key.column: 21
+        }
+      ],
+      key.entities: [
+        {
+          key.kind: source.lang.swift.ref.class,
+          key.name: "DogObject",
+          key.usr: "s:18index_constructors9DogObjectC",
+          key.line: 6,
+          key.column: 21
+        },
+        {
+          key.kind: source.lang.swift.decl.var.instance,
+          key.name: "name",
+          key.usr: "s:18index_constructors11HorseObjectC4nameXev",
+          key.line: 7,
+          key.column: 7
+        },
+        {
+          key.kind: source.lang.swift.decl.function.method.instance,
+          key.name: "flip()",
+          key.usr: "s:18index_constructors11HorseObjectC4flipyyF",
+          key.line: 9,
+          key.column: 21,
+          key.attributes: [
+            {
+              key.attribute: source.decl.attribute.objc
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/test/SourceKit/Mixed/complete_twice_bridging_header.swift b/test/SourceKit/Mixed/complete_twice_bridging_header.swift
new file mode 100644
index 0000000..e8a370c
--- /dev/null
+++ b/test/SourceKit/Mixed/complete_twice_bridging_header.swift
@@ -0,0 +1,13 @@
+// REQUIRES: objc_interop
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %sourcekitd-test -req=complete -pos=8:5 %s -- %s -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h == -req=complete -pos=8:5 %s -- %s -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h | %FileCheck %s --check-prefix=CHECK-MEMBERS
+// RUN: %sourcekitd-test -req=complete -pos=9:1 %s -- %s -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h == -req=complete -pos=9:1 %s -- %s -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h | %FileCheck %s --check-prefix=CHECK-GLOBALS
+// RUN: stat %t/*.pch
+
+func foo(x: BaseInHead) {
+  x.
+}
+
+// CHECK-GLOBALS: doSomethingInHead(:)
+// CHECK-GLOBALS: test1(:)
+// CHECK-MEMBERS: doIt(:)
diff --git a/test/SourceKit/Mixed/cursor_mixed_header.swift b/test/SourceKit/Mixed/cursor_mixed_header.swift
index 5198681..4170257 100644
--- a/test/SourceKit/Mixed/cursor_mixed_header.swift
+++ b/test/SourceKit/Mixed/cursor_mixed_header.swift
@@ -10,6 +10,10 @@
 
 // RUN: %sourcekitd-test -req=cursor -pos=3:7 %s -- %s %mcp_opt -module-name Mixed -import-objc-header %S/Inputs/header.h | %FileCheck %s
 
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %sourcekitd-test -req=cursor -pos=3:7 %s -- %s %mcp_opt -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h | %FileCheck %s
+// RUN: stat %t/*.pch
+
 // CHECK: source.lang.swift.ref.function.method.instance ({{.*}}Inputs/header.h:4:9-4:23)
 // CHECK: doIt(_:)
 // CHECK: c:objc(cs)BaseInHead(im)doIt:
diff --git a/test/TBD/Inputs/protocol.log b/test/TBD/Inputs/protocol.log
index 69e5764..b91173f 100644
--- a/test/TBD/Inputs/protocol.log
+++ b/test/TBD/Inputs/protocol.log
@@ -4,9 +4,6 @@
 <unknown>:0: error: symbol '_T04test014PublicInternalB6StructV17internalVarGetSetSivfi' (test.PublicInternalPublicStruct.(internalVarGetSet : Swift.Int).(variable initialization expression)) is in generated IR file, but not in TBD file
 <unknown>:0: error: symbol '_T04test06PublicbB6StructV12publicVarGetSivfi' (test.PublicPublicPublicStruct.(publicVarGet : Swift.Int).(variable initialization expression)) is in generated IR file, but not in TBD file
 <unknown>:0: error: symbol '_T04test06PublicbB6StructV15publicVarGetSetSivfi' (test.PublicPublicPublicStruct.(publicVarGetSet : Swift.Int).(variable initialization expression)) is in generated IR file, but not in TBD file
-<unknown>:0: error: symbol '_T04test06PublicbB6StructVAA0B0A2aDP12publicMethodyyFTW' (protocol witness for test.Public.publicMethod () -> () in conformance test.PublicPublicPublicStruct : test.Public in test) is in generated IR file, but not in TBD file
-<unknown>:0: error: symbol '_T04test06PublicbB6StructVAA0B0AAWP' (protocol witness table for test.PublicPublicPublicStruct : test.Public in test) is in generated IR file, but not in TBD file
-<unknown>:0: error: symbol '_T04test06PublicbB6StructVAA0B0AAWa' (protocol witness table accessor for test.PublicPublicPublicStruct : test.Public in test) is in generated IR file, but not in TBD file
 <unknown>:0: error: symbol '_T04test013PublicPrivateB6StructV13privateVarGetSifg' (test.PublicPrivatePublicStruct.privateVarGet.getter : Swift.Int) is in TBD file, but not in generated IR
 <unknown>:0: error: symbol '_T04test013PublicPrivateB6StructV16privateVarGetSetSifg' (test.PublicPrivatePublicStruct.privateVarGetSet.getter : Swift.Int) is in TBD file, but not in generated IR
 <unknown>:0: error: symbol '_T04test013PublicPrivateB6StructV16privateVarGetSetSifm' (test.PublicPrivatePublicStruct.privateVarGetSet.materializeForSet : Swift.Int) is in TBD file, but not in generated IR
diff --git a/test/attr/attr_nonobjc.swift b/test/attr/attr_nonobjc.swift
index 1695a5d..5e10617 100644
--- a/test/attr/attr_nonobjc.swift
+++ b/test/attr/attr_nonobjc.swift
@@ -68,7 +68,7 @@
 }
 
 class DynamicAndNonObjCNotAllowed {
-  @nonobjc dynamic func redundantAttributes() { } // expected-error {{declaration is marked dynamic, and cannot be marked @nonobjc}}
+  @nonobjc dynamic func redundantAttributes() { } // expected-error {{a declaration cannot be both '@nonobjc' and 'dynamic'}}
 }
 
 class IBOutletAndNonObjCNotAllowed {
@@ -102,3 +102,6 @@
     }
   }
 }
+
+struct SomeStruct { }
+@nonobjc extension SomeStruct { } // expected-error{{only extensions of classes can be declared @nonobjc}}
diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift
index b22006e..eef63fb 100644
--- a/test/attr/attr_objc.swift
+++ b/test/attr/attr_objc.swift
@@ -1,6 +1,6 @@
-// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s -swift-version 4
-// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 4 | %FileCheck %s
-// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 4 2> %t.dump
+// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference
+// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference | %FileCheck %s
+// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference 2> %t.dump
 // RUN: %FileCheck -check-prefix CHECK-DUMP %s < %t.dump
 // REQUIRES: objc_interop
 
@@ -30,7 +30,7 @@
 
 //===--- Subjects of @objc attribute.
 
-@objc extension PlainClass { } // expected-error{{@objc cannot be applied to this declaration}}{{1-7=}}
+@objc extension PlainStruct { } // expected-error{{'@objc' can only be applied to an extension of a class}}{{1-7=}}
 
 @objc  
 var subject_globalVar: Int // expected-error {{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}}
@@ -1665,6 +1665,32 @@
 }
 
 //===---
+//===--- @IBInspectable implies @objc
+//===---
+
+// CHECK-LABEL: {{^}}class HasIBInspectable {
+class HasIBInspectable {
+  @IBInspectable var goodProperty: AnyObject?
+  // CHECK: {{^}}  @IBInspectable @objc var goodProperty: AnyObject?
+
+  @IBInspectable var badProperty: PlainStruct?
+  // expected-error@-1{{property cannot be marked @IBInspectable because its type cannot be represented in Objective-C}}
+}
+
+//===---
+//===--- @GKInspectable implies @objc
+//===---
+
+// CHECK-LABEL: {{^}}class HasGKInspectable {
+class HasGKInspectable {
+  @GKInspectable var goodProperty: AnyObject?
+  // CHECK: {{^}}  @GKInspectable @objc var goodProperty: AnyObject?
+
+  @GKInspectable var badProperty: PlainStruct?
+  // expected-error@-1{{property cannot be marked @GKInspectable because its type cannot be represented in Objective-C}}
+}
+
+//===---
 //===--- @NSManaged implies @objc
 //===---
 
@@ -2133,6 +2159,17 @@
   @objc func func_dictionary2b(x: Dictionary<String, Int>) { }
 }
 
+@objc extension PlainClass {
+  // CHECK-LABEL: @objc final func objc_ext_objc_okay(_: Int) {
+  final func objc_ext_objc_okay(_: Int) { }
+
+  final func objc_ext_objc_not_okay(_: PlainStruct) { }
+  // expected-error@-1{{method cannot be in an @objc extension of a class (without @nonobjc) because the type of the parameter cannot be represented in Objective-C}}
+  // expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
+
+  // CHECK-LABEL: {{^}} @nonobjc final func objc_ext_objc_explicit_nonobjc(_: PlainStruct) {
+  @nonobjc final func objc_ext_objc_explicit_nonobjc(_: PlainStruct) { }
+}
 
 @objc class ObjC_Class1 : Hashable { 
   var hashValue: Int { return 0 }
diff --git a/test/attr/attr_objcMembers.swift b/test/attr/attr_objcMembers.swift
new file mode 100644
index 0000000..7482013
--- /dev/null
+++ b/test/attr/attr_objcMembers.swift
@@ -0,0 +1,41 @@
+// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s
+// REQUIRES: objc_interop
+
+import Foundation
+
+@objcMembers
+class SomeClassWithObjCMembers {
+  func foo() { }
+}
+
+extension SomeClassWithObjCMembers {
+  var bar: NSObject? { get { return nil } set { } }
+}
+
+// @objcMembers is inherited
+class SubClassOfSomeClassWithObjCMembers : SomeClassWithObjCMembers {
+  func baz() { }
+
+  // Don't complain about things not expressible in Objective-C.
+  func notForObjC() -> (Int, Int) { return (0, 0) }
+}
+
+extension SubClassOfSomeClassWithObjCMembers {
+  func wibble() { }
+}
+
+// @objc should be inferred for everything referenced here.
+func selectorTest() {
+  _ = #selector(SomeClassWithObjCMembers.foo)
+  _ = #selector(getter: SomeClassWithObjCMembers.bar)
+  _ = #selector(SubClassOfSomeClassWithObjCMembers.baz)
+  _ = #selector(SubClassOfSomeClassWithObjCMembers.wibble)
+}
+
+@nonobjc extension SomeClassWithObjCMembers {
+  func notInferredObjC() { } // expected-note{{add '@objc' to expose this instance method to Objective-C}}
+}
+
+func selectorTestFail() {
+  _ = #selector(SomeClassWithObjCMembers.notInferredObjC) // expected-error{{argument of '#selector' refers to instance method 'notInferredObjC()' that is not exposed to Objective-C}}
+}
diff --git a/test/attr/attr_objc_swift3_deprecated.swift b/test/attr/attr_objc_swift3_deprecated.swift
new file mode 100644
index 0000000..6fdad84
--- /dev/null
+++ b/test/attr/attr_objc_swift3_deprecated.swift
@@ -0,0 +1,28 @@
+// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s -swift-version 3 -warn-swift3-objc-inference
+// REQUIRES: objc_interop
+
+import Foundation
+
+class ObjCSubclass : NSObject {
+  func foo() { } // expected-warning{{inference of '@objc' for members of Objective-C-derived classes is deprecated}}
+    // expected-note@-1{{add `@objc` to continue exposing an Objective-C entry point (Swift 3 behavior)}}{{3-3=@objc }}
+    // expected-note@-2{{add `@nonobjc` to suppress the Objective-C entry point (Swift 4 behavior)}}{{3-3=@nonobjc }}
+
+  var bar: NSObject? = nil // expected-warning{{inference of '@objc' for members of Objective-C-derived classes is deprecated}}
+    // expected-note@-1{{add `@objc` to continue exposing an Objective-C entry point (Swift 3 behavior)}}{{3-3=@objc }}
+    // expected-note@-2{{add `@nonobjc` to suppress the Objective-C entry point (Swift 4 behavior)}}{{3-3=@nonobjc }}
+}
+
+class DynamicMembers {
+  dynamic func foo() { } // expected-warning{{inference of '@objc' for 'dynamic' members is deprecated}}{{3-3=@objc }}
+  
+  dynamic var bar: NSObject? = nil // expected-warning{{inference of '@objc' for 'dynamic' members is deprecated}}{{3-3=@objc }}
+}
+
+// Suppress diagnostices about references to inferred @objc declarations
+// in this mode.
+func test(sc: ObjCSubclass, dm: DynamicMembers) {
+  _ = #selector(sc.foo)
+  _ = #selector(getter: dm.bar)
+  _ = #keyPath(DynamicMembers.bar)
+}
diff --git a/test/attr/attr_objc_swift3_deprecated_uses.swift b/test/attr/attr_objc_swift3_deprecated_uses.swift
new file mode 100644
index 0000000..2e5b492
--- /dev/null
+++ b/test/attr/attr_objc_swift3_deprecated_uses.swift
@@ -0,0 +1,83 @@
+// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s -swift-version 3
+// REQUIRES: objc_interop
+
+import Foundation
+
+class ObjCSubclass : NSObject {
+  func foo() { } // expected-note 2{{add '@objc' to expose this instance method to Objective-C}}{{3-3=@objc }}
+  var bar: NSObject? = nil // expected-note 2{{add '@objc' to expose this var to Objective-C}}{{3-3=@objc }}
+
+  var isEditing: Bool { // expected-warning{{var 'isEditing' with '@objc' setter depends on deprecated inference of '@objc'}}{{3-3=@objc }}
+    get { return false }
+
+    @objc(setEditing:)
+    set { }
+  }
+
+  subscript (i: Int) -> NSObject? { // expected-warning{{'subscript' with '@objc' getter depends on deprecated inference of '@objc'}}{{3-3=@objc }}
+    @objc(objectAtIndex:)
+    get {
+      return nil
+    }
+
+    set { }
+  }
+}
+
+class DynamicMembers {
+  dynamic func foo() { }
+  
+  dynamic var bar: NSObject? = nil
+
+  func overridableFunc() { }
+  var overridableVar: NSObject? = nil
+}
+
+extension ObjCSubclass {
+  func overridableFunc() { } // expected-note{{add '@objc' to expose this instance method to Objective-C}}{{3-3=@objc }}
+
+  var overridableVar: NSObject? { // expected-note{{add '@objc' to expose this var to Objective-C}}{{3-3=@objc }}
+    get { return nil }
+    set { }
+  }
+}
+
+class ObjCSubSubclass : ObjCSubclass {
+  override func foo() { } // okay: from the class
+
+  override var bar: NSObject? { // okay: from the class
+  get { return nil }
+    set { }
+  }
+
+  override func overridableFunc() { } // expected-warning{{override of instance method 'overridableFunc()' from extension of 'ObjCSubclass' depends on deprecated inference of '@objc'}}
+
+  override var overridableVar: NSObject? { // expected-warning{{override of var 'overridableVar' from extension of 'ObjCSubclass' depends on deprecated inference of '@objc'}}
+    get { return nil }
+    set { }
+  }
+}
+
+class SubclassDynamicMembers : DynamicMembers {
+  override func overridableFunc() { }  // okay, explicit dynamic
+
+  override var overridableVar: NSObject? { // okay, explicit dynamic
+    get { return nil }
+    set { }
+  }
+}
+
+func testSelector(sc: ObjCSubclass, dm: DynamicMembers) {
+  _ = #selector(sc.foo) // expected-warning{{argument of '#selector' refers to instance method 'foo()' in 'ObjCSubclass' that depends on '@objc' attribute inference deprecated in Swift 4}}
+  _ = #selector(getter: dm.bar) // okay, explicit dynamic
+}
+
+func testKeypath(dm: DynamicMembers) {
+  _ = #keyPath(ObjCSubclass.bar)   // expected-warning{{argument of '#keyPath' refers to property 'bar' in 'ObjCSubclass' that depends on '@objc' attribute inference deprecated in Swift 4}}
+  _ = #keyPath(DynamicMembers.bar) // okay: dynamic keyword implies @objc
+}
+
+func testDynamicCalls(ao: AnyObject) {
+  ao.foo?() // expected-warning{{reference to instance method 'foo()' of 'ObjCSubclass' depends on '@objc' attribute inference deprecated in Swift 4}}
+  _ = ao.bar! // expected-warning{{reference to var 'bar' of 'ObjCSubclass' depends on '@objc' attribute inference deprecated in Swift 4}}
+}
diff --git a/test/attr/attr_objc_swift4.swift b/test/attr/attr_objc_swift4.swift
new file mode 100644
index 0000000..e49fd97
--- /dev/null
+++ b/test/attr/attr_objc_swift4.swift
@@ -0,0 +1,22 @@
+// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s -swift-version 4 -enable-source-import -I %S/Inputs
+// REQUIRES: objc_interop
+
+import Foundation
+
+class ObjCSubclass : NSObject {
+  func foo() { } // expected-note{{add '@objc' to expose this instance method to Objective-C}}
+}
+
+class DynamicMembers {
+  dynamic func foo() { } // expected-error{{'dynamic' instance method 'foo()' must also be '@objc'}}{{3-3=@objc }}
+  
+  dynamic var bar: NSObject? = nil
+ // expected-error@-1{{'dynamic' var 'bar' must also be '@objc'}}{{3-3=@objc }}
+}
+
+func test(sc: ObjCSubclass, dm: DynamicMembers) {
+  _ = #selector(sc.foo) // expected-error{{argument of '#selector' refers to instance method 'foo()' that is not exposed to Objective-C}}
+
+  _ = #selector(getter: dm.bar)
+  _ = #keyPath(DynamicMembers.bar)
+}
diff --git a/test/attr/attr_specialize.swift b/test/attr/attr_specialize.swift
index db6ee99..5fc979d 100644
--- a/test/attr/attr_specialize.swift
+++ b/test/attr/attr_specialize.swift
@@ -151,8 +151,10 @@
 
 @_specialize(where T: P) // expected-error{{Only same-type and layout requirements are supported by '_specialize' attribute}}
 @_specialize(where T: Int) // expected-error{{Only conformances to protocol types are supported by '_specialize' attribute}} expected-error{{Only same-type and layout requirements are supported by '_specialize' attribute}}
+// expected-error@-1{{type 'T' constrained to non-protocol type 'Int'}}
 
 @_specialize(where T: S1) // expected-error{{Only conformances to protocol types are supported by '_specialize' attribute}} expected-error{{Only same-type and layout requirements are supported by '_specialize' attribute}}
+// expected-error@-1{{type 'T' constrained to non-protocol type 'S1'}}
 @_specialize(where T: C1) // expected-error{{Only conformances to protocol types are supported by '_specialize' attribute}} expected-error{{Only same-type and layout requirements are supported by '_specialize' attribute}}
 @_specialize(where Int: P) // expected-error{{type 'Int' in conformance requirement does not refer to a generic parameter or associated type}} expected-error{{Only same-type and layout requirements are supported by '_specialize' attribute}} expected-error{{too few type parameters are specified in '_specialize' attribute (got 0, but expected 1)}} expected-error{{Missing constraint for 'T' in '_specialize' attribute}}
 func funcWithForbiddenSpecializeRequirement<T>(_ t: T) {
diff --git a/test/decl/ext/generic.swift b/test/decl/ext/generic.swift
index a478406..a3b1b54 100644
--- a/test/decl/ext/generic.swift
+++ b/test/decl/ext/generic.swift
@@ -138,7 +138,7 @@
 
 extension GenericClass where Self : P3 { }
 // expected-error@-1{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'GenericClass'?}} {{30-34=GenericClass}}
-// expected-error@-2{{type 'GenericClass' in conformance requirement does not refer to a generic parameter or associated type}}
+// expected-error@-2{{type 'GenericClass<T>' in conformance requirement does not refer to a generic parameter or associated type}}
 
 protocol P4 {
   associatedtype T
diff --git a/test/decl/inherit/override.swift b/test/decl/inherit/override.swift
index d8a81ee..334b377 100644
--- a/test/decl/inherit/override.swift
+++ b/test/decl/inherit/override.swift
@@ -13,8 +13,8 @@
   @objc var v2: Int { return 0 } // expected-note{{overridden declaration is here}}
   @objc var v3: Int = 0 // expected-note{{overridden declaration is here}}
 
-  dynamic func f3D() { }
-  dynamic func f4D() -> ObjCClassA { }
+  dynamic func f3D() { } // expected-error{{'dynamic' instance method 'f3D()' must also be '@objc'}}{{3-3=@objc }}
+  dynamic func f4D() -> ObjCClassA { } // expected-error{{'dynamic' instance method 'f4D()' must also be '@objc'}}{{3-3=@objc }}
 }
 
 extension A {
@@ -76,7 +76,7 @@
 
   func method2(_ x: Sub, withInt y: Int) { }
 
-  func method3(_ x: Base, withInt y: Int) { } // expected-note{{method 'method3(_:withInt:)' declared here}}
+  @objc func method3(_ x: Base, withInt y: Int) { } // expected-note{{method 'method3(_:withInt:)' declared here}}
 }
 
 class ObjCSub : ObjCSuper {
@@ -84,5 +84,5 @@
 
   override func method2(_ x: Base, withInt y: Int) { } // okay, overrides trivially
 
-  func method3(_ x: Sub, withInt y: Int) { } // expected-error{{method3(_:withInt:)' with Objective-C selector 'method3:withInt:' conflicts with method 'method3(_:withInt:)' from superclass 'ObjCSuper' with the same Objective-C selector}}
+  @objc(method3:withInt:) func method3(_ x: Sub, with y: Int) { } // expected-error{{method3(_:with:)' with Objective-C selector 'method3:withInt:' conflicts with method 'method3(_:withInt:)' from superclass 'ObjCSuper' with the same Objective-C selector}}
 }
diff --git a/test/decl/protocol/objc.swift b/test/decl/protocol/objc.swift
index eb46aa6..b69259d 100644
--- a/test/decl/protocol/objc.swift
+++ b/test/decl/protocol/objc.swift
@@ -79,11 +79,11 @@
   @objc(method) func otherMethod() { } // expected-error{{Objective-C method 'method' provided by method 'otherMethod()' conflicts with optional requirement method 'method()' in protocol 'OptP1'}}
   // expected-note@-1{{rename method to match requirement 'method()'}}{{22-33=method}}
 
-  var otherProp1: ObjCClass {
+  @objc var otherProp1: ObjCClass {
     @objc(property1) get { return ObjCClass() } // expected-error{{Objective-C method 'property1' provided by getter for 'otherProp1' conflicts with optional requirement getter for 'property1' in protocol 'OptP1'}}
   }
 
-  var otherProp2: ObjCClass {
+  @objc var otherProp2: ObjCClass {
     get { return ObjCClass() }
     @objc(setProperty2:) set { } // expected-error{{Objective-C method 'setProperty2:' provided by setter for 'otherProp2' conflicts with optional requirement setter for 'property2' in protocol 'OptP1'}}
   }
@@ -92,7 +92,7 @@
 @objc class OptC1b : OptP1 { // expected-note 2{{class 'OptC1b' declares conformance to protocol 'OptP1' here}}
   @objc(property1) func someMethod() { } // expected-error{{Objective-C method 'property1' provided by method 'someMethod()' conflicts with optional requirement getter for 'property1' in protocol 'OptP1'}}
 
-  var someProp: ObjCClass {
+  @objc var someProp: ObjCClass {
     @objc(method) get { return ObjCClass() } // expected-error{{Objective-C method 'method' provided by getter for 'someProp' conflicts with optional requirement method 'method()' in protocol 'OptP1'}}
   }
 }
diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift
index 5b61cb1..d741884 100644
--- a/test/decl/protocol/req/recursion.swift
+++ b/test/decl/protocol/req/recursion.swift
@@ -65,8 +65,7 @@
 }
 
 protocol I {
-  // FIXME: these are spurious
-  init() // expected-note {{protocol requires initializer 'init()' with type '()'}}
+  init()
 }
 
 protocol PI {
diff --git a/test/decl/typealias/associated_types.swift b/test/decl/typealias/associated_types.swift
index 24b16b9..9f53579 100644
--- a/test/decl/typealias/associated_types.swift
+++ b/test/decl/typealias/associated_types.swift
@@ -17,5 +17,5 @@
 }
 
 
-func generic<T: BaseProto>(_ assoc: T.AssocTy) {} // no-warning
+func generic<T: BaseProto>(_: T, _ assoc: T.AssocTy) {} // no-warning
 
diff --git a/test/expr/dynamic_lookup.swift b/test/expr/dynamic_lookup.swift
index 6496f44..a728896 100644
--- a/test/expr/dynamic_lookup.swift
+++ b/test/expr/dynamic_lookup.swift
@@ -1,7 +1,7 @@
 // RUN: %target-typecheck-verify-swift
 
 @objc class HasStaticProperties {
-  class var staticVar1: Int { return 4 }
+  @objc class var staticVar1: Int { return 4 }
 }
 
 func testStaticProperty(classObj: AnyObject.Type) {
diff --git a/test/expr/unary/selector/Inputs/property_helper.swift b/test/expr/unary/selector/Inputs/property_helper.swift
index d306803..2b2a161 100644
--- a/test/expr/unary/selector/Inputs/property_helper.swift
+++ b/test/expr/unary/selector/Inputs/property_helper.swift
@@ -5,7 +5,7 @@
   @objc private(set) var privateSetVar = 2 // expected-note 2{{'privateSetVar' declared here}}
   @objc internal var internalVar = 2
 
-  internal func internalFunc() {}
+  @objc internal func internalFunc() {}
 
   private func privateFunc() {} // expected-note 2{{'privateFunc' declared here}}
 }
diff --git a/test/expr/unary/selector/property.swift b/test/expr/unary/selector/property.swift
index df2803b..5aea71b 100644
--- a/test/expr/unary/selector/property.swift
+++ b/test/expr/unary/selector/property.swift
@@ -143,9 +143,9 @@
 // Looking up inherited members
 
 class BaseClass: NSObject {
-  var myVar = 1
+  @objc var myVar = 1
 
-  func myFunc() {
+  @objc func myFunc() {
   }
 }
 
diff --git a/test/expr/unary/selector/selector.swift b/test/expr/unary/selector/selector.swift
index aad9880..6a0ce63 100644
--- a/test/expr/unary/selector/selector.swift
+++ b/test/expr/unary/selector/selector.swift
@@ -129,7 +129,7 @@
 }
 
 @objc class SR1827 {
-  func bar() {}
+  @objc func bar() {}
 }
 
 switch optionalSel {
diff --git a/test/multifile/Inputs/protocol-conformance/rdar31302713.swift b/test/multifile/Inputs/protocol-conformance/rdar31302713.swift
new file mode 100644
index 0000000..5c8e442
--- /dev/null
+++ b/test/multifile/Inputs/protocol-conformance/rdar31302713.swift
@@ -0,0 +1,24 @@
+public protocol Animal {
+  associatedtype AnimalSnackType : AnimalSnack
+  func snack(on: AnimalSnackType)
+}
+
+public protocol AnimalSnack {
+  associatedtype EatWith
+  func eat(with: EatWith)
+}
+
+extension AnimalSnack where EatWith : Animal {}
+
+public protocol FurryAnimal : Animal {
+    associatedtype Fangs : Animal
+    func bite(with: Fangs)
+}
+
+extension FurryAnimal {
+  public func snack(on: FurryAnimalSnack<Self>) {}
+}
+
+public struct FurryAnimalSnack<T : FurryAnimal> : AnimalSnack {
+  public func eat(with: T) {}
+}
diff --git a/test/multifile/protocol-conformance-rdar31302713.swift b/test/multifile/protocol-conformance-rdar31302713.swift
new file mode 100644
index 0000000..b2a8a01
--- /dev/null
+++ b/test/multifile/protocol-conformance-rdar31302713.swift
@@ -0,0 +1,6 @@
+// RUN: %target-swift-frontend -emit-ir -primary-file %s %S/Inputs/protocol-conformance/rdar31302713.swift -module-name animal_snack
+
+public struct FunctionalFurryAnimal<Fangs : Animal> : FurryAnimal
+    where Fangs.AnimalSnackType.EatWith == Fangs {
+  public func bite(with: Fangs) {}
+}
diff --git a/test/multifile/synthesized-accessors/one-module-imported/library.swift b/test/multifile/synthesized-accessors/one-module-imported/library.swift
index e087e4a..5ed3ccc 100644
--- a/test/multifile/synthesized-accessors/one-module-imported/library.swift
+++ b/test/multifile/synthesized-accessors/one-module-imported/library.swift
@@ -2,6 +2,8 @@
 
 import CoreGraphics
 
+// Case 1 - witness is imported accessor
+
 protocol OtherPoint {
   associatedtype FloatType
 
@@ -10,3 +12,12 @@
 }
 
 extension CGPoint: OtherPoint {}
+
+// Case 2 - witness is extension method of imported type
+
+extension CGPoint {
+  var z: Float {
+    get { return 0.0 }
+    set { }
+  }
+}
diff --git a/test/multifile/synthesized-accessors/one-module-imported/main.swift b/test/multifile/synthesized-accessors/one-module-imported/main.swift
index f6c391f..237e114 100644
--- a/test/multifile/synthesized-accessors/one-module-imported/main.swift
+++ b/test/multifile/synthesized-accessors/one-module-imported/main.swift
@@ -8,6 +8,8 @@
 
 import CoreGraphics
 
+// Case 1 - witness is imported accessor
+
 protocol MyPoint {
   associatedtype FloatType
 
@@ -17,5 +19,13 @@
 
 extension CGPoint: MyPoint {}
 
+// Case 2 - witness is extension method of imported type
+
+protocol MyProto {
+  var z: Float { get set }
+}
+
+extension CGPoint : MyProto {}
+
 // Dummy statement
 _ = ()
diff --git a/test/stdlib/BridgeNonVerbatim.swift b/test/stdlib/BridgeNonVerbatim.swift
index 7757295..e4ff7a0 100644
--- a/test/stdlib/BridgeNonVerbatim.swift
+++ b/test/stdlib/BridgeNonVerbatim.swift
@@ -16,7 +16,7 @@
 //  outlive the array.  
 //
 //===----------------------------------------------------------------------===//
-// RUN: %target-run-stdlib-swift %s | %FileCheck %s
+// RUN: %target-run-stdlib-swift
 // REQUIRES: executable_test
 //
 // REQUIRES: objc_interop
@@ -61,50 +61,48 @@
   var value: Int
 }
 
-// CHECK: testing...
-print("testing...")
+let BridgeNonVerbatimTests = TestSuite("BrideNonVerbatim")
 
-func testScope() {
-  let a = [X(1), X(2), X(3)]
-  let nsx: NSArray = a._bridgeToObjectiveC()
+BridgeNonVerbatimTests.test("testing") {
+    func testScope() {
+      let a = [X(1), X(2), X(3)]
+      let nsx: NSArray = a._bridgeToObjectiveC()
 
-  // construction of these tracked objects is lazy
-  // CHECK-NEXT: trackedCount = 0 .
-  print("trackedCount = \(LifetimeTracked.instances) .")
+      // construction of these tracked objects is lazy
+      expectEqual(LifetimeTracked.instances, 0)
 
-  // We can get a single element out
-  // CHECK-NEXT: nsx[0]: 1 .
-  let one = nsx.object(at: 0) as! LifetimeTracked
-  print("nsx[0]: \(one.value) .")
+      // We can get a single element out
+      let one = nsx.object(at: 0) as! LifetimeTracked
+      expectEqual(one.value, 1)
 
-  // We can get the element again, but it may not have the same identity
-  // CHECK-NEXT: object identity matches?
-  let anotherOne = nsx.object(at: 0) as! LifetimeTracked
-  print("object identity matches? \(one === anotherOne)")
+      // We can get the element again, but it may not have the same identity
+      let anotherOne = nsx.object(at: 0) as! LifetimeTracked
+      expectEqualReference(one, anotherOne)
 
-  // Because the elements come back at +0, we really don't want to
-  // treat them as objects, or we'll get double deletion
-  var objects: [Int] = [0, 0]
+      // Because the elements come back at +0, we really don't want to
+      // treat them as objects, or we'll get double deletion
+      var objects: [Int] = [0, 0]
 
-  objects.withUnsafeMutableBufferPointer {
-    // FIXME: Can't elide signature and use $0 here <rdar://problem/17770732> 
-    (buf: inout UnsafeMutableBufferPointer<Int>) -> () in
-    nsx.available_getObjects(
-      AutoreleasingUnsafeMutablePointer(buf.baseAddress!),
-      range: NSRange(location: 1, length: 2))
-    return
-  }
+      objects.withUnsafeMutableBufferPointer {
+        // FIXME: Can't elide signature and use $0 here <rdar://problem/17770732> 
+        (buf: inout UnsafeMutableBufferPointer<Int>) -> () in
+        nsx.available_getObjects(
+          AutoreleasingUnsafeMutablePointer(buf.baseAddress!),
+          range: NSRange(location: 1, length: 2))
+        return
+      }
 
-  // CHECK-NEXT: getObjects yields them at +0: true
-  var x = objects[0]
-  print("getObjects yields them at +0: "
-    + "\(_isUnique_native(&x))")
+      var x = objects[0]
+      // getObjects yields them at +0:
+      expectTrue(_isUnique_native(&x))
+    }
+
+    autoreleasepool() {
+      testScope()
+    }
+
+    // leaks?
+    expectEqual(LifetimeTracked.instances, 0)
 }
 
-autoreleasepool() {
-  testScope()
-}
-
-// CHECK-NEXT: leaks = 0 .
-print("leaks = \(LifetimeTracked.instances) .")
-
+runAllTests()
diff --git a/test/stdlib/Inputs/CommonArrayTests.gyb b/test/stdlib/Inputs/CommonArrayTests.gyb
index f0a2e1f..4cb3387 100644
--- a/test/stdlib/Inputs/CommonArrayTests.gyb
+++ b/test/stdlib/Inputs/CommonArrayTests.gyb
@@ -87,7 +87,7 @@
   do {
     let expected = [E.A, E.B, E.C, E.D]
     let sliceable = ${ArrayType}(expected)
-    checkSliceableWithBidirectionalIndex(expected, sliceable)
+    checkBidirectionalCollection(expected, sliceable)
   }
 
   /*
@@ -95,7 +95,7 @@
   do {
     let expected = [[E.A, E.B], [E.B, E.C], [E.D], [E.A, E.B, E.D]]
     let sliceable = ${ArrayType}(expected)
-    checkSliceableWithBidirectionalIndex(
+    checkBidirectionalCollection(
       expected, sliceable, SourceLocStack().withCurrentLoc())
   }
   */
diff --git a/test/stdlib/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m b/test/stdlib/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m
index c9d0687..fc52377 100644
--- a/test/stdlib/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m
+++ b/test/stdlib/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m
@@ -55,7 +55,6 @@
       @"_SwiftNativeNSStringBase",
       @"_SwiftNativeNSEnumeratorBase",
       @"_SwiftNativeNSDataBase",
-      @"_SwiftNativeNSCharacterSetBase",
       @"_SwiftNativeNSIndexSetBase",
       nil];
 
diff --git a/test/stdlib/TestCharacterSet.swift b/test/stdlib/TestCharacterSet.swift
index fe94c66..a4b1dce 100644
--- a/test/stdlib/TestCharacterSet.swift
+++ b/test/stdlib/TestCharacterSet.swift
@@ -160,9 +160,16 @@
     func test_classForCoder() {
         // confirm internal bridged impl types are not exposed to archival machinery
         let cs = CharacterSet() as NSCharacterSet
-        let expected: AnyClass = NSCharacterSet.self as AnyClass
-        expectTrue(cs.classForCoder == expected)
-        expectTrue(cs.classForKeyedArchiver == expected)
+        
+        // Either of the following two are OK
+        let expectedImmutable: AnyClass = NSCharacterSet.self as AnyClass
+        let expectedMutable: AnyClass = NSMutableCharacterSet.self as AnyClass
+        
+        let actualClass: AnyClass = cs.classForCoder
+        let actualClassForCoder: AnyClass = cs.classForKeyedArchiver!
+        
+        expectTrue(actualClass == expectedImmutable || actualClass == expectedMutable)
+        expectTrue(actualClassForCoder == expectedImmutable || actualClassForCoder == expectedMutable)
     }
 
     func test_AnyHashableContainingCharacterSet() {
@@ -241,9 +248,58 @@
         expectEqual(0x6, bitmap[12])
         expectEqual(8192, bitmap.count)
     }
+    
+    func test_setOperationsOfEmptySet() {
+        // The following tests pass on these versions of the OS
+        if #available(OSX 10.12.3, iOS 10.3, watchOS 3.2, tvOS 10.2, *) {
+            let emptySet = CharacterSet()
+            let abcSet = CharacterSet(charactersIn: "abc")
+            
+            expectTrue(abcSet.isSuperset(of: emptySet))
+            expectTrue(emptySet.isSuperset(of: emptySet))
+            expectFalse(emptySet.isSuperset(of: abcSet))
+            
+            expectTrue(abcSet.isStrictSuperset(of: emptySet))
+            expectFalse(emptySet.isStrictSuperset(of: emptySet))
+            expectFalse(emptySet.isStrictSuperset(of: abcSet))
+            
+            expectTrue(emptySet.isSubset(of: abcSet))
+            expectTrue(emptySet.isSubset(of: emptySet))
+            expectFalse(abcSet.isSubset(of: emptySet))
+            
+            expectTrue(emptySet.isStrictSubset(of: abcSet))
+            expectFalse(emptySet.isStrictSubset(of: emptySet))
+            expectFalse(abcSet.isStrictSubset(of: emptySet))
+            expectFalse(abcSet.isStrictSubset(of: abcSet))
+            
+            expectEqual(emptySet, emptySet)
+            expectNotEqual(abcSet, emptySet)
+        }
+    }
+    
+    func test_moreSetOperations() {
+        // previous to these releases the subset methods improperly calculated strict subsets
+        // as of macOS 10.12.4, iOS 10.3, watchOS 3.2 and tvOS 10.2 CoreFoundation had a bug
+        // fix that corrected this behavior.
+        // TODO: figure out why the simulator is claiming this as a failure.
+        // https://bugs.swift.org/browse/SR-4457
+        #if os(macOS)
+            if #available(OSX 10.12.4, iOS 10.3, watchOS 3.2, tvOS 10.2, *) {
+                let abcSet = CharacterSet(charactersIn: "abc")
+                let abcdSet = CharacterSet(charactersIn: "abcd")
+                
+                expectEqual(abcSet, abcSet)
+                expectNotEqual(abcSet, abcdSet)
+                
+                expectTrue(abcSet.isStrictSubset(of:abcdSet))
+                expectFalse(abcdSet.isStrictSubset(of:abcSet))
+                expectTrue(abcdSet.isStrictSuperset(of:abcSet))
+                expectFalse(abcSet.isStrictSuperset(of:abcdSet))
+            }
+        #endif
+    }
 }
 
-
 #if !FOUNDATION_XCTEST
 var CharacterSetTests = TestSuite("TestCharacterSet")
 CharacterSetTests.test("testBasicConstruction") { TestCharacterSet().testBasicConstruction() }
@@ -264,6 +320,8 @@
 CharacterSetTests.test("test_symmetricDifference") { TestCharacterSet().test_symmetricDifference() }
 CharacterSetTests.test("test_hasMember") { TestCharacterSet().test_hasMember() }
 CharacterSetTests.test("test_bitmap") { TestCharacterSet().test_bitmap() }
+CharacterSetTests.test("test_setOperationsOfEmptySet") { TestCharacterSet().test_setOperationsOfEmptySet() }
+CharacterSetTests.test("test_moreSetOperations") { TestCharacterSet().test_moreSetOperations() }
 runAllTests()
 #endif
 
diff --git a/test/stdlib/TestData.swift b/test/stdlib/TestData.swift
index 4d106bb..c84f89e 100644
--- a/test/stdlib/TestData.swift
+++ b/test/stdlib/TestData.swift
@@ -944,6 +944,23 @@
             }
         }
     }
+
+    func test_rangeZoo() {
+        let r1 = Range(0..<1)
+        let r2 = CountableRange(0..<1)
+        let r3 = ClosedRange(0..<1)
+        let r4 = CountableClosedRange(0..<1)
+
+        let data = Data(bytes: [8, 1, 2, 3, 4])
+        let slice1: Data = data[r1]
+        let slice2: Data = data[r2]
+        let slice3: Data = data[r3]
+        let slice4: Data = data[r4]
+        expectEqual(slice1[0], 8)
+        expectEqual(slice2[0], 8)
+        expectEqual(slice3[0], 8)
+        expectEqual(slice4[0], 8)
+    }
 }
 
 #if !FOUNDATION_XCTEST
@@ -989,6 +1006,7 @@
 DataTests.test("test_noCopyBehavior") { TestData().test_noCopyBehavior() }
 DataTests.test("test_doubleDeallocation") { TestData().test_doubleDeallocation() }
 DataTests.test("test_repeatingValueInitialization") { TestData().test_repeatingValueInitialization() }
+DataTests.test("test_rangeZoo") { TestData().test_rangeZoo() }
 
 // XCTest does not have a crash detection, whereas lit does
 DataTests.test("bounding failure subdata") {
diff --git a/test/stdlib/TestDate.swift b/test/stdlib/TestDate.swift
index c7631b6..66a0ac8 100644
--- a/test/stdlib/TestDate.swift
+++ b/test/stdlib/TestDate.swift
@@ -51,12 +51,6 @@
         d1 += 10
         expectTrue(d1 > d3)
     }
-    
-    func testDateHash() {
-        let d0 = NSDate()
-        let d1 = Date(timeIntervalSinceReferenceDate: d0.timeIntervalSinceReferenceDate)
-        expectEqual(d0.hashValue, d1.hashValue)
-    }
 
     func testCast() {
         let d0 = NSDate()
@@ -202,7 +196,6 @@
 var DateTests = TestSuite("TestDate")
 DateTests.test("testDateComparison") { TestDate().testDateComparison() }
 DateTests.test("testDateMutation") { TestDate().testDateMutation() }
-DateTests.test("testDateHash") { TestDate().testDateHash() }
 DateTests.test("testCast") { TestDate().testCast() }
 DateTests.test("testDistantPast") { TestDate().testDistantPast() }
 DateTests.test("testDistantFuture") { TestDate().testDistantFuture() }
diff --git a/test/stdlib/UnsafeRawBufferPointer.swift b/test/stdlib/UnsafeRawBufferPointer.swift
index 577f0f6..b509af5 100644
--- a/test/stdlib/UnsafeRawBufferPointer.swift
+++ b/test/stdlib/UnsafeRawBufferPointer.swift
@@ -23,7 +23,7 @@
     // Mutable view of value2's bytes.
     withUnsafeMutableBytes(of: &value2) { bytes2 in
       expectEqual(bytes1.count, bytes2.count)
-      bytes2[0..<bytes2.count].copyBytes(from: bytes1)
+      bytes2.copyBytes(from: bytes1)
     }
   }
   expectEqual(value2, value1)
@@ -45,8 +45,15 @@
   defer { buffer.deallocate() }
   buffer.copyBytes(from: [0, 1, 2, 3] as [UInt8])
   let leftBytes = buffer[0..<2]
-  let rightBytes = buffer[0..<2]
-  leftBytes[0..<2] = rightBytes
+
+  // Subscript assign.
+  var rightBytes = buffer[2..<4]
+  buffer[2..<4] = leftBytes
+  expectEqualSequence(leftBytes, rightBytes)
+  
+  // Subscript assign into a `var` mutable slice.
+  buffer.copyBytes(from: [0, 1, 2, 3] as [UInt8])
+  rightBytes[2..<4] = leftBytes
   expectEqualSequence(leftBytes, rightBytes)
 }
 
@@ -69,7 +76,7 @@
     // Mutable view of array2's bytes.
     array2.withUnsafeMutableBytes { bytes2 in
       expectEqual(bytes1.count, bytes2.count)
-      bytes2[0..<bytes2.count].copyBytes(from: bytes1)
+      bytes2.copyBytes(from: bytes1)
     }
   }
   expectEqual(array2, array1)
@@ -120,7 +127,7 @@
   let buffer = UnsafeMutableRawBufferPointer(start: nil, count: 0)
   let source: [Int64] = [5, 4, 3, 2, 1]
   expectCrashLater()
-  var (it, bound) = buffer.initializeMemory(as: Int64.self, from: source)
+  _ = buffer.initializeMemory(as: Int64.self, from: source)
 }
 
 UnsafeRawBufferPointerTestSuite.test("initializeMemory(as:from:).validNilPtr") {
@@ -148,11 +155,11 @@
 // Test the empty buffer.
 UnsafeRawBufferPointerTestSuite.test("empty") {
   let emptyBytes = UnsafeRawBufferPointer(start: nil, count: 0)
-  for byte in emptyBytes {
+  for _ in emptyBytes {
     expectUnreachable()
   }
   let emptyMutableBytes = UnsafeMutableRawBufferPointer.allocate(count: 0)
-  for byte in emptyMutableBytes {
+  for _ in emptyMutableBytes {
     expectUnreachable()
   }
   emptyMutableBytes.deallocate()
@@ -186,7 +193,8 @@
   for i in 0..<MemoryLayout<Int32>.stride {
     expectEqual(0xFF, bytes[i])
   }
-  let bytes2 = bytes[MemoryLayout<Int32>.stride..<bytes.count]
+  let bytes2 = UnsafeMutableRawBufferPointer(
+    rebasing: bytes[MemoryLayout<Int32>.stride..<bytes.count])
   for i in 0..<MemoryLayout<Int32>.stride {
     expectEqual(0, bytes2[i])
   }
@@ -218,7 +226,7 @@
   }
   let median = (numInts/2 * MemoryLayout<Int>.stride)
   var firstHalf = bytes[0..<median]
-  var secondHalf = bytes[median..<bytes.count]
+  let secondHalf = bytes[median..<bytes.count]
   firstHalf[0..<firstHalf.count] = secondHalf
   expectEqualSequence(firstHalf, secondHalf)
 }
@@ -227,7 +235,7 @@
   let buffer = UnsafeMutableRawBufferPointer.allocate(count: 2)
   defer { buffer.deallocate() }
 
-  let bytes = buffer[1..<2]
+  let bytes = UnsafeRawBufferPointer(rebasing: buffer[1..<2])
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
@@ -240,7 +248,7 @@
   let buffer = UnsafeMutableRawBufferPointer.allocate(count: 2)
   defer { buffer.deallocate() }
 
-  let bytes = buffer[0..<1]
+  let bytes = UnsafeRawBufferPointer(rebasing: buffer[0..<1])
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
@@ -253,7 +261,7 @@
   let buffer = UnsafeMutableRawBufferPointer.allocate(count: 2)
   defer { buffer.deallocate() }
 
-  let bytes = buffer[1..<2]
+  var bytes = UnsafeMutableRawBufferPointer(rebasing: buffer[1..<2])
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
@@ -266,7 +274,7 @@
   let buffer = UnsafeMutableRawBufferPointer.allocate(count: 2)
   defer { buffer.deallocate() }
 
-  let bytes = buffer[0..<1]
+  var bytes = UnsafeMutableRawBufferPointer(rebasing: buffer[0..<1])
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
@@ -279,7 +287,7 @@
   let buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
   defer { buffer.deallocate() }
 
-  let bytes = buffer[1..<3]
+  let bytes = UnsafeRawBufferPointer(rebasing: buffer[1..<3])
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
@@ -292,7 +300,7 @@
   let buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
   defer { buffer.deallocate() }
 
-  let bytes = buffer[0..<2]
+  let bytes = UnsafeRawBufferPointer(rebasing: buffer[0..<2])
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
@@ -305,7 +313,7 @@
   var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
   defer { buffer.deallocate() }
 
-  var bytes = buffer[1..<3]
+  var bytes = UnsafeMutableRawBufferPointer(rebasing: buffer[1..<3])
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
@@ -318,7 +326,8 @@
   var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
   defer { buffer.deallocate() }
 
-  var bytes = buffer[0..<2]
+  var bytes = UnsafeMutableRawBufferPointer(rebasing: buffer[0..<2])
+
   if _isDebugAssertConfiguration() {
     expectCrashLater()
   }
@@ -353,26 +362,27 @@
   var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
   defer { buffer.deallocate() }
 
-  var bytes = buffer[0..<2]
+  let bytes = buffer[0..<2]
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
   }
   // Performs a valid byte-wise copy but triggers a debug range size check.
-  bytes.copyBytes(from: buffer)
+  UnsafeMutableRawBufferPointer(rebasing: bytes).copyBytes(from: buffer)
 }
 
 UnsafeRawBufferPointerTestSuite.test("copyBytes.sequence.overflow") {
   var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
   defer { buffer.deallocate() }
   
-  var bytes = buffer[0..<2]
+  let bytes = buffer[0..<2]
 
   if _isDebugAssertConfiguration() {
     expectCrashLater()
   }
   // Performs a valid byte-wise copy but triggers a debug range size check.
-  bytes.copyBytes(from: [0, 1, 2] as [UInt8])
+  UnsafeMutableRawBufferPointer(rebasing: bytes).copyBytes(
+    from: [0, 1, 2] as [UInt8])
 }
 
 UnsafeRawBufferPointerTestSuite.test("load.before")
@@ -454,7 +464,7 @@
 }
 
 UnsafeRawBufferPointerTestSuite.test("copy.overlap") {
-  var bytes = UnsafeMutableRawBufferPointer.allocate(count: 4)
+  let bytes = UnsafeMutableRawBufferPointer.allocate(count: 4)
   // Right Overlap
   bytes[0] = 1
   bytes[1] = 2
diff --git a/tools/SourceKit/include/SourceKit/Core/LangSupport.h b/tools/SourceKit/include/SourceKit/Core/LangSupport.h
index fce5664..0ec966f 100644
--- a/tools/SourceKit/include/SourceKit/Core/LangSupport.h
+++ b/tools/SourceKit/include/SourceKit/Core/LangSupport.h
@@ -285,6 +285,7 @@
   /// All available actions on the code under cursor.
   ArrayRef<StringRef> AvailableActions;
   bool IsSystem = false;
+  llvm::Optional<unsigned> ParentNameOffset;
 };
 
 struct RangeInfo {
diff --git a/tools/SourceKit/lib/SwiftLang/CMakeLists.txt b/tools/SourceKit/lib/SwiftLang/CMakeLists.txt
index 6845ec1..8513bff 100644
--- a/tools/SourceKit/lib/SwiftLang/CMakeLists.txt
+++ b/tools/SourceKit/lib/SwiftLang/CMakeLists.txt
@@ -8,7 +8,7 @@
   SwiftIndexing.cpp
   SwiftLangSupport.cpp
   SwiftSourceDocInfo.cpp
-  DEPENDS SourceKitCore swiftDriver swiftFrontend swiftClangImporter swiftIndex swiftIDE
+  DEPENDS SourceKitCore swiftDriver swiftFrontend swiftClangImporter swiftIDE
           swiftAST swiftMarkup swiftParse swiftSIL swiftSILGen swiftSILOptimizer
           swiftIRGen swiftSema swiftBasic swiftSerialization swiftOption libcmark_static
     # Clang dependencies.
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
index 5d0d69e..c719d7c 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
@@ -455,7 +455,7 @@
 void walkRelatedDecls(const ValueDecl *VD, const FnTy &Fn) {
   llvm::SmallDenseMap<DeclName, unsigned, 16> NamesSeen;
   ++NamesSeen[VD->getFullName()];
-  SmallVector<ValueDecl *, 8> RelatedDecls;
+  SmallVector<UnqualifiedLookupResult, 8> RelatedDecls;
 
   if (isa<ParamDecl>(VD))
     return; // Parameters don't have interesting related declarations.
@@ -473,13 +473,16 @@
 
     if (RelatedVD != VD) {
       ++NamesSeen[RelatedVD->getFullName()];
-      RelatedDecls.push_back(RelatedVD);
+      RelatedDecls.push_back(result);
     }
   }
 
   // Now provide the results along with whether the name is duplicate or not.
-  for (auto RelatedVD : RelatedDecls) {
-    Fn(RelatedVD, NamesSeen[RelatedVD->getFullName()] > 1);
+  ValueDecl *OriginalBase = VD->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
+  for (auto Related : RelatedDecls) {
+    ValueDecl *RelatedVD = Related.getValueDecl();
+    bool SameBase = Related.getBaseDecl() && Related.getBaseDecl() == OriginalBase;
+    Fn(RelatedVD, SameBase, NamesSeen[RelatedVD->getFullName()] > 1);
   }
 }
 
@@ -610,6 +613,28 @@
   return false;
 }
 
+static Optional<unsigned> getParamParentNameOffset(const ValueDecl *VD) {
+  SourceLoc Loc;
+  if (auto PD = dyn_cast<ParamDecl>(VD)) {
+    auto *DC = PD->getDeclContext();
+    switch (DC->getContextKind()) {
+      case DeclContextKind::SubscriptDecl:
+        Loc = cast<SubscriptDecl>(DC)->getNameLoc();
+        break;
+      case DeclContextKind::AbstractFunctionDecl:
+        Loc = cast<AbstractFunctionDecl>(DC)->getNameLoc();
+        break;
+      default:
+        break;
+    }
+  }
+  if (Loc.isInvalid())
+    return None;
+  auto &SM = VD->getASTContext().SourceMgr;
+  return SM.getLocOffsetInBuffer(Loc, SM.getIDForBufferIdentifier(SM.
+    getBufferIdentifierForLoc(Loc)).getValue());
+}
+
 /// Returns true for failure to resolve.
 static bool passCursorInfoForDecl(const ValueDecl *VD,
                                   const ModuleDecl *MainModule,
@@ -741,7 +766,7 @@
   });
 
   DelayedStringRetriever RelDeclsStream(SS);
-  walkRelatedDecls(VD, [&](const ValueDecl *RelatedDecl, bool DuplicateName) {
+  walkRelatedDecls(VD, [&](const ValueDecl *RelatedDecl, bool UseOriginalBase, bool DuplicateName) {
     RelDeclsStream.startPiece();
     {
       RelDeclsStream<<"<RelatedName usr=\"";
@@ -755,7 +780,7 @@
         PO.SkipIntroducerKeywords = true;
         PO.ArgAndParamPrinting = PrintOptions::ArgAndParamPrintingMode::ArgumentOnly;
         XMLEscapingPrinter Printer(RelDeclsStream);
-        if (BaseType) {
+        if (UseOriginalBase && BaseType) {
           PO.setBaseType(BaseType);
           PO.PrintAsMember = true;
         }
@@ -850,6 +875,7 @@
   Info.LocalizationKey = LocalizationKey;
   Info.IsSystem = IsSystem;
   Info.TypeInterface = StringRef();
+  Info.ParentNameOffset = getParamParentNameOffset(VD);
   Receiver(Info);
   return false;
 }
@@ -865,8 +891,8 @@
     return clang::DeclarationName(&Ctx.Idents.get(Info.BaseName));
   } else {
     ArrayRef<StringRef> Args = llvm::makeArrayRef(Info.ArgNames);
-    std::vector<clang::IdentifierInfo *> Pieces(Args.size(), nullptr);
-    std::transform(Args.begin(), Args.end(), Pieces.begin(),
+    std::vector<clang::IdentifierInfo *> Pieces;
+    std::transform(Args.begin(), Args.end(), std::back_inserter(Pieces),
       [&](StringRef T) { return &Ctx.Idents.get(T.endswith(":") ?
                                                 T.drop_back() : T); });
     return clang::DeclarationName(Ctx.Selectors.getSelector(
@@ -879,8 +905,9 @@
 static DeclName
 getSwiftDeclName(ASTContext &Ctx, NameTranslatingInfo &Info) {
   assert(SwiftLangSupport::getNameKindForUID(Info.NameKind) == NameKind::Swift);
-  std::vector<Identifier> Args(Info.ArgNames.size(), Identifier());
-  std::transform(Info.ArgNames.begin(), Info.ArgNames.end(), Args.begin(),
+  std::vector<Identifier> Args;
+  std::transform(Info.ArgNames.begin(), Info.ArgNames.end(),
+                 std::back_inserter(Args),
                  [&](StringRef T) { return Ctx.getIdentifier(T); });
   return DeclName(Ctx, Ctx.getIdentifier(Info.BaseName),
                   llvm::makeArrayRef(Args));
@@ -899,6 +926,7 @@
     if (!Name.empty()) {
       Result.NameKind = SwiftLangSupport::getUIDForNameKind(NameKind::ObjC);
       Result.BaseName = Name.str();
+      Receiver(Result);
     } else if (ObjCSelector Selector = ResultPair.second) {
       Result.NameKind = SwiftLangSupport::getUIDForNameKind(NameKind::ObjC);
       SmallString<64> Buffer;
@@ -912,11 +940,11 @@
           [](StringRef P) { return StringRef(P.data(), P.size() + 1); });
       }
       Result.ArgNames.insert(Result.ArgNames.begin(), Pieces.begin(), Pieces.end());
+      Receiver(Result);
     } else {
       Receiver(Result);
       return true;
     }
-    Receiver(Result);
     return false;
   }
   case NameKind::ObjC: {
@@ -929,10 +957,9 @@
       NameTranslatingInfo Result;
       Result.NameKind = SwiftLangSupport::getUIDForNameKind(NameKind::Swift);
       Result.BaseName = Name.getBaseName().str();
-      Result.ArgNames.resize(Name.getArgumentNames().size());
       std::transform(Name.getArgumentNames().begin(),
                      Name.getArgumentNames().end(),
-                     Result.ArgNames.begin(),
+                     std::back_inserter(Result.ArgNames),
                      [](Identifier Id) { return Id.str(); });
       Receiver(Result);
       return false;
@@ -1019,6 +1046,7 @@
     return false;
   }
 };
+
 static void resolveCursor(SwiftLangSupport &Lang,
                           StringRef InputFile, unsigned Offset,
                           unsigned Length, bool Actionables,
diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp
index 8424d46..7fa5d58 100644
--- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp
+++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp
@@ -101,6 +101,7 @@
 static sourcekitd_uid_t KeyModuleInterfaceName;
 static sourcekitd_uid_t KeyLength;
 static sourcekitd_uid_t KeyActionable;
+static sourcekitd_uid_t KeyParentLoc;
 static sourcekitd_uid_t KeySourceText;
 static sourcekitd_uid_t KeyUSR;
 static sourcekitd_uid_t KeyOriginalUSR;
@@ -118,6 +119,7 @@
 static sourcekitd_uid_t KeyEnableSubStructure;
 static sourcekitd_uid_t KeySyntacticOnly;
 static sourcekitd_uid_t KeyLine;
+static sourcekitd_uid_t KeyColumn;
 static sourcekitd_uid_t KeyFormatOptions;
 static sourcekitd_uid_t KeyCodeCompleteOptions;
 static sourcekitd_uid_t KeyAnnotations;
@@ -226,6 +228,7 @@
   KeyModuleInterfaceName = sourcekitd_uid_get_from_cstr("key.module_interface_name");
   KeyLength = sourcekitd_uid_get_from_cstr("key.length");
   KeyActionable = sourcekitd_uid_get_from_cstr("key.actionable");
+  KeyParentLoc = sourcekitd_uid_get_from_cstr("key.parent_loc");;
   KeySourceText = sourcekitd_uid_get_from_cstr("key.sourcetext");
   KeyUSR = sourcekitd_uid_get_from_cstr("key.usr");
   KeyOriginalUSR = sourcekitd_uid_get_from_cstr("key.original_usr");
@@ -244,6 +247,7 @@
   KeyEnableSubStructure = sourcekitd_uid_get_from_cstr("key.enablesubstructure");
   KeySyntacticOnly = sourcekitd_uid_get_from_cstr("key.syntactic_only");
   KeyLine = sourcekitd_uid_get_from_cstr("key.line");
+  KeyColumn = sourcekitd_uid_get_from_cstr("key.column");
   KeyFormatOptions = sourcekitd_uid_get_from_cstr("key.editor.format.options");
   KeyCodeCompleteOptions =
       sourcekitd_uid_get_from_cstr("key.codecomplete.options");
@@ -1265,6 +1269,9 @@
                                                                 KeyActionName));
   }
 
+  uint64_t ParentOffset =
+    sourcekitd_variant_dictionary_get_int64(Info, KeyParentLoc);
+
   OS << Kind << " (";
   if (Offset.hasValue()) {
     if (Filename != FilePath)
@@ -1321,6 +1328,9 @@
   for (auto Action : AvailableActions)
     OS << Action << '\n';
   OS << "ACTIONS END\n";
+  if (ParentOffset) {
+    OS << "PARENT OFFSET: " << ParentOffset << "\n";
+  }
 }
 
 static void printRangeInfo(sourcekitd_variant_t Info, StringRef FilenameIn,
diff --git a/tools/SourceKit/tools/sourcekitd/bin/XPC/Client/sourcekitd.cpp b/tools/SourceKit/tools/sourcekitd/bin/XPC/Client/sourcekitd.cpp
index 41a82b7..b98d503 100644
--- a/tools/SourceKit/tools/sourcekitd/bin/XPC/Client/sourcekitd.cpp
+++ b/tools/SourceKit/tools/sourcekitd/bin/XPC/Client/sourcekitd.cpp
@@ -17,6 +17,7 @@
 
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Mutex.h"
+#include "llvm/Support/TargetSelect.h"
 #include <chrono>
 #include <xpc/xpc.h>
 #include <dispatch/dispatch.h>
@@ -250,6 +251,11 @@
 void sourcekitd::initialize() {
   initializeTracing();
 
+  llvm::InitializeAllTargets();
+  llvm::InitializeAllTargetMCs();
+  llvm::InitializeAllAsmPrinters();
+  llvm::InitializeAllAsmParsers();
+
   assert(!GlobalConn);
   GlobalConn = xpc_connection_create(SOURCEKIT_XPCSERVICE_IDENTIFIER, nullptr);
 
diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/DictionaryKeys.h b/tools/SourceKit/tools/sourcekitd/lib/API/DictionaryKeys.h
index dc32012..098c8cf 100644
--- a/tools/SourceKit/tools/sourcekitd/lib/API/DictionaryKeys.h
+++ b/tools/SourceKit/tools/sourcekitd/lib/API/DictionaryKeys.h
@@ -41,6 +41,7 @@
 extern SourceKit::UIdent KeySyntacticOnly;
 extern SourceKit::UIdent KeyLength;
 extern SourceKit::UIdent KeyActionable;
+extern SourceKit::UIdent KeyParentLoc;
 extern SourceKit::UIdent KeyKind;
 extern SourceKit::UIdent KeyAccessibility;
 extern SourceKit::UIdent KeySetterAccessibility;
diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp
index 4c7b3e9..3fd3ee6 100644
--- a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp
+++ b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp
@@ -35,6 +35,7 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/TargetSelect.h"
 #include <mutex>
 
 // FIXME: Portability.
@@ -149,6 +150,11 @@
 static SourceKit::Context *GlobalCtx = nullptr;
 
 void sourcekitd::initialize() {
+  llvm::InitializeAllTargets();
+  llvm::InitializeAllTargetMCs();
+  llvm::InitializeAllAsmPrinters();
+  llvm::InitializeAllAsmParsers();
+
   GlobalCtx = new SourceKit::Context(sourcekitd::getRuntimeLibPath(),
                                      SourceKit::createSwiftLangSupport);
   GlobalCtx->getNotificationCenter().addDocumentUpdateNotificationReceiver(
@@ -810,13 +816,14 @@
       return Rec(createErrorRequestInvalid("cannot specify 'key.selectorpieces' "
                                            "and 'key.argnames' at the same time"));
     }
-    Input.ArgNames.resize(ArgParts.size() + Selectors.size());
-    std::transform(ArgParts.begin(), ArgParts.end(), Input.ArgNames.begin(),
+    std::transform(ArgParts.begin(), ArgParts.end(),
+                   std::back_inserter(Input.ArgNames),
       [](const char *C) {
         StringRef Original(C);
         return Original == "_" ? StringRef() : Original;
       });
-    std::transform(Selectors.begin(), Selectors.end(), Input.ArgNames.begin(),
+    std::transform(Selectors.begin(), Selectors.end(),
+                   std::back_inserter(Input.ArgNames),
                    [](const char *C) { return StringRef(C); });
     return Lang.getNameInfo(*SourceFile, Offset, Input, Args,
       [Rec](const NameTranslatingInfo &Info) { reportNameInfo(Info, Rec); });
@@ -1429,6 +1436,9 @@
       Entry.set(KeyActionName, Name);
     }
   }
+  if (Info.ParentNameOffset) {
+    Elem.set(KeyParentLoc, Info.ParentNameOffset.getValue());
+  }
   if (!Info.AnnotatedRelatedDeclarations.empty()) {
     auto RelDecls = Elem.setArray(KeyRelatedDecls);
     for (auto AnnotDecl : Info.AnnotatedRelatedDeclarations) {
diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-Common.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-Common.cpp
index cc4fa29..893cd4e 100644
--- a/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-Common.cpp
+++ b/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-Common.cpp
@@ -55,6 +55,7 @@
 UIdent sourcekitd::KeySyntacticOnly("key.syntactic_only");
 UIdent sourcekitd::KeyLength("key.length");
 UIdent sourcekitd::KeyActionable("key.actionable");
+UIdent sourcekitd::KeyParentLoc("key.parent_loc");
 UIdent sourcekitd::KeyKind("key.kind");
 UIdent sourcekitd::KeyAccessibility("key.accessibility");
 UIdent sourcekitd::KeySetterAccessibility("key.setter_accessibility");
diff --git a/tools/driver/modulewrap_main.cpp b/tools/driver/modulewrap_main.cpp
index 3f6413f..fcd7c25 100644
--- a/tools/driver/modulewrap_main.cpp
+++ b/tools/driver/modulewrap_main.cpp
@@ -168,7 +168,7 @@
   LangOpts.Target = Invocation.getTargetTriple();
   ASTContext ASTCtx(LangOpts, SearchPathOpts, SrcMgr, Instance.getDiags());
   ClangImporterOptions ClangImporterOpts;
-  ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ClangImporterOpts),
+  ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ClangImporterOpts, ""),
                          true);
   ModuleDecl *M = ModuleDecl::create(ASTCtx.getIdentifier("swiftmodule"), ASTCtx);
   SILOptions SILOpts;
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index d51b958..21154ee 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -1673,10 +1673,10 @@
       auto LastPartOfA = getLastPartOfUsr(VC);
         if (LastPartOfA && LastPartOfR.getValue() == LastPartOfA.getValue()) {
           R->annotate(NodeAnnotation::ModernizeEnum);
-          llvm::Twine FullName = llvm::Twine().concat(A->getName()).concat(".").
-            concat(Child->getName());
+          std::string FullName = (llvm::Twine(A->getName()) + "." +
+            Child->getName()).str();
           R->addAnnotateComment(NodeAnnotation::ModernizeEnum,
-                                R->getSDKContext().buffer(FullName.str()));
+                                R->getSDKContext().buffer(FullName));
           foundMatch(R, A);
           return true;
         }
diff --git a/tools/swift-ide-test/CMakeLists.txt b/tools/swift-ide-test/CMakeLists.txt
index 4347a75..e260cab 100644
--- a/tools/swift-ide-test/CMakeLists.txt
+++ b/tools/swift-ide-test/CMakeLists.txt
@@ -5,7 +5,6 @@
   LINK_LIBRARIES
     swiftDriver
     swiftFrontend
-    swiftIndex
     swiftIDE
   LLVM_COMPONENT_DEPENDS
     DebugInfoCodeView
diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp
index 444070b..a42fc68 100644
--- a/tools/swift-ide-test/swift-ide-test.cpp
+++ b/tools/swift-ide-test/swift-ide-test.cpp
@@ -244,6 +244,10 @@
 ModuleCachePath("module-cache-path", llvm::cl::desc("Clang module cache path"));
 
 static llvm::cl::opt<std::string>
+PCHOutputDir("pch-output-dir", llvm::cl::desc("place autogenerated PCH files in this directory"));
+
+
+static llvm::cl::opt<std::string>
     CompletionCachePath("completion-cache-path",
                         llvm::cl::desc("Code completion cache path"),
                         llvm::cl::ZeroOrMore);
@@ -313,6 +317,12 @@
                    llvm::cl::init(false));
 
 static llvm::cl::opt<bool>
+EnableSwift3ObjCInference(
+                  "enable-swift3-objc-inference",
+                  llvm::cl::desc("Enable Swift 3's @objc inference rules"),
+                  llvm::cl::init(false));
+
+static llvm::cl::opt<bool>
 DisableObjCAttrRequiresFoundationModule(
     "disable-objc-attr-requires-foundation-module",
     llvm::cl::desc("Allow @objc to be used freely"),
@@ -593,6 +603,7 @@
                << " at offset " << CodeCompletionOffset << "\n";
 
   CompilerInvocation Invocation(InitInvok);
+
   Invocation.setCodeCompletionPoint(CleanFile.get(), CodeCompletionOffset);
 
 
@@ -2967,6 +2978,8 @@
   }
   InitInvok.getClangImporterOptions().ModuleCachePath =
     options::ModuleCachePath;
+  InitInvok.getClangImporterOptions().PrecompiledHeaderOutputDir =
+    options::PCHOutputDir;
   InitInvok.setImportSearchPaths(options::ImportPaths);
   std::vector<SearchPathOptions::FrameworkSearchPath> FramePaths;
   for (const auto &path : options::FrameworkPaths) {
@@ -2980,12 +2993,17 @@
     options::EnableSourceImport;
   InitInvok.getFrontendOptions().ImplicitObjCHeaderPath =
     options::ImportObjCHeader;
+  InitInvok.getClangImporterOptions().BridgingHeader =
+    options::ImportObjCHeader;
   InitInvok.getLangOptions().EnableAccessControl =
     !options::DisableAccessControl;
   InitInvok.getLangOptions().CodeCompleteInitsInPostfixExpr |=
       options::CodeCompleteInitsInPostfixExpr;
   InitInvok.getLangOptions().InferImportAsMember |=
     options::InferImportAsMember;
+  InitInvok.getLangOptions().EnableSwift3ObjCInference =
+    options::EnableSwift3ObjCInference ||
+    InitInvok.getLangOptions().isSwiftVersion3();
   InitInvok.getClangImporterOptions().ImportForwardDeclarations |=
     options::ObjCForwardDeclarations;
   InitInvok.getClangImporterOptions().InferImportAsMember |=
diff --git a/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp b/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp
index 163969d..2d1e0a7 100644
--- a/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp
+++ b/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp
@@ -17,6 +17,7 @@
 #include "SourceKit/SwiftLang/Factory.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/TargetSelect.h"
 #include "gtest/gtest.h"
 
 using namespace SourceKit;
@@ -102,6 +103,10 @@
   LangSupport &getLang() { return Ctx.getSwiftLangSupport(); }
 
   void SetUp() {
+    llvm::InitializeAllTargets();
+    llvm::InitializeAllTargetMCs();
+    llvm::InitializeAllAsmPrinters();
+    llvm::InitializeAllAsmParsers();
     NumTasks = 0;
   }
 
diff --git a/utils/build-presets.ini b/utils/build-presets.ini
index 075c485..312fe8e 100644
--- a/utils/build-presets.ini
+++ b/utils/build-presets.ini
@@ -737,6 +737,9 @@
 
 dash-dash
 
+# rdar://problem/31454823
+skip-test-lldb
+
 install-foundation
 install-libdispatch
 reconfigure
diff --git a/utils/build-script b/utils/build-script
index 6bcc247..21039fc 100755
--- a/utils/build-script
+++ b/utils/build-script
@@ -19,42 +19,37 @@
 import sys
 import time
 
-import android.adb.commands # noqa (E402 module level import not at top of file)
+import android.adb.commands
 
-# FIXME: Instead of modifying the system path in order to enable imports from
-#        other directories, all Python modules related to the build script
-#        should be moved to the `swift_build_support` module. Remove "noqa"
-#        markers when this is fixed.
-#        For additional information, see: https://bugs.swift.org/browse/SR-237.
-sys.path.append(os.path.dirname(__file__))
-from SwiftBuildSupport import (
+from swift_build_support.swift_build_support import (
+    arguments,
+    debug,
+    diagnostics,
+    host,
+    migration,
+    products,
+    shell,
+    tar,
+    targets,
+    workspace
+)
+
+from swift_build_support.swift_build_support.SwiftBuildSupport import (
     HOME,
     SWIFT_BUILD_ROOT,
+    SWIFT_REPO_NAME,
     SWIFT_SOURCE_ROOT,
     get_all_preset_names,
-    get_preset_options,
-)  # noqa (E402 module level import not at top of file)
+    get_preset_options,  
+)
 
-sys.path.append(os.path.join(os.path.dirname(__file__), 'swift_build_support'))
-
-# E402 means module level import not at top of file
-from swift_build_support import arguments  # noqa (E402)
-from swift_build_support import diagnostics  # noqa (E402)
-from swift_build_support import host  # noqa (E402)
-from swift_build_support.toolchain import host_toolchain  # noqa (E402)
-import swift_build_support.debug      # noqa (E402)
-from swift_build_support import migration  # noqa (E402)
-from swift_build_support import products  # noqa (E402)
-from swift_build_support import shell  # noqa (E402)
-import swift_build_support.tar        # noqa (E402)
-import swift_build_support.targets    # noqa (E402)
-from swift_build_support.targets import StdlibDeploymentTarget  # noqa (E402)
-from swift_build_support.cmake import CMake  # noqa (E402)
-import swift_build_support.workspace    # noqa (E402)
-
+from swift_build_support.swift_build_support.cmake import CMake
+from swift_build_support.swift_build_support.targets import \
+    StdlibDeploymentTarget
+from swift_build_support.swift_build_support.toolchain import host_toolchain
 
 build_script_impl = os.path.join(
-    SWIFT_SOURCE_ROOT, "swift", "utils", "build-script-impl")
+    SWIFT_SOURCE_ROOT, SWIFT_REPO_NAME, "utils", "build-script-impl")
 
 
 def exit_rejecting_arguments(message, parser=None):
@@ -443,7 +438,7 @@
 
         if args.build_subdir is None:
             args.build_subdir = \
-                swift_build_support.workspace.compute_build_subdir(args)
+                workspace.compute_build_subdir(args)
 
         # Add optional stdlib-deployment-targets
         if args.android:
@@ -466,7 +461,7 @@
         self.toolchain = toolchain
         self.args = args
 
-        self.workspace = swift_build_support.workspace.Workspace(
+        self.workspace = workspace.Workspace(
             source_root=SWIFT_SOURCE_ROOT,
             build_root=os.path.join(SWIFT_BUILD_ROOT, args.build_subdir))
 
@@ -818,7 +813,7 @@
         if platform.system() == 'Darwin':
             impl_args += [
                 "--toolchain-prefix",
-                swift_build_support.targets.darwin_toolchain_prefix(
+                targets.darwin_toolchain_prefix(
                     args.install_prefix),
                 "--host-lipo", toolchain.lipo,
             ]
@@ -1096,7 +1091,8 @@
         args.preset_file_names = [
             os.path.join(HOME, ".swift-build-presets"),
             os.path.join(
-                SWIFT_SOURCE_ROOT, "swift", "utils", "build-presets.ini")
+                SWIFT_SOURCE_ROOT, SWIFT_REPO_NAME, "utils",
+                "build-presets.ini")
         ]
 
     if args.show_presets:
@@ -1894,7 +1890,7 @@
         help="The installation prefix. This is where built Swift products "
              "(like bin, lib, and include) will be installed.",
         metavar="PATH",
-        default=swift_build_support.targets.install_prefix())
+        default=targets.install_prefix())
     parser.add_argument(
         "--install-symroot",
         help="the path to install debug symbols into",
@@ -2200,7 +2196,7 @@
 
     # Show SDKs, if requested.
     if args.show_sdks:
-        swift_build_support.debug.print_xcodebuild_versions()
+        debug.print_xcodebuild_versions()
 
     # Clean build directory if requested.
     if args.clean:
@@ -2222,8 +2218,7 @@
         print('-- Package file: {} --'.format(args.symbols_package))
 
         if platform.system() == 'Darwin':
-            prefix = swift_build_support.targets.darwin_toolchain_prefix(
-                args.install_prefix)
+            prefix = targets.darwin_toolchain_prefix(args.install_prefix)
         else:
             prefix = args.install_prefix
 
@@ -2232,8 +2227,8 @@
         # run `tar` without the leading '/' (we remove it ourselves to keep
         # `tar` from emitting a warning).
         with shell.pushd(args.install_symroot):
-            swift_build_support.tar.tar(source=prefix.lstrip('/'),
-                                        destination=args.symbols_package)
+            tar.tar(source=prefix.lstrip('/'),
+                    destination=args.symbols_package)
 
     return 0
 
diff --git a/utils/coverage/coverage-generate-data b/utils/coverage/coverage-generate-data
index 3154daa..8f4fc1c 100755
--- a/utils/coverage/coverage-generate-data
+++ b/utils/coverage/coverage-generate-data
@@ -225,15 +225,15 @@
 
     logging.info('Starting merge on %s', build_dir)
     folders = find_folders(build_dir, '.profdir')
-    pool.map_async(merge_profdir, folders).get(9999999)
+    pool.map_async(merge_profdir, folders).get(999999)
 
     logging.info('Starting coverage data dump...')
     merged_profraw_files = find_files(build_dir, 'merged.profraw')
-    pool.map_async(dump_coverage_data, merged_profraw_files).get(9999999)
+    pool.map_async(dump_coverage_data, merged_profraw_files).get(999999)
 
     logging.info('Starting coverage data dump demangling...')
     coverage_log_files = find_files(build_dir, 'coverage.log')
-    pool.map_async(demangle_coverage_data, coverage_log_files).get(9999999)
+    pool.map_async(demangle_coverage_data, coverage_log_files).get(999999)
     return 0
 
 
diff --git a/utils/coverage/coverage-touch-tests b/utils/coverage/coverage-touch-tests
index 6f034f4..ef43dbf 100755
--- a/utils/coverage/coverage-touch-tests
+++ b/utils/coverage/coverage-touch-tests
@@ -126,7 +126,7 @@
     covering_tests = set().union(*pool.map_async(
         worker,
         enumerate(relevant_changes)
-    ).get(9999999))
+    ).get(999999))
 
     logging.info('Combined covering tests:')
     for covering_test in covering_tests:
diff --git a/utils/python_lint.py b/utils/python_lint.py
old mode 100644
new mode 100755
diff --git a/utils/recursive-lipo b/utils/recursive-lipo
index 44f962f..056b5f3 100755
--- a/utils/recursive-lipo
+++ b/utils/recursive-lipo
@@ -7,11 +7,8 @@
 import os
 import os.path
 import shutil
-import sys
 
-sys.path.append(os.path.join(os.path.dirname(__file__), 'swift_build_support'))
-
-from swift_build_support import shell  # noqa (E402)
+from swift_build_support.swift_build_support import shell
 
 
 def merge_file_lists(src_root_dirs, skip_files, skip_subpaths):
diff --git a/utils/run-test b/utils/run-test
index bd4b3b8..0083448 100755
--- a/utils/run-test
+++ b/utils/run-test
@@ -17,13 +17,16 @@
 import shutil
 import sys
 
-sys.path.append(os.path.dirname(__file__))
-sys.path.append(os.path.join(os.path.dirname(__file__), 'swift_build_support'))
+from swift_build_support.swift_build_support import (
+    arguments,
+    shell
+)
 
-from SwiftBuildSupport import SWIFT_SOURCE_ROOT  # noqa (E402)
-from swift_build_support import arguments  # noqa (E402)
-from swift_build_support import shell  # noqa (E402)
-from swift_build_support.targets import StdlibDeploymentTarget  # noqa (E402)
+from swift_build_support.swift_build_support.SwiftBuildSupport import \
+    SWIFT_SOURCE_ROOT
+
+from swift_build_support.swift_build_support.targets import \
+    StdlibDeploymentTarget
 
 
 TEST_MODES = [
diff --git a/utils/swift_build_support/__init__.py b/utils/swift_build_support/__init__.py
new file mode 100644
index 0000000..ae8c0a2
--- /dev/null
+++ b/utils/swift_build_support/__init__.py
@@ -0,0 +1,16 @@
+# swift_build_support/__init__.py - Helpers for building Swift -*- python -*-
+#
+# This source file is part of the Swift.org open source project
+#
+# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+# Licensed under Apache License v2.0 with Runtime Library Exception
+#
+# See https://swift.org/LICENSE.txt for license information
+# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+#
+# ----------------------------------------------------------------------------
+#
+# This file needs to be here in order for Python to treat the
+# utils/swift_build_support/ directory as a module.
+#
+# ----------------------------------------------------------------------------
diff --git a/utils/SwiftBuildSupport.py b/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py
similarity index 82%
rename from utils/SwiftBuildSupport.py
rename to utils/swift_build_support/swift_build_support/SwiftBuildSupport.py
index 302cfdf..3c94271 100644
--- a/utils/SwiftBuildSupport.py
+++ b/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py
@@ -18,12 +18,8 @@
     import configparser as ConfigParser
 
 import os
-import sys
 
-sys.path.append(os.path.join(os.path.dirname(__file__), 'swift_build_support'))
-
-# E402 means module level import not at top of file
-from swift_build_support import diagnostics  # noqa (E402)
+import diagnostics
 
 
 HOME = os.environ.get("HOME", "/")
@@ -35,8 +31,9 @@
     # Are we in a Swift checkout? Start from this file and check its parent
     # directories.
     #
-    # $SWIFT_SOURCE_ROOT/swift/utils/SwiftBuildSupport.py
-    (swift_path, parent_dirname) = os.path.split(os.path.dirname(__file__))
+    # $SWIFT_SOURCE_ROOT/swift/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py
+    utils_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+    (swift_path, parent_dirname) = os.path.split(utils_path)
     if parent_dirname != "utils":
         return result
     if not os.path.exists(os.path.join(swift_path, 'CMakeLists.txt')):
@@ -46,7 +43,7 @@
     # Are we in an LLVM checkout? Start from the Swift checkout and check /its/
     # parent directories.
     #
-    # $SWIFT_SOURCE_ROOT/llvm/tools/swift/utils/SwiftBuildSupport.py
+    # $SWIFT_SOURCE_ROOT/llvm/tools/swift/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py
     (llvm_path, parent_dirname) = os.path.split(result)
     if parent_dirname != "tools":
         return result
@@ -68,6 +65,29 @@
     "SWIFT_BUILD_ROOT", os.path.join(SWIFT_SOURCE_ROOT, "build"))
 
 
+def _get_default_swift_repo_name():
+    result = ""
+
+    # Are we in a Swift checkout? Start from this file and check its parent
+    # directories.
+    #
+    # $SWIFT_SOURCE_ROOT/$SWIFT_REPO_NAME/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py
+    utils_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+    (swift_path, parent_dirname) = os.path.split(utils_path)
+    if parent_dirname != "utils":
+        return result
+    if not os.path.exists(os.path.join(swift_path, 'CMakeLists.txt')):
+        return result
+    (_, swift_repo_name) = os.path.split(swift_path)
+    return swift_repo_name
+
+
+# Set SWIFT_REPO_NAME in your environment to control the name of the swift
+# directory name that is used.
+SWIFT_REPO_NAME = os.environ.get(
+    "SWIFT_REPO_NAME", _get_default_swift_repo_name())
+
+
 def _load_preset_files_impl(preset_file_names, substitutions={}):
     config = ConfigParser.SafeConfigParser(substitutions, allow_no_value=True)
     if config.read(preset_file_names) == []:
@@ -154,7 +174,8 @@
         sdks_to_configure = swift_sdks_opt.split("=")[1].split(";")
         tgts = []
         # Expand SDKs in to their deployment targets
-        from swift_build_support.targets import StdlibDeploymentTarget
+        from swift_build_support.swift_build_support.targets \
+            import StdlibDeploymentTarget
         for sdk in sdks_to_configure:
             if sdk == "OSX":
                 tgts += StdlibDeploymentTarget.OSX.targets
diff --git a/utils/swift_build_support/swift_build_support/cmake.py b/utils/swift_build_support/swift_build_support/cmake.py
index 4559e2b..43d6f14 100644
--- a/utils/swift_build_support/swift_build_support/cmake.py
+++ b/utils/swift_build_support/swift_build_support/cmake.py
@@ -111,11 +111,14 @@
             define("CMAKE_CONFIGURATION_TYPES",
                    "Debug;Release;MinSizeRel;RelWithDebInfo")
 
-        if args.clang_compiler_version:
-            major, minor, patch, _ = args.clang_compiler_version.components
+        if args.clang_user_visible_version:
+            major, minor, patch, _ = args.clang_user_visible_version.components
             define("LLVM_VERSION_MAJOR:STRING", major)
             define("LLVM_VERSION_MINOR:STRING", minor)
             define("LLVM_VERSION_PATCH:STRING", patch)
+            define("CLANG_VERSION_MAJOR:STRING", major)
+            define("CLANG_VERSION_MINOR:STRING", minor)
+            define("CLANG_VERSION_PATCH:STRING", patch)
 
         if args.build_ninja and args.cmake_generator == 'Ninja':
             define('CMAKE_MAKE_PROGRAM', toolchain.ninja)
diff --git a/utils/swift_build_support/swift_build_support/shell.py b/utils/swift_build_support/swift_build_support/shell.py
index 57d4b9e..a6046a7 100644
--- a/utils/swift_build_support/swift_build_support/shell.py
+++ b/utils/swift_build_support/swift_build_support/shell.py
@@ -229,7 +229,7 @@
     print("Running ``%s`` with up to %d processes." %
           (fn.__name__, n_processes))
     pool = Pool(processes=n_processes, initializer=init, initargs=(l,))
-    results = pool.map_async(func=fn, iterable=pool_args).get(9999999)
+    results = pool.map_async(func=fn, iterable=pool_args).get(999999)
     pool.close()
     pool.join()
     return results
diff --git a/utils/swift_build_support/tests/test_cmake.py b/utils/swift_build_support/tests/test_cmake.py
index 0f2c309..65b5d20 100644
--- a/utils/swift_build_support/tests/test_cmake.py
+++ b/utils/swift_build_support/tests/test_cmake.py
@@ -37,6 +37,7 @@
                          distcc=False,
                          cmake_generator="Ninja",
                          clang_compiler_version=None,
+                         clang_user_visible_version=None,
                          build_jobs=8,
                          build_args=[],
                          verbose_build=False,
@@ -187,17 +188,33 @@
     def test_common_options_clang_compiler_version(self):
         args = self.default_args()
         args.clang_compiler_version = CompilerVersion(
-            string_representation="3.8.0",
-            components=("3", "8", "0", None))
+            string_representation="999.0.999",
+            components=("999", "0", "999", None))
         cmake = self.cmake(args)
         self.assertEqual(
             list(cmake.common_options()),
             ["-G", "Ninja",
              "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
              "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
-             "-DLLVM_VERSION_MAJOR:STRING=3",
-             "-DLLVM_VERSION_MINOR:STRING=8",
+             "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
+
+    def test_common_options_clang_user_visible_version(self):
+        args = self.default_args()
+        args.clang_user_visible_version = CompilerVersion(
+            string_representation="9.0.0",
+            components=("9", "0", "0", None))
+        cmake = self.cmake(args)
+        self.assertEqual(
+            list(cmake.common_options()),
+            ["-G", "Ninja",
+             "-DCMAKE_C_COMPILER:PATH=/path/to/clang",
+             "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
+             "-DLLVM_VERSION_MAJOR:STRING=9",
+             "-DLLVM_VERSION_MINOR:STRING=0",
              "-DLLVM_VERSION_PATCH:STRING=0",
+             "-DCLANG_VERSION_MAJOR:STRING=9",
+             "-DCLANG_VERSION_MINOR:STRING=0",
+             "-DCLANG_VERSION_PATCH:STRING=0",
              "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
 
     def test_common_options_build_ninja(self):
@@ -218,9 +235,12 @@
         args.export_compile_commands = True
         args.distcc = True
         args.cmake_generator = 'Xcode'
+        args.clang_user_visible_version = CompilerVersion(
+            string_representation="9.0.0",
+            components=("9", "0", "0", None))
         args.clang_compiler_version = CompilerVersion(
-            string_representation="3.8.0",
-            components=("3", "8", "0", None))
+            string_representation="999.0.900",
+            components=("999", "0", "900", None))
         args.build_ninja = True
         cmake = self.cmake(args)
         self.assertEqual(
@@ -234,9 +254,12 @@
              "-DCMAKE_CXX_COMPILER_ARG1=/path/to/clang++",
              "-DCMAKE_CONFIGURATION_TYPES=" +
              "Debug;Release;MinSizeRel;RelWithDebInfo",
-             "-DLLVM_VERSION_MAJOR:STRING=3",
-             "-DLLVM_VERSION_MINOR:STRING=8",
-             "-DLLVM_VERSION_PATCH:STRING=0"])
+             "-DLLVM_VERSION_MAJOR:STRING=9",
+             "-DLLVM_VERSION_MINOR:STRING=0",
+             "-DLLVM_VERSION_PATCH:STRING=0",
+             "-DCLANG_VERSION_MAJOR:STRING=9",
+             "-DCLANG_VERSION_MINOR:STRING=0",
+             "-DCLANG_VERSION_PATCH:STRING=0"])
         # NOTE: No "-DCMAKE_MAKE_PROGRAM=/path/to/built/ninja" because
         #       cmake_generator is 'Xcode'
 
diff --git a/utils/update-checkout b/utils/update-checkout
index dc435ca..2dac27c 100755
--- a/utils/update-checkout
+++ b/utils/update-checkout
@@ -1,493 +1,15 @@
 #!/usr/bin/env python
-# utils/update-checkout - Utility to update your local checkouts -*- python -*-
-#
-# This source file is part of the Swift.org open source project
-#
-# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
-# Licensed under Apache License v2.0 with Runtime Library Exception
-#
-# See https://swift.org/LICENSE.txt for license information
-# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 
-from __future__ import print_function
-
-import argparse
-import json
-import os
-import re
 import sys
-import traceback
 
-from functools import reduce
-from multiprocessing import freeze_support
+import update_checkout
 
-sys.path.append(os.path.dirname(__file__))
-
-from SwiftBuildSupport import (
-    SWIFT_SOURCE_ROOT,
-)  # noqa (E402 module level import not at top of file)
-
-SCRIPT_FILE = os.path.abspath(__file__)
-SCRIPT_DIR = os.path.dirname(SCRIPT_FILE)
-
-sys.path.append(os.path.join(SCRIPT_DIR, 'swift_build_support'))
-
-from swift_build_support import shell  # noqa (E402)
-
-
-def confirm_tag_in_repo(tag, repo_name):
-    tag_exists = shell.capture(['git', 'ls-remote', '--tags',
-                                'origin', tag], echo=False)
-    if not tag_exists:
-        print("Tag '" + tag + "' does not exist for '" +
-              repo_name + "', just updating regularly")
-        tag = None
-    return tag
-
-
-def find_rev_by_timestamp(timestamp, repo_name, refspec):
-    base_args = ["git", "log", "-1", "--format=%H",
-                 '--before=' + timestamp]
-    # Prefer the most-recent change _made by swift-ci_ before the timestamp,
-    # falling back to most-recent in general if there is none by swift-ci.
-    rev = shell.capture(base_args + ['--author', 'swift-ci', refspec]).strip()
-    if rev:
-        return rev
-    rev = shell.capture(base_args + [refspec]).strip()
-    if rev:
-        return rev
-    else:
-        raise RuntimeError('No rev in %s before timestamp %s' %
-                           (repo_name, timestamp))
-
-
-def get_branch_for_repo(config, repo_name, scheme_name, scheme_map,
-                        cross_repos_pr):
-    cross_repo = False
-    repo_branch = scheme_name
-    if scheme_map:
-        scheme_branch = scheme_map[repo_name]
-        repo_branch = scheme_branch
-        remote_repo_id = config['repos'][repo_name]['remote']['id']
-        if remote_repo_id in cross_repos_pr:
-            cross_repo = True
-            pr_id = cross_repos_pr[remote_repo_id]
-            repo_branch = "ci_pr_{0}".format(pr_id)
-            shell.run(["git", "checkout", scheme_branch],
-                      echo=True)
-            shell.capture(["git", "branch", "-D", repo_branch],
-                          echo=True, allow_non_zero_exit=True)
-            shell.run(["git", "fetch", "origin",
-                       "pull/{0}/merge:{1}"
-                       .format(pr_id, repo_branch)], echo=True)
-    return repo_branch, cross_repo
-
-
-def update_single_repository(args):
-    config, repo_name, scheme_name, scheme_map, tag, timestamp, \
-        reset_to_remote, should_clean, cross_repos_pr = args
-    repo_path = os.path.join(SWIFT_SOURCE_ROOT, repo_name)
-    if not os.path.isdir(repo_path):
-        return
-
-    try:
-        print("Updating '" + repo_path + "'")
-        with shell.pushd(repo_path, dry_run=False, echo=False):
-            cross_repo = False
-            checkout_target = None
-            if tag:
-                checkout_target = confirm_tag_in_repo(tag, repo_name)
-            elif scheme_name:
-                checkout_target, cross_repo = get_branch_for_repo(
-                    config, repo_name, scheme_name, scheme_map, cross_repos_pr)
-                if timestamp:
-                    checkout_target = find_rev_by_timestamp(timestamp,
-                                                            repo_name,
-                                                            checkout_target)
-            elif timestamp:
-                checkout_target = find_rev_by_timestamp(timestamp, repo_name,
-                                                        "HEAD")
-
-            # The clean option restores a repository to pristine condition.
-            if should_clean:
-                shell.run(['git', 'clean', '-fdx'], echo=True)
-                shell.run(['git', 'submodule', 'foreach', '--recursive', 'git',
-                           'clean', '-fdx'], echo=True)
-                shell.run(['git', 'submodule', 'foreach', '--recursive', 'git',
-                           'reset', '--hard', 'HEAD'], echo=True)
-                shell.run(['git', 'reset', '--hard', 'HEAD'], echo=True)
-                # It is possible to reset --hard and still be mid-rebase.
-                try:
-                    shell.run(['git', 'rebase', '--abort'], echo=True)
-                except Exception:
-                    pass
-
-            if checkout_target:
-                shell.run(['git', 'status', '--porcelain', '-uno'],
-                          echo=False)
-                shell.run(['git', 'checkout', checkout_target], echo=True)
-
-            # It's important that we checkout, fetch, and rebase, in order.
-            # .git/FETCH_HEAD updates the not-for-merge attributes based on
-            # which branch was checked out during the fetch.
-            shell.run(["git", "fetch", "--recurse-submodules=yes"], echo=True)
-
-            # If we were asked to reset to the specified branch, do the hard
-            # reset and return.
-            if checkout_target and reset_to_remote and not cross_repo:
-                shell.run(['git', 'reset', '--hard',
-                           "origin/%s" % checkout_target], echo=True)
-                return
-
-            # Query whether we have a "detached HEAD", which will mean that
-            # we previously checked out a tag rather than a branch.
-            detached_head = False
-            try:
-                # This git command returns error code 1 if HEAD is detached.
-                # Otherwise there was some other error, and we need to handle
-                # it like other command errors.
-                shell.run(["git", "symbolic-ref", "-q", "HEAD"], echo=False)
-            except Exception as e:
-                if e.ret == 1:
-                    detached_head = True
-                else:
-                    raise  # Pass this error up the chain.
-
-            # If we have a detached HEAD in this repository, we don't want
-            # to rebase. With a detached HEAD, the fetch will have marked
-            # all the branches in FETCH_HEAD as not-for-merge, and the
-            # "git rebase FETCH_HEAD" will try to rebase the tree from the
-            # default branch's current head, making a mess.
-
-            # Prior to Git 2.6, this is the way to do a "git pull
-            # --rebase" that respects rebase.autostash.  See
-            # http://stackoverflow.com/a/30209750/125349
-            if not cross_repo and not detached_head:
-                shell.run(["git", "rebase", "FETCH_HEAD"], echo=True)
-            elif detached_head:
-                print(repo_path,
-                      "\nDetached HEAD; probably checked out a tag. No need "
-                      "to rebase.\n")
-
-            shell.run(["git", "submodule", "update", "--recursive"], echo=True)
-    except Exception:
-        (type, value, tb) = sys.exc_info()
-        print('Error on repo "%s": %s' % (repo_path, traceback.format_exc()))
-        return value
-
-
-def get_timestamp_to_match(args):
-    if not args.match_timestamp:
-        return None
-    with shell.pushd(os.path.join(SWIFT_SOURCE_ROOT, "swift"),
-                     dry_run=False, echo=False):
-        return shell.capture(["git", "log", "-1", "--format=%cI"],
-                             echo=False).strip()
-
-
-def update_all_repositories(args, config, scheme_name, cross_repos_pr):
-    scheme_map = None
-    if scheme_name:
-        # This loop is only correct, since we know that each alias set has
-        # unique contents. This is checked by validate_config. Thus the first
-        # branch scheme data that has scheme_name as one of its aliases is
-        # the only possible correct answer.
-        for v in config['branch-schemes'].values():
-            if scheme_name in v['aliases']:
-                scheme_map = v['repos']
-                break
-    pool_args = []
-    timestamp = get_timestamp_to_match(args)
-    for repo_name in config['repos'].keys():
-        if repo_name in args.skip_repository_list:
-            print("Skipping update of '" + repo_name + "', requested by user")
-            continue
-        my_args = [config,
-                   repo_name,
-                   scheme_name,
-                   scheme_map,
-                   args.tag,
-                   timestamp,
-                   args.reset_to_remote,
-                   args.clean,
-                   cross_repos_pr]
-        pool_args.append(my_args)
-
-    return shell.run_parallel(update_single_repository, pool_args,
-                              args.n_processes)
-
-
-def obtain_additional_swift_sources(pool_args):
-    (args, repo_name, repo_info, repo_branch, remote, with_ssh, scheme_name,
-     skip_history, skip_repository_list) = pool_args
-
-    with shell.pushd(SWIFT_SOURCE_ROOT, dry_run=False, echo=False):
-
-        print("Cloning '" + repo_name + "'")
-
-        if skip_history:
-            shell.run(['git', 'clone', '--recursive', '--depth', '1',
-                       remote, repo_name], echo=True)
-        else:
-            shell.run(['git', 'clone', '--recursive', remote,
-                       repo_name], echo=True)
-        if scheme_name:
-            src_path = os.path.join(SWIFT_SOURCE_ROOT, repo_name, ".git")
-            shell.run(['git', '--git-dir', src_path, '--work-tree',
-                       os.path.join(SWIFT_SOURCE_ROOT, repo_name),
-                       'checkout', repo_branch], echo=False)
-    with shell.pushd(os.path.join(SWIFT_SOURCE_ROOT, repo_name),
-                     dry_run=False, echo=False):
-        shell.run(["git", "submodule", "update", "--recursive"],
-                  echo=False)
-
-
-def obtain_all_additional_swift_sources(args, config, with_ssh, scheme_name,
-                                        skip_history, skip_repository_list):
-
-    pool_args = []
-    with shell.pushd(SWIFT_SOURCE_ROOT, dry_run=False, echo=False):
-        for repo_name, repo_info in config['repos'].items():
-            if repo_name in skip_repository_list:
-                print("Skipping clone of '" + repo_name + "', requested by "
-                      "user")
-                continue
-
-            if os.path.isdir(os.path.join(repo_name, ".git")):
-                print("Skipping clone of '" + repo_name + "', directory "
-                      "already exists")
-                continue
-
-            # If we have a url override, use that url instead of
-            # interpolating.
-            remote_repo_info = repo_info['remote']
-            if 'url' in remote_repo_info:
-                remote = remote_repo_info['url']
-            else:
-                remote_repo_id = remote_repo_info['id']
-                if with_ssh is True or 'https-clone-pattern' not in config:
-                    remote = config['ssh-clone-pattern'] % remote_repo_id
-                else:
-                    remote = config['https-clone-pattern'] % remote_repo_id
-
-            repo_branch = None
-            if scheme_name:
-                for v in config['branch-schemes'].values():
-                    if scheme_name not in v['aliases']:
-                        continue
-                    repo_branch = v['repos'][repo_name]
-                    break
-                else:
-                    repo_branch = scheme_name
-
-            pool_args.append([args, repo_name, repo_info, repo_branch, remote,
-                              with_ssh, scheme_name, skip_history,
-                              skip_repository_list])
-
-    if not pool_args:
-        print("Not cloning any repositories.")
-        return
-
-    return shell.run_parallel(obtain_additional_swift_sources, pool_args,
-                              args.n_processes)
-
-
-def dump_repo_hashes(config):
-    max_len = reduce(lambda acc, x: max(acc, len(x)),
-                     config['repos'].keys(), 0)
-    fmt = "{:<%r}{}" % (max_len + 5)
-    for repo_name, repo_info in sorted(config['repos'].items(),
-                                       key=lambda x: x[0]):
-        with shell.pushd(os.path.join(SWIFT_SOURCE_ROOT, repo_name),
-                         dry_run=False,
-                         echo=False):
-            h = shell.capture(["git", "log", "--oneline", "-n", "1"],
-                              echo=False).strip()
-            print(fmt.format(repo_name, h))
-
-
-def dump_hashes_config(args, config):
-    branch_scheme_name = args.dump_hashes_config
-    new_config = {}
-    config_copy_keys = ['ssh-clone-pattern', 'https-clone-pattern', 'repos']
-    for config_copy_key in config_copy_keys:
-        new_config[config_copy_key] = config[config_copy_key]
-    repos = {}
-    branch_scheme = {'aliases': [branch_scheme_name], 'repos': repos}
-    new_config['branch-schemes'] = {args.dump_hashes_config: branch_scheme}
-    for repo_name, repo_info in sorted(config['repos'].items(),
-                                       key=lambda x: x[0]):
-        with shell.pushd(os.path.join(SWIFT_SOURCE_ROOT, repo_name),
-                         dry_run=False,
-                         echo=False):
-            h = shell.capture(["git", "rev-parse", "HEAD"],
-                              echo=False).strip()
-            repos[repo_name] = str(h)
-    print(json.dumps(new_config, indent=4))
-
-
-def validate_config(config):
-    # Make sure that our branch-names are unique.
-    scheme_names = config['branch-schemes'].keys()
-    if len(scheme_names) != len(set(scheme_names)):
-        raise RuntimeError('Configuration file has duplicate schemes?!')
-
-    # Ensure the branch-scheme name is also an alias
-    # This guarantees sensible behavior of update_repository_to_scheme when
-    # the branch-scheme is passed as the scheme name
-    for scheme_name in config['branch-schemes'].keys():
-        if scheme_name not in config['branch-schemes'][scheme_name]['aliases']:
-            raise RuntimeError('branch-scheme name: "{0}" must be an alias '
-                               'too.'.format(scheme_name))
-
-    # Then make sure the alias names used by our branches are unique.
-    #
-    # We do this by constructing a list consisting of len(names),
-    # set(names). Then we reduce over that list summing the counts and taking
-    # the union of the sets. We have uniqueness if the length of the union
-    # equals the length of the sum of the counts.
-    data = [(len(v['aliases']), set(v['aliases']))
-            for v in config['branch-schemes'].values()]
-    result = reduce(lambda acc, x: (acc[0] + x[0], acc[1] | x[1]), data,
-                    (0, set([])))
-    if result[0] == len(result[1]):
-        return
-    raise RuntimeError('Configuration file has schemes with duplicate '
-                       'aliases?!')
-
-
-def main():
-    parser = argparse.ArgumentParser(
-        formatter_class=argparse.RawDescriptionHelpFormatter,
-        description="""
-repositories.
-
-By default, updates your checkouts of Swift, SourceKit, LLDB, and SwiftPM.""")
-    parser.add_argument(
-        "--clone",
-        help="Obtain Sources for Swift and Related Projects",
-        action="store_true")
-    parser.add_argument(
-        "--clone-with-ssh",
-        help="Obtain Sources for Swift and Related Projects via SSH",
-        action="store_true")
-    parser.add_argument(
-        "--skip-history",
-        help="Skip histories when obtaining sources",
-        action="store_true")
-    parser.add_argument(
-        "--skip-repository",
-        metavar="DIRECTORY",
-        default=[],
-        help="Skip the specified repository",
-        dest='skip_repository_list',
-        action="append")
-    parser.add_argument(
-        "--scheme",
-        help='Use branches from the specified branch-scheme. A "branch-scheme"'
-        ' is a list of (repo, branch) pairs.',
-        metavar='BRANCH-SCHEME',
-        dest='scheme')
-    parser.add_argument(
-        '--reset-to-remote',
-        help='Reset each branch to the remote state.',
-        action='store_true')
-    parser.add_argument(
-        '--clean',
-        help='Clean unrelated files from each repository.',
-        action='store_true')
-    parser.add_argument(
-        "--config",
-        default=os.path.join(SCRIPT_DIR, "update-checkout-config.json"),
-        help="Configuration file to use")
-    parser.add_argument(
-        "--github-comment",
-        help="""Check out related pull requests referenced in the given
-        free-form GitHub-style comment.""",
-        metavar='GITHUB-COMMENT',
-        dest='github_comment')
-    parser.add_argument(
-        '--dump-hashes',
-        action='store_true',
-        help='Dump the git hashes of all repositories being tracked')
-    parser.add_argument(
-        '--dump-hashes-config',
-        help='Dump the git hashes of all repositories packaged into '
-             'update-checkout-config.json',
-        metavar='BRANCH-SCHEME-NAME')
-    parser.add_argument(
-        "--tag",
-        help="""Check out each repository to the specified tag.""",
-        metavar='TAG-NAME')
-    parser.add_argument(
-        "--match-timestamp",
-        help='Check out adjacent repositories to match timestamp of '
-        ' current swift checkout.',
-        action='store_true')
-    parser.add_argument(
-        "-j", "--jobs",
-        type=int,
-        help="Number of threads to run at once",
-        default=0,
-        dest="n_processes")
-    args = parser.parse_args()
-
-    if args.reset_to_remote and not args.scheme:
-        print("update-checkout usage error: --reset-to-remote must specify "
-              "--scheme=foo")
-        exit(1)
-
-    clone = args.clone
-    clone_with_ssh = args.clone_with_ssh
-    skip_history = args.skip_history
-    scheme = args.scheme
-    github_comment = args.github_comment
-
-    with open(args.config) as f:
-        config = json.load(f)
-    validate_config(config)
-
-    if args.dump_hashes:
-        dump_repo_hashes(config)
-        return (None, None)
-
-    if args.dump_hashes_config:
-        dump_hashes_config(args, config)
-        return (None, None)
-
-    cross_repos_pr = {}
-    if github_comment:
-        regex_pr = r'(apple/[-a-zA-Z0-9_]+/pull/\d+|apple/[-a-zA-Z0-9_]+#\d+)'
-        repos_with_pr = re.findall(regex_pr, github_comment)
-        print("Found related pull requests:", str(repos_with_pr))
-        repos_with_pr = [pr.replace('/pull/', '#') for pr in repos_with_pr]
-        cross_repos_pr = dict(pr.split('#') for pr in repos_with_pr)
-
-    clone_results = None
-    if clone or clone_with_ssh:
-        # If branch is None, default to using the default branch alias
-        # specified by our configuration file.
-        if scheme is None:
-            scheme = config['default-branch-scheme']
-
-        skip_repo_list = args.skip_repository_list
-        clone_results = obtain_all_additional_swift_sources(args, config,
-                                                            clone_with_ssh,
-                                                            scheme,
-                                                            skip_history,
-                                                            skip_repo_list)
-
-    update_results = update_all_repositories(args, config, scheme,
-                                             cross_repos_pr)
-    return (clone_results, update_results)
-
-
-if __name__ == "__main__":
-    freeze_support()
-    clone_results, update_results = main()
-    fail_count = 0
-    fail_count += shell.check_parallel_results(clone_results, "CLONE")
-    fail_count += shell.check_parallel_results(update_results, "UPDATE")
-    if fail_count > 0:
-        print("update-checkout failed, fix errors and try again")
-    sys.exit(fail_count)
+# The internal Windows implementation tries to import the current module using
+# sys.modules[__name__]. This file (called 'update-checkout') is not a valid
+# Python module name, as it contains a '-' and doesn't end with '.py'. This
+# results in errors running update-checkout on Windows:'ImportError: No module
+# named update-checkout'.
+# As such, we need to manually set sys.modules[__name__] to a valid module
+# identifier to work around these errors.
+sys.modules[__name__] = sys.modules['update_checkout']
+update_checkout.main()
diff --git a/utils/update-checkout-config.json b/utils/update-checkout-config.json
index 6b0a100..55f95a3 100644
--- a/utils/update-checkout-config.json
+++ b/utils/update-checkout-config.json
@@ -118,15 +118,15 @@
                 "clang": "swift-4.0-branch",
                 "swift": "swift-4.0-branch",
                 "lldb": "swift-4.0-branch",
-                "cmark": "swift-3.1-branch",
-                "llbuild": "swift-3.1-branch",
-                "swiftpm": "swift-3.1-branch",
+                "cmark": "master",
+                "llbuild": "master",
+                "swiftpm": "master",
                 "compiler-rt": "swift-4.0-branch",
-                "swift-corelibs-xctest": "swift-3.1-branch",
-                "swift-corelibs-foundation": "swift-3.1-branch",
-                "swift-corelibs-libdispatch": "swift-3.1-branch",
-                "swift-integration-tests": "swift-3.1-branch",
-                "swift-xcode-playground-support": "swift-3.1-branch",
+                "swift-corelibs-xctest": "master",
+                "swift-corelibs-foundation": "master",
+                "swift-corelibs-libdispatch": "master",
+                "swift-integration-tests": "master",
+                "swift-xcode-playground-support": "master",
                 "ninja": "release"
             }
         }
diff --git a/utils/update_checkout.py b/utils/update_checkout.py
new file mode 100755
index 0000000..d8091c0
--- /dev/null
+++ b/utils/update_checkout.py
@@ -0,0 +1,486 @@
+# utils/update_checkout.py - Utility to update local checkouts --*- python -*-
+#
+# This source file is part of the Swift.org open source project
+#
+# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+# Licensed under Apache License v2.0 with Runtime Library Exception
+#
+# See https://swift.org/LICENSE.txt for license information
+# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+from __future__ import print_function
+
+import argparse
+import json
+import os
+import re
+import sys
+import traceback
+
+from functools import reduce
+from multiprocessing import freeze_support
+
+from swift_build_support.swift_build_support import shell
+from swift_build_support.swift_build_support.SwiftBuildSupport import \
+    SWIFT_SOURCE_ROOT
+
+
+SCRIPT_FILE = os.path.abspath(__file__)
+SCRIPT_DIR = os.path.dirname(SCRIPT_FILE)
+
+
+def confirm_tag_in_repo(tag, repo_name):
+    tag_exists = shell.capture(['git', 'ls-remote', '--tags',
+                                'origin', tag], echo=False)
+    if not tag_exists:
+        print("Tag '" + tag + "' does not exist for '" +
+              repo_name + "', just updating regularly")
+        tag = None
+    return tag
+
+
+def find_rev_by_timestamp(timestamp, repo_name, refspec):
+    base_args = ["git", "log", "-1", "--format=%H",
+                 '--before=' + timestamp]
+    # Prefer the most-recent change _made by swift-ci_ before the timestamp,
+    # falling back to most-recent in general if there is none by swift-ci.
+    rev = shell.capture(base_args + ['--author', 'swift-ci', refspec]).strip()
+    if rev:
+        return rev
+    rev = shell.capture(base_args + [refspec]).strip()
+    if rev:
+        return rev
+    else:
+        raise RuntimeError('No rev in %s before timestamp %s' %
+                           (repo_name, timestamp))
+
+
+def get_branch_for_repo(config, repo_name, scheme_name, scheme_map,
+                        cross_repos_pr):
+    cross_repo = False
+    repo_branch = scheme_name
+    if scheme_map:
+        scheme_branch = scheme_map[repo_name]
+        repo_branch = scheme_branch
+        remote_repo_id = config['repos'][repo_name]['remote']['id']
+        if remote_repo_id in cross_repos_pr:
+            cross_repo = True
+            pr_id = cross_repos_pr[remote_repo_id]
+            repo_branch = "ci_pr_{0}".format(pr_id)
+            shell.run(["git", "checkout", scheme_branch],
+                      echo=True)
+            shell.capture(["git", "branch", "-D", repo_branch],
+                          echo=True, allow_non_zero_exit=True)
+            shell.run(["git", "fetch", "origin",
+                       "pull/{0}/merge:{1}"
+                       .format(pr_id, repo_branch)], echo=True)
+    return repo_branch, cross_repo
+
+
+def update_single_repository(args):
+    config, repo_name, scheme_name, scheme_map, tag, timestamp, \
+        reset_to_remote, should_clean, cross_repos_pr = args
+    repo_path = os.path.join(SWIFT_SOURCE_ROOT, repo_name)
+    if not os.path.isdir(repo_path):
+        return
+
+    try:
+        print("Updating '" + repo_path + "'")
+        with shell.pushd(repo_path, dry_run=False, echo=False):
+            cross_repo = False
+            checkout_target = None
+            if tag:
+                checkout_target = confirm_tag_in_repo(tag, repo_name)
+            elif scheme_name:
+                checkout_target, cross_repo = get_branch_for_repo(
+                    config, repo_name, scheme_name, scheme_map, cross_repos_pr)
+                if timestamp:
+                    checkout_target = find_rev_by_timestamp(timestamp,
+                                                            repo_name,
+                                                            checkout_target)
+            elif timestamp:
+                checkout_target = find_rev_by_timestamp(timestamp, repo_name,
+                                                        "HEAD")
+
+            # The clean option restores a repository to pristine condition.
+            if should_clean:
+                shell.run(['git', 'clean', '-fdx'], echo=True)
+                shell.run(['git', 'submodule', 'foreach', '--recursive', 'git',
+                           'clean', '-fdx'], echo=True)
+                shell.run(['git', 'submodule', 'foreach', '--recursive', 'git',
+                           'reset', '--hard', 'HEAD'], echo=True)
+                shell.run(['git', 'reset', '--hard', 'HEAD'], echo=True)
+                # It is possible to reset --hard and still be mid-rebase.
+                try:
+                    shell.run(['git', 'rebase', '--abort'], echo=True)
+                except Exception:
+                    pass
+
+            if checkout_target:
+                shell.run(['git', 'status', '--porcelain', '-uno'],
+                          echo=False)
+                shell.run(['git', 'checkout', checkout_target], echo=True)
+
+            # It's important that we checkout, fetch, and rebase, in order.
+            # .git/FETCH_HEAD updates the not-for-merge attributes based on
+            # which branch was checked out during the fetch.
+            shell.run(["git", "fetch", "--recurse-submodules=yes"], echo=True)
+
+            # If we were asked to reset to the specified branch, do the hard
+            # reset and return.
+            if checkout_target and reset_to_remote and not cross_repo:
+                shell.run(['git', 'reset', '--hard',
+                           "origin/%s" % checkout_target], echo=True)
+                return
+
+            # Query whether we have a "detached HEAD", which will mean that
+            # we previously checked out a tag rather than a branch.
+            detached_head = False
+            try:
+                # This git command returns error code 1 if HEAD is detached.
+                # Otherwise there was some other error, and we need to handle
+                # it like other command errors.
+                shell.run(["git", "symbolic-ref", "-q", "HEAD"], echo=False)
+            except Exception as e:
+                if e.ret == 1:
+                    detached_head = True
+                else:
+                    raise  # Pass this error up the chain.
+
+            # If we have a detached HEAD in this repository, we don't want
+            # to rebase. With a detached HEAD, the fetch will have marked
+            # all the branches in FETCH_HEAD as not-for-merge, and the
+            # "git rebase FETCH_HEAD" will try to rebase the tree from the
+            # default branch's current head, making a mess.
+
+            # Prior to Git 2.6, this is the way to do a "git pull
+            # --rebase" that respects rebase.autostash.  See
+            # http://stackoverflow.com/a/30209750/125349
+            if not cross_repo and not detached_head:
+                shell.run(["git", "rebase", "FETCH_HEAD"], echo=True)
+            elif detached_head:
+                print(repo_path,
+                      "\nDetached HEAD; probably checked out a tag. No need "
+                      "to rebase.\n")
+
+            shell.run(["git", "submodule", "update", "--recursive"], echo=True)
+    except Exception:
+        (type, value, tb) = sys.exc_info()
+        print('Error on repo "%s": %s' % (repo_path, traceback.format_exc()))
+        return value
+
+
+def get_timestamp_to_match(args):
+    if not args.match_timestamp:
+        return None
+    with shell.pushd(os.path.join(SWIFT_SOURCE_ROOT, "swift"),
+                     dry_run=False, echo=False):
+        return shell.capture(["git", "log", "-1", "--format=%cI"],
+                             echo=False).strip()
+
+
+def update_all_repositories(args, config, scheme_name, cross_repos_pr):
+    scheme_map = None
+    if scheme_name:
+        # This loop is only correct, since we know that each alias set has
+        # unique contents. This is checked by validate_config. Thus the first
+        # branch scheme data that has scheme_name as one of its aliases is
+        # the only possible correct answer.
+        for v in config['branch-schemes'].values():
+            if scheme_name in v['aliases']:
+                scheme_map = v['repos']
+                break
+    pool_args = []
+    timestamp = get_timestamp_to_match(args)
+    for repo_name in config['repos'].keys():
+        if repo_name in args.skip_repository_list:
+            print("Skipping update of '" + repo_name + "', requested by user")
+            continue
+        my_args = [config,
+                   repo_name,
+                   scheme_name,
+                   scheme_map,
+                   args.tag,
+                   timestamp,
+                   args.reset_to_remote,
+                   args.clean,
+                   cross_repos_pr]
+        pool_args.append(my_args)
+
+    return shell.run_parallel(update_single_repository, pool_args,
+                              args.n_processes)
+
+
+def obtain_additional_swift_sources(pool_args):
+    (args, repo_name, repo_info, repo_branch, remote, with_ssh, scheme_name,
+     skip_history, skip_repository_list) = pool_args
+
+    with shell.pushd(SWIFT_SOURCE_ROOT, dry_run=False, echo=False):
+
+        print("Cloning '" + repo_name + "'")
+
+        if skip_history:
+            shell.run(['git', 'clone', '--recursive', '--depth', '1',
+                       remote, repo_name], echo=True)
+        else:
+            shell.run(['git', 'clone', '--recursive', remote,
+                       repo_name], echo=True)
+        if scheme_name:
+            src_path = os.path.join(SWIFT_SOURCE_ROOT, repo_name, ".git")
+            shell.run(['git', '--git-dir', src_path, '--work-tree',
+                       os.path.join(SWIFT_SOURCE_ROOT, repo_name),
+                       'checkout', repo_branch], echo=False)
+    with shell.pushd(os.path.join(SWIFT_SOURCE_ROOT, repo_name),
+                     dry_run=False, echo=False):
+        shell.run(["git", "submodule", "update", "--recursive"],
+                  echo=False)
+
+
+def obtain_all_additional_swift_sources(args, config, with_ssh, scheme_name,
+                                        skip_history, skip_repository_list):
+
+    pool_args = []
+    with shell.pushd(SWIFT_SOURCE_ROOT, dry_run=False, echo=False):
+        for repo_name, repo_info in config['repos'].items():
+            if repo_name in skip_repository_list:
+                print("Skipping clone of '" + repo_name + "', requested by "
+                      "user")
+                continue
+
+            if os.path.isdir(os.path.join(repo_name, ".git")):
+                print("Skipping clone of '" + repo_name + "', directory "
+                      "already exists")
+                continue
+
+            # If we have a url override, use that url instead of
+            # interpolating.
+            remote_repo_info = repo_info['remote']
+            if 'url' in remote_repo_info:
+                remote = remote_repo_info['url']
+            else:
+                remote_repo_id = remote_repo_info['id']
+                if with_ssh is True or 'https-clone-pattern' not in config:
+                    remote = config['ssh-clone-pattern'] % remote_repo_id
+                else:
+                    remote = config['https-clone-pattern'] % remote_repo_id
+
+            repo_branch = None
+            if scheme_name:
+                for v in config['branch-schemes'].values():
+                    if scheme_name not in v['aliases']:
+                        continue
+                    repo_branch = v['repos'][repo_name]
+                    break
+                else:
+                    repo_branch = scheme_name
+
+            pool_args.append([args, repo_name, repo_info, repo_branch, remote,
+                              with_ssh, scheme_name, skip_history,
+                              skip_repository_list])
+
+    if not pool_args:
+        print("Not cloning any repositories.")
+        return
+
+    return shell.run_parallel(obtain_additional_swift_sources, pool_args,
+                              args.n_processes)
+
+
+def dump_repo_hashes(config):
+    max_len = reduce(lambda acc, x: max(acc, len(x)),
+                     config['repos'].keys(), 0)
+    fmt = "{:<%r}{}" % (max_len + 5)
+    for repo_name, repo_info in sorted(config['repos'].items(),
+                                       key=lambda x: x[0]):
+        with shell.pushd(os.path.join(SWIFT_SOURCE_ROOT, repo_name),
+                         dry_run=False,
+                         echo=False):
+            h = shell.capture(["git", "log", "--oneline", "-n", "1"],
+                              echo=False).strip()
+            print(fmt.format(repo_name, h))
+
+
+def dump_hashes_config(args, config):
+    branch_scheme_name = args.dump_hashes_config
+    new_config = {}
+    config_copy_keys = ['ssh-clone-pattern', 'https-clone-pattern', 'repos']
+    for config_copy_key in config_copy_keys:
+        new_config[config_copy_key] = config[config_copy_key]
+    repos = {}
+    branch_scheme = {'aliases': [branch_scheme_name], 'repos': repos}
+    new_config['branch-schemes'] = {args.dump_hashes_config: branch_scheme}
+    for repo_name, repo_info in sorted(config['repos'].items(),
+                                       key=lambda x: x[0]):
+        with shell.pushd(os.path.join(SWIFT_SOURCE_ROOT, repo_name),
+                         dry_run=False,
+                         echo=False):
+            h = shell.capture(["git", "rev-parse", "HEAD"],
+                              echo=False).strip()
+            repos[repo_name] = str(h)
+    print(json.dumps(new_config, indent=4))
+
+
+def validate_config(config):
+    # Make sure that our branch-names are unique.
+    scheme_names = config['branch-schemes'].keys()
+    if len(scheme_names) != len(set(scheme_names)):
+        raise RuntimeError('Configuration file has duplicate schemes?!')
+
+    # Ensure the branch-scheme name is also an alias
+    # This guarantees sensible behavior of update_repository_to_scheme when
+    # the branch-scheme is passed as the scheme name
+    for scheme_name in config['branch-schemes'].keys():
+        if scheme_name not in config['branch-schemes'][scheme_name]['aliases']:
+            raise RuntimeError('branch-scheme name: "{0}" must be an alias '
+                               'too.'.format(scheme_name))
+
+    # Then make sure the alias names used by our branches are unique.
+    #
+    # We do this by constructing a list consisting of len(names),
+    # set(names). Then we reduce over that list summing the counts and taking
+    # the union of the sets. We have uniqueness if the length of the union
+    # equals the length of the sum of the counts.
+    data = [(len(v['aliases']), set(v['aliases']))
+            for v in config['branch-schemes'].values()]
+    result = reduce(lambda acc, x: (acc[0] + x[0], acc[1] | x[1]), data,
+                    (0, set([])))
+    if result[0] == len(result[1]):
+        return
+    raise RuntimeError('Configuration file has schemes with duplicate '
+                       'aliases?!')
+
+
+def main():
+    freeze_support()
+    parser = argparse.ArgumentParser(
+        formatter_class=argparse.RawDescriptionHelpFormatter,
+        description="""
+repositories.
+
+By default, updates your checkouts of Swift, SourceKit, LLDB, and SwiftPM.""")
+    parser.add_argument(
+        "--clone",
+        help="Obtain Sources for Swift and Related Projects",
+        action="store_true")
+    parser.add_argument(
+        "--clone-with-ssh",
+        help="Obtain Sources for Swift and Related Projects via SSH",
+        action="store_true")
+    parser.add_argument(
+        "--skip-history",
+        help="Skip histories when obtaining sources",
+        action="store_true")
+    parser.add_argument(
+        "--skip-repository",
+        metavar="DIRECTORY",
+        default=[],
+        help="Skip the specified repository",
+        dest='skip_repository_list',
+        action="append")
+    parser.add_argument(
+        "--scheme",
+        help='Use branches from the specified branch-scheme. A "branch-scheme"'
+        ' is a list of (repo, branch) pairs.',
+        metavar='BRANCH-SCHEME',
+        dest='scheme')
+    parser.add_argument(
+        '--reset-to-remote',
+        help='Reset each branch to the remote state.',
+        action='store_true')
+    parser.add_argument(
+        '--clean',
+        help='Clean unrelated files from each repository.',
+        action='store_true')
+    parser.add_argument(
+        "--config",
+        default=os.path.join(SCRIPT_DIR, "update-checkout-config.json"),
+        help="Configuration file to use")
+    parser.add_argument(
+        "--github-comment",
+        help="""Check out related pull requests referenced in the given
+        free-form GitHub-style comment.""",
+        metavar='GITHUB-COMMENT',
+        dest='github_comment')
+    parser.add_argument(
+        '--dump-hashes',
+        action='store_true',
+        help='Dump the git hashes of all repositories being tracked')
+    parser.add_argument(
+        '--dump-hashes-config',
+        help='Dump the git hashes of all repositories packaged into '
+             'update-checkout-config.json',
+        metavar='BRANCH-SCHEME-NAME')
+    parser.add_argument(
+        "--tag",
+        help="""Check out each repository to the specified tag.""",
+        metavar='TAG-NAME')
+    parser.add_argument(
+        "--match-timestamp",
+        help='Check out adjacent repositories to match timestamp of '
+        ' current swift checkout.',
+        action='store_true')
+    parser.add_argument(
+        "-j", "--jobs",
+        type=int,
+        help="Number of threads to run at once",
+        default=0,
+        dest="n_processes")
+    args = parser.parse_args()
+
+    if args.reset_to_remote and not args.scheme:
+        print("update-checkout usage error: --reset-to-remote must specify "
+              "--scheme=foo")
+        exit(1)
+
+    clone = args.clone
+    clone_with_ssh = args.clone_with_ssh
+    skip_history = args.skip_history
+    scheme = args.scheme
+    github_comment = args.github_comment
+
+    with open(args.config) as f:
+        config = json.load(f)
+    validate_config(config)
+
+    if args.dump_hashes:
+        dump_repo_hashes(config)
+        return (None, None)
+
+    if args.dump_hashes_config:
+        dump_hashes_config(args, config)
+        return (None, None)
+
+    cross_repos_pr = {}
+    if github_comment:
+        regex_pr = r'(apple/[-a-zA-Z0-9_]+/pull/\d+|apple/[-a-zA-Z0-9_]+#\d+)'
+        repos_with_pr = re.findall(regex_pr, github_comment)
+        print("Found related pull requests:", str(repos_with_pr))
+        repos_with_pr = [pr.replace('/pull/', '#') for pr in repos_with_pr]
+        cross_repos_pr = dict(pr.split('#') for pr in repos_with_pr)
+
+    clone_results = None
+    if clone or clone_with_ssh:
+        # If branch is None, default to using the default branch alias
+        # specified by our configuration file.
+        if scheme is None:
+            scheme = config['default-branch-scheme']
+
+        skip_repo_list = args.skip_repository_list
+        clone_results = obtain_all_additional_swift_sources(args, config,
+                                                            clone_with_ssh,
+                                                            scheme,
+                                                            skip_history,
+                                                            skip_repo_list)
+
+    update_results = update_all_repositories(args, config, scheme,
+                                             cross_repos_pr)
+    fail_count = 0
+    fail_count += shell.check_parallel_results(clone_results, "CLONE")
+    fail_count += shell.check_parallel_results(update_results, "UPDATE")
+    if fail_count > 0:
+        print("update-checkout failed, fix errors and try again")
+    sys.exit(fail_count)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/validation-test/SIL/crashers/005-swift-silfunction-verify.sil b/validation-test/SIL/crashers/005-swift-silfunction-verify.sil
deleted file mode 100644
index d3c647d..0000000
--- a/validation-test/SIL/crashers/005-swift-silfunction-verify.sil
+++ /dev/null
@@ -1,3 +0,0 @@
-// RUN: not --crash %target-sil-opt %s
-// REQUIRES: asserts
-sil shared_external@a:$()->()
diff --git a/validation-test/SIL/crashers_fixed/005-swift-silfunction-verify.sil b/validation-test/SIL/crashers_fixed/005-swift-silfunction-verify.sil
new file mode 100644
index 0000000..0dc7388
--- /dev/null
+++ b/validation-test/SIL/crashers_fixed/005-swift-silfunction-verify.sil
@@ -0,0 +1,2 @@
+// RUN: %target-sil-opt %s
+sil shared_external@a:$()->()
diff --git a/validation-test/Serialization/Foundation-determinism-wmo.swift b/validation-test/Serialization/Foundation-determinism-wmo.swift
index 5c321ba..ccb2db6 100644
--- a/validation-test/Serialization/Foundation-determinism-wmo.swift
+++ b/validation-test/Serialization/Foundation-determinism-wmo.swift
@@ -2,6 +2,7 @@
 // RUN: %target-build-swift -module-name Foundation -parse-as-library %S/../../stdlib/public/SDK/Foundation/*.swift %T/../../../stdlib/public/SDK/Foundation/8/*.swift -emit-module-path %t.2.swiftmodule -force-single-frontend-invocation
 // RUN: diff <(llvm-bcanalyzer -dump %t.1.swiftmodule | sed -e 's/\.[0-9]\.swiftmodule/\.x\.swiftmodule/g') <(llvm-bcanalyzer -dump %t.2.swiftmodule | sed -e 's/\.[0-9]\.swiftmodule/\.x\.swiftmodule/g')
 
+// REQUIRES: sr4342
 // REQUIRES: objc_interop
 // REQUIRES: PTRSIZE=64
 
diff --git a/validation-test/Serialization/Foundation-determinism.swift b/validation-test/Serialization/Foundation-determinism.swift
index 16d6335..2984084 100644
--- a/validation-test/Serialization/Foundation-determinism.swift
+++ b/validation-test/Serialization/Foundation-determinism.swift
@@ -2,6 +2,7 @@
 // RUN: %target-build-swift -module-name Foundation -parse-as-library %S/../../stdlib/public/SDK/Foundation/*.swift %T/../../../stdlib/public/SDK/Foundation/8/*.swift -emit-module-path %t.2.swiftmodule
 // RUN: diff <(llvm-bcanalyzer -dump %t.1.swiftmodule | sed -e 's/\.[0-9]\.swiftmodule/\.x\.swiftmodule/g') <(llvm-bcanalyzer -dump %t.2.swiftmodule | sed -e 's/\.[0-9]\.swiftmodule/\.x\.swiftmodule/g')
 
+// REQUIRES: sr4342
 // REQUIRES: objc_interop
 // REQUIRES: PTRSIZE=64
 
diff --git a/validation-test/compiler_crashers/28727-objectty-haserror-cannot-have-errortype-wrapped-inside-lvaluetype.swift b/validation-test/compiler_crashers/28727-objectty-haserror-cannot-have-errortype-wrapped-inside-lvaluetype.swift
new file mode 100644
index 0000000..0b01481
--- /dev/null
+++ b/validation-test/compiler_crashers/28727-objectty-haserror-cannot-have-errortype-wrapped-inside-lvaluetype.swift
@@ -0,0 +1,10 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol P}extension P{lazy var f={extension{var f=((self
diff --git a/validation-test/compiler_crashers/28728-d-isbeingvalidated-d-hasvalidsignature.swift b/validation-test/compiler_crashers/28728-d-isbeingvalidated-d-hasvalidsignature.swift
new file mode 100644
index 0000000..57e4115
--- /dev/null
+++ b/validation-test/compiler_crashers/28728-d-isbeingvalidated-d-hasvalidsignature.swift
@@ -0,0 +1,11 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+typealias e:a
+struct A:a{}typealias a=A
diff --git a/validation-test/compiler_crashers/28729-archetype-bad-generic-context-nesting.swift b/validation-test/compiler_crashers/28729-archetype-bad-generic-context-nesting.swift
new file mode 100644
index 0000000..361b334
--- /dev/null
+++ b/validation-test/compiler_crashers/28729-archetype-bad-generic-context-nesting.swift
@@ -0,0 +1,13 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol P{
+protocol
+P{typealias a{}struct B{extension{protocol P{
+func a:a
diff --git a/validation-test/compiler_crashers/28730-unreachable-executed-at-swift-lib-ast-astcontext-cpp-1229.swift b/validation-test/compiler_crashers/28730-unreachable-executed-at-swift-lib-ast-astcontext-cpp-1229.swift
new file mode 100644
index 0000000..45eb3d8
--- /dev/null
+++ b/validation-test/compiler_crashers/28730-unreachable-executed-at-swift-lib-ast-astcontext-cpp-1229.swift
@@ -0,0 +1,9 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+class a=protocol P{{}typealias e:P}}extension P{func a{}typealias e:a
diff --git a/validation-test/compiler_crashers/28732-type-hasarchetype-not-fully-substituted.swift b/validation-test/compiler_crashers/28732-type-hasarchetype-not-fully-substituted.swift
new file mode 100644
index 0000000..b094724
--- /dev/null
+++ b/validation-test/compiler_crashers/28732-type-hasarchetype-not-fully-substituted.swift
@@ -0,0 +1,15 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+{
+protocol A{
+struct A:P{
+}typealias a
+protocol
+P{typealias e:=a
diff --git a/validation-test/compiler_crashers/28733-parent-parent-is-nominaltype-parent-is-boundgenerictype-parent-is-unboundgeneric.swift b/validation-test/compiler_crashers/28733-parent-parent-is-nominaltype-parent-is-boundgenerictype-parent-is-unboundgeneric.swift
new file mode 100644
index 0000000..9482b4a
--- /dev/null
+++ b/validation-test/compiler_crashers/28733-parent-parent-is-nominaltype-parent-is-boundgenerictype-parent-is-unboundgeneric.swift
@@ -0,0 +1,10 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol P{class a:Self.a
diff --git a/validation-test/compiler_crashers/28734-conformingreplacementtype-is-substitutabletype-conformingreplacementtype-is-depe.swift b/validation-test/compiler_crashers/28734-conformingreplacementtype-is-substitutabletype-conformingreplacementtype-is-depe.swift
new file mode 100644
index 0000000..0d4aaf2
--- /dev/null
+++ b/validation-test/compiler_crashers/28734-conformingreplacementtype-is-substitutabletype-conformingreplacementtype-is-depe.swift
@@ -0,0 +1,14 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol P{typealias a
+struct A{{}func a:a
+{
+}
+struct A{extension{var f=a
diff --git a/validation-test/compiler_crashers/28735-reftype-hastypeparameter-cannot-have-a-dependent-type-here.swift b/validation-test/compiler_crashers/28735-reftype-hastypeparameter-cannot-have-a-dependent-type-here.swift
new file mode 100644
index 0000000..7c5167b
--- /dev/null
+++ b/validation-test/compiler_crashers/28735-reftype-hastypeparameter-cannot-have-a-dependent-type-here.swift
@@ -0,0 +1,10 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol A{protocol A:A{class a{let c=a}typealias a
diff --git a/validation-test/compiler_crashers_2_fixed/0059-sr3321.swift b/validation-test/compiler_crashers_2_fixed/0059-sr3321.swift
index a96e2a3..864f890 100644
--- a/validation-test/compiler_crashers_2_fixed/0059-sr3321.swift
+++ b/validation-test/compiler_crashers_2_fixed/0059-sr3321.swift
@@ -1,12 +1,6 @@
 // RUN: %target-swift-frontend %s -emit-ir
 // RUN: %target-swift-frontend %s -emit-ir -O
 
-// XFAIL: *
-
-// Note: this was passing for the wrong reasons before. We need to
-// correctly model cases where a nested type of an abstract conformance is
-// in fact concrete and, therefore, has concrete conformances.
-
 protocol ControllerB {
     associatedtype T: Controller
 }
diff --git a/validation-test/compiler_crashers_2_fixed/0069-sr3657.swift b/validation-test/compiler_crashers_2_fixed/0069-sr3657.swift
index b1183bd..ba0b0e6 100644
--- a/validation-test/compiler_crashers_2_fixed/0069-sr3657.swift
+++ b/validation-test/compiler_crashers_2_fixed/0069-sr3657.swift
@@ -8,4 +8,4 @@
   typealias T = Int
 }
 
-func superclassConformance1<T>(t: T.T) where T : P3, T : C {}
+func superclassConformance1<T>(_: T, t: T.T) where T : P3, T : C {}
diff --git a/validation-test/compiler_crashers_2/0076-sr3500.swift b/validation-test/compiler_crashers_2_fixed/0076-sr3500.swift
similarity index 81%
rename from validation-test/compiler_crashers_2/0076-sr3500.swift
rename to validation-test/compiler_crashers_2_fixed/0076-sr3500.swift
index 2a514fe..f931112 100644
--- a/validation-test/compiler_crashers_2/0076-sr3500.swift
+++ b/validation-test/compiler_crashers_2_fixed/0076-sr3500.swift
@@ -1,4 +1,4 @@
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: %target-swift-frontend %s -emit-ir
 
 protocol A {
   associatedtype Coordinate: Strideable
diff --git a/validation-test/compiler_crashers_2/0084-rdar31093854.swift b/validation-test/compiler_crashers_2_fixed/0084-rdar31093854.swift
similarity index 71%
rename from validation-test/compiler_crashers_2/0084-rdar31093854.swift
rename to validation-test/compiler_crashers_2_fixed/0084-rdar31093854.swift
index 165cad5..7edcf08 100644
--- a/validation-test/compiler_crashers_2/0084-rdar31093854.swift
+++ b/validation-test/compiler_crashers_2_fixed/0084-rdar31093854.swift
@@ -1,4 +1,4 @@
-// RUN: not --crash %target-swift-frontend -swift-version 4 %s -typecheck -o /dev/null
+// RUN: not %target-swift-frontend -swift-version 4 %s -typecheck -o /dev/null
 
 // This should actually type check successfully.
 
diff --git a/validation-test/compiler_crashers_2_fixed/0088-sr4315.swift b/validation-test/compiler_crashers_2_fixed/0088-sr4315.swift
new file mode 100644
index 0000000..5482b42
--- /dev/null
+++ b/validation-test/compiler_crashers_2_fixed/0088-sr4315.swift
@@ -0,0 +1,28 @@
+// RUN: %target-swift-frontend -emit-ir %s
+
+public protocol ParsableResult {
+    associatedtype Parser
+}
+
+final class ResultElement<T> {
+}
+
+
+enum InteractiveAPIError: Error {
+    case malformedResult
+}
+
+class XMLSAXElementParser<ChildElement> {
+    public required init() {}
+}
+
+
+
+final class InteractiveAPICall<Document: ParsableResult, Parser>:
+XMLSAXElementParser<Document.Parser> where Document.Parser == Parser {
+
+    required init() {}
+
+    func result(_: Document) {
+    }
+}
diff --git a/validation-test/compiler_crashers_fixed/28731-genericenv-nullptr-too-much-circularity.swift b/validation-test/compiler_crashers_fixed/28731-genericenv-nullptr-too-much-circularity.swift
new file mode 100644
index 0000000..a64aa23
--- /dev/null
+++ b/validation-test/compiler_crashers_fixed/28731-genericenv-nullptr-too-much-circularity.swift
@@ -0,0 +1,10 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not %target-swift-frontend %s -emit-ir
+protocol A:a{typealias a}class a:A
diff --git a/validation-test/stdlib/Collection/LazyFilterCollection.swift.gyb b/validation-test/stdlib/Collection/LazyFilterCollection.swift.gyb
index dddad9a..ff3513f 100644
--- a/validation-test/stdlib/Collection/LazyFilterCollection.swift.gyb
+++ b/validation-test/stdlib/Collection/LazyFilterCollection.swift.gyb
@@ -109,12 +109,12 @@
       expected,
       MinimalSequence(elements: base).lazy.filter(predicate))
 % elif traversal == '' and kind == 'Collection':
-    checkForwardCollection(
+    checkOneLevelOfForwardCollection(
       expected,
       MinimalCollection(elements: base).lazy.filter(predicate),
       sameValue: { $0 == $1 })
 % else:
-    check${traversal}${kind}(
+    checkOneLevelOf${traversal}${kind}(
       expected,
       Minimal${traversal}${kind}(elements: base).lazy.filter(predicate),
       sameValue: { $0 == $1 })
diff --git a/validation-test/stdlib/CollectionType.swift.gyb b/validation-test/stdlib/CollectionType.swift.gyb
index 4c83fc5..c5f60eb 100644
--- a/validation-test/stdlib/CollectionType.swift.gyb
+++ b/validation-test/stdlib/CollectionType.swift.gyb
@@ -474,8 +474,8 @@
     }
 
     checkCollection(
-      collection,
-      expected: Array(1..<count+1).map(OpaqueValue.init) as [OpaqueValue<Int>]
+      Array(1..<count+1).map(OpaqueValue.init) as [OpaqueValue<Int>],
+      collection
     ) { $0.value == $1.value }
   }
 }
@@ -547,8 +547,8 @@
     }
 
     checkCollection(
+      Array(1..<count+1).map(OpaqueValue.init) as [OpaqueValue<Int>],
       collection,
-      expected: Array(1..<count+1).map(OpaqueValue.init) as [OpaqueValue<Int>],
       resiliencyChecks: .none) { $0.value == $1.value }
   }
 }
diff --git a/validation-test/stdlib/Data.swift b/validation-test/stdlib/Data.swift
index d87e001..3fa4f10 100644
--- a/validation-test/stdlib/Data.swift
+++ b/validation-test/stdlib/Data.swift
@@ -7,6 +7,7 @@
 import Foundation
 
 var DataTestSuite = TestSuite("Data")
+
 DataTestSuite.test("Data.Iterator semantics") {
   // Empty data
   checkSequence([], Data())
@@ -45,7 +46,10 @@
   let array: [UInt8] = [0, 1, 2, 3, 4, 5, 6, 7]
   var data = Data(bytes: array)
 
-  checkRandomAccessCollection(array, data)
+  // FIXME: Iteration over Data slices is currently broken:
+  // [SR-4292] Foundation.Data.copyBytes is zero-based.
+  //           Data.Iterator assumes it is not.
+  // checkRandomAccessCollection(array, data)
 
   for i in 0..<data.count {
     for j in i..<data.count {
@@ -55,6 +59,11 @@
         expectEqual(dataSlice.startIndex, i)
         expectEqual(dataSlice.endIndex, j)
         
+        // FIXME: Iteration over Data slices is currently broken:
+        // [SR-4292] Foundation.Data.copyBytes is zero-based.
+        //           Data.Iterator assumes it is not.
+        // expectEqual(dataSlice[i], arraySlice[i])
+
         dataSlice[i] = 0xFF
         
         expectEqual(dataSlice.startIndex, i)
diff --git a/validation-test/stdlib/Lazy.swift.gyb b/validation-test/stdlib/Lazy.swift.gyb
index 062ac99..db741c9 100644
--- a/validation-test/stdlib/Lazy.swift.gyb
+++ b/validation-test/stdlib/Lazy.swift.gyb
@@ -698,7 +698,7 @@
     Minimal${TraversalCollection}<OpaqueValue<Int>>
   >.self, &again)
 
-  check${Traversal}Collection(
+  checkOneLevelOf${Traversal}Collection(
     expected, base.lazy, resiliencyChecks: .none
   ) { $0.value == $1.value }
 
@@ -1124,7 +1124,7 @@
     LazyFilterCollection<MinimalCollection<OpaqueValue<Int>>>
   >.test(filtered)
 
-  checkForwardCollection(
+  checkOneLevelOfForwardCollection(
     stride(from: 0, to: 100, by: 2).map(OpaqueValue.init), filtered,
     resiliencyChecks: .none
   ) {
diff --git a/validation-test/stdlib/Slice.swift.gyb b/validation-test/stdlib/Slice.swift.gyb
index 0503ef3..8fda74a 100644
--- a/validation-test/stdlib/Slice.swift.gyb
+++ b/validation-test/stdlib/Slice.swift.gyb
@@ -83,8 +83,8 @@
     expectType(${Slice}<${Collection}<OpaqueValue<Int>>>.self, &slice)
 
     checkCollection(
+      test.expected,
       slice,
-      expected: test.expected,
       stackTrace: SourceLocStack().with(test.loc))
       { $0.value == $1.value }
   }
diff --git a/validation-test/stdlib/Unicode.swift.gyb b/validation-test/stdlib/Unicode.swift.gyb
index d64f02e..c792e4f 100644
--- a/validation-test/stdlib/Unicode.swift.gyb
+++ b/validation-test/stdlib/Unicode.swift.gyb
@@ -1607,7 +1607,7 @@
 
 func checkUTF16View(_ expected: [UInt16], _ subject: String,
     _ stackTrace: SourceLocStack) {
-  checkSliceableWithBidirectionalIndex(expected, subject.utf16)
+  checkBidirectionalCollection(expected, subject.utf16)
 }
 
 func forStringsWithUnpairedSurrogates(_ checkClosure: (UTF16Test, String) -> Void) {
@@ -1848,7 +1848,7 @@
   test in
 
   let subject = NonContiguousNSString(test.utf32) as String
-  checkSliceableWithBidirectionalIndex(
+  checkBidirectionalCollection(
     test.unicodeScalars, subject.unicodeScalars)
 }
 
@@ -1858,7 +1858,7 @@
     let expectedScalars = (test.scalarsHead + test.scalarsRepairedTail).map {
       UnicodeScalar($0)!
     }
-    checkSliceableWithBidirectionalIndex(
+    checkBidirectionalCollection(
       expectedScalars, subject.unicodeScalars)
   }
 }
diff --git a/validation-test/stdlib/UnicodeTrie.swift.gyb b/validation-test/stdlib/UnicodeTrie.swift.gyb
index b7eda54..f592819 100644
--- a/validation-test/stdlib/UnicodeTrie.swift.gyb
+++ b/validation-test/stdlib/UnicodeTrie.swift.gyb
@@ -144,7 +144,7 @@
   )
 
   let expectedCharacters: [Character] = Array(subject.characters)
-  checkSliceableWithBidirectionalIndex(expectedCharacters, subject.characters)
+  checkBidirectionalCollection(expectedCharacters, subject.characters)
 }
 
 func checkGraphemeClusterSegmentation(
diff --git a/validation-test/stdlib/UnsafeBufferPointer.swift.gyb b/validation-test/stdlib/UnsafeBufferPointer.swift.gyb
index 35240a0..4f0ae01 100644
--- a/validation-test/stdlib/UnsafeBufferPointer.swift.gyb
+++ b/validation-test/stdlib/UnsafeBufferPointer.swift.gyb
@@ -6,31 +6,325 @@
 
 // Tests
 
+func allocateForRawBuffer(count: Int) -> UnsafeMutableRawPointer {
+  return UnsafeMutableRawPointer.allocate(bytes: count, alignedTo: 1)
+}
+func allocateForBuffer<T>(count: Int) -> UnsafeMutablePointer<T> {
+  return UnsafeMutablePointer<T>.allocate(capacity: count)
+}
+func deallocateForRawBuffer(
+  _ memory: UnsafeMutableRawPointer, count: Int
+) {
+  memory.deallocate(bytes: count, alignedTo: 1)
+}
+func deallocateForBuffer<T>(
+  _ memory: UnsafeMutablePointer<T>, count: Int
+) {
+  memory.deallocate(capacity: count)
+}
+
+// Initialize memory with arbitrary equatable, comparable values.
+func initUnsafeRawBufferPointer(_ b: UnsafeMutableRawBufferPointer) {
+  _ = b.initializeMemory(as: UInt8.self, from: UInt8(0)..<numericCast(b.count))
+}
+func initUnsafeBufferPointer(_ b: UnsafeMutableBufferPointer<Float>) {
+  _ = b.initialize(from: (0..<b.count).lazy.map {Float($0)})
+}
+
+// Test Suites
+
+var UnsafeBufferPointerTestSuite = TestSuite("UnsafeBufferPointer")
+var UnsafeMutableBufferPointerTestSuite = TestSuite("UnsafeMutableBufferPointer")
+var UnsafeRawBufferPointerTestSuite = TestSuite("UnsafeRawBufferPointer")
+var UnsafeMutableRawBufferPointerTestSuite = TestSuite("UnsafeMutableRawBufferPointer")
+
+% for (SelfName, IsMutable, IsRaw, SelfType, PointerType) in [
+%   ('UnsafeBufferPointer', False, False, 'UnsafeBufferPointer<Float>', 'UnsafePointer<Float>'),
+%   ('UnsafeMutableBufferPointer', True, False, 'UnsafeMutableBufferPointer<Float>', 'UnsafeMutablePointer<Float>'),
+%   ('UnsafeRawBufferPointer', False, True, 'UnsafeRawBufferPointer', 'UnsafeRawPointer'),
+%   ('UnsafeMutableRawBufferPointer', True, True, 'UnsafeMutableRawBufferPointer', 'UnsafeMutableRawPointer')
+% ]:
+%   Raw = 'Raw' if IsRaw else ''
+%   Element = 'UInt8' if IsRaw else 'Float'
+
+${SelfName}TestSuite.test("AssociatedTypes") {
+  expectRandomAccessCollectionAssociatedTypes(
+    collectionType: ${SelfType}.self,
+%   if IsRaw:
+    iteratorType: ${SelfType}.Iterator.self,
+%   else:
+    iteratorType: IndexingIterator<${SelfType}>.self,
+%   end
+    subSequenceType: ${'Mutable' if IsMutable else ''}RandomAccessSlice<${SelfType}>.self,
+    indexType: Int.self,
+    indexDistanceType: Int.self,
+    indicesType: CountableRange<Int>.self)
+
+  expect${'Mutable' if IsMutable else ''}CollectionType(${SelfType}.self)
+}
+
+${SelfName}TestSuite.test("rebasing") {
+  let rawbuffer = UnsafeMutableRawBufferPointer.allocate(count: 4 * MemoryLayout<Int>.stride)
+  defer { rawbuffer.deallocate() }
+
+  rawbuffer.copyBytes(from: [0, 1, 2, 3])
+
+%   if IsRaw:
+  let buffer = rawbuffer
+%   else:
+  let intPtr = rawbuffer.baseAddress!.bindMemory(to: Int.self, capacity: 4)
+  let buffer = UnsafeMutableBufferPointer(start: intPtr, count: 4)
+%   end
+
+  for i in buffer.indices {
+    let slice = buffer[i..<buffer.endIndex]
+    let rebased = ${SelfName}(rebasing: slice)
+    expectEqual(rebased.startIndex, 0)
+    expectEqual(rebased.endIndex, rebased.count)
+    expectEqual(rebased.endIndex, buffer.endIndex - i)
+    expectEqual(rebased[0], slice[i])
+    if rebased.count > 1 {
+      expectEqual(rebased[1], slice[i + 1])
+
+      // Rebase again. Tests Mutable->Immutable initializer
+      // and an rvalue slice with literal indices.
+      let rebased2 = ${SelfName}(rebasing: rebased[1..<2])
+      expectEqual(rebased2.startIndex, 0)
+      expectEqual(rebased2.endIndex, 1)
+      expectEqual(rebased2[0], slice[i + 1])
+    }
+  }
+}
+
+// Allocate two buffers. Initialize one and copy it into the other. Pass those
+// to the specified generic collection test function `checkBuffers`.
+func checkWithExpectedBuffer(checkBuffers: (${SelfType}, ${SelfType}) -> Void) {
+  // A collection just big enough to be sliced up interestingly.
+  let elementCount = 4
+
+%   if IsRaw:
+  var memory: UnsafeMutableRawPointer
+  var memoryCopy: UnsafeMutableRawPointer
+%   else:
+  var memory: UnsafeMutablePointer<Float>
+  var memoryCopy: UnsafeMutablePointer<Float>
+%   end
+
+  memory = allocateFor${Raw}Buffer(count: elementCount)
+  defer { deallocateFor${Raw}Buffer(
+      memory, count: elementCount) }
+
+  memoryCopy = allocateFor${Raw}Buffer(count: elementCount)
+  defer { deallocateFor${Raw}Buffer(memoryCopy, count: elementCount) }
+
+  initUnsafe${Raw}BufferPointer(
+    UnsafeMutable${Raw}BufferPointer(start: memory, count: elementCount))
+
+  let buffer = ${SelfType}(start: memory, count: elementCount)
+
+  let expectedBuffer = UnsafeMutable${Raw}BufferPointer(start: memoryCopy,
+    count: elementCount)
+
+%   if IsRaw:
+    expectedBuffer.copyBytes(from: buffer)
+%   else:
+    _ = expectedBuffer.initialize(from: buffer)
+%   end
+
+  let expected = ${SelfType}(
+    start: expectedBuffer.baseAddress, count: expectedBuffer.count)
+
+  checkBuffers(expected, buffer)
+}
+
+${SelfName}TestSuite.test("RandomAccessCollection") {
+  checkWithExpectedBuffer { (expected: ${SelfType}, buffer: ${SelfType}) in
+    checkRandomAccessCollection(expected, buffer,
+      sameValue: { (a: ${Element}, b: ${Element}) in a == b })
+  }
+}
+
+${SelfName}TestSuite.test("nilBaseAddress") {
+  let emptyBuffer = ${SelfType}(start: nil, count: 0)
+  expectNil(emptyBuffer.baseAddress)
+  expectEqual(0, emptyBuffer.count)
+  expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex)
+
+  var iter = emptyBuffer.makeIterator()
+  expectNil(iter.next())
+
+  expectEqualSequence([], emptyBuffer)
+}
+
+${SelfName}TestSuite.test("nonNilButEmpty") {
+  let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0)
+  defer { emptyAllocated.deallocate(capacity: 0) }
+
+  let emptyBuffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: 0)
+  expectEqual(emptyAllocated, emptyBuffer.baseAddress)
+  expectEqual(0, emptyBuffer.count)
+  expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex)
+
+  var iter = emptyBuffer.makeIterator()
+  expectNil(iter.next())
+
+  expectEqualSequence([], emptyBuffer)
+}
+
+%   if IsRaw:
+${SelfName}TestSuite.test("nonNilNonEmpty") {
+  let count = 4
+  let allocated = UnsafeMutableRawPointer.allocate(bytes: count, alignedTo: 1)
+  defer { allocated.deallocate(bytes: count, alignedTo: 1) }
+  let uint8Ptr = allocated.initializeMemory(as: UInt8.self, count: count, to: 1)
+  uint8Ptr[count - 1] = 2
+
+  let buffer = ${SelfType}(start: ${PointerType}(allocated), count: count - 1)
+  expectEqual(allocated, buffer.baseAddress)
+  expectEqual(count - 1, buffer.count)
+  expectEqual(count - 1, buffer.endIndex - buffer.startIndex)
+
+  uint8Ptr[1] = 0
+  expectEqual(1, buffer[0])
+  expectEqual(0, buffer[1])
+  expectEqual(1, buffer[2])
+
+  var iter = buffer.makeIterator()
+  expectEqual(1, iter.next())
+  expectEqual(0, iter.next())
+  expectEqual(1, iter.next())
+  expectNil(iter.next())
+
+  expectEqualSequence([1, 0, 1], buffer.map { Int($0) })
+
+  expectEqual(2, uint8Ptr[count-1])
+}
+%   else: # !IsRaw
+${SelfName}TestSuite.test("nonNilNonEmpty") {
+  let count = 4
+  let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count)
+  defer { allocated.deallocate(capacity: count) }
+  allocated.initialize(to: 1.0, count: count)
+  allocated[count - 1] = 2.0
+
+  let buffer = ${SelfType}(start: ${PointerType}(allocated), count: count - 1)
+  expectEqual(allocated, buffer.baseAddress)
+  expectEqual(count - 1, buffer.count)
+  expectEqual(count - 1, buffer.endIndex - buffer.startIndex)
+
+  allocated[1] = 0.0
+  expectEqual(1.0, buffer[0])
+  expectEqual(0.0, buffer[1])
+  expectEqual(1.0, buffer[2])
+
+  var iter = buffer.makeIterator()
+  expectEqual(1.0, iter.next())
+  expectEqual(0.0, iter.next())
+  expectEqual(1.0, iter.next())
+  expectNil(iter.next())
+
+  expectEqualSequence([1.0, 0.0, 1.0], buffer)
+
+  expectEqual(2.0, allocated[count-1])
+}
+%   end # !IsRaw
+
+${SelfName}TestSuite.test("badCount")
+  .skip(.custom(
+    { _isFastAssertConfiguration() },
+    reason: "this trap is not guaranteed to happen in -Ounchecked"))
+  .code {
+  expectCrashLater()
+
+  let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0)
+  defer { emptyAllocated.deallocate(capacity: 0) }
+
+  let buffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: -1)
+  _ = buffer
+}
+
+${SelfName}TestSuite.test("badNilCount")
+  .skip(.custom(
+    { _isFastAssertConfiguration() },
+    reason: "this trap is not guaranteed to happen in -Ounchecked"))
+  .code {
+  expectCrashLater()
+
+  let buffer = ${SelfType}(start: nil, count: 1)
+  _ = buffer
+}
+% end # for SelfName, IsRaw, SelfType
+
+UnsafeMutableRawBufferPointerTestSuite.test("changeElementViaBuffer") {
+  let count = 4
+  let allocated = UnsafeMutableRawPointer.allocate(bytes: count, alignedTo: 1)
+  defer { allocated.deallocate(bytes: count, alignedTo: 1) }
+  let uint8Ptr = allocated.initializeMemory(as: UInt8.self, count: count, to: 1)
+  uint8Ptr[count-1] = UInt8.max
+
+  var buffer = UnsafeMutableRawBufferPointer(start: allocated, count: count - 1)
+
+  buffer[1] = 0
+  expectEqual(1, buffer[0])
+  expectEqual(0, buffer[1])
+  expectEqual(1, buffer[2])
+
+  expectEqual(1, uint8Ptr[0])
+  expectEqual(0, uint8Ptr[1])
+  expectEqual(1, uint8Ptr[2])
+  expectEqual(UInt8.max, uint8Ptr[count-1])
+
+  buffer.sort()
+  expectEqual(0, buffer[0])
+  expectEqual(1, buffer[1])
+  expectEqual(1, buffer[2])
+
+  expectEqual(0, uint8Ptr[0])
+  expectEqual(1, uint8Ptr[1])
+  expectEqual(1, uint8Ptr[2])
+  expectEqual(UInt8.max, uint8Ptr[count-1])
+}
+
+UnsafeMutableBufferPointerTestSuite.test("changeElementViaBuffer") {
+  let count = 4
+  let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count)
+  defer { allocated.deallocate(capacity: count) }
+  allocated.initialize(to: 1.0, count: count)
+  allocated[count-1] = -1.0
+
+  var buffer = UnsafeMutableBufferPointer(start: allocated, count: count - 1)
+
+  buffer[1] = 0.0
+  expectEqual(1.0, buffer[0])
+  expectEqual(0.0, buffer[1])
+  expectEqual(1.0, buffer[2])
+
+  expectEqual(1.0, allocated[0])
+  expectEqual(0.0, allocated[1])
+  expectEqual(1.0, allocated[2])
+  expectEqual(-1.0, allocated[count-1])
+
+  buffer.sort()
+  expectEqual(0.0, buffer[0])
+  expectEqual(1.0, buffer[1])
+  expectEqual(1.0, buffer[2])
+
+  expectEqual(0.0, allocated[0])
+  expectEqual(1.0, allocated[1])
+  expectEqual(1.0, allocated[2])
+  expectEqual(-1.0, allocated[count-1])
+}
+
 protocol SubscriptTest {
   static var start: Int { get }
   static var end: Int { get }
   static var elementCount: Int { get }
 }
 
+// Initialize memory with opaque values, for use with subscript tests.
 extension SubscriptTest {
   static var elementCount: Int { get { return end - start } }
 
-  static func allocateForRawBuffer(count: Int) -> UnsafeMutableRawPointer {
-    return UnsafeMutableRawPointer.allocate(bytes: count, alignedTo: 1)
-  }
-  static func allocateForBuffer(count: Int
-  ) -> UnsafeMutablePointer<OpaqueValue<Int>> {
-    return UnsafeMutablePointer<OpaqueValue<Int>>.allocate(capacity: count)
-  }
-  static func deallocateForRawBuffer(
-    _ memory: UnsafeMutableRawPointer, count: Int) {
-    memory.deallocate(bytes: count, alignedTo: 1)
-  }
-  static func deallocateForBuffer(
-    _ memory: UnsafeMutablePointer<OpaqueValue<Int>>, count: Int) {
-    memory.deallocate(capacity: count)
-  }
-
 % for SelfType in ['UnsafeRawBufferPointer', 'UnsafeMutableRawBufferPointer']:
   /// Create and populate an `${SelfType}` for use with unit tests.
   /// PRECONDITION: `memory` must be allocated with space for
@@ -182,7 +476,7 @@
   func replacementValuesSlice(
     from memory: UnsafeMutableRawPointer,
     replacementValues: [OpaqueValue<Int>]
-  ) -> UnsafeMutableRawBufferPointer
+  ) -> UnsafeMutableRawBufferPointer.SubSequence
   {
     for (i, value) in replacementValues.enumerated() {
       memory.initializeMemory(
@@ -312,181 +606,14 @@
     replacementValues: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]),
 ]
 
-
-// Test Suites
-
-var UnsafeBufferPointerTestSuite = TestSuite("UnsafeBufferPointer")
-var UnsafeMutableBufferPointerTestSuite = TestSuite("UnsafeMutableBufferPointer")
-var UnsafeRawBufferPointerTestSuite = TestSuite("UnsafeRawBufferPointer")
-var UnsafeMutableRawBufferPointerTestSuite = TestSuite("UnsafeMutableRawBufferPointer")
-
-% for (SelfName, IsMutable, IsRaw, SelfType, PointerType) in [
-%   ('UnsafeBufferPointer', False, False, 'UnsafeBufferPointer<Float>', 'UnsafePointer<Float>'),
-%   ('UnsafeMutableBufferPointer', True, False, 'UnsafeMutableBufferPointer<Float>', 'UnsafeMutablePointer<Float>'),
-%   ('UnsafeRawBufferPointer', False, True, 'UnsafeRawBufferPointer', 'UnsafeRawPointer'),
-%   ('UnsafeMutableRawBufferPointer', True, True, 'UnsafeMutableRawBufferPointer', 'UnsafeMutableRawPointer')
+% for (SelfName, IsRaw) in [
+%   ('UnsafeBufferPointer', False),
+%   ('UnsafeRawBufferPointer', True),
+%   ('UnsafeMutableBufferPointer', False),
+%   ('UnsafeMutableRawBufferPointer', True)
 % ]:
 
-%   if IsRaw:
-${SelfName}TestSuite.test("AssociatedTypes") {
-  expectRandomAccessCollectionAssociatedTypes(
-    collectionType: ${SelfType}.self,
-    iteratorType: ${SelfType}.Iterator.self,
-    subSequenceType: ${SelfType}.self,
-    indexType: Int.self,
-    indexDistanceType: Int.self,
-    indicesType: CountableRange<Int>.self)
-
-  expect${'Mutable' if IsMutable else ''}CollectionType(${SelfType}.self)
-}
-%   else: # !IsRaw
-${SelfName}TestSuite.test("AssociatedTypes") {
-  typealias Subject = ${SelfName}<OpaqueValue<Int>>
-  expectRandomAccessCollectionAssociatedTypes(
-    collectionType: Subject.self,
-    iteratorType: IndexingIterator<Subject>.self,
-    subSequenceType: ${'Mutable' if IsMutable else ''}RandomAccessSlice<Subject>.self,
-    indexType: Int.self,
-    indexDistanceType: Int.self,
-    indicesType: CountableRange<Int>.self)
-
-  expect${'Mutable' if IsMutable else ''}CollectionType(Subject.self)
-}
-%   end # !IsRaw
-
-${SelfName}TestSuite.test("nilBaseAddress") {
-  let emptyBuffer = ${SelfType}(start: nil, count: 0)
-  expectNil(emptyBuffer.baseAddress)
-  expectEqual(0, emptyBuffer.count)
-  expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex)
-
-  var iter = emptyBuffer.makeIterator()
-  expectNil(iter.next())
-
-  expectEqualSequence([], emptyBuffer)
-}
-
-${SelfName}TestSuite.test("nonNilButEmpty") {
-  let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0)
-  defer { emptyAllocated.deallocate(capacity: 0) }
-
-  let emptyBuffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: 0)
-  expectEqual(emptyAllocated, emptyBuffer.baseAddress)
-  expectEqual(0, emptyBuffer.count)
-  expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex)
-
-  var iter = emptyBuffer.makeIterator()
-  expectNil(iter.next())
-
-  expectEqualSequence([], emptyBuffer)
-}
-
-%   if IsRaw:
-${SelfName}TestSuite.test("nonNilNonEmpty") {
-  let count = 4
-  let allocated = UnsafeMutableRawPointer.allocate(bytes: count, alignedTo: 1)
-  defer { allocated.deallocate(bytes: count, alignedTo: 1) }
-  let uint8Ptr = allocated.initializeMemory(as: UInt8.self, count: count, to: 1)
-  uint8Ptr[count - 1] = 2
-
-  let buffer = ${SelfType}(start: ${PointerType}(allocated), count: count - 1)
-  expectEqual(allocated, buffer.baseAddress)
-  expectEqual(count - 1, buffer.count)
-  expectEqual(count - 1, buffer.endIndex - buffer.startIndex)
-
-  uint8Ptr[1] = 0
-  expectEqual(1, buffer[0])
-  expectEqual(0, buffer[1])
-  expectEqual(1, buffer[2])
-
-  var iter = buffer.makeIterator()
-  expectEqual(1, iter.next())
-  expectEqual(0, iter.next())
-  expectEqual(1, iter.next())
-  expectNil(iter.next())
-
-  expectEqualSequence([1, 0, 1], buffer.map { Int($0) })
-
-  expectEqual(2, uint8Ptr[count-1])
-}
-%   else: # !IsRaw
-${SelfName}TestSuite.test("nonNilNonEmpty") {
-  let count = 4
-  let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count)
-  defer { allocated.deallocate(capacity: count) }
-  allocated.initialize(to: 1.0, count: count)
-  allocated[count - 1] = 2.0
-
-  let buffer = ${SelfType}(start: ${PointerType}(allocated), count: count - 1)
-  expectEqual(allocated, buffer.baseAddress)
-  expectEqual(count - 1, buffer.count)
-  expectEqual(count - 1, buffer.endIndex - buffer.startIndex)
-
-  allocated[1] = 0.0
-  expectEqual(1.0, buffer[0])
-  expectEqual(0.0, buffer[1])
-  expectEqual(1.0, buffer[2])
-
-  var iter = buffer.makeIterator()
-  expectEqual(1.0, iter.next())
-  expectEqual(0.0, iter.next())
-  expectEqual(1.0, iter.next())
-  expectNil(iter.next())
-
-  expectEqualSequence([1.0, 0.0, 1.0], buffer)
-
-  expectEqual(2.0, allocated[count-1])
-}
-%   end # !IsRaw
-
-${SelfName}TestSuite.test("badCount")
-  .skip(.custom(
-    { _isFastAssertConfiguration() },
-    reason: "this trap is not guaranteed to happen in -Ounchecked"))
-  .code {
-  expectCrashLater()
-
-  let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0)
-  defer { emptyAllocated.deallocate(capacity: 0) }
-
-  let buffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: -1)
-  _ = buffer
-}
-
-${SelfName}TestSuite.test("badNilCount")
-  .skip(.custom(
-    { _isFastAssertConfiguration() },
-    reason: "this trap is not guaranteed to happen in -Ounchecked"))
-  .code {
-  expectCrashLater()
-
-  let buffer = ${SelfType}(start: nil, count: 1)
-  _ = buffer
-}
-
-${SelfName}TestSuite.test("RandomAccessCollection") {
-  let elementCount = SubscriptGetTest.elementCount
-  var memory = SubscriptGetTest.allocateFor${'Raw' if IsRaw else ''}Buffer(
-    count: elementCount)
-  defer { SubscriptGetTest.deallocateFor${'Raw' if IsRaw else ''}Buffer(
-      memory, count: elementCount) }
-  var memoryCopy = SubscriptGetTest.allocateFor${'Raw' if IsRaw else ''}Buffer(
-    count: elementCount)
-  defer { SubscriptGetTest.deallocateFor${'Raw' if IsRaw else ''}Buffer(
-      memoryCopy, count: elementCount) }
-
-  var buffer = SubscriptGetTest.create${SelfName}(from: memory)
-  var expected = UnsafeMutable${'Raw' if IsRaw else ''}BufferPointer(
-    start: memoryCopy, count: buffer.count)
-
-%   if IsRaw:
-  expected.copyBytes(from: buffer)
-  checkRandomAccessCollection(expected, buffer) { $0 == $1 }
-%   else:
-  expected.baseAddress!.initialize(from: buffer)
-  checkRandomAccessCollection(expected, buffer) { $0.value == $1.value }
-%   end
-}
+%   Raw = 'Raw' if IsRaw else ''
 
 %   for RangeName in ['range', 'countableRange', 'closedRange', 'countableClosedRange']:
 ${SelfName}TestSuite.test("subscript/${RangeName}/get").forEach(in: subscriptGetTests) {
@@ -510,10 +637,14 @@
 
   let elementCount = SubscriptGetTest.elementCount
 
-  var memory = SubscriptGetTest.allocateFor${'Raw' if IsRaw else ''}Buffer(
-    count: elementCount)
-  defer { SubscriptGetTest.deallocateFor${'Raw' if IsRaw else ''}Buffer(
-      memory, count: elementCount) }
+%     if IsRaw:
+  var memory: UnsafeMutableRawPointer
+%     else:
+  var memory: UnsafeMutablePointer<OpaqueValue<Int>>
+%     end
+
+  memory = allocateFor${Raw}Buffer(count: elementCount)
+  defer { deallocateFor${Raw}Buffer(memory, count: elementCount) }
 
   let buffer = SubscriptGetTest.create${SelfName}(from: memory)
 
@@ -542,15 +673,17 @@
     )
   }
 }
-%    end
 
-% end
+%   end # RangeName
+% end # SelfName, IsMutable, IsRaw, SelfType, PointerType
 
 % for (SelfName, IsRaw) in [
 %   ('UnsafeMutableBufferPointer', False),
 %   ('UnsafeMutableRawBufferPointer', True)
 % ]:
+%   Raw = 'Raw' if IsRaw else ''
 %   for RangeName in ['range', 'countableRange', 'closedRange', 'countableClosedRange']:
+
 UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/${RangeName}/set")
 %     if not IsRaw:
   // UnsafeRawBuffer (currently) invokes Collection._failEarlyRangeCheck
@@ -585,7 +718,7 @@
       return false
     }
   }
-%      else:
+%      else: # !closed
   expectedValues = test.expectedValues
   replacementValues = test.replacementValues
   let isOutOfBounds: () -> Bool = {
@@ -596,15 +729,21 @@
       return false
     }
   }
-%      end
+%      end # !closed
 
-  var memory = SubscriptSetTest.allocateFor${'Raw' if IsRaw else ''}Buffer(
-    count: elementCount)
-  defer { SubscriptSetTest.deallocateFor${'Raw' if IsRaw else ''}Buffer(
-      memory, count: elementCount) }
-  var sliceMemory = SubscriptSetTest.allocateFor${'Raw' if IsRaw else ''}Buffer(
-    count: replacementValues.count)
-  defer { SubscriptSetTest.deallocateFor${'Raw' if IsRaw else ''}Buffer(
+%     if IsRaw:
+  var memory: UnsafeMutableRawPointer
+  var sliceMemory: UnsafeMutableRawPointer
+%     else:
+  var memory: UnsafeMutablePointer<OpaqueValue<Int>>
+  var sliceMemory: UnsafeMutablePointer<OpaqueValue<Int>>
+%     end
+
+  memory = allocateFor${Raw}Buffer(count: elementCount)
+  defer { deallocateFor${Raw}Buffer(memory, count: elementCount) }
+
+  sliceMemory = allocateFor${Raw}Buffer(count: replacementValues.count)
+  defer { deallocateFor${Raw}Buffer(
       sliceMemory, count: replacementValues.count) }
 
   var buffer = SubscriptSetTest.create${SelfName}(from: memory)
@@ -640,67 +779,9 @@
     )
   }
 }
+
 %   end # RangeName
+
 % end # SelfName
 
-UnsafeMutableRawBufferPointerTestSuite.test("changeElementViaBuffer") {
-  let count = 4
-  let allocated = UnsafeMutableRawPointer.allocate(bytes: count, alignedTo: 1)
-  defer { allocated.deallocate(bytes: count, alignedTo: 1) }
-  let uint8Ptr = allocated.initializeMemory(as: UInt8.self, count: count, to: 1)
-  uint8Ptr[count-1] = UInt8.max
-
-  var buffer = UnsafeMutableRawBufferPointer(start: allocated, count: count - 1)
-
-  buffer[1] = 0
-  expectEqual(1, buffer[0])
-  expectEqual(0, buffer[1])
-  expectEqual(1, buffer[2])
-
-  expectEqual(1, uint8Ptr[0])
-  expectEqual(0, uint8Ptr[1])
-  expectEqual(1, uint8Ptr[2])
-  expectEqual(UInt8.max, uint8Ptr[count-1])
-
-  buffer.sort()
-  expectEqual(0, buffer[0])
-  expectEqual(1, buffer[1])
-  expectEqual(1, buffer[2])
-
-  expectEqual(0, uint8Ptr[0])
-  expectEqual(1, uint8Ptr[1])
-  expectEqual(1, uint8Ptr[2])
-  expectEqual(UInt8.max, uint8Ptr[count-1])
-}
-
-UnsafeMutableBufferPointerTestSuite.test("changeElementViaBuffer") {
-  let count = 4
-  let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count)
-  defer { allocated.deallocate(capacity: count) }
-  allocated.initialize(to: 1.0, count: count)
-  allocated[count-1] = -1.0
-
-  var buffer = UnsafeMutableBufferPointer(start: allocated, count: count - 1)
-
-  buffer[1] = 0.0
-  expectEqual(1.0, buffer[0])
-  expectEqual(0.0, buffer[1])
-  expectEqual(1.0, buffer[2])
-
-  expectEqual(1.0, allocated[0])
-  expectEqual(0.0, allocated[1])
-  expectEqual(1.0, allocated[2])
-  expectEqual(-1.0, allocated[count-1])
-
-  buffer.sort()
-  expectEqual(0.0, buffer[0])
-  expectEqual(1.0, buffer[1])
-  expectEqual(1.0, buffer[2])
-
-  expectEqual(0.0, allocated[0])
-  expectEqual(1.0, allocated[1])
-  expectEqual(1.0, allocated[2])
-  expectEqual(-1.0, allocated[count-1])
-}
-
 runAllTests()