about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2021-10-22 15:44:28 -0300
committerSantiago Pastorino <spastorino@gmail.com>2021-10-22 15:49:46 -0300
commitda79fa964cfe82cfca3d9db6e32108888c837459 (patch)
tree25f617a7d92bc672a0b13681b3d89656292d0e78
parent74454c4888a0a5a5bca17b5adb1440c6b552608b (diff)
downloadrust-da79fa964cfe82cfca3d9db6e32108888c837459.tar.gz
rust-da79fa964cfe82cfca3d9db6e32108888c837459.zip
Add rustc_strict_coherence attribute and use it to check overlap
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs15
-rw-r--r--src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs19
-rw-r--r--src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr12
-rw-r--r--src/test/ui/coherence/coherence-overlap-negate-strict.rs18
6 files changed, 64 insertions, 2 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 85b0db468d1..33188d375f5 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -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)),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index fddb225345f..084cd95de60 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -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,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index d422bd66b10..35fd3153680 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -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
diff --git a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs
new file mode 100644
index 00000000000..16ace450b06
--- /dev/null
+++ b/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() {}
diff --git a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr
new file mode 100644
index 00000000000..5e436223119
--- /dev/null
+++ b/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`.
diff --git a/src/test/ui/coherence/coherence-overlap-negate-strict.rs b/src/test/ui/coherence/coherence-overlap-negate-strict.rs
new file mode 100644
index 00000000000..b3ae9a7bf78
--- /dev/null
+++ b/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() {}