Repository: rustwasm/wasm-bindgen
Pull request #4300 (2024-11-29 17:04:51)

Remove dead code
The code changes here should most definitely not cause any observable changes to runtime behavior.
However, instead they unfortunately cause memory allocation errors (for more info see CI), presumably caused by some UB somewhere.

daxpedda: Figured it out: I removed a `bool` parameter from a function that had 2 `bool` parameters and deleted the wrong `bool` at the call site. :facepalm: 

Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index bf6acf42..5263ee20 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -68,12 +68,12 @@ jobs:
     - run: cargo clippy --no-deps --all-features -p example-tests -- -D warnings
     - run: cargo clippy --no-deps --all-features -p wasm-bindgen-externref-xform -- -D warnings
     - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p wasm-bindgen-futures -- -D warnings
-    - run: cargo clippy --no-deps --features spans,strict-macro -p wasm-bindgen-macro -- -D warnings
-    - run: cargo clippy --no-deps --features extra-traits,spans,strict-macro -p wasm-bindgen-macro-support -- -D warnings
+    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-macro -- -D warnings
+    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-macro-support -- -D warnings
     - run: cargo clippy --no-deps --all-features -p wasm-bindgen-multi-value-xform -- -D warnings
     - run: cargo clippy --no-deps --all-features -p wasm-bindgen-shared -- -D warnings
     - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p wasm-bindgen-test -- -D warnings
-    - run: cargo clippy --no-deps -p wasm-bindgen-test-macro -- -D warnings
+    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-test-macro -- -D warnings
     - run: cargo clippy --no-deps --all-features -p wasm-bindgen-threads-xform -- -D warnings
     - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p typescript-tests -- -D warnings
     - run: cargo clippy --no-deps --all-features -p wasm-bindgen-wasm-conventions -- -D warnings
@@ -540,7 +540,7 @@ jobs:
         path: docs.tar.gz
 
   msrv-resolver:
-    name: Check for feature resolver v1 error message
+    name: Check feature resolver version 1 compatibility
     runs-on: ubuntu-latest
     strategy:
       fail-fast: false
@@ -565,7 +565,7 @@ jobs:
         cargo update -p bumpalo --precise 3.12.0
         cargo update -p log --precise 0.4.18
         cargo update -p scoped-tls --precise 1.0.0
-    - run: diff <(cargo build --target ${{ matrix.target }} ${{ matrix.features }} --message-format json | jq -r "select(.reason == \"compiler-message\") | .message.message") error-${{ matrix.rust }}.txt
+    - run: cargo build --target ${{ matrix.target }} ${{ matrix.features }}
 
   msrv-lib:
     name: Check MSRV for libraries
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2e4d998..205eafe5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,15 +5,15 @@
 
 ### Added
 
-* Add clear error message to communicate new feature resolver version requirements.
-  [#4312](https://github.com/rustwasm/wasm-bindgen/pull/4312)
-
 * Add support for multi-threading in Node.js.
   [#4318](https://github.com/rustwasm/wasm-bindgen/pull/4318)
 
 * Add `WASM_BINDGEN_TEST_DRIVER_TIMEOUT` environment variable to control the timeout to start and connect to the test driver.
   [#4320](https://github.com/rustwasm/wasm-bindgen/pull/4320)
 
+* Add support for number slices of type `MaybeUninit<T>`.
+  [#4316](https://github.com/rustwasm/wasm-bindgen/pull/4316)
+
 ### Changed
 
 * Remove `once_cell/critical-section` requirement for `no_std` with atomics.
@@ -27,6 +27,9 @@
 * Fix macro-hygiene for calls to `std::thread_local!`.
   [#4315](https://github.com/rustwasm/wasm-bindgen/pull/4315)
 
+* Fix feature resolver version 1 compatibility.
+  [#4327](https://github.com/rustwasm/wasm-bindgen/pull/4327)
+
 --------------------------------------------------------------------------------
 
 ## [0.2.97](https://github.com/rustwasm/wasm-bindgen/compare/0.2.96...0.2.97)
diff --git a/Cargo.toml b/Cargo.toml
index d0aaa348..dae4e2bd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -47,26 +47,12 @@ serde = { version = "1.0", optional = true }
 serde_json = { version = "1.0", optional = true }
 wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.97", default-features = false }
 
-[target.'cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"), target_feature = "atomics"))'.dependencies]
-wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.97", default-features = false, features = [
-  "atomics",
-] }
-
-[target.'cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"), wasm_bindgen_unstable_test_coverage))'.dependencies]
-wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.97", default-features = false, features = [
-  "coverage",
-] }
-
-[target.'cfg(__wasm_bindgen_resolver_1)'.dependencies]
-wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.97", default-features = false, features = [
-  "xxx_resolver_1",
-] }
-
 [dev-dependencies]
 wasm-bindgen-test = { path = 'crates/test' }
 
 [target.'cfg(target_arch = "wasm32")'.dev-dependencies]
 js-sys = { path = 'crates/js-sys' }
+paste = "1"
 serde_derive = "1.0"
 wasm-bindgen-futures = { path = 'crates/futures' }
 wasm-bindgen-test-crate-a = { path = 'tests/crates/a' }
@@ -90,7 +76,7 @@ too_many_arguments = "allow"
 type_complexity = "allow"
 
 [workspace]
