@@ -264,6 +264,11 @@ SerializedDiagPath("serialize-diagnostics-path",
264264 llvm::cl::desc (" Serialize diagnostics to a path" ),
265265 llvm::cl::cat(Category));
266266
267+ static llvm::cl::opt<std::string>
268+ BreakageAllowlistPath (" breakage-allowlist-path" ,
269+ llvm::cl::desc (" An allowlist of breakages to not complain about" ),
270+ llvm::cl::cat(Category));
271+
267272} // namespace options
268273
269274namespace {
@@ -2320,6 +2325,50 @@ createDiagConsumer(llvm::raw_ostream &OS, bool &FailOnError) {
23202325 }
23212326}
23222327
2328+ static int readFileLineByLine (StringRef Path, llvm::StringSet<> &Lines) {
2329+ auto FileBufOrErr = llvm::MemoryBuffer::getFile (Path);
2330+ if (!FileBufOrErr) {
2331+ llvm::errs () << " error opening file '" << Path << " ': "
2332+ << FileBufOrErr.getError ().message () << ' \n ' ;
2333+ return 1 ;
2334+ }
2335+
2336+ StringRef BufferText = FileBufOrErr.get ()->getBuffer ();
2337+ while (!BufferText.empty ()) {
2338+ StringRef Line;
2339+ std::tie (Line, BufferText) = BufferText.split (' \n ' );
2340+ Line = Line.trim ();
2341+ if (Line.empty ())
2342+ continue ;
2343+ if (Line.startswith (" // " )) // comment.
2344+ continue ;
2345+ Lines.insert (Line);
2346+ }
2347+ return 0 ;
2348+ }
2349+
2350+ static bool readBreakageAllowlist (SDKContext &Ctx, llvm::StringSet<> &lines) {
2351+ if (options::BreakageAllowlistPath.empty ())
2352+ return 0 ;
2353+ CompilerInstance instance;
2354+ CompilerInvocation invok;
2355+ invok.setModuleName (" ForClangImporter" );
2356+ if (instance.setup (invok))
2357+ return 1 ;
2358+ ClangImporterOptions impOpts;
2359+ auto importer = ClangImporter::create (instance.getASTContext (), impOpts);
2360+ SmallString<128 > preprocessedFilePath;
2361+ if (auto error = llvm::sys::fs::createTemporaryFile (
2362+ " breakage-allowlist-" , " txt" , preprocessedFilePath)) {
2363+ return 1 ;
2364+ }
2365+ if (importer->runPreprocessor (options::BreakageAllowlistPath,
2366+ preprocessedFilePath.str ())) {
2367+ return 1 ;
2368+ }
2369+ return readFileLineByLine (preprocessedFilePath, lines);
2370+ }
2371+
23232372static int diagnoseModuleChange (SDKContext &Ctx, SDKNodeRoot *LeftModule,
23242373 SDKNodeRoot *RightModule, StringRef OutputPath,
23252374 llvm::StringSet<> ProtocolReqAllowlist) {
@@ -2337,9 +2386,14 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule,
23372386 OS = FileOS.get ();
23382387 }
23392388 bool FailOnError;
2340- std::unique_ptr<DiagnosticConsumer> pConsumer =
2341- createDiagConsumer (*OS, FailOnError);
2342-
2389+ auto allowedBreakages = std::make_unique<llvm::StringSet<>>();
2390+ if (readBreakageAllowlist (Ctx, *allowedBreakages)) {
2391+ Ctx.getDiags ().diagnose (SourceLoc (), diag::cannot_read_allowlist,
2392+ options::BreakageAllowlistPath);
2393+ }
2394+ auto pConsumer = std::make_unique<FilteringDiagnosticConsumer>(
2395+ createDiagConsumer (*OS, FailOnError), std::move (allowedBreakages));
2396+ SWIFT_DEFER { pConsumer->finishProcessing (); };
23432397 Ctx.addDiagConsumer (*pConsumer);
23442398 Ctx.setCommonVersion (std::min (LeftModule->getJsonFormatVersion (),
23452399 RightModule->getJsonFormatVersion ()));
@@ -2352,7 +2406,7 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule,
23522406 // Find member hoist changes to help refine diagnostics.
23532407 findTypeMemberDiffs (LeftModule, RightModule, Ctx.getTypeMemberDiffs ());
23542408 DiagnosisEmitter::diagnosis (LeftModule, RightModule, Ctx);
2355- return FailOnError && Ctx. getDiags (). hadAnyError () ? 1 : 0 ;
2409+ return FailOnError && pConsumer-> hasError () ? 1 : 0 ;
23562410}
23572411
23582412static int diagnoseModuleChange (StringRef LeftPath, StringRef RightPath,
@@ -2493,28 +2547,6 @@ static int generateMigrationScript(StringRef LeftPath, StringRef RightPath,
24932547 return 0 ;
24942548}
24952549
2496- static int readFileLineByLine (StringRef Path, llvm::StringSet<> &Lines) {
2497- auto FileBufOrErr = llvm::MemoryBuffer::getFile (Path);
2498- if (!FileBufOrErr) {
2499- llvm::errs () << " error opening file '" << Path << " ': "
2500- << FileBufOrErr.getError ().message () << ' \n ' ;
2501- return 1 ;
2502- }
2503-
2504- StringRef BufferText = FileBufOrErr.get ()->getBuffer ();
2505- while (!BufferText.empty ()) {
2506- StringRef Line;
2507- std::tie (Line, BufferText) = BufferText.split (' \n ' );
2508- Line = Line.trim ();
2509- if (Line.empty ())
2510- continue ;
2511- if (Line.startswith (" // " )) // comment.
2512- continue ;
2513- Lines.insert (Line);
2514- }
2515- return 0 ;
2516- }
2517-
25182550// This function isn't referenced outside its translation unit, but it
25192551// can't use the "static" keyword because its address is used for
25202552// getMainExecutable (since some platforms don't support taking the
0 commit comments