Add incompatible flags for removing legacy cc_toolchain skylark apis

Progress on #4571.

RELNOTES: Added `--incompatible_disable_legacy_flags_cc_toolchain_api` to
deprecate legacy `cc_toolchain` Skylark API for legacy CROSSTOOL fields.
PiperOrigin-RevId: 214764514
diff --git a/site/docs/skylark/backward-compatibility.md b/site/docs/skylark/backward-compatibility.md
index 4561e25..6e0760d 100644
--- a/site/docs/skylark/backward-compatibility.md
+++ b/site/docs/skylark/backward-compatibility.md
@@ -53,6 +53,8 @@
     flags](#disable-depsets-in-c-toolchain-api-in-user-flags)
 *   [Disallow using CROSSTOOL to select the cc_toolchain label](#disallow-using-crosstool-to-select-the-cc_toolchain-label)
 *   [Disallow using C++ Specific Make Variables from the configuration](#disallow-using-c-specific-make-variables-from-the-configuration)
+*   [Disable legacy C++ configuration API](#disable-legacy-c-configuration-api)
+*   [Disable legacy C++ toolchain API](#disable-legacy-c-toolchain-api)
 
 
 ### Dictionary concatenation
@@ -662,5 +664,163 @@
 *   Default: `false`
 *   Introduced in: `0.18.0`
 
-<!-- Add new options here -->
+### Disable legacy C++ configuration API
 
+This turns off legacy Starlark access to cc toolchain information via the
+`ctx.fragments.cpp` fragment. Instead of declaring dependency on the `ctx.fragments.cpp` using the
+`fragments` attribute declare a dependency on the `@bazel_tools//tools/cpp:current_cc_toolchain`
+via implicit attribute named `_cc_toolchain` (see example below). Use `find_cpp_toolchain` from
+`@bazel_tools//tools/cpp:toolchain_utils.bzl` to get the current C++ toolchain in the rule
+  implementation.
+
+```python
+# Before
+def _impl(ctx):
+  ...
+  ctx.fragments.cpp.compiler_options()
+
+foo = rule(
+    implementation = _impl,
+    fragments = ["cpp"],
+    ...
+)
+
+# After
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
+
+def _impl(ctx):
+  ...
+  cc_toolchain = find_cpp_toolchain(ctx)
+  cc_toolchain.compiler_options()
+
+foo = rule(
+    implementation = _impl,
+    attrs = {
+        "_cc_toolchain": attr.label(
+            default=Label("@bazel_tools//tools/cpp:current_cc_toolchain")
+        ),
+    },
+)
+```
+
+List of all legacy fields and their corresponding `cc_toolchain` alternative:
+
+|`ctx.fragments.cpp` | `cc_toolchain`  |
+|---|---|
+| `ar_executable` |  `ar_executable()` |
+| `built_in_include_directories` |  `built_in_include_directories` |
+| `c_options` |  `c_options()` |
+| `compiler` |  `compiler` |
+| `compiler_executable` |  `compiler_executable()` |
+| `compiler_options(unused_arg)` |  `compiler_options()` |
+| `cpu` |  `cpu` |
+| `cxx_options(unused_arg)` |  `cxx_options()` |
+| `dynamic_link_options(unused_arg, bool)` |  `dynamic_link_options(bool)` |
+| `fully_static_link_options(unused_arg, True)` |  `fully_static_link_options(True)` |
+| `ld_executable` |  `ld_executable()` |
+| `link_options` |  `link_options_do_not_use` |
+| `mostly_static_link_options(unused_arg, bool)` |  `mostly_static_link_options(bool)` |
+| `nm_executable` |  `nm_executable()` |
+| `objcopy_executable` |  `objcopy_executable()` |
+| `objdump_executable` |  `objdump_executable()` |
+| `preprocessor_executable` |  `preprocessor_executable()` |
+| `strip_executable` |  `strip_executable()` |
+| `sysroot` |  `sysroot` |
+| `target_gnu_system_name` |  `target_gnu_system_name` |
+| `unfiltered_compiler_options(unused_arg)` |  `unfiltered_compiler_options(unused_arg)` |
+
+*   Flag: `--incompatible_disable_legacy_cpp_toolchain_skylark_api`
+*   Default: `false`
+*   Introduced in: `0.18.0`
+
+### Disable legacy C++ toolchain API
+
+We have deprecated the `cc_toolchain` Starlark API returning legacy CROSSTOOL fields:
+
+* ar_executable
+* c_options
+* compiler_executable
+* compiler_options
+* cxx_options
+* dynamic_link_options
+* fully_static_link_options
+* ld_executable
+* link_options
+* mostly_static_link_options
+* nm_executable
+* objcopy_executable
+* objdump_executable
+* preprocessor_executable
+* strip_executable
+* unfiltered_compiler_options
+
+Use the new API from [cc_common](https://docs.bazel.build/versions/master/skylark/lib/cc_common.html)
+
+```python
+# Before:
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
+
+def _impl(ctx):
+    cc_toolchain = find_cc_toolchain(ctx)
+    compiler_options = (
+        cc_toolchain.compiler_options() +
+        cc_toolchain.unfiltered_compiler_options([]) +
+        ["-w", "-Wno-error"]
+    )
+    link_options = (
+        ["-shared", "-static-libgcc"] +
+        cc_toolchain.mostly_static_link_options(True) +
+        ["-Wl,-whole-archive"] +
+        [l.path for l in libs] +
+        ["-Wl,-no-whole-archive"] +
+        cc_toolchain.link_options_do_not_use
+    )
+
+# After
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
+load(
+    "@bazel_tools//tools/build_defs/cc:action_names.bzl",
+    "CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME",
+    "C_COMPILE_ACTION_NAME",
+)
+
+def _impl(ctx):
+    cc_toolchain = find_cc_toolchain(ctx)
+    feature_configuration = cc_common.configure_features(
+        cc_toolchain = cc_toolchain,
+        requested_features = ctx.features,
+        unsupported_features = ctx.disabled_features,
+    )
+    compile_variables = cc_common.create_compile_variables(
+        feature_configuration = feature_configuration,
+        cc_toolchain = cc_toolchain,
+        user_compile_flags = depset(["-w", "-Wno-error"]),
+    )
+    compiler_options = cc_common.get_memory_inefficient_command_line(
+        feature_configuration = feature_configuration,
+        action_name = C_COMPILE_ACTION_NAME,
+        variables = compile_variables,
+    )
+
+    link_variables = cc_common.create_link_variables(
+        feature_configuration = feature_configuration,
+        cc_toolchain = cc_toolchain,
+        is_linking_dynamic_library = True,
+        user_link_flags =
+            ["-static-libgcc"] +
+            ["-Wl,-whole-archive"] +
+            [lib.path for lib in libs] +
+            ["-Wl,-no-whole-archive"],
+    )
+    link_flags = cc_common.get_memory_inefficient_command_line(
+        feature_configuration = feature_configuration,
+        action_name = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME,
+        variables = link_variables,
+    )
+```
+
+*   Flag: `--incompatible_disable_legacy_flags_cc_toolchain_api`
+*   Default: `false`
+*   Introduced in: `0.19.0`
+
+<!-- Add new options here -->
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 3bbcfeb..32255c5 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
@@ -1212,25 +1212,34 @@
           null,
           "Information about the C++ toolchain API is not accessible "
               + "anymore through ctx.fragments.cpp "
-              + "(See --incompatible_disable_legacy_cpp_toolchain_skylark_api). "
+              + "(see --incompatible_disable_legacy_cpp_toolchain_skylark_api on "
+              + "http://docs.bazel.build/versions/master/skylark/backward-compatibility.html"
+              + "#disable-legacy-c-configuration-api for migration notes). "
               + "Use CcToolchainInfo instead.");
     }
   }
 
   public void checkForLegacyCompilationApiAvailability() throws EvalException {
-    if (cppOptions.disableLegacyCompilationApi) {
+    if (cppOptions.disableLegacyCompilationApi || cppOptions.disableLegacyFlagsCcToolchainApi) {
       throw new EvalException(
           null,
           "Skylark APIs accessing compilation flags has been removed. "
-              + "Use the new API on cc_common.");
+              + "Use the new API on cc_common (see "
+              + "--incompatible_disable_legacy_flags_cc_toolchain_api on"
+              + "https://docs.bazel.build/versions/master/skylark/backward-compatibility.html"
+              + "#disable-legacy-c-toolchain-api for migration notes).");
     }
   }
 
   public void checkForLegacyLinkingApiAvailability() throws EvalException {
-    if (cppOptions.disableLegacyLinkingApi) {
+    if (cppOptions.disableLegacyLinkingApi || cppOptions.disableLegacyFlagsCcToolchainApi) {
       throw new EvalException(
           null,
-          "Skylark APIs accessing linking flags has been removed. Use the new API on cc_common.");
+          "Skylark APIs accessing linking flags has been removed. "
+              + "Use the new API on cc_common (see "
+              + "--incompatible_disable_legacy_flags_cc_toolchain_api on"
+              + "https://docs.bazel.build/versions/master/skylark/backward-compatibility.html"
+              + "#disable-legacy-c-toolchain-api for migration notes).");
     }
   }
 
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 2edf165..b18333c 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
@@ -776,7 +776,7 @@
         OptionMetadataTag.INCOMPATIBLE_CHANGE,
         OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
       },
-      help = "Flag for disabling access to the C++ toolchain API through the ctx.fragments.cpp .")
+      help = "Flag for disabling access to the C++ toolchain API through the ctx.fragments.cpp.")
   public boolean disableLegacyToolchainSkylarkApi;
 
   @Option(
@@ -798,6 +798,20 @@
   public boolean disableLegacyCompilationApi;
 
   @Option(
+      name = "incompatible_disable_legacy_flags_cc_toolchain_api",
+      defaultValue = "false",
+      documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
+      effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS},
+      metadataTags = {
+        OptionMetadataTag.INCOMPATIBLE_CHANGE,
+        OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
+      },
+      help =
+          "Flag for disabling the legacy cc_toolchain Skylark API for accessing legacy "
+              + "CROSSTOOL fields.")
+  public boolean disableLegacyFlagsCcToolchainApi;
+
+  @Option(
       name = "experimental_disable_linking_mode_flags",
       defaultValue = "false",
       documentationCategory = OptionDocumentationCategory.TOOLCHAIN,
@@ -822,7 +836,7 @@
       effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS},
       metadataTags = {OptionMetadataTag.EXPERIMENTAL},
       help =
