about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs9
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs38
-rw-r--r--compiler/rustc_ast/src/visit.rs38
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs51
-rw-r--r--compiler/rustc_expand/messages.ftl7
-rw-r--r--compiler/rustc_expand/src/base.rs47
-rw-r--r--compiler/rustc_expand/src/errors.rs12
-rw-r--r--compiler/rustc_expand/src/expand.rs152
-rw-r--r--compiler/rustc_parse/src/errors.rs3
-rw-r--r--compiler/rustc_parse/src/parser/item.rs24
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs28
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs10
-rw-r--r--compiler/rustc_resolve/src/lib.rs14
-rw-r--r--compiler/rustc_resolve/src/macros.rs152
-rw-r--r--tests/ui/delegation/body-identity-glob.rs32
-rw-r--r--tests/ui/delegation/empty-glob.rs11
-rw-r--r--tests/ui/delegation/empty-glob.stderr8
-rw-r--r--tests/ui/delegation/glob-bad-path.rs12
-rw-r--r--tests/ui/delegation/glob-bad-path.stderr15
-rw-r--r--tests/ui/delegation/glob-glob-conflict.rs33
-rw-r--r--tests/ui/delegation/glob-glob-conflict.stderr25
-rw-r--r--tests/ui/delegation/glob-glob.rs36
-rw-r--r--tests/ui/delegation/glob-non-fn.rs38
-rw-r--r--tests/ui/delegation/glob-non-fn.stderr62
-rw-r--r--tests/ui/delegation/glob-non-impl.rs20
-rw-r--r--tests/ui/delegation/glob-non-impl.stderr26
-rw-r--r--tests/ui/delegation/glob-override.rs37
-rw-r--r--tests/ui/delegation/glob.rs35
-rw-r--r--tests/ui/delegation/macro-inside-glob.rs26
29 files changed, 878 insertions, 123 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index fe888d2004f..7f766e63e06 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3161,13 +3161,16 @@ pub struct Delegation {
     pub path: Path,
     pub rename: Option<Ident>,
     pub body: Option<P<Block>>,
+    /// The item was expanded from a glob delegation item.
+    pub from_glob: bool,
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct DelegationMac {
     pub qself: Option<P<QSelf>>,
     pub prefix: Path,
-    pub suffixes: ThinVec<(Ident, Option<Ident>)>,
+    // Some for list delegation, and None for glob delegation.
+    pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
     pub body: Option<P<Block>>,
 }
 
@@ -3294,7 +3297,7 @@ pub enum ItemKind {
     ///
     /// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
     Delegation(Box<Delegation>),
-    /// A list delegation item (`reuse prefix::{a, b, c}`).
+    /// A list or glob delegation item (`reuse prefix::{a, b, c}`, `reuse prefix::*`).
     /// Treated similarly to a macro call and expanded early.
     DelegationMac(Box<DelegationMac>),
 }
@@ -3375,7 +3378,7 @@ pub enum AssocItemKind {
     MacCall(P<MacCall>),
     /// An associated delegation item.
     Delegation(Box<Delegation>),
-    /// An associated delegation item list.
+    /// An associated list or glob delegation item.
     DelegationMac(Box<DelegationMac>),
 }
 
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 182ad7359af..35aa53e978c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1162,7 +1162,14 @@ impl NoopVisitItemKind for ItemKind {
             }
             ItemKind::MacCall(m) => vis.visit_mac_call(m),
             ItemKind::MacroDef(def) => vis.visit_macro_def(def),
-            ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
+            ItemKind::Delegation(box Delegation {
+                id,
+                qself,
+                path,
+                rename,
+                body,
+                from_glob: _,
+            }) => {
                 vis.visit_id(id);
                 vis.visit_qself(qself);
                 vis.visit_path(path);
@@ -1176,10 +1183,12 @@ impl NoopVisitItemKind for ItemKind {
             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(suffixes) = suffixes {
+                    for (ident, rename) in suffixes {
+                        vis.visit_ident(ident);
+                        if let Some(rename) = rename {
+                            vis.visit_ident(rename);
+                        }
                     }
                 }
                 if let Some(body) = body {
@@ -1218,7 +1227,14 @@ impl NoopVisitItemKind for AssocItemKind {
                 visit_opt(ty, |ty| visitor.visit_ty(ty));
             }
             AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
-            AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
+            AssocItemKind::Delegation(box Delegation {
+                id,
+                qself,
+                path,
+                rename,
+                body,
+                from_glob: _,
+            }) => {
                 visitor.visit_id(id);
                 visitor.visit_qself(qself);
                 visitor.visit_path(path);
@@ -1232,10 +1248,12 @@ impl NoopVisitItemKind for AssocItemKind {
             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(suffixes) = suffixes {
+                    for (ident, rename) in suffixes {
+                        visitor.visit_ident(ident);
+                        if let Some(rename) = rename {
+                            visitor.visit_ident(rename);
+                        }
                     }
                 }
                 if let Some(body) = body {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 104a401cd53..ed34a44db67 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -408,7 +408,14 @@ impl WalkItemKind for ItemKind {
             }
             ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
             ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
-            ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
+            ItemKind::Delegation(box Delegation {
+                id,
+                qself,
+                path,
+                rename,
+                body,
+                from_glob: _,
+            }) => {
                 if let Some(qself) = qself {
                     try_visit!(visitor.visit_ty(&qself.ty));
                 }
@@ -421,10 +428,12 @@ impl WalkItemKind for ItemKind {
                     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);
+                if let Some(suffixes) = suffixes {
+                    for (ident, rename) in suffixes {
+                        visitor.visit_ident(*ident);
+                        if let Some(rename) = rename {
+                            visitor.visit_ident(*rename);
+                        }
                     }
                 }
                 visit_opt!(visitor, visit_block, body);
@@ -837,7 +846,14 @@ impl WalkItemKind for AssocItemKind {
             AssocItemKind::MacCall(mac) => {
                 try_visit!(visitor.visit_mac_call(mac));
             }
-            AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
+            AssocItemKind::Delegation(box Delegation {
+                id,
+                qself,
+                path,
+                rename,
+                body,
+                from_glob: _,
+            }) => {
                 if let Some(qself) = qself {
                     try_visit!(visitor.visit_ty(&qself.ty));
                 }
@@ -850,10 +866,12 @@ impl WalkItemKind for AssocItemKind {
                     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);
+                if let Some(suffixes) = suffixes {
+                    for (ident, rename) in suffixes {
+                        visitor.visit_ident(*ident);
+                        if let Some(rename) = rename {
+                            visitor.visit_ident(*rename);
+                        }
                     }
                 }
                 visit_opt!(visitor, visit_block, body);
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 474741fb067..49ac5ece337 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -9,6 +9,12 @@ use rustc_ast::ptr::P;
 use rustc_ast::ModKind;
 use rustc_span::symbol::Ident;
 
+enum DelegationKind<'a> {
+    Single,
+    List(&'a [(Ident, Option<Ident>)]),
+    Glob,
+}
+
 fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
     format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
 }
@@ -387,7 +393,7 @@ impl<'a> State<'a> {
                 &item.vis,
                 &deleg.qself,
                 &deleg.path,
-                None,
+                DelegationKind::Single,
                 &deleg.body,
             ),
             ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
@@ -395,7 +401,7 @@ impl<'a> State<'a> {
                 &item.vis,
                 &deleg.qself,
                 &deleg.prefix,
-                Some(&deleg.suffixes),
+                deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
                 &deleg.body,
             ),
         }
@@ -579,7 +585,7 @@ impl<'a> State<'a> {
                 vis,
                 &deleg.qself,
                 &deleg.path,
-                None,
+                DelegationKind::Single,
                 &deleg.body,
             ),
             ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
@@ -587,20 +593,20 @@ impl<'a> State<'a> {
                 vis,
                 &deleg.qself,
                 &deleg.prefix,
-                Some(&deleg.suffixes),
+                deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
                 &deleg.body,
             ),
         }
         self.ann.post(self, AnnNode::SubItem(id))
     }
 
-    pub(crate) fn print_delegation(
+    fn print_delegation(
         &mut self,
         attrs: &[ast::Attribute],
         vis: &ast::Visibility,
         qself: &Option<P<ast::QSelf>>,
         path: &ast::Path,
-        suffixes: Option<&[(Ident, Option<Ident>)]>,
+        kind: DelegationKind<'_>,
         body: &Option<P<ast::Block>>,
     ) {
         if body.is_some() {
@@ -614,21 +620,28 @@ impl<'a> State<'a> {
         } else {
             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(",");
+        match kind {
+            DelegationKind::Single => {}
+            DelegationKind::List(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("}");
+            }
+            DelegationKind::Glob => {
+                self.word("::");
+                self.word("*");
             }
-            self.word("}");
         }
         if let Some(body) = body {
             self.nbsp();
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 2e150f7bb27..6113580491e 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -35,8 +35,8 @@ expand_duplicate_matcher_binding = duplicate matcher binding
     .label = duplicate binding
     .label2 = previous binding
 
-expand_empty_delegation_list =
-    empty list delegation is not supported
+expand_empty_delegation_mac =
+    empty {$kind} delegation is not supported
 
 expand_expected_paren_or_brace =
     expected `(` or `{"{"}`, found `{$token}`
@@ -58,6 +58,9 @@ expand_feature_removed =
     .label = feature has been removed
     .reason = {$reason}
 
+expand_glob_delegation_outside_impls =
+    glob delegation is only supported in impls
+
 expand_helper_attribute_name_invalid =
     `{$name}` cannot be a name of derive helper attribute
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index ddc6490ac0c..d8e6d3525da 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -357,6 +357,10 @@ where
     }
 }
 
+pub trait GlobDelegationExpander {
+    fn expand(&self, ecx: &mut ExtCtxt<'_>) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()>;
+}
+
 // Use a macro because forwarding to a simple function has type system issues
 macro_rules! make_stmts_default {
     ($me:expr) => {
@@ -714,6 +718,9 @@ pub enum SyntaxExtensionKind {
         /// The produced AST fragment is appended to the input AST fragment.
         Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
     ),
+
+    /// A glob delegation.
+    GlobDelegation(Box<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>),
 }
 
 /// A struct representing a macro definition in "lowered" form ready for expansion.
@@ -748,7 +755,9 @@ impl SyntaxExtension {
     /// Returns which kind of macro calls this syntax extension.
     pub fn macro_kind(&self) -> MacroKind {
         match self.kind {
-            SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
+            SyntaxExtensionKind::Bang(..)
+            | SyntaxExtensionKind::LegacyBang(..)
+            | SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
             SyntaxExtensionKind::Attr(..)
             | SyntaxExtensionKind::LegacyAttr(..)
             | SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
@@ -922,6 +931,32 @@ impl SyntaxExtension {
         SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition)
     }
 
+    pub fn glob_delegation(
+        trait_def_id: DefId,
+        impl_def_id: LocalDefId,
+        edition: Edition,
+    ) -> SyntaxExtension {
+        struct GlobDelegationExpanderImpl {
+            trait_def_id: DefId,
+            impl_def_id: LocalDefId,
+        }
+        impl GlobDelegationExpander for GlobDelegationExpanderImpl {
+            fn expand(
+                &self,
+                ecx: &mut ExtCtxt<'_>,
+            ) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()> {
+                match ecx.resolver.glob_delegation_suffixes(self.trait_def_id, self.impl_def_id) {
+                    Ok(suffixes) => ExpandResult::Ready(suffixes),
+                    Err(Indeterminate) if ecx.force_mode => ExpandResult::Ready(Vec::new()),
+                    Err(Indeterminate) => ExpandResult::Retry(()),
+                }
+            }
+        }
+
+        let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id };
+        SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Box::new(expander)), edition)
+    }
+
     pub fn expn_data(
         &self,
         parent: LocalExpnId,
@@ -1030,6 +1065,16 @@ pub trait ResolverExpand {
 
     /// Tools registered with `#![register_tool]` and used by tool attributes and lints.
     fn registered_tools(&self) -> &RegisteredTools;
+
+    /// Mark this invocation id as a glob delegation.
+    fn register_glob_delegation(&mut self, invoc_id: LocalExpnId);
+
+    /// Names of specific methods to which glob delegation expands.
+    fn glob_delegation_suffixes(
+        &mut self,
+        trait_def_id: DefId,
+        impl_def_id: LocalDefId,
+    ) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;
 }
 
 pub trait LintStoreExpand {
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 3f8b4661e5f..c883121fb40 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -435,8 +435,16 @@ pub struct ExpectedParenOrBrace<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(expand_empty_delegation_list)]
-pub(crate) struct EmptyDelegationList {
+#[diag(expand_empty_delegation_mac)]
+pub(crate) struct EmptyDelegationMac {
+    #[primary_span]
+    pub span: Span,
+    pub kind: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_glob_delegation_outside_impls)]
+pub(crate) struct GlobDelegationOutsideImpls {
     #[primary_span]
     pub span: Span,
 }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c28a09eb57c..716bfc8c26b 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::{
-    EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
-    RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
+    EmptyDelegationMac, GlobDelegationOutsideImpls, 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};
@@ -343,6 +343,9 @@ pub enum InvocationKind {
         is_const: bool,
         item: Annotatable,
     },
+    GlobDelegation {
+        item: P<ast::AssocItem>,
+    },
 }
 
 impl InvocationKind {
@@ -370,6 +373,7 @@ impl Invocation {
             InvocationKind::Bang { span, .. } => *span,
             InvocationKind::Attr { attr, .. } => attr.span,
             InvocationKind::Derive { path, .. } => path.span,
+            InvocationKind::GlobDelegation { item } => item.span,
         }
     }
 
@@ -378,6 +382,7 @@ impl Invocation {
             InvocationKind::Bang { span, .. } => span,
             InvocationKind::Attr { attr, .. } => &mut attr.span,
             InvocationKind::Derive { path, .. } => &mut path.span,
+            InvocationKind::GlobDelegation { item } => &mut item.span,
         }
     }
 }
@@ -800,6 +805,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 _ => unreachable!(),
             },
+            InvocationKind::GlobDelegation { item } => {
+                let AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };
+                let suffixes = match ext {
+                    SyntaxExtensionKind::GlobDelegation(expander) => match expander.expand(self.cx)
+                    {
+                        ExpandResult::Ready(suffixes) => suffixes,
+                        ExpandResult::Retry(()) => {
+                            // Reassemble the original invocation for retrying.
+                            return ExpandResult::Retry(Invocation {
+                                kind: InvocationKind::GlobDelegation { item },
+                                ..invoc
+                            });
+                        }
+                    },
+                    SyntaxExtensionKind::LegacyBang(..) => {
+                        let msg = "expanded a dummy glob delegation";
+                        let guar = self.cx.dcx().span_delayed_bug(span, msg);
+                        return ExpandResult::Ready(fragment_kind.dummy(span, guar));
+                    }
+                    _ => unreachable!(),
+                };
+
+                type Node = AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>;
+                let single_delegations = build_single_delegations::<Node>(
+                    self.cx, deleg, &item, &suffixes, item.span, true,
+                );
+                fragment_kind.expect_from_annotatables(
+                    single_delegations.map(|item| Annotatable::ImplItem(P(item))),
+                )
+            }
         })
     }
 
@@ -1067,7 +1102,7 @@ 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>)> {
+    fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
         None
     }
     fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
@@ -1126,7 +1161,7 @@ impl InvocationCollectorNode for P<ast::Item> {
             _ => unreachable!(),
         }
     }
-    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+    fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
         match &self.kind {
             ItemKind::DelegationMac(deleg) => Some((deleg, self)),
             _ => None,
@@ -1270,7 +1305,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
             _ => unreachable!(),
         }
     }
-    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+    fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
         match &self.wrapped.kind {
             AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
             _ => None,
@@ -1311,7 +1346,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
             _ => unreachable!(),
         }
     }
-    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+    fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
         match &self.wrapped.kind {
             AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
             _ => None,
@@ -1487,7 +1522,7 @@ 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>)> {
+    fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
         match &self.kind {
             StmtKind::Item(item) => match &item.kind {
                 ItemKind::DelegationMac(deleg) => Some((deleg, item)),
@@ -1684,6 +1719,44 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag>
     }
 }
 
+fn build_single_delegations<'a, Node: InvocationCollectorNode>(
+    ecx: &ExtCtxt<'_>,
+    deleg: &'a ast::DelegationMac,
+    item: &'a ast::Item<Node::ItemKind>,
+    suffixes: &'a [(Ident, Option<Ident>)],
+    item_span: Span,
+    from_glob: bool,
+) -> impl Iterator<Item = ast::Item<Node::ItemKind>> + 'a {
+    if suffixes.is_empty() {
+        // Report an error for now, to avoid keeping stem for resolution and
+        // stability checks.
+        let kind = String::from(if from_glob { "glob" } else { "list" });
+        ecx.dcx().emit_err(EmptyDelegationMac { span: item.span, kind });
+    }
+
+    suffixes.iter().map(move |&(ident, rename)| {
+        let mut path = deleg.prefix.clone();
+        path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args: None });
+
+        ast::Item {
+            attrs: item.attrs.clone(),
+            id: ast::DUMMY_NODE_ID,
+            span: if from_glob { item_span } else { 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(),
+                from_glob,
+            })),
+            tokens: None,
+        }
+    })
+}
+
 struct InvocationCollector<'a, 'b> {
     cx: &'a mut ExtCtxt<'b>,
     invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
@@ -1702,6 +1775,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
         let expn_id = LocalExpnId::fresh_empty();
+        if matches!(kind, InvocationKind::GlobDelegation { .. }) {
+            // In resolver we need to know which invocation ids are delegations early,
+            // before their `ExpnData` is filled.
+            self.cx.resolver.register_glob_delegation(expn_id);
+        }
         let vis = kind.placeholder_visibility();
         self.invocations.push((
             Invocation {
@@ -1734,6 +1812,14 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         self.collect(kind, InvocationKind::Attr { attr, pos, item, derives })
     }
 
+    fn collect_glob_delegation(
+        &mut self,
+        item: P<ast::AssocItem>,
+        kind: AstFragmentKind,
+    ) -> AstFragment {
+        self.collect(kind, InvocationKind::GlobDelegation { item })
+    }
+
     /// If `item` is an attribute invocation, remove the attribute and return it together with
     /// its position and derives following it. We have to collect the derives in order to resolve
     /// legacy derive helpers (helpers written before derives that introduce them).
@@ -1901,37 +1987,27 @@ 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,
-                        });
+                None if let Some((deleg, item)) = node.delegation() => {
+                    let Some(suffixes) = &deleg.suffixes else {
+                        let item = match node.to_annotatable() {
+                            Annotatable::ImplItem(item) => item,
+                            ann @ (Annotatable::Item(_)
+                            | Annotatable::TraitItem(_)
+                            | Annotatable::Stmt(_)) => {
+                                let span = ann.span();
+                                self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span });
+                                return Default::default();
+                            }
+                            _ => unreachable!(),
+                        };
+                        return self.collect_glob_delegation(item, Node::KIND).make_ast::<Node>();
+                    };
 
+                    let single_delegations = build_single_delegations::<Node>(
+                        self.cx, deleg, item, suffixes, item.span, false,
+                    );
+                    Node::flatten_outputs(single_delegations.map(|item| {
+                        let mut item = Node::from_item(item);
                         assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
                     }))
                 }
@@ -1983,7 +2059,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 if node.delegation().is_some() => unreachable!(),
                 None => {
                     assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
                 }
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 7566a4d5066..936fc9d6b77 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2699,12 +2699,13 @@ pub(crate) struct SingleColonImportPath {
 
 #[derive(Diagnostic)]
 #[diag(parse_bad_item_kind)]
-#[help]
 pub(crate) struct BadItemKind {
     #[primary_span]
     pub span: Span,
     pub descr: &'static str,
     pub ctx: &'static str,
+    #[help]
+    pub help: Option<()>,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 42f8c6e38b9..2db777a9f70 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -707,15 +707,25 @@ impl<'a> Parser<'a> {
         };
 
         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 suffixes = if self.eat(&token::BinOp(token::Star)) {
+                None
+            } else {
+                let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));
+                Some(self.parse_delim_comma_seq(Delimiter::Brace, parse_suffix)?.0)
+            };
             let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
             (Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
         } else {
             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)? };
+            let deleg = Delegation {
+                id: DUMMY_NODE_ID,
+                qself,
+                path,
+                rename,
+                body: body(self)?,
+                from_glob: false,
+            };
             (ident, ItemKind::Delegation(Box::new(deleg)))
         };
 
