From a88f0122e3a745970fd9f747c7ddc049dfd81da8 Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Fri, 20 Jun 2014 22:59:50 +0000 Subject: [PATCH] Driver: In crashdumps with -fmodule, dump the module dependencies llvm-svn: 211421 --- clang/lib/Driver/Driver.cpp | 7 ++- clang/lib/Driver/Tools.cpp | 57 +++++++++++++++++------- clang/test/Driver/Inputs/module/module.modulemap | 4 ++ clang/test/Driver/Inputs/module/simple.h | 1 + clang/test/Driver/crash-report-modules.m | 30 +++++++++++++ clang/test/Driver/crash-report.c | 2 - 6 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 clang/test/Driver/Inputs/module/module.modulemap create mode 100644 clang/test/Driver/Inputs/module/simple.h create mode 100644 clang/test/Driver/crash-report-modules.m diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 3740c5a..4698999 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -519,9 +519,14 @@ void Driver::generateCompilationDiagnostics(Compilation &C, for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end(); it != ie; ++it) { Diag(clang::diag::note_drv_command_failed_diag_msg) << *it; + std::string Script = StringRef(*it).rsplit('.').first; + // In some cases (modules) we'll dump extra data to help with reproducing + // the crash into a directory next to the output. + if (llvm::sys::fs::exists(Script + ".cache")) + Diag(clang::diag::note_drv_command_failed_diag_msg) + << Script + ".cache"; std::string Err; - std::string Script = StringRef(*it).rsplit('.').first; Script += ".sh"; llvm::raw_fd_ostream ScriptOS(Script.c_str(), Err, llvm::sys::fs::F_Excl); if (!Err.empty()) { diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 6117364..de03ce6 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -2327,8 +2327,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - // The make clang go fast button. - CmdArgs.push_back("-disable-free"); + // We normally speed up the clang process a bit by skipping destructors at + // exit, but when we're generating diagnostics we can rely on some of the + // cleanup. + if (!C.isForDiagnostics()) + CmdArgs.push_back("-disable-free"); // Disable the verification pass in -asserts builds. #ifdef NDEBUG @@ -3574,21 +3577,37 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fmodule_map_file)) A->render(Args, CmdArgs); - // If a module path was provided, pass it along. Otherwise, use a temporary - // directory. - if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) { - if (HaveModules) - A->render(Args, CmdArgs); - } else if (HaveModules) { - SmallString<128> DefaultModuleCache; - llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, - DefaultModuleCache); - llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang"); - llvm::sys::path::append(DefaultModuleCache, "ModuleCache"); + // -fmodule-cache-path specifies where our module files should be written. + SmallString<128> ModuleCachePath; + if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) + ModuleCachePath = A->getValue(); + if (HaveModules) { + if (C.isForDiagnostics()) { + // When generating crash reports, we want to emit the modules along with + // the reproduction sources, so we ignore any provided module path. + ModuleCachePath = Output.getFilename(); + llvm::sys::path::replace_extension(ModuleCachePath, ".cache"); + llvm::sys::path::append(ModuleCachePath, "modules"); + } else if (ModuleCachePath.empty()) { + // No module path was provided: use the default. + llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, + ModuleCachePath); + llvm::sys::path::append(ModuleCachePath, "org.llvm.clang"); + llvm::sys::path::append(ModuleCachePath, "ModuleCache"); + } const char Arg[] = "-fmodules-cache-path="; - DefaultModuleCache.insert(DefaultModuleCache.begin(), - Arg, Arg + strlen(Arg)); - CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache)); + ModuleCachePath.insert(ModuleCachePath.begin(), Arg, Arg + strlen(Arg)); + CmdArgs.push_back(Args.MakeArgString(ModuleCachePath)); + } + + // When building modules and generating crashdumps, we need to dump a module + // dependency VFS alongside the output. + if (HaveModules && C.isForDiagnostics()) { + SmallString<128> VFSDir(Output.getFilename()); + llvm::sys::path::replace_extension(VFSDir, ".cache"); + llvm::sys::path::append(VFSDir, "vfs"); + CmdArgs.push_back("-module-dependency-dir"); + CmdArgs.push_back(Args.MakeArgString(VFSDir)); } if (Arg *A = Args.getLastArg(options::OPT_fmodules_user_build_path)) @@ -4033,9 +4052,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } #endif + // Enable rewrite includes if the user's asked for it or if we're generating + // diagnostics. + // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be + // nice to enable this when doing a crashdump for modules as well. if (Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) || - C.isForDiagnostics()) + (C.isForDiagnostics() && !HaveModules)) CmdArgs.push_back("-frewrite-includes"); // Only allow -traditional or -traditional-cpp outside in preprocessing modes. diff --git a/clang/test/Driver/Inputs/module/module.modulemap b/clang/test/Driver/Inputs/module/module.modulemap new file mode 100644 index 0000000..4fddd4b --- /dev/null +++ b/clang/test/Driver/Inputs/module/module.modulemap @@ -0,0 +1,4 @@ +module simple { + header "simple.h" + export * +} diff --git a/clang/test/Driver/Inputs/module/simple.h b/clang/test/Driver/Inputs/module/simple.h new file mode 100644 index 0000000..afd674e --- /dev/null +++ b/clang/test/Driver/Inputs/module/simple.h @@ -0,0 +1 @@ +#define MODULE_MACRO 10 diff --git a/clang/test/Driver/crash-report-modules.m b/clang/test/Driver/crash-report-modules.m new file mode 100644 index 0000000..4487a340 --- /dev/null +++ b/clang/test/Driver/crash-report-modules.m @@ -0,0 +1,30 @@ +// RUN: rm -rf %t +// RUN: mkdir %t + +// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH= TMPDIR=%t TEMP=%t TMP=%t \ +// RUN: %clang -fsyntax-only %s -I %S/Inputs/module \ +// RUN: -fmodules -fmodules-cache-path=/tmp/ -DFOO=BAR 2>&1 | FileCheck %s + +// RUN: FileCheck --check-prefix=CHECKSRC %s -input-file %t/crash-report-*.mi +// RUN: FileCheck --check-prefix=CHECKSH %s -input-file %t/crash-report-*.sh +// REQUIRES: crash-recovery + +// because of the glob (*.mi, *.sh) +// REQUIRES: shell + +// FIXME: This XFAIL is cargo-culted from crash-report.c. Do we need it? +// XFAIL: mingw32 + +@import simple; +const int x = MODULE_MACRO; + +// CHECK: Preprocessed source(s) and associated run script(s) are located at: +// CHECK-NEXT: note: diagnostic msg: {{.*}}.mi +// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache + +// CHECKSRC: @import simple; +// CHECKSRC: const int x = 10; + +// CHECKSH: -cc1 +// CHECKSH: -D "FOO=BAR" +// CHECKSH-NOT: -fmodules-cache-path=/tmp/ diff --git a/clang/test/Driver/crash-report.c b/clang/test/Driver/crash-report.c index c9e7866..5a414e4 100644 --- a/clang/test/Driver/crash-report.c +++ b/clang/test/Driver/crash-report.c @@ -3,7 +3,6 @@ // RUN: not env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 %clang -fsyntax-only %s \ // RUN: -F/tmp/ -I /tmp/ -idirafter /tmp/ -iquote /tmp/ -isystem /tmp/ \ // RUN: -iprefix /the/prefix -iwithprefix /tmp -iwithprefixbefore /tmp/ \ -// RUN: -fmodules -fcxx-modules -fmodules-cache-path=/tmp/ \ // RUN: -Xclang -internal-isystem -Xclang /tmp/ \ // RUN: -Xclang -internal-externc-isystem -Xclang /tmp/ \ // RUN: -DFOO=BAR 2>&1 | FileCheck %s @@ -34,7 +33,6 @@ FOO // CHECKSH-NOT: -iprefix /the/prefix // CHECKSH-NOT: -iwithprefix /tmp/ // CHECKSH-NOT: -iwithprefixbefore /tmp/ -// CHECKSH-NOT: -fmodules-cache-path=/tmp/ // CHECKSH-NOT: -internal-isystem /tmp/ // CHECKSH-NOT: -internal-externc-isystem /tmp/ // CHECKSH-NOT: -dwarf-debug-flags -- 2.7.4