diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index e13f6cabb5296..50733512faec8 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -477,11 +477,11 @@ impl<'a> LoweringContext<'a> {
                 });
             }
 
-            fn visit_trait_item(&mut self, item: &'tcx TraitItem) {
+            fn visit_trait_item(&mut self, item: &'tcx AssocItem) {
                 self.lctx.allocate_hir_id_counter(item.id);
 
                 match item.kind {
-                    TraitItemKind::Method(_, None) => {
+                    AssocItemKind::Fn(_, None) => {
                         // Ignore patterns in trait methods without bodies
                         self.with_hir_id_owner(None, |this| {
                             visit::walk_trait_item(this, item)
@@ -493,7 +493,7 @@ impl<'a> LoweringContext<'a> {
                 }
             }
 
-            fn visit_impl_item(&mut self, item: &'tcx ImplItem) {
+            fn visit_impl_item(&mut self, item: &'tcx AssocItem) {
                 self.lctx.allocate_hir_id_counter(item.id);
                 self.with_hir_id_owner(Some(item.id), |this| {
                     visit::walk_impl_item(this, item);
@@ -1211,7 +1211,7 @@ impl<'a> LoweringContext<'a> {
                             let ct = self.with_new_scopes(|this| {
                                 hir::AnonConst {
                                     hir_id: this.lower_node_id(node_id),
-                                    body: this.lower_const_body(&path_expr),
+                                    body: this.lower_const_body(path_expr.span, Some(&path_expr)),
                                 }
                             });
                             return GenericArg::Const(ConstArg {
@@ -1253,6 +1253,14 @@ impl<'a> LoweringContext<'a> {
         ty
     }
 
+    fn ty(&mut self, span: Span, kind: hir::TyKind) -> hir::Ty {
+        hir::Ty { hir_id: self.next_id(), kind, span }
+    }
+
+    fn ty_tup(&mut self, span: Span, tys: HirVec<hir::Ty>) -> hir::Ty {
+        self.ty(span, hir::TyKind::Tup(tys))
+    }
+
     fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::Ty {
         let kind = match t.kind {
             TyKind::Infer => hir::TyKind::Infer,
@@ -1418,7 +1426,13 @@ impl<'a> LoweringContext<'a> {
                 }
             }
             TyKind::Mac(_) => bug!("`TyKind::Mac` should have been expanded by now"),
-            TyKind::CVarArgs => bug!("`TyKind::CVarArgs` should have been handled elsewhere"),
+            TyKind::CVarArgs => {
+                self.sess.delay_span_bug(
+                    t.span,
+                    "`TyKind::CVarArgs` should have been handled elsewhere",
+                );
+                hir::TyKind::Err
+            }
         };
 
         hir::Ty {
@@ -2084,32 +2098,19 @@ impl<'a> LoweringContext<'a> {
                     .iter()
                     .map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed()))
                     .collect();
-                let mk_tup = |this: &mut Self, tys, span| {
-                    hir::Ty { kind: hir::TyKind::Tup(tys), hir_id: this.next_id(), span }
+                let output_ty = match output {
+                    FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
+                    FunctionRetTy::Default(_) => P(this.ty_tup(span, hir::HirVec::new())),
+                };
+                let args = hir_vec![GenericArg::Type(this.ty_tup(span, inputs))];
+                let binding = hir::TypeBinding {
+                    hir_id: this.next_id(),
+                    ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
+                    span: output_ty.span,
+                    kind: hir::TypeBindingKind::Equality { ty: output_ty },
                 };
                 (
-                    hir::GenericArgs {
-                        args: hir_vec![GenericArg::Type(mk_tup(this, inputs, span))],
-                        bindings: hir_vec![
-                            hir::TypeBinding {
-                                hir_id: this.next_id(),
-                                ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
-                                kind: hir::TypeBindingKind::Equality {
-                                    ty: output
-                                        .as_ref()
-                                        .map(|ty| this.lower_ty(
-                                            &ty,
-                                            ImplTraitContext::disallowed()
-                                        ))
-                                        .unwrap_or_else(||
-                                            P(mk_tup(this, hir::HirVec::new(), span))
-                                        ),
-                                },
-                                span: output.as_ref().map_or(span, |ty| ty.span),
-                            }
-                        ],
-                        parenthesized: true,
-                    },
+                    hir::GenericArgs { args, bindings: hir_vec![binding], parenthesized: true },
                     false,
                 )
             }
@@ -2474,17 +2475,13 @@ impl<'a> LoweringContext<'a> {
             })
         );
 
-        // Create the `Foo<...>` refernece itself. Note that the `type
+        // Create the `Foo<...>` reference itself. Note that the `type
         // Foo = impl Trait` is, internally, created as a child of the
         // async fn, so the *type parameters* are inherited.  It's
         // only the lifetime parameters that we must supply.
         let opaque_ty_ref = hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, generic_args.into());
-
-        hir::FunctionRetTy::Return(P(hir::Ty {
-            kind: opaque_ty_ref,
-            span: opaque_ty_span,
-            hir_id: self.next_id(),
-        }))
+        let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
+        hir::FunctionRetTy::Return(P(opaque_ty))
     }
 
     /// Transforms `-> T` into `Future<Output = T>`
@@ -2496,16 +2493,8 @@ impl<'a> LoweringContext<'a> {
     ) -> hir::GenericBound {
         // Compute the `T` in `Future<Output = T>` from the return type.
         let output_ty = match output {
-            FunctionRetTy::Ty(ty) => {
-                self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(fn_def_id)))
-            }
-            FunctionRetTy::Default(ret_ty_span) => {
-                P(hir::Ty {
-                    hir_id: self.next_id(),
-                    kind: hir::TyKind::Tup(hir_vec![]),
-                    span: *ret_ty_span,
-                })
-            }
+            FunctionRetTy::Ty(ty) => self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(fn_def_id))),
+            FunctionRetTy::Default(ret_ty_span) => P(self.ty_tup(*ret_ty_span, hir_vec![])),
         };
 
         // "<Output = T>"
@@ -3003,7 +2992,7 @@ impl<'a> LoweringContext<'a> {
         self.with_new_scopes(|this| {
             hir::AnonConst {
                 hir_id: this.lower_node_id(c.id),
-                body: this.lower_const_body(&c.value),
+                body: this.lower_const_body(c.value.span, Some(&c.value)),
             }
         })
     }
diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs
index ff9d8c85df8b9..46c944fa67881 100644
--- a/src/librustc/hir/lowering/item.rs
+++ b/src/librustc/hir/lowering/item.rs
@@ -86,7 +86,7 @@ impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> {
         }
     }
 
-    fn visit_trait_item(&mut self, item: &'tcx TraitItem) {
+    fn visit_trait_item(&mut self, item: &'tcx AssocItem) {
         self.lctx.with_hir_id_owner(item.id, |lctx| {
             let hir_item = lctx.lower_trait_item(item);
             let id = hir::TraitItemId { hir_id: hir_item.hir_id };
@@ -97,7 +97,7 @@ impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> {
         visit::walk_trait_item(self, item);
     }
 
-    fn visit_impl_item(&mut self, item: &'tcx ImplItem) {
+    fn visit_impl_item(&mut self, item: &'tcx AssocItem) {
         self.lctx.with_hir_id_owner(item.id, |lctx| {
             let hir_item = lctx.lower_impl_item(item);
             let id = hir::ImplItemId { hir_id: hir_item.hir_id };
@@ -250,7 +250,7 @@ impl LoweringContext<'_> {
             return None;
         }
 
-        let kind = self.lower_item_kind(i.id, &mut ident, &attrs, &mut vis, &i.kind);
+        let kind = self.lower_item_kind(i.span, i.id, &mut ident, &attrs, &mut vis, &i.kind);
 
         Some(hir::Item {
             hir_id: self.lower_node_id(i.id),
@@ -264,6 +264,7 @@ impl LoweringContext<'_> {
 
     fn lower_item_kind(
         &mut self,
+        span: Span,
         id: NodeId,
         ident: &mut Ident,
         attrs: &hir::HirVec<Attribute>,
@@ -292,7 +293,7 @@ impl LoweringContext<'_> {
                         }
                     ),
                     m,
-                    self.lower_const_body(e),
+                    self.lower_const_body(span, Some(e)),
                 )
             }
             ItemKind::Const(ref t, ref e) => {
@@ -305,7 +306,7 @@ impl LoweringContext<'_> {
                             ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
                         }
                     ),
-                    self.lower_const_body(e)
+                    self.lower_const_body(span, Some(e))
                 )
             }
             ItemKind::Fn(FnSig { ref decl, header }, ref generics, ref body) => {
@@ -317,7 +318,12 @@ impl LoweringContext<'_> {
                     // `impl Future<Output = T>` here because lower_body
                     // only cares about the input argument patterns in the function
                     // declaration (decl), not the return types.
-                    let body_id = this.lower_maybe_async_body(&decl, header.asyncness.node, body);
+                    let body_id = this.lower_maybe_async_body(
+                        span,
+                        &decl,
+                        header.asyncness.node,
+                        Some(body),
+                    );
 
                     let (generics, decl) = this.add_in_band_defs(
                         generics,
@@ -807,20 +813,20 @@ impl LoweringContext<'_> {
         }
     }
 
-    fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
+    fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem {
         let trait_item_def_id = self.resolver.definitions().local_def_id(i.id);
 
         let (generics, kind) = match i.kind {
-            TraitItemKind::Const(ref ty, ref default) => (
+            AssocItemKind::Const(ref ty, ref default) => (
                 self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
                 hir::TraitItemKind::Const(
                     self.lower_ty(ty, ImplTraitContext::disallowed()),
                     default
                         .as_ref()
-                        .map(|x| self.lower_const_body(x)),
+                        .map(|x| self.lower_const_body(i.span, Some(x))),
                 ),
             ),
-            TraitItemKind::Method(ref sig, None) => {
+            AssocItemKind::Fn(ref sig, None) => {
                 let names = self.lower_fn_params_to_names(&sig.decl);
                 let (generics, sig) = self.lower_method_sig(
                     &i.generics,
@@ -831,8 +837,8 @@ impl LoweringContext<'_> {
                 );
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names)))
             }
-            TraitItemKind::Method(ref sig, Some(ref body)) => {
-                let body_id = self.lower_fn_body_block(&sig.decl, body);
+            AssocItemKind::Fn(ref sig, Some(ref body)) => {
+                let body_id = self.lower_fn_body_block(i.span, &sig.decl, Some(body));
                 let (generics, sig) = self.lower_method_sig(
                     &i.generics,
                     sig,
@@ -842,7 +848,7 @@ impl LoweringContext<'_> {
                 );
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
             }
-            TraitItemKind::Type(ref bounds, ref default) => {
+            AssocItemKind::TyAlias(ref bounds, ref default) => {
                 let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
                 let kind = hir::TraitItemKind::Type(
                     self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
@@ -853,7 +859,7 @@ impl LoweringContext<'_> {
 
                 (generics, kind)
             },
-            TraitItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
+            AssocItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
         };
 
         hir::TraitItem {
@@ -866,21 +872,21 @@ impl LoweringContext<'_> {
         }
     }
 
-    fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
+    fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
         let (kind, has_default) = match i.kind {
-            TraitItemKind::Const(_, ref default) => {
+            AssocItemKind::Const(_, ref default) => {
                 (hir::AssocItemKind::Const, default.is_some())
             }
-            TraitItemKind::Type(_, ref default) => {
+            AssocItemKind::TyAlias(_, ref default) => {
                 (hir::AssocItemKind::Type, default.is_some())
             }
-            TraitItemKind::Method(ref sig, ref default) => (
+            AssocItemKind::Fn(ref sig, ref default) => (
                 hir::AssocItemKind::Method {
                     has_self: sig.decl.has_self(),
                 },
                 default.is_some(),
             ),
-            TraitItemKind::Macro(..) => unimplemented!(),
+            AssocItemKind::Macro(..) => unimplemented!(),
         };
         hir::TraitItemRef {
             id: hir::TraitItemId { hir_id: self.lower_node_id(i.id) },
@@ -891,21 +897,29 @@ impl LoweringContext<'_> {
         }
     }
 
-    fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
+    /// Construct `ExprKind::Err` for the given `span`.
+    fn expr_err(&mut self, span: Span) -> hir::Expr {
+        self.expr(span, hir::ExprKind::Err, ThinVec::new())
+    }
+
+    fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem {
         let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
 
         let (generics, kind) = match i.kind {
-            ImplItemKind::Const(ref ty, ref expr) => (
+            AssocItemKind::Const(ref ty, ref expr) => (
                 self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
                 hir::ImplItemKind::Const(
                     self.lower_ty(ty, ImplTraitContext::disallowed()),
-                    self.lower_const_body(expr),
+                    self.lower_const_body(i.span, expr.as_deref()),
                 ),
             ),
-            ImplItemKind::Method(ref sig, ref body) => {
+            AssocItemKind::Fn(ref sig, ref body) => {
                 self.current_item = Some(i.span);
                 let body_id = self.lower_maybe_async_body(
-                    &sig.decl, sig.header.asyncness.node, body
+                    i.span,
+                    &sig.decl,
+                    sig.header.asyncness.node,
+                    body.as_deref(),
                 );
                 let impl_trait_return_allow = !self.is_in_trait_impl;
                 let (generics, sig) = self.lower_method_sig(
@@ -918,21 +932,26 @@ impl LoweringContext<'_> {
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
             }
-            ImplItemKind::TyAlias(ref ty) => {
+            AssocItemKind::TyAlias(_, ref ty) => {
                 let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
-                let kind = match ty.kind.opaque_top_hack() {
+                let kind = match ty {
                     None => {
-                        let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
-                        hir::ImplItemKind::TyAlias(ty)
+                        hir::ImplItemKind::TyAlias(P(self.ty(i.span, hir::TyKind::Err)))
                     }
-                    Some(bs) => {
-                        let bounds = self.lower_param_bounds(bs, ImplTraitContext::disallowed());
-                        hir::ImplItemKind::OpaqueTy(bounds)
+                    Some(ty) => match ty.kind.opaque_top_hack() {
+                        None => {
+                            let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
+                            hir::ImplItemKind::TyAlias(ty)
+                        }
+                        Some(bs) => {
+                            let bs = self.lower_param_bounds(bs, ImplTraitContext::disallowed());
+                            hir::ImplItemKind::OpaqueTy(bs)
+                        }
                     }
                 };
                 (generics, kind)
             },
-            ImplItemKind::Macro(..) => bug!("`TyMac` should have been expanded by now"),
+            AssocItemKind::Macro(..) => bug!("`TyMac` should have been expanded by now"),
         };
 
         hir::ImplItem {
@@ -949,7 +968,7 @@ impl LoweringContext<'_> {
         // [1] since `default impl` is not yet implemented, this is always true in impls
     }
 
-    fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef {
+    fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
         hir::ImplItemRef {
             id: hir::ImplItemId { hir_id: self.lower_node_id(i.id) },
             ident: i.ident,
@@ -957,15 +976,18 @@ impl LoweringContext<'_> {
             vis: self.lower_visibility(&i.vis, Some(i.id)),
             defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
             kind: match &i.kind {
-                ImplItemKind::Const(..) => hir::AssocItemKind::Const,
-                ImplItemKind::TyAlias(ty) => match ty.kind.opaque_top_hack() {
+                AssocItemKind::Const(..) => hir::AssocItemKind::Const,
+                AssocItemKind::TyAlias(_, ty) => match ty
+                    .as_deref()
+                    .and_then(|ty| ty.kind.opaque_top_hack())
+                {
                     None => hir::AssocItemKind::Type,
                     Some(_) => hir::AssocItemKind::OpaqueTy,
                 },
-                ImplItemKind::Method(sig, _) => hir::AssocItemKind::Method {
+                AssocItemKind::Fn(sig, _) => hir::AssocItemKind::Method {
                     has_self: sig.decl.has_self(),
                 },
-                ImplItemKind::Macro(..) => unimplemented!(),
+                AssocItemKind::Macro(..) => unimplemented!(),
             },
         }
 
@@ -1063,23 +1085,39 @@ impl LoweringContext<'_> {
         ))
     }
 
-    fn lower_fn_body_block(&mut self, decl: &FnDecl, body: &Block) -> hir::BodyId {
-        self.lower_fn_body(decl, |this| this.lower_block_expr(body))
+    fn lower_fn_body_block(
+        &mut self,
+        span: Span,
+        decl: &FnDecl,
+        body: Option<&Block>,
+    ) -> hir::BodyId {
+        self.lower_fn_body(decl, |this| this.lower_block_expr_opt(span, body))
+    }
+
+    fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr {
+        match block {
+            Some(block) => self.lower_block_expr(block),
+            None => self.expr_err(span),
+        }
     }
 
-    pub(super) fn lower_const_body(&mut self, expr: &Expr) -> hir::BodyId {
-        self.lower_body(|this| (hir_vec![], this.lower_expr(expr)))
+    pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
+        self.lower_body(|this| (hir_vec![], match expr {
+            Some(expr) => this.lower_expr(expr),
+            None => this.expr_err(span),
+        }))
     }
 
     fn lower_maybe_async_body(
         &mut self,
+        span: Span,
         decl: &FnDecl,
         asyncness: IsAsync,
-        body: &Block,
+        body: Option<&Block>,
     ) -> hir::BodyId {
         let closure_id = match asyncness {
             IsAsync::Async { closure_id, .. } => closure_id,
-            IsAsync::NotAsync => return self.lower_fn_body_block(decl, body),
+            IsAsync::NotAsync => return self.lower_fn_body_block(span, decl, body),
         };
 
         self.lower_body(|this| {
@@ -1213,15 +1251,16 @@ impl LoweringContext<'_> {
                 parameters.push(new_parameter);
             }
 
+            let body_span = body.map_or(span, |b| b.span);
             let async_expr = this.make_async_expr(
                 CaptureBy::Value,
                 closure_id,
                 None,
-                body.span,
+                body_span,
                 hir::AsyncGeneratorKind::Fn,
                 |this| {
                     // Create a block from the user's function body:
-                    let user_body = this.lower_block_expr(body);
+                    let user_body = this.lower_block_expr_opt(body_span, body);
 
                     // Transform into `drop-temps { <user-body> }`, an expression:
                     let desugared_span = this.mark_span_with_reason(
@@ -1251,7 +1290,7 @@ impl LoweringContext<'_> {
                     );
                     this.expr_block(P(body), ThinVec::new())
                 });
-            (HirVec::from(parameters), this.expr(body.span, async_expr, ThinVec::new()))
+            (HirVec::from(parameters), this.expr(body_span, async_expr, ThinVec::new()))
         })
     }
 
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 7f72154e42c61..0fdd509a0bbec 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -1249,7 +1249,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         ast_visit::walk_poly_trait_ref(self, t, m);
     }
 
-    fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
+    fn visit_trait_item(&mut self, trait_item: &'a ast::AssocItem) {
         self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
             run_early_pass!(cx, check_trait_item, trait_item);
             ast_visit::walk_trait_item(cx, trait_item);
@@ -1257,7 +1257,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         });
     }
 
-    fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) {
+    fn visit_impl_item(&mut self, impl_item: &'a ast::AssocItem) {
         self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
             run_early_pass!(cx, check_impl_item, impl_item);
             ast_visit::walk_impl_item(cx, impl_item);
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index a8d886866795e..0054f149f8c27 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -258,10 +258,10 @@ macro_rules! early_lint_methods {
                 c: Span,
                 d: ast::NodeId
             );
-            fn check_trait_item(a: &ast::TraitItem);
-            fn check_trait_item_post(a: &ast::TraitItem);
-            fn check_impl_item(a: &ast::ImplItem);
-            fn check_impl_item_post(a: &ast::ImplItem);
+            fn check_trait_item(a: &ast::AssocItem);
+            fn check_trait_item_post(a: &ast::AssocItem);
+            fn check_impl_item(a: &ast::AssocItem);
+            fn check_impl_item_post(a: &ast::AssocItem);
             fn check_struct_def(a: &ast::VariantData);
             fn check_struct_def_post(a: &ast::VariantData);
             fn check_struct_field(a: &ast::StructField);
diff --git a/src/librustc_error_codes/error_codes/E0743.md b/src/librustc_error_codes/error_codes/E0743.md
index aaf19d8478ca2..1780fe59cbd69 100644
--- a/src/librustc_error_codes/error_codes/E0743.md
+++ b/src/librustc_error_codes/error_codes/E0743.md
@@ -1,11 +1,17 @@
-C-variadic has been used on a non-foreign function.
+The C-variadic type `...` has been nested inside another type.
 
 Erroneous code example:
 
 ```compile_fail,E0743
-fn foo2(x: u8, ...) {} // error!
+#![feature(c_variadic)]
+
+fn foo2(x: u8, y: &...) {} // error!
 ```
 
-Only foreign functions can use C-variadic (`...`). It is used to give an
-undefined number of parameters to a given function (like `printf` in C). The
-equivalent in Rust would be to use macros directly.
+Only foreign functions can use the C-variadic type (`...`).
+In such functions, `...` may only occur non-nested.
+That is, `y: &'a ...` is not allowed.
+
+A C-variadic type is used to give an undefined number
+of parameters to a given function (like `printf` in C).
+The equivalent in Rust would be to use macros directly.
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 8c225b83f40e8..e84ac82942c8e 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -712,8 +712,8 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
         ret
     }
 
-    fn should_ignore_fn(ret_ty: &ast::FnDecl) -> bool {
-        if let ast::FunctionRetTy::Ty(ref ty) = ret_ty.output {
+    fn should_ignore_fn(ret_ty: &ast::FunctionRetTy) -> bool {
+        if let ast::FunctionRetTy::Ty(ref ty) = ret_ty {
             fn involves_impl_trait(ty: &ast::Ty) -> bool {
                 match ty.kind {
                     ast::TyKind::ImplTrait(..) => true,
@@ -742,7 +742,7 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
                             },
                             Some(&ast::GenericArgs::Parenthesized(ref data)) => {
                                 any_involves_impl_trait(data.inputs.iter()) ||
-                                any_involves_impl_trait(data.output.iter())
+                                ReplaceBodyWithLoop::should_ignore_fn(&data.output)
                             }
                         }
                     }),
@@ -762,7 +762,7 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
 
     fn is_sig_const(sig: &ast::FnSig) -> bool {
         sig.header.constness.node == ast::Constness::Const ||
-            ReplaceBodyWithLoop::should_ignore_fn(&sig.decl)
+            ReplaceBodyWithLoop::should_ignore_fn(&sig.decl.output)
     }
 }
 
@@ -776,22 +776,17 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
         self.run(is_const, |s| noop_visit_item_kind(i, s))
     }
 
-    fn flat_map_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+    fn flat_map_trait_item(&mut self, i: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         let is_const = match i.kind {
-            ast::TraitItemKind::Const(..) => true,
-            ast::TraitItemKind::Method(ref sig, _) => Self::is_sig_const(sig),
+            ast::AssocItemKind::Const(..) => true,
+            ast::AssocItemKind::Fn(ref sig, _) => Self::is_sig_const(sig),
             _ => false,
         };
-        self.run(is_const, |s| noop_flat_map_trait_item(i, s))
+        self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
     }
 
-    fn flat_map_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
-        let is_const = match i.kind {
-            ast::ImplItemKind::Const(..) => true,
-            ast::ImplItemKind::Method(ref sig, _) => Self::is_sig_const(sig),
-            _ => false,
-        };
-        self.run(is_const, |s| noop_flat_map_impl_item(i, s))
+    fn flat_map_impl_item(&mut self, i: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
+        self.flat_map_trait_item(i)
     }
 
     fn visit_anon_const(&mut self, c: &mut ast::AnonConst) {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 10b00d35d9bca..1fc89961889f1 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -268,8 +268,8 @@ impl EarlyLintPass for UnsafeCode {
         }
     }
 
-    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::TraitItem) {
-        if let ast::TraitItemKind::Method(ref sig, None) = item.kind {
+    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) {
+        if let ast::AssocItemKind::Fn(ref sig, None) = item.kind {
             if sig.header.unsafety == ast::Unsafety::Unsafe {
                 self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
             }
@@ -615,9 +615,9 @@ declare_lint_pass!(
 );
 
 impl EarlyLintPass for AnonymousParameters {
-    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::TraitItem) {
+    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
         match it.kind {
-            ast::TraitItemKind::Method(ref sig, _) => {
+            ast::AssocItemKind::Fn(ref sig, _) => {
                 for arg in sig.decl.inputs.iter() {
                     match arg.pat.kind {
                         ast::PatKind::Ident(_, ident, None) => {
diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs
index 1e9203f377f38..38ae7050abe48 100644
--- a/src/librustc_parse/config.rs
+++ b/src/librustc_parse/config.rs
@@ -344,12 +344,12 @@ impl<'a> MutVisitor for StripUnconfigured<'a> {
         noop_flat_map_item(configure!(self, item), self)
     }
 
-    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
-        noop_flat_map_impl_item(configure!(self, item), self)
+    fn flat_map_impl_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
+        noop_flat_map_assoc_item(configure!(self, item), self)
     }
 
-    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
-        noop_flat_map_trait_item(configure!(self, item), self)
+    fn flat_map_trait_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
+        noop_flat_map_assoc_item(configure!(self, item), self)
     }
 
     fn visit_mac(&mut self, _mac: &mut ast::Mac) {
diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs
index faff386e92318..58c3652438057 100644
--- a/src/librustc_parse/lib.rs
+++ b/src/librustc_parse/lib.rs
@@ -305,10 +305,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
         Nonterminal::NtItem(ref item) => {
             prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
         }
-        Nonterminal::NtTraitItem(ref item) => {
-            prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
-        }
-        Nonterminal::NtImplItem(ref item) => {
+        Nonterminal::NtTraitItem(ref item) | Nonterminal::NtImplItem(ref item) => {
             prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
         }
         Nonterminal::NtIdent(ident, is_raw) => {
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 3cd4988ce0be5..e4dff07e92cb8 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -1381,7 +1381,7 @@ impl<'a> Parser<'a> {
                 args
             }
         };
-        let output = self.parse_ret_ty(true)?;
+        let output = self.parse_ret_ty(true, true)?;
 
         Ok(P(FnDecl {
             inputs: inputs_captures,
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 34ef12e818c57..0840a1551dbf4 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -6,7 +6,7 @@ use crate::maybe_whole;
 use rustc_errors::{PResult, Applicability, DiagnosticBuilder, StashKey};
 use rustc_error_codes::*;
 use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
-use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
+use syntax::ast::{AssocItem, AssocItemKind, ItemKind, UseTree, UseTreeKind};
 use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
 use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
 use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, Variant, VariantData, StructField};
@@ -648,7 +648,7 @@ impl<'a> Parser<'a> {
         Ok((Ident::invalid(), item_kind, Some(attrs)))
     }
 
-    fn parse_impl_body(&mut self) -> PResult<'a, (Vec<ImplItem>, Vec<Attribute>)> {
+    fn parse_impl_body(&mut self) -> PResult<'a, (Vec<AssocItem>, Vec<Attribute>)> {
         self.expect(&token::OpenDelim(token::Brace))?;
         let attrs = self.parse_inner_attributes()?;
 
@@ -669,60 +669,6 @@ impl<'a> Parser<'a> {
         Ok((impl_items, attrs))
     }
 
-    /// Parses an impl item.
-    pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> {
-        maybe_whole!(self, NtImplItem, |x| x);
-        let attrs = self.parse_outer_attributes()?;
-        let mut unclosed_delims = vec![];
-        let (mut item, tokens) = self.collect_tokens(|this| {
-            let item = this.parse_impl_item_(at_end, attrs);
-            unclosed_delims.append(&mut this.unclosed_delims);
-            item
-        })?;
-        self.unclosed_delims.append(&mut unclosed_delims);
-
-        // See `parse_item` for why this clause is here.
-        if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
-            item.tokens = Some(tokens);
-        }
-        Ok(item)
-    }
-
-    fn parse_impl_item_(
-        &mut self,
-        at_end: &mut bool,
-        mut attrs: Vec<Attribute>,
-    ) -> PResult<'a, ImplItem> {
-        let lo = self.token.span;
-        let vis = self.parse_visibility(FollowedByType::No)?;
-        let defaultness = self.parse_defaultness();
-        let (name, kind, generics) = if self.eat_keyword(kw::Type) {
-            let (name, ty, generics) = self.parse_type_alias()?;
-            (name, ast::ImplItemKind::TyAlias(ty), generics)
-        } else if self.is_const_item() {
-            self.parse_impl_const()?
-        } else if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(&vis), at_end)? {
-            // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
-            (Ident::invalid(), ast::ImplItemKind::Macro(mac), Generics::default())
-        } else {
-            let (name, inner_attrs, generics, kind) = self.parse_impl_method(at_end)?;
-            attrs.extend(inner_attrs);
-            (name, kind, generics)
-        };
-
-        Ok(ImplItem {
-            id: DUMMY_NODE_ID,
-            span: lo.to(self.prev_span),
-            ident: name,
-            vis,
-            defaultness,
-            attrs,
-            generics,
-            kind,
-            tokens: None,
-        })
-    }
-
     /// Parses defaultness (i.e., `default` or nothing).
     fn parse_defaultness(&mut self) -> Defaultness {
         // `pub` is included for better error messages
@@ -745,26 +691,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Returns `true` if we are looking at `const ID`
-    /// (returns `false` for things like `const fn`, etc.).
-    fn is_const_item(&self) -> bool {
-        self.token.is_keyword(kw::Const) &&
-            !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe])
-    }
-
-    /// This parses the grammar:
-    ///     ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
-    fn parse_impl_const(&mut self) -> PResult<'a, (Ident, ImplItemKind, Generics)> {
-        self.expect_keyword(kw::Const)?;
-        let name = self.parse_ident()?;
-        self.expect(&token::Colon)?;
-        let typ = self.parse_ty()?;
-        self.expect(&token::Eq)?;
-        let expr = self.parse_expr()?;
-        self.expect_semi()?;
-        Ok((name, ImplItemKind::Const(typ, expr), Generics::default()))
-    }
-
     /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
     fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
         // Parse optional `auto` prefix.
@@ -857,13 +783,30 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parses the items in a trait declaration.
-    pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> {
+    pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, AssocItem> {
+        maybe_whole!(self, NtImplItem, |x| x);
+        self.parse_assoc_item(at_end, |_| true)
+    }
+
+    pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, AssocItem> {
         maybe_whole!(self, NtTraitItem, |x| x);
+        // This is somewhat dubious; We don't want to allow
+        // param names to be left off if there is a definition...
+        //
+        // We don't allow param names to be left off in edition 2018.
+        self.parse_assoc_item(at_end, |t| t.span.rust_2018())
+    }
+
+    /// Parses associated items.
+    fn parse_assoc_item(
+        &mut self,
+        at_end: &mut bool,
+        is_name_required: fn(&token::Token) -> bool,
+    ) -> PResult<'a, AssocItem> {
         let attrs = self.parse_outer_attributes()?;
         let mut unclosed_delims = vec![];
         let (mut item, tokens) = self.collect_tokens(|this| {
-            let item = this.parse_trait_item_(at_end, attrs);
+            let item = this.parse_assoc_item_(at_end, attrs, is_name_required);
             unclosed_delims.append(&mut this.unclosed_delims);
             item
         })?;
@@ -875,54 +818,66 @@ impl<'a> Parser<'a> {
         Ok(item)
     }
 
-    fn parse_trait_item_(
+    fn parse_assoc_item_(
         &mut self,
         at_end: &mut bool,
         mut attrs: Vec<Attribute>,
-    ) -> PResult<'a, TraitItem> {
+        is_name_required: fn(&token::Token) -> bool,
+    ) -> PResult<'a, AssocItem> {
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
+        let defaultness = self.parse_defaultness();
         let (name, kind, generics) = if self.eat_keyword(kw::Type) {
-            self.parse_trait_item_assoc_ty()?
+            self.parse_assoc_ty()?
         } else if self.is_const_item() {
-            self.parse_trait_item_const()?
-        } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? {
-            // trait item macro.
-            (Ident::invalid(), TraitItemKind::Macro(mac), Generics::default())
+            self.parse_assoc_const()?
+        } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? {
+            (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default())
         } else {
-            self.parse_trait_item_method(at_end, &mut attrs)?
+            self.parse_assoc_fn(at_end, &mut attrs, is_name_required)?
         };
 
-        Ok(TraitItem {
+        Ok(AssocItem {
             id: DUMMY_NODE_ID,
+            span: lo.to(self.prev_span),
             ident: name,
             attrs,
             vis,
+            defaultness,
             generics,
             kind,
-            span: lo.to(self.prev_span),
             tokens: None,
         })
     }
 
-    fn parse_trait_item_const(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
+    /// Returns `true` if we are looking at `const ID`
+    /// (returns `false` for things like `const fn`, etc.).
+    fn is_const_item(&self) -> bool {
+        self.token.is_keyword(kw::Const) &&
+            !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe])
+    }
+
+    /// This parses the grammar:
+    ///
+    ///     AssocConst = "const" Ident ":" Ty "=" Expr ";"
+    fn parse_assoc_const(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
         self.expect_keyword(kw::Const)?;
         let ident = self.parse_ident()?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
-        let default = if self.eat(&token::Eq) {
+        let expr = if self.eat(&token::Eq) {
             Some(self.parse_expr()?)
         } else {
             None
         };
         self.expect_semi()?;
-        Ok((ident, TraitItemKind::Const(ty, default), Generics::default()))
+        Ok((ident, AssocItemKind::Const(ty, expr), Generics::default()))
     }
 
     /// Parses the following grammar:
     ///
-    ///     TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
-    fn parse_trait_item_assoc_ty(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
+    ///     AssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
+    fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
         let ident = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
 
@@ -941,7 +896,7 @@ impl<'a> Parser<'a> {
         };
         self.expect_semi()?;
 
-        Ok((ident, TraitItemKind::Type(bounds, default), generics))
+        Ok((ident, AssocItemKind::TyAlias(bounds, default), generics))
     }
 
     /// Parses a `UseTree`.
@@ -1772,8 +1727,6 @@ impl<'a> Parser<'a> {
 pub(super) struct ParamCfg {
     /// Is `self` is allowed as the first parameter?
     pub is_self_allowed: bool,
-    /// Is `...` allowed as the tail of the parameter list?
-    pub allow_c_variadic: 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,
@@ -1789,16 +1742,8 @@ impl<'a> Parser<'a> {
         attrs: Vec<Attribute>,
         header: FnHeader,
     ) -> PResult<'a, Option<P<Item>>> {
-        let is_c_abi = match header.ext {
-            ast::Extern::None => false,
-            ast::Extern::Implicit => true,
-            ast::Extern::Explicit(abi) => abi.symbol_unescaped == sym::C,
-        };
         let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
             is_self_allowed: false,
-            // FIXME: Parsing should not depend on ABI or unsafety and
-            // the variadic parameter should always be parsed.
-            allow_c_variadic: is_c_abi && header.unsafety == Unsafety::Unsafe,
             is_name_required: |_| true,
         })?;
         let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -1817,7 +1762,6 @@ impl<'a> Parser<'a> {
         self.expect_keyword(kw::Fn)?;
         let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
             is_self_allowed: false,
-            allow_c_variadic: true,
             is_name_required: |_| true,
         })?;
         let span = lo.to(self.token.span);
@@ -1833,48 +1777,39 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Parses a method or a macro invocation in a trait impl.
-    fn parse_impl_method(
-        &mut self,
-        at_end: &mut bool,
-    ) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ImplItemKind)> {
-        let (ident, sig, generics) = self.parse_method_sig(|_| true)?;
-        *at_end = true;
-        let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-        Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body)))
-    }
-
-    fn parse_trait_item_method(
+    fn parse_assoc_fn(
         &mut self,
         at_end: &mut bool,
         attrs: &mut Vec<Attribute>,
-    ) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
-        // This is somewhat dubious; We don't want to allow
-        // argument names to be left off if there is a definition...
-        //
-        // We don't allow argument names to be left off in edition 2018.
-        let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
-        let body = self.parse_trait_method_body(at_end, attrs)?;
-        Ok((ident, TraitItemKind::Method(sig, body), generics))
+        is_name_required: fn(&token::Token) -> bool,
+    ) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
+        let header = self.parse_fn_front_matter()?;
+        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+            is_self_allowed: true,
+            is_name_required,
+        })?;
+        let sig = FnSig { header, decl };
+        let body = self.parse_assoc_fn_body(at_end, attrs)?;
+        Ok((ident, AssocItemKind::Fn(sig, body), generics))
     }
 
-    /// Parse the "body" of a method in a trait item definition.
+    /// Parse the "body" of a method in an associated item definition.
     /// This can either be `;` when there's no body,
     /// or e.g. a block when the method is a provided one.
-    fn parse_trait_method_body(
+    fn parse_assoc_fn_body(
         &mut self,
         at_end: &mut bool,
         attrs: &mut Vec<Attribute>,
     ) -> PResult<'a, Option<P<Block>>> {
         Ok(match self.token.kind {
             token::Semi => {
-                debug!("parse_trait_method_body(): parsing required method");
+                debug!("parse_assoc_fn_body(): parsing required method");
                 self.bump();
                 *at_end = true;
                 None
             }
             token::OpenDelim(token::Brace) => {
-                debug!("parse_trait_method_body(): parsing provided method");
+                debug!("parse_assoc_fn_body(): parsing provided method");
                 *at_end = true;
                 let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
                 attrs.extend(inner_attrs.iter().cloned());
@@ -1895,21 +1830,6 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Parse the "signature", including the identifier, parameters, and generics
-    /// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
-    fn parse_method_sig(
-        &mut self,
-        is_name_required: fn(&token::Token) -> bool,
-    ) -> PResult<'a, (Ident, FnSig, Generics)> {
-        let header = self.parse_fn_front_matter()?;
-        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
-            is_self_allowed: true,
-            allow_c_variadic: false,
-            is_name_required,
-        })?;
-        Ok((ident, FnSig { header, decl }, generics))
-    }
-
     /// Parses all the "front matter" for a `fn` declaration, up to
     /// and including the `fn` keyword:
     ///
@@ -1959,64 +1879,29 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, P<FnDecl>> {
         Ok(P(FnDecl {
             inputs: self.parse_fn_params(cfg)?,
-            output: self.parse_ret_ty(ret_allow_plus)?,
+            output: self.parse_ret_ty(ret_allow_plus, true)?,
         }))
     }
 
     /// 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 sp = self.token.span;
         let is_trait_item = cfg.is_self_allowed;
-        let mut c_variadic = false;
         // Parse the arguments, starting out with `self` being possibly allowed...
-        let (params, _) = self.parse_paren_comma_seq(|p| {
-            let param = p.parse_param_general(&cfg, is_trait_item);
+        let (mut params, _) = self.parse_paren_comma_seq(|p| {
+            let param = p.parse_param_general(&cfg, is_trait_item).or_else(|mut e| {
+                e.emit();
+                let lo = p.prev_span;
+                // Skip every token until next possible arg or end.
+                p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
+                // Create a placeholder argument for proper arg count (issue #34264).
+                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;
-
-            match param {
-                Ok(param) => Ok(
-                    if let TyKind::CVarArgs = param.ty.kind {
-                        c_variadic = true;
-                        if p.token != token::CloseDelim(token::Paren) {
-                            p.span_err(
-                                p.token.span,
-                                "`...` must be the last argument of a C-variadic function",
-                            );
-                            // FIXME(eddyb) this should probably still push `CVarArgs`.
-                            // Maybe AST validation/HIR lowering should emit the above error?
-                            None
-                        } else {
-                            Some(param)
-                        }
-                    } else {
-                        Some(param)
-                    }
-                ),
-                Err(mut e) => {
-                    e.emit();
-                    let lo = p.prev_span;
-                    // Skip every token until next possible arg or end.
-                    p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
-                    // Create a placeholder argument for proper arg count (issue #34264).
-                    let span = lo.to(p.prev_span);
-                    Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
-                }
-            }
+            param
         })?;
-
-        let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
-
         // Replace duplicated recovered params with `_` pattern to avoid unnecessary errors.
         self.deduplicate_recovered_params_names(&mut params);
-
-        if c_variadic && params.len() <= 1 {
-            self.span_err(
-                sp,
-                "C-variadic function must be declared with at least one named argument",
-            );
-        }
-
         Ok(params)
     }
 
@@ -2061,12 +1946,12 @@ impl<'a> Parser<'a> {
             }
 
             self.eat_incorrect_doc_comment_for_param_type();
-            (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
+            (pat, self.parse_ty_for_param()?)
         } else {
             debug!("parse_param_general ident_to_pat");
             let parser_snapshot_before_ty = self.clone();
             self.eat_incorrect_doc_comment_for_param_type();
-            let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
+            let mut ty = self.parse_ty_for_param();
             if ty.is_ok() && self.token != token::Comma &&
                self.token != token::CloseDelim(token::Paren) {
                 // This wasn't actually a type, but a pattern looking like a type,
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index 5334fc485e7a6..aeba6dd2f67c5 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -182,11 +182,7 @@ impl<'a> Parser<'a> {
                 // `(T, U) -> R`
                 let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
                 let span = ident.span.to(self.prev_span);
-                let output = if self.eat(&token::RArrow) {
-                    Some(self.parse_ty_common(false, false, false)?)
-                } else {
-                    None
-                };
+                let output = self.parse_ret_ty(false, false)?;
                 ParenthesizedArgs { inputs, output, span }.into()
             };
 
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index 84ffef68e9a66..6f7ab0542d5fa 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -10,7 +10,7 @@ use syntax::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam
 use syntax::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
 use syntax::ast::{Mutability, AnonConst, Mac};
 use syntax::token::{self, Token};
-use syntax::struct_span_fatal;
+use syntax::struct_span_err;
 use syntax_pos::source_map::Span;
 use syntax_pos::symbol::kw;
 
@@ -30,6 +30,13 @@ impl<'a> Parser<'a> {
         self.parse_ty_common(true, true, false)
     }
 
+    /// Parse a type suitable for a function or function pointer parameter.
+    /// The difference from `parse_ty` is that this version allows `...`
+    /// (`CVarArgs`) at the top level of the the type.
+    pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
+        self.parse_ty_common(true, true, true)
+    }
+
     /// Parses a type in restricted contexts where `+` is not permitted.
     ///
     /// Example 1: `&'a TYPE`
@@ -41,16 +48,26 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an optional return type `[ -> TY ]` in a function declaration.
-    pub(super) fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> {
-        if self.eat(&token::RArrow) {
-            Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true, false)?))
+    pub(super) fn parse_ret_ty(
+        &mut self,
+        allow_plus: bool,
+        allow_qpath_recovery: bool,
+    ) -> PResult<'a, FunctionRetTy> {
+        Ok(if self.eat(&token::RArrow) {
+            // FIXME(Centril): Can we unconditionally `allow_plus`?
+            FunctionRetTy::Ty(self.parse_ty_common(allow_plus, allow_qpath_recovery, false)?)
         } else {
-            Ok(FunctionRetTy::Default(self.token.span.shrink_to_lo()))
-        }
+            FunctionRetTy::Default(self.token.span.shrink_to_lo())
+        })
     }
 
-    pub(super) fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool,
-                       allow_c_variadic: bool) -> PResult<'a, P<Ty>> {
+    fn parse_ty_common(
+        &mut self,
+        allow_plus: bool,
+        allow_qpath_recovery: bool,
+        // Is `...` (`CVarArgs`) legal in the immediate top level call?
+        allow_c_variadic: bool,
+    ) -> PResult<'a, P<Ty>> {
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
         maybe_whole!(self, NtTy, |x| x);
 
@@ -192,17 +209,21 @@ impl<'a> Parser<'a> {
                     TyKind::Path(None, path)
                 }
             }
-        } else if self.check(&token::DotDotDot) {
+        } else if self.eat(&token::DotDotDot) {
             if allow_c_variadic {
-                self.eat(&token::DotDotDot);
                 TyKind::CVarArgs
             } else {
-                return Err(struct_span_fatal!(
+                // FIXME(Centril): Should we just allow `...` syntactically
+                // anywhere in a type and use semantic restrictions instead?
+                struct_span_err!(
                     self.sess.span_diagnostic,
-                    self.token.span,
+                    lo.to(self.prev_span),
                     E0743,
-                    "only foreign functions are allowed to be C-variadic",
-                ));
+                    "C-variadic type `...` may not be nested inside another type",
+                )
+                .emit();
+
+                TyKind::Err
             }
         } else {
             let msg = format!("expected type, found {}", self.this_token_descr());
@@ -287,7 +308,6 @@ impl<'a> Parser<'a> {
         self.expect_keyword(kw::Fn)?;
         let cfg = ParamCfg {
             is_self_allowed: false,
-            allow_c_variadic: true,
             is_name_required: |_| false,
         };
         let decl = self.parse_fn_decl(cfg, false)?;
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 202b6ae2f94c4..e90231f984b1f 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -250,6 +250,26 @@ impl<'a> AstValidator<'a> {
     }
 
     fn check_fn_decl(&self, fn_decl: &FnDecl) {
+        match &*fn_decl.inputs {
+            [Param { ty, span, .. }] => if let TyKind::CVarArgs = ty.kind {
+                self.err_handler()
+                    .span_err(
+                        *span,
+                        "C-variadic function must be declared with at least one named argument",
+                    );
+            },
+            [ps @ .., _] => for Param { ty, span, .. } in ps {
+                if let TyKind::CVarArgs = ty.kind {
+                    self.err_handler()
+                        .span_err(
+                            *span,
+                            "`...` must be the last argument of a C-variadic function",
+                        );
+                }
+            }
+            _ => {}
+        }
+
         fn_decl
             .inputs
             .iter()
@@ -259,18 +279,65 @@ impl<'a> AstValidator<'a> {
                 !arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr)
             })
             .for_each(|attr| if attr.is_doc_comment() {
-                let mut err = self.err_handler().struct_span_err(
+                self.err_handler().struct_span_err(
                     attr.span,
                     "documentation comments cannot be applied to function parameters"
-                );
-                err.span_label(attr.span, "doc comments are not allowed here");
-                err.emit();
-            }
-            else {
+                )
+                .span_label(attr.span, "doc comments are not allowed here")
+                .emit();
+            } else {
                 self.err_handler().span_err(attr.span, "allow, cfg, cfg_attr, deny, \
                 forbid, and warn are the only allowed built-in attributes in function parameters")
             });
     }
+
+    fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
+        if let Defaultness::Default = defaultness {
+            self.err_handler()
+                .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
+                .emit();
+        }
+    }
+
+    fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
+        if body.is_some() {
+            return;
+        }
+
+        self.err_handler()
+            .struct_span_err(sp, &format!("associated {} in `impl` without body", ctx))
+            .span_suggestion(
+                self.session.source_map().end_point(sp),
+                &format!("provide a definition for the {}", ctx),
+                sugg.to_string(),
+                Applicability::HasPlaceholders,
+            )
+            .emit();
+    }
+
+    fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
+        let span = match bounds {
+            [] => return,
+            [b0] => b0.span(),
+            [b0, .., bl] => b0.span().to(bl.span()),
+        };
+        self.err_handler()
+            .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
+            .emit();
+    }
+
+    fn check_c_varadic_type(&self, decl: &FnDecl) {
+        for Param { ty, span, .. } in &decl.inputs {
+            if let TyKind::CVarArgs = ty.kind {
+                self.err_handler()
+                    .struct_span_err(
+                        *span,
+                        "only foreign or `unsafe extern \"C\" functions may be C-variadic",
+                    )
+                    .emit();
+            }
+        }
+    }
 }
 
 enum GenericPosition {
@@ -477,7 +544,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 for impl_item in impl_items {
                     self.invalid_visibility(&impl_item.vis, None);
-                    if let ImplItemKind::Method(ref sig, _) = impl_item.kind {
+                    if let AssocItemKind::Fn(ref sig, _) = impl_item.kind {
                         self.check_trait_fn_not_const(sig.header.constness);
                         self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
                     }
@@ -519,6 +586,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         }
                     }
                 }
+                // Reject C-varadic type unless the function is `unsafe extern "C"` semantically.
+                match sig.header.ext {
+                    Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) |
+                    Extern::Implicit if sig.header.unsafety == Unsafety::Unsafe => {}
+                    _ => self.check_c_varadic_type(&sig.decl),
+                }
             }
             ItemKind::ForeignMod(..) => {
                 self.invalid_visibility(
@@ -554,26 +627,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     }
                 }
                 self.no_questions_in_bounds(bounds, "supertraits", true);
-                for trait_item in trait_items {
-                    if let TraitItemKind::Method(ref sig, ref block) = trait_item.kind {
-                        self.check_fn_decl(&sig.decl);
-                        self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node);
-                        self.check_trait_fn_not_const(sig.header.constness);
-                        if block.is_none() {
-                            Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
-                                if mut_ident {
-                                    self.lint_buffer.buffer_lint(
-                                        lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
-                                        trait_item.id, span,
-                                        "patterns aren't allowed in methods without bodies");
-                                } else {
-                                    struct_span_err!(self.session, span, E0642,
-                                        "patterns aren't allowed in methods without bodies").emit();
-                                }
-                            });
-                        }
-                    }
-                }
             }
             ItemKind::Mod(_) => {
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
@@ -639,10 +692,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             GenericArgs::Parenthesized(ref data) => {
                 walk_list!(self, visit_ty, &data.inputs);
-                if let Some(ref type_) = data.output {
+                if let FunctionRetTy::Ty(ty) = &data.output {
                     // `-> Foo` syntax is essentially an associated type binding,
                     // so it is also allowed to contain nested `impl Trait`.
-                    self.with_impl_trait(None, |this| this.visit_ty(type_));
+                    self.with_impl_trait(None, |this| this.visit_ty(ty));
                 }
             }
         }
@@ -737,17 +790,59 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             |this| visit::walk_enum_def(this, enum_definition, generics, item_id))
     }
 
-    fn visit_impl_item(&mut self, ii: &'a ImplItem) {
-        if let ImplItemKind::Method(ref sig, _) = ii.kind {
-            self.check_fn_decl(&sig.decl);
+    fn visit_impl_item(&mut self, ii: &'a AssocItem) {
+        match &ii.kind {
+            AssocItemKind::Const(_, body) => {
+                self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;");
+            }
+            AssocItemKind::Fn(sig, 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>;");
+                self.check_impl_assoc_type_no_bounds(bounds);
+            }
+            _ => {}
         }
         visit::walk_impl_item(self, ii);
     }
 
-    fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'a AssocItem) {
         self.invalid_visibility(&ti.vis, None);
+        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() {
+                Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
+                    if mut_ident {
+                        self.lint_buffer.buffer_lint(
+                            lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
+                            ti.id, span,
+                            "patterns aren't allowed in methods without bodies"
+                        );
+                    } else {
+                        struct_span_err!(
+                            self.session, span, E0642,
+                            "patterns aren't allowed in methods without bodies"
+                        ).emit();
+                    }
+                });
+            }
+        }
+
         visit::walk_trait_item(self, ti);
     }
+
+    fn visit_assoc_item(&mut self, item: &'a AssocItem) {
+        if let AssocItemKind::Fn(sig, _) = &item.kind {
+            self.check_c_varadic_type(&sig.decl);
+        }
+        visit::walk_assoc_item(self, item);
+    }
 }
 
 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool {
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index a5924efefc2af..66ceb4212c8ac 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -314,12 +314,12 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_fn(self, fk, fd, s)
     }
 
-    fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'v ast::AssocItem) {
         self.record("TraitItem", Id::None, ti);
         ast_visit::walk_trait_item(self, ti)
     }
 
