Const drop selection candidates
This commit is contained in:
parent
894ce921a0
commit
a13b13ff46
9 changed files with 212 additions and 25 deletions
|
@ -529,6 +529,9 @@ pub enum ImplSource<'tcx, N> {
|
||||||
|
|
||||||
/// ImplSource for a trait alias.
|
/// ImplSource for a trait alias.
|
||||||
TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
|
TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
|
||||||
|
|
||||||
|
/// ImplSource for a `const Drop` implementation.
|
||||||
|
ConstDrop(ImplSourceConstDropData),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, N> ImplSource<'tcx, N> {
|
impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
|
@ -543,7 +546,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::Object(d) => d.nested,
|
ImplSource::Object(d) => d.nested,
|
||||||
ImplSource::FnPointer(d) => d.nested,
|
ImplSource::FnPointer(d) => d.nested,
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||||
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
|
| ImplSource::Pointee(ImplSourcePointeeData)
|
||||||
|
| ImplSource::ConstDrop(ImplSourceConstDropData) => Vec::new(),
|
||||||
ImplSource::TraitAlias(d) => d.nested,
|
ImplSource::TraitAlias(d) => d.nested,
|
||||||
ImplSource::TraitUpcasting(d) => d.nested,
|
ImplSource::TraitUpcasting(d) => d.nested,
|
||||||
}
|
}
|
||||||
|
@ -560,7 +564,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::Object(d) => &d.nested[..],
|
ImplSource::Object(d) => &d.nested[..],
|
||||||
ImplSource::FnPointer(d) => &d.nested[..],
|
ImplSource::FnPointer(d) => &d.nested[..],
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||||
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
|
| ImplSource::Pointee(ImplSourcePointeeData)
|
||||||
|
| ImplSource::ConstDrop(ImplSourceConstDropData) => &[],
|
||||||
ImplSource::TraitAlias(d) => &d.nested[..],
|
ImplSource::TraitAlias(d) => &d.nested[..],
|
||||||
ImplSource::TraitUpcasting(d) => &d.nested[..],
|
ImplSource::TraitUpcasting(d) => &d.nested[..],
|
||||||
}
|
}
|
||||||
|
@ -621,6 +626,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
nested: d.nested.into_iter().map(f).collect(),
|
nested: d.nested.into_iter().map(f).collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ImplSource::ConstDrop(ImplSourceConstDropData) => {
|
||||||
|
ImplSource::ConstDrop(ImplSourceConstDropData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -712,6 +720,9 @@ pub struct ImplSourceDiscriminantKindData;
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||||
pub struct ImplSourcePointeeData;
|
pub struct ImplSourcePointeeData;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||||
|
pub struct ImplSourceConstDropData;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
|
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
|
||||||
pub struct ImplSourceTraitAliasData<'tcx, N> {
|
pub struct ImplSourceTraitAliasData<'tcx, N> {
|
||||||
pub alias_def_id: DefId,
|
pub alias_def_id: DefId,
|
||||||
|
|
|
@ -143,6 +143,9 @@ pub enum SelectionCandidate<'tcx> {
|
||||||
BuiltinObjectCandidate,
|
BuiltinObjectCandidate,
|
||||||
|
|
||||||
BuiltinUnsizeCandidate,
|
BuiltinUnsizeCandidate,
|
||||||
|
|
||||||
|
/// Implementation of `const Drop`.
|
||||||
|
ConstDropCandidate,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of trait evaluation. The order is important
|
/// The result of trait evaluation. The order is important
|
||||||
|
|
|
@ -32,6 +32,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
|
||||||
super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
|
super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
|
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
|
super::ImplSource::ConstDrop(ref d) => write!(f, "{:?}", d),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,4 +127,5 @@ TrivialTypeFoldableAndLiftImpls! {
|
||||||
super::IfExpressionCause,
|
super::IfExpressionCause,
|
||||||
super::ImplSourceDiscriminantKindData,
|
super::ImplSourceDiscriminantKindData,
|
||||||
super::ImplSourcePointeeData,
|
super::ImplSourcePointeeData,
|
||||||
|
super::ImplSourceConstDropData,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1477,7 +1477,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
}
|
}
|
||||||
super::ImplSource::AutoImpl(..)
|
super::ImplSource::AutoImpl(..)
|
||||||
| super::ImplSource::Builtin(..)
|
| super::ImplSource::Builtin(..)
|
||||||
| super::ImplSource::TraitUpcasting(_) => {
|
| super::ImplSource::TraitUpcasting(_)
|
||||||
|
| super::ImplSource::ConstDrop(_) => {
|
||||||
// These traits have no associated types.
|
// These traits have no associated types.
|
||||||
selcx.tcx().sess.delay_span_bug(
|
selcx.tcx().sess.delay_span_bug(
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
|
@ -1549,7 +1550,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
||||||
| super::ImplSource::Param(..)
|
| super::ImplSource::Param(..)
|
||||||
| super::ImplSource::Builtin(..)
|
| super::ImplSource::Builtin(..)
|
||||||
| super::ImplSource::TraitUpcasting(_)
|
| super::ImplSource::TraitUpcasting(_)
|
||||||
| super::ImplSource::TraitAlias(..) => {
|
| super::ImplSource::TraitAlias(..)
|
||||||
|
| super::ImplSource::ConstDrop(_) => {
|
||||||
// we don't create Select candidates with this kind of resolution
|
// we don't create Select candidates with this kind of resolution
|
||||||
span_bug!(
|
span_bug!(
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, TypeFoldable};
|
use rustc_middle::ty::{self, Ty, TypeFoldable};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use crate::traits::coherence::Conflict;
|
use crate::traits::coherence::Conflict;
|
||||||
|
@ -277,6 +277,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
|
self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
|
||||||
} else if lang_items.unsize_trait() == Some(def_id) {
|
} else if lang_items.unsize_trait() == Some(def_id) {
|
||||||
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
||||||
|
} else if lang_items.drop_trait() == Some(def_id)
|
||||||
|
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
|
||||||
|
{
|
||||||
|
if self.is_in_const_context {
|
||||||
|
self.assemble_const_drop_candidates(obligation, &mut candidates)?;
|
||||||
|
} else {
|
||||||
|
// `~const Drop` when we are not in a const context has no effect.
|
||||||
|
candidates.vec.push(ConstDropCandidate)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if lang_items.clone_trait() == Some(def_id) {
|
if lang_items.clone_trait() == Some(def_id) {
|
||||||
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
|
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
|
||||||
|
@ -803,4 +812,103 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assemble_const_drop_candidates(
|
||||||
|
&mut self,
|
||||||
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||||
|
) -> Result<(), SelectionError<'tcx>> {
|
||||||
|
let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)];
|
||||||
|
|
||||||
|
while let Some((ty, depth)) = stack.pop() {
|
||||||
|
self.check_recursion_depth(depth, obligation)?;
|
||||||
|
let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
|
||||||
|
let mut copy_obligation =
|
||||||
|
obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
|
||||||
|
trait_ref: ty::TraitRef {
|
||||||
|
def_id: self.tcx().require_lang_item(hir::LangItem::Copy, None),
|
||||||
|
substs: self.tcx().mk_substs_trait(ty, &[]),
|
||||||
|
},
|
||||||
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
}));
|
||||||
|
copy_obligation.recursion_depth = depth + 1;
|
||||||
|
self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates);
|
||||||
|
let copy_conditions = self.copy_clone_conditions(©_obligation);
|
||||||
|
self.assemble_builtin_bound_candidates(copy_conditions, &mut copy_candidates);
|
||||||
|
if !copy_candidates.vec.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match ty.kind() {
|
||||||
|
ty::Int(_)
|
||||||
|
| ty::Uint(_)
|
||||||
|
| ty::Float(_)
|
||||||
|
| ty::Infer(ty::IntVar(_))
|
||||||
|
| ty::Infer(ty::FloatVar(_))
|
||||||
|
| ty::FnPtr(_)
|
||||||
|
| ty::Never
|
||||||
|
| ty::Ref(..)
|
||||||
|
| ty::FnDef(..)
|
||||||
|
| ty::RawPtr(_)
|
||||||
|
| ty::Bool
|
||||||
|
| ty::Char
|
||||||
|
| ty::Str
|
||||||
|
| ty::Foreign(_) => {} // Do nothing. These types satisfy `const Drop`.
|
||||||
|
|
||||||
|
ty::Adt(def, subst) => {
|
||||||
|
let mut set = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
|
||||||
|
self.assemble_candidates_from_impls(obligation, &mut set);
|
||||||
|
if set
|
||||||
|
.vec
|
||||||
|
.into_iter()
|
||||||
|
.find(|candidate| {
|
||||||
|
if let SelectionCandidate::ImplCandidate(did) = candidate {
|
||||||
|
matches!(self.tcx().impl_constness(*did), hir::Constness::NotConst)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
// could not find a const impl for Drop, iterate over its fields.
|
||||||
|
stack
|
||||||
|
.extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Array(ty, _) => stack.push((ty, depth + 1)),
|
||||||
|
|
||||||
|
ty::Tuple(_) => stack.extend(ty.tuple_fields().map(|t| (t, depth + 1))),
|
||||||
|
|
||||||
|
ty::Closure(_, substs) => {
|
||||||
|
stack.extend(substs.as_closure().upvar_tys().map(|t| (t, depth + 1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Generator(_, substs, _) => {
|
||||||
|
let substs = substs.as_generator();
|
||||||
|
stack.extend(substs.upvar_tys().map(|t| (t, depth + 1)));
|
||||||
|
stack.push((substs.witness(), depth + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::GeneratorWitness(tys) => stack.extend(
|
||||||
|
self.tcx().erase_late_bound_regions(*tys).iter().map(|t| (t, depth + 1)),
|
||||||
|
),
|
||||||
|
|
||||||
|
ty::Slice(ty) => stack.push((ty, depth + 1)),
|
||||||
|
|
||||||
|
ty::Opaque(..)
|
||||||
|
| ty::Dynamic(..)
|
||||||
|
| ty::Error(_)
|
||||||
|
| ty::Bound(..)
|
||||||
|
| ty::Infer(_)
|
||||||
|
| ty::Placeholder(_)
|
||||||
|
| ty::Projection(..)
|
||||||
|
| ty::Param(..) => return Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// all types have passed.
|
||||||
|
candidates.vec.push(ConstDropCandidate);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ use crate::traits::TraitNotObjectSafe;
|
||||||
use crate::traits::VtblSegment;
|
use crate::traits::VtblSegment;
|
||||||
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
|
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
|
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceConstDropData,
|
||||||
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
|
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
|
||||||
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
|
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
|
||||||
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
|
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
|
||||||
|
@ -124,6 +124,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
|
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
|
||||||
Ok(ImplSource::TraitUpcasting(data))
|
Ok(ImplSource::TraitUpcasting(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstDropCandidate => Ok(ImplSource::ConstDrop(ImplSourceConstDropData)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1038,6 +1038,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
|
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_recursion_depth<T: Display + TypeFoldable<'tcx>>(
|
||||||
|
&self,
|
||||||
|
depth: usize,
|
||||||
|
error_obligation: &Obligation<'tcx, T>,
|
||||||
|
) -> Result<(), OverflowError> {
|
||||||
|
if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
|
||||||
|
match self.query_mode {
|
||||||
|
TraitQueryMode::Standard => {
|
||||||
|
self.infcx.report_overflow_error(error_obligation, true);
|
||||||
|
}
|
||||||
|
TraitQueryMode::Canonical => {
|
||||||
|
return Err(OverflowError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks that the recursion limit has not been exceeded.
|
/// Checks that the recursion limit has not been exceeded.
|
||||||
///
|
///
|
||||||
/// The weird return type of this function allows it to be used with the `try` (`?`)
|
/// The weird return type of this function allows it to be used with the `try` (`?`)
|
||||||
|
@ -1047,17 +1065,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
obligation: &Obligation<'tcx, T>,
|
obligation: &Obligation<'tcx, T>,
|
||||||
error_obligation: &Obligation<'tcx, V>,
|
error_obligation: &Obligation<'tcx, V>,
|
||||||
) -> Result<(), OverflowError> {
|
) -> Result<(), OverflowError> {
|
||||||
if !self.infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
|
self.check_recursion_depth(obligation.recursion_depth, error_obligation)
|
||||||
match self.query_mode {
|
|
||||||
TraitQueryMode::Standard => {
|
|
||||||
self.infcx().report_overflow_error(error_obligation, true);
|
|
||||||
}
|
|
||||||
TraitQueryMode::Canonical => {
|
|
||||||
return Err(OverflowError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
|
fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
|
||||||
|
@ -1079,10 +1087,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
// Respect const trait obligations
|
// Respect const trait obligations
|
||||||
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
|
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
|
||||||
if Some(obligation.predicate.skip_binder().trait_ref.def_id)
|
|
||||||
!= tcx.lang_items().sized_trait()
|
|
||||||
// const Sized bounds are skipped
|
|
||||||
{
|
|
||||||
match candidate {
|
match candidate {
|
||||||
// const impl
|
// const impl
|
||||||
ImplCandidate(def_id)
|
ImplCandidate(def_id)
|
||||||
|
@ -1097,12 +1101,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// generator, this will raise error in other places
|
// generator, this will raise error in other places
|
||||||
// or ignore error with const_async_blocks feature
|
// or ignore error with const_async_blocks feature
|
||||||
GeneratorCandidate => {}
|
GeneratorCandidate => {}
|
||||||
|
ConstDropCandidate => {}
|
||||||
_ => {
|
_ => {
|
||||||
// reject all other types of candidates
|
// reject all other types of candidates
|
||||||
return Err(Unimplemented);
|
return Err(Unimplemented);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
|
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
|
||||||
if let ImplCandidate(def_id) = candidate {
|
if let ImplCandidate(def_id) = candidate {
|
||||||
|
@ -1476,14 +1480,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
(
|
(
|
||||||
BuiltinCandidate { has_nested: false }
|
BuiltinCandidate { has_nested: false }
|
||||||
| DiscriminantKindCandidate
|
| DiscriminantKindCandidate
|
||||||
| PointeeCandidate,
|
| PointeeCandidate
|
||||||
|
| ConstDropCandidate,
|
||||||
_,
|
_,
|
||||||
) => true,
|
) => true,
|
||||||
(
|
(
|
||||||
_,
|
_,
|
||||||
BuiltinCandidate { has_nested: false }
|
BuiltinCandidate { has_nested: false }
|
||||||
| DiscriminantKindCandidate
|
| DiscriminantKindCandidate
|
||||||
| PointeeCandidate,
|
| PointeeCandidate
|
||||||
|
| ConstDropCandidate,
|
||||||
) => false,
|
) => false,
|
||||||
|
|
||||||
(ParamCandidate(other), ParamCandidate(victim)) => {
|
(ParamCandidate(other), ParamCandidate(victim)) => {
|
||||||
|
|
|
@ -386,7 +386,8 @@ fn resolve_associated_item<'tcx>(
|
||||||
| traits::ImplSource::TraitAlias(..)
|
| traits::ImplSource::TraitAlias(..)
|
||||||
| traits::ImplSource::DiscriminantKind(..)
|
| traits::ImplSource::DiscriminantKind(..)
|
||||||
| traits::ImplSource::Pointee(..)
|
| traits::ImplSource::Pointee(..)
|
||||||
| traits::ImplSource::TraitUpcasting(_) => None,
|
| traits::ImplSource::TraitUpcasting(_)
|
||||||
|
| traits::ImplSource::ConstDrop(_) => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,57 @@ const fn b() -> u8 {
|
||||||
|
|
||||||
const C: u8 = b();
|
const C: u8 = b();
|
||||||
|
|
||||||
|
macro_rules! implements_const_drop {
|
||||||
|
($($exp:expr),*$(,)?) => {
|
||||||
|
$(
|
||||||
|
const _: () = a($exp);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod t {
|
||||||
|
pub struct Foo;
|
||||||
|
pub enum Bar { A }
|
||||||
|
pub fn foo() {}
|
||||||
|
pub struct ConstDrop;
|
||||||
|
|
||||||
|
impl const Drop for ConstDrop {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HasConstDrop(pub ConstDrop);
|
||||||
|
pub struct TrivialFields(pub u8, pub i8, pub usize, pub isize);
|
||||||
|
}
|
||||||
|
|
||||||
|
use t::*;
|
||||||
|
|
||||||
|
implements_const_drop! {
|
||||||
|
1u8,
|
||||||
|
2,
|
||||||
|
3.0,
|
||||||
|
Foo,
|
||||||
|
Bar::A,
|
||||||
|
foo,
|
||||||
|
ConstDrop,
|
||||||
|
HasConstDrop(ConstDrop),
|
||||||
|
TrivialFields(1, 2, 3, 4),
|
||||||
|
&1,
|
||||||
|
&1 as *const i32,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
struct HasDropGlue(Box<u8>);
|
||||||
|
struct HasDropImpl;
|
||||||
|
impl Drop for HasDropImpl {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
println!("not trivial drop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These types should pass because ~const in a non-const context should have no effect.
|
||||||
|
a(HasDropGlue(Box::new(0)));
|
||||||
|
a(HasDropImpl);
|
||||||
|
|
||||||
assert_eq!(C, 2);
|
assert_eq!(C, 2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue