Reject relaxed bounds inside trait alias bounds

This commit is contained in:
León Orell Valerian Liehr 2025-10-16 16:14:39 +02:00
parent 690a8a6dfd
commit ce68cd3762
No known key found for this signature in database
GPG key ID: D17A07215F68E713
18 changed files with 131 additions and 116 deletions

View file

@ -426,7 +426,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|this| {
this.lower_param_bounds(
bounds,
RelaxedBoundPolicy::Allowed,
RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::TraitAlias),
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
)
},

View file

@ -296,6 +296,7 @@ enum RelaxedBoundPolicy<'a> {
enum RelaxedBoundForbiddenReason {
TraitObjectTy,
SuperTrait,
TraitAlias,
AssocTyBounds,
LateBoundVarsInScope,
}
@ -2132,6 +2133,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
gate("supertrait bounds", "traits");
return;
}
RelaxedBoundForbiddenReason::TraitAlias => {
gate("trait alias bounds", "trait aliases");
return;
}
RelaxedBoundForbiddenReason::AssocTyBounds
| RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
};

View file

@ -202,9 +202,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// where we are guaranteed to catch *all* bounds like in
// `Self::lower_poly_trait_ref`. List of concrete issues:
// FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait
// bounds or associated type bounds (ATB)!
// FIXME(trait_alias, #143122): We don't call it for the RHS. Arguably however,
// AST lowering should reject them outright.
// 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);
}

View file

@ -1,5 +1,3 @@
#![feature(trait_alias)]
pub struct Foo;
pub trait Bar {

View file

@ -1,5 +1,5 @@
error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block
--> $DIR/doc-alias-assoc-const.rs:10:11
--> $DIR/doc-alias-assoc-const.rs:8:11
|
LL | #[doc(alias = "CONST_BAZ")]
| ^^^^^^^^^^^^^^^^^^^

View file

@ -1,9 +0,0 @@
//@ check-pass
//@ compile-flags: --crate-type=lib
#![feature(trait_alias)]
// Checks that `?Sized` in a trait alias doesn't trigger an ICE.
use std::ops::{Index, IndexMut};
pub trait SlicePrereq<T> = ?Sized + IndexMut<usize, Output = <[T] as Index<usize>>::Output>;

View file

@ -0,0 +1,20 @@
// Test that we reject trait object types that effectively (i.e., after trait alias expansion)
// don't contain any bounds.
#![feature(trait_alias)]
trait Empty0 =;
// Nest a couple of levels deep:
trait Empty1 = Empty0;
trait Empty2 = Empty1;
// Straight list expansion:
type Type0 = dyn Empty2; //~ ERROR at least one trait is required for an object type [E0224]
// Twice:
trait Empty3 = Empty2 + Empty2;
type Type1 = dyn Empty3; //~ ERROR at least one trait is required for an object type [E0224]
fn main() {}

View file

@ -0,0 +1,21 @@
error[E0224]: at least one trait is required for an object type
--> $DIR/effectively-empty-trait-object-type.rs:13:14
|
LL | trait Empty2 = Empty1;
| ------------ this alias does not contain a trait
...
LL | type Type0 = dyn Empty2;
| ^^^^^^^^^^
error[E0224]: at least one trait is required for an object type
--> $DIR/effectively-empty-trait-object-type.rs:18:14
|
LL | trait Empty3 = Empty2 + Empty2;
| ------------ this alias does not contain a trait
LL |
LL | type Type1 = dyn Empty3;
| ^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0224`.

View file

@ -0,0 +1,17 @@
// Ensure that there are straightforward ways to define "empty" / "trivial" / "unit" trait aliases
// which don't impose any constraints when used as a bound (since they expand to nothing).
//@ check-pass
#![feature(trait_alias)]
trait Empty =;
trait Trivial = where;
trait Unit = where Self:;
fn check<T: ?Sized + Empty>() {}
fn main() {
check::<()>(); // OK. "`(): Empty`" is trivially satisfied
check::<str>(); // OK. `Empty` is truly empty and isn't implicitly bounded by `Sized`.
}

View file

@ -1,29 +0,0 @@
//@ build-pass (FIXME(62277): could be check-pass?)
// Test that `dyn ... + ?Sized + ...` resulting from the expansion of trait aliases is okay.
#![feature(trait_alias)]
trait Foo {}
trait S = ?Sized;
// Nest a couple of levels deep:
trait _0 = S;
trait _1 = _0;
// Straight list expansion:
type _T0 = dyn _1 + Foo;
// In second position:
type _T1 = dyn Foo + _1;
// ... and with an auto trait:
type _T2 = dyn Foo + Send + _1;
// Twice:
trait _2 = _1 + _1;
type _T3 = dyn _2 + Foo;
fn main() {}

View file

@ -1,22 +0,0 @@
// Test that `dyn ?Sized` (i.e., a trait object with only a maybe buond) is not allowed, when just
// `?Sized` results from trait alias expansion.
#![feature(trait_alias)]
trait S = ?Sized;
// Nest a couple of levels deep:
trait _0 = S;
trait _1 = _0;
// Straight list expansion:
type _T0 = dyn _1;
//~^ ERROR at least one trait is required for an object type [E0224]
// Twice:
trait _2 = _1 + _1;
type _T1 = dyn _2;
//~^ ERROR at least one trait is required for an object type [E0224]
fn main() {}

View file

@ -1,21 +0,0 @@
error[E0224]: at least one trait is required for an object type
--> $DIR/only-maybe-bound.rs:13:12
|
LL | trait _1 = _0;
| -------- this alias does not contain a trait
...
LL | type _T0 = dyn _1;
| ^^^^^^
error[E0224]: at least one trait is required for an object type
--> $DIR/only-maybe-bound.rs:19:12
|
LL | trait _2 = _1 + _1;
| -------- this alias does not contain a trait
LL |
LL | type _T1 = dyn _2;
| ^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0224`.

View file

@ -0,0 +1,19 @@
#![feature(trait_alias)]
// Ensure that relaxed bounds are not permitted in the `Self` bounds of trait aliases because trait
// aliases (like traits) aren't implicitly bounded by `Sized` so there's nothing to relax.
trait Alias0 = ?Sized; //~ ERROR relaxed bounds are not permitted in trait alias bounds
trait Alias1 = where Self: ?Sized; //~ ERROR this relaxed bound is not permitted here
trait Alias2<T: ?Sized> =; // OK
trait Alias3<T> = where T: ?Sized; // OK
// Make sure that we don't permit "relaxing" trait aliases since we don't want to expand trait
// aliases during sized elaboration for simplicity as we'd need to handle relaxing arbitrary bounds
// (e.g., ones with modifiers, outlives-bounds, …) and where-clauses.
trait SizedAlias = Sized;
fn take<T: ?SizedAlias>() {} //~ ERROR bound modifier `?` can only be applied to `Sized`
fn main() {}

View file

@ -0,0 +1,24 @@
error: relaxed bounds are not permitted in trait alias bounds
--> $DIR/relaxed-bounds.rs:6:16
|
LL | trait Alias0 = ?Sized;
| ^^^^^^
|
= note: trait aliases are not implicitly bounded by `Sized`, so there is nothing to relax
error: this relaxed bound is not permitted here
--> $DIR/relaxed-bounds.rs:7:28
|
LL | trait Alias1 = where Self: ?Sized;
| ^^^^^^
|
= 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 `Sized`
--> $DIR/relaxed-bounds.rs:17:12
|
LL | fn take<T: ?SizedAlias>() {}
| ^^^^^^^^^^^
error: aborting due to 3 previous errors

View file

@ -1,7 +0,0 @@
// Test that `dyn ?Sized` (i.e., a trait object with only a maybe buond) is not allowed.
type _0 = dyn ?Sized;
//~^ ERROR at least one trait is required for an object type [E0224]
//~| ERROR relaxed bounds are not permitted in trait object types
fn main() {}

View file

@ -1,17 +0,0 @@
error: relaxed bounds are not permitted in trait object types
--> $DIR/only-maybe-bound.rs:3:15
|
LL | type _0 = dyn ?Sized;
| ^^^^^^
|
= note: trait object types are not implicitly bounded by `Sized`, so there is nothing to relax
error[E0224]: at least one trait is required for an object type
--> $DIR/only-maybe-bound.rs:3:11
|
LL | type _0 = dyn ?Sized;
| ^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0224`.

View file

@ -30,6 +30,9 @@ trait Tr: ?Sized {} //~ ERROR relaxed bounds are not permitted in supertrait bou
// Test that relaxed `Sized` bounds are rejected in trait object types:
type O0 = dyn ?Sized;
//~^ ERROR relaxed bounds are not permitted in trait object types
//~| ERROR at least one trait is required for an object type [E0224]
type O1 = dyn Tr + ?Sized; //~ ERROR relaxed bounds are not permitted in trait object types
type O2 = dyn ?Sized + ?Sized + Tr;
//~^ ERROR relaxed bounds are not permitted in trait object types

View file

@ -55,7 +55,15 @@ LL | trait Tr: ?Sized {}
= note: traits are not implicitly bounded by `Sized`, so there is nothing to relax
error: relaxed bounds are not permitted in trait object types
--> $DIR/relaxed-bounds-invalid-places.rs:33:20
--> $DIR/relaxed-bounds-invalid-places.rs:33:15
|
LL | type O0 = dyn ?Sized;
| ^^^^^^
|
= note: trait object types are not implicitly bounded by `Sized`, so there is nothing to relax
error: relaxed bounds are not permitted in trait object types
--> $DIR/relaxed-bounds-invalid-places.rs:36:20
|
LL | type O1 = dyn Tr + ?Sized;
| ^^^^^^
@ -63,7 +71,7 @@ LL | type O1 = dyn Tr + ?Sized;
= note: trait object types are not implicitly bounded by `Sized`, so there is nothing to relax
error: relaxed bounds are not permitted in trait object types
--> $DIR/relaxed-bounds-invalid-places.rs:34:15
--> $DIR/relaxed-bounds-invalid-places.rs:37:15
|
LL | type O2 = dyn ?Sized + ?Sized + Tr;
| ^^^^^^
@ -71,7 +79,7 @@ LL | type O2 = dyn ?Sized + ?Sized + Tr;
= note: trait object types are not implicitly bounded by `Sized`, so there is nothing to relax
error: relaxed bounds are not permitted in trait object types
--> $DIR/relaxed-bounds-invalid-places.rs:34:24
--> $DIR/relaxed-bounds-invalid-places.rs:37:24
|
LL | type O2 = dyn ?Sized + ?Sized + Tr;
| ^^^^^^
@ -90,5 +98,12 @@ error: bound modifier `?` can only be applied to `Sized`
LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
| ^^^^^^^^^^^^^^^
error: aborting due to 12 previous errors
error[E0224]: at least one trait is required for an object type
--> $DIR/relaxed-bounds-invalid-places.rs:33:11
|
LL | type O0 = dyn ?Sized;
| ^^^^^^^^^^
error: aborting due to 14 previous errors
For more information about this error, try `rustc --explain E0224`.