Skip to content

Commit

Permalink
Auto merge of rust-lang#129021 - compiler-errors:ptr-cast-outlives, r…
Browse files Browse the repository at this point in the history
…=<try>

Check WF of source type's signature on fn pointer cast

TODO: description

r? lcnr
  • Loading branch information
bors committed Aug 12, 2024
2 parents e08b80c + aa3574c commit f781a78
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 20 deletions.
60 changes: 50 additions & 10 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1978,28 +1978,68 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {

match cast_kind {
CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => {
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
let src_sig = op.ty(body, tcx).fn_sig(tcx);

// FIXME: Explained higher-ranked case.
if src_sig.has_bound_regions()
&& let ty::FnPtr(target_sig) = *ty.kind()
&& let Some(target_sig) = target_sig.no_bound_vars()
{
let src_sig = self.infcx.instantiate_binder_with_fresh_vars(
span,
BoundRegionConversionTime::HigherRankedType,
src_sig,
);
let src_ty = Ty::new_fn_ptr(self.tcx(), ty::Binder::dummy(src_sig));
self.prove_predicate(
ty::ClauseKind::WellFormed(src_ty.into()),
location.to_locations(),
ConstraintCategory::Cast { unsize_to: None },
);

let src_ty = self.normalize(src_ty, location);
if let Err(terr) = self.sub_types(
src_ty,
*ty,
location.to_locations(),
ConstraintCategory::Cast { unsize_to: None },
) {
span_mirbug!(
self,
rvalue,
"equating {:?} with {:?} yields {:?}",
target_sig,
src_sig,
terr
);
};
}

let src_ty = Ty::new_fn_ptr(tcx, src_sig);
// FIXME: Explain why this is needed.
self.prove_predicate(
ty::ClauseKind::WellFormed(src_ty.into()),
location.to_locations(),
ConstraintCategory::Cast { unsize_to: None },
);

// The type that we see in the fcx is like
// `foo::<'a, 'b>`, where `foo` is the path to a
// function definition. When we extract the
// signature, it comes from the `fn_sig` query,
// and hence may contain unnormalized results.
let fn_sig = self.normalize(fn_sig, location);

let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig);

if let Err(terr) = self.eq_types(
let src_ty = self.normalize(src_ty, location);
if let Err(terr) = self.sub_types(
src_ty,
*ty,
ty_fn_ptr_from,
location.to_locations(),
ConstraintCategory::Cast { unsize_to: None },
) {
span_mirbug!(
self,
rvalue,
"equating {:?} with {:?} yields {:?}",
ty_fn_ptr_from,
src_ty,
ty,
terr
);
Expand All @@ -2014,9 +2054,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let ty_fn_ptr_from =
Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *safety));

if let Err(terr) = self.eq_types(
*ty,
if let Err(terr) = self.sub_types(
ty_fn_ptr_from,
*ty,
location.to_locations(),
ConstraintCategory::Cast { unsize_to: None },
) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
at.lub(DefineOpaqueTypes::Yes, b, a)
} else {
at.sup(DefineOpaqueTypes::Yes, b, a)
.map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
.map(|InferOk { value: (), obligations }| InferOk { value: b, obligations })
};

// In the new solver, lazy norm may allow us to shallowly equate
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/impl-trait/recursive-ice-101862.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ LL | vec![].append(&mut ice(x.as_ref()));
= note: `#[warn(unconditional_recursion)]` on by default

error[E0792]: expected generic type parameter, found `&str`
--> $DIR/recursive-ice-101862.rs:6:5
--> $DIR/recursive-ice-101862.rs:6:19
|
LL | pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
| --------------- this generic parameter must be used with a generic type parameter
LL |
LL | vec![].append(&mut ice(x.as_ref()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error; 1 warning emitted

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
static UNIT: &'static &'static () = &&();

fn foo<'a: 'a, 'b: 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }

fn bad<'a, T>(x: &'a T) -> &'static T {
let f: fn(_, &'a T) -> &'static T = foo;
//~^ ERROR lifetime may not live long enough
f(UNIT, x)
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: lifetime may not live long enough
--> $DIR/implied-bounds-on-nested-references-plus-variance-early-bound.rs:6:12
|
LL | fn bad<'a, T>(x: &'a T) -> &'static T {
| -- lifetime `'a` defined here
LL | let f: fn(_, &'a T) -> &'static T = foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
trait ToArg<T> {
type Arg;
}
impl<T, U> ToArg<T> for U {
type Arg = T;
}

fn extend_inner<'a, 'b>(x: &'a str) -> <&'b &'a () as ToArg<&'b str>>::Arg { x }
fn extend<'a, 'b>(x: &'a str) -> &'b str {
(extend_inner as fn(_) -> _)(x)
//~^ ERROR lifetime may not live long enough
}

fn main() {
let y = extend(&String::from("Hello World"));
println!("{}", y);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: lifetime may not live long enough
--> $DIR/implied-bounds-on-nested-references-plus-variance-unnormalized.rs:10:5
|
LL | fn extend<'a, 'b>(x: &'a str) -> &'b str {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | (extend_inner as fn(_) -> _)(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
= help: consider adding the following bound: `'a: 'b`

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
//@ check-pass
//@ known-bug: #25860

// Should fail. The combination of variance and implied bounds for nested
// references allows us to infer a longer lifetime than we can prove.

static UNIT: &'static &'static () = &&();

fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }

fn bad<'a, T>(x: &'a T) -> &'static T {
let f: fn(_, &'a T) -> &'static T = foo;
//~^ ERROR lifetime may not live long enough
f(UNIT, x)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: lifetime may not live long enough
--> $DIR/implied-bounds-on-nested-references-plus-variance.rs:6:12
|
LL | fn bad<'a, T>(x: &'a T) -> &'static T {
| -- lifetime `'a` defined here
LL | let f: fn(_, &'a T) -> &'static T = foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`

error: aborting due to 1 previous error

1 change: 1 addition & 0 deletions tests/ui/traits/next-solver/alias-bound-unsound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ fn main() {
//~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
println!("{x}");
}
8 changes: 7 additions & 1 deletion tests/ui/traits/next-solver/alias-bound-unsound.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ LL | drop(<() as Foo>::copy_me(&x));
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 6 previous errors
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
--> $DIR/alias-bound-unsound.rs:24:31
|
LL | drop(<() as Foo>::copy_me(&x));
| ^^

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0275`.

0 comments on commit f781a78

Please sign in to comment.