Skip to content

Commit 78d0faa

Browse files
committed
Work around coroutine bug in GCC 13
Non-trivial control flow along with coroutines triggerse an internal compiler error in GCC. We avoid this by simplifying the control flow in which `co_await`s and `co_return`s appear, by creating variables that hold the coroutines, and then jumping to them. This works because when calling a coroutine function, it always suspends immediately, without executing any logic.
1 parent 2844944 commit 78d0faa

File tree

1 file changed

+32
-18
lines changed

1 file changed

+32
-18
lines changed

src/libstore/build/derivation-goal.cc

+32-18
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,26 @@ void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
116116
wantedOutputs = newWanted;
117117
}
118118

119+
static Goal::Co empty_co() {
120+
co_return Goal::Return{};
121+
}
119122

120123
Goal::Co DerivationGoal::init() {
121124
trace("init");
122125

126+
Co gcc_bug_workaround{empty_co()};
127+
128+
if (useDerivation && (buildMode != bmNormal || !worker.evalStore.isValidPath(drvPath))) {
129+
gcc_bug_workaround = await({upcast_goal(worker.makePathSubstitutionGoal(drvPath))});
130+
}
131+
132+
co_await std::move(gcc_bug_workaround);
133+
123134
if (useDerivation) {
124135
/* The first thing to do is to make sure that the derivation
125136
exists. If it doesn't, it may be created through a
126137
substitute. */
127138

128-
if (buildMode != bmNormal || !worker.evalStore.isValidPath(drvPath)) {
129-
co_await await({upcast_goal(worker.makePathSubstitutionGoal(drvPath))});
130-
}
131-
132139
trace("loading derivation");
133140

134141
if (nrFailed != 0) {
@@ -410,6 +417,9 @@ Goal::Co DerivationGoal::gaveUpOnSubstitution()
410417

411418
/* Determine the full set of input paths. */
412419

420+
// needed because of GCC bug
421+
std::optional<std::pair<Co, Co>> gcc_bug_workaround{};
422+
413423
/* First, the input derivations. */
414424
if (useDerivation) {
415425
auto & fullDrv = *dynamic_cast<Derivation *>(drv.get());
@@ -483,14 +493,10 @@ Goal::Co DerivationGoal::gaveUpOnSubstitution()
483493

484494
resolvedDrvGoal = worker.makeDerivationGoal(
485495
pathResolved, wantedOutputs, buildMode);
486-
co_await await({resolvedDrvGoal});
487496

488-
co_return resolvedFinished();
489-
}
490-
491-
/* If we get this far, we know no dynamic drvs inputs */
492-
493-
for (auto & [depDrvPath, depNode] : fullDrv.inputDrvs.map) {
497+
gcc_bug_workaround = {await({resolvedDrvGoal}), resolvedFinished()};
498+
} else for (auto & [depDrvPath, depNode] : fullDrv.inputDrvs.map) {
499+
/* If we get this far, we know no dynamic drvs inputs */
494500
for (auto & outputName : depNode.value) {
495501
/* Don't need to worry about `inputGoals`, because
496502
impure derivations are always resolved above. Can
@@ -515,19 +521,27 @@ Goal::Co DerivationGoal::gaveUpOnSubstitution()
515521
}
516522
}
517523

518-
/* Second, the input sources. */
519-
worker.store.computeFSClosure(drv->inputSrcs, inputPaths);
524+
bool has_resolved_drv_goal = gcc_bug_workaround.has_value();
525+
526+
if (!gcc_bug_workaround) {
527+
gcc_bug_workaround = {yield(), tryToBuild()};
528+
}
529+
530+
if (!has_resolved_drv_goal) {
531+
/* Second, the input sources. */
532+
worker.store.computeFSClosure(drv->inputSrcs, inputPaths);
520533

521-
debug("added input paths %s", worker.store.showPaths(inputPaths));
534+
debug("added input paths %s", worker.store.showPaths(inputPaths));
522535

523-
/* What type of derivation are we building? */
524-
derivationType = drv->type();
536+
/* What type of derivation are we building? */
537+
derivationType = drv->type();
538+
}
525539

526540
/* Okay, try to build. Note that here we don't wait for a build
527541
slot to become available, since we don't need one if there is a
528542
build hook. */
529-
co_await yield();
530-
co_return tryToBuild();
543+
co_await std::move(gcc_bug_workaround->first);
544+
co_return std::move(gcc_bug_workaround->second);
531545
}
532546

533547
void DerivationGoal::started()

0 commit comments

Comments
 (0)