about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-07-18 11:37:19 -0400
committerMichael Goulet <michael@errs.io>2024-08-05 09:55:14 -0400
commit6a891ec4fe0db4790e9d000b15c5ec79907605b3 (patch)
treeae4a34205bcfa8d496680ec6dc2d26de260cdf46
parent9179d9b334e3f5e8772e1a563308dc95a1cde960 (diff)
downloadrust-6a891ec4fe0db4790e9d000b15c5ec79907605b3.tar.gz
rust-6a891ec4fe0db4790e9d000b15c5ec79907605b3.zip
Enforce supertrait outlives obligations hold when confirming impl
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs34
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs2
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs1
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr17
-rw-r--r--tests/ui/static/static-lifetime.rs1
-rw-r--r--tests/ui/static/static-lifetime.stderr30
-rw-r--r--tests/ui/wf/wf-in-where-clause-static.current.stderr12
-rw-r--r--tests/ui/wf/wf-in-where-clause-static.next.stderr12
-rw-r--r--tests/ui/wf/wf-in-where-clause-static.rs10
10 files changed, 120 insertions, 12 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 4474bbc2351..77ce81e44a0 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -87,6 +87,19 @@ where
                 .map(|pred| goal.with(cx, pred));
             ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
 
+            // We currently elaborate all supertrait obligations from impls. This
+            // can be removed when we actually do coinduction correctly and just
+            // register that the impl header must be WF.
+            let goal_clause: I::Clause = goal.predicate.upcast(cx);
+            for clause in elaborate::elaborate(cx, [goal_clause]) {
+                if matches!(
+                    clause.kind().skip_binder(),
+                    ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
+                ) {
+                    ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
+                }
+            }
+
             ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
         })
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index cc9174d3aad..2bc2a8fe693 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -7,6 +7,7 @@ use std::fmt::{self, Display};
 use std::ops::ControlFlow;
 use std::{cmp, iter};
 
+use hir::def::DefKind;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Diag, EmissionGuarantee};
@@ -14,8 +15,9 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
 use rustc_infer::infer::relate::TypeRelation;
-use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
-use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
+use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
+use rustc_infer::infer::DefineOpaqueTypes;
+use rustc_infer::traits::util::elaborate;
 use rustc_infer::traits::TraitObligation;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{dep_kinds, DepNodeIndex};
@@ -2798,6 +2800,34 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             });
         }
 
+        if matches!(self.tcx().def_kind(def_id), DefKind::Impl { of_trait: true })
+            && let Some(header) = self.tcx().impl_trait_header(def_id)
+        {
+            let trait_clause: ty::Clause<'tcx> =
+                header.trait_ref.instantiate(self.tcx(), args).upcast(self.tcx());
+            for clause in elaborate(self.tcx(), [trait_clause]) {
+                if matches!(
+                    clause.kind().skip_binder(),
+                    ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
+                ) {
+                    let clause = normalize_with_depth_to(
+                        self,
+                        param_env,
+                        cause.clone(),
+                        recursion_depth,
+                        clause,
+                        &mut obligations,
+                    );
+                    obligations.push(Obligation {
+                        cause: cause.clone(),
+                        recursion_depth,
+                        param_env,
+                        predicate: clause.as_predicate(),
+                    });
+                }
+            }
+        }
+
         obligations
     }
 }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index e1a3764fa76..263ba676427 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -451,6 +451,8 @@ pub trait Clause<I: Interner<Clause = Self>>:
     + UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
     + UpcastFrom<I, ty::TraitRef<I>>
     + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+    + UpcastFrom<I, ty::TraitPredicate<I>>
+    + UpcastFrom<I, ty::Binder<I, ty::TraitPredicate<I>>>
     + UpcastFrom<I, ty::ProjectionPredicate<I>>
     + UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
     + IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs
index a7489f6fbaf..38be3250c7d 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs
@@ -5,6 +5,7 @@ trait Trait<'a>: 'a {
 // if the `T: 'a` bound gets implied we would probably get ub here again
 impl<'a, T> Trait<'a> for T {
     //~^ ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
     type Type = ();
 }
 
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
index b898df0835c..b2aa1abbbdb 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
@@ -16,8 +16,21 @@ help: consider adding an explicit lifetime bound
 LL | impl<'a, T: 'a> Trait<'a> for T {
    |           ++++
 
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:27
+   |
+LL | impl<'a, T> Trait<'a> for T {
+   |      --                   ^ ...so that the type `T` will meet its required lifetime bounds
+   |      |
+   |      the parameter type `T` must be valid for the lifetime `'a` as defined here...
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL | impl<'a, T: 'a> Trait<'a> for T {
+   |           ++++
+
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:21:10
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:22:10
    |
 LL |     let x = String::from("Hello World!");
    |         - binding `x` declared here
@@ -33,7 +46,7 @@ help: consider cloning the value if the performance cost is acceptable
 LL |     let y = f(&x.clone(), ());
    |                 ++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0309, E0505.
 For more information about an error, try `rustc --explain E0309`.
diff --git a/tests/ui/static/static-lifetime.rs b/tests/ui/static/static-lifetime.rs
index ce1eeb6105f..a861a2ffeda 100644
--- a/tests/ui/static/static-lifetime.rs
+++ b/tests/ui/static/static-lifetime.rs
@@ -1,6 +1,7 @@
 pub trait Arbitrary: Sized + 'static {}
 
 impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound
+//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter `'a`
 
 fn main() {
 }
diff --git a/tests/ui/static/static-lifetime.stderr b/tests/ui/static/static-lifetime.stderr
index 8c9434ce3cb..7a956dbfeef 100644
--- a/tests/ui/static/static-lifetime.stderr
+++ b/tests/ui/static/static-lifetime.stderr
@@ -11,6 +11,32 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
    |      ^^
    = note: but lifetime parameter must outlive the static lifetime
 
-error: aborting due to 1 previous error
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/static-lifetime.rs:3:34
+   |
+LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/static-lifetime.rs:3:6
+   |
+LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   |      ^^
+note: ...so that the types are compatible
+  --> $DIR/static-lifetime.rs:3:34
+   |
+LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected `<Cow<'a, A> as Arbitrary>`
+              found `<Cow<'_, A> as Arbitrary>`
+   = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that the declared lifetime parameter bounds are satisfied
+  --> $DIR/static-lifetime.rs:3:34
+   |
+LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0478`.
+Some errors have detailed explanations: E0478, E0495.
+For more information about an error, try `rustc --explain E0478`.
diff --git a/tests/ui/wf/wf-in-where-clause-static.current.stderr b/tests/ui/wf/wf-in-where-clause-static.current.stderr
new file mode 100644
index 00000000000..d0bb89884c6
--- /dev/null
+++ b/tests/ui/wf/wf-in-where-clause-static.current.stderr
@@ -0,0 +1,12 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/wf-in-where-clause-static.rs:18:18
+   |
+LL |     let s = foo(&String::from("blah blah blah"));
+   |             -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
+   |             |    |
+   |             |    creates a temporary value which is freed while still in use
+   |             argument requires that borrow lasts for `'static`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/wf/wf-in-where-clause-static.next.stderr b/tests/ui/wf/wf-in-where-clause-static.next.stderr
new file mode 100644
index 00000000000..d0bb89884c6
--- /dev/null
+++ b/tests/ui/wf/wf-in-where-clause-static.next.stderr
@@ -0,0 +1,12 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/wf-in-where-clause-static.rs:18:18
+   |
+LL |     let s = foo(&String::from("blah blah blah"));
+   |             -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
+   |             |    |
+   |             |    creates a temporary value which is freed while still in use
+   |             argument requires that borrow lasts for `'static`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/wf/wf-in-where-clause-static.rs b/tests/ui/wf/wf-in-where-clause-static.rs
index a3d360e1fb5..8ee654ef7cf 100644
--- a/tests/ui/wf/wf-in-where-clause-static.rs
+++ b/tests/ui/wf/wf-in-where-clause-static.rs
@@ -1,9 +1,6 @@
-//@ check-pass
-//@ known-bug: #98117
-
-// Should fail. Functions are responsible for checking the well-formedness of
-// their own where clauses, so this should fail and require an explicit bound
-// `T: 'static`.
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 use std::fmt::Display;
 
@@ -19,5 +16,6 @@ where
 
 fn main() {
     let s = foo(&String::from("blah blah blah"));
+    //~^ ERROR temporary value dropped while borrowed
     println!("{}", s);
 }