Skip to content

Commit a707f40

Browse files
committed
Auto merge of #95819 - oli-obk:mir_can't_hold_all_these_lifetimes, r=estebank
Enforce Copy bounds for repeat elements while considering lifetimes fixes #95477 this is a breaking change in order to fix a soundness bug. Before this PR we only checked whether the repeat element type had an `impl Copy`, but not whether that impl also had the appropriate lifetimes. E.g. if the impl was for `YourType<'static>` and not a general `'a`, then copying any type other than a `'static` one should have been rejected, but wasn't. r? `@lcnr`
2 parents 1c8966e + 67ce547 commit a707f40

24 files changed

+184
-97
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+12-41
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,13 @@ use rustc_middle::ty::{
3737
use rustc_span::def_id::CRATE_DEF_ID;
3838
use rustc_span::{Span, DUMMY_SP};
3939
use rustc_target::abi::VariantIdx;
40-
use rustc_trait_selection::infer::InferCtxtExt as _;
41-
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
4240
use rustc_trait_selection::traits::query::type_op;
4341
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
4442
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
4543
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
4644
use rustc_trait_selection::traits::query::Fallible;
47-
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
45+
use rustc_trait_selection::traits::PredicateObligation;
4846

49-
use rustc_const_eval::transform::{
50-
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
51-
};
5247
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
5348
use rustc_mir_dataflow::move_paths::MoveData;
5449
use rustc_mir_dataflow::ResultsCursor;
@@ -1868,41 +1863,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
18681863
Operand::Move(place) => {
18691864
// Make sure that repeated elements implement `Copy`.
18701865
let span = body.source_info(location).span;
1871-
let ty = operand.ty(body, tcx);
1872-
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
1873-
let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env);
1874-
let is_const_fn =
1875-
is_const_fn_in_array_repeat_expression(&ccx, &place, &body);
1876-
1877-
debug!("check_rvalue: is_const_fn={:?}", is_const_fn);
1878-
1879-
let def_id = body.source.def_id().expect_local();
1880-
let obligation = traits::Obligation::new(
1881-
ObligationCause::new(
1882-
span,
1883-
self.tcx().hir().local_def_id_to_hir_id(def_id),
1884-
traits::ObligationCauseCode::RepeatElementCopy {
1885-
is_const_fn,
1886-
},
1887-
),
1888-
self.param_env,
1889-
ty::Binder::dummy(ty::TraitRef::new(
1890-
self.tcx().require_lang_item(
1891-
LangItem::Copy,
1892-
Some(self.last_span),
1893-
),
1894-
tcx.mk_substs_trait(ty, &[]),
1895-
))
1896-
.without_const()
1897-
.to_predicate(self.tcx()),
1898-
);
1899-
self.infcx.report_selection_error(
1900-
obligation.clone(),
1901-
&obligation,
1902-
&traits::SelectionError::Unimplemented,
1903-
false,
1904-
);
1905-
}
1866+
let ty = place.ty(body, tcx).ty;
1867+
let trait_ref = ty::TraitRef::new(
1868+
tcx.require_lang_item(LangItem::Copy, Some(span)),
1869+
tcx.mk_substs_trait(ty, &[]),
1870+
);
1871+
1872+
self.prove_trait_ref(
1873+
trait_ref,
1874+
Locations::Single(location),
1875+
ConstraintCategory::CopyBound,
1876+
);
19061877
}
19071878
}
19081879
}

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2227,7 +2227,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
22272227
}
22282228
ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
22292229
err.note(
2230-
"the `Copy` trait is required because the repeated element will be copied",
2230+
"the `Copy` trait is required because this value will be copied for each element of the array",
22312231
);
22322232

22332233
if is_const_fn {

compiler/rustc_typeck/src/check/expr.rs

+40
Original file line numberDiff line numberDiff line change
@@ -1292,9 +1292,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12921292
return tcx.ty_error();
12931293
}
12941294

1295+
self.check_repeat_element_needs_copy_bound(element, count, element_ty);
1296+
12951297
tcx.mk_ty(ty::Array(t, count))
12961298
}
12971299

