From 4e6e68e27a36f38da58dcbadd31c8f5d591f4571 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Apr 2022 16:38:48 +0000 Subject: [PATCH 1/5] Check that repeat expression elements are Copy (ignoring lifetimes) in typeck and that they are Copy (with proper lifetime checks) in borrowck --- compiler/rustc_borrowck/src/type_check/mod.rs | 51 ++++--------------- compiler/rustc_typeck/src/check/expr.rs | 28 ++++++++++ .../ui/array-slice-vec/repeat_empty_ok.stderr | 8 +-- .../issues/issue-61336-2.stderr | 4 +- .../const-generics/issues/issue-61336.stderr | 4 +- .../const-blocks/fn-call-in-non-const.rs | 2 +- .../const-blocks/fn-call-in-non-const.stderr | 12 +++-- .../ui/consts/const-blocks/migrate-fail.rs | 4 +- .../consts/const-blocks/migrate-fail.stderr | 24 ++++++--- src/test/ui/consts/const-blocks/nll-fail.rs | 4 +- .../ui/consts/const-blocks/nll-fail.stderr | 24 ++++++--- .../ui/consts/const-blocks/trait-error.rs | 2 +- .../ui/consts/const-blocks/trait-error.stderr | 15 ++++-- src/test/ui/consts/const-fn-in-vec.stderr | 4 +- src/test/ui/lifetimes/copy_modulo_regions.rs | 19 +++++++ .../ui/lifetimes/copy_modulo_regions.stderr | 14 +++++ src/test/ui/repeat-to-run-dtor-twice.stderr | 4 +- 17 files changed, 141 insertions(+), 82 deletions(-) create mode 100644 src/test/ui/lifetimes/copy_modulo_regions.rs create mode 100644 src/test/ui/lifetimes/copy_modulo_regions.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6dcdd46816e..c4a190b44cb 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -37,18 +37,13 @@ use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; -use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use rustc_trait_selection::traits::query::Fallible; -use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; +use rustc_trait_selection::traits::PredicateObligation; -use rustc_const_eval::transform::{ - check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression, -}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; @@ -1868,41 +1863,17 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L Operand::Move(place) => { // Make sure that repeated elements implement `Copy`. let span = body.source_info(location).span; - let ty = operand.ty(body, tcx); - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { - let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); - let is_const_fn = - is_const_fn_in_array_repeat_expression(&ccx, &place, &body); + let ty = place.ty(body, tcx).ty; + let trait_ref = ty::TraitRef::new( + tcx.require_lang_item(LangItem::Copy, Some(span)), + tcx.mk_substs_trait(ty, &[]), + ); - debug!("check_rvalue: is_const_fn={:?}", is_const_fn); - - let def_id = body.source.def_id().expect_local(); - let obligation = traits::Obligation::new( - ObligationCause::new( - span, - self.tcx().hir().local_def_id_to_hir_id(def_id), - traits::ObligationCauseCode::RepeatElementCopy { - is_const_fn, - }, - ), - self.param_env, - ty::Binder::dummy(ty::TraitRef::new( - self.tcx().require_lang_item( - LangItem::Copy, - Some(self.last_span), - ), - tcx.mk_substs_trait(ty, &[]), - )) - .without_const() - .to_predicate(self.tcx()), - ); - self.infcx.report_selection_error( - obligation.clone(), - &obligation, - &traits::SelectionError::Unimplemented, - false, - ); - } + self.prove_trait_ref( + trait_ref, + Locations::Single(location), + ConstraintCategory::CopyBound, + ); } } } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 47cb1ea48cb..7111bbaa3cd 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1292,6 +1292,34 @@ fn check_expr_repeat( return tcx.ty_error(); } + let is_const = match &element.kind { + hir::ExprKind::ConstBlock(..) => true, + hir::ExprKind::Path(qpath) => { + let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); + matches!( + res, + Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) + ) + } + _ => false, + }; + + if !is_const { + let is_const_fn = match element.kind { + hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { + ty::FnDef(def_id, _) => tcx.is_const_fn(def_id), + _ => false, + }, + _ => false, + }; + + if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { + let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn }; + self.require_type_meets(element_ty, element.span, code, lang_item); + } + } + tcx.mk_ty(ty::Array(t, count)) } diff --git a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr index eba1a8e2278..cf5efdaab2a 100644 --- a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr +++ b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied - --> $DIR/repeat_empty_ok.rs:8:19 + --> $DIR/repeat_empty_ok.rs:8:20 | LL | let headers = [Header{value: &[]}; 128]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` | = note: the `Copy` trait is required because the repeated element will be copied help: consider annotating `Header<'_>` with `#[derive(Copy)]` @@ -11,10 +11,10 @@ LL | #[derive(Copy)] | error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied - --> $DIR/repeat_empty_ok.rs:13:19 + --> $DIR/repeat_empty_ok.rs:13:20 | LL | let headers = [Header{value: &[0]}; 128]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` | = note: the `Copy` trait is required because the repeated element will be copied help: consider annotating `Header<'_>` with `#[derive(Copy)]` diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr index 48aaaf5e544..ccc42f08acf 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/issue-61336-2.rs:6:5 + --> $DIR/issue-61336-2.rs:6:6 | LL | [x; { N }] - | ^^^^^^^^^^ the trait `Copy` is not implemented for `T` + | ^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr index 665a1a677a1..a6a7fee0007 100644 --- a/src/test/ui/const-generics/issues/issue-61336.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/issue-61336.rs:6:5 + --> $DIR/issue-61336.rs:6:6 | LL | [x; N] - | ^^^^^^ the trait `Copy` is not implemented for `T` + | ^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` diff --git a/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs b/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs index 19217843759..18b4dc714de 100644 --- a/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs +++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs @@ -12,5 +12,5 @@ const fn copy() -> u32 { fn main() { let _: [u32; 2] = [copy(); 2]; let _: [Option; 2] = [no_copy(); 2]; - //~^ ERROR the trait bound `Option: Copy` is not satisfied + //~^ ERROR the trait bound `Bar: Copy` is not satisfied } diff --git a/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr index 52a1669e330..ef05f723aca 100644 --- a/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr +++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -1,13 +1,17 @@ -error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/fn-call-in-non-const.rs:14:31 +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/fn-call-in-non-const.rs:14:32 | LL | let _: [Option; 2] = [no_copy(); 2]; - | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` + | ^^^^^^^^^ the trait `Copy` is not implemented for `Bar` | - = help: the trait `Copy` is implemented for `Option` + = note: required because of the requirements on the impl of `Copy` for `Option` = note: the `Copy` trait is required because the repeated element will be copied = 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];` = help: create an inline `const` block, see RFC #2920 for more information +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | error: aborting due to previous error diff --git a/src/test/ui/consts/const-blocks/migrate-fail.rs b/src/test/ui/consts/const-blocks/migrate-fail.rs index bb12139a7ba..d5a17249cc9 100644 --- a/src/test/ui/consts/const-blocks/migrate-fail.rs +++ b/src/test/ui/consts/const-blocks/migrate-fail.rs @@ -11,13 +11,13 @@ mod non_constants { fn no_impl_copy_empty_value_multiple_elements() { let x = None; let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277] } fn no_impl_copy_value_multiple_elements() { let x = Some(Bar); let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277] } } diff --git a/src/test/ui/consts/const-blocks/migrate-fail.stderr b/src/test/ui/consts/const-blocks/migrate-fail.stderr index 318fec60290..1898ab3b469 100644 --- a/src/test/ui/consts/const-blocks/migrate-fail.stderr +++ b/src/test/ui/consts/const-blocks/migrate-fail.stderr @@ -1,20 +1,28 @@ -error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/migrate-fail.rs:13:37 +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/migrate-fail.rs:13:38 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `Copy` is not implemented for `Option` + | ^ the trait `Copy` is not implemented for `Bar` | - = help: the trait `Copy` is implemented for `Option` + = note: required because of the requirements on the impl of `Copy` for `Option` = note: the `Copy` trait is required because the repeated element will be copied +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | -error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/migrate-fail.rs:19:37 +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/migrate-fail.rs:19:38 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `Copy` is not implemented for `Option` + | ^ the trait `Copy` is not implemented for `Bar` | - = help: the trait `Copy` is implemented for `Option` + = note: required because of the requirements on the impl of `Copy` for `Option` = note: the `Copy` trait is required because the repeated element will be copied +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-blocks/nll-fail.rs b/src/test/ui/consts/const-blocks/nll-fail.rs index 871387c1fd0..9d4aef39e54 100644 --- a/src/test/ui/consts/const-blocks/nll-fail.rs +++ b/src/test/ui/consts/const-blocks/nll-fail.rs @@ -10,13 +10,13 @@ mod non_constants { fn no_impl_copy_empty_value_multiple_elements() { let x = None; let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277] } fn no_impl_copy_value_multiple_elements() { let x = Some(Bar); let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277] } } diff --git a/src/test/ui/consts/const-blocks/nll-fail.stderr b/src/test/ui/consts/const-blocks/nll-fail.stderr index 5a34361aa83..3201a1e68e8 100644 --- a/src/test/ui/consts/const-blocks/nll-fail.stderr +++ b/src/test/ui/consts/const-blocks/nll-fail.stderr @@ -1,20 +1,28 @@ -error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/nll-fail.rs:12:37 +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/nll-fail.rs:12:38 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `Copy` is not implemented for `Option` + | ^ the trait `Copy` is not implemented for `Bar` | - = help: the trait `Copy` is implemented for `Option` + = note: required because of the requirements on the impl of `Copy` for `Option` = note: the `Copy` trait is required because the repeated element will be copied +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | -error[E0277]: the trait bound `Option: Copy` is not satisfied - --> $DIR/nll-fail.rs:18:37 +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/nll-fail.rs:18:38 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `Copy` is not implemented for `Option` + | ^ the trait `Copy` is not implemented for `Bar` | - = help: the trait `Copy` is implemented for `Option` + = note: required because of the requirements on the impl of `Copy` for `Option` = note: the `Copy` trait is required because the repeated element will be copied +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-blocks/trait-error.rs b/src/test/ui/consts/const-blocks/trait-error.rs index 5a614cbdd15..49d1e9b9434 100644 --- a/src/test/ui/consts/const-blocks/trait-error.rs +++ b/src/test/ui/consts/const-blocks/trait-error.rs @@ -3,5 +3,5 @@ fn main() { [Foo(String::new()); 4]; - //~^ ERROR the trait bound `Foo: Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Copy` is not satisfied [E0277] } diff --git a/src/test/ui/consts/const-blocks/trait-error.stderr b/src/test/ui/consts/const-blocks/trait-error.stderr index 6979ff36176..8a6ca61e0c5 100644 --- a/src/test/ui/consts/const-blocks/trait-error.stderr +++ b/src/test/ui/consts/const-blocks/trait-error.stderr @@ -1,11 +1,18 @@ -error[E0277]: the trait bound `Foo: Copy` is not satisfied - --> $DIR/trait-error.rs:5:5 +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/trait-error.rs:5:6 | LL | [Foo(String::new()); 4]; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | - = help: the trait `Copy` is implemented for `Foo` +note: required because of the requirements on the impl of `Copy` for `Foo` + --> $DIR/trait-error.rs:1:10 + | +LL | #[derive(Copy, Clone)] + | ^^^^ = note: the `Copy` trait is required because the repeated element will be copied + = 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];` + = help: create an inline `const` block, see RFC #2920 for more information + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/consts/const-fn-in-vec.stderr b/src/test/ui/consts/const-fn-in-vec.stderr index f02cb4f1ff1..0572dda7470 100644 --- a/src/test/ui/consts/const-fn-in-vec.stderr +++ b/src/test/ui/consts/const-fn-in-vec.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/const-fn-in-vec.rs:4:32 + --> $DIR/const-fn-in-vec.rs:4:33 | LL | let strings: [String; 5] = [String::new(); 5]; - | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | = note: the `Copy` trait is required because the repeated element will be copied = 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];` diff --git a/src/test/ui/lifetimes/copy_modulo_regions.rs b/src/test/ui/lifetimes/copy_modulo_regions.rs new file mode 100644 index 00000000000..1d5d90ffcb4 --- /dev/null +++ b/src/test/ui/lifetimes/copy_modulo_regions.rs @@ -0,0 +1,19 @@ +#![feature(nll)] + +#[derive(Clone)] +struct Foo<'a>(fn(&'a ()) -> &'a ()); + +impl Copy for Foo<'static> {} + +fn mk_foo<'a>() -> Foo<'a> { + println!("mk_foo"); + Foo(|x| x) +} + +fn foo<'a>() -> [Foo<'a>; 100] { + [mk_foo::<'a>(); 100] //~ ERROR lifetime may not live long enough +} + +fn main() { + foo(); +} diff --git a/src/test/ui/lifetimes/copy_modulo_regions.stderr b/src/test/ui/lifetimes/copy_modulo_regions.stderr new file mode 100644 index 00000000000..e027bc45426 --- /dev/null +++ b/src/test/ui/lifetimes/copy_modulo_regions.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/copy_modulo_regions.rs:14:5 + | +LL | fn foo<'a>() -> [Foo<'a>; 100] { + | -- lifetime `'a` defined here +LL | [mk_foo::<'a>(); 100] + | ^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Foo<'a>` is invariant over the parameter `'a` + = help: see for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-to-run-dtor-twice.stderr index 904413712cd..fd64ce8bcea 100644 --- a/src/test/ui/repeat-to-run-dtor-twice.stderr +++ b/src/test/ui/repeat-to-run-dtor-twice.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `Foo: Copy` is not satisfied - --> $DIR/repeat-to-run-dtor-twice.rs:17:13 + --> $DIR/repeat-to-run-dtor-twice.rs:17:15 | LL | let _ = [ a; 5 ]; - | ^^^^^^^^ the trait `Copy` is not implemented for `Foo` + | ^ the trait `Copy` is not implemented for `Foo` | = note: the `Copy` trait is required because the repeated element will be copied help: consider annotating `Foo` with `#[derive(Copy)]` From bc14b6bea6a410f11a7ea5db84ad753673b78150 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 12 Apr 2022 07:28:07 +0000 Subject: [PATCH 2/5] Add new repeat expr test. Also add repeat expr test folder and move all related tests to it --- src/test/ui/repeat-expr/infer.rs | 16 ++++++++++++++++ .../{ => repeat-expr}/repeat-expr-in-static.rs | 0 .../repeat-to-run-dtor-twice.rs | 0 .../repeat-to-run-dtor-twice.stderr | 0 src/test/ui/{ => repeat-expr}/repeat_count.rs | 0 .../ui/{ => repeat-expr}/repeat_count.stderr | 0 src/tools/tidy/src/ui_tests.rs | 2 +- 7 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/repeat-expr/infer.rs rename src/test/ui/{ => repeat-expr}/repeat-expr-in-static.rs (100%) rename src/test/ui/{ => repeat-expr}/repeat-to-run-dtor-twice.rs (100%) rename src/test/ui/{ => repeat-expr}/repeat-to-run-dtor-twice.stderr (100%) rename src/test/ui/{ => repeat-expr}/repeat_count.rs (100%) rename src/test/ui/{ => repeat-expr}/repeat_count.stderr (100%) diff --git a/src/test/ui/repeat-expr/infer.rs b/src/test/ui/repeat-expr/infer.rs new file mode 100644 index 00000000000..8197713b97e --- /dev/null +++ b/src/test/ui/repeat-expr/infer.rs @@ -0,0 +1,16 @@ +// check-pass + +#[derive(Clone, Default)] +struct MaybeCopy(T); + +impl Copy for MaybeCopy {} + +fn is_copy(x: T) { + println!("{}", std::any::type_name::()); +} + +fn main() { + is_copy(MaybeCopy::default()); + [MaybeCopy::default(); 13]; + // didn't work, because `Copy` was only checked in the mir +} diff --git a/src/test/ui/repeat-expr-in-static.rs b/src/test/ui/repeat-expr/repeat-expr-in-static.rs similarity index 100% rename from src/test/ui/repeat-expr-in-static.rs rename to src/test/ui/repeat-expr/repeat-expr-in-static.rs diff --git a/src/test/ui/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.rs similarity index 100% rename from src/test/ui/repeat-to-run-dtor-twice.rs rename to src/test/ui/repeat-expr/repeat-to-run-dtor-twice.rs diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr similarity index 100% rename from src/test/ui/repeat-to-run-dtor-twice.stderr rename to src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr diff --git a/src/test/ui/repeat_count.rs b/src/test/ui/repeat-expr/repeat_count.rs similarity index 100% rename from src/test/ui/repeat_count.rs rename to src/test/ui/repeat-expr/repeat_count.rs diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat-expr/repeat_count.stderr similarity index 100% rename from src/test/ui/repeat_count.stderr rename to src/test/ui/repeat-expr/repeat_count.stderr diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 1f6f2336481..6b715f727b2 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -7,7 +7,7 @@ const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. -const ROOT_ENTRY_LIMIT: usize = 980; +const ROOT_ENTRY_LIMIT: usize = 977; const ISSUES_ENTRY_LIMIT: usize = 2278; fn check_entries(path: &Path, bad: &mut bool) { From 018f9347fcc265b21e5269254c50b73ac8c2a3de Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 28 Apr 2022 09:40:42 +0000 Subject: [PATCH 3/5] Update the diagnostic message to match the new span --- .../src/traits/error_reporting/suggestions.rs | 2 +- src/test/ui/array-slice-vec/repeat_empty_ok.stderr | 4 ++-- src/test/ui/const-generics/issues/issue-61336-2.stderr | 2 +- src/test/ui/const-generics/issues/issue-61336.stderr | 2 +- src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr | 2 +- src/test/ui/consts/const-blocks/migrate-fail.stderr | 4 ++-- src/test/ui/consts/const-blocks/nll-fail.stderr | 4 ++-- src/test/ui/consts/const-blocks/trait-error.stderr | 2 +- src/test/ui/consts/const-fn-in-vec.stderr | 2 +- src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 0c1ca65c48f..187df6f7de0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2227,7 +2227,7 @@ fn note_obligation_cause_code( } ObligationCauseCode::RepeatElementCopy { is_const_fn } => { err.note( - "the `Copy` trait is required because the repeated element will be copied", + "the `Copy` trait is required because this value will be copied for each element of the array", ); if is_const_fn { diff --git a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr index cf5efdaab2a..724bdcd920a 100644 --- a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr +++ b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied LL | let headers = [Header{value: &[]}; 128]; | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` | - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Header<'_>` with `#[derive(Copy)]` | LL | #[derive(Copy)] @@ -16,7 +16,7 @@ error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied LL | let headers = [Header{value: &[0]}; 128]; | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>` | - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Header<'_>` with `#[derive(Copy)]` | LL | #[derive(Copy)] diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr index ccc42f08acf..5bb35669623 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied LL | [x; { N }] | ^ the trait `Copy` is not implemented for `T` | - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider restricting type parameter `T` | LL | fn g(x: T) -> [T; N] { diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr index a6a7fee0007..8d9e545b456 100644 --- a/src/test/ui/const-generics/issues/issue-61336.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied LL | [x; N] | ^ the trait `Copy` is not implemented for `T` | - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider restricting type parameter `T` | LL | fn g(x: T) -> [T; N] { diff --git a/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr index ef05f723aca..5306fed2251 100644 --- a/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr +++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -5,7 +5,7 @@ LL | let _: [Option; 2] = [no_copy(); 2]; | ^^^^^^^^^ the trait `Copy` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Copy` for `Option` - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array = 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];` = help: create an inline `const` block, see RFC #2920 for more information help: consider annotating `Bar` with `#[derive(Copy)]` diff --git a/src/test/ui/consts/const-blocks/migrate-fail.stderr b/src/test/ui/consts/const-blocks/migrate-fail.stderr index 1898ab3b469..2e7ff5cb8b3 100644 --- a/src/test/ui/consts/const-blocks/migrate-fail.stderr +++ b/src/test/ui/consts/const-blocks/migrate-fail.stderr @@ -5,7 +5,7 @@ LL | let arr: [Option; 2] = [x; 2]; | ^ the trait `Copy` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Copy` for `Option` - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Bar` with `#[derive(Copy)]` | LL | #[derive(Copy)] @@ -18,7 +18,7 @@ LL | let arr: [Option; 2] = [x; 2]; | ^ the trait `Copy` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Copy` for `Option` - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Bar` with `#[derive(Copy)]` | LL | #[derive(Copy)] diff --git a/src/test/ui/consts/const-blocks/nll-fail.stderr b/src/test/ui/consts/const-blocks/nll-fail.stderr index 3201a1e68e8..c0d273b5a9a 100644 --- a/src/test/ui/consts/const-blocks/nll-fail.stderr +++ b/src/test/ui/consts/const-blocks/nll-fail.stderr @@ -5,7 +5,7 @@ LL | let arr: [Option; 2] = [x; 2]; | ^ the trait `Copy` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Copy` for `Option` - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Bar` with `#[derive(Copy)]` | LL | #[derive(Copy)] @@ -18,7 +18,7 @@ LL | let arr: [Option; 2] = [x; 2]; | ^ the trait `Copy` is not implemented for `Bar` | = note: required because of the requirements on the impl of `Copy` for `Option` - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Bar` with `#[derive(Copy)]` | LL | #[derive(Copy)] diff --git a/src/test/ui/consts/const-blocks/trait-error.stderr b/src/test/ui/consts/const-blocks/trait-error.stderr index 8a6ca61e0c5..ece200ad10b 100644 --- a/src/test/ui/consts/const-blocks/trait-error.stderr +++ b/src/test/ui/consts/const-blocks/trait-error.stderr @@ -9,7 +9,7 @@ note: required because of the requirements on the impl of `Copy` for `Foo for more information = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/const-fn-in-vec.stderr b/src/test/ui/consts/const-fn-in-vec.stderr index 0572dda7470..9eb7524b504 100644 --- a/src/test/ui/consts/const-fn-in-vec.stderr +++ b/src/test/ui/consts/const-fn-in-vec.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | let strings: [String; 5] = [String::new(); 5]; | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array = 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];` = help: create an inline `const` block, see RFC #2920 for more information diff --git a/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr index fd64ce8bcea..36b93616375 100644 --- a/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr +++ b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `Foo: Copy` is not satisfied LL | let _ = [ a; 5 ]; | ^ the trait `Copy` is not implemented for `Foo` | - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Foo` with `#[derive(Copy)]` | LL | #[derive(Copy)] From be54947315b6d2892ed09281a7770e1f09c673e7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 29 Apr 2022 18:49:02 +0000 Subject: [PATCH 4/5] Extract copy bound check into a function --- compiler/rustc_typeck/src/check/expr.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 7111bbaa3cd..8dd288e5555 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1292,6 +1292,18 @@ fn check_expr_repeat( return tcx.ty_error(); } + self.check_repeat_element_needs_copy_bound(element, count, element_ty); + + tcx.mk_ty(ty::Array(t, count)) + } + + fn check_repeat_element_needs_copy_bound( + &self, + element: &hir::Expr<'_>, + count: ty::Const<'tcx>, + element_ty: Ty<'tcx>, + ) { + let tcx = self.tcx; let is_const = match &element.kind { hir::ExprKind::ConstBlock(..) => true, hir::ExprKind::Path(qpath) => { @@ -1303,7 +1315,6 @@ fn check_expr_repeat( } _ => false, }; - if !is_const { let is_const_fn = match element.kind { hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { @@ -1319,8 +1330,6 @@ fn check_expr_repeat( self.require_type_meets(element_ty, element.span, code, lang_item); } } - - tcx.mk_ty(ty::Array(t, count)) } fn check_expr_tuple( From 67ce547f474fbe34e8aafe4bfc284c3856673744 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 29 Apr 2022 18:56:57 +0000 Subject: [PATCH 5/5] Refactor and document the repeat length check --- compiler/rustc_typeck/src/check/expr.rs | 41 +++++++++++++------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8dd288e5555..a1e8d2040dd 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1304,31 +1304,34 @@ fn check_repeat_element_needs_copy_bound( element_ty: Ty<'tcx>, ) { let tcx = self.tcx; - let is_const = match &element.kind { - hir::ExprKind::ConstBlock(..) => true, + // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy. + match &element.kind { + hir::ExprKind::ConstBlock(..) => return, hir::ExprKind::Path(qpath) => { let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); - matches!( - res, - Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) - ) + if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res + { + return; + } } + _ => {} + } + // If someone calls a const fn, they can extract that call out into a separate constant (or a const + // block in the future), so we check that to tell them that in the diagnostic. Does not affect typeck. + let is_const_fn = match element.kind { + hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { + ty::FnDef(def_id, _) => tcx.is_const_fn(def_id), + _ => false, + }, _ => false, }; - if !is_const { - let is_const_fn = match element.kind { - hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { - ty::FnDef(def_id, _) => tcx.is_const_fn(def_id), - _ => false, - }, - _ => false, - }; - if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { - let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); - let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn }; - self.require_type_meets(element_ty, element.span, code, lang_item); - } + // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we + // don't copy that one element, we move it. Only check for Copy if the length is larger. + if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { + let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn }; + self.require_type_meets(element_ty, element.span, code, lang_item); } }