More robustly reject relaxing non-default trait bounds

This commit is contained in:
León Orell Valerian Liehr
2025-10-15 19:43:40 +02:00
parent aee9d3b4c0
commit 03dfb84ee1
12 changed files with 226 additions and 119 deletions

View File

@@ -204,7 +204,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait
// bounds, trait alias bounds, assoc type bounds (ATB)!
let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates);
self.check_and_report_invalid_relaxed_bounds(bounds);
self.reject_duplicate_relaxed_bounds(bounds);
}
let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
@@ -308,6 +308,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
!self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any()
}
fn reject_duplicate_relaxed_bounds(&self, relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>) {
let tcx = self.tcx();
let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
for bound in &relaxed_bounds {
if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
}
}
for (trait_def_id, spans) in grouped_bounds {
if spans.len() > 1 {
let name = tcx.item_name(trait_def_id);
self.dcx()
.struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
.with_code(E0203)
.emit();
}
}
}
pub(crate) fn require_bound_to_relax_default_trait(
&self,
trait_ref: hir::TraitRef<'_>,
span: Span,
) {
let tcx = self.tcx();
if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res
&& (tcx.is_lang_item(def_id, hir::LangItem::Sized) || tcx.is_default_trait(def_id))
{
return;
}
self.dcx().span_err(
span,
if tcx.sess.opts.unstable_opts.experimental_default_bounds
|| tcx.features().more_maybe_bounds()
{
"bound modifier `?` can only be applied to default traits"
} else {
"bound modifier `?` can only be applied to `Sized`"
},
);
}
/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
///
/// ### Examples

View File

@@ -8,7 +8,7 @@ use rustc_errors::{
};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId, PolyTraitRef};
use rustc_hir::{self as hir, HirId};
use rustc_middle::bug;
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -35,52 +35,6 @@ use crate::fluent_generated as fluent;
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Check for duplicate relaxed bounds and relaxed bounds of non-default traits.
pub(crate) fn check_and_report_invalid_relaxed_bounds(
&self,
relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
) {
let tcx = self.tcx();
let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
for bound in &relaxed_bounds {
if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
}
}
for (trait_def_id, spans) in grouped_bounds {
if spans.len() > 1 {
let name = tcx.item_name(trait_def_id);
self.dcx()
.struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
.with_code(E0203)
.emit();
}
}
let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP);
for bound in relaxed_bounds {
if let Res::Def(DefKind::Trait, def_id) = bound.trait_ref.path.res
&& (def_id == sized_def_id || tcx.is_default_trait(def_id))
{
continue;
}
self.dcx().span_err(
bound.span,
if tcx.sess.opts.unstable_opts.experimental_default_bounds
|| tcx.features().more_maybe_bounds()
{
"bound modifier `?` can only be applied to default traits like `Sized`"
} else {
"bound modifier `?` can only be applied to `Sized`"
},
);
}
}
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
/// the type parameter's name as a placeholder.
pub(crate) fn report_missing_type_params(

View File

@@ -767,7 +767,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// We use the *resolved* bound vars later instead of the HIR ones since the former
// also include the bound vars of the overarching predicate if applicable.
let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } =
let hir::PolyTraitRef { bound_generic_params: _, modifiers, trait_ref, span } =
*poly_trait_ref;
let hir::TraitBoundModifiers { constness, polarity } = modifiers;
@@ -791,6 +791,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds),
rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds),
rustc_ast::BoundPolarity::Maybe(_) => {
self.require_bound_to_relax_default_trait(trait_ref, span);
(ty::PredicatePolarity::Positive, &mut Vec::new())
}
};

View File

@@ -1782,9 +1782,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
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))
self.default_traits().iter().any(|&default_trait| self.is_lang_item(def_id, default_trait))
}
/// Returns a range of the start/end indices specified with the

View File

@@ -1,12 +1,17 @@
#![feature(auto_traits)]
#![feature(auto_traits, lang_items)]
trait Trait1 {}
auto trait Trait2 {}
trait Trait3: ?Trait1 {} //~ ERROR relaxed bounds are not permitted in supertrait bounds
trait Trait4 where Self: ?Trait1 {} //~ ERROR this relaxed bound is not permitted here
#[lang = "default_trait1"] trait Trait1 {}
#[lang = "default_trait2"] auto trait Trait2 {}
trait Trait3: ?Trait1 {}
//~^ ERROR relaxed bounds are not permitted in supertrait bounds
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`
fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
//~^ ERROR relaxed bounds are not permitted in trait object types
//~| ERROR bound modifier `?` can only be applied to `Sized`
fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
//~^ ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`

