@@ -773,6 +773,79 @@ final class ExplicitModuleBuildTests: XCTestCase {
773773 }
774774 }
775775
776+ // This is a regression test for the following scenario:
777+ // 1. The user does a clean build of their project with explicit modules
778+ // 2. The user starts a subsequent build using changed flags/environment which do not affect incremental builds (e.g. color diagnostics)
779+ // 3. That flag/environment change does affect PCM hashes returned by the clang dependency scanner.
780+ // 4. The driver determines that modules need to rebuild, sources don't need to rebuild, and verification needs to re-run.
781+ // 5. The driver decides it's safe to skip the pre-compile jobs (the module builds) because the only post-compile jobs are for verification.
782+ // 6. Verification fails because the modules with the new PCM hashes are missing.
783+ // Ideally, this should never happen. If a flag doesn't invalidate Swift compilation, it shouldn;t be impacting module hashes either. But I
784+ // think we should be resilient to this by rebuilding the modules in this scenario.
785+ //
786+ // The below test is somewhat fragile in that it will be redundant if we canonicalize away -fcolor-diagnostics in clang, but it's useful to ensure
787+ // end to end behavior does not regress again.
788+ func testExplicitModuleBuildDoesNotSkipPrecompiledModulesWhenOnlyVerificationIsInvalidated( ) throws {
789+ try withTemporaryDirectory { path in
790+ try localFileSystem. changeCurrentWorkingDirectory ( to: path)
791+ let moduleCachePath = path. appending ( component: " ModuleCache " )
792+ try localFileSystem. createDirectory ( moduleCachePath)
793+ let main = path. appending ( component: " testExplicitModuleBuildEndToEnd.swift " )
794+ try localFileSystem. writeFileContents ( main, bytes:
795+ """
796+ import C;
797+ import E;
798+ import G;
799+
800+ func foo() {
801+ funcE()
802+ }
803+ """
804+ )
805+ let outputFileMap = path. appending ( component: " output-file-map.json " )
806+ try localFileSystem. writeFileContents ( outputFileMap, bytes: ByteString ( encodingAsUTF8: """
807+ {
808+ " " : {
809+ " swift-dependencies " : " \( path. appending ( component: " main.swiftdeps " ) . nativePathString ( escaped: true ) ) "
810+ },
811+ " \( path. appending ( component: " testExplicitModuleBuildEndToEnd.swift " ) . nativePathString ( escaped: true ) ) " : {
812+ " swift-dependencies " : " \( path. appending ( component: " testExplicitModuleBuildEndToEnd.swiftdeps " ) . nativePathString ( escaped: true ) ) " ,
813+ " object " : " \( path. appending ( component: " testExplicitModuleBuildEndToEnd.o " ) . nativePathString ( escaped: true ) ) "
814+ }
815+ }
816+ """ ) )
817+
818+ let cHeadersPath : AbsolutePath =
819+ try testInputsPath. appending ( component: " ExplicitModuleBuilds " )
820+ . appending ( component: " CHeaders " )
821+ let swiftModuleInterfacesPath : AbsolutePath =
822+ try testInputsPath. appending ( component: " ExplicitModuleBuilds " )
823+ . appending ( component: " Swift " )
824+ let sdkArgumentsForTesting = ( try ? Driver . sdkArgumentsForTesting ( ) ) ?? [ ]
825+ let invocationArguments = [ " swiftc " ,
826+ " -incremental " , " -c " ,
827+ " -emit-module " ,
828+ " -enable-library-evolution " , " -emit-module-interface " , " -driver-show-incremental " , " -v " ,
829+ " -Xcc " , " -Xclang " , " -Xcc " , " -fbuiltin-headers-in-system-modules " ,
830+ " -I " , cHeadersPath. nativePathString ( escaped: true ) ,
831+ " -I " , swiftModuleInterfacesPath. nativePathString ( escaped: true ) ,
832+ " -explicit-module-build " ,
833+ " -output-file-map " , outputFileMap. nativePathString ( escaped: true ) ,
834+ " -module-cache-path " , moduleCachePath. nativePathString ( escaped: true ) ,
835+ " -working-directory " , path. nativePathString ( escaped: true ) ,
836+ main. nativePathString ( escaped: true ) ] + sdkArgumentsForTesting
837+ var driver = try Driver ( args: invocationArguments)
838+ let jobs = try driver. planBuild ( )
839+ try driver. run ( jobs: jobs)
840+ XCTAssertFalse ( driver. diagnosticEngine. hasErrors)
841+
842+ var incrementalDriver = try Driver ( args: invocationArguments + [ " -color-diagnostics " ] )
843+ let incrementalJobs = try incrementalDriver. planBuild ( )
844+ try incrementalDriver. run ( jobs: incrementalJobs)
845+ XCTAssertFalse ( incrementalDriver. diagnosticEngine. hasErrors)
846+ }
847+ }
848+
776849 /// Test generation of explicit module build jobs for dependency modules when the driver
777850 /// is invoked with -explicit-module-build, -verify-emitted-module-interface and -enable-library-evolution.
778851 func testExplicitModuleVerifyInterfaceJobs( ) throws {
0 commit comments