about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2022-01-30 18:55:22 -0300
committerSantiago Pastorino <spastorino@gmail.com>2022-01-31 11:50:43 -0300
commita9bfb5d83754710a8cb7da2f7d17f62ec3cafdcc (patch)
tree3fd1b7a15b4aabb631434f71d896376c760721dc /compiler
parent427eba2f0bacdeaebc992a78eb2889564de7d7cf (diff)
downloadrust-a9bfb5d83754710a8cb7da2f7d17f62ec3cafdcc.tar.gz
rust-a9bfb5d83754710a8cb7da2f7d17f62ec3cafdcc.zip
Move overlap_mode into trait level attribute + feature flag
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs50
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs73
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs12
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs13
8 files changed, 92 insertions, 63 deletions
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 0b65a5ff3ec..bfe2459dc8d 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -161,6 +161,9 @@ declare_features! (
     (active, staged_api, "1.0.0", None, None),
     /// Added for testing E0705; perma-unstable.
     (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+    /// Use for stable + negative coherence and strict coherence depending on trait's
+    /// rustc_strict_coherence value.
+    (active, with_negative_coherence, "1.60.0", None, None),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index fc7f01f041d..25601ffb37d 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -697,7 +697,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
-    rustc_attr!(TEST, rustc_with_negative_coherence, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 087be313b26..36025ea637f 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -4,6 +4,7 @@ use crate::ty::{self, TyCtxt};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::{DefId, DefIdMap};
+use rustc_span::symbol::sym;
 
 /// A per-trait graph of impls in specialization order. At the moment, this
 /// graph forms a tree rooted with the trait itself, with all other nodes
@@ -31,11 +32,23 @@ pub struct Graph {
 
     /// Whether an error was emitted while constructing the graph.
     pub has_errored: bool,
+
+    /// Overlap mode to be used
+    pub overlap_mode: OverlapMode,
 }
 
 impl Graph {
     pub fn new() -> Graph {
-        Graph { parent: Default::default(), children: Default::default(), has_errored: false }
+        Graph {
+            parent: Default::default(),
+            children: Default::default(),
+            has_errored: false,
+            overlap_mode: OverlapMode::Stable,
+        }
+    }
+
+    pub fn set_overlap_mode(&mut self, overlap_mode: OverlapMode) {
+        self.overlap_mode = overlap_mode;
     }
 
     /// The parent of a given impl, which is the `DefId` of the trait when the
@@ -45,6 +58,41 @@ impl Graph {
     }
 }
 
+/// What kind of overlap check are we doing -- this exists just for testing and feature-gating
+/// purposes.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable, Debug, TyEncodable, TyDecodable)]
+pub enum OverlapMode {
+    /// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types)
+    Stable,
+    /// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses.
+    WithNegative,
+    /// Just check for negative impls, not for "where clause not implemented": used for testing.
+    Strict,
+}
+
+impl OverlapMode {
+    pub fn get<'tcx>(tcx: TyCtxt<'tcx>, trait_id: DefId) -> OverlapMode {
+        let with_negative_coherence = tcx.features().with_negative_coherence;
+        let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence);
+
+        if with_negative_coherence {
+            if strict_coherence { OverlapMode::Strict } else { OverlapMode::WithNegative }
+        } else if strict_coherence {
+            bug!("To use strict_coherence you need to set with_negative_coherence feature flag");
+        } else {
+            OverlapMode::Stable
+        }
+    }
+
+    pub fn use_negative_impl(&self) -> bool {
+        *self == OverlapMode::Strict || *self == OverlapMode::WithNegative
+    }
+
+    pub fn use_implicit_negative(&self) -> bool {
+        *self == OverlapMode::Stable || *self == OverlapMode::WithNegative
+    }
+}
+
 /// Children of a given impl, grouped into blanket/non-blanket varieties as is
 /// done in `TraitDef`.
 #[derive(Default, TyEncodable, TyDecodable, Debug, HashStable)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d99bdd3bdd5..ba8ade088ba 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1205,7 +1205,6 @@ symbols! {
         rustc_trivial_field_reads,
         rustc_unsafe_specialization_marker,
         rustc_variance,
-        rustc_with_negative_coherence,
         rustdoc,
         rustdoc_internals,
         rustfmt,
@@ -1489,6 +1488,7 @@ symbols! {
         width,
         windows,
         windows_subsystem,
+        with_negative_coherence,
         wrapping_add,
         wrapping_mul,
         wrapping_sub,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index ab1dc8fcbfe..21775a5c49f 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -13,8 +13,8 @@ use crate::traits::{
     self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
     PredicateObligations, SelectionContext,
 };
-use rustc_ast::Attribute;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
@@ -62,6 +62,7 @@ pub fn overlapping_impls<F1, F2, R>(
     impl1_def_id: DefId,
     impl2_def_id: DefId,
     skip_leak_check: SkipLeakCheck,
+    overlap_mode: OverlapMode,
     on_overlap: F1,
     no_overlap: F2,
 ) -> R
@@ -99,7 +100,7 @@ where
 
     let overlaps = tcx.infer_ctxt().enter(|infcx| {
         let selcx = &mut SelectionContext::intercrate(&infcx);
-        overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some()
+        overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some()
     });
 
     if !overlaps {
@@ -112,7 +113,9 @@ where
     tcx.infer_ctxt().enter(|infcx| {
         let selcx = &mut SelectionContext::intercrate(&infcx);
         selcx.enable_tracking_intercrate_ambiguity_causes();
-        on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap())
+        on_overlap(
+            overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(),
+        )
     })
 }
 
@@ -138,56 +141,6 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
     header
 }
 
-/// What kind of overlap check are we doing -- this exists just for testing and feature-gating
-/// purposes.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-enum OverlapMode {
-    /// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types)
-    Stable,
-    /// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses.
-    WithNegative,
-    /// Just check for negative impls, not for "where clause not implemented": used for testing.
-    Strict,
-}
-
-impl OverlapMode {
-    fn use_negative_impl(&self) -> bool {
-        *self == OverlapMode::Strict || *self == OverlapMode::WithNegative
-    }
-
-    fn use_implicit_negative(&self) -> bool {
-        *self == OverlapMode::Stable || *self == OverlapMode::WithNegative
-    }
-}
-
-fn overlap_mode<'tcx>(tcx: TyCtxt<'tcx>, impl1_def_id: DefId, impl2_def_id: DefId) -> OverlapMode {
-    // Find the possible coherence mode override opt-in attributes for each `DefId`
-    let find_coherence_attr = |attr: &Attribute| {
-        let name = attr.name_or_empty();
-        match name {
-            sym::rustc_with_negative_coherence | sym::rustc_strict_coherence => Some(name),
-            _ => None,
-        }
-    };
-    let impl1_coherence_mode = tcx.get_attrs(impl1_def_id).iter().find_map(find_coherence_attr);
-    let impl2_coherence_mode = tcx.get_attrs(impl2_def_id).iter().find_map(find_coherence_attr);
-
-    // If there are any (that currently happens in tests), they need to match. Otherwise, the
-    // default 1.0 rules are used.
-    match (impl1_coherence_mode, impl2_coherence_mode) {
-        (None, None) => OverlapMode::Stable,
-        (Some(sym::rustc_with_negative_coherence), Some(sym::rustc_with_negative_coherence)) => {
-            OverlapMode::WithNegative
-        }
-        (Some(sym::rustc_strict_coherence), Some(sym::rustc_strict_coherence)) => {
-            OverlapMode::Strict
-        }
-        (Some(mode), _) | (_, Some(mode)) => {
-            bug!("Use the same coherence mode on both impls: {}", mode)
-        }
-    }
-}
-
 /// Can both impl `a` and impl `b` be satisfied by a common type (including
 /// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls.
 fn overlap<'cx, 'tcx>(
@@ -195,11 +148,19 @@ fn overlap<'cx, 'tcx>(
     skip_leak_check: SkipLeakCheck,
     impl1_def_id: DefId,
     impl2_def_id: DefId,
+    overlap_mode: OverlapMode,
 ) -> Option<OverlapResult<'tcx>> {
     debug!("overlap(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
 
     selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
-        overlap_within_probe(selcx, skip_leak_check, impl1_def_id, impl2_def_id, snapshot)
+        overlap_within_probe(
+            selcx,
+            skip_leak_check,
+            impl1_def_id,
+            impl2_def_id,
+            overlap_mode,
+            snapshot,
+        )
     })
 }
 
