diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 7951b7e7b75a0..6d3ee2bb54b62 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
>,
- pub rename: Option,
pub path: Path,
+ pub rename: Option,
+ pub body: Option>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct DelegationMac {
+ pub qself: Option
>,
+ pub prefix: Path,
+ pub suffixes: ThinVec<(Ident, Option)>,
pub body: Option>,
}
@@ -3243,10 +3252,13 @@ pub enum ItemKind {
/// A macro definition.
MacroDef(MacroDef),
- /// A delegation item (`reuse`).
+ /// A single delegation item (`reuse`).
///
/// E.g. `reuse ::name { target_expr_template }`.
Delegation(Box),
+ /// A list delegation item (`reuse prefix::{a, b, c}`).
+ /// Treated similarly to a macro call and expanded early.
+ DelegationMac(Box),
}
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),
/// An associated delegation item.
Delegation(Box),
+ /// An associated delegation item list.
+ DelegationMac(Box),
}
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 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 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 5c4162295bbc1..1cfb8972a6280 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 d36193ef7b0ab..7794edc350519 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 61fb5c16ad612..1255c1bba0876 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 09f9ca53a7ac0..16c3ee948a480 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>,
+ path: &ast::Path,
+ suffixes: Option<&[(Ident, Option)]>,
+ body: &Option>,
) {
- 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 b7aae2af9ef97..7ae988a5be6c8 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 b0563bfdea749..a5fc9e9d89c1e 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 ddf7b1a007a8e..a049ac251e1e7 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 = 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, Self::AttrsTy, AddSemicolon) {
unreachable!()
}
+ fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> {
+ None
+ }
+ fn delegation_item_kind(_deleg: Box) -> Self::ItemKind {
+ unreachable!()
+ }
+ fn from_item(_item: ast::Item) -> Self {
+ unreachable!()
+ }
+ fn flatten_outputs(_outputs: impl Iterator- ) -> 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 {
_ => unreachable!(),
}
}
+ fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> {
+ match &self.kind {
+ ItemKind::DelegationMac(deleg) => Some((deleg, self)),
+ _ => None,
+ }
+ }
+ fn delegation_item_kind(deleg: Box) -> Self::ItemKind {
+ ItemKind::Delegation(deleg)
+ }
+ fn from_item(item: ast::Item) -> Self {
+ P(item)
+ }
+ fn flatten_outputs(items: impl Iterator
- ) -> 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 {
struct TraitItemTag;
impl InvocationCollectorNode for AstNodeWrapper
, TraitItemTag> {
type OutputTy = SmallVec<[P; 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, TraitItemTag>
_ => unreachable!(),
}
}
+ fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> {
+ match &self.wrapped.kind {
+ AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
+ _ => None,
+ }
+ }
+ fn delegation_item_kind(deleg: Box) -> Self::ItemKind {
+ AssocItemKind::Delegation(deleg)
+ }
+ fn from_item(item: ast::Item) -> Self {
+ AstNodeWrapper::new(P(item), TraitItemTag)
+ }
+ fn flatten_outputs(items: impl Iterator- ) -> Self::OutputTy {
+ items.flatten().collect()
+ }
}
struct ImplItemTag;
impl InvocationCollectorNode for AstNodeWrapper
, ImplItemTag> {
type OutputTy = SmallVec<[P; 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, ImplItemTag>
_ => unreachable!(),
}
}
+ fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item)> {
+ match &self.wrapped.kind {
+ AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
+ _ => None,
+ }
+ }
+ fn delegation_item_kind(deleg: Box) -> Self::ItemKind {
+ AssocItemKind::Delegation(deleg)
+ }
+ fn from_item(item: ast::Item) -> Self {
+ AstNodeWrapper::new(P(item), ImplItemTag)
+ }
+ fn flatten_outputs(items: impl Iterator- ) -> Self::OutputTy {
+ items.flatten().collect()
+ }
}
impl InvocationCollectorNode for P {
@@ -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)> {
+ match &self.kind {
+ StmtKind::Item(item) => match &item.kind {
+ ItemKind::DelegationMac(deleg) => Some((deleg, item)),
+ _ => None,
+ },
+ _ => None,
+ }
+ }
+ fn delegation_item_kind(deleg: Box) -> Self::ItemKind {
+ ItemKind::Delegation(deleg)
+ }
+ fn from_item(item: ast::Item) -> Self {
+ ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) }
+ }
+ fn flatten_outputs(items: impl Iterator
- ) -> 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::()
})
}
+ 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 29957bd2f71ea..5a3bfb8372520 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(
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index c37d3f0441d0b..d845e8ab90d51 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 d7664d1c1fff7..a980d5dcaba4b 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 c1da8928f3021..a5fa94faeadcd 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 3467f1c3edfda..3e9aa3e0a6f21 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 a27a6bceda335..741a650da55e0 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 3443bbe6e1158..074bf810eaf4b 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 5dd95a1896bb1..322f2922f9253 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 64451030adf0f..12815291c1d1c 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 e196d1817f34a..90e9e58ef9ca4 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 6209b37004bf1..e1c7dc35087b2 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 d2723dc32e043..f378e05304b29 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 f669ac3730e26..883ff523bcfea 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 0000000000000..1f08ab4e1a4c2
--- /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 0000000000000..e0697f42283ec
--- /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 0000000000000..50d3c0eee223c
--- /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 0000000000000..6c996807d6ba8
--- /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 0000000000000..f3b53e331ad88
--- /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 0000000000000..208b14816797a
--- /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 ::{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 0000000000000..16c74d396ef00
--- /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 ::{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 f4b3da76c56c7..80b8724a5bf9e 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();
}