diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 152ceeee869..0aaeacb6a23 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -63,13 +63,16 @@ fn relate_mir_and_user_ty<'tcx>( user_ty: Ty<'tcx>, ) -> Result<(), NoSolution> { let cause = ObligationCause::dummy_with_span(span); + ocx.register_obligation(Obligation::new( + ocx.infcx.tcx, + cause.clone(), + param_env, + ty::ClauseKind::WellFormed(user_ty.into()), + )); + let user_ty = ocx.normalize(&cause, param_env, user_ty); ocx.eq(&cause, param_env, mir_ty, user_ty)?; - // FIXME(#104764): We should check well-formedness before normalization. - let predicate = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(user_ty.into()))); - ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); Ok(()) } @@ -113,31 +116,38 @@ fn relate_mir_and_user_args<'tcx>( ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); } + // Now prove the well-formedness of `def_id` with `substs`. + // Note for some items, proving the WF of `ty` is not sufficient because the + // well-formedness of an item may depend on the WF of gneneric args not present in the + // item's type. Currently this is true for associated consts, e.g.: + // ```rust + // impl MyTy { + // const CONST: () = { /* arbitrary code that depends on T being WF */ }; + // } + // ``` + for arg in args { + ocx.register_obligation(Obligation::new( + tcx, + cause.clone(), + param_env, + ty::ClauseKind::WellFormed(arg), + )); + } + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + ocx.register_obligation(Obligation::new( + tcx, + cause.clone(), + param_env, + ty::ClauseKind::WellFormed(self_ty.into()), + )); + let self_ty = ocx.normalize(&cause, param_env, self_ty); let impl_self_ty = tcx.type_of(impl_def_id).instantiate(tcx, args); let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( - impl_self_ty.into(), - ))); - ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); } - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the args being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `args` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - let predicate = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into()))); - ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); Ok(()) } diff --git a/tests/ui/wf/wf-associated-const.rs b/tests/ui/wf/wf-associated-const.rs index dffa1713eff..629d807cb7f 100644 --- a/tests/ui/wf/wf-associated-const.rs +++ b/tests/ui/wf/wf-associated-const.rs @@ -1,8 +1,5 @@ // check that associated consts can assume the impl header is well-formed. -// FIXME(aliemjay): we should check the impl header is WF at the use site -// but we currently don't in some cases. This is *unsound*. - trait Foo<'a, 'b, T>: Sized { const EVIL: fn(u: &'b u32) -> &'a u32; } @@ -27,11 +24,13 @@ impl<'a, 'b> Evil<'a, 'b> { // *check* that it holds at the use site. fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { - <()>::EVIL(b) // FIXME: should be an error + <()>::EVIL(b) + //~^ ERROR lifetime may not live long enough } fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { - ::EVIL(b) // FIXME: should be an error + ::EVIL(b) + //~^ ERROR lifetime may not live long enough } fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { diff --git a/tests/ui/wf/wf-associated-const.stderr b/tests/ui/wf/wf-associated-const.stderr index e025d5d468a..b0e1a118fab 100644 --- a/tests/ui/wf/wf-associated-const.stderr +++ b/tests/ui/wf/wf-associated-const.stderr @@ -1,5 +1,29 @@ error: lifetime may not live long enough - --> $DIR/wf-associated-const.rs:38:5 + --> $DIR/wf-associated-const.rs:27:5 + | +LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | <()>::EVIL(b) + | ^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/wf-associated-const.rs:32:5 + | +LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | ::EVIL(b) + | ^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/wf-associated-const.rs:37:5 | LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { | -- -- lifetime `'b` defined here @@ -10,5 +34,5 @@ LL | ::INHERENT_EVIL(b) | = help: consider adding the following bound: `'b: 'a` -error: aborting due to previous error +error: aborting due to 3 previous errors