about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs27
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs26
-rw-r--r--compiler/rustc_ast/src/visit.rs26
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs20
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs74
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/errors.rs7
-rw-r--r--compiler/rustc_expand/src/expand.rs117
-rw-r--r--compiler/rustc_parse/src/parser/item.rs31
-rw-r--r--compiler/rustc_parse/src/parser/path.rs7
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs5
-rw-r--r--compiler/rustc_passes/src/lang_items.rs8
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs6
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs2
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs15
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs4
-rw-r--r--src/tools/rustfmt/src/items.rs4
-rw-r--r--src/tools/rustfmt/src/visitor.rs2
-rw-r--r--tests/ui/delegation/bad-resolve.rs4
-rw-r--r--tests/ui/delegation/bad-resolve.stderr16
-rw-r--r--tests/ui/delegation/body-identity-list.rs32
-rw-r--r--tests/ui/delegation/empty-list.rs8
-rw-r--r--tests/ui/delegation/empty-list.stderr8
-rw-r--r--tests/ui/delegation/inner-attr.rs8
-rw-r--r--tests/ui/delegation/inner-attr.stderr18
-rw-r--r--tests/ui/delegation/list.rs46
-rw-r--r--tests/ui/delegation/macro-inside-list.rs26
-rw-r--r--tests/ui/delegation/rename.rs15
29 files changed, 509 insertions, 58 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 7951b7e7b75..6d3ee2bb54b 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2961,6 +2961,7 @@ impl Item {
             | ItemKind::GlobalAsm(_)
             | ItemKind::MacCall(_)
             | ItemKind::Delegation(_)
+            | ItemKind::DelegationMac(_)
             | ItemKind::MacroDef(_) => None,
             ItemKind::Static(_) => None,
             ItemKind::Const(i) => Some(&i.generics),
@@ -3123,8 +3124,16 @@ pub struct Delegation {
     /// Path resolution id.
     pub id: NodeId,
     pub qself: Option<P<QSelf>>,
-    pub rename: Option<Ident>,
     pub path: Path,
+    pub rename: Option<Ident>,
+    pub body: Option<P<Block>>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct DelegationMac {
+    pub qself: Option<P<QSelf>>,
+    pub prefix: Path,
+    pub suffixes: ThinVec<(Ident, Option<Ident>)>,
     pub body: Option<P<Block>>,
 }
 
@@ -3243,10 +3252,13 @@ pub enum ItemKind {
     /// A macro definition.
     MacroDef(MacroDef),
 
-    /// A delegation item (`reuse`).
+    /// A single delegation item (`reuse`).
     ///
     /// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
     Delegation(Box<Delegation>),
+    /// A list delegation item (`reuse prefix::{a, b, c}`).
+    /// Treated similarly to a macro call and expanded early.
+    DelegationMac(Box<DelegationMac>),
 }
 
 impl ItemKind {
@@ -3255,7 +3267,7 @@ impl ItemKind {
         match self {
             Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
             | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
-            | Delegation(..) => "a",
+            | Delegation(..) | DelegationMac(..) => "a",
             ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
         }
     }
@@ -3280,6 +3292,7 @@ impl ItemKind {
             ItemKind::MacroDef(..) => "macro definition",
             ItemKind::Impl { .. } => "implementation",
             ItemKind::Delegation(..) => "delegated function",
+            ItemKind::DelegationMac(..) => "delegation",
         }
     }
 
@@ -3323,6 +3336,8 @@ pub enum AssocItemKind {
     MacCall(P<MacCall>),
     /// An associated delegation item.
     Delegation(Box<Delegation>),
+    /// An associated delegation item list.
+    DelegationMac(Box<DelegationMac>),
 }
 
 impl AssocItemKind {
@@ -3331,7 +3346,9 @@ impl AssocItemKind {
             Self::Const(box ConstItem { defaultness, .. })
             | Self::Fn(box Fn { defaultness, .. })
             | Self::Type(box TyAlias { defaultness, .. }) => defaultness,
-            Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final,
+            Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
+                Defaultness::Final
+            }
         }
     }
 }
@@ -3344,6 +3361,7 @@ impl From<AssocItemKind> for ItemKind {
             AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
             AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
             AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
+            AssocItemKind::DelegationMac(delegation) => ItemKind::DelegationMac(delegation),
         }
     }
 }
@@ -3358,6 +3376,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
             ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
             ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
             ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
+            ItemKind::DelegationMac(d) => AssocItemKind::DelegationMac(d),
             _ => return Err(item_kind),
         })
     }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 5c4162295bb..1cfb8972a62 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1170,6 +1170,19 @@ impl NoopVisitItemKind for ItemKind {
                     vis.visit_block(body);
                 }
             }
+            ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
+                vis.visit_qself(qself);
+                vis.visit_path(prefix);
+                for (ident, rename) in suffixes {
+                    vis.visit_ident(ident);
+                    if let Some(rename) = rename {
+                        vis.visit_ident(rename);
+                    }
+                }
+                if let Some(body) = body {
+                    vis.visit_block(body);
+                }
+            }
         }
     }
 }
@@ -1213,6 +1226,19 @@ impl NoopVisitItemKind for AssocItemKind {
                     visitor.visit_block(body);
                 }
             }
+            AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
+                visitor.visit_qself(qself);
+                visitor.visit_path(prefix);
+                for (ident, rename) in suffixes {
+                    visitor.visit_ident(ident);
+                    if let Some(rename) = rename {
+                        visitor.visit_ident(rename);
+                    }
+                }
+                if let Some(body) = body {
+                    visitor.visit_block(body);
+                }
+            }
         }
     }
 }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index d36193ef7b0..7794edc3505 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -403,6 +403,19 @@ impl WalkItemKind for ItemKind {
                 visit_opt!(visitor, visit_ident, *rename);
                 visit_opt!(visitor, visit_block, body);
             }
+            ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
+                if let Some(qself) = qself {
+                    try_visit!(visitor.visit_ty(&qself.ty));
+                }
+                try_visit!(visitor.visit_path(prefix, item.id));
+                for (ident, rename) in suffixes {
+                    visitor.visit_ident(*ident);
+                    if let Some(rename) = rename {
+                        visitor.visit_ident(*rename);
+                    }
+                }
+                visit_opt!(visitor, visit_block, body);
+            }
         }
         V::Result::output()
     }
@@ -815,6 +828,19 @@ impl WalkItemKind for AssocItemKind {
                 visit_opt!(visitor, visit_ident, *rename);
                 visit_opt!(visitor, visit_block, body);
             }
+            AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
+                if let Some(qself) = qself {
+                    try_visit!(visitor.visit_ty(&qself.ty));
+                }
+                try_visit!(visitor.visit_path(prefix, item.id));
+                for (ident, rename) in suffixes {
+                    visitor.visit_ident(*ident);
+                    if let Some(rename) = rename {
+                        visitor.visit_ident(*rename);
+                    }
+                }
+                visit_opt!(visitor, visit_block, body);
+            }
         }
         V::Result::output()
     }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 61fb5c16ad6..1255c1bba08 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -460,8 +460,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     delegation_results.body_id,
                 )
             }
-            ItemKind::MacCall(..) => {
-                panic!("`TyMac` should have been expanded by now")
+            ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
+                panic!("macros should have been expanded by now")
             }
         }
     }
@@ -845,7 +845,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 (delegation_results.generics, item_kind, true)
             }
-            AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                panic!("macros should have been expanded by now")
+            }
         };
 
         let item = hir::TraitItem {
@@ -869,7 +871,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
             AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
                 has_self: self.delegation_has_self(i.id, delegation.id, i.span),
             },
-            AssocItemKind::MacCall(..) => unimplemented!(),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                panic!("macros should have been expanded by now")
+            }
         };
         let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
         hir::TraitItemRef {
@@ -964,7 +968,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
                 )
             }
-            AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                panic!("macros should have been expanded by now")
+            }
         };
 
         let item = hir::ImplItem {
@@ -993,7 +999,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
                     has_self: self.delegation_has_self(i.id, delegation.id, i.span),
                 },
