diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index e8637ba45cf1d..d4f7fd4106627 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(effects): 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, TypingMode}; 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 @@ -125,11 +123,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() @@ -140,6 +134,7 @@ impl Qualif for HasMutInterior { } } +// FIXME(effects): 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 @@ -159,11 +154,7 @@ impl Qualif for NeedsDrop { ty.needs_drop(cx.tcx, cx.param_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) } @@ -192,16 +183,32 @@ impl Qualif for NeedsNonConstDrop { return false; } - // FIXME(effects): Reimplement const drop checking. - NeedsDrop::in_any_value_of_ty(cx, ty) + if cx.tcx.features().effects() { + 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 { @@ -257,14 +264,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_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 3322a2643d7d3..0e54797f673df 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -18,6 +18,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_session::DataTypeKind; use rustc_span::symbol::sym; use rustc_target::abi::{FIRST_VARIANT, ReprOptions, VariantIdx}; +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 2e88caa5c4844..914edd6152d79 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -383,6 +383,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, @@ -667,6 +671,7 @@ bidirectional_lang_item_map! { CoroutineYield, Destruct, DiscriminantKind, + Drop, DynMetadata, Fn, FnMut, 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 10ac427d710f8..f0b0db0627920 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -10,8 +10,8 @@ use tracing::instrument; use super::assembly::Candidate; use crate::delegate::SolverDelegate; use crate::solve::{ - BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, - QueryResult, assembly, + AdtDestructorKind, BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, + NoSolution, QueryResult, assembly, }; impl assembly::GoalKind for ty::HostEffectPredicate @@ -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![]; + } + // FIXME(effects): We elaborate here because the implied const bounds // aren't necessarily elaborated. We probably should prefix this query // with `explicit_`... @@ -404,10 +408,92 @@ 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 = 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(|ty| goal.predicate.trait_ref.with_self_ty(cx, 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 => {} + } + const_conditions + } + + ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => { + vec![goal.predicate.trait_ref.with_self_ty(cx, ty)] + } + + ty::Tuple(tys) => { + tys.iter().map(|ty| goal.predicate.trait_ref.with_self_ty(cx, 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(_) => 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(_, _) => return Err(NoSolution), + + ty::Dynamic(..) + | ty::Param(_) + | ty::Alias(..) + | ty::Placeholder(_) + | ty::Foreign(_) => return Err(NoSolution), + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{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 5af1aa2f8faa9..f7e0570bdd555 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 08515b344caba..23c3d7d2ab790 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 d6ca22a90a4db..68e3173a38e35 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 fe4558730513a..13081f3154be9 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 bcb9dfb704b1d..7a96b6e770582 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 381e4d78c2856..d6d84e338ffeb 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 | @@ -90,7 +96,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0015, E0277, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const-drop.stock.stderr b/tests/ui/traits/const-traits/const-drop.stock.stderr index 399e784967357..dd8a6a5d765b4 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 | @@ -92,7 +100,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0015, E0277, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs b/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs index cfcf0523828d5..ba2aa045f9a9a 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 0000000000000..da1aeb0c17182 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-drop-fail.rs @@ -0,0 +1,38 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver + +#![feature(no_core, const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete +#![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 0000000000000..09ba07ea8f773 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-drop-fail.stderr @@ -0,0 +1,45 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/minicore-drop-fail.rs:4:39 + | +LL | #![feature(no_core, const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0493]: destructor of `NotDropImpl` cannot be evaluated at compile-time + --> $DIR/minicore-drop-fail.rs:28: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:30: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:32: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:36: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; 1 warning emitted + +For more information about this error, try `rustc --explain E0493`.