Don't reject *multiple* relaxed bounds, reject *duplicate* ones.

Having multiple relaxed bounds like `?Sized + ?Iterator` is actually *fine*.
We actually want to reject *duplicate* relaxed bounds like `?Sized + ?Sized`
because these most certainly represent a user error.

Note that this doesn't mean that we accept more code because a bound like
`?Iterator` is still invalid as it's not relaxing a *default* trait and
the only way to define / use more default bounds is under the experimental
and internal feature `more_maybe_bounds` plus `lang_items` plus unstable
flag `-Zexperimental-default-bounds` (historical context: for the longest
time, bounds like `?Iterator` were actually allowed and lead to a hard
warning).

Ultimately, this simply *reframes* the diagnostic. The scope of
`more_maybe_bounds` / `-Zexperimental-default-bounds` remains unchanged
as well.
This commit is contained in:
León Orell Valerian Liehr 2025-07-18 12:24:56 +02:00
parent 879f62bb3c
commit cdc3d701cb
No known key found for this signature in database
GPG key ID: D17A07215F68E713
15 changed files with 128 additions and 150 deletions

View file

@ -1,15 +1,15 @@
Having multiple relaxed default bounds is unsupported.
Having duplicate relaxed default bounds is unsupported.
Erroneous code example:
```compile_fail,E0203
struct Bad<T: ?Sized + ?Send>{
inner: T
struct Bad<T: ?Sized + ?Sized>{
inner: T,
}
```
Here the type `T` cannot have a relaxed bound for multiple default traits
(`Sized` and `Send`). This can be fixed by only using one relaxed bound.
Here the type parameter `T` cannot have duplicate relaxed bounds for default
trait `Sized`. This can be fixed by only using one relaxed bound:
```
struct Good<T: ?Sized>{

View file

@ -371,9 +371,6 @@ hir_analysis_missing_type_params =
*[other] parameters
} must be specified on the object type
hir_analysis_multiple_relaxed_default_bounds =
type parameter has more than one relaxed default bound, only one is supported
hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
hir_analysis_must_implement_not_function = not a function

View file

@ -278,13 +278,6 @@ pub(crate) struct CopyImplOnTypeWithDtor {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)]
pub(crate) struct MultipleRelaxedDefaultBounds {
#[primary_span]
pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)]
pub(crate) struct CopyImplOnNonAdt {

View file

@ -35,31 +35,29 @@ use crate::fluent_generated as fluent;
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Check for multiple relaxed bounds and relaxed bounds of non-default traits.
/// 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 unique_bounds = FxIndexSet::default();
let mut seen_repeat = false;
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 {
seen_repeat |= !unique_bounds.insert(trait_def_id);
grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
}
}
if relaxed_bounds.len() > 1 {
let err = errors::MultipleRelaxedDefaultBounds {
spans: relaxed_bounds.iter().map(|ptr| ptr.span).collect(),
};
if seen_repeat {
tcx.dcx().emit_err(err);
} else if !tcx.features().more_maybe_bounds() {
tcx.sess.create_feature_err(err, sym::more_maybe_bounds).emit();
};
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);

View file

@ -8,15 +8,7 @@ trait Trait4 where Self: ?Trait1 {} //~ ERROR this relaxed bound is not permitte
fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
//~^ ERROR relaxed bounds are 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
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`
trait Trait {}
// Do not suggest `#![feature(more_maybe_bounds)]` for repetitions
fn baz<T: ?Trait + ?Trait>(_ : T) {}
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
//~| 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 main() {}

View file

@ -18,15 +18,6 @@ error: relaxed bounds are not permitted in trait object types
LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
| ^^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/feature-gate-more-maybe-bounds.rs:10: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
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:10:11
|
@ -39,24 +30,5 @@ error: bound modifier `?` can only be applied to `Sized`
LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
| ^^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/feature-gate-more-maybe-bounds.rs:17:11
|
LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
| ^^^^^^ ^^^^^^
error: aborting due to 5 previous errors
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:17:11
|
LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
| ^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/feature-gate-more-maybe-bounds.rs:17:20
|
LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
| ^^^^^^
error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0203`.

View file

@ -0,0 +1,22 @@
fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
//~^ ERROR duplicate relaxed `Sized` bounds
//~| ERROR duplicate relaxed `Iterator` bounds
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~| ERROR bound modifier `?` can only be applied to `Sized`
trait Trait {
// We used to say "type parameter has more than one relaxed default bound"
// even on *associated types* like here. Test that we no longer do that.
type Type: ?Sized + ?Sized;
//~^ ERROR duplicate relaxed `Sized` bounds
//~| ERROR duplicate relaxed `Sized` bounds
}
// We used to emit an additional error about "multiple relaxed default bounds".
// However, multiple relaxed bounds are actually *fine* if they're distinct.
// Ultimately, we still reject this because `Sized` is
// the only (stable) default trait, so we're fine.
fn not_dupes<T: ?Sized + ?Iterator>() {}
//~^ ERROR bound modifier `?` can only be applied to `Sized`
fn main() {}

View file

@ -0,0 +1,47 @@
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/duplicate-relaxed-bounds.rs:1:13
|
LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
| ^^^^^^ ^^^^^^
error[E0203]: duplicate relaxed `Iterator` bounds
--> $DIR/duplicate-relaxed-bounds.rs:1:31
|
LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
| ^^^^^^^^^ ^^^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/duplicate-relaxed-bounds.rs:1:31
|
LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
| ^^^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/duplicate-relaxed-bounds.rs:1:43
|
LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
| ^^^^^^^^^
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/duplicate-relaxed-bounds.rs:19:26
|
LL | fn not_dupes<T: ?Sized + ?Iterator>() {}
| ^^^^^^^^^
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/duplicate-relaxed-bounds.rs:10:16
|
LL | type Type: ?Sized + ?Sized;
| ^^^^^^ ^^^^^^
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/duplicate-relaxed-bounds.rs:10:16
|
LL | type Type: ?Sized + ?Sized;
| ^^^^^^ ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0203`.

View file

@ -1,39 +1,38 @@
// Regression test for #127441
// Tests that we make the correct suggestion
// in case there are more than one `?Sized`
// bounds on a function parameter
// Test that we emit a correct structured suggestions for dynamically sized ("maybe unsized")
// function parameters.
// We used to emit a butchered suggestion if duplicate relaxed `Sized` bounds were present.
// issue: <https://github.com/rust-lang/rust/issues/127441>.
use std::fmt::Debug;
fn foo1<T: ?Sized>(a: T) {}
//~^ ERROR he size for values of type `T` cannot be known at compilation time
//~^ ERROR the size for values of type `T` cannot be known at compilation time
fn foo2<T: ?Sized + ?Sized>(a: T) {}
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
//~^ ERROR duplicate relaxed `Sized` bounds
//~| ERROR the size for values of type `T` cannot be known at compilation time
fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
//~| ERROR he size for values of type `T` cannot be known at compilation time
//~^ ERROR duplicate relaxed `Sized` bounds
//~| ERROR the size for values of type `T` cannot be known at compilation time
fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
//~^ ERROR duplicate relaxed `Sized` bounds
//~| ERROR the size for values of type `T` cannot be known at compilation time
fn foo5(_: impl ?Sized) {}
//~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time
fn foo6(_: impl ?Sized + ?Sized) {}
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
//~^ ERROR duplicate relaxed `Sized` bounds
//~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim
fn foo7(_: impl ?Sized + ?Sized + Debug) {}
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
//~^ ERROR duplicate relaxed `Sized` bounds
//~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
//~^ ERROR duplicate relaxed `Sized` bounds
//~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
fn main() {}

View file

@ -1,41 +1,41 @@
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:12
|
LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
| ^^^^^^ ^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:12
|
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
| ^^^^^^ ^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:12
|
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
| ^^^^^^ ^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:17
|
LL | fn foo6(_: impl ?Sized + ?Sized) {}
| ^^^^^^ ^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:17
|
LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
| ^^^^^^ ^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17
error[E0203]: duplicate relaxed `Sized` bounds
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:17
|
LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
| ^^^^^^ ^^^^^^
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:23
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:8:23
|
LL | fn foo1<T: ?Sized>(a: T) {}
| - ^ doesn't have a size known at compile-time
@ -54,7 +54,7 @@ LL | fn foo1<T: ?Sized>(a: &T) {}
| +
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:32
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:32
|
LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
| - ^ doesn't have a size known at compile-time
@ -73,7 +73,7 @@ LL | fn foo2<T: ?Sized + ?Sized>(a: &T) {}
| +
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:40
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:40
|
LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
| - ^ doesn't have a size known at compile-time
@ -92,7 +92,7 @@ LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: &T) {}
| +
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:41
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:41
|
LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
| - ^ doesn't have a size known at compile-time
@ -111,7 +111,7 @@ LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: &T) {}
| +
error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:12
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:23:12
|
LL | fn foo5(_: impl ?Sized) {}
| ^^^^^^^^^^^
@ -131,7 +131,7 @@ LL | fn foo5(_: &impl ?Sized) {}
| +
error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:12
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:12
|
LL | fn foo6(_: impl ?Sized + ?Sized) {}
| ^^^^^^^^^^^^^^^^^^^^
@ -151,7 +151,7 @@ LL | fn foo6(_: &impl ?Sized + ?Sized) {}
| +
error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:12
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:12
|
LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -171,7 +171,7 @@ LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {}
| +
error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
--> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:12
--> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:12
|
LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,6 +1,6 @@
// 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 placed like supertrait bounds and trait object types where we currently don't perform
// there are places like supertrait bounds and trait object types where we currently don't perform
// this check.
#![feature(auto_traits, more_maybe_bounds, negative_impls)]

View file

@ -1,9 +0,0 @@
#![feature(more_maybe_bounds)]
trait Trait {}
fn foo<T: ?Trait + ?Trait>(_: T) {}
//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
fn main() {}

View file

@ -1,21 +0,0 @@
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/maybe-polarity-repeated.rs:4:11
|
LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
| ^^^^^^ ^^^^^^
error: bound modifier `?` can only be applied to default traits like `Sized`
--> $DIR/maybe-polarity-repeated.rs:4:11
|
LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
| ^^^^^^
error: bound modifier `?` can only be applied to default traits like `Sized`
--> $DIR/maybe-polarity-repeated.rs:4:20
|
LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
| ^^^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0203`.

View file

@ -16,8 +16,7 @@ struct S4<T>(T) where for<'a> T: ?Trait<'a>;
//~| ERROR bound modifier `?` can only be applied to `Sized`
struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
//~^ ERROR type parameter has more than one relaxed default bound
//~| ERROR bound modifier `?` can only be applied to `Sized`
//~^ ERROR bound modifier `?` can only be applied to `Sized`
impl<T> S1<T> {
fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here
@ -33,4 +32,3 @@ type O2 = dyn ?Sized + ?Sized + Tr;
//~| ERROR relaxed bounds are not permitted in trait object types
fn main() {}

View file

@ -31,7 +31,7 @@ LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
= note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
error: this relaxed bound is not permitted here
--> $DIR/relaxed-bounds-invalid-places.rs:23:21
--> $DIR/relaxed-bounds-invalid-places.rs:22:21
|
LL | fn f() where T: ?Sized {}
| ^^^^^^
@ -39,7 +39,7 @@ LL | fn f() where T: ?Sized {}
= note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
error: relaxed bounds are not permitted in supertrait bounds
--> $DIR/relaxed-bounds-invalid-places.rs:26:11
--> $DIR/relaxed-bounds-invalid-places.rs:25:11
|
LL | trait Tr: ?Sized {}
| ^^^^^^
@ -47,19 +47,19 @@ LL | trait Tr: ?Sized {}
= note: traits are `?Sized` by default
error: relaxed bounds are not permitted in trait object types
--> $DIR/relaxed-bounds-invalid-places.rs:30:20
--> $DIR/relaxed-bounds-invalid-places.rs:29:20
|
LL | type O1 = dyn Tr + ?Sized;
| ^^^^^^
error: relaxed bounds are not permitted in trait object types
--> $DIR/relaxed-bounds-invalid-places.rs:31:15
--> $DIR/relaxed-bounds-invalid-places.rs:30:15
|
LL | type O2 = dyn ?Sized + ?Sized + Tr;
| ^^^^^^
error: relaxed bounds are not permitted in trait object types
--> $DIR/relaxed-bounds-invalid-places.rs:31:24
--> $DIR/relaxed-bounds-invalid-places.rs:30:24
|
LL | type O2 = dyn ?Sized + ?Sized + Tr;
| ^^^^^^
@ -70,21 +70,11 @@ error: bound modifier `?` can only be applied to `Sized`
LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
| ^^^^^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/relaxed-bounds-invalid-places.rs:18:33
|
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
error: bound modifier `?` can only be applied to `Sized`
--> $DIR/relaxed-bounds-invalid-places.rs:18:33
|
LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
| ^^^^^^^^^^^^^^^
error: aborting due to 12 previous errors
error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0203`.