diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b8339c74dac03..c501bbdd9d9ff 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3179,6 +3179,8 @@ pub enum BoundPolarity { Negative(Span), /// `Type: ?Trait` Maybe(Span), + /// `Type: only Trait`, + Only(Span), } impl BoundPolarity { @@ -3187,6 +3189,7 @@ impl BoundPolarity { Self::Positive => "", Self::Negative(_) => "!", Self::Maybe(_) => "?", + Self::Only(_) => "only", } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8b4a2795ec90c..d64fbd72a3158 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2219,6 +2219,8 @@ impl<'hir> LoweringContext<'_, 'hir> { if let ast::BoundPolarity::Maybe(_) = modifiers.polarity { self.validate_relaxed_bound(trait_ref, *span, rbp); + } else if let ast::BoundPolarity::Only(_) = modifiers.polarity { + self.validate_only_bound(trait_ref, *span); } hir::PolyTraitRef { @@ -2229,6 +2231,18 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn validate_only_bound(&self, trait_ref: hir::TraitRef<'_>, span: Span) { + if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res + && !(self.tcx.is_lang_item(def_id, hir::LangItem::MetaSized) + || self.tcx.is_lang_item(def_id, hir::LangItem::Sized) + || self.tcx.is_lang_item(def_id, hir::LangItem::PointeeSized)) + { + self.dcx() + .struct_span_err(span, "`only` may only be applied to sizedness traits") + .emit(); + } + } + fn validate_relaxed_bound( &self, trait_ref: hir::TraitRef<'_>, @@ -2778,6 +2792,7 @@ impl<'hir> LoweringContext<'_, 'hir> { BoundPolarity::Positive => BoundPolarity::Positive, BoundPolarity::Negative(span) => BoundPolarity::Negative(self.lower_span(span)), BoundPolarity::Maybe(span) => BoundPolarity::Maybe(self.lower_span(span)), + BoundPolarity::Only(span) => BoundPolarity::Only(self.lower_span(span)), }; hir::TraitBoundModifiers { constness, polarity } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 8b2da2acaa520..b90d8fc862cb3 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1478,7 +1478,9 @@ impl<'a> State<'a> { } match polarity { ast::BoundPolarity::Positive => {} - ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => { + ast::BoundPolarity::Negative(_) + | ast::BoundPolarity::Maybe(_) + | ast::BoundPolarity::Only(_) => { self.word(polarity.as_str()); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 770ccc7dff51f..f5640fbb4a5d4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -31,12 +31,14 @@ struct CollectedBound { maybe: bool, /// `!Trait` negative: bool, + /// `only Trait` + only_modifier: bool, } impl CollectedBound { - /// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered. + /// Returns `true` if any of `Trait`, `?Trait`, `only Trait` or `!Trait` were encountered. fn any(&self) -> bool { - self.positive || self.maybe || self.negative + self.positive || self.maybe || self.negative || self.only_modifier } } @@ -112,6 +114,7 @@ fn collect_bounds<'a, 'tcx>( match ptr.modifiers.polarity { hir::BoundPolarity::Maybe(_) => collect_into.maybe = true, hir::BoundPolarity::Negative(_) => collect_into.negative = true, + hir::BoundPolarity::Only(_) => collect_into.only_modifier = true, hir::BoundPolarity::Positive => collect_into.positive = true, } }); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 943256ce07352..a43c5efb27f9d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -973,7 +973,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // we still need to perform several validation steps (see below). Instead, simply "pour" all // resulting bounds "down the drain", i.e., into a new `Vec` that just gets dropped at the end. let transient = match polarity { - hir::BoundPolarity::Positive => { + hir::BoundPolarity::Positive | hir::BoundPolarity::Only(_) => { // To elaborate on the comment directly above, regarding `PointeeSized` specifically, // we don't "reify" such bounds to avoid trait system limitations -- namely, // non-global where-clauses being preferred over item bounds (where `PointeeSized` @@ -990,9 +990,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let bounds = if transient { &mut Vec::new() } else { bounds }; let polarity = match polarity { - hir::BoundPolarity::Positive | hir::BoundPolarity::Maybe(_) => { - ty::PredicatePolarity::Positive - } + hir::BoundPolarity::Positive + | hir::BoundPolarity::Maybe(_) + | hir::BoundPolarity::Only(_) => ty::PredicatePolarity::Positive, hir::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, }; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 0204c4c9ab5fa..c42f663e85c10 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -824,6 +824,7 @@ impl<'a> State<'a> { hir::BoundPolarity::Positive => {} hir::BoundPolarity::Negative(_) => self.word("!"), hir::BoundPolarity::Maybe(_) => self.word("?"), + hir::BoundPolarity::Only(_) => self.word_space("only"), } self.print_formal_generic_params(t.bound_generic_params); self.print_trait_ref(&t.trait_ref); diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index 2d1db430ac27c..d22ac803ebbd1 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -106,6 +106,7 @@ pub enum TokenType { KwMod, KwMove, KwMut, + KwOnly, KwPub, KwRaw, KwRef, @@ -247,6 +248,7 @@ impl TokenType { KwMod, KwMove, KwMut, + KwOnly, KwPub, KwRaw, KwRef, @@ -324,6 +326,7 @@ impl TokenType { TokenType::KwMod => Some(kw::Mod), TokenType::KwMove => Some(kw::Move), TokenType::KwMut => Some(kw::Mut), + TokenType::KwOnly => Some(kw::Only), TokenType::KwPub => Some(kw::Pub), TokenType::KwRaw => Some(kw::Raw), TokenType::KwRef => Some(kw::Ref), @@ -540,6 +543,7 @@ macro_rules! exp { (Mod) => { exp!(@kw, Mod, KwMod) }; (Move) => { exp!(@kw, Move, KwMove) }; (Mut) => { exp!(@kw, Mut, KwMut) }; + (Only) => { exp!(@kw, Only, KwOnly) }; (Pub) => { exp!(@kw, Pub, KwPub) }; (Raw) => { exp!(@kw, Raw, KwRaw) }; (Ref) => { exp!(@kw, Ref, KwRef) }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index b5151cf20ab02..7ed12d1d9f559 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1120,6 +1120,7 @@ impl<'a> Parser<'a> { || self.check(exp!(OpenParen)) || self.can_begin_maybe_const_bound() || self.check_keyword(exp!(Const)) + || self.check_keyword(exp!(Only)) || self.check_keyword(exp!(Async)) || self.check_keyword(exp!(Use)) } @@ -1201,7 +1202,9 @@ impl<'a> Parser<'a> { match polarity { BoundPolarity::Positive => {} - BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => { + BoundPolarity::Negative(span) + | BoundPolarity::Maybe(span) + | BoundPolarity::Only(span) => { return self .dcx() .emit_err(errors::ModifierLifetime { span, modifier: polarity.as_str() }); @@ -1265,6 +1268,8 @@ impl<'a> Parser<'a> { } else if self.eat(exp!(Bang)) { self.psess.gated_spans.gate(sym::negative_bounds, self.prev_token.span); BoundPolarity::Negative(self.prev_token.span) + } else if self.eat_keyword(exp!(Only)) { + BoundPolarity::Only(self.prev_token.span) } else { BoundPolarity::Positive }; @@ -1274,7 +1279,9 @@ impl<'a> Parser<'a> { BoundPolarity::Positive => { // All trait bound modifiers allowed to combine with positive polarity } - BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => { + BoundPolarity::Maybe(polarity_span) + | BoundPolarity::Negative(polarity_span) + | BoundPolarity::Only(polarity_span) => { match (asyncness, constness) { (BoundAsyncness::Normal, BoundConstness::Never) => { // Ok, no modifiers. @@ -1346,7 +1353,9 @@ impl<'a> Parser<'a> { if let Some(binder_span) = binder_span { match modifiers.polarity { - BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => { + BoundPolarity::Negative(polarity_span) + | BoundPolarity::Maybe(polarity_span) + | BoundPolarity::Only(polarity_span) => { self.dcx().emit_err(errors::BinderAndPolarity { binder_span, polarity_span, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 02fe3171cd9f4..e980eabea4005 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -129,6 +129,7 @@ symbols! { ContractRequires: "contract_requires", Default: "default", MacroRules: "macro_rules", + Only: "only", Raw: "raw", Reuse: "reuse", Safe: "safe", diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 8172ef1848e80..2ef2261b95173 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -267,6 +267,7 @@ pub(crate) fn print_generic_bound( hir::BoundPolarity::Positive => "", hir::BoundPolarity::Maybe(_) => "?", hir::BoundPolarity::Negative(_) => "!", + hir::BoundPolarity::Only(_) => "only", })?; print_poly_trait(ty, cx).fmt(f) } diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 55c0372259c0f..f88e74a55e2b6 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -576,6 +576,7 @@ fn poly_trait_ref_search_pat(poly_trait_ref: &PolyTraitRef<'_>) -> (Pat, Pat) { .or_else(|| match polarity { BoundPolarity::Negative(_) => Some(Pat::Str("!")), BoundPolarity::Maybe(_) => Some(Pat::Str("?")), + BoundPolarity::Only(_) => Some(Pat::Str("only")), BoundPolarity::Positive => None, }) .unwrap_or(trait_ref_search_pat.0); diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index 2c75840bc0abf..61773001ab080 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef)) {} //~ ERROR incorrect parentheses around t fn foo2_no_space(_: &dyn(Drop + AsRef)) {} //~ ERROR incorrect parentheses around trait bounds fn foo3(_: &dyn {Drop + AsRef}) {} //~ ERROR expected parameter name, found `{` -//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `[`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{` +//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `[`, `async`, `const`, `for`, `only`, `use`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type fn foo4(_: &dyn >) {} //~ ERROR expected identifier, found `<` diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index a2c9161cfbe11..de03737363ab8 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -39,11 +39,11 @@ error: expected parameter name, found `{` LL | fn foo3(_: &dyn {Drop + AsRef}) {} | ^ expected parameter name -error: expected one of `!`, `(`, `)`, `,`, `?`, `[`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{` +error: expected one of `!`, `(`, `)`, `,`, `?`, `[`, `async`, `const`, `for`, `only`, `use`, `~`, lifetime, or path, found `{` --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef}) {} - | -^ expected one of 13 possible tokens + | -^ expected one of 14 possible tokens | | | help: missing `,` diff --git a/tests/ui/trait-bounds/only-bound.rs b/tests/ui/trait-bounds/only-bound.rs new file mode 100644 index 0000000000000..8d8f3aa5ca5d1 --- /dev/null +++ b/tests/ui/trait-bounds/only-bound.rs @@ -0,0 +1,86 @@ +#![feature(sized_hierarchy)] +use std::marker::{MetaSized, PointeeSized}; +use std::mem::{size_of, size_of_val}; +use std::fmt::Debug; + +fn foo(t: T) { + size_of::(); + size_of_val(&t); +} + +fn bar(t: T) { + //~^ ERROR the size for values of type `T` cannot be known at compilation time + size_of::(); + size_of_val(&t); +} + +fn barfoo(t: T) { + //~^ ERROR the size for values of type `T` cannot be known at compilation time + size_of::(); + size_of_val(&t); + //~^ ERROR the size for values of type `T` cannot be known +} + +trait OnlyPointeeSized: only PointeeSized { + fn foo(&self) { + size_of_val(self); + //~^ ERROR the size for values of type `Self` cannot be known + } +} + +trait NonSizedOnly1: only Debug {} +//~^ ERROR `only` may only be applied to sizedness traits + +trait Trait {} + +trait NonSizedOnly2: only Trait {} +//~^ ERROR `only` may only be applied to sizedness traits + +trait OnlyOnly: only OnlyPointeeSized {} +//~^ ERROR `only` may only be applied to sizedness traits + +trait DoubleOnly: only PointeeSized + only MetaSized {} +// Redundant, but not illegal. + +trait InheritedOnly: OnlyPointeeSized { + fn foo(&self) { + size_of_val(self); + // This works fine, `only` is not transitive, this trait still has the + // `MetaSized` default supertrait. + } +} + + + +fn only(){ + let only = 0u32; +} + +mod a{ + #[allow(non_camel_case_types)] + struct only {} +} + +mod b { + use std::marker::{MetaSized, PointeeSized}; + + #[allow(non_camel_case_types)] + trait only: only PointeeSized { + fn foo(&self) { + size_of_val(self); + //~^ ERROR the size for values of type `Self` cannot be known + } + } +} + +mod only{ + pub trait Alpha {} +} + +// In the below context, rust will attempt to look for `Alpha` in the crate root, not in a module +// `only` +//fn alpha(){ +//} + + +fn main() {} diff --git a/tests/ui/trait-bounds/only-bound.stderr b/tests/ui/trait-bounds/only-bound.stderr new file mode 100644 index 0000000000000..e20ab70b8ee97 --- /dev/null +++ b/tests/ui/trait-bounds/only-bound.stderr @@ -0,0 +1,100 @@ +error: `only` may only be applied to sizedness traits + --> $DIR/only-bound.rs:31:22 + | +LL | trait NonSizedOnly1: only Debug {} + | ^^^^^^^^^^ + +error: `only` may only be applied to sizedness traits + --> $DIR/only-bound.rs:36:22 + | +LL | trait NonSizedOnly2: only Trait {} + | ^^^^^^^^^^ + +error: `only` may only be applied to sizedness traits + --> $DIR/only-bound.rs:39:17 + | +LL | trait OnlyOnly: only OnlyPointeeSized {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/only-bound.rs:11:30 + | +LL | fn bar(t: T) { + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn bar(t: &T) { + | + + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/only-bound.rs:17:36 + | +LL | fn barfoo(t: T) { + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn barfoo(t: &T) { + | + + +error[E0277]: the size for values of type `T` cannot be known + --> $DIR/only-bound.rs:20:17 + | +LL | size_of_val(&t); + | ----------- ^^ doesn't have a known size + | | + | required by a bound introduced by this call + | +note: required by a bound in `std::mem::size_of_val` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL +help: consider further restricting type parameter `T` with unstable trait `MetaSized` + | +LL | fn barfoo(t: T) { + | ++++++++++++++++++++++++ + +error[E0277]: the size for values of type `Self` cannot be known + --> $DIR/only-bound.rs:26:21 + | +LL | size_of_val(self); + | ----------- ^^^^ the trait `MetaSized` is not implemented for `Self` + | | + | required by a bound introduced by this call + | + = note: the trait bound `Self: MetaSized` is not satisfied +note: required by a bound in `std::mem::size_of_val` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL +help: consider borrowing here + | +LL | size_of_val(&self); + | + +LL | size_of_val(&mut self); + | ++++ + +error[E0277]: the size for values of type `Self` cannot be known + --> $DIR/only-bound.rs:70:25 + | +LL | size_of_val(self); + | ----------- ^^^^ the trait `MetaSized` is not implemented for `Self` + | | + | required by a bound introduced by this call + | + = note: the trait bound `Self: MetaSized` is not satisfied +note: required by a bound in `std::mem::size_of_val` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL +help: consider borrowing here + | +LL | size_of_val(&self); + | + +LL | size_of_val(&mut self); + | ++++ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`.