Skip to content

Commit 4a9d409

Browse files
committed
[Parseable Output] Emit parseable messages on failure in CompilerInstance.setup
FrontendTool sets up diagnostic infrastructure early and suppresses stdout diagnostics if frontend-parseable-output is enabled. It then calls `CompilerInstance.setup` which may fail - if it fails, we exit early. But that means we have not gotten a chance to emit parseable-output. This change moves emission of the `began` parseable message to before `CompilerInstance.setup`, and ensures that a corresponding `finished` message is emitted if the setup fails. Resolves rdar://93187783
1 parent d5ac631 commit 4a9d409

File tree

2 files changed

+93
-73
lines changed

2 files changed

+93
-73
lines changed

lib/FrontendTool/FrontendTool.cpp

Lines changed: 84 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,57 +2072,8 @@ int swift::performFrontend(ArrayRef<const char *> Args,
20722072
PDC.setSuppressOutput(true);
20732073
}
20742074

2075-
// Because the serialized diagnostics consumer is initialized here,
2076-
// diagnostics emitted above, within CompilerInvocation::parseArgs, are never
2077-
// serialized. This is a non-issue because, in nearly all cases, frontend
2078-
// arguments are generated by the driver, not directly by a user. The driver
2079-
// is responsible for emitting diagnostics for its own errors. See SR-2683
2080-
// for details.
2081-
std::unique_ptr<DiagnosticConsumer> SerializedConsumerDispatcher =
2082-
createSerializedDiagnosticConsumerIfNeeded(
2083-
Invocation.getFrontendOptions().InputsAndOutputs);
2084-
if (SerializedConsumerDispatcher)
2085-
Instance->addDiagnosticConsumer(SerializedConsumerDispatcher.get());
2086-
2087-
std::unique_ptr<DiagnosticConsumer> FixItsConsumer =
2088-
createJSONFixItDiagnosticConsumerIfNeeded(Invocation);
2089-
if (FixItsConsumer)
2090-
Instance->addDiagnosticConsumer(FixItsConsumer.get());
2091-
2092-
if (Invocation.getDiagnosticOptions().UseColor)
2093-
PDC.forceColors();
2094-
2095-
PDC.setPrintEducationalNotes(
2096-
Invocation.getDiagnosticOptions().PrintEducationalNotes);
2097-
2098-
PDC.setFormattingStyle(
2099-
Invocation.getDiagnosticOptions().PrintedFormattingStyle);
2100-
2101-
if (Invocation.getFrontendOptions().PrintStats) {
2102-
llvm::EnableStatistics();
2103-
}
2104-
2105-
const DiagnosticOptions &diagOpts = Invocation.getDiagnosticOptions();
2106-
bool verifierEnabled = diagOpts.VerifyMode != DiagnosticOptions::NoVerify;
2107-
2108-
std::string InstanceSetupError;
2109-
if (Instance->setup(Invocation, InstanceSetupError)) {
2110-
return finishDiagProcessing(1, /*verifierEnabled*/ false);
2111-
}
2112-
2113-
// The compiler instance has been configured; notify our observer.
2114-
if (observer) {
2115-
observer->configuredCompiler(*Instance);
2116-
}
2117-
2118-
if (verifierEnabled) {
2119-
// Suppress printed diagnostic output during the compile if the verifier is
2120-
// enabled.
2121-
PDC.setSuppressOutput(true);
2122-
}
2123-
2124-
if (Invocation.getFrontendOptions().FrontendParseableOutput) {
2125-
const auto &IO = Invocation.getFrontendOptions().InputsAndOutputs;
2075+
auto emitParseableBeganMessage = [&Invocation, &Args]() {
2076+
const auto &IO = Invocation.getFrontendOptions().InputsAndOutputs;
21262077
const auto OSPid = getpid();
21272078
const auto ProcInfo = sys::TaskProcessInformation(OSPid);
21282079

@@ -2151,27 +2102,9 @@ int swift::performFrontend(ArrayRef<const char *> Args,
21512102
constructDetailedTaskDescription(Invocation, IO.getAllInputs(), Args),
21522103
OSPid, ProcInfo);
21532104
}
2154-
}
2155-
2156-
int ReturnValue = 0;
2157-
bool HadError = performCompile(*Instance, ReturnValue, observer);
2158-
2159-
if (verifierEnabled) {
2160-
DiagnosticEngine &diags = Instance->getDiags();
2161-
if (diags.hasFatalErrorOccurred() &&
2162-
!Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError) {
2163-
diags.resetHadAnyError();
2164-
PDC.setSuppressOutput(false);
2165-
diags.diagnose(SourceLoc(), diag::verify_encountered_fatal);
2166-
HadError = true;
2167-
}
2168-
}
2169-
2170-
auto r = finishDiagProcessing(HadError ? 1 : ReturnValue, verifierEnabled);
2171-
if (auto *StatsReporter = Instance->getStatsReporter())
2172-
StatsReporter->noteCurrentProcessExitStatus(r);
2105+
};
21732106

