Add wasm64 support. (#2866)

This PR adds support for `wasm64-unknown-unknown` although there are no
prebuilt `wasm64-unknown-unknown` rustc toolchains. Compiling for
`wasm64` will be left up to anyone using this target triple until we get
T2 support for wasm64.

---------

Co-authored-by: Andre Brisco <andre.brisco@freeform.co>
diff --git a/docs/src/flatten.md b/docs/src/flatten.md
index d3daa1b..2755299 100644
--- a/docs/src/flatten.md
+++ b/docs/src/flatten.md
@@ -1234,7 +1234,7 @@
 ## rust_wasm_bindgen
 
 <pre>
-rust_wasm_bindgen(<a href="#rust_wasm_bindgen-name">name</a>, <a href="#rust_wasm_bindgen-bindgen_flags">bindgen_flags</a>, <a href="#rust_wasm_bindgen-target">target</a>, <a href="#rust_wasm_bindgen-wasm_file">wasm_file</a>)
+rust_wasm_bindgen(<a href="#rust_wasm_bindgen-name">name</a>, <a href="#rust_wasm_bindgen-bindgen_flags">bindgen_flags</a>, <a href="#rust_wasm_bindgen-target">target</a>, <a href="#rust_wasm_bindgen-target_arch">target_arch</a>, <a href="#rust_wasm_bindgen-wasm_file">wasm_file</a>)
 </pre>
 
 Generates javascript and typescript bindings for a webassembly module using [wasm-bindgen][ws].
@@ -1251,6 +1251,7 @@
 | <a id="rust_wasm_bindgen-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
 | <a id="rust_wasm_bindgen-bindgen_flags"></a>bindgen_flags |  Flags to pass directly to the bindgen executable. See https://github.com/rustwasm/wasm-bindgen/ for details.   | List of strings | optional |  `[]`  |
 | <a id="rust_wasm_bindgen-target"></a>target |  The type of output to generate. See https://rustwasm.github.io/wasm-bindgen/reference/deployment.html for details.   | String | optional |  `"bundler"`  |
+| <a id="rust_wasm_bindgen-target_arch"></a>target_arch |  The target architecture to use for the wasm-bindgen command line option.   | String | optional |  `"wasm32"`  |
 | <a id="rust_wasm_bindgen-wasm_file"></a>wasm_file |  The `.wasm` file or crate to generate bindings for.   | <a href="https://bazel.build/concepts/labels">Label</a> | required |  |
 
 
diff --git a/docs/src/rust_wasm_bindgen.md b/docs/src/rust_wasm_bindgen.md
index cb83723..0eb91be 100644
--- a/docs/src/rust_wasm_bindgen.md
+++ b/docs/src/rust_wasm_bindgen.md
@@ -51,7 +51,7 @@
 ## rust_wasm_bindgen
 
 <pre>
-rust_wasm_bindgen(<a href="#rust_wasm_bindgen-name">name</a>, <a href="#rust_wasm_bindgen-bindgen_flags">bindgen_flags</a>, <a href="#rust_wasm_bindgen-target">target</a>, <a href="#rust_wasm_bindgen-wasm_file">wasm_file</a>)
+rust_wasm_bindgen(<a href="#rust_wasm_bindgen-name">name</a>, <a href="#rust_wasm_bindgen-bindgen_flags">bindgen_flags</a>, <a href="#rust_wasm_bindgen-target">target</a>, <a href="#rust_wasm_bindgen-target_arch">target_arch</a>, <a href="#rust_wasm_bindgen-wasm_file">wasm_file</a>)
 </pre>
 
 Generates javascript and typescript bindings for a webassembly module using [wasm-bindgen][ws].
@@ -68,6 +68,7 @@
 | <a id="rust_wasm_bindgen-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
 | <a id="rust_wasm_bindgen-bindgen_flags"></a>bindgen_flags |  Flags to pass directly to the bindgen executable. See https://github.com/rustwasm/wasm-bindgen/ for details.   | List of strings | optional |  `[]`  |
 | <a id="rust_wasm_bindgen-target"></a>target |  The type of output to generate. See https://rustwasm.github.io/wasm-bindgen/reference/deployment.html for details.   | String | optional |  `"bundler"`  |
+| <a id="rust_wasm_bindgen-target_arch"></a>target_arch |  The target architecture to use for the wasm-bindgen command line option.   | String | optional |  `"wasm32"`  |
 | <a id="rust_wasm_bindgen-wasm_file"></a>wasm_file |  The `.wasm` file or crate to generate bindings for.   | <a href="https://bazel.build/concepts/labels">Label</a> | required |  |
 
 
diff --git a/rust/platform/platform.bzl b/rust/platform/platform.bzl
index edaa586..3727d34 100644
--- a/rust/platform/platform.bzl
+++ b/rust/platform/platform.bzl
@@ -67,13 +67,28 @@
         )
 
     native.platform(
-        name = "wasm",
+        name = "wasm32",
         constraint_values = [
             "@platforms//cpu:wasm32",
             str(Label("//rust/platform/os:unknown")),
         ],
     )
 
