Skip to content

Commit

Permalink
Support impl in foreign modules for macro use
Browse files Browse the repository at this point in the history
Allow `impl` blocks in foreign modules for more ergonomic use in macros.
`impl` blocks still have no meaning in foreign modules and will cause an
error if still present during lowering.

Also adds explicit tests for the previous similar foreign module macro
extensions to ensure that neither this nor those are accepted or crash
the compiler when *not* fed to a macro.
  • Loading branch information
maurer committed Sep 27, 2022
1 parent 57ee5cf commit f728939
Show file tree
Hide file tree
Showing 37 changed files with 438 additions and 177 deletions.
5 changes: 5 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3005,6 +3005,9 @@ pub enum ForeignItemKind {
TyAlias(Box<TyAlias>),
/// A macro expanding to foreign items.
MacCall(P<MacCall>),
/// An impl declaration - parseable for proc_macro purposes, but currently has no meaning in
/// real Rust code.
Impl(Box<Impl>),
}

impl From<ForeignItemKind> for ItemKind {
Expand All @@ -3014,6 +3017,7 @@ impl From<ForeignItemKind> for ItemKind {
ForeignItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
ForeignItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
ForeignItemKind::MacCall(a) => ItemKind::MacCall(a),
ForeignItemKind::Impl(i) => ItemKind::Impl(i),
}
}
}
Expand All @@ -3027,6 +3031,7 @@ impl TryFrom<ItemKind> for ForeignItemKind {
ItemKind::Fn(fn_kind) => ForeignItemKind::Fn(fn_kind),
ItemKind::TyAlias(ty_alias_kind) => ForeignItemKind::TyAlias(ty_alias_kind),
ItemKind::MacCall(a) => ForeignItemKind::MacCall(a),
ItemKind::Impl(i) => ForeignItemKind::Impl(i),
_ => return Err(item_kind),
})
}
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,25 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
ForeignItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
ForeignItemKind::Impl(box Impl {
defaultness,
unsafety,
generics,
constness,
polarity,
of_trait,
self_ty,
items,
}) => {
visit_defaultness(defaultness, visitor);
visit_unsafety(unsafety, visitor);
visitor.visit_generics(generics);
visit_constness(constness, visitor);
visit_polarity(polarity, visitor);
visit_opt(of_trait, |trait_ref| visitor.visit_trait_ref(trait_ref));
visitor.visit_ty(self_ty);
items.flat_map_in_place(|item| visitor.flat_map_impl_item(item));
}
}
visitor.visit_span(span);
visit_lazy_tts(tokens, visitor);
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,21 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
ForeignItemKind::MacCall(mac) => {
visitor.visit_mac_call(mac);
}
ForeignItemKind::Impl(box Impl {
defaultness: _,
unsafety: _,
ref generics,
constness: _,
polarity: _,
ref of_trait,
ref self_ty,
ref items,
}) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_trait_ref, of_trait);
visitor.visit_ty(self_ty);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl);
}
}
}

Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,11 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
// Evaluate with the lifetimes in `params` in-scope.
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.
match parent_hir.node().expect_item().kind {
hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }) => {
match parent_hir.node() {
hir::OwnerNode::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }),
..
}) => {
lctx.is_in_trait_impl = of_trait.is_some();
}
_ => {}
Expand Down Expand Up @@ -685,6 +688,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
// This is not a type, but we will have emitted an error earlier and want the
// compiler to finish its work cleanly.
ForeignItemKind::Impl(_) => hir::ForeignItemKind::Type,
},
vis_span: self.lower_span(i.vis.span),
span: self.lower_span(i.span),
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_foreign_item_ascii_only(fi.ident);
}
ForeignItemKind::MacCall(..) => {}
ForeignItemKind::Impl(..) => {
self.err_handler()
.struct_span_err(fi.span, "`impl` blocks are not allowed in `extern` blocks")
.emit();
return;
}
}

visit::walk_foreign_item(self, fi)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
}
ast::ForeignItemKind::MacCall(..) => {}
ast::ForeignItemKind::Impl(..) => {}
}

visit::walk_foreign_item(self, i)
Expand Down
47 changes: 47 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,53 @@ impl<'a> State<'a> {
self.word(";");
}
}
ast::ForeignItemKind::Impl(box ast::Impl {
unsafety,
polarity,
defaultness,
constness,
ref generics,
ref of_trait,
ref self_ty,
ref items,
}) => {
self.head("");
self.print_visibility(&item.vis);
self.print_defaultness(*defaultness);
self.print_unsafety(*unsafety);
self.word("impl");

if generics.params.is_empty() {
self.nbsp();
} else {
self.print_generic_params(&generics.params);
self.space();
}

self.print_constness(*constness);

if let ast::ImplPolarity::Negative(_) = polarity {
self.word("!");
}

if let Some(ref t) = *of_trait {
self.print_trait_ref(t);
self.space();
self.word_space("for");
}

self.print_type(self_ty);
self.print_where_clause(&generics.where_clause);

self.space();
self.bopen();
self.print_inner_attributes(&item.attrs);
for impl_item in items {
self.print_assoc_item(impl_item);
}
let empty = item.attrs.is_empty() && items.is_empty();
self.bclose(item.span, empty);
}
}
self.ann.post(self, AnnNode::SubItem(id))
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3186,6 +3186,8 @@ pub enum ForeignItemKind<'hir> {
Static(&'hir Ty<'hir>, Mutability),
/// A foreign type.
Type,
/// A foreign impl (currently meaningless)
Impl(&'hir Impl<'hir>),
}

/// A variable captured by a closure.
Expand Down
25 changes: 10 additions & 15 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,22 +564,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
// `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
visitor.visit_enum_def(enum_definition, item.hir_id())
}
ItemKind::Impl(Impl {
unsafety: _,
defaultness: _,
polarity: _,
constness: _,
defaultness_span: _,
ref generics,
ref of_trait,
ref self_ty,
items,
}) => {
ItemKind::Impl(impl_) => {
visitor.visit_id(item.hir_id());
visitor.visit_generics(generics);
walk_list!(visitor, visit_trait_ref, of_trait);
visitor.visit_ty(self_ty);
walk_list!(visitor, visit_impl_item_ref, *items);
walk_impl(visitor, impl_);
}
ItemKind::Struct(ref struct_definition, ref generics)
| ItemKind::Union(ref struct_definition, ref generics) => {
Expand Down Expand Up @@ -798,6 +785,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
}
ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
ForeignItemKind::Type => (),
ForeignItemKind::Impl(ref impl_) => walk_impl(visitor, impl_),
}
}

Expand Down Expand Up @@ -978,6 +966,13 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
}
}

pub fn walk_impl<'v, V: Visitor<'v>>(visitor: &mut V, impl_: &'v Impl<'v>) {
visitor.visit_generics(impl_.generics);
walk_list!(visitor, visit_trait_ref, &impl_.of_trait);
visitor.visit_ty(impl_.self_ty);
walk_list!(visitor, visit_impl_item_ref, impl_.items);
}

pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
foreign_item_ref: &'v ForeignItemRef,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ impl Target {
hir::ForeignItemKind::Fn(..) => Target::ForeignFn,
hir::ForeignItemKind::Static(..) => Target::ForeignStatic,
hir::ForeignItemKind::Type => Target::ForeignTy,
hir::ForeignItemKind::Impl(..) => Target::Impl,
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
}
hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true),
hir::ForeignItemKind::Type => (),
hir::ForeignItemKind::Impl(..) => (),
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2217,7 +2217,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP

Node::ForeignItem(item) => match item.kind {
ForeignItemKind::Static(..) => NO_GENERICS,
ForeignItemKind::Fn(_, _, ref generics) => *generics,
ForeignItemKind::Fn(_, _, ref generics)
| ForeignItemKind::Impl(hir::Impl { ref generics, .. }) => *generics,
ForeignItemKind::Type => NO_GENERICS,
},

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
ForeignItemKind::Static(t, _) => icx.to_ty(t),
ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
ForeignItemKind::Impl(..) => span_bug!(foreign_item.span, "compute_type_of_foreign_item: unexpected item type: {:?}", foreign_item.kind),
},

Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
Expand Down
93 changes: 46 additions & 47 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,8 @@ impl<'a> State<'a> {
pub fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
self.hardbreak_if_not_bol();
self.maybe_print_comment(item.span.lo());
self.print_outer_attributes(self.attrs(item.hir_id()));
let attrs = self.attrs(item.hir_id());
self.print_outer_attributes(attrs);
match item.kind {
hir::ForeignItemKind::Fn(decl, arg_names, generics) => {
self.head("");
Expand Down Expand Up @@ -415,6 +416,7 @@ impl<'a> State<'a> {
self.end(); // end the head-ibox
self.end() // end the outer cbox
}
hir::ForeignItemKind::Impl(impl_) => self.print_impl(impl_, attrs, item.span),
}
}

Expand Down Expand Up @@ -477,6 +479,48 @@ impl<'a> State<'a> {
self.end(); // end the outer ibox
}

fn print_impl(
&mut self,
impl_: &hir::Impl<'_>,
attrs: &[ast::Attribute],
span: rustc_span::Span,
) {
self.head("");
self.print_defaultness(impl_.defaultness);
self.print_unsafety(impl_.unsafety);
self.word_nbsp("impl");

if !impl_.generics.params.is_empty() {
self.print_generic_params(impl_.generics.params);
self.space();
}

if impl_.constness == hir::Constness::Const {
self.word_nbsp("const");
}

if let hir::ImplPolarity::Negative(_) = impl_.polarity {
self.word("!");
}

if let Some(ref t) = impl_.of_trait {
self.print_trait_ref(t);
self.space();
self.word_space("for");
}

self.print_type(impl_.self_ty);
self.print_where_clause(impl_.generics);

self.space();
self.bopen();
self.print_inner_attributes(attrs);
for impl_item in impl_.items {
self.ann.nested(self, Nested::ImplItem(impl_item.id));
}
self.bclose(span);
}

/// Pretty-print an item
pub fn print_item(&mut self, item: &hir::Item<'_>) {
self.hardbreak_if_not_bol();
Expand Down Expand Up @@ -619,52 +663,7 @@ impl<'a> State<'a> {
self.head("union");
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
}
hir::ItemKind::Impl(&hir::Impl {
unsafety,
polarity,
defaultness,
constness,
defaultness_span: _,
generics,
ref of_trait,
self_ty,
items,
}) => {
self.head("");
self.print_defaultness(defaultness);
self.print_unsafety(unsafety);
self.word_nbsp("impl");

if !generics.params.is_empty() {
self.print_generic_params(generics.params);
self.space();
}

if constness == hir::Constness::Const {
self.word_nbsp("const");
}

if let hir::ImplPolarity::Negative(_) = polarity {
self.word("!");
}

if let Some(t) = of_trait {
self.print_trait_ref(t);
self.space();
self.word_space("for");
}

self.print_type(self_ty);
self.print_where_clause(generics);

self.space();
self.bopen();
self.print_inner_attributes(attrs);
for impl_item in items {
self.ann.nested(self, Nested::ImplItem(impl_item.id));
}
self.bclose(item.span);
}
hir::ItemKind::Impl(impl_) => self.print_impl(impl_, attrs, item.span),
hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, trait_items) => {
self.head("");
self.print_is_auto(is_auto);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1302,7 +1302,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
hir::ForeignItemKind::Static(ref ty, _) => {
vis.check_foreign_static(it.hir_id(), ty.span);
}
hir::ForeignItemKind::Type => (),
hir::ForeignItemKind::Type | hir::ForeignItemKind::Impl(..) => (),
}
}
}
Expand Down
Loading

0 comments on commit f728939

Please sign in to comment.