Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b9024f8

Browse files
committedJul 18, 2018
rustc: Stabilize #[wasm_import_module] as #[link(...)]
This commit stabilizes the `#[wasm_import_module]` attribute as `#[link(wasm_import_module = "...")]`. Tracked by rust-lang#52090 this new directive in the `#[link]` attribute is used to configured the module name that the imports are listed with. The WebAssembly specification indicates two utf-8 names are associated with all imported items, one for the module the item comes from and one for the item itself. The item itself is configurable in Rust via its identifier or `#[link_name = "..."]`, but the module name was previously not configurable and defaulted to `"env"`. This commit ensures that this is also configurable. Closes rust-lang#52090
1 parent 29ee654 commit b9024f8

16 files changed

+165
-160
lines changed
 

‎src/librustc/hir/check_attr.rs

-21
Original file line numberDiff line numberDiff line change
@@ -65,35 +65,14 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
6565
.emit();
6666
}
6767

68-
let mut has_wasm_import_module = false;
6968
for attr in &item.attrs {
7069
if attr.check_name("inline") {
7170
self.check_inline(attr, &item.span, target)
7271
} else if attr.check_name("non_exhaustive") {
7372
self.check_non_exhaustive(attr, item, target)
74-
} else if attr.check_name("wasm_import_module") {
75-
has_wasm_import_module = true;
76-
if attr.value_str().is_none() {
77-
self.tcx.sess.span_err(attr.span, "\
78-
must be of the form #[wasm_import_module = \"...\"]");
79-
}
80-
if target != Target::ForeignMod {
81-
self.tcx.sess.span_err(attr.span, "\
82-
must only be attached to foreign modules");
83-
}
8473
}
8574
}
8675

87-
if target == Target::ForeignMod &&
88-
!has_wasm_import_module &&
89-
self.tcx.sess.target.target.arch == "wasm32" &&
90-
false // FIXME: eventually enable this warning when stable
91-
{
92-
self.tcx.sess.span_warn(item.span, "\
93-
must have a #[wasm_import_module = \"...\"] attribute, this \
94-
will become a hard error before too long");
95-
}
96-
9776
self.check_repr(item, target);
9877
self.check_used(item, target);
9978
}

‎src/librustc/ich/impls_cstore.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ impl_stable_hash_for!(struct middle::cstore::NativeLibrary {
3131
kind,
3232
name,
3333
cfg,
34-
foreign_module
34+
foreign_module,
35+
wasm_import_module
3536
});
3637

3738
impl_stable_hash_for!(struct middle::cstore::ForeignModule {

‎src/librustc/middle/cstore.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,10 @@ pub enum NativeLibraryKind {
128128
#[derive(Clone, RustcEncodable, RustcDecodable)]
129129
pub struct NativeLibrary {
130130
pub kind: NativeLibraryKind,
131-
pub name: Symbol,
131+
pub name: Option<Symbol>,
132132
pub cfg: Option<ast::MetaItem>,
133133
pub foreign_module: Option<DefId>,
134+
pub wasm_import_module: Option<Symbol>,
134135
}
135136

136137
#[derive(Clone, Hash, RustcEncodable, RustcDecodable)]

‎src/librustc_codegen_llvm/attributes.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -226,13 +226,22 @@ pub fn provide(providers: &mut Providers) {
226226

227227
pub fn provide_extern(providers: &mut Providers) {
228228
providers.wasm_import_module_map = |tcx, cnum| {
229+
// Build up a map from DefId to a `NativeLibrary` structure, where
230+
// `NativeLibrary` internally contains information about
231+
// `#[link(wasm_import_module = "...")]` for example.
232+
let native_libs = tcx.native_libraries(cnum);
233+
let mut def_id_to_native_lib = FxHashMap();
234+
for lib in native_libs.iter() {
235+
if let Some(id) = lib.foreign_module {
236+
def_id_to_native_lib.insert(id, lib);
237+
}
238+
}
239+
229240
let mut ret = FxHashMap();
230241
for lib in tcx.foreign_modules(cnum).iter() {
231-
let attrs = tcx.get_attrs(lib.def_id);
232-
let mut module = None;
233-
for attr in attrs.iter().filter(|a| a.check_name("wasm_import_module")) {
234-
module = attr.value_str();
235-
}
242+
let module = def_id_to_native_lib
243+
.get(&lib.def_id)
244+
.and_then(|s| s.wasm_import_module);
236245
let module = match module {
237246
Some(s) => s,
238247
None => continue,
@@ -244,7 +253,7 @@ pub fn provide_extern(providers: &mut Providers) {
244253
}
245254

246255
Lrc::new(ret)
247-
}
256+
};
248257
}
249258

250259
fn wasm_import_module(tcx: TyCtxt, id: DefId) -> Option<CString> {

‎src/librustc_codegen_llvm/back/link.rs

+36-23
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,9 @@ fn link_rlib<'a>(sess: &'a Session,
449449
NativeLibraryKind::NativeFramework |
450450
NativeLibraryKind::NativeUnknown => continue,
451451
}
452-
ab.add_native_library(&lib.name.as_str());
452+
if let Some(name) = lib.name {
453+
ab.add_native_library(&name.as_str());
454+
}
453455
}
454456

455457
// After adding all files to the archive, we need to update the
@@ -583,21 +585,24 @@ fn link_staticlib(sess: &Session,
583585
fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
584586
let lib_args: Vec<_> = all_native_libs.iter()
585587
.filter(|l| relevant_lib(sess, l))
586-
.filter_map(|lib| match lib.kind {
587-
NativeLibraryKind::NativeStaticNobundle |
588-
NativeLibraryKind::NativeUnknown => {
589-
if sess.target.target.options.is_like_msvc {
590-
Some(format!("{}.lib", lib.name))
591-
} else {
592-
Some(format!("-l{}", lib.name))
593-
}
594-
},
595-
NativeLibraryKind::NativeFramework => {
596-
// ld-only syntax, since there are no frameworks in MSVC
597-
Some(format!("-framework {}", lib.name))
598-
},
599-
// These are included, no need to print them
600-
NativeLibraryKind::NativeStatic => None,
588+
.filter_map(|lib| {
589+
let name = lib.name?;
590+
match lib.kind {
591+
NativeLibraryKind::NativeStaticNobundle |
592+
NativeLibraryKind::NativeUnknown => {
593+
if sess.target.target.options.is_like_msvc {
594+
Some(format!("{}.lib", name))
595+
} else {
596+
Some(format!("-l{}", name))
597+
}
598+
},
599+
NativeLibraryKind::NativeFramework => {
600+
// ld-only syntax, since there are no frameworks in MSVC
601+
Some(format!("-framework {}", name))
602+
},
603+
// These are included, no need to print them
604+
NativeLibraryKind::NativeStatic => None,
605+
}
601606
})
602607
.collect();
603608
if !lib_args.is_empty() {
@@ -1211,11 +1216,15 @@ fn add_local_native_libraries(cmd: &mut dyn Linker,
12111216

12121217
let search_path = archive_search_paths(sess);
12131218
for lib in relevant_libs {
1219+
let name = match lib.name {
1220+
Some(ref l) => l,
1221+
None => continue,
1222+
};
12141223
match lib.kind {
1215-
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()),
1216-
NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()),
1217-
NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()),
1218-
NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(),
1224+
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
1225+
NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
1226+
NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()),
1227+
NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(),
12191228
&search_path)
12201229
}
12211230
}
@@ -1578,19 +1587,23 @@ fn add_upstream_native_libraries(cmd: &mut dyn Linker,
15781587
let crates = &codegen_results.crate_info.used_crates_static;
15791588
for &(cnum, _) in crates {
15801589
for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
1590+
let name = match lib.name {
1591+
Some(ref l) => l,
1592+
None => continue,
1593+
};
15811594
if !relevant_lib(sess, &lib) {
15821595
continue
15831596
}
15841597
match lib.kind {
1585-
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()),
1586-
NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()),
1598+
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
1599+
NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
15871600
NativeLibraryKind::NativeStaticNobundle => {
15881601
// Link "static-nobundle" native libs only if the crate they originate from
15891602
// is being linked statically to the current crate. If it's linked dynamically
15901603
// or is an rlib already included via some other dylib crate, the symbols from
15911604
// native libs will have already been included in that dylib.
15921605
if data[cnum.as_usize() - 1] == Linkage::Static {
1593-
cmd.link_staticlib(&lib.name.as_str())
1606+
cmd.link_staticlib(&name.as_str())
15941607
}
15951608
},
15961609
// ignore statically included native libraries here as we've

‎src/librustc_codegen_llvm/back/wasm.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ const WASM_EXTERNAL_KIND_GLOBAL: u8 = 3;
3434
///
3535
/// This function is intended as a hack for now where we manually rewrite the
3636
/// wasm output by LLVM to have the correct import modules listed. The
37-
/// `#[wasm_import_module]` attribute in Rust translates to the module that each
38-
/// symbol is imported from, so here we manually go through the wasm file,
39-
/// decode it, rewrite imports, and then rewrite the wasm module.
37+
/// `#[link(wasm_import_module = "...")]` attribute in Rust translates to the
38+
/// module that each symbol is imported from, so here we manually go through the
39+
/// wasm file, decode it, rewrite imports, and then rewrite the wasm module.
4040
///
4141
/// Support for this was added to LLVM in
4242
/// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still

‎src/librustc_metadata/native_libs.rs

+80-52
Original file line numberDiff line numberDiff line change
@@ -61,56 +61,75 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
6161
Some(item) => item,
6262
None => continue,
6363
};
64-
let kind = items.iter().find(|k| {
65-
k.check_name("kind")
66-
}).and_then(|a| a.value_str()).map(Symbol::as_str);
67-
let kind = match kind.as_ref().map(|s| &s[..]) {
68-
Some("static") => cstore::NativeStatic,
69-
Some("static-nobundle") => cstore::NativeStaticNobundle,
70-
Some("dylib") => cstore::NativeUnknown,
71-
Some("framework") => cstore::NativeFramework,
72-
Some(k) => {
73-
struct_span_err!(self.tcx.sess, m.span, E0458,
74-
"unknown kind: `{}`", k)
75-
.span_label(m.span, "unknown kind").emit();
76-
cstore::NativeUnknown
77-
}
78-
None => cstore::NativeUnknown
79-
};
80-
let n = items.iter().find(|n| {
81-
n.check_name("name")
82-
}).and_then(|a| a.value_str());
83-
let n = match n {
84-
Some(n) => n,
85-
None => {
86-
struct_span_err!(self.tcx.sess, m.span, E0459,
87-
"#[link(...)] specified without `name = \"foo\"`")
88-
.span_label(m.span, "missing `name` argument").emit();
89-
Symbol::intern("foo")
90-
}
64+
let mut lib = NativeLibrary {
65+
name: None,
66+
kind: cstore::NativeUnknown,
67+
cfg: None,
68+
foreign_module: Some(self.tcx.hir.local_def_id(it.id)),
69+
wasm_import_module: None,
9170
};
92-
let cfg = items.iter().find(|k| {
93-
k.check_name("cfg")
94-
}).and_then(|a| a.meta_item_list());
95-
let cfg = if let Some(list) = cfg {
96-
if list.is_empty() {
97-
self.tcx.sess.span_err(m.span(), "`cfg()` must have an argument");
98-
return;
99-
} else if let cfg @ Some(..) = list[0].meta_item() {
100-
cfg.cloned()
71+
let mut kind_specified = false;
72+
73+
for item in items.iter() {
74+
if item.check_name("kind") {
75+
kind_specified = true;
76+
let kind = match item.value_str() {
77+
Some(name) => name,
78+
None => continue, // skip like historical compilers
79+
};
80+
lib.kind = match &kind.as_str()[..] {
81+
"static" => cstore::NativeStatic,
82+
"static-nobundle" => cstore::NativeStaticNobundle,
83+
"dylib" => cstore::NativeUnknown,
84+
"framework" => cstore::NativeFramework,
85+
k => {
86+
struct_span_err!(self.tcx.sess, m.span, E0458,
87+
"unknown kind: `{}`", k)
88+
.span_label(item.span, "unknown kind").emit();
89+
cstore::NativeUnknown
90+
}
91+
};
92+
} else if item.check_name("name") {
93+
lib.name = item.value_str();
94+
} else if item.check_name("cfg") {
95+
let cfg = match item.meta_item_list() {
96+
Some(list) => list,
97+
None => continue, // skip like historical compilers
98+
};
99+
if cfg.is_empty() {
100+
self.tcx.sess.span_err(
101+
item.span(),
102+
"`cfg()` must have an argument",
103+
);
104+
} else if let cfg @ Some(..) = cfg[0].meta_item() {
105+
lib.cfg = cfg.cloned();
106+
} else {
107+
self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
108+
}
109+
} else if item.check_name("wasm_import_module") {
110+
match item.value_str() {
111+
Some(s) => lib.wasm_import_module = Some(s),
112+
None => {
113+
let msg = "must be of the form #[link(wasm_import_module = \"...\")]";
114+
self.tcx.sess.span_err(item.span(), msg);
115+
}
116+
}
101117
} else {
102-
self.tcx.sess.span_err(list[0].span(), "invalid argument for `cfg(..)`");
103-
return;
118+
// currently, like past compilers, ignore unknown
119+
// directives here.
104120
}
105-
} else {
106-
None
107-
};
108-
let lib = NativeLibrary {
109-
name: n,
110-
kind,
111-
cfg,
112-
foreign_module: Some(self.tcx.hir.local_def_id(it.id)),
113-
};
121+
}
122+
123+
// In general we require #[link(name = "...")] but we allow
124+
// #[link(wasm_import_module = "...")] without the `name`.
125+
let requires_name = kind_specified || lib.wasm_import_module.is_none();
126+
if lib.name.is_none() && requires_name {
127+
struct_span_err!(self.tcx.sess, m.span, E0459,
128+
"#[link(...)] specified without \
129+
`name = \"foo\"`")
130+
.span_label(m.span, "missing `name` argument")
131+
.emit();
132+
}
114133
self.register_native_lib(Some(m.span), lib);
115134
}
116135
}
@@ -121,7 +140,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
121140

122141
impl<'a, 'tcx> Collector<'a, 'tcx> {
123142
fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
124-
if lib.name.as_str().is_empty() {
143+
if lib.name.as_ref().map(|s| s.as_str().is_empty()).unwrap_or(false) {
125144
match span {
126145
Some(span) => {
127146
struct_span_err!(self.tcx.sess, span, E0454,
@@ -167,10 +186,14 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
167186
let mut renames = FxHashSet();
168187
for &(ref name, ref new_name, _) in &self.tcx.sess.opts.libs {
169188
if let &Some(ref new_name) = new_name {
189+
let any_duplicate = self.libs
190+
.iter()
191+
.filter_map(|lib| lib.name.as_ref())
192+
.any(|n| n == name);
170193
if new_name.is_empty() {
171194
self.tcx.sess.err(
172195
&format!("an empty renaming target was specified for library `{}`",name));
173-
} else if !self.libs.iter().any(|lib| lib.name == name as &str) {
196+
} else if !any_duplicate {
174197
self.tcx.sess.err(&format!("renaming of the library `{}` was specified, \
175198
however this crate contains no #[link(...)] \
176199
attributes referencing this library.", name));
@@ -189,14 +212,18 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
189212
for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
190213
let mut found = false;
191214
for lib in self.libs.iter_mut() {
192-
if lib.name == name as &str {
215+
let lib_name = match lib.name {
216+
Some(n) => n,
217+
None => continue,
218+
};
219+
if lib_name == name as &str {
193220
let mut changed = false;
194221
if let Some(k) = kind {
195222
lib.kind = k;
196223
changed = true;
197224
}
198225
if let &Some(ref new_name) = new_name {
199-
lib.name = Symbol::intern(new_name);
226+
lib.name = Some(Symbol::intern(new_name));
200227
changed = true;
201228
}
202229
if !changed {
@@ -212,10 +239,11 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
212239
// Add if not found
213240
let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
214241
let lib = NativeLibrary {
215-
name: Symbol::intern(new_name.unwrap_or(name)),
242+
name: Some(Symbol::intern(new_name.unwrap_or(name))),
216243
kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
217244
cfg: None,
218245
foreign_module: None,
246+
wasm_import_module: None,
219247
};
220248
self.register_native_lib(None, lib);
221249
}

‎src/libsyntax/feature_gate.rs

-7
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,6 @@ declare_features! (
407407
// `use path as _;` and `extern crate c as _;`
408408
(active, underscore_imports, "1.26.0", Some(48216), None),
409409

410-
// The #![wasm_import_module] attribute
411-
(active, wasm_import_module, "1.26.0", Some(52090), None),
412-
413410
// Allows keywords to be escaped for use as identifiers
414411
(active, raw_identifiers, "1.26.0", Some(48589), None),
415412

@@ -969,10 +966,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
969966
"the `#[no_debug]` attribute was an experimental feature that has been \
970967
deprecated due to lack of demand",
971968
cfg_fn!(no_debug))),
972-
("wasm_import_module", Normal, Gated(Stability::Unstable,
973-
"wasm_import_module",
974-
"experimental attribute",
975-
cfg_fn!(wasm_import_module))),
976969
("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
977970
"omit_gdb_pretty_printer_section",
978971
"the `#[omit_gdb_pretty_printer_section]` \

‎src/test/run-make/wasm-import-module/bar.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99
// except according to those terms.
1010

1111
#![crate_type = "cdylib"]
12-
#![feature(wasm_import_module)]
1312
#![deny(warnings)]
1413

1514
extern crate foo;
1615

17-
#[wasm_import_module = "./me"]
16+
#[link(wasm_import_module = "./me")]
1817
extern {
1918
#[link_name = "me_in_dep"]
2019
fn dep();

‎src/test/run-make/wasm-import-module/foo.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@
99
// except according to those terms.
1010

1111
#![crate_type = "rlib"]
12-
#![feature(wasm_import_module)]
1312
#![deny(warnings)]
1413

15-
#[wasm_import_module = "./dep"]
14+
#[link(wasm_import_module = "./dep")]
1615
extern {
1716
pub fn dep();
1817
}

‎src/test/ui/error-codes/E0458.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0458]: unknown kind: `wonderful_unicorn`
22
--> $DIR/E0458.rs:11:1
33
|
44
LL | #[link(kind = "wonderful_unicorn")] extern {} //~ ERROR E0458
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown kind
5+
| ^^^^^^^--------------------------^^
6+
| |
7+
| unknown kind
68

79
error[E0459]: #[link(...)] specified without `name = "foo"`
810
--> $DIR/E0458.rs:11:1

‎src/test/ui/feature-gate-wasm_import_module.rs

-15
This file was deleted.

‎src/test/ui/feature-gate-wasm_import_module.stderr

-11
This file was deleted.

‎src/test/ui/issue-43926.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: `cfg()` must have an argument
2-
--> $DIR/issue-43926.rs:11:1
2+
--> $DIR/issue-43926.rs:11:20
33
|
44
LL | #[link(name="foo", cfg())] //~ ERROR `cfg()` must have an argument
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^
66

77
error: aborting due to previous error
88

‎src/test/ui/wasm-import-module.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(wasm_import_module)]
11+
#[link(name = "...", wasm_import_module)] //~ ERROR: must be of the form
12+
extern {}
1213

13-
#[wasm_import_module] //~ ERROR: must be of the form
14+
#[link(name = "...", wasm_import_module(x))] //~ ERROR: must be of the form
1415
extern {}
1516

16-
#[wasm_import_module = "foo"] //~ ERROR: must only be attached to
17-
fn foo() {}
17+
#[link(name = "...", wasm_import_module())] //~ ERROR: must be of the form
18+
extern {}
1819

1920
fn main() {}
2021

‎src/test/ui/wasm-import-module.stderr

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
error: must be of the form #[wasm_import_module = "..."]
2-
--> $DIR/wasm-import-module.rs:13:1
1+
error: must be of the form #[link(wasm_import_module = "...")]
2+
--> $DIR/wasm-import-module.rs:11:22
33
|
4-
LL | #[wasm_import_module] //~ ERROR: must be of the form
5-
| ^^^^^^^^^^^^^^^^^^^^^
4+
LL | #[link(name = "...", wasm_import_module)] //~ ERROR: must be of the form
5+
| ^^^^^^^^^^^^^^^^^^
66

7-
error: must only be attached to foreign modules
8-
--> $DIR/wasm-import-module.rs:16:1
7+
error: must be of the form #[link(wasm_import_module = "...")]
8+
--> $DIR/wasm-import-module.rs:14:22
99
|
10-
LL | #[wasm_import_module = "foo"] //~ ERROR: must only be attached to
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
10+
LL | #[link(name = "...", wasm_import_module(x))] //~ ERROR: must be of the form
11+
| ^^^^^^^^^^^^^^^^^^^^^
1212

13-
error: aborting due to 2 previous errors
13+
error: must be of the form #[link(wasm_import_module = "...")]
14+
--> $DIR/wasm-import-module.rs:17:22
15+
|
16+
LL | #[link(name = "...", wasm_import_module())] //~ ERROR: must be of the form
17+
| ^^^^^^^^^^^^^^^^^^^^
18+
19+
error: aborting due to 3 previous errors
1420

0 commit comments

Comments
 (0)
Please sign in to comment.