From de424d99f3889bb7543b7a5fe1f5007cb3e3b884 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Wed, 5 Apr 2023 11:50:11 -0700 Subject: [PATCH 1/9] Basics: add a stub for centralized configurations for block list --- include/swift/AST/ASTContext.h | 3 ++ include/swift/Basic/BlockList.h | 50 +++++++++++++++++++++++++++++++++ lib/Basic/BlockList.cpp | 41 +++++++++++++++++++++++++++ lib/Basic/CMakeLists.txt | 1 + 4 files changed, 95 insertions(+) create mode 100644 include/swift/Basic/BlockList.h create mode 100644 lib/Basic/BlockList.cpp diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 7d5b910b66d6f..2f95b602abe6d 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -30,6 +30,7 @@ #include "swift/Basic/LangOptions.h" #include "swift/Basic/Located.h" #include "swift/Basic/Malloc.h" +#include "swift/Basic/BlockList.h" #include "swift/SymbolGraphGen/SymbolGraphOptions.h" #include "clang/AST/DeclTemplate.h" #include "llvm/ADT/ArrayRef.h" @@ -360,6 +361,8 @@ class ASTContext final { /// The Swift module currently being compiled. ModuleDecl *MainModule = nullptr; + /// The block list where we can find special actions based on module name; + BlockListStore blockListConfig; private: /// The current generation number, which reflects the number of /// times that external modules have been loaded. diff --git a/include/swift/Basic/BlockList.h b/include/swift/Basic/BlockList.h new file mode 100644 index 0000000000000..ed08688f444c5 --- /dev/null +++ b/include/swift/Basic/BlockList.h @@ -0,0 +1,50 @@ +//===--- BlockList.h ---------------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 some miscellaneous overloads of hash_value() and +// simple_display(). +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_BASIC_BLOCKLIST_H +#define SWIFT_BASIC_BLOCKLIST_H + +#include "swift/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace swift { + +enum class BlockListAction : uint8_t { + ShouldUseBinaryModule = 0, + ShouldUseTextualModule, +}; + +enum class BlockListKeyKind: uint8_t { + ModuleName, + ProjectName +}; + +class BlockListStore { +public: + struct Implementation; + bool hasBlockListAction(StringRef key, BlockListKeyKind keyKind, + BlockListAction action); + void addConfigureFilePath(StringRef path); + BlockListStore(); + ~BlockListStore(); +private: + Implementation &Impl; +}; + +} // namespace swift + +#endif // SWIFT_BASIC_BLOCKLIST_H diff --git a/lib/Basic/BlockList.cpp b/lib/Basic/BlockList.cpp new file mode 100644 index 0000000000000..a085e95136fd4 --- /dev/null +++ b/lib/Basic/BlockList.cpp @@ -0,0 +1,41 @@ +//===--- BlockList.cpp - BlockList utilities ------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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/BlockList.h" + +struct swift::BlockListStore::Implementation { + void addConfigureFilePath(StringRef path); + bool hasBlockListAction(StringRef key, BlockListKeyKind keyKind, + BlockListAction action); +}; + +swift::BlockListStore::BlockListStore(): Impl(*new Implementation()) {} + +swift::BlockListStore::~BlockListStore() { delete &Impl; } + +bool swift::BlockListStore::hasBlockListAction(StringRef key, + BlockListKeyKind keyKind, BlockListAction action) { + return Impl.hasBlockListAction(key, keyKind, action); +} + +void swift::BlockListStore::addConfigureFilePath(StringRef path) { + Impl.addConfigureFilePath(path); +} + +bool swift::BlockListStore::Implementation::hasBlockListAction(StringRef key, + BlockListKeyKind keyKind, BlockListAction action) { + return false; +} + +void swift::BlockListStore::Implementation::addConfigureFilePath(StringRef path) { + +} diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 2d4fe91f0ceeb..77e23450fbee6 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -78,6 +78,7 @@ add_swift_host_library(swiftBasic STATIC Unicode.cpp UUID.cpp Version.cpp + BlockList.cpp ${llvm_revision_inc} ${clang_revision_inc} From 382ff2ae732dcbd62f228a0134c446205b54e40d Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Wed, 5 Apr 2023 12:20:49 -0700 Subject: [PATCH 2/9] Frontend: add a frontend argument to pass down block list config file path --- include/swift/Basic/LangOptions.h | 3 +++ include/swift/Option/FrontendOptions.td | 3 +++ lib/AST/ASTContext.cpp | 4 ++++ lib/Frontend/CompilerInvocation.cpp | 3 +++ 4 files changed, 13 insertions(+) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 918112ea30753..a1db5170e74de 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -566,6 +566,9 @@ namespace swift { /// The model of concurrency to be used. ConcurrencyModel ActiveConcurrencyModel = ConcurrencyModel::Standard; + /// All block list configuration files to be honored in this compilation. + std::vector BlocklistConfigFilePath; + bool isConcurrencyModelTaskToThread() const { return ActiveConcurrencyModel == ConcurrencyModel::TaskToThread; } diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index ef7178f5ae383..25ba1cad95284 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -240,6 +240,9 @@ def Raccess_note : Separate<["-"], "Raccess-note">, def Raccess_note_EQ : Joined<["-"], "Raccess-note=">, Alias; +def block_list_file + : Separate<["-"], "blocklist-file">, MetaVarName<"">, + HelpText<"The path to a blocklist configuration file">; } // end let Flags = [FrontendOption, NoDriverOption] def debug_crash_Group : OptionGroup<"">; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 0a2b122d693b4..d764f8f892478 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -694,6 +694,10 @@ ASTContext::ASTContext( // Register any request-evaluator functions available at the AST layer. registerAccessRequestFunctions(evaluator); registerNameLookupRequestFunctions(evaluator); + // Insert all block list config paths. + for (auto path: langOpts.BlocklistConfigFilePath) { + blockListConfig.addConfigureFilePath(path); + } } ASTContext::~ASTContext() { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 5db7f2c63d38b..d1a8eb1754a68 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1211,6 +1211,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.DumpTypeWitnessSystems = Args.hasArg(OPT_dump_type_witness_systems); + for (auto A : Args.getAllArgValues(options::OPT_block_list_file)) { + Opts.BlocklistConfigFilePath.push_back(A); + } if (const Arg *A = Args.getLastArg(options::OPT_concurrency_model)) { Opts.ActiveConcurrencyModel = llvm::StringSwitch(A->getValue()) From 8f26c8f5a0a574e3062a90a144cd75fcead89c50 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Wed, 5 Apr 2023 13:44:08 -0700 Subject: [PATCH 3/9] Basics: only allow ASTContext to add block list path --- include/swift/Basic/BlockList.h | 5 +++-- lib/Basic/BlockList.cpp | 14 +++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/swift/Basic/BlockList.h b/include/swift/Basic/BlockList.h index ed08688f444c5..7719b014c2563 100644 --- a/include/swift/Basic/BlockList.h +++ b/include/swift/Basic/BlockList.h @@ -23,7 +23,7 @@ namespace swift { -enum class BlockListAction : uint8_t { +enum class BlockListAction: uint8_t { ShouldUseBinaryModule = 0, ShouldUseTextualModule, }; @@ -38,10 +38,11 @@ class BlockListStore { struct Implementation; bool hasBlockListAction(StringRef key, BlockListKeyKind keyKind, BlockListAction action); - void addConfigureFilePath(StringRef path); BlockListStore(); ~BlockListStore(); private: + friend class ASTContext; + void addConfigureFilePath(StringRef path); Implementation &Impl; }; diff --git a/lib/Basic/BlockList.cpp b/lib/Basic/BlockList.cpp index a085e95136fd4..cb8a2209645e0 100644 --- a/lib/Basic/BlockList.cpp +++ b/lib/Basic/BlockList.cpp @@ -10,9 +10,16 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/YAMLTraits.h" #include "swift/Basic/BlockList.h" +#include "swift/Basic/SourceManager.h" struct swift::BlockListStore::Implementation { + llvm::StringMap> ModuleActionDict; + llvm::StringMap> ProjectActionDict; void addConfigureFilePath(StringRef path); bool hasBlockListAction(StringRef key, BlockListKeyKind keyKind, BlockListAction action); @@ -33,7 +40,12 @@ void swift::BlockListStore::addConfigureFilePath(StringRef path) { bool swift::BlockListStore::Implementation::hasBlockListAction(StringRef key, BlockListKeyKind keyKind, BlockListAction action) { - return false; + auto *dict = keyKind == BlockListKeyKind::ModuleName ? &ModuleActionDict : + &ProjectActionDict; + auto it = dict->find(key); + if (it == dict->end()) + return false; + return llvm::is_contained(it->second, action); } void swift::BlockListStore::Implementation::addConfigureFilePath(StringRef path) { From 13efc5d49747098d6eb8c47d0e79db49b68f7fd2 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Thu, 6 Apr 2023 13:14:26 -0700 Subject: [PATCH 4/9] Basics: define a YAML-based blocklist format An example of this format is: --- actionToTakeFor: ModuleName: - moduleName1 ProjectName: - projectName1 --- include/swift/Basic/BlockList.h | 7 +- lib/Basic/BlockList.cpp | 84 ++++++++++++++++++++- unittests/Basic/BlocklistTest.cpp | 117 ++++++++++++++++++++++++++++++ unittests/Basic/CMakeLists.txt | 1 + 4 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 unittests/Basic/BlocklistTest.cpp diff --git a/include/swift/Basic/BlockList.h b/include/swift/Basic/BlockList.h index 7719b014c2563..f9093adc89d1e 100644 --- a/include/swift/Basic/BlockList.h +++ b/include/swift/Basic/BlockList.h @@ -24,11 +24,13 @@ namespace swift { enum class BlockListAction: uint8_t { - ShouldUseBinaryModule = 0, + Undefined = 0, + ShouldUseBinaryModule, ShouldUseTextualModule, }; enum class BlockListKeyKind: uint8_t { + Undefined = 0, ModuleName, ProjectName }; @@ -36,13 +38,12 @@ enum class BlockListKeyKind: uint8_t { class BlockListStore { public: struct Implementation; + void addConfigureFilePath(StringRef path); bool hasBlockListAction(StringRef key, BlockListKeyKind keyKind, BlockListAction action); BlockListStore(); ~BlockListStore(); private: - friend class ASTContext; - void addConfigureFilePath(StringRef path); Implementation &Impl; }; diff --git a/lib/Basic/BlockList.cpp b/lib/Basic/BlockList.cpp index cb8a2209645e0..d0620584e6a23 100644 --- a/lib/Basic/BlockList.cpp +++ b/lib/Basic/BlockList.cpp @@ -18,11 +18,31 @@ #include "swift/Basic/SourceManager.h" struct swift::BlockListStore::Implementation { + SourceManager SM; llvm::StringMap> ModuleActionDict; llvm::StringMap> ProjectActionDict; void addConfigureFilePath(StringRef path); bool hasBlockListAction(StringRef key, BlockListKeyKind keyKind, BlockListAction action); + void collectBlockList(llvm::yaml::Node *N, BlockListAction action); + + llvm::StringMap> *getDictToUse(BlockListKeyKind kind) { + switch (kind) { + case BlockListKeyKind::ModuleName: + return &ModuleActionDict; + case BlockListKeyKind::ProjectName: + return &ProjectActionDict; + case BlockListKeyKind::Undefined: + return nullptr; + } + } + static std::string getScalaString(llvm::yaml::Node *N) { + llvm::SmallString<64> Buffer; + if (auto *scala = dyn_cast(N)) { + return scala->getValue(Buffer).str(); + } + return std::string(); + } }; swift::BlockListStore::BlockListStore(): Impl(*new Implementation()) {} @@ -40,14 +60,74 @@ void swift::BlockListStore::addConfigureFilePath(StringRef path) { bool swift::BlockListStore::Implementation::hasBlockListAction(StringRef key, BlockListKeyKind keyKind, BlockListAction action) { - auto *dict = keyKind == BlockListKeyKind::ModuleName ? &ModuleActionDict : - &ProjectActionDict; + auto *dict = getDictToUse(keyKind); + assert(dict); auto it = dict->find(key); if (it == dict->end()) return false; return llvm::is_contained(it->second, action); } +void swift::BlockListStore::Implementation::collectBlockList(llvm::yaml::Node *N, + BlockListAction action) { + namespace yaml = llvm::yaml; + auto *pair = dyn_cast(N); + if (!pair) + return; + std::string rawKey = getScalaString(pair->getKey()); + auto keyKind = llvm::StringSwitch(rawKey) +#define CASE(X) .Case(#X, BlockListKeyKind::X) + CASE(ModuleName) + CASE(ProjectName) +#undef CASE + .Default(BlockListKeyKind::Undefined); + if (keyKind == BlockListKeyKind::Undefined) + return; + auto *dictToUse = getDictToUse(keyKind); + assert(dictToUse); + auto *seq = dyn_cast(pair->getValue()); + if (!seq) + return; + for (auto &node: *seq) { + std::string name = getScalaString(&node); + dictToUse->insert({name, std::vector()}) + .first->second.push_back(action); + } +} + void swift::BlockListStore::Implementation::addConfigureFilePath(StringRef path) { + namespace yaml = llvm::yaml; + // Load the input file. + llvm::ErrorOr> FileBufOrErr = + vfs::getFileOrSTDIN(*SM.getFileSystem(), path, + /*FileSize*/-1, /*RequiresNullTerminator*/true, + /*IsVolatile*/false, /*RetryCount*/30); + if (!FileBufOrErr) { + return; + } + StringRef Buffer = FileBufOrErr->get()->getBuffer(); + yaml::Stream Stream(llvm::MemoryBufferRef(Buffer, path), + SM.getLLVMSourceMgr()); + for (auto DI = Stream.begin(); DI != Stream.end(); ++ DI) { + assert(DI != Stream.end() && "Failed to read a document"); + yaml::Node *N = DI->getRoot(); + for (auto &pair: *dyn_cast(N)) { + std::string key = getScalaString(pair.getKey()); + auto action = llvm::StringSwitch(key) +#define CASE(X) .Case(#X, BlockListAction::X) + CASE(ShouldUseBinaryModule) + CASE(ShouldUseTextualModule) +#undef CASE + .Default(BlockListAction::Undefined); + if (action == BlockListAction::Undefined) + continue; + auto *map = dyn_cast(pair.getValue()); + if (!map) + continue; + for (auto &innerPair: *map) { + collectBlockList(&innerPair, action); + } + } + } } diff --git a/unittests/Basic/BlocklistTest.cpp b/unittests/Basic/BlocklistTest.cpp new file mode 100644 index 0000000000000..f7f9f9fcfe34a --- /dev/null +++ b/unittests/Basic/BlocklistTest.cpp @@ -0,0 +1,117 @@ +//===------- BlocklistTest.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 "gtest/gtest.h" +#include "swift/AST/SearchPathOptions.h" +#include "swift/Basic/Defer.h" +#include "swift/Basic/BlockList.h" + +using namespace swift; + +static std::string createFilename(StringRef base, StringRef name) { + SmallString<256> path = base; + llvm::sys::path::append(path, name); + return llvm::Twine(path).str(); +} + +static bool emitFileWithContents(StringRef path, StringRef contents, + std::string *pathOut = nullptr) { + int FD; + if (llvm::sys::fs::openFileForWrite(path, FD)) + return true; + if (pathOut) + *pathOut = path.str(); + llvm::raw_fd_ostream file(FD, /*shouldClose=*/true); + file << contents; + return false; +} + +static bool emitFileWithContents(StringRef base, StringRef name, + StringRef contents, + std::string *pathOut = nullptr) { + return emitFileWithContents(createFilename(base, name), contents, pathOut); +} + +TEST(BlocklistTest, testYamlParsing) { + SmallString<256> temp; + ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory( + "BlocklistTest.testYamlParsing", temp)); + SWIFT_DEFER { llvm::sys::fs::remove_directories(temp); }; + BlockListStore store; + std::string path1, path2; + ASSERT_FALSE(emitFileWithContents(temp, "block1.yaml", + "---\n" + "ShouldUseBinaryModule:\n" + " ModuleName:\n" + " - M1 #rdar12345\n" + " - M2 #rdar12345\n" + " - M3\n" + " - M4\n" + " ProjectName:\n" + " - P1\n" + " - P2\n" + " - P3 #rdar12344\n" + " - P4\n" + "---\n" + "ShouldUseTextualModule:\n" + " ModuleName:\n" + " - M1_2 #rdar12345\n" + " - M2_2 #rdar12345\n" + " - M3_2\n" + " - M4_2\n" + " ProjectName:\n" + " - P1_2\n" + " - P2_2\n" + " - P3_2 #rdar12344\n" + " - P4_2\n", + &path1)); + ASSERT_FALSE(emitFileWithContents(temp, "block2.yml", + "---\n" + "ShouldUseBinaryModule:\n" + " ModuleName:\n" + " - M1_block2 #rdar12345\n" + " ProjectName:\n" + " - P1_block2\n" + "---\n" + "ShouldUseTextualModule:\n" + " ModuleName:\n" + " - M1_2_block2 #rdar12345\n" + " ProjectName:\n" + " - P1_2_block2\n", + &path2)); + store.addConfigureFilePath(path1); + store.addConfigureFilePath(path2); + ASSERT_TRUE(store.hasBlockListAction("M1", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_TRUE(store.hasBlockListAction("M2", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_TRUE(store.hasBlockListAction("P1", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_TRUE(store.hasBlockListAction("P2", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseBinaryModule)); + + ASSERT_TRUE(store.hasBlockListAction("M1_2", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseTextualModule)); + ASSERT_TRUE(store.hasBlockListAction("M2_2", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseTextualModule)); + ASSERT_TRUE(store.hasBlockListAction("P1_2", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseTextualModule)); + ASSERT_TRUE(store.hasBlockListAction("P2_2", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseTextualModule)); + + ASSERT_FALSE(store.hasBlockListAction("P1", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_FALSE(store.hasBlockListAction("P2", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_FALSE(store.hasBlockListAction("M1", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_FALSE(store.hasBlockListAction("M2", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseBinaryModule)); + + ASSERT_TRUE(store.hasBlockListAction("M1_block2", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_TRUE(store.hasBlockListAction("P1_block2", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_TRUE(store.hasBlockListAction("M1_2_block2", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseTextualModule)); + ASSERT_TRUE(store.hasBlockListAction("P1_2_block2", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseTextualModule)); + + ASSERT_FALSE(store.hasBlockListAction("M1_block2", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_FALSE(store.hasBlockListAction("P1_block2", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseBinaryModule)); + ASSERT_FALSE(store.hasBlockListAction("M1_2_block2", BlockListKeyKind::ProjectName, BlockListAction::ShouldUseTextualModule)); + ASSERT_FALSE(store.hasBlockListAction("P1_2_block2", BlockListKeyKind::ModuleName, BlockListAction::ShouldUseTextualModule)); +} diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt index 547751e6cac8f..1f5eee1459618 100644 --- a/unittests/Basic/CMakeLists.txt +++ b/unittests/Basic/CMakeLists.txt @@ -7,6 +7,7 @@ handle_gyb_sources( add_swift_unittest(SwiftBasicTests BlotMapVectorTest.cpp + BlocklistTest.cpp CacheTest.cpp ClangImporterOptionsTest.cpp ClusteredBitVectorTest.cpp From 109586fc41f3a0ce034f8888c0a68883e0e8eb35 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Fri, 7 Apr 2023 21:26:19 -0700 Subject: [PATCH 5/9] Frontend: pass down blocklist file paths from frontend options. NFC --- include/swift/Basic/LangOptions.h | 2 +- include/swift/Frontend/FrontendOptions.h | 2 ++ lib/AST/ASTContext.cpp | 2 +- lib/Frontend/ArgsToFrontendOptionsConverter.cpp | 3 +++ lib/Frontend/CompilerInvocation.cpp | 4 +--- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index a1db5170e74de..eb134cc63433d 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -567,7 +567,7 @@ namespace swift { ConcurrencyModel ActiveConcurrencyModel = ConcurrencyModel::Standard; /// All block list configuration files to be honored in this compilation. - std::vector BlocklistConfigFilePath; + std::vector BlocklistConfigFilePaths; bool isConcurrencyModelTaskToThread() const { return ActiveConcurrencyModel == ConcurrencyModel::TaskToThread; diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 21449e8cc698f..0ae98619e8a95 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -512,6 +512,8 @@ class FrontendOptions { /// textual imports bool EmitClangHeaderWithNonModularIncludes = false; + /// All block list configuration files to be honored in this compilation. + std::vector BlocklistConfigFilePaths; private: static bool canActionEmitDependencies(ActionType); static bool canActionEmitReferenceDependencies(ActionType); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d764f8f892478..90076f328bd07 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -695,7 +695,7 @@ ASTContext::ASTContext( registerAccessRequestFunctions(evaluator); registerNameLookupRequestFunctions(evaluator); // Insert all block list config paths. - for (auto path: langOpts.BlocklistConfigFilePath) { + for (auto path: langOpts.BlocklistConfigFilePaths) { blockListConfig.addConfigureFilePath(path); } } diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 389ad9837e7cf..df4bc148ae6e7 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -350,6 +350,9 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.serializedPathObfuscator.addMapping(SplitMap.first, SplitMap.second); } Opts.emptyABIDescriptor = Args.hasArg(OPT_empty_abi_descriptor); + for (auto A : Args.getAllArgValues(options::OPT_block_list_file)) { + Opts.BlocklistConfigFilePaths.push_back(A); + } return false; } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index d1a8eb1754a68..c606ca98be9f2 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1211,9 +1211,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.DumpTypeWitnessSystems = Args.hasArg(OPT_dump_type_witness_systems); - for (auto A : Args.getAllArgValues(options::OPT_block_list_file)) { - Opts.BlocklistConfigFilePath.push_back(A); - } + Opts.BlocklistConfigFilePaths = FrontendOpts.BlocklistConfigFilePaths; if (const Arg *A = Args.getLastArg(options::OPT_concurrency_model)) { Opts.ActiveConcurrencyModel = llvm::StringSwitch(A->getValue()) From 64b201d4220153e8178cb2987e5476efdb6d8f85 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Sat, 8 Apr 2023 08:37:47 -0700 Subject: [PATCH 6/9] Basics: refactor blocklist actions to a def file. NFC --- include/swift/Basic/BlockList.h | 4 ++-- include/swift/Basic/BlockListAction.def | 25 +++++++++++++++++++++++++ lib/Basic/BlockList.cpp | 6 ++---- 3 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 include/swift/Basic/BlockListAction.def diff --git a/include/swift/Basic/BlockList.h b/include/swift/Basic/BlockList.h index f9093adc89d1e..737987e9e8037 100644 --- a/include/swift/Basic/BlockList.h +++ b/include/swift/Basic/BlockList.h @@ -25,8 +25,8 @@ namespace swift { enum class BlockListAction: uint8_t { Undefined = 0, - ShouldUseBinaryModule, - ShouldUseTextualModule, +#define BLOCKLIST_ACTION(NAME) NAME, +#include "BlockListAction.def" }; enum class BlockListKeyKind: uint8_t { diff --git a/include/swift/Basic/BlockListAction.def b/include/swift/Basic/BlockListAction.def new file mode 100644 index 0000000000000..724795c02a7ea --- /dev/null +++ b/include/swift/Basic/BlockListAction.def @@ -0,0 +1,25 @@ +//===--- BlockListAction.def - Define all blocklist actions -----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 definition file describes all block list actions for meta-programming +// purposes. +// +//===----------------------------------------------------------------------===// + +#ifndef BLOCKLIST_ACTION +#define BLOCKLIST_ACTION(NAME) +#endif + +BLOCKLIST_ACTION(ShouldUseBinaryModule) +BLOCKLIST_ACTION(ShouldUseTextualModule) + +#undef BLOCKLIST_ACTION diff --git a/lib/Basic/BlockList.cpp b/lib/Basic/BlockList.cpp index d0620584e6a23..7ee2f69508e3a 100644 --- a/lib/Basic/BlockList.cpp +++ b/lib/Basic/BlockList.cpp @@ -115,10 +115,8 @@ void swift::BlockListStore::Implementation::addConfigureFilePath(StringRef path) for (auto &pair: *dyn_cast(N)) { std::string key = getScalaString(pair.getKey()); auto action = llvm::StringSwitch(key) -#define CASE(X) .Case(#X, BlockListAction::X) - CASE(ShouldUseBinaryModule) - CASE(ShouldUseTextualModule) -#undef CASE +#define BLOCKLIST_ACTION(X) .Case(#X, BlockListAction::X) +#include "swift/Basic/BlockListAction.def" .Default(BlockListAction::Undefined); if (action == BlockListAction::Undefined) continue; From 606476f33ce65cbbde987fc2c0162ee249f249a5 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Sat, 8 Apr 2023 22:11:11 -0700 Subject: [PATCH 7/9] ModuleInterface: add a block list action to downgrade module interface verification errors to warnings --- include/swift/Basic/BlockListAction.def | 1 + lib/Frontend/ModuleInterfaceBuilder.cpp | 11 ++++++++++- test/ModuleInterface/blocklist_action.swift | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/ModuleInterface/blocklist_action.swift diff --git a/include/swift/Basic/BlockListAction.def b/include/swift/Basic/BlockListAction.def index 724795c02a7ea..316de256e8b10 100644 --- a/include/swift/Basic/BlockListAction.def +++ b/include/swift/Basic/BlockListAction.def @@ -21,5 +21,6 @@ BLOCKLIST_ACTION(ShouldUseBinaryModule) BLOCKLIST_ACTION(ShouldUseTextualModule) +BLOCKLIST_ACTION(DowngradeInterfaceVerificationFailure) #undef BLOCKLIST_ACTION diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index a898ae822d6ca..c00ebb8693bfe 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -180,6 +180,14 @@ bool ExplicitModuleInterfaceBuilder::collectDepsForSerialization( return false; } +static bool shouldDowngradeInterfaceVerificationError(const FrontendOptions &opts, + ASTContext &ctx) { + return opts.DowngradeInterfaceVerificationError || + ctx.blockListConfig.hasBlockListAction(opts.ModuleName, + BlockListKeyKind::ModuleName, + BlockListAction::DowngradeInterfaceVerificationFailure); +} + std::error_code ExplicitModuleInterfaceBuilder::buildSwiftModuleFromInterface( StringRef InterfacePath, StringRef OutputPath, bool ShouldSerializeDeps, std::unique_ptr *ModuleBuffer, @@ -206,7 +214,8 @@ std::error_code ExplicitModuleInterfaceBuilder::buildSwiftModuleFromInterface( << " to " << OutputPath << "\n"); LLVM_DEBUG(llvm::dbgs() << "Performing sema\n"); - if (isTypeChecking && FEOpts.DowngradeInterfaceVerificationError) { + if (isTypeChecking && + shouldDowngradeInterfaceVerificationError(FEOpts, Instance.getASTContext())) { ErrorDowngradeConsumerRAII R(Instance.getDiags()); Instance.performSema(); return std::error_code(); diff --git a/test/ModuleInterface/blocklist_action.swift b/test/ModuleInterface/blocklist_action.swift new file mode 100644 index 0000000000000..5014dd774f1bc --- /dev/null +++ b/test/ModuleInterface/blocklist_action.swift @@ -0,0 +1,21 @@ +// REQUIRES: objc_interop +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule -emit-module-interface-path %t/Test.swiftinterface -module-name Test %s +// RUN: %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface) -module-name Test + +// RUN: echo "<<<<<>>>>>>>>" >> %t/Test.swiftinterface +// RUN: not %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface) -module-name Test + +// RUN: echo "---" > %t/blocklist.yml +// RUN: echo "DowngradeInterfaceVerificationFailure:" >> %t/blocklist.yml +// RUN: echo " ModuleName:" >> %t/blocklist.yml +// RUN: echo " - FooBar" >> %t/blocklist.yml + +// RUN: not %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface) -module-name Test -blocklist-file %t/blocklist.yml + +// RUN: echo " - Test" >> %t/blocklist.yml + +// RUN: %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface) -module-name Test -downgrade-typecheck-interface-error +// RUN: %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface) -module-name Test -blocklist-file %t/blocklist.yml + +public func foo() {} From 5dd92d6ab8ca6d5c215426099e629b4d82ef763f Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 11 Apr 2023 12:09:55 -0700 Subject: [PATCH 8/9] Frontend: infer default blocklists to use when the explicit paths aren't given by swift-driver Although swift-driver always passes down these blocklist for the compiler to consume, some frontend tools, like ABI checker, are invoked by the build system directly. Therefore, we need to teach the compiler to infer these blocklist files like prebuilt module cache. --- include/swift/Frontend/Frontend.h | 3 +++ lib/Frontend/CompilerInvocation.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 04d85157cc19e..2a3dc394abae5 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -232,6 +232,9 @@ class CompilerInvocation { /// options have been parsed. void setDefaultPrebuiltCacheIfNecessary(); + /// If we haven't explicitly passed -blocklist-paths, set it to the default value. + void setDefaultBlocklistsIfNecessary(); + /// Computes the runtime resource path relative to the given Swift /// executable. static void computeRuntimeResourcePathFromExecutablePath( diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c606ca98be9f2..859be1b929522 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -159,6 +159,31 @@ void CompilerInvocation::setDefaultPrebuiltCacheIfNecessary() { (llvm::Twine(pair.first) + "preferred-interfaces" + pair.second).str(); } +void CompilerInvocation::setDefaultBlocklistsIfNecessary() { + if (!LangOpts.BlocklistConfigFilePaths.empty()) + return; + if (SearchPathOpts.RuntimeResourcePath.empty()) + return; + // XcodeDefault.xctoolchain/usr/lib/swift + SmallString<64> blocklistDir{SearchPathOpts.RuntimeResourcePath}; + // XcodeDefault.xctoolchain/usr/lib + llvm::sys::path::remove_filename(blocklistDir); + // XcodeDefault.xctoolchain/usr + llvm::sys::path::remove_filename(blocklistDir); + // XcodeDefault.xctoolchain/usr/local/lib/swift/blocklists + llvm::sys::path::append(blocklistDir, "local", "lib", "swift", "blocklists"); + std::error_code EC; + if (llvm::sys::fs::is_directory(blocklistDir)) { + for (llvm::sys::fs::directory_iterator F(blocklistDir, EC), FE; + F != FE; F.increment(EC)) { + StringRef ext = llvm::sys::path::extension(F->path()); + if (ext == "yml" || ext == "yaml") { + LangOpts.BlocklistConfigFilePaths.push_back(F->path()); + } + } + } +} + static void updateRuntimeLibraryPaths(SearchPathOptions &SearchPathOpts, llvm::Triple &Triple) { llvm::SmallString<128> LibPath(SearchPathOpts.RuntimeResourcePath); @@ -2934,6 +2959,7 @@ bool CompilerInvocation::parseArgs( updateRuntimeLibraryPaths(SearchPathOpts, LangOpts.Target); setDefaultPrebuiltCacheIfNecessary(); + setDefaultBlocklistsIfNecessary(); // Now that we've parsed everything, setup some inter-option-dependent state. setIRGenOutputOptsFromFrontendOptions(IRGenOpts, FrontendOpts); From b19c45fc85564d0e3673331496bfdd6e2f9be337 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Sat, 8 Apr 2023 16:11:07 -0700 Subject: [PATCH 9/9] ModuleInterface: pass down block list file paths to module interface building context and command lines --- lib/Frontend/CompilerInvocation.cpp | 3 ++- lib/Frontend/ModuleInterfaceLoader.cpp | 7 ++++++ .../blocklist-path-pass-down.swift | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/ScanDependencies/blocklist-path-pass-down.swift diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 859be1b929522..8728acd97f539 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1236,7 +1236,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.DumpTypeWitnessSystems = Args.hasArg(OPT_dump_type_witness_systems); - Opts.BlocklistConfigFilePaths = FrontendOpts.BlocklistConfigFilePaths; + for (auto &block: FrontendOpts.BlocklistConfigFilePaths) + Opts.BlocklistConfigFilePaths.push_back(block); if (const Arg *A = Args.getLastArg(options::OPT_concurrency_model)) { Opts.ActiveConcurrencyModel = llvm::StringSwitch(A->getValue()) diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index d90388db17c6d..290e3bbc5dfe0 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1723,6 +1723,13 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( // module cache path at this point. if (buildModuleCacheDirIfAbsent && !moduleCachePath.empty()) (void)llvm::sys::fs::create_directories(moduleCachePath); + + // Inherit all block list configuration files + frontendOpts.BlocklistConfigFilePaths = langOpts.BlocklistConfigFilePaths; + for (auto &blocklist: langOpts.BlocklistConfigFilePaths) { + GenericArgs.push_back("-blocklist-file"); + GenericArgs.push_back(blocklist); + } } /// Calculate an output filename in \p genericSubInvocation's cache path that diff --git a/test/ScanDependencies/blocklist-path-pass-down.swift b/test/ScanDependencies/blocklist-path-pass-down.swift new file mode 100644 index 0000000000000..6387ba5c2c8c5 --- /dev/null +++ b/test/ScanDependencies/blocklist-path-pass-down.swift @@ -0,0 +1,23 @@ +// REQUIRES: objc_interop +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/Frameworks +// RUN: mkdir -p %t/Frameworks/E.framework/ +// RUN: mkdir -p %t/Frameworks/E.framework/Modules +// RUN: mkdir -p %t/Frameworks/E.framework/Modules/E.swiftmodule + +// RUN: echo "---" > %t/blocklist.yml +// RUN: echo "action:" >> %t/blocklist.yml + +// Copy over the interface +// RUN: cp %S/Inputs/Swift/E.swiftinterface %t/Frameworks/E.framework/Modules/E.swiftmodule/%module-target-triple.swiftinterface + + +// Run the scan +// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -F %t/Frameworks/ -sdk %t -blocklist-file %t/blocklist.yml +// RUN: %FileCheck %s < %t/deps.json + +import E + +// CHECK: "-blocklist-file" +// CHECK-NEXT: {{.*}}blocklist.yml"