-                AssocItemKind::MacCall(..) => unimplemented!(),
+                AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                    panic!("macros should have been expanded by now")
+                }
             },
             trait_item_def_id: self
                 .resolver
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 09f9ca53a7a..16c3ee948a4 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -5,6 +5,7 @@ use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
 use ast::StaticItem;
 use itertools::{Itertools, Position};
 use rustc_ast as ast;
+use rustc_ast::ptr::P;
 use rustc_ast::ModKind;
 use rustc_span::symbol::Ident;
 
@@ -374,9 +375,22 @@ impl<'a> State<'a> {
                     state.print_visibility(&item.vis)
                 });
             }
-            ast::ItemKind::Delegation(box delegation) => {
-                self.print_delegation(delegation, &item.vis, &item.attrs)
-            }
+            ast::ItemKind::Delegation(deleg) => self.print_delegation(
+                &item.attrs,
+                &item.vis,
+                &deleg.qself,
+                &deleg.path,
+                None,
+                &deleg.body,
+            ),
+            ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
+                &item.attrs,
+                &item.vis,
+                &deleg.qself,
+                &deleg.prefix,
+                Some(&deleg.suffixes),
+                &deleg.body,
+            ),
         }
         self.ann.post(self, AnnNode::Item(item))
     }
@@ -553,31 +567,63 @@ impl<'a> State<'a> {
                     self.word(";");
                 }
             }
