Support ?Trait bounds in supertraits and dyn Trait under a feature gate

This commit is contained in:
Bryanskiy 2024-02-23 16:39:57 +03:00
parent 28e684b470
commit 2a73553513
34 changed files with 305 additions and 85 deletions

View File

@ -1525,8 +1525,14 @@ fn lower_generics<T>(
continue; continue;
} }
let is_param = *is_param.get_or_insert_with(compute_is_param); let is_param = *is_param.get_or_insert_with(compute_is_param);
if !is_param { if !is_param && !self.tcx.features().more_maybe_bounds {
self.dcx().emit_err(MisplacedRelaxTraitBound { span: bound.span() }); self.tcx
.sess
.create_feature_err(
MisplacedRelaxTraitBound { span: bound.span() },
sym::more_maybe_bounds,
)
.emit();
} }
} }
} }

View File

@ -1216,6 +1216,7 @@ fn lower_path_ty(
itctx, itctx,
TraitBoundModifiers::NONE, TraitBoundModifiers::NONE,
); );
let bound = (bound, hir::TraitBoundModifier::None);
let bounds = this.arena.alloc_from_iter([bound]); let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span); let lifetime_bound = this.elided_dyn_bound(t.span);
(bounds, lifetime_bound) (bounds, lifetime_bound)
@ -1348,21 +1349,17 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
// We can safely ignore constness here since AST validation // We can safely ignore constness here since AST validation
// takes care of rejecting invalid modifier combinations and // takes care of rejecting invalid modifier combinations and
// const trait bounds in trait object types. // const trait bounds in trait object types.
GenericBound::Trait(ty, modifiers) => match modifiers.polarity { GenericBound::Trait(ty, modifiers) => {
BoundPolarity::Positive | BoundPolarity::Negative(_) => { // Still, don't pass along the constness here; we don't want to
Some(this.lower_poly_trait_ref( // synthesize any host effect args, it'd only cause problems.
ty, let modifiers = TraitBoundModifiers {
itctx, constness: BoundConstness::Never,
// Still, don't pass along the constness here; we don't want to ..*modifiers
// synthesize any host effect args, it'd only cause problems. };
TraitBoundModifiers { let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers);
constness: BoundConstness::Never, let polarity = this.lower_trait_bound_modifiers(modifiers);
..*modifiers Some((trait_ref, polarity))
}, }
))
}
BoundPolarity::Maybe(_) => None,
},
GenericBound::Outlives(lifetime) => { GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() { if lifetime_bound.is_none() {
lifetime_bound = Some(this.lower_lifetime(lifetime)); lifetime_bound = Some(this.lower_lifetime(lifetime));
@ -2688,6 +2685,7 @@ fn ty_path(&mut self, mut hir_id: HirId, span: Span, qpath: hir::QPath<'hir>) ->
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
span: self.lower_span(span), span: self.lower_span(span),
}; };
let principal = (principal, hir::TraitBoundModifier::None);
// The original ID is taken by the `PolyTraitRef`, // The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one. // so the `Ty` itself needs a different one.

View File

@ -1345,14 +1345,28 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
match bound { match bound {
GenericBound::Trait(trait_ref, modifiers) => { GenericBound::Trait(trait_ref, modifiers) => {
match (ctxt, modifiers.constness, modifiers.polarity) { match (ctxt, modifiers.constness, modifiers.polarity) {
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
self.dcx().emit_err(errors::OptionalTraitSupertrait { if !self.features.more_maybe_bounds =>
span: trait_ref.span, {
path_str: pprust::path_to_string(&trait_ref.trait_ref.path), self.session
}); .create_feature_err(
errors::OptionalTraitSupertrait {
span: trait_ref.span,
path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
},
sym::more_maybe_bounds,
)
.emit();
} }
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
self.dcx().emit_err(errors::OptionalTraitObject { span: trait_ref.span }); if !self.features.more_maybe_bounds =>
{
self.session
.create_feature_err(
errors::OptionalTraitObject { span: trait_ref.span },
sym::more_maybe_bounds,
)
.emit();
} }
( (
BoundKind::TraitObject, BoundKind::TraitObject,

View File

@ -205,6 +205,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, lifetime_capture_rules_2024, "1.76.0", None), (unstable, lifetime_capture_rules_2024, "1.76.0", None),
/// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406 /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
(unstable, link_cfg, "1.14.0", None), (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. /// Allows the `multiple_supertrait_upcastable` lint.
(unstable, multiple_supertrait_upcastable, "1.69.0", None), (unstable, multiple_supertrait_upcastable, "1.69.0", None),
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!

View File

@ -2832,7 +2832,11 @@ pub enum TyKind<'hir> {
OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool), OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool),
/// A trait object type `Bound1 + Bound2 + Bound3` /// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime. /// 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. /// Unused for now.
Typeof(&'hir AnonConst), Typeof(&'hir AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been /// `TyKind::Infer` means the type should be inferred instead of it having been

View File

@ -902,7 +902,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)); try_visit!(visitor.visit_array_length(length));
} }
TyKind::TraitObject(bounds, ref lifetime, _syntax) => { 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)); try_visit!(visitor.visit_lifetime(lifetime));
} }
TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)), TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)),