@@ -1237,7 +1247,11 @@ impl<'a> Parser<'a> {
         // FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
         let span = self.psess.source_map().guess_head_span(span);
         let descr = kind.descr();
-        self.dcx().emit_err(errors::BadItemKind { span, descr, ctx });
+        let help = match kind {
+            ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => None,
+            _ => Some(()),
+        };
+        self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help });
         None
     }
 
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 689109b2840..e035749fc39 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -19,6 +19,7 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
 use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
 use rustc_attr as attr;
 use rustc_data_structures::sync::Lrc;
+use rustc_expand::base::ResolverExpand;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def::{self, *};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
@@ -1358,6 +1359,14 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     self.visit_invoc_in_module(item.id);
                 }
                 AssocCtxt::Impl => {
+                    let invoc_id = item.id.placeholder_to_expn_id();
+                    if !self.r.glob_delegation_invoc_ids.contains(&invoc_id) {
+                        self.r
+                            .impl_unexpanded_invocations
+                            .entry(self.r.invocation_parent(invoc_id))
+                            .or_default()
+                            .insert(invoc_id);
+                    }
                     self.visit_invoc(item.id);
                 }
             }
@@ -1379,18 +1388,21 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             self.r.feed_visibility(feed, vis);
         }
 
+        let ns = match item.kind {
+            AssocItemKind::Const(..) | AssocItemKind::Delegation(..) | AssocItemKind::Fn(..) => {
+                ValueNS
+            }
+            AssocItemKind::Type(..) => TypeNS,
+            AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
+        };
         if ctxt == AssocCtxt::Trait {
-            let ns = match item.kind {
-                AssocItemKind::Const(..)
-                | AssocItemKind::Delegation(..)
-                | AssocItemKind::Fn(..) => ValueNS,
-                AssocItemKind::Type(..) => TypeNS,
-                AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
-            };
-
             let parent = self.parent_scope.module;
             let expansion = self.parent_scope.expansion;
             self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion));
+        } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) {
+            let impl_def_id = self.r.tcx.local_parent(local_def_id);
+            let key = BindingKey::new(item.ident.normalize_to_macros_2_0(), ns);
+            self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key);
         }
 
         visit::walk_assoc_item(self, item, ctxt);
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index ca97d10617b..fb6e55f2b7b 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -144,8 +144,9 @@ 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!(),
+            ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
+                return self.visit_macro_invoc(i.id);
+            }
         };
         let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
 
@@ -294,8 +295,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
             AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn,
             AssocItemKind::Const(..) => DefKind::AssocConst,
             AssocItemKind::Type(..) => DefKind::AssocTy,
-            AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
-            AssocItemKind::DelegationMac(..) => unreachable!(),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                return self.visit_macro_invoc(i.id);
+            }
         };
 
         let def = self.create_def(i.id, i.ident.name, def_kind, i.span);
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9557b0f5ebc..3a831a7f19e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1089,7 +1089,7 @@ pub struct Resolver<'a, 'tcx> {
     single_segment_macro_resolutions:
         Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>,
     multi_segment_macro_resolutions:
-        Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>)>,
+        Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>, Namespace)>,
     builtin_attrs: Vec<(Ident, ParentScope<'a>)>,
     /// `derive(Copy)` marks items they are applied to so they are treated specially later.
     /// Derive macros cannot modify the item themselves and have to store the markers in the global
@@ -1163,6 +1163,15 @@ pub struct Resolver<'a, 'tcx> {
     doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
     doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
     all_macro_rules: FxHashMap<Symbol, Res>,
+
+    /// Invocation ids of all glob delegations.
+    glob_delegation_invoc_ids: FxHashSet<LocalExpnId>,
+    /// Analogue of module `unexpanded_invocations` but in trait impls, excluding glob delegations.
+    /// Needed because glob delegations wait for all other neighboring macros to expand.
+    impl_unexpanded_invocations: FxHashMap<LocalDefId, FxHashSet<LocalExpnId>>,
+    /// Simplified analogue of module `resolutions` but in trait impls, excluding glob delegations.
+    /// Needed because glob delegations exclude explicitly defined names.
+    impl_binding_keys: FxHashMap<LocalDefId, FxHashSet<BindingKey>>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1504,6 +1513,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             doc_link_traits_in_scope: Default::default(),
             all_macro_rules: Default::default(),
             delegation_fn_sigs: Default::default(),
+            glob_delegation_invoc_ids: Default::default(),
+            impl_unexpanded_invocations: Default::default(),
+            impl_binding_keys: Default::default(),
         };
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 268e7f06d04..87794d11cea 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
 use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
 use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
 use crate::Namespace::*;
-use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
+use crate::{BindingKey, BuiltinMacroState, Determinacy, MacroData, Used};
 use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
 use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
 use rustc_ast::expand::StrippedCfgItem;
@@ -198,6 +198,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
         self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
 
         parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
+        if let Some(unexpanded_invocations) =
+            self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion))
+        {
+            unexpanded_invocations.remove(&expansion);
+        }
     }
 
     fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) {
@@ -262,15 +267,21 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
             }
         };
 
-        let (path, kind, inner_attr, derives) = match invoc.kind {
-            InvocationKind::Attr { ref attr, ref derives, .. } => (
-                &attr.get_normal_item().path,
-                MacroKind::Attr,
-                attr.style == ast::AttrStyle::Inner,
-                self.arenas.alloc_ast_paths(derives),
-            ),
-            InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]),
-            InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]),
+        let (mut derives, mut inner_attr, mut deleg_impl) = (&[][..], false, None);
+        let (path, kind) = match invoc.kind {
+            InvocationKind::Attr { ref attr, derives: ref attr_derives, .. } => {
+                derives = self.arenas.alloc_ast_paths(attr_derives);
+                inner_attr = attr.style == ast::AttrStyle::Inner;
+                (&attr.get_normal_item().path, MacroKind::Attr)
+            }
+            InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang),
+            InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive),
+            InvocationKind::GlobDelegation { ref item } => {
+                let ast::AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };
+                deleg_impl = Some(self.invocation_parent(invoc_id));
+                // It is sufficient to consider glob delegation a bang macro for now.
+                (&deleg.prefix, MacroKind::Bang)
+            }
         };
 
         // Derives are not included when `invocations` are collected, so we have to add them here.
@@ -286,10 +297,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
             node_id,
             force,
             soft_custom_inner_attributes_gate(path, invoc),
+            deleg_impl,
         )?;
 
         let span = invoc.span();
