fix(toolchains): register py cc toolchain for workspace builds (#1670)

The workspace `python_register_toolchains()` function only registered
the plain Python toolchain by its specific name. The py cc toolchain
wasn't also being named. This meant things like
`//python/cc:current_py_cc_headers` couldn't find their toolchain.
Bzlmod doesn't have this problem because it uses the `:all` pattern to
register everything.

To fix, also register the py cc toolchain where the plain Python
toolchain is registered, which makes it available.

Fixes https://github.com/bazelbuild/rules_python/issues/1669
diff --git a/.bazelrc b/.bazelrc
index 4188090..250377a 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -4,8 +4,8 @@
 # (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it)
 # To update these lines, execute
 # `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
-build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/dupe_requirements,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/ignore_root_user_error,tests/integration/pip_repository_entry_points
-query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/dupe_requirements,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/ignore_root_user_error,tests/integration/pip_repository_entry_points
+build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/dupe_requirements,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/ignore_root_user_error,tests/integration/pip_repository_entry_points,tests/integration/py_cc_toolchain_registered
+query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/dupe_requirements,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/ignore_root_user_error,tests/integration/pip_repository_entry_points,tests/integration/py_cc_toolchain_registered
 
 test --test_output=errors
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4089ae4..2c2b5e4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -64,6 +64,9 @@
 * (coverage): coverage reports are now created when the version-aware
   rules are used.
   ([#1600](https://github.com/bazelbuild/rules_python/issues/1600))
+* (toolchains) Workspace builds register the py cc toolchain (bzlmod already
+  was). This makes e.g. `//python/cc:current_py_cc_headers` Just Work.
+  ([#1669](https://github.com/bazelbuild/rules_python/issues/1669))
 
 ### Added
 
diff --git a/python/repositories.bzl b/python/repositories.bzl
index e444c49..21becb5 100644
--- a/python/repositories.bzl
+++ b/python/repositories.bzl
@@ -584,6 +584,10 @@
                 toolchain_repo_name = toolchain_repo_name,
                 platform = platform,
             ))
+            native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_cc_toolchain".format(
+                toolchain_repo_name = toolchain_repo_name,
+                platform = platform,
+            ))
 
     toolchain_aliases(
         name = name,
diff --git a/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl b/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl
index 2b8b2ee..931a9c1 100644
--- a/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl
+++ b/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl
@@ -62,6 +62,18 @@
 
 _tests.append(_test_current_toolchain_headers)
 
+def _test_toolchain_is_registered_by_default(name):
+    analysis_test(
+        name = name,
+        impl = _test_toolchain_is_registered_by_default_impl,
+        target = "//python/cc:current_py_cc_headers",
+    )
+
+def _test_toolchain_is_registered_by_default_impl(env, target):
+    env.expect.that_target(target).has_provider(CcInfo)
+
+_tests.append(_test_toolchain_is_registered_by_default)
+
 def current_py_cc_headers_test_suite(name):
     test_suite(
         name = name,
diff --git a/tests/integration/BUILD.bazel b/tests/integration/BUILD.bazel
index e7f700a..0e793cd 100644
--- a/tests/integration/BUILD.bazel
+++ b/tests/integration/BUILD.bazel
@@ -91,3 +91,13 @@
     bzlmod = False,
     workspace_path = "ignore_root_user_error",
 )
+
+rules_python_integration_test(
+    name = "py_cc_toolchain_registered_test",
+)
+
+rules_python_integration_test(
+    name = "py_cc_toolchain_registered_workspace_test",
+    bzlmod = False,
+    workspace_path = "py_cc_toolchain_registered",
+)
diff --git a/tests/integration/py_cc_toolchain_registered/.bazelrc b/tests/integration/py_cc_toolchain_registered/.bazelrc
new file mode 100644
index 0000000..741d758
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/.bazelrc
@@ -0,0 +1,2 @@
+# This aids debugging on failure
+build --toolchain_resolution_debug=python
diff --git a/tests/integration/py_cc_toolchain_registered/BUILD.bazel b/tests/integration/py_cc_toolchain_registered/BUILD.bazel
new file mode 100644
index 0000000..9c9275c
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/BUILD.bazel
@@ -0,0 +1,19 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load(":defs.bzl", "py_cc_toolchain_available_test")
+
+# Simple test to verify that the py_cc_toolchain is registered and available
+# by default (for bzlmod) and when users setup a hermetic toolchain (workspace)
+py_cc_toolchain_available_test(name = "py_cc_toolchain_available_test")
diff --git a/tests/integration/py_cc_toolchain_registered/MODULE.bazel b/tests/integration/py_cc_toolchain_registered/MODULE.bazel
new file mode 100644
index 0000000..ad3b813
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/MODULE.bazel
@@ -0,0 +1,7 @@
+module(name = "py_cc_toolchain_registered")
+
+bazel_dep(name = "rules_python", version = "0.0.0")
+local_path_override(
+    module_name = "rules_python",
+    path = "../../..",
+)
diff --git a/tests/integration/py_cc_toolchain_registered/WORKSPACE b/tests/integration/py_cc_toolchain_registered/WORKSPACE
new file mode 100644
index 0000000..de90854
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/WORKSPACE
@@ -0,0 +1,13 @@
+local_repository(
+    name = "rules_python",
+    path = "../../..",
+)
+
+load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
+
+py_repositories()
+
+python_register_toolchains(
+    name = "python_3_11",
+    python_version = "3.11",
+)
diff --git a/tests/integration/py_cc_toolchain_registered/defs.bzl b/tests/integration/py_cc_toolchain_registered/defs.bzl
new file mode 100644
index 0000000..65d6184
--- /dev/null
+++ b/tests/integration/py_cc_toolchain_registered/defs.bzl
@@ -0,0 +1,38 @@
+# Copyright 2022 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Defs to implement tests."""
+
+def _py_cc_toolchain_available_test_impl(ctx):
+    toolchain = ctx.toolchains["@rules_python//python/cc:toolchain_type"]
+
+    if toolchain == None:
+        fail("expected @rules_python//python/cc:toolchain_type toolchain " +
+             "to be found, but it was not found")
+
+    executable = ctx.actions.declare_file(ctx.label.name)
+    ctx.actions.write(executable, "# no-op file", is_executable = True)
+    return [DefaultInfo(
+        executable = executable,
+    )]
+
+py_cc_toolchain_available_test = rule(
+    implementation = _py_cc_toolchain_available_test_impl,
+    toolchains = [
+        config_common.toolchain_type(
+            "@rules_python//python/cc:toolchain_type",
+            mandatory = False,
+        ),
+    ],
+    test = True,
+)