View File

@@ -1,34 +1,54 @@
error: relaxed bounds are not permitted in supertrait bounds
--> $DIR/feature-gate-more-maybe-bounds.rs:5:15
--> $DIR/feature-gate-more-maybe-bounds.rs:6:15
|
LL | trait Trait3: ?Trait1 {}
| ^^^^^^^
error: this relaxed bound is not permitted here
--> $DIR/feature-gate-more-maybe-bounds.rs:6:26
|
LL | trait Trait4 where Self: ?Trait1 {}
| ^^^^^^^
|
= note: in this context, relaxed bounds are only allowed on type parameters defined on the closest item
error: relaxed bounds are not permitted in trait object types
--> $DIR/feature-gate-more-maybe-bounds.rs:8:28
--> $DIR/feature-gate-more-maybe-bounds.rs:12:28
|
LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
| ^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:10:11
--> $DIR/feature-gate-more-maybe-bounds.rs:6:15
|
LL | trait Trait3: ?Trait1 {}
| ^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:6:15
|
LL | trait Trait3: ?Trait1 {}
| ^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:6:15
|
LL | trait Trait3: ?Trait1 {}
| ^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:12:28
|
LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
| ^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:15:11
|
LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
| ^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:10:21
--> $DIR/feature-gate-more-maybe-bounds.rs:15:21
|
LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
| ^^^^^^^
error: aborting due to 5 previous errors
error: aborting due to 8 previous errors

View File

@@ -12,12 +12,17 @@ trait MetaSized_: MetaSized { }
trait NegMetaSized: ?MetaSized { }
//~^ ERROR relaxed bounds are not permitted in supertrait bounds
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`
trait PointeeSized_: PointeeSized { }
trait NegPointeeSized: ?PointeeSized { }
//~^ ERROR relaxed bounds are not permitted in supertrait bounds
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`
trait Bare {}

View File