View File

@ -831,7 +831,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
match ty.kind { 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()), [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
_ => false, _ => false,
}, },

View File

@ -652,7 +652,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
debug!(?bounds, ?lifetime, "TraitObject"); debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope }; let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| { self.with(scope, |this| {
for bound in bounds { for (bound, _) in bounds {
this.visit_poly_trait_ref_inner( this.visit_poly_trait_ref_inner(
bound, bound,
NonLifetimeBinderAllowed::Deny("trait object types"), NonLifetimeBinderAllowed::Deny("trait object types"),

View File

@ -9,7 +9,7 @@
use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt};
use rustc_span::symbol::Ident; 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_trait_selection::traits;
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -75,10 +75,16 @@ pub(crate) fn add_sized_bound(
} }
} }
if unbounds.len() > 1 { if unbounds.len() > 1 && !tcx.features().more_maybe_bounds {
self.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { self.tcx()
spans: unbounds.iter().map(|ptr| ptr.span).collect(), .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_sized_unbound = false;

View File

@ -698,7 +698,7 @@ pub(crate) fn complain_about_missing_assoc_tys(
&self, &self,
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>, associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
potential_assoc_types: Vec<usize>, potential_assoc_types: Vec<usize>,
trait_bounds: &[hir::PolyTraitRef<'_>], trait_bounds: &[(hir::PolyTraitRef<'_>, hir::TraitBoundModifier)],
) { ) {
if associated_types.values().all(|v| v.is_empty()) { if associated_types.values().all(|v| v.is_empty()) {
return; return;
@ -744,12 +744,12 @@ pub(crate) fn complain_about_missing_assoc_tys(
// related to issue #91997, turbofishes added only when in an expr or pat // related to issue #91997, turbofishes added only when in an expr or pat
let mut in_expr_or_pat = false; let mut in_expr_or_pat = false;
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id)); let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.0.trait_ref.hir_ref_id));
in_expr_or_pat = match grandparent { in_expr_or_pat = match grandparent {
Node::Expr(_) | Node::Pat(_) => true, Node::Expr(_) | Node::Pat(_) => true,
_ => false, _ => false,
}; };
match bound.trait_ref.path.segments { match bound.0.trait_ref.path.segments {
// FIXME: `trait_ref.path.span` can point to a full path with multiple // 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 // segments, even though `trait_ref.path.segments` is of length `1`. Work
// around that bug here, even though it should be fixed elsewhere. // around that bug here, even though it should be fixed elsewhere.
@ -790,7 +790,7 @@ pub(crate) fn complain_about_missing_assoc_tys(
// and we can then use their span to indicate this to the user. // and we can then use their span to indicate this to the user.
let bound_names = trait_bounds let bound_names = trait_bounds
.iter() .iter()
.filter_map(|poly_trait_ref| { .filter_map(|(poly_trait_ref, _)| {
let path = poly_trait_ref.trait_ref.path.segments.last()?; let path = poly_trait_ref.trait_ref.path.segments.last()?;
let args = path.args?; let args = path.args?;

View File

@ -34,7 +34,7 @@ pub(super) fn prohibit_or_lint_bare_trait_object_ty(
.ok() .ok()
.is_some_and(|s| s.trim_end().ends_with('<')); .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![( let mut sugg = vec![(
self_ty.span.shrink_to_lo(), self_ty.span.shrink_to_lo(),
@ -176,7 +176,7 @@ fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -
let mut is_downgradable = true; let mut is_downgradable = true;
let is_object_safe = match self_ty.kind { let is_object_safe = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => { 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) => { Res::Def(DefKind::Trait, id) => {
if Some(id) == owner { if Some(id) == owner {
// For recursive traits, don't downgrade the error. (#119652) // For recursive traits, don't downgrade the error. (#119652)

View File

@ -27,7 +27,7 @@ pub(super) fn lower_trait_object_ty(
&self, &self,
span: Span, span: Span,
hir_id: hir::HirId, hir_id: hir::HirId,
hir_trait_bounds: &[hir::PolyTraitRef<'tcx>], hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)],
lifetime: &hir::Lifetime, lifetime: &hir::Lifetime,
borrowed: bool, borrowed: bool,
representation: DynKind, representation: DynKind,
@ -37,7 +37,10 @@ pub(super) fn lower_trait_object_ty(
let mut bounds = Bounds::default(); let mut bounds = Bounds::default();
let mut potential_assoc_types = Vec::new(); let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self; 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 { if let GenericArgCountResult {
correct: correct:
Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
@ -249,7 +252,7 @@ pub(super) fn lower_trait_object_ty(
let args = tcx.mk_args(&args); let args = tcx.mk_args(&args);
let span = i.bottom().1; 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.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
&& hir_bound.span.contains(span) && hir_bound.span.contains(span)
}); });

View File

@ -300,13 +300,16 @@ fn print_type(&mut self, ty: &hir::Ty<'_>) {
self.word_space("dyn"); self.word_space("dyn");
} }
let mut first = true; let mut first = true;
for bound in bounds { for (bound, modifier) in bounds {
if first { if first {
first = false; first = false;
} else { } else {
self.nbsp(); self.nbsp();
self.word_space("+"); self.word_space("+");
} }
if *modifier == TraitBoundModifier::Maybe {
self.word("?");
}
self.print_poly_trait_ref(bound); self.print_poly_trait_ref(bound);
} }
if !lifetime.is_elided() { if !lifetime.is_elided() {

View File

@ -429,7 +429,7 @@ fn ty_has_local_parent(
path_has_local_parent(ty_path, cx, impl_parent, impl_parent_parent) path_has_local_parent(ty_path, cx, impl_parent, impl_parent_parent)
} }
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => path_has_local_parent( TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => path_has_local_parent(
principle_poly_trait_ref.trait_ref.path, principle_poly_trait_ref.0.trait_ref.path,
cx, cx,
impl_parent, impl_parent,
impl_parent_parent, impl_parent_parent,
@ -527,7 +527,7 @@ fn self_ty_kind_for_diagnostic(ty: &rustc_hir::Ty<'_>, tcx: TyCtxt<'_>) -> (Span
.to_string(), .to_string(),
), ),
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => { TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
let path = &principle_poly_trait_ref.trait_ref.path; let path = &principle_poly_trait_ref.0.trait_ref.path;
( (
path_span_without_args(path), path_span_without_args(path),
path.res path.res

View File

@ -113,9 +113,11 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; 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(); 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 }; 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 }); cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id });
} }

View File

@ -1229,6 +1229,7 @@
modifiers, modifiers,
module, module,
module_path, module_path,
more_maybe_bounds,
more_qualified_paths, more_qualified_paths,
more_struct_aliases, more_struct_aliases,
movbe_target_feature, movbe_target_feature,

View File

@ -84,7 +84,7 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
} }
hir::TyKind::TraitObject(bounds, ..) => { hir::TyKind::TraitObject(bounds, ..) => {
for bound in bounds { for (bound, _) in bounds {
self.current_index.shift_in(1); self.current_index.shift_in(1);
self.visit_poly_trait_ref(bound); self.visit_poly_trait_ref(bound);
self.current_index.shift_out(1); self.current_index.shift_out(1);

View File

@ -607,7 +607,7 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
_, _,
) = t.kind ) = t.kind
{ {
for ptr in poly_trait_refs { for (ptr, _) in poly_trait_refs {
if Some(self.1) == ptr.trait_ref.trait_def_id() { if Some(self.1) == ptr.trait_ref.trait_def_id() {
self.0.push(ptr.span); self.0.push(ptr.span);
} }

View File

@ -437,7 +437,7 @@ pub fn report_object_safety_error<'tcx>(
if tcx.parent_hir_node(hir_id).fn_sig().is_some() { if tcx.parent_hir_node(hir_id).fn_sig().is_some() {
// Do not suggest `impl Trait` when dealing with things like super-traits. // Do not suggest `impl Trait` when dealing with things like super-traits.
err.span_suggestion_verbose( err.span_suggestion_verbose(
ty.span.until(trait_ref.span), ty.span.until(trait_ref.0.span),
"consider using an opaque type instead", "consider using an opaque type instead",
"impl ", "impl ",
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,

View File

@ -3040,11 +3040,11 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
match ty.kind { match ty.kind {
hir::TyKind::TraitObject(traits, _, _) => { hir::TyKind::TraitObject(traits, _, _) => {
let (span, kw) = match 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. // Missing `dyn` in front of trait object.
(ty.span.shrink_to_lo(), "dyn ") (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:?}"), [] => span_bug!(ty.span, "trait object with no traits: {ty:?}"),
}; };
let needs_parens = traits.len() != 1; let needs_parens = traits.len() != 1;

View File

@ -1858,7 +1858,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
} }
TyKind::Path(_) => clean_qpath(ty, cx), TyKind::Path(_) => clean_qpath(ty, cx),
TyKind::TraitObject(bounds, ref lifetime, _) => { 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 = let lifetime =
if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None }; if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None };
DynTrait(bounds, lifetime) DynTrait(bounds, lifetime)

View File

@ -545,7 +545,7 @@ fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
if !lt.is_elided() { if !lt.is_elided() {
self.unelided_trait_object_lifetime = true; self.unelided_trait_object_lifetime = true;
} }
for bound in bounds { for (bound, _) in bounds {
self.visit_poly_trait_ref(bound); self.visit_poly_trait_ref(bound);
} }
}, },

View File

@ -181,7 +181,7 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
// Iterate the bounds and add them to our seen hash // Iterate the bounds and add them to our seen hash
// If we haven't yet seen it, add it to the fixed traits // 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 { let Some(def_id) = bound.trait_ref.trait_def_id() else {
continue; continue;
}; };
@ -196,9 +196,9 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
// If the number of unique traits isn't the same as the number of traits in the bounds, // 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 // there must be 1 or more duplicates
if bounds.len() != unique_traits.len() { 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); bounds_span = bounds_span.to(bound.span);
} }

View File

@ -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. // Returns true if given type is `Any` trait.
fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool { fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool {
if let TyKind::TraitObject(traits, ..) = t.kind if let TyKind::TraitObject(traits, ..) = t.kind {
&& !traits.is_empty() return traits
&& let Some(trait_did) = traits[0].trait_ref.trait_def_id() .iter()
// Only Send/Sync can be used as additional traits, so it is enough to .any(|(bound, _)| {
// check only the first trait. if let Some(trait_did) = bound.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::Any, trait_did) && cx.tcx.is_diagnostic_item(sym::Any, trait_did)
{ {
return true; return true;
}
false
});
} }
false false

View File

@ -55,6 +55,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
TyKind::TraitObject(param_bounds, _, _) => { TyKind::TraitObject(param_bounds, _, _) => {
let has_lifetime_parameters = param_bounds.iter().any(|bound| { let has_lifetime_parameters = param_bounds.iter().any(|bound| {
bound bound
.0
.bound_generic_params .bound_generic_params
.iter() .iter()
.any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) .any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))

View File

@ -0,0 +1,17 @@
#![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<dyn Trait1 + ?Trait2>) {}
//~^ ERROR `?Trait` is not permitted in trait object types
fn bar<T: ?Trait1 + ?Trait2>(_: 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`; all other traits are not bound by default
//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
fn main() {}

View File

@ -0,0 +1,53 @@
error[E0658]: `?Trait` is not permitted in supertraits
--> $DIR/feature-gate-more-maybe-bounds.rs:5: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:10:28
|
LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
| ^^^^^^^
|
= 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:7: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:12:11
|
LL | fn bar<T: ?Trait1 + ?Trait2>(_: 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`; all other traits are not bound by default
--> $DIR/feature-gate-more-maybe-bounds.rs:12:11
|
LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
| ^^^^^^^
warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/feature-gate-more-maybe-bounds.rs:12:21
|
LL | fn bar<T: ?Trait1 + ?Trait2>(_: 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`.

View File

@ -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 --> $DIR/maybe-bounds.rs:1:11
| |
LL | trait Tr: ?Sized {} LL | trait Tr: ?Sized {}
| ^^^^^^ | ^^^^^^
| |
= note: traits are `?Sized` by default = 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 --> $DIR/maybe-bounds.rs:4:20
| |
LL | type A1 = dyn Tr + (?Sized); 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 --> $DIR/maybe-bounds.rs:6:28
| |
LL | type A2 = dyn for<'a> Tr + (?Sized); 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 error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -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 --> $DIR/trait-object-trait-parens.rs:8:24
| |
LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; 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 --> $DIR/trait-object-trait-parens.rs:13:16
| |
LL | let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>; LL | let _: Box<?Sized + (for<'a> 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 --> $DIR/trait-object-trait-parens.rs:18:44
| |
LL | let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>; LL | let _: Box<for<'a> 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 warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/trait-object-trait-parens.rs:8:16 --> $DIR/trait-object-trait-parens.rs:8:16
@ -91,4 +100,5 @@ LL | let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
error: aborting due to 6 previous errors; 3 warnings emitted 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`.

View File

@ -0,0 +1,27 @@
//@ check-pass
#![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: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
//~^ WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
//~| WARN relaxing a default bound only does something for `?Sized`; 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);
}

View File

@ -0,0 +1,20 @@
warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/maybe-polarity-pass.rs:14:20
|
LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
| ^^^^^^^
warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/maybe-polarity-pass.rs:14:30
|
LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
| ^^^^^^^
warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/maybe-polarity-pass.rs:14:40
|
LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
| ^^^^^^^
warning: 3 warnings emitted

View File

@ -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 --> $DIR/maybe-bound.rs:5:15
| |
LL | type _0 = dyn ?Sized + Foo; 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 --> $DIR/maybe-bound.rs:8:21
| |
LL | type _1 = dyn Foo + ?Sized; 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 --> $DIR/maybe-bound.rs:11:21
| |
LL | type _2 = dyn Foo + ?Sized + ?Sized; 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 --> $DIR/maybe-bound.rs:11:30
| |
LL | type _2 = dyn Foo + ?Sized + ?Sized; 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 --> $DIR/maybe-bound.rs:15:15
| |
LL | type _3 = dyn ?Sized + Foo; 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 error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -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 --> $DIR/only-maybe-bound.rs:3:15
| |
LL | type _0 = dyn ?Sized; 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 error[E0224]: at least one trait is required for an object type
--> $DIR/only-maybe-bound.rs:3:11 --> $DIR/only-maybe-bound.rs:3:11
@ -12,4 +15,5 @@ LL | type _0 = dyn ?Sized;
error: aborting due to 2 previous errors 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`.

View File

@ -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 --> $DIR/maybe-bounds-where.rs:1:28
| |
LL | struct S1<T>(T) where (T): ?Sized; LL | struct S1<T>(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 --> $DIR/maybe-bounds-where.rs:4:27
| |
LL | struct S2<T>(T) where u8: ?Sized; LL | struct S2<T>(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 --> $DIR/maybe-bounds-where.rs:7:35
| |
LL | struct S3<T>(T) where &'static T: ?Sized; LL | struct S3<T>(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 --> $DIR/maybe-bounds-where.rs:12:34
| |
LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>; LL | struct S4<T>(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 --> $DIR/maybe-bounds-where.rs:21:21
| |
LL | fn f() where T: ?Sized {} 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 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 --> $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<T>(*const T) where T: ?Trait<'static> + ?Sized; LL | struct S5<T>(*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 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 --> $DIR/maybe-bounds-where.rs:16:33
@ -48,4 +66,5 @@ LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
error: aborting due to 6 previous errors; 2 warnings emitted 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`.