-          "If true, Bazel will not read crosstool flags from legacy crosstool fields (see #5187.")
+          "If true, Bazel will not read crosstool flags from legacy crosstool fields (see #5187).")
   public boolean disableLegacyCrosstoolFields;
 
   @Option(
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderTest.java
index 6d4f41d..9ee61dd 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProviderTest.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.rules.cpp;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -145,7 +144,13 @@
 
   private void testDisablingLinkingApiMethod(String method) throws Exception {
     useConfiguration("--experimental_disable_legacy_cc_linking_api");
-    scratch.file(
+    testDisablingLinkingApiMethodWithConfiguration(method);
+    useConfiguration("--incompatible_disable_legacy_flags_cc_toolchain_api");
+    testDisablingLinkingApiMethodWithConfiguration(method);
+  }
+
+  private void testDisablingLinkingApiMethodWithConfiguration(String method) throws Exception {
+    scratch.overwriteFile(
         "test/rule.bzl",
         "def _impl(ctx):",
         "  provider = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]",
@@ -158,18 +163,15 @@
         "  fragments = [ 'cpp' ],",
         "  attrs = {'_cc_toolchain': attr.label(default=Label('//test:toolchain')) }",
         ")");
-    scratch.file(
+    scratch.overwriteFile(
         "test/BUILD",
         "load(':rule.bzl', 'my_rule')",
         "cc_toolchain_alias(name = 'toolchain')",
         "my_rule(name = 'target')");
-    AssertionError e =
-        assertThrows(AssertionError.class, () -> getConfiguredTarget("//test:target"));
-    assertThat(e)
-        .hasMessageThat()
-        .contains(
-            "Skylark APIs accessing linking flags has been removed. "
-                + "Use the new API on cc_common.");
+    invalidatePackages();
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//test:target");
+    assertContainsEvent("Skylark APIs accessing linking flags has been removed.");
   }
 
   @Test
@@ -214,7 +216,13 @@
 
   private void testDisablingCompilationApiMethod(String method) throws Exception {
     useConfiguration("--experimental_disable_legacy_cc_compilation_api");
-    scratch.file(
+    testDisablingCompilationApiMethodWithConfiguration(method);
+    useConfiguration("--incompatible_disable_legacy_flags_cc_toolchain_api");
+    testDisablingCompilationApiMethodWithConfiguration(method);
+  }
+
+  private void testDisablingCompilationApiMethodWithConfiguration(String method) throws Exception {
+    scratch.overwriteFile(
         "test/rule.bzl",
         "def _impl(ctx):",
         "  provider = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]",
@@ -227,18 +235,15 @@
         "  fragments = [ 'cpp' ],",
         "  attrs = {'_cc_toolchain': attr.label(default=Label('//test:toolchain')) }",
         ")");
-    scratch.file(
+    scratch.overwriteFile(
         "test/BUILD",
         "load(':rule.bzl', 'my_rule')",
         "cc_toolchain_alias(name = 'toolchain')",
         "my_rule(name = 'target')");
-    AssertionError e =
-        assertThrows(AssertionError.class, () -> getConfiguredTarget("//test:target"));
-    assertThat(e)
-        .hasMessageThat()
-        .contains(
-            "Skylark APIs accessing compilation flags has been removed. "
-                + "Use the new API on cc_common.");
+    invalidatePackages();
+    reporter.removeHandler(failFastHandler);
+    getConfiguredTarget("//test:target");
+    assertContainsEvent("Skylark APIs accessing compilation flags has been removed.");
   }
 
   @Test