about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs7
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs90
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile2
-rwxr-xr-xsrc/ci/scripts/should-skip-this.sh1
-rw-r--r--src/test/ui/coherence/coherence-overlap-double-negative.rs12
-rw-r--r--src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs4
-rw-r--r--src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr11
-rw-r--r--src/test/ui/coherence/coherence-overlap-super-negative.rs18
m---------src/tools/miri16
10 files changed, 108 insertions, 55 deletions
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index e7cef9e198b..83ab761aa55 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -748,6 +748,13 @@ pub struct TraitPredicate<'tcx> {
 
     pub constness: BoundConstness,
 
+    /// If polarity is Positive: we are proving that the trait is implemented.
+    ///
+    /// If polarity is Negative: we are proving that a negative impl of this trait
+    /// exists. (Note that coherence also checks whether negative impls of supertraits
+    /// exist via a series of predicates.)
+    ///
+    /// If polarity is Reserved: that's a bug.
     pub polarity: ImplPolarity,
 }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 91695257137..d5b1aa00e52 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1129,7 +1129,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         }
 
         for param in &generics.params {
-            if let GenericParamKind::Lifetime { .. } = param.kind {
+            if let GenericParamKind::Lifetime = param.kind {
                 continue;
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index a3d32acc6fb..94a4001bbb9 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -17,8 +17,8 @@ use crate::traits::{
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::CRATE_HIR_ID;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::{util, TraitEngine};
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{self, TreatParams};
 use rustc_middle::ty::fold::TypeFoldable;
@@ -353,6 +353,8 @@ fn negative_impl<'cx, 'tcx>(
     })
 }
 
+/// Try to prove that a negative impl exist for the given obligation and their super predicates.
+#[instrument(level = "debug", skip(selcx))]
 fn negative_impl_exists<'cx, 'tcx>(
     selcx: &SelectionContext<'cx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -360,42 +362,66 @@ fn negative_impl_exists<'cx, 'tcx>(
     o: &PredicateObligation<'tcx>,
 ) -> bool {
     let infcx = &selcx.infcx().fork();
+
+    if resolve_negative_obligation(infcx, param_env, region_context, o) {
+        return true;
+    }
+
+    // Try to prove a negative obligation exist for super predicates
+    for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
+        if resolve_negative_obligation(infcx, param_env, region_context, &o) {
+            return true;
+        }
+    }
+
+    false
+}
+
+#[instrument(level = "debug", skip(infcx))]
+fn resolve_negative_obligation<'cx, 'tcx>(
+    infcx: &InferCtxt<'cx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    region_context: DefId,
+    o: &PredicateObligation<'tcx>,
+) -> bool {
     let tcx = infcx.tcx;
-    o.flip_polarity(tcx)
-        .map(|o| {
-            let mut fulfillment_cx = FulfillmentContext::new();
-            fulfillment_cx.register_predicate_obligation(infcx, o);
-
-            let errors = fulfillment_cx.select_all_or_error(infcx);
-            if !errors.is_empty() {
-                return false;
-            }
 
-            let mut outlives_env = OutlivesEnvironment::new(param_env);
-            // FIXME -- add "assumed to be well formed" types into the `outlives_env`
+    let Some(o) = o.flip_polarity(tcx) else {
+        return false;
+    };
 
-            // "Save" the accumulated implied bounds into the outlives environment
-            // (due to the FIXME above, there aren't any, but this step is still needed).
-            // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used
-            // by the "dummy" causes elsewhere (body-id is only relevant when checking
-            // function bodies with closures).
-            outlives_env.save_implied_bounds(CRATE_HIR_ID);
+    let mut fulfillment_cx = FulfillmentContext::new();
+    fulfillment_cx.register_predicate_obligation(infcx, o);
 
-            infcx.process_registered_region_obligations(
-                outlives_env.region_bound_pairs_map(),
-                Some(tcx.lifetimes.re_root_empty),
-                param_env,
-            );
+    let errors = fulfillment_cx.select_all_or_error(infcx);
 
-            let errors =
-                infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default());
-            if !errors.is_empty() {
-                return false;
-            }
+    if !errors.is_empty() {
+        return false;
+    }
 
-            true
-        })
-        .unwrap_or(false)
+    let mut outlives_env = OutlivesEnvironment::new(param_env);
+    // FIXME -- add "assumed to be well formed" types into the `outlives_env`
+
+    // "Save" the accumulated implied bounds into the outlives environment
+    // (due to the FIXME above, there aren't any, but this step is still needed).
+    // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used
+    // by the "dummy" causes elsewhere (body-id is only relevant when checking
+    // function bodies with closures).
+    outlives_env.save_implied_bounds(CRATE_HIR_ID);
+
+    infcx.process_registered_region_obligations(
+        outlives_env.region_bound_pairs_map(),
+        Some(tcx.lifetimes.re_root_empty),
+        param_env,
+    );
+
+    let errors = infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default());
+
+    if !errors.is_empty() {
+        return false;
+    }
+
+    true
 }
 
 pub fn trait_ref_is_knowable<'tcx>(
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index b0f052e6cf0..d78fc6d2083 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # https://github.com/puppeteer/puppeteer/issues/375
 #
 # We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.8.1 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.8.3 --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh
index bb48fcb5a21..c046a6c8a26 100755
--- a/src/ci/scripts/should-skip-this.sh
+++ b/src/ci/scripts/should-skip-this.sh
@@ -25,6 +25,7 @@ if [[ -n "${CI_ONLY_WHEN_SUBMODULES_CHANGED-}" ]]; then
     elif ! (git diff --quiet "$BASE_COMMIT" -- \
              src/test/rustdoc-gui \
              src/librustdoc \
+             src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile \
              src/tools/rustdoc-gui); then
         # There was a change in either rustdoc or in its GUI tests.
         echo "Rustdoc was updated"
diff --git a/src/test/ui/coherence/coherence-overlap-double-negative.rs b/src/test/ui/coherence/coherence-overlap-double-negative.rs
new file mode 100644
index 00000000000..1ea0ddc7430
--- /dev/null
+++ b/src/test/ui/coherence/coherence-overlap-double-negative.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(with_negative_coherence)]
+
+trait A {}
+trait B: A {}
+
+impl !A for u32 {}
+impl !B for u32 {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs
index c240a183982..48dffc921a3 100644
--- a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs
+++ b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 #![feature(negative_impls)]
 #![feature(rustc_attrs)]
 #![feature(trait_alias)]
@@ -13,7 +15,5 @@ impl !A for u32 {}
 trait C {}
 impl<T: AB> C for T {}
 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
deleted file mode 100644
index 30d837a5c50..00000000000
--- a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-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 | 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-super-negative.rs b/src/test/ui/coherence/coherence-overlap-super-negative.rs
new file mode 100644
index 00000000000..d296a094a37
--- /dev/null
+++ b/src/test/ui/coherence/coherence-overlap-super-negative.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(with_negative_coherence)]
+
+trait Trait1: Trait2 {}
+trait Trait2 {}
+
+struct MyType {}
+impl !Trait2 for MyType {}
+
+#[rustc_strict_coherence]
+trait Foo {}
+impl<T: Trait1> Foo for T {}
+impl Foo for MyType {}
+
+fn main() {}
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 7bc0c986217629e6c831edcb133532023a5aec6
+Subproject 8e818ffa1b85f4e740c4096fd38c62b2b73f4d8