@@ -208,12 +169,10 @@ fn overlap_within_probe<'cx, 'tcx>(
     skip_leak_check: SkipLeakCheck,
     impl1_def_id: DefId,
     impl2_def_id: DefId,
+    overlap_mode: OverlapMode,
     snapshot: &CombinedSnapshot<'_, 'tcx>,
 ) -> Option<OverlapResult<'tcx>> {
     let infcx = selcx.infcx();
-    let tcx = infcx.tcx;
-
-    let overlap_mode = overlap_mode(tcx, impl1_def_id, impl2_def_id);
 
     if overlap_mode.use_negative_impl() {
         if negative_impl(selcx, impl1_def_id, impl2_def_id)
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 2c5e7e40cc8..15276e69db8 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -257,6 +257,7 @@ pub(super) fn specialization_graph_provider(
     trait_id: DefId,
 ) -> specialization_graph::Graph {
     let mut sg = specialization_graph::Graph::new();
+    sg.set_overlap_mode(specialization_graph::OverlapMode::get(tcx, trait_id));
 
     let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect();
 
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 3ac273fd19b..c1a271b9e5a 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -41,6 +41,7 @@ trait ChildrenExt<'tcx> {
         tcx: TyCtxt<'tcx>,
         impl_def_id: DefId,
         simplified_self: Option<SimplifiedType>,
+        overlap_mode: OverlapMode,
     ) -> Result<Inserted, OverlapError>;
 }
 
@@ -92,6 +93,7 @@ impl ChildrenExt<'_> for Children {
         tcx: TyCtxt<'_>,
         impl_def_id: DefId,
         simplified_self: Option<SimplifiedType>,
+        overlap_mode: OverlapMode,
     ) -> Result<Inserted, OverlapError> {
         let mut last_lint = None;
         let mut replace_children = Vec::new();
@@ -142,6 +144,7 @@ impl ChildrenExt<'_> for Children {
                     possible_sibling,
                     impl_def_id,
                     traits::SkipLeakCheck::default(),
+                    overlap_mode,
                     |_| true,
                     || false,
                 );
@@ -166,6 +169,7 @@ impl ChildrenExt<'_> for Children {
                 possible_sibling,
                 impl_def_id,
                 traits::SkipLeakCheck::Yes,
+                overlap_mode,
                 |overlap| {
                     if let Some(overlap_kind) =
                         tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
@@ -327,8 +331,12 @@ impl GraphExt for Graph {
         loop {
             use self::Inserted::*;
 
-            let insert_result =
-                self.children.entry(parent).or_default().insert(tcx, impl_def_id, simplified)?;
+            let insert_result = self.children.entry(parent).or_default().insert(
+                tcx,
+                impl_def_id,
+                simplified,
+                self.overlap_mode,
+            )?;
 
             match insert_result {
                 BecameNewSibling(opt_lint) => {
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index a409201372b..cf71e0f300c 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -4,6 +4,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_index::vec::IndexVec;
+use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Symbol;
 use rustc_trait_selection::traits::{self, SkipLeakCheck};
@@ -99,7 +100,12 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
         }
     }
 
-    fn check_for_overlapping_inherent_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId) {
+    fn check_for_overlapping_inherent_impls(
+        &self,
+        overlap_mode: OverlapMode,
+        impl1_def_id: DefId,
+        impl2_def_id: DefId,
+    ) {
         traits::overlapping_impls(
             self.tcx,
             impl1_def_id,
@@ -107,6 +113,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
             // We go ahead and just skip the leak check for
             // inherent impls without warning.
             SkipLeakCheck::Yes,
+            overlap_mode,
             |overlap| {
                 self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
                 false
@@ -131,6 +138,8 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentOverlapChecker<'tcx> {
                     return;
                 }
 
+                let overlap_mode = OverlapMode::get(self.tcx, item.def_id.to_def_id());
+
                 let impls_items = impls
                     .iter()
                     .map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id)))
@@ -145,6 +154,7 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentOverlapChecker<'tcx> {
                         for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
                             if self.impls_have_common_items(impl_items1, impl_items2) {
                                 self.check_for_overlapping_inherent_impls(
+                                    overlap_mode,
                                     impl1_def_id,
                                     impl2_def_id,
                                 );
@@ -288,6 +298,7 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentOverlapChecker<'tcx> {
                                 let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx];
                                 if self.impls_have_common_items(impl_items1, impl_items2) {
                                     self.check_for_overlapping_inherent_impls(
+                                        overlap_mode,
                                         impl1_def_id,
                                         impl2_def_id,
                                     );