-        let def_id = res.opt_def_id();
+        let def_id = if deleg_impl.is_some() { None } else { res.opt_def_id() };
         invoc_id.set_expn_data(
             ext.expn_data(
                 parent_scope.expansion,
@@ -452,6 +464,45 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
     fn registered_tools(&self) -> &RegisteredTools {
         self.registered_tools
     }
+
+    fn register_glob_delegation(&mut self, invoc_id: LocalExpnId) {
+        self.glob_delegation_invoc_ids.insert(invoc_id);
+    }
+
+    fn glob_delegation_suffixes(
+        &mut self,
+        trait_def_id: DefId,
+        impl_def_id: LocalDefId,
+    ) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate> {
+        let target_trait = self.expect_module(trait_def_id);
+        if !target_trait.unexpanded_invocations.borrow().is_empty() {
+            return Err(Indeterminate);
+        }
+        // FIXME: Instead of waiting try generating all trait methods, and pruning
+        // the shadowed ones a bit later, e.g. when all macro expansion completes.
+        // Pros: expansion will be stuck less (but only in exotic cases), the implementation may be
+        // less hacky.
+        // Cons: More code is generated just to be deleted later, deleting already created `DefId`s
+        // may be nontrivial.
+        if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get(&impl_def_id)
+            && !unexpanded_invocations.is_empty()
+        {
+            return Err(Indeterminate);
+        }
+
+        let mut idents = Vec::new();
+        target_trait.for_each_child(self, |this, ident, ns, _binding| {
+            // FIXME: Adjust hygiene for idents from globs, like for glob imports.
+            if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id)
+                && overriding_keys.contains(&BindingKey::new(ident.normalize_to_macros_2_0(), ns))
+            {
+                // The name is overridden, do not produce it from the glob delegation.
+            } else {
+                idents.push((ident, None));
+            }
+        });
+        Ok(idents)
+    }
 }
 
 impl<'a, 'tcx> Resolver<'a, 'tcx> {
@@ -468,15 +519,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         node_id: NodeId,
         force: bool,
         soft_custom_inner_attributes_gate: bool,
+        deleg_impl: Option<LocalDefId>,
     ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
-        let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
-        {
+        let (ext, res) = match self.resolve_macro_or_delegation_path(
+            path,
+            Some(kind),
+            parent_scope,
+            true,
+            force,
+            deleg_impl,
+        ) {
             Ok((Some(ext), res)) => (ext, res),
             Ok((None, res)) => (self.dummy_ext(kind), res),
             Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
             Err(Determinacy::Undetermined) => return Err(Indeterminate),
         };
 
+        // Everything below is irrelevant to glob delegation, take a shortcut.
+        if deleg_impl.is_some() {
+            if !matches!(res, Res::Err | Res::Def(DefKind::Trait, _)) {
+                self.dcx().emit_err(MacroExpectedFound {
+                    span: path.span,
+                    expected: "trait",
+                    article: "a",
+                    found: res.descr(),
+                    macro_path: &pprust::path_to_string(path),
+                    remove_surrounding_derive: None,
+                    add_as_non_derive: None,
+                });
+                return Ok((self.dummy_ext(kind), Res::Err));
+            }
+
+            return Ok((ext, res));
+        }
+
         // Report errors for the resolved macro.
         for segment in &path.segments {
             if let Some(args) = &segment.args {
@@ -606,11 +682,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         trace: bool,
         force: bool,
     ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
+        self.resolve_macro_or_delegation_path(path, kind, parent_scope, trace, force, None)
+    }
+
+    fn resolve_macro_or_delegation_path(
+        &mut self,
+        path: &ast::Path,
+        kind: Option<MacroKind>,
+        parent_scope: &ParentScope<'a>,
+        trace: bool,
+        force: bool,
+        deleg_impl: Option<LocalDefId>,
+    ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
         let path_span = path.span;
         let mut path = Segment::from_path(path);
 
         // Possibly apply the macro helper hack
-        if kind == Some(MacroKind::Bang)
+        if deleg_impl.is_none()
+            && kind == Some(MacroKind::Bang)
             && path.len() == 1
             && path[0].ident.span.ctxt().outer_expn_data().local_inner_macros
         {
@@ -618,13 +707,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             path.insert(0, Segment::from_ident(root));
         }
 
-        let res = if path.len() > 1 {
-            let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) {
+        let res = if deleg_impl.is_some() || path.len() > 1 {
+            let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS };
+            let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope) {
                 PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
                 PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
                 PathResult::NonModule(..)
                 | PathResult::Indeterminate
                 | PathResult::Failed { .. } => Err(Determinacy::Determined),
+                PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
+                    Ok(module.res().unwrap())
+                }
                 PathResult::Module(..) => unreachable!(),
             };
 
@@ -636,6 +729,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     kind,
                     *parent_scope,
                     res.ok(),
+                    ns,
                 ));
             }
 
@@ -670,7 +764,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             res
         };
 
-        res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext.clone()), res))
+        let res = res?;
+        let ext = match deleg_impl {
+            Some(impl_def_id) => match res {
+                def::Res::Def(DefKind::Trait, def_id) => {
+                    let edition = self.tcx.sess.edition();
+                    Some(Lrc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition)))
+                }
+                _ => None,
+            },
+            None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()),
+        };
+        Ok((ext, res))
     }
 
     pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) {
@@ -706,14 +811,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         };
 
         let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions);
