Merge pull request #17307 from benlangmuir/notification-test-non-determinism-42

[4.2] [sourcekit] Fix non-deterministic failure in CompileNotifications tests
diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def
index 6511fb4..cbd6400 100644
--- a/include/swift/AST/Attr.def
+++ b/include/swift/AST/Attr.def
@@ -348,6 +348,11 @@
 
 SIMPLE_DECL_ATTR(_frozen, Frozen, OnEnum | UserInaccessible, 76)
 
+SIMPLE_DECL_ATTR(_forbidSerializingReference, ForbidSerializingReference,
+  OnAnyDecl |
+  LongAttribute | RejectByParser | UserInaccessible | NotSerialized,
+  77)
+
 #undef TYPE_ATTR
 #undef DECL_ATTR_ALIAS
 #undef CONTEXTUAL_DECL_ATTR_ALIAS
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 7205a8e..b22c14b 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -3835,6 +3835,11 @@
       "cannot be referenced from " FRAGILE_FUNC_KIND "3",
       (DescriptiveDeclKind, DeclName, AccessLevel, unsigned))
 
+WARNING(resilience_decl_unavailable_warn,
+        none, "%0 %1 is %select{private|fileprivate|internal|%error|%error}2 and "
+        "should not be referenced from " FRAGILE_FUNC_KIND "3",
+        (DescriptiveDeclKind, DeclName, AccessLevel, unsigned))
+
 #undef FRAGILE_FUNC_KIND
 
 NOTE(resilience_decl_declared_here_public,
diff --git a/include/swift/Serialization/ModuleFile.h b/include/swift/Serialization/ModuleFile.h
index 300e594..77bb843 100644
--- a/include/swift/Serialization/ModuleFile.h
+++ b/include/swift/Serialization/ModuleFile.h
@@ -625,6 +625,13 @@
     return static_cast<Status>(Bits.Status);
   }
 
+  /// Transfers ownership of a buffer that might contain source code where
+  /// other parts of the compiler could have emitted diagnostics, to keep them
+  /// alive even if the ModuleFile is destroyed.
+  ///
+  /// Should only be called when getStatus() indicates a failure.
+  std::unique_ptr<llvm::MemoryBuffer> takeBufferForDiagnostics();
+
   /// Returns the list of modules this module depends on.
   ArrayRef<Dependency> getDependencies() const {
     return Dependencies;
diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h
index 13db711..00fa1d5 100644
--- a/include/swift/Serialization/SerializedModuleLoader.h
+++ b/include/swift/Serialization/SerializedModuleLoader.h
@@ -29,6 +29,8 @@
   using LoadedModulePair = std::pair<std::unique_ptr<ModuleFile>, unsigned>;
   std::vector<LoadedModulePair> LoadedModuleFiles;
 
+  SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 2> OrphanedMemoryBuffers;
+
   explicit SerializedModuleLoader(ASTContext &ctx, DependencyTracker *tracker);
 
 public:
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index ef48703..f681109 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -4617,6 +4617,8 @@
               "This Objective-C class has only been forward-declared; "
               "import its owning module to use it");
           result->getAttrs().add(attr);
+          result->getAttrs().add(
+              new (Impl.SwiftContext) ForbidSerializingReferenceAttr(true));
           return result;
         }
 
diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp
index e2ca4ca..578bea4 100644
--- a/lib/Sema/DerivedConformanceRawRepresentable.cpp
+++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp
@@ -121,6 +121,22 @@
   toRawDecl->setBody(body);
 }
 
+static void maybeMarkAsInlinable(DerivedConformance &derived,
+                                 AbstractFunctionDecl *afd) {
+  ASTContext &C = derived.TC.Context;
+  auto parentDC = derived.getConformanceContext();
+  if (parentDC->getParentModule()->getResilienceStrategy() !=
+      ResilienceStrategy::Resilient) {
+    AccessScope access =
+        afd->getFormalAccessScope(nullptr,
+                                  /*treatUsableFromInlineAsPublic*/true);
+    if (auto *attr = afd->getAttrs().getAttribute<UsableFromInlineAttr>())
+      attr->setInvalid();
+    if (access.isPublic())
+      afd->getAttrs().add(new (C) InlinableAttr(/*implicit*/false));
+  }
+}
+
 static VarDecl *deriveRawRepresentable_raw(DerivedConformance &derived) {
   ASTContext &C = derived.TC.Context;
 
@@ -143,14 +159,7 @@
 
   // If the containing module is not resilient, make sure clients can get at
   // the raw value without function call overhead.
-  if (parentDC->getParentModule()->getResilienceStrategy() !=
-      ResilienceStrategy::Resilient) {
-    AccessScope access =
-        enumDecl->getFormalAccessScope(nullptr,
-                                       /*treatUsableFromInlineAsPublic*/true);
-    if (access.isPublic())
-      getterDecl->getAttrs().add(new (C) InlinableAttr(/*implicit*/false));
-  }
+  maybeMarkAsInlinable(derived, getterDecl);
 
   derived.addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
 
@@ -350,14 +359,7 @@
 
   // If the containing module is not resilient, make sure clients can construct
   // an instance without function call overhead.
-  if (parentDC->getParentModule()->getResilienceStrategy() !=
-      ResilienceStrategy::Resilient) {
-    AccessScope access =
-        enumDecl->getFormalAccessScope(nullptr,
-                                       /*treatUsableFromInlineAsPublic*/true);
-    if (access.isPublic())
-      initDecl->getAttrs().add(new (C) InlinableAttr(/*implicit*/false));
-  }
+  maybeMarkAsInlinable(derived, initDecl);
 
   C.addSynthesizedDecl(initDecl);
 
diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp
index 70d72e9..b0d9d4f 100644
--- a/lib/Sema/ResilienceDiagnostics.cpp
+++ b/lib/Sema/ResilienceDiagnostics.cpp
@@ -86,6 +86,13 @@
   }
 }
 
+/// A uniquely-typed boolean to reduce the chances of accidentally inverting
+/// a check.
+enum class DowngradeToWarning: bool {
+  No,
+  Yes
+};
+
 bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
                                            const ValueDecl *D,
                                            const DeclContext *DC,
@@ -119,11 +126,18 @@
   if (D->isDynamic())
     return false;
 
-  // FIXME: Figure out what to do with typealiases
-  if (isa<TypeAliasDecl>(D))
-    return false;
+  DowngradeToWarning downgradeToWarning = DowngradeToWarning::No;
 
-  diagnose(loc, diag::resilience_decl_unavailable,
+  // Swift 4.2 did not perform any checks for type aliases.
+  if (!Context.isSwiftVersionAtLeast(5) &&
+      isa<TypeAliasDecl>(D))
+    downgradeToWarning = DowngradeToWarning::Yes;
+
+  auto diagID = diag::resilience_decl_unavailable;
+  if (downgradeToWarning == DowngradeToWarning::Yes)
+    diagID = diag::resilience_decl_unavailable_warn;
+
+  diagnose(loc, diagID,
            D->getDescriptiveKind(), D->getFullName(),
            D->getFormalAccessScope().accessLevelForDiagnostics(),
            static_cast<unsigned>(Kind));
@@ -136,6 +150,6 @@
              D->getDescriptiveKind(), D->getFullName());
   }
 
-  return true;
+  return (downgradeToWarning == DowngradeToWarning::No);
 }
 
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index e4799eb..7aa453b 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -80,6 +80,7 @@
   IGNORED_ATTR(Effects)
   IGNORED_ATTR(Exported)
   IGNORED_ATTR(FixedLayout)
+  IGNORED_ATTR(ForbidSerializingReference)
   IGNORED_ATTR(Frozen)
   IGNORED_ATTR(Implements)
   IGNORED_ATTR(ImplicitlyUnwrappedOptional)
@@ -804,6 +805,7 @@
     IGNORED_ATTR(Dynamic)
     IGNORED_ATTR(Effects)
     IGNORED_ATTR(Exported)
+    IGNORED_ATTR(ForbidSerializingReference)
     IGNORED_ATTR(GKInspectable)
     IGNORED_ATTR(IBDesignable)
     IGNORED_ATTR(IBInspectable)
@@ -1977,9 +1979,7 @@
 
   // On internal declarations, @inlinable implies @usableFromInline.
   if (VD->getAttrs().hasAttribute<InlinableAttr>()) {
-    if (attr->isImplicit())
-      attr->setInvalid();
-    else
+    if (TC.Context.isSwiftVersionAtLeast(4,2))
       diagnoseAndRemoveAttr(attr, diag::inlinable_implies_usable_from_inline);
     return;
   }
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 889a997..8d15c25 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -5717,6 +5717,7 @@
     UNINTERESTING_ATTR(DynamicMemberLookup)
     UNINTERESTING_ATTR(SILGenName)
     UNINTERESTING_ATTR(Exported)
