diff options
| -rw-r--r-- | compiler/rustc_feature/src/builtin_attrs.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/callee.rs | 40 | ||||
| -rw-r--r-- | src/test/ui/cycle-me.rs | 31 | ||||
| -rw-r--r-- | src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs | 66 | ||||
| -rw-r--r-- | src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr | 38 |
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 + |
