Rollup merge of #89413 - matthewjasper:spec-marker-fix, r=nikomatsakis
Correctly handle supertraits for min_specialization Supertraits of specialization markers could circumvent checks for min_specialization. Elaborating predicates prevents this. r? ````@nikomatsakis````
This commit is contained in:
commit
05b4cd6789
@ -64,7 +64,9 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
|
||||
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
|
||||
pub use self::structural_match::search_for_structural_match_violation;
|
||||
pub use self::structural_match::NonStructuralMatchTy;
|
||||
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
|
||||
pub use self::util::{
|
||||
elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs,
|
||||
};
|
||||
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
|
||||
pub use self::util::{
|
||||
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
|
||||
|
@ -74,7 +74,7 @@ use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
|
||||
use rustc_infer::traits::specialization_graph::Node;
|
||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||
use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::{self, translate_substs, wf};
|
||||
|
||||
@ -294,13 +294,27 @@ fn check_predicates<'tcx>(
|
||||
span: Span,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
|
||||
let impl1_predicates: Vec<_> = traits::elaborate_predicates(
|
||||
tcx,
|
||||
tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(),
|
||||
)
|
||||
.map(|obligation| obligation.predicate)
|
||||
.collect();
|
||||
|
||||
let mut impl2_predicates = if impl2_node.is_from_trait() {
|
||||
// Always applicable traits have to be always applicable without any
|
||||
// assumptions.
|
||||
InstantiatedPredicates::empty()
|
||||
Vec::new()
|
||||
} else {
|
||||
tcx.predicates_of(impl2_node.def_id()).instantiate(tcx, impl2_substs)
|
||||
traits::elaborate_predicates(
|
||||
tcx,
|
||||
tcx.predicates_of(impl2_node.def_id())
|
||||
.instantiate(tcx, impl2_substs)
|
||||
.predicates
|
||||
.into_iter(),
|
||||
)
|
||||
.map(|obligation| obligation.predicate)
|
||||
.collect()
|
||||
};
|
||||
debug!(
|
||||
"check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)",
|
||||
@ -322,13 +336,12 @@ fn check_predicates<'tcx>(
|
||||
// which is sound because we forbid impls like the following
|
||||
//
|
||||
// impl<D: Debug> AlwaysApplicable for D { }
|
||||
let always_applicable_traits =
|
||||
impl1_predicates.predicates.iter().copied().filter(|&predicate| {
|
||||
matches!(
|
||||
trait_predicate_kind(tcx, predicate),
|
||||
Some(TraitSpecializationKind::AlwaysApplicable)
|
||||
)
|
||||
});
|
||||
let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| {
|
||||
matches!(
|
||||
trait_predicate_kind(tcx, predicate),
|
||||
Some(TraitSpecializationKind::AlwaysApplicable)
|
||||
)
|
||||
});
|
||||
|
||||
// Include the well-formed predicates of the type parameters of the impl.
|
||||
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
|
||||
@ -340,18 +353,19 @@ fn check_predicates<'tcx>(
|
||||
arg,
|
||||
span,
|
||||
) {
|
||||
impl2_predicates
|
||||
.predicates
|
||||
.extend(obligations.into_iter().map(|obligation| obligation.predicate))
|
||||
impl2_predicates.extend(
|
||||
traits::elaborate_obligations(tcx, obligations)
|
||||
.map(|obligation| obligation.predicate),
|
||||
)
|
||||
}
|
||||
}
|
||||
impl2_predicates.predicates.extend(
|
||||
impl2_predicates.extend(
|
||||
traits::elaborate_predicates(tcx, always_applicable_traits)
|
||||
.map(|obligation| obligation.predicate),
|
||||
);
|
||||
|
||||
for predicate in impl1_predicates.predicates {
|
||||
if !impl2_predicates.predicates.contains(&predicate) {
|
||||
for predicate in impl1_predicates {
|
||||
if !impl2_predicates.contains(&predicate) {
|
||||
check_specialization_on(tcx, predicate, span)
|
||||
}
|
||||
}
|
||||
|
@ -266,14 +266,21 @@ unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(issue = "none", feature = "std_internals")]
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
pub trait NonDrop {}
|
||||
|
||||
// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
|
||||
// and thus we can't implement drop-handling
|
||||
//
|
||||
#[unstable(issue = "none", feature = "std_internals")]
|
||||
impl<T: Copy> NonDrop for T {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(issue = "none", feature = "std_internals")]
|
||||
// TrustedRandomAccess (without NoCoerce) must not be implemented because
|
||||
// subtypes/supertypes of `T` might not be `Copy`
|
||||
// subtypes/supertypes of `T` might not be `NonDrop`
|
||||
unsafe impl<T, A: Allocator> TrustedRandomAccessNoCoerce for IntoIter<T, A>
|
||||
where
|
||||
T: Copy,
|
||||
T: NonDrop,
|
||||
{
|
||||
const MAY_HAVE_SIDE_EFFECT: bool = false;
|
||||
}
|
||||
|
@ -6,24 +6,14 @@ use super::{AsIntoIter, InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec};
|
||||
|
||||
/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
|
||||
/// source allocation, i.e. executing the pipeline in place.
|
||||
///
|
||||
/// The SourceIter parent trait is necessary for the specializing function to access the allocation
|
||||
/// which is to be reused. But it is not sufficient for the specialization to be valid. See
|
||||
/// additional bounds on the impl.
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
pub(super) trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}
|
||||
pub(super) trait InPlaceIterableMarker {}
|
||||
|
||||
// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
|
||||
// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
|
||||
// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
|
||||
// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
|
||||
// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
|
||||
// several other specializations already depend on.
|
||||
impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
|
||||
impl<T> InPlaceIterableMarker for T where T: InPlaceIterable {}
|
||||
|
||||
impl<T, I> SpecFromIter<T, I> for Vec<T>
|
||||
where
|
||||
I: Iterator<Item = T> + SourceIterMarker,
|
||||
I: Iterator<Item = T> + SourceIter<Source: AsIntoIter> + InPlaceIterableMarker,
|
||||
{
|
||||
default fn from_iter(mut iterator: I) -> Self {
|
||||
// Additional requirements which cannot expressed via trait bounds. We rely on const eval
|
||||
|
@ -249,14 +249,14 @@ impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
|
||||
unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, I: Iterator> SourceIter for Enumerate<I>
|
||||
unsafe impl<I> SourceIter for Enumerate<I>
|
||||
where
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -135,15 +135,14 @@ where
|
||||
impl<I: FusedIterator, P> FusedIterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, P, I: Iterator> SourceIter for Filter<I, P>
|
||||
unsafe impl<P, I> SourceIter for Filter<I, P>
|
||||
where
|
||||
P: FnMut(&I::Item) -> bool,
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -129,15 +129,14 @@ where
|
||||
impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F> where F: FnMut(I::Item) -> Option<B> {}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, B, I: Iterator, F> SourceIter for FilterMap<I, F>
|
||||
unsafe impl<I, F> SourceIter for FilterMap<I, F>
|
||||
where
|
||||
F: FnMut(I::Item) -> Option<B>,
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -149,15 +149,14 @@ where
|
||||
impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, I: Iterator, F> SourceIter for Inspect<I, F>
|
||||
unsafe impl<I, F> SourceIter for Inspect<I, F>
|
||||
where
|
||||
F: FnMut(&I::Item),
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -201,15 +201,14 @@ where
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, B, I: Iterator, F> SourceIter for Map<I, F>
|
||||
unsafe impl<I, F> SourceIter for Map<I, F>
|
||||
where
|
||||
F: FnMut(I::Item) -> B,
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -80,15 +80,14 @@ where
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, B, I: Iterator, P> SourceIter for MapWhile<I, P>
|
||||
unsafe impl<I, P> SourceIter for MapWhile<I, P>
|
||||
where
|
||||
P: FnMut(I::Item) -> Option<B>,
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -92,9 +92,10 @@ pub use self::zip::zip;
|
||||
/// [`as_inner`]: SourceIter::as_inner
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
#[doc(hidden)]
|
||||
#[rustc_specialization_trait]
|
||||
pub unsafe trait SourceIter {
|
||||
/// A source stage in an iterator pipeline.
|
||||
type Source: Iterator;
|
||||
type Source;
|
||||
|
||||
/// Retrieve the source of an iterator pipeline.
|
||||
///
|
||||
@ -200,14 +201,14 @@ where
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, I, E> SourceIter for ResultShunt<'_, I, E>
|
||||
unsafe impl<I, E> SourceIter for ResultShunt<'_, I, E>
|
||||
where
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut Self::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -321,14 +321,14 @@ impl<I: Iterator> Peekable<I> {
|
||||
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
|
||||
unsafe impl<I: Iterator> SourceIter for Peekable<I>
|
||||
where
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -90,15 +90,14 @@ where
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<St, F, B, S: Iterator, I: Iterator> SourceIter for Scan<I, St, F>
|
||||
unsafe impl<St, F, I> SourceIter for Scan<I, St, F>
|
||||
where
|
||||
I: SourceIter<Source = S>,
|
||||
F: FnMut(&mut St, I::Item) -> Option<B>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -222,14 +222,14 @@ where
|
||||
impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, I: Iterator> SourceIter for Skip<I>
|
||||
unsafe impl<I> SourceIter for Skip<I>
|
||||
where
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -105,15 +105,14 @@ where
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, P, I: Iterator> SourceIter for SkipWhile<I, P>
|
||||
unsafe impl<P, I> SourceIter for SkipWhile<I, P>
|
||||
where
|
||||
P: FnMut(&I::Item) -> bool,
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -130,14 +130,14 @@ where
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, I: Iterator> SourceIter for Take<I>
|
||||
unsafe impl<I> SourceIter for Take<I>
|
||||
where
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -118,15 +118,14 @@ where
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S: Iterator, P, I: Iterator> SourceIter for TakeWhile<I, P>
|
||||
unsafe impl<P, I> SourceIter for TakeWhile<I, P>
|
||||
where
|
||||
P: FnMut(&I::Item) -> bool,
|
||||
I: SourceIter<Source = S>,
|
||||
I: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = I::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut I::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.iter) }
|
||||
}
|
||||
|
@ -414,16 +414,14 @@ where
|
||||
// Arbitrarily selects the left side of the zip iteration as extractable "source"
|
||||
// it would require negative trait bounds to be able to try both
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<S, A, B> SourceIter for Zip<A, B>
|
||||
unsafe impl<A, B> SourceIter for Zip<A, B>
|
||||
where
|
||||
A: SourceIter<Source = S>,
|
||||
B: Iterator,
|
||||
S: Iterator,
|
||||
A: SourceIter,
|
||||
{
|
||||
type Source = S;
|
||||
type Source = A::Source;
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_inner(&mut self) -> &mut S {
|
||||
unsafe fn as_inner(&mut self) -> &mut A::Source {
|
||||
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
|
||||
unsafe { SourceIter::as_inner(&mut self.a) }
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
// Check that supertraits cannot be used to work around min_specialization
|
||||
// limitations.
|
||||
|
||||
#![feature(min_specialization)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
trait HasMethod {
|
||||
fn method(&self);
|
||||
}
|
||||
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
trait Marker: HasMethod {}
|
||||
|
||||
trait Spec {
|
||||
fn spec_me(&self);
|
||||
}
|
||||
|
||||
impl<T> Spec for T {
|
||||
default fn spec_me(&self) {}
|
||||
}
|
||||
|
||||
impl<T: Marker> Spec for T {
|
||||
//~^ ERROR cannot specialize on trait `HasMethod`
|
||||
fn spec_me(&self) {
|
||||
self.method();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,13 @@
|
||||
error: cannot specialize on trait `HasMethod`
|
||||
--> $DIR/spec-marker-supertraits.rs:22:1
|
||||
|
|
||||
LL | / impl<T: Marker> Spec for T {
|
||||
LL | |
|
||||
LL | | fn spec_me(&self) {
|
||||
LL | | self.method();
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
x
Reference in New Issue
Block a user