diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 738435891f16f..59bce93ff870c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3542,6 +3542,19 @@ impl VisibilityKind { } } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct ImplRestriction { + pub kind: RestrictionKind, + pub span: Span, + pub tokens: Option, +} + +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub enum RestrictionKind { + Unrestricted, + Restricted { path: Box, id: NodeId, shorthand: bool }, +} + /// Field definition in a struct, variant or union. /// /// E.g., `bar: usize` as in `struct Foo { bar: usize }`. @@ -3741,6 +3754,7 @@ pub struct Trait { pub constness: Const, pub safety: Safety, pub is_auto: IsAuto, + pub impl_restriction: ImplRestriction, pub ident: Ident, pub generics: Generics, #[visitable(extra = BoundKind::SuperTraits)] diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 3d2477e5f033f..73bfa0ba7ab6d 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -8,8 +8,8 @@ use std::marker::PhantomData; use crate::tokenstream::LazyAttrTokenStream; use crate::{ Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField, - FieldDef, ForeignItem, GenericParam, Item, NodeId, Param, Pat, PatField, Path, Stmt, StmtKind, - Ty, Variant, Visibility, WherePredicate, + FieldDef, ForeignItem, GenericParam, ImplRestriction, Item, NodeId, Param, Pat, PatField, Path, + Stmt, StmtKind, Ty, Variant, Visibility, WherePredicate, }; /// A trait for AST nodes having an ID. @@ -97,7 +97,19 @@ macro_rules! impl_has_tokens_none { }; } -impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility); +impl_has_tokens!( + AssocItem, + AttrItem, + Block, + Expr, + ForeignItem, + Item, + Pat, + Path, + Ty, + Visibility, + ImplRestriction +); impl_has_tokens_none!( Arm, ExprField, @@ -242,7 +254,7 @@ impl_has_attrs!( Variant, WherePredicate, ); -impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); +impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility, ImplRestriction); impl HasAttrs for Box { const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 8556e8288670f..22298a30b927e 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -467,6 +467,7 @@ macro_rules! common_visitor_and_walkers { RangeEnd, RangeSyntax, Recovered, + RestrictionKind, Safety, StaticItem, StrLit, @@ -595,6 +596,7 @@ macro_rules! common_visitor_and_walkers { fn visit_poly_trait_ref(PolyTraitRef); fn visit_precise_capturing_arg(PreciseCapturingArg); fn visit_qself(QSelf); + fn visit_impl_restriction(ImplRestriction); fn visit_trait_ref(TraitRef); fn visit_ty_pat(TyPat); fn visit_ty(Ty); @@ -1115,6 +1117,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_poly_trait_ref(PolyTraitRef); pub fn walk_precise_capturing_arg(PreciseCapturingArg); pub fn walk_qself(QSelf); + pub fn walk_impl_restriction(ImplRestriction); pub fn walk_trait_ref(TraitRef); pub fn walk_ty_pat(TyPat); pub fn walk_ty(Ty); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4f58fef2d24c3..90251025965dc 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -512,6 +512,8 @@ impl<'hir> LoweringContext<'_, 'hir> { constness, is_auto, safety, + // FIXME(impl_restrictions): lower to HIR + impl_restriction: _, ident, generics, bounds, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 891570b053e53..9c5b0422cbed0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -576,6 +576,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(coroutines, "coroutine syntax is experimental"); gate_all!(const_block_items, "const block items are experimental"); gate_all!(final_associated_functions, "`final` on trait functions is experimental"); + gate_all!(impl_restriction, "`impl` restrictions are experimental"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 74ed0405498d9..25b398b849246 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -80,6 +80,10 @@ pub fn vis_to_string(v: &ast::Visibility) -> String { State::new().vis_to_string(v) } +pub fn impl_restriction_to_string(r: &ast::ImplRestriction) -> String { + State::new().impl_restriction_to_string(r) +} + pub fn meta_list_item_to_string(li: &ast::MetaItemInner) -> String { State::new().meta_list_item_to_string(li) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c8874ed99dca9..9e03cc9cc71ec 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1110,6 +1110,10 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere Self::to_string(|s| s.print_visibility(v)) } + fn impl_restriction_to_string(&self, r: &ast::ImplRestriction) -> String { + Self::to_string(|s| s.print_impl_restriction(r)) + } + fn block_to_string(&self, blk: &ast::Block) -> String { Self::to_string(|s| { let (cb, ib) = s.head(""); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 57e105010343c..3407feb3dcc3a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -365,6 +365,7 @@ impl<'a> State<'a> { constness, safety, is_auto, + impl_restriction, ident, generics, bounds, @@ -375,6 +376,7 @@ impl<'a> State<'a> { self.print_constness(*constness); self.print_safety(*safety); self.print_is_auto(*is_auto); + self.print_impl_restriction(impl_restriction); self.word_nbsp("trait"); self.print_ident(*ident); self.print_generic_params(&generics.params); @@ -483,6 +485,20 @@ impl<'a> State<'a> { } } + pub(crate) fn print_impl_restriction(&mut self, impl_restriction: &ast::ImplRestriction) { + match &impl_restriction.kind { + ast::RestrictionKind::Restricted { path, shorthand, .. } => { + let path = Self::to_string(|s| s.print_path(path, false, 0)); + if *shorthand { + self.word_nbsp(format!("impl({path})")) + } else { + self.word_nbsp(format!("impl(in {path})")) + } + } + ast::RestrictionKind::Unrestricted => {} + } + } + fn print_defaultness(&mut self, defaultness: ast::Defaultness) { if let ast::Defaultness::Default(_) = defaultness { self.word_nbsp("default"); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 5becbac186766..def3415bdc57c 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -518,6 +518,8 @@ declare_features! ( (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)), /// Target features on hexagon. (unstable, hexagon_target_feature, "1.27.0", Some(150250)), + /// Allows `impl(crate) trait Foo` restrictions. + (incomplete, impl_restriction, "CURRENT_RUSTC_VERSION", Some(105077)), /// Allows `impl Trait` to be used inside associated types (RFC 2515). (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)), /// Allows `impl Trait` in bindings (`let`). diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 2a084a888e330..bf82453ddc184 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1268,6 +1268,26 @@ pub(crate) struct IncorrectVisibilityRestriction { pub inner_str: String, } +#[derive(Diagnostic)] +#[diag("incorrect `impl` restriction")] +#[help( + "some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path" +)] +pub(crate) struct IncorrectImplRestriction { + #[primary_span] + #[suggestion( + "help: use `in` to restrict implementations to the path `{$inner_str}`", + code = "in {inner_str}", + applicability = "machine-applicable" + )] + pub span: Span, + pub inner_str: String, +} + #[derive(Diagnostic)] #[diag(" ... else {\"{\"} ... {\"}\"} is not allowed")] pub(crate) struct AssignmentElseNotAllowed { @@ -2403,6 +2423,14 @@ pub(crate) struct TraitAliasCannotBeUnsafe { pub span: Span, } +#[derive(Diagnostic)] +#[diag("trait aliases cannot be `impl`-restricted")] +pub(crate) struct TraitAliasCannotBeImplRestricted { + #[primary_span] + #[label("trait aliases cannot be `impl`-restricted")] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("associated `static` items are not allowed")] pub(crate) struct AssociatedStaticItemNotAllowed { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 69610d062919d..063cb274fac41 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1025,17 +1025,79 @@ impl<'a> Parser<'a> { } } - /// Is this an `(const unsafe? auto?| unsafe auto? | auto) trait` item? + /// Is there an `[ impl(in? path) ]? trait` item `dist` tokens ahead? + fn is_trait_with_maybe_impl_restriction_in_front(&self, dist: usize) -> bool { + // `trait` + if self.is_keyword_ahead(dist, &[kw::Trait]) { + return true; + } + // `impl(` + if !self.is_keyword_ahead(dist, &[kw::Impl]) + || !self.look_ahead(dist + 1, |t| t == &token::OpenParen) + { + return false; + } + // `crate | super | self) trait` + if self.is_keyword_ahead(dist + 2, &[kw::Crate, kw::Super, kw::SelfLower]) + && self.look_ahead(dist + 3, |t| t == &token::CloseParen) + && self.is_keyword_ahead(dist + 4, &[kw::Trait]) + { + return true; + } + // `impl(in? something) trait` + // We catch cases where the `in` keyword is missing to provide a + // better error message. This is handled later in + // `self.recover_incorrect_impl_restriction`. + self.tree_look_ahead(dist + 2, |t| { + if let TokenTree::Token(token, _) = t { token.is_keyword(kw::Trait) } else { false } + }) + .unwrap_or(false) + } + + /// Is this an `(const unsafe? auto? [ impl(in? path) ]? | unsafe auto? [ impl(in? path) ]? | auto [ impl(in? path) ]? | [ impl(in? path) ]?) trait` item? fn check_trait_front_matter(&mut self) -> bool { - // auto trait - self.check_keyword(exp!(Auto)) && self.is_keyword_ahead(1, &[kw::Trait]) - // unsafe auto trait - || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) - || self.check_keyword(exp!(Const)) && ((self.is_keyword_ahead(1, &[kw::Trait]) || self.is_keyword_ahead(1, &[kw::Auto]) && self.is_keyword_ahead(2, &[kw::Trait])) - || self.is_keyword_ahead(1, &[kw::Unsafe]) && self.is_keyword_ahead(2, &[kw::Trait, kw::Auto])) + // `[ impl(in? path) ]? trait` + if self.is_trait_with_maybe_impl_restriction_in_front(0) { + return true; + } + // `auto [ impl(in? path) ]? trait` + if self.check_keyword(exp!(Auto)) && self.is_trait_with_maybe_impl_restriction_in_front(1) { + return true; + } + // `unsafe auto? [ impl(in? path) ]? trait` + if self.check_keyword(exp!(Unsafe)) + && (self.is_trait_with_maybe_impl_restriction_in_front(1) + || self.is_keyword_ahead(1, &[kw::Auto]) + && self.is_trait_with_maybe_impl_restriction_in_front(2)) + { + return true; + } + // `const` ... + if !self.check_keyword(exp!(Const)) { + return false; + } + // `const [ impl(in? path) ]? trait` + if self.is_trait_with_maybe_impl_restriction_in_front(1) { + return true; + } + // `const (unsafe | auto) [ impl(in? path) ]? trait` + if self.is_keyword_ahead(1, &[kw::Unsafe, kw::Auto]) + && self.is_trait_with_maybe_impl_restriction_in_front(2) + { + return true; + } + // `const unsafe auto [ impl(in? path) ]? trait` + self.is_keyword_ahead(1, &[kw::Unsafe]) + && self.is_keyword_ahead(2, &[kw::Auto]) + && self.is_trait_with_maybe_impl_restriction_in_front(3) } - /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. + /// Parses `const? unsafe? auto? [impl(in? path)]? trait Foo { ... }` or `trait Foo = Bar;`. + /// + /// FIXME(restrictions): The current keyword order follows the grammar specified in RFC 3323. + /// However, whether the restriction should be grouped closer to the visibility modifier + /// (e.g., `pub impl(crate) const unsafe auto trait`) remains an unresolved design question. + /// This ordering must be kept in sync with the logic in `check_trait_front_matter`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> { let constness = self.parse_constness(Case::Sensitive); if let Const::Yes(span) = constness { @@ -1050,6 +1112,8 @@ impl<'a> Parser<'a> { IsAuto::No }; + let impl_restriction = self.parse_impl_restriction()?; + self.expect_keyword(exp!(Trait))?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; @@ -1078,6 +1142,9 @@ impl<'a> Parser<'a> { if let Safety::Unsafe(_) = safety { self.dcx().emit_err(errors::TraitAliasCannotBeUnsafe { span: whole_span }); } + if let RestrictionKind::Restricted { .. } = impl_restriction.kind { + self.dcx().emit_err(errors::TraitAliasCannotBeImplRestricted { span: whole_span }); + } self.psess.gated_spans.gate(sym::trait_alias, whole_span); @@ -1090,6 +1157,7 @@ impl<'a> Parser<'a> { constness, is_auto, safety, + impl_restriction, ident, generics, bounds, @@ -2843,8 +2911,8 @@ impl<'a> Parser<'a> { && !self.is_unsafe_foreign_mod() // Rule out `async gen {` and `async gen move {` && !self.is_async_gen_block() - // Rule out `const unsafe auto` and `const unsafe trait`. - && !self.is_keyword_ahead(2, &[kw::Auto, kw::Trait]) + // Rule out `const unsafe auto` and `const unsafe trait` and `const unsafe impl`. + && !self.is_keyword_ahead(2, &[kw::Auto, kw::Trait, kw::Impl]) ) }) // `extern ABI fn` diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f95fe61b0abdc..1379d63dd66a2 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -34,8 +34,8 @@ use rustc_ast::tokenstream::{ use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation, Mutability, - Recovered, Safety, StrLit, Visibility, VisibilityKind, + DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, ImplRestriction, MgcaDisambiguation, + Mutability, Recovered, RestrictionKind, Safety, StrLit, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::debug_assert_matches; @@ -49,7 +49,10 @@ use token_type::TokenTypeSet; pub use token_type::{ExpKeywordPair, ExpTokenPair, TokenType}; use tracing::debug; -use crate::errors::{self, IncorrectVisibilityRestriction, NonStringAbiLiteral, TokenDescription}; +use crate::errors::{ + self, IncorrectImplRestriction, IncorrectVisibilityRestriction, NonStringAbiLiteral, + TokenDescription, +}; use crate::exp; #[cfg(test)] @@ -1525,6 +1528,60 @@ impl<'a> Parser<'a> { Ok(()) } + /// Parses an optional `impl` restriction. + /// Enforces the `impl_restriction` feature gate whenever an explicit restriction is encountered. + fn parse_impl_restriction(&mut self) -> PResult<'a, ImplRestriction> { + if self.eat_keyword(exp!(Impl)) { + let lo = self.prev_token.span; + // No units or tuples are allowed to follow `impl` here, so we can safely bump `(`. + self.expect(exp!(OpenParen))?; + if self.eat_keyword(exp!(In)) { + let path = self.parse_path(PathStyle::Mod)?; // `in path` + self.expect(exp!(CloseParen))?; // `)` + let restriction = RestrictionKind::Restricted { + path: Box::new(path), + id: ast::DUMMY_NODE_ID, + shorthand: false, + }; + let span = lo.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::impl_restriction, span); + return Ok(ImplRestriction { kind: restriction, span, tokens: None }); + } else if self.look_ahead(1, |t| t == &token::CloseParen) + && self.is_keyword_ahead(0, &[kw::Crate, kw::Super, kw::SelfLower]) + { + let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` + self.expect(exp!(CloseParen))?; // `)` + let restriction = RestrictionKind::Restricted { + path: Box::new(path), + id: ast::DUMMY_NODE_ID, + shorthand: true, + }; + let span = lo.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::impl_restriction, span); + return Ok(ImplRestriction { kind: restriction, span, tokens: None }); + } else { + self.recover_incorrect_impl_restriction(lo)?; + // Emit diagnostic, but continue with no impl restriction. + } + } + Ok(ImplRestriction { + kind: RestrictionKind::Unrestricted, + span: self.token.span.shrink_to_lo(), + tokens: None, + }) + } + + /// Recovery for e.g. `impl(something) trait` + fn recover_incorrect_impl_restriction(&mut self, lo: Span) -> PResult<'a, ()> { + let path = self.parse_path(PathStyle::Mod)?; + self.expect(exp!(CloseParen))?; // `)` + let path_str = pprust::path_to_string(&path); + self.dcx().emit_err(IncorrectImplRestriction { span: path.span, inner_str: path_str }); + let end = self.prev_token.span; + self.psess.gated_spans.gate(sym::impl_restriction, lo.to(end)); + Ok(()) + } + /// Parses `extern string_literal?`. fn parse_extern(&mut self, case: Case) -> Extern { if self.eat_keyword_case(exp!(Extern), case) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4ae4aac7f7839..7d1e9c28f4c67 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1264,6 +1264,7 @@ symbols! { immediate_abort: "immediate-abort", impl_header_lifetime_elision, impl_lint_pass, + impl_restriction, impl_trait_in_assoc_type, impl_trait_in_bindings, impl_trait_in_fn_trait_return, diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 239f721ae05be..50cfb0ed89dec 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -449,6 +449,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { constness: lc, is_auto: la, safety: lu, + impl_restriction: liprt, ident: li, generics: lg, bounds: lb, @@ -458,6 +459,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { constness: rc, is_auto: ra, safety: ru, + impl_restriction: riprt, ident: ri, generics: rg, bounds: rb, @@ -467,6 +469,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) && la == ra && matches!(lu, Safety::Default) == matches!(ru, Safety::Default) + && eq_impl_restriction(liprt, riprt) && eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) @@ -820,8 +823,8 @@ pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { matches!( (l, r), (Defaultness::Implicit, Defaultness::Implicit) - | (Defaultness::Default(_), Defaultness::Default(_)) - | (Defaultness::Final(_), Defaultness::Final(_)) + | (Defaultness::Default(_), Defaultness::Default(_)) + | (Defaultness::Final(_), Defaultness::Final(_)) ) } @@ -834,6 +837,29 @@ pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool { } } +pub fn eq_impl_restriction(l: &ImplRestriction, r: &ImplRestriction) -> bool { + eq_restriction_kind(&l.kind, &r.kind) +} + +fn eq_restriction_kind(l: &RestrictionKind, r: &RestrictionKind) -> bool { + match (l, r) { + (RestrictionKind::Unrestricted, RestrictionKind::Unrestricted) => true, + ( + RestrictionKind::Restricted { + path: l_path, + shorthand: l_short, + id: _, + }, + RestrictionKind::Restricted { + path: r_path, + shorthand: r_short, + id: _, + }, + ) => l_short == r_short && eq_path(l_path, r_path), + _ => false, + } +} + pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool { eq_fn_ret_ty(&l.output, &r.output) && over(&l.inputs, &r.inputs, |l, r| { diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 90466b0b11106..776574223d7f2 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1168,6 +1168,7 @@ pub(crate) fn format_trait( constness, is_auto, safety, + ref impl_restriction, ident, ref generics, ref bounds, @@ -1176,11 +1177,12 @@ pub(crate) fn format_trait( let mut result = String::with_capacity(128); let header = format!( - "{}{}{}{}trait ", + "{}{}{}{}{}trait ", format_visibility(context, &item.vis), format_constness(constness), format_safety(safety), format_auto(is_auto), + format_impl_restriction(context, impl_restriction), ); result.push_str(&header); diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index b676803379f7c..b052e74d8bf20 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -2,8 +2,8 @@ use std::borrow::Cow; use rustc_ast::YieldKind; use rustc_ast::ast::{ - self, Attribute, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Visibility, - VisibilityKind, + self, Attribute, ImplRestriction, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, + RestrictionKind, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_span::{BytePos, LocalExpnId, Span, Symbol, SyntaxContext, sym, symbol}; @@ -74,6 +74,40 @@ pub(crate) fn format_visibility( } } +pub(crate) fn format_impl_restriction( + context: &RewriteContext<'_>, + impl_restriction: &ImplRestriction, +) -> String { + format_restriction("impl", context, &impl_restriction.kind) +} + +fn format_restriction( + kw: &'static str, + context: &RewriteContext<'_>, + restriction: &RestrictionKind, +) -> String { + match restriction { + RestrictionKind::Unrestricted => String::new(), + RestrictionKind::Restricted { + ref path, + id: _, + shorthand, + } => { + let Path { ref segments, .. } = **path; + let mut segments_iter = segments.iter().map(|seg| rewrite_ident(context, seg.ident)); + if path.is_global() && segments_iter.next().is_none() { + panic!("non-global path in {kw}(restricted)?"); + } + // FIXME use `segments_iter.intersperse("::").collect::()` once + // `#![feature(iter_intersperse)]` is re-stabilized. + let path = itertools::join(segments_iter, "::"); + let in_str = if *shorthand { "" } else { "in " }; + + format!("{kw}({in_str}{path}) ") + } + } +} + #[inline] pub(crate) fn format_coro(coroutine_kind: &ast::CoroutineKind) -> &'static str { match coroutine_kind { diff --git a/src/tools/rustfmt/tests/source/impl-restriction.rs b/src/tools/rustfmt/tests/source/impl-restriction.rs new file mode 100644 index 0000000000000..4459d9a8ba2b5 --- /dev/null +++ b/src/tools/rustfmt/tests/source/impl-restriction.rs @@ -0,0 +1,41 @@ +#![feature(impl_restriction)] + +pub +impl(crate) +trait Foo {} + +pub impl +( in +crate ) +trait +Bar +{} + +pub +impl ( in foo +:: +bar ) +trait Baz {} + +pub +const +impl +(self) +trait QuxConst {} + +pub +auto impl( +super +) +trait QuxAuto {} + +pub +unsafe impl +(in crate) +trait QuxUnsafe {} + +pub const +unsafe impl +(in super +::foo) +trait QuxConstUnsafe {} diff --git a/src/tools/rustfmt/tests/target/impl-restriction.rs b/src/tools/rustfmt/tests/target/impl-restriction.rs new file mode 100644 index 0000000000000..4ff617af0f257 --- /dev/null +++ b/src/tools/rustfmt/tests/target/impl-restriction.rs @@ -0,0 +1,15 @@ +#![feature(impl_restriction)] + +pub impl(crate) trait Foo {} + +pub impl(in crate) trait Bar {} + +pub impl(in foo::bar) trait Baz {} + +pub const impl(self) trait QuxConst {} + +pub auto impl(super) trait QuxAuto {} + +pub unsafe impl(in crate) trait QuxUnsafe {} + +pub const unsafe impl(in super::foo) trait QuxConstUnsafe {} diff --git a/tests/ui/README.md b/tests/ui/README.md index d2b189a0e022c..a24cb761c6790 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -699,6 +699,11 @@ This test category revolves around trait objects with `Sized` having illegal ope Tests on lifetime elision in impl function signatures. See [Lifetime elision | Nomicon](https://doc.rust-lang.org/nomicon/lifetime-elision.html). +## `tests/ui/impl-restriction/` +Tests for `#![feature(impl_restriction)]`. See [Tracking issue for restrictions #105077 +](https://github.com/rust-lang/rust/issues/105077). + + ## `tests/ui/impl-trait/` Tests for trait impls. diff --git a/tests/ui/impl-restriction/feature-gate-impl-restriction.rs b/tests/ui/impl-restriction/feature-gate-impl-restriction.rs new file mode 100644 index 0000000000000..95a050fe444ab --- /dev/null +++ b/tests/ui/impl-restriction/feature-gate-impl-restriction.rs @@ -0,0 +1,43 @@ +//@ compile-flags: --crate-type=lib +//@ revisions: with_gate without_gate +//@[with_gate] check-pass + +#![cfg_attr(with_gate, feature(impl_restriction))] +#![cfg_attr(with_gate, allow(incomplete_features))] +#![feature(auto_traits, const_trait_impl)] + +pub impl(crate) trait Bar {} //[without_gate]~ ERROR `impl` restrictions are experimental +pub impl(in crate) trait BarInCrate {} //[without_gate]~ ERROR `impl` restrictions are experimental + +mod foo { + pub impl(in crate::foo) trait Baz {} //[without_gate]~ ERROR `impl` restrictions are experimental + pub unsafe impl(super) trait BazUnsafeSuper {} //[without_gate]~ ERROR `impl` restrictions are experimental + pub auto impl(self) trait BazAutoSelf {} //[without_gate]~ ERROR `impl` restrictions are experimental + pub const impl(in self) trait BazConst {} //[without_gate]~ ERROR `impl` restrictions are experimental + + mod foo_inner { + pub impl(in crate::foo::foo_inner) trait Qux {} //[without_gate]~ ERROR `impl` restrictions are experimental + pub unsafe auto impl(in crate::foo::foo_inner) trait QuxAutoUnsafe {} //[without_gate]~ ERROR `impl` restrictions are experimental + pub const unsafe impl(in crate::foo::foo_inner) trait QuxConstUnsafe {} //[without_gate]~ ERROR `impl` restrictions are experimental + } + + #[cfg(false)] + pub impl(crate) trait Bar {} //[without_gate]~ ERROR `impl` restrictions are experimental + #[cfg(false)] + pub impl(in crate) trait BarInCrate {} //[without_gate]~ ERROR `impl` restrictions are experimental + #[cfg(false)] + pub unsafe impl(self) trait BazUnsafeSelf {} //[without_gate]~ ERROR `impl` restrictions are experimental + #[cfg(false)] + pub auto impl(in super) trait BazAutoSuper {} //[without_gate]~ ERROR `impl` restrictions are experimental + #[cfg(false)] + pub const impl(super) trait BazConstSuper {} //[without_gate]~ ERROR `impl` restrictions are experimental + + #[cfg(false)] + mod cfged_out_foo { + pub impl(in crate::foo::cfged_out_foo) trait CfgedOutQux {} //[without_gate]~ ERROR `impl` restrictions are experimental + pub unsafe auto impl(in crate::foo::cfged_out_foo) trait CfgedOutQuxUnsafeAuto {} //[without_gate]~ ERROR `impl` restrictions are experimental + pub const unsafe impl(in crate::foo::cfged_out_foo) trait CfgedOutQuxConstUnsafe {} //[without_gate]~ ERROR `impl` restrictions are experimental + } + + // auto traits cannot be const, so we do not include these combinations in the test. +} diff --git a/tests/ui/impl-restriction/feature-gate-impl-restriction.without_gate.stderr b/tests/ui/impl-restriction/feature-gate-impl-restriction.without_gate.stderr new file mode 100644 index 0000000000000..4f99d962d4bb7 --- /dev/null +++ b/tests/ui/impl-restriction/feature-gate-impl-restriction.without_gate.stderr @@ -0,0 +1,173 @@ +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:9:5 + | +LL | pub impl(crate) trait Bar {} + | ^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:10:5 + | +LL | pub impl(in crate) trait BarInCrate {} + | ^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:13:9 + | +LL | pub impl(in crate::foo) trait Baz {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:14:16 + | +LL | pub unsafe impl(super) trait BazUnsafeSuper {} + | ^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:15:14 + | +LL | pub auto impl(self) trait BazAutoSelf {} + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:16:15 + | +LL | pub const impl(in self) trait BazConst {} + | ^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:19:13 + | +LL | pub impl(in crate::foo::foo_inner) trait Qux {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:20:25 + | +LL | ... pub unsafe auto impl(in crate::foo::foo_inner) trait QuxAutoUnsafe {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:21:26 + | +LL | ... pub const unsafe impl(in crate::foo::foo_inner) trait QuxConstUnsafe {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:25:9 + | +LL | pub impl(crate) trait Bar {} + | ^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:27:9 + | +LL | pub impl(in crate) trait BarInCrate {} + | ^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:29:16 + | +LL | pub unsafe impl(self) trait BazUnsafeSelf {} + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:31:14 + | +LL | pub auto impl(in super) trait BazAutoSuper {} + | ^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:33:15 + | +LL | pub const impl(super) trait BazConstSuper {} + | ^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:37:13 + | +LL | pub impl(in crate::foo::cfged_out_foo) trait CfgedOutQux {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:38:25 + | +LL | ... pub unsafe auto impl(in crate::foo::cfged_out_foo) trait CfgedOutQuxUnsafeAuto {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/feature-gate-impl-restriction.rs:39:26 + | +LL | ... pub const unsafe impl(in crate::foo::cfged_out_foo) trait CfgedOutQuxConstUnsafe {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 17 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.rs b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.rs new file mode 100644 index 0000000000000..d6490d5b4f978 --- /dev/null +++ b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.rs @@ -0,0 +1,20 @@ +//@ compile-flags: --crate-type=lib +//@ revisions: with_gate without_gate +#![cfg_attr(with_gate, feature(impl_restriction))] +//[with_gate]~^ WARN the feature `impl_restriction` is incomplete and may not be safe to use and/or cause compiler crashes +#![feature(auto_traits, const_trait_impl)] + +mod foo { + pub impl(crate::foo) trait Baz {} //~ ERROR incorrect `impl` restriction + //[without_gate]~^ ERROR `impl` restrictions are experimental + pub unsafe impl(crate::foo) trait BazUnsafe {} //~ ERROR incorrect `impl` restriction + //[without_gate]~^ ERROR `impl` restrictions are experimental + pub auto impl(crate::foo) trait BazAuto {} //~ ERROR incorrect `impl` restriction + //[without_gate]~^ ERROR `impl` restrictions are experimental + pub const impl(crate::foo) trait BazConst {} //~ ERROR incorrect `impl` restriction + //[without_gate]~^ ERROR `impl` restrictions are experimental + pub const unsafe impl(crate::foo) trait BazConstUnsafe {} //~ ERROR incorrect `impl` restriction + //[without_gate]~^ ERROR `impl` restrictions are experimental + pub unsafe auto impl(crate::foo) trait BazUnsafeAuto {} //~ ERROR incorrect `impl` restriction + //[without_gate]~^ ERROR `impl` restrictions are experimental +} diff --git a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.with_gate.stderr b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.with_gate.stderr new file mode 100644 index 0000000000000..ad183b23e0138 --- /dev/null +++ b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.with_gate.stderr @@ -0,0 +1,107 @@ +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:8:14 + | +LL | pub impl(crate::foo) trait Baz {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub impl(in crate::foo) trait Baz {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:10:21 + | +LL | pub unsafe impl(crate::foo) trait BazUnsafe {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub unsafe impl(in crate::foo) trait BazUnsafe {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:12:19 + | +LL | pub auto impl(crate::foo) trait BazAuto {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub auto impl(in crate::foo) trait BazAuto {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:14:20 + | +LL | pub const impl(crate::foo) trait BazConst {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub const impl(in crate::foo) trait BazConst {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:16:27 + | +LL | pub const unsafe impl(crate::foo) trait BazConstUnsafe {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub const unsafe impl(in crate::foo) trait BazConstUnsafe {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:18:26 + | +LL | pub unsafe auto impl(crate::foo) trait BazUnsafeAuto {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub unsafe auto impl(in crate::foo) trait BazUnsafeAuto {} + | ++ + +warning: the feature `impl_restriction` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/recover-incorrect-impl-restriction.rs:3:32 + | +LL | #![cfg_attr(with_gate, feature(impl_restriction))] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 6 previous errors; 1 warning emitted + diff --git a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.without_gate.stderr b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.without_gate.stderr new file mode 100644 index 0000000000000..d949172ffb458 --- /dev/null +++ b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.without_gate.stderr @@ -0,0 +1,159 @@ +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:8:14 + | +LL | pub impl(crate::foo) trait Baz {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub impl(in crate::foo) trait Baz {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:10:21 + | +LL | pub unsafe impl(crate::foo) trait BazUnsafe {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub unsafe impl(in crate::foo) trait BazUnsafe {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:12:19 + | +LL | pub auto impl(crate::foo) trait BazAuto {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub auto impl(in crate::foo) trait BazAuto {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:14:20 + | +LL | pub const impl(crate::foo) trait BazConst {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub const impl(in crate::foo) trait BazConst {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:16:27 + | +LL | pub const unsafe impl(crate::foo) trait BazConstUnsafe {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub const unsafe impl(in crate::foo) trait BazConstUnsafe {} + | ++ + +error: incorrect `impl` restriction + --> $DIR/recover-incorrect-impl-restriction.rs:18:26 + | +LL | pub unsafe auto impl(crate::foo) trait BazUnsafeAuto {} + | ^^^^^^^^^^ + | + = help: some possible `impl` restrictions are: + `impl(crate)`: can only be implemented in the current crate + `impl(super)`: can only be implemented in the parent module + `impl(self)`: can only be implemented in current module + `impl(in path::to::module)`: can only be implemented in the specified path +help: help: use `in` to restrict implementations to the path `crate::foo` + | +LL | pub unsafe auto impl(in crate::foo) trait BazUnsafeAuto {} + | ++ + +error[E0658]: `impl` restrictions are experimental + --> $DIR/recover-incorrect-impl-restriction.rs:8:9 + | +LL | pub impl(crate::foo) trait Baz {} + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/recover-incorrect-impl-restriction.rs:10:16 + | +LL | pub unsafe impl(crate::foo) trait BazUnsafe {} + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/recover-incorrect-impl-restriction.rs:12:14 + | +LL | pub auto impl(crate::foo) trait BazAuto {} + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/recover-incorrect-impl-restriction.rs:14:15 + | +LL | pub const impl(crate::foo) trait BazConst {} + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/recover-incorrect-impl-restriction.rs:16:22 + | +LL | pub const unsafe impl(crate::foo) trait BazConstUnsafe {} + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/recover-incorrect-impl-restriction.rs:18:21 + | +LL | pub unsafe auto impl(crate::foo) trait BazUnsafeAuto {} + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.rs b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.rs new file mode 100644 index 0000000000000..62622e1d55861 --- /dev/null +++ b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.rs @@ -0,0 +1,28 @@ +//@ compile-flags: --crate-type=lib +//@ revisions: with_gate without_gate +#![cfg_attr(with_gate, feature(impl_restriction))] +//[with_gate]~^ WARN the feature `impl_restriction` is incomplete and may not be safe to use and/or cause compiler crashes +#![feature(auto_traits, const_trait_impl, trait_alias)] + +impl(crate) trait Alias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted +//[without_gate]~^ ERROR `impl` restrictions are experimental +auto impl(in crate) trait AutoAlias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted +//~^ ERROR trait aliases cannot be `auto` +//[without_gate]~| ERROR `impl` restrictions are experimental +unsafe impl(self) trait UnsafeAlias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted +//~^ ERROR trait aliases cannot be `unsafe` +//[without_gate]~| ERROR `impl` restrictions are experimental +const impl(in self) trait ConstAlias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted +//[without_gate]~^ ERROR `impl` restrictions are experimental + +mod foo { + impl(super) trait InnerAlias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted + //[without_gate]~^ ERROR `impl` restrictions are experimental + const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted + //~^ ERROR trait aliases cannot be `unsafe` + //[without_gate]~| ERROR `impl` restrictions are experimental + unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted + //~^ ERROR trait aliases cannot be `auto` + //~^^ ERROR trait aliases cannot be `unsafe` + //[without_gate]~| ERROR `impl` restrictions are experimental +} diff --git a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.with_gate.stderr b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.with_gate.stderr new file mode 100644 index 0000000000000..70287aca42aad --- /dev/null +++ b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.with_gate.stderr @@ -0,0 +1,83 @@ +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:7:1 + | +LL | impl(crate) trait Alias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `auto` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1 + | +LL | auto impl(in crate) trait AutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1 + | +LL | auto impl(in crate) trait AutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `unsafe` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:1 + | +LL | unsafe impl(self) trait UnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:1 + | +LL | unsafe impl(self) trait UnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:1 + | +LL | const impl(in self) trait ConstAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:19:5 + | +LL | impl(super) trait InnerAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `unsafe` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:5 + | +LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:5 + | +LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `auto` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + | +LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` + +error: trait aliases cannot be `unsafe` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + | +LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + | +LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +warning: the feature `impl_restriction` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:3:32 + | +LL | #![cfg_attr(with_gate, feature(impl_restriction))] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 12 previous errors; 1 warning emitted + diff --git a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.without_gate.stderr b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.without_gate.stderr new file mode 100644 index 0000000000000..7bff90396708d --- /dev/null +++ b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.without_gate.stderr @@ -0,0 +1,145 @@ +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:7:1 + | +LL | impl(crate) trait Alias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `auto` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1 + | +LL | auto impl(in crate) trait AutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1 + | +LL | auto impl(in crate) trait AutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `unsafe` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:1 + | +LL | unsafe impl(self) trait UnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:1 + | +LL | unsafe impl(self) trait UnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:1 + | +LL | const impl(in self) trait ConstAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:19:5 + | +LL | impl(super) trait InnerAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `unsafe` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:5 + | +LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:5 + | +LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error: trait aliases cannot be `auto` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + | +LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` + +error: trait aliases cannot be `unsafe` + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + | +LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` + +error: trait aliases cannot be `impl`-restricted + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + | +LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted + +error[E0658]: `impl` restrictions are experimental + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:7:1 + | +LL | impl(crate) trait Alias = Copy; + | ^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:6 + | +LL | auto impl(in crate) trait AutoAlias = Copy; + | ^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:8 + | +LL | unsafe impl(self) trait UnsafeAlias = Copy; + | ^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:7 + | +LL | const impl(in self) trait ConstAlias = Copy; + | ^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:19:5 + | +LL | impl(super) trait InnerAlias = Copy; + | ^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:18 + | +LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `impl` restrictions are experimental + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:17 + | +LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #105077 for more information + = help: add `#![feature(impl_restriction)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 19 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 890b429b4ac7d..f4f66745372b5 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -800,6 +800,111 @@ macro_rules! p { }; } +#[test] +fn test_impl_restriction() { + assert_eq!( + stringify!(pub impl(crate) trait Foo {}), + "pub impl(crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(in crate) trait Foo {}), + "pub impl(in crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(super) trait Foo {}), + "pub impl(super) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(in super) trait Foo {}), + "pub impl(in super) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(self) trait Foo {}), + "pub impl(self) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(in self) trait Foo {}), + "pub impl(in self) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(in path::to) trait Foo {}), + "pub impl(in path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(in ::path::to) trait Foo {}), + "pub impl(in ::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(in self::path::to) trait Foo {}), + "pub impl(in self::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(in super::path::to) trait Foo {}), + "pub impl(in super::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub impl(in crate::path::to) trait Foo {}), + "pub impl(in crate::path::to) trait Foo {}" + ); + + assert_eq!( + stringify!(pub auto impl(crate) trait Foo {}), + "pub auto impl(crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub auto impl(in crate::path::to) trait Foo {}), + "pub auto impl(in crate::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub unsafe impl(crate) trait Foo {}), + "pub unsafe impl(crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub unsafe impl(in crate::path::to) trait Foo {}), + "pub unsafe impl(in crate::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub const impl(crate) trait Foo {}), + "pub const impl(crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub const impl(in crate::path::to) trait Foo {}), + "pub const impl(in crate::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub unsafe auto impl(crate) trait Foo {}), + "pub unsafe auto impl(crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub unsafe auto impl(in crate::path::to) trait Foo {}), + "pub unsafe auto impl(in crate::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub const auto impl(crate) trait Foo {}), + "pub const auto impl(crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub const auto impl(in crate::path::to) trait Foo {}), + "pub const auto impl(in crate::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub const unsafe impl(crate) trait Foo {}), + "pub const unsafe impl(crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub const unsafe impl(in crate::path::to) trait Foo {}), + "pub const unsafe impl(in crate::path::to) trait Foo {}" + ); + assert_eq!( + stringify!(pub const unsafe auto impl(crate) trait Foo {}), + "pub const unsafe auto impl(crate) trait Foo {}" + ); + assert_eq!( + stringify!(pub const unsafe auto impl(in crate::path::to) trait Foo {}), + "pub const unsafe auto impl(in crate::path::to) trait Foo {}" + ); +} + #[test] fn test_punct() { // For all these cases, we should preserve spaces between the tokens.