+    # Add alias for wasm to maintain backwards compatibility.
+    native.alias(
+        name = "wasm",
+        actual = ":wasm32",
+        deprecation = "Use `@rules_rust//rust/platform:wasm32` instead",
+    )
+
+    native.platform(
+        name = "wasm64",
+        constraint_values = [
+            "@platforms//cpu:wasm64",
+            str(Label("//rust/platform/os:unknown")),
+        ],
+    )
+
     native.platform(
         name = "wasi",
         constraint_values = [
diff --git a/rust/platform/triple_mappings.bzl b/rust/platform/triple_mappings.bzl
index 567f1f8..3ab6f6d 100644
--- a/rust/platform/triple_mappings.bzl
+++ b/rust/platform/triple_mappings.bzl
@@ -49,6 +49,8 @@
     "x86_64-unknown-none",
 ]
 
+# Note that only platforms with `std` artifacts should be added
+# to this list: https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-3
 SUPPORTED_T3_PLATFORM_TRIPLES = [
     "aarch64-unknown-nto-qnx710",
 ]
@@ -82,6 +84,7 @@
     "thumbv7m": "armv7-m",
     "thumbv8m.main": "armv8-m",
     "wasm32": None,
+    "wasm64": None,
     "x86_64": "x86_64",
 }
 
@@ -357,6 +360,11 @@
             "@platforms//cpu:wasm32",
             "@platforms//os:none",
         ]
+    if target_triple == "wasm64-unknown-unknown":
+        return [
+            "@platforms//cpu:wasm64",
+            "@platforms//os:none",
+        ]
 
     triple_struct = triple(target_triple)
 
diff --git a/rust/private/dummy_cc_toolchain/BUILD.bazel b/rust/private/dummy_cc_toolchain/BUILD.bazel
index 848480f..df4290a 100644
--- a/rust/private/dummy_cc_toolchain/BUILD.bazel
+++ b/rust/private/dummy_cc_toolchain/BUILD.bazel
@@ -1,20 +1,29 @@
+# When compiling Rust code for wasm (wasm32 or wasm64), we avoid linking to cpp code so we introduce a dummy cc
+# toolchain since we know we'll never look it up.
+#
+# TODO(jedmonds@spotify.com): Need to support linking C code to rust code when compiling for wasm32 or wasm64.
+
 load("@rules_cc//cc:defs.bzl", "cc_toolchain")
 load(":dummy_cc_toolchain.bzl", "dummy_cc_config", "dummy_cc_toolchain")
 
-dummy_cc_toolchain(name = "dummy_cc_wasm32")
+dummy_cc_toolchain(name = "dummy_cc_wasm")
 
