Restore missing dep from depfile support

The restriction about not having phony rules that were dirty because of
a missing input was causing incremental build breaks because phony edges
are automatically created for each file listed in a depfile.

Restore the original behavior for these edges, while keeping the error
for phony rules defined in the ninja file.

Test: run ninja_tests (through build-prebuilts.sh)
Change-Id: Id41b7ecd329844a97db4d3cb9c585f26ac2774bd
diff --git a/src/build_test.cc b/src/build_test.cc
index 406b291..2400f18 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -914,6 +914,29 @@
   ASSERT_EQ("cc foo.c", edge->EvaluateCommand());
 }
 
+TEST_F(BuildTest, DepFileOKWithPhonyOutputs) {
+  string err;
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cc\n  command = cc $in\n  depfile = $out.d\n"
+"build foo.o: cc foo.c\n"));
+
+  BuildConfig config(config_);
+  config.uses_phony_outputs = true;
+  Builder builder(&state_, config, nullptr, nullptr, &fs_, &status_, 0);
+  builder.command_runner_.reset(&command_runner_);
+  command_runner_.commands_ran_.clear();
+
+  fs_.Create("foo.c", "");
+  GetNode("bar.h")->MarkDirty();  // Mark bar.h as missing.
+  fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
+  EXPECT_TRUE(builder.AddTarget("foo.o", &err));
+  ASSERT_EQ("", err);
+
+  ASSERT_TRUE(GetNode("bar.h")->in_edge()->phony_from_depfile_);
+
+  builder.command_runner_.release();
+}
+
 TEST_F(BuildTest, DepFileParseError) {
   string err;
   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
diff --git a/src/graph.cc b/src/graph.cc
index b1cdf77..e93a2e1 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -345,7 +345,9 @@
       // 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() && !(*o)->exists()) {
-        if (missing_phony_is_err_) {
+        // For phony targets defined in the ninja file, error when using dirty phony edges.
+        // The phony edges automatically created from depfiles still need the old behavior.
+        if (missing_phony_is_err_ && !edge->phony_from_depfile_) {
           *err = "output " + (*o)->path() + " of phony edge doesn't exist. Missing 'phony_output = true'?";
           return false;
         } else {
@@ -875,4 +877,6 @@
   // to avoid a potential stuck build.  If we do call RecomputeDirty for
   // this node, it will simply set outputs_ready_ to the correct value.
   phony_edge->outputs_ready_ = true;
+
+  phony_edge->phony_from_depfile_ = true;
 }
diff --git a/src/graph.h b/src/graph.h
index 07bd377..4559027 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -378,6 +378,7 @@
   size_t id_ = 0;
   bool outputs_ready_ = false;
   bool deps_missing_ = false;
+  bool phony_from_depfile_ = false;
   DepScanInfo dep_scan_info_;
 
   DeclIndex dfs_location() const { return pos_.dfs_location(); }