diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 073f0c6bc47..6c4026408ed 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -682,7 +682,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty(t, ImplTraitContext::disallowed()); hir::ForeignItemKind::Static(ty, m) } - ForeignItemKind::Ty => hir::ForeignItemKind::Type, + ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"), }, vis: self.lower_visibility(&i.vis, None), diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 206cdefecc9..c539f98aecf 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -22,6 +22,9 @@ use syntax::expand::is_proc_macro_attr; use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use syntax::walk_list; +const MORE_EXTERN: &str = + "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; + /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { Yes, @@ -423,14 +426,59 @@ impl<'a> AstValidator<'a> { } } - fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) { + fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) { let span = match bounds { [] => return, [b0] => b0.span(), [b0, .., bl] => b0.span().to(bl.span()), }; self.err_handler() - .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect") + .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx)) + .emit(); + } + + fn check_foreign_ty_genericless(&self, generics: &Generics) { + let cannot_have = |span, descr, remove_descr| { + self.err_handler() + .struct_span_err( + span, + &format!("`type`s inside `extern` blocks cannot have {}", descr), + ) + .span_suggestion( + span, + &format!("remove the {}", remove_descr), + String::new(), + Applicability::MaybeIncorrect, + ) + .span_label(self.current_extern_span(), "`extern` block begins here") + .note(MORE_EXTERN) + .emit(); + }; + + if !generics.params.is_empty() { + cannot_have(generics.span, "generic parameters", "generic parameters"); + } + + if !generics.where_clause.predicates.is_empty() { + cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause"); + } + } + + fn check_foreign_ty_bodyless(&self, ident: Ident, body: Option<&Ty>) { + let body = match body { + None => return, + Some(body) => body, + }; + self.err_handler() + .struct_span_err(ident.span, "incorrect `type` inside `extern` block") + .span_label(ident.span, "cannot have a body") + .span_label(body.span, "the invalid body") + .span_label( + self.current_extern_span(), + "`extern` blocks define existing foreign types and types \ + inside of them cannot have a body", + ) + .note(MORE_EXTERN) .emit(); } @@ -458,7 +506,7 @@ impl<'a> AstValidator<'a> { "`extern` blocks define existing foreign functions and functions \ inside of them cannot have a body", ) - .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html") + .note(MORE_EXTERN) .emit(); } @@ -912,7 +960,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); } - ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} + ForeignItemKind::TyAlias(generics, bounds, body) => { + self.check_foreign_ty_bodyless(fi.ident, body.as_deref()); + self.check_type_no_bounds(bounds, "`extern` blocks"); + self.check_foreign_ty_genericless(generics); + } + ForeignItemKind::Static(..) | ForeignItemKind::Macro(..) => {} } visit::walk_foreign_item(self, fi) @@ -1159,7 +1212,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } AssocItemKind::TyAlias(_, bounds, body) => { self.check_impl_item_provided(item.span, body, "type", " = ;"); - self.check_impl_assoc_type_no_bounds(bounds); + self.check_type_no_bounds(bounds, "`impl`s"); } _ => {} } diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index 32c91f4a634..c543f7095b9 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -397,7 +397,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } } - ast::ForeignItemKind::Ty => { + ast::ForeignItemKind::TyAlias(..) => { gate_feature_post!(&self, extern_types, i.span, "extern types are experimental"); } ast::ForeignItemKind::Macro(..) => {} diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 0fcda7f763e..b0e1b5d4f42 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1019,13 +1019,13 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(&item.attrs); - match item.kind { - ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => { + match &item.kind { + ast::ForeignItemKind::Fn(sig, gen, body) => { self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); } - ast::ForeignItemKind::Static(ref t, m) => { + ast::ForeignItemKind::Static(t, m) => { self.head(visibility_qualified(&item.vis, "static")); - if m == ast::Mutability::Mut { + if *m == ast::Mutability::Mut { self.word_space("mut"); } self.print_ident(item.ident); @@ -1035,14 +1035,10 @@ impl<'a> State<'a> { self.end(); // end the head-ibox self.end(); // end the outer cbox } - ast::ForeignItemKind::Ty => { - self.head(visibility_qualified(&item.vis, "type")); - self.print_ident(item.ident); - self.s.word(";"); - self.end(); // end the head-ibox - self.end(); // end the outer cbox + ast::ForeignItemKind::TyAlias(generics, bounds, ty) => { + self.print_associated_type(item.ident, generics, bounds, ty.as_deref()); } - ast::ForeignItemKind::Macro(ref m) => { + ast::ForeignItemKind::Macro(m) => { self.print_mac(m); if m.args.need_semicolon() { self.s.word(";"); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 96b3cf79720..4a5b4ff8e04 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -876,7 +876,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; - let (ident, kind) = if self.check_keyword(kw::Type) { + let (ident, kind) = if self.eat_keyword(kw::Type) { // FOREIGN TYPE ITEM self.parse_item_foreign_type()? } else if self.check_fn_front_matter() { @@ -925,10 +925,12 @@ impl<'a> Parser<'a> { /// Parses a type from a foreign module. fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { - self.expect_keyword(kw::Type)?; - let ident = self.parse_ident()?; - self.expect_semi()?; - Ok((ident, ForeignItemKind::Ty)) + let (ident, kind) = self.parse_assoc_ty()?; + let kind = match kind { + AssocItemKind::TyAlias(g, b, d) => ForeignItemKind::TyAlias(g, b, d), + _ => unreachable!(), + }; + Ok((ident, kind)) } fn is_static_global(&mut self) -> bool { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 280a7a8fdba..f5e64443dda 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -829,7 +829,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ForeignItemKind::Static(..) => { (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS) } - ForeignItemKind::Ty => { + ForeignItemKind::TyAlias(..) => { (Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS) } ForeignItemKind::Macro(_) => unreachable!(), diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 0e4e9c15286..1a1a9b1076e 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -437,7 +437,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { match foreign_item.kind { - ForeignItemKind::Fn(_, ref generics, _) => { + ForeignItemKind::Fn(_, ref generics, _) + | ForeignItemKind::TyAlias(ref generics, ..) => { self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { visit::walk_foreign_item(this, foreign_item); }); @@ -447,7 +448,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_foreign_item(this, foreign_item); }); } - ForeignItemKind::Ty | ForeignItemKind::Macro(..) => { + ForeignItemKind::Macro(..) => { visit::walk_foreign_item(self, foreign_item); } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 561a4a83d28..5668be40eef 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1540,7 +1540,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { self.visit_ty(ty); } - ast::ForeignItemKind::Ty => { + ast::ForeignItemKind::TyAlias(..) => { if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { down_cast_data!(var_data, DefData, item.span); self.dumper.dump_def(&access, var_data); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 401e1722751..e983802ee11 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -173,7 +173,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { })) } // FIXME(plietar): needs a new DefKind in rls-data - ast::ForeignItemKind::Ty => None, + ast::ForeignItemKind::TyAlias(..) => None, ast::ForeignItemKind::Macro(..) => None, } } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index d3c4d6d5723..bd7bd9bc616 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -773,7 +773,7 @@ impl Sig for ast::ForeignItem { Ok(extend_sig(ty_sig, text, defs, vec![])) } - ast::ForeignItemKind::Ty => { + ast::ForeignItemKind::TyAlias(..) => { let mut text = "type ".to_owned(); let name = self.ident.to_string(); let defs = vec![SigElement { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index af0195ffc61..fe353bc994a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2610,7 +2610,7 @@ pub enum ForeignItemKind { /// A function. Fn(FnSig, Generics, Option>), /// A type. - Ty, + TyAlias(Generics, GenericBounds, Option>), /// A macro expanding to an item. Macro(Mac), } @@ -2620,7 +2620,7 @@ impl ForeignItemKind { match *self { ForeignItemKind::Fn(..) => "foreign function", ForeignItemKind::Static(..) => "foreign static item", - ForeignItemKind::Ty => "foreign type", + ForeignItemKind::TyAlias(..) => "foreign type", ForeignItemKind::Macro(..) => "macro in foreign module", } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index f3857b3a414..d36b0a28a8c 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1051,7 +1051,11 @@ pub fn noop_flat_map_foreign_item( visit_opt(body, |body| visitor.visit_block(body)); } ForeignItemKind::Static(t, _m) => visitor.visit_ty(t), - ForeignItemKind::Ty => {} + ForeignItemKind::TyAlias(generics, bounds, ty) => { + visitor.visit_generics(generics); + visit_bounds(bounds, visitor); + visit_opt(ty, |ty| visitor.visit_ty(ty)); + } ForeignItemKind::Macro(mac) => visitor.visit_mac(mac), } visitor.visit_id(id); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index edcfd7f4e78..ed57fc8abf3 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -535,7 +535,11 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI visitor.visit_fn(kind, item.span, item.id); } ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), - ForeignItemKind::Ty => (), + ForeignItemKind::TyAlias(ref generics, ref bounds, ref ty) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_ty, ty); + } ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), } diff --git a/src/test/ui/parser/foreign-ty-semantic-fail.rs b/src/test/ui/parser/foreign-ty-semantic-fail.rs new file mode 100644 index 00000000000..96b15232b10 --- /dev/null +++ b/src/test/ui/parser/foreign-ty-semantic-fail.rs @@ -0,0 +1,18 @@ +#![feature(extern_types)] + +fn main() {} + +extern "C" { + type A: Ord; + //~^ ERROR bounds on `type`s in `extern` blocks have no effect + type B<'a> where 'a: 'static; + //~^ ERROR `type`s inside `extern` blocks cannot have generic parameters + //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses + type C where T: 'static; + //~^ ERROR `type`s inside `extern` blocks cannot have generic parameters + //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses + type D = u8; + //~^ ERROR incorrect `type` inside `extern` block + + type E: where; +} diff --git a/src/test/ui/parser/foreign-ty-semantic-fail.stderr b/src/test/ui/parser/foreign-ty-semantic-fail.stderr new file mode 100644 index 00000000000..588e4966aae --- /dev/null +++ b/src/test/ui/parser/foreign-ty-semantic-fail.stderr @@ -0,0 +1,65 @@ +error: bounds on `type`s in `extern` blocks have no effect + --> $DIR/foreign-ty-semantic-fail.rs:6:13 + | +LL | type A: Ord; + | ^^^ + +error: `type`s inside `extern` blocks cannot have generic parameters + --> $DIR/foreign-ty-semantic-fail.rs:8:11 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type B<'a> where 'a: 'static; + | ^^^^ help: remove the generic parameters + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have `where` clauses + --> $DIR/foreign-ty-semantic-fail.rs:8:16 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type B<'a> where 'a: 'static; + | ^^^^^^^^^^^^^^^^^ help: remove the `where` clause + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have generic parameters + --> $DIR/foreign-ty-semantic-fail.rs:11:11 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type C where T: 'static; + | ^^^^^^^^ help: remove the generic parameters + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have `where` clauses + --> $DIR/foreign-ty-semantic-fail.rs:11:20 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type C where T: 'static; + | ^^^^^^^^^^^^^^^^ help: remove the `where` clause + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect `type` inside `extern` block + --> $DIR/foreign-ty-semantic-fail.rs:14:10 + | +LL | extern "C" { + | ---------- `extern` blocks define existing foreign types and types inside of them cannot have a body +... +LL | type D = u8; + | ^ -- the invalid body + | | + | cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/foreign-ty-syntactic-pass.rs b/src/test/ui/parser/foreign-ty-syntactic-pass.rs new file mode 100644 index 00000000000..a746de1f14f --- /dev/null +++ b/src/test/ui/parser/foreign-ty-syntactic-pass.rs @@ -0,0 +1,12 @@ +// check-pass + +fn main() {} + +#[cfg(FALSE)] +extern "C" { + type A: Ord; + type A<'a> where 'a: 'static; + type A where T: 'static; + type A = u8; + type A<'a: 'static, T: Ord + 'static>: Eq + PartialEq where T: 'static + Copy = Vec; +} diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs index 9c321c4bd0d..fa9c7ababcf 100644 --- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs +++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs @@ -11,11 +11,11 @@ impl X { //~| ERROR associated types are not yet supported in inherent impls type Z: Ord; //~^ ERROR associated type in `impl` without body - //~| ERROR bounds on associated `type`s in `impl`s have no effect + //~| ERROR bounds on `type`s in `impl`s have no effect //~| ERROR associated types are not yet supported in inherent impls type W: Ord where Self: Eq; //~^ ERROR associated type in `impl` without body - //~| ERROR bounds on associated `type`s in `impl`s have no effect + //~| ERROR bounds on `type`s in `impl`s have no effect //~| ERROR associated types are not yet supported in inherent impls type W where Self: Eq; //~^ ERROR associated type in `impl` without body diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr index 65e1981e3ac..541d9317c79 100644 --- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr +++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr @@ -14,7 +14,7 @@ LL | type Z: Ord; | | | help: provide a definition for the type: `= ;` -error: bounds on associated `type`s in `impl`s have no effect +error: bounds on `type`s in `impl`s have no effect --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:13 | LL | type Z: Ord; @@ -28,7 +28,7 @@ LL | type W: Ord where Self: Eq; | | | help: provide a definition for the type: `= ;` -error: bounds on associated `type`s in `impl`s have no effect +error: bounds on `type`s in `impl`s have no effect --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:13 | LL | type W: Ord where Self: Eq;