Skip to content

Commit c8f86ca

Browse files
committed
Elaborate predicates in min_specialization checks
Supertraits of specialization markers could circumvent checks for min_specialization. Elaborating predicates prevents this.
1 parent 6dc08b9 commit c8f86ca

File tree

4 files changed

+76
-18
lines changed

4 files changed

+76
-18
lines changed

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
6464
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
6565
pub use self::structural_match::search_for_structural_match_violation;
6666
pub use self::structural_match::NonStructuralMatchTy;
67-
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
67+
pub use self::util::{
68+
elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs,
69+
};
6870
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
6971
pub use self::util::{
7072
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,

compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
7474
use rustc_infer::traits::specialization_graph::Node;
7575
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
7676
use rustc_middle::ty::trait_def::TraitSpecializationKind;
77-
use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable};
77+
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
7878
use rustc_span::Span;
7979
use rustc_trait_selection::traits::{self, translate_substs, wf};
8080

@@ -294,13 +294,27 @@ fn check_predicates<'tcx>(
294294
span: Span,
295295
) {
296296
let tcx = infcx.tcx;
297-
let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
297+
let impl1_predicates: Vec<_> = traits::elaborate_predicates(
298+
tcx,
299+
tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(),
300+
)
301+
.map(|obligation| obligation.predicate)
302+
.collect();
303+
298304
let mut impl2_predicates = if impl2_node.is_from_trait() {
299305
// Always applicable traits have to be always applicable without any
300306
// assumptions.
301-
InstantiatedPredicates::empty()
307+
Vec::new()
302308
} else {
303-
tcx.predicates_of(impl2_node.def_id()).instantiate(tcx, impl2_substs)
309+
traits::elaborate_predicates(
310+
tcx,
311+
tcx.predicates_of(impl2_node.def_id())
312+
.instantiate(tcx, impl2_substs)
313+
.predicates
314+
.into_iter(),
315+
)
316+
.map(|obligation| obligation.predicate)
317+
.collect()
304318
};
305319
debug!(
306320
"check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)",
@@ -322,13 +336,12 @@ fn check_predicates<'tcx>(
322336
// which is sound because we forbid impls like the following
323337
//
324338
// impl<D: Debug> AlwaysApplicable for D { }
325-
let always_applicable_traits =
326-
impl1_predicates.predicates.iter().copied().filter(|&predicate| {
327-
matches!(
328-
trait_predicate_kind(tcx, predicate),
329-
Some(TraitSpecializationKind::AlwaysApplicable)
330-
)
331-
});
339+
let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| {
340+
matches!(
341+
trait_predicate_kind(tcx, predicate),
342+
Some(TraitSpecializationKind::AlwaysApplicable)
343+
)
344+
});
332345

333346
// Include the well-formed predicates of the type parameters of the impl.
334347
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
@@ -340,18 +353,19 @@ fn check_predicates<'tcx>(
340353
arg,
341354
span,
342355
) {
343-
impl2_predicates
344-
.predicates
345-
.extend(obligations.into_iter().map(|obligation| obligation.predicate))
356+
impl2_predicates.extend(
357+
traits::elaborate_obligations(tcx, obligations)
358+
.map(|obligation| obligation.predicate),
359+
)
346360
}
347361
}
348-
impl2_predicates.predicates.extend(
362+
impl2_predicates.extend(
349363
traits::elaborate_predicates(tcx, always_applicable_traits)
350364
.map(|obligation| obligation.predicate),
351365
);
352366

353-
for predicate in impl1_predicates.predicates {
354-
if !impl2_predicates.predicates.contains(&predicate) {
367+
for predicate in impl1_predicates {
368+
if !impl2_predicates.contains(&predicate) {
355369
check_specialization_on(tcx, predicate, span)
356370
}
357371
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Check that supertraits cannot be used to work around min_specialization
2+
// limitations.
3+
4+
#![feature(min_specialization)]
5+
#![feature(rustc_attrs)]
6+
7+
trait HasMethod {
8+
fn method(&self);
9+
}
10+
11+
#[rustc_unsafe_specialization_marker]
12+
trait Marker: HasMethod {}
13+
14+
trait Spec {
15+
fn spec_me(&self);
16+
}
17+
18+
impl<T> Spec for T {
19+
default fn spec_me(&self) {}
20+
}
21+
22+
impl<T: Marker> Spec for T {
23+
//~^ ERROR cannot specialize on trait `HasMethod`
24+
fn spec_me(&self) {
25+
self.method();
26+
}
27+
}
28+
29+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: cannot specialize on trait `HasMethod`
2+
--> $DIR/spec-marker-supertraits.rs:22:1
3+
|
4+
LL | / impl<T: Marker> Spec for T {
5+
LL | |
6+
LL | | fn spec_me(&self) {
7+
LL | | self.method();
8+
LL | | }
9+
LL | | }
10+
| |_^
11+
12+
error: aborting due to previous error
13+

0 commit comments

Comments
 (0)