mirror of
https://github.com/rust-lang/rust
synced 2024-10-14 12:33:57 +00:00
borrowck: wf-check fn item args
This commit is contained in:
parent
f9c2421a2a
commit
a3fe3bbb2c
|
@ -406,6 +406,16 @@ fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location)
|
||||||
instantiated_predicates,
|
instantiated_predicates,
|
||||||
locations,
|
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3049,8 +3049,9 @@ fn extend_reserve(&mut self, additional: usize) {
|
||||||
#[stable(feature = "hash_extend_copy", since = "1.4.0")]
|
#[stable(feature = "hash_extend_copy", since = "1.4.0")]
|
||||||
impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
|
impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
|
||||||
where
|
where
|
||||||
K: Eq + Hash + Copy,
|
// FIXME(aliemjay): the bound `+ 'a` should not be necessary.
|
||||||
V: Copy,
|
K: Eq + Hash + Copy + 'a,
|
||||||
|
V: Copy + 'a,
|
||||||
S: BuildHasher,
|
S: BuildHasher,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
15
tests/ui/borrowck/fn-item-check-trait-ref.rs
Normal file
15
tests/ui/borrowck/fn-item-check-trait-ref.rs
Normal file
|
@ -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
tests/ui/borrowck/fn-item-check-trait-ref.stderr
Normal file
12
tests/ui/borrowck/fn-item-check-trait-ref.stderr
Normal file
|
@ -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
tests/ui/borrowck/fn-item-check-type-params.rs
Normal file
57
tests/ui/borrowck/fn-item-check-type-params.rs
Normal file
|
@ -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
tests/ui/borrowck/fn-item-check-type-params.stderr
Normal file
43
tests/ui/borrowck/fn-item-check-type-params.stderr
Normal file
|
@ -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`.
|
|
@ -17,6 +17,7 @@ pub fn crash<V>(v: &V)
|
||||||
v.t(|| {});
|
v.t(|| {});
|
||||||
//~^ ERROR: higher-ranked lifetime error
|
//~^ ERROR: higher-ranked lifetime error
|
||||||
//~| ERROR: higher-ranked lifetime error
|
//~| ERROR: higher-ranked lifetime error
|
||||||
|
//~| ERROR: higher-ranked lifetime error
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -6,6 +6,15 @@ LL | v.t(|| {});
|
||||||
|
|
|
|
||||||
= note: could not prove `{closure@$DIR/issue-59311.rs:17:9: 17:11} well-formed`
|
= 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
|
error: higher-ranked lifetime error
|
||||||
--> $DIR/issue-59311.rs:17:9
|
--> $DIR/issue-59311.rs:17:9
|
||||||
|
|
|
|
||||||
|
@ -14,5 +23,5 @@ LL | v.t(|| {});
|
||||||
|
|
|
|
||||||
= note: could not prove `for<'a> &'a V: 'b`
|
= note: could not prove `for<'a> &'a V: 'b`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
// check-pass
|
// issue: #84591
|
||||||
// known-bug: #84591
|
|
||||||
|
|
||||||
// Should fail. Subtrait can incorrectly extend supertrait lifetimes even when
|
// Subtrait was able to incorrectly extend supertrait lifetimes even when
|
||||||
// supertrait has weaker implied bounds than subtrait. Strongly related to
|
// supertrait had weaker implied bounds than subtrait.
|
||||||
// issue #25860.
|
|
||||||
|
|
||||||
trait Subtrait<T>: Supertrait {}
|
trait Subtrait<T>: Supertrait {}
|
||||||
trait Supertrait {
|
trait Supertrait {
|
||||||
|
@ -34,6 +32,7 @@ fn main() {
|
||||||
{
|
{
|
||||||
let x = "Hello World".to_string();
|
let x = "Hello World".to_string();
|
||||||
subs_to_soup((x.as_str(), &mut d));
|
subs_to_soup((x.as_str(), &mut d));
|
||||||
|
//~^ does not live long enough
|
||||||
}
|
}
|
||||||
println!("{}", d);
|
println!("{}", d);
|
||||||
}
|
}
|
|
@ -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`.
|
|
@ -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);
|
||||||
|
}
|
|
@ -11,6 +11,8 @@ fn f<T, S>(data: &[T], key: impl Fn(&T) -> S) {
|
||||||
fn g<T>(data: &[T]) {
|
fn g<T>(data: &[T]) {
|
||||||
f(data, identity)
|
f(data, identity)
|
||||||
//~^ ERROR the parameter type
|
//~^ ERROR the parameter type
|
||||||
|
//~| ERROR the parameter type
|
||||||
|
//~| ERROR the parameter type
|
||||||
//~| ERROR mismatched types
|
//~| ERROR mismatched types
|
||||||
//~| ERROR implementation of `FnOnce` is not general
|
//~| ERROR implementation of `FnOnce` is not general
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,36 @@ help: consider adding an explicit lifetime bound
|
||||||
LL | fn g<T: 'static>(data: &[T]) {
|
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
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue_74400.rs:12:5
|
--> $DIR/issue_74400.rs:12:5
|
||||||
|
|
|
|
||||||
|
@ -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: `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`
|
= 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.
|
Some errors have detailed explanations: E0308, E0310.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0310]: the parameter type `T` may not live long enough
|
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;
|
LL | type InnerOpaque<T> = impl Sized;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
@ -12,6 +12,21 @@ help: consider adding an explicit lifetime bound
|
||||||
LL | fn test<T: 'static>() {
|
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`.
|
For more information about this error, try `rustc --explain E0310`.
|
||||||
|
|
|
@ -43,7 +43,9 @@ fn define<T>() -> OuterOpaque<T> {}
|
||||||
|
|
||||||
fn test<T>() {
|
fn test<T>() {
|
||||||
let outer = define::<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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
// check-pass
|
|
||||||
// known-bug: #104005
|
|
||||||
|
|
||||||
// Should fail. Function type parameters with implicit type annotations are not
|
|
||||||
// checked for well-formedness, which allows incorrect borrowing.
|
|
||||||
|
|
||||||
// In contrast, user annotations are always checked for well-formedness, and the
|
|
||||||
// commented code below is correctly rejected by the borrow checker.
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// *incorrectly* compiles
|
|
||||||
let val = extend_lt(&String::from("blah blah blah"));
|
|
||||||
println!("{}", val);
|
|
||||||
|
|
||||||
// *correctly* fails to compile
|
|
||||||
// let val = extend_lt::<_, &_>(&String::from("blah blah blah"));
|
|
||||||
// println!("{}", val);
|
|
||||||
}
|
|
Loading…
Reference in a new issue