1300+
fn check_repeat_element_needs_copy_bound(
1301+
&self,
1302+
element: &hir::Expr<'_>,
1303+
count: ty::Const<'tcx>,
1304+
element_ty: Ty<'tcx>,
1305+
) {
1306+
let tcx = self.tcx;
1307+
// Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
1308+
match &element.kind {
1309+
hir::ExprKind::ConstBlock(..) => return,
1310+
hir::ExprKind::Path(qpath) => {
1311+
let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
1312+
if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res
1313+
{
1314+
return;
1315+
}
1316+
}
1317+
_ => {}
1318+
}
1319+
// If someone calls a const fn, they can extract that call out into a separate constant (or a const
1320+
// block in the future), so we check that to tell them that in the diagnostic. Does not affect typeck.
1321+
let is_const_fn = match element.kind {
1322+
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
1323+
ty::FnDef(def_id, _) => tcx.is_const_fn(def_id),
1324+
_ => false,
1325+
},
1326+
_ => false,
1327+
};
1328+
1329+
// If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we
1330+
// don't copy that one element, we move it. Only check for Copy if the length is larger.
1331+
if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
1332+
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
1333+
let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn };
1334+
self.require_type_meets(element_ty, element.span, code, lang_item);
1335+
}
1336+
}
1337+
12981338
fn check_expr_tuple(
12991339
&self,
13001340
elts: &'tcx [hir::Expr<'tcx>],

src/test/ui/array-slice-vec/repeat_empty_ok.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
2-
--> $DIR/repeat_empty_ok.rs:8:19
2+
--> $DIR/repeat_empty_ok.rs:8:20
33
|
44
LL | let headers = [Header{value: &[]}; 128];
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
5+
| ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
66
|
7-
= note: the `Copy` trait is required because the repeated element will be copied
7+
= note: the `Copy` trait is required because this value will be copied for each element of the array
88
help: consider annotating `Header<'_>` with `#[derive(Copy)]`
99
|
1010
LL | #[derive(Copy)]
1111
|
1212

1313
error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
14-
--> $DIR/repeat_empty_ok.rs:13:19
14+
--> $DIR/repeat_empty_ok.rs:13:20
1515
|
1616
LL | let headers = [Header{value: &[0]}; 128];
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
17+
| ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
1818
|
19-
= note: the `Copy` trait is required because the repeated element will be copied
19+
= note: the `Copy` trait is required because this value will be copied for each element of the array
2020
help: consider annotating `Header<'_>` with `#[derive(Copy)]`
2121
|
2222
LL | #[derive(Copy)]

