Add --incompatible_force_strict_header_check_from_starlark flag

Header checking should always be strict in Bazel, but a gap exists in
the Starlark API that allows it to be set to "LOOSE" in certain
circumstances. This adds a fix behind an incompatibility flag.

See #11677

RELNOTES: Add flag --incompatible_force_strict_header_check_from_starlark
PiperOrigin-RevId: 319036858
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java
index 4515374..872ad08 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java
@@ -79,6 +79,14 @@
   }
 
   @Override
+  public HeadersCheckingMode determineStarlarkHeadersCheckingMode(CppConfiguration cppConfig) {
+    if (cppConfig.strictHeaderCheckingFromStarlark()) {
+      return HeadersCheckingMode.STRICT;
+    }
+    return HeadersCheckingMode.LOOSE;
+  }
+
+  @Override
   public IncludeProcessing getIncludeProcessing() {
     return includeProcessing;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
index e001d27..1f5489d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
@@ -1777,7 +1777,14 @@
             .addAdditionalCompilationInputs(
                 Sequence.cast(additionalInputs, Artifact.class, "additional_inputs"))
             .addAditionalIncludeScanningRoots(headersForClifDoNotUseThisParam)
-            .setPurpose(common.getPurpose(getSemantics()));
+            .setPurpose(common.getPurpose(getSemantics()))
+            .setHeadersCheckingMode(
+                getSemantics()
+                    .determineStarlarkHeadersCheckingMode(
+                        actions
+                            .getActionConstructionContext()
+                            .getConfiguration()
+                            .getFragment(CppConfiguration.class)));
     if (disallowNopicOutputs) {
       helper.setGenerateNoPicAction(false);
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
index 80e8c229..3e8ce56 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
@@ -733,4 +733,8 @@
   public boolean experimentalStarlarkCcImport() {
     return cppOptions.experimentalStarlarkCcImport;
   }
+
+  public boolean strictHeaderCheckingFromStarlark() {
+    return cppOptions.forceStrictHeaderCheckFromStarlark;
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
index 16ef0fc..2a76e39 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
@@ -989,6 +989,18 @@
       help = "If enabled, the Starlark version of cc_import can be used.")
   public boolean experimentalStarlarkCcImport;
 
+  @Option(
+      name = "incompatible_force_strict_header_check_from_starlark",
+      defaultValue = "false",
+      documentationCategory = OptionDocumentationCategory.INPUT_STRICTNESS,
+      effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS, OptionEffectTag.CHANGES_INPUTS},
+      metadataTags = {
+        OptionMetadataTag.INCOMPATIBLE_CHANGE,
+        OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
+      },
+      help = "If enabled, set strict header checking in the Starlark API")
+  public boolean forceStrictHeaderCheckFromStarlark;
+
   /** See {@link #targetLibcTopLabel} documentation. * */
   @Override
   public FragmentOptions getNormalized() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppSemantics.java
index f411173..cd17c6c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppSemantics.java
@@ -39,6 +39,9 @@
   /** Determines the applicable mode of headers checking for the passed in ruleContext. */
   HeadersCheckingMode determineHeadersCheckingMode(RuleContext ruleContext);
 
+  /** Determines the applicable mode of headers checking in Starlark. */
+  HeadersCheckingMode determineStarlarkHeadersCheckingMode(CppConfiguration cppConfiguration);
+
   /** Returns the include processing closure, which handles include processing for this build */
   IncludeProcessing getIncludeProcessing();
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java
index fad0815..41e356e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
 import com.google.devtools.build.lib.rules.cpp.CppCompileActionBuilder;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode;
 import com.google.devtools.build.lib.rules.cpp.CppSemantics;
 import com.google.devtools.build.lib.rules.cpp.HeaderDiscovery.DotdPruningMode;
@@ -90,6 +91,14 @@
   }
 
   @Override
+  public HeadersCheckingMode determineStarlarkHeadersCheckingMode(CppConfiguration cppConfig) {
+    if (cppConfig.strictHeaderCheckingFromStarlark()) {
+      return HeadersCheckingMode.STRICT;
+    }
+    return HeadersCheckingMode.LOOSE;
+  }
+
+  @Override
   public IncludeProcessing getIncludeProcessing() {
     return includeProcessing;
   }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/MockCppSemantics.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/MockCppSemantics.java
index 1931d54..5df8966 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/MockCppSemantics.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/MockCppSemantics.java
@@ -52,6 +52,11 @@
   }
 
   @Override
+  public HeadersCheckingMode determineStarlarkHeadersCheckingMode(CppConfiguration cppConfig) {
+    return HeadersCheckingMode.LOOSE;
+  }
+
+  @Override
   public boolean needsDotdInputPruning() {
     return true;
   }