Skip to content

Commit

Permalink
Add rustc_strict_coherence attribute and use it to check overlap
Browse files Browse the repository at this point in the history
  • Loading branch information
spastorino committed Oct 22, 2021
1 parent 74454c4 commit da79fa9
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 2 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Expand Up @@ -556,6 +556,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word)),
rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Expand Up @@ -1142,6 +1142,7 @@ symbols! {
rustc_specialization_trait,
rustc_stable,
rustc_std_internal_symbol,
rustc_strict_coherence,
rustc_symbol_name,
rustc_synthetic,
rustc_test_marker,
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_trait_selection/src/traits/coherence.rs
Expand Up @@ -222,11 +222,22 @@ fn overlap_within_probe(
})
.chain(obligations)
.find(|o| {
!selcx.predicate_may_hold_fatal(o)
|| o.flip_polarity(tcx)
// if both impl headers are set to strict coherence it means that this will be accepted
// only if it's stated that T: !Trait. So only prove that the negated obligation holds.
if tcx.has_attr(a_def_id, sym::rustc_strict_coherence)
&& tcx.has_attr(b_def_id, sym::rustc_strict_coherence)
{
o.flip_polarity(tcx)
.as_ref()
.map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o))
.unwrap_or(false)
} else {
!selcx.predicate_may_hold_fatal(o)
|| o.flip_polarity(tcx)
.as_ref()
.map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o))
.unwrap_or(false)
}
});
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
// to the canonical trait query form, `infcx.predicate_may_hold`, once
Expand Down
19 changes: 19 additions & 0 deletions src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs
@@ -0,0 +1,19 @@
#![feature(negative_impls)]
#![feature(rustc_attrs)]
#![feature(trait_alias)]

trait A {}
trait B {}
trait AB = A + B;

impl !A for u32 {}

trait C {}
#[rustc_strict_coherence]
impl<T: AB> C for T {}
#[rustc_strict_coherence]
impl C for u32 {}
//~^ ERROR: conflicting implementations of trait `C` for type `u32` [E0119]
// FIXME this should work, we should implement an `assemble_neg_candidates` fn

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr
@@ -0,0 +1,12 @@
error[E0119]: conflicting implementations of trait `C` for type `u32`
--> $DIR/coherence-overlap-negate-alias-strict.rs:15:1
|
LL | impl<T: AB> C for T {}
| ------------------- first implementation here
LL | #[rustc_strict_coherence]
LL | impl C for u32 {}
| ^^^^^^^^^^^^^^ conflicting implementation for `u32`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0119`.
18 changes: 18 additions & 0 deletions src/test/ui/coherence/coherence-overlap-negate-strict.rs
@@ -0,0 +1,18 @@
// check-pass

#![feature(negative_impls)]
#![feature(rustc_attrs)]
#![feature(trait_alias)]

trait A {}
trait B {}

impl !A for u32 {}

trait C {}
#[rustc_strict_coherence]
impl<T: A + B> C for T {}
#[rustc_strict_coherence]
impl C for u32 {}

fn main() {}

0 comments on commit da79fa9

Please sign in to comment.