diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index dcce54d66c2d9..2dd059d13e6b9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1465,8 +1465,14 @@ impl<'hir> LoweringContext<'_, 'hir> { continue; } let is_param = *is_param.get_or_insert_with(compute_is_param); - if !is_param { - self.dcx().emit_err(MisplacedRelaxTraitBound { span: bound.span() }); + if !is_param && !self.tcx.features().more_maybe_bounds { + self.tcx + .sess + .create_feature_err( + MisplacedRelaxTraitBound { span: bound.span() }, + sym::more_maybe_bounds, + ) + .emit(); } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c5b5acf7f32d8..cc9bcf7a2ad5e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1238,6 +1238,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx, TraitBoundModifiers::NONE, ); + let bound = (bound, hir::TraitBoundModifier::None); let bounds = this.arena.alloc_from_iter([bound]); let lifetime_bound = this.elided_dyn_bound(t.span); (bounds, lifetime_bound) @@ -1369,21 +1370,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We can safely ignore constness here since AST validation // takes care of rejecting invalid modifier combinations and // const trait bounds in trait object types. - GenericBound::Trait(ty, modifiers) => match modifiers.polarity { - BoundPolarity::Positive | BoundPolarity::Negative(_) => { - Some(this.lower_poly_trait_ref( - ty, - itctx, - // Still, don't pass along the constness here; we don't want to - // synthesize any host effect args, it'd only cause problems. - TraitBoundModifiers { - constness: BoundConstness::Never, - ..*modifiers - }, - )) - } - BoundPolarity::Maybe(_) => None, - }, + GenericBound::Trait(ty, modifiers) => { + // Still, don't pass along the constness here; we don't want to + // synthesize any host effect args, it'd only cause problems. + let modifiers = TraitBoundModifiers { + constness: BoundConstness::Never, + ..*modifiers + }; + let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers); + let polarity = this.lower_trait_bound_modifiers(modifiers); + Some((trait_ref, polarity)) + } GenericBound::Outlives(lifetime) => { if lifetime_bound.is_none() { lifetime_bound = Some(this.lower_lifetime(lifetime)); @@ -2543,6 +2540,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, span: self.lower_span(span), }; + let principal = (principal, hir::TraitBoundModifier::None); // The original ID is taken by the `PolyTraitRef`, // so the `Ty` itself needs a different one. diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 4e3d560ce8983..b25c9ce5bf1ec 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1289,14 +1289,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { if let GenericBound::Trait(poly, modifiers) = bound { match (ctxt, modifiers.constness, modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitSupertrait { - span: poly.span, - path_str: pprust::path_to_string(&poly.trait_ref.path), - }); + (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) + if !self.features.more_maybe_bounds => + { + self.session + .create_feature_err( + errors::OptionalTraitSupertrait { + span: poly.span, + path_str: pprust::path_to_string(&poly.trait_ref.path), + }, + sym::more_maybe_bounds, + ) + .emit(); } - (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span }); + (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) + if !self.features.more_maybe_bounds => + { + self.session + .create_feature_err( + errors::OptionalTraitObject { span: poly.span }, + sym::more_maybe_bounds, + ) + .emit(); } (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => { self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span }); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2647f09c8c96a..8618ea9969f9c 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -207,6 +207,8 @@ declare_features! ( (unstable, lifetime_capture_rules_2024, "1.76.0", None), /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406 (unstable, link_cfg, "1.14.0", None), + /// Allows using `?Trait` trait bounds in more contexts. + (internal, more_maybe_bounds, "CURRENT_RUSTC_VERSION", None), /// Allows the `multiple_supertrait_upcastable` lint. (unstable, multiple_supertrait_upcastable, "1.69.0", None), /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2268905430a7a..1f75fe8060578 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2673,7 +2673,11 @@ pub enum TyKind<'hir> { OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), + TraitObject( + &'hir [(PolyTraitRef<'hir>, TraitBoundModifier)], + &'hir Lifetime, + TraitObjectSyntax, + ), /// Unused for now. Typeof(AnonConst), /// `TyKind::Infer` means the type should be inferred instead of it having been diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index cd9f9ff9109c1..8d464293fc9f1 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -887,7 +887,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul try_visit!(visitor.visit_array_length(length)); } TyKind::TraitObject(bounds, ref lifetime, _syntax) => { - walk_list!(visitor, visit_poly_trait_ref, bounds); + for (bound, _modifier) in bounds { + try_visit!(visitor.visit_poly_trait_ref(bound)); + } try_visit!(visitor.visit_lifetime(lifetime)); } TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 6aee1183a106e..bfed1bbf04040 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -379,6 +379,12 @@ language_item_table! { String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; + + // Experimental lang items for `MCP: Low level components for async drop`(https://github.com/rust-lang/compiler-team/issues/727) + DefaultTrait4, sym::default_trait4, default_trait4_trait, Target::Trait, GenericRequirement::None; + DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None; + DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None; + DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None; } pub enum GenericRequirement { diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index aafb5c1c0b4bc..13f1aae0c14df 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -72,11 +72,27 @@ impl<'tcx> Bounds<'tcx> { )); } - pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { - let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); - let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]); - // Preferable to put this obligation first, since we report better errors for sized ambiguity. - self.clauses.insert(0, (trait_ref.to_predicate(tcx), span)); + pub fn push_lang_item_trait( + &mut self, + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + lang_item: LangItem, + span: Span, + ) { + assert_eq!(lang_item.target(), rustc_hir::Target::Trait); + if lang_item == LangItem::Sized { + let sized_trait = tcx.require_lang_item(lang_item, Some(span)); + let trait_ref = ty::TraitRef::new(tcx, sized_trait, [ty]); + // Preferable to put this obligation first, since we report better errors for sized ambiguity. + self.clauses.insert(0, (trait_ref.to_predicate(tcx), span)); + } else { + // Do not generate default bounds if lang item was not defined + let Some(trait_def_id) = tcx.lang_items().get(lang_item) else { + return; + }; + let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]); + self.clauses.push((trait_ref.to_predicate(tcx), span)); + } } pub fn clauses(&self) -> impl Iterator, Span)> + '_ { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index eb0ffc19d4540..09f6185d7e976 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -321,8 +321,8 @@ fn bounds_from_generic_predicates<'tcx>( ty::ClauseKind::Trait(trait_predicate) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); - if Some(def_id) != tcx.lang_items().sized_trait() { - // Type params are `Sized` by default, do not add that restriction to the list + if !tcx.is_default_trait(def_id) { + // Do not add that restriction to the list // if it is a positive requirement. entry.push(trait_predicate.def_id()); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index c26f982fa473c..d6e4fee7eae62 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -849,7 +849,7 @@ impl<'tcx> TypeVisitor> for GATArgsCollector<'tcx> { fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { match ty.kind { - hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments { + hir::TyKind::TraitObject([(trait_ref, _)], ..) => match trait_ref.trait_ref.path.segments { [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), _ => false, }, diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 02291cc603e13..66057026e3289 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -30,8 +30,8 @@ fn associated_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, assoc_item_def_id); let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter); - // Associated types are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + // Implicit bounds are added to associated types unless a `?Trait` bound is found + icx.lowerer().add_implicit_traits(&mut bounds, item_ty, hir_bounds, None, span); let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); @@ -70,8 +70,8 @@ fn opaque_type_bounds<'tcx>( ty::print::with_reduced_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter); - // Opaque types are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + // Implicit bounds are added to opaque types unless a `?Trait` bound is found + icx.lowerer().add_implicit_traits(&mut bounds, item_ty, hir_bounds, None, span); debug!(?bounds); tcx.arena.alloc_from_iter(bounds.clauses()) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 472657290ed1f..0c64bbc0e150b 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -135,11 +135,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => { - is_trait = Some(self_bounds); + is_trait = Some((self_bounds, item.span)); } _ => {} } }; + if let Node::TraitItem(item) = node { + // Implicitly add `Self: Trait` clauses on trait associated items. + // See `add_implicit_super_traits` doc for more details. + let parent = tcx.local_parent(item.hir_id().owner.def_id); + // FIXME(experimental_default_bounds): default bounds on `Pointee::Metadata` causes a normalization fail + if Some(parent.to_def_id()) != tcx.lang_items().pointee_trait() { + let mut bounds = Bounds::default(); + let self_ty_where_predicates = (parent, item.generics.predicates); + icx.lowerer().add_implicit_traits_with_filter( + &mut bounds, + tcx.types.self_param, + &[], + Some(self_ty_where_predicates), + item.span, + |tr| tr != hir::LangItem::Sized, + ); + predicates.extend(bounds.clauses()); + } + } let generics = tcx.generics_of(def_id); @@ -148,11 +167,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // on a trait we must also consider the bounds that follow the trait's name, // like `trait Foo: A + B + C`. if let Some(self_bounds) = is_trait { - predicates.extend( - icx.lowerer() - .lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All) - .clauses(), + let mut bounds = icx.lowerer().lower_mono_bounds( + tcx.types.self_param, + self_bounds.0, + PredicateFilter::All, ); + icx.lowerer().add_implicit_super_traits( + def_id, + &mut bounds, + self_bounds.0, + hir_generics, + self_bounds.1, + ); + predicates.extend(bounds.clauses()); } // In default impls, we can assume that the self type implements @@ -177,8 +204,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen GenericParamKind::Type { .. } => { let param_ty = icx.lowerer().lower_ty_param(param.hir_id); let mut bounds = Bounds::default(); - // Params are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound( + // Implicit bounds are added to type params unless a `?Trait` bound is found + icx.lowerer().add_implicit_traits( &mut bounds, param_ty, &[], @@ -601,7 +628,14 @@ pub(super) fn implied_predicates_with_filter( let icx = ItemCtxt::new(tcx, trait_def_id); let self_param_ty = tcx.types.self_param; - let superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter); + let mut superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter); + icx.lowerer().add_implicit_super_traits( + trait_def_id, + &mut superbounds, + bounds, + generics, + item.span, + ); let where_bounds_that_match = icx.probe_ty_param_bounds_in_generics( generics, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index a5f038d383d88..ae40ea01da5b3 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -652,7 +652,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { debug!(?bounds, ?lifetime, "TraitObject"); let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { - for bound in bounds { + for (bound, _) in bounds { this.visit_poly_trait_ref_inner( bound, NonLifetimeBinderAllowed::Deny("trait object types"), 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 11bd3e5282dc1..a2a10e642d0d8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_span::symbol::Ident; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::{sym, ErrorGuaranteed, Span, Symbol}; use rustc_trait_selection::traits; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use smallvec::SmallVec; @@ -16,26 +16,178 @@ use crate::bounds::Bounds; use crate::errors; use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; -impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// Add a `Sized` bound to the `bounds` if appropriate. +impl<'tcx, 'a> dyn HirTyLowerer<'tcx> + '_ +where + 'tcx: 'a, +{ + /// Add a `Sized` or default auto traits bounds to the `bounds` if appropriate. /// - /// Doesn't add the bound if the HIR bounds contain any of `Sized`, `?Sized` or `!Sized`. - pub(crate) fn add_sized_bound( + /// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`. + pub(crate) fn add_implicit_traits( &self, bounds: &mut Bounds<'tcx>, self_ty: Ty<'tcx>, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], + hir_bounds: &'a [hir::GenericBound<'a>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, span: Span, ) { + self.add_implicit_traits_with_filter( + bounds, + self_ty, + hir_bounds, + self_ty_where_predicates, + span, + |_| true, + ); + } + + /// Lazily sets `experimental_default_bounds` to true on trait super bounds. + /// For optimization purposes instead of adding default supertraits, bounds + /// are added to the associative items: + /// + /// ```ignore(illustrative) + /// // Default bounds are generated in the following way: + /// trait Trait { + /// fn foo(&self) where Self: Leak {} + /// } + /// + /// // instead of this: + /// trait Trait: Leak { + /// fn foo(&self) {} + /// } + /// ``` + /// It is not always possible to do this because of backward compatibility: + /// + /// ```ignore(illustrative) + /// pub trait Trait {} + /// pub trait Trait1 : Trait {} + /// ``` + /// + /// or: + /// + /// ```ignore(illustrative) + /// trait Trait { + /// type Type where Self: Sized; + /// } + /// trait Trait2 : Trait {} + /// ``` + /// + /// Therefore, `experimental_default_bounds` are still being added to supertraits if + /// the `SelfTyParam` or `TypeBinding` was found in a trait header. + pub(crate) fn add_implicit_super_traits( + &self, + trait_def_id: LocalDefId, + bounds: &mut Bounds<'tcx>, + hir_bounds: &'a [hir::GenericBound<'a>], + hir_generics: &'tcx hir::Generics<'tcx>, + span: Span, + ) { + assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias)); + + struct TraitInfoCollector { + found: bool, + } + + impl<'tcx> hir::intravisit::Visitor<'tcx> for TraitInfoCollector { + fn visit_assoc_type_binding(&mut self, _: &'tcx hir::TypeBinding<'tcx>) { + self.found = true; + } + + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { + if matches!( + &t.kind, + hir::TyKind::Path(hir::QPath::Resolved( + _, + hir::Path { res: hir::def::Res::SelfTyParam { .. }, .. }, + )) + ) { + self.found = true; + return; + } + hir::intravisit::walk_ty(self, t); + } + } + + let mut visitor = TraitInfoCollector { found: false }; + for bound in hir_bounds { + hir::intravisit::walk_param_bound(&mut visitor, bound); + } + hir::intravisit::walk_generics(&mut visitor, hir_generics); + + if visitor.found { + let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); + self.add_implicit_traits_with_filter( + bounds, + self.tcx().types.self_param, + hir_bounds, + Some(self_ty_where_predicates), + span, + |default_trait| { + default_trait != hir::LangItem::Sized + && !self.tcx().is_default_trait(trait_def_id.to_def_id()) + }, + ); + } + } + + pub(crate) fn add_implicit_traits_with_filter( + &self, + bounds: &mut Bounds<'tcx>, + self_ty: Ty<'tcx>, + hir_bounds: &'a [hir::GenericBound<'a>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + span: Span, + f: impl Fn(hir::LangItem) -> bool, + ) { + self.tcx().default_traits().iter().filter(|&&default_trait| f(default_trait)).for_each( + |default_trait| { + self.add_implicit_trait( + *default_trait, + bounds, + self_ty, + hir_bounds, + self_ty_where_predicates, + span, + ); + }, + ); + } + + pub(crate) fn add_implicit_trait( + &self, + trait_: hir::LangItem, + bounds: &mut Bounds<'tcx>, + self_ty: Ty<'tcx>, + hir_bounds: &'a [hir::GenericBound<'a>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + span: Span, + ) { + let tcx = self.tcx(); + let trait_id = tcx.lang_items().get(trait_); + + if self.check_for_implicit_trait(trait_id, hir_bounds, self_ty_where_predicates) { + // There was no `?Trait` or `!Trait` bound; + // add `Trait` if it's available. + bounds.push_lang_item_trait(tcx, self_ty, trait_, span); + } + } + + fn check_for_implicit_trait( + &self, + trait_def_id: Option, + hir_bounds: &'a [hir::GenericBound<'a>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + ) -> bool { + let Some(trait_def_id) = trait_def_id else { + return false; + }; let tcx = self.tcx(); - let sized_def_id = tcx.lang_items().sized_trait(); - let mut seen_negative_sized_bound = false; - let mut seen_positive_sized_bound = false; + let mut seen_negative_bound = false; + let mut seen_positive_bound = false; // Try to find an unbound in bounds. let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); - let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| { + let mut search_bounds = |hir_bounds: &'a [hir::GenericBound<'a>]| { for hir_bound in hir_bounds { let hir::GenericBound::Trait(ptr, modifier) = hir_bound else { continue; @@ -43,17 +195,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match modifier { hir::TraitBoundModifier::Maybe => unbounds.push(ptr), hir::TraitBoundModifier::Negative => { - if let Some(sized_def_id) = sized_def_id - && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_negative_sized_bound = true; + if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) { + seen_negative_bound = true; } } hir::TraitBoundModifier::None => { - if let Some(sized_def_id) = sized_def_id - && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_positive_sized_bound = true; + if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) { + seen_positive_bound = true; } } _ => {} @@ -71,36 +219,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - if unbounds.len() > 1 { - tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { - spans: unbounds.iter().map(|ptr| ptr.span).collect(), - }); + if unbounds.len() > 1 && !tcx.features().more_maybe_bounds { + self.tcx() + .sess + .create_feature_err( + errors::MultipleRelaxedDefaultBounds { + spans: unbounds.iter().map(|ptr| ptr.span).collect(), + }, + sym::more_maybe_bounds, + ) + .emit(); } - let mut seen_sized_unbound = false; + let mut seen_unbound = false; for unbound in unbounds { - if let Some(sized_def_id) = sized_def_id - && unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_sized_unbound = true; - continue; + let unbound_def_id = unbound.trait_ref.trait_def_id(); + if unbound_def_id == Some(trait_def_id) { + seen_unbound = true; } - // There was a `?Trait` bound, but it was not `?Sized`; warn. - tcx.dcx().span_warn( - unbound.span, - "relaxing a default bound only does something for `?Sized`; \ - all other traits are not bound by default", - ); - } - if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound { - // There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound; - // we don't need to do anything. - } else if sized_def_id.is_some() { - // There was no `?Sized`, `!Sized` or explicit `Sized` bound; - // add `Sized` if it's available. - bounds.push_sized(tcx, self_ty, span); + let emit_relax_warn = || { + let unbound_traits = + match self.tcx().sess.opts.unstable_opts.experimental_default_bounds { + true => "`?Sized` and `experimental_default_bounds`", + false => "`?Sized`", + }; + tcx.dcx().span_warn( + unbound.span, + format!( + "relaxing a default bound only does something for {}; \ + all other traits are not bound by default", + unbound_traits + ), + ); + }; + + match unbound_def_id { + Some(def_id) if !tcx.is_default_trait(def_id) => emit_relax_warn(), + None => emit_relax_warn(), + _ => {} + } } + + !(seen_unbound || seen_negative_bound || seen_positive_bound) } /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 8e64a9425bb9f..a52f117978faa 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -709,7 +709,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, associated_types: FxIndexMap>, potential_assoc_types: Vec, - trait_bounds: &[hir::PolyTraitRef<'_>], + trait_bounds: &[(hir::PolyTraitRef<'_>, hir::TraitBoundModifier)], ) { if associated_types.values().all(|v| v.is_empty()) { return; @@ -751,7 +751,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if object_safety_violations { return; } - if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { + if let ([], [(bound, _)]) = (&potential_assoc_types[..], &trait_bounds) { match bound.trait_ref.path.segments { // FIXME: `trait_ref.path.span` can point to a full path with multiple // segments, even though `trait_ref.path.segments` is of length `1`. Work @@ -793,7 +793,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // and we can then use their span to indicate this to the user. let bound_names = trait_bounds .iter() - .filter_map(|poly_trait_ref| { + .filter_map(|(poly_trait_ref, _)| { let path = poly_trait_ref.trait_ref.path.segments.last()?; let args = path.args?; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index d9d36f5299b58..09f2a828d3c0d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -34,7 +34,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .ok() .is_some_and(|s| s.trim_end().ends_with('<')); - let is_global = poly_trait_ref.trait_ref.path.is_global(); + let is_global = poly_trait_ref.0.trait_ref.path.is_global(); let mut sugg = vec![( self_ty.span.shrink_to_lo(), @@ -176,7 +176,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut is_downgradable = true; let is_object_safe = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { - objects.iter().all(|o| match o.trait_ref.path.res { + objects.iter().all(|(o, _)| match o.trait_ref.path.res { Res::Def(DefKind::Trait, id) => { if Some(id) == owner { // For recursive traits, don't downgrade the error. (#119652) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 97ba946b7e013..6b8c41aa21ae0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -24,7 +24,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, hir_id: hir::HirId, - hir_trait_bounds: &[hir::PolyTraitRef<'tcx>], + hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)], lifetime: &hir::Lifetime, borrowed: bool, representation: DynKind, @@ -34,7 +34,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut bounds = Bounds::default(); let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in hir_trait_bounds.iter().rev() { + for (trait_bound, modifier) in hir_trait_bounds.iter().rev() { + if *modifier == hir::TraitBoundModifier::Maybe { + continue; + } if let GenericArgCountResult { correct: Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), @@ -54,6 +57,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + let ast_bounds: Vec<_> = hir_trait_bounds + .iter() + .map(|&(trait_ref, polarity)| hir::GenericBound::Trait(trait_ref, polarity)) + .collect(); + + self.add_implicit_traits_with_filter( + &mut bounds, + dummy_self, + &ast_bounds, + None, + span, + |tr| tr != hir::LangItem::Sized, + ); + let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; for (pred, span) in bounds.clauses() { @@ -245,7 +262,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args = tcx.mk_args(&args); let span = i.bottom().1; - let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { + let empty_generic_args = hir_trait_bounds.iter().any(|(hir_bound, _)| { hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) && hir_bound.span.contains(span) }); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 285b99c2c69d5..2381da857138e 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -292,13 +292,16 @@ impl<'a> State<'a> { self.word_space("dyn"); } let mut first = true; - for bound in bounds { + for (bound, modifier) in bounds { if first { first = false; } else { self.nbsp(); self.word_space("+"); } + if *modifier == TraitBoundModifier::Maybe { + self.word("?"); + } self.print_poly_trait_ref(bound); } if !lifetime.is_elided() { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index 265a315a55979..c3dba8787e33a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -82,7 +82,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { } hir::TyKind::TraitObject(bounds, ..) => { - for bound in bounds { + for (bound, _) in bounds { self.current_index.shift_in(1); self.visit_poly_trait_ref(bound); self.current_index.shift_out(1); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 0bbabefaf9540..b6de20d8c4b14 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -607,7 +607,7 @@ impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { _, ) = t.kind { - for ptr in poly_trait_refs { + for (ptr, _) in poly_trait_refs { if Some(self.1) == ptr.trait_ref.trait_def_id() { self.0.push(ptr.span); } diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 890e25368bc75..4481f4d4036da 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -62,7 +62,7 @@ pub fn report_object_safety_error<'tcx>( if let Some(hir_id) = hir_id && let hir::Node::Ty(ty) = tcx.hir_node(hir_id) - && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind + && let hir::TyKind::TraitObject([(trait_ref, _), ..], ..) = ty.kind { let mut hir_id = hir_id; while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) { diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 69d623b547b58..70d45d8e5b426 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -47,7 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { .super_predicates_of(def_id) .predicates .into_iter() - .filter_map(|(pred, _)| pred.as_trait_clause()); + .filter_map(|(pred, _)| pred.as_trait_clause()) + .filter(|pred| !cx.tcx.is_default_trait(pred.def_id())); if direct_super_traits_iter.count() > 1 { cx.emit_span_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 004c2c2e4f44f..feca67d1f98fb 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { TyKind::Path(QPath::Resolved(_, ty_path)) => { path_has_local_parent(ty_path, cx, parent, parent_parent) } - TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => { + TyKind::TraitObject([(principle_poly_trait_ref, _), ..], _, _) => { path_has_local_parent( principle_poly_trait_ref.trait_ref.path, cx, diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 789f154eac5bc..44b449a59bf56 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -112,9 +112,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; - for bound in &bounds[..] { + for (bound, modifier) in &bounds[..] { let def_id = bound.trait_ref.trait_def_id(); - if cx.tcx.lang_items().drop_trait() == def_id { + if cx.tcx.lang_items().drop_trait() == def_id + && *modifier != hir::TraitBoundModifier::Maybe + { let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 45fa5e8f7ca38..0955ef37ddffd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -993,6 +993,25 @@ impl<'tcx> TyCtxt<'tcx> { self.type_of(ordering_enum).no_bound_vars().unwrap() } + pub fn default_traits(self) -> &'static [rustc_hir::LangItem] { + match self.sess.opts.unstable_opts.experimental_default_bounds { + true => &[ + LangItem::Sized, + LangItem::DefaultTrait1, + LangItem::DefaultTrait2, + LangItem::DefaultTrait3, + LangItem::DefaultTrait4, + ], + false => &[LangItem::Sized], + } + } + + pub fn is_default_trait(self, def_id: DefId) -> bool { + self.default_traits() + .iter() + .any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id)) + } + /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. pub fn get_diagnostic_item(self, name: Symbol) -> Option { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index e5450182bf299..3652b60d82e14 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -986,25 +986,32 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); - let mut has_sized_bound = false; - let mut has_negative_sized_bound = false; + let mut default_trait_bounds = FxHashSet::default(); + let mut default_negative_trait_bounds = FxHashSet::default(); let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); - for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { + 'pred: for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { ty::ClauseKind::Trait(pred) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); - // Don't print `+ Sized`, but rather `+ ?Sized` if absent. - if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { - match pred.polarity { - ty::PredicatePolarity::Positive => { - has_sized_bound = true; - continue; + // Don't print implicit bounds. + for default_trait in tcx.default_traits() { + let lang_item_id = tcx.lang_items().get(*default_trait); + if let Some(default_trait_id) = lang_item_id + && trait_ref.def_id() == default_trait_id + { + match pred.polarity { + ty::PredicatePolarity::Positive => { + default_trait_bounds.insert(*default_trait); + continue 'pred; + } + ty::PredicatePolarity::Negative => { + default_negative_trait_bounds.insert(*default_trait); + } } - ty::PredicatePolarity::Negative => has_negative_sized_bound = true, } } @@ -1042,7 +1049,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut first = true; // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait - let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; + let paren_needed = + fn_traits.len() > 1 || traits.len() > 0 || default_trait_bounds.is_empty(); for (fn_once_trait_ref, entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; @@ -1188,16 +1196,30 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { })?; } - let add_sized = has_sized_bound && (first || has_negative_sized_bound); - let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound; - if add_sized || add_maybe_sized { - if !first { - write!(self, " + ")?; + for default_trait in tcx.default_traits() { + if tcx.lang_items().get(*default_trait).is_none() { + // default bounds weren't generated + continue; } - if add_maybe_sized { - write!(self, "?")?; + + let has_default_bound = default_trait_bounds.contains(default_trait); + let has_negative_default_bound = default_negative_trait_bounds.contains(default_trait); + + let add_bound = has_default_bound && (first || has_negative_default_bound); + let add_maybe_bound = !has_default_bound && !has_negative_default_bound; + + if add_bound || add_maybe_bound { + if !first { + write!(self, " + ")?; + } else { + first = false; + } + + if add_maybe_bound { + write!(self, "?")?; + } + write!(self, "{}", default_trait.variant_name())?; } - write!(self, "Sized")?; } if !with_forced_trimmed_paths() { @@ -1412,6 +1434,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { auto_traits.sort_by_cached_key(|did| with_no_trimmed_paths!(self.tcx().def_path_str(*did))); for def_id in auto_traits { + if self.tcx().is_default_trait(def_id) + && self.tcx().lang_items().sized_trait() != Some(def_id) + { + continue; + } if !first { p!(" + "); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0184ff5497952..e28e75a51abf9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1371,6 +1371,12 @@ impl<'tcx> ParamTy { ParamTy { index, name } } + // Dummy param which is used for proving object safety. + // See `receiver_is_dispatchable`. + pub fn dummy() -> Self { + ParamTy::new(u32::MAX, Symbol::intern("RustaceansAreAwesome")) + } + pub fn for_def(def: &ty::GenericParamDef) -> ParamTy { ParamTy::new(def.index, def.name) } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6a556e2a1f517..005a46738d89a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1672,6 +1672,8 @@ options! { "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], "emit the bc module with thin LTO info (default: yes)"), + experimental_default_bounds: bool = (false, parse_bool, [TRACKED], + "enable default bounds for experimental group of auto traits"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), external_clangrt: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 99591b5e1440b..6c43550ce0bd5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -682,6 +682,15 @@ symbols! { default_fn, default_lib_allocator, default_method_body_is_const, + // -------------------------- + // Lang items which are used only for experiments with auto traits with default bounds. + // These lang items are not actually defined in core/std. Experiment is a part of + // `MCP: Low level components for async drop`(https://github.com/rust-lang/compiler-team/issues/727) + default_trait1, + default_trait2, + default_trait3, + default_trait4, + // -------------------------- default_type_parameter_fallback, default_type_params, delayed_bug_from_inside_query, @@ -1196,6 +1205,7 @@ symbols! { modifiers, module, module_path, + more_maybe_bounds, more_qualified_paths, more_struct_aliases, movbe_target_feature, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index a778414d9d1bc..0f81f3920d0af 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -29,6 +29,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Float(_) | ty::FnDef(..) | ty::FnPtr(_) + | ty::Foreign(..) | ty::Error(_) | ty::Never | ty::Char => Ok(vec![]), @@ -38,7 +39,6 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::Dynamic(..) | ty::Param(..) - | ty::Foreign(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Placeholder(..) | ty::Bound(..) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index ed76ea74f08f9..0ea02e70bd14b 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1011,6 +1011,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, ) -> Option> { let self_ty = goal.predicate.self_ty(); + + let check_impls = || { + let mut disqualifying_impl = None; + self.tcx().for_each_relevant_impl_treating_projections( + goal.predicate.def_id(), + goal.predicate.self_ty(), + TreatProjections::NextSolverLookup, + |impl_def_id| { + disqualifying_impl = Some(impl_def_id); + }, + ); + if let Some(def_id) = disqualifying_impl { + debug!(?def_id, ?goal, "disqualified auto-trait implementation"); + // No need to actually consider the candidate here, + // since we do that in `consider_impl_candidate`. + Some(Err(NoSolution)) + } else { + None + } + }; match *self_ty.kind() { // Stall int and float vars until they are resolved to a concrete // numerical type. That's because the check for impls below treats @@ -1021,6 +1041,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)) } + // Backward compatibility for default auto traits. + // Test: ui/traits/default_auto_traits/extern-types.rs + ty::Foreign(..) if self.tcx().is_default_trait(goal.predicate.def_id()) => { + check_impls() + }, + // These types cannot be structurally decomposed into constituent // types, and therefore have no built-in auto impl. ty::Dynamic(..) @@ -1075,25 +1101,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Adt(_, _) // FIXME: Handling opaques here is kinda sus. Especially because we // simplify them to SimplifiedType::Placeholder. - | ty::Alias(ty::Opaque, _) => { - let mut disqualifying_impl = None; - self.tcx().for_each_relevant_impl_treating_projections( - goal.predicate.def_id(), - goal.predicate.self_ty(), - TreatProjections::NextSolverLookup, - |impl_def_id| { - disqualifying_impl = Some(impl_def_id); - }, - ); - if let Some(def_id) = disqualifying_impl { - debug!(?def_id, ?goal, "disqualified auto-trait implementation"); - // No need to actually consider the candidate here, - // since we do that in `consider_impl_candidate`. - return Some(Err(NoSolution)); - } else { - None - } - } + | ty::Alias(ty::Opaque, _) => check_impls(), ty::Error(_) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index cc879c42ce95b..520305350780d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3025,11 +3025,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match ty.kind { hir::TyKind::TraitObject(traits, _, _) => { let (span, kw) = match traits { - [first, ..] if first.span.lo() == ty.span.lo() => { + [(first, _), ..] if first.span.lo() == ty.span.lo() => { // Missing `dyn` in front of trait object. (ty.span.shrink_to_lo(), "dyn ") } - [first, ..] => (ty.span.until(first.span), ""), + [(first, _), ..] => (ty.span.until(first.span), ""), [] => span_bug!(ty.span, "trait object with no traits: {ty:?}"), }; let needs_parens = traits.len() != 1; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 1971136e54c72..9cb636a9d386e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -115,7 +115,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // with more relevant type information and hide redundant E0282 errors. errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) - if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() => + if self.tcx.is_default_trait(pred.def_id()) => { 1 } @@ -2344,7 +2344,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + if self.tcx.is_default_trait(trait_ref.def_id()) { match self.tainted_by_errors() { None => { let err = self.emit_inference_failure_err( diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5e1343b50ce7f..e9ee4c1ea791e 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -23,7 +23,6 @@ use rustc_middle::ty::{ use rustc_middle::ty::{GenericArg, GenericArgs}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; -use rustc_span::symbol::Symbol; use rustc_span::Span; use smallvec::SmallVec; @@ -737,8 +736,7 @@ fn receiver_is_dispatchable<'tcx>( // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now. // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can // replace this with `dyn Trait` - let unsized_self_ty: Ty<'tcx> = - Ty::new_param(tcx, u32::MAX, Symbol::intern("RustaceansAreAwesome")); + let unsized_self_ty: Ty<'tcx> = Ty::new(tcx, ty::Param(ty::ParamTy::dummy())); // `Receiver[Self => U]` let unsized_receiver_ty = diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 40d206b92b8df..5d208f4136b50 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -726,6 +726,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let def_id = obligation.predicate.def_id(); + let mut check_impls = || { + // Only consider auto impls if there are no manual impls for the root of `self_ty`. + // + // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl + // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls + // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined. + // + // Generally, we have to guarantee that for all `SimplifiedType`s the only crate + // which may define impls for that type is either the crate defining the type + // or the trait. This should be guaranteed by the orphan check. + let mut has_impl = false; + self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true); + if !has_impl { + candidates.vec.push(AutoImplCandidate) + } + }; if self.tcx().trait_is_auto(def_id) { match *self_ty.kind() { ty::Dynamic(..) => { @@ -739,6 +755,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // we don't add any `..` impl. Default traits could // still be provided by a manual implementation for // this trait and type. + + // Backward compatibility for default auto traits. + // Test: ui/traits/default_auto_traits/extern-types.rs + if self.tcx().is_default_trait(def_id) { + check_impls() + } + } + // Used for proving `DispatchFromDyn` for default auto traits. + // See `receiver_is_dispatchable`. + ty::Param(param) if param == ty::ParamTy::dummy() => { + candidates.vec.push(AutoImplCandidate) } ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) @@ -824,22 +851,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Coroutine(..) | ty::Never | ty::Tuple(_) - | ty::CoroutineWitness(..) => { - // Only consider auto impls if there are no manual impls for the root of `self_ty`. - // - // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl - // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls - // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined. - // - // Generally, we have to guarantee that for all `SimplifiedType`s the only crate - // which may define impls for that type is either the crate defining the type - // or the trait. This should be guaranteed by the orphan check. - let mut has_impl = false; - self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true); - if !has_impl { - candidates.vec.push(AutoImplCandidate) - } - } + | ty::CoroutineWitness(..) => check_impls(), ty::Error(_) => {} // do not add an auto trait impl for `ty::Error` for now. } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index fc12fed353738..4badb556eaf33 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2334,15 +2334,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never + | ty::Foreign(..) | ty::Char => ty::Binder::dummy(Vec::new()), + // Used for proving `DispatchFromDyn` for default auto traits. + // See `receiver_is_dispatchable`. + ty::Param(param) if param == ty::ParamTy::dummy() => ty::Binder::dummy(Vec::new()), + // Treat this like `struct str([u8]);` ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]), ty::Placeholder(..) | ty::Dynamic(..) | ty::Param(..) - | ty::Foreign(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 46a0a4eb5ef8f..dfe9931e17ee2 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -536,11 +536,17 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti for (p, _) in predicates { if let Some(poly_trait_ref) = p.as_trait_clause() { - if Some(poly_trait_ref.def_id()) == sized_trait { + let poly_trait_id = poly_trait_ref.def_id(); + if Some(poly_trait_id) == sized_trait { // FIXME(#120456) - is `swap_remove` correct? types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder()); continue; } + if tcx.is_default_trait(poly_trait_id) { + // Do not emit other default traits because there are no yet + // relaxed bounds for them. + continue; + } } pretty_predicates.push(p.to_string()); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fc4f48262e5dc..71bf41250aa94 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1833,7 +1833,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T } TyKind::Path(_) => clean_qpath(ty, cx), TyKind::TraitObject(bounds, ref lifetime, _) => { - let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect(); + let bounds = bounds.iter().map(|(bound, _)| clean_poly_trait_ref(bound, cx)).collect(); let lifetime = if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None }; DynTrait(bounds, lifetime) diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 443d6189c1f77..f83101cee11c0 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -545,7 +545,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { if !lt.is_elided() { self.unelided_trait_object_lifetime = true; } - for bound in bounds { + for (bound, _) in bounds { self.visit_poly_trait_ref(bound); } }, diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 9468d367a9261..319ca815332ae 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { // Iterate the bounds and add them to our seen hash // If we haven't yet seen it, add it to the fixed traits - for bound in bounds { + for (bound, _) in bounds { let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; }; @@ -196,9 +196,9 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { // If the number of unique traits isn't the same as the number of traits in the bounds, // there must be 1 or more duplicates if bounds.len() != unique_traits.len() { - let mut bounds_span = bounds[0].span; + let mut bounds_span = bounds[0].0.span; - for bound in bounds.iter().skip(1) { + for (bound, _) in bounds.iter().skip(1) { bounds_span = bounds_span.to(bound.span); } diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index 801e886261993..83cc9f2d8df23 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs @@ -81,14 +81,17 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m // Returns true if given type is `Any` trait. fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool { - if let TyKind::TraitObject(traits, ..) = t.kind - && !traits.is_empty() - && let Some(trait_did) = traits[0].trait_ref.trait_def_id() - // Only Send/Sync can be used as additional traits, so it is enough to - // check only the first trait. - && cx.tcx.is_diagnostic_item(sym::Any, trait_did) - { - return true; + if let TyKind::TraitObject(traits, ..) = t.kind { + return traits + .iter() + .any(|(bound, _)| { + if let Some(trait_did) = bound.trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::Any, trait_did) + { + return true; + } + false + }); } false diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs index 0aa50c99c1690..5a762e0007f77 100644 --- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs @@ -55,6 +55,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { TyKind::TraitObject(param_bounds, _, _) => { let has_lifetime_parameters = param_bounds.iter().any(|bound| { bound + .0 .bound_generic_params .iter() .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. })) diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs new file mode 100644 index 0000000000000..8d3b692f132b5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Zexperimental-default-bounds + +#![feature(auto_traits)] + +trait Trait1 {} +auto trait Trait2 {} +trait Trait3: ?Trait1 {} +//~^ ERROR `?Trait` is not permitted in supertraits +trait Trait4 where Self: ?Trait1 {} +//~^ ERROR ?Trait` bounds are only permitted at the point where a type parameter is declared + +fn foo(_: Box) {} +//~^ ERROR `?Trait` is not permitted in trait object types +fn bar(_: T) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| WARN relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default +//~| WARN relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr new file mode 100644 index 0000000000000..457b7bed47211 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -0,0 +1,53 @@ +error[E0658]: `?Trait` is not permitted in supertraits + --> $DIR/feature-gate-more-maybe-bounds.rs:7:15 + | +LL | trait Trait3: ?Trait1 {} + | ^^^^^^^ + | + = note: traits are `?Trait1` by default + = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types + --> $DIR/feature-gate-more-maybe-bounds.rs:12:28 + | +LL | fn foo(_: Box) {} + | ^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` bounds are only permitted at the point where a type parameter is declared + --> $DIR/feature-gate-more-maybe-bounds.rs:9:26 + | +LL | trait Trait4 where Self: ?Trait1 {} + | ^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/feature-gate-more-maybe-bounds.rs:14:11 + | +LL | fn bar(_: T) {} + | ^^^^^^^ ^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +warning: relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default + --> $DIR/feature-gate-more-maybe-bounds.rs:14:11 + | +LL | fn bar(_: T) {} + | ^^^^^^^ + +warning: relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default + --> $DIR/feature-gate-more-maybe-bounds.rs:14:21 + | +LL | fn bar(_: T) {} + | ^^^^^^^ + +error: aborting due to 4 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0203, E0658. +For more information about an error, try `rustc --explain E0203`. diff --git a/tests/ui/maybe-bounds.stderr b/tests/ui/maybe-bounds.stderr index 1d823b6acb283..230d11fd0ae66 100644 --- a/tests/ui/maybe-bounds.stderr +++ b/tests/ui/maybe-bounds.stderr @@ -1,22 +1,31 @@ -error: `?Trait` is not permitted in supertraits +error[E0658]: `?Trait` is not permitted in supertraits --> $DIR/maybe-bounds.rs:1:11 | LL | trait Tr: ?Sized {} | ^^^^^^ | = note: traits are `?Sized` by default + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bounds.rs:4:20 | LL | type A1 = dyn Tr + (?Sized); | ^^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bounds.rs:6:28 | LL | type A2 = dyn for<'a> Tr + (?Sized); | ^^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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 3 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr index 3134746b930ac..ff32b173d4941 100644 --- a/tests/ui/parser/trait-object-trait-parens.stderr +++ b/tests/ui/parser/trait-object-trait-parens.stderr @@ -1,20 +1,29 @@ -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:8:24 | LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; | ^^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:13:16 | LL | let _: Box Trait<'a>) + (Obj)>; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:18:44 | LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; | ^^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: trait objects without an explicit `dyn` are deprecated --> $DIR/trait-object-trait-parens.rs:8:16 @@ -91,4 +100,5 @@ LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; error: aborting due to 6 previous errors; 3 warnings emitted -For more information about this error, try `rustc --explain E0225`. +Some errors have detailed explanations: E0225, E0658. +For more information about an error, try `rustc --explain E0225`. diff --git a/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs new file mode 100644 index 0000000000000..5a8f6cdeba45a --- /dev/null +++ b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs @@ -0,0 +1,26 @@ +//@ check-pass +//@ compile-flags: -Zexperimental-default-bounds + +#![feature(auto_traits, lang_items, no_core, start, rustc_attrs, trait_alias)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "default_trait1"] +auto trait DefaultTrait1 {} + +#[lang = "default_trait2"] +auto trait DefaultTrait2 {} + +trait Trait {} +trait Trait1 : Trait {} + +trait Trait2 { + type Type; +} +trait Trait3 = Trait2; + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/tests/ui/traits/default_auto_traits/default-bounds.rs b/tests/ui/traits/default_auto_traits/default-bounds.rs new file mode 100644 index 0000000000000..21dddca7c69d7 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/default-bounds.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Zexperimental-default-bounds + +#![feature( + auto_traits, + lang_items, + negative_impls, + no_core, + start, + rustc_attrs +)] +#![allow(incomplete_features)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +pub trait Copy {} + +#[lang = "default_trait1"] +auto trait Leak {} + +#[lang = "default_trait2"] +auto trait SyncDrop {} + +struct Forbidden; + +impl !Leak for Forbidden {} +impl !SyncDrop for Forbidden {} + +struct Accepted; + +fn bar(_: T) {} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + // checking that bounds can be added explicitly + bar(Forbidden); + //~^ ERROR the trait bound `Forbidden: Leak` is not satisfied + //~| ERROR the trait bound `Forbidden: SyncDrop` is not satisfied + bar(Accepted); + 0 +} diff --git a/tests/ui/traits/default_auto_traits/default-bounds.stderr b/tests/ui/traits/default_auto_traits/default-bounds.stderr new file mode 100644 index 0000000000000..64a35ac69c89c --- /dev/null +++ b/tests/ui/traits/default_auto_traits/default-bounds.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `Forbidden: SyncDrop` is not satisfied + --> $DIR/default-bounds.rs:39:9 + | +LL | bar(Forbidden); + | --- ^^^^^^^^^ the trait `SyncDrop` is not implemented for `Forbidden` + | | + | required by a bound introduced by this call + | +note: required by a bound in `bar` + --> $DIR/default-bounds.rs:34:8 + | +LL | fn bar(_: T) {} + | ^ required by this bound in `bar` + +error[E0277]: the trait bound `Forbidden: Leak` is not satisfied + --> $DIR/default-bounds.rs:39:9 + | +LL | bar(Forbidden); + | --- ^^^^^^^^^ the trait `Leak` is not implemented for `Forbidden` + | | + | required by a bound introduced by this call + | +note: required by a bound in `bar` + --> $DIR/default-bounds.rs:34:11 + | +LL | fn bar(_: T) {} + | ^^^^ required by this bound in `bar` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default_auto_traits/extern-types.current.stderr b/tests/ui/traits/default_auto_traits/extern-types.current.stderr new file mode 100644 index 0000000000000..e1bd99b900f56 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/extern-types.current.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied + --> $DIR/extern-types.rs:44:13 + | +LL | foo(x); + | --- ^ the trait `Leak` is not implemented for `extern_non_leak::Opaque` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/extern-types.rs:20:8 + | +LL | fn foo(_: &T) {} + | ^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default_auto_traits/extern-types.next.stderr b/tests/ui/traits/default_auto_traits/extern-types.next.stderr new file mode 100644 index 0000000000000..e1bd99b900f56 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/extern-types.next.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied + --> $DIR/extern-types.rs:44:13 + | +LL | foo(x); + | --- ^ the trait `Leak` is not implemented for `extern_non_leak::Opaque` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/extern-types.rs:20:8 + | +LL | fn foo(_: &T) {} + | ^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default_auto_traits/extern-types.rs b/tests/ui/traits/default_auto_traits/extern-types.rs new file mode 100644 index 0000000000000..06f79af2b5634 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/extern-types.rs @@ -0,0 +1,52 @@ +//@ compile-flags: -Zexperimental-default-bounds +//@ revisions: current next +//@ [next] compile-flags: -Znext-solver + +#![feature(auto_traits, extern_types, lang_items, negative_impls, no_core, start, rustc_attrs)] +#![allow(incomplete_features)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +pub trait Copy {} + +#[lang = "default_trait1"] +auto trait Leak {} + +// implicit T: Leak here +fn foo(_: &T) {} + +mod extern_leak { + use crate::*; + + extern "C" { + type Opaque; + } + + fn forward_extern_ty(x: &Opaque) { + // ok, extern type leak by default + crate::foo(x); + } +} + +mod extern_non_leak { + use crate::*; + + extern "C" { + type Opaque; + } + + impl !Leak for Opaque {} + fn forward_extern_ty(x: &Opaque) { + foo(x); + //~^ ERROR: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied + } +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs new file mode 100644 index 0000000000000..9d28df8d53a83 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs @@ -0,0 +1,78 @@ +//@ compile-flags: -Zexperimental-default-bounds + +#![feature( + auto_traits, + lang_items, + more_maybe_bounds, + negative_impls, + no_core, start, + trait_upcasting, + rustc_attrs +)] +#![allow(internal_features)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +pub unsafe trait Copy {} +unsafe impl<'a, T: ?Sized> Copy for &'a T {} + +#[lang = "receiver"] +trait Receiver {} +impl Receiver for &T {} + +#[lang = "unsize"] +trait Unsize {} + +#[lang = "coerce_unsized"] +trait CoerceUnsized {} +impl<'a, 'b: 'a, T: ?Sized + ?Leak + Unsize, U: ?Sized + ?Leak> CoerceUnsized<&'a U> for &'b T {} + +#[lang = "dispatch_from_dyn"] +trait DispatchFromDyn {} +impl<'a, T: ?Sized + ?Leak + Unsize, U: ?Sized + ?Leak> DispatchFromDyn<&'a U> for &'a T {} + +#[lang = "default_trait1"] +auto trait Leak {} + +#[lang = "default_trait2"] +auto trait SyncDrop {} + +struct NonLeakS; +impl !Leak for NonLeakS {} +struct LeakS; + +trait Trait { + fn leak_foo(&self) {} + fn maybe_leak_foo(&self) where Self: ?Leak {} +} + +impl Trait for NonLeakS {} +impl Trait for LeakS {} + +// add implicit supertraits +trait Trait2 {} +impl Trait2 for LeakS {} + +fn test_trait_object() { + let _: &dyn Trait = &NonLeakS; + //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied + let _: &dyn Trait = &LeakS; + let _: &(dyn Trait + ?Leak) = &LeakS; + let x: &(dyn Trait + ?Leak) = &NonLeakS; + x.leak_foo(); + //~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied + x.maybe_leak_foo(); +} + +fn test_traits_upcasting() { + let _: &dyn Trait2<()> = &LeakS; + let _: &dyn Leak = &LeakS; + let _: &dyn SyncDrop = &LeakS; +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr new file mode 100644 index 0000000000000..6c31299d80fd7 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied + --> $DIR/maybe-bounds-in-dyn-traits.rs:61:25 + | +LL | let _: &dyn Trait = &NonLeakS; + | ^^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS` + | + = note: required for the cast from `&NonLeakS` to `&dyn Trait` + +error[E0277]: the trait bound `dyn Trait: Leak` is not satisfied + --> $DIR/maybe-bounds-in-dyn-traits.rs:66:7 + | +LL | x.leak_foo(); + | ^^^^^^^^ the trait `Leak` is not implemented for `dyn Trait` + | +note: required by a bound in `Trait::leak_foo` + --> $DIR/maybe-bounds-in-dyn-traits.rs:49:5 + | +LL | fn leak_foo(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs new file mode 100644 index 0000000000000..0951060ce27ef --- /dev/null +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs @@ -0,0 +1,117 @@ +//@ compile-flags: -Zexperimental-default-bounds + +#![feature( + auto_traits, + associated_type_defaults, + generic_const_items, + lang_items, + more_maybe_bounds, + negative_impls, + no_core, + start, + rustc_attrs +)] +#![allow(incomplete_features)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "receiver"] +trait Receiver {} +impl Receiver for &T {} +impl Receiver for &mut T {} + +#[lang = "default_trait1"] +auto trait Leak {} + +struct NonLeakS; +impl !Leak for NonLeakS {} +struct LeakS; + +mod supertraits { + use crate::*; + + trait MaybeLeakT1: ?Leak {} + trait MaybeLeakT2 where Self: ?Leak {} + + impl MaybeLeakT1 for NonLeakS {} + impl MaybeLeakT2 for NonLeakS {} +} + +mod maybe_self_assoc_type { + use crate::*; + + trait TestBase1 {} + trait TestBase2 {} + + trait Test1 { + type MaybeLeakSelf: TestBase1 where Self: ?Leak; + //~^ ERROR the trait bound `Self: Leak` is not satisfied + type LeakSelf: TestBase1; + } + + trait Test2 { + type MaybeLeakSelf: TestBase2 where Self: ?Leak; + type LeakSelf: TestBase2; + } + + trait Test3 { + type Leak1 = LeakS; + type Leak2 = NonLeakS; + //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied + } + + trait Test4 { + type MaybeLeak1: ?Leak = LeakS; + type MaybeLeak2: ?Leak = NonLeakS; + } + + trait Test5: ?Leak { + // ok, because assoc types has implicit where Self: Leak + type MaybeLeakSelf1: TestBase1; + type MaybeLeakSelf2: TestBase2; + } +} + +mod maybe_self_assoc_const { + use crate::*; + + const fn size_of() -> usize { + 0 + } + + trait Trait { + const CLeak: usize = size_of::(); + const CNonLeak: usize = size_of::() where Self: ?Leak; + //~^ ERROR the trait bound `Self: Leak` is not satisfied + } +} + +mod methods { + use crate::*; + + trait Trait { + fn leak_foo(&self) {} + fn maybe_leak_foo(&self) where Self: ?Leak {} + fn mut_leak_foo(&mut self) {} + // there is no relax bound on corresponding Receiver impl + fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {} + //~^ `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` + } + + impl Trait for NonLeakS {} + impl Trait for LeakS {} + + fn foo() { + LeakS.leak_foo(); + LeakS.maybe_leak_foo(); + NonLeakS.leak_foo(); + //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied + NonLeakS.maybe_leak_foo(); + } +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr new file mode 100644 index 0000000000000..f66450203a3d8 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr @@ -0,0 +1,71 @@ +error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied + --> $DIR/maybe-bounds-in-traits.rs:62:22 + | +LL | type Leak2 = NonLeakS; + | ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS` + | +note: required by a bound in `Test3::Leak2` + --> $DIR/maybe-bounds-in-traits.rs:62:9 + | +LL | type Leak2 = NonLeakS; + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Test3::Leak2` + +error[E0277]: the trait bound `Self: Leak` is not satisfied + --> $DIR/maybe-bounds-in-traits.rs:50:29 + | +LL | type MaybeLeakSelf: TestBase1 where Self: ?Leak; + | ^^^^^^^^^^^^^^^ the trait `Leak` is not implemented for `Self` + | +note: required by a bound in `TestBase1` + --> $DIR/maybe-bounds-in-traits.rs:46:21 + | +LL | trait TestBase1 {} + | ^ required by this bound in `TestBase1` +help: consider further restricting `Self` + | +LL | trait Test1: Leak { + | ++++++ + +error[E0658]: `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/maybe-bounds-in-traits.rs:100:31 + | +LL | fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {} + | ^^^^^^^^^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0277]: the trait bound `Self: Leak` is not satisfied + --> $DIR/maybe-bounds-in-traits.rs:87:43 + | +LL | const CNonLeak: usize = size_of::() where Self: ?Leak; + | ^^^^ the trait `Leak` is not implemented for `Self` + | +note: required by a bound in `size_of` + --> $DIR/maybe-bounds-in-traits.rs:81:22 + | +LL | const fn size_of() -> usize { + | ^ required by this bound in `size_of` +help: consider further restricting `Self` + | +LL | trait Trait: Leak { + | ++++++ + +error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied + --> $DIR/maybe-bounds-in-traits.rs:110:18 + | +LL | NonLeakS.leak_foo(); + | ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS` + | +note: required by a bound in `methods::Trait::leak_foo` + --> $DIR/maybe-bounds-in-traits.rs:96:9 + | +LL | fn leak_foo(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0658. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/maybe-polarity-pass.rs b/tests/ui/traits/maybe-polarity-pass.rs new file mode 100644 index 0000000000000..b254fdc787041 --- /dev/null +++ b/tests/ui/traits/maybe-polarity-pass.rs @@ -0,0 +1,28 @@ +//@ check-pass +//@ compile-flags: -Zdeduplicate-diagnostics=yes -Zexperimental-default-bounds + +#![feature(auto_traits)] +#![feature(more_maybe_bounds)] +#![feature(negative_impls)] + +trait Trait1 {} +auto trait Trait2 {} + +trait Trait3 : ?Trait1 {} +trait Trait4 where Self: Trait1 {} + +fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {} +fn bar(_: &T) {} +//~^ WARN relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default +//~| WARN relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default +//~| WARN relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default + +struct S; +impl !Trait2 for S {} +impl Trait1 for S {} +impl Trait3 for S {} + +fn main() { + foo(Box::new(S)); + bar(&S); +} diff --git a/tests/ui/traits/maybe-polarity-pass.stderr b/tests/ui/traits/maybe-polarity-pass.stderr new file mode 100644 index 0000000000000..7af7e9e78225c --- /dev/null +++ b/tests/ui/traits/maybe-polarity-pass.stderr @@ -0,0 +1,20 @@ +warning: relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default + --> $DIR/maybe-polarity-pass.rs:15:20 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +warning: relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default + --> $DIR/maybe-polarity-pass.rs:15:30 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +warning: relaxing a default bound only does something for `?Sized` and `experimental_default_bounds`; all other traits are not bound by default + --> $DIR/maybe-polarity-pass.rs:15:40 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +warning: 3 warnings emitted + diff --git a/tests/ui/traits/wf-object/maybe-bound.stderr b/tests/ui/traits/wf-object/maybe-bound.stderr index 2fe3f0fc39f40..be7afabd0d01d 100644 --- a/tests/ui/traits/wf-object/maybe-bound.stderr +++ b/tests/ui/traits/wf-object/maybe-bound.stderr @@ -1,32 +1,48 @@ -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:5:15 | LL | type _0 = dyn ?Sized + Foo; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:8:21 | LL | type _1 = dyn Foo + ?Sized; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:11:21 | LL | type _2 = dyn Foo + ?Sized + ?Sized; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:11:30 | LL | type _2 = dyn Foo + ?Sized + ?Sized; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:15:15 | LL | type _3 = dyn ?Sized + Foo; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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 5 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/wf-object/only-maybe-bound.stderr b/tests/ui/traits/wf-object/only-maybe-bound.stderr index cbc41feec1e8c..26269476eaaee 100644 --- a/tests/ui/traits/wf-object/only-maybe-bound.stderr +++ b/tests/ui/traits/wf-object/only-maybe-bound.stderr @@ -1,8 +1,11 @@ -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/only-maybe-bound.rs:3:15 | LL | type _0 = dyn ?Sized; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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[E0224]: at least one trait is required for an object type --> $DIR/only-maybe-bound.rs:3:11 @@ -12,4 +15,5 @@ LL | type _0 = dyn ?Sized; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0224`. +Some errors have detailed explanations: E0224, E0658. +For more information about an error, try `rustc --explain E0224`. diff --git a/tests/ui/unsized/maybe-bounds-where.stderr b/tests/ui/unsized/maybe-bounds-where.stderr index 683bd387bb292..f785126166781 100644 --- a/tests/ui/unsized/maybe-bounds-where.stderr +++ b/tests/ui/unsized/maybe-bounds-where.stderr @@ -1,32 +1,47 @@ -error: `?Trait` bounds are only permitted at the point where a type parameter is declared +error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared --> $DIR/maybe-bounds-where.rs:1:28 | LL | struct S1(T) where (T): ?Sized; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` bounds are only permitted at the point where a type parameter is declared +error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared --> $DIR/maybe-bounds-where.rs:4:27 | LL | struct S2(T) where u8: ?Sized; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` bounds are only permitted at the point where a type parameter is declared +error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared --> $DIR/maybe-bounds-where.rs:7:35 | LL | struct S3(T) where &'static T: ?Sized; | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` bounds are only permitted at the point where a type parameter is declared +error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared --> $DIR/maybe-bounds-where.rs:12:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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: `?Trait` bounds are only permitted at the point where a type parameter is declared +error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared --> $DIR/maybe-bounds-where.rs:21:21 | LL | fn f() where T: ?Sized {} | ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-bounds-where.rs:12:34 @@ -39,6 +54,9 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ ^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-bounds-where.rs:16:33 @@ -48,4 +66,5 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; error: aborting due to 6 previous errors; 2 warnings emitted -For more information about this error, try `rustc --explain E0203`. +Some errors have detailed explanations: E0203, E0658. +For more information about an error, try `rustc --explain E0203`.