Skip to content
Closed
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
7 changes: 7 additions & 0 deletions compiler/rustc_errors/src/diagnostic_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustc_ast_pretty::pprust;
use rustc_attr_data_structures::RustcVersion;
use rustc_macros::Subdiagnostic;
use rustc_span::edition::Edition;
use rustc_span::symbol::LabelSymbol;
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTuple};
use rustc_type_ir::{ClosureKind, FloatTy};
Expand Down Expand Up @@ -168,6 +169,12 @@ impl IntoDiagArg for Symbol {
}
}

impl IntoDiagArg for LabelSymbol {
fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
self.to_string().into_diag_arg(path)
}
}

impl<'a> IntoDiagArg for &'a str {
fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
self.to_string().into_diag_arg(path)
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rustc_errors::{
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
use rustc_span::symbol::LabelSymbol;
use rustc_span::{Ident, Span, Symbol};

use crate::fluent_generated as fluent;
Expand Down Expand Up @@ -2191,7 +2192,7 @@ pub(crate) struct KeywordLifetime {
pub(crate) struct InvalidLabel {
#[primary_span]
pub span: Span,
pub name: Symbol,
pub name: LabelSymbol,
}

#[derive(Diagnostic)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3077,7 +3077,7 @@ impl<'a> Parser<'a> {
if let Some((ident, is_raw)) = self.token.lifetime() {
// Disallow `'fn`, but with a better error message than `expect_lifetime`.
if matches!(is_raw, IdentIsRaw::No) && ident.without_first_quote().is_reserved() {
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.into() });
}

self.bump();
Expand Down
18 changes: 11 additions & 7 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3127,7 +3127,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
} else {
self.suggest_introducing_lifetime(
&mut err,
Some(lifetime_ref.ident.name.as_str()),
Some(lifetime_ref.ident),
|err, _, span, message, suggestion, span_suggs| {
err.multipart_suggestion_verbose(
message,
Expand All @@ -3145,7 +3145,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
fn suggest_introducing_lifetime(
&self,
err: &mut Diag<'_>,
name: Option<&str>,
name: Option<Ident>,
suggest: impl Fn(
&mut Diag<'_>,
bool,
Expand Down Expand Up @@ -3192,7 +3192,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
let mut rm_inner_binders: FxIndexSet<Span> = Default::default();
let (span, sugg) = if span.is_empty() {
let mut binder_idents: FxIndexSet<Ident> = Default::default();
binder_idents.insert(Ident::from_str(name.unwrap_or("'a")));
binder_idents
.insert(name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime)));

// We need to special case binders in the following situation:
// Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
Expand Down Expand Up @@ -3226,9 +3227,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
"".to_string(),
|mut binders, (i, x)| {
if i != 0 {
binders += ", ";
binders.push_str(", ");
}
binders += x.as_str();
binders.push_str(&x.to_string());
Copy link
Member Author

Choose a reason for hiding this comment

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

I use push_str.

binders
},
);
Expand All @@ -3247,15 +3248,18 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
.source_map()
.span_through_char(span, '<')
.shrink_to_hi();
let sugg = format!("{}, ", name.unwrap_or("'a"));
let sugg = format!(
"{}, ",
name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime))
);
(span, sugg)
};

if higher_ranked {
let message = Cow::from(format!(
"consider making the {} lifetime-generic with a new `{}` lifetime",
kind.descr(),
name.unwrap_or("'a"),
name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime)),
Copy link
Member Author

Choose a reason for hiding this comment

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

use interned 'a

));
should_continue = suggest(
err,
Expand Down
50 changes: 49 additions & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ symbols! {
default_field_values,
default_fn,
default_lib_allocator,
default_lifetime: "'a",
Copy link
Member Author

Choose a reason for hiding this comment

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

I pre-intern 'a.

default_method_body_is_const,
// --------------------------
// Lang items which are used only for experiments with auto traits with default bounds.
Expand Down Expand Up @@ -2477,6 +2478,10 @@ impl Ident {
pub fn as_str(&self) -> &str {
self.name.as_str()
}

pub fn as_lifetime(&self) -> Option<Ident> {
self.name.as_lifetime().map(|sym| Ident::with_dummy_span(sym))
}
}

impl PartialEq for Ident {
Expand Down Expand Up @@ -2546,6 +2551,14 @@ impl IdentPrinter {

impl fmt::Display for IdentPrinter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(lifetime) = self.symbol.as_lifetime() {
f.write_str("'")?;
if self.is_raw {
f.write_str("r#")?;
}
return fmt::Display::fmt(&lifetime, f);
}

if self.is_raw {
Copy link
Member Author

Choose a reason for hiding this comment

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

When Ident starts with ', the contents are printed recursively.

f.write_str("r#")?;
} else if self.symbol == kw::DollarCrate {
Expand Down Expand Up @@ -2640,6 +2653,11 @@ impl Symbol {
self == sym::empty
}

pub fn as_lifetime(self) -> Option<Symbol> {
let name = self.as_str();
name.strip_prefix("'").map(Symbol::intern)
}

/// This method is supposed to be used in error messages, so it's expected to be
/// identical to printing the original identifier token written in source code
/// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag
Expand Down Expand Up @@ -2946,7 +2964,13 @@ impl Ident {
/// We see this identifier in a normal identifier position, like variable name or a type.
/// How was it written originally? Did it use the raw form? Let's try to guess.
pub fn is_raw_guess(self) -> bool {
self.name.can_be_raw() && self.is_reserved()
if self.name == kw::StaticLifetime || self.name == kw::UnderscoreLifetime {
false
} else if let Some(lifetime) = self.as_lifetime() {
lifetime.is_raw_guess()
Comment on lines +2969 to +2970
Copy link
Member Author

Choose a reason for hiding this comment

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

where do you use this

I use Ident::as_lifetime here.

} else {
self.name.can_be_raw() && self.is_reserved()
}
Comment on lines +2967 to +2973
Copy link
Member Author

Choose a reason for hiding this comment

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

There are two keywords that need to be excluded here.

}

/// Whether this would be the identifier for a tuple field like `self.0`, as
Expand All @@ -2972,3 +2996,27 @@ pub fn used_keywords(edition: impl Copy + FnOnce() -> Edition) -> Vec<Symbol> {
})
.collect()
}

/// A newtype around `Symbol` specifically for label printing.
/// This ensures type safety when dealing with labels and provides
/// specialized formatting behavior for label contexts.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct LabelSymbol(Symbol);
Comment on lines +3000 to +3004
Copy link
Member Author

Choose a reason for hiding this comment

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

I create a new type for label print.


impl fmt::Display for LabelSymbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.as_str())
}
}

impl From<Symbol> for LabelSymbol {
fn from(symbol: Symbol) -> Self {
LabelSymbol(symbol)
}
}

impl From<Ident> for LabelSymbol {
fn from(ident: Ident) -> Self {
LabelSymbol(ident.name)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//@ edition: 2021
fn a(_: dyn Trait + 'r#fn) { //~ ERROR use of undeclared lifetime name `'r#fn` [E0261]

}

trait Trait {}

#[derive(Eq, PartialEq)]
struct Test {
a: &'r#fn str,
//~^ ERROR use of undeclared lifetime name `'r#fn` [E0261]
//~| ERROR use of undeclared lifetime name `'r#fn` [E0261]
}

trait Trait1<T>
where T: for<'a> Trait1<T> + 'r#fn { } //~ ERROR use of undeclared lifetime name `'r#fn` [E0261]



fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
error[E0261]: use of undeclared lifetime name `'r#fn`
--> $DIR/error-lifetime-name-issue-143150.rs:2:21
|
LL | fn a(_: dyn Trait + 'r#fn) {
| ^^^^^ undeclared lifetime
|
help: consider introducing lifetime `'r#fn` here
|
LL | fn a<'r#fn>(_: dyn Trait + 'r#fn) {
| +++++++

error[E0261]: use of undeclared lifetime name `'r#fn`
--> $DIR/error-lifetime-name-issue-143150.rs:10:9
|
LL | a: &'r#fn str,
| ^^^^^ undeclared lifetime
|
help: consider introducing lifetime `'r#fn` here
|
LL | struct Test<'r#fn> {
| +++++++

error[E0261]: use of undeclared lifetime name `'r#fn`
--> $DIR/error-lifetime-name-issue-143150.rs:10:9
|
LL | #[derive(Eq, PartialEq)]
| -- lifetime `'r#fn` is missing in item created through this procedural macro
LL | struct Test {
LL | a: &'r#fn str,
| ^^^^^ undeclared lifetime
|
help: consider introducing lifetime `'r#fn` here
|
LL | struct Test<'r#fn> {
| +++++++

error[E0261]: use of undeclared lifetime name `'r#fn`
--> $DIR/error-lifetime-name-issue-143150.rs:16:32
|
LL | where T: for<'a> Trait1<T> + 'r#fn { }
| ^^^^^ undeclared lifetime
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the bound lifetime-generic with a new `'r#fn` lifetime
|
LL - where T: for<'a> Trait1<T> + 'r#fn { }
LL + where for<'r#fn, 'a> T: Trait1<T> + 'r#fn { }
|
help: consider introducing lifetime `'r#fn` here
|
LL | trait Trait1<'r#fn, T>
| ++++++

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0261`.
Loading