Skip to content

Commit 8fb4fa5

Browse files
fix: don't make ABI explicit when not guaranteed to preserve semantics (#4293)
1 parent 930d0f7 commit 8fb4fa5

File tree

6 files changed

+72
-16
lines changed

6 files changed

+72
-16
lines changed

src/formatting/items.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,19 @@ struct Item<'a> {
195195
}
196196

197197
impl<'a> Item<'a> {
198-
fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
198+
fn from_foreign_mod(
199+
fm: &'a ast::ForeignMod,
200+
span: Span,
201+
config: &Config,
202+
attrs: &[ast::Attribute],
203+
) -> Item<'a> {
199204
Item {
200205
keyword: "",
201206
abi: format_extern(
202207
ast::Extern::from_abi(fm.abi),
203208
config.force_explicit_abi(),
204209
true,
210+
Some(attrs),
205211
),
206212
vis: None,
207213
body: fm
@@ -293,6 +299,7 @@ impl<'a> FnSig<'a> {
293299
self.ext,
294300
context.config.force_explicit_abi(),
295301
false,
302+
None,
296303
));
297304
result
298305
}
@@ -337,8 +344,13 @@ impl<'a> FmtVisitor<'a> {
337344
}
338345
}
339346

340-
pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
341-
let item = Item::from_foreign_mod(fm, span, self.config);
347+
pub(crate) fn format_foreign_mod(
348+
&mut self,
349+
fm: &ast::ForeignMod,
350+
span: Span,
351+
attrs: &[ast::Attribute],
352+
) {
353+
let item = Item::from_foreign_mod(fm, span, self.config, attrs);
342354
self.format_item(&item);
343355
}
344356

src/formatting/types.rs

+1
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ fn rewrite_bare_fn(
785785
bare_fn.ext,
786786
context.config.force_explicit_abi(),
787787
false,
788+
None,
788789
));
789790

790791
result.push_str("fn");

src/formatting/utils.rs

+21-12
Original file line numberDiff line numberDiff line change
@@ -147,19 +147,28 @@ pub(crate) fn format_extern(
147147
ext: ast::Extern,
148148
explicit_abi: bool,
149149
is_mod: bool,
150+
attrs: Option<&[ast::Attribute]>,
150151
) -> Cow<'static, str> {
151-
let abi = match ext {
152-
ast::Extern::None => "Rust".to_owned(),
153-
ast::Extern::Implicit => "C".to_owned(),
154-
ast::Extern::Explicit(abi) => abi.symbol_unescaped.to_string(),
155-
};
156-
157-
if abi == "Rust" && !is_mod {
158-
Cow::from("")
159-
} else if abi == "C" && !explicit_abi {
160-
Cow::from("extern ")
161-
} else {
162-
Cow::from(format!(r#"extern "{}" "#, abi))
152+
let format_explicit_abi = |abi: &str| Cow::from(format!(r#"extern "{}" "#, abi));
153+
let explicit_conversion_preserves_semantics =
154+
|| !is_mod || (is_mod && attrs.map_or(true, |a| a.is_empty()));
155+
156+
match ext {
157+
ast::Extern::None if !is_mod => Cow::from(""),
158+
ast::Extern::Explicit(ast::StrLit {
159+
symbol_unescaped, ..
160+
}) if !is_mod && symbol_unescaped == rustc_span::sym::rust => Cow::from(""),
161+
ast::Extern::Implicit if !explicit_abi || !explicit_conversion_preserves_semantics() => {
162+
Cow::from("extern ")
163+
}
164+
ast::Extern::Explicit(ast::StrLit {
165+
symbol_unescaped, ..
166+
}) if !explicit_abi && symbol_unescaped == rustc_span::sym::C => Cow::from("extern "),
167+
ast::Extern::None => format_explicit_abi("Rust"),
168+
ast::Extern::Implicit => format_explicit_abi("C"),
169+
ast::Extern::Explicit(ast::StrLit {
170+
symbol_unescaped, ..
171+
}) => format_explicit_abi(&symbol_unescaped.to_string()),
163172
}
164173
}
165174

src/formatting/visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
513513
}
514514
ast::ItemKind::ForeignMod(ref foreign_mod) => {
515515
self.format_missing_with_indent(source!(self, item.span).lo());
516-
self.format_foreign_mod(foreign_mod, item.span);
516+
self.format_foreign_mod(foreign_mod, item.span, item.attrs());
517517
}
518518
ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => {
519519
self.visit_static(&StaticParts::from_item(item));

tests/source/extern.rs

+17
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,20 @@ libc::c_long;
8282
extern {
8383

8484
}
85+
86+
// #2908 - https://github.com/rust-lang/rustfmt/issues/2908
87+
#[wasm_bindgen(module = "child_process", version = "*")]
88+
extern {
89+
#[wasm_bindgen(js_name = execSync)]
90+
fn exec_sync(cmd: &str) -> Buffer;
91+
92+
fn foo() -> Bar;
93+
}
94+
95+
// Users that have an existing explicit ABI would need to convert to implicit
96+
// manually, as rustfmt will be conservative and not attempt to convert explicit
97+
// to implicit in the wasm case.
98+
#[wasm_bindgen]
99+
extern "C" {
100+
fn foo() -> Bar;
101+
}

tests/target/extern.rs

+17
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,20 @@ extern "C" {
8484
}
8585

8686
extern "C" {}
87+
88+
// #2908 - https://github.com/rust-lang/rustfmt/issues/2908
89+
#[wasm_bindgen(module = "child_process", version = "*")]
90+
extern {
91+
#[wasm_bindgen(js_name = execSync)]
92+
fn exec_sync(cmd: &str) -> Buffer;
93+
94+
fn foo() -> Bar;
95+
}
96+
97+
// Users that have an existing explicit ABI would need to convert to implicit
98+
// manually, as rustfmt will be conservative and not attempt to convert explicit
99+
// to implicit in the wasm case.
100+
#[wasm_bindgen]
101+
extern "C" {
102+
fn foo() -> Bar;
103+
}

0 commit comments

Comments
 (0)