2174-
if (Invocation.getFrontendOptions().FrontendParseableOutput) {
2107+
auto emitParseableFinishedMessage = [&Invocation, &Args, &FileSpecificDiagnostics](int ExitStatus) {
21752108
const auto &IO = Invocation.getFrontendOptions().InputsAndOutputs;
21762109
const auto OSPid = getpid();
21772110
const auto ProcInfo = sys::TaskProcessInformation(OSPid);
@@ -2197,7 +2130,7 @@ int swift::performFrontend(ArrayRef<const char *> Args,
21972130

21982131
emitFinishedMessage(llvm::errs(),
21992132
mapFrontendInvocationToAction(Invocation),
2200-
JoinedDiags.str(), r, Pid - idx, ProcInfo);
2133+
JoinedDiags.str(), ExitStatus, Pid - idx, ProcInfo);
22012134
return false;
22022135
});
22032136
} else {
@@ -2214,10 +2147,88 @@ int swift::performFrontend(ArrayRef<const char *> Args,
22142147
std::ostream_iterator<std::string>(JoinedDiags, Delim));
22152148
emitFinishedMessage(llvm::errs(),
22162149
mapFrontendInvocationToAction(Invocation),
2217-
JoinedDiags.str(), r, OSPid, ProcInfo);
2150+
JoinedDiags.str(), ExitStatus, OSPid, ProcInfo);
22182151
}
2152+
};
2153+
2154+
// Because the serialized diagnostics consumer is initialized here,
2155+
// diagnostics emitted above, within CompilerInvocation::parseArgs, are never
2156+
// serialized. This is a non-issue because, in nearly all cases, frontend
2157+
// arguments are generated by the driver, not directly by a user. The driver
2158+
// is responsible for emitting diagnostics for its own errors. See SR-2683
2159+
// for details.
2160+
std::unique_ptr<DiagnosticConsumer> SerializedConsumerDispatcher =
2161+
createSerializedDiagnosticConsumerIfNeeded(
2162+
Invocation.getFrontendOptions().InputsAndOutputs);
2163+
if (SerializedConsumerDispatcher)
2164+
Instance->addDiagnosticConsumer(SerializedConsumerDispatcher.get());
2165+
2166+
std::unique_ptr<DiagnosticConsumer> FixItsConsumer =
2167+
createJSONFixItDiagnosticConsumerIfNeeded(Invocation);
2168+
if (FixItsConsumer)
2169+
Instance->addDiagnosticConsumer(FixItsConsumer.get());
2170+
2171+
if (Invocation.getDiagnosticOptions().UseColor)
2172+
PDC.forceColors();
2173+
2174+
PDC.setPrintEducationalNotes(
2175+
Invocation.getDiagnosticOptions().PrintEducationalNotes);
2176+
2177+
PDC.setFormattingStyle(
2178+
Invocation.getDiagnosticOptions().PrintedFormattingStyle);
2179+
2180+
if (Invocation.getFrontendOptions().PrintStats) {
2181+
llvm::EnableStatistics();
22192182
}
22202183

2184+
2185+
if (Invocation.getFrontendOptions().FrontendParseableOutput)
2186+
emitParseableBeganMessage();
2187+
2188+
const DiagnosticOptions &diagOpts = Invocation.getDiagnosticOptions();
2189+
bool verifierEnabled = diagOpts.VerifyMode != DiagnosticOptions::NoVerify;
2190+
2191+
std::string InstanceSetupError;
2192+
if (Instance->setup(Invocation, InstanceSetupError)) {
2193+
int ReturnCode = 1;
2194+
if (Invocation.getFrontendOptions().FrontendParseableOutput)
2195+
emitParseableFinishedMessage(ReturnCode);
2196+
2197+
return finishDiagProcessing(ReturnCode, /*verifierEnabled*/ false);
2198+
}
2199+
2200+
// The compiler instance has been configured; notify our observer.
2201+
if (observer) {
2202+
observer->configuredCompiler(*Instance);
2203+
}
2204+
2205+
if (verifierEnabled) {
2206+
// Suppress printed diagnostic output during the compile if the verifier is
2207+
// enabled.
2208+
PDC.setSuppressOutput(true);
2209+
}
2210+
2211+
int ReturnValue = 0;
2212+
bool HadError = performCompile(*Instance, ReturnValue, observer);
2213+
2214+
if (verifierEnabled) {
2215+
DiagnosticEngine &diags = Instance->getDiags();
2216+
if (diags.hasFatalErrorOccurred() &&
2217+
!Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError) {
2218+
diags.resetHadAnyError();
2219+
PDC.setSuppressOutput(false);
2220+
diags.diagnose(SourceLoc(), diag::verify_encountered_fatal);
2221+
HadError = true;
2222+
}
2223+
}
2224+
2225+
auto r = finishDiagProcessing(HadError ? 1 : ReturnValue, verifierEnabled);
2226+
if (auto *StatsReporter = Instance->getStatsReporter())
2227+
StatsReporter->noteCurrentProcessExitStatus(r);
2228+
2229+
if (Invocation.getFrontendOptions().FrontendParseableOutput)
2230+
emitParseableFinishedMessage(r);
2231+
22212232
return r;
22222233
}
22232234

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: not %target-swift-frontend(mock-sdk: -sdk %/S/../ModuleInterface/Inputs/BadStdlib.sdk -module-cache-path %/t/module-cache -resource-dir %/S/../ModuleInterface/Inputs/BadStdlib.sdk) -primary-file %s -o %t.out -emit-module -emit-module-path %t.swiftmodule -module-name parseable_output_early -frontend-parseable-output 2>&1 | %FileCheck %s
2+
3+
// CHECK: {{[1-9][0-9]*}}
4+
// CHECK-NEXT: {
5+
// CHECK-NEXT: "kind": "began",
6+
// CHECK-NEXT: "name": "compile",
7+
8+
// CHECK: "kind": "finished",
9+
// CHECK-NEXT: "name": "compile",

0 commit comments

Comments
 (0)