Auto merge of #132329 - compiler-errors:fn-and-destruct, r=lcnr
Implement `~const Destruct` effect goal in the new solver This also fixed a subtle bug/limitation of the `NeedsConstDrop` check. Specifically, the "`Qualif`" API basically treats const drops as totally structural, even though dropping something that has an explicit `Drop` implementation cannot be structurally decomposed. For example: ```rust #![feature(const_trait_impl)] #[const_trait] trait Foo { fn foo(); } struct Conditional<T: Foo>(T); impl Foo for () { fn foo() { println!("uh oh"); } } impl<T> const Drop for Conditional<T> where T: ~const Foo { fn drop(&mut self) { T::foo(); } } const FOO: () = { let _ = Conditional(()); //~^ This should error. }; fn main() {} ``` In this example, when checking if the `Conditional(())` rvalue is const-drop, since `Conditional` has a const destructor, we would previously recurse into the `()` value and determine it has nothing to drop, which means that it is considered to *not* need a const drop -- even though dropping `Conditional(())` would mean evaluating the destructor which relies on that `T: const Foo` bound to hold! This could be fixed alternatively by banning any const conditions on `const Drop` impls, but that really sucks -- that means that basically no *interesting* const drop impls could be written. We have the capability to totally and intuitively support the right behavior, which I've implemented here.
This commit is contained in:
commit
743003b1a6
43 changed files with 525 additions and 231 deletions
|
@ -24,7 +24,7 @@ use rustc_span::{Span, Symbol, sym};
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
||||||
};
|
};
|
||||||
use tracing::{debug, instrument, trace};
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
use super::ops::{self, NonConstOp, Status};
|
use super::ops::{self, NonConstOp, Status};
|
||||||
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
||||||
|
@ -47,7 +47,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
||||||
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
|
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
|
||||||
///
|
///
|
||||||
/// Only updates the cursor if absolutely necessary
|
/// Only updates the cursor if absolutely necessary
|
||||||
fn needs_drop(
|
pub(crate) fn needs_drop(
|
||||||
&mut self,
|
&mut self,
|
||||||
ccx: &'mir ConstCx<'mir, 'tcx>,
|
ccx: &'mir ConstCx<'mir, 'tcx>,
|
||||||
local: Local,
|
local: Local,
|
||||||
|
@ -421,6 +421,43 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_drop_terminator(
|
||||||
|
&mut self,
|
||||||
|
dropped_place: Place<'tcx>,
|
||||||
|
location: Location,
|
||||||
|
terminator_span: Span,
|
||||||
|
) {
|
||||||
|
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
|
||||||
|
|
||||||
|
let needs_drop = if let Some(local) = dropped_place.as_local() {
|
||||||
|
self.qualifs.needs_drop(self.ccx, local, location)
|
||||||
|
} else {
|
||||||
|
qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
|
||||||
|
};
|
||||||
|
// If this type doesn't need a drop at all, then there's nothing to enforce.
|
||||||
|
if !needs_drop {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut err_span = self.span;
|
||||||
|
let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
|
||||||
|
// Use the span where the local was declared as the span of the drop error.
|
||||||
|
err_span = self.body.local_decls[local].source_info.span;
|
||||||
|
self.qualifs.needs_non_const_drop(self.ccx, local, location)
|
||||||
|
} else {
|
||||||
|
qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.check_op_spanned(
|
||||||
|
ops::LiveDrop {
|
||||||
|
dropped_at: terminator_span,
|
||||||
|
dropped_ty: ty_of_dropped_place,
|
||||||
|
needs_non_const_drop,
|
||||||
|
},
|
||||||
|
err_span,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
|
@ -866,35 +903,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut err_span = self.span;
|
self.check_drop_terminator(*dropped_place, location, terminator.source_info.span);
|
||||||
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
|
|
||||||
|
|
||||||
let ty_needs_non_const_drop =
|
|
||||||
qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
|
|
||||||
|
|
||||||
debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop);
|
|
||||||
|
|
||||||
if !ty_needs_non_const_drop {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
|
|
||||||
// Use the span where the local was declared as the span of the drop error.
|
|
||||||
err_span = self.body.local_decls[local].source_info.span;
|
|
||||||
self.qualifs.needs_non_const_drop(self.ccx, local, location)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
|
|
||||||
if needs_non_const_drop {
|
|
||||||
self.check_op_spanned(
|
|
||||||
ops::LiveDrop {
|
|
||||||
dropped_at: Some(terminator.source_info.span),
|
|
||||||
dropped_ty: ty_of_dropped_place,
|
|
||||||
},
|
|
||||||
err_span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
|
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
|
||||||
|
|
|
@ -459,17 +459,43 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct LiveDrop<'tcx> {
|
pub(crate) struct LiveDrop<'tcx> {
|
||||||
pub dropped_at: Option<Span>,
|
pub dropped_at: Span,
|
||||||
pub dropped_ty: Ty<'tcx>,
|
pub dropped_ty: Ty<'tcx>,
|
||||||
|
pub needs_non_const_drop: bool,
|
||||||
}
|
}
|
||||||
impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
|
impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
|
||||||
|
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||||
|
if self.needs_non_const_drop {
|
||||||
|
Status::Forbidden
|
||||||
|
} else {
|
||||||
|
Status::Unstable {
|
||||||
|
gate: sym::const_destruct,
|
||||||
|
gate_already_checked: false,
|
||||||
|
safe_to_expose_on_stable: false,
|
||||||
|
is_function_call: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||||
ccx.dcx().create_err(errors::LiveDrop {
|
if self.needs_non_const_drop {
|
||||||
span,
|
ccx.dcx().create_err(errors::LiveDrop {
|
||||||
dropped_ty: self.dropped_ty,
|
span,
|
||||||
kind: ccx.const_kind(),
|
dropped_ty: self.dropped_ty,
|
||||||
dropped_at: self.dropped_at,
|
kind: ccx.const_kind(),
|
||||||
})
|
dropped_at: self.dropped_at,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ccx.tcx.sess.create_feature_err(
|
||||||
|
errors::LiveDrop {
|
||||||
|
span,
|
||||||
|
dropped_ty: self.dropped_ty,
|
||||||
|
kind: ccx.const_kind(),
|
||||||
|
dropped_at: self.dropped_at,
|
||||||
|
},
|
||||||
|
sym::const_destruct,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::{self, BasicBlock, Location};
|
use rustc_middle::mir::{self, BasicBlock, Location};
|
||||||
use rustc_middle::ty::{Ty, TyCtxt};
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::Span;
|
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use super::ConstCx;
|
use super::ConstCx;
|
||||||
use super::check::Qualifs;
|
use crate::check_consts::check::Checker;
|
||||||
use super::ops::{self, NonConstOp};
|
|
||||||
use super::qualifs::{NeedsNonConstDrop, Qualif};
|
|
||||||
use crate::check_consts::rustc_allow_const_fn_unstable;
|
use crate::check_consts::rustc_allow_const_fn_unstable;
|
||||||
|
|
||||||
/// Returns `true` if we should use the more precise live drop checker that runs after drop
|
/// Returns `true` if we should use the more precise live drop checker that runs after drop
|
||||||
|
@ -45,29 +42,16 @@ pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
|
// I know it's not great to be creating a new const checker, but I'd
|
||||||
|
// rather use it so we can deduplicate the error emitting logic that
|
||||||
|
// it contains.
|
||||||
|
let mut visitor = CheckLiveDrops { checker: Checker::new(&ccx) };
|
||||||
|
|
||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CheckLiveDrops<'mir, 'tcx> {
|
struct CheckLiveDrops<'mir, 'tcx> {
|
||||||
ccx: &'mir ConstCx<'mir, 'tcx>,
|
checker: Checker<'mir, 'tcx>,
|
||||||
qualifs: Qualifs<'mir, 'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// So we can access `body` and `tcx`.
|
|
||||||
impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
|
|
||||||
type Target = ConstCx<'mir, 'tcx>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.ccx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> CheckLiveDrops<'_, 'tcx> {
|
|
||||||
fn check_live_drop(&self, span: Span, dropped_ty: Ty<'tcx>) {
|
|
||||||
ops::LiveDrop { dropped_at: None, dropped_ty }.build_error(self.ccx, span).emit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
||||||
|
@ -87,28 +71,11 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
||||||
|
|
||||||
match &terminator.kind {
|
match &terminator.kind {
|
||||||
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
|
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
|
||||||
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
|
self.checker.check_drop_terminator(
|
||||||
|
*dropped_place,
|
||||||
if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
|
location,
|
||||||
// Instead of throwing a bug, we just return here. This is because we have to
|
terminator.source_info.span,
|
||||||
// run custom `const Drop` impls.
|
);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if dropped_place.is_indirect() {
|
|
||||||
self.check_live_drop(terminator.source_info.span, dropped_ty);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop elaboration is not precise enough to accept code like
|
|
||||||
// `tests/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option<Vec<T>>` is
|
|
||||||
// initialized with `None` and never changed, it still emits drop glue.
|
|
||||||
// Hence we additionally check the qualifs here to allow more code to pass.
|
|
||||||
if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
|
|
||||||
// Use the span where the dropped local was declared for the error.
|
|
||||||
let span = self.body.local_decls[dropped_place.local].source_info.span;
|
|
||||||
self.check_live_drop(span, dropped_ty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::TerminatorKind::UnwindTerminate(_)
|
mir::TerminatorKind::UnwindTerminate(_)
|
||||||
|
|
|
@ -2,11 +2,14 @@
|
||||||
//!
|
//!
|
||||||
//! See the `Qualif` trait for more info.
|
//! 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_errors::ErrorGuaranteed;
|
||||||
use rustc_hir::LangItem;
|
use rustc_hir::LangItem;
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_middle::mir::*;
|
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_middle::{bug, mir};
|
||||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
@ -59,26 +62,12 @@ pub trait Qualif {
|
||||||
/// It also determines the `Qualif`s for primitive types.
|
/// It also determines the `Qualif`s for primitive types.
|
||||||
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool;
|
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.
|
/// Returns `true` if the `Qualif` is structural in an ADT's fields, i.e. if we may
|
||||||
|
/// recurse into an operand *value* to determine whether it has this `Qualif`.
|
||||||
///
|
///
|
||||||
/// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes
|
/// If this returns false, `in_any_value_of_ty` will be invoked to determine the
|
||||||
/// qualified if part of it is assigned a value with that `Qualif`. However, some ADTs *always*
|
/// final qualif for this ADT.
|
||||||
/// have a certain `Qualif`, regardless of whether their fields have it. For example, a type
|
fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool;
|
||||||
/// 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 this `Qualif` behaves sructurally for pointers and references:
|
|
||||||
/// the pointer/reference qualifies if and only if the pointee qualifies.
|
|
||||||
///
|
|
||||||
/// (This is currently `false` for all our instances, but that may change in the future. Also,
|
|
||||||
/// by keeping it abstract, the handling of `Deref` in `in_place` becomes more clear.)
|
|
||||||
fn deref_structural<'tcx>(cx: &ConstCx<'_, 'tcx>) -> bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constant containing interior mutability (`UnsafeCell<T>`).
|
/// Constant containing interior mutability (`UnsafeCell<T>`).
|
||||||
|
@ -101,6 +90,11 @@ impl Qualif for HasMutInterior {
|
||||||
return false;
|
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
|
// 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.
|
// 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
|
// Instead we invoke an obligation context manually, and provide the opaque type inference settings
|
||||||
|
@ -129,18 +123,10 @@ impl Qualif for HasMutInterior {
|
||||||
!errors.is_empty()
|
!errors.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_adt_inherently<'tcx>(
|
fn is_structural_in_adt_value<'tcx>(_cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
|
||||||
_cx: &ConstCx<'_, 'tcx>,
|
|
||||||
adt: AdtDef<'tcx>,
|
|
||||||
_: GenericArgsRef<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
|
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
|
||||||
// It arises structurally for all other types.
|
// It arises structurally for all other types.
|
||||||
adt.is_unsafe_cell()
|
!adt.is_unsafe_cell()
|
||||||
}
|
|
||||||
|
|
||||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +140,7 @@ pub struct NeedsDrop;
|
||||||
impl Qualif for NeedsDrop {
|
impl Qualif for NeedsDrop {
|
||||||
const ANALYSIS_NAME: &'static str = "flow_needs_drop";
|
const ANALYSIS_NAME: &'static str = "flow_needs_drop";
|
||||||
const IS_CLEARED_ON_MOVE: bool = true;
|
const IS_CLEARED_ON_MOVE: bool = true;
|
||||||
|
const ALLOW_PROMOTED: bool = true;
|
||||||
|
|
||||||
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
|
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
|
||||||
qualifs.needs_drop
|
qualifs.needs_drop
|
||||||
|
@ -163,16 +150,8 @@ impl Qualif for NeedsDrop {
|
||||||
ty.needs_drop(cx.tcx, cx.typing_env)
|
ty.needs_drop(cx.tcx, cx.typing_env)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_adt_inherently<'tcx>(
|
fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
!adt.has_dtor(cx.tcx)
|
||||||
adt: AdtDef<'tcx>,
|
|
||||||
_: GenericArgsRef<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
adt.has_dtor(cx.tcx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,20 +175,46 @@ impl Qualif for NeedsNonConstDrop {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(const_trait_impl): Reimplement const drop checking.
|
// If this doesn't need drop at all, then don't select `~const Destruct`.
|
||||||
NeedsDrop::in_any_value_of_ty(cx, ty)
|
if !ty.needs_drop(cx.tcx, cx.typing_env) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We check that the type is `~const Destruct` since that will verify that
|
||||||
|
// the type is both `~const Drop` (if a drop impl exists for the adt), *and*
|
||||||
|
// that the components of this type are also `~const Destruct`. This
|
||||||
|
// amounts to verifying that there are no values in this ADT that may have
|
||||||
|
// a non-const drop.
|
||||||
|
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
|
||||||
|
let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env);
|
||||||
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
ocx.register_obligation(Obligation::new(
|
||||||
|
cx.tcx,
|
||||||
|
ObligationCause::misc(cx.body.span, cx.def_id()),
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_adt_inherently<'tcx>(
|
fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
// As soon as an ADT has a destructor, then the drop becomes non-structural
|
||||||
adt: AdtDef<'tcx>,
|
// in its value since:
|
||||||
_: GenericArgsRef<'tcx>,
|
// 1. The destructor may have `~const` bounds which are not present on the type.
|
||||||
) -> bool {
|
// Someone needs to check that those are satisfied.
|
||||||
adt.has_non_const_dtor(cx.tcx)
|
// While this could be instead satisfied by checking that the `~const Drop`
|
||||||
}
|
// impl holds (i.e. replicating part of the `in_any_value_of_ty` logic above),
|
||||||
|
// even in this case, we have another problem, which is,
|
||||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
// 2. The destructor may *modify* the operand being dropped, so even if we
|
||||||
false
|
// did recurse on the components of the operand, we may not be even dropping
|
||||||
|
// the same values that were present before the custom destructor was invoked.
|
||||||
|
!adt.has_dtor(cx.tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,14 +266,15 @@ where
|
||||||
Rvalue::Aggregate(kind, operands) => {
|
Rvalue::Aggregate(kind, operands) => {
|
||||||
// Return early if we know that the struct or enum being constructed is always
|
// Return early if we know that the struct or enum being constructed is always
|
||||||
// qualified.
|
// qualified.
|
||||||
if let AggregateKind::Adt(adt_did, _, args, ..) = **kind {
|
if let AggregateKind::Adt(adt_did, ..) = **kind {
|
||||||
let def = cx.tcx.adt_def(adt_did);
|
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.
|
// 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)) {
|
// Also, if the ADT is not structural in its fields,
|
||||||
return true;
|
// then we cannot recurse on its fields. Instead,
|
||||||
|
// we fall back to checking the qualif for *any* value
|
||||||
|
// of the ADT.
|
||||||
|
if def.is_union() || !Q::is_structural_in_adt_value(cx, def) {
|
||||||
|
return Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +311,11 @@ where
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(elem, ProjectionElem::Deref) && !Q::deref_structural(cx) {
|
// `Deref` currently unconditionally "qualifies" if `in_any_value_of_ty` returns true,
|
||||||
|
// i.e., we treat all qualifs as non-structural for deref projections. Generally,
|
||||||
|
// we can say very little about `*ptr` even if we know that `ptr` satisfies all
|
||||||
|
// sorts of properties.
|
||||||
|
if matches!(elem, ProjectionElem::Deref) {
|
||||||
// We have to assume that this qualifies.
|
// We have to assume that this qualifies.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -411,7 +411,7 @@ pub struct LiveDrop<'tcx> {
|
||||||
pub kind: ConstContext,
|
pub kind: ConstContext,
|
||||||
pub dropped_ty: Ty<'tcx>,
|
pub dropped_ty: Ty<'tcx>,
|
||||||
#[label(const_eval_dropped_at_label)]
|
#[label(const_eval_dropped_at_label)]
|
||||||
pub dropped_at: Option<Span>,
|
pub dropped_at: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
|
|
@ -426,6 +426,8 @@ declare_features! (
|
||||||
(unstable, const_async_blocks, "1.53.0", Some(85368)),
|
(unstable, const_async_blocks, "1.53.0", Some(85368)),
|
||||||
/// Allows `const || {}` closures in const contexts.
|
/// Allows `const || {}` closures in const contexts.
|
||||||
(incomplete, const_closures, "1.68.0", Some(106003)),
|
(incomplete, const_closures, "1.68.0", Some(106003)),
|
||||||
|
/// Allows using `~const Destruct` bounds and calling drop impls in const contexts.
|
||||||
|
(unstable, const_destruct, "CURRENT_RUSTC_VERSION", Some(133214)),
|
||||||
/// Allows `for _ in _` loops in const contexts.
|
/// Allows `for _ in _` loops in const contexts.
|
||||||
(unstable, const_for, "1.56.0", Some(87575)),
|
(unstable, const_for, "1.56.0", Some(87575)),
|
||||||
/// Be more precise when looking for live drops in a const context.
|
/// Be more precise when looking for live drops in a const context.
|
||||||
|
|
|
@ -269,13 +269,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Adjust::Deref(None) => {
|
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) => {
|
Adjust::Pointer(_pointer_coercion) => {
|
||||||
// FIXME(effects): We should probably enforce these.
|
// FIXME(const_trait_impl): We should probably enforce these.
|
||||||
}
|
}
|
||||||
Adjust::ReborrowPin(_mutability) => {
|
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.
|
// `&mut T: DerefMut` tho, so it's kinda moot.
|
||||||
}
|
}
|
||||||
Adjust::Borrow(_) => {
|
Adjust::Borrow(_) => {
|
||||||
|
|
|
@ -18,6 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||||
use rustc_query_system::ich::StableHashingContext;
|
use rustc_query_system::ich::StableHashingContext;
|
||||||
use rustc_session::DataTypeKind;
|
use rustc_session::DataTypeKind;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
use rustc_type_ir::solve::AdtDestructorKind;
|
||||||
use tracing::{debug, info, trace};
|
use tracing::{debug, info, trace};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -232,6 +233,13 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
|
||||||
fn is_fundamental(self) -> bool {
|
fn is_fundamental(self) -> bool {
|
||||||
self.is_fundamental()
|
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)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)]
|
||||||
|
@ -402,10 +410,6 @@ impl<'tcx> AdtDef<'tcx> {
|
||||||
self.destructor(tcx).is_some()
|
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.
|
/// Asserts this is a struct or union and returns its unique variant.
|
||||||
pub fn non_enum_variant(self) -> &'tcx VariantDef {
|
pub fn non_enum_variant(self) -> &'tcx VariantDef {
|
||||||
assert!(self.is_struct() || self.is_union());
|
assert!(self.is_struct() || self.is_union());
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
pub mod tls;
|
pub mod tls;
|
||||||
|
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::{assert_matches, debug_assert_matches};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
@ -377,10 +377,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_is_const(self, def_id: DefId) -> bool {
|
fn impl_is_const(self, def_id: DefId) -> bool {
|
||||||
|
debug_assert_matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true });
|
||||||
self.is_conditionally_const(def_id)
|
self.is_conditionally_const(def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_is_const(self, def_id: DefId) -> bool {
|
fn fn_is_const(self, def_id: DefId) -> bool {
|
||||||
|
debug_assert_matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
|
||||||
|
self.is_conditionally_const(def_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alias_has_const_conditions(self, def_id: DefId) -> bool {
|
||||||
|
debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::OpaqueTy);
|
||||||
self.is_conditionally_const(def_id)
|
self.is_conditionally_const(def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,6 +670,7 @@ bidirectional_lang_item_map! {
|
||||||
CoroutineYield,
|
CoroutineYield,
|
||||||
Destruct,
|
Destruct,
|
||||||
DiscriminantKind,
|
DiscriminantKind,
|
||||||
|
Drop,
|
||||||
DynMetadata,
|
DynMetadata,
|
||||||
Fn,
|
Fn,
|
||||||
FnMut,
|
FnMut,
|
||||||
|
|
|
@ -12,7 +12,7 @@ use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::delegate::SolverDelegate;
|
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.
|
// Calculates the constituent types of a type for `auto trait` purposes.
|
||||||
#[instrument(level = "trace", skip(ecx), ret)]
|
#[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
|
/// 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
|
/// 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
|
/// we assemble a built-in object candidate for an object type, since they
|
||||||
|
|
|
@ -84,6 +84,10 @@ where
|
||||||
let cx = ecx.cx();
|
let cx = ecx.cx();
|
||||||
let mut candidates = vec![];
|
let mut candidates = vec![];
|
||||||
|
|
||||||
|
if !ecx.cx().alias_has_const_conditions(alias_ty.def_id) {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
|
||||||
for clause in elaborate::elaborate(
|
for clause in elaborate::elaborate(
|
||||||
cx,
|
cx,
|
||||||
cx.explicit_implied_const_bounds(alias_ty.def_id)
|
cx.explicit_implied_const_bounds(alias_ty.def_id)
|
||||||
|
@ -338,10 +342,27 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_destruct_candidate(
|
fn consider_builtin_destruct_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, D>,
|
ecx: &mut EvalCtxt<'_, D>,
|
||||||
_goal: Goal<I, Self>,
|
goal: Goal<I, Self>,
|
||||||
) -> Result<Candidate<I>, NoSolution> {
|
) -> 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(
|
fn consider_builtin_transmute_candidate(
|
||||||
|
|
|
@ -610,6 +610,7 @@ symbols! {
|
||||||
const_compare_raw_pointers,
|
const_compare_raw_pointers,
|
||||||
const_constructor,
|
const_constructor,
|
||||||
const_deallocate,
|
const_deallocate,
|
||||||
|
const_destruct,
|
||||||
const_eval_limit,
|
const_eval_limit,
|
||||||
const_eval_select,
|
const_eval_select,
|
||||||
const_evaluatable_checked,
|
const_evaluatable_checked,
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_ast_ir::Mutability;
|
||||||
use crate::elaborate::Elaboratable;
|
use crate::elaborate::Elaboratable;
|
||||||
use crate::fold::{TypeFoldable, TypeSuperFoldable};
|
use crate::fold::{TypeFoldable, TypeSuperFoldable};
|
||||||
use crate::relate::Relate;
|
use crate::relate::Relate;
|
||||||
use crate::solve::Reveal;
|
use crate::solve::{AdtDestructorKind, Reveal};
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||||
use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
|
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 sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
|
||||||
|
|
||||||
fn is_fundamental(self) -> bool;
|
fn is_fundamental(self) -> bool;
|
||||||
|
|
||||||
|
fn destructor(self, interner: I) -> Option<AdtDestructorKind>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
|
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 impl_is_const(self, def_id: Self::DefId) -> bool;
|
||||||
fn fn_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(
|
fn const_conditions(
|
||||||
self,
|
self,
|
||||||
def_id: Self::DefId,
|
def_id: Self::DefId,
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub enum TraitSolverLangItem {
|
||||||
CoroutineYield,
|
CoroutineYield,
|
||||||
Destruct,
|
Destruct,
|
||||||
DiscriminantKind,
|
DiscriminantKind,
|
||||||
|
Drop,
|
||||||
DynMetadata,
|
DynMetadata,
|
||||||
Fn,
|
Fn,
|
||||||
FnMut,
|
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,
|
||||||
|
}
|
||||||
|
|
|
@ -953,7 +953,7 @@ marker_impls! {
|
||||||
///
|
///
|
||||||
/// This should be used for `~const` bounds,
|
/// This should be used for `~const` bounds,
|
||||||
/// as non-const bounds will always hold for every type.
|
/// as non-const bounds will always hold for every type.
|
||||||
#[unstable(feature = "const_trait_impl", issue = "67792")]
|
#[unstable(feature = "const_destruct", issue = "133214")]
|
||||||
#[lang = "destruct"]
|
#[lang = "destruct"]
|
||||||
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
|
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
|
||||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//@ known-bug: #103507
|
//@ known-bug: #103507
|
||||||
|
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![feature(const_trait_impl, negative_impls)]
|
#![feature(const_trait_impl, negative_impls, const_destruct)]
|
||||||
|
|
||||||
use std::marker::Destruct;
|
use std::marker::Destruct;
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
|
||||||
--> $DIR/drop-fail.rs:8:9
|
--> $DIR/drop-fail.rs:9:9
|
||||||
|
|
|
|
||||||
LL | let x = Some(Vec::new());
|
LL | let x = Some(Vec::new());
|
||||||
| ^ the destructor for this type cannot be evaluated in constants
|
| ^ the destructor for this type cannot be evaluated in constants
|
||||||
|
...
|
||||||
|
LL | };
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
|
||||||
--> $DIR/drop-fail.rs:39:9
|
--> $DIR/drop-fail.rs:40:9
|
||||||
|
|
|
|
||||||
LL | let mut tmp = None;
|
LL | let mut tmp = None;
|
||||||
| ^^^^^^^ the destructor for this type cannot be evaluated in constants
|
| ^^^^^^^ the destructor for this type cannot be evaluated in constants
|
||||||
|
...
|
||||||
|
LL | };
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//@ revisions: stock precise
|
//@ revisions: stock precise
|
||||||
|
|
||||||
|
#![feature(const_destruct)]
|
||||||
#![cfg_attr(precise, feature(const_precise_live_drops))]
|
#![cfg_attr(precise, feature(const_precise_live_drops))]
|
||||||
|
|
||||||
// `x` is *not* always moved into the final value and may be dropped inside the initializer.
|
// `x` is *not* always moved into the final value and may be dropped inside the initializer.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
|
||||||
--> $DIR/drop-fail.rs:8:9
|
--> $DIR/drop-fail.rs:9:9
|
||||||
|
|
|
|
||||||
LL | let x = Some(Vec::new());
|
LL | let x = Some(Vec::new());
|
||||||
| ^ the destructor for this type cannot be evaluated in constants
|
| ^ the destructor for this type cannot be evaluated in constants
|
||||||
|
@ -8,7 +8,7 @@ LL | };
|
||||||
| - value is dropped here
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `(Vec<i32>,)` cannot be evaluated at compile-time
|
error[E0493]: destructor of `(Vec<i32>,)` cannot be evaluated at compile-time
|
||||||
--> $DIR/drop-fail.rs:21:9
|
--> $DIR/drop-fail.rs:22:9
|
||||||
|
|
|
|
||||||
LL | let vec_tuple = (Vec::new(),);
|
LL | let vec_tuple = (Vec::new(),);
|
||||||
| ^^^^^^^^^ the destructor for this type cannot be evaluated in constants
|
| ^^^^^^^^^ the destructor for this type cannot be evaluated in constants
|
||||||
|
@ -17,7 +17,7 @@ LL | };
|
||||||
| - value is dropped here
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Result<Vec<i32>, Vec<i32>>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Result<Vec<i32>, Vec<i32>>` cannot be evaluated at compile-time
|
||||||
--> $DIR/drop-fail.rs:29:9
|
--> $DIR/drop-fail.rs:30:9
|
||||||
|
|
|
|
||||||
LL | let x: Result<_, Vec<i32>> = Ok(Vec::new());
|
LL | let x: Result<_, Vec<i32>> = Ok(Vec::new());
|
||||||
| ^ the destructor for this type cannot be evaluated in constants
|
| ^ the destructor for this type cannot be evaluated in constants
|
||||||
|
@ -26,7 +26,7 @@ LL | };
|
||||||
| - value is dropped here
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
|
||||||
--> $DIR/drop-fail.rs:39:9
|
--> $DIR/drop-fail.rs:40:9
|
||||||
|
|
|
|
||||||
LL | let mut tmp = None;
|
LL | let mut tmp = None;
|
||||||
| ^^^^^^^ the destructor for this type cannot be evaluated in constants
|
| ^^^^^^^ the destructor for this type cannot be evaluated in constants
|
||||||
|
|
|
@ -3,6 +3,8 @@ error[E0493]: destructor of `S` cannot be evaluated at compile-time
|
||||||
|
|
|
|
||||||
LL | let s = S;
|
LL | let s = S;
|
||||||
| ^ the destructor for this type cannot be evaluated in constant functions
|
| ^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
LL | }
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(const_cmp)]
|
#![feature(const_cmp)]
|
||||||
|
#![feature(const_destruct)]
|
||||||
|
|
||||||
use std::marker::Destruct;
|
use std::marker::Destruct;
|
||||||
|
|
||||||
|
|
|
@ -11,19 +11,19 @@ LL | #![feature(const_cmp)]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:13:8
|
--> $DIR/fn_trait_refs.rs:14:8
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:13:24
|
--> $DIR/fn_trait_refs.rs:14:24
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:13:8
|
--> $DIR/fn_trait_refs.rs:14:8
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -31,7 +31,7 @@ LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:13:8
|
--> $DIR/fn_trait_refs.rs:14:8
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -39,7 +39,7 @@ LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:13:24
|
--> $DIR/fn_trait_refs.rs:14:24
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -47,19 +47,19 @@ LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:20:8
|
--> $DIR/fn_trait_refs.rs:21:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:20:27
|
--> $DIR/fn_trait_refs.rs:21:27
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:20:8
|
--> $DIR/fn_trait_refs.rs:21:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -67,7 +67,7 @@ LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:20:8
|
--> $DIR/fn_trait_refs.rs:21:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -75,7 +75,7 @@ LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:20:27
|
--> $DIR/fn_trait_refs.rs:21:27
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -83,13 +83,13 @@ LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:27:8
|
--> $DIR/fn_trait_refs.rs:28:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnOnce<()>,
|
LL | T: ~const FnOnce<()>,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:27:8
|
--> $DIR/fn_trait_refs.rs:28:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnOnce<()>,
|
LL | T: ~const FnOnce<()>,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -97,7 +97,7 @@ LL | T: ~const FnOnce<()>,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:27:8
|
--> $DIR/fn_trait_refs.rs:28:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnOnce<()>,
|
LL | T: ~const FnOnce<()>,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -105,19 +105,19 @@ LL | T: ~const FnOnce<()>,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:34:8
|
--> $DIR/fn_trait_refs.rs:35:8
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:34:24
|
--> $DIR/fn_trait_refs.rs:35:24
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:34:8
|
--> $DIR/fn_trait_refs.rs:35:8
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -125,7 +125,7 @@ LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:34:8
|
--> $DIR/fn_trait_refs.rs:35:8
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -133,7 +133,7 @@ LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:34:24
|
--> $DIR/fn_trait_refs.rs:35:24
|
||||||
|
|
|
|
||||||
LL | T: ~const Fn<()> + ~const Destruct,
|
LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -141,19 +141,19 @@ LL | T: ~const Fn<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:48:8
|
--> $DIR/fn_trait_refs.rs:49:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:48:27
|
--> $DIR/fn_trait_refs.rs:49:27
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:48:8
|
--> $DIR/fn_trait_refs.rs:49:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -161,7 +161,7 @@ LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:48:8
|
--> $DIR/fn_trait_refs.rs:49:8
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -169,7 +169,7 @@ LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: `~const` can only be applied to `#[const_trait]` traits
|
error: `~const` can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/fn_trait_refs.rs:48:27
|
--> $DIR/fn_trait_refs.rs:49:27
|
||||||
|
|
|
|
||||||
LL | T: ~const FnMut<()> + ~const Destruct,
|
LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -177,7 +177,7 @@ LL | T: ~const FnMut<()> + ~const Destruct,
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error[E0015]: cannot call non-const operator in constants
|
error[E0015]: cannot call non-const operator in constants
|
||||||
--> $DIR/fn_trait_refs.rs:70:17
|
--> $DIR/fn_trait_refs.rs:71:17
|
||||||
|
|
|
|
||||||
LL | assert!(test_one == (1, 1, 1));
|
LL | assert!(test_one == (1, 1, 1));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -185,7 +185,7 @@ LL | assert!(test_one == (1, 1, 1));
|
||||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||||
|
|
||||||
error[E0015]: cannot call non-const operator in constants
|
error[E0015]: cannot call non-const operator in constants
|
||||||
--> $DIR/fn_trait_refs.rs:73:17
|
--> $DIR/fn_trait_refs.rs:74:17
|
||||||
|
|
|
|
||||||
LL | assert!(test_two == (2, 2));
|
LL | assert!(test_two == (2, 2));
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -193,7 +193,7 @@ LL | assert!(test_two == (2, 2));
|
||||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||||
|
|
||||||
error[E0015]: cannot call non-const closure in constant functions
|
error[E0015]: cannot call non-const closure in constant functions
|
||||||
--> $DIR/fn_trait_refs.rs:15:5
|
--> $DIR/fn_trait_refs.rs:16:5
|
||||||
|
|
|
|
||||||
LL | f()
|
LL | f()
|
||||||
| ^^^
|
| ^^^
|
||||||
|
@ -205,7 +205,7 @@ LL | T: ~const Fn<()> + ~const Destruct + ~const Fn(),
|
||||||
| +++++++++++++
|
| +++++++++++++
|
||||||
|
|
||||||
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
||||||
--> $DIR/fn_trait_refs.rs:11:23
|
--> $DIR/fn_trait_refs.rs:12:23
|
||||||
|
|
|
|
||||||
LL | const fn tester_fn<T>(f: T) -> T::Output
|
LL | const fn tester_fn<T>(f: T) -> T::Output
|
||||||
| ^ the destructor for this type cannot be evaluated in constant functions
|
| ^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
@ -214,7 +214,7 @@ LL | }
|
||||||
| - value is dropped here
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0015]: cannot call non-const closure in constant functions
|
error[E0015]: cannot call non-const closure in constant functions
|
||||||
--> $DIR/fn_trait_refs.rs:22:5
|
--> $DIR/fn_trait_refs.rs:23:5
|
||||||
|
|
|
|
||||||
LL | f()
|
LL | f()
|
||||||
| ^^^
|
| ^^^
|
||||||
|
@ -226,7 +226,7 @@ LL | T: ~const FnMut<()> + ~const Destruct + ~const FnMut(),
|
||||||
| ++++++++++++++++
|
| ++++++++++++++++
|
||||||
|
|
||||||
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
||||||
--> $DIR/fn_trait_refs.rs:18:27
|
--> $DIR/fn_trait_refs.rs:19:27
|
||||||
|
|
|
|
||||||
LL | const fn tester_fn_mut<T>(mut f: T) -> T::Output
|
LL | const fn tester_fn_mut<T>(mut f: T) -> T::Output
|
||||||
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
@ -235,7 +235,7 @@ LL | }
|
||||||
| - value is dropped here
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0015]: cannot call non-const closure in constant functions
|
error[E0015]: cannot call non-const closure in constant functions
|
||||||
--> $DIR/fn_trait_refs.rs:29:5
|
--> $DIR/fn_trait_refs.rs:30:5
|
||||||
|
|
|
|
||||||
LL | f()
|
LL | f()
|
||||||
| ^^^
|
| ^^^
|
||||||
|
@ -247,7 +247,7 @@ LL | T: ~const FnOnce<()> + ~const FnOnce(),
|
||||||
| +++++++++++++++++
|
| +++++++++++++++++
|
||||||
|
|
||||||
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
||||||
--> $DIR/fn_trait_refs.rs:32:21
|
--> $DIR/fn_trait_refs.rs:33:21
|
||||||
|
|
|
|
||||||
LL | const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output)
|
LL | const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output)
|
||||||
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
@ -256,7 +256,7 @@ LL | }
|
||||||
| - value is dropped here
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
||||||
--> $DIR/fn_trait_refs.rs:46:25
|
--> $DIR/fn_trait_refs.rs:47:25
|
||||||
|
|
|
|
||||||
LL | const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output)
|
LL | const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output)
|
||||||
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
|
|
@ -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: 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
|
= note: adding a non-const method body in the future would be a breaking change
|
||||||
|
|
||||||
error[E0716]: temporary value dropped while borrowed
|
error[E0493]: destructor of `Panic` cannot be evaluated at compile-time
|
||||||
--> $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
|
|
||||||
--> $DIR/promoted_const_call.rs:10:30
|
--> $DIR/promoted_const_call.rs:10:30
|
||||||
|
|
|
|
||||||
LL | let _: &'static _ = &id(&Panic);
|
LL | let _: &'static _ = &id(&Panic);
|
||||||
| ---------- ^^^^^ - temporary value is freed at the end of this statement
|
| ^^^^^ - value is dropped here
|
||||||
| | |
|
| |
|
||||||
| | creates a temporary value which is freed while still in use
|
| the destructor for this type cannot be evaluated in constants
|
||||||
| type annotation requires that borrow lasts for `'static`
|
|
||||||
|
|
||||||
error[E0716]: temporary value dropped while borrowed
|
error[E0716]: temporary value dropped while borrowed
|
||||||
--> $DIR/promoted_const_call.rs:16:26
|
--> $DIR/promoted_const_call.rs:16:26
|
||||||
|
@ -69,6 +57,7 @@ LL | let _: &'static _ = &&(Panic, 0).1;
|
||||||
LL | }
|
LL | }
|
||||||
| - temporary value is freed at the end of this statement
|
| - 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`.
|
||||||
|
|
|
@ -22,7 +22,9 @@ error[E0493]: destructor of `String` cannot be evaluated at compile-time
|
||||||
--> $DIR/promoted_const_call2.rs:4:30
|
--> $DIR/promoted_const_call2.rs:4:30
|
||||||
|
|
|
|
||||||
LL | let _: &'static _ = &id(&String::new());
|
LL | let _: &'static _ = &id(&String::new());
|
||||||
| ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants
|
| ^^^^^^^^^^^^^ - value is dropped here
|
||||||
|
| |
|
||||||
|
| the destructor for this type cannot be evaluated in constants
|
||||||
|
|
||||||
error[E0716]: temporary value dropped while borrowed
|
error[E0716]: temporary value dropped while borrowed
|
||||||
--> $DIR/promoted_const_call2.rs:11:26
|
--> $DIR/promoted_const_call2.rs:11:26
|
||||||
|
|
|
@ -3,6 +3,9 @@ error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
||||||
|
|
|
|
||||||
LL | let mut x = None;
|
LL | let mut x = None;
|
||||||
| ^^^^^ the destructor for this type cannot be evaluated in constants
|
| ^^^^^ the destructor for this type cannot be evaluated in constants
|
||||||
|
...
|
||||||
|
LL | };
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0080]: evaluation of constant value failed
|
error[E0080]: evaluation of constant value failed
|
||||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
|
@ -26,6 +29,8 @@ error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
||||||
|
|
|
|
||||||
LL | let _z = x;
|
LL | let _z = x;
|
||||||
| ^^ the destructor for this type cannot be evaluated in constants
|
| ^^ the destructor for this type cannot be evaluated in constants
|
||||||
|
LL | };
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0080]: evaluation of constant value failed
|
error[E0080]: evaluation of constant value failed
|
||||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
|
@ -49,42 +54,62 @@ error[E0493]: destructor of `(u32, Option<String>)` cannot be evaluated at compi
|
||||||
|
|
|
|
||||||
LL | let mut a: (u32, Option<String>) = (0, None);
|
LL | let mut a: (u32, Option<String>) = (0, None);
|
||||||
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
LL | let _ = &mut a.1;
|
||||||
|
LL | }
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
|
||||||
--> $DIR/qualif-indirect-mutation-fail.rs:34:9
|
--> $DIR/qualif-indirect-mutation-fail.rs:34:9
|
||||||
|
|
|
|
||||||
LL | let x: Option<T> = None;
|
LL | let x: Option<T> = None;
|
||||||
| ^ the destructor for this type cannot be evaluated in constant functions
|
| ^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
LL | let _ = x.is_some();
|
||||||
|
LL | }
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
|
||||||
--> $DIR/qualif-indirect-mutation-fail.rs:42:9
|
--> $DIR/qualif-indirect-mutation-fail.rs:42:9
|
||||||
|
|
|
|
||||||
LL | let _y = x;
|
LL | let _y = x;
|
||||||
| ^^ the destructor for this type cannot be evaluated in constant functions
|
| ^^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
LL | }
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
||||||
--> $DIR/qualif-indirect-mutation-fail.rs:50:9
|
--> $DIR/qualif-indirect-mutation-fail.rs:50:9
|
||||||
|
|
|
|
||||||
LL | let mut y: Option<String> = None;
|
LL | let mut y: Option<String> = None;
|
||||||
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
LL | std::ptr::addr_of_mut!(y);
|
||||||
|
LL | }
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
||||||
--> $DIR/qualif-indirect-mutation-fail.rs:47:9
|
--> $DIR/qualif-indirect-mutation-fail.rs:47:9
|
||||||
|
|
|
|
||||||
LL | let mut x: Option<String> = None;
|
LL | let mut x: Option<String> = None;
|
||||||
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
| ^^^^^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
...
|
||||||
|
LL | }
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
||||||
--> $DIR/qualif-indirect-mutation-fail.rs:60:9
|
--> $DIR/qualif-indirect-mutation-fail.rs:60:9
|
||||||
|
|
|
|
||||||
LL | let y: Option<String> = None;
|
LL | let y: Option<String> = None;
|
||||||
| ^ the destructor for this type cannot be evaluated in constant functions
|
| ^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
LL | std::ptr::addr_of!(y);
|
||||||
|
LL | }
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
|
||||||
--> $DIR/qualif-indirect-mutation-fail.rs:57:9
|
--> $DIR/qualif-indirect-mutation-fail.rs:57:9
|
||||||
|
|
|
|
||||||
LL | let x: Option<String> = None;
|
LL | let x: Option<String> = None;
|
||||||
| ^ the destructor for this type cannot be evaluated in constant functions
|
| ^ the destructor for this type cannot be evaluated in constant functions
|
||||||
|
...
|
||||||
|
LL | }
|
||||||
|
| - value is dropped here
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//@ known-bug: #103507
|
//@ known-bug: #103507
|
||||||
|
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl, const_destruct)]
|
||||||
|
|
||||||
use std::marker::Destruct;
|
use std::marker::Destruct;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// FIXME check-pass
|
// FIXME check-pass
|
||||||
|
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(const_precise_live_drops)]
|
#![feature(const_precise_live_drops, const_destruct)]
|
||||||
|
|
||||||
use std::marker::Destruct;
|
use std::marker::Destruct;
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,9 @@ error[E0493]: destructor of `E` cannot be evaluated at compile-time
|
||||||
--> $DIR/const-drop-bound.rs:12:13
|
--> $DIR/const-drop-bound.rs:12:13
|
||||||
|
|
|
|
||||||
LL | Err(_e) => None,
|
LL | Err(_e) => None,
|
||||||
| ^^ the destructor for this type cannot be evaluated in constant functions
|
| ^^ - value is dropped here
|
||||||
|
| |
|
||||||
|
| the destructor for this type cannot be evaluated in constant functions
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//@ known-bug: #110395
|
//@ known-bug: #110395
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl, const_destruct)]
|
||||||
// #![cfg_attr(precise, feature(const_precise_live_drops))]
|
// #![cfg_attr(precise, feature(const_precise_live_drops))]
|
||||||
|
|
||||||
use std::marker::{Destruct, PhantomData};
|
use std::marker::{Destruct, PhantomData};
|
||||||
|
|
|
@ -25,7 +25,9 @@ error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
||||||
--> $DIR/const-drop-fail.rs:23:36
|
--> $DIR/const-drop-fail.rs:23:36
|
||||||
|
|
|
|
||||||
LL | const fn check<T: ~const Destruct>(_: T) {}
|
LL | const fn check<T: ~const Destruct>(_: T) {}
|
||||||
| ^ the destructor for this type cannot be evaluated in constant functions
|
| ^ - value is dropped here
|
||||||
|
| |
|
||||||
|
| the destructor for this type cannot be evaluated in constant functions
|
||||||
|
|
||||||
error[E0080]: evaluation of constant value failed
|
error[E0080]: evaluation of constant value failed
|
||||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//@ known-bug: #110395
|
//@ known-bug: #110395
|
||||||
|
|
||||||
//@ revisions: stock precise
|
//@ revisions: stock precise
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl, const_destruct)]
|
||||||
#![cfg_attr(precise, feature(const_precise_live_drops))]
|
#![cfg_attr(precise, feature(const_precise_live_drops))]
|
||||||
|
|
||||||
use std::marker::{Destruct, PhantomData};
|
use std::marker::{Destruct, PhantomData};
|
||||||
|
|
|
@ -72,11 +72,21 @@ note: required by a bound in `t::ConstDropWithBound`
|
||||||
LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
|
LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
|
||||||
| ^^^^^ required by this bound in `ConstDropWithBound`
|
| ^^^^^ 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
|
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
||||||
--> $DIR/const-drop.rs:18:32
|
--> $DIR/const-drop.rs:18:32
|
||||||
|
|
|
|
||||||
LL | const fn a<T: ~const Destruct>(_: T) {}
|
LL | const fn a<T: ~const Destruct>(_: T) {}
|
||||||
| ^ the destructor for this type cannot be evaluated in constant functions
|
| ^ - value is dropped here
|
||||||
|
| |
|
||||||
|
| the destructor for this type cannot be evaluated in constant functions
|
||||||
|
|
||||||
error[E0277]: the trait bound `T: ~const SomeTrait` is not satisfied
|
error[E0277]: the trait bound `T: ~const SomeTrait` is not satisfied
|
||||||
--> $DIR/const-drop.rs:69:13
|
--> $DIR/const-drop.rs:69:13
|
||||||
|
@ -84,7 +94,7 @@ error[E0277]: the trait bound `T: ~const SomeTrait` is not satisfied
|
||||||
LL | T::foo();
|
LL | T::foo();
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 10 previous errors
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0493.
|
Some errors have detailed explanations: E0277, E0493.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// FIXME run-pass
|
// FIXME run-pass
|
||||||
//@ known-bug: #110395
|
//@ known-bug: #110395
|
||||||
//@ revisions: stock precise
|
//@ revisions: stock precise
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl, const_destruct)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![cfg_attr(precise, feature(const_precise_live_drops))]
|
#![cfg_attr(precise, feature(const_precise_live_drops))]
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,14 @@ note: required by a bound in `t::ConstDropWithBound`
|
||||||
LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
|
LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
|
||||||
| ^^^^^ required by this bound in `ConstDropWithBound`
|
| ^^^^^ 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
|
error[E0493]: destructor of `T` cannot be evaluated at compile-time
|
||||||
--> $DIR/const-drop.rs:18:32
|
--> $DIR/const-drop.rs:18:32
|
||||||
|
|
|
|
||||||
|
@ -86,7 +94,7 @@ error[E0277]: the trait bound `T: ~const SomeTrait` is not satisfied
|
||||||
LL | T::foo();
|
LL | T::foo();
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 10 previous errors
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0493.
|
Some errors have detailed explanations: E0277, E0493.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
rustc_attrs,
|
rustc_attrs,
|
||||||
fundamental,
|
fundamental,
|
||||||
marker_trait_attr,
|
marker_trait_attr,
|
||||||
const_trait_impl
|
const_trait_impl,
|
||||||
|
const_destruct
|
||||||
)]
|
)]
|
||||||
#![allow(internal_features, incomplete_features)]
|
#![allow(internal_features, incomplete_features)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
@ -444,12 +445,12 @@ impl<T: ?Sized> Deref for Ref<'_, T> {
|
||||||
|
|
||||||
#[lang = "clone"]
|
#[lang = "clone"]
|
||||||
#[rustc_trivial_field_reads]
|
#[rustc_trivial_field_reads]
|
||||||
// FIXME: #[const_trait]
|
#[const_trait]
|
||||||
pub trait Clone: Sized {
|
pub trait Clone: Sized {
|
||||||
fn clone(&self) -> Self;
|
fn clone(&self) -> Self;
|
||||||
fn clone_from(&mut self, source: &Self)
|
fn clone_from(&mut self, source: &Self)
|
||||||
where
|
where
|
||||||
// FIXME: Self: ~const Destruct,
|
Self: ~const Destruct,
|
||||||
{
|
{
|
||||||
*self = source.clone()
|
*self = source.clone()
|
||||||
}
|
}
|
||||||
|
@ -458,7 +459,7 @@ pub trait Clone: Sized {
|
||||||
#[lang = "structural_peq"]
|
#[lang = "structural_peq"]
|
||||||
pub trait StructuralPartialEq {}
|
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_must_be_overridden]
|
||||||
#[rustc_intrinsic]
|
#[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, const_destruct)]
|
||||||
|
#![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`.
|
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0493]: destructor of `ConstDrop` cannot be evaluated at compile-time
|
||||||
|
--> $DIR/minicore-drop-without-feature-gate.rs:24:13
|
||||||
|
|
|
||||||
|
LL | let _ = ConstDrop;
|
||||||
|
| ^^^^^^^^^- value is dropped here
|
||||||
|
| |
|
||||||
|
| the destructor for this type cannot be evaluated in constant functions
|
||||||
|
|
|
||||||
|
= note: see issue #133214 <https://github.com/rust-lang/rust/issues/133214> for more information
|
||||||
|
= help: add `#![feature(const_destruct)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0493`.
|
|
@ -0,0 +1,26 @@
|
||||||
|
//@ aux-build:minicore.rs
|
||||||
|
//@ compile-flags: --crate-type=lib -Znext-solver
|
||||||
|
//@ revisions: yes no
|
||||||
|
//@[yes] check-pass
|
||||||
|
// gate-test-const_destruct
|
||||||
|
|
||||||
|
#![feature(no_core, const_trait_impl)]
|
||||||
|
#![cfg_attr(yes, feature(const_destruct))]
|
||||||
|
#![no_std]
|
||||||
|
#![no_core]
|
||||||
|
|
||||||
|
extern crate minicore;
|
||||||
|
use minicore::*;
|
||||||
|
|
||||||
|
struct ConstDrop;
|
||||||
|
impl const Drop for ConstDrop {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that `ConstDrop` can only be dropped when the `const_drop`
|
||||||
|
// feature gate is enabled. Otherwise, we should error if there is a drop
|
||||||
|
// impl at all.
|
||||||
|
const fn test() {
|
||||||
|
let _ = ConstDrop;
|
||||||
|
//[no]~^ ERROR destructor of `ConstDrop` cannot be evaluated at compile-time
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
//@ known-bug: #110395
|
//@ known-bug: #110395
|
||||||
// FIXME check-pass
|
// FIXME check-pass
|
||||||
|
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl, const_destruct)]
|
||||||
|
|
||||||
use std::marker::Destruct;
|
use std::marker::Destruct;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//@ compile-flags: -Znext-solver
|
//@ compile-flags: -Znext-solver
|
||||||
//@ check-pass
|
//@ check-pass
|
||||||
|
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl, const_destruct)]
|
||||||
|
|
||||||
fn foo(_: impl std::marker::Destruct) {}
|
fn foo(_: impl std::marker::Destruct) {}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue