diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 9ed1d49d05bd1..3e6aa358ee0d1 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -35,7 +35,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, Substs, UnpackedKind}; +use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSubsts}; use rustc::ty::{ self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserType, CanonicalUserTypeAnnotation, UserTypeAnnotationIndex, @@ -283,7 +283,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { location.to_locations(), ConstraintCategory::Boring, ) { - let annotation = self.cx.instantiated_type_annotations[&annotation_index]; + let annotation = &self.mir.user_type_annotations[annotation_index]; span_mirbug!( self, constant, @@ -293,6 +293,39 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { terr, ); } + } else { + match *constant.literal { + ty::LazyConst::Unevaluated(def_id, substs) => { + if let Err(terr) = self.cx.fully_perform_op( + location.to_locations(), + ConstraintCategory::Boring, + self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( + constant.ty, def_id, UserSubsts { substs, user_self_ty: None }, + )), + ) { + span_mirbug!( + self, + constant, + "bad constant type {:?} ({:?})", + constant, + terr + ); + } + } + ty::LazyConst::Evaluated(lit) => { + if let ty::FnDef(def_id, substs) = lit.ty.sty { + let tcx = self.tcx(); + + let instantiated_predicates = tcx + .predicates_of(def_id) + .instantiate(tcx, substs); + self.cx.normalize_and_prove_instantiated_predicates( + instantiated_predicates, + location.to_locations(), + ); + } + } + } } } @@ -374,8 +407,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } - /// Checks that the constant's `ty` field matches up with what - /// would be expected from its literal. + /// Checks that the constant's `ty` field matches up with what would be + /// expected from its literal. Unevaluated constants and well-formed + /// constraints are checked by `visit_constant`. fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) { debug!( "sanitize_constant(constant={:?}, location={:?})", @@ -387,35 +421,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ty::LazyConst::Unevaluated(..) => return, }; - // FIXME(#46702) -- We need some way to get the predicates - // associated with the "pre-evaluated" form of the - // constant. For example, consider that the constant - // may have associated constant projections (`>::SOME_CONST`) that impose - // constraints on `'a` and `'b`. These constraints - // would be lost if we just look at the normalized - // value. - if let ty::FnDef(def_id, substs) = literal.ty.sty { - let tcx = self.tcx(); - let type_checker = &mut self.cx; - - // FIXME -- For now, use the substitutions from - // `value.ty` rather than `value.val`. The - // renumberer will rewrite them to independent - // sets of regions; in principle, we ought to - // derive the type of the `value.val` from "first - // principles" and equate with value.ty, but as we - // are transitioning to the miri-based system, we - // don't have a handy function for that, so for - // now we just ignore `value.val` regions. - - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - type_checker.normalize_and_prove_instantiated_predicates( - instantiated_predicates, - location.to_locations(), - ); - } - debug!("sanitize_constant: expected_ty={:?}", literal.ty); if let Err(terr) = self.cx.eq_types( @@ -740,15 +745,6 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> { reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, - /// For each user-type annotation (identified by a UserTypeAnnotationIndex), we create - /// an "instantiated" version at the beginning of type check, which replaces each - /// canonical variable with a fresh inference variable. These instantiated versions are - /// stored either in this field or in user_substs, depending on the kind of user-type - /// annotation. They are then referenced by the code which has the job of enforcing these - /// annotations. Part of the reason for this setup is that it allows us to enforce basic - /// WF criteria on the types even if the code that referenced them is dead - /// code (see #54943). - instantiated_type_annotations: FxHashMap>, } struct BorrowCheckContext<'a, 'tcx: 'a> { @@ -905,23 +901,19 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { borrowck_context, reported_errors: Default::default(), universal_region_relations, - instantiated_type_annotations: Default::default(), }; - checker.instantiate_user_type_annotations(); + checker.check_user_type_annotations(); checker } - /// Instantiate canonical types from user type annotations in the `Mir` into the - /// `TypeChecker`. Used when relating user type annotations and when checking if - /// annotations are well-formed. - fn instantiate_user_type_annotations(&mut self) { + /// Equate the inferred type and the annotated type for user type annotations + fn check_user_type_annotations(&mut self) { debug!( - "instantiate_user_type_annotations: user_type_annotations={:?}", + "check_user_type_annotations: user_type_annotations={:?}", self.mir.user_type_annotations ); - for annotation_index in self.mir.user_type_annotations.indices() { - let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = - self.mir.user_type_annotations[annotation_index]; + for user_annotation in &self.mir.user_type_annotations { + let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let (annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars( span, user_ty ); @@ -937,7 +929,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) { span_mirbug!( self, - self.mir.user_type_annotations[annotation_index], + user_annotation, "bad user type ({:?} = {:?}): {:?}", ty, inferred_ty, @@ -961,7 +953,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) { span_mirbug!( self, - self.mir.user_type_annotations[annotation_index], + user_annotation, "bad user type AscribeUserType({:?}, {:?} {:?}): {:?}", inferred_ty, def_id, @@ -971,12 +963,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } }, } - self.instantiated_type_annotations.insert(annotation_index, inferred_ty); } - debug!( - "instantiate_user_type_annotations: instantiated_type_annotations={:?}", - self.instantiated_type_annotations, - ); } /// Given some operation `op` that manipulates types, proves @@ -1108,7 +1095,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { a, v, user_ty, locations, ); - let annotated_type = self.instantiated_type_annotations[&user_ty.base]; + let annotated_type = self.mir.user_type_annotations[user_ty.base].inferred_ty; let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); let tcx = self.infcx.tcx; @@ -1293,7 +1280,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { location.to_locations(), ConstraintCategory::Boring, ) { - let annotation = self.instantiated_type_annotations[&annotation_index]; + let annotation = &mir.user_type_annotations[annotation_index]; span_mirbug!( self, stmt, @@ -1352,7 +1339,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Locations::All(stmt.source_info.span), ConstraintCategory::TypeAnnotation, ) { - let annotation = self.instantiated_type_annotations[&projection.base]; + let annotation = &mir.user_type_annotations[projection.base]; span_mirbug!( self, stmt, diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs new file mode 100644 index 0000000000000..123be6b3e4098 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs @@ -0,0 +1,29 @@ +// Test that we still check constants are well-formed, even when we there's no +// type annotation to check. + +#![feature(nll)] + +const FUN: fn(&'static ()) = |_| {}; +struct A; +impl A { + const ASSOCIATED_FUN: fn(&'static ()) = |_| {}; +} + +struct B<'a>(&'a ()); +impl B<'static> { + const ALSO_ASSOCIATED_FUN: fn(&'static ()) = |_| {}; +} + +trait Z: 'static { + const TRAIT_ASSOCIATED_FUN: fn(&'static Self) = |_| (); +} + +impl Z for () {} + +fn main() { + let x = (); + FUN(&x); //~ ERROR `x` does not live long enough + A::ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough + B::ALSO_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough + <_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr new file mode 100644 index 0000000000000..57cfaa2db0432 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr @@ -0,0 +1,50 @@ +error[E0597]: `x` does not live long enough + --> $DIR/constant-in-expr-inherent-2.rs:25:9 + | +LL | FUN(&x); //~ ERROR `x` does not live long enough + | ----^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + +error[E0597]: `x` does not live long enough + --> $DIR/constant-in-expr-inherent-2.rs:26:23 + | +LL | A::ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough + | ------------------^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + +error[E0597]: `x` does not live long enough + --> $DIR/constant-in-expr-inherent-2.rs:27:28 + | +LL | B::ALSO_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough + | -----------------------^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +LL | <_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough +LL | } + | - `x` dropped here while still borrowed + +error[E0597]: `x` does not live long enough + --> $DIR/constant-in-expr-inherent-2.rs:28:31 + | +LL | <_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough + | --------------------------^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +LL | } + | - `x` dropped here while still borrowed + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0597`.