+    UNINTERESTING_ATTR(ForbidSerializingReference)
     UNINTERESTING_ATTR(GKInspectable)
     UNINTERESTING_ATTR(IBAction)
     UNINTERESTING_ATTR(IBDesignable)
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 5b00159..1dd34c9 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -1198,6 +1198,10 @@
       return true;
     if (value->isStatic() != isStatic)
       return true;
+
+    if (value->getAttrs().hasAttribute<ForbidSerializingReferenceAttr>())
+      return true;
+
     // FIXME: Should be able to move a value from an extension in a derived
     // module to the original definition in a base module.
     if (expectedModule && !value->hasClangNode() &&
diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp
index eca8558..9f143d6 100644
--- a/lib/Serialization/ModuleFile.cpp
+++ b/lib/Serialization/ModuleFile.cpp
@@ -1468,6 +1468,17 @@
   return getStatus();
 }
 
+std::unique_ptr<llvm::MemoryBuffer> ModuleFile::takeBufferForDiagnostics() {
+  assert(getStatus() != Status::Valid);
+
+  // Today, the only buffer that might have diagnostics in them is the input
+  // buffer, and even then only if it has imported module contents.
+  if (!importedHeaderInfo.contents.empty())
+    return std::move(ModuleInputBuffer);
+
+  return nullptr;
+}
+
 ModuleFile::~ModuleFile() { }
 
 void ModuleFile::lookupValue(DeclName name,
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index ae1ece9..e6cb2e4 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -609,6 +609,10 @@
           isa<PrecedenceGroupDecl>(D)) &&
          "cannot cross-reference this decl");
 
+  assert((!isDeclXRef(D) ||
+          !D->getAttrs().hasAttribute<ForbidSerializingReferenceAttr>()) &&
+         "cannot cross-reference this decl");
+
   assert((allowTypeAliasXRef || !isa<TypeAliasDecl>(D) ||
           D->getModuleContext() == M) &&
          "cannot cross-reference typealiases directly (use the NameAliasType)");
@@ -1070,28 +1074,38 @@
   publicImportSet.insert(publicImports.begin(), publicImports.end());
 
   removeDuplicateImports(allImports);
+
   auto clangImporter =
     static_cast<ClangImporter *>(M->getASTContext().getClangModuleLoader());
