Repository: rust-lang/rustfmt (rust)

Issue:
Stripping `extern "Rust"` from functions
Rustfmt currently strips `extern "Rust"` from function signatures. e.g formatting `extern "Rust" fn foo() {}` to `fn foo() {}`. This seems to be intentional from the current code.

The problem here is this essentially deletes documentation from the code. Given a function such as:
```rust
#[no_mangle]
extern "Rust" fn foo() { /* do stuff */ }
```
With the ABI explicitly added here, it's clear that the odd ABI choice is intentional. Without the explicit ABI, it's unclear whether the choice was intentional, or an ABI was forgotten (e.g. `extern "C"`).

Can't find anything relevant from the style guide about this removal.

Pull request description:
refactor ABI formatting
whenever we see an `extern "Rust"` on a function, we don't strip it from the function (which fixes #5701)

Patch:
diff --git a/src/items.rs b/src/items.rs
index a72646ef..1f4a1421 100644
--- a/src/items.rs
+++ b/src/items.rs
@@ -248,7 +248,6 @@ impl<'a> Item<'a> {
             abi: format_extern(
                 ast::Extern::from_abi(fm.abi, DUMMY_SP),
                 config.force_explicit_abi(),
-                true,
             ),
             vis: None,
             body: fm
@@ -336,7 +335,6 @@ impl<'a> FnSig<'a> {
         result.push_str(&format_extern(
             self.ext,
             context.config.force_explicit_abi(),
-            false,
         ));
         result
     }
diff --git a/src/types.rs b/src/types.rs
index 8be474d5..f2e229d7 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -892,7 +892,6 @@ fn rewrite_bare_fn(
     result.push_str(&format_extern(
         bare_fn.ext,
         context.config.force_explicit_abi(),
-        false,
     ));
 
     result.push_str("fn");
diff --git a/src/utils.rs b/src/utils.rs
index d1cb197c..ae7c50b4 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -131,23 +131,18 @@ pub(crate) fn format_mutability(mutability: ast::Mutability) -> &'static str {
 }
 
 #[inline]
-pub(crate) fn format_extern(
-    ext: ast::Extern,
-    explicit_abi: bool,
-    is_mod: bool,
-) -> 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}" "#))
+pub(crate) fn format_extern(ext: ast::Extern, explicit_abi: bool) -> Cow<'static, str> {
+    match ext {
+        ast::Extern::None => Cow::from(""),
+        ast::Extern::Implicit(_) if explicit_abi => Cow::from("extern \"C\" "),
+        ast::Extern::Implicit(_) => Cow::from("extern "),
+        // turn `extern "C"` into `extern` when `explicit_abi` is set to false
+        ast::Extern::Explicit(abi, _) if abi.symbol_unescaped == sym::C && !explicit_abi => {
+            Cow::from("extern ")
+        }
+        ast::Extern::Explicit(abi, _) => {
+            Cow::from(format!(r#"extern "{}" "#, abi.symbol_unescaped))
+        }
     }
 }
 


Test patch:
diff --git a/tests/target/extern-rust.rs b/tests/target/extern-rust.rs
new file mode 100644
index 00000000..32824c91
--- /dev/null
+++ b/tests/target/extern-rust.rs
@@ -0,0 +1,1 @@
+extern "Rust" fn uwu() {}