-        for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions {
+        for (mut path, path_span, kind, parent_scope, initial_res, ns) in macro_resolutions {
             // FIXME: Path resolution will ICE if segment IDs present.
             for seg in &mut path {
                 seg.id = None;
             }
             match self.resolve_path(
                 &path,
-                Some(MacroNS),
+                Some(ns),
                 &parent_scope,
                 Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
                 None,
@@ -721,6 +826,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
                     check_consistency(self, &path, path_span, kind, initial_res, res)
                 }
+                // This may be a trait for glob delegation expansions.
+                PathResult::Module(ModuleOrUniformRoot::Module(module)) => check_consistency(
+                    self,
+                    &path,
+                    path_span,
+                    kind,
+                    initial_res,
+                    module.res().unwrap(),
+                ),
                 path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
                     let mut suggestion = None;
                     let (span, label, module) =
diff --git a/tests/ui/delegation/body-identity-glob.rs b/tests/ui/delegation/body-identity-glob.rs
new file mode 100644
index 00000000000..58b644f46d6
--- /dev/null
+++ b/tests/ui/delegation/body-identity-glob.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::* {
+        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-glob.rs b/tests/ui/delegation/empty-glob.rs
new file mode 100644
index 00000000000..d98579d8972
--- /dev/null
+++ b/tests/ui/delegation/empty-glob.rs
@@ -0,0 +1,11 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+
+struct S;
+impl S {
+    reuse Trait::*; //~ ERROR empty glob delegation is not supported
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/empty-glob.stderr b/tests/ui/delegation/empty-glob.stderr
new file mode 100644
index 00000000000..f4d282f6a0f
--- /dev/null
+++ b/tests/ui/delegation/empty-glob.stderr
@@ -0,0 +1,8 @@
+error: empty glob delegation is not supported
+  --> $DIR/empty-glob.rs:8:5
+   |
+LL |     reuse Trait::*;
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/delegation/glob-bad-path.rs b/tests/ui/delegation/glob-bad-path.rs
new file mode 100644
index 00000000000..7bc4f0153a3
--- /dev/null
+++ b/tests/ui/delegation/glob-bad-path.rs
@@ -0,0 +1,12 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+struct S;
+
+impl Trait for u8 {
+    reuse unresolved::*; //~ ERROR failed to resolve: use of undeclared crate or module `unresolved`
+    reuse S::*; //~ ERROR expected trait, found struct `S`
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/glob-bad-path.stderr b/tests/ui/delegation/glob-bad-path.stderr
new file mode 100644
index 00000000000..0c06364b3f0
--- /dev/null
+++ b/tests/ui/delegation/glob-bad-path.stderr
@@ -0,0 +1,15 @@
+error: expected trait, found struct `S`
+  --> $DIR/glob-bad-path.rs:9:11
+   |
+LL |     reuse S::*;
+   |           ^ not a trait
+
+error[E0433]: failed to resolve: use of undeclared crate or module `unresolved`
+  --> $DIR/glob-bad-path.rs:8:11
+   |
+LL |     reuse unresolved::*;
+   |           ^^^^^^^^^^ use of undeclared crate or module `unresolved`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/delegation/glob-glob-conflict.rs b/tests/ui/delegation/glob-glob-conflict.rs
new file mode 100644
index 00000000000..2843bf8c493
--- /dev/null
+++ b/tests/ui/delegation/glob-glob-conflict.rs
@@ -0,0 +1,33 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait1 {
+    fn method(&self) -> u8;
+}
+trait Trait2 {
+    fn method(&self) -> u8;
+}
+trait Trait {
+    fn method(&self) -> u8;
+}
+
+impl Trait1 for u8 {
+    fn method(&self) -> u8 { 0 }
+}
+impl Trait1 for u16 {
+    fn method(&self) -> u8 { 1 }
+}
+impl Trait2 for u8 {
+    fn method(&self) -> u8 { 2 }
+}
+
+impl Trait for u8 {
+    reuse Trait1::*;
+    reuse Trait2::*; //~ ERROR duplicate definitions with name `method`
+}
+impl Trait for u16 {
+    reuse Trait1::*;
+    reuse Trait1::*; //~ ERROR duplicate definitions with name `method`
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/glob-glob-conflict.stderr b/tests/ui/delegation/glob-glob-conflict.stderr
new file mode 100644
index 00000000000..8c7e5a4b023
--- /dev/null
+++ b/tests/ui/delegation/glob-glob-conflict.stderr
@@ -0,0 +1,25 @@
+error[E0201]: duplicate definitions with name `method`:
+  --> $DIR/glob-glob-conflict.rs:26:5
+   |
+LL |     fn method(&self) -> u8;
+   |     ----------------------- item in trait
+...
+LL |     reuse Trait1::*;
+   |     ---------------- previous definition here
+LL |     reuse Trait2::*;
+   |     ^^^^^^^^^^^^^^^^ duplicate definition
+
+error[E0201]: duplicate definitions with name `method`:
+  --> $DIR/glob-glob-conflict.rs:30:5
+   |
+LL |     fn method(&self) -> u8;
+   |     ----------------------- item in trait
+...
+LL |     reuse Trait1::*;
+   |     ---------------- previous definition here
+LL |     reuse Trait1::*;
+   |     ^^^^^^^^^^^^^^^^ duplicate definition
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0201`.
diff --git a/tests/ui/delegation/glob-glob.rs b/tests/ui/delegation/glob-glob.rs
new file mode 100644
index 00000000000..ef7f9a15e19
--- /dev/null
+++ b/tests/ui/delegation/glob-glob.rs
@@ -0,0 +1,36 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod inner {
+    pub trait TraitFoo {
+        fn foo(&self) -> u8;
+    }
+    pub trait TraitBar {
+        fn bar(&self) -> u8;
+    }
+
+    impl TraitFoo for u8 {
+        fn foo(&self) -> u8 { 0 }
+    }
+    impl TraitBar for u8 {
+        fn bar(&self) -> u8 { 1 }
+    }
+}
+
+trait Trait {
+    fn foo(&self) -> u8;
+    fn bar(&self) -> u8;
+}
+
+impl Trait for u8 {
+    reuse inner::TraitFoo::*;
+    reuse inner::TraitBar::*;
+}
+
+fn main() {
+    let u = 0u8;
+    u.foo();
+    u.bar();
+}
diff --git a/tests/ui/delegation/glob-non-fn.rs b/tests/ui/delegation/glob-non-fn.rs
new file mode 100644
index 00000000000..ab312d51f49
--- /dev/null
+++ b/tests/ui/delegation/glob-non-fn.rs
@@ -0,0 +1,38 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn method(&self);
+    const CONST: u8;
+    type Type;
+    #[allow(non_camel_case_types)]
+    type method;
+}
+
+impl Trait for u8 {
+    fn method(&self) {}
+    const CONST: u8 = 0;
+    type Type = u8;
+    type method = u8;
+}
+
+struct Good(u8);
+impl Trait for Good {
+    reuse Trait::* { &self.0 }
+    // Explicit definitions for non-delegatable items.
+    const CONST: u8 = 0;
+    type Type = u8;
+    type method = u8;
+}
+
+struct Bad(u8);
+impl Trait for Bad { //~ ERROR not all trait items implemented, missing: `CONST`, `Type`, `method`
+    reuse Trait::* { &self.0 }
+    //~^ ERROR item `CONST` is an associated method, which doesn't match its trait `Trait`
+    //~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait`
+    //~| ERROR duplicate definitions with name `method`
+    //~| ERROR expected function, found associated constant `Trait::CONST`
+    //~| ERROR expected function, found associated type `Trait::Type`
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/glob-non-fn.stderr b/tests/ui/delegation/glob-non-fn.stderr
new file mode 100644
index 00000000000..4b918c53b84
--- /dev/null
+++ b/tests/ui/delegation/glob-non-fn.stderr
@@ -0,0 +1,62 @@
+error[E0324]: item `CONST` is an associated method, which doesn't match its trait `Trait`
+  --> $DIR/glob-non-fn.rs:30:5
+   |
+LL |     const CONST: u8;
+   |     ---------------- item in trait
+...
+LL |     reuse Trait::* { &self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
+
+error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait`
+  --> $DIR/glob-non-fn.rs:30:5
+   |
+LL |     type Type;
+   |     ---------- item in trait
+...
+LL |     reuse Trait::* { &self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
+
+error[E0201]: duplicate definitions with name `method`:
+  --> $DIR/glob-non-fn.rs:30:5
+   |
+LL |     fn method(&self);
+   |     ----------------- item in trait
+...
+LL |     reuse Trait::* { &self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     duplicate definition
+   |     previous definition here
+
+error[E0423]: expected function, found associated constant `Trait::CONST`
+  --> $DIR/glob-non-fn.rs:30:11
+   |
+LL |     reuse Trait::* { &self.0 }
+   |           ^^^^^ not a function
+
+error[E0423]: expected function, found associated type `Trait::Type`
+  --> $DIR/glob-non-fn.rs:30:11
+   |
+LL |     reuse Trait::* { &self.0 }
+   |           ^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method`
+  --> $DIR/glob-non-fn.rs:29:1
+   |
+LL |     const CONST: u8;
+   |     --------------- `CONST` from trait
+LL |     type Type;
+   |     --------- `Type` from trait
+LL |     #[allow(non_camel_case_types)]
+LL |     type method;
+   |     ----------- `method` from trait
+...
+LL | impl Trait for Bad {
+   | ^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0046, E0201, E0324, E0423.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/delegation/glob-non-impl.rs b/tests/ui/delegation/glob-non-impl.rs
new file mode 100644
index 00000000000..d523731eeb3
--- /dev/null
+++ b/tests/ui/delegation/glob-non-impl.rs
@@ -0,0 +1,20 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn method() {}
+}
+
+reuse Trait::*; //~ ERROR glob delegation is only supported in impls
+
+trait OtherTrait {
+    reuse Trait::*; //~ ERROR glob delegation is only supported in impls
+}
+
+extern {
+    reuse Trait::*; //~ ERROR delegation is not supported in `extern` blocks
+}
+
+fn main() {
+    reuse Trait::*; //~ ERROR glob delegation is only supported in impls
+}
diff --git a/tests/ui/delegation/glob-non-impl.stderr b/tests/ui/delegation/glob-non-impl.stderr
new file mode 100644
index 00000000000..ea458fd5e90
--- /dev/null
+++ b/tests/ui/delegation/glob-non-impl.stderr
@@ -0,0 +1,26 @@
+error: delegation is not supported in `extern` blocks
+  --> $DIR/glob-non-impl.rs:15:5
+   |
+LL |     reuse Trait::*;
+   |     ^^^^^^^^^^^^^^^
+
+error: glob delegation is only supported in impls
+  --> $DIR/glob-non-impl.rs:8:1
+   |
+LL | reuse Trait::*;
+   | ^^^^^^^^^^^^^^^
+
+error: glob delegation is only supported in impls
+  --> $DIR/glob-non-impl.rs:11:5
+   |
+LL |     reuse Trait::*;
+   |     ^^^^^^^^^^^^^^^
+
+error: glob delegation is only supported in impls
+  --> $DIR/glob-non-impl.rs:19:5
+   |
+LL |     reuse Trait::*;
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/delegation/glob-override.rs b/tests/ui/delegation/glob-override.rs
new file mode 100644
index 00000000000..1d0dcf1df6e
--- /dev/null
+++ b/tests/ui/delegation/glob-override.rs
@@ -0,0 +1,37 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn foo(&self) -> u8;
+    fn bar(&self) -> u8;
+}
+
+impl Trait for u8 {
+    fn foo(&self) -> u8 { 0 }
+    fn bar(&self) -> u8 { 1 }
+}
+
+struct S(u8);
+struct Z(u8);
+
+impl Trait for S {
+    reuse Trait::* { &self.0 }
+    fn bar(&self) -> u8 { 2 }
+}
+
+impl Trait for Z {
+    reuse Trait::* { &self.0 }
+    reuse Trait::bar { &self.0 }
+}
+
+fn main() {
+    let s = S(2);
+    s.foo();
+    s.bar();
+
+    let z = Z(2);
+    z.foo();
+    z.bar();
+}
diff --git a/tests/ui/delegation/glob.rs b/tests/ui/delegation/glob.rs
new file mode 100644
index 00000000000..5bc80c16648
--- /dev/null
+++ b/tests/ui/delegation/glob.rs
@@ -0,0 +1,35 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn foo(&self) -> u8;
+    fn bar(&self) -> u8;
+}
+
+impl Trait for u8 {
+    fn foo(&self) -> u8 { 0 }
+    fn bar(&self) -> u8 { 1 }
+}
+
+struct S(u8);
+struct Z(u8);
+
+impl Trait for S {
+    reuse Trait::* { &self.0 }
+}
+
+impl Trait for Z {
+    reuse <u8 as Trait>::* { &self.0 }
+}
+
+fn main() {
+    let s = S(2);
+    s.foo();
+    s.bar();
+
+    let z = Z(3);
+    z.foo();
+    z.bar();
+}
diff --git a/tests/ui/delegation/macro-inside-glob.rs b/tests/ui/delegation/macro-inside-glob.rs
new file mode 100644
index 00000000000..1d529341c5b
--- /dev/null
+++ b/tests/ui/delegation/macro-inside-glob.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:ident) => { &$self.0 } }
+impl Trait for S {
+    reuse <u8!() as Trait>::* { self_0!(self) }
+}
+
+fn main() {
+    let s = S(2);
+    s.foo();
+    s.bar();
+}