-            ast::AssocItemKind::Delegation(box delegation) => {
-                self.print_delegation(delegation, vis, &item.attrs)
-            }
+            ast::AssocItemKind::Delegation(deleg) => self.print_delegation(
+                &item.attrs,
+                vis,
+                &deleg.qself,
+                &deleg.path,
+                None,
+                &deleg.body,
+            ),
+            ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
+                &item.attrs,
+                vis,
+                &deleg.qself,
+                &deleg.prefix,
+                Some(&deleg.suffixes),
+                &deleg.body,
+            ),
         }
         self.ann.post(self, AnnNode::SubItem(id))
     }
 
     pub(crate) fn print_delegation(
         &mut self,
-        delegation: &ast::Delegation,
-        vis: &ast::Visibility,
         attrs: &[ast::Attribute],
+        vis: &ast::Visibility,
+        qself: &Option<P<ast::QSelf>>,
+        path: &ast::Path,
+        suffixes: Option<&[(Ident, Option<Ident>)]>,
+        body: &Option<P<ast::Block>>,
     ) {
-        if delegation.body.is_some() {
+        if body.is_some() {
             self.head("");
         }
         self.print_visibility(vis);
-        self.word_space("reuse");
+        self.word_nbsp("reuse");
 
-        if let Some(qself) = &delegation.qself {
-            self.print_qpath(&delegation.path, qself, false);
+        if let Some(qself) = qself {
+            self.print_qpath(path, qself, false);
         } else {
-            self.print_path(&delegation.path, false, 0);
+            self.print_path(path, false, 0);
+        }
+        if let Some(suffixes) = suffixes {
+            self.word("::");
+            self.word("{");
+            for (i, (ident, rename)) in suffixes.iter().enumerate() {
+                self.print_ident(*ident);
+                if let Some(rename) = rename {
+                    self.nbsp();
+                    self.word_nbsp("as");
+                    self.print_ident(*rename);
+                }
+                if i != suffixes.len() - 1 {
+                    self.word_space(",");
+                }
+            }
+            self.word("}");
         }
-        if let Some(body) = &delegation.body {
+        if let Some(body) = body {
             self.nbsp();
             self.print_block_with_attrs(body, attrs);
         } else {
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index b7aae2af9ef..7ae988a5be6 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -30,6 +30,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
     .label = duplicate binding
     .label2 = previous binding
 
+expand_empty_delegation_list =
+    empty list delegation is not supported
+
 expand_expected_paren_or_brace =
     expected `(` or `{"{"}`, found `{$token}`
 
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index b0563bfdea7..a5fc9e9d89c 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -433,3 +433,10 @@ pub struct ExpectedParenOrBrace<'a> {
     pub span: Span,
     pub token: Cow<'a, str>,
 }
+
+#[derive(Diagnostic)]
+#[diag(expand_empty_delegation_list)]
+pub(crate) struct EmptyDelegationList {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index ddf7b1a007a..a049ac251e1 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1,8 +1,8 @@
 use crate::base::*;
 use crate::config::StripUnconfigured;
 use crate::errors::{
-    IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported,
-    UnsupportedKeyValue, WrongFragmentKind,
+    EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
+    RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
 };
 use crate::mbe::diagnostics::annotate_err_with_kind;
 use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
@@ -1041,6 +1041,7 @@ enum AddSemicolon {
 trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     type OutputTy = SmallVec<[Self; 1]>;
     type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec;
+    type ItemKind = ItemKind;
     const KIND: AstFragmentKind;
     fn to_annotatable(self) -> Annotatable;
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
@@ -1059,6 +1060,18 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
         unreachable!()
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        None
+    }
+    fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        unreachable!()
+    }
+    fn from_item(_item: ast::Item<Self::ItemKind>) -> Self {
+        unreachable!()
+    }
+    fn flatten_outputs(_outputs: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        unreachable!()
+    }
     fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
     fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
     }
@@ -1106,6 +1119,21 @@ impl InvocationCollectorNode for P<ast::Item> {
             _ => unreachable!(),
         }
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        match &self.kind {
+            ItemKind::DelegationMac(deleg) => Some((deleg, self)),
+            _ => None,
+        }
+    }
+    fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        ItemKind::Delegation(deleg)
+    }
+    fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
+        P(item)
+    }
+    fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        items.flatten().collect()
+    }
     fn wrap_flat_map_node_noop_flat_map(
         mut node: Self,
         collector: &mut InvocationCollector<'_, '_>,
@@ -1214,6 +1242,7 @@ impl InvocationCollectorNode for P<ast::Item> {
 struct TraitItemTag;
 impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> {
     type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+    type ItemKind = AssocItemKind;
     const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
     fn to_annotatable(self) -> Annotatable {
         Annotatable::TraitItem(self.wrapped)
@@ -1234,11 +1263,27 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
             _ => unreachable!(),
         }
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        match &self.wrapped.kind {
+            AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
+            _ => None,
+        }
+    }
+    fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        AssocItemKind::Delegation(deleg)
+    }
+    fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
+        AstNodeWrapper::new(P(item), TraitItemTag)
+    }
+    fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        items.flatten().collect()
+    }
 }
 
 struct ImplItemTag;
 impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> {
     type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+    type ItemKind = AssocItemKind;
     const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
     fn to_annotatable(self) -> Annotatable {
         Annotatable::ImplItem(self.wrapped)
@@ -1259,6 +1304,21 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
             _ => unreachable!(),
         }
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        match &self.wrapped.kind {
+            AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
+            _ => None,
+        }
+    }
+    fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        AssocItemKind::Delegation(deleg)
+    }
+    fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
+        AstNodeWrapper::new(P(item), ImplItemTag)
+    }
+    fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        items.flatten().collect()
+    }
 }
 
 impl InvocationCollectorNode for P<ast::ForeignItem> {
@@ -1420,6 +1480,24 @@ impl InvocationCollectorNode for ast::Stmt {
         };
         (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        match &self.kind {
+            StmtKind::Item(item) => match &item.kind {
+                ItemKind::DelegationMac(deleg) => Some((deleg, item)),
+                _ => None,
+            },
+            _ => None,
+        }
+    }
+    fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        ItemKind::Delegation(deleg)
+    }
+    fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
+        ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) }
+    }
+    fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        items.flatten().collect()
+    }
     fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
         // If this is a macro invocation with a semicolon, then apply that
         // semicolon to the final statement produced by expansion.
@@ -1818,6 +1896,40 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                     Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
                     res
                 }