-  ModuleDecl *importedHeaderModule = clangImporter->getImportedHeaderModule();
+  ModuleDecl *bridgingHeaderModule = clangImporter->getImportedHeaderModule();
+  ModuleDecl::ImportedModule bridgingHeaderImport{{}, bridgingHeaderModule};
+
+  // Make sure the bridging header module is always at the top of the import
+  // list, mimicking how it is processed before any module imports when
+  // compiling source files.
+  if (llvm::is_contained(allImports, bridgingHeaderImport)) {
+    off_t importedHeaderSize = 0;
+    time_t importedHeaderModTime = 0;
+    std::string contents;
+    if (!options.ImportedHeader.empty()) {
+      contents = clangImporter->getBridgingHeaderContents(
+          options.ImportedHeader, importedHeaderSize, importedHeaderModTime);
+    }
+    assert(publicImportSet.count(bridgingHeaderImport));
+    ImportedHeader.emit(ScratchRecord,
+                        publicImportSet.count(bridgingHeaderImport),
+                        importedHeaderSize, importedHeaderModTime,
+                        options.ImportedHeader);
+    if (!contents.empty()) {
+      contents.push_back('\0');
+      ImportedHeaderContents.emit(ScratchRecord, contents);
+    }
+  }
+
   ModuleDecl *theBuiltinModule = M->getASTContext().TheBuiltinModule;
   for (auto import : allImports) {
-    if (import.second == theBuiltinModule)
-      continue;
-
-    if (import.second == importedHeaderModule) {
-      off_t importedHeaderSize = 0;
-      time_t importedHeaderModTime = 0;
-      std::string contents;
-      if (!options.ImportedHeader.empty())
-        contents = clangImporter->getBridgingHeaderContents(
-            options.ImportedHeader, importedHeaderSize, importedHeaderModTime);
-      ImportedHeader.emit(ScratchRecord, publicImportSet.count(import),
-                          importedHeaderSize, importedHeaderModTime,
-                          options.ImportedHeader);
-      if (!contents.empty()) {
-        contents.push_back('\0');
-        ImportedHeaderContents.emit(ScratchRecord, contents);
-      }
+    if (import.second == theBuiltinModule ||
+        import.second == bridgingHeaderModule) {
       continue;
     }
 
diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp
index d7f8729..02edb2e 100644
--- a/lib/Serialization/SerializedModuleLoader.cpp
+++ b/lib/Serialization/SerializedModuleLoader.cpp
@@ -223,7 +223,14 @@
     M.removeFile(*fileUnit);
   }
 
-  // This is the failure path. If we have a location, diagnose the issue.
+  // From here on is the failure path.
+
+  // Even though the module failed to load, it's possible its contents include
+  // a source buffer that need to survive because it's already been used for
+  // diagnostics.
+  if (auto orphanedBuffer = loadedModuleFile->takeBufferForDiagnostics())
+    OrphanedMemoryBuffers.push_back(std::move(orphanedBuffer));
+
   if (!diagLoc)
     return nullptr;
 
diff --git a/test/ClangImporter/Inputs/custom-modules/ForwardDeclarationsHelper.h b/test/ClangImporter/Inputs/custom-modules/ForwardDeclarationsHelper.h
new file mode 100644
index 0000000..c1f02bf
--- /dev/null
+++ b/test/ClangImporter/Inputs/custom-modules/ForwardDeclarationsHelper.h
@@ -0,0 +1,4 @@
+@class Confusing;
+
+@protocol Confusing
+@end
diff --git a/test/ClangImporter/Inputs/custom-modules/module.map b/test/ClangImporter/Inputs/custom-modules/module.map
index f7c389a..d9c458e 100644
--- a/test/ClangImporter/Inputs/custom-modules/module.map
+++ b/test/ClangImporter/Inputs/custom-modules/module.map
@@ -212,3 +212,7 @@
 module Warnings7 { header "Warnings7.h" }
 module Warnings8 { header "Warnings8.h" }
 module Warnings9 { header "Warnings9.h" }
+
+module ForwardDeclarationsHelper {
+  header "ForwardDeclarationsHelper.h"
+}
diff --git a/test/ClangImporter/objc_forward_declarations.swift b/test/ClangImporter/objc_forward_declarations.swift
new file mode 100644
index 0000000..045cfb4
--- /dev/null
+++ b/test/ClangImporter/objc_forward_declarations.swift
@@ -0,0 +1,9 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t -I %S/Inputs/custom-modules -enable-objc-interop %s
+// RUN: %target-swift-ide-test -print-module -module-to-print objc_forward_declarations -I %t -I %S/Inputs/custom-modules -enable-objc-interop -enable-objc-forward-declarations -source-filename x | %FileCheck %s
+
+// CHECK: class Innocuous : Confusing {
+
+import ForwardDeclarationsHelper
+
+public class Innocuous: Confusing {}
diff --git a/test/Compatibility/attr_inlinable_old_spelling_4.swift b/test/Compatibility/attr_inlinable_old_spelling_4.swift
index ab7d51b..4488d2e 100644
--- a/test/Compatibility/attr_inlinable_old_spelling_4.swift
+++ b/test/Compatibility/attr_inlinable_old_spelling_4.swift
@@ -5,3 +5,6 @@
 
 @_inlineable public func oldInlinableFunction() {}
 @_versioned func oldVersionedFunction() {}
+
+// No warning here
+@_inlineable @_versioned func redundantAttribute() {}
diff --git a/test/Compatibility/attr_inlinable_old_spelling_42.swift b/test/Compatibility/attr_inlinable_old_spelling_42.swift
index 0cc4c4f..c4df55a 100644
--- a/test/Compatibility/attr_inlinable_old_spelling_42.swift
+++ b/test/Compatibility/attr_inlinable_old_spelling_42.swift
@@ -7,3 +7,6 @@
 
 @_versioned func oldVersionedFunction() {}
 // expected-warning@-1 {{'@_versioned' has been renamed to '@usableFromInline'}}{{2-12=usableFromInline}}
+
+@inlinable @usableFromInline func redundantAttribute() {}
+// expected-warning@-1 {{'@inlinable' declaration is already '@usableFromInline'}}
diff --git a/test/Compatibility/attr_inlinable_typealias.swift b/test/Compatibility/attr_inlinable_typealias.swift
new file mode 100644
index 0000000..fde1daa
--- /dev/null
+++ b/test/Compatibility/attr_inlinable_typealias.swift
@@ -0,0 +1,23 @@
+// RUN: %target-typecheck-verify-swift -swift-version 4
+
+private typealias PrivateAlias = Int
+// expected-note@-1 {{type alias 'PrivateAlias' is not '@usableFromInline' or public}}
+
+internal typealias InternalAlias = Int
+// expected-note@-1 {{type alias 'InternalAlias' is not '@usableFromInline' or public}}
+
+@usableFromInline typealias UsableFromInlineAlias = Int
+
+public typealias PublicAlias = Int
+
+@inlinable public func f() {
+  _ = PrivateAlias.self
+  // expected-warning@-1 {{type alias 'PrivateAlias' is private and should not be referenced from an '@inlinable' function}}
+
+  _ = InternalAlias.self
+  // expected-warning@-1 {{type alias 'InternalAlias' is internal and should not be referenced from an '@inlinable' function}}
+
+  _ = UsableFromInlineAlias.self
+
+  _ = PublicAlias.self
+}
diff --git a/test/SIL/Serialization/Inputs/def_generic.swift b/test/SIL/Serialization/Inputs/def_generic.swift
index 44140dc..a4fc851 100644
--- a/test/SIL/Serialization/Inputs/def_generic.swift
+++ b/test/SIL/Serialization/Inputs/def_generic.swift
@@ -1,15 +1,12 @@
 @_fixed_layout
 public class A<T> {
-  typealias Element = T
-  @usableFromInline
-  @inlinable
-  func convertFromArrayLiteral(_ elements: Element...) -> A {
+  @usableFromInline typealias Element = T
+
+  @inlinable func convertFromArrayLiteral(_ elements: Element...) -> A {
     return A()
   }
 
-  @usableFromInline
-  @inlinable
-  init() {}
+  @inlinable init() {}
 
   @inlinable public subscript<U>(value: T) -> U? {
     return nil
diff --git a/test/attr/attr_inlinable.swift b/test/attr/attr_inlinable.swift
index 649a0aa..efea113 100644
--- a/test/attr/attr_inlinable.swift
+++ b/test/attr/attr_inlinable.swift
@@ -1,7 +1,7 @@
-// RUN: %target-typecheck-verify-swift -swift-version 4
-// RUN: %target-typecheck-verify-swift -swift-version 4 -enable-testing
-// RUN: %target-typecheck-verify-swift -swift-version 4 -enable-resilience
-// RUN: %target-typecheck-verify-swift -swift-version 4 -enable-resilience -enable-testing
+// RUN: %target-typecheck-verify-swift -swift-version 4.2
+// RUN: %target-typecheck-verify-swift -swift-version 4.2 -enable-testing
+// RUN: %target-typecheck-verify-swift -swift-version 4.2 -enable-resilience
+// RUN: %target-typecheck-verify-swift -swift-version 4.2 -enable-resilience -enable-testing
 @inlinable struct TestInlinableStruct {}
 // expected-error@-1 {{'@inlinable' attribute cannot be applied to this declaration}}
 
diff --git a/test/attr/attr_inlinable_typealias.swift b/test/attr/attr_inlinable_typealias.swift
index 480d280..850ad8b 100644
--- a/test/attr/attr_inlinable_typealias.swift
+++ b/test/attr/attr_inlinable_typealias.swift
@@ -1,11 +1,10 @@
-// RUN: %target-typecheck-verify-swift
-
-// None of this is enforced for now, but make sure we don't crash or
-// do anything stupid when a typealias is annotated with @usableFromInline.
+// RUN: %target-typecheck-verify-swift -swift-version 5
 
 private typealias PrivateAlias = Int
+// expected-note@-1 {{type alias 'PrivateAlias' is not '@usableFromInline' or public}}
 
 internal typealias InternalAlias = Int
+// expected-note@-1 {{type alias 'InternalAlias' is not '@usableFromInline' or public}}
 
 @usableFromInline typealias UsableFromInlineAlias = Int
 
@@ -13,8 +12,10 @@
 
 @inlinable public func f() {
   _ = PrivateAlias.self
+  // expected-error@-1 {{type alias 'PrivateAlias' is private and cannot be referenced from an '@inlinable' function}}
 
   _ = InternalAlias.self
+  // expected-error@-1 {{type alias 'InternalAlias' is internal and cannot be referenced from an '@inlinable' function}}
 
   _ = UsableFromInlineAlias.self
 
diff --git a/validation-test/Serialization/Inputs/bridging-header-first/AmbivalentProtocol.h b/validation-test/Serialization/Inputs/bridging-header-first/AmbivalentProtocol.h
new file mode 100644
index 0000000..230d8c9
--- /dev/null
+++ b/validation-test/Serialization/Inputs/bridging-header-first/AmbivalentProtocol.h
@@ -0,0 +1,2 @@
+@protocol AmbivalentProtocol
+@end
diff --git a/validation-test/Serialization/Inputs/bridging-header-first/Module/modular.h b/validation-test/Serialization/Inputs/bridging-header-first/Module/modular.h
new file mode 100644
index 0000000..3c52813
--- /dev/null
+++ b/validation-test/Serialization/Inputs/bridging-header-first/Module/modular.h
@@ -0,0 +1 @@
+#import <AmbivalentProtocol.h>
diff --git a/validation-test/Serialization/Inputs/bridging-header-first/Module/module.modulemap b/validation-test/Serialization/Inputs/bridging-header-first/Module/module.modulemap
new file mode 100644
index 0000000..d380519
--- /dev/null
+++ b/validation-test/Serialization/Inputs/bridging-header-first/Module/module.modulemap
@@ -0,0 +1,4 @@
+module Module {
+    umbrella header "modular.h"
+    module * { export * }
+}
diff --git a/validation-test/Serialization/Inputs/bridging-header-first/bridging.h b/validation-test/Serialization/Inputs/bridging-header-first/bridging.h
new file mode 100644
index 0000000..4c894e1
--- /dev/null
+++ b/validation-test/Serialization/Inputs/bridging-header-first/bridging.h
@@ -0,0 +1 @@
+#import "AmbivalentProtocol.h"
diff --git a/validation-test/Serialization/Inputs/bridging-header-first/mangled.txt b/validation-test/Serialization/Inputs/bridging-header-first/mangled.txt
new file mode 100644
index 0000000..4fdc28b
--- /dev/null
+++ b/validation-test/Serialization/Inputs/bridging-header-first/mangled.txt
@@ -0,0 +1 @@
+$S4main1CCACycfc
diff --git a/validation-test/Serialization/bridging-header-first.swift b/validation-test/Serialization/bridging-header-first.swift
new file mode 100644
index 0000000..8465323
--- /dev/null
+++ b/validation-test/Serialization/bridging-header-first.swift
@@ -0,0 +1,32 @@
+// RUN: %empty-directory(%t)
+
+// RUN: %target-build-swift -emit-module -emit-executable %s -g -I %S/Inputs/bridging-header-first/ -import-objc-header %S/Inputs/bridging-header-first/bridging.h -o %t/main
+// RUN: llvm-bcanalyzer -dump %t/main.swiftmodule | %FileCheck -check-prefix CHECK-DUMP %s
+// RUN: %lldb-moduleimport-test %t/main -type-from-mangled %S/Inputs/bridging-header-first/mangled.txt 2>&1 | %FileCheck -check-prefix CHECK-RESOLVED-TYPE %s
+
+// RUN: %target-build-swift -emit-module -emit-executable %s -g -I %S/Inputs/bridging-header-first/ -import-objc-header %S/Inputs/bridging-header-first/bridging.h -o %t/main -whole-module-optimization
+// RUN: llvm-bcanalyzer -dump %t/main.swiftmodule | %FileCheck -check-prefix CHECK-DUMP %s
+// RUN: %lldb-moduleimport-test %t/main -type-from-mangled %S/Inputs/bridging-header-first/mangled.txt 2>&1 | %FileCheck -check-prefix CHECK-RESOLVED-TYPE %s
+
+// REQUIRES: objc_interop
+
+// CHECK-DUMP-LABEL: CONTROL_BLOCK
+// CHECK-DUMP: MODULE_NAME
+// CHECK-DUMP-SAME: 'main'
+
+// CHECK-DUMP-LABEL: INPUT_BLOCK
+// CHECK-DUMP: IMPORTED_HEADER
+// CHECK-DUMP-SAME: '{{.+}}/bridging.h'
+// CHECK-DUMP: IMPORTED_MODULE
+// CHECK-DUMP-SAME: 'Module'
+// CHECK-DUMP: IMPORTED_MODULE
+// CHECK-DUMP-SAME: 'Swift'
+
+
+// CHECK-RESOLVED-TYPE: @convention(method) (C.Type) -> () -> C
+
+import Module
+class C {}
+extension C: AmbivalentProtocol {
+  func f() {}
+}