gn: Diag on distinct toolchains with the same name.

Previously, toolchains with the same name used to silently write to the same output
directory and clobber each others generated .ninja files.  After this patch, this still
happens, but gn writes an error message while writing the final build.ninja file.

Example output:
ERROR at //build/toolchain/mac2/BUILD.gn:51:3: Duplicate toolchain.
  toolchain(target_name) {
  ^-----------------------
Two or more toolchains write to the same directory:
  //out/gn1/clang_x64/

This can be fixed by making sure that distinct toolchains have
distinct names.

See //build/toolchain/mac3/BUILD.gn:51:3: Previous toolchain.
  toolchain(target_name) {
  ^-----------------------

Depends on https://codereview.chromium.org/2485523002/

BUG=661054

Review-Url: https://codereview.chromium.org/2483713003
Cr-Original-Commit-Position: refs/heads/master@{#430473}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: eab6e2d58dc3b71e094ff58d822980ca3473caf8
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index a805bb9..74a7787 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -130,6 +130,21 @@
   return result;
 }
 
+// Given two toolchains with the same name, generates an error message
+// that describes the problem.
+Err GetDuplicateToolchainError(const SourceFile& source_file,
+                               const Toolchain* previous_toolchain,
+                               const Toolchain* toolchain) {
+  Err result(toolchain->defined_from(), "Duplicate toolchain.",
+      "Two or more toolchains write to the same directory:\n  " +
+      source_file.GetDir().value() + "\n\n"
+      "This can be fixed by making sure that distinct toolchains have\n"
+      "distinct names.\n");
+  result.AppendSubErr(
+      Err(previous_toolchain->defined_from(), "Previous toolchain."));
+  return result;
+}
+
 }  // namespace
 
 NinjaBuildWriter::NinjaBuildWriter(
@@ -156,8 +171,7 @@
 bool NinjaBuildWriter::Run(Err* err) {
   WriteNinjaRules();
   WriteAllPools();
-  WriteSubninjas();
-  return WritePhonyAndAllRules(err);
+  return WriteSubninjas(err) && WritePhonyAndAllRules(err);
 }
 
 // static
@@ -287,7 +301,7 @@
   }
 }
 
-void NinjaBuildWriter::WriteSubninjas() {
+bool NinjaBuildWriter::WriteSubninjas(Err* err) {
   // Write toolchains sorted by their name, to make output deterministic.
   std::vector<std::pair<const Settings*, const Toolchain*>> sorted_settings(
       used_toolchains_.begin(), used_toolchains_.end());
@@ -302,12 +316,29 @@
               return GetNinjaFileForToolchain(a.first) <
                      GetNinjaFileForToolchain(b.first);
             });
+
+  SourceFile previous_subninja;
+  const Toolchain* previous_toolchain = nullptr;
+
   for (const auto& pair : sorted_settings) {
+    SourceFile subninja = GetNinjaFileForToolchain(pair.first);
+
+    // Since the toolchains are sorted, comparing to the previous subninja is
+    // enough to find duplicates.
+    if (subninja == previous_subninja) {
+      *err =
+          GetDuplicateToolchainError(subninja, previous_toolchain, pair.second);
+      return false;
+    }
+
     out_ << "subninja ";
-    path_output_.WriteFile(out_, GetNinjaFileForToolchain(pair.first));
+    path_output_.WriteFile(out_, subninja);
     out_ << std::endl;
+    previous_subninja = subninja;
+    previous_toolchain = pair.second;
   }
   out_ << std::endl;
+  return true;
 }
 
 bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
diff --git a/tools/gn/ninja_build_writer.h b/tools/gn/ninja_build_writer.h
index 530ac71..51535aa 100644
--- a/tools/gn/ninja_build_writer.h
+++ b/tools/gn/ninja_build_writer.h
@@ -49,9 +49,8 @@
  private:
   void WriteNinjaRules();
   void WriteAllPools();
-  void WriteSubninjas();
-  bool WritePhonyAndAllRules(
-      Err* err);
+  bool WriteSubninjas(Err* err);
+  bool WritePhonyAndAllRules(Err* err);
 
   void WritePhonyRule(const Target* target, const std::string& phony_name);