src/test/ui/const-generics/issues/issue-61336-2.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
error[E0277]: the trait bound `T: Copy` is not satisfied
2-
--> $DIR/issue-61336-2.rs:6:5
2+
--> $DIR/issue-61336-2.rs:6:6
33
|
44
LL | [x; { N }]
5-
| ^^^^^^^^^^ the trait `Copy` is not implemented for `T`
5+
| ^ the trait `Copy` is not implemented for `T`
66
|
7-
= note: the `Copy` trait is required because the repeated element will be copied
7+
= note: the `Copy` trait is required because this value will be copied for each element of the array
88
help: consider restricting type parameter `T`
99
|
1010
LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {

src/test/ui/const-generics/issues/issue-61336.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
error[E0277]: the trait bound `T: Copy` is not satisfied
2-
--> $DIR/issue-61336.rs:6:5
2+
--> $DIR/issue-61336.rs:6:6
33
|
44
LL | [x; N]
5-
| ^^^^^^ the trait `Copy` is not implemented for `T`
5+
| ^ the trait `Copy` is not implemented for `T`
66
|
7-
= note: the `Copy` trait is required because the repeated element will be copied
7+
= note: the `Copy` trait is required because this value will be copied for each element of the array
88
help: consider restricting type parameter `T`
99
|
1010
LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {

src/test/ui/consts/const-blocks/fn-call-in-non-const.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ const fn copy() -> u32 {
1212
fn main() {
1313
let _: [u32; 2] = [copy(); 2];
1414
let _: [Option<Bar>; 2] = [no_copy(); 2];
15-
//~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied
15+
//~^ ERROR the trait bound `Bar: Copy` is not satisfied
1616
}

src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
2-
--> $DIR/fn-call-in-non-const.rs:14:31
1+
error[E0277]: the trait bound `Bar: Copy` is not satisfied
2+
--> $DIR/fn-call-in-non-const.rs:14:32
33
|
44
LL | let _: [Option<Bar>; 2] = [no_copy(); 2];
5-
| ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
5+
| ^^^^^^^^^ the trait `Copy` is not implemented for `Bar`
66
|
7-
= help: the trait `Copy` is implemented for `Option<T>`
8-
= note: the `Copy` trait is required because the repeated element will be copied
7+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
8+
= note: the `Copy` trait is required because this value will be copied for each element of the array
99
= help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
1010
= help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
11+
help: consider annotating `Bar` with `#[derive(Copy)]`
12+
|
13+
LL | #[derive(Copy)]
14+
|
1115

1216
error: aborting due to previous error
1317

src/test/ui/consts/const-blocks/migrate-fail.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ mod non_constants {
1111
fn no_impl_copy_empty_value_multiple_elements() {
1212
let x = None;
1313
let arr: [Option<Bar>; 2] = [x; 2];
14-
//~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
14+
//~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
1515
}
1616

1717
fn no_impl_copy_value_multiple_elements() {
1818
let x = Some(Bar);
1919
let arr: [Option<Bar>; 2] = [x; 2];
20-
//~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
20+
//~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
2121
}
2222
}
2323

src/test/ui/consts/const-blocks/migrate-fail.stderr

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
1-
error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
2-
--> $DIR/migrate-fail.rs:13:37
1+
error[E0277]: the trait bound `Bar: Copy` is not satisfied
2+
--> $DIR/migrate-fail.rs:13:38
33
|
44
LL | let arr: [Option<Bar>; 2] = [x; 2];
5-
| ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
5+
| ^ the trait `Copy` is not implemented for `Bar`
6+
|
7+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
8+
= note: the `Copy` trait is required because this value will be copied for each element of the array
9+
help: consider annotating `Bar` with `#[derive(Copy)]`
10+
|
11+
LL | #[derive(Copy)]
612
|
7-
= help: the trait `Copy` is implemented for `Option<T>`
8-
= note: the `Copy` trait is required because the repeated element will be copied
913

10-
error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
11-
--> $DIR/migrate-fail.rs:19:37
14+
error[E0277]: the trait bound `Bar: Copy` is not satisfied
15+
--> $DIR/migrate-fail.rs:19:38
1216
|
1317
LL | let arr: [Option<Bar>; 2] = [x; 2];
14-
| ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
18+
| ^ the trait `Copy` is not implemented for `Bar`
19+
|
20+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
21+
= note: the `Copy` trait is required because this value will be copied for each element of the array
22+
help: consider annotating `Bar` with `#[derive(Copy)]`
23+
|
24+
LL | #[derive(Copy)]
1525
|
16-
= help: the trait `Copy` is implemented for `Option<T>`
17-
= note: the `Copy` trait is required because the repeated element will be copied
1826

1927
error: aborting due to 2 previous errors
2028

src/test/ui/consts/const-blocks/nll-fail.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ mod non_constants {
1010
fn no_impl_copy_empty_value_multiple_elements() {
1111
let x = None;
1212
let arr: [Option<Bar>; 2] = [x; 2];
13-
//~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
13+
//~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
1414
}
1515

1616
fn no_impl_copy_value_multiple_elements() {
1717
let x = Some(Bar);
1818
let arr: [Option<Bar>; 2] = [x; 2];
19-
//~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
19+
//~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
2020
}
2121
}
2222

src/test/ui/consts/const-blocks/nll-fail.stderr

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
1-
error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
2-
--> $DIR/nll-fail.rs:12:37
1+
error[E0277]: the trait bound `Bar: Copy` is not satisfied
2+
--> $DIR/nll-fail.rs:12:38
33
|
44
LL | let arr: [Option<Bar>; 2] = [x; 2];
5-
| ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
5+
| ^ the trait `Copy` is not implemented for `Bar`
6+
|
7+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
8+
= note: the `Copy` trait is required because this value will be copied for each element of the array
9+
help: consider annotating `Bar` with `#[derive(Copy)]`
10+
|
11+
LL | #[derive(Copy)]
612
|
7-
= help: the trait `Copy` is implemented for `Option<T>`
8-
= note: the `Copy` trait is required because the repeated element will be copied
913

10-
error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
11-
--> $DIR/nll-fail.rs:18:37
14+
error[E0277]: the trait bound `Bar: Copy` is not satisfied
15+
--> $DIR/nll-fail.rs:18:38
1216
|
1317
LL | let arr: [Option<Bar>; 2] = [x; 2];
14-
| ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
18+
| ^ the trait `Copy` is not implemented for `Bar`
19+
|
20+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
21+
= note: the `Copy` trait is required because this value will be copied for each element of the array
22+
help: consider annotating `Bar` with `#[derive(Copy)]`
23+
|
24+
LL | #[derive(Copy)]
1525
|
16-
= help: the trait `Copy` is implemented for `Option<T>`
17-
= note: the `Copy` trait is required because the repeated element will be copied
1826

1927
error: aborting due to 2 previous errors
2028

src/test/ui/consts/const-blocks/trait-error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ struct Foo<T>(T);
33

44
fn main() {
55
[Foo(String::new()); 4];
6-
//~^ ERROR the trait bound `Foo<String>: Copy` is not satisfied [E0277]
6+
//~^ ERROR the trait bound `String: Copy` is not satisfied [E0277]
77
}

src/test/ui/consts/const-blocks/trait-error.stderr

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
error[E0277]: the trait bound `Foo<String>: Copy` is not satisfied
2-
--> $DIR/trait-error.rs:5:5
1+
error[E0277]: the trait bound `String: Copy` is not satisfied
2+
--> $DIR/trait-error.rs:5:6
33
|
44
LL | [Foo(String::new()); 4];
5-
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Foo<String>`
5+
| ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
66
|
7-
= help: the trait `Copy` is implemented for `Foo<T>`
8-
= note: the `Copy` trait is required because the repeated element will be copied
7+
note: required because of the requirements on the impl of `Copy` for `Foo<String>`
8+
--> $DIR/trait-error.rs:1:10
9+
|
10+
LL | #[derive(Copy, Clone)]
11+
| ^^^^
12+
= note: the `Copy` trait is required because this value will be copied for each element of the array
13+
= help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
14+
= help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
15+
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
916

1017
error: aborting due to previous error
1118

src/test/ui/consts/const-fn-in-vec.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
error[E0277]: the trait bound `String: Copy` is not satisfied
2-
--> $DIR/const-fn-in-vec.rs:4:32
2+
--> $DIR/const-fn-in-vec.rs:4:33
33
|
44
LL | let strings: [String; 5] = [String::new(); 5];
5-
| ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
5+
| ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
66
|
7-
= note: the `Copy` trait is required because the repeated element will be copied
7+
= note: the `Copy` trait is required because this value will be copied for each element of the array
88
= help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
99
= help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
1010

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(nll)]
2+
3+
#[derive(Clone)]
4+
struct Foo<'a>(fn(&'a ()) -> &'a ());
5+
6+
impl Copy for Foo<'static> {}
7+
8+
fn mk_foo<'a>() -> Foo<'a> {
9+
println!("mk_foo");
10+
Foo(|x| x)
11+
}
12+
13+
fn foo<'a>() -> [Foo<'a>; 100] {
14+
[mk_foo::<'a>(); 100] //~ ERROR lifetime may not live long enough
15+
}
16+
17+
fn main() {
18+
foo();
19+
}

0 commit comments

Comments
 (0)