From 3b25e92a8fbb5856499a84e02bf393a9c18eb962 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Sep 2021 12:12:21 +0000 Subject: [PATCH 1/4] Debug --- .../rustc_const_eval/src/transform/check_consts/check.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 2854e6fd396c2..4e3a8b64094af 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -1004,11 +1004,12 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { } let mut err_span = self.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, - 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; From e0c2ff7ccc0b0ffe095bbf7e1ae358d96bb9152f Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Sep 2021 12:15:17 +0000 Subject: [PATCH 2/4] Allow more cases to match ~const Drop. --- .../src/traits/select/candidate_assembly.rs | 80 +++++++++++-------- .../const-drop-bound.rs | 20 +++++ 2 files changed, 68 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 1d0c54f86dea8..c925672fa3529 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -284,32 +284,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // structs and enums. self.assemble_candidates_from_impls(obligation, &mut candidates); - // For other types, we'll use the builtin rules. - let copy_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); - } else if lang_items.discriminant_kind_trait() == Some(def_id) { - // `DiscriminantKind` is automatically implemented for every type. - candidates.vec.push(DiscriminantKindCandidate); - } else if lang_items.pointee_trait() == Some(def_id) { - // `Pointee` is automatically implemented for every type. - candidates.vec.push(PointeeCandidate); - } else if lang_items.sized_trait() == Some(def_id) { - // Sized is never implementable by end-users, it is - // always automatically computed. - let sized_conditions = self.sized_conditions(obligation); - self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); - } else if lang_items.unsize_trait() == Some(def_id) { - 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 { - debug!("passing ~const Drop bound; in non-const context"); - // `~const Drop` when we are not in a const context has no effect. - candidates.vec.push(ConstDropCandidate) - } + // For other types, we'll use the builtin rules. + let copy_conditions = self.copy_clone_conditions(obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); + } else if lang_items.discriminant_kind_trait() == Some(def_id) { + // `DiscriminantKind` is automatically implemented for every type. + candidates.vec.push(DiscriminantKindCandidate); + } else if lang_items.pointee_trait() == Some(def_id) { + // `Pointee` is automatically implemented for every type. + candidates.vec.push(PointeeCandidate); + } else if lang_items.sized_trait() == Some(def_id) { + // Sized is never implementable by end-users, it is + // always automatically computed. + let sized_conditions = self.sized_conditions(obligation); + self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); + } else if lang_items.unsize_trait() == Some(def_id) { + 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, stack, &mut candidates)?; + } else { + debug!("passing ~const Drop bound; in non-const context"); + // `~const Drop` when we are not in a const context has no effect. + candidates.vec.push(ConstDropCandidate) + } } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -911,9 +911,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn assemble_const_drop_candidates( + fn assemble_const_drop_candidates<'a>( &mut self, obligation: &TraitObligation<'tcx>, + obligation_stack: &TraitObligationStack<'a, 'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)]; @@ -922,7 +923,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut noreturn = false; self.check_recursion_depth(depth, obligation)?; - let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + let mut new_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; let mut copy_obligation = obligation.with(obligation.predicate.rebind(ty::TraitPredicate { trait_ref: ty::TraitRef { @@ -933,13 +934,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { polarity: ty::ImplPolarity::Positive, })); copy_obligation.recursion_depth = depth + 1; - self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates); + self.assemble_candidates_from_impls(©_obligation, &mut new_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() { + self.assemble_builtin_bound_candidates(copy_conditions, &mut new_candidates); + let copy_stack = self.push_stack(obligation_stack.list(), ©_obligation); + self.assemble_candidates_from_caller_bounds(©_stack, &mut new_candidates)?; + + let const_drop_obligation = + obligation.with(obligation.predicate.rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: self.tcx().require_lang_item(hir::LangItem::Drop, None), + substs: self.tcx().mk_substs_trait(ty, &[]), + }, + constness: ty::BoundConstness::ConstIfConst, + })); + + let const_drop_stack = self.push_stack(obligation_stack.list(), &const_drop_obligation); + self.assemble_candidates_from_caller_bounds(&const_drop_stack, &mut new_candidates)?; + + if !new_candidates.vec.is_empty() { noreturn = true; } - debug!(?copy_candidates.vec, "assemble_const_drop_candidates - copy"); + debug!(?new_candidates.vec, "assemble_const_drop_candidates"); match ty.kind() { ty::Int(_) diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs new file mode 100644 index 0000000000000..83fa32bf092bb --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs @@ -0,0 +1,20 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] +#![feature(const_precise_live_drops)] + +const fn foo(res: Result) -> Option where E: ~const Drop { + match res { + Ok(t) => Some(t), + Err(_e) => None, + } +} + +pub struct Foo(T); + +const fn baz(res: Result, Foo>) -> Option> { + foo(res) +} + +fn main() {} From b2005117bc475700f117ab01cf72fb46f1fe2d69 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Sep 2021 12:15:35 +0000 Subject: [PATCH 3/4] Allow features like const_try in d_m_b_i_c --- compiler/rustc_passes/src/check_const.rs | 6 +++ .../trait-default-body-stability.rs | 51 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 82486a6a5f2e2..9ccf76b5700c2 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -173,6 +173,12 @@ impl<'tcx> CheckConstVisitor<'tcx> { None => return true, }; + // If the function belongs to a trait, then it must enable the const_trait_impl + // feature to use that trait function (with a const default body). + if tcx.trait_of_item(def_id).is_some() { + return true; + } + // If this crate is not using stability attributes, or this function is not claiming to be a // stable `const fn`, that is all that is required. if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs new file mode 100644 index 0000000000000..cbfdf89b7bd19 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs @@ -0,0 +1,51 @@ +// check-pass + +#![feature(staged_api)] +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] +#![feature(const_t_try)] +#![feature(const_try)] +#![feature(try_trait_v2)] + +#![stable(feature = "foo", since = "1.0")] + +use std::ops::{ControlFlow, FromResidual, Try}; + +#[stable(feature = "foo", since = "1.0")] +pub struct T; + +#[stable(feature = "foo", since = "1.0")] +#[rustc_const_unstable(feature = "const_t_try", issue = "none")] +impl const Try for T { + type Output = T; + type Residual = T; + + fn from_output(t: T) -> T { + t + } + + fn branch(self) -> ControlFlow { + ControlFlow::Continue(self) + } +} + +#[stable(feature = "foo", since = "1.0")] +#[rustc_const_unstable(feature = "const_t_try", issue = "none")] +impl const FromResidual for T { + fn from_residual(t: T) -> T { + t + } +} + +#[stable(feature = "foo", since = "1.0")] +pub trait Tr { + #[default_method_body_is_const] + #[stable(feature = "foo", since = "1.0")] + fn bar() -> T { + T? + // Should be allowed. + // Must enable unstable features to call this trait fn in const contexts. + } +} + +fn main() {} From 4f29f3cef85a2a66fcfc76bc7fa3cca3d84266f8 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 24 Nov 2021 16:07:38 +0800 Subject: [PATCH 4/4] Add impl polarity to fields --- .../src/traits/select/candidate_assembly.rs | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index c925672fa3529..0ff3611f8f80d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -284,32 +284,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // structs and enums. self.assemble_candidates_from_impls(obligation, &mut candidates); - // For other types, we'll use the builtin rules. - let copy_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); - } else if lang_items.discriminant_kind_trait() == Some(def_id) { - // `DiscriminantKind` is automatically implemented for every type. - candidates.vec.push(DiscriminantKindCandidate); - } else if lang_items.pointee_trait() == Some(def_id) { - // `Pointee` is automatically implemented for every type. - candidates.vec.push(PointeeCandidate); - } else if lang_items.sized_trait() == Some(def_id) { - // Sized is never implementable by end-users, it is - // always automatically computed. - let sized_conditions = self.sized_conditions(obligation); - self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); - } else if lang_items.unsize_trait() == Some(def_id) { - 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, stack, &mut candidates)?; - } else { - debug!("passing ~const Drop bound; in non-const context"); - // `~const Drop` when we are not in a const context has no effect. - candidates.vec.push(ConstDropCandidate) - } + // For other types, we'll use the builtin rules. + let copy_conditions = self.copy_clone_conditions(obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); + } else if lang_items.discriminant_kind_trait() == Some(def_id) { + // `DiscriminantKind` is automatically implemented for every type. + candidates.vec.push(DiscriminantKindCandidate); + } else if lang_items.pointee_trait() == Some(def_id) { + // `Pointee` is automatically implemented for every type. + candidates.vec.push(PointeeCandidate); + } else if lang_items.sized_trait() == Some(def_id) { + // Sized is never implementable by end-users, it is + // always automatically computed. + let sized_conditions = self.sized_conditions(obligation); + self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); + } else if lang_items.unsize_trait() == Some(def_id) { + 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, stack, &mut candidates)?; + } else { + debug!("passing ~const Drop bound; in non-const context"); + // `~const Drop` when we are not in a const context has no effect. + candidates.vec.push(ConstDropCandidate) + } } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -947,6 +947,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs: self.tcx().mk_substs_trait(ty, &[]), }, constness: ty::BoundConstness::ConstIfConst, + polarity: ty::ImplPolarity::Positive, })); let const_drop_stack = self.push_stack(obligation_stack.list(), &const_drop_obligation);