about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-11-29 12:23:05 +0000
committerbors <bors@rust-lang.org>2018-11-29 12:23:05 +0000
commit0c1dc62c1ec3c23dcb5e90500a2b3b25817ad03a (patch)
tree9eff411fcec26978368a52f56a1146e918b2694a /src/libsyntax/parse
parent147e60c5f89cfa2d3ffc247413956a37582c98e7 (diff)
parent3b64f86beb82b78496a5d5fe3c43944ef7ebd95d (diff)
downloadrust-0c1dc62c1ec3c23dcb5e90500a2b3b25817ad03a.tar.gz
rust-0c1dc62c1ec3c23dcb5e90500a2b3b25817ad03a.zip
Auto merge of #56340 - GuillaumeGomez:rollup, r=GuillaumeGomez
Rollup of 22 pull requests

Successful merges:

 - #55391 (bootstrap: clean up a few clippy findings)
 - #56021 (avoid features_untracked)
 - #56023 (atomic::Ordering: Get rid of misleading parts of intro)
 - #56080 (Reduce the amount of bold text at doc.rlo)
 - #56114 (Enclose type in backticks for "non-exhaustive patterns" error)
 - #56124 (Fix small doc mistake on std::io::read::read_to_end)
 - #56127 (Update an outdated comment in mir building)
 - #56148 (Add rustc-guide as a submodule)
 - #56149 (Make std::os::unix/linux::fs::MetadataExt::a/m/ctime* documentation clearer)
 - #56220 (Suggest appropriate place for lifetime when declared after type arguments)
 - #56223 (Make JSON output from -Zprofile-json valid)
 - #56236 (Remove unsafe `unsafe` inner function.)
 - #56255 (Update outdated code comments in StringReader)
 - #56257 (rustc-guide has moved to rust-lang/)
 - #56273 (Add missing doc link)
 - #56289 (Fix small typo in comment of thread::stack_size)
 - #56294 (Fix a typo in the documentation of std::ffi)
 - #56312 (Deduplicate literal -> constant lowering)
 - #56319 (fix futures creating aliasing mutable and shared ref)
 - #56321 (rustdoc: add bottom margin spacing to nested lists)
 - #56322 (resolve: Fix false-positives from lint `absolute_paths_not_starting_with_crate`)
 - #56330 (Clean up span in non-trailing `..` suggestion)

Failed merges:

r? @ghost
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/lexer/mod.rs5
-rw-r--r--src/libsyntax/parse/parser.rs57
2 files changed, 49 insertions, 13 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 0584cd5a3df..c90c62c13f9 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -60,11 +60,11 @@ pub struct StringReader<'a> {
     // cache a direct reference to the source text, so that we don't have to
     // retrieve it via `self.source_file.src.as_ref().unwrap()` all the time.
     src: Lrc<String>,
-    /// Stack of open delimiters and their spans. Used for error message.
     token: token::Token,
     span: Span,
     /// The raw source span which *does not* take `override_span` into account
     span_src_raw: Span,
+    /// Stack of open delimiters and their spans. Used for error message.
     open_braces: Vec<(token::DelimToken, Span)>,
     /// The type and spans for all braces
     ///
@@ -506,8 +506,7 @@ impl<'a> StringReader<'a> {
         }
     }
 
-    /// Advance the StringReader by one character. If a newline is
-    /// discovered, add it to the SourceFile's list of line start offsets.
+    /// Advance the StringReader by one character.
     crate fn bump(&mut self) {
         let next_src_index = self.src_index(self.next_pos);
         if next_src_index < self.end_src_index {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c82ebd6aa51..506199b60ad 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3952,7 +3952,7 @@ impl<'a> Parser<'a> {
                     );
                     err.emit();
                 }
-                self.bump();  // `..` || `...`:w
+                self.bump();  // `..` || `...`
 
                 if self.token == token::CloseDelim(token::Brace) {
                     etc_span = Some(etc_sp);
@@ -3972,7 +3972,7 @@ impl<'a> Parser<'a> {
                     ate_comma = true;
                 }
 
-                etc_span = Some(etc_sp);
+                etc_span = Some(etc_sp.until(self.span));
                 if self.token == token::CloseDelim(token::Brace) {
                     // If the struct looks otherwise well formed, recover and continue.
                     if let Some(sp) = comma_sp {
@@ -5172,8 +5172,12 @@ impl<'a> Parser<'a> {
     /// Parses (possibly empty) list of lifetime and type parameters, possibly including
     /// trailing comma and erroneous trailing attributes.
     crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
+        let mut lifetimes = Vec::new();
         let mut params = Vec::new();
-        let mut seen_ty_param = false;
+        let mut seen_ty_param: Option<Span> = None;
+        let mut last_comma_span = None;
+        let mut bad_lifetime_pos = vec![];
+        let mut suggestions = vec![];
         loop {
             let attrs = self.parse_outer_attributes()?;
             if self.check_lifetime() {
@@ -5184,25 +5188,42 @@ impl<'a> Parser<'a> {
                 } else {
                     Vec::new()
                 };
-                params.push(ast::GenericParam {
+                lifetimes.push(ast::GenericParam {
                     ident: lifetime.ident,
                     id: lifetime.id,
                     attrs: attrs.into(),
                     bounds,
                     kind: ast::GenericParamKind::Lifetime,
                 });
-                if seen_ty_param {
-                    self.span_err(self.prev_span,
-                        "lifetime parameters must be declared prior to type parameters");
+                if let Some(sp) = seen_ty_param {
+                    let param_span = self.prev_span;
+                    let ate_comma = self.eat(&token::Comma);
+                    let remove_sp = if ate_comma {
+                        param_span.until(self.span)
+                    } else {
+                        last_comma_span.unwrap_or(param_span).to(param_span)
+                    };
+                    bad_lifetime_pos.push(param_span);
+
+                    if let Ok(snippet) = self.sess.source_map().span_to_snippet(param_span) {
+                        suggestions.push((remove_sp, String::new()));
+                        suggestions.push((sp.shrink_to_lo(), format!("{}, ", snippet)));
+                    }
+                    if ate_comma {
+                        last_comma_span = Some(self.prev_span);
+                        continue
+                    }
                 }
             } else if self.check_ident() {
                 // Parse type parameter.
                 params.push(self.parse_ty_param(attrs)?);
-                seen_ty_param = true;
+                if seen_ty_param.is_none() {
+                    seen_ty_param = Some(self.prev_span);
+                }
             } else {
                 // Check for trailing attributes and stop parsing.
                 if !attrs.is_empty() {
-                    let param_kind = if seen_ty_param { "type" } else { "lifetime" };
+                    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));
                 }
@@ -5212,8 +5233,24 @@ impl<'a> Parser<'a> {
             if !self.eat(&token::Comma) {
                 break
             }
+            last_comma_span = Some(self.prev_span);
+        }
+        if !bad_lifetime_pos.is_empty() {
+            let mut err = self.struct_span_err(
+                bad_lifetime_pos,
+                "lifetime parameters must be declared prior to type parameters",
+            );
+            if !suggestions.is_empty() {
+                err.multipart_suggestion_with_applicability(
+                    "move the lifetime parameter prior to the first type parameter",
+                    suggestions,
+                    Applicability::MachineApplicable,
+                );
+            }
+            err.emit();
         }
-        Ok(params)
+        lifetimes.extend(params);  // ensure the correct order of lifetimes and type params
+        Ok(lifetimes)
     }
 
     /// Parse a set of optional generic type parameter declarations. Where