Implement and use BikeshedGuaranteedNoDrop for union/unsafe field validity

This commit is contained in:
Michael Goulet 2025-02-06 20:08:29 +00:00
parent c72d443cdd
commit 516afd557c
21 changed files with 365 additions and 66 deletions

View file

@ -267,6 +267,11 @@ where
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// Consider (possibly several) candidates to upcast or unsize a type to another
/// type, excluding the coercion of a sized type into a `dyn Trait`.
///
@ -478,6 +483,9 @@ where
Some(TraitSolverLangItem::TransmuteTrait) => {
G::consider_builtin_transmute_candidate(self, goal)
}
Some(TraitSolverLangItem::BikeshedGuaranteedNoDrop) => {
G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal)
}
_ => Err(NoSolution),
}
};

View file

@ -374,6 +374,13 @@ where
unreachable!("TransmuteFrom is not const")
}
fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
unreachable!("BikeshedGuaranteedNoDrop is not const");
}
fn consider_structural_builtin_unsize_candidates(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,

View file

@ -942,6 +942,13 @@ where
) -> Result<Candidate<I>, NoSolution> {
panic!("`TransmuteFrom` does not have an associated type: {:?}", goal)
}
fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
_ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
unreachable!("`BikeshedGuaranteedNoDrop` does not have an associated type: {:?}", goal)
}
}
impl<D, I> EvalCtxt<'_, D>

View file

@ -625,6 +625,101 @@ where
})
}
/// NOTE: This is implemented as a built-in goal and not a set of impls like:
///
/// ```
/// impl<T> BikeshedGuaranteedNoDrop for T where T: Copy {}
/// impl<T> BikeshedGuaranteedNoDrop for ManuallyDrop<T> {}
/// ```
///
/// because these impls overlap, and I'd rather not build a coherence hack for
/// this harmless overlap.
fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
let cx = ecx.cx();
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
let ty = goal.predicate.self_ty();
match ty.kind() {
// `&mut T` and `&T` always implement `BikeshedGuaranteedNoDrop`.
ty::Ref(..) => {}
// `ManuallyDrop<T>` always implements `BikeshedGuaranteedNoDrop`.
ty::Adt(def, _) if def.is_manually_drop() => {}
// Arrays and tuples implement `BikeshedGuaranteedNoDrop` only if
// their constituent types implement `BikeshedGuaranteedNoDrop`.
ty::Tuple(tys) => {
ecx.add_goals(
GoalSource::ImplWhereBound,
tys.iter().map(|elem_ty| {
goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty]))
}),
);
}
ty::Array(elem_ty, _) => {
ecx.add_goal(
GoalSource::ImplWhereBound,
goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])),
);
}
// All other types implement `BikeshedGuaranteedNoDrop` only if
// they implement `Copy`. We could be smart here and short-circuit
// some trivially `Copy`/`!Copy` types, but there's no benefit.
ty::FnDef(..)
| ty::FnPtr(..)
| ty::Error(_)
| ty::Uint(_)
| ty::Int(_)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Bool
| ty::Float(_)
| ty::Char
| ty::RawPtr(..)
| ty::Never
| ty::Pat(..)
| ty::Dynamic(..)
| ty::Str
| ty::Slice(_)
| ty::Foreign(..)
| ty::Adt(..)
| ty::Alias(..)
| ty::Param(_)
| ty::Placeholder(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::UnsafeBinder(_)
| ty::CoroutineWitness(..) => {
ecx.add_goal(
GoalSource::ImplWhereBound,
goal.with(
cx,
ty::TraitRef::new(
cx,
cx.require_lang_item(TraitSolverLangItem::Copy),
[ty],
),
),
);
}
ty::Bound(..)
| ty::Infer(
ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
) => {
panic!("unexpected type `{ty:?}`")
}
}
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
/// ```ignore (builtin impl example)
/// trait Trait {
/// fn foo(&self);