From a316f5b72e6a9277f0fb912eab8e7a47074bb500 Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Sun, 5 Oct 2025 12:57:48 +0200 Subject: [PATCH 1/2] don't make empty ident when printing `'` ident from `extern "'"` --- compiler/rustc_span/src/symbol.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 083e04730bc3..35786d893287 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2463,9 +2463,10 @@ #[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)] pub struct Ident { - // `name` should never be the empty symbol. If you are considering that, - // you are probably conflating "empty identifier with "no identifier" and - // you should use `Option` instead. + /// `name` should never be the empty symbol. If you are considering that, + /// you are probably conflating "empty identifier with "no identifier" and + /// you should use `Option` instead. + /// Trying to construct an `Ident` with an empty name will trigger debug assertions. pub name: Symbol, pub span: Span, } @@ -2508,6 +2509,8 @@ pub fn with_span_pos(self, span: Span) -> Ident { Ident::new(self.name, span.with_ctxt(self.span.ctxt())) } + /// Creates a new ident with the same span and name with leading quote removed, if any. + /// If called on an empty ident, or with name just a single quote, returns an empty ident which is invalid. pub fn without_first_quote(self) -> Ident { Ident::new(Symbol::intern(self.as_str().trim_start_matches('\'')), self.span) } @@ -3095,10 +3098,15 @@ pub fn is_reserved_lifetime(self) -> bool { } pub fn is_raw_lifetime_guess(self) -> bool { - let name_without_apostrophe = self.without_first_quote(); - name_without_apostrophe.name != self.name - && name_without_apostrophe.name.can_be_raw() - && name_without_apostrophe.is_reserved_lifetime() + // Check that the name isn't just a single quote. + // `self.without_first_quote()` would return empty ident, which triggers debug assert. + if self.name.as_str() == "'" { + return false; + } + let ident_without_apostrophe = self.without_first_quote(); + ident_without_apostrophe.name != self.name + && ident_without_apostrophe.name.can_be_raw() + && ident_without_apostrophe.is_reserved_lifetime() } pub fn guess_print_mode(self) -> IdentPrintMode { From 5234d36597b8f22aba25eef67d892315a439e927 Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Sun, 5 Oct 2025 13:18:02 +0200 Subject: [PATCH 2/2] add test --- .../extern/extern-single-quote-issue-147365.rs | 9 +++++++++ .../extern-single-quote-issue-147365.stderr | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/ui/extern/extern-single-quote-issue-147365.rs create mode 100644 tests/ui/extern/extern-single-quote-issue-147365.stderr diff --git a/tests/ui/extern/extern-single-quote-issue-147365.rs b/tests/ui/extern/extern-single-quote-issue-147365.rs new file mode 100644 index 000000000000..b50016bd65f3 --- /dev/null +++ b/tests/ui/extern/extern-single-quote-issue-147365.rs @@ -0,0 +1,9 @@ +//@ needs-rustc-debug-assertions + +// https://github.com/rust-lang/rust/issues/147365 +// Ensures we don't trigger debug assert by creating an empty Ident when determining whether +// the single quote is a raw lifetime. + +extern "'" {} //~ ERROR invalid ABI: found `'` + +fn main() {} diff --git a/tests/ui/extern/extern-single-quote-issue-147365.stderr b/tests/ui/extern/extern-single-quote-issue-147365.stderr new file mode 100644 index 000000000000..d761bc3ebf32 --- /dev/null +++ b/tests/ui/extern/extern-single-quote-issue-147365.stderr @@ -0,0 +1,16 @@ +error[E0703]: invalid ABI: found `'` + --> $DIR/extern-single-quote-issue-147365.rs:7:8 + | +LL | extern "'" {} + | ^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions +help: there's a similarly named valid ABI `C` + | +LL - extern "'" {} +LL + extern "C" {} + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0703`.