-    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+    fn visit_impl_item(&mut self, ii: &'v ast::AssocItem) {
         self.record("ImplItem", Id::None, ii);
         ast_visit::walk_impl_item(self, ii)
     }
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 81f06a14d95f5..f01867f32c67b 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -8,6 +8,7 @@
 
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
+#![feature(slice_patterns)]
 
 #![recursion_limit="256"]
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index e2578d67e730c..e94e0dc695cd6 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -30,7 +30,7 @@ use errors::Applicability;
 use syntax::ast::{Name, Ident};
 use syntax::attr;
 use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
-use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
+use syntax::ast::{MetaItemKind, StmtKind, AssocItem, AssocItemKind};
 use syntax::token::{self, Token};
 use syntax::span_err;
 use syntax::source_map::{respan, Spanned};
@@ -1164,10 +1164,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         self.parent_scope.legacy = orig_current_legacy_scope;
     }
 
-    fn visit_trait_item(&mut self, item: &'b TraitItem) {
+    fn visit_trait_item(&mut self, item: &'b AssocItem) {
         let parent = self.parent_scope.module;
 
-        if let TraitItemKind::Macro(_) = item.kind {
+        if let AssocItemKind::Macro(_) = item.kind {
             self.visit_invoc(item.id);
             return
         }
@@ -1175,15 +1175,15 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         // Add the item to the trait info.
         let item_def_id = self.r.definitions.local_def_id(item.id);
         let (res, ns) = match item.kind {
-            TraitItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
-            TraitItemKind::Method(ref sig, _) => {
+            AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
+            AssocItemKind::Fn(ref sig, _) => {
                 if sig.decl.has_self() {
                     self.r.has_self.insert(item_def_id);
                 }
                 (Res::Def(DefKind::Method, item_def_id), ValueNS)
             }
-            TraitItemKind::Type(..) => (Res::Def(DefKind::AssocTy, item_def_id), TypeNS),
-            TraitItemKind::Macro(_) => bug!(),  // handled above
+            AssocItemKind::TyAlias(..) => (Res::Def(DefKind::AssocTy, item_def_id), TypeNS),
+            AssocItemKind::Macro(_) => bug!(),  // handled above
         };
 
         let vis = ty::Visibility::Public;
@@ -1193,8 +1193,8 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         visit::walk_trait_item(self, item);
     }
 
-    fn visit_impl_item(&mut self, item: &'b ast::ImplItem) {
-        if let ast::ImplItemKind::Macro(..) = item.kind {
+    fn visit_impl_item(&mut self, item: &'b ast::AssocItem) {
+        if let ast::AssocItemKind::Macro(..) = item.kind {
             self.visit_invoc(item.id);
         } else {
             self.resolve_visibility(&item.vis);
diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs
index dd6b1d2119e3d..9bae339f80ea4 100644
--- a/src/librustc_resolve/def_collector.rs
+++ b/src/librustc_resolve/def_collector.rs
@@ -50,7 +50,7 @@ impl<'a> DefCollector<'a> {
         header: &FnHeader,
         generics: &'a Generics,
         decl: &'a FnDecl,
-        body: &'a Block,
+        body: Option<&'a Block>,
     ) {
         let (closure_id, return_impl_trait_id) = match header.asyncness.node {
             IsAsync::Async {
@@ -74,7 +74,9 @@ impl<'a> DefCollector<'a> {
                 closure_id, DefPathData::ClosureExpr, span,
             );
             this.with_parent(closure_def, |this| {
-                visit::walk_block(this, body);
+                if let Some(body) = body {
+                    visit::walk_block(this, body);
+                }
             })
         })
     }
@@ -123,7 +125,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
                     &sig.header,
                     generics,
                     &sig.decl,
-                    body,
+                    Some(body),
                 )
             }
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
@@ -210,23 +212,20 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         visit::walk_generic_param(self, param);
     }
 
-    fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'a AssocItem) {
         let def_data = match ti.kind {
-            TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
-                DefPathData::ValueNs(ti.ident.name),
-            TraitItemKind::Type(..) => {
-                DefPathData::TypeNs(ti.ident.name)
-            },
-            TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
+            AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ti.ident.name),
+            AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ti.ident.name),
+            AssocItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
         };
 
         let def = self.create_def(ti.id, def_data, ti.span);
         self.with_parent(def, |this| visit::walk_trait_item(this, ti));
     }
 
-    fn visit_impl_item(&mut self, ii: &'a ImplItem) {
+    fn visit_impl_item(&mut self, ii: &'a AssocItem) {
         let def_data = match ii.kind {
-            ImplItemKind::Method(FnSig {
+            AssocItemKind::Fn(FnSig {
                 ref header,
                 ref decl,
             }, ref body) if header.asyncness.node.is_async() => {
@@ -237,13 +236,13 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
                     header,
                     &ii.generics,
                     decl,
-                    body,
+                    body.as_deref(),
                 )
             }
-            ImplItemKind::Method(..) |
-            ImplItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name),
-            ImplItemKind::TyAlias(..) => DefPathData::TypeNs(ii.ident.name),
-            ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
+            AssocItemKind::Fn(..) |
+            AssocItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name),
+            AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ii.ident.name),
+            AssocItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
         };
 
         let def = self.create_def(ii.id, def_data, ii.span);
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 4f95d6fe70f17..4321f62e03bc8 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -806,7 +806,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                 this.with_generic_param_rib(&trait_item.generics, AssocItemRibKind,
                                     |this| {
                                         match trait_item.kind {
-                                            TraitItemKind::Const(ref ty, ref default) => {
+                                            AssocItemKind::Const(ref ty, ref default) => {
                                                 this.visit_ty(ty);
 
                                                 // Only impose the restrictions of
@@ -818,13 +818,13 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                                     });
                                                 }
                                             }
-                                            TraitItemKind::Method(_, _) => {
+                                            AssocItemKind::Fn(_, _) => {
                                                 visit::walk_trait_item(this, trait_item)
                                             }
-                                            TraitItemKind::Type(..) => {
+                                            AssocItemKind::TyAlias(..) => {
                                                 visit::walk_trait_item(this, trait_item)
                                             }
-                                            TraitItemKind::Macro(_) => {
+                                            AssocItemKind::Macro(_) => {
                                                 panic!("unexpanded macro in resolve!")
                                             }
                                         };
@@ -989,13 +989,13 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
     /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
     fn with_trait_items<T>(
         &mut self,
-        trait_items: &Vec<TraitItem>,
+        trait_items: &Vec<AssocItem>,
         f: impl FnOnce(&mut Self) -> T,
     ) -> T {
         let trait_assoc_types = replace(
             &mut self.diagnostic_metadata.current_trait_assoc_types,
             trait_items.iter().filter_map(|item| match &item.kind {
-                TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
+                AssocItemKind::TyAlias(bounds, _) if bounds.len() == 0 => Some(item.ident),
                 _ => None,
             }).collect(),
         );
@@ -1063,7 +1063,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                               opt_trait_reference: &Option<TraitRef>,
                               self_type: &Ty,
                               item_id: NodeId,
-                              impl_items: &[ImplItem]) {
+                              impl_items: &[AssocItem]) {
         debug!("resolve_implementation");
         // If applicable, create a rib for the type parameters.
         self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
@@ -1092,9 +1092,9 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                                                 |this| {
                                         use crate::ResolutionError::*;
                                         match impl_item.kind {
-                                            ImplItemKind::Const(..) => {
+                                            AssocItemKind::Const(..) => {
                                                 debug!(
-                                                    "resolve_implementation ImplItemKind::Const",
+                                                    "resolve_implementation AssocItemKind::Const",
                                                 );
                                                 // If this is a trait impl, ensure the const
                                                 // exists in trait
@@ -1109,7 +1109,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                                     visit::walk_impl_item(this, impl_item)
                                                 });
                                             }
-                                            ImplItemKind::Method(..) => {
+                                            AssocItemKind::Fn(..) => {
                                                 // If this is a trait impl, ensure the method
                                                 // exists in trait
                                                 this.check_trait_item(impl_item.ident,
@@ -1119,7 +1119,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
 
                                                 visit::walk_impl_item(this, impl_item);
                                             }
-                                            ImplItemKind::TyAlias(ref ty) => {
+                                            AssocItemKind::TyAlias(_, Some(ref ty)) => {
                                                 // If this is a trait impl, ensure the type
                                                 // exists in trait
                                                 this.check_trait_item(impl_item.ident,
@@ -1129,7 +1129,8 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
 
                                                 this.visit_ty(ty);
                                             }
-                                            ImplItemKind::Macro(_) =>
+                                            AssocItemKind::TyAlias(_, None) => {}
+                                            AssocItemKind::Macro(_) =>
                                                 panic!("unexpanded macro in resolve!"),
                                         }
                                     });
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 396d948433961..df6ad51d1045b 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -676,7 +676,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         generics: &'l ast::Generics,
         trait_ref: &'l Option<ast::TraitRef>,
         typ: &'l ast::Ty,
-        impl_items: &'l [ast::ImplItem],
+        impl_items: &'l [ast::AssocItem],
     ) {
         if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
             if !self.span.filter_generated(item.span) {
@@ -707,7 +707,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         item: &'l ast::Item,
         generics: &'l ast::Generics,
         trait_refs: &'l ast::GenericBounds,
-        methods: &'l [ast::TraitItem],
+        methods: &'l [ast::AssocItem],
     ) {
         let name = item.ident.to_string();
         let qualname = format!("::{}",
@@ -811,9 +811,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 match **generic_args {
                     ast::GenericArgs::AngleBracketed(ref data) => {
                         for arg in &data.args {
-                            match arg {
-                                ast::GenericArg::Type(ty) => self.visit_ty(ty),
-                                _ => {}
+                            if let ast::GenericArg::Type(ty) = arg {
+                                self.visit_ty(ty);
                             }
                         }
                     }
@@ -821,8 +820,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                         for t in &data.inputs {
                             self.visit_ty(t);
                         }
-                        if let Some(ref t) = data.output {
-                            self.visit_ty(t);
+                        if let ast::FunctionRetTy::Ty(ty) = &data.output {
+                            self.visit_ty(ty);
                         }
                     }
                 }
@@ -1030,11 +1029,11 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         // }
     }
 
-    fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) {
+    fn process_trait_item(&mut self, trait_item: &'l ast::AssocItem, trait_id: DefId) {
         self.process_macro_use(trait_item.span);
         let vis_span = trait_item.span.shrink_to_lo();
         match trait_item.kind {
-            ast::TraitItemKind::Const(ref ty, ref expr) => {
+            ast::AssocItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(
                     trait_item.id,
                     trait_item.ident,
@@ -1045,7 +1044,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     &trait_item.attrs,
                 );
             }
-            ast::TraitItemKind::Method(ref sig, ref body) => {
+            ast::AssocItemKind::Fn(ref sig, ref body) => {
                 self.process_method(
                     sig,
                     body.as_ref().map(|x| &**x),
@@ -1056,7 +1055,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     trait_item.span,
                 );
             }
-            ast::TraitItemKind::Type(ref bounds, ref default_ty) => {
+            ast::AssocItemKind::TyAlias(ref bounds, ref default_ty) => {
                 // FIXME do something with _bounds (for type refs)
                 let name = trait_item.ident.name.to_string();
                 let qualname = format!("::{}",
@@ -1098,28 +1097,28 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     self.visit_ty(default_ty)
                 }
             }
-            ast::TraitItemKind::Macro(_) => {}
+            ast::AssocItemKind::Macro(_) => {}
         }
     }
 
-    fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) {
+    fn process_impl_item(&mut self, impl_item: &'l ast::AssocItem, impl_id: DefId) {
         self.process_macro_use(impl_item.span);
         match impl_item.kind {
-            ast::ImplItemKind::Const(ref ty, ref expr) => {
+            ast::AssocItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(
                     impl_item.id,
                     impl_item.ident,
                     &ty,
-                    Some(expr),
+                    expr.as_deref(),
                     impl_id,
                     impl_item.vis.clone(),
                     &impl_item.attrs,
                 );
             }
-            ast::ImplItemKind::Method(ref sig, ref body) => {
+            ast::AssocItemKind::Fn(ref sig, ref body) => {
                 self.process_method(
                     sig,
-                    Some(body),
+                    body.as_deref(),
                     impl_item.id,
                     impl_item.ident,
                     &impl_item.generics,
@@ -1127,13 +1126,14 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     impl_item.span,
                 );
             }
-            ast::ImplItemKind::TyAlias(ref ty) => {
+            ast::AssocItemKind::TyAlias(_, None) => {}
+            ast::AssocItemKind::TyAlias(_, Some(ref ty)) => {
                 // FIXME: uses of the assoc type should ideally point to this
                 // 'def' and the name here should be a ref to the def in the
                 // trait.
                 self.visit_ty(ty)
             }
-            ast::ImplItemKind::Macro(_) => {}
+            ast::AssocItemKind::Macro(_) => {}
         }
     }
 
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 92ba071a03d68..f7f84333857f6 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -254,7 +254,7 @@ pub struct ParenthesizedArgs {
     pub inputs: Vec<P<Ty>>,
 
     /// `C`
-    pub output: Option<P<Ty>>,
+    pub output: FunctionRetTy,
 }
 
 impl ParenthesizedArgs {
@@ -1603,54 +1603,43 @@ pub struct FnSig {
     pub decl: P<FnDecl>,
 }
 
-/// Represents an item declaration within a trait declaration,
-/// possibly including a default implementation. A trait item is
-/// either required (meaning it doesn't have an implementation, just a
-/// signature) or provided (meaning it has a default implementation).
+/// Represents associated items.
+/// These include items in `impl` and `trait` definitions.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct TraitItem {
+pub struct AssocItem {
     pub attrs: Vec<Attribute>,
     pub id: NodeId,
     pub span: Span,
     pub vis: Visibility,
     pub ident: Ident,
 
+    pub defaultness: Defaultness,
     pub generics: Generics,
-    pub kind: TraitItemKind,
+    pub kind: AssocItemKind,
     /// See `Item::tokens` for what this is.
     pub tokens: Option<TokenStream>,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum TraitItemKind {
+/// Represents various kinds of content within an `impl`.
+///
+/// The term "provided" in the variants below refers to the item having a default
+/// definition / body. Meanwhile, a "required" item lacks a definition / body.
+/// In an implementation, all items must be provided.
+/// The `Option`s below denote the bodies, where `Some(_)`
+/// means "provided" and conversely `None` means "required".
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum AssocItemKind  {
+    /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
+    /// If `def` is parsed, then the associated constant is provided, and otherwise required.
     Const(P<Ty>, Option<P<Expr>>),
-    Method(FnSig, Option<P<Block>>),
-    Type(GenericBounds, Option<P<Ty>>),
-    Macro(Mac),
-}
 
-/// Represents anything within an `impl` block.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct ImplItem {
-    pub attrs: Vec<Attribute>,
-    pub id: NodeId,
-    pub span: Span,
-    pub vis: Visibility,
-    pub ident: Ident,
+    /// An associated function.
+    Fn(FnSig, Option<P<Block>>),
 
-    pub defaultness: Defaultness,
-    pub generics: Generics,
-    pub kind: ImplItemKind,
-    /// See `Item::tokens` for what this is.
-    pub tokens: Option<TokenStream>,
-}
+    /// An associated type.
+    TyAlias(GenericBounds, Option<P<Ty>>),
 
-/// Represents various kinds of content within an `impl`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum ImplItemKind {
-    Const(P<Ty>, P<Expr>),
-    Method(FnSig, P<Block>),
-    TyAlias(P<Ty>),
+    /// A macro expanding to an associated item.
     Macro(Mac),
 }
 
@@ -2189,7 +2178,7 @@ impl fmt::Debug for ImplPolarity {
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum FunctionRetTy {
+pub enum FunctionRetTy { // FIXME(Centril): Rename to `FnRetTy` and in HIR also.
     /// Returns type is not specified.
     ///
     /// Functions default to `()` and closures default to inference.
@@ -2602,7 +2591,7 @@ pub enum ItemKind {
     /// A trait declaration (`trait`).
     ///
     /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
-    Trait(IsAuto, Unsafety, Generics, GenericBounds, Vec<TraitItem>),
+    Trait(IsAuto, Unsafety, Generics, GenericBounds, Vec<AssocItem>),
     /// Trait alias
     ///
     /// E.g., `trait Foo = Bar + Quux;`.
@@ -2617,7 +2606,7 @@ pub enum ItemKind {
         Generics,
         Option<TraitRef>, // (optional) trait this impl implements
         P<Ty>,            // self
-        Vec<ImplItem>,
+        Vec<AssocItem>,
     ),
     /// A macro invocation.
     ///
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index 079a0f6fafa2c..13a9ed5f215d2 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -749,6 +749,6 @@ macro_rules! derive_has_attrs {
 }
 
 derive_has_attrs! {
-    Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
+    Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::AssocItem, ast::Arm,
     ast::Field, ast::FieldPat, ast::Variant, ast::Param
 }
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index 3d2c3b1d4f901..871ec2c008eee 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -571,54 +571,52 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_assoc_ty_constraint(self, constraint)
     }
 
-    fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) {
         match ti.kind {
-            ast::TraitItemKind::Method(ref sig, ref block) => {
+            ast::AssocItemKind::Fn(ref sig, ref block) => {
                 if block.is_none() {
                     self.check_extern(sig.header.ext);
                 }
-                if sig.decl.c_variadic() {
-                    gate_feature_post!(&self, c_variadic, ti.span,
-                                       "C-variadic functions are unstable");
-                }
                 if sig.header.constness.node == ast::Constness::Const {
                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
                 }
             }
-            ast::TraitItemKind::Type(_, ref default) => {
-                if let Some(ty) = default {
-                    self.check_impl_trait(ty);
-                    gate_feature_post!(&self, associated_type_defaults, ti.span,
-                                       "associated type defaults are unstable");
+            ast::AssocItemKind::TyAlias(_, ref default) => {
+                if let Some(_) = default {
+                    gate_feature_post!(
+                        &self, associated_type_defaults, ti.span,
+                        "associated type defaults are unstable"
+                    );
                 }
-                self.check_gat(&ti.generics, ti.span);
             }
             _ => {}
         }
         visit::walk_trait_item(self, ti)
     }
 
-    fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
+    fn visit_assoc_item(&mut self, ii: &'a ast::AssocItem) {
         if ii.defaultness == ast::Defaultness::Default {
-            gate_feature_post!(&self, specialization,
-                              ii.span,
-                              "specialization is unstable");
+            gate_feature_post!(&self, specialization, ii.span, "specialization is unstable");
         }
 
         match ii.kind {
-            ast::ImplItemKind::Method(ref sig, _) => {
+            ast::AssocItemKind::Fn(ref sig, _) => {
                 if sig.decl.c_variadic() {
-                    gate_feature_post!(&self, c_variadic, ii.span,
-                                       "C-variadic functions are unstable");
+                    gate_feature_post!(
+                        &self, c_variadic, ii.span,
+                        "C-variadic functions are unstable"
+                    );
                 }
             }
-            ast::ImplItemKind::TyAlias(ref ty) => {
-                self.check_impl_trait(ty);
+            ast::AssocItemKind::TyAlias(_, ref ty) => {
+                if let Some(ty) = ty {
+                    self.check_impl_trait(ty);
+                }
                 self.check_gat(&ii.generics, ii.span);
             }
             _ => {}
         }
-        visit::walk_impl_item(self, ii)
+        visit::walk_assoc_item(self, ii)
     }
 
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index f8795d885d216..2a6cff5971c57 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -103,12 +103,12 @@ pub trait MutVisitor: Sized {
         noop_visit_item_kind(i, self);
     }
 
-    fn flat_map_trait_item(&mut self, i: TraitItem) -> SmallVec<[TraitItem; 1]> {
-        noop_flat_map_trait_item(i, self)
+    fn flat_map_trait_item(&mut self, i: AssocItem) -> SmallVec<[AssocItem; 1]> {
+        noop_flat_map_assoc_item(i, self)
     }
 
-    fn flat_map_impl_item(&mut self, i: ImplItem) -> SmallVec<[ImplItem; 1]> {
-        noop_flat_map_impl_item(i, self)
+    fn flat_map_impl_item(&mut self, i: AssocItem) -> SmallVec<[AssocItem; 1]> {
+        noop_flat_map_assoc_item(i, self)
     }
 
     fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
@@ -553,7 +553,7 @@ pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>(args: &mut Parenth
                                                               vis: &mut T) {
     let ParenthesizedArgs { inputs, output, span } = args;
     visit_vec(inputs, |input| vis.visit_ty(input));
-    visit_opt(output, |output| vis.visit_ty(output));
+    noop_visit_fn_ret_ty(output, vis);
     vis.visit_span(span);
 }
 
@@ -742,7 +742,11 @@ pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T)
 pub fn noop_visit_fn_decl<T: MutVisitor>(decl: &mut P<FnDecl>, vis: &mut T) {
     let FnDecl { inputs, output } = decl.deref_mut();
     inputs.flat_map_in_place(|param| vis.flat_map_param(param));
-    match output {
+    noop_visit_fn_ret_ty(output, vis);
+}
+
+pub fn noop_visit_fn_ret_ty<T: MutVisitor>(fn_ret_ty: &mut FunctionRetTy, vis: &mut T) {
+    match fn_ret_ty {
         FunctionRetTy::Default(span) => vis.visit_span(span),
         FunctionRetTy::Ty(ty) => vis.visit_ty(ty),
     }
@@ -936,58 +940,30 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
     }
 }
 
-pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, visitor: &mut T)
-    -> SmallVec<[TraitItem; 1]>
+pub fn noop_flat_map_assoc_item<T: MutVisitor>(mut item: AssocItem, visitor: &mut T)
+    -> SmallVec<[AssocItem; 1]>
 {
-    let TraitItem { id, ident, vis, attrs, generics, kind, span, tokens: _ } = &mut item;
+    let AssocItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } =
+        &mut item;
     visitor.visit_id(id);
     visitor.visit_ident(ident);
     visitor.visit_vis(vis);
     visit_attrs(attrs, visitor);
     visitor.visit_generics(generics);
-    match kind {
-        TraitItemKind::Const(ty, default) => {
+    match kind  {
+        AssocItemKind::Const(ty, expr) => {
             visitor.visit_ty(ty);
-            visit_opt(default, |default| visitor.visit_expr(default));
+            visit_opt(expr, |expr| visitor.visit_expr(expr));
         }
-        TraitItemKind::Method(sig, body) => {
+        AssocItemKind::Fn(sig, body) => {
             visit_fn_sig(sig, visitor);
             visit_opt(body, |body| visitor.visit_block(body));
         }
-        TraitItemKind::Type(bounds, default) => {
+        AssocItemKind::TyAlias(bounds, ty) => {
             visit_bounds(bounds, visitor);
-            visit_opt(default, |default| visitor.visit_ty(default));
-        }
-        TraitItemKind::Macro(mac) => {
-            visitor.visit_mac(mac);
-        }
-    }
-    visitor.visit_span(span);
-
-    smallvec![item]
-}
-
-pub fn noop_flat_map_impl_item<T: MutVisitor>(mut item: ImplItem, visitor: &mut T)
-                                              -> SmallVec<[ImplItem; 1]>
-{
-    let ImplItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } =
-        &mut item;
-    visitor.visit_id(id);
-    visitor.visit_ident(ident);
-    visitor.visit_vis(vis);
-    visit_attrs(attrs, visitor);
-    visitor.visit_generics(generics);
-    match kind  {
-        ImplItemKind::Const(ty, expr) => {
-            visitor.visit_ty(ty);
-            visitor.visit_expr(expr);
-        }
-        ImplItemKind::Method(sig, body) => {
-            visit_fn_sig(sig, visitor);
-            visitor.visit_block(body);
+            visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
-        ImplItemKind::TyAlias(ty) => visitor.visit_ty(ty),
-        ImplItemKind::Macro(mac) => visitor.visit_mac(mac),
+        AssocItemKind::Macro(mac) => visitor.visit_mac(mac),
     }
     visitor.visit_span(span);
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index f0c5fb32fb16d..87f6ae85b6970 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -335,8 +335,8 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
         token::NtLifetime(e)        => e.to_string(),
         token::NtLiteral(ref e)     => expr_to_string(e),
         token::NtTT(ref tree)       => tt_to_string(tree.clone()),
-        token::NtImplItem(ref e)    => impl_item_to_string(e),
-        token::NtTraitItem(ref e)   => trait_item_to_string(e),
+        // FIXME(Centril): merge these variants.
+        token::NtImplItem(ref e) | token::NtTraitItem(ref e) => assoc_item_to_string(e),
         token::NtVis(ref e)         => vis_to_string(e),
         token::NtForeignItem(ref e) => foreign_item_to_string(e),
     }
@@ -374,12 +374,8 @@ pub fn item_to_string(i: &ast::Item) -> String {
     to_string(|s| s.print_item(i))
 }
 
-fn impl_item_to_string(i: &ast::ImplItem) -> String {
-    to_string(|s| s.print_impl_item(i))
-}
-
-fn trait_item_to_string(i: &ast::TraitItem) -> String {
-    to_string(|s| s.print_trait_item(i))
+fn assoc_item_to_string(i: &ast::AssocItem) -> String {
+    to_string(|s| s.print_assoc_item(i))
 }
 
 pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
@@ -887,17 +883,9 @@ impl<'a> PrintState<'a> for State<'a> {
 
             ast::GenericArgs::Parenthesized(ref data) => {
                 self.s.word("(");
-                self.commasep(
-                    Inconsistent,
-                    &data.inputs,
-                    |s, ty| s.print_type(ty));
+                self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
                 self.s.word(")");
-
-                if let Some(ref ty) = data.output {
-                    self.space_if_not_bol();
-                    self.word_space("->");
-                    self.print_type(ty);
-                }
+                self.print_fn_ret_ty(&data.output);
             }
         }
     }
@@ -1128,16 +1116,15 @@ impl<'a> State<'a> {
         self.s.word(";")
     }
 
-    fn print_associated_type(&mut self,
-                             ident: ast::Ident,
-                             bounds: Option<&ast::GenericBounds>,
-                             ty: Option<&ast::Ty>)
-                             {
+    fn print_associated_type(
+        &mut self,
+        ident: ast::Ident,
+        bounds: &ast::GenericBounds,
+        ty: Option<&ast::Ty>,
+    ) {
         self.word_space("type");
         self.print_ident(ident);
-        if let Some(bounds) = bounds {
-            self.print_type_bounds(":", bounds);
-        }
+        self.print_type_bounds(":", bounds);
         if let Some(ty) = ty {
             self.s.space();
             self.word_space("=");
@@ -1310,7 +1297,7 @@ impl<'a> State<'a> {
                 self.bopen();
                 self.print_inner_attributes(&item.attrs);
                 for impl_item in impl_items {
-                    self.print_impl_item(impl_item);
+                    self.print_assoc_item(impl_item);
                 }
                 self.bclose(item.span);
             }
@@ -1337,7 +1324,7 @@ impl<'a> State<'a> {
                 self.s.word(" ");
                 self.bopen();
                 for trait_item in trait_items {
-                    self.print_trait_item(trait_item);
+                    self.print_assoc_item(trait_item);
                 }
                 self.bclose(item.span);
             }
@@ -1531,92 +1518,39 @@ impl<'a> State<'a> {
         }
     }
 
-    crate fn print_method_sig(&mut self,
-                            ident: ast::Ident,
-                            generics: &ast::Generics,
-                            m: &ast::FnSig,
-                            vis: &ast::Visibility)
-                            {
-        self.print_fn(&m.decl,
-                      m.header,
-                      Some(ident),
-                      &generics,
-                      vis)
-    }
-
-    crate fn print_trait_item(&mut self, ti: &ast::TraitItem)
-                            {
-        self.ann.pre(self, AnnNode::SubItem(ti.id));
+    crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+        self.ann.pre(self, AnnNode::SubItem(item.id));
         self.hardbreak_if_not_bol();
-        self.maybe_print_comment(ti.span.lo());
-        self.print_outer_attributes(&ti.attrs);
-        match ti.kind {
-            ast::TraitItemKind::Const(ref ty, ref default) => {
-                self.print_associated_const(
-                    ti.ident,
-                    ty,
-                    default.as_ref().map(|expr| &**expr),
-                    &source_map::respan(ti.span.shrink_to_lo(), ast::VisibilityKind::Inherited),
-                );
+        self.maybe_print_comment(item.span.lo());
+        self.print_outer_attributes(&item.attrs);
+        self.print_defaultness(item.defaultness);
+        match &item.kind {
+            ast::AssocItemKind::Const(ty, expr) => {
+                self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis);
             }
-            ast::TraitItemKind::Method(ref sig, ref body) => {
+            ast::AssocItemKind::Fn(sig, body) => {
                 if body.is_some() {
                     self.head("");
                 }
-                self.print_method_sig(
-                    ti.ident,
-                    &ti.generics,
-                    sig,
-                    &source_map::respan(ti.span.shrink_to_lo(), ast::VisibilityKind::Inherited),
-                );
-                if let Some(ref body) = *body {
+                self.print_fn(&sig.decl, sig.header, Some(item.ident), &item.generics, &item.vis);
+                if let Some(body) = body {
                     self.nbsp();
-                    self.print_block_with_attrs(body, &ti.attrs);
+                    self.print_block_with_attrs(body, &item.attrs);
                 } else {
                     self.s.word(";");
                 }
             }
-            ast::TraitItemKind::Type(ref bounds, ref default) => {
-                self.print_associated_type(ti.ident, Some(bounds),
-                                           default.as_ref().map(|ty| &**ty));
+            ast::AssocItemKind::TyAlias(bounds, ty) => {
+                self.print_associated_type(item.ident, bounds, ty.as_deref());
             }
-            ast::TraitItemKind::Macro(ref mac) => {
+            ast::AssocItemKind::Macro(mac) => {
                 self.print_mac(mac);
                 if mac.args.need_semicolon() {
                     self.s.word(";");
                 }
             }
         }
-        self.ann.post(self, AnnNode::SubItem(ti.id))
-    }
-
-    crate fn print_impl_item(&mut self, ii: &ast::ImplItem) {
-        self.ann.pre(self, AnnNode::SubItem(ii.id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(ii.span.lo());
-        self.print_outer_attributes(&ii.attrs);
-        self.print_defaultness(ii.defaultness);
-        match ii.kind {
-            ast::ImplItemKind::Const(ref ty, ref expr) => {
-                self.print_associated_const(ii.ident, ty, Some(expr), &ii.vis);
-            }
-            ast::ImplItemKind::Method(ref sig, ref body) => {
-                self.head("");
-                self.print_method_sig(ii.ident, &ii.generics, sig, &ii.vis);
-                self.nbsp();
-                self.print_block_with_attrs(body, &ii.attrs);
-            }
-            ast::ImplItemKind::TyAlias(ref ty) => {
-                self.print_associated_type(ii.ident, None, Some(ty));
-            }
-            ast::ImplItemKind::Macro(ref mac) => {
-                self.print_mac(mac);
-                if mac.args.need_semicolon() {
-                    self.s.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(ii.id))
+        self.ann.post(self, AnnNode::SubItem(item.id))
     }
 
     crate fn print_stmt(&mut self, st: &ast::Stmt) {
@@ -2109,7 +2043,7 @@ impl<'a> State<'a> {
                 self.print_asyncness(asyncness);
                 self.print_capture_clause(capture_clause);
 
-                self.print_fn_block_params(decl);
+                self.print_fn_params_and_ret(decl, true);
                 self.s.space();
                 self.print_expr(body);
                 self.end(); // need to close a box
@@ -2540,36 +2474,16 @@ impl<'a> State<'a> {
             self.print_ident(name);
         }
         self.print_generic_params(&generics.params);
-        self.print_fn_params_and_ret(decl);
+        self.print_fn_params_and_ret(decl, false);
         self.print_where_clause(&generics.where_clause)
     }
 
-    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl) {
-        self.popen();
-        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, false));
-        self.pclose();
-
-        self.print_fn_output(decl)
-    }
-
-    crate fn print_fn_block_params(&mut self, decl: &ast::FnDecl) {
-        self.s.word("|");
-        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, true));
-        self.s.word("|");
-
-        if let ast::FunctionRetTy::Default(..) = decl.output {
-            return;
-        }
-
-        self.space_if_not_bol();
-        self.word_space("->");
-        match decl.output {
-            ast::FunctionRetTy::Ty(ref ty) => {
-                self.print_type(ty);
-                self.maybe_print_comment(ty.span.lo())
-            }
-            ast::FunctionRetTy::Default(..) => unreachable!(),
-        }
+    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
+        let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
+        self.word(open);
+        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
+        self.word(close);
+        self.print_fn_ret_ty(&decl.output)
     }
 
     crate fn print_movability(&mut self, movability: ast::Movability) {
@@ -2791,24 +2705,14 @@ impl<'a> State<'a> {
         self.end();
     }
 
-    crate fn print_fn_output(&mut self, decl: &ast::FnDecl) {
-        if let ast::FunctionRetTy::Default(..) = decl.output {
-            return;
-        }
-
-        self.space_if_not_bol();
-        self.ibox(INDENT_UNIT);
-        self.word_space("->");
-        match decl.output {
-            ast::FunctionRetTy::Default(..) => unreachable!(),
-            ast::FunctionRetTy::Ty(ref ty) =>
-                self.print_type(ty),
-        }
-        self.end();
-
-        match decl.output {
-            ast::FunctionRetTy::Ty(ref output) => self.maybe_print_comment(output.span.lo()),
-            _ => {}
+    crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FunctionRetTy) {
+        if let ast::FunctionRetTy::Ty(ty) = fn_ret_ty {
+            self.space_if_not_bol();
+            self.ibox(INDENT_UNIT);
+            self.word_space("->");
+            self.print_type(ty);
+            self.end();
+            self.maybe_print_comment(ty.span.lo());
         }
     }
 
diff --git a/src/libsyntax/token.rs b/src/libsyntax/token.rs
index 6f45211ac5f29..263f8192241f2 100644
--- a/src/libsyntax/token.rs
+++ b/src/libsyntax/token.rs
@@ -685,8 +685,8 @@ pub enum Nonterminal {
     // Used only for passing items to proc macro attributes (they are not
     // strictly necessary for that, `Annotatable` can be converted into
     // tokens directly, but doing that naively regresses pretty-printing).
-    NtTraitItem(ast::TraitItem),
-    NtImplItem(ast::ImplItem),
+    NtTraitItem(ast::AssocItem),
+    NtImplItem(ast::AssocItem),
     NtForeignItem(ast::ForeignItem),
 }
 
diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs
index a64fec7096132..3db9955d304a3 100644
--- a/src/libsyntax/util/node_count.rs
+++ b/src/libsyntax/util/node_count.rs
@@ -73,13 +73,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_fn(self, fk, fd, s)
     }
-    fn visit_trait_item(&mut self, ti: &TraitItem) {
+    fn visit_assoc_item(&mut self, ti: &AssocItem) {
         self.count += 1;
-        walk_trait_item(self, ti)
-    }
-    fn visit_impl_item(&mut self, ii: &ImplItem) {
-        self.count += 1;
-        walk_impl_item(self, ii)
+        walk_assoc_item(self, ti)
     }
     fn visit_trait_ref(&mut self, t: &TraitRef) {
         self.count += 1;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 4ee09b4b87afa..51e7fa1eb38b4 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -25,7 +25,7 @@ pub enum FnKind<'a> {
     ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block),
 
     /// E.g., `fn foo(&self)`.
-    Method(Ident, &'a FnSig, Option<&'a Visibility>, &'a Block),
+    Method(Ident, &'a FnSig, &'a Visibility, &'a Block),
 
     /// E.g., `|x, y| body`.
     Closure(&'a Expr),
@@ -83,8 +83,9 @@ pub trait Visitor<'ast>: Sized {
     fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) {
         walk_fn(self, fk, fd, s)
     }
-    fn visit_trait_item(&mut self, ti: &'ast TraitItem) { walk_trait_item(self, ti) }
-    fn visit_impl_item(&mut self, ii: &'ast ImplItem) { walk_impl_item(self, ii) }
+    fn visit_trait_item(&mut self, i: &'ast AssocItem) { walk_trait_item(self, i) }
+    fn visit_impl_item(&mut self, i: &'ast AssocItem) { walk_impl_item(self, i) }
+    fn visit_assoc_item(&mut self, i: &'ast AssocItem) { walk_assoc_item(self, i) }
     fn visit_trait_ref(&mut self, t: &'ast TraitRef) { walk_trait_ref(self, t) }
     fn visit_param_bound(&mut self, bounds: &'ast GenericBound) {
         walk_param_bound(self, bounds)
@@ -420,7 +421,7 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V,
         }
         GenericArgs::Parenthesized(ref data) => {
             walk_list!(visitor, visit_ty, &data.inputs);
-            walk_list!(visitor, visit_ty, &data.output);
+            walk_fn_ret_ty(visitor, &data.output);
         }
     }
 }
@@ -581,52 +582,37 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
     }
 }
 
-pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a TraitItem) {
-    visitor.visit_vis(&trait_item.vis);
-    visitor.visit_ident(trait_item.ident);
-    walk_list!(visitor, visit_attribute, &trait_item.attrs);
-    visitor.visit_generics(&trait_item.generics);
-    match trait_item.kind {
-        TraitItemKind::Const(ref ty, ref default) => {
+pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
+    visitor.visit_assoc_item(item);
+}
+
+pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
+    visitor.visit_assoc_item(item);
+}
+
+pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
+    visitor.visit_vis(&item.vis);
+    visitor.visit_ident(item.ident);
+    walk_list!(visitor, visit_attribute, &item.attrs);
+    visitor.visit_generics(&item.generics);
+    match item.kind {
+        AssocItemKind::Const(ref ty, ref expr) => {
             visitor.visit_ty(ty);
-            walk_list!(visitor, visit_expr, default);
+            walk_list!(visitor, visit_expr, expr);
         }
-        TraitItemKind::Method(ref sig, None) => {
+        AssocItemKind::Fn(ref sig, None) => {
             visitor.visit_fn_header(&sig.header);
             walk_fn_decl(visitor, &sig.decl);
         }
-        TraitItemKind::Method(ref sig, Some(ref body)) => {
-            visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None, body),
-                             &sig.decl, trait_item.span, trait_item.id);
+        AssocItemKind::Fn(ref sig, Some(ref body)) => {
+            visitor.visit_fn(FnKind::Method(item.ident, sig, &item.vis, body),
+                             &sig.decl, item.span, item.id);
         }
-        TraitItemKind::Type(ref bounds, ref default) => {
+        AssocItemKind::TyAlias(ref bounds, ref ty) => {
             walk_list!(visitor, visit_param_bound, bounds);
-            walk_list!(visitor, visit_ty, default);
-        }
-        TraitItemKind::Macro(ref mac) => {
-            visitor.visit_mac(mac);
-        }
-    }
-}
-
-pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, impl_item: &'a ImplItem) {
-    visitor.visit_vis(&impl_item.vis);
-    visitor.visit_ident(impl_item.ident);
-    walk_list!(visitor, visit_attribute, &impl_item.attrs);
-    visitor.visit_generics(&impl_item.generics);
-    match impl_item.kind {
-        ImplItemKind::Const(ref ty, ref expr) => {
-            visitor.visit_ty(ty);
-            visitor.visit_expr(expr);
-        }
-        ImplItemKind::Method(ref sig, ref body) => {
-            visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), body),
-                             &sig.decl, impl_item.span, impl_item.id);
-        }
-        ImplItemKind::TyAlias(ref ty) => {
-            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_ty, ty);
         }
-        ImplItemKind::Macro(ref mac) => {
+        AssocItemKind::Macro(ref mac) => {
             visitor.visit_mac(mac);
         }
     }
diff --git a/src/libsyntax_expand/base.rs b/src/libsyntax_expand/base.rs
index a4449ca5b1d22..2cfcbd3161f4d 100644
--- a/src/libsyntax_expand/base.rs
+++ b/src/libsyntax_expand/base.rs
@@ -31,8 +31,8 @@ crate use syntax_pos::hygiene::MacroKind;
 #[derive(Debug,Clone)]
 pub enum Annotatable {
     Item(P<ast::Item>),
-    TraitItem(P<ast::TraitItem>),
-    ImplItem(P<ast::ImplItem>),
+    TraitItem(P<ast::AssocItem>),
+    ImplItem(P<ast::AssocItem>),
     ForeignItem(P<ast::ForeignItem>),
     Stmt(P<ast::Stmt>),
     Expr(P<ast::Expr>),
@@ -137,14 +137,14 @@ impl Annotatable {
         }
     }
 
-    pub fn expect_trait_item(self) -> ast::TraitItem {
+    pub fn expect_trait_item(self) -> ast::AssocItem {
         match self {
             Annotatable::TraitItem(i) => i.into_inner(),
             _ => panic!("expected Item")
         }
     }
 
-    pub fn expect_impl_item(self) -> ast::ImplItem {
+    pub fn expect_impl_item(self) -> ast::AssocItem {
         match self {
             Annotatable::ImplItem(i) => i.into_inner(),
             _ => panic!("expected Item")
@@ -382,12 +382,12 @@ pub trait MacResult {
     }
 
     /// Creates zero or more impl items.
-    fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::ImplItem; 1]>> {
+    fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         None
     }
 
     /// Creates zero or more trait items.
-    fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::TraitItem; 1]>> {
+    fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         None
     }
 
@@ -468,8 +468,8 @@ make_MacEager! {
     expr: P<ast::Expr>,
     pat: P<ast::Pat>,
     items: SmallVec<[P<ast::Item>; 1]>,
-    impl_items: SmallVec<[ast::ImplItem; 1]>,
-    trait_items: SmallVec<[ast::TraitItem; 1]>,
+    impl_items: SmallVec<[ast::AssocItem; 1]>,
+    trait_items: SmallVec<[ast::AssocItem; 1]>,
     foreign_items: SmallVec<[ast::ForeignItem; 1]>,
     stmts: SmallVec<[ast::Stmt; 1]>,
     ty: P<ast::Ty>,
@@ -484,11 +484,11 @@ impl MacResult for MacEager {
         self.items
     }
 
-    fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::ImplItem; 1]>> {
+    fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         self.impl_items
     }
 
-    fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::TraitItem; 1]>> {
+    fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         self.trait_items
     }
 
@@ -588,11 +588,11 @@ impl MacResult for DummyResult {
         Some(SmallVec::new())
     }
 
-    fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::ImplItem; 1]>> {
+    fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         Some(SmallVec::new())
     }
 
-    fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::TraitItem; 1]>> {
+    fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         Some(SmallVec::new())
     }
 
diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs
index 9bfedb3b6174e..d4223af27abe6 100644
--- a/src/libsyntax_expand/expand.rs
+++ b/src/libsyntax_expand/expand.rs
@@ -155,10 +155,10 @@ ast_fragments! {
     Items(SmallVec<[P<ast::Item>; 1]>) {
         "item"; many fn flat_map_item; fn visit_item; fn make_items;
     }
-    TraitItems(SmallVec<[ast::TraitItem; 1]>) {
+    TraitItems(SmallVec<[ast::AssocItem; 1]>) {
         "trait item"; many fn flat_map_trait_item; fn visit_trait_item; fn make_trait_items;
     }
-    ImplItems(SmallVec<[ast::ImplItem; 1]>) {
+    ImplItems(SmallVec<[ast::AssocItem; 1]>) {
         "impl item"; many fn flat_map_impl_item; fn visit_impl_item; fn make_impl_items;
     }
     ForeignItems(SmallVec<[ast::ForeignItem; 1]>) {
@@ -1317,7 +1317,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
     }
 
-    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+    fn flat_map_trait_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         let mut item = configure!(self, item);
 
         let (attr, traits, after_derive) = self.classify_item(&mut item);
@@ -1327,16 +1327,16 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
 
         match item.kind {
-            ast::TraitItemKind::Macro(mac) => {
-                let ast::TraitItem { attrs, span, .. } = item;
+            ast::AssocItemKind::Macro(mac) => {
+                let ast::AssocItem { attrs, span, .. } = item;
                 self.check_attributes(&attrs);
                 self.collect_bang(mac, span, AstFragmentKind::TraitItems).make_trait_items()
             }
-            _ => noop_flat_map_trait_item(item, self),
+            _ => noop_flat_map_assoc_item(item, self),
         }
     }
 
-    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+    fn flat_map_impl_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         let mut item = configure!(self, item);
 
         let (attr, traits, after_derive) = self.classify_item(&mut item);
@@ -1346,12 +1346,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
 
         match item.kind {
-            ast::ImplItemKind::Macro(mac) => {
-                let ast::ImplItem { attrs, span, .. } = item;
+            ast::AssocItemKind::Macro(mac) => {
+                let ast::AssocItem { attrs, span, .. } = item;
                 self.check_attributes(&attrs);
                 self.collect_bang(mac, span, AstFragmentKind::ImplItems).make_impl_items()
             }
-            _ => noop_flat_map_impl_item(item, self),
+            _ => noop_flat_map_assoc_item(item, self),
         }
     }
 
diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs
index faea04e691be5..22e99baae5be0 100644
--- a/src/libsyntax_expand/placeholders.rs
+++ b/src/libsyntax_expand/placeholders.rs
@@ -50,14 +50,15 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option<ast::Visi
             kind: ast::ItemKind::Mac(mac_placeholder()),
             tokens: None,
         })]),
-        AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![ast::TraitItem {
+        AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![ast::AssocItem {
             id, span, ident, vis, attrs, generics,
-            kind: ast::TraitItemKind::Macro(mac_placeholder()),
+            kind: ast::AssocItemKind::Macro(mac_placeholder()),
+            defaultness: ast::Defaultness::Final,
             tokens: None,
         }]),
-        AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![ast::ImplItem {
+        AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![ast::AssocItem {
             id, span, ident, vis, attrs, generics,
-            kind: ast::ImplItemKind::Macro(mac_placeholder()),
+            kind: ast::AssocItemKind::Macro(mac_placeholder()),
             defaultness: ast::Defaultness::Final,
             tokens: None,
         }]),
@@ -252,17 +253,17 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
         noop_flat_map_item(item, self)
     }
 
-    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+    fn flat_map_trait_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         match item.kind {
-            ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(),
-            _ => noop_flat_map_trait_item(item, self),
+            ast::AssocItemKind::Macro(_) => self.remove(item.id).make_trait_items(),
+            _ => noop_flat_map_assoc_item(item, self),
         }
     }
 
-    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+    fn flat_map_impl_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         match item.kind {
-            ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(),
-            _ => noop_flat_map_impl_item(item, self),
+            ast::AssocItemKind::Macro(_) => self.remove(item.id).make_impl_items(),
+            _ => noop_flat_map_assoc_item(item, self),
         }
     }
 
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 5bd84b43a7801..b7707bfb8e5fb 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -504,13 +504,13 @@ impl<'a> TraitDef<'a> {
                            type_ident: Ident,
                            generics: &Generics,
                            field_tys: Vec<P<ast::Ty>>,
-                           methods: Vec<ast::ImplItem>)
+                           methods: Vec<ast::AssocItem>)
                            -> P<ast::Item> {
         let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
 
-        // Transform associated types from `deriving::ty::Ty` into `ast::ImplItem`
+        // Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
         let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
-            ast::ImplItem {
+            ast::AssocItem {
                 id: ast::DUMMY_NODE_ID,
                 span: self.span,
                 ident,
@@ -518,8 +518,10 @@ impl<'a> TraitDef<'a> {
                 defaultness: ast::Defaultness::Final,
                 attrs: Vec::new(),
                 generics: Generics::default(),
-                kind: ast::ImplItemKind::TyAlias(
-                    type_def.to_ty(cx, self.span, type_ident, generics)),
+                kind: ast::AssocItemKind::TyAlias(
+                    Vec::new(),
+                    Some(type_def.to_ty(cx, self.span, type_ident, generics)),
+                ),
                 tokens: None,
             }
         });
@@ -910,7 +912,7 @@ impl<'a> MethodDef<'a> {
                      explicit_self: Option<ast::ExplicitSelf>,
                      arg_types: Vec<(Ident, P<ast::Ty>)>,
                      body: P<Expr>)
-                     -> ast::ImplItem {
+                     -> ast::AssocItem {
         // Create the generics that aren't for `Self`.
         let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
 
@@ -948,7 +950,7 @@ impl<'a> MethodDef<'a> {
         };
 
         // Create the method.
-        ast::ImplItem {
+        ast::AssocItem {
             id: ast::DUMMY_NODE_ID,
             attrs: self.attributes.clone(),
             generics: fn_generics,
@@ -956,7 +958,7 @@ impl<'a> MethodDef<'a> {
             vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited),
             defaultness: ast::Defaultness::Final,
             ident: method_ident,
-            kind: ast::ImplItemKind::Method(sig, body_block),
+            kind: ast::AssocItemKind::Fn(sig, Some(body_block)),
             tokens: None,
         }
     }
diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
index cb6060525fc0d..7af38c88f4334 100644
--- a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
@@ -1,8 +1,8 @@
 error: C-variadic function must be declared with at least one named argument
-  --> $DIR/variadic-ffi-no-fixed-args.rs:2:11
+  --> $DIR/variadic-ffi-no-fixed-args.rs:2:12
    |
 LL |     fn foo(...);
-   |           ^
+   |            ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs
index b3c1f60b7ebf6..ea21592997bfe 100644
--- a/src/test/ui/did_you_mean/issue-40006.rs
+++ b/src/test/ui/did_you_mean/issue-40006.rs
@@ -18,10 +18,10 @@ trait A { //~ ERROR missing
 trait B {
     fn xxx() { ### } //~ ERROR expected
 }
-trait C { //~ ERROR missing `fn`, `type`, or `const` for trait-item declaration
+trait C { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration
     L = M;
 }
-trait D { //~ ERROR missing `fn`, `type`, or `const` for trait-item declaration
+trait D { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration
     Z = { 2 + 3 };
 }
 trait E {
diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr
index 30ae6ed4c6d49..d1e995013cb93 100644
--- a/src/test/ui/did_you_mean/issue-40006.stderr
+++ b/src/test/ui/did_you_mean/issue-40006.stderr
@@ -1,4 +1,4 @@
-error: missing `fn`, `type`, or `const` for impl-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:1:13
    |
 LL |   impl dyn A {
@@ -6,7 +6,7 @@ LL |   impl dyn A {
 LL | |     Y
    | |____^ missing `fn`, `type`, or `const`
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:7:10
    |
 LL |   trait X {
@@ -14,7 +14,7 @@ LL |   trait X {
 LL | |     X() {}
    | |____^ missing `fn`, `type`, or `const`
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:15:10
    |
 LL |   trait A {
@@ -28,7 +28,7 @@ error: expected `[`, found `#`
 LL |     fn xxx() { ### }
    |                 ^ expected `[`
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:21:10
    |
 LL |   trait C {
@@ -36,7 +36,7 @@ LL |   trait C {
 LL | |     L = M;
    | |____^ missing `fn`, `type`, or `const`
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:24:10
    |
 LL |   trait D {
@@ -50,7 +50,7 @@ error: expected one of `!` or `::`, found `(`
 LL |     ::Y ();
    |         ^ expected one of `!` or `::`
 
-error: missing `fn`, `type`, or `const` for impl-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:32:8
    |
 LL |     pub hello_method(&self) {
diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
index d9ebcdecb9bfd..1f61473c9d2f4 100644
--- a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
+++ b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
@@ -16,15 +16,6 @@ LL |     type Baa = impl Debug;
    = note: for more information, see https://github.com/rust-lang/rust/issues/63063
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
-error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:18:18
-   |
-LL |     type Assoc = impl Debug;
-   |                  ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/63063
-   = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
-
 error[E0658]: associated type defaults are unstable
   --> $DIR/feature-gate-type_alias_impl_trait.rs:18:5
    |
@@ -34,6 +25,15 @@ LL |     type Assoc = impl Debug;
    = note: for more information, see https://github.com/rust-lang/rust/issues/29661
    = help: add `#![feature(associated_type_defaults)]` to the crate attributes to enable
 
+error[E0658]: `impl Trait` in type aliases is unstable
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:18:18
+   |
+LL |     type Assoc = impl Debug;
+   |                  ^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/63063
+   = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
+
 error[E0658]: `impl Trait` in type aliases is unstable
   --> $DIR/feature-gate-type_alias_impl_trait.rs:24:24
    |
diff --git a/src/test/ui/invalid/invalid-variadic-function.rs b/src/test/ui/invalid/invalid-variadic-function.rs
deleted file mode 100644
index 8d23f0e477077..0000000000000
--- a/src/test/ui/invalid/invalid-variadic-function.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-extern "C" fn foo(x: u8, ...);
-//~^ ERROR only foreign functions are allowed to be C-variadic
-//~| ERROR expected one of `->`, `where`, or `{`, found `;`
diff --git a/src/test/ui/invalid/invalid-variadic-function.stderr b/src/test/ui/invalid/invalid-variadic-function.stderr
deleted file mode 100644
index 7e58b17e7db74..0000000000000
--- a/src/test/ui/invalid/invalid-variadic-function.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0743]: only foreign functions are allowed to be C-variadic
-  --> $DIR/invalid-variadic-function.rs:1:26
-   |
-LL | extern "C" fn foo(x: u8, ...);
-   |                          ^^^
-
-error: expected one of `->`, `where`, or `{`, found `;`
-  --> $DIR/invalid-variadic-function.rs:1:30
-   |
-LL | extern "C" fn foo(x: u8, ...);
-   |                              ^ expected one of `->`, `where`, or `{`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0743`.
diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs
index db3984cd18987..8b1a39a94e67a 100644
--- a/src/test/ui/issues/issue-58856-1.rs
+++ b/src/test/ui/issues/issue-58856-1.rs
@@ -1,6 +1,8 @@
 impl A {
+    //~^ ERROR cannot find type `A` in this scope
     fn b(self>
     //~^ ERROR expected one of `)`, `,`, or `:`, found `>`
+    //~| ERROR expected `;` or `{`, found `>`
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr
index 58ab0a142d6f1..0ea6b01754890 100644
--- a/src/test/ui/issues/issue-58856-1.stderr
+++ b/src/test/ui/issues/issue-58856-1.stderr
@@ -1,10 +1,23 @@
 error: expected one of `)`, `,`, or `:`, found `>`
-  --> $DIR/issue-58856-1.rs:2:14
+  --> $DIR/issue-58856-1.rs:3:14
    |
 LL |     fn b(self>
    |         -    ^ help: `)` may belong here
    |         |
    |         unclosed delimiter
 
-error: aborting due to previous error
+error: expected `;` or `{`, found `>`
+  --> $DIR/issue-58856-1.rs:3:14
+   |
+LL |     fn b(self>
+   |              ^ expected `;` or `{`
+
+error[E0412]: cannot find type `A` in this scope
+  --> $DIR/issue-58856-1.rs:1:6
+   |
+LL | impl A {
+   |      ^ not found in this scope
+
+error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr
index e0b15130c337d..e8ef981f515fc 100644
--- a/src/test/ui/issues/issue-60075.stderr
+++ b/src/test/ui/issues/issue-60075.stderr
@@ -4,7 +4,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
 LL |         });
    |          ^ expected one of `.`, `;`, `?`, `else`, or an operator
 
-error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;`
   --> $DIR/issue-60075.rs:6:11
    |
 LL |     fn qux() -> Option<usize> {
diff --git a/src/test/ui/parser/impl-item-const-pass.rs b/src/test/ui/parser/impl-item-const-pass.rs
new file mode 100644
index 0000000000000..d1124561374a5
--- /dev/null
+++ b/src/test/ui/parser/impl-item-const-pass.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+impl X {
+    const Y: u8;
+}
diff --git a/src/test/ui/parser/impl-item-const-semantic-fail.rs b/src/test/ui/parser/impl-item-const-semantic-fail.rs
new file mode 100644
index 0000000000000..5d4692f9f14ac
--- /dev/null
+++ b/src/test/ui/parser/impl-item-const-semantic-fail.rs
@@ -0,0 +1,7 @@
+fn main() {}
+
+struct X;
+
+impl X {
+    const Y: u8; //~ ERROR associated constant in `impl` without body
+}
diff --git a/src/test/ui/parser/impl-item-const-semantic-fail.stderr b/src/test/ui/parser/impl-item-const-semantic-fail.stderr
new file mode 100644
index 0000000000000..ec3bee0ce6824
--- /dev/null
+++ b/src/test/ui/parser/impl-item-const-semantic-fail.stderr
@@ -0,0 +1,10 @@
+error: associated constant in `impl` without body
+  --> $DIR/impl-item-const-semantic-fail.rs:6:5
+   |
+LL |     const Y: u8;
+   |     ^^^^^^^^^^^-
+   |                |
+   |                help: provide a definition for the constant: `= <expr>;`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/impl-item-fn-no-body-pass.rs b/src/test/ui/parser/impl-item-fn-no-body-pass.rs
new file mode 100644
index 0000000000000..16b09d64e8c17
--- /dev/null
+++ b/src/test/ui/parser/impl-item-fn-no-body-pass.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+impl X {
+    fn f();
+}
diff --git a/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.rs
new file mode 100644
index 0000000000000..cb183db59643e
--- /dev/null
+++ b/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.rs
@@ -0,0 +1,7 @@
+fn main() {}
+
+struct X;
+
+impl X {
+    fn f(); //~ ERROR associated function in `impl` without body
+}
diff --git a/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.stderr
new file mode 100644
index 0000000000000..1acb727368bce
--- /dev/null
+++ b/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.stderr
@@ -0,0 +1,10 @@
+error: associated function in `impl` without body
+  --> $DIR/impl-item-fn-no-body-semantic-fail.rs:6:5
+   |
+LL |     fn f();
+   |     ^^^^^^-
+   |           |
+   |           help: provide a definition for the function: `{ <body> }`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/impl-item-type-no-body-pass.rs b/src/test/ui/parser/impl-item-type-no-body-pass.rs
new file mode 100644
index 0000000000000..74a9c6ab7e8a6
--- /dev/null
+++ b/src/test/ui/parser/impl-item-type-no-body-pass.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+impl X {
+    type Y;
+    type Z: Ord;
+    type W: Ord where Self: Eq;
+    type W where Self: Eq;
+}
diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs
new file mode 100644
index 0000000000000..71c7d4ba21db6
--- /dev/null
+++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs
@@ -0,0 +1,22 @@
+#![feature(generic_associated_types)]
+//~^ WARN the feature `generic_associated_types` is incomplete
+
+fn main() {}
+
+struct X;
+
+impl X {
+    type Y;
+    //~^ ERROR associated type in `impl` without body
+    //~| ERROR associated types are not yet supported in inherent impls
+    type Z: Ord;
+    //~^ ERROR associated type in `impl` without body
+    //~| ERROR bounds on associated `type`s in `impl`s have no effect
+    //~| ERROR associated types are not yet supported in inherent impls
+    type W: Ord where Self: Eq;
+    //~^ ERROR associated type in `impl` without body
+    //~| ERROR bounds on associated `type`s in `impl`s have no effect
+    //~| ERROR associated types are not yet supported in inherent impls
+    type W where Self: Eq;
+    //~^ ERROR associated type in `impl` without body
+}
diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
new file mode 100644
index 0000000000000..6f1439c8f0b29
--- /dev/null
+++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
@@ -0,0 +1,73 @@
+error: associated type in `impl` without body
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:9:5
+   |
+LL |     type Y;
+   |     ^^^^^^-
+   |           |
+   |           help: provide a definition for the type: `= <type>;`
+
+error: associated type in `impl` without body
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:5
+   |
+LL |     type Z: Ord;
+   |     ^^^^^^^^^^^-
+   |                |
+   |                help: provide a definition for the type: `= <type>;`
+
+error: bounds on associated `type`s in `impl`s have no effect
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:13
+   |
+LL |     type Z: Ord;
+   |             ^^^
+
+error: associated type in `impl` without body
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:5
+   |
+LL |     type W: Ord where Self: Eq;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                               |
+   |                               help: provide a definition for the type: `= <type>;`
+
+error: bounds on associated `type`s in `impl`s have no effect
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:13
+   |
+LL |     type W: Ord where Self: Eq;
+   |             ^^^
+
+error: associated type in `impl` without body
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:20:5
+   |
+LL |     type W where Self: Eq;
+   |     ^^^^^^^^^^^^^^^^^^^^^-
+   |                          |
+   |                          help: provide a definition for the type: `= <type>;`
+
+warning: the feature `generic_associated_types` is incomplete and may cause the compiler to crash
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:1:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0202]: associated types are not yet supported in inherent impls (see #8995)
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:9:5
+   |
+LL |     type Y;
+   |     ^^^^^^^
+
+error[E0202]: associated types are not yet supported in inherent impls (see #8995)
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:5
+   |
+LL |     type Z: Ord;
+   |     ^^^^^^^^^^^^
+
+error[E0202]: associated types are not yet supported in inherent impls (see #8995)
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:5
+   |
+LL |     type W: Ord where Self: Eq;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0202`.
diff --git a/src/test/ui/parser/issue-21153.stderr b/src/test/ui/parser/issue-21153.stderr
index 70f55f0aeb9ff..6e20a9ce3c432 100644
--- a/src/test/ui/parser/issue-21153.stderr
+++ b/src/test/ui/parser/issue-21153.stderr
@@ -1,4 +1,4 @@
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-21153.rs:1:29
    |
 LL |   trait MyTrait<T>: Iterator {
diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr
index 70256a59231fb..1a97f54160b24 100644
--- a/src/test/ui/parser/issue-32446.stderr
+++ b/src/test/ui/parser/issue-32446.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...`
   --> $DIR/issue-32446.rs:4:11
    |
 LL | trait T { ... }
-   |           ^^^ expected one of 9 possible tokens
+   |           ^^^ expected one of 10 possible tokens
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr
index 0a433ab278e43..7647ba500e03a 100644
--- a/src/test/ui/parser/macro/trait-non-item-macros.stderr
+++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2`
   --> $DIR/trait-non-item-macros.rs:2:19
    |
 LL |     ($a:expr) => ($a)
-   |                   ^^ expected one of 8 possible tokens
+   |                   ^^ expected one of 9 possible tokens
 ...
 LL |     bah!(2);
    |     -------- in this macro invocation
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
index cbaf9315e8540..7e8abf22d55ab 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
@@ -7,11 +7,11 @@ LL | trait T {
 LL | fn main() {}
    |                                                                  ^
 
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct`
+error: expected one of `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct`
   --> $DIR/missing-close-brace-in-trait.rs:5:12
    |
 LL | pub(crate) struct Bar<T>();
-   |            ^^^^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`
+   |            ^^^^^^ expected one of 7 possible tokens
 
 error[E0601]: `main` function not found in crate `missing_close_brace_in_trait`
   --> $DIR/missing-close-brace-in-trait.rs:1:1
diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs
new file mode 100644
index 0000000000000..09f967f161ede
--- /dev/null
+++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs
@@ -0,0 +1,12 @@
+#![feature(specialization)]
+
+fn main() {}
+
+trait X {
+    default const A: u8; //~ ERROR `default` is only allowed on items in `impl` definitions
+    default const B: u8 = 0;  //~ ERROR `default` is only allowed on items in `impl` definitions
+    default type D; //~ ERROR `default` is only allowed on items in `impl` definitions
+    default type C: Ord; //~ ERROR `default` is only allowed on items in `impl` definitions
+    default fn f1(); //~ ERROR `default` is only allowed on items in `impl` definitions
+    default fn f2() {} //~ ERROR `default` is only allowed on items in `impl` definitions
+}
diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr
new file mode 100644
index 0000000000000..54111df342343
--- /dev/null
+++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr
@@ -0,0 +1,38 @@
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:6:5
+   |
+LL |     default const A: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:7:5
+   |
+LL |     default const B: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:8:5
+   |
+LL |     default type D;
+   |     ^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:9:5
+   |
+LL |     default type C: Ord;
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:10:5
+   |
+LL |     default fn f1();
+   |     ^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:11:5
+   |
+LL |     default fn f2() {}
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/parser/trait-item-with-defaultness-pass.rs b/src/test/ui/parser/trait-item-with-defaultness-pass.rs
new file mode 100644
index 0000000000000..a6318bd99e2f6
--- /dev/null
+++ b/src/test/ui/parser/trait-item-with-defaultness-pass.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+trait X {
+    default const A: u8;
+    default const B: u8 = 0;
+    default type D;
+    default type C: Ord;
+    default fn f1();
+    default fn f2() {}
+}
diff --git a/src/test/ui/parser/variadic-ffi-3.rs b/src/test/ui/parser/variadic-ffi-3.rs
deleted file mode 100644
index ce83cc87abe00..0000000000000
--- a/src/test/ui/parser/variadic-ffi-3.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn foo(x: isize, ...) {
-    //~^ ERROR: only foreign functions are allowed to be C-variadic
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/variadic-ffi-3.stderr b/src/test/ui/parser/variadic-ffi-3.stderr
deleted file mode 100644
index aeeebdb991483..0000000000000
--- a/src/test/ui/parser/variadic-ffi-3.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0743]: only foreign functions are allowed to be C-variadic
-  --> $DIR/variadic-ffi-3.rs:1:18
-   |
-LL | fn foo(x: isize, ...) {
-   |                  ^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0743`.
diff --git a/src/test/ui/parser/variadic-ffi-4.rs b/src/test/ui/parser/variadic-ffi-4.rs
deleted file mode 100644
index 5f8b3f8f539b8..0000000000000
--- a/src/test/ui/parser/variadic-ffi-4.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-extern "C" fn foo(x: isize, ...) {
-    //~^ ERROR: only foreign functions are allowed to be C-variadic
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/variadic-ffi-4.stderr b/src/test/ui/parser/variadic-ffi-4.stderr
deleted file mode 100644
index da83276c72dd1..0000000000000
--- a/src/test/ui/parser/variadic-ffi-4.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0743]: only foreign functions are allowed to be C-variadic
-  --> $DIR/variadic-ffi-4.rs:1:29
-   |
-LL | extern "C" fn foo(x: isize, ...) {
-   |                             ^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0743`.
diff --git a/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.rs b/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.rs
new file mode 100644
index 0000000000000..9eeee195e56e4
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.rs
@@ -0,0 +1,9 @@
+fn f1<'a>(x: u8, y: &'a ...) {}
+//~^ ERROR C-variadic type `...` may not be nested inside another type
+
+fn f2<'a>(x: u8, y: Vec<&'a ...>) {}
+//~^ ERROR C-variadic type `...` may not be nested inside another type
+
+fn main() {
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.stderr b/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.stderr
new file mode 100644
index 0000000000000..8b9d676a45dae
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.stderr
@@ -0,0 +1,24 @@
+error[E0743]: C-variadic type `...` may not be nested inside another type
+  --> $DIR/variadic-ffi-nested-syntactic-fail.rs:1:25
+   |
+LL | fn f1<'a>(x: u8, y: &'a ...) {}
+   |                         ^^^
+
+error[E0743]: C-variadic type `...` may not be nested inside another type
+  --> $DIR/variadic-ffi-nested-syntactic-fail.rs:4:29
+   |
+LL | fn f2<'a>(x: u8, y: Vec<&'a ...>) {}
+   |                             ^^^
+
+error[E0308]: mismatched types
+  --> $DIR/variadic-ffi-nested-syntactic-fail.rs:8:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0743.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.rs b/src/test/ui/parser/variadic-ffi-semantic-restrictions.rs
new file mode 100644
index 0000000000000..aa85f6d6b522b
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.rs
@@ -0,0 +1,76 @@
+#![feature(c_variadic)]
+
+fn main() {}
+
+fn f1_1(x: isize, ...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+
+fn f1_2(...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR C-variadic function must be declared with at least one named argument
+
+extern "C" fn f2_1(x: isize, ...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+
+extern "C" fn f2_2(...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR C-variadic function must be declared with at least one named argument
+
+extern "C" fn f2_3(..., x: isize) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR `...` must be the last argument of a C-variadic function
+
+extern fn f3_1(x: isize, ...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+
+extern fn f3_2(...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR C-variadic function must be declared with at least one named argument
+
+extern fn f3_3(..., x: isize) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR `...` must be the last argument of a C-variadic function
+
+extern {
+    fn e_f1(...);
+    //~^ ERROR C-variadic function must be declared with at least one named argument
+    fn e_f2(..., x: isize);
+    //~^ ERROR `...` must be the last argument of a C-variadic function
+}
+
+struct X;
+
+impl X {
+    fn i_f1(x: isize, ...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    fn i_f2(...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR C-variadic function must be declared with at least one named argument
+    fn i_f3(..., x: isize, ...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR `...` must be the last argument of a C-variadic function
+    fn i_f4(..., x: isize, ...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR `...` must be the last argument of a C-variadic function
+}
+
+trait T {
+    fn t_f1(x: isize, ...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    fn t_f2(x: isize, ...);
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    fn t_f3(...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR C-variadic function must be declared with at least one named argument
+    fn t_f4(...);
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR C-variadic function must be declared with at least one named argument
+    fn t_f5(..., x: isize) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR `...` must be the last argument of a C-variadic function
+    fn t_f6(..., x: isize);
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR `...` must be the last argument of a C-variadic function
+}
diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
new file mode 100644
index 0000000000000..21992a29670c9
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
@@ -0,0 +1,206 @@
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:5:19
+   |
+LL | fn f1_1(x: isize, ...) {}
+   |                   ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9
+   |
+LL | fn f1_2(...) {}
+   |         ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9
+   |
+LL | fn f1_2(...) {}
+   |         ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30
+   |
+LL | extern "C" fn f2_1(x: isize, ...) {}
+   |                              ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
+   |
+LL | extern "C" fn f2_2(...) {}
+   |                    ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
+   |
+LL | extern "C" fn f2_2(...) {}
+   |                    ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20
+   |
+LL | extern "C" fn f2_3(..., x: isize) {}
+   |                    ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20
+   |
+LL | extern "C" fn f2_3(..., x: isize) {}
+   |                    ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:23:26
+   |
+LL | extern fn f3_1(x: isize, ...) {}
+   |                          ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16
+   |
+LL | extern fn f3_2(...) {}
+   |                ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16
+   |
+LL | extern fn f3_2(...) {}
+   |                ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16
+   |
+LL | extern fn f3_3(..., x: isize) {}
+   |                ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16
+   |
+LL | extern fn f3_3(..., x: isize) {}
+   |                ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:35:13
+   |
+LL |     fn e_f1(...);
+   |             ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:37:13
+   |
+LL |     fn e_f2(..., x: isize);
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:44:23
+   |
+LL |     fn i_f1(x: isize, ...) {}
+   |                       ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13
+   |
+LL |     fn i_f2(...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13
+   |
+LL |     fn i_f2(...) {}
+   |             ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13
+   |
+LL |     fn i_f3(..., x: isize, ...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13
+   |
+LL |     fn i_f3(..., x: isize, ...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:49:28
+   |
+LL |     fn i_f3(..., x: isize, ...) {}
+   |                            ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
+   |
+LL |     fn i_f4(..., x: isize, ...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
+   |
+LL |     fn i_f4(..., x: isize, ...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:53:28
+   |
+LL |     fn i_f4(..., x: isize, ...) {}
+   |                            ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:60:23
+   |
+LL |     fn t_f1(x: isize, ...) {}
+   |                       ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:23
+   |
+LL |     fn t_f2(x: isize, ...);
+   |                       ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13
+   |
+LL |     fn t_f3(...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13
+   |
+LL |     fn t_f3(...) {}
+   |             ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13
+   |
+LL |     fn t_f4(...);
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13
+   |
+LL |     fn t_f4(...);
+   |             ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13
+   |
+LL |     fn t_f5(..., x: isize) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13
+   |
+LL |     fn t_f5(..., x: isize) {}
+   |             ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
+   |
+LL |     fn t_f6(..., x: isize);
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
+   |
+LL |     fn t_f6(..., x: isize);
+   |             ^^^^
+
+error: aborting due to 34 previous errors
+
diff --git a/src/test/ui/parser/variadic-ffi-syntactic-pass.rs b/src/test/ui/parser/variadic-ffi-syntactic-pass.rs
new file mode 100644
index 0000000000000..3875d6af13716
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-syntactic-pass.rs
@@ -0,0 +1,53 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn f1_1(x: isize, ...) {}
+
+#[cfg(FALSE)]
+fn f1_2(...) {}
+
+#[cfg(FALSE)]
+extern "C" fn f2_1(x: isize, ...) {}
+
+#[cfg(FALSE)]
+extern "C" fn f2_2(...) {}
+
+#[cfg(FALSE)]
+extern "C" fn f2_3(..., x: isize) {}
+
+#[cfg(FALSE)]
+extern fn f3_1(x: isize, ...) {}
+
+#[cfg(FALSE)]
+extern fn f3_2(...) {}
+
+#[cfg(FALSE)]
+extern fn f3_3(..., x: isize) {}
+
+#[cfg(FALSE)]
+extern {
+    fn e_f1(...);
+    fn e_f2(..., x: isize);
+}
+
+struct X;
+
+#[cfg(FALSE)]
+impl X {
+    fn i_f1(x: isize, ...) {}
+    fn i_f2(...) {}
+    fn i_f3(..., x: isize, ...) {}
+    fn i_f4(..., x: isize, ...) {}
+}
+
+#[cfg(FALSE)]
+trait T {
+    fn t_f1(x: isize, ...) {}
+    fn t_f2(x: isize, ...);
+    fn t_f3(...) {}
+    fn t_f4(...);
+    fn t_f5(..., x: isize) {}
+    fn t_f6(..., x: isize);
+}