diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index bc416acc58d..b965ad7bd87 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -2,11 +2,14 @@ //! //! See the `Qualif` trait for more info. +// FIXME(const_trait_impl): This API should be really reworked. It's dangerously general for +// having basically only two use-cases that act in different ways. + use rustc_errors::ErrorGuaranteed; use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; -use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty}; +use rustc_middle::ty::{self, AdtDef, Ty}; use rustc_middle::{bug, mir}; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use tracing::instrument; @@ -59,19 +62,9 @@ pub trait Qualif { /// It also determines the `Qualif`s for primitive types. fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool; - /// Returns `true` if this `Qualif` is inherent to the given struct or enum. - /// - /// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes - /// qualified if part of it is assigned a value with that `Qualif`. However, some ADTs *always* - /// have a certain `Qualif`, regardless of whether their fields have it. For example, a type - /// with a custom `Drop` impl is inherently `NeedsDrop`. - /// - /// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound. - fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, - adt: AdtDef<'tcx>, - args: GenericArgsRef<'tcx>, - ) -> bool; + /// Returns `true` if the `Qualif` is not structural, i.e. that we should not recurse + /// into the operand. + fn is_non_structural<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool; /// Returns `true` if this `Qualif` behaves sructurally for pointers and references: /// the pointer/reference qualifies if and only if the pointee qualifies. @@ -101,6 +94,11 @@ impl Qualif for HasMutInterior { return false; } + // Avoid selecting for `UnsafeCell` either. + if ty.ty_adt_def().is_some_and(|adt| adt.is_unsafe_cell()) { + return true; + } + // We do not use `ty.is_freeze` here, because that requires revealing opaque types, which // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error. // Instead we invoke an obligation context manually, and provide the opaque type inference settings @@ -129,11 +127,7 @@ impl Qualif for HasMutInterior { !errors.is_empty() } - fn in_adt_inherently<'tcx>( - _cx: &ConstCx<'_, 'tcx>, - adt: AdtDef<'tcx>, - _: GenericArgsRef<'tcx>, - ) -> bool { + fn is_non_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool { // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. // It arises structurally for all other types. adt.is_unsafe_cell() @@ -144,6 +138,7 @@ impl Qualif for HasMutInterior { } } +// FIXME(const_trait_impl): Get rid of this! /// Constant containing an ADT that implements `Drop`. /// This must be ruled out because implicit promotion would remove side-effects /// that occur as part of dropping that value. N.B., the implicit promotion has @@ -163,11 +158,7 @@ impl Qualif for NeedsDrop { ty.needs_drop(cx.tcx, cx.typing_env) } - fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, - adt: AdtDef<'tcx>, - _: GenericArgsRef<'tcx>, - ) -> bool { + fn is_non_structural<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool { adt.has_dtor(cx.tcx) } @@ -196,16 +187,32 @@ impl Qualif for NeedsNonConstDrop { return false; } - // FIXME(const_trait_impl): Reimplement const drop checking. - NeedsDrop::in_any_value_of_ty(cx, ty) + if cx.tcx.features().const_trait_impl() { + let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span)); + let infcx = cx.tcx.infer_ctxt().build(TypingMode::from_param_env(cx.param_env)); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligation(Obligation::new( + cx.tcx, + ObligationCause::misc(cx.body.span, cx.def_id()), + cx.param_env, + ty::Binder::dummy(ty::TraitRef::new(cx.tcx, destruct_def_id, [ty])) + .to_host_effect_clause(cx.tcx, match cx.const_kind() { + rustc_hir::ConstContext::ConstFn => ty::BoundConstness::Maybe, + rustc_hir::ConstContext::Static(_) + | rustc_hir::ConstContext::Const { .. } => ty::BoundConstness::Const, + }), + )); + !ocx.select_all_or_error().is_empty() + } else { + NeedsDrop::in_any_value_of_ty(cx, ty) + } } - fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, - adt: AdtDef<'tcx>, - _: GenericArgsRef<'tcx>, - ) -> bool { - adt.has_non_const_dtor(cx.tcx) + fn is_non_structural<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool { + // Even a `const` dtor may have `~const` bounds that may need to + // be satisfied, so this becomes non-structural as soon as the + // ADT gets a destructor at all. + adt.has_dtor(cx.tcx) } fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { @@ -261,14 +268,10 @@ where Rvalue::Aggregate(kind, operands) => { // Return early if we know that the struct or enum being constructed is always // qualified. - if let AggregateKind::Adt(adt_did, _, args, ..) = **kind { + if let AggregateKind::Adt(adt_did, ..) = **kind { let def = cx.tcx.adt_def(adt_did); - if Q::in_adt_inherently(cx, def, args) { - return true; - } - // Don't do any value-based reasoning for unions. - if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) { - return true; + if def.is_union() || Q::is_non_structural(cx, def) { + return Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ce6ce0381a9..47af8c681da 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -269,13 +269,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } Adjust::Deref(None) => { - // FIXME(effects): We *could* enforce `&T: ~const Deref` here. + // FIXME(const_trait_impl): We *could* enforce `&T: ~const Deref` here. } Adjust::Pointer(_pointer_coercion) => { - // FIXME(effects): We should probably enforce these. + // FIXME(const_trait_impl): We should probably enforce these. } Adjust::ReborrowPin(_mutability) => { - // FIXME(effects): We could enforce these; they correspond to + // FIXME(const_trait_impl): We could enforce these; they correspond to // `&mut T: DerefMut` tho, so it's kinda moot. } Adjust::Borrow(_) => { diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 79d56702be2..447cbc8932e 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -18,6 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; use rustc_session::DataTypeKind; use rustc_span::symbol::sym; +use rustc_type_ir::solve::AdtDestructorKind; use tracing::{debug, info, trace}; use super::{ @@ -232,6 +233,13 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { fn is_fundamental(self) -> bool { self.is_fundamental() } + + fn destructor(self, tcx: TyCtxt<'tcx>) -> Option { + Some(match self.destructor(tcx)?.constness { + hir::Constness::Const => AdtDestructorKind::Const, + hir::Constness::NotConst => AdtDestructorKind::NotConst, + }) + } } #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)] @@ -402,10 +410,6 @@ impl<'tcx> AdtDef<'tcx> { self.destructor(tcx).is_some() } - pub fn has_non_const_dtor(self, tcx: TyCtxt<'tcx>) -> bool { - matches!(self.destructor(tcx), Some(Destructor { constness: hir::Constness::NotConst, .. })) - } - /// Asserts this is a struct or union and returns its unique variant. pub fn non_enum_variant(self) -> &'tcx VariantDef { assert!(self.is_struct() || self.is_union()); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 55c29825fbc..4a0d50c153c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -384,6 +384,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.is_conditionally_const(def_id) } + fn alias_has_const_conditions(self, def_id: DefId) -> bool { + self.is_conditionally_const(def_id) + } + fn const_conditions( self, def_id: DefId, @@ -663,6 +667,7 @@ bidirectional_lang_item_map! { CoroutineYield, Destruct, DiscriminantKind, + Drop, DynMetadata, Fn, FnMut, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index a56febec48c..05ce61bc067 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -12,7 +12,7 @@ use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; use crate::delegate::SolverDelegate; -use crate::solve::{EvalCtxt, Goal, NoSolution}; +use crate::solve::{AdtDestructorKind, EvalCtxt, Goal, NoSolution}; // Calculates the constituent types of a type for `auto trait` purposes. #[instrument(level = "trace", skip(ecx), ret)] @@ -703,6 +703,78 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( } } +pub(in crate::solve) fn const_conditions_for_destruct( + cx: I, + self_ty: I::Ty, +) -> Result>, NoSolution> { + let destruct_def_id = cx.require_lang_item(TraitSolverLangItem::Destruct); + + match self_ty.kind() { + // An ADT is `~const Destruct` only if all of the fields are, + // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`. + ty::Adt(adt_def, args) => { + let mut const_conditions: Vec<_> = adt_def + .all_field_tys(cx) + .iter_instantiated(cx, args) + .map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty])) + .collect(); + match adt_def.destructor(cx) { + // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`. + Some(AdtDestructorKind::NotConst) => return Err(NoSolution), + // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. + Some(AdtDestructorKind::Const) => { + let drop_def_id = cx.require_lang_item(TraitSolverLangItem::Drop); + let drop_trait_ref = ty::TraitRef::new(cx, drop_def_id, [self_ty]); + const_conditions.push(drop_trait_ref); + } + // No `Drop` impl, no need to require anything else. + None => {} + } + Ok(const_conditions) + } + + ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => { + Ok(vec![ty::TraitRef::new(cx, destruct_def_id, [ty])]) + } + + ty::Tuple(tys) => Ok(tys + .iter() + .map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty])) + .collect()), + + // Trivially implement `~const Destruct` + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Str + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Never + | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) + | ty::Error(_) => Ok(vec![]), + + // Coroutines and closures could implement `~const Drop`, + // but they don't really need to right now. + ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) => Err(NoSolution), + + ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => { + Err(NoSolution) + } + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + } +} + /// Assemble a list of predicates that would be present on a theoretical /// user impl for an object type. These predicates must be checked any time /// we assemble a built-in object candidate for an object type, since they diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 603a68eb890..81b5199002b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -84,6 +84,10 @@ where let cx = ecx.cx(); let mut candidates = vec![]; + if !ecx.cx().alias_has_const_conditions(alias_ty.def_id) { + return vec![]; + } + for clause in elaborate::elaborate( cx, cx.explicit_implied_const_bounds(alias_ty.def_id) @@ -338,10 +342,27 @@ where } fn consider_builtin_destruct_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, ) -> Result, NoSolution> { - Err(NoSolution) + let cx = ecx.cx(); + + let self_ty = goal.predicate.self_ty(); + let const_conditions = structural_traits::const_conditions_for_destruct(cx, self_ty)?; + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.add_goals( + GoalSource::Misc, + const_conditions.into_iter().map(|trait_ref| { + goal.with( + cx, + ty::Binder::dummy(trait_ref) + .to_host_effect_clause(cx, goal.predicate.constness), + ) + }), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_transmute_candidate( diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 5af1aa2f8fa..f7e0570bdd5 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -11,7 +11,7 @@ use rustc_ast_ir::Mutability; use crate::elaborate::Elaboratable; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::relate::Relate; -use crate::solve::Reveal; +use crate::solve::{AdtDestructorKind, Reveal}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, CollectAndApply, Interner, UpcastFrom}; @@ -537,6 +537,8 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { fn sized_constraint(self, interner: I) -> Option>; fn is_fundamental(self) -> bool; + + fn destructor(self, interner: I) -> Option; } pub trait ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 93b9c2e2892..0ae688848eb 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -225,6 +225,7 @@ pub trait Interner: fn impl_is_const(self, def_id: Self::DefId) -> bool; fn fn_is_const(self, def_id: Self::DefId) -> bool; + fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool; fn const_conditions( self, def_id: Self::DefId, diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index df43346065d..eeb80bc3ab4 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -19,6 +19,7 @@ pub enum TraitSolverLangItem { CoroutineYield, Destruct, DiscriminantKind, + Drop, DynMetadata, Fn, FnMut, diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index fe455873051..13081f3154b 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -326,3 +326,10 @@ impl MaybeCause { } } } + +/// Indicates that a `impl Drop for Adt` is `const` or not. +#[derive(Debug)] +pub enum AdtDestructorKind { + NotConst, + Const, +} diff --git a/tests/ui/consts/promoted_const_call.stderr b/tests/ui/consts/promoted_const_call.stderr index bcb9dfb704b..7a96b6e7705 100644 --- a/tests/ui/consts/promoted_const_call.stderr +++ b/tests/ui/consts/promoted_const_call.stderr @@ -7,25 +7,13 @@ LL | impl const Drop for Panic { fn drop(&mut self) { panic!(); } } = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_call.rs:10:26 - | -LL | let _: &'static _ = &id(&Panic); - | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | }; - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed +error[E0493]: destructor of `Panic` cannot be evaluated at compile-time --> $DIR/promoted_const_call.rs:10:30 | LL | let _: &'static _ = &id(&Panic); - | ---------- ^^^^^ - temporary value is freed at the end of this statement - | | | - | | creates a temporary value which is freed while still in use - | type annotation requires that borrow lasts for `'static` + | ^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_call.rs:16:26 @@ -69,6 +57,7 @@ LL | let _: &'static _ = &&(Panic, 0).1; LL | } | - temporary value is freed at the end of this statement -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0716`. +Some errors have detailed explanations: E0493, E0716. +For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/traits/const-traits/const-drop.precise.stderr b/tests/ui/traits/const-traits/const-drop.precise.stderr index ed90b234761..4f673187d49 100644 --- a/tests/ui/traits/const-traits/const-drop.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop.precise.stderr @@ -72,6 +72,12 @@ note: required by a bound in `t::ConstDropWithBound` LL | pub struct ConstDropWithBound(pub core::marker::PhantomData); | ^^^^^ required by this bound in `ConstDropWithBound` +error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time + --> $DIR/const-drop.rs:23:13 + | +LL | let _ = S(&mut c); + | ^^^^^^^^^ the destructor for this type cannot be evaluated in constant functions + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop.rs:18:32 | @@ -84,7 +90,7 @@ error[E0277]: the trait bound `T: ~const SomeTrait` is not satisfied LL | T::foo(); | ^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0277, E0493. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop.stock.stderr b/tests/ui/traits/const-traits/const-drop.stock.stderr index 2b46b048e90..51a66396c4b 100644 --- a/tests/ui/traits/const-traits/const-drop.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop.stock.stderr @@ -72,6 +72,14 @@ note: required by a bound in `t::ConstDropWithBound` LL | pub struct ConstDropWithBound(pub core::marker::PhantomData); | ^^^^^ required by this bound in `ConstDropWithBound` +error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time + --> $DIR/const-drop.rs:23:13 + | +LL | let _ = S(&mut c); + | ^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop.rs:18:32 | @@ -86,7 +94,7 @@ error[E0277]: the trait bound `T: ~const SomeTrait` is not satisfied LL | T::foo(); | ^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0277, E0493. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs b/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs index 209a111c243..498e698ef1c 100644 --- a/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs +++ b/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs @@ -444,12 +444,12 @@ impl Deref for Ref<'_, T> { #[lang = "clone"] #[rustc_trivial_field_reads] -// FIXME: #[const_trait] +#[const_trait] pub trait Clone: Sized { fn clone(&self) -> Self; fn clone_from(&mut self, source: &Self) where - // FIXME: Self: ~const Destruct, + Self: ~const Destruct, { *self = source.clone() } @@ -458,7 +458,7 @@ pub trait Clone: Sized { #[lang = "structural_peq"] pub trait StructuralPartialEq {} -// FIXME: const fn drop(_: T) {} +pub const fn drop(_: T) {} #[rustc_intrinsic_must_be_overridden] #[rustc_intrinsic] diff --git a/tests/ui/traits/const-traits/effects/minicore-drop-fail.rs b/tests/ui/traits/const-traits/effects/minicore-drop-fail.rs new file mode 100644 index 00000000000..57c39d2c1a1 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-drop-fail.rs @@ -0,0 +1,37 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver + +#![feature(no_core, const_trait_impl)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +struct Contains(T); + +struct NotDropImpl; +impl Drop for NotDropImpl { + fn drop(&mut self) {} +} + +#[const_trait] trait Foo {} +impl Foo for () {} + +struct Conditional(T); +impl const Drop for Conditional where T: ~const Foo { + fn drop(&mut self) {} +} + +const fn test() { + let _ = NotDropImpl; + //~^ ERROR destructor of `NotDropImpl` cannot be evaluated at compile-time + let _ = Contains(NotDropImpl); + //~^ ERROR destructor of `Contains` cannot be evaluated at compile-time + let _ = Conditional(()); + //~^ ERROR destructor of `Conditional<()>` cannot be evaluated at compile-time +} + +const fn drop_arbitrary(_: T) { + //~^ ERROR destructor of `T` cannot be evaluated at compile-time +} diff --git a/tests/ui/traits/const-traits/effects/minicore-drop-fail.stderr b/tests/ui/traits/const-traits/effects/minicore-drop-fail.stderr new file mode 100644 index 00000000000..12d1877a18a --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-drop-fail.stderr @@ -0,0 +1,36 @@ +error[E0493]: destructor of `NotDropImpl` cannot be evaluated at compile-time + --> $DIR/minicore-drop-fail.rs:27:13 + | +LL | let _ = NotDropImpl; + | ^^^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `Contains` cannot be evaluated at compile-time + --> $DIR/minicore-drop-fail.rs:29:13 + | +LL | let _ = Contains(NotDropImpl); + | ^^^^^^^^^^^^^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `Conditional<()>` cannot be evaluated at compile-time + --> $DIR/minicore-drop-fail.rs:31:13 + | +LL | let _ = Conditional(()); + | ^^^^^^^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> $DIR/minicore-drop-fail.rs:35:28 + | +LL | const fn drop_arbitrary(_: T) { + | ^ the destructor for this type cannot be evaluated in constant functions +LL | +LL | } + | - value is dropped here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0493`.