@@ -13,19 +13,63 @@ LL | trait NegMetaSized: ?MetaSized { }
| ^^^^^^^^^^
error: relaxed bounds are not permitted in supertrait bounds
--> $DIR/default-supertrait.rs:19:24
--> $DIR/default-supertrait.rs:21:24
|
LL | trait NegPointeeSized: ?PointeeSized { }
| ^^^^^^^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/default-supertrait.rs:13:21
|
LL | trait NegMetaSized: ?MetaSized { }
| ^^^^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/default-supertrait.rs:13:21
|
LL | trait NegMetaSized: ?MetaSized { }
| ^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/default-supertrait.rs:13:21
|
LL | trait NegMetaSized: ?MetaSized { }
| ^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/default-supertrait.rs:21:24
|
LL | trait NegPointeeSized: ?PointeeSized { }
| ^^^^^^^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/default-supertrait.rs:21:24
|
LL | trait NegPointeeSized: ?PointeeSized { }
| ^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/default-supertrait.rs:21:24
|
LL | trait NegPointeeSized: ?PointeeSized { }
| ^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: the size for values of type `T` cannot be known
--> $DIR/default-supertrait.rs:52:38
--> $DIR/default-supertrait.rs:57:38
|
LL | fn with_bare_trait<T: PointeeSized + Bare>() {
| ^^^^ doesn't have a known size
|
note: required by a bound in `Bare`
--> $DIR/default-supertrait.rs:22:1
--> $DIR/default-supertrait.rs:27:1
|
LL | trait Bare {}
| ^^^^^^^^^^^^^ required by this bound in `Bare`
@@ -35,7 +79,7 @@ LL | fn with_bare_trait<T: PointeeSized + Bare + std::marker::MetaSized>() {
| ++++++++++++++++++++++++
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/default-supertrait.rs:35:22
--> $DIR/default-supertrait.rs:40:22
|
LL | fn with_metasized_supertrait<T: PointeeSized + MetaSized_>() {
| - this type parameter needs to be `Sized`
@@ -43,13 +87,13 @@ LL | requires_sized::<T>();
| ^ doesn't have a size known at compile-time
|
note: required by a bound in `requires_sized`
--> $DIR/default-supertrait.rs:24:22
--> $DIR/default-supertrait.rs:29:22
|
LL | fn requires_sized<T: Sized>() {}
| ^^^^^ required by this bound in `requires_sized`
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/default-supertrait.rs:43:22
--> $DIR/default-supertrait.rs:48:22
|
LL | fn with_pointeesized_supertrait<T: PointeeSized + PointeeSized_>() {
| - this type parameter needs to be `Sized`
@@ -57,19 +101,19 @@ LL | requires_sized::<T>();
| ^ doesn't have a size known at compile-time
|
note: required by a bound in `requires_sized`
--> $DIR/default-supertrait.rs:24:22
--> $DIR/default-supertrait.rs:29:22
|
LL | fn requires_sized<T: Sized>() {}
| ^^^^^ required by this bound in `requires_sized`
error[E0277]: the size for values of type `T` cannot be known
--> $DIR/default-supertrait.rs:45:26
--> $DIR/default-supertrait.rs:50:26
|
LL | requires_metasized::<T>();
| ^ doesn't have a known size
|
note: required by a bound in `requires_metasized`
--> $DIR/default-supertrait.rs:25:26
--> $DIR/default-supertrait.rs:30:26
|
LL | fn requires_metasized<T: MetaSized>() {}
| ^^^^^^^^^ required by this bound in `requires_metasized`
@@ -79,7 +123,7 @@ LL | fn with_pointeesized_supertrait<T: PointeeSized + PointeeSized_ + std::mark
| ++++++++++++++++++++++++
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/default-supertrait.rs:54:22
--> $DIR/default-supertrait.rs:59:22
|
LL | fn with_bare_trait<T: PointeeSized + Bare>() {
| - this type parameter needs to be `Sized`
@@ -88,19 +132,19 @@ LL | requires_sized::<T>();
| ^ doesn't have a size known at compile-time
|
note: required by a bound in `requires_sized`
--> $DIR/default-supertrait.rs:24:22
--> $DIR/default-supertrait.rs:29:22
|
LL | fn requires_sized<T: Sized>() {}
| ^^^^^ required by this bound in `requires_sized`
error[E0277]: the size for values of type `T` cannot be known
--> $DIR/default-supertrait.rs:56:26
--> $DIR/default-supertrait.rs:61:26
|
LL | requires_metasized::<T>();
| ^ doesn't have a known size
|
note: required by a bound in `requires_metasized`
--> $DIR/default-supertrait.rs:25:26
--> $DIR/default-supertrait.rs:30:26
|
LL | fn requires_metasized<T: MetaSized>() {}
| ^^^^^^^^^ required by this bound in `requires_metasized`
@@ -109,6 +153,6 @@ help: consider further restricting type parameter `T` with unstable trait `MetaS
LL | fn with_bare_trait<T: PointeeSized + Bare + std::marker::MetaSized>() {
| ++++++++++++++++++++++++
error: aborting due to 9 previous errors
error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -1,7 +1,5 @@
struct Foo<T: ?Hash> {}
//~^ ERROR expected trait, found derive macro `Hash`
//~| ERROR bound modifier `?` can only be applied to `Sized`
// issue: <https://github.com/rust-lang/rust/issues/37534>
struct Foo<T: ?Hash> {} //~ ERROR expected trait, found derive macro `Hash`
fn main() {}
// https://github.com/rust-lang/rust/issues/37534

View File

@@ -1,5 +1,5 @@
error[E0404]: expected trait, found derive macro `Hash`
--> $DIR/relaxing-default-bound-error-37534.rs:1:16
--> $DIR/relaxing-default-bound-error-37534.rs:3:16
|
LL | struct Foo<T: ?Hash> {}
| ^^^^ not a trait
@@ -9,12 +9,6 @@ help: consider importing this trait instead
LL + use std::hash::Hash;
|
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/relaxing-default-bound-error-37534.rs:1:15
|
LL | struct Foo<T: ?Hash> {}
| ^^^^^
error: aborting due to 2 previous errors
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0404`.

View File

@@ -1,40 +1,40 @@
// FIXME(more_maybe_bounds): Even under `more_maybe_bounds` / `-Zexperimental-default-bounds`,
// trying to relax non-default bounds should still be an error in all contexts! As you can see
// there are places like supertrait bounds, trait object types or associated type bounds (ATB)
// where we currently don't perform this check.
#![feature(auto_traits, more_maybe_bounds, negative_impls)]
trait Trait1 {}
auto trait Trait2 {}
// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`.
trait Trait3: ?Trait1 {}
//~^ ERROR bound modifier `?` can only be applied to default traits
//~| ERROR bound modifier `?` can only be applied to default traits
//~| ERROR bound modifier `?` can only be applied to default traits
trait Trait4 where Self: Trait1 {}
// FIXME: `?Trait2` should be rejected, `Trait2` isn't marked `#[lang = "default_traitN"]`.
fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {}
//~^ ERROR bound modifier `?` can only be applied to default traits
fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
//~^ ERROR bound modifier `?` can only be applied to default traits like `Sized`
//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
//~^ ERROR bound modifier `?` can only be applied to default traits
//~| ERROR bound modifier `?` can only be applied to default traits
//~| ERROR bound modifier `?` can only be applied to default traits
// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`.
fn baz<T>() where T: Iterator<Item: ?Trait1> {}
//~^ ERROR this relaxed bound is not permitted here
//~| ERROR bound modifier `?` can only be applied to default traits
struct S1<T>(T);
impl<T> S1<T> {
fn f() where T: ?Trait1 {}
//~^ ERROR this relaxed bound is not permitted here
//~| ERROR bound modifier `?` can only be applied to default traits
}
trait Trait5<'a> {}
struct S2<T>(T) where for<'a> T: ?Trait5<'a>;
//~^ ERROR this relaxed bound is not permitted here
//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
//~| ERROR bound modifier `?` can only be applied to default traits
struct S;
impl !Trait2 for S {}

View File

@@ -1,5 +1,5 @@
error: this relaxed bound is not permitted here
--> $DIR/more_maybe_bounds.rs:23:37
--> $DIR/more_maybe_bounds.rs:21:37
|
LL | fn baz<T>() where T: Iterator<Item: ?Trait1> {}
| ^^^^^^^
@@ -7,7 +7,7 @@ LL | fn baz<T>() where T: Iterator<Item: ?Trait1> {}
= note: in this context, relaxed bounds are only allowed on type parameters defined on the closest item
error: this relaxed bound is not permitted here
--> $DIR/more_maybe_bounds.rs:29:21
--> $DIR/more_maybe_bounds.rs:28:21
|
LL | fn f() where T: ?Trait1 {}
| ^^^^^^^
@@ -22,29 +22,69 @@ LL | struct S2<T>(T) where for<'a> T: ?Trait5<'a>;
|
= note: in this context, relaxed bounds are only allowed on type parameters defined on the closest item
error: bound modifier `?` can only be applied to default traits like `Sized`
--> $DIR/more_maybe_bounds.rs:17:20
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:6:15
|
LL | trait Trait3: ?Trait1 {}
| ^^^^^^^
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:6:15
|
LL | trait Trait3: ?Trait1 {}
| ^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:6:15
|
LL | trait Trait3: ?Trait1 {}
| ^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:13:29
|
LL | fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {}
| ^^^^^^^
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:16:20
|
LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
| ^^^^^^^
error: bound modifier `?` can only be applied to default traits like `Sized`
--> $DIR/more_maybe_bounds.rs:17:30
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:16:30
|
LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
| ^^^^^^^
error: bound modifier `?` can only be applied to default traits like `Sized`
--> $DIR/more_maybe_bounds.rs:17:40
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:16:40
|
LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
| ^^^^^^^
error: bound modifier `?` can only be applied to default traits like `Sized`
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:21:37
|
LL | fn baz<T>() where T: Iterator<Item: ?Trait1> {}
| ^^^^^^^
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:35:34
|
LL | struct S2<T>(T) where for<'a> T: ?Trait5<'a>;
| ^^^^^^^^^^^
error: aborting due to 7 previous errors
error: bound modifier `?` can only be applied to default traits
--> $DIR/more_maybe_bounds.rs:28:21
|
LL | fn f() where T: ?Trait1 {}
| ^^^^^^^
error: aborting due to 13 previous errors