diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 1f4b2c7879cc7..e980667c5e468 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -594,7 +594,7 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> { } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - if self.needs_non_const_drop { + let mut err = if self.needs_non_const_drop { ccx.dcx().create_err(diagnostics::LiveDrop { span, dropped_ty: self.dropped_ty, @@ -611,7 +611,30 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> { }, sym::const_destruct, ) + }; + + // If the dropped type is a type parameter, suggest adding a `[const] Destruct` bound. + // The suggestion is only offered on nightly, since `[const]` bounds are unstable. + if let Param(param_ty) = self.dropped_ty.kind() + && ccx.tcx.sess.is_nightly_build() + { + let tcx = ccx.tcx; + let caller = ccx.def_id(); + if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() { + let destruct_def_id = tcx.lang_items().destruct_trait(); + suggest_constraining_type_param( + tcx, + generics, + &mut err, + param_ty.name.as_str(), + "[const] Destruct", + destruct_def_id, + None, + ); + } } + + err } } diff --git a/tests/run-make/const-destruct-stable-toolchain/const-drop-nightly.stderr b/tests/run-make/const-destruct-stable-toolchain/const-drop-nightly.stderr new file mode 100644 index 0000000000000..52f68743b6275 --- /dev/null +++ b/tests/run-make/const-destruct-stable-toolchain/const-drop-nightly.stderr @@ -0,0 +1,16 @@ +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> const-drop.rs:1:24 + | +LL | const fn const_drop(_: T) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + | +help: consider restricting type parameter `T` with unstable trait `Destruct` + | +LL | const fn const_drop(_: T) {} + | ++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/run-make/const-destruct-stable-toolchain/const-drop-stable.stderr b/tests/run-make/const-destruct-stable-toolchain/const-drop-stable.stderr new file mode 100644 index 0000000000000..dc37d840658fd --- /dev/null +++ b/tests/run-make/const-destruct-stable-toolchain/const-drop-stable.stderr @@ -0,0 +1,11 @@ +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> const-drop.rs:1:24 + | +1 | const fn const_drop(_: T) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/run-make/const-destruct-stable-toolchain/const-drop.rs b/tests/run-make/const-destruct-stable-toolchain/const-drop.rs new file mode 100644 index 0000000000000..6479498281fe5 --- /dev/null +++ b/tests/run-make/const-destruct-stable-toolchain/const-drop.rs @@ -0,0 +1,3 @@ +const fn const_drop(_: T) {} + +fn main() {} diff --git a/tests/run-make/const-destruct-stable-toolchain/rmake.rs b/tests/run-make/const-destruct-stable-toolchain/rmake.rs new file mode 100644 index 0000000000000..c1ff48b3214f0 --- /dev/null +++ b/tests/run-make/const-destruct-stable-toolchain/rmake.rs @@ -0,0 +1,26 @@ +//@ needs-target-std +// +// Test that the suggestion to constrain a type parameter that is dropped in a const +// function with a `[const] Destruct` bound is only offered on nightly, since the bound +// requires an unstable feature. + +use run_make_support::{diff, rustc}; + +fn main() { + let out = rustc() + .input("const-drop.rs") + .env("RUSTC_BOOTSTRAP", "-1") + .run_fail() + .assert_stderr_not_contains("consider restricting type parameter `T`") + .stderr_utf8(); + diff().expected_file("const-drop-stable.stderr").actual_text("(rustc)", &out).run(); + let out = rustc() + .input("const-drop.rs") + .ui_testing() + .run_fail() + .assert_stderr_contains( + "consider restricting type parameter `T` with unstable trait `Destruct`", + ) + .stderr_utf8(); + diff().expected_file("const-drop-nightly.stderr").actual_text("(rustc)", &out).run(); +} diff --git a/tests/ui/consts/min_const_fn/min_const_fn.stderr b/tests/ui/consts/min_const_fn/min_const_fn.stderr index 0e939e5121aa9..0904de2af0d46 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn.stderr @@ -73,6 +73,11 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^ - value is dropped here | | | the destructor for this type cannot be evaluated in constant functions + | +help: consider restricting opaque type `impl std::fmt::Debug` with unstable trait `Destruct` + | +LL | const fn no_apit(_x: impl std::fmt::Debug + [const] Destruct) {} + | ++++++++++++++++++ error: aborting due to 9 previous errors diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr index 16db7791cd849..9dcd2b0ac0326 100644 --- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr @@ -6,6 +6,11 @@ LL | const fn unwrap_or_else T>(self, f: F) -> T { ... LL | } | - value is dropped here + | +help: consider further restricting type parameter `F` with unstable trait `Destruct` + | +LL | const fn unwrap_or_else T + [const] Destruct>(self, f: F) -> T { + | ++++++++++++++++++ error[E0493]: destructor of `Opt` cannot be evaluated at compile-time --> $DIR/unstable-const-fn-in-libcore.rs:19:55 diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index f217370b024b5..1b410322aacbe 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -15,6 +15,11 @@ LL | const fn get>(self: R) -> u32 { ... LL | } | - value is dropped here + | +help: consider further restricting type parameter `R` with unstable trait `Destruct` + | +LL | const fn get + [const] Destruct>(self: R) -> u32 { + | ++++++++++++++++++ error[E0801]: invalid generic `self` parameter type: `R` --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49 diff --git a/tests/ui/static/static-drop-scope.stderr b/tests/ui/static/static-drop-scope.stderr index 0fdf081e23432..84e99a3988121 100644 --- a/tests/ui/static/static-drop-scope.stderr +++ b/tests/ui/static/static-drop-scope.stderr @@ -37,6 +37,11 @@ LL | const fn const_drop(_: T) {} | ^ - value is dropped here | | | the destructor for this type cannot be evaluated in constant functions + | +help: consider restricting type parameter `T` with unstable trait `Destruct` + | +LL | const fn const_drop(_: T) {} + | ++++++++++++++++++ error[E0493]: destructor of `(T, ())` cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:17:5 diff --git a/tests/ui/traits/const-traits/minicore-drop-fail.stderr b/tests/ui/traits/const-traits/minicore-drop-fail.stderr index 12d1877a18aba..2cb1256e37667 100644 --- a/tests/ui/traits/const-traits/minicore-drop-fail.stderr +++ b/tests/ui/traits/const-traits/minicore-drop-fail.stderr @@ -30,6 +30,11 @@ LL | const fn drop_arbitrary(_: T) { LL | LL | } | - value is dropped here + | +help: consider restricting type parameter `T` with trait `Destruct` + | +LL | const fn drop_arbitrary(_: T) { + | ++++++++++++++++++ error: aborting due to 4 previous errors