Skip to content

Commit f02f7b0

Browse files
Rollup merge of #81503 - henryboisdequin:fix-const-fn-arr-err-msg, r=estebank
Suggest to create a new `const` item if the `fn` in the array is a `const fn` Fixes #73734. If the `fn` in the array repeat expression is a `const fn`, suggest creating a new `const` item. On nightly, suggest creating an inline `const` block. This PR also removes the `suggest_const_in_array_repeat_expressions` as it is no longer necessary. Example: ```rust fn main() { // Should not compile but hint to create a new const item (stable) or an inline const block (nightly) let strings: [String; 5] = [String::new(); 5]; println!("{:?}", strings); } ``` Gives this error: ``` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:3:32 | 2 | let strings: [String; 5] = [String::new(); 5]; | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `String` | = note: the `Copy` trait is required because the repeated element will be copied ``` With this change, this is the error message: ``` error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:3:32 | LL | let strings: [String; 5] = [String::new(); 5]; | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | = help: moving the function call to a new `const` item will resolve the error ```
2 parents 9503ea1 + 64fe2c1 commit f02f7b0

File tree

8 files changed

+90
-4
lines changed

8 files changed

+90
-4
lines changed

compiler/rustc_middle/src/traits/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,10 @@ pub enum ObligationCauseCode<'tcx> {
228228
/// Inline asm operand type must be `Sized`.
229229
InlineAsmSized,
230230
/// `[T, ..n]` implies that `T` must be `Copy`.
231-
RepeatVec,
231+
/// If the function in the array repeat expression is a `const fn`,
232+
/// display a help message suggesting to move the function call to a
233+
/// new `const` item while saying that `T` doesn't implement `Copy`.
234+
RepeatVec(bool),
232235

233236
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
234237
FieldSized {

compiler/rustc_mir/src/borrow_check/type_check/mod.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}
4343
use crate::dataflow::impls::MaybeInitializedPlaces;
4444
use crate::dataflow::move_paths::MoveData;
4545
use crate::dataflow::ResultsCursor;
46+
use crate::transform::{
47+
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
48+
};
4649

4750
use crate::borrow_check::{
4851
borrow_set::BorrowSet,
@@ -1988,18 +1991,24 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19881991
Operand::Copy(..) | Operand::Constant(..) => {
19891992
// These are always okay: direct use of a const, or a value that can evidently be copied.
19901993
}
1991-
Operand::Move(_) => {
1994+
Operand::Move(place) => {
19921995
// Make sure that repeated elements implement `Copy`.
19931996
let span = body.source_info(location).span;
19941997
let ty = operand.ty(body, tcx);
19951998
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
1999+
let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env);
2000+
let is_const_fn =
2001+
is_const_fn_in_array_repeat_expression(&ccx, &place, &body);
2002+
2003+
debug!("check_rvalue: is_const_fn={:?}", is_const_fn);
2004+
19962005
let def_id = body.source.def_id().expect_local();
19972006
self.infcx.report_selection_error(
19982007
&traits::Obligation::new(
19992008
ObligationCause::new(
20002009
span,
20012010
self.tcx().hir().local_def_id_to_hir_id(def_id),
2002-
traits::ObligationCauseCode::RepeatVec,
2011+
traits::ObligationCauseCode::RepeatVec(is_const_fn),
20032012
),
20042013
self.param_env,
20052014
ty::Binder::bind(ty::TraitRef::new(

compiler/rustc_mir/src/transform/promote_consts.rs

+35
Original file line numberDiff line numberDiff line change
@@ -1231,3 +1231,38 @@ pub fn promote_candidates<'tcx>(
12311231

12321232
promotions
12331233
}
1234+
1235+
/// This function returns `true` if the function being called in the array
1236+
/// repeat expression is a `const` function.
1237+
crate fn is_const_fn_in_array_repeat_expression<'tcx>(
1238+
ccx: &ConstCx<'_, 'tcx>,
1239+
place: &Place<'tcx>,
1240+
body: &Body<'tcx>,
1241+
) -> bool {
1242+
match place.as_local() {
1243+
// rule out cases such as: `let my_var = some_fn(); [my_var; N]`
1244+
Some(local) if body.local_decls[local].is_user_variable() => return false,
1245+
None => return false,
1246+
_ => {}
1247+
}
1248+
1249+
for block in body.basic_blocks() {
1250+
if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
1251+
&block.terminator
1252+
{
1253+
if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
1254+
if let ty::FnDef(def_id, _) = *ty.kind() {
1255+
if let Some((destination_place, _)) = destination {
1256+
if destination_place == place {
1257+
if is_const_fn(ccx.tcx, def_id) {
1258+
return true;
1259+
}
1260+
}
1261+
}
1262+
}
1263+
}
1264+
}
1265+
}
1266+
1267+
false
1268+
}

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

+17-1
Original file line numberDiff line numberDiff line change
@@ -1881,10 +1881,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
18811881
ObligationCauseCode::Coercion { source: _, target } => {
18821882
err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
18831883
}
1884-
ObligationCauseCode::RepeatVec => {
1884+
ObligationCauseCode::RepeatVec(is_const_fn) => {
18851885
err.note(
18861886
"the `Copy` trait is required because the repeated element will be copied",
18871887
);
1888+
1889+
if is_const_fn {
1890+
err.help(
1891+
"consider creating a new `const` item and initializing with the result \
1892+
of the function call to be used in the repeat position, like \
1893+
`const VAL: Type = const_fn();` and `let x = [VAL; 42];`",
1894+
);
1895+
}
1896+
1897+
if self.tcx.sess.is_nightly_build() && is_const_fn {
1898+
err.help(
1899+
"create an inline `const` block, see PR \
1900+
#2920 <https://github.com/rust-lang/rfcs/pull/2920> \
1901+
for more information",
1902+
);
1903+
}
18881904
}
18891905
ObligationCauseCode::VariableType(hir_id) => {
18901906
let parent_node = self.tcx.hir().get_parent_node(hir_id);

src/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
This directory contains the source code of the rust project, including:
2+
23
- The test suite
34
- The bootstrapping build system
45
- Various submodules for tools, like rustdoc, rls, etc.

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

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ LL | let _: [Option<Bar>; 2] = [no_copy(); 2];
77
= help: the following implementations were found:
88
<Option<T> as Copy>
99
= note: the `Copy` trait is required because the repeated element will be copied
10+
= help: consider creating a new `const` item and initializing 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];`
11+
= help: create an inline `const` block, see PR #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
1012

1113
error: aborting due to previous error
1214

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

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
// should hint to create an inline `const` block
3+
// or to create a new `const` item
4+
let strings: [String; 5] = [String::new(); 5];
5+
//~^ ERROR the trait bound `String: Copy` is not satisfied
6+
println!("{:?}", strings);
7+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0277]: the trait bound `String: Copy` is not satisfied
2+
--> $DIR/const-fn-in-vec.rs:4:32
3+
|
4+
LL | let strings: [String; 5] = [String::new(); 5];
5+
| ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
6+
|
7+
= note: the `Copy` trait is required because the repeated element will be copied
8+
= help: consider creating a new `const` item and initializing 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];`
9+
= help: create an inline `const` block, see PR #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
10+
11+
error: aborting due to previous error
12+
13+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)