+                None if let Some((deleg, item)) = node.delegation_list() => {
+                    if deleg.suffixes.is_empty() {
+                        // Report an error for now, to avoid keeping stem for resolution and
+                        // stability checks.
+                        self.cx.dcx().emit_err(EmptyDelegationList { span: item.span });
+                    }
+
+                    Node::flatten_outputs(deleg.suffixes.iter().map(|&(ident, rename)| {
+                        let mut path = deleg.prefix.clone();
+                        path.segments.push(ast::PathSegment {
+                            ident,
+                            id: ast::DUMMY_NODE_ID,
+                            args: None,
+                        });
+
+                        let mut item = Node::from_item(ast::Item {
+                            attrs: item.attrs.clone(),
+                            id: ast::DUMMY_NODE_ID,
+                            span: ident.span,
+                            vis: item.vis.clone(),
+                            ident: rename.unwrap_or(ident),
+                            kind: Node::delegation_item_kind(Box::new(ast::Delegation {
+                                id: ast::DUMMY_NODE_ID,
+                                qself: deleg.qself.clone(),
+                                path,
+                                rename,
+                                body: deleg.body.clone(),
+                            })),
+                            tokens: None,
+                        });
+
+                        assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
+                    }))
+                }
                 None => {
                     match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
                         assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this))
@@ -1866,6 +1978,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                         self.collect_bang(mac, Node::KIND).make_ast::<Node>()
                     })
                 }
+                None if node.delegation_list().is_some() => unreachable!(),
                 None => {
                     assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
                 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 29957bd2f71..5a3bfb83725 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -685,20 +685,35 @@ impl<'a> Parser<'a> {
             (None, self.parse_path(PathStyle::Expr)?)
         };
 
-        let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None };
+        let rename = |this: &mut Self| {
+            Ok(if this.eat_keyword(kw::As) { Some(this.parse_ident()?) } else { None })
+        };
+        let body = |this: &mut Self| {
+            Ok(if this.check(&token::OpenDelim(Delimiter::Brace)) {
+                Some(this.parse_block()?)
+            } else {
+                this.expect(&token::Semi)?;
+                None
+            })
+        };
 
-        let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
-            Some(self.parse_block()?)
+        let (ident, item_kind) = if self.eat(&token::PathSep) {
+            let (suffixes, _) = self.parse_delim_comma_seq(Delimiter::Brace, |p| {
+                Ok((p.parse_path_segment_ident()?, rename(p)?))
+            })?;
+            let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
+            (Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
         } else {
-            self.expect(&token::Semi)?;
-            None
+            let rename = rename(self)?;
+            let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
+            let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body: body(self)? };
+            (ident, ItemKind::Delegation(Box::new(deleg)))
         };
+
         let span = span.to(self.prev_token.span);
         self.psess.gated_spans.gate(sym::fn_delegation, span);
 
-        let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
-        let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body };
-        Ok((ident, ItemKind::Delegation(Box::new(deleg))))
+        Ok((ident, item_kind))
     }
 
     fn parse_item_list<T>(
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index c37d3f0441d..d845e8ab90d 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -95,12 +95,15 @@ impl<'a> Parser<'a> {
             debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
         }
 
-        if !self.recover_colon_before_qpath_proj() {
+        let is_import_coupler = self.is_import_coupler();
+        if !is_import_coupler && !self.recover_colon_before_qpath_proj() {
             self.expect(&token::PathSep)?;
         }
 
         let qself = P(QSelf { ty, path_span, position: path.segments.len() });
-        self.parse_path_segments(&mut path.segments, style, None)?;
+        if !is_import_coupler {
+            self.parse_path_segments(&mut path.segments, style, None)?;
+        }
 
         Ok((
             qself,
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d7664d1c1ff..a980d5dcaba 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -522,7 +522,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
                 Impl,
                 MacCall,
                 MacroDef,
-                Delegation
+                Delegation,
+                DelegationMac
             ]
         );
         ast_visit::walk_item(self, i)
@@ -650,7 +651,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
         record_variants!(
             (self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
-            [Const, Fn, Type, MacCall, Delegation]
+            [Const, Fn, Type, MacCall, Delegation, DelegationMac]
         );
         ast_visit::walk_assoc_item(self, i, ctxt);
     }
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index c1da8928f30..a5fa94faead 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -285,7 +285,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
             ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias,
             ast::ItemKind::Impl(_) => Target::Impl,
             ast::ItemKind::MacroDef(_) => Target::MacroDef,
-            ast::ItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
+            ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => {
+                unreachable!("macros should have been expanded")
+            }
         };
 
         self.check_for_lang(
@@ -340,7 +342,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
             }
             ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
             ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)),
