Skip to content

Commit

Permalink
Rollup merge of rust-lang#57540 - estebank:eval-more, r=petrochenkov
Browse files Browse the repository at this point in the history
Modify some parser diagnostics to continue evaluating beyond the parser

Continue evaluating further errors after parser errors on:
 - trailing type argument attribute
 - lifetime in incorrect location
 - incorrect binary literal
 - missing `for` in `impl Trait for Foo`
 - type argument in `where` clause
 - incorrect float literal
 - incorrect `..` in pattern
 - associated types
 - incorrect discriminator value variant error

and others. All of these were found by making `continue-parse-after-error` `true` by default to identify errors that would need few changes. There are now only a handful of errors that have any change with `continue-parse-after-error` enabled.

These changes make it so `rust` _won't_ stop evaluation after finishing parsing, enabling type checking errors to be displayed on the existing code without having to fix the parse errors.

Each commit has an individual diagnostic change with their corresponding tests.

CC rust-lang#48724.
  • Loading branch information
Centril committed Jan 14, 2019
2 parents 816e31b + 28ea03e commit 2f7a226
Show file tree
Hide file tree
Showing 41 changed files with 344 additions and 141 deletions.
2 changes: 1 addition & 1 deletion src/libsyntax/parse/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ impl<'a> StringReader<'a> {

/// Report a lexical error with a given span.
fn err_span(&self, sp: Span, m: &str) {
self.sess.span_diagnostic.span_err(sp, m)
self.sess.span_diagnostic.struct_span_err(sp, m).emit();
}


Expand Down
8 changes: 7 additions & 1 deletion src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, diag: Option<(Span,
} else {
let msg = format!("invalid suffix `{}` for float literal", suf);
diag.struct_span_err(span, &msg)
.span_label(span, format!("invalid suffix `{}`", suf))
.help("valid suffixes are `f32` and `f64`")
.emit();
}
Expand Down Expand Up @@ -673,7 +674,11 @@ fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
_ => None,
};
if let Some(err) = err {
err!(diag, |span, diag| diag.span_err(span, err));
err!(diag, |span, diag| {
diag.struct_span_err(span, err)
.span_label(span, "not supported")
.emit();
});
}
return filtered_float_lit(Symbol::intern(s), Some(suf), diag)
}
Expand Down Expand Up @@ -712,6 +717,7 @@ fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
} else {
let msg = format!("invalid suffix `{}` for numeric literal", suf);
diag.struct_span_err(span, &msg)
.span_label(span, format!("invalid suffix `{}`", suf))
.help("the suffix must be one of the integral types \
(`u32`, `isize`, etc)")
.emit();
Expand Down
143 changes: 114 additions & 29 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}
Expand Down Expand Up @@ -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()?;
Expand Down Expand Up @@ -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)?);
Expand All @@ -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))
Expand Down Expand Up @@ -5256,8 +5268,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
}
Expand Down Expand Up @@ -5315,39 +5331,62 @@ 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.
let lo = self.span;
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;
Expand All @@ -5357,7 +5396,29 @@ 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))
}
Expand Down Expand Up @@ -5386,8 +5447,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 {
Expand Down Expand Up @@ -5587,15 +5652,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);
Expand Down Expand Up @@ -5932,7 +6002,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 {
Expand Down Expand Up @@ -6048,7 +6121,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();
Expand Down Expand Up @@ -6939,7 +7018,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;
Expand All @@ -6961,7 +7040,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);
Expand All @@ -6978,11 +7059,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 })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: trailing attribute after lifetime parameters
--> $DIR/attrs-with-no-formal-in-generics-1.rs:9:25
|
LL | impl<#[rustc_1] 'a, 'b, #[oops]> RefIntPair<'a, 'b> {
| ^^^^^^^
| ^^^^^^^ attributes must go before parameters

error: aborting due to previous error

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: trailing attribute after type parameters
--> $DIR/attrs-with-no-formal-in-generics-2.rs:9:35
|
LL | impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {}
| ^^^^^^^
| ^^^^^^^ attributes must go before parameters

error: aborting due to previous error

Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@
struct RefIntPair<'a, 'b>(&'a u32, &'b u32);

fn hof_lt<Q>(_: Q)
where Q: for <#[rustc_1] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32
where Q: for <#[allow(unused)] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32
//~^ ERROR trailing attribute after lifetime parameters
{
{}

}

fn main() {

}
fn main() {}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: trailing attribute after lifetime parameters
--> $DIR/attrs-with-no-formal-in-generics-3.rs:8:38
--> $DIR/attrs-with-no-formal-in-generics-3.rs:8:44
|
LL | where Q: for <#[rustc_1] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32
| ^^^^^^^
LL | where Q: for <#[allow(unused)] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32
| ^^^^^^^ attributes must go before parameters

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/old-suffixes-are-really-forbidden.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ error: invalid suffix `is` for numeric literal
--> $DIR/old-suffixes-are-really-forbidden.rs:2:13
|
LL | let a = 1_is; //~ ERROR invalid suffix
| ^^^^
| ^^^^ invalid suffix `is`
|
= help: the suffix must be one of the integral types (`u32`, `isize`, etc)

error: invalid suffix `us` for numeric literal
--> $DIR/old-suffixes-are-really-forbidden.rs:3:13
|
LL | let b = 2_us; //~ ERROR invalid suffix
| ^^^^
| ^^^^ invalid suffix `us`
|
= help: the suffix must be one of the integral types (`u32`, `isize`, etc)

Expand Down
Loading

0 comments on commit 2f7a226

Please sign in to comment.