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
4 changes: 2 additions & 2 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,12 +625,12 @@ impl TokenKind {
}

impl Token {
pub fn new(kind: TokenKind, span: Span) -> Self {
pub const fn new(kind: TokenKind, span: Span) -> Self {
Token { kind, span }
}

/// Some token that will be thrown away later.
pub fn dummy() -> Self {
pub const fn dummy() -> Self {
Token::new(TokenKind::Question, DUMMY_SP)
}

Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_parse/src/parser/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,11 @@ impl<'a> Parser<'a> {
pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> {
let mut params = ThinVec::new();
let mut done = false;
let prev = self.parsing_generics;
self.parsing_generics = true;
while !done {
let attrs = self.parse_outer_attributes()?;
let param = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let param = match self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
if this.eat_keyword_noexpect(kw::SelfUpper) {
// `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
// as if `Self` never existed.
Expand Down Expand Up @@ -288,14 +290,21 @@ impl<'a> Parser<'a> {
}
// We just ate the comma, so no need to capture the trailing token.
Ok((param, Trailing::No, UsePreAttrPos::No))
})?;
}) {
Ok(param) => param,
Err(err) => {
self.parsing_generics = prev;
return Err(err);
}
};

if let Some(param) = param {
params.push(param);
} else {
break;
}
}
self.parsing_generics = prev;
Ok(params)
}

Expand Down
42 changes: 16 additions & 26 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,17 @@ pub enum Recovery {
pub struct Parser<'a> {
pub psess: &'a ParseSess,
/// The current token.
pub token: Token,
pub token: Token = Token::dummy(),
/// The spacing for the current token.
token_spacing: Spacing,
token_spacing: Spacing = Spacing::Alone,
/// The previous token.
pub prev_token: Token,
pub capture_cfg: bool,
restrictions: Restrictions,
expected_token_types: TokenTypeSet,
pub prev_token: Token = Token::dummy(),
pub capture_cfg: bool = false,
restrictions: Restrictions = Restrictions::empty(),
expected_token_types: TokenTypeSet = TokenTypeSet::new(),
token_cursor: TokenCursor,
// The number of calls to `bump`, i.e. the position in the token stream.
num_bump_calls: u32,
num_bump_calls: u32 = 0,
// During parsing we may sometimes need to "unglue" a glued token into two
// or three component tokens (e.g. `>>` into `>` and `>`, or `>>=` into `>`
// and `>` and `=`), so the parser can consume them one at a time. This
Expand All @@ -204,25 +204,27 @@ pub struct Parser<'a> {
//
// This value is always 0, 1, or 2. It can only reach 2 when splitting
// `>>=` or `<<=`.
break_last_token: u32,
break_last_token: u32 = 0,
/// This field is used to keep track of how many left angle brackets we have seen. This is
/// required in order to detect extra leading left angle brackets (`<` characters) and error
/// appropriately.
///
/// See the comments in the `parse_path_segment` function for more details.
unmatched_angle_bracket_count: u16,
angle_bracket_nesting: u16,
unmatched_angle_bracket_count: u16 = 0,
angle_bracket_nesting: u16 = 0,
/// Keep track of when we're within `<...>` for proper error recovery.
parsing_generics: bool = false,

last_unexpected_token_span: Option<Span>,
last_unexpected_token_span: Option<Span> = None,
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
subparser_name: Option<&'static str>,
capture_state: CaptureState,
/// This allows us to recover when the user forget to add braces around
/// multiple statements in the closure body.
current_closure: Option<ClosureSpans>,
current_closure: Option<ClosureSpans> = None,
/// Whether the parser is allowed to do recovery.
/// This is disabled when parsing macro arguments, see #103534
recovery: Recovery,
recovery: Recovery = Recovery::Allowed,
}

// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with
Expand Down Expand Up @@ -351,27 +353,15 @@ impl<'a> Parser<'a> {
) -> Self {
let mut parser = Parser {
psess,
token: Token::dummy(),
token_spacing: Spacing::Alone,
prev_token: Token::dummy(),
capture_cfg: false,
restrictions: Restrictions::empty(),
expected_token_types: TokenTypeSet::new(),
token_cursor: TokenCursor { curr: TokenTreeCursor::new(stream), stack: Vec::new() },
num_bump_calls: 0,
break_last_token: 0,
unmatched_angle_bracket_count: 0,
angle_bracket_nesting: 0,
last_unexpected_token_span: None,
subparser_name,
capture_state: CaptureState {
capturing: Capturing::No,
parser_replacements: Vec::new(),
inner_attr_parser_ranges: Default::default(),
seen_attrs: IntervalSet::new(u32::MAX as usize),
},
current_closure: None,
recovery: Recovery::Allowed,
..
};

// Make parser point to the first token.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/token_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ macro_rules! exp {
pub(super) struct TokenTypeSet(u128);

impl TokenTypeSet {
pub(super) fn new() -> TokenTypeSet {
pub(super) const fn new() -> TokenTypeSet {
TokenTypeSet(0)
}

Expand Down
47 changes: 44 additions & 3 deletions compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1488,21 +1488,62 @@ impl<'a> Parser<'a> {
return Ok(());
}

let snapshot = if self.parsing_generics {
// The snapshot is only relevant if we're parsing the generics of an `fn` to avoid
// incorrect recovery.
Some(self.create_snapshot_for_diagnostic())
} else {
None
};
// Parse `(T, U) -> R`.
let inputs_lo = self.token.span;
let mode =
FnParseMode { req_name: |_, _| false, context: FnContext::Free, req_body: false };
let inputs: ThinVec<_> =
self.parse_fn_params(&mode)?.into_iter().map(|input| input.ty).collect();
let params = match self.parse_fn_params(&mode) {
Ok(params) => params,
Err(err) => {
if let Some(snapshot) = snapshot {
self.restore_snapshot(snapshot);
err.cancel();
return Ok(());
} else {
return Err(err);
}
}
};
Comment on lines +1502 to +1513
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These changes weren't strictly necessary for the test case, but we should always be restoring snapshots if we encounter parse errors in recovery logic.

let inputs: ThinVec<_> = params.into_iter().map(|input| input.ty).collect();
let inputs_span = inputs_lo.to(self.prev_token.span);
let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
let output = match self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)
{
Ok(output) => output,
Err(err) => {
if let Some(snapshot) = snapshot {
self.restore_snapshot(snapshot);
err.cancel();
return Ok(());
} else {
return Err(err);
}
}
};
let args = ast::ParenthesizedArgs {
span: fn_path_segment.span().to(self.prev_token.span),
inputs,
inputs_span,
output,
}
.into();

if let Some(snapshot) = snapshot
&& ![token::Comma, token::Gt, token::Plus].contains(&self.token.kind)
{
// We would expect another bound or the end of type params by now. Most likely we've
// encountered a `(` *not* representing `Trait()`, but rather the start of the `fn`'s
// argument list where the generic param list wasn't properly closed.
self.restore_snapshot(snapshot);
return Ok(());
}

*fn_path_segment = ast::PathSegment {
ident: fn_path_segment.ident,
args: Some(args),
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/parser/missing-closing-generics-bracket.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Issue #141436
//@ run-rustfix
#![allow(dead_code)]

trait Trait<'a> {}

fn foo<T: Trait<'static>>() {}
//~^ ERROR expected one of

fn main() {}
10 changes: 10 additions & 0 deletions tests/ui/parser/missing-closing-generics-bracket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Issue #141436
//@ run-rustfix
#![allow(dead_code)]

trait Trait<'a> {}

fn foo<T: Trait<'static>() {}
//~^ ERROR expected one of

fn main() {}
13 changes: 13 additions & 0 deletions tests/ui/parser/missing-closing-generics-bracket.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: expected one of `+`, `,`, `::`, `=`, or `>`, found `(`
--> $DIR/missing-closing-generics-bracket.rs:7:25
|
LL | fn foo<T: Trait<'static>() {}
| ^ expected one of `+`, `,`, `::`, `=`, or `>`
|
help: you might have meant to end the type parameters here
|
LL | fn foo<T: Trait<'static>>() {}
| +

error: aborting due to 1 previous error

Loading