mirror of
https://github.com/rust-lang/rust.git
synced 2025-10-02 18:27:37 +00:00
Rollup merge of #144897 - fee1-dead-contrib:raw_lifetimes_printing, r=fmease
print raw lifetime idents with r# This replaces rust-lang/rust#143185 and fixes rust-lang/rust#143150 cc ``@fmease``
This commit is contained in:
commit
2dbd411d22
@ -7,6 +7,7 @@ pub use NtPatKind::*;
|
||||
pub use TokenKind::*;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::IdentPrintMode;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
|
||||
#[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint.
|
||||
#[allow(hidden_glob_reexports)]
|
||||
@ -344,15 +345,24 @@ pub enum IdentIsRaw {
|
||||
Yes,
|
||||
}
|
||||
|
||||
impl From<bool> for IdentIsRaw {
|
||||
fn from(b: bool) -> Self {
|
||||
if b { Self::Yes } else { Self::No }
|
||||
impl IdentIsRaw {
|
||||
pub fn to_print_mode_ident(self) -> IdentPrintMode {
|
||||
match self {
|
||||
IdentIsRaw::No => IdentPrintMode::Normal,
|
||||
IdentIsRaw::Yes => IdentPrintMode::RawIdent,
|
||||
}
|
||||
}
|
||||
pub fn to_print_mode_lifetime(self) -> IdentPrintMode {
|
||||
match self {
|
||||
IdentIsRaw::No => IdentPrintMode::Normal,
|
||||
IdentIsRaw::Yes => IdentPrintMode::RawLifetime,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IdentIsRaw> for bool {
|
||||
fn from(is_raw: IdentIsRaw) -> bool {
|
||||
matches!(is_raw, IdentIsRaw::Yes)
|
||||
impl From<bool> for IdentIsRaw {
|
||||
fn from(b: bool) -> Self {
|
||||
if b { Self::Yes } else { Self::No }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ use std::borrow::Cow;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{Comment, CommentStyle};
|
||||
@ -441,7 +441,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
|
||||
|
||||
fn print_ident(&mut self, ident: Ident) {
|
||||
self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
|
||||
self.word(IdentPrinter::for_ast_ident(ident, ident.guess_print_mode()).to_string());
|
||||
self.ann_post(ident)
|
||||
}
|
||||
|
||||
@ -1015,17 +1015,16 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
|
||||
/* Name components */
|
||||
token::Ident(name, is_raw) => {
|
||||
IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
|
||||
IdentPrinter::new(name, is_raw.to_print_mode_ident(), convert_dollar_crate)
|
||||
.to_string()
|
||||
.into()
|
||||
}
|
||||
token::NtIdent(ident, is_raw) => {
|
||||
IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
|
||||
IdentPrinter::for_ast_ident(ident, is_raw.to_print_mode_ident()).to_string().into()
|
||||
}
|
||||
|
||||
token::Lifetime(name, IdentIsRaw::No)
|
||||
| token::NtLifetime(Ident { name, .. }, IdentIsRaw::No) => name.to_string().into(),
|
||||
token::Lifetime(name, IdentIsRaw::Yes)
|
||||
| token::NtLifetime(Ident { name, .. }, IdentIsRaw::Yes) => {
|
||||
format!("'r#{}", &name.as_str()[1..]).into()
|
||||
token::Lifetime(name, is_raw) | token::NtLifetime(Ident { name, .. }, is_raw) => {
|
||||
IdentPrinter::new(name, is_raw.to_print_mode_lifetime(), None).to_string().into()
|
||||
}
|
||||
|
||||
/* Other */
|
||||
|
@ -250,12 +250,14 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
||||
Question => op("?"),
|
||||
SingleQuote => op("'"),
|
||||
|
||||
Ident(sym, is_raw) => {
|
||||
trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
|
||||
}
|
||||
Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident {
|
||||
sym,
|
||||
is_raw: matches!(is_raw, IdentIsRaw::Yes),
|
||||
span,
|
||||
})),
|
||||
NtIdent(ident, is_raw) => trees.push(TokenTree::Ident(Ident {
|
||||
sym: ident.name,
|
||||
is_raw: is_raw.into(),
|
||||
is_raw: matches!(is_raw, IdentIsRaw::Yes),
|
||||
span: ident.span,
|
||||
})),
|
||||
|
||||
@ -263,7 +265,11 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
||||
let ident = rustc_span::Ident::new(name, span).without_first_quote();
|
||||
trees.extend([
|
||||
TokenTree::Punct(Punct { ch: b'\'', joint: true, span }),
|
||||
TokenTree::Ident(Ident { sym: ident.name, is_raw: is_raw.into(), span }),
|
||||
TokenTree::Ident(Ident {
|
||||
sym: ident.name,
|
||||
is_raw: matches!(is_raw, IdentIsRaw::Yes),
|
||||
span,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
NtLifetime(ident, is_raw) => {
|
||||
|
@ -463,9 +463,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
|
||||
parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
|
||||
parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
|
||||
|
||||
parse_invalid_label =
|
||||
invalid label name `{$name}`
|
||||
|
||||
parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
|
||||
.label = invalid suffix `{$suffix}`
|
||||
.tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
|
||||
@ -495,6 +492,8 @@ parse_invalid_unicode_escape = invalid unicode character escape
|
||||
parse_invalid_variable_declaration =
|
||||
invalid variable declaration
|
||||
|
||||
parse_keyword_label = labels cannot use keyword names
|
||||
|
||||
parse_keyword_lifetime =
|
||||
lifetimes cannot use keyword names
|
||||
|
||||
|
@ -2228,11 +2228,10 @@ pub(crate) struct KeywordLifetime {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_invalid_label)]
|
||||
pub(crate) struct InvalidLabel {
|
||||
#[diag(parse_keyword_label)]
|
||||
pub(crate) struct KeywordLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -3094,7 +3094,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::KeywordLabel { span: ident.span });
|
||||
}
|
||||
|
||||
self.bump();
|
||||
|
@ -1502,8 +1502,7 @@ impl<'a> Parser<'a> {
|
||||
pub(super) fn expect_lifetime(&mut self) -> Lifetime {
|
||||
if let Some((ident, is_raw)) = self.token.lifetime() {
|
||||
if matches!(is_raw, IdentIsRaw::No)
|
||||
&& ident.without_first_quote().is_reserved()
|
||||
&& ![kw::UnderscoreLifetime, kw::StaticLifetime].contains(&ident.name)
|
||||
&& ident.without_first_quote().is_reserved_lifetime()
|
||||
{
|
||||
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
|
||||
}
|
||||
|
@ -3094,7 +3094,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,
|
||||
@ -3112,7 +3112,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,
|
||||
@ -3159,7 +3159,7 @@ 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::from_str("'a")));
|
||||
|
||||
// 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`
|
||||
@ -3189,16 +3189,11 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let binders_sugg = binder_idents.into_iter().enumerate().fold(
|
||||
"".to_string(),
|
||||
|mut binders, (i, x)| {
|
||||
if i != 0 {
|
||||
binders += ", ";
|
||||
}
|
||||
binders += x.as_str();
|
||||
binders
|
||||
},
|
||||
);
|
||||
let binders_sugg: String = binder_idents
|
||||
.into_iter()
|
||||
.map(|ident| ident.to_string())
|
||||
.intersperse(", ".to_owned())
|
||||
.collect();
|
||||
let sugg = format!(
|
||||
"{}<{}>{}",
|
||||
if higher_ranked { "for" } else { "" },
|
||||
@ -3214,7 +3209,8 @@ 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.map(|i| i.to_string()).as_deref().unwrap_or("'a"));
|
||||
(span, sugg)
|
||||
};
|
||||
|
||||
@ -3222,7 +3218,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||
let message = Cow::from(format!(
|
||||
"consider making the {} lifetime-generic with a new `{}` lifetime",
|
||||
kind.descr(),
|
||||
name.unwrap_or("'a"),
|
||||
name.map(|i| i.to_string()).as_deref().unwrap_or("'a"),
|
||||
));
|
||||
should_continue = suggest(
|
||||
err,
|
||||
|
@ -2533,10 +2533,16 @@ impl fmt::Debug for Ident {
|
||||
/// except that AST identifiers don't keep the rawness flag, so we have to guess it.
|
||||
impl fmt::Display for Ident {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&IdentPrinter::new(self.name, self.is_raw_guess(), None), f)
|
||||
fmt::Display::fmt(&IdentPrinter::new(self.name, self.guess_print_mode(), None), f)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum IdentPrintMode {
|
||||
Normal,
|
||||
RawIdent,
|
||||
RawLifetime,
|
||||
}
|
||||
|
||||
/// The most general type to print identifiers.
|
||||
///
|
||||
/// AST pretty-printer is used as a fallback for turning AST structures into token streams for
|
||||
@ -2552,7 +2558,7 @@ impl fmt::Display for Ident {
|
||||
/// done for a token stream or a single token.
|
||||
pub struct IdentPrinter {
|
||||
symbol: Symbol,
|
||||
is_raw: bool,
|
||||
mode: IdentPrintMode,
|
||||
/// Span used for retrieving the crate name to which `$crate` refers to,
|
||||
/// if this field is `None` then the `$crate` conversion doesn't happen.
|
||||
convert_dollar_crate: Option<Span>,
|
||||
@ -2560,32 +2566,51 @@ pub struct IdentPrinter {
|
||||
|
||||
impl IdentPrinter {
|
||||
/// The most general `IdentPrinter` constructor. Do not use this.
|
||||
pub fn new(symbol: Symbol, is_raw: bool, convert_dollar_crate: Option<Span>) -> IdentPrinter {
|
||||
IdentPrinter { symbol, is_raw, convert_dollar_crate }
|
||||
pub fn new(
|
||||
symbol: Symbol,
|
||||
mode: IdentPrintMode,
|
||||
convert_dollar_crate: Option<Span>,
|
||||
) -> IdentPrinter {
|
||||
IdentPrinter { symbol, mode, convert_dollar_crate }
|
||||
}
|
||||
|
||||
/// This implementation is supposed to be used when printing identifiers
|
||||
/// as a part of pretty-printing for larger AST pieces.
|
||||
/// Do not use this either.
|
||||
pub fn for_ast_ident(ident: Ident, is_raw: bool) -> IdentPrinter {
|
||||
IdentPrinter::new(ident.name, is_raw, Some(ident.span))
|
||||
pub fn for_ast_ident(ident: Ident, mode: IdentPrintMode) -> IdentPrinter {
|
||||
IdentPrinter::new(ident.name, mode, Some(ident.span))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IdentPrinter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.is_raw {
|
||||
f.write_str("r#")?;
|
||||
} else if self.symbol == kw::DollarCrate {
|
||||
if let Some(span) = self.convert_dollar_crate {
|
||||
let s = match self.mode {
|
||||
IdentPrintMode::Normal
|
||||
if self.symbol == kw::DollarCrate
|
||||
&& let Some(span) = self.convert_dollar_crate =>
|
||||
{
|
||||
let converted = span.ctxt().dollar_crate_name();
|
||||
if !converted.is_path_segment_keyword() {
|
||||
f.write_str("::")?;
|
||||
}
|
||||
return fmt::Display::fmt(&converted, f);
|
||||
converted
|
||||
}
|
||||
}
|
||||
fmt::Display::fmt(&self.symbol, f)
|
||||
IdentPrintMode::Normal => self.symbol,
|
||||
IdentPrintMode::RawIdent => {
|
||||
f.write_str("r#")?;
|
||||
self.symbol
|
||||
}
|
||||
IdentPrintMode::RawLifetime => {
|
||||
f.write_str("'r#")?;
|
||||
let s = self
|
||||
.symbol
|
||||
.as_str()
|
||||
.strip_prefix("'")
|
||||
.expect("only lifetime idents should be passed with RawLifetime mode");
|
||||
Symbol::intern(s)
|
||||
}
|
||||
};
|
||||
s.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3020,6 +3045,29 @@ impl Ident {
|
||||
self.name.can_be_raw() && self.is_reserved()
|
||||
}
|
||||
|
||||
/// Given the name of a lifetime without the first quote (`'`),
|
||||
/// returns whether the lifetime name is reserved (therefore invalid)
|
||||
pub fn is_reserved_lifetime(self) -> bool {
|
||||
self.is_reserved() && ![kw::Underscore, kw::Static].contains(&self.name)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
pub fn guess_print_mode(self) -> IdentPrintMode {
|
||||
if self.is_raw_lifetime_guess() {
|
||||
IdentPrintMode::RawLifetime
|
||||
} else if self.is_raw_guess() {
|
||||
IdentPrintMode::RawIdent
|
||||
} else {
|
||||
IdentPrintMode::Normal
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this would be the identifier for a tuple field like `self.0`, as
|
||||
/// opposed to a named field like `self.thing`.
|
||||
pub fn is_numeric(self) -> bool {
|
||||
|
@ -1,5 +1,5 @@
|
||||
fn main() {
|
||||
[(); &(&'static: loop { |x| {}; }) as *const _ as usize]
|
||||
//~^ ERROR: invalid label name `'static`
|
||||
//~^ ERROR: labels cannot use keyword names
|
||||
//~| ERROR: type annotations needed
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: invalid label name `'static`
|
||||
error: labels cannot use keyword names
|
||||
--> $DIR/issue-52437.rs:2:13
|
||||
|
|
||||
LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
|
||||
|
@ -1,4 +1,4 @@
|
||||
fn main() {
|
||||
'break: loop { //~ ERROR invalid label name `'break`
|
||||
'break: loop { //~ ERROR labels cannot use keyword names
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: invalid label name `'break`
|
||||
error: labels cannot use keyword names
|
||||
--> $DIR/issue-46311.rs:2:5
|
||||
|
|
||||
LL | 'break: loop {
|
||||
|
@ -1,5 +1,5 @@
|
||||
fn main() {
|
||||
'static: loop { //~ ERROR invalid label name `'static`
|
||||
break 'static //~ ERROR invalid label name `'static`
|
||||
'static: loop { //~ ERROR labels cannot use keyword names
|
||||
break 'static //~ ERROR labels cannot use keyword names
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
error: invalid label name `'static`
|
||||
error: labels cannot use keyword names
|
||||
--> $DIR/label-static.rs:2:5
|
||||
|
|
||||
LL | 'static: loop {
|
||||
| ^^^^^^^
|
||||
|
||||
error: invalid label name `'static`
|
||||
error: labels cannot use keyword names
|
||||
--> $DIR/label-static.rs:3:15
|
||||
|
|
||||
LL | break 'static
|
||||
|
@ -1,5 +1,5 @@
|
||||
fn main() {
|
||||
'_: loop { //~ ERROR invalid label name `'_`
|
||||
break '_ //~ ERROR invalid label name `'_`
|
||||
'_: loop { //~ ERROR labels cannot use keyword names
|
||||
break '_ //~ ERROR labels cannot use keyword names
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
error: invalid label name `'_`
|
||||
error: labels cannot use keyword names
|
||||
--> $DIR/label-underscore.rs:2:5
|
||||
|
|
||||
LL | '_: loop {
|
||||
| ^^
|
||||
|
||||
error: invalid label name `'_`
|
||||
error: labels cannot use keyword names
|
||||
--> $DIR/label-underscore.rs:3:15
|
||||
|
|
||||
LL | break '_
|
||||
|
21
tests/ui/lifetimes/raw/use-of-undeclared-raw-lifetimes.rs
Normal file
21
tests/ui/lifetimes/raw/use-of-undeclared-raw-lifetimes.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Check that we properly suggest `r#fn` if we use it undeclared.
|
||||
// https://github.com/rust-lang/rust/issues/143150
|
||||
//
|
||||
//@ edition: 2021
|
||||
|
||||
fn a(_: dyn Trait + 'r#fn) {
|
||||
//~^ ERROR use of undeclared lifetime name `'r#fn` [E0261]
|
||||
}
|
||||
|
||||
trait Trait {}
|
||||
|
||||
struct Test {
|
||||
a: &'r#fn str,
|
||||
//~^ 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() {}
|
@ -0,0 +1,42 @@
|
||||
error[E0261]: use of undeclared lifetime name `'r#fn`
|
||||
--> $DIR/use-of-undeclared-raw-lifetimes.rs:6: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/use-of-undeclared-raw-lifetimes.rs:13: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/use-of-undeclared-raw-lifetimes.rs:18: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 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0261`.
|
@ -24,14 +24,14 @@ fn main() {
|
||||
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
|
||||
//~| ERROR expected
|
||||
//~| HELP add `'` to close the char literal
|
||||
//~| ERROR invalid label name
|
||||
//~| ERROR labels cannot use keyword names
|
||||
|
||||
f<'_>();
|
||||
//~^ ERROR comparison operators cannot be chained
|
||||
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
|
||||
//~| ERROR expected
|
||||
//~| HELP add `'` to close the char literal
|
||||
//~| ERROR invalid label name
|
||||
//~| ERROR labels cannot use keyword names
|
||||
|
||||
let _ = f<u8>;
|
||||
//~^ ERROR comparison operators cannot be chained
|
||||
|
@ -53,7 +53,7 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
|
||||
LL | let _ = f::<u8, i8>();
|
||||
| ++
|
||||
|
||||
error: invalid label name `'_`
|
||||
error: labels cannot use keyword names
|
||||
--> $DIR/require-parens-for-chained-comparison.rs:22:15
|
||||
|
|
||||
LL | let _ = f<'_, i8>();
|
||||
@ -81,7 +81,7 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
|
||||
LL | let _ = f::<'_, i8>();
|
||||
| ++
|
||||
|
||||
error: invalid label name `'_`
|
||||
error: labels cannot use keyword names
|
||||
--> $DIR/require-parens-for-chained-comparison.rs:29:7
|
||||
|
|
||||
LL | f<'_>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user