summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/parser/path.rs')
-rw-r--r--compiler/rustc_parse/src/parser/path.rs58
1 files changed, 39 insertions, 19 deletions
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 5333d3b85..b50d2984a 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -332,7 +332,7 @@ impl<'a> Parser<'a> {
style: PathStyle,
lo: Span,
ty_generics: Option<&Generics>,
- ) -> PResult<'a, Vec<AngleBracketedArg>> {
+ ) -> PResult<'a, ThinVec<AngleBracketedArg>> {
// We need to detect whether there are extra leading left angle brackets and produce an
// appropriate error and suggestion. This cannot be implemented by looking ahead at
// upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
@@ -404,7 +404,7 @@ impl<'a> Parser<'a> {
let is_first_invocation = style == PathStyle::Expr;
// Take a snapshot before attempting to parse - we can restore this later.
- let snapshot = if is_first_invocation { Some(self.clone()) } else { None };
+ let snapshot = is_first_invocation.then(|| self.clone());
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
match self.parse_angle_args(ty_generics) {
@@ -472,8 +472,8 @@ impl<'a> Parser<'a> {
pub(super) fn parse_angle_args(
&mut self,
ty_generics: Option<&Generics>,
- ) -> PResult<'a, Vec<AngleBracketedArg>> {
- let mut args = Vec::new();
+ ) -> PResult<'a, ThinVec<AngleBracketedArg>> {
+ let mut args = ThinVec::new();
while let Some(arg) = self.parse_angle_arg(ty_generics)? {
args.push(arg);
if !self.eat(&token::Comma) {
@@ -653,7 +653,7 @@ impl<'a> Parser<'a> {
pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
// Parse const argument.
let value = if let token::OpenDelim(Delimiter::Brace) = self.token.kind {
- self.parse_block_expr(None, self.token.span, BlockCheckMode::Default)?
+ self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?
} else {
self.handle_unambiguous_unbraced_const_arg()?
};
@@ -675,22 +675,42 @@ impl<'a> Parser<'a> {
GenericArg::Const(self.parse_const_arg()?)
} else if self.check_type() {
// Parse type argument.
- let is_const_fn =
- self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis));
- let mut snapshot = self.create_snapshot_for_diagnostic();
+
+ // Proactively create a parser snapshot enabling us to rewind and try to reparse the
+ // input as a const expression in case we fail to parse a type. If we successfully
+ // do so, we will report an error that it needs to be wrapped in braces.
+ let mut snapshot = None;
+ if self.may_recover() && self.token.can_begin_expr() {
+ snapshot = Some(self.create_snapshot_for_diagnostic());
+ }
+
match self.parse_ty() {
- Ok(ty) => GenericArg::Type(ty),
+ Ok(ty) => {
+ // Since the type parser recovers from some malformed slice and array types and
+ // successfully returns a type, we need to look for `TyKind::Err`s in the
+ // type to determine if error recovery has occurred and if the input is not a
+ // syntactically valid type after all.
+ if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind
+ && let ast::TyKind::Err = inner_ty.kind
+ && let Some(snapshot) = snapshot
+ && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
+ {
+ return Ok(Some(self.dummy_const_arg_needs_braces(
+ self.struct_span_err(expr.span, "invalid const generic expression"),
+ expr.span,
+ )));
+ }
+
+ GenericArg::Type(ty)
+ }
Err(err) => {
- if is_const_fn {
- match (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) {
- Ok(expr) => {
- self.restore_snapshot(snapshot);
- return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
- }
- Err(err) => {
- err.cancel();
- }
- }
+ if let Some(snapshot) = snapshot
+ && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
+ {
+ return Ok(Some(self.dummy_const_arg_needs_braces(
+ err,
+ expr.span,
+ )));
}
// Try to recover from possible `const` arg without braces.
return self.recover_const_arg(start, err).map(Some);