about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2018-10-28 11:38:50 -0700
committerEsteban Küber <esteban@kuber.com.ar>2018-10-28 11:38:50 -0700
commitea57134607b31733d507bc9289033064fa8b6cb5 (patch)
treea83c4b3a97b3e9a1d995036f0b50a6f58b567fa9
parent3e6f30ec3e6bda159063fcd126dcb14725fef92d (diff)
downloadrust-ea57134607b31733d507bc9289033064fa8b6cb5.tar.gz
rust-ea57134607b31733d507bc9289033064fa8b6cb5.zip
Produce targeted diagnostic when using doc comments on fn args
Before parsing argument names and types, try to consume an incorrectly
included doc comment or attribute in order to recover and continue
parsing the rest of the fn definition.
-rw-r--r--src/libsyntax/parse/parser.rs37
-rw-r--r--src/test/ui/parser/fn-arg-doc-comment.rs37
-rw-r--r--src/test/ui/parser/fn-arg-doc-comment.stderr63
-rw-r--r--src/test/ui/parser/issue-33413.stderr5
-rw-r--r--src/test/ui/parser/lifetime-in-pattern.stderr5
-rw-r--r--src/test/ui/parser/removed-syntax-mode.stderr5
-rw-r--r--src/test/ui/self/self-vs-path-ambiguity.stderr5
7 files changed, 152 insertions, 5 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 589b3e30fcf..3056d1c545c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1789,6 +1789,35 @@ impl<'a> Parser<'a> {
         self.look_ahead(offset + 1, |t| t == &token::Colon)
     }
 
+    /// Skip unexpected attributes and doc comments in this position and emit an appropriate error.
+    fn eat_incorrect_doc_comment(&mut self, applied_to: &str) {
+        if let token::DocComment(_) = self.token {
+            let mut err = self.diagnostic().struct_span_err(
+                self.span,
+                &format!("documentation comments cannot be applied to {}", applied_to),
+            );
+            err.span_label(self.span, "doc comments are not allowed here");
+            err.emit();
+            self.bump();
+        } else if self.token == token::Pound && self.look_ahead(1, |t| {
+            *t == token::OpenDelim(token::Bracket)
+        }) {
+            let lo = self.span;
+            // Skip every token until next possible arg.
+            while self.token != token::CloseDelim(token::Bracket) {
+                self.bump();
+            }
+            let sp = lo.to(self.span);
+            self.bump();
+            let mut err = self.diagnostic().struct_span_err(
+                sp,
+                &format!("attributes cannot be applied to {}", applied_to),
+            );
+            err.span_label(sp, "attributes are not allowed here");
+            err.emit();
+        }
+    }
+
     /// This version of parse arg doesn't necessarily require
     /// identifier names.
     fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
