aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/Driver/ToolChainTest.cpp
diff options
context:
space:
mode:
authorSerge Pavlov <sepavloff@gmail.com>2022-10-31 12:59:15 +0700
committerSerge Pavlov <sepavloff@gmail.com>2022-10-31 15:36:41 +0700
commitfd3d7a9f8cbb5ad81fb96d92d5f7b1d51a4d4127 (patch)
tree085b3e47f468106d61b52a438fb1617156afd46f /clang/unittests/Driver/ToolChainTest.cpp
parent1af81ab4846f0d07d3ac3079f95d66779a4d9430 (diff)
downloadllvm-fd3d7a9f8cbb5ad81fb96d92d5f7b1d51a4d4127.zip
llvm-fd3d7a9f8cbb5ad81fb96d92d5f7b1d51a4d4127.tar.gz
llvm-fd3d7a9f8cbb5ad81fb96d92d5f7b1d51a4d4127.tar.bz2
Handle errors in expansion of response files
Previously an error raised during an expansion of response files (including configuration files) was ignored and only the fact of its presence was reported to the user with generic error messages. This made it difficult to analyze problems. For example, if a configuration file tried to read an inexistent file, the error message said that 'configuration file cannot be found', which is wrong and misleading. This change enhances handling errors in the expansion so that users could get more informative error messages. Differential Revision: https://reviews.llvm.org/D136090
Diffstat (limited to 'clang/unittests/Driver/ToolChainTest.cpp')
-rw-r--r--clang/unittests/Driver/ToolChainTest.cpp201
1 files changed, 201 insertions, 0 deletions
diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp
index 10b20a9..b143cd6 100644
--- a/clang/unittests/Driver/ToolChainTest.cpp
+++ b/clang/unittests/Driver/ToolChainTest.cpp
@@ -450,4 +450,205 @@ TEST(ToolChainTest, ConfigFileSearch) {
}
}
+struct FileSystemWithError : public llvm::vfs::FileSystem {
+ llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
+ return std::make_error_code(std::errc::no_such_file_or_directory);
+ }
+ llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
+ openFileForRead(const Twine &Path) override {
+ return std::make_error_code(std::errc::permission_denied);
+ }
+ llvm::vfs::directory_iterator dir_begin(const Twine &Dir,
+ std::error_code &EC) override {
+ return llvm::vfs::directory_iterator();
+ }
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+ return std::make_error_code(std::errc::permission_denied);
+ }
+ llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
+ return std::make_error_code(std::errc::permission_denied);
+ }
+};
+
+TEST(ToolChainTest, ConfigFileError) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
+ new SimpleDiagnosticConsumer());
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS(new FileSystemWithError);
+
+ Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
+ "clang LLVM compiler", FS);
+ std::unique_ptr<Compilation> C(
+ TheDriver.BuildCompilation({"/home/test/bin/clang", "--no-default-config",
+ "--config", "./root.cfg", "--version"}));
+ ASSERT_TRUE(C);
+ ASSERT_TRUE(C->containsError());
+ EXPECT_EQ(1U, Diags.getNumErrors());
+ EXPECT_STREQ("configuration file './root.cfg' cannot be opened: cannot get "
+ "absolute path",
+ DiagConsumer->Errors[0].c_str());
+}
+
+TEST(ToolChainTest, BadConfigFile) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
+ new SimpleDiagnosticConsumer());
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+ IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
+ new llvm::vfs::InMemoryFileSystem);
+
+#ifdef _WIN32
+ const char *TestRoot = "C:\\";
+#define FILENAME "C:/opt/root.cfg"
+#define DIRNAME "C:/opt"
+#else
+ const char *TestRoot = "/";
+#define FILENAME "/opt/root.cfg"
+#define DIRNAME "/opt"
+#endif
+ // UTF-16 string must be aligned on 2-byte boundary. Strings and char arrays
+ // do not provide necessary alignment, so copy constant string into properly
+ // allocated memory in heap.
+ llvm::BumpPtrAllocator Alloc;
+ char *StrBuff = (char *)Alloc.Allocate(16, 4);
+ std::memset(StrBuff, 0, 16);
+ std::memcpy(StrBuff, "\xFF\xFE\x00\xD8\x00\x00", 6);
+ StringRef BadUTF(StrBuff, 6);
+ FS->setCurrentWorkingDirectory(TestRoot);
+ FS->addFile("/opt/root.cfg", 0, llvm::MemoryBuffer::getMemBuffer(BadUTF));
+ FS->addFile("/home/user/test.cfg", 0,
+ llvm::MemoryBuffer::getMemBuffer("@file.rsp"));
+
+ {
+ Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
+ "clang LLVM compiler", FS);
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
+ {"/home/test/bin/clang", "--config", "/opt/root.cfg", "--version"}));
+ ASSERT_TRUE(C);
+ ASSERT_TRUE(C->containsError());
+ EXPECT_EQ(1U, DiagConsumer->Errors.size());
+ EXPECT_STREQ("cannot read configuration file '" FILENAME
+ "': Could not convert UTF16 to UTF8",
+ DiagConsumer->Errors[0].c_str());
+ }
+ DiagConsumer->clear();
+ {
+ Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
+ "clang LLVM compiler", FS);
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
+ {"/home/test/bin/clang", "--config", "/opt", "--version"}));
+ ASSERT_TRUE(C);
+ ASSERT_TRUE(C->containsError());
+ EXPECT_EQ(1U, DiagConsumer->Errors.size());
+ EXPECT_STREQ("configuration file '" DIRNAME
+ "' cannot be opened: not a regular file",
+ DiagConsumer->Errors[0].c_str());
+ }
+ DiagConsumer->clear();
+ {
+ Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
+ "clang LLVM compiler", FS);
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
+ {"/home/test/bin/clang", "--config", "root",
+ "--config-system-dir=", "--config-user-dir=", "--version"}));
+ ASSERT_TRUE(C);
+ ASSERT_TRUE(C->containsError());
+ EXPECT_EQ(1U, DiagConsumer->Errors.size());
+ EXPECT_STREQ("configuration file 'root' cannot be found",
+ DiagConsumer->Errors[0].c_str());
+ }
+
+#undef FILENAME
+#undef DIRNAME
+}
+
+TEST(ToolChainTest, ConfigInexistentInclude) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
+ new SimpleDiagnosticConsumer());
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+ IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
+ new llvm::vfs::InMemoryFileSystem);
+
+#ifdef _WIN32
+ const char *TestRoot = "C:\\";
+#define USERCONFIG "C:\\home\\user\\test.cfg"
+#define UNEXISTENT "C:\\home\\user\\file.rsp"
+#else
+ const char *TestRoot = "/";
+#define USERCONFIG "/home/user/test.cfg"
+#define UNEXISTENT "/home/user/file.rsp"
+#endif
+ FS->setCurrentWorkingDirectory(TestRoot);
+ FS->addFile("/home/user/test.cfg", 0,
+ llvm::MemoryBuffer::getMemBuffer("@file.rsp"));
+
+ {
+ Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
+ "clang LLVM compiler", FS);
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
+ {"/home/test/bin/clang", "--config", "test.cfg",
+ "--config-system-dir=", "--config-user-dir=/home/user", "--version"}));
+ ASSERT_TRUE(C);
+ ASSERT_TRUE(C->containsError());
+ EXPECT_EQ(1U, DiagConsumer->Errors.size());
+ EXPECT_STREQ("cannot read configuration file '" USERCONFIG
+ "': cannot not open file '" UNEXISTENT "'",
+ DiagConsumer->Errors[0].c_str());
+ }
+
+#undef USERCONFIG
+#undef UNEXISTENT
+}
+
+TEST(ToolChainTest, ConfigRecursiveInclude) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
+ new SimpleDiagnosticConsumer());
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+ IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
+ new llvm::vfs::InMemoryFileSystem);
+
+#ifdef _WIN32
+ const char *TestRoot = "C:\\";
+#define USERCONFIG "C:\\home\\user\\test.cfg"
+#define INCLUDED1 "C:\\home\\user\\file1.cfg"
+#else
+ const char *TestRoot = "/";
+#define USERCONFIG "/home/user/test.cfg"
+#define INCLUDED1 "/home/user/file1.cfg"
+#endif
+ FS->setCurrentWorkingDirectory(TestRoot);
+ FS->addFile("/home/user/test.cfg", 0,
+ llvm::MemoryBuffer::getMemBuffer("@file1.cfg"));
+ FS->addFile("/home/user/file1.cfg", 0,
+ llvm::MemoryBuffer::getMemBuffer("@file2.cfg"));
+ FS->addFile("/home/user/file2.cfg", 0,
+ llvm::MemoryBuffer::getMemBuffer("@file3.cfg"));
+ FS->addFile("/home/user/file3.cfg", 0,
+ llvm::MemoryBuffer::getMemBuffer("@file1.cfg"));
+
+ {
+ Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
+ "clang LLVM compiler", FS);
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
+ {"/home/test/bin/clang", "--config", "test.cfg",
+ "--config-system-dir=", "--config-user-dir=/home/user", "--version"}));
+ ASSERT_TRUE(C);
+ ASSERT_TRUE(C->containsError());
+ EXPECT_EQ(1U, DiagConsumer->Errors.size());
+ EXPECT_STREQ("cannot read configuration file '" USERCONFIG
+ "': recursive expansion of: '" INCLUDED1 "'",
+ DiagConsumer->Errors[0].c_str());
+ }
+
+#undef USERCONFIG
+#undef INCLUDED1
+}
+
} // end anonymous namespace.