-            ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
+            ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(_) => {
+                unreachable!("macros should have been expanded")
+            }
         };
 
         self.check_for_lang(
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 3467f1c3edf..3e9aa3e0a6f 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -825,7 +825,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             }
             ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
 
-            ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(),
+            ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
+                unreachable!()
+            }
         }
     }
 
@@ -1381,7 +1383,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 | AssocItemKind::Delegation(..)
                 | AssocItemKind::Fn(..) => ValueNS,
                 AssocItemKind::Type(..) => TypeNS,
-                AssocItemKind::MacCall(_) => bug!(), // handled above
+                AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
             };
 
             let parent = self.parent_scope.module;
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index a27a6bceda3..741a650da55 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -139,6 +139,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
             ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
             ItemKind::Use(..) => return visit::walk_item(self, i),
             ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
+            ItemKind::DelegationMac(..) => unreachable!(),
         };
         let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
 
@@ -278,6 +279,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
             AssocItemKind::Const(..) => DefKind::AssocConst,
             AssocItemKind::Type(..) => DefKind::AssocTy,
             AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
+            AssocItemKind::DelegationMac(..) => unreachable!(),
         };
 
         let def = self.create_def(i.id, i.ident.name, def_kind, i.span);
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 3443bbe6e11..074bf810eaf 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -236,7 +236,7 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't
             ast::ItemKind::Impl(..) => return,
 
             // Should be unreachable at this stage
-            ast::ItemKind::MacCall(..) => panic!(
+            ast::ItemKind::MacCall(..) | ast::ItemKind::DelegationMac(..) => panic!(
                 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
             ),
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 5dd95a1896b..322f2922f92 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2561,7 +2561,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
             ItemKind::ExternCrate(..) => {}
 
-            ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"),
+            ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
+                panic!("unexpanded macro in resolve!")
+            }
         }
     }
 
@@ -2849,7 +2851,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
                         walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
                     }),
-                AssocItemKind::MacCall(_) => {
+                AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
                     panic!("unexpanded macro in resolve!")
                 }
             };
@@ -3116,7 +3118,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     },
                 );
             }
-            AssocItemKind::MacCall(_) => {
+            AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
                 panic!("unexpanded macro in resolve!")
             }
         }
@@ -3218,7 +3220,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             AssocItemKind::Fn(..) => (E0324, "method"),
             AssocItemKind::Type(..) => (E0325, "type"),
             AssocItemKind::Delegation(..) => (E0324, "method"),
-            AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                span_bug!(span, "unexpanded macro")
+            }
         };
         let trait_path = path_names_to_string(path);
         self.report_error(
@@ -4790,7 +4794,8 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
             | ItemKind::ExternCrate(..)
             | ItemKind::MacroDef(..)
             | ItemKind::GlobalAsm(..)
-            | ItemKind::MacCall(..) => {}
+            | ItemKind::MacCall(..)
+            | ItemKind::DelegationMac(..) => {}
             ItemKind::Delegation(..) => {
                 // Delegated functions have lifetimes, their count is not necessarily zero.
                 // But skipping the delegation items here doesn't mean that the count will be considered zero,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 64451030adf..12815291c1d 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2045,7 +2045,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             AssocSuggestion::MethodWithSelf { called }
                         }
                         ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
-                        ast::AssocItemKind::MacCall(_) => continue,
+                        ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(..) => {
+                            continue;
+                        }
                     });
                 }
             }
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index e196d1817f3..90e9e58ef9c 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -739,8 +739,8 @@ impl<'a> FmtVisitor<'a> {
                 (_, Const(..)) => Ordering::Greater,
                 (MacCall(..), _) => Ordering::Less,
                 (_, MacCall(..)) => Ordering::Greater,
-                (Delegation(..), _) => Ordering::Less,
-                (_, Delegation(..)) => Ordering::Greater,
+                (Delegation(..), _) | (DelegationMac(..), _) => Ordering::Less,
+                (_, Delegation(..)) | (_, DelegationMac(..)) => Ordering::Greater,
             });
             let mut prev_kind = None;
             for (buf, item) in buffer {
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 6209b37004b..e1c7dc35087 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -586,7 +586,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                     );
                     self.push_rewrite(item.span, rewrite);
                 }
