Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit warning when bound is trivially false #100090

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
90 changes: 67 additions & 23 deletions compiler/rustc_typeck/src/check/wfcheck.rs
Expand Up @@ -10,7 +10,7 @@ use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs};
use rustc_infer::infer::outlives::obligations::TypeOutlives;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Normalized;
use rustc_infer::traits::{Normalized, TraitEngine, TraitEngineExt as _};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
Expand All @@ -27,7 +27,8 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _
use rustc_trait_selection::traits::query::normalize::AtExt;
use rustc_trait_selection::traits::query::NoSolution;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
self, FulfillmentContext, ObligationCause, ObligationCauseCode, ObligationCtxt,
SelectionContext, WellFormedLoc,
};

use std::cell::LazyCell;
Expand Down Expand Up @@ -1817,7 +1818,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
/// aren't true.
fn check_false_global_bounds(&mut self) {
let tcx = self.ocx.infcx.tcx;
let tcx = self.infcx.tcx;
let mut span = self.span;
let empty_env = ty::ParamEnv::empty();

Expand All @@ -1833,33 +1834,76 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
if let ty::PredicateKind::WellFormed(..) = obligation.predicate.kind().skip_binder() {
continue;
}
let pred = obligation.predicate;
// Match the existing behavior.
if pred.is_global() && !pred.has_late_bound_regions() {
let pred = self.normalize(span, None, pred);
let hir_node = tcx.hir().find(self.body_id);

// only use the span of the predicate clause (#90869)
let pred = obligation.predicate;

if let Some(hir::Generics { predicates, .. }) =
hir_node.and_then(|node| node.generics())
{
let obligation_span = obligation.cause.span();

span = predicates
.iter()
// There seems to be no better way to find out which predicate we are in
.find(|pred| pred.span().contains(obligation_span))
.map(|pred| pred.span())
.unwrap_or(obligation_span);
}
// only use the span of the predicate clause (#90869)
let hir_node = tcx.hir().find(self.body_id);
if let Some(hir::Generics { predicates, .. }) =
hir_node.and_then(|node| node.generics())
{
let obligation_span = obligation.cause.span();
span = predicates
.iter()
// There seems to be no better way to find out which predicate we are in
.find(|pred| pred.span().contains(obligation_span))
.map(|pred| pred.span())
.unwrap_or(obligation_span);
}

// Match the existing behavior.
if pred.is_global() && !pred.has_late_bound_regions() {
let normalized_pred = self.normalize(span, None, pred);
let obligation = traits::Obligation::new(
traits::ObligationCause::new(span, self.body_id, traits::TrivialBound),
empty_env,
pred,
normalized_pred,
);
self.ocx.register_obligation(obligation);
self.register_obligation(obligation);
} else {
self.infcx.probe(|_| {
// Manually normalize because `wfcx.normalize` may report errors
let Normalized { value: normalized_pred, obligations } = traits::normalize(
&mut SelectionContext::new(self.infcx),
self.param_env,
ObligationCause::dummy(),
pred,
);
if normalized_pred.is_global() {
let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
fulfill_cx.register_predicate_obligations(self.infcx, obligations);
fulfill_cx.register_predicate_obligation(
self.infcx,
traits::Obligation::new(
traits::ObligationCause::new(
span,
self.body_id,
traits::TrivialBound,
),
empty_env,
normalized_pred,
),
);
if !fulfill_cx.select_all_or_error(self.infcx).is_empty() {
let mut diag = self.tcx()
.sess
.struct_span_warn(
span,
format!("the where-clause bound `{pred}` is impossible to satisfy"),
);
diag.span_label(
self.span,
"this item cannot be referenced without causing an error",
);
if self.infcx.tcx.sess.opts.unstable_features.is_nightly_build() {
diag.help(
"add `#![feature(trivial_bounds)]` to the crate attributes to allow it",
);
}
diag.emit();
}
}
});
}
}
}
Expand Down
@@ -1,8 +1,32 @@
warning: the where-clause bound `for<'a> <Parameterized<'a> as Foo>::Item == &'a i32` is impossible to satisfy
--> $DIR/bound-lifetime-in-binding-only.rs:67:19
|
LL | fn ok3<T>() where for<'a> Parameterized<'a>: Foo<Item=&'a i32> {
| _- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | |
LL | |
LL | | }
| |_- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

warning: the where-clause bound `for<'a> Parameterized<'a>: Foo` is impossible to satisfy
--> $DIR/bound-lifetime-in-binding-only.rs:67:19
|
LL | fn ok3<T>() where for<'a> Parameterized<'a>: Foo<Item=&'a i32> {
| _- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | |
LL | |
LL | | }
| |_- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

error: fatal error triggered by #[rustc_error]
--> $DIR/bound-lifetime-in-binding-only.rs:71:1
--> $DIR/bound-lifetime-in-binding-only.rs:73:1
|
LL | fn main() { }
| ^^^^^^^^^

error: aborting due to previous error
error: aborting due to previous error; 2 warnings emitted

Expand Up @@ -65,6 +65,8 @@ fn ok2<T: for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>>() {

#[cfg(ok)]
fn ok3<T>() where for<'a> Parameterized<'a>: Foo<Item=&'a i32> {
//[ok]~^ WARNING the where-clause bound
//[ok]~| WARNING the where-clause bound
}

#[rustc_error]
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/associated-types/issue-59324.rs
Expand Up @@ -12,7 +12,7 @@ pub trait ThriftService<Bug: NotFoo>:
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
//~| ERROR the trait bound `Bug: Foo` is not satisfied
Service<AssocType = <Bug as Foo>::OnlyFoo>
{
{
fn get_service(
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
&self,
Expand Down
1 change: 1 addition & 0 deletions src/test/ui/associated-types/issue-69398.rs
Expand Up @@ -12,6 +12,7 @@ pub trait Broken {
impl<T> Broken for T {
type Assoc = ();
fn broken(&self) where Self::Assoc: Foo {
//~^ WARNING the where-clause bound
let _x: <Self::Assoc as Foo>::Bar;
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/associated-types/issue-69398.stderr
@@ -0,0 +1,14 @@
warning: the where-clause bound `<T as Broken>::Assoc: Foo` is impossible to satisfy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit unfortunate that the bound we say is not the bound that's written.

--> $DIR/issue-69398.rs:14:28
|
LL | fn broken(&self) where Self::Assoc: Foo {
| _____- ^^^^^^^^^^^^^^^^
LL | |
LL | | let _x: <Self::Assoc as Foo>::Bar;
LL | | }
| |_____- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

warning: 1 warning emitted

3 changes: 3 additions & 0 deletions src/test/ui/consts/issue-67696-const-prop-ice.rs
Expand Up @@ -11,6 +11,9 @@ trait A {

impl A for [fn(&())] {
fn foo(&self) -> Self where Self: Copy { *(&[] as &[_]) }
//~^ WARNING the where-clause bound
//~| WARNING the where-clause bound
//~| WARNING the where-clause bound
}

impl A for i32 {
Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/consts/issue-67696-const-prop-ice.stderr
@@ -0,0 +1,26 @@
warning: the where-clause bound `[for<'r> fn(&'r ())]: Copy` is impossible to satisfy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is certainly not great.

--> $DIR/issue-67696-const-prop-ice.rs:13:33
|
LL | fn foo(&self) -> Self where Self: Copy { *(&[] as &[_]) }
| ----------------------------^^^^^^^^^^------------------- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

warning: the where-clause bound `[for<'r> fn(&'r ())]: Clone` is impossible to satisfy
--> $DIR/issue-67696-const-prop-ice.rs:13:33
|
LL | fn foo(&self) -> Self where Self: Copy { *(&[] as &[_]) }
| ----------------------------^^^^^^^^^^------------------- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

warning: the where-clause bound `[for<'r> fn(&'r ())]: Sized` is impossible to satisfy
--> $DIR/issue-67696-const-prop-ice.rs:13:33
|
LL | fn foo(&self) -> Self where Self: Copy { *(&[] as &[_]) }
| ----------------------------^^^^^^^^^^------------------- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

warning: 3 warnings emitted

1 change: 1 addition & 0 deletions src/test/ui/feature-gates/feature-gate-trivial_bounds.rs
Expand Up @@ -63,6 +63,7 @@ fn return_str() -> str where str: Sized { //~ ERROR
// This is currently accepted because the function pointer isn't
// considered global.
fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
//~^ WARNING the where-clause bound
x.test();
}

Expand Down
14 changes: 13 additions & 1 deletion src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
Expand Up @@ -113,6 +113,18 @@ LL | fn return_str() -> str where str: Sized {
= help: see issue #48214
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable

error: aborting due to 11 previous errors
warning: the where-clause bound `for<'r> fn(&'r ()): Foo` is impossible to satisfy
--> $DIR/feature-gate-trivial_bounds.rs:65:32
|
LL | fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
| _- ^^^^^^^^^^^^
LL | |
LL | | x.test();
LL | | }
| |_- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

error: aborting due to 11 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0277`.
Expand Up @@ -7,6 +7,7 @@ impl<B: BufferMut, C> BufferUdpStateContext<B> for C {}
trait StackContext
where
Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>,
//~^ WARNING the where-clause bound
{
type Dispatcher;
}
Expand All @@ -26,6 +27,7 @@ where
struct EthernetWorker<C>(C)
where
Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>;
//~^ WARNING the where-clause bound
impl<C> EthernetWorker<C> {}
//~^ ERROR: is not satisfied [E0277]

Expand Down
@@ -1,5 +1,20 @@
warning: the where-clause bound `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>` is impossible to satisfy
--> $DIR/issue-89118.rs:9:5
|
LL | / trait StackContext
LL | | where
LL | | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>,
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | |
LL | | {
LL | | type Dispatcher;
LL | | }
| |_- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
--> $DIR/issue-89118.rs:19:8
--> $DIR/issue-89118.rs:20:8
|
LL | C: StackContext,
| ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
Expand All @@ -18,8 +33,18 @@ LL | where
LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext`

warning: the where-clause bound `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>` is impossible to satisfy
--> $DIR/issue-89118.rs:29:5
|
LL | / struct EthernetWorker<C>(C)
LL | | where
LL | | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>;
| |_____^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
--> $DIR/issue-89118.rs:29:9
--> $DIR/issue-89118.rs:31:9
|
LL | impl<C> EthernetWorker<C> {}
| ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
Expand All @@ -30,7 +55,7 @@ note: required because of the requirements on the impl of `for<'a> BufferUdpStat
LL | impl<B: BufferMut, C> BufferUdpStateContext<B> for C {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ ^
note: required by a bound in `EthernetWorker`
--> $DIR/issue-89118.rs:28:14
--> $DIR/issue-89118.rs:29:14
|
LL | struct EthernetWorker<C>(C)
| -------------- required by a bound in this
Expand All @@ -39,7 +64,7 @@ LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EthernetWorker`

error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
--> $DIR/issue-89118.rs:22:20
--> $DIR/issue-89118.rs:23:20
|
LL | type Handler = Ctx<C::Dispatcher>;
| ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
Expand All @@ -58,6 +83,6 @@ LL | where
LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext`

error: aborting due to 3 previous errors
error: aborting due to 3 previous errors; 2 warnings emitted

For more information about this error, try `rustc --explain E0277`.
1 change: 1 addition & 0 deletions src/test/ui/issues/issue-36839.rs
Expand Up @@ -12,6 +12,7 @@ pub trait Broken {
impl<T> Broken for T {
type Assoc = ();
fn broken(&self) where Self::Assoc: Foo {
//~^ WARNING the where-clause bound
let _x: <Self::Assoc as Foo>::Bar;
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/issues/issue-36839.stderr
@@ -0,0 +1,14 @@
warning: the where-clause bound `<T as Broken>::Assoc: Foo` is impossible to satisfy
--> $DIR/issue-36839.rs:14:28
|
LL | fn broken(&self) where Self::Assoc: Foo {
| _____- ^^^^^^^^^^^^^^^^
LL | |
LL | | let _x: <Self::Assoc as Foo>::Bar;
LL | | }
| |_____- this item cannot be referenced without causing an error
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to allow it

warning: 1 warning emitted

1 change: 1 addition & 0 deletions src/test/ui/issues/issue-39970.rs
Expand Up @@ -13,6 +13,7 @@ impl<'a> Array<'a> for () {
impl Visit for () where
//(): for<'a> Array<'a, Element=&'a ()>, // No ICE
(): for<'a> Array<'a, Element=()>, // ICE
//~^ WARNING the where-clause bound
{}

fn main() {
Expand Down