Disable check_includes_strict optimizations when there are exceptions.

This has caused CI failures such as https://ci.chromium.org/ui/p/chromium/builders/try/linux-rel/2968325/overview

Bug: 556959580
Change-Id: I7e99d66d0f573861f7a9c2b5817491536a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27600
Reviewed-by: Junji Watanabe <jwata@google.com>
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/docs/reference.md b/docs/reference.md
index 3b55a39..bea64cc 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -5771,8 +5771,9 @@
   3. Dependents of this target cannot transitively include headers from this
      target's "public_deps" (they must depend on those targets directly).
 
-  Note that targets listed in "allow_circular_includes_from" act as an escape
-  hatch and bypass these strict checks.
+  Note that targets listed in "allow_circular_includes_from" and
+  "check_includes_strict_exceptions" act as an escape hatch and bypass these
+  strict checks.
 
   This enforces strict API boundary separation. Under this strict model:
   * "public_deps" act as interface dependencies (dependencies required to
@@ -5780,7 +5781,8 @@
     forwarded to dependents.
   * "deps" act as private implementation dependencies (dependencies required to
     compile this target's sources). This also allows dependent targets to
-    compile without waiting for this target's private "deps".
+    compile without waiting for this target's private "deps" (unless
+    check_includes_strict_exceptions is non-empty).
 
   When false (the default), the default loose include checking rules apply.
 ```
diff --git a/src/gn/resolved_target_data.cc b/src/gn/resolved_target_data.cc
index 72758c3..b20c526 100644
--- a/src/gn/resolved_target_data.cc
+++ b/src/gn/resolved_target_data.cc
@@ -82,7 +82,17 @@
   // binding headers via `public_deps`), dependents only need hard deps from
   // `public_deps()`. The target's own compilation still gets hard deps from its
   // `private_deps()` in NinjaTargetWriter::WriteInputDepsStampOrPhonyAndGetDep.
-  return !target->hard_dep() && (target->check_includes_strict() ||
+  //
+  // However, a target marked as check_includes_strict doesn't truly have the
+  // properties of check_includes_strict until there are no exemptions with
+  // target as the includer. Since we don't have an efficient way to check this,
+  // and exemptions are designed to be temporary anyway, we just disable them if
+  // exemptions exist.
+  return !target->hard_dep() && ((target->check_includes_strict() &&
+                                  target->settings()
+                                      ->build_settings()
+                                      ->check_includes_strict_exceptions()
+                                      .empty()) ||
                                  target->source_types_used().RustSourceUsed());
 }
 
diff --git a/src/gn/variables.cc b/src/gn/variables.cc
index 15b60d2..3b7c9b7 100644
--- a/src/gn/variables.cc
+++ b/src/gn/variables.cc
@@ -928,8 +928,9 @@
   3. Dependents of this target cannot transitively include headers from this
      target's "public_deps" (they must depend on those targets directly).
 
-  Note that targets listed in "allow_circular_includes_from" act as an escape
-  hatch and bypass these strict checks.
+  Note that targets listed in "allow_circular_includes_from" and
+  "check_includes_strict_exceptions" act as an escape hatch and bypass these
+  strict checks.
 
   This enforces strict API boundary separation. Under this strict model:
   * "public_deps" act as interface dependencies (dependencies required to
@@ -937,7 +938,8 @@
     forwarded to dependents.
   * "deps" act as private implementation dependencies (dependencies required to
     compile this target's sources). This also allows dependent targets to
-    compile without waiting for this target's private "deps".
+    compile without waiting for this target's private "deps" (unless
+    check_includes_strict_exceptions is non-empty).
 
   When false (the default), the default loose include checking rules apply.