-                ast::ItemKind::Delegation(..) => {
+                ast::ItemKind::Delegation(..) | ast::ItemKind::DelegationMac(..) => {
                     // TODO: rewrite delegation items once syntax is established.
                     // For now, leave the contents of the Span unformatted.
                     self.push_rewrite(item.span, None)
diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs
index d2723dc32e0..f378e05304b 100644
--- a/tests/ui/delegation/bad-resolve.rs
+++ b/tests/ui/delegation/bad-resolve.rs
@@ -36,4 +36,8 @@ impl Trait for S {
     //~^ ERROR cannot find function `foo` in this scope
 }
 
+mod prefix {}
+reuse unresolved_prefix::{a, b, c}; //~ ERROR use of undeclared crate or module `unresolved_prefix`
+reuse prefix::{self, super, crate}; //~ ERROR `crate` in paths can only be used in start position
+
 fn main() {}
diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr
index f669ac3730e..883ff523bcf 100644
--- a/tests/ui/delegation/bad-resolve.stderr
+++ b/tests/ui/delegation/bad-resolve.stderr
@@ -63,7 +63,19 @@ LL |     type Type;
 LL | impl Trait for S {
    | ^^^^^^^^^^^^^^^^ missing `Type` in implementation
 
-error: aborting due to 8 previous errors
+error[E0433]: failed to resolve: use of undeclared crate or module `unresolved_prefix`
+  --> $DIR/bad-resolve.rs:40:7
+   |
+LL | reuse unresolved_prefix::{a, b, c};
+   |       ^^^^^^^^^^^^^^^^^ use of undeclared crate or module `unresolved_prefix`
+
+error[E0433]: failed to resolve: `crate` in paths can only be used in start position
+  --> $DIR/bad-resolve.rs:41:29
+   |
+LL | reuse prefix::{self, super, crate};
+   |                             ^^^^^ `crate` in paths can only be used in start position
+
+error: aborting due to 10 previous errors
 
-Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0575, E0576.
+Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0433, E0575, E0576.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/delegation/body-identity-list.rs b/tests/ui/delegation/body-identity-list.rs
new file mode 100644
index 00000000000..1f08ab4e1a4
--- /dev/null
+++ b/tests/ui/delegation/body-identity-list.rs
@@ -0,0 +1,32 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn foo(&self) {}
+    fn bar(&self) {}
+}
+
+impl Trait for u8 {}
+
+struct S(u8);
+
+mod to_import {
+    pub fn check(arg: &u8) -> &u8 { arg }
+}
+
+impl Trait for S {
+    reuse Trait::{foo, bar} {
+        use to_import::check;
+
+        let _arr = Some(self.0).map(|x| [x * 2; 3]);
+        check(&self.0)
+    }
+}
+
+fn main() {
+    let s = S(0);
+    s.foo();
+    s.bar();
+}
diff --git a/tests/ui/delegation/empty-list.rs b/tests/ui/delegation/empty-list.rs
new file mode 100644
index 00000000000..e0697f42283
--- /dev/null
+++ b/tests/ui/delegation/empty-list.rs
@@ -0,0 +1,8 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod m {}
+
+reuse m::{}; //~ ERROR empty list delegation is not supported
+
+fn main() {}
diff --git a/tests/ui/delegation/empty-list.stderr b/tests/ui/delegation/empty-list.stderr
new file mode 100644
index 00000000000..50d3c0eee22
--- /dev/null
+++ b/tests/ui/delegation/empty-list.stderr
@@ -0,0 +1,8 @@
+error: empty list delegation is not supported
+  --> $DIR/empty-list.rs:6:1
+   |
+LL | reuse m::{};
+   | ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/delegation/inner-attr.rs b/tests/ui/delegation/inner-attr.rs
new file mode 100644
index 00000000000..6c996807d6b
--- /dev/null
+++ b/tests/ui/delegation/inner-attr.rs
@@ -0,0 +1,8 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+fn a() {}
+
+reuse a as b { #![rustc_dummy] self } //~ ERROR an inner attribute is not permitted in this context
+
+fn main() {}
diff --git a/tests/ui/delegation/inner-attr.stderr b/tests/ui/delegation/inner-attr.stderr
new file mode 100644
index 00000000000..f3b53e331ad
--- /dev/null
+++ b/tests/ui/delegation/inner-attr.stderr
@@ -0,0 +1,18 @@
+error: an inner attribute is not permitted in this context
+  --> $DIR/inner-attr.rs:6:16
+   |
+LL | reuse a as b { #![rustc_dummy] self }
+   |                ^^^^^^^^^^^^^^^
+LL |
+LL | fn main() {}
+   | ------------ the inner attribute doesn't annotate this function
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+help: to annotate the function, change the attribute from inner to outer style
+   |
+LL - reuse a as b { #![rustc_dummy] self }
+LL + reuse a as b { #[rustc_dummy] self }
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/delegation/list.rs b/tests/ui/delegation/list.rs
new file mode 100644
index 00000000000..208b1481679
--- /dev/null
+++ b/tests/ui/delegation/list.rs
@@ -0,0 +1,46 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn foo(&self) -> u8 { 0 }
+    fn bar(&self) -> u8 { 1 }
+}
+
+impl Trait for u8 {}
+
+struct S(u8);
+struct Z(u8);
+
+impl Trait for S {
+    reuse Trait::{foo, bar} { &self.0 }
+}
+
+impl Trait for Z {
+    reuse <u8 as Trait>::{foo, bar} { &self.0 }
+}
+
+trait Trait2 where Self: Trait {
+    reuse Trait::{foo, bar};
+}
+
+mod to_reuse {
+    pub fn a() {}
+    pub fn b() {}
+}
+
+reuse to_reuse::{a, b};
+
+fn main() {
+    let s = S(2);
+    s.foo();
+    s.bar();
+
+    let z = Z(3);
+    z.foo();
+    z.bar();
+
+    a();
+    b();
+}
diff --git a/tests/ui/delegation/macro-inside-list.rs b/tests/ui/delegation/macro-inside-list.rs
new file mode 100644
index 00000000000..16c74d396ef
--- /dev/null
+++ b/tests/ui/delegation/macro-inside-list.rs
@@ -0,0 +1,26 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn foo(&self) -> u8 { 0 }
+    fn bar(&self) -> u8 { 1 }
+}
+
+impl Trait for u8 {}
+
+struct S(u8);
+
+// Macro expansion works inside delegation items.
+macro_rules! u8 { () => { u8 } }
+macro_rules! self_0 { () => { &self.0 } }
+impl Trait for S {
+    reuse <u8!() as Trait>::{foo, bar} { self_0!() }
+}
+
+fn main() {
+    let s = S(2);
+    s.foo();
+    s.bar();
+}
diff --git a/tests/ui/delegation/rename.rs b/tests/ui/delegation/rename.rs
index f4b3da76c56..80b8724a5bf 100644
--- a/tests/ui/delegation/rename.rs
+++ b/tests/ui/delegation/rename.rs
@@ -5,16 +5,23 @@
 
 mod to_reuse {
     pub fn a() {}
+    pub fn b() {}
 }
 
-reuse to_reuse::a as b;
+reuse to_reuse::a as x;
+reuse to_reuse::{a as y, b as z};
 
 struct S;
 impl S {
-    reuse to_reuse::a as b;
+    reuse to_reuse::a as x;
+    reuse to_reuse::{a as y, b as z};
 }
 
 fn main() {
-    b();
-    S::b();
+    x();
+    y();
+    z();
+    S::x();
+    S::y();
+    S::z();
 }