Index: docs/UsersManual.rst =================================================================== --- docs/UsersManual.rst +++ docs/UsersManual.rst @@ -561,6 +561,16 @@ The -fno-crash-diagnostics flag can be helpful for speeding the process of generating a delta reduced test case. +Clang is also capable of generating preprocessed source file(s) and associated +run script(s) even without a crash. This is specially useful when trying to +generate a reproducer for warnings or errors while using modules. + +.. option:: -gen-reproducer + + Generates preprocessed source files, a reproducer script and if relevant, a + cache containing: built module pcm's and all headers needed to rebuilt the + same modules. + .. _rpass: Options to Emit Optimization Reports Index: include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- include/clang/Basic/DiagnosticDriverKinds.td +++ include/clang/Basic/DiagnosticDriverKinds.td @@ -92,7 +92,7 @@ def err_drv_command_signalled : Error< "%0 command failed due to signal (use -v to see invocation)">; def err_drv_force_crash : Error< - "failing because environment variable '%0' is set">; + "failing because %select{environment variable|option}0 '%1' is set">; def err_drv_invalid_mfloat_abi : Error< "invalid float ABI '%0'">; def err_drv_invalid_libcxx_deployment : Error< Index: include/clang/Driver/Driver.h =================================================================== --- include/clang/Driver/Driver.h +++ include/clang/Driver/Driver.h @@ -215,6 +215,11 @@ /// Use lazy precompiled headers for PCH support. unsigned CCCUsePCH : 1; + /// Force clang to emit reproducer for driver invocation. This is enabled + /// indirectly by setting FORCE_CLANG_DIAGNOSTICS_CRASH environment variable + /// or when using the -gen-reproducer driver flag. + unsigned GenReproducer : 1; + private: /// Certain options suppress the 'no input files' warning. unsigned SuppressMissingInputWarning : 1; Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -184,6 +184,8 @@ def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">, HelpText<"Emit ARC errors even if the migrator can fix them">, Flags<[CC1Option]>; +def gen_reproducer: Flag<["-"], "gen-reproducer">, InternalDebugOpt, + HelpText<"Auto-generates preprocessed source files and a reproduction script">; def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>, HelpText<"Run the migrator">; @@ -580,7 +582,8 @@ def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group; def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit=">, Group; -def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group, Flags<[NoArgumentUnused]>; +def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group, Flags<[NoArgumentUnused]>, + HelpText<"Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash">; def fcreate_profile : Flag<["-"], "fcreate-profile">, Group; def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group, HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>; Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -62,7 +62,7 @@ CCCPrintBindings(false), CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), DefaultTargetTriple(DefaultTargetTriple), CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true), - SuppressMissingInputWarning(false) { + GenReproducer(false), SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) @@ -596,6 +596,9 @@ CCCGenericGCCName = A->getValue(); CCCUsePCH = Args.hasFlag(options::OPT_ccc_pch_is_pch, options::OPT_ccc_pch_is_pth); + GenReproducer = Args.hasFlag(options::OPT_gen_reproducer, + options::OPT_fno_crash_diagnostics, + !!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")); // FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld // and getToolChain is const. if (IsCLMode()) { Index: test/Driver/crash-report-crashfile.m =================================================================== --- test/Driver/crash-report-crashfile.m +++ test/Driver/crash-report-crashfile.m @@ -3,15 +3,32 @@ // RUN: mkdir -p %t/i %t/m %t // RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH= TMPDIR=%t TEMP=%t TMP=%t \ -// RUN: %clang -fsyntax-only %s -I %S/Inputs/module -isysroot %/t/i/ \ -// RUN: -fmodules -fmodules-cache-path=%t/m/ -DFOO=BAR 2>&1 | FileCheck %s +// RUN: %clang -fsyntax-only %s \ +// RUN: -I %S/Inputs/module -isysroot %/t/i/ \ +// RUN: -fmodules -fmodules-cache-path=%t/m/ -DFOO=BAR 2>&1 | \ +// RUN: FileCheck -check-prefix=CRASH_ENV %s + +// RUN: not env TMPDIR=%t TEMP=%t TMP=%t \ +// RUN: %clang -gen-reproducer -fsyntax-only %s \ +// RUN: -I %S/Inputs/module -isysroot %/t/i/ \ +// RUN: -fmodules -fmodules-cache-path=%t/m/ -DFOO=BAR 2>&1 | \ +// RUN: FileCheck -check-prefix=CRASH_FLAG %s @import simple; const int x = MODULE_MACRO; -// CHECK: Preprocessed source(s) and associated run script(s) are located at: -// CHECK-NEXT: note: diagnostic msg: {{.*}}.m -// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache -// CHECK-NEXT: note: diagnostic msg: {{.*}}.sh -// CHECK-NEXT: note: diagnostic msg: Crash backtrace is located in -// CHECK-NEXT: note: diagnostic msg: {{.*}}Library/Logs/DiagnosticReports{{.*}} +// CRASH_ENV: failing because environment variable 'FORCE_CLANG_DIAGNOSTICS_CRASH' is set +// CRASH_ENV: Preprocessed source(s) and associated run script(s) are located at: +// CRASH_ENV-NEXT: note: diagnostic msg: {{.*}}.m +// CRASH_ENV-NEXT: note: diagnostic msg: {{.*}}.cache +// CRASH_ENV-NEXT: note: diagnostic msg: {{.*}}.sh +// CRASH_ENV-NEXT: note: diagnostic msg: Crash backtrace is located in +// CRASH_ENV-NEXT: note: diagnostic msg: {{.*}}Library/Logs/DiagnosticReports{{.*}} + +// CRASH_FLAG: failing because option '-gen-reproducer' is set +// CRASH_FLAG: Preprocessed source(s) and associated run script(s) are located at: +// CRASH_FLAG-NEXT: note: diagnostic msg: {{.*}}.m +// CRASH_FLAG-NEXT: note: diagnostic msg: {{.*}}.cache +// CRASH_FLAG-NEXT: note: diagnostic msg: {{.*}}.sh +// CRASH_FLAG-NEXT: note: diagnostic msg: Crash backtrace is located in +// CRASH_FLAG-NEXT: note: diagnostic msg: {{.*}}Library/Logs/DiagnosticReports{{.*}} Index: tools/driver/driver.cpp =================================================================== --- tools/driver/driver.cpp +++ tools/driver/driver.cpp @@ -460,8 +460,12 @@ Res = TheDriver.ExecuteCompilation(*C, FailingCommands); // Force a crash to test the diagnostics. - if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) { - Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH"; + if (TheDriver.GenReproducer) { + if (!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) + Diags.Report(diag::err_drv_force_crash) << 1 << "-gen-reproducer"; + else + Diags.Report(diag::err_drv_force_crash) + << 0 << "FORCE_CLANG_DIAGNOSTICS_CRASH"; // Pretend that every command failed. FailingCommands.clear();