-exclude = ["crates/msrv"]
+exclude = ["crates/msrv/resolver", "crates/msrv/lib", "crates/msrv/cli"]
 members = [
   "benchmarks",
   "crates/cli",
diff --git a/README.md b/README.md
index 05266a62..d8e07bc0 100644
--- a/README.md
+++ b/README.md
@@ -114,8 +114,6 @@ Libraries that are released on [crates.io](https://crates.io) have a MSRV of v1.
 
 CLI tools and their corresponding support libraries have a MSRV of v1.76. Changes to the MSRV will be accompanied by a patch version bump.
 
-[Feature resolver version 2](https://doc.rust-lang.org/1.83.0/cargo/reference/resolver.html#feature-resolver-version-2) is required.
-
 ## License
 
 This project is licensed under either of
diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml
index 70323125..3e0603b9 100644
--- a/crates/backend/Cargo.toml
+++ b/crates/backend/Cargo.toml
@@ -14,18 +14,14 @@ rust-version = "1.57"
 version = "0.2.97"
 
 [features]
-atomics = []
-coverage = []
 default = ["std"]
 extra-traits = ["syn/extra-traits"]
 spans = []
 std = []
-xxx_resolver_1 = []
 
 [dependencies]
 bumpalo = "3.0.0"
 log = "0.4"
-once_cell = "1.12"
 proc-macro2 = "1.0"
 quote = '1.0'
 syn = { version = '2.0', features = ['full'] }
diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs
index a715ec75..23599fc8 100644
--- a/crates/backend/src/codegen.rs
+++ b/crates/backend/src/codegen.rs
@@ -2,13 +2,12 @@ use crate::ast;
 use crate::encode;
 use crate::encode::EncodeChunk;
 use crate::Diagnostic;
-use once_cell::sync::Lazy;
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::format_ident;
 use quote::quote_spanned;
 use quote::{quote, ToTokens};
+use std::cell::RefCell;
 use std::collections::{HashMap, HashSet};
-use std::sync::Mutex;
 use syn::parse_quote;
 use syn::spanned::Spanned;
 use wasm_bindgen_shared as shared;
@@ -224,7 +223,6 @@ impl ToTokens for ast::Struct {
         let free_fn = Ident::new(&shared::free_function(&name_str), Span::call_site());
         let unwrap_fn = Ident::new(&shared::unwrap_function(&name_str), Span::call_site());
         let wasm_bindgen = &self.wasm_bindgen;
-        let maybe_no_coverage = coverage();
         (quote! {
             #[automatically_derived]
             impl #wasm_bindgen::describe::WasmDescribe for #name {
@@ -296,11 +294,11 @@ impl ToTokens for ast::Struct {
             #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
             #[automatically_derived]
             const _: () = {
+                #wasm_bindgen::__wbindgen_coverage! {
                 #[no_mangle]
                 #[doc(hidden)]
                 // `allow_delayed` is whether it's ok to not actually free the `ptr` immediately
                 // if it's still borrowed.
-                #maybe_no_coverage
                 pub unsafe extern "C" fn #free_fn(ptr: u32, allow_delayed: u32) {
                     use #wasm_bindgen::__rt::alloc::rc::Rc;
 
@@ -315,6 +313,7 @@ impl ToTokens for ast::Struct {
                         let _ = <#name as #wasm_bindgen::convert::FromWasmAbi>::from_abi(ptr);
                     }
                 }
+                }
             };
 
             #[automatically_derived]
@@ -476,7 +475,6 @@ impl ToTokens for ast::StructField {
             quote! { assert_copy::<#ty>() }
         };
         let maybe_assert_copy = respan(maybe_assert_copy, ty);
-        let maybe_no_coverage = coverage();
 
         // Split this out so that it isn't affected by `quote_spanned!`.
         //
@@ -495,9 +493,9 @@ impl ToTokens for ast::StructField {
         (quote! {
             #[automatically_derived]
             const _: () = {
+                #wasm_bindgen::__wbindgen_coverage! {
                 #[cfg_attr(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")), no_mangle)]
                 #[doc(hidden)]
-                #maybe_no_coverage
                 pub unsafe extern "C" fn #getter(js: u32)
                     -> #wasm_bindgen::convert::WasmRet<<#ty as #wasm_bindgen::convert::IntoWasmAbi>::Abi>
                 {
@@ -512,6 +510,7 @@ impl ToTokens for ast::StructField {
                     let val = #val;
                     <#ty as IntoWasmAbi>::into_abi(val).into()
                 }
+                }
             };
         })
         .to_tokens(tokens);
@@ -537,9 +536,9 @@ impl ToTokens for ast::StructField {
             #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
             #[automatically_derived]
             const _: () = {
+                #wasm_bindgen::__wbindgen_coverage! {
                 #[no_mangle]
                 #[doc(hidden)]
-                #maybe_no_coverage
                 pub unsafe extern "C" fn #setter(
                     js: u32,
                     #(#args,)*
@@ -553,6 +552,7 @@ impl ToTokens for ast::StructField {
                     let val = <#ty as FromWasmAbi>::from_abi(val);
                     (*js).borrow_mut().#rust_name = val;
                 }
+                }
             };
         })
         .to_tokens(tokens);
@@ -788,23 +788,22 @@ impl TryToTokens for ast::Export {
             quote! {}
         };
 
-        let maybe_no_coverage = coverage();
-
         (quote! {
             #[automatically_derived]
             const _: () = {
+                #wasm_bindgen::__wbindgen_coverage! {
                 #(#attrs)*
                 #[cfg_attr(
                     all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
                     export_name = #export_name,
                 )]
-                #maybe_no_coverage
                 pub unsafe extern "C" fn #generated_name(#(#args),*) -> #wasm_bindgen::convert::WasmRet<#projection::Abi> {
                     #start_check
 
                     let #ret = #call;
                     #convert_ret
                 }
+                }
             };
         })
         .to_tokens(into);
@@ -1159,8 +1158,6 @@ impl ToTokens for ast::StringEnum {
         let hole = variant_count + 1;
         let attrs = &self.rust_attrs;
 
-        let maybe_no_coverage = coverage();
-
         let invalid_to_str_msg = format!(
             "Converting an invalid string enum ({}) back to a string is currently not supported",
             enum_name
@@ -1247,7 +1244,6 @@ impl ToTokens for ast::StringEnum {
 
             #[automatically_derived]
             impl #wasm_bindgen::describe::WasmDescribe for #enum_name {
-                #maybe_no_coverage
                 fn describe() {
                     use #wasm_bindgen::describe::*;
                     inform(STRING_ENUM);
@@ -1546,7 +1542,6 @@ impl ToTokens for ast::Enum {
         } else {
             quote! { u32 }
         };
-        let maybe_no_coverage = coverage();
         let cast_clauses = self.variants.iter().map(|variant| {
             let variant_name = &variant.name;
             quote! {
@@ -1594,7 +1589,6 @@ impl ToTokens for ast::Enum {
 
             #[automatically_derived]
             impl #wasm_bindgen::describe::WasmDescribe for #enum_name {
-                #maybe_no_coverage
                 fn describe() {
                     use #wasm_bindgen::describe::*;
                     inform(ENUM);
@@ -1778,20 +1772,9 @@ fn thread_local_import(
                     __inner: &_VAL,
                 }
             };
-            #[cfg(all(not(feature = "std"), not(feature = "atomics")))]
-            let inner = quote! {
-                static _VAL: #wasm_bindgen::__rt::LazyCell<#actual_ty> = #wasm_bindgen::__rt::LazyCell::new(init);
-                #wasm_bindgen::JsThreadLocal {
-                    __inner: &_VAL,
-                }
-            };
-            #[cfg(all(not(feature = "std"), feature = "atomics"))]
+            #[cfg(not(feature = "std"))]
             let inner = quote! {
-                #[thread_local]
-                static _VAL: #wasm_bindgen::__rt::LazyCell<#actual_ty> = #wasm_bindgen::__rt::LazyCell::new(init);
-                #wasm_bindgen::JsThreadLocal {
-                    __inner: || unsafe {  #wasm_bindgen::__rt::LazyCell::force(&_VAL) as *const #actual_ty },
-                }
+                #wasm_bindgen::__wbindgen_thread_local!(#wasm_bindgen, #actual_ty)
             };
 
             quote! {
@@ -1847,20 +1830,16 @@ impl<T: ToTokens> ToTokens for Descriptor<'_, T> {
         // It's up to the descriptors themselves to ensure they have unique
         // names for unique items imported, currently done via `ShortHash` and
         // hashing appropriate data into the symbol name.
-        static DESCRIPTORS_EMITTED: Lazy<Mutex<HashSet<String>>> = Lazy::new(Default::default);
+        thread_local! {
+            static DESCRIPTORS_EMITTED: RefCell<HashSet<String>> = RefCell::default();
+        }
 
         let ident = self.ident;
 
-        if !DESCRIPTORS_EMITTED
-            .lock()
-            .unwrap()
-            .insert(ident.to_string())
-        {
+        if !DESCRIPTORS_EMITTED.with(|list| list.borrow_mut().insert(ident.to_string())) {
             return;
         }
 
-        let maybe_no_coverage = coverage();
-
         let name = Ident::new(&format!("__wbindgen_describe_{}", ident), ident.span());
         let inner = &self.inner;
         let attrs = &self.attrs;
@@ -1869,16 +1848,17 @@ impl<T: ToTokens> ToTokens for Descriptor<'_, T> {
             #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
             #[automatically_derived]
             const _: () = {
+                #wasm_bindgen::__wbindgen_coverage! {
                 #(#attrs)*
                 #[no_mangle]
                 #[doc(hidden)]
-                #maybe_no_coverage
                 pub extern "C" fn #name() {
                     use #wasm_bindgen::describe::*;
                     // See definition of `link_mem_intrinsics` for what this is doing
                     #wasm_bindgen::__rt::link_mem_intrinsics();
                     #inner
                 }
+                }
             };
         })
         .to_tokens(tokens);
@@ -1963,10 +1943,3 @@ fn respan(input: TokenStream, span: &dyn ToTokens) -> TokenStream {
     }
     new_tokens.into_iter().collect()
 }
-
-fn coverage() -> Option<TokenStream> {
-    #[cfg(all(not(feature = "xxx_resolver_1"), feature = "coverage"))]
-    return Some(quote! { #[coverage(off)] });
-    #[cfg(any(feature = "xxx_resolver_1", not(feature = "coverage")))]
-    None
-}
diff --git a/crates/cli-support/src/js/binding.rs b/crates/cli-support/src/js/binding.rs
index d5ed0136..54be1481 100644
--- a/crates/cli-support/src/js/binding.rs
+++ b/crates/cli-support/src/js/binding.rs
@@ -1246,7 +1246,6 @@ fn instruction(
 
         Instruction::CachedStringLoad {
             owned,
-            optional: _,
             mem,
             free,
             table,
diff --git a/crates/cli-support/src/wit/mod.rs b/crates/cli-support/src/wit/mod.rs
index 07fb5090..930fddca 100644
--- a/crates/cli-support/src/wit/mod.rs
+++ b/crates/cli-support/src/wit/mod.rs
@@ -1205,7 +1205,7 @@ impl<'a> Context<'a> {
         kind: AdapterJsImportKind,
     ) -> Result<AdapterId, Error> {
         let import = self.module.imports.get(import);
-        let (import_module, import_name) = (import.module.clone(), import.name.clone());
+        let import_name = import.name.clone();
         let import_id = import.id();
         let core_id = match import.kind {
             walrus::ImportKind::Function(f) => f,
@@ -1242,7 +1242,6 @@ impl<'a> Context<'a> {
             ret.input,
             vec![],
             AdapterKind::Import {
-                module: import_module,
                 name: import_name,
                 kind,
             },
diff --git a/crates/cli-support/src/wit/outgoing.rs b/crates/cli-support/src/wit/outgoing.rs
index ba15babf..b5eaeefa 100644
--- a/crates/cli-support/src/wit/outgoing.rs
+++ b/crates/cli-support/src/wit/outgoing.rs
@@ -110,7 +110,7 @@ impl InstructionBuilder<'_, '_> {
             Descriptor::Ref(d) => self.outgoing_ref(false, d)?,
             Descriptor::RefMut(d) => self.outgoing_ref(true, d)?,
 
-            Descriptor::CachedString => self.cached_string(false, true)?,
+            Descriptor::CachedString => self.cached_string(true)?,
 
             Descriptor::String => {
                 // fetch the ptr/length ...
@@ -193,7 +193,7 @@ impl InstructionBuilder<'_, '_> {
                     &[AdapterType::NamedExternref(name.clone())],
                 );
             }
-            Descriptor::CachedString => self.cached_string(false, false)?,
+            Descriptor::CachedString => self.cached_string(false)?,
 
             Descriptor::String => {
                 self.instruction(
@@ -335,7 +335,7 @@ impl InstructionBuilder<'_, '_> {
             Descriptor::Ref(d) => self.outgoing_option_ref(false, d)?,
             Descriptor::RefMut(d) => self.outgoing_option_ref(true, d)?,
 
-            Descriptor::CachedString => self.cached_string(true, true)?,
+            Descriptor::CachedString => self.cached_string(true)?,
 
             Descriptor::String | Descriptor::Vector(_) => {
                 let kind = arg.vector_kind().ok_or_else(|| {
@@ -525,7 +525,7 @@ impl InstructionBuilder<'_, '_> {
                     &[AdapterType::NamedExternref(name.clone()).option()],
                 );
             }
-            Descriptor::CachedString => self.cached_string(true, false)?,
+            Descriptor::CachedString => self.cached_string(false)?,
             Descriptor::String | Descriptor::Slice(_) => {
                 let kind = arg.vector_kind().ok_or_else(|| {
                     format_err!(
@@ -574,14 +574,13 @@ impl InstructionBuilder<'_, '_> {
         self.instruction(&[AdapterType::I64], instr, &[output]);
     }
 
-    fn cached_string(&mut self, optional: bool, owned: bool) -> Result<(), Error> {
+    fn cached_string(&mut self, owned: bool) -> Result<(), Error> {
         let mem = self.cx.memory()?;
         let free = self.cx.free()?;
         self.instruction(
             &[AdapterType::I32, AdapterType::I32],
             Instruction::CachedStringLoad {
                 owned,
-                optional,
                 mem,
                 free,
                 table: None,
diff --git a/crates/cli-support/src/wit/standard.rs b/crates/cli-support/src/wit/standard.rs
index b0b1cb68..8b3780f3 100644
--- a/crates/cli-support/src/wit/standard.rs
+++ b/crates/cli-support/src/wit/standard.rs
@@ -40,8 +40,6 @@ pub enum AdapterKind {
         instructions: Vec<InstructionData>,
     },
     Import {
-        #[allow(dead_code)]
-        module: String,
         name: String,
         kind: AdapterJsImportKind,
     },
@@ -314,8 +312,6 @@ pub enum Instruction {
     /// pops ptr/length i32, loads string from cache
     CachedStringLoad {
         owned: bool,
-        #[allow(dead_code)]
-        optional: bool,
         mem: walrus::MemoryId,
         free: walrus::FunctionId,
         /// If we're in reference-types mode, the externref table ID to get the cached string from.
diff --git a/crates/macro-support/Cargo.toml b/crates/macro-support/Cargo.toml
index ed92337b..41c28fc1 100644
--- a/crates/macro-support/Cargo.toml
+++ b/crates/macro-support/Cargo.toml
@@ -14,14 +14,11 @@ rust-version = "1.57"
 version = "0.2.97"
 
 [features]
-atomics = ["wasm-bindgen-backend/atomics"]
-coverage = ["wasm-bindgen-backend/coverage"]
 default = ["std"]
 extra-traits = ["syn/extra-traits"]
 spans = ["wasm-bindgen-backend/spans"]
 std = ["wasm-bindgen-backend/std"]
 strict-macro = []
-xxx_resolver_1 = ["wasm-bindgen-backend/xxx_resolver_1"]
 
 [dependencies]
 proc-macro2 = "1.0"
diff --git a/crates/macro/Cargo.toml b/crates/macro/Cargo.toml
index ebb4377f..e6a5f56d 100644
--- a/crates/macro/Cargo.toml
+++ b/crates/macro/Cargo.toml
@@ -17,14 +17,11 @@ version = "0.2.97"
 proc-macro = true
 
 [features]
-atomics = ["wasm-bindgen-macro-support/atomics"]
-coverage = ["wasm-bindgen-macro-support/coverage"]
 default = ["std"]
 spans = ["wasm-bindgen-macro-support/spans"]
 std = ["wasm-bindgen-macro-support/std"]
 strict-macro = ["wasm-bindgen-macro-support/strict-macro"]
 xxx_debug_only_print_generated_code = []
-xxx_resolver_1 = ["wasm-bindgen-macro-support/xxx_resolver_1"]
 
 [dependencies]
 quote = "1.0"
diff --git a/crates/macro/src/lib.rs b/crates/macro/src/lib.rs
index 5ae63303..aa4ab3f0 100644
--- a/crates/macro/src/lib.rs
+++ b/crates/macro/src/lib.rs
@@ -1,37 +1,11 @@
 #![doc(html_root_url = "https://docs.rs/wasm-bindgen-macro/0.2")]
-#![cfg_attr(
-    all(
-        not(feature = "xxx_resolver_1"),
-        any(feature = "coverage", all(not(feature = "std"), feature = "atomics"))
-    ),
-    feature(allow_internal_unstable),
-    allow(internal_features)
-)]
 
 extern crate proc_macro;
 
 use proc_macro::TokenStream;
 use quote::quote;
 
-#[cfg(feature = "xxx_resolver_1")]
-compile_error!("Feature resolver version 2 or up is required.\n\
-                Please add `resolver = \"2\"` to your `Cargo.toml`.\n\
-                \n\
-                See <https://doc.rust-lang.org/1.83.0/cargo/reference/resolver.html#feature-resolver-version-2>.");
-
 #[proc_macro_attribute]
-#[cfg_attr(
-    all(not(feature = "xxx_resolver_1"), feature = "coverage"),
-    allow_internal_unstable(coverage_attribute)
-)]
-#[cfg_attr(
-    all(
-        not(feature = "xxx_resolver_1"),
-        not(feature = "std"),
-        feature = "atomics"
-    ),
-    allow_internal_unstable(thread_local)
-)]
 pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
     match wasm_bindgen_macro_support::expand(attr.into(), input.into()) {
         Ok(tokens) => {
@@ -58,10 +32,6 @@ pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
 /// let worker = Worker::new(&wasm_bindgen::link_to!(module = "/src/worker.js"));
 /// ```
 #[proc_macro]
-#[cfg_attr(
-    all(not(feature = "xxx_resolver_1"), feature = "coverage"),
-    allow_internal_unstable(coverage_attribute)
-)]
 pub fn link_to(input: TokenStream) -> TokenStream {
     match wasm_bindgen_macro_support::expand_link_to(input.into()) {
         Ok(tokens) => {
@@ -78,10 +48,6 @@ pub fn link_to(input: TokenStream) -> TokenStream {
 }
 
 #[proc_macro_attribute]
-#[cfg_attr(
-    all(not(feature = "xxx_resolver_1"), feature = "coverage"),
-    allow_internal_unstable(coverage_attribute)
-)]
 pub fn __wasm_bindgen_class_marker(attr: TokenStream, input: TokenStream) -> TokenStream {
     match wasm_bindgen_macro_support::expand_class_marker(attr.into(), input.into()) {
         Ok(tokens) => {
diff --git a/crates/msrv/resolver/Cargo.toml b/crates/msrv/resolver/Cargo.toml
index 0f44e15a..6c7eeffb 100644
--- a/crates/msrv/resolver/Cargo.toml
+++ b/crates/msrv/resolver/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 edition = "2021"
-name = "msrv-library-test"
+name = "msrv-resolver-test"
 publish = false
 resolver = "1"
 version = "0.0.0"
diff --git a/crates/msrv/resolver/error-1.57.txt b/crates/msrv/resolver/error-1.57.txt
deleted file mode 100644
index 5a255fbc..00000000
--- a/crates/msrv/resolver/error-1.57.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Feature resolver version 2 or up is required.
-Please add `resolver = "2"` to your `Cargo.toml`.
-
-See <https://doc.rust-lang.org/1.83.0/cargo/reference/resolver.html#feature-resolver-version-2>.
-aborting due to previous error
diff --git a/crates/msrv/resolver/error-stable.txt b/crates/msrv/resolver/error-stable.txt
deleted file mode 100644
index 5dd74366..00000000
--- a/crates/msrv/resolver/error-stable.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Feature resolver version 2 or up is required.
-Please add `resolver = "2"` to your `Cargo.toml`.
-
-See <https://doc.rust-lang.org/1.83.0/cargo/reference/resolver.html#feature-resolver-version-2>.
diff --git a/guide/src/reference/types/boxed-number-slices.md b/guide/src/reference/types/boxed-number-slices.md
index 6df85e18..4196d48e 100644
--- a/guide/src/reference/types/boxed-number-slices.md
+++ b/guide/src/reference/types/boxed-number-slices.md
@@ -1,4 +1,4 @@
-# Boxed Number Slices: `Box<[u8]>`, `Box<[i8]>`, `Box<[u16]>`, `Box<[i16]>`, `Box<[u32]>`, `Box<[i32]>`, `Box<[u64]>`, `Box<[i64]>`, `Box<[f32]>`, and `Box<[f64]>`
+# Boxed Number Slices: `Box<[u8]>`, `Box<[i8]>`, `Box<[u16]>`, `Box<[i16]>`, `Box<[u32]>`, `Box<[i32]>`, `Box<[u64]>`, `Box<[i64]>`, `Box<[f32]>`, `Box<[f64]>`, `Box<[MaybeUninit<u8>]>`, `Box<[MaybeUninit<i8>]>`, `Box<[MaybeUninit<u16>]>`, `Box<[MaybeUninit<i16>]>`, `Box<[MaybeUninit<u32>]>`, `Box<[MaybeUninit<i32>]>`, `Box<[MaybeUninit<u64>]>`, `Box<[MaybeUninit<i64>]>`, `Box<[MaybeUninit<f32>]>`, and `Box<[MaybeUninit<f64>]>`
 
 | `T` parameter | `&T` parameter | `&mut T` parameter | `T` return value | `Option<T>` parameter | `Option<T>` return value | JavaScript representation |
 |:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -8,6 +8,10 @@
 from the Wasm linear memory when returning a boxed slice to JavaScript, and vice
 versa when receiving a JavaScript `TypedArray` as a boxed slice in Rust.
 
+> **Note:** Numeric `MaybeUninit<T>` can always be assumed to be initialized
+> upon transmission from Rust to JS and vice-versa. However, uninitialized
+> values coming from Rust might contain unspecified values.
+
 ## Example Rust Usage
 
 ```rust
diff --git a/guide/src/reference/types/number-slices.md b/guide/src/reference/types/number-slices.md
index 191430a9..11da9967 100644
--- a/guide/src/reference/types/number-slices.md
+++ b/guide/src/reference/types/number-slices.md
@@ -1,9 +1,13 @@
-# Number Slices: `[u8]`, `[i8]`, `[u16]`, `[i16]`, `[u32]`, `[i32]`, `[u64]`, `[i64]`, `[f32]`, and `[f64]`
+# Number Slices: `[u8]`, `[i8]`, `[u16]`, `[i16]`, `[u32]`, `[i32]`, `[u64]`, `[i64]`, `[f32]`, `[f64]`, `[MaybeUninit<u8>]`, `[MaybeUninit<i8>]`, `[MaybeUninit<u16>]`, `[MaybeUninit<i16>]`, `[MaybeUninit<u32>]`, `[MaybeUninit<i32>]`, `[MaybeUninit<u64>]`, `[MaybeUninit<i64>]`, `[MaybeUninit<f32>]`, and `[MaybeUninit<f64>]`
 
 | `T` parameter | `&T` parameter | `&mut T` parameter | `T` return value | `Option<&T>` parameter | `Option<T>` return value | JavaScript representation |
 |:---:|:---:|:---:|:---:|:---:|:---:|:---:|
 | No | Yes | Yes | No | No | No | A JavaScript `TypedArray` view of the Wasm memory for the boxed slice of the appropriate type (`Int32Array`, `Uint8Array`, etc) |
 
+> **Note:** Numeric `MaybeUninit<T>` can always be assumed to be initialized
+> upon transmission from Rust to JS and vice-versa. However, uninitialized
+> values coming from Rust might contain unspecified values.
+
 ## Example Rust Usage
 
 ```rust
diff --git a/src/convert/slices.rs b/src/convert/slices.rs
index 6c23926e..ac9a4624 100644
--- a/src/convert/slices.rs
+++ b/src/convert/slices.rs
@@ -1,7 +1,7 @@
 use alloc::boxed::Box;
 use alloc::string::String;
 use alloc::vec::Vec;
-use core::mem;
+use core::mem::{self, MaybeUninit};
 use core::ops::{Deref, DerefMut};
 use core::str;
 
@@ -118,12 +118,19 @@ impl<T> DerefMut for MutSlice<T> {
 }
 
 macro_rules! vectors {
-    ($($t:ident)*) => ($(
+    ($($t:ty)*) => ($(
+        vectors_internal!($t);
+        vectors_internal!(MaybeUninit<$t>);
+    )*)
+}
+
+macro_rules! vectors_internal {
+    ($t:ty) => {
         impl WasmDescribeVector for $t {
             #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
             fn describe_vector() {
                 inform(VECTOR);
-                $t::describe();
+                <$t>::describe();
             }
         }
 
@@ -167,7 +174,9 @@ macro_rules! vectors {
 
         impl<'a> OptionIntoWasmAbi for &'a [$t] {
             #[inline]
-            fn none() -> WasmSlice { null_slice() }
+            fn none() -> WasmSlice {
+                null_slice()
+            }
         }
 
         impl<'a> IntoWasmAbi for &'a mut [$t] {
@@ -181,7 +190,9 @@ macro_rules! vectors {
 
         impl<'a> OptionIntoWasmAbi for &'a mut [$t] {
             #[inline]
-            fn none() -> WasmSlice { null_slice() }
+            fn none() -> WasmSlice {
+                null_slice()
+            }
         }
 
         impl RefFromWasmAbi for [$t] {
@@ -215,7 +226,7 @@ macro_rules! vectors {
                 Self::ref_from_abi(js)
             }
         }
-    )*)
+    };
 }
 
 vectors! {
diff --git a/src/describe.rs b/src/describe.rs
index 99874498..708e1103 100644
--- a/src/describe.rs
+++ b/src/describe.rs
@@ -6,7 +6,7 @@
 use alloc::boxed::Box;
 use alloc::string::String;
 use alloc::vec::Vec;
-use core::ptr::NonNull;
+use core::{mem::MaybeUninit, ptr::NonNull};
 
 use crate::{Clamped, JsError, JsObject, JsValue};
 use cfg_if::cfg_if;
@@ -229,6 +229,13 @@ impl<T: WasmDescribe, E: Into<JsValue>> WasmDescribe for Result<T, E> {
     }
 }
 
+impl<T: WasmDescribe> WasmDescribe for MaybeUninit<T> {
+    #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
+    fn describe() {
+        T::describe();
+    }
+}
+
 impl<T: WasmDescribe> WasmDescribe for Clamped<T> {
     #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
     fn describe() {
diff --git a/src/lib.rs b/src/lib.rs
index 6e17e245..73a61477 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,10 +6,15 @@
 //! interface.
 
 #![no_std]
-#![cfg_attr(wasm_bindgen_unstable_test_coverage, feature(coverage_attribute))]
+#![cfg_attr(
+    wasm_bindgen_unstable_test_coverage,
+    feature(coverage_attribute, allow_internal_unstable),
+    allow(internal_features)
+)]
 #![cfg_attr(
     all(not(feature = "std"), target_feature = "atomics"),
-    feature(thread_local)
+    feature(thread_local, allow_internal_unstable),
+    allow(internal_features)
 )]
 #![allow(coherence_leak_check)]
 #![doc(html_root_url = "https://docs.rs/wasm-bindgen/0.2")]
@@ -1708,6 +1713,54 @@ pub mod __rt {
         }
     }
 
+    #[macro_export]
+    #[doc(hidden)]
+    #[cfg(all(not(feature = "std"), not(target_feature = "atomics")))]
+    macro_rules! __wbindgen_thread_local {
+        ($wasm_bindgen:tt, $actual_ty:ty) => {{
+            static _VAL: $wasm_bindgen::__rt::LazyCell<$actual_ty> =
+                $wasm_bindgen::__rt::LazyCell::new(init);
+            $wasm_bindgen::JsThreadLocal { __inner: &_VAL }
+        }};
+    }
+
+    #[macro_export]
+    #[doc(hidden)]
+    #[cfg(all(not(feature = "std"), target_feature = "atomics"))]
+    #[allow_internal_unstable(thread_local)]
+    macro_rules! __wbindgen_thread_local {
+        ($wasm_bindgen:tt, $actual_ty:ty) => {{
+            #[thread_local]
+            static _VAL: $wasm_bindgen::__rt::LazyCell<$actual_ty> =
+                $wasm_bindgen::__rt::LazyCell::new(init);
+            $wasm_bindgen::JsThreadLocal {
+                __inner: || unsafe {
+                    $wasm_bindgen::__rt::LazyCell::force(&_VAL) as *const $actual_ty
+                },
+            }
+        }};
+    }
+
+    #[macro_export]
+    #[doc(hidden)]
+    #[cfg(not(wasm_bindgen_unstable_test_coverage))]
+    macro_rules! __wbindgen_coverage {
+        ($item:item) => {
+            $item
+        };
+    }
+
+    #[macro_export]
+    #[doc(hidden)]
+    #[cfg(wasm_bindgen_unstable_test_coverage)]
+    #[allow_internal_unstable(coverage_attribute)]
+    macro_rules! __wbindgen_coverage {
+        ($item:item) => {
+            #[coverage(off)]
+            $item
+        };
+    }
+
     #[inline]
     pub fn assert_not_null<T>(s: *mut T) {
         if s.is_null() {


Test patch:
diff --git a/crates/cli/tests/reference/echo.d.ts b/crates/cli/tests/reference/echo.d.ts
index 7f72b5e2..c318f636 100644
--- a/crates/cli/tests/reference/echo.d.ts
+++ b/crates/cli/tests/reference/echo.d.ts
@@ -25,6 +25,14 @@ export function echo_vec_u32(a: Uint32Array): Uint32Array;
 export function echo_vec_i32(a: Int32Array): Int32Array;
 export function echo_vec_u64(a: BigUint64Array): BigUint64Array;
 export function echo_vec_i64(a: BigInt64Array): BigInt64Array;
+export function echo_vec_uninit_u8(a: Uint8Array): Uint8Array;
+export function echo_vec_uninit_i8(a: Int8Array): Int8Array;
+export function echo_vec_uninit_u16(a: Uint16Array): Uint16Array;
+export function echo_vec_uninit_i16(a: Int16Array): Int16Array;
+export function echo_vec_uninit_u32(a: Uint32Array): Uint32Array;
+export function echo_vec_uninit_i32(a: Int32Array): Int32Array;
+export function echo_vec_uninit_u64(a: BigUint64Array): BigUint64Array;
+export function echo_vec_uninit_i64(a: BigInt64Array): BigInt64Array;
 export function echo_vec_string(a: (string)[]): (string)[];
 export function echo_struct(a: Foo): Foo;
 export function echo_vec_struct(a: (Foo)[]): (Foo)[];
@@ -53,6 +61,14 @@ export function echo_option_vec_u32(a?: Uint32Array): Uint32Array | undefined;
 export function echo_option_vec_i32(a?: Int32Array): Int32Array | undefined;
 export function echo_option_vec_u64(a?: BigUint64Array): BigUint64Array | undefined;
 export function echo_option_vec_i64(a?: BigInt64Array): BigInt64Array | undefined;
+export function echo_option_vec_uninit_u8(a?: Uint8Array): Uint8Array | undefined;
+export function echo_option_vec_uninit_i8(a?: Int8Array): Int8Array | undefined;
+export function echo_option_vec_uninit_u16(a?: Uint16Array): Uint16Array | undefined;
+export function echo_option_vec_uninit_i16(a?: Int16Array): Int16Array | undefined;
+export function echo_option_vec_uninit_u32(a?: Uint32Array): Uint32Array | undefined;
+export function echo_option_vec_uninit_i32(a?: Int32Array): Int32Array | undefined;
+export function echo_option_vec_uninit_u64(a?: BigUint64Array): BigUint64Array | undefined;
+export function echo_option_vec_uninit_i64(a?: BigInt64Array): BigInt64Array | undefined;
 export function echo_option_vec_string(a?: (string)[]): (string)[] | undefined;
 export function echo_option_struct(a?: Foo): Foo | undefined;
 export function echo_option_vec_struct(a?: (Foo)[]): (Foo)[] | undefined;
diff --git a/crates/cli/tests/reference/echo.js b/crates/cli/tests/reference/echo.js
index f2eb7da3..1809b0e8 100644
--- a/crates/cli/tests/reference/echo.js
+++ b/crates/cli/tests/reference/echo.js
@@ -554,6 +554,110 @@ export function echo_vec_i64(a) {
     return v2;
 }
 
+/**
+ * @param {Uint8Array} a
+ * @returns {Uint8Array}
+ */
+export function echo_vec_uninit_u8(a) {
+    const ptr0 = passArray8ToWasm0(a, wasm.__wbindgen_malloc);
+    const len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_vec_uninit_u8(ptr0, len0);
+    var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
+    wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
+    return v2;
+}
+
+/**
+ * @param {Int8Array} a
+ * @returns {Int8Array}
+ */
+export function echo_vec_uninit_i8(a) {
+    const ptr0 = passArray8ToWasm0(a, wasm.__wbindgen_malloc);
+    const len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_vec_uninit_i8(ptr0, len0);
+    var v2 = getArrayI8FromWasm0(ret[0], ret[1]).slice();
+    wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
+    return v2;
+}
+
+/**
+ * @param {Uint16Array} a
+ * @returns {Uint16Array}
+ */
+export function echo_vec_uninit_u16(a) {
+    const ptr0 = passArray16ToWasm0(a, wasm.__wbindgen_malloc);
+    const len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_vec_uninit_u16(ptr0, len0);
+    var v2 = getArrayU16FromWasm0(ret[0], ret[1]).slice();
+    wasm.__wbindgen_free(ret[0], ret[1] * 2, 2);
+    return v2;
+}
+
+/**
+ * @param {Int16Array} a
+ * @returns {Int16Array}
+ */
+export function echo_vec_uninit_i16(a) {
+    const ptr0 = passArray16ToWasm0(a, wasm.__wbindgen_malloc);
+    const len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_vec_uninit_i16(ptr0, len0);
+    var v2 = getArrayI16FromWasm0(ret[0], ret[1]).slice();
+    wasm.__wbindgen_free(ret[0], ret[1] * 2, 2);
+    return v2;
+}
+
+/**
+ * @param {Uint32Array} a
+ * @returns {Uint32Array}
+ */
+export function echo_vec_uninit_u32(a) {
+    const ptr0 = passArray32ToWasm0(a, wasm.__wbindgen_malloc);
+    const len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_vec_uninit_u32(ptr0, len0);
+    var v2 = getArrayU32FromWasm0(ret[0], ret[1]).slice();
+    wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
+    return v2;
+}
+
+/**
+ * @param {Int32Array} a
+ * @returns {Int32Array}
+ */
+export function echo_vec_uninit_i32(a) {
+    const ptr0 = passArray32ToWasm0(a, wasm.__wbindgen_malloc);
+    const len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_vec_uninit_i32(ptr0, len0);
+    var v2 = getArrayI32FromWasm0(ret[0], ret[1]).slice();
+    wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
+    return v2;
+}
+
+/**
+ * @param {BigUint64Array} a
+ * @returns {BigUint64Array}
+ */
+export function echo_vec_uninit_u64(a) {
+    const ptr0 = passArray64ToWasm0(a, wasm.__wbindgen_malloc);
+    const len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_vec_uninit_u64(ptr0, len0);
+    var v2 = getArrayU64FromWasm0(ret[0], ret[1]).slice();
+    wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
+    return v2;
+}
+
+/**
+ * @param {BigInt64Array} a
+ * @returns {BigInt64Array}
+ */
+export function echo_vec_uninit_i64(a) {
+    const ptr0 = passArray64ToWasm0(a, wasm.__wbindgen_malloc);
+    const len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_vec_uninit_i64(ptr0, len0);
+    var v2 = getArrayI64FromWasm0(ret[0], ret[1]).slice();
+    wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
+    return v2;
+}
+
 function addToExternrefTable0(obj) {
     const idx = wasm.__externref_table_alloc();
     wasm.__wbindgen_export_2.set(idx, obj);
@@ -912,6 +1016,134 @@ export function echo_option_vec_i64(a) {
     return v2;
 }
 
+/**
+ * @param {Uint8Array | undefined} [a]
+ * @returns {Uint8Array | undefined}
+ */
+export function echo_option_vec_uninit_u8(a) {
+    var ptr0 = isLikeNone(a) ? 0 : passArray8ToWasm0(a, wasm.__wbindgen_malloc);
+    var len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_option_vec_uninit_u8(ptr0, len0);
+    let v2;
+    if (ret[0] !== 0) {
+        v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
+        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
+    }
+    return v2;
+}
+
+/**
+ * @param {Int8Array | undefined} [a]
+ * @returns {Int8Array | undefined}
+ */
+export function echo_option_vec_uninit_i8(a) {
+    var ptr0 = isLikeNone(a) ? 0 : passArray8ToWasm0(a, wasm.__wbindgen_malloc);
+    var len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_option_vec_uninit_i8(ptr0, len0);
+    let v2;
+    if (ret[0] !== 0) {
+        v2 = getArrayI8FromWasm0(ret[0], ret[1]).slice();
+        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
+    }
+    return v2;
+}
+
+/**
+ * @param {Uint16Array | undefined} [a]
+ * @returns {Uint16Array | undefined}
+ */
+export function echo_option_vec_uninit_u16(a) {
+    var ptr0 = isLikeNone(a) ? 0 : passArray16ToWasm0(a, wasm.__wbindgen_malloc);
+    var len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_option_vec_uninit_u16(ptr0, len0);
+    let v2;
+    if (ret[0] !== 0) {
+        v2 = getArrayU16FromWasm0(ret[0], ret[1]).slice();
+        wasm.__wbindgen_free(ret[0], ret[1] * 2, 2);
+    }
+    return v2;
+}
+
+/**
+ * @param {Int16Array | undefined} [a]
+ * @returns {Int16Array | undefined}
+ */
+export function echo_option_vec_uninit_i16(a) {
+    var ptr0 = isLikeNone(a) ? 0 : passArray16ToWasm0(a, wasm.__wbindgen_malloc);
+    var len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_option_vec_uninit_i16(ptr0, len0);
+    let v2;
+    if (ret[0] !== 0) {
+        v2 = getArrayI16FromWasm0(ret[0], ret[1]).slice();
+        wasm.__wbindgen_free(ret[0], ret[1] * 2, 2);
+    }
+    return v2;
+}
+
+/**
+ * @param {Uint32Array | undefined} [a]
+ * @returns {Uint32Array | undefined}
+ */
+export function echo_option_vec_uninit_u32(a) {
+    var ptr0 = isLikeNone(a) ? 0 : passArray32ToWasm0(a, wasm.__wbindgen_malloc);
+    var len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_option_vec_uninit_u32(ptr0, len0);
+    let v2;
+    if (ret[0] !== 0) {
+        v2 = getArrayU32FromWasm0(ret[0], ret[1]).slice();
+        wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
+    }
+    return v2;
+}
+
+/**
+ * @param {Int32Array | undefined} [a]
+ * @returns {Int32Array | undefined}
+ */
+export function echo_option_vec_uninit_i32(a) {
+    var ptr0 = isLikeNone(a) ? 0 : passArray32ToWasm0(a, wasm.__wbindgen_malloc);
+    var len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_option_vec_uninit_i32(ptr0, len0);
+    let v2;
+    if (ret[0] !== 0) {
+        v2 = getArrayI32FromWasm0(ret[0], ret[1]).slice();
+        wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
+    }
+    return v2;
+}
+
+/**
+ * @param {BigUint64Array | undefined} [a]
+ * @returns {BigUint64Array | undefined}
+ */
+export function echo_option_vec_uninit_u64(a) {
+    var ptr0 = isLikeNone(a) ? 0 : passArray64ToWasm0(a, wasm.__wbindgen_malloc);
+    var len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_option_vec_uninit_u64(ptr0, len0);
+    let v2;
+    if (ret[0] !== 0) {
+        v2 = getArrayU64FromWasm0(ret[0], ret[1]).slice();
+        wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
+    }
+    return v2;
+}
+
+/**
+ * @param {BigInt64Array | undefined} [a]
+ * @returns {BigInt64Array | undefined}
+ */
+export function echo_option_vec_uninit_i64(a) {
+    var ptr0 = isLikeNone(a) ? 0 : passArray64ToWasm0(a, wasm.__wbindgen_malloc);
+    var len0 = WASM_VECTOR_LEN;
+    const ret = wasm.echo_option_vec_uninit_i64(ptr0, len0);
+    let v2;
+    if (ret[0] !== 0) {
+        v2 = getArrayI64FromWasm0(ret[0], ret[1]).slice();
+        wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
+    }
+    return v2;
+}
+
 /**
  * @param {(string)[] | undefined} [a]
  * @returns {(string)[] | undefined}
diff --git a/crates/cli/tests/reference/echo.rs b/crates/cli/tests/reference/echo.rs
index bee663ec..815db98c 100644
--- a/crates/cli/tests/reference/echo.rs
+++ b/crates/cli/tests/reference/echo.rs
@@ -1,3 +1,4 @@
+use std::mem::MaybeUninit;
 use wasm_bindgen::prelude::*;
 
 #[wasm_bindgen]
@@ -42,6 +43,14 @@ echo!(
     (echo_vec_i32, Vec<i32>),
     (echo_vec_u64, Vec<u64>),
     (echo_vec_i64, Vec<i64>),
+    (echo_vec_uninit_u8, Vec<MaybeUninit<u8>>),
+    (echo_vec_uninit_i8, Vec<MaybeUninit<i8>>),
+    (echo_vec_uninit_u16, Vec<MaybeUninit<u16>>),
+    (echo_vec_uninit_i16, Vec<MaybeUninit<i16>>),
+    (echo_vec_uninit_u32, Vec<MaybeUninit<u32>>),
+    (echo_vec_uninit_i32, Vec<MaybeUninit<i32>>),
+    (echo_vec_uninit_u64, Vec<MaybeUninit<u64>>),
+    (echo_vec_uninit_i64, Vec<MaybeUninit<i64>>),
     (echo_vec_string, Vec<String>),
     (echo_struct, Foo),
     (echo_vec_struct, Vec<Foo>),
@@ -70,6 +79,14 @@ echo!(
     (echo_option_vec_i32, Option<Vec<i32>>),
     (echo_option_vec_u64, Option<Vec<u64>>),
     (echo_option_vec_i64, Option<Vec<i64>>),
+    (echo_option_vec_uninit_u8, Option<Vec<MaybeUninit<u8>>>),
+    (echo_option_vec_uninit_i8, Option<Vec<MaybeUninit<i8>>>),
+    (echo_option_vec_uninit_u16, Option<Vec<MaybeUninit<u16>>>),
+    (echo_option_vec_uninit_i16, Option<Vec<MaybeUninit<i16>>>),
+    (echo_option_vec_uninit_u32, Option<Vec<MaybeUninit<u32>>>),
+    (echo_option_vec_uninit_i32, Option<Vec<MaybeUninit<i32>>>),
+    (echo_option_vec_uninit_u64, Option<Vec<MaybeUninit<u64>>>),
+    (echo_option_vec_uninit_i64, Option<Vec<MaybeUninit<i64>>>),
     (echo_option_vec_string, Option<Vec<String>>),
     (echo_option_struct, Option<Foo>),
     (echo_option_vec_struct, Option<Vec<Foo>>)
diff --git a/crates/cli/tests/reference/echo.wat b/crates/cli/tests/reference/echo.wat
index f73b2362..aff42b9d 100644
--- a/crates/cli/tests/reference/echo.wat
+++ b/crates/cli/tests/reference/echo.wat
@@ -61,22 +61,38 @@
   (func $"echo_vec_i32 multivalue shim" (;44;) (type 5) (param i32 i32) (result i32 i32))
   (func $"echo_vec_u64 multivalue shim" (;45;) (type 5) (param i32 i32) (result i32 i32))
   (func $"echo_vec_i64 multivalue shim" (;46;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_vec_string multivalue shim" (;47;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_vec_struct multivalue shim" (;48;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_u64 multivalue shim" (;49;) (type 8) (param i32 i64) (result i32 i64))
-  (func $"echo_option_i64 multivalue shim" (;50;) (type 8) (param i32 i64) (result i32 i64))
-  (func $"echo_option_f64 multivalue shim" (;51;) (type 10) (param i32 f64) (result i32 f64))
-  (func $"echo_option_string multivalue shim" (;52;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_u8 multivalue shim" (;53;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_i8 multivalue shim" (;54;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_u16 multivalue shim" (;55;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_i16 multivalue shim" (;56;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_u32 multivalue shim" (;57;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_i32 multivalue shim" (;58;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_u64 multivalue shim" (;59;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_i64 multivalue shim" (;60;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_string multivalue shim" (;61;) (type 5) (param i32 i32) (result i32 i32))
-  (func $"echo_option_vec_struct multivalue shim" (;62;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_uninit_u8 multivalue shim" (;47;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_uninit_i8 multivalue shim" (;48;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_uninit_u16 multivalue shim" (;49;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_uninit_i16 multivalue shim" (;50;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_uninit_u32 multivalue shim" (;51;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_uninit_i32 multivalue shim" (;52;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_uninit_u64 multivalue shim" (;53;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_uninit_i64 multivalue shim" (;54;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_string multivalue shim" (;55;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_vec_struct multivalue shim" (;56;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_u64 multivalue shim" (;57;) (type 8) (param i32 i64) (result i32 i64))
+  (func $"echo_option_i64 multivalue shim" (;58;) (type 8) (param i32 i64) (result i32 i64))
+  (func $"echo_option_f64 multivalue shim" (;59;) (type 10) (param i32 f64) (result i32 f64))
+  (func $"echo_option_string multivalue shim" (;60;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_u8 multivalue shim" (;61;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_i8 multivalue shim" (;62;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_u16 multivalue shim" (;63;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_i16 multivalue shim" (;64;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_u32 multivalue shim" (;65;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_i32 multivalue shim" (;66;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_u64 multivalue shim" (;67;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_i64 multivalue shim" (;68;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_uninit_u8 multivalue shim" (;69;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_uninit_i8 multivalue shim" (;70;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_uninit_u16 multivalue shim" (;71;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_uninit_i16 multivalue shim" (;72;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_uninit_u32 multivalue shim" (;73;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_uninit_i32 multivalue shim" (;74;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_uninit_u64 multivalue shim" (;75;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_uninit_i64 multivalue shim" (;76;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_string multivalue shim" (;77;) (type 5) (param i32 i32) (result i32 i32))
+  (func $"echo_option_vec_struct multivalue shim" (;78;) (type 5) (param i32 i32) (result i32 i32))
   (table (;0;) 128 externref)
   (memory (;0;) 17)
   (export "memory" (memory 0))
@@ -106,6 +122,14 @@
   (export "echo_vec_i32" (func $"echo_vec_i32 multivalue shim"))
   (export "echo_vec_u64" (func $"echo_vec_u64 multivalue shim"))
   (export "echo_vec_i64" (func $"echo_vec_i64 multivalue shim"))
+  (export "echo_vec_uninit_u8" (func $"echo_vec_uninit_u8 multivalue shim"))
+  (export "echo_vec_uninit_i8" (func $"echo_vec_uninit_i8 multivalue shim"))
+  (export "echo_vec_uninit_u16" (func $"echo_vec_uninit_u16 multivalue shim"))
+  (export "echo_vec_uninit_i16" (func $"echo_vec_uninit_i16 multivalue shim"))
+  (export "echo_vec_uninit_u32" (func $"echo_vec_uninit_u32 multivalue shim"))
+  (export "echo_vec_uninit_i32" (func $"echo_vec_uninit_i32 multivalue shim"))
+  (export "echo_vec_uninit_u64" (func $"echo_vec_uninit_u64 multivalue shim"))
+  (export "echo_vec_uninit_i64" (func $"echo_vec_uninit_i64 multivalue shim"))
   (export "echo_vec_string" (func $"echo_vec_string multivalue shim"))
   (export "echo_struct" (func $echo_struct))
   (export "echo_vec_struct" (func $"echo_vec_struct multivalue shim"))
@@ -134,6 +158,14 @@
   (export "echo_option_vec_i32" (func $"echo_option_vec_i32 multivalue shim"))
   (export "echo_option_vec_u64" (func $"echo_option_vec_u64 multivalue shim"))
   (export "echo_option_vec_i64" (func $"echo_option_vec_i64 multivalue shim"))
+  (export "echo_option_vec_uninit_u8" (func $"echo_option_vec_uninit_u8 multivalue shim"))
+  (export "echo_option_vec_uninit_i8" (func $"echo_option_vec_uninit_i8 multivalue shim"))
+  (export "echo_option_vec_uninit_u16" (func $"echo_option_vec_uninit_u16 multivalue shim"))
+  (export "echo_option_vec_uninit_i16" (func $"echo_option_vec_uninit_i16 multivalue shim"))
+  (export "echo_option_vec_uninit_u32" (func $"echo_option_vec_uninit_u32 multivalue shim"))
+  (export "echo_option_vec_uninit_i32" (func $"echo_option_vec_uninit_i32 multivalue shim"))
+  (export "echo_option_vec_uninit_u64" (func $"echo_option_vec_uninit_u64 multivalue shim"))
+  (export "echo_option_vec_uninit_i64" (func $"echo_option_vec_uninit_i64 multivalue shim"))
   (export "echo_option_vec_string" (func $"echo_option_vec_string multivalue shim"))
   (export "echo_option_struct" (func $echo_option_struct))
   (export "echo_option_vec_struct" (func $"echo_option_vec_struct multivalue shim"))
diff --git a/crates/macro/ui-tests/wasm-bindgen.stderr b/crates/macro/ui-tests/wasm-bindgen.stderr
index 2ec13836..2dfacc7b 100644
--- a/crates/macro/ui-tests/wasm-bindgen.stderr
+++ b/crates/macro/ui-tests/wasm-bindgen.stderr
@@ -1,16 +1,10 @@
-error[E0433]: failed to resolve: could not find `convert` in `test`
+error[E0433]: failed to resolve: could not find `__wbindgen_coverage` in `test`
   --> ui-tests/wasm-bindgen.rs:37:1
    |
 37 | #[wasm_bindgen(wasm_bindgen = test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not find `convert` in `test`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not find `__wbindgen_coverage` in `test`
    |
    = note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider importing one of these items
-   |
-3  + use crate::test::test::convert;
-   |
-3  + use wasm_bindgen::convert;
-   |
 
 error[E0425]: cannot find function `future_to_promise` in module `test`
   --> ui-tests/wasm-bindgen.rs:40:1
diff --git a/crates/test-macro/Cargo.toml b/crates/test-macro/Cargo.toml
index cfbfc747..4997340e 100644
--- a/crates/test-macro/Cargo.toml
+++ b/crates/test-macro/Cargo.toml
@@ -12,10 +12,6 @@ version = "0.3.47"
 [lib]
 proc-macro = true
 
-[features]
-coverage = []
-xxx_resolver_1 = []
-
 [dependencies]
 proc-macro2 = "1.0"
 quote = "1.0"
diff --git a/crates/test-macro/src/lib.rs b/crates/test-macro/src/lib.rs
index 0916132d..510944cc 100644
--- a/crates/test-macro/src/lib.rs
+++ b/crates/test-macro/src/lib.rs
@@ -1,12 +1,6 @@
 //! See the README for `wasm-bindgen-test` for a bit more info about what's
 //! going on here.
 
-#![cfg_attr(
-    all(not(feature = "xxx_resolver_1"), feature = "coverage"),
-    feature(allow_internal_unstable),
-    allow(internal_features)
-)]
-
 extern crate proc_macro;
 
 use proc_macro2::*;
@@ -18,10 +12,6 @@ use std::sync::atomic::*;
 static CNT: AtomicUsize = AtomicUsize::new(0);
 
 #[proc_macro_attribute]
-#[cfg_attr(
-    all(not(feature = "xxx_resolver_1"), feature = "coverage"),
-    allow_internal_unstable(coverage_attribute)
-)]
 pub fn wasm_bindgen_test(
     attr: proc_macro::TokenStream,
     body: proc_macro::TokenStream,
@@ -109,21 +99,17 @@ pub fn wasm_bindgen_test(
     // main test harness. This is the entry point for all tests.
     let name = format_ident!("__wbgt_{}_{}", ident, CNT.fetch_add(1, Ordering::SeqCst));
     let wasm_bindgen_path = attributes.wasm_bindgen_path;
-    let coverage = if cfg!(feature = "coverage") {
-        Some(quote! { #[coverage(off)] })
-    } else {
-        None
-    };
     tokens.extend(
         quote! {
             const _: () = {
+                #wasm_bindgen_path::__rt::wasm_bindgen::__wbindgen_coverage! {
                 #[no_mangle]
                 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
-                #coverage
                 pub extern "C" fn #name(cx: &#wasm_bindgen_path::__rt::Context) {
                     let test_name = ::core::concat!(::core::module_path!(), "::", ::core::stringify!(#ident));
                     #test_body
                 }
+                }
             };
         },
     );
diff --git a/crates/test/Cargo.toml b/crates/test/Cargo.toml
index 72825958..d3083b0e 100644
--- a/crates/test/Cargo.toml
+++ b/crates/test/Cargo.toml
@@ -23,12 +23,6 @@ wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.3.47' }
 
 [target.'cfg(all(target_arch = "wasm32", wasm_bindgen_unstable_test_coverage))'.dependencies]
 minicov = "0.3"
-wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.3.47', features = ["coverage"] }
-
-[target.'cfg(__wasm_bindgen_resolver_1)'.dependencies]
-wasm-bindgen-test-macro = { path = "../test-macro", version = "=0.3.47", features = [
-  "xxx_resolver_1",
-] }
 
 [lints.rust]
 unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] }
diff --git a/crates/test/src/rt/mod.rs b/crates/test/src/rt/mod.rs
index 2d508c6e..0c28b134 100644
--- a/crates/test/src/rt/mod.rs
+++ b/crates/test/src/rt/mod.rs
@@ -99,6 +99,7 @@ use core::future::Future;
 use core::pin::Pin;
 use core::task::{self, Poll};
 use js_sys::{Array, Function, Promise};
+pub use wasm_bindgen;
 use wasm_bindgen::prelude::*;
 use wasm_bindgen_futures::future_to_promise;
 
diff --git a/tests/wasm/slice.js b/tests/wasm/slice.js
index 3e65dfc5..e7fac78f 100644
--- a/tests/wasm/slice.js
+++ b/tests/wasm/slice.js
@@ -7,22 +7,30 @@ exports.js_export = () => {
     i8[1] = 2;
     assert.deepStrictEqual(wasm.export_i8(i8), i8);
     assert.deepStrictEqual(wasm.export_optional_i8(i8), i8);
+    assert.deepStrictEqual(wasm.export_uninit_i8(i8), i8);
+    assert.deepStrictEqual(wasm.export_optional_uninit_i8(i8), i8);
     const u8 = new Uint8Array(2);
     u8[0] = 1;
     u8[1] = 2;
     assert.deepStrictEqual(wasm.export_u8(u8), u8);
     assert.deepStrictEqual(wasm.export_optional_u8(u8), u8);
+    assert.deepStrictEqual(wasm.export_uninit_u8(u8), u8);
+    assert.deepStrictEqual(wasm.export_optional_uninit_u8(u8), u8);
 
     const i16 = new Int16Array(2);
     i16[0] = 1;
     i16[1] = 2;
     assert.deepStrictEqual(wasm.export_i16(i16), i16);
     assert.deepStrictEqual(wasm.export_optional_i16(i16), i16);
+    assert.deepStrictEqual(wasm.export_uninit_i16(i16), i16);
+    assert.deepStrictEqual(wasm.export_optional_uninit_i16(i16), i16);
     const u16 = new Uint16Array(2);
     u16[0] = 1;
     u16[1] = 2;
     assert.deepStrictEqual(wasm.export_u16(u16), u16);
     assert.deepStrictEqual(wasm.export_optional_u16(u16), u16);
+    assert.deepStrictEqual(wasm.export_uninit_u16(u16), u16);
+    assert.deepStrictEqual(wasm.export_optional_uninit_u16(u16), u16);
 
     const i32 = new Int32Array(2);
     i32[0] = 1;
@@ -31,6 +39,10 @@ exports.js_export = () => {
     assert.deepStrictEqual(wasm.export_optional_i32(i32), i32);
     assert.deepStrictEqual(wasm.export_isize(i32), i32);
     assert.deepStrictEqual(wasm.export_optional_isize(i32), i32);
+    assert.deepStrictEqual(wasm.export_uninit_i32(i32), i32);
+    assert.deepStrictEqual(wasm.export_optional_uninit_i32(i32), i32);
+    assert.deepStrictEqual(wasm.export_uninit_isize(i32), i32);
+    assert.deepStrictEqual(wasm.export_optional_uninit_isize(i32), i32);
     const u32 = new Uint32Array(2);
     u32[0] = 1;
     u32[1] = 2;
@@ -38,17 +50,25 @@ exports.js_export = () => {
     assert.deepStrictEqual(wasm.export_optional_u32(u32), u32);
     assert.deepStrictEqual(wasm.export_usize(u32), u32);
     assert.deepStrictEqual(wasm.export_optional_usize(u32), u32);
+    assert.deepStrictEqual(wasm.export_uninit_u32(u32), u32);
+    assert.deepStrictEqual(wasm.export_optional_uninit_u32(u32), u32);
+    assert.deepStrictEqual(wasm.export_uninit_usize(u32), u32);
+    assert.deepStrictEqual(wasm.export_optional_uninit_usize(u32), u32);
 
     const f32 = new Float32Array(2);
     f32[0] = 1;
     f32[1] = 2;
     assert.deepStrictEqual(wasm.export_f32(f32), f32);
     assert.deepStrictEqual(wasm.export_optional_f32(f32), f32);
+    assert.deepStrictEqual(wasm.export_uninit_f32(f32), f32);
+    assert.deepStrictEqual(wasm.export_optional_uninit_f32(f32), f32);
     const f64 = new Float64Array(2);
     f64[0] = 1;
     f64[1] = 2;
     assert.deepStrictEqual(wasm.export_f64(f64), f64);
     assert.deepStrictEqual(wasm.export_optional_f64(f64), f64);
+    assert.deepStrictEqual(wasm.export_uninit_f64(f64), f64);
+    assert.deepStrictEqual(wasm.export_optional_uninit_f64(f64), f64);
 
     assert.strictEqual(wasm.export_optional_i8(undefined), undefined);
     assert.strictEqual(wasm.export_optional_u8(undefined), undefined);
@@ -60,6 +80,17 @@ exports.js_export = () => {
     assert.strictEqual(wasm.export_optional_usize(undefined), undefined);
     assert.strictEqual(wasm.export_optional_f32(undefined), undefined);
     assert.strictEqual(wasm.export_optional_f64(undefined), undefined);
+
+    assert.strictEqual(wasm.export_optional_uninit_i8(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_u8(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_i16(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_u16(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_i32(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_isize(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_u32(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_usize(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_f32(undefined), undefined);
+    assert.strictEqual(wasm.export_optional_uninit_f64(undefined), undefined);
 };
 
 const test_import = (a, b, c) => {
@@ -84,44 +115,65 @@ exports.import_js_usize = test_import;
 exports.import_js_f32 = test_import;
 exports.import_js_f64 = test_import;
 
+exports.import_js_uninit_i8 = test_import;
+exports.import_js_uninit_u8 = test_import;
+exports.import_js_uninit_i16 = test_import;
+exports.import_js_uninit_u16 = test_import;
+exports.import_js_uninit_i32 = test_import;
+exports.import_js_uninit_isize = test_import;
+exports.import_js_uninit_u32 = test_import;
+exports.import_js_uninit_usize = test_import;
+exports.import_js_uninit_f32 = test_import;
+exports.import_js_uninit_f64 = test_import;
+
 exports.js_import = () => {
     const i8 = new Int8Array(2);
     i8[0] = 1;
     i8[1] = 2;
     assert.deepStrictEqual(wasm.import_rust_i8(i8), i8);
+    assert.deepStrictEqual(wasm.import_rust_uninit_i8(i8), i8);
     const u8 = new Uint8Array(2);
     u8[0] = 1;
     u8[1] = 2;
     assert.deepStrictEqual(wasm.import_rust_u8(u8), u8);
+    assert.deepStrictEqual(wasm.import_rust_uninit_u8(u8), u8);
 
     const i16 = new Int16Array(2);
     i16[0] = 1;
     i16[1] = 2;
     assert.deepStrictEqual(wasm.import_rust_i16(i16), i16);
+    assert.deepStrictEqual(wasm.import_rust_uninit_i16(i16), i16);
     const u16 = new Uint16Array(2);
     u16[0] = 1;
     u16[1] = 2;
     assert.deepStrictEqual(wasm.import_rust_u16(u16), u16);
+    assert.deepStrictEqual(wasm.import_rust_uninit_u16(u16), u16);
 
     const i32 = new Int32Array(2);
     i32[0] = 1;
     i32[1] = 2;
     assert.deepStrictEqual(wasm.import_rust_i32(i32), i32);
     assert.deepStrictEqual(wasm.import_rust_isize(i32), i32);
+    assert.deepStrictEqual(wasm.import_rust_uninit_i32(i32), i32);
+    assert.deepStrictEqual(wasm.import_rust_uninit_isize(i32), i32);
     const u32 = new Uint32Array(2);
     u32[0] = 1;
     u32[1] = 2;
     assert.deepStrictEqual(wasm.import_rust_u32(u32), u32);
     assert.deepStrictEqual(wasm.import_rust_usize(u32), u32);
+    assert.deepStrictEqual(wasm.import_rust_uninit_u32(u32), u32);
+    assert.deepStrictEqual(wasm.import_rust_uninit_usize(u32), u32);
 
     const f32 = new Float32Array(2);
     f32[0] = 1;
     f32[1] = 2;
     assert.deepStrictEqual(wasm.import_rust_f32(f32), f32);
+    assert.deepStrictEqual(wasm.import_rust_uninit_f32(f32), f32);
     const f64 = new Float64Array(2);
     f64[0] = 1;
     f64[1] = 2;
     assert.deepStrictEqual(wasm.import_rust_f64(f64), f64);
+    assert.deepStrictEqual(wasm.import_rust_uninit_f64(f64), f64);
 };
 
 exports.js_pass_array = () => {
@@ -135,6 +187,17 @@ exports.js_pass_array = () => {
     wasm.pass_array_rust_usize([1, 2]);
     wasm.pass_array_rust_f32([1, 2]);
     wasm.pass_array_rust_f64([1, 2]);
+
+    wasm.pass_array_rust_uninit_i8([1, 2]);
+    wasm.pass_array_rust_uninit_u8([1, 2]);
+    wasm.pass_array_rust_uninit_i16([1, 2]);
+    wasm.pass_array_rust_uninit_u16([1, 2]);
+    wasm.pass_array_rust_uninit_i32([1, 2]);
+    wasm.pass_array_rust_uninit_u32([1, 2]);
+    wasm.pass_array_rust_uninit_isize([1, 2]);
+    wasm.pass_array_rust_uninit_usize([1, 2]);
+    wasm.pass_array_rust_uninit_f32([1, 2]);
+    wasm.pass_array_rust_uninit_f64([1, 2]);
 };
 
 const import_mut_foo = (a, b, c) => {
@@ -163,6 +226,17 @@ exports.import_mut_js_usize = import_mut_foo;
 exports.import_mut_js_f32 = import_mut_foo;
 exports.import_mut_js_f64 = import_mut_foo;
 
+exports.import_mut_js_uninit_i8 = import_mut_foo;
+exports.import_mut_js_uninit_u8 = import_mut_foo;
+exports.import_mut_js_uninit_i16 = import_mut_foo;
+exports.import_mut_js_uninit_u16 = import_mut_foo;
+exports.import_mut_js_uninit_i32 = import_mut_foo;
+exports.import_mut_js_uninit_u32 = import_mut_foo;
+exports.import_mut_js_uninit_isize = import_mut_foo;
+exports.import_mut_js_uninit_usize = import_mut_foo;
+exports.import_mut_js_uninit_f32 = import_mut_foo;
+exports.import_mut_js_uninit_f64 = import_mut_foo;
+
 const export_mut_run = (a, rust) => {
     assert.strictEqual(a.length, 3);
     a[0] = 1;
@@ -188,6 +262,17 @@ exports.js_export_mut = () => {
     export_mut_run(new Uint32Array(3), wasm.export_mut_usize);
     export_mut_run(new Float32Array(3), wasm.export_mut_f32);
     export_mut_run(new Float64Array(3), wasm.export_mut_f64);
+
+    export_mut_run(new Int8Array(3), wasm.export_mut_uninit_i8);
+    export_mut_run(new Uint8Array(3), wasm.export_mut_uninit_u8);
+    export_mut_run(new Int16Array(3), wasm.export_mut_uninit_i16);
+    export_mut_run(new Uint16Array(3), wasm.export_mut_uninit_u16);
+    export_mut_run(new Int32Array(3), wasm.export_mut_uninit_i32);
+    export_mut_run(new Uint32Array(3), wasm.export_mut_uninit_u32);
+    export_mut_run(new Int32Array(3), wasm.export_mut_uninit_isize);
+    export_mut_run(new Uint32Array(3), wasm.export_mut_uninit_usize);
+    export_mut_run(new Float32Array(3), wasm.export_mut_uninit_f32);
+    export_mut_run(new Float64Array(3), wasm.export_mut_uninit_f64);
 };
 
 exports.js_return_vec = () => {
diff --git a/tests/wasm/slice.rs b/tests/wasm/slice.rs
index 15e9a9ac..6b18a634 100644
--- a/tests/wasm/slice.rs
+++ b/tests/wasm/slice.rs
@@ -1,3 +1,7 @@
+#![cfg(test)]
+
+use paste::paste;
+use std::mem::MaybeUninit;
 use wasm_bindgen::prelude::*;
 use wasm_bindgen::Clamped;
 use wasm_bindgen_test::*;
@@ -19,12 +23,19 @@ extern "C" {
     fn js_clamped2(val: Clamped<Vec<u8>>, offset: u8);
     #[wasm_bindgen(js_name = js_clamped)]
     fn js_clamped3(val: Clamped<&mut [u8]>, offset: u8);
+
+    #[wasm_bindgen(js_name = js_clamped)]
+    fn js_clamped_uninit(val: Clamped<&[MaybeUninit<u8>]>, offset: u8);
+    #[wasm_bindgen(js_name = js_clamped)]
+    fn js_clamped2_uninit(val: Clamped<Vec<MaybeUninit<u8>>>, offset: u8);
+    #[wasm_bindgen(js_name = js_clamped)]
+    fn js_clamped3_uninit(val: Clamped<&mut [MaybeUninit<u8>]>, offset: u8);
 }
 
 macro_rules! export_macro {
-    ($(($i:ident, $n:ident, $optional_n:ident))*) => ($(
+    ($($i:ident),*) => ( paste! { $(
         #[wasm_bindgen]
-        pub fn $n(a: &[$i]) -> Vec<$i> {
+        pub fn [<export_ $i>](a: &[$i]) -> Vec<$i> {
             assert_eq!(a.len(), 2);
             assert_eq!(a[0], 1 as $i);
             assert_eq!(a[1], 2 as $i);
@@ -32,108 +43,140 @@ macro_rules! export_macro {
         }
 
         #[wasm_bindgen]
-        pub fn $optional_n(a: Option<Vec<$i>>) -> Option<Vec<$i>> {
+        pub fn [<export_optional_ $i>](a: Option<Vec<$i>>) -> Option<Vec<$i>> {
             a.map(|a| {
                 assert_eq!(a.len(), 2);
                 assert_eq!(a[0], 1 as $i);
                 assert_eq!(a[1], 2 as $i);
                 a.to_vec()
             })
+
         }
-    )*)
-}
 
-export_macro! {
-    (i8, export_i8, export_optional_i8)
-    (u8, export_u8, export_optional_u8)
-    (i16, export_i16, export_optional_i16)
-    (u16, export_u16, export_optional_u16)
-    (i32, export_i32, export_optional_i32)
-    (u32, export_u32, export_optional_u32)
-    (isize, export_isize, export_optional_isize)
-    (usize, export_usize, export_optional_usize)
-    (f32, export_f32, export_optional_f32)
-    (f64, export_f64, export_optional_f64)
+        #[wasm_bindgen]
+        pub fn [<export_uninit_ $i>](a: &[MaybeUninit<$i>]) -> Vec<MaybeUninit<$i>> {
+            assert_eq!(a.len(), 2);
+            let slice = slice_ref(a);
+            assert_eq!(slice[0], 1 as $i);
+            assert_eq!(slice[1], 2 as $i);
+            a.to_vec()
+        }
+
+        #[wasm_bindgen]
+        pub fn [<export_optional_uninit_ $i>](a: Option<Vec<MaybeUninit<$i>>>) -> Option<Vec<MaybeUninit<$i>>> {
+            a.map(|a| {
+                assert_eq!(a.len(), 2);
+                let slice = slice_ref(&a);
+                assert_eq!(slice[0], 1 as $i);
+                assert_eq!(slice[1], 2 as $i);
+                a.to_vec()
+            })
+
+        }
+    )* } );
 }
 
+export_macro!(i8, u8, i16, u16, i32, u32, isize, usize, f32, f64);
+
 #[wasm_bindgen_test]
 fn export() {
     js_export();
 }
 
 macro_rules! import_macro {
-    ($(($rust:ident, $js:ident, $i:ident))*) => ($(
+    ($($i:ident),*) => ( paste! { $(
         #[wasm_bindgen(module = "tests/wasm/slice.js")]
         extern "C" {
-            fn $js(a: &[$i], b: Option<&[$i]>, c: Option<&[$i]>) -> Vec<$i>;
+            fn [<import_js_ $i>](a: &[$i], b: Option<&[$i]>, c: Option<&[$i]>) -> Vec<$i>;
         }
 
         #[wasm_bindgen]
-        pub fn $rust(a: &[$i]) -> Vec<$i> {
+        pub fn [<import_rust_ $i>](a: &[$i]) -> Vec<$i> {
             assert_eq!(a.len(), 2);
             assert_eq!(a[0], 1 as $i);
             assert_eq!(a[1], 2 as $i);
-            $js(a, Some(a), None)
+            [<import_js_ $i>](a, Some(a), None)
         }
-    )*)
-}
 
-import_macro! {
-    (import_rust_i8, import_js_i8, i8)
-    (import_rust_u8, import_js_u8, u8)
-    (import_rust_i16, import_js_i16, i16)
-    (import_rust_u16, import_js_u16, u16)
-    (import_rust_i32, import_js_i32, i32)
-    (import_rust_u32, import_js_u32, u32)
-    (import_rust_isize, import_js_isize, isize)
-    (import_rust_usize, import_js_usize, usize)
-    (import_rust_f32, import_js_f32, f32)
-    (import_rust_f64, import_js_f64, f64)
+        #[wasm_bindgen(module = "tests/wasm/slice.js")]
+        extern "C" {
+            fn [<import_js_uninit_ $i>](a: &[MaybeUninit<$i>], b: Option<&[MaybeUninit<$i>]>, c: Option<&[MaybeUninit<$i>]>) -> Vec<MaybeUninit<$i>>;
+        }
+
+        #[wasm_bindgen]
+        pub fn [<import_rust_uninit_ $i>](a: &[MaybeUninit<$i>]) -> Vec<MaybeUninit<$i>> {
+            assert_eq!(a.len(), 2);
+            let slice = slice_ref(a);
+            assert_eq!(slice[0], 1 as $i);
+            assert_eq!(slice[1], 2 as $i);
+            [<import_js_uninit_ $i>](a, Some(a), None)
+        }
+    )* } )
 }
 
+import_macro!(i8, u8, i16, u16, i32, u32, isize, usize, f32, f64);
+
 #[wasm_bindgen_test]
 fn import() {
     js_import();
 }
 
 macro_rules! pass_array_marco {
-    ($(($rust:ident, $i:ident))*) => ($(
+    ($($i:ident),*) => ( paste! { $(
         #[wasm_bindgen]
-        pub fn $rust(a: &[$i]) {
+        pub fn [<pass_array_rust_ $i>](a: &[$i]) {
             assert_eq!(a.len(), 2);
             assert_eq!(a[0], 1 as $i);
             assert_eq!(a[1], 2 as $i);
         }
-    )*)
-}
 
-pass_array_marco! {
-    (pass_array_rust_i8, i8)
-    (pass_array_rust_u8, u8)
-    (pass_array_rust_i16, i16)
-    (pass_array_rust_u16, u16)
-    (pass_array_rust_i32, i32)
-    (pass_array_rust_u32, u32)
-    (pass_array_rust_isize, isize)
-    (pass_array_rust_usize, usize)
-    (pass_array_rust_f32, f32)
-    (pass_array_rust_f64, f64)
+        #[wasm_bindgen]
+        pub fn [<pass_array_rust_uninit_ $i>](a: &[MaybeUninit<$i>]) {
+            assert_eq!(a.len(), 2);
+            let a = slice_ref(a);
+            assert_eq!(a[0], 1 as $i);
+            assert_eq!(a[1], 2 as $i);
+        }
+    )* } )
 }
 
+pass_array_marco!(i8, u8, i16, u16, i32, u32, isize, usize, f32, f64);
+
 #[wasm_bindgen_test]
 fn pass_array() {
     js_pass_array();
 }
 
 macro_rules! import_mut_macro {
-    ($(($rust:ident, $js:ident, $i:ident))*) => (
+    ($($i:ident),*) => ( paste! {
         $(
             #[wasm_bindgen(module = "tests/wasm/slice.js")]
             extern "C" {
-                fn $js(a: &mut [$i], b: Option<&mut [$i]>, c: Option<&mut [$i]>);
+                fn [<import_mut_js_ $i>](a: &mut [$i], b: Option<&mut [$i]>, c: Option<&mut [$i]>);
+                fn [<import_mut_js_uninit_ $i>](a: &mut [MaybeUninit<$i>], b: Option<&mut [MaybeUninit<$i>]>, c: Option<&mut [MaybeUninit<$i>]>);
+            }
+
+            fn [<import_mut_rust_ $i>]() {
+                let mut buf1 = [
+                    1 as $i,
+                    2 as $i,
+                    3 as $i,
+                ];
+                let mut buf2 = [
+                    4 as $i,
+                    5 as $i,
+                    6 as $i,
+                ];
+                [<import_mut_js_ $i>](&mut buf1, Some(&mut buf2), None);
+                assert_eq!(buf1[0], 4 as $i);
+                assert_eq!(buf1[1], 5 as $i);
+                assert_eq!(buf1[2], 3 as $i);
+                assert_eq!(buf2[0], 8 as $i);
+                assert_eq!(buf2[1], 7 as $i);
+                assert_eq!(buf2[2], 6 as $i);
             }
 
-            fn $rust() {
+            fn [<import_mut_rust_uninit_ $i>]() {
                 let mut buf1 = [
                     1 as $i,
                     2 as $i,
@@ -144,7 +187,7 @@ macro_rules! import_mut_macro {
                     5 as $i,
                     6 as $i,
                 ];
-                $js(&mut buf1, Some(&mut buf2), None);
+                [<import_mut_js_uninit_ $i>](slice_uninit_mut(&mut buf1), Some(slice_uninit_mut(&mut buf2)), None);
                 assert_eq!(buf1[0], 4 as $i);
                 assert_eq!(buf1[1], 5 as $i);
                 assert_eq!(buf1[2], 3 as $i);
@@ -156,26 +199,18 @@ macro_rules! import_mut_macro {
 
         #[wasm_bindgen_test]
         fn import_mut() {
-            $($rust();)*
+            $([<import_mut_rust_ $i>]();)*
+            $([<import_mut_rust_uninit_ $i>]();)*
         }
-    )
+    } )
 }
 
-import_mut_macro! {
-    (import_mut_rust_i8, import_mut_js_i8, i8)
-    (import_mut_rust_u8, import_mut_js_u8, u8)
-    (import_mut_rust_i16, import_mut_js_i16, i16)
-    (import_mut_rust_u16, import_mut_js_u16, u16)
-    (import_mut_rust_i32, import_mut_js_i32, i32)
-    (import_mut_rust_u32, import_mut_js_u32, u32)
-    (import_mut_rust_f32, import_mut_js_f32, f32)
-    (import_mut_rust_f64, import_mut_js_f64, f64)
-}
+import_mut_macro!(i8, u8, i16, u16, i32, u32, f32, f64);
 
 macro_rules! export_mut_macro {
-    ($(($i:ident, $n:ident))*) => ($(
+    ($($i:ident),*) => ( paste! { $(
         #[wasm_bindgen]
-        pub fn $n(a: &mut [$i])  {
+        pub fn [<export_mut_ $i>](a: &mut [$i])  {
             assert_eq!(a.len(), 3);
             assert_eq!(a[0], 1 as $i);
             assert_eq!(a[1], 2 as $i);
@@ -183,22 +218,22 @@ macro_rules! export_mut_macro {
             a[0] = 4 as $i;
             a[1] = 5 as $i;
         }
-    )*)
-}
 
-export_mut_macro! {
-    (i8, export_mut_i8)
-    (u8, export_mut_u8)
-    (i16, export_mut_i16)
-    (u16, export_mut_u16)
-    (i32, export_mut_i32)
-    (u32, export_mut_u32)
-    (isize, export_mut_isize)
-    (usize, export_mut_usize)
-    (f32, export_mut_f32)
-    (f64, export_mut_f64)
+        #[wasm_bindgen]
+        pub fn [<export_mut_uninit_ $i>](a: &mut [MaybeUninit<$i>])  {
+            assert_eq!(a.len(), 3);
+            let a = slice_mut(a);
+            assert_eq!(a[0], 1 as $i);
+            assert_eq!(a[1], 2 as $i);
+            assert_eq!(a[2], 3 as $i);
+            a[0] = 4 as $i;
+            a[1] = 5 as $i;
+        }
+    )* } )
 }
 
+export_mut_macro!(i8, u8, i16, u16, i32, u32, isize, usize, f32, f64);
+
 #[wasm_bindgen_test]
 fn export_mut() {
     js_export_mut();
@@ -249,4 +284,24 @@ fn take_clamped() {
     js_clamped(Clamped(&[1, 2, 3]), 1);
     js_clamped2(Clamped(vec![4, 5, 6]), 4);
     js_clamped3(Clamped(&mut [7, 8, 9]), 7);
+
+    js_clamped_uninit(Clamped(slice_uninit_ref(&[1, 2, 3])), 1);
+    js_clamped2_uninit(Clamped(slice_uninit_ref(&[4, 5, 6]).to_vec()), 4);
+    js_clamped3_uninit(Clamped(slice_uninit_mut(&mut [7, 8, 9])), 7);
+}
+
+fn slice_ref<T>(slice: &[MaybeUninit<T>]) -> &[T] {
+    unsafe { &*(std::ptr::from_ref(slice) as *const [T]) }
+}
+
+fn slice_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
+    unsafe { &mut *(std::ptr::from_mut(slice) as *mut [T]) }
+}
+
+fn slice_uninit_ref<T>(slice: &[T]) -> &[MaybeUninit<T>] {
+    unsafe { &*(std::ptr::from_ref(slice) as *const [MaybeUninit<T>]) }
+}
+
+fn slice_uninit_mut<T>(slice: &mut [T]) -> &mut [MaybeUninit<T>] {
+    unsafe { &mut *(std::ptr::from_mut(slice) as *mut [MaybeUninit<T>]) }
 }