@@ -1797,7 +1826,11 @@ impl<'a> Parser<'a> {
         let (pat, ty) = if require_name || self.is_named_argument() {
             debug!("parse_arg_general parse_pat (require_name:{})",
                    require_name);
-            let pat = self.parse_pat()?;
+            self.eat_incorrect_doc_comment("method arguments");
+            let pat = self.parse_pat().map_err(|mut err| {
+                err.span_label(self.span, "expected argument name");
+                err
+            })?;
 
             if let Err(mut err) = self.expect(&token::Colon) {
                 // If we find a pattern followed by an identifier, it could be an (incorrect)
@@ -1819,10 +1852,12 @@ impl<'a> Parser<'a> {
                 return Err(err);
             }
 
+            self.eat_incorrect_doc_comment("a method argument's type");
             (pat, self.parse_ty()?)
         } else {
             debug!("parse_arg_general ident_to_pat");
             let parser_snapshot_before_ty = self.clone();
+            self.eat_incorrect_doc_comment("a method argument's type");
             let mut ty = self.parse_ty();
             if ty.is_ok() && self.token == token::Colon {
                 // This wasn't actually a type, but a pattern looking like a type,
diff --git a/src/test/ui/parser/fn-arg-doc-comment.rs b/src/test/ui/parser/fn-arg-doc-comment.rs
new file mode 100644
index 00000000000..22af94b6284
--- /dev/null
+++ b/src/test/ui/parser/fn-arg-doc-comment.rs
@@ -0,0 +1,37 @@
+pub fn f(
+    /// Comment
+    //~^ ERROR documentation comments cannot be applied to method arguments
+    //~| NOTE doc comments are not allowed here
+    id: u8,
+    /// Other
+    //~^ ERROR documentation comments cannot be applied to method arguments
+    //~| NOTE doc comments are not allowed here
+    a: u8,
+) {}
+
+fn foo(#[allow(dead_code)] id: i32) {}
+//~^ ERROR attributes cannot be applied to method arguments
+//~| NOTE attributes are not allowed here
+
+fn bar(id: #[allow(dead_code)] i32) {}
+//~^ ERROR attributes cannot be applied to a method argument's type
+//~| NOTE attributes are not allowed here
+
+fn main() {
+    // verify that the parser recovered and properly typechecked the args
+    f("", "");
+    //~^ ERROR mismatched types
+    //~| NOTE expected u8, found reference
+    //~| NOTE expected
+    //~| ERROR mismatched types
+    //~| NOTE expected u8, found reference
+    //~| NOTE expected
+    foo("");
+    //~^ ERROR mismatched types
+    //~| NOTE expected i32, found reference
+    //~| NOTE expected
+    bar("");
+    //~^ ERROR mismatched types
+    //~| NOTE expected i32, found reference
+    //~| NOTE expected
+}
diff --git a/src/test/ui/parser/fn-arg-doc-comment.stderr b/src/test/ui/parser/fn-arg-doc-comment.stderr
new file mode 100644
index 00000000000..73a24eebb3f
--- /dev/null
+++ b/src/test/ui/parser/fn-arg-doc-comment.stderr
@@ -0,0 +1,63 @@
+error: documentation comments cannot be applied to method arguments
+  --> $DIR/fn-arg-doc-comment.rs:2:5
+   |
+LL |     /// Comment
+   |     ^^^^^^^^^^^ doc comments are not allowed here
+
+error: documentation comments cannot be applied to method arguments
+  --> $DIR/fn-arg-doc-comment.rs:6:5
+   |
+LL |     /// Other
+   |     ^^^^^^^^^ doc comments are not allowed here
+
+error: attributes cannot be applied to method arguments
+  --> $DIR/fn-arg-doc-comment.rs:12:8
+   |
+LL | fn foo(#[allow(dead_code)] id: i32) {}
+   |        ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here
+
+error: attributes cannot be applied to a method argument's type
+  --> $DIR/fn-arg-doc-comment.rs:16:12
+   |
+LL | fn bar(id: #[allow(dead_code)] i32) {}
+   |            ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here
+
+error[E0308]: mismatched types
+  --> $DIR/fn-arg-doc-comment.rs:22:7
+   |
+LL |     f("", "");
+   |       ^^ expected u8, found reference
+   |
+   = note: expected type `u8`
+              found type `&'static str`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-arg-doc-comment.rs:22:11
+   |
+LL |     f("", "");
+   |           ^^ expected u8, found reference
+   |
+   = note: expected type `u8`
+              found type `&'static str`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-arg-doc-comment.rs:29:9
+   |
+LL |     foo("");
+   |         ^^ expected i32, found reference
+   |
+   = note: expected type `i32`
+              found type `&'static str`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-arg-doc-comment.rs:33:9
+   |
+LL |     bar("");
+   |         ^^ expected i32, found reference
+   |
+   = note: expected type `i32`
+              found type `&'static str`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/issue-33413.stderr b/src/test/ui/parser/issue-33413.stderr
index 189ace74b9c..4cdd14a3e27 100644
--- a/src/test/ui/parser/issue-33413.stderr
+++ b/src/test/ui/parser/issue-33413.stderr
@@ -2,7 +2,10 @@ error: expected pattern, found `*`
   --> $DIR/issue-33413.rs:14:10
    |
 LL |     fn f(*, a: u8) -> u8 {} //~ ERROR expected pattern, found `*`
-   |          ^ expected pattern
+   |          ^
+   |          |
+   |          expected pattern
+   |          expected argument name
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/lifetime-in-pattern.stderr b/src/test/ui/parser/lifetime-in-pattern.stderr
index 86cc3c5b0cb..83ca1b0ba26 100644
--- a/src/test/ui/parser/lifetime-in-pattern.stderr
+++ b/src/test/ui/parser/lifetime-in-pattern.stderr
@@ -2,7 +2,10 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/lifetime-in-pattern.rs:13:10
    |
 LL | fn test(&'a str) {
-   |          ^^ unexpected lifetime
+   |          ^^
+   |          |
+   |          unexpected lifetime
+   |          expected argument name
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/removed-syntax-mode.stderr b/src/test/ui/parser/removed-syntax-mode.stderr
index 7a274553d57..c5bc92e37b5 100644
--- a/src/test/ui/parser/removed-syntax-mode.stderr
+++ b/src/test/ui/parser/removed-syntax-mode.stderr
@@ -2,7 +2,10 @@ error: expected pattern, found `+`
   --> $DIR/removed-syntax-mode.rs:13:6
    |
 LL | fn f(+x: isize) {} //~ ERROR expected pattern, found `+`
-   |      ^ expected pattern
+   |      ^
+   |      |
+   |      expected pattern
+   |      expected argument name
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/self/self-vs-path-ambiguity.stderr b/src/test/ui/self/self-vs-path-ambiguity.stderr
index 76517433170..4cad8401f23 100644
--- a/src/test/ui/self/self-vs-path-ambiguity.stderr
+++ b/src/test/ui/self/self-vs-path-ambiguity.stderr
@@ -2,7 +2,10 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/self-vs-path-ambiguity.rs:19:11
    |
 LL |     fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern
-   |           ^^ unexpected lifetime
+   |           ^^
+   |           |
+   |           unexpected lifetime
+   |           expected argument name
 
 error: aborting due to previous error