Skip to content

Commit 4e6e68e

Browse files
committed
Check that repeat expression elements are Copy (ignoring lifetimes) in typeck and that they are Copy (with proper lifetime checks) in borrowck
1 parent 0e7915d commit 4e6e68e

File tree

17 files changed

+142
-83
lines changed

17 files changed

+142
-83
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 12 additions & 41 deletions
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_typeck/src/check/expr.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12921292
return tcx.ty_error();
12931293
}
12941294

1295+
let is_const = match &element.kind {
1296+
hir::ExprKind::ConstBlock(..) => true,
1297+
hir::ExprKind::Path(qpath) => {
1298+
let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
1299+
matches!(
1300+
res,
1301+
Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _)
1302+
)
1303+
}
1304+
_ => false,
1305+
};
1306+
1307+
if !is_const {
1308+
let is_const_fn = match element.kind {
1309+
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
1310+
ty::FnDef(def_id, _) => tcx.is_const_fn(def_id),
1311+
_ => false,
1312+
},
1313+
_ => false,
1314+
};
1315+
1316+
if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
1317+
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
1318+
let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn };
1319+
self.require_type_meets(element_ty, element.span, code, lang_item);
1320+
}
1321+
}
1322+
12951323
tcx.mk_ty(ty::Array(t, count))
12961324
}
12971325

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
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
|
77
= note: the `Copy` trait is required because the repeated element will be copied
88
help: consider annotating `Header<'_>` with `#[derive(Copy)]`
@@ -11,10 +11,10 @@ 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
|
1919
= note: the `Copy` trait is required because the repeated element will be copied
2020
help: consider annotating `Header<'_>` with `#[derive(Copy)]`

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
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
|
77
= note: the `Copy` trait is required because the repeated element will be copied
88
help: consider restricting type parameter `T`

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
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
|
77
= note: the `Copy` trait is required because the repeated element will be copied
88
help: consider restricting type parameter `T`

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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 8 additions & 4 deletions
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>`
7+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
88
= note: the `Copy` trait is required because the repeated element will be copied
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 16 additions & 8 deletions
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`
66
|
7-
= help: the trait `Copy` is implemented for `Option<T>`
7+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
88
= note: the `Copy` trait is required because the repeated element will be copied
9+
help: consider annotating `Bar` with `#[derive(Copy)]`
10+
|
11+
LL | #[derive(Copy)]
12+
|
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`
1519
|
16-
= help: the trait `Copy` is implemented for `Option<T>`
20+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
1721
= note: the `Copy` trait is required because the repeated element will be copied
22+
help: consider annotating `Bar` with `#[derive(Copy)]`
23+
|
24+
LL | #[derive(Copy)]
25+
|
1826

1927
error: aborting due to 2 previous errors
2028

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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 16 additions & 8 deletions
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`
66
|
7-
= help: the trait `Copy` is implemented for `Option<T>`
7+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
88
= note: the `Copy` trait is required because the repeated element will be copied
9+
help: consider annotating `Bar` with `#[derive(Copy)]`
10+
|
11+
LL | #[derive(Copy)]
12+
|
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`
1519
|
16-
= help: the trait `Copy` is implemented for `Option<T>`
20+
= note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
1721
= note: the `Copy` trait is required because the repeated element will be copied
22+
help: consider annotating `Bar` with `#[derive(Copy)]`
23+
|
24+
LL | #[derive(Copy)]
25+
|
1826

1927
error: aborting due to 2 previous errors
2028

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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 11 additions & 4 deletions
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>`
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+
| ^^^^
812
= note: the `Copy` trait is required because the repeated element will be copied
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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
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
|
77
= note: the `Copy` trait is required because the repeated element will be copied
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];`
Lines changed: 19 additions & 0 deletions
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+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/copy_modulo_regions.rs:14:5
3+
|
4+
LL | fn foo<'a>() -> [Foo<'a>; 100] {
5+
| -- lifetime `'a` defined here
6+
LL | [mk_foo::<'a>(); 100]
7+
| ^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
8+
|
9+
= note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant
10+
= note: the struct `Foo<'a>` is invariant over the parameter `'a`
11+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
12+
13+
error: aborting due to previous error
14+

src/test/ui/repeat-to-run-dtor-twice.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the trait bound `Foo: Copy` is not satisfied
2-
--> $DIR/repeat-to-run-dtor-twice.rs:17:13
2+
--> $DIR/repeat-to-run-dtor-twice.rs:17:15
33
|
44
LL | let _ = [ a; 5 ];
5-
| ^^^^^^^^ the trait `Copy` is not implemented for `Foo`
5+
| ^ the trait `Copy` is not implemented for `Foo`
66
|
77
= note: the `Copy` trait is required because the repeated element will be copied
88
help: consider annotating `Foo` with `#[derive(Copy)]`

0 commit comments

Comments
 (0)