diff options
| author | bors <bors@rust-lang.org> | 2019-01-14 23:00:50 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-01-14 23:00:50 +0000 |
| commit | aea9f0aa976db2f5de28be3b6b287c6889cd926b (patch) | |
| tree | 1f45e79c5694619f8b0ea8a4652abce5a2c49a52 /src/libsyntax/parse/parser.rs | |
| parent | 03acbd71c977cd63ce5f39ba9b6fe9ffd578785a (diff) | |
| parent | 8a62e393b8fba95e989020f2efbf846ca02113f9 (diff) | |
| download | rust-aea9f0aa976db2f5de28be3b6b287c6889cd926b.tar.gz rust-aea9f0aa976db2f5de28be3b6b287c6889cd926b.zip | |
Auto merge of #57607 - Centril:rollup, r=Centril
Rollup of 8 pull requests Successful merges: - #57043 (Fix poor worst case performance of set intersection) - #57480 (Clean up and fix a bug in query plumbing) - #57481 (provide suggestion for invalid boolean cast) - #57540 (Modify some parser diagnostics to continue evaluating beyond the parser) - #57570 (Querify local `plugin_registrar_fn` and `proc_macro_decls_static`) - #57572 (Unaccept `extern_in_paths`) - #57585 (Recover from item trailing semicolon) - #57589 (Add a debug_assert to Vec::set_len) Failed merges: r? @ghost
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 215 |
1 files changed, 152 insertions, 63 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5c8ed94731a..823c786bded 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1012,7 +1012,10 @@ impl<'a> Parser<'a> { if text.is_empty() { self.span_bug(sp, "found empty literal suffix in Some") } - self.span_err(sp, &format!("{} with a suffix is invalid", kind)); + let msg = format!("{} with a suffix is invalid", kind); + self.struct_span_err(sp, &msg) + .span_label(sp, msg) + .emit(); } } } @@ -1299,7 +1302,7 @@ impl<'a> Parser<'a> { fn token_is_bare_fn_keyword(&mut self) -> bool { self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) || - self.check_keyword(keywords::Extern) && self.is_extern_non_path() + self.check_keyword(keywords::Extern) } /// parse a `TyKind::BareFn` type: @@ -1768,9 +1771,11 @@ impl<'a> Parser<'a> { Mutability::Immutable } else { let span = self.prev_span; - self.span_err(span, - "expected mut or const in raw pointer type (use \ - `*mut T` or `*const T` as appropriate)"); + let msg = "expected mut or const in raw pointer type"; + self.struct_span_err(span, msg) + .span_label(span, msg) + .help("use `*mut T` or `*const T` as appropriate") + .emit(); Mutability::Immutable }; let t = self.parse_ty_no_plus()?; @@ -3815,8 +3820,12 @@ impl<'a> Parser<'a> { ddpos = Some(fields.len()); } else { // Emit a friendly error, ignore `..` and continue parsing - self.span_err(self.prev_span, - "`..` can only be used once per tuple or tuple struct pattern"); + self.struct_span_err( + self.prev_span, + "`..` can only be used once per tuple or tuple struct pattern", + ) + .span_label(self.prev_span, "can only be used once per pattern") + .emit(); } } else if !self.check(&token::CloseDelim(token::Paren)) { fields.push(self.parse_pat(None)?); @@ -3832,7 +3841,10 @@ impl<'a> Parser<'a> { if ddpos == Some(fields.len()) && trailing_comma { // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. - self.span_err(self.prev_span, "trailing comma is not permitted after `..`"); + let msg = "trailing comma is not permitted after `..`"; + self.struct_span_err(self.prev_span, msg) + .span_label(self.prev_span, msg) + .emit(); } Ok((fields, ddpos, trailing_comma)) @@ -4605,10 +4617,6 @@ impl<'a> Parser<'a> { self.token.is_keyword(keywords::Crate) && self.look_ahead(1, |t| t != &token::ModSep) } - fn is_extern_non_path(&self) -> bool { - self.token.is_keyword(keywords::Extern) && self.look_ahead(1, |t| t != &token::ModSep) - } - fn is_existential_type_decl(&self) -> bool { self.token.is_keyword(keywords::Existential) && self.look_ahead(1, |t| t.is_keyword(keywords::Type)) @@ -4712,12 +4720,10 @@ impl<'a> Parser<'a> { // like a path (1 token), but it fact not a path. // `union::b::c` - path, `union U { ... }` - not a path. // `crate::b::c` - path, `crate struct S;` - not a path. - // `extern::b::c` - path, `extern crate c;` - not a path. } else if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_union_item() && !self.is_crate_vis() && - !self.is_extern_non_path() && !self.is_existential_type_decl() && !self.is_auto_trait_item() { let pth = self.parse_path(PathStyle::Expr)?; @@ -5256,8 +5262,12 @@ impl<'a> Parser<'a> { // Check for trailing attributes and stop parsing. if !attrs.is_empty() { let param_kind = if seen_ty_param.is_some() { "type" } else { "lifetime" }; - self.span_err(attrs[0].span, - &format!("trailing attribute after {} parameters", param_kind)); + self.struct_span_err( + attrs[0].span, + &format!("trailing attribute after {} parameters", param_kind), + ) + .span_label(attrs[0].span, "attributes must go before parameters") + .emit(); } break } @@ -5315,19 +5325,28 @@ impl<'a> Parser<'a> { /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings, /// possibly including trailing comma. - fn parse_generic_args(&mut self) - -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> { + fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> { let mut args = Vec::new(); let mut bindings = Vec::new(); let mut seen_type = false; let mut seen_binding = false; + let mut first_type_or_binding_span: Option<Span> = None; + let mut bad_lifetime_pos = vec![]; + let mut last_comma_span = None; + let mut suggestions = vec![]; loop { if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. args.push(GenericArg::Lifetime(self.expect_lifetime())); if seen_type || seen_binding { - self.span_err(self.prev_span, - "lifetime parameters must be declared prior to type parameters"); + let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span); + bad_lifetime_pos.push(self.prev_span); + if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) { + suggestions.push((remove_sp, String::new())); + suggestions.push(( + first_type_or_binding_span.unwrap().shrink_to_lo(), + format!("{}, ", snippet))); + } } } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. @@ -5335,19 +5354,33 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; self.bump(); let ty = self.parse_ty()?; + let span = lo.to(self.prev_span); bindings.push(TypeBinding { id: ast::DUMMY_NODE_ID, ident, ty, - span: lo.to(self.prev_span), + span, }); seen_binding = true; + if first_type_or_binding_span.is_none() { + first_type_or_binding_span = Some(span); + } } else if self.check_type() { // Parse type argument. let ty_param = self.parse_ty()?; if seen_binding { - self.span_err(ty_param.span, - "type parameters must be declared prior to associated type bindings"); + self.struct_span_err( + ty_param.span, + "type parameters must be declared prior to associated type bindings" + ) + .span_label( + ty_param.span, + "must be declared prior to associated type bindings", + ) + .emit(); + } + if first_type_or_binding_span.is_none() { + first_type_or_binding_span = Some(ty_param.span); } args.push(GenericArg::Type(ty_param)); seen_type = true; @@ -5357,8 +5390,30 @@ impl<'a> Parser<'a> { if !self.eat(&token::Comma) { break + } else { + last_comma_span = Some(self.prev_span); } } + if !bad_lifetime_pos.is_empty() { + let mut err = self.struct_span_err( + bad_lifetime_pos.clone(), + "lifetime parameters must be declared prior to type parameters" + ); + for sp in &bad_lifetime_pos { + err.span_label(*sp, "must be declared prior to type parameters"); + } + if !suggestions.is_empty() { + err.multipart_suggestion_with_applicability( + &format!( + "move the lifetime parameter{} prior to the first type parameter", + if bad_lifetime_pos.len() > 1 { "s" } else { "" }, + ), + suggestions, + Applicability::MachineApplicable, + ); + } + err.emit(); + } Ok((args, bindings)) } @@ -5386,8 +5441,12 @@ impl<'a> Parser<'a> { // change we parse those generics now, but report an error. if self.choose_generics_over_qpath() { let generics = self.parse_generics()?; - self.span_err(generics.span, - "generic parameters on `where` clauses are reserved for future use"); + self.struct_span_err( + generics.span, + "generic parameters on `where` clauses are reserved for future use", + ) + .span_label(generics.span, "currently unsupported") + .emit(); } loop { @@ -5587,15 +5646,20 @@ impl<'a> Parser<'a> { // *mut self // *not_self // Emit special error for `self` cases. + let msg = "cannot pass `self` by raw pointer"; (if isolated_self(self, 1) { self.bump(); - self.span_err(self.span, "cannot pass `self` by raw pointer"); + self.struct_span_err(self.span, msg) + .span_label(self.span, msg) + .emit(); SelfKind::Value(Mutability::Immutable) } else if self.look_ahead(1, |t| t.is_mutability()) && isolated_self(self, 2) { self.bump(); self.bump(); - self.span_err(self.span, "cannot pass `self` by raw pointer"); + self.struct_span_err(self.span, msg) + .span_label(self.span, msg) + .emit(); SelfKind::Value(Mutability::Immutable) } else { return Ok(None); @@ -5932,7 +5996,10 @@ impl<'a> Parser<'a> { tps.where_clause = self.parse_where_clause()?; self.expect(&token::Semi)?; if unsafety != Unsafety::Normal { - self.span_err(self.prev_span, "trait aliases cannot be unsafe"); + let msg = "trait aliases cannot be unsafe"; + self.struct_span_err(self.prev_span, msg) + .span_label(self.prev_span, msg) + .emit(); } Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) } else { @@ -6048,7 +6115,13 @@ impl<'a> Parser<'a> { Some(ty_second) => { // impl Trait for Type if !has_for { - self.span_err(missing_for_span, "missing `for` in a trait impl"); + self.struct_span_err(missing_for_span, "missing `for` in a trait impl") + .span_suggestion_short_with_applicability( + missing_for_span, + "add `for` here", + " for ".to_string(), + Applicability::MachineApplicable, + ).emit(); } let ty_first = ty_first.into_inner(); @@ -6409,41 +6482,52 @@ impl<'a> Parser<'a> { } } + fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool { + if self.eat(&token::Semi) { + let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); + err.span_suggestion_short_with_applicability( + self.prev_span, + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + if !items.is_empty() { + let previous_item = &items[items.len()-1]; + let previous_item_kind_name = match previous_item.node { + // say "braced struct" because tuple-structs and + // braceless-empty-struct declarations do take a semicolon + ItemKind::Struct(..) => Some("braced struct"), + ItemKind::Enum(..) => Some("enum"), + ItemKind::Trait(..) => Some("trait"), + ItemKind::Union(..) => Some("union"), + _ => None, + }; + if let Some(name) = previous_item_kind_name { + err.help(&format!("{} declarations are not followed by a semicolon", name)); + } + } + err.emit(); + true + } else { + false + } + } + /// Given a termination token, parse all of the items in a module fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item()? { items.push(item); + self.maybe_consume_incorrect_semicolon(&items); } if !self.eat(term) { let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected item, found {}", token_str)); - if self.token == token::Semi { - let msg = "consider removing this semicolon"; - err.span_suggestion_short_with_applicability( - self.span, msg, String::new(), Applicability::MachineApplicable - ); - if !items.is_empty() { // Issue #51603 - let previous_item = &items[items.len()-1]; - let previous_item_kind_name = match previous_item.node { - // say "braced struct" because tuple-structs and - // braceless-empty-struct declarations do take a semicolon - ItemKind::Struct(..) => Some("braced struct"), - ItemKind::Enum(..) => Some("enum"), - ItemKind::Trait(..) => Some("trait"), - ItemKind::Union(..) => Some("union"), - _ => None, - }; - if let Some(name) = previous_item_kind_name { - err.help(&format!("{} declarations are not followed by a semicolon", - name)); - } - } - } else { + if !self.maybe_consume_incorrect_semicolon(&items) { + let mut err = self.fatal(&format!("expected item, found {}", token_str)); err.span_label(self.span, "expected item"); + return Err(err); } - return Err(err); } let hi = if self.span.is_dummy() { @@ -6939,7 +7023,7 @@ impl<'a> Parser<'a> { fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> { let mut variants = Vec::new(); let mut all_nullary = true; - let mut any_disr = None; + let mut any_disr = vec![]; while self.token != token::CloseDelim(token::Brace) { let variant_attrs = self.parse_outer_attributes()?; let vlo = self.span; @@ -6961,7 +7045,9 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, value: self.parse_expr()?, }); - any_disr = disr_expr.as_ref().map(|c| c.value.span); + if let Some(sp) = disr_expr.as_ref().map(|c| c.value.span) { + any_disr.push(sp); + } struct_def = VariantData::Unit(ast::DUMMY_NODE_ID); } else { struct_def = VariantData::Unit(ast::DUMMY_NODE_ID); @@ -6978,11 +7064,15 @@ impl<'a> Parser<'a> { if !self.eat(&token::Comma) { break; } } self.expect(&token::CloseDelim(token::Brace))?; - match any_disr { - Some(disr_span) if !all_nullary => - self.span_err(disr_span, - "discriminator values can only be used with a field-less enum"), - _ => () + if !any_disr.is_empty() && !all_nullary { + let mut err =self.struct_span_err( + any_disr.clone(), + "discriminator values can only be used with a field-less enum", + ); + for sp in any_disr { + err.span_label(sp, "only valid in field-less enums"); + } + err.emit(); } Ok(ast::EnumDef { variants }) @@ -7113,8 +7203,7 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } - if self.check_keyword(keywords::Extern) && self.is_extern_non_path() { - self.bump(); // `extern` + if self.eat_keyword(keywords::Extern) { if self.eat_keyword(keywords::Crate) { return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?)); } @@ -7623,7 +7712,7 @@ impl<'a> Parser<'a> { fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>, at_end: &mut bool) -> PResult<'a, Option<Mac>> { - if self.token.is_path_start() && !self.is_extern_non_path() { + if self.token.is_path_start() { let prev_span = self.prev_span; let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; |
