Replace slashes with underscores in default crate names. (#1334)

This change is consistent with the existing documentation, which says that all illegal characters will be converted to underscores (but in reality, only hyphens were converted).

This change has no risk of breakage, since it turns broken builds into passing ones, but not vice versa.
diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl
index f3a874a..6968187 100644
--- a/rust/private/rust.bzl
+++ b/rust/private/rust.bzl
@@ -305,7 +305,9 @@
     crate_name = compute_crate_name(ctx.workspace_name, ctx.label, toolchain, ctx.attr.crate_name)
     _assert_correct_dep_mapping(ctx)
 
-    output = ctx.actions.declare_file(ctx.label.name + toolchain.binary_ext)
+    # If the target's label contains "/" characters, we need to convert those to
+    # something safe, otherwise they get converted into path separators.
+    output = ctx.actions.declare_file(ctx.label.name.replace("/", "_") + toolchain.binary_ext)
 
     deps = transform_deps(ctx.attr.deps)
     proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx))
diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl
index 1e61993..83dbb1e 100644
--- a/rust/private/utils.bzl
+++ b/rust/private/utils.bzl
@@ -272,7 +272,9 @@
     Returns:
         str: The name of the crate for this target.
     """
-    return name.replace("-", "_")
+    for illegal in ("-", "/"):
+        name = name.replace(illegal, "_")
+    return name
 
 def _invalid_chars_in_crate_name(name):
     """Returns any invalid chars in the given crate name.
diff --git a/test/unit/crate_name/crate_name_test.bzl b/test/unit/crate_name/crate_name_test.bzl
index 968f2b5..8671951 100644
--- a/test/unit/crate_name/crate_name_test.bzl
+++ b/test/unit/crate_name/crate_name_test.bzl
@@ -48,7 +48,7 @@
 
 def _invalid_default_crate_name_test_impl(ctx):
     env = analysistest.begin(ctx)
-    asserts.expect_failure(env, "contains invalid character(s): /")
+    asserts.expect_failure(env, "contains invalid character(s): @")
     return analysistest.end(env)
 
 def _invalid_custom_crate_name_test_impl(ctx):
@@ -119,7 +119,7 @@
 
 def _crate_name_test():
     rust_library(
-        name = "default-crate-name-library",
+        name = "default/crate-name-library",
         srcs = ["lib.rs"],
         edition = "2018",
     )
@@ -132,7 +132,7 @@
     )
 
     rust_binary(
-        name = "default-crate-name-binary",
+        name = "default/crate-name-binary",
         srcs = ["main.rs"],
         edition = "2018",
     )
@@ -145,7 +145,7 @@
     )
 
     rust_test(
-        name = "default-crate-name-test",
+        name = "default/crate-name-test",
         srcs = ["main.rs"],
         edition = "2018",
     )
@@ -158,7 +158,7 @@
     )
 
     rust_library(
-        name = "invalid/default-crate-name",
+        name = "invalid@default-crate-name",
         srcs = ["lib.rs"],
         edition = "2018",
         tags = ["manual", "norustfmt"],
@@ -197,7 +197,7 @@
 
     default_crate_name_library_test(
         name = "default_crate_name_library_test",
-        target_under_test = ":default-crate-name-library",
+        target_under_test = ":default/crate-name-library",
     )
 
     custom_crate_name_library_test(
@@ -207,7 +207,7 @@
 
     default_crate_name_binary_test(
         name = "default_crate_name_binary_test",
-        target_under_test = ":default-crate-name-binary",
+        target_under_test = ":default/crate-name-binary",
     )
 
     custom_crate_name_binary_test(
@@ -217,7 +217,7 @@
 
     default_crate_name_test_test(
         name = "default_crate_name_test_test",
-        target_under_test = ":default-crate-name-test",
+        target_under_test = ":default/crate-name-test",
     )
 
     custom_crate_name_test_test(
@@ -227,7 +227,7 @@
 
     invalid_default_crate_name_test(
         name = "invalid_default_crate_name_test",
-        target_under_test = ":invalid/default-crate-name",
+        target_under_test = ":invalid@default-crate-name",
     )
 
     invalid_custom_crate_name_test(