diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 33d5a86beb3b0..af27e0162f938 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -19,9 +19,8 @@ use rustc_middle::query::Providers; use rustc_middle::traits::solve::NoSolution; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ - self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFlags, - TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, - Upcast, + self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -111,9 +110,6 @@ where let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; - if !tcx.features().trivial_bounds() { - wfcx.check_false_global_bounds() - } f(&mut wfcx)?; let errors = wfcx.select_all_or_error(); @@ -121,6 +117,10 @@ where return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } + if !tcx.features().trivial_bounds() { + wfcx.check_false_global_bounds()?; + } + let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; debug!(?assumed_wf_types); @@ -2274,7 +2274,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that /// aren't true. #[instrument(level = "debug", skip(self))] - fn check_false_global_bounds(&mut self) { + fn check_false_global_bounds(&mut self) -> Result<(), ErrorGuaranteed> { let tcx = self.ocx.infcx.tcx; let mut span = self.span; let empty_env = ty::ParamEnv::empty(); @@ -2283,6 +2283,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { // Check elaborated bounds. let implied_obligations = traits::elaborate(tcx, predicates_with_span); + let mut global_obligations = vec![]; for (pred, obligation_span) in implied_obligations { // We lower empty bounds like `Vec:` as // `WellFormed(Vec)`, which will later get checked by @@ -2290,10 +2291,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() { continue; } - // Match the existing behavior. - if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) { - let pred = self.normalize(span, None, pred); - + // Match the existing behavior. We normalize first to handle where-bounds + // like `u32: Trait`. + let clause = ObligationCause::misc(span, self.body_def_id); + let Ok(pred) = self.deeply_normalize(&clause, self.param_env, pred) else { + tcx.dcx().delayed_bug("encountered errors when normalizing where-clauses"); + continue; + }; + if pred.is_global() && pred.kind().bound_vars().is_empty() { // only use the span of the predicate clause (#90869) let hir_node = tcx.hir_node_by_def_id(self.body_def_id); if let Some(hir::Generics { predicates, .. }) = hir_node.generics() { @@ -2315,9 +2320,17 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { empty_env, pred, ); - self.ocx.register_obligation(obligation); + global_obligations.push(obligation); } } + + self.register_obligations(global_obligations); + let errors = self.select_all_or_error(); + if !errors.is_empty() { + Err(self.infcx.err_ctxt().report_fulfillment_errors(errors)) + } else { + Ok(()) + } } } diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index a718eb23bed59..40546efa40b9c 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -12,8 +12,7 @@ fn take( K = { () } >, ) {} -//~^^^^^^ ERROR implementation of `Project` is not general enough -//~^^^^ ERROR higher-ranked subtype error +//~^^^ ERROR higher-ranked subtype error //~| ERROR higher-ranked subtype error trait Project { type Out; } diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index 967814c9c3d9d..f77f37f101eef 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -12,14 +12,5 @@ LL | K = { () } | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: implementation of `Project` is not general enough - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:9:4 - | -LL | fn take( - | ^^^^ implementation of `Project` is not general enough - | - = note: `Project` would have to be implemented for the type `for<'a> fn(&'a str) -> &'a str` - = note: ...but `Project` is actually implemented for the type `fn(&'0 str) -> &'0 str`, for some specific lifetime `'0` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/issue-69398.rs b/tests/ui/associated-types/issue-69398.rs index 654c0f6e4b54a..b558646b4ae94 100644 --- a/tests/ui/associated-types/issue-69398.rs +++ b/tests/ui/associated-types/issue-69398.rs @@ -1,4 +1,5 @@ //@ check-pass +#![feature(trivial_bounds)] pub trait Foo { type Bar; diff --git a/tests/ui/consts/issue-67696-const-prop-ice.rs b/tests/ui/consts/issue-67696-const-prop-ice.rs index 09e5ba74c338a..49b68f12a334b 100644 --- a/tests/ui/consts/issue-67696-const-prop-ice.rs +++ b/tests/ui/consts/issue-67696-const-prop-ice.rs @@ -2,7 +2,7 @@ //@ compile-flags: --emit=mir,link -Zmir-opt-level=4 // Checks that we don't ICE due to attempting to run const prop // on a function with unsatisifable 'where' clauses - +#![feature(trivial_bounds)] #![allow(unused)] trait A { diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.rs b/tests/ui/feature-gates/feature-gate-trivial_bounds.rs index 3dbaf5dea250e..dafdc7682d7a9 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.rs +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.rs @@ -60,9 +60,7 @@ fn return_str() -> str where str: Sized { //~ ERROR *"Sized".to_string().into_boxed_str() } -// This is currently accepted because the function pointer isn't -// considered global. -fn global_hr(x: fn(&())) where fn(&()): Foo { // OK +fn global_hr(x: fn(&())) where fn(&()): Foo { //~ ERROR x.test(); } diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr index 7d9c5b8165169..5223577ce45f1 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -145,6 +145,19 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable LL + #![feature(trivial_bounds)] | -error: aborting due to 11 previous errors +error[E0277]: the trait bound `for<'a> fn(&'a ()): Foo` is not satisfied + --> $DIR/feature-gate-trivial_bounds.rs:63:32 + | +LL | fn global_hr(x: fn(&())) where fn(&()): Foo { + | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `for<'a> fn(&'a ())` + | + = help: the trait `Foo` is implemented for `()` + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-36839.rs b/tests/ui/issues/issue-36839.rs index 654c0f6e4b54a..b558646b4ae94 100644 --- a/tests/ui/issues/issue-36839.rs +++ b/tests/ui/issues/issue-36839.rs @@ -1,4 +1,5 @@ //@ check-pass +#![feature(trivial_bounds)] pub trait Foo { type Bar; diff --git a/tests/ui/issues/issue-42796.rs b/tests/ui/issues/issue-42796.rs index 5e83a1cd67785..ce7ecf0b41a4d 100644 --- a/tests/ui/issues/issue-42796.rs +++ b/tests/ui/issues/issue-42796.rs @@ -1,3 +1,4 @@ +#![feature(trivial_bounds)] pub trait Mirror { type Image; } diff --git a/tests/ui/issues/issue-42796.stderr b/tests/ui/issues/issue-42796.stderr index 670b98c770898..3a063b12752fd 100644 --- a/tests/ui/issues/issue-42796.stderr +++ b/tests/ui/issues/issue-42796.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `s` - --> $DIR/issue-42796.rs:18:20 + --> $DIR/issue-42796.rs:19:20 | LL | let s = "Hello!".to_owned(); | - move occurs because `s` has type `String`, which does not implement the `Copy` trait diff --git a/tests/ui/layout/unsatisfiable-sized-ungated.rs b/tests/ui/layout/unsatisfiable-sized-ungated.rs index d9c1f739bdbfa..602ddee54cf90 100644 --- a/tests/ui/layout/unsatisfiable-sized-ungated.rs +++ b/tests/ui/layout/unsatisfiable-sized-ungated.rs @@ -1,8 +1,5 @@ -//@ check-pass -// issue: #123134 - -//! This is a variant of `trivial-bounds-sized.rs` that compiles without any -//! feature gates and used to trigger a delayed bug. +// Regression test for #123134. This is a variant of `trivial-bounds-sized.rs` +// that previously compiled without any feature gate and used to trigger a delayed bug. trait Api: Sized { type Device: ?Sized; @@ -36,8 +33,7 @@ impl Adapter for T { fn open() -> OpenDevice where ::Device: Sized, - // ^ the bound expands to `<::A as Api>::Device: Sized`, which - // is not considered trivial due to containing the type parameter `T` + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time { unreachable!() } diff --git a/tests/ui/layout/unsatisfiable-sized-ungated.stderr b/tests/ui/layout/unsatisfiable-sized-ungated.stderr new file mode 100644 index 0000000000000..146a200975651 --- /dev/null +++ b/tests/ui/layout/unsatisfiable-sized-ungated.stderr @@ -0,0 +1,16 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsatisfiable-sized-ungated.rs:35:9 + | +LL | ::Device: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mir/issue-91745.rs b/tests/ui/mir/issue-91745.rs index 654c0f6e4b54a..ac8ac49a3e8b1 100644 --- a/tests/ui/mir/issue-91745.rs +++ b/tests/ui/mir/issue-91745.rs @@ -1,3 +1,4 @@ +#![feature(trivial_bounds)] //@ check-pass pub trait Foo { diff --git a/tests/ui/trait-bounds/issue-94999.rs b/tests/ui/trait-bounds/issue-94999.rs index b6a180a1579c7..cdd1b92dabd22 100644 --- a/tests/ui/trait-bounds/issue-94999.rs +++ b/tests/ui/trait-bounds/issue-94999.rs @@ -1,4 +1,5 @@ //@ check-pass +#![feature(trivial_bounds)] trait Identity { type T; @@ -25,6 +26,8 @@ impl Clone for X where >::T: Clone, X: Holds, + //~^ WARN trait bound X: Holds does not depend on any type or lifetime parameters + // FIXME(#140311): This shouldn't lint { fn clone(&self) -> Self { Self(self.0.clone()) diff --git a/tests/ui/trait-bounds/issue-94999.stderr b/tests/ui/trait-bounds/issue-94999.stderr new file mode 100644 index 0000000000000..2ff55ad573bb9 --- /dev/null +++ b/tests/ui/trait-bounds/issue-94999.stderr @@ -0,0 +1,10 @@ +warning: trait bound X: Holds does not depend on any type or lifetime parameters + --> $DIR/issue-94999.rs:28:8 + | +LL | X: Holds, + | ^^^^^^^^^^^^ + | + = note: `#[warn(trivial_bounds)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/trivial-bounds/not-trivial-after-norm-1.next.stderr b/tests/ui/trivial-bounds/not-trivial-after-norm-1.next.stderr new file mode 100644 index 0000000000000..16fef4d835652 --- /dev/null +++ b/tests/ui/trivial-bounds/not-trivial-after-norm-1.next.stderr @@ -0,0 +1,23 @@ +error[E0283]: type annotations needed + --> $DIR/not-trivial-after-norm-1.rs:28:5 + | +LL | impls_incomplete::<(), _>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_incomplete` + | +note: multiple `impl`s or `where` clauses satisfying `(): Incomplete<_>` found + --> $DIR/not-trivial-after-norm-1.rs:14:1 + | +LL | impl Incomplete for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | (): Incomplete<::Assoc>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_incomplete` + --> $DIR/not-trivial-after-norm-1.rs:15:24 + | +LL | fn impls_incomplete, U>() {} + | ^^^^^^^^^^^^^ required by this bound in `impls_incomplete` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/trivial-bounds/not-trivial-after-norm-1.rs b/tests/ui/trivial-bounds/not-trivial-after-norm-1.rs new file mode 100644 index 0000000000000..d806a9f5d6a12 --- /dev/null +++ b/tests/ui/trivial-bounds/not-trivial-after-norm-1.rs @@ -0,0 +1,33 @@ +//@[current] check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait With { + type Assoc; +} +impl With for T { + type Assoc = T; +} + +trait Incomplete {} +impl Incomplete for () {} +fn impls_incomplete, U>() {} +fn foo() +where + u32: With, + // This where-bound is global before normalization + // and references `T` afterwards. We check whether + // global where-bounds hold by proving them in an empty + // `param_env`. + // + // Make sure we don't introduce params by normalizing after + // checking whether the where-bound is global. + (): Incomplete<::Assoc>, +{ + impls_incomplete::<(), _>(); + //[next]~^ ERROR type annotations needed + // FIXME(-Znext-solver): This should match the behavior of the old solver +} + +fn main() {} diff --git a/tests/ui/trivial-bounds/not-trivial-after-norm-2.rs b/tests/ui/trivial-bounds/not-trivial-after-norm-2.rs new file mode 100644 index 0000000000000..29d5c66604f86 --- /dev/null +++ b/tests/ui/trivial-bounds/not-trivial-after-norm-2.rs @@ -0,0 +1,32 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait With { + type Assoc; +} +impl With for u32 { + type Assoc = [u32; 0]; +} + +trait Trait {} +impl Trait for [u32; N] {} + +fn foo() +where + u32: With, + // This where-bound is global before normalization + // and references `T` afterwards. We check whether + // global where-bounds hold by proving them in an empty + // `param_env`. + // + // Make sure we don't introduce params by normalizing after + // checking whether the where-bound is global. Proving + // `[u32; N]: Trait` then caused an ICE when trying to fetch + // the type of `N`. + ::Assoc: Trait, +{ +} + +fn main() {} diff --git a/tests/ui/trivial-bounds/trivial-after-norm.current.stderr b/tests/ui/trivial-bounds/trivial-after-norm.current.stderr new file mode 100644 index 0000000000000..a686017950cc5 --- /dev/null +++ b/tests/ui/trivial-bounds/trivial-after-norm.current.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `u32: Trait` is not satisfied + --> $DIR/trivial-after-norm.rs:18:5 + | +LL | T::Assoc: Trait, + | ^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32` + | +help: this trait has no implementations, consider adding one + --> $DIR/trivial-after-norm.rs:12:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/trivial-bounds/trivial-after-norm.next.stderr b/tests/ui/trivial-bounds/trivial-after-norm.next.stderr new file mode 100644 index 0000000000000..a686017950cc5 --- /dev/null +++ b/tests/ui/trivial-bounds/trivial-after-norm.next.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `u32: Trait` is not satisfied + --> $DIR/trivial-after-norm.rs:18:5 + | +LL | T::Assoc: Trait, + | ^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32` + | +help: this trait has no implementations, consider adding one + --> $DIR/trivial-after-norm.rs:12:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/trivial-bounds/trivial-after-norm.rs b/tests/ui/trivial-bounds/trivial-after-norm.rs new file mode 100644 index 0000000000000..49661d7bf34eb --- /dev/null +++ b/tests/ui/trivial-bounds/trivial-after-norm.rs @@ -0,0 +1,23 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait With { + type Assoc; +} +impl With for T { + type Assoc = T; +} + +trait Trait {} +fn foo() +where + T: With, + // This where-bound only global after normalization. We still + // check whether it is a trivial bound. + T::Assoc: Trait, + //~^ ERROR the trait bound `u32: Trait` is not satisfied +{ +} + +fn main() {} diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.rs b/tests/ui/where-clauses/higher-ranked-fn-type.rs index 7ad7a896e8d38..7df8f2cee8b39 100644 --- a/tests/ui/where-clauses/higher-ranked-fn-type.rs +++ b/tests/ui/where-clauses/higher-ranked-fn-type.rs @@ -1,6 +1,6 @@ //@ revisions: quiet verbose //@ [verbose]compile-flags: -Zverbose-internals - +#![feature(trivial_bounds)] #![allow(unused_parens)] trait Foo {