Auto merge of #145240 - Zalathar:rollup-7r97lia, r=Zalathar
Rollup of 5 pull requests Successful merges: - rust-lang/rust#135331 (Reject relaxed bounds inside associated type bounds (ATB)) - rust-lang/rust#144156 (Check coroutine upvars in dtorck constraint) - rust-lang/rust#145091 (`NllRegionVariableOrigin` remove `from_forall`) - rust-lang/rust#145194 (Ignore coroutine witness type region args in auto trait confirmation) - rust-lang/rust#145225 (Fix macro infinite recursion test to not trigger warning about semicolon in expr) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
577166503a
22 changed files with 239 additions and 82 deletions
|
|
@ -296,6 +296,7 @@ enum RelaxedBoundPolicy<'a> {
|
|||
enum RelaxedBoundForbiddenReason {
|
||||
TraitObjectTy,
|
||||
SuperTrait,
|
||||
AssocTyBounds,
|
||||
LateBoundVarsInScope,
|
||||
}
|
||||
|
||||
|
|
@ -1109,9 +1110,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
|
||||
hir::AssocItemConstraintKind::Equality { term: err_ty.into() }
|
||||
} else {
|
||||
// FIXME(#135229): These should be forbidden!
|
||||
let bounds =
|
||||
self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx);
|
||||
let bounds = self.lower_param_bounds(
|
||||
bounds,
|
||||
RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::AssocTyBounds),
|
||||
itctx,
|
||||
);
|
||||
hir::AssocItemConstraintKind::Bound { bounds }
|
||||
}
|
||||
}
|
||||
|
|
@ -2124,7 +2127,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
diag.emit();
|
||||
return;
|
||||
}
|
||||
RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
|
||||
RelaxedBoundForbiddenReason::AssocTyBounds
|
||||
| RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ fn region_definitions<'tcx>(
|
|||
for info in var_infos.iter() {
|
||||
let origin = match info.origin {
|
||||
RegionVariableOrigin::Nll(origin) => origin,
|
||||
_ => NllRegionVariableOrigin::Existential { from_forall: false, name: None },
|
||||
_ => NllRegionVariableOrigin::Existential { name: None },
|
||||
};
|
||||
|
||||
let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
|
||||
|
|
|
|||
|
|
@ -1939,10 +1939,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
//
|
||||
// and here we prefer to blame the source (the y = x statement).
|
||||
let blame_source = match from_region_origin {
|
||||
NllRegionVariableOrigin::FreeRegion
|
||||
| NllRegionVariableOrigin::Existential { from_forall: false, name: _ } => true,
|
||||
NllRegionVariableOrigin::Placeholder(_)
|
||||
| NllRegionVariableOrigin::Existential { from_forall: true, name: _ } => false,
|
||||
NllRegionVariableOrigin::FreeRegion => true,
|
||||
NllRegionVariableOrigin::Placeholder(_) => false,
|
||||
// `'existential: 'whatever` never results in a region error by itself.
|
||||
// We may always infer it to `'static` afterall. This means while an error
|
||||
// path may go through an existential, these existentials are never the
|
||||
// `from_region`.
|
||||
NllRegionVariableOrigin::Existential { name: _ } => {
|
||||
unreachable!("existentials can outlive everything")
|
||||
}
|
||||
};
|
||||
|
||||
// To pick a constraint to blame, we organize constraints by how interesting we expect them
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
|
|||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
F: Fn() -> RegionCtxt,
|
||||
{
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall: false, name: None };
|
||||
let origin = NllRegionVariableOrigin::Existential { name: None };
|
||||
fold_regions(self.infcx.tcx, value, |_region, _depth| {
|
||||
self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
*ex_reg_var
|
||||
} else {
|
||||
let ex_reg_var =
|
||||
self.next_existential_region_var(true, br.kind.get_name(infcx.infcx.tcx));
|
||||
self.next_existential_region_var(br.kind.get_name(infcx.infcx.tcx));
|
||||
debug!(?ex_reg_var);
|
||||
reg_map.insert(br, ex_reg_var);
|
||||
|
||||
|
|
@ -244,17 +244,9 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn next_existential_region_var(
|
||||
&mut self,
|
||||
from_forall: bool,
|
||||
name: Option<Symbol>,
|
||||
) -> ty::Region<'tcx> {
|
||||
let origin = NllRegionVariableOrigin::Existential { name, from_forall };
|
||||
|
||||
let reg_var =
|
||||
self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name));
|
||||
|
||||
reg_var
|
||||
fn next_existential_region_var(&mut self, name: Option<Symbol>) -> ty::Region<'tcx> {
|
||||
let origin = NllRegionVariableOrigin::Existential { name };
|
||||
self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name))
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
|
|
|
|||
|
|
@ -199,12 +199,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// However, this can easily get out of sync! Ideally, we would perform this step
|
||||
// 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 e.g., trait object tys or
|
||||
// supertrait bounds!
|
||||
// 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.
|
||||
// FIXME(associated_type_bounds): We don't call this for them. However, AST
|
||||
// lowering should reject them outright (#135229).
|
||||
// AST lowering should reject them outright.
|
||||
let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates);
|
||||
self.check_and_report_invalid_relaxed_bounds(bounds);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -485,17 +485,6 @@ pub enum NllRegionVariableOrigin {
|
|||
|
||||
Existential {
|
||||
name: Option<Symbol>,
|
||||
/// If this is true, then this variable was created to represent a lifetime
|
||||
/// bound in a `for` binder. For example, it might have been created to
|
||||
/// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`.
|
||||
/// Such variables are created when we are trying to figure out if there
|
||||
/// is any valid instantiation of `'a` that could fit into some scenario.
|
||||
///
|
||||
/// This is used to inform error reporting: in the case that we are trying to
|
||||
/// determine whether there is any valid instantiation of a `'a` variable that meets
|
||||
/// some constraint C, we want to blame the "source" of that `for` type,
|
||||
/// rather than blaming the source of the constraint C.
|
||||
from_forall: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -319,39 +319,65 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
|
|||
}
|
||||
|
||||
ty::Coroutine(def_id, args) => {
|
||||
// rust-lang/rust#49918: types can be constructed, stored
|
||||
// in the interior, and sit idle when coroutine yields
|
||||
// (and is subsequently dropped).
|
||||
// rust-lang/rust#49918: Locals can be stored across await points in the coroutine,
|
||||
// called interior/witness types. Since we do not compute these witnesses until after
|
||||
// building MIR, we consider all coroutines to unconditionally require a drop during
|
||||
// MIR building. However, considering the coroutine to unconditionally require a drop
|
||||
// here may unnecessarily require its upvars' regions to be live when they don't need
|
||||
// to be, leading to borrowck errors: <https://github.com/rust-lang/rust/issues/116242>.
|
||||
//
|
||||
// It would be nice to descend into interior of a
|
||||
// coroutine to determine what effects dropping it might
|
||||
// have (by looking at any drop effects associated with
|
||||
// its interior).
|
||||
// Here, we implement a more precise approximation for the coroutine's dtorck constraint
|
||||
// by considering whether any of the interior types needs drop. Note that this is still
|
||||
// an approximation because the coroutine interior has its regions erased, so we must add
|
||||
// *all* of the upvars to live types set if we find that *any* interior type needs drop.
|
||||
// This is because any of the regions captured in the upvars may be stored in the interior,
|
||||
// which then has its regions replaced by a binder (conceptually erasing the regions),
|
||||
// so there's no way to enforce that the precise region in the interior type is live
|
||||
// since we've lost that information by this point.
|
||||
//
|
||||
// However, the interior's representation uses things like
|
||||
// CoroutineWitness that explicitly assume they are not
|
||||
// traversed in such a manner. So instead, we will
|
||||
// simplify things for now by treating all coroutines as
|
||||
// if they were like trait objects, where its upvars must
|
||||
// all be alive for the coroutine's (potential)
|
||||
// destructor.
|
||||
// Note also that this check requires that the coroutine's upvars are use-live, since
|
||||
// a region from a type that does not have a destructor that was captured in an upvar
|
||||
// may flow into an interior type with a destructor. This is stronger than requiring
|
||||
// the upvars are drop-live.
|
||||
//
|
||||
// In particular, skipping over `_interior` is safe
|
||||
// because any side-effects from dropping `_interior` can
|
||||
// only take place through references with lifetimes
|
||||
// derived from lifetimes attached to the upvars and resume
|
||||
// argument, and we *do* incorporate those here.
|
||||
// For example, if we capture two upvar references `&'1 (), &'2 ()` and have some type
|
||||
// in the interior, `for<'r> { NeedsDrop<'r> }`, we have no way to tell whether the
|
||||
// region `'r` came from the `'1` or `'2` region, so we require both are live. This
|
||||
// could even be unnecessary if `'r` was actually a `'static` region or some region
|
||||
// local to the coroutine! That's why it's an approximation.
|
||||
let args = args.as_coroutine();
|
||||
|
||||
// While we conservatively assume that all coroutines require drop
|
||||
// to avoid query cycles during MIR building, we can check the actual
|
||||
// witness during borrowck to avoid unnecessary liveness constraints.
|
||||
// Note that we don't care about whether the resume type has any drops since this is
|
||||
// redundant; there is no storage for the resume type, so if it is actually stored
|
||||
// in the interior, we'll already detect the need for a drop by checking the interior.
|
||||
let typing_env = tcx.erase_regions(typing_env);
|
||||
if tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
|
||||
let needs_drop = tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
|
||||
witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env))
|
||||
}) {
|
||||
});
|
||||
if needs_drop {
|
||||
// Pushing types directly to `constraints.outlives` is equivalent
|
||||
// to requiring them to be use-live, since if we were instead to
|
||||
// recurse on them like we do below, we only end up collecting the
|
||||
// types that are relevant for drop-liveness.
|
||||
constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
|
||||
constraints.outlives.push(args.resume_ty().into());
|
||||
} else {
|
||||
// Even if a witness type doesn't need a drop, we still require that
|
||||
// the upvars are drop-live. This is only needed if we aren't already
|
||||
// counting *all* of the upvars as use-live above, since use-liveness
|
||||
// is a *stronger requirement* than drop-liveness. Recursing here
|
||||
// unconditionally would just be collecting duplicated types for no
|
||||
// reason.
|
||||
for ty in args.upvar_tys() {
|
||||
dtorck_constraint_for_ty_inner(
|
||||
tcx,
|
||||
typing_env,
|
||||
span,
|
||||
depth + 1,
|
||||
ty,
|
||||
constraints,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2333,10 +2333,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
|
||||
ty::Coroutine(def_id, args) => {
|
||||
let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
|
||||
let tcx = self.tcx();
|
||||
let witness = Ty::new_coroutine_witness(
|
||||
self.tcx(),
|
||||
tcx,
|
||||
def_id,
|
||||
self.tcx().mk_args(args.as_coroutine().parent_args()),
|
||||
ty::GenericArgs::for_item(tcx, def_id, |def, _| match def.kind {
|
||||
// HACK: Coroutine witnesse types are lifetime erased, so they
|
||||
// never reference any lifetime args from the coroutine. We erase
|
||||
// the regions here since we may get into situations where a
|
||||
// coroutine is recursively contained within itself, leading to
|
||||
// witness types that differ by region args. This means that
|
||||
// cycle detection in fulfillment will not kick in, which leads
|
||||
// to unnecessary overflows in async code. See the issue:
|
||||
// <https://github.com/rust-lang/rust/issues/145151>.
|
||||
ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
|
||||
ty::GenericParamDefKind::Type { .. }
|
||||
| ty::GenericParamDefKind::Const { .. } => args[def.index as usize],
|
||||
}),
|
||||
);
|
||||
ty::Binder::dummy(AutoImplConstituents {
|
||||
types: [ty].into_iter().chain(iter::once(witness)).collect(),
|
||||
|
|
|
|||
18
tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr
Normal file
18
tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
error[E0597]: `y` does not live long enough
|
||||
--> $DIR/drop-live-upvar-2.rs:31:26
|
||||
|
|
||||
LL | let y = ();
|
||||
| - binding `y` declared here
|
||||
LL | drop_me = Droppy(&y);
|
||||
| ^^ borrowed value does not live long enough
|
||||
...
|
||||
LL | }
|
||||
| - `y` dropped here while still borrowed
|
||||
LL | }
|
||||
| - borrow might be used here, when `fut` is dropped and runs the destructor for coroutine
|
||||
|
|
||||
= note: values in a scope are dropped in the opposite order they are defined
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
||||
37
tests/ui/async-await/drop-live-upvar-2.rs
Normal file
37
tests/ui/async-await/drop-live-upvar-2.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
//@ revisions: may_dangle may_not_dangle
|
||||
//@[may_dangle] check-pass
|
||||
//@ edition: 2018
|
||||
|
||||
// Ensure that if a coroutine's interior has no drop types then we don't require the upvars to
|
||||
// be *use-live*, but instead require them to be *drop-live*. In this case, `Droppy<&'?0 ()>`
|
||||
// does not require that `'?0` is live for drops since the parameter is `#[may_dangle]` in
|
||||
// the may_dangle revision, but not in the may_not_dangle revision.
|
||||
|
||||
#![feature(dropck_eyepatch)]
|
||||
|
||||
struct Droppy<T>(T);
|
||||
|
||||
#[cfg(may_dangle)]
|
||||
unsafe impl<#[may_dangle] T> Drop for Droppy<T> {
|
||||
fn drop(&mut self) {
|
||||
// This does not use `T` of course.
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(may_not_dangle)]
|
||||
impl<T> Drop for Droppy<T> {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let drop_me;
|
||||
let fut;
|
||||
{
|
||||
let y = ();
|
||||
drop_me = Droppy(&y);
|
||||
//[may_not_dangle]~^ ERROR `y` does not live long enough
|
||||
fut = async {
|
||||
std::mem::drop(drop_me);
|
||||
};
|
||||
}
|
||||
}
|
||||
23
tests/ui/async-await/drop-live-upvar.rs
Normal file
23
tests/ui/async-await/drop-live-upvar.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//@ edition: 2018
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/144155>.
|
||||
|
||||
struct NeedsDrop<'a>(&'a Vec<i32>);
|
||||
|
||||
async fn await_point() {}
|
||||
|
||||
impl Drop for NeedsDrop<'_> {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
let v = vec![1, 2, 3];
|
||||
let x = NeedsDrop(&v);
|
||||
let c = async {
|
||||
std::future::ready(()).await;
|
||||
drop(x);
|
||||
};
|
||||
drop(v);
|
||||
//~^ ERROR cannot move out of `v` because it is borrowed
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
22
tests/ui/async-await/drop-live-upvar.stderr
Normal file
22
tests/ui/async-await/drop-live-upvar.stderr
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
error[E0505]: cannot move out of `v` because it is borrowed
|
||||
--> $DIR/drop-live-upvar.rs:19:10
|
||||
|
|
||||
LL | let v = vec![1, 2, 3];
|
||||
| - binding `v` declared here
|
||||
LL | let x = NeedsDrop(&v);
|
||||
| -- borrow of `v` occurs here
|
||||
...
|
||||
LL | drop(v);
|
||||
| ^ move out of `v` occurs here
|
||||
LL |
|
||||
LL | }
|
||||
| - borrow might be used here, when `c` is dropped and runs the destructor for coroutine
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | let x = NeedsDrop(&v.clone());
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0505`.
|
||||
14
tests/ui/async-await/recursive-async-auto-trait-overflow.rs
Normal file
14
tests/ui/async-await/recursive-async-auto-trait-overflow.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Regression test for <https://github.com/rust-lang/rust/issues/145151>.
|
||||
|
||||
//@ edition: 2024
|
||||
//@ check-pass
|
||||
|
||||
async fn process<'a>() {
|
||||
Box::pin(process()).await;
|
||||
}
|
||||
|
||||
fn require_send(_: impl Send) {}
|
||||
|
||||
fn main() {
|
||||
require_send(process());
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
fn main() {
|
||||
macro_rules! stack {
|
||||
($overflow:expr) => {
|
||||
print!(stack!($overflow));
|
||||
print!(stack!($overflow))
|
||||
//~^ ERROR recursion limit reached while expanding
|
||||
//~| ERROR format argument must be a string literal
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ LL | stack!("overflow");
|
|||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expanding `stack! { "overflow" }`
|
||||
= note: to `print! (stack! ("overflow"));`
|
||||
= note: to `print! (stack! ("overflow"))`
|
||||
= note: expanding `print! { stack! ("overflow") }`
|
||||
= note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))); }`
|
||||
= note: expanding `stack! { "overflow" }`
|
||||
= note: to `print! (stack! ("overflow"));`
|
||||
= note: to `print! (stack! ("overflow"))`
|
||||
= note: expanding `print! { stack! ("overflow") }`
|
||||
= note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))); }`
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ LL | stack!("overflow");
|
|||
= note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might be missing a string literal to format with
|
||||
|
|
||||
LL | print!("{}", stack!($overflow));
|
||||
LL | print!("{}", stack!($overflow))
|
||||
| +++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
fn main() {
|
||||
macro_rules! stack {
|
||||
($overflow:expr) => {
|
||||
println!(stack!($overflow));
|
||||
println!(stack!($overflow))
|
||||
//~^ ERROR recursion limit reached while expanding
|
||||
//~| ERROR format argument must be a string literal
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ LL | stack!("overflow");
|
|||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expanding `stack! { "overflow" }`
|
||||
= note: to `println! (stack! ("overflow"));`
|
||||
= note: to `println! (stack! ("overflow"))`
|
||||
= note: expanding `println! { stack! ("overflow") }`
|
||||
= note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))); }`
|
||||
= note: expanding `stack! { "overflow" }`
|
||||
= note: to `println! (stack! ("overflow"));`
|
||||
= note: to `println! (stack! ("overflow"))`
|
||||
= note: expanding `println! { stack! ("overflow") }`
|
||||
= note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))); }`
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ LL | stack!("overflow");
|
|||
= note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might be missing a string literal to format with
|
||||
|
|
||||
LL | println!("{}", stack!($overflow));
|
||||
LL | println!("{}", stack!($overflow))
|
||||
| +++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// 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 and trait object types where we currently don't perform
|
||||
// this check.
|
||||
// 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 {}
|
||||
|
|
@ -13,11 +13,15 @@ trait Trait4 where Self: Trait1 {}
|
|||
|
||||
// FIXME: `?Trait2` should be rejected, `Trait2` isn't marked `#[lang = "default_traitN"]`.
|
||||
fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {}
|
||||
|
||||
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`
|
||||
|
||||
// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`.
|
||||
fn baz<T>() where T: Iterator<Item: ?Trait1> {}
|
||||
|
||||
struct S;
|
||||
impl !Trait2 for S {}
|
||||
impl Trait1 for S {}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
error: bound modifier `?` can only be applied to default traits like `Sized`
|
||||
--> $DIR/more_maybe_bounds.rs:16:20
|
||||
--> $DIR/more_maybe_bounds.rs:17: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:16:30
|
||||
--> $DIR/more_maybe_bounds.rs:17: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:16:40
|
||||
--> $DIR/more_maybe_bounds.rs:17:40
|
||||
|
|
||||
LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
|
||||
| ^^^^^^^
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ impl<T> S1<T> {
|
|||
fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here
|
||||
}
|
||||
|
||||
// Test associated type bounds (ATB).
|
||||
// issue: <https://github.com/rust-lang/rust/issues/135229>
|
||||
struct S6<T>(T) where T: Iterator<Item: ?Sized>; //~ ERROR this relaxed bound is not permitted here
|
||||
|
||||
trait Tr: ?Sized {} //~ ERROR relaxed bounds are not permitted in supertrait bounds
|
||||
|
||||
// Test that relaxed `Sized` bounds are rejected in trait object types:
|
||||
|
|
|
|||
|
|
@ -38,8 +38,16 @@ LL | fn f() where T: ?Sized {}
|
|||
|
|
||||
= 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:27:41
|
||||
|
|
||||
LL | struct S6<T>(T) where T: Iterator<Item: ?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:25:11
|
||||
--> $DIR/relaxed-bounds-invalid-places.rs:29:11
|
||||
|
|
||||
LL | trait Tr: ?Sized {}
|
||||
| ^^^^^^
|
||||
|
|
@ -47,19 +55,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:29:20
|
||||
--> $DIR/relaxed-bounds-invalid-places.rs:33:20
|
||||
|
|
||||
LL | type O1 = dyn Tr + ?Sized;
|
||||
| ^^^^^^
|
||||
|
||||
error: relaxed bounds are not permitted in trait object types
|
||||
--> $DIR/relaxed-bounds-invalid-places.rs:30:15
|
||||
--> $DIR/relaxed-bounds-invalid-places.rs:34:15
|
||||
|
|
||||
LL | type O2 = dyn ?Sized + ?Sized + Tr;
|
||||
| ^^^^^^
|
||||
|
||||
error: relaxed bounds are not permitted in trait object types
|
||||
--> $DIR/relaxed-bounds-invalid-places.rs:30:24
|
||||
--> $DIR/relaxed-bounds-invalid-places.rs:34:24
|
||||
|
|
||||
LL | type O2 = dyn ?Sized + ?Sized + Tr;
|
||||
| ^^^^^^
|
||||
|
|
@ -76,5 +84,5 @@ error: bound modifier `?` can only be applied to `Sized`
|
|||
LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue