Skip to content

Commit

Permalink
fix: don't make ABI explicit when not guaranteed to preserve semantics (
Browse files Browse the repository at this point in the history
  • Loading branch information
calebcartwright authored Jun 30, 2020
1 parent 930d0f7 commit 8fb4fa5
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 16 deletions.
18 changes: 15 additions & 3 deletions src/formatting/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,19 @@ struct Item<'a> {
}

impl<'a> Item<'a> {
fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
fn from_foreign_mod(
fm: &'a ast::ForeignMod,
span: Span,
config: &Config,
attrs: &[ast::Attribute],
) -> Item<'a> {
Item {
keyword: "",
abi: format_extern(
ast::Extern::from_abi(fm.abi),
config.force_explicit_abi(),
true,
Some(attrs),
),
vis: None,
body: fm
Expand Down Expand Up @@ -293,6 +299,7 @@ impl<'a> FnSig<'a> {
self.ext,
context.config.force_explicit_abi(),
false,
None,
));
result
}
Expand Down Expand Up @@ -337,8 +344,13 @@ impl<'a> FmtVisitor<'a> {
}
}

pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
let item = Item::from_foreign_mod(fm, span, self.config);
pub(crate) fn format_foreign_mod(
&mut self,
fm: &ast::ForeignMod,
span: Span,
attrs: &[ast::Attribute],
) {
let item = Item::from_foreign_mod(fm, span, self.config, attrs);
self.format_item(&item);
}

Expand Down
1 change: 1 addition & 0 deletions src/formatting/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ fn rewrite_bare_fn(
bare_fn.ext,
context.config.force_explicit_abi(),
false,
None,
));

result.push_str("fn");
Expand Down
33 changes: 21 additions & 12 deletions src/formatting/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,28 @@ pub(crate) fn format_extern(
ext: ast::Extern,
explicit_abi: bool,
is_mod: bool,
attrs: Option<&[ast::Attribute]>,
) -> Cow<'static, str> {
let abi = match ext {
ast::Extern::None => "Rust".to_owned(),
ast::Extern::Implicit => "C".to_owned(),
ast::Extern::Explicit(abi) => abi.symbol_unescaped.to_string(),
};

if abi == "Rust" && !is_mod {
Cow::from("")
} else if abi == "C" && !explicit_abi {
Cow::from("extern ")
} else {
Cow::from(format!(r#"extern "{}" "#, abi))
let format_explicit_abi = |abi: &str| Cow::from(format!(r#"extern "{}" "#, abi));
let explicit_conversion_preserves_semantics =
|| !is_mod || (is_mod && attrs.map_or(true, |a| a.is_empty()));

match ext {
ast::Extern::None if !is_mod => Cow::from(""),
ast::Extern::Explicit(ast::StrLit {
symbol_unescaped, ..
}) if !is_mod && symbol_unescaped == rustc_span::sym::rust => Cow::from(""),
ast::Extern::Implicit if !explicit_abi || !explicit_conversion_preserves_semantics() => {
Cow::from("extern ")
}
ast::Extern::Explicit(ast::StrLit {
symbol_unescaped, ..
}) if !explicit_abi && symbol_unescaped == rustc_span::sym::C => Cow::from("extern "),
ast::Extern::None => format_explicit_abi("Rust"),
ast::Extern::Implicit => format_explicit_abi("C"),
ast::Extern::Explicit(ast::StrLit {
symbol_unescaped, ..
}) => format_explicit_abi(&symbol_unescaped.to_string()),
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/formatting/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
}
ast::ItemKind::ForeignMod(ref foreign_mod) => {
self.format_missing_with_indent(source!(self, item.span).lo());
self.format_foreign_mod(foreign_mod, item.span);
self.format_foreign_mod(foreign_mod, item.span, item.attrs());
}
ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => {
self.visit_static(&StaticParts::from_item(item));
Expand Down
17 changes: 17 additions & 0 deletions tests/source/extern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,20 @@ libc::c_long;
extern {

}

// #2908 - https://github.com/rust-lang/rustfmt/issues/2908
#[wasm_bindgen(module = "child_process", version = "*")]
extern {
#[wasm_bindgen(js_name = execSync)]
fn exec_sync(cmd: &str) -> Buffer;

fn foo() -> Bar;
}

// Users that have an existing explicit ABI would need to convert to implicit
// manually, as rustfmt will be conservative and not attempt to convert explicit
// to implicit in the wasm case.
#[wasm_bindgen]
extern "C" {
fn foo() -> Bar;
}
17 changes: 17 additions & 0 deletions tests/target/extern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,20 @@ extern "C" {
}

extern "C" {}

// #2908 - https://github.com/rust-lang/rustfmt/issues/2908
#[wasm_bindgen(module = "child_process", version = "*")]
extern {
#[wasm_bindgen(js_name = execSync)]
fn exec_sync(cmd: &str) -> Buffer;

fn foo() -> Bar;
}

// Users that have an existing explicit ABI would need to convert to implicit
// manually, as rustfmt will be conservative and not attempt to convert explicit
// to implicit in the wasm case.
#[wasm_bindgen]
extern "C" {
fn foo() -> Bar;
}

0 comments on commit 8fb4fa5

Please sign in to comment.