about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-01-29 01:30:01 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-02-02 10:33:55 +0100
commit8674efdb7c9d263caef8d282086a4243eae8df20 (patch)
tree3dd62df510860da588ea8020fff68cae396733ff /src
parentcdd41ea5fc37d1ba879fd52743bde35fde4a89df (diff)
downloadrust-8674efdb7c9d263caef8d282086a4243eae8df20.tar.gz
rust-8674efdb7c9d263caef8d282086a4243eae8df20.zip
parser: move restrictions re. `self` to `ast_validation`.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_ast_passes/ast_validation.rs44
-rw-r--r--src/librustc_parse/parser/diagnostics.rs12
-rw-r--r--src/librustc_parse/parser/item.rs60
-rw-r--r--src/librustc_parse/parser/ty.rs4
-rw-r--r--src/test/ui/invalid-self-argument/bare-fn-start.rs6
-rw-r--r--src/test/ui/invalid-self-argument/bare-fn-start.stderr6
-rw-r--r--src/test/ui/parser/self-param-semantic-fail.rs64
-rw-r--r--src/test/ui/parser/self-param-semantic-fail.stderr220
-rw-r--r--src/test/ui/parser/self-param-syntactic-pass.rs66
9 files changed, 426 insertions, 56 deletions
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 152086bfce0..f37f93c0254 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -23,6 +23,12 @@ use syntax::print::pprust;
 use syntax::visit::{self, Visitor};
 use syntax::walk_list;
 
