diff --git a/src/graph.cc b/src/graph.cc index 227c615822..8e6ff697e0 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -284,8 +284,11 @@ bool DependencyScan::RecomputeOutputDirty(const Edge* edge, Node* output) { if (edge->is_phony()) { // Phony edges don't write any output. Outputs are only dirty if - // there are no inputs and we're missing the output. - if (edge->inputs_.empty() && !output->exists()) { + // there are no inputs or validations and we're missing the output. + // If a phony target has inputs or validations, or the output exists, + // they are used for dirty calculation instead of this fallback. + if (edge->inputs_.empty() && edge->validations_.empty() && + !output->exists()) { explanations_.Record( output, "output %s of phony edge with no inputs doesn't exist", output->path().c_str()); diff --git a/src/graph_test.cc b/src/graph_test.cc index d29118ae3a..afd4d0eb96 100644 --- a/src/graph_test.cc +++ b/src/graph_test.cc @@ -1140,4 +1140,19 @@ TEST_F(GraphTest, EdgeQueuePriority) { EXPECT_TRUE(queue.empty()); } +TEST_F(GraphTest, PhonyOutputWithValidation) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, + "build valid: phony\n" + "build out: phony |@ valid\n")); + fs_.Create("valid", ""); + + string err; + std::vector validation_nodes; + EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), &validation_nodes, &err)); + ASSERT_EQ("", err); + // Phony output with validation should not be dirty even if output is missing. + EXPECT_FALSE(GetNode("out")->dirty()); + ASSERT_EQ(1u, validation_nodes.size()); + EXPECT_EQ("valid", validation_nodes[0]->path()); +}