-# When compiling Rust code for wasm32, we avoid linking to cpp code so we introduce a dummy cc
-# toolchain since we know we'll never look it up.
-# TODO(jedmonds@spotify.com): Need to support linking C code to rust code when compiling for wasm32.
 toolchain(
     name = "dummy_cc_wasm32_toolchain",
-    target_compatible_with = ["//rust/platform/cpu:wasm32"],
-    toolchain = ":dummy_cc_wasm32_toolchain_cc",
+    target_compatible_with = ["@platforms//cpu:wasm32"],
+    toolchain = ":dummy_cc_wasm_toolchain_cc",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+toolchain(
+    name = "dummy_cc_wasm64_toolchain",
+    target_compatible_with = ["@platforms//cpu:wasm64"],
+    toolchain = ":dummy_cc_wasm_toolchain_cc",
     toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
 
 cc_toolchain(
-    name = "dummy_cc_wasm32_toolchain_cc",
+    name = "dummy_cc_wasm_toolchain_cc",
     all_files = ":empty",
     compiler_files = ":empty",
     dwp_files = ":empty",
@@ -23,7 +32,7 @@
     strip_files = ":empty",
     supports_param_files = 0,
     toolchain_config = ":cc_toolchain_config",
-    toolchain_identifier = "dummy_wasm32_cc",
+    toolchain_identifier = "dummy_wasm_cc",
 )
 
 dummy_cc_config(
diff --git a/rust/private/dummy_cc_toolchain/dummy_cc_toolchain.bzl b/rust/private/dummy_cc_toolchain/dummy_cc_toolchain.bzl
index 8cbf617..89012ea 100644
--- a/rust/private/dummy_cc_toolchain/dummy_cc_toolchain.bzl
+++ b/rust/private/dummy_cc_toolchain/dummy_cc_toolchain.bzl
@@ -13,7 +13,7 @@
 def _config_impl(ctx):
     return cc_common.create_cc_toolchain_config_info(
         ctx = ctx,
-        toolchain_identifier = "dummy-wasm32-cc-toolchain",
+        toolchain_identifier = "dummy-wasm-cc-toolchain",
         host_system_name = "unknown",
         target_system_name = "unknown",
         target_cpu = "unknown",
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index b17a3e0..5836040 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -1010,7 +1010,7 @@
         # Rust's built-in linker can handle linking wasm files. We don't want to attempt to use the cc
         # linker since it won't understand.
         compilation_mode = ctx.var["COMPILATION_MODE"]
-        if toolchain.target_arch != "wasm32":
+        if toolchain.target_arch not in ("wasm32", "wasm64"):
             if output_dir:
                 use_pic = _should_use_pic(cc_toolchain, feature_configuration, crate_info.type, compilation_mode)
                 rpaths = _compute_rpaths(toolchain, output_dir, dep_info, use_pic)
diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl
index c7be258..a0fda35 100644
--- a/rust/private/utils.bzl
+++ b/rust/private/utils.bzl
@@ -788,7 +788,7 @@
     prefix = "lib"
     if toolchain.target_triple and toolchain.target_os == "windows" and crate_type not in ("lib", "rlib"):
         prefix = ""
-    if toolchain.target_arch == "wasm32" and crate_type == "cdylib":
+    if toolchain.target_arch in ("wasm32", "wasm64") and crate_type == "cdylib":
         prefix = ""
 
     return "{prefix}{name}{lib_hash}{extension}".format(
diff --git a/rust/repositories.bzl b/rust/repositories.bzl
index 48aa179..44a8293 100644
--- a/rust/repositories.bzl
+++ b/rust/repositories.bzl
@@ -1069,3 +1069,4 @@
     if register_toolchain:
         native.register_toolchains(*all_toolchain_names)
         native.register_toolchains(str(Label("//rust/private/dummy_cc_toolchain:dummy_cc_wasm32_toolchain")))
+        native.register_toolchains(str(Label("//rust/private/dummy_cc_toolchain:dummy_cc_wasm64_toolchain")))
diff --git a/util/fetch_shas/fetch_shas.py b/util/fetch_shas/fetch_shas.py
index 7e0dbff..bf0538d 100755
--- a/util/fetch_shas/fetch_shas.py
+++ b/util/fetch_shas/fetch_shas.py
@@ -273,7 +273,7 @@
 
         file_key_to_sha = {}
 
-        retries = []
+        artifacts = []
 
         logging.info("Parsing artifacts...")
         for channel, versioned_info in manifest_data.items():
@@ -340,7 +340,7 @@
                         template = tool_template.replace("{target}", target)
 
                         # See if we can download the file directly.
-                        retries.extend(
+                        artifacts.extend(
                             [
                                 template.format(pkg=pkg_name, ext="tar.gz"),
                                 template.format(pkg=pkg_name, ext="tar.xz"),
@@ -352,7 +352,7 @@
         # Do a brute force check to find additional sha256 values.
         file_key_to_sha.update(
             download_direct_sha256s(
-                artifacts=sorted(set(retries)),
+                artifacts=sorted(set(artifacts)),
                 output_dir=tmp_dir / "retries",
             )
         )
diff --git a/util/fetch_shas/fetch_shas_TARGETS.txt b/util/fetch_shas/fetch_shas_TARGETS.txt
index 81acd7a..b7aea7f 100644
--- a/util/fetch_shas/fetch_shas_TARGETS.txt
+++ b/util/fetch_shas/fetch_shas_TARGETS.txt
@@ -71,6 +71,7 @@
 wasm32-unknown-emscripten
 wasm32-unknown-unknown
 wasm32-wasi
+wasm64-unknown-unknown
 x86_64-apple-darwin
 x86_64-apple-ios
 x86_64-fortanix-unknown-sgx
diff --git a/wasm_bindgen/private/transitions.bzl b/wasm_bindgen/private/transitions.bzl
index ef84443..9ae1994 100644
--- a/wasm_bindgen/private/transitions.bzl
+++ b/wasm_bindgen/private/transitions.bzl
@@ -1,18 +1,18 @@
 """Transition implementations for wasm-bindgen rust Rules"""
 
-def _wasm_bindgen_transition(_settings, _attr):
+def _wasm_bindgen_transition(_settings, attr):
     """The implementation of the `wasm_bindgen_transition` transition
 
     Args:
         _settings (dict): A dict {String:Object} of all settings declared
             in the inputs parameter to `transition()`
-        _attr (dict): A dict of attributes and values of the rule to which
+        attr (dict): A dict of attributes and values of the rule to which
             the transition is attached
 
     Returns:
         dict: A dict of new build settings values to apply
     """
-    return {"//command_line_option:platforms": str(Label("//rust/platform:wasm"))}
+    return {"//command_line_option:platforms": str(Label("//rust/platform:{}".format(attr.target_arch)))}
 
 wasm_bindgen_transition = transition(
     implementation = _wasm_bindgen_transition,
diff --git a/wasm_bindgen/private/wasm_bindgen.bzl b/wasm_bindgen/private/wasm_bindgen.bzl
index 30a401b..95a7c0b 100644
--- a/wasm_bindgen/private/wasm_bindgen.bzl
+++ b/wasm_bindgen/private/wasm_bindgen.bzl
@@ -113,6 +113,11 @@
         default = "bundler",
         values = ["web", "bundler", "nodejs", "no-modules", "deno"],
     ),
+    "target_arch": attr.string(
+        doc = "The target architecture to use for the wasm-bindgen command line option.",
+        default = "wasm32",
+        values = ["wasm32", "wasm64"],
+    ),
     "wasm_file": attr.label(
         doc = "The `.wasm` file or crate to generate bindings for.",
         allow_single_file = True,
@@ -142,6 +147,11 @@
             default = "bundler",
             values = ["web", "bundler", "nodejs", "no-modules", "deno"],
         ),
+        "target_arch": attr.string(
+            doc = "The target architecture to use for the wasm-bindgen command line option.",
+            default = "wasm32",
+            values = ["wasm32", "wasm64"],
+        ),
         "wasm_file": attr.label(
             doc = "The `.wasm` file or crate to generate bindings for.",
             allow_single_file = True,