+/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
+enum SelfSemantic {
+    Yes,
+    No,
+}
+
 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
 #[derive(Clone, Copy)]
 enum BoundContext {
@@ -302,7 +308,13 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn check_fn_decl(&self, fn_decl: &FnDecl) {
+    fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
+        self.check_decl_cvaradic_pos(fn_decl);
+        self.check_decl_attrs(fn_decl);
+        self.check_decl_self_param(fn_decl, self_semantic);
+    }
+
+    fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
         match &*fn_decl.inputs {
             [Param { ty, span, .. }] => {
                 if let TyKind::CVarArgs = ty.kind {
@@ -324,7 +336,9 @@ impl<'a> AstValidator<'a> {
             }
             _ => {}
         }
+    }
 
+    fn check_decl_attrs(&self, fn_decl: &FnDecl) {
         fn_decl
             .inputs
             .iter()
@@ -352,6 +366,21 @@ impl<'a> AstValidator<'a> {
             });
     }
 
+    fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
+        if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
+            if param.is_self() {
+                self.err_handler()
+                    .struct_span_err(
+                        param.span,
+                        "`self` parameter only allowed in associated `fn`s",
+                    )
+                    .span_label(param.span, "not semantically valid as function parameter")
+                    .note("associated `fn`s are those in `impl` or `trait` definitions")
+                    .emit();
+            }
+        }
+    }
+
     fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
         if let Defaultness::Default = defaultness {
             self.err_handler()
@@ -504,7 +533,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_expr(&mut self, expr: &'a Expr) {
         match &expr.kind {
             ExprKind::Closure(_, _, _, fn_decl, _, _) => {
-                self.check_fn_decl(fn_decl);
+                self.check_fn_decl(fn_decl, SelfSemantic::No);
             }
             ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
                 struct_span_err!(
@@ -524,7 +553,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_ty(&mut self, ty: &'a Ty) {
         match ty.kind {
             TyKind::BareFn(ref bfty) => {
-                self.check_fn_decl(&bfty.decl);
+                self.check_fn_decl(&bfty.decl, SelfSemantic::No);
                 Self::check_decl_no_pat(&bfty.decl, |span, _| {
                     struct_span_err!(
                         self.session,
@@ -685,7 +714,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Fn(ref sig, ref generics, _) => {
                 self.visit_fn_header(&sig.header);
-                self.check_fn_decl(&sig.decl);
+                self.check_fn_decl(&sig.decl, SelfSemantic::No);
                 // We currently do not permit const generics in `const fn`, as
                 // this is tantamount to allowing compile-time dependent typing.
                 if sig.header.constness.node == Constness::Const {
@@ -793,7 +822,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
         match fi.kind {
             ForeignItemKind::Fn(ref decl, _) => {
-                self.check_fn_decl(decl);
+                self.check_fn_decl(decl, SelfSemantic::No);
                 Self::check_decl_no_pat(decl, |span, _| {
                     struct_span_err!(
                         self.session,
@@ -987,9 +1016,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             AssocItemKind::Const(_, body) => {
                 self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;");
             }
-            AssocItemKind::Fn(sig, body) => {
+            AssocItemKind::Fn(_, body) => {
                 self.check_impl_item_provided(ii.span, body, "function", " { <body> }");
-                self.check_fn_decl(&sig.decl);
             }
             AssocItemKind::TyAlias(bounds, body) => {
                 self.check_impl_item_provided(ii.span, body, "type", " = <type>;");
@@ -1005,7 +1033,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         self.check_defaultness(ti.span, ti.defaultness);
 
         if let AssocItemKind::Fn(sig, block) = &ti.kind {
-            self.check_fn_decl(&sig.decl);
             self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node);
             self.check_trait_fn_not_const(sig.header.constness);
             if block.is_none() {
@@ -1035,6 +1062,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem) {
         if let AssocItemKind::Fn(sig, _) = &item.kind {
+            self.check_fn_decl(&sig.decl, SelfSemantic::Yes);
             self.check_c_varadic_type(&sig.decl);
         }
         visit::walk_assoc_item(self, item);
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 80bc5c158a6..09f393a81ab 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -1336,8 +1336,8 @@ impl<'a> Parser<'a> {
         err: &mut DiagnosticBuilder<'_>,
         pat: P<ast::Pat>,
         require_name: bool,
-        is_self_allowed: bool,
-        is_trait_item: bool,
+        is_self_semantic: bool,
+        in_assoc_item: bool,
     ) -> Option<Ident> {
         // If we find a pattern followed by an identifier, it could be an (incorrect)
         // C-style parameter declaration.
@@ -1357,13 +1357,13 @@ impl<'a> Parser<'a> {
             return Some(ident);
         } else if let PatKind::Ident(_, ident, _) = pat.kind {
             if require_name
-                && (is_trait_item
+                && (in_assoc_item
                     || self.token == token::Comma
                     || self.token == token::Lt
                     || self.token == token::CloseDelim(token::Paren))
             {
                 // `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}`
-                if is_self_allowed {
+                if is_self_semantic {
                     err.span_suggestion(
                         pat.span,
                         "if this is a `self` type, give it a parameter name",
@@ -1423,12 +1423,12 @@ impl<'a> Parser<'a> {
     pub(super) fn recover_bad_self_param(
         &mut self,
         mut param: ast::Param,
-        is_trait_item: bool,
+        in_assoc_item: bool,
     ) -> PResult<'a, ast::Param> {
         let sp = param.pat.span;
         param.ty.kind = TyKind::Err;
         let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function");
-        if is_trait_item {
+        if in_assoc_item {
             err.span_label(sp, "must be the first associated function parameter");
         } else {
             err.span_label(sp, "not valid as function parameter");
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 66116611323..0ff595f4444 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1715,8 +1715,9 @@ impl<'a> Parser<'a> {
 
 /// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
 pub(super) struct ParamCfg {
-    /// Is `self` is allowed as the first parameter?
-    pub is_self_allowed: bool,
+    /// Is `self` is *semantically* allowed as the first parameter?
+    /// This is only used for diagnostics.
+    pub in_assoc_item: bool,
     /// `is_name_required` decides if, per-parameter,
     /// the parameter must have a pattern or just a type.
     pub is_name_required: fn(&token::Token) -> bool,
@@ -1732,8 +1733,8 @@ impl<'a> Parser<'a> {
         attrs: Vec<Attribute>,
         header: FnHeader,
     ) -> PResult<'a, Option<P<Item>>> {
-        let (ident, decl, generics) =
-            self.parse_fn_sig(ParamCfg { is_self_allowed: false, is_name_required: |_| true })?;
+        let cfg = ParamCfg { in_assoc_item: false, is_name_required: |_| true };
+        let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
         let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
         let kind = ItemKind::Fn(FnSig { decl, header }, generics, body);
         self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
@@ -1747,20 +1748,13 @@ impl<'a> Parser<'a> {
         attrs: Vec<Attribute>,
         extern_sp: Span,
     ) -> PResult<'a, P<ForeignItem>> {
+        let cfg = ParamCfg { in_assoc_item: false, is_name_required: |_| true };
         self.expect_keyword(kw::Fn)?;
-        let (ident, decl, generics) =
-            self.parse_fn_sig(ParamCfg { is_self_allowed: false, is_name_required: |_| true })?;
+        let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
         let span = lo.to(self.token.span);
         self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
-        Ok(P(ast::ForeignItem {
-            ident,
-            attrs,
-            kind: ForeignItemKind::Fn(decl, generics),
-            id: DUMMY_NODE_ID,
-            span,
-            vis,
-            tokens: None,
-        }))
+        let kind = ForeignItemKind::Fn(decl, generics);
+        Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None }))
     }
 
     fn parse_assoc_fn(
@@ -1769,9 +1763,9 @@ impl<'a> Parser<'a> {
         attrs: &mut Vec<Attribute>,
         is_name_required: fn(&token::Token) -> bool,
     ) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
+        let cfg = ParamCfg { in_assoc_item: true, is_name_required };
         let header = self.parse_fn_front_matter()?;
-        let (ident, decl, generics) =
-            self.parse_fn_sig(ParamCfg { is_self_allowed: true, is_name_required })?;
+        let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
         let sig = FnSig { header, decl };
         let body = self.parse_assoc_fn_body(at_end, attrs)?;
         Ok((ident, AssocItemKind::Fn(sig, body), generics))
@@ -1847,7 +1841,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse the "signature", including the identifier, parameters, and generics of a function.
-    fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
+    fn parse_fn_sig(&mut self, cfg: &ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
         let ident = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
         let decl = self.parse_fn_decl(cfg, true)?;
@@ -1858,7 +1852,7 @@ impl<'a> Parser<'a> {
     /// Parses the parameter list and result type of a function declaration.
     pub(super) fn parse_fn_decl(
         &mut self,
-        cfg: ParamCfg,
+        cfg: &ParamCfg,
         ret_allow_plus: bool,
     ) -> PResult<'a, P<FnDecl>> {
         Ok(P(FnDecl {
@@ -1868,11 +1862,11 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses the parameter list of a function, including the `(` and `)` delimiters.
-    fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
-        let is_trait_item = cfg.is_self_allowed;
-        // Parse the arguments, starting out with `self` being possibly allowed...
+    fn parse_fn_params(&mut self, cfg: &ParamCfg) -> PResult<'a, Vec<Param>> {
+        let mut first_param = true;
+        // Parse the arguments, starting out with `self` being allowed...
         let (mut params, _) = self.parse_paren_comma_seq(|p| {
-            let param = p.parse_param_general(&cfg, is_trait_item).or_else(|mut e| {
+            let param = p.parse_param_general(&cfg, first_param).or_else(|mut e| {
                 e.emit();
                 let lo = p.prev_span;
                 // Skip every token until next possible arg or end.
@@ -1881,7 +1875,7 @@ impl<'a> Parser<'a> {
                 Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_span))))
             });
             // ...now that we've parsed the first argument, `self` is no longer allowed.
-            cfg.is_self_allowed = false;
+            first_param = false;
             param
         })?;
         // Replace duplicated recovered params with `_` pattern to avoid unnecessary errors.
@@ -1889,20 +1883,20 @@ impl<'a> Parser<'a> {
         Ok(params)
     }
 
-    /// Skips unexpected attributes and doc comments in this position and emits an appropriate
-    /// error.
-    /// This version of parse param doesn't necessarily require identifier names.
-    fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> {
+    /// Parses a single function parameter.
+    ///
+    /// - `self` is syntactically allowed when `first_param` holds.
+    fn parse_param_general(&mut self, cfg: &ParamCfg, first_param: bool) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
 
         // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
         if let Some(mut param) = self.parse_self_param()? {
             param.attrs = attrs.into();
-            return if cfg.is_self_allowed {
+            return if first_param {
                 Ok(param)
             } else {
-                self.recover_bad_self_param(param, is_trait_item)
+                self.recover_bad_self_param(param, cfg.in_assoc_item)
             };
         }
 
@@ -1919,8 +1913,8 @@ impl<'a> Parser<'a> {
                     &mut err,
                     pat,
                     is_name_required,
-                    cfg.is_self_allowed,
-                    is_trait_item,
+                    first_param && cfg.in_assoc_item,
+                    cfg.in_assoc_item,
                 ) {
                     err.emit();
                     Ok(dummy_arg(ident))
@@ -1975,8 +1969,6 @@ impl<'a> Parser<'a> {
     }
 
     /// Returns the parsed optional self parameter and whether a self shortcut was used.
-    ///
-    /// See `parse_self_param_with_attrs` to collect attributes.
     fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
         // Extract an identifier *after* having confirmed that the token is one.
         let expect_self_ident = |this: &mut Self| {
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index a4cc9fa48f2..51367a37ad7 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -288,8 +288,8 @@ impl<'a> Parser<'a> {
         let unsafety = self.parse_unsafety();
         let ext = self.parse_extern()?;
         self.expect_keyword(kw::Fn)?;
-        let cfg = ParamCfg { is_self_allowed: false, is_name_required: |_| false };
-        let decl = self.parse_fn_decl(cfg, false)?;
+        let cfg = ParamCfg { in_assoc_item: false, is_name_required: |_| false };
+        let decl = self.parse_fn_decl(&cfg, false)?;
         Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl })))
     }
 
diff --git a/src/test/ui/invalid-self-argument/bare-fn-start.rs b/src/test/ui/invalid-self-argument/bare-fn-start.rs
index a003a01941b..8c92b7bc7c4 100644
--- a/src/test/ui/invalid-self-argument/bare-fn-start.rs
+++ b/src/test/ui/invalid-self-argument/bare-fn-start.rs
@@ -1,6 +1,6 @@
 fn a(&self) { }
-//~^ ERROR unexpected `self` parameter in function
-//~| NOTE not valid as function parameter
-//~| NOTE `self` is only valid as the first parameter of an associated function
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+//~| NOTE not semantically valid as function parameter
+//~| NOTE associated `fn`s are those in `impl` or `trait` definitions
 
 fn main() { }
diff --git a/src/test/ui/invalid-self-argument/bare-fn-start.stderr b/src/test/ui/invalid-self-argument/bare-fn-start.stderr
index 23de6502094..59120a60a6d 100644
--- a/src/test/ui/invalid-self-argument/bare-fn-start.stderr
+++ b/src/test/ui/invalid-self-argument/bare-fn-start.stderr
@@ -1,10 +1,10 @@
-error: unexpected `self` parameter in function
+error: `self` parameter only allowed in associated `fn`s
   --> $DIR/bare-fn-start.rs:1:6
    |
 LL | fn a(&self) { }
-   |      ^^^^^ not valid as function parameter
+   |      ^^^^^ not semantically valid as function parameter
    |
-   = note: `self` is only valid as the first parameter of an associated function
+   = note: associated `fn`s are those in `impl` or `trait` definitions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/self-param-semantic-fail.rs b/src/test/ui/parser/self-param-semantic-fail.rs
new file mode 100644
index 00000000000..773cf922b4d
--- /dev/null
+++ b/src/test/ui/parser/self-param-semantic-fail.rs
@@ -0,0 +1,64 @@
+// This test ensures that `self` is semantically rejected
+// in contexts with `FnDecl` but outside of associated `fn`s.
+// FIXME(Centril): For now closures are an exception.
+
+fn main() {}
+
+fn free() {
+    fn f1(self) {}
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f2(mut self) {}
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f3(&self) {}
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f4(&mut self) {}
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f5<'a>(&'a self) {}
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f6<'a>(&'a mut self) {}
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f7(self: u8) {}
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f8(mut self: u8) {}
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+}
+
+extern {
+    fn f1(self);
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f2(mut self);
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    //~| ERROR patterns aren't allowed in
+    fn f3(&self);
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f4(&mut self);
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f5<'a>(&'a self);
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f6<'a>(&'a mut self);
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f7(self: u8);
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    fn f8(mut self: u8);
+    //~^ ERROR `self` parameter only allowed in associated `fn`s
+    //~| ERROR patterns aren't allowed in
+}
+
+type X1 = fn(self);
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+type X2 = fn(mut self);
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+//~| ERROR patterns aren't allowed in
+type X3 = fn(&self);
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+type X4 = fn(&mut self);
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+type X5 = for<'a> fn(&'a self);
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+type X6 = for<'a> fn(&'a mut self);
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+type X7 = fn(self: u8);
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+type X8 = fn(mut self: u8);
+//~^ ERROR `self` parameter only allowed in associated `fn`s
+//~| ERROR patterns aren't allowed in
diff --git a/src/test/ui/parser/self-param-semantic-fail.stderr b/src/test/ui/parser/self-param-semantic-fail.stderr
new file mode 100644
index 00000000000..b45e4a5d26f
--- /dev/null
+++ b/src/test/ui/parser/self-param-semantic-fail.stderr
@@ -0,0 +1,220 @@
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:8:11
+   |
+LL |     fn f1(self) {}
+   |           ^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:10:11
+   |
+LL |     fn f2(mut self) {}
+   |           ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:12:11
+   |
+LL |     fn f3(&self) {}
+   |           ^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:14:11
+   |
+LL |     fn f4(&mut self) {}
+   |           ^^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:16:15
+   |
+LL |     fn f5<'a>(&'a self) {}
+   |               ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:18:15
+   |
+LL |     fn f6<'a>(&'a mut self) {}
+   |               ^^^^^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:20:11
+   |
+LL |     fn f7(self: u8) {}
+   |           ^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:22:11
+   |
+LL |     fn f8(mut self: u8) {}
+   |           ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:27:11
+   |
+LL |     fn f1(self);
+   |           ^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:29:11
+   |
+LL |     fn f2(mut self);
+   |           ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error[E0130]: patterns aren't allowed in foreign function declarations
+  --> $DIR/self-param-semantic-fail.rs:29:11
+   |
+LL |     fn f2(mut self);
+   |           ^^^^^^^^ pattern not allowed in foreign function
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:32:11
+   |
+LL |     fn f3(&self);
+   |           ^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:34:11
+   |
+LL |     fn f4(&mut self);
+   |           ^^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:36:15
+   |
+LL |     fn f5<'a>(&'a self);
+   |               ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:38:15
+   |
+LL |     fn f6<'a>(&'a mut self);
+   |               ^^^^^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:40:11
+   |
+LL |     fn f7(self: u8);
+   |           ^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:42:11
+   |
+LL |     fn f8(mut self: u8);
+   |           ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error[E0130]: patterns aren't allowed in foreign function declarations
+  --> $DIR/self-param-semantic-fail.rs:42:11
+   |
+LL |     fn f8(mut self: u8);
+   |           ^^^^^^^^ pattern not allowed in foreign function
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:47:14
+   |
+LL | type X1 = fn(self);
+   |              ^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:49:14
+   |
+LL | type X2 = fn(mut self);
+   |              ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error[E0561]: patterns aren't allowed in function pointer types
+  --> $DIR/self-param-semantic-fail.rs:49:14
+   |
+LL | type X2 = fn(mut self);
+   |              ^^^^^^^^
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:52:14
+   |
+LL | type X3 = fn(&self);
+   |              ^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:54:14
+   |
+LL | type X4 = fn(&mut self);
+   |              ^^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:56:22
+   |
+LL | type X5 = for<'a> fn(&'a self);
+   |                      ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:58:22
+   |
+LL | type X6 = for<'a> fn(&'a mut self);
+   |                      ^^^^^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:60:14
+   |
+LL | type X7 = fn(self: u8);
+   |              ^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error: `self` parameter only allowed in associated `fn`s
+  --> $DIR/self-param-semantic-fail.rs:62:14
+   |
+LL | type X8 = fn(mut self: u8);
+   |              ^^^^^^^^ not semantically valid as function parameter
+   |
+   = note: associated `fn`s are those in `impl` or `trait` definitions
+
+error[E0561]: patterns aren't allowed in function pointer types
+  --> $DIR/self-param-semantic-fail.rs:62:14
+   |
+LL | type X8 = fn(mut self: u8);
+   |              ^^^^^^^^
+
+error: aborting due to 28 previous errors
+
+Some errors have detailed explanations: E0130, E0561.
+For more information about an error, try `rustc --explain E0130`.
diff --git a/src/test/ui/parser/self-param-syntactic-pass.rs b/src/test/ui/parser/self-param-syntactic-pass.rs
new file mode 100644
index 00000000000..9e215e6cdd4
--- /dev/null
+++ b/src/test/ui/parser/self-param-syntactic-pass.rs
@@ -0,0 +1,66 @@
+// This test ensures that `self` is syntactically accepted in all places an `FnDecl` is parsed.
+// FIXME(Centril): For now closures are an exception.
+
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn free() {
+    fn f(self) {}
+    fn f(mut self) {}
+    fn f(&self) {}
+    fn f(&mut self) {}
+    fn f(&'a self) {}
+    fn f(&'a mut self) {}
+    fn f(self: u8) {}
+    fn f(mut self: u8) {}
+}
+
+#[cfg(FALSE)]
+extern {
+    fn f(self);
+    fn f(mut self);
+    fn f(&self);
+    fn f(&mut self);
+    fn f(&'a self);
+    fn f(&'a mut self);
+    fn f(self: u8);
+    fn f(mut self: u8);
+}
+
+#[cfg(FALSE)]
+trait X {
+    fn f(self) {}
+    fn f(mut self) {}
+    fn f(&self) {}
+    fn f(&mut self) {}
+    fn f(&'a self) {}
+    fn f(&'a mut self) {}
+    fn f(self: u8) {}
+    fn f(mut self: u8) {}
+}
+
+#[cfg(FALSE)]
+impl X for Y {
+    fn f(self) {}
+    fn f(mut self) {}
+    fn f(&self) {}
+    fn f(&mut self) {}
+    fn f(&'a self) {}
+    fn f(&'a mut self) {}
+    fn f(self: u8) {}
+    fn f(mut self: u8) {}
+}
+
+#[cfg(FALSE)]
+impl X for Y {
+    type X = fn(self);
+    type X = fn(mut self);
+    type X = fn(&self);
+    type X = fn(&mut self);
+    type X = fn(&'a self);
+    type X = fn(&'a mut self);
+    type X = fn(self: u8);
+    type X = fn(mut self: u8);
+}