mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-22 03:44:24 +00:00
Implement ~const Destruct in new solver
This commit is contained in:
parent
a7d9ebdf08
commit
59408add4d
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(_) => {
|
||||
|
@ -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<TyCtxt<'tcx>> for AdtDef<'tcx> {
|
||||
fn is_fundamental(self) -> bool {
|
||||
self.is_fundamental()
|
||||
}
|
||||
|
||||
fn destructor(self, tcx: TyCtxt<'tcx>) -> Option<AdtDestructorKind> {
|
||||
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());
|
||||
|
@ -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,
|
||||
|
@ -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<I: Interner>(
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
|
||||
cx: I,
|
||||
self_ty: I::Ty,
|
||||
) -> Result<Vec<ty::TraitRef<I>>, 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
|
||||
|
@ -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<I, Self>,
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, 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(
|
||||
|
@ -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<I: Interner>: Copy + Debug + Hash + Eq {
|
||||
fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
|
||||
|
||||
fn is_fundamental(self) -> bool;
|
||||
|
||||
fn destructor(self, interner: I) -> Option<AdtDestructorKind>;
|
||||
}
|
||||
|
||||
pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
|
||||
|
@ -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,
|
||||
|
@ -19,6 +19,7 @@ pub enum TraitSolverLangItem {
|
||||
CoroutineYield,
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
Drop,
|
||||
DynMetadata,
|
||||
Fn,
|
||||
FnMut,
|
||||
|
@ -326,3 +326,10 @@ impl MaybeCause {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that a `impl Drop for Adt` is `const` or not.
|
||||
#[derive(Debug)]
|
||||
pub enum AdtDestructorKind {
|
||||
NotConst,
|
||||
Const,
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -72,6 +72,12 @@ note: required by a bound in `t::ConstDropWithBound`
|
||||
LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
|
||||
| ^^^^^ 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`.
|
||||
|
@ -72,6 +72,14 @@ note: required by a bound in `t::ConstDropWithBound`
|
||||
LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
|
||||
| ^^^^^ 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`.
|
||||
|
@ -444,12 +444,12 @@ impl<T: ?Sized> 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: ~const Destruct>(_: T) {}
|
||||
pub const fn drop<T: ~const Destruct>(_: T) {}
|
||||
|
||||
#[rustc_intrinsic_must_be_overridden]
|
||||
#[rustc_intrinsic]
|
||||
|
37
tests/ui/traits/const-traits/effects/minicore-drop-fail.rs
Normal file
37
tests/ui/traits/const-traits/effects/minicore-drop-fail.rs
Normal file
@ -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>(T);
|
||||
|
||||
struct NotDropImpl;
|
||||
impl Drop for NotDropImpl {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
#[const_trait] trait Foo {}
|
||||
impl Foo for () {}
|
||||
|
||||
struct Conditional<T: Foo>(T);
|
||||
impl<T> const Drop for Conditional<T> 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<NotDropImpl>` cannot be evaluated at compile-time
|
||||
let _ = Conditional(());
|
||||
//~^ ERROR destructor of `Conditional<()>` cannot be evaluated at compile-time
|
||||
}
|
||||
|
||||
const fn drop_arbitrary<T>(_: T) {
|
||||
//~^ ERROR destructor of `T` cannot be evaluated at compile-time
|
||||
}
|
@ -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<NotDropImpl>` 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>(_: 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`.
|
Loading…
Reference in New Issue
Block a user