Skip to content

Commit

Permalink
borrowck: wf-check fn item args
Browse files Browse the repository at this point in the history
  • Loading branch information
aliemjay authored and lcnr committed Jan 16, 2024
1 parent f9c2421 commit a3fe3bb
Show file tree
Hide file tree
Showing 17 changed files with 269 additions and 49 deletions.
10 changes: 10 additions & 0 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,16 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
instantiated_predicates,
locations,
);

assert!(!matches!(
tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)),
Some(DefKind::Impl { of_trait: true })
));
self.cx.prove_predicates(
args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())),
locations,
ConstraintCategory::Boring,
);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions library/std/src/collections/hash/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3049,8 +3049,9 @@ where
#[stable(feature = "hash_extend_copy", since = "1.4.0")]
impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
where
K: Eq + Hash + Copy,
V: Copy,
// FIXME(aliemjay): the bound `+ 'a` should not be necessary.
K: Eq + Hash + Copy + 'a,
V: Copy + 'a,
S: BuildHasher,
{
#[inline]
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/borrowck/fn-item-check-trait-ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// The method `assert_static` should be callable only for static values,
// because the impl has an implied bound `where T: 'static`.

// check-fail

trait AnyStatic<Witness>: Sized {
fn assert_static(self) {}
}

impl<T> AnyStatic<&'static T> for T {}

fn main() {
(&String::new()).assert_static();
//~^ ERROR temporary value dropped while borrowed
}
12 changes: 12 additions & 0 deletions tests/ui/borrowck/fn-item-check-trait-ref.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/fn-item-check-trait-ref.rs:13:7
|
LL | (&String::new()).assert_static();
| --^^^^^^^^^^^^^------------------ temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'static`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0716`.
57 changes: 57 additions & 0 deletions tests/ui/borrowck/fn-item-check-type-params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Regression test for #104005.
//
// Previously, different borrowck implementations used to disagree here.
// The status of each is documented on `fn test_*`.

// check-fail

use std::fmt::Display;

trait Displayable {
fn display(self) -> Box<dyn Display>;
}

impl<T: Display> Displayable for (T, Option<&'static T>) {
fn display(self) -> Box<dyn Display> {
Box::new(self.0)
}
}

fn extend_lt<T, U>(val: T) -> Box<dyn Display>
where
(T, Option<U>): Displayable,
{
Displayable::display((val, None))
}

// AST: fail
// HIR: pass
// MIR: pass
pub fn test_call<'a>(val: &'a str) {
extend_lt(val);
//~^ ERROR borrowed data escapes outside of function
}

// AST: fail
// HIR: fail
// MIR: pass
pub fn test_coercion<'a>() {
let _: fn(&'a str) -> _ = extend_lt;
//~^ ERROR lifetime may not live long enough
}

// AST: fail
// HIR: fail
// MIR: fail
pub fn test_arg() {
fn want<I, O>(_: I, _: impl Fn(I) -> O) {}
want(&String::new(), extend_lt);
//~^ ERROR temporary value dropped while borrowed
}

// An exploit of the unsoundness.
fn main() {
let val = extend_lt(&String::from("blah blah blah"));
//~^ ERROR temporary value dropped while borrowed
println!("{}", val);
}
43 changes: 43 additions & 0 deletions tests/ui/borrowck/fn-item-check-type-params.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
error[E0521]: borrowed data escapes outside of function
--> $DIR/fn-item-check-type-params.rs:31:5
|
LL | pub fn test_call<'a>(val: &'a str) {
| -- --- `val` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
LL | extend_lt(val);
| ^^^^^^^^^^^^^^
| |
| `val` escapes the function body here
| argument requires that `'a` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/fn-item-check-type-params.rs:39:12
|
LL | pub fn test_coercion<'a>() {
| -- lifetime `'a` defined here
LL | let _: fn(&'a str) -> _ = extend_lt;
| ^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`

error[E0716]: temporary value dropped while borrowed
--> $DIR/fn-item-check-type-params.rs:48:11
|
LL | want(&String::new(), extend_lt);
| ------^^^^^^^^^^^^^------------- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'static`

error[E0716]: temporary value dropped while borrowed
--> $DIR/fn-item-check-type-params.rs:54:26
|
LL | let val = extend_lt(&String::from("blah blah blah"));
| -----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'static`

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0521, E0716.
For more information about an error, try `rustc --explain E0521`.
1 change: 1 addition & 0 deletions tests/ui/higher-ranked/trait-bounds/issue-59311.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ where
v.t(|| {});
//~^ ERROR: higher-ranked lifetime error
//~| ERROR: higher-ranked lifetime error
//~| ERROR: higher-ranked lifetime error
}

fn main() {}
11 changes: 10 additions & 1 deletion tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ LL | v.t(|| {});
|
= note: could not prove `{closure@$DIR/issue-59311.rs:17:9: 17:11} well-formed`

error: higher-ranked lifetime error
--> $DIR/issue-59311.rs:17:5
|
LL | v.t(|| {});
| ^^^^^^^^^^
|
= note: could not prove `{closure@$DIR/issue-59311.rs:17:9: 17:11} well-formed`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: higher-ranked lifetime error
--> $DIR/issue-59311.rs:17:9
|
Expand All @@ -14,5 +23,5 @@ LL | v.t(|| {});
|
= note: could not prove `for<'a> &'a V: 'b`

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// check-pass
// known-bug: #84591
// issue: #84591

// Should fail. Subtrait can incorrectly extend supertrait lifetimes even when
// supertrait has weaker implied bounds than subtrait. Strongly related to
// issue #25860.
// Subtrait was able to incorrectly extend supertrait lifetimes even when
// supertrait had weaker implied bounds than subtrait.

trait Subtrait<T>: Supertrait {}
trait Supertrait {
Expand Down Expand Up @@ -34,6 +32,7 @@ fn main() {
{
let x = "Hello World".to_string();
subs_to_soup((x.as_str(), &mut d));
//~^ does not live long enough
}
println!("{}", d);
}
16 changes: 16 additions & 0 deletions tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0597]: `x` does not live long enough
--> $DIR/implied-bounds-on-trait-hierarchy-1.rs:34:23
|
LL | let x = "Hello World".to_string();
| - binding `x` declared here
LL | subs_to_soup((x.as_str(), &mut d));
| ^ borrowed value does not live long enough
LL |
LL | }
| - `x` dropped here while still borrowed
LL | println!("{}", d);
| - borrow later used here

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0597`.
45 changes: 45 additions & 0 deletions tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// check-pass
// known-bug: #84591

trait Subtrait<'a, 'b, R>: Supertrait<'a, 'b> {}
trait Supertrait<'a, 'b> {
fn convert<T: ?Sized>(x: &'a T) -> &'b T;
}

fn need_hrtb_subtrait<'a_, 'b_, S, T: ?Sized>(x: &'a_ T) -> &'b_ T
where
S: for<'a, 'b> Subtrait<'a, 'b, &'b &'a ()>,
{
need_hrtb_supertrait::<S, T>(x)
// This call works and drops the implied bound `'a: 'b`
// of the where-bound. This means the where-bound can
// now be used to transmute any two lifetimes.
}

fn need_hrtb_supertrait<'a_, 'b_, S, T: ?Sized>(x: &'a_ T) -> &'b_ T
where
S: for<'a, 'b> Supertrait<'a, 'b>,
{
S::convert(x)
}

struct MyStruct;
impl<'a: 'b, 'b> Supertrait<'a, 'b> for MyStruct {
fn convert<T: ?Sized>(x: &'a T) -> &'b T {
x
}
}
impl<'a, 'b> Subtrait<'a, 'b, &'b &'a ()> for MyStruct {}

fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
need_hrtb_subtrait::<MyStruct, T>(x)
}

fn main() {
let d;
{
let x = "Hello World".to_string();
d = extend_lifetime(&x);
}
println!("{}", d);
}
2 changes: 2 additions & 0 deletions tests/ui/lifetimes/lifetime-errors/issue_74400.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ fn f<T, S>(data: &[T], key: impl Fn(&T) -> S) {
fn g<T>(data: &[T]) {
f(data, identity)
//~^ ERROR the parameter type
//~| ERROR the parameter type
//~| ERROR the parameter type
//~| ERROR mismatched types
//~| ERROR implementation of `FnOnce` is not general
}
32 changes: 31 additions & 1 deletion tests/ui/lifetimes/lifetime-errors/issue_74400.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,36 @@ help: consider adding an explicit lifetime bound
LL | fn g<T: 'static>(data: &[T]) {
| +++++++++

error[E0310]: the parameter type `T` may not live long enough
--> $DIR/issue_74400.rs:12:5
|
LL | f(data, identity)
| ^^^^^^^^^^^^^^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider adding an explicit lifetime bound
|
LL | fn g<T: 'static>(data: &[T]) {
| +++++++++

error[E0310]: the parameter type `T` may not live long enough
--> $DIR/issue_74400.rs:12:5
|
LL | f(data, identity)
| ^^^^^^^^^^^^^^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider adding an explicit lifetime bound
|
LL | fn g<T: 'static>(data: &[T]) {
| +++++++++

error[E0308]: mismatched types
--> $DIR/issue_74400.rs:12:5
|
Expand All @@ -35,7 +65,7 @@ LL | f(data, identity)
= note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `FnOnce<(&'1 T,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 T,)>`, for some specific lifetime `'2`

error: aborting due to 3 previous errors
error: aborting due to 5 previous errors

Some errors have detailed explanations: E0308, E0310.
For more information about an error, try `rustc --explain E0308`.
2 changes: 1 addition & 1 deletion tests/ui/type-alias-impl-trait/wf-nested.fail.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:55:27
--> $DIR/wf-nested.rs:57:27
|
LL | type InnerOpaque<T> = impl Sized;
| ^^^^^^^^^^
Expand Down
17 changes: 16 additions & 1 deletion tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ help: consider adding an explicit lifetime bound
LL | fn test<T: 'static>() {
| +++++++++

error: aborting due to 1 previous error
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:46:17
|
LL | let _ = outer.get();
| ^^^^^^^^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider adding an explicit lifetime bound
|
LL | fn test<T: 'static>() {
| +++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0310`.
4 changes: 3 additions & 1 deletion tests/ui/type-alias-impl-trait/wf-nested.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ mod pass_sound {

fn test<T>() {
let outer = define::<T>();
let _ = outer.get(); //[pass_sound]~ ERROR `T` may not live long enough
let _ = outer.get();
//[pass_sound]~^ ERROR `T` may not live long enough
//[pass_sound]~| ERROR `T` may not live long enough
}
}

Expand Down
Loading

0 comments on commit a3fe3bb

Please sign in to comment.