Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2463,9 +2463,10 @@ pub const STDLIB_STABLE_CRATES: &[Symbol] = &[sym::std, sym::core, sym::alloc, s

#[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<Ident>` 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<Ident>` instead.
/// Trying to construct an `Ident` with an empty name will trigger debug assertions.
pub name: Symbol,
pub span: Span,
}
Expand Down Expand Up @@ -2508,6 +2509,8 @@ impl 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)
}
Expand Down Expand Up @@ -3095,10 +3098,15 @@ impl Ident {
}

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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thumbs up for the name/ident renaming here.

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 {
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/extern/extern-single-quote-issue-147365.rs
Original file line number Diff line number Diff line change
@@ -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() {}
16 changes: 16 additions & 0 deletions tests/ui/extern/extern-single-quote-issue-147365.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading