about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs40
-rw-r--r--src/test/ui/cycle-me.rs31
-rw-r--r--src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs66
-rw-r--r--src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr38
6 files changed, 174 insertions, 3 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index a8719be84c2..f54e090e4e0 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -565,6 +565,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         template!(Word, List: "delay_span_bug_from_inside_query")
     ),
     rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)),
+    rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
     rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
     rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
     rustc_attr!(
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 4c80b84e3d2..93cb34999c3 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1010,6 +1010,7 @@ symbols! {
         rustc_dump_program_clauses,
         rustc_dump_user_substs,
         rustc_error,
+        rustc_evaluate_where_clauses,
         rustc_expected_cgu_reuse,
         rustc_if_this_changed,
         rustc_inherit_overflow_checks,
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index b48102e0fc9..cb8f336721a 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -6,8 +6,14 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{Namespace, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::{infer, traits};
+use rustc_infer::{
+    infer,
+    traits::{self, Obligation},
+};
+use rustc_infer::{
+    infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
+    traits::ObligationCause,
+};
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
@@ -17,6 +23,7 @@ use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
 use rustc_trait_selection::autoderef::Autoderef;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use std::iter;
 
 /// Checks that it is legal to call methods of the trait corresponding
@@ -294,7 +301,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         let (fn_sig, def_id) = match *callee_ty.kind() {
-            ty::FnDef(def_id, _) => (callee_ty.fn_sig(self.tcx), Some(def_id)),
+            ty::FnDef(def_id, subst) => {
+                // Unit testing: function items annotated with
+                // `#[rustc_evaluate_where_clauses]` trigger special output
+                // to let us test the trait evaluation system.
+                if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
+                    let predicates = self.tcx.predicates_of(def_id);
+                    let predicates = predicates.instantiate(self.tcx, subst);
+                    for (predicate, predicate_span) in
+                        predicates.predicates.iter().zip(&predicates.spans)
+                    {
+                        let obligation = Obligation::new(
+                            ObligationCause::dummy_with_span(callee_expr.span),
+                            self.param_env,
+                            predicate.clone(),
+                        );
+                        let result = self.infcx.evaluate_obligation(&obligation);
+                        self.tcx
+                            .sess
+                            .struct_span_err(
+                                callee_expr.span,
+                                &format!("evaluate({:?}) = {:?}", predicate, result),
+                            )
+                            .span_label(*predicate_span, "predicate")
+                            .emit();
+                    }
+                }
+                (callee_ty.fn_sig(self.tcx), Some(def_id))
+            }
             ty::FnPtr(sig) => (sig, None),
             ref t => {
                 let mut unit_variant = None;
diff --git a/src/test/ui/cycle-me.rs b/src/test/ui/cycle-me.rs
new file mode 100644
index 00000000000..eb1ffe51ffc
--- /dev/null
+++ b/src/test/ui/cycle-me.rs
@@ -0,0 +1,31 @@
+#![feature(rustc_attrs)]
+
+// A (reached depth 0)
+//   ...
+//      B // depth 1 -- reached depth = 0
+//          C // depth 2 -- reached depth = 1 (should be 0)
+//              B
+//          A // depth 0
+//   D (reached depth 1)
+//      C (cache -- reached depth = 2)
+
+struct A {
+    b: B,
+    c: C,
+}
+
+struct B {
+    c: C,
+    a: Option<Box<A>>,
+}
+
+struct C {
+    b: Option<Box<B>>,
+}
+
+#[rustc_evaluate_where_clauses]
+fn test<X: Send>() {}
+
+fn main() {
+    test::<A>();
+}
diff --git a/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs b/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs
new file mode 100644
index 00000000000..1b357575cb8
--- /dev/null
+++ b/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs
@@ -0,0 +1,66 @@
+// Regression test for issue #83538. The problem here is that we have
+// two cycles:
+//
+// * `Ty` embeds `Box<Ty>` indirectly, which depends on `Global: 'static`, which is OkModuloRegions.
+// * But `Ty` also references `First`, which has a cycle on itself. That should just be `Ok`.
+//
+// But our caching mechanism was blending both cycles and giving the incorrect result.
+
+#![feature(rustc_attrs)]
+#![allow(bad_style)]
+
+struct First {
+    b: Vec<First>,
+}
+
+pub struct Second {
+    d: Vec<First>,
+}
+
+struct Third<f> {
+    g: Vec<f>,
+}
+
+enum Ty {
+    j(Fourth, Fifth, Sixth),
+}
+
+struct Fourth {
+    o: Vec<Ty>,
+}
+
+struct Fifth {
+    bounds: First,
+}
+
+struct Sixth {
+    p: Box<Ty>,
+}
+
+#[rustc_evaluate_where_clauses]
+fn forward()
+where
+    Vec<First>: Unpin,
+    Third<Ty>: Unpin,
+{
+}
+
+#[rustc_evaluate_where_clauses]
+fn reverse()
+where
+    Third<Ty>: Unpin,
+    Vec<First>: Unpin,
+{
+}
+
+fn main() {
+    // The only ERROR included here is the one that is totally wrong:
+
+    forward();
+    //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+    //~| ERROR evaluate(Binder(TraitPredicate(<Third<Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+
+    reverse();
+    //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+    //~| ERROR evaluate(Binder(TraitPredicate(<Third<Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+}
diff --git a/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr b/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr
new file mode 100644
index 00000000000..82e00c3b97f
--- /dev/null
+++ b/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr
@@ -0,0 +1,38 @@
+error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+  --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
+   |
+LL |     Vec<First>: Unpin,
+   |                 ----- predicate
+...
+LL |     forward();
+   |     ^^^^^^^
+
+error: evaluate(Binder(TraitPredicate(<Third<Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+  --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
+   |
+LL |     Third<Ty>: Unpin,
+   |                ----- predicate
+...
+LL |     forward();
+   |     ^^^^^^^
+
+error: evaluate(Binder(TraitPredicate(<Third<Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+  --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
+   |
+LL |     Third<Ty>: Unpin,
+   |                ----- predicate
+...
+LL |     reverse();
+   |     ^^^^^^^
+
+error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+  --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
+   |
+LL |     Vec<First>: Unpin,
+   |                 ----- predicate
+...
+LL |     reverse();
+   |     ^^^^^^^
+
+error: aborting due to 4 previous errors
+