about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2022-03-15 16:30:30 +0100
committerlcnr <rust@lcnr.de>2022-03-30 11:23:58 +0200
commitbef6f3e895beede5bfd5ba4bb12898615c156d59 (patch)
tree724e0593725707bbff014409e6b495142830315b
parent4558a125b6108f3c080e88d7746e1d422b969bef (diff)
downloadrust-bef6f3e895beede5bfd5ba4bb12898615c156d59.tar.gz
rust-bef6f3e895beede5bfd5ba4bb12898615c156d59.zip
rework implementation for inherent impls for builtin types
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs25
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs28
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs38
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs7
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs13
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs13
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs18
-rw-r--r--compiler/rustc_passes/src/check_attr.rs21
-rw-r--r--compiler/rustc_query_impl/src/keys.rs20
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs96
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs378
-rw-r--r--compiler/rustc_typeck/src/coherence/mod.rs3
-rw-r--r--library/alloc/src/slice.rs13
-rw-r--r--library/alloc/src/str.rs9
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/std/src/f32.rs39
-rw-r--r--library/std/src/f64.rs40
21 files changed, 365 insertions, 414 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index e2f0b413ff3..7c53f839a92 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -636,6 +636,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         template!(Word), ErrorFollowing,
         "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
     ),
+    rustc_attr!(
+        rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing,
+        "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
+    ),
+    rustc_attr!(
+        rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing,
+        "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
+    ),
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
         type_: Normal,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 2e6ce7b7040..de8c0800ac1 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -95,6 +95,11 @@ crate struct CrateMetadata {
     /// FIXME: Used only from queries and can use query cache,
     /// so pre-decoding can probably be avoided.
     trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<SimplifiedType>)]>>,
+    /// Inherent impls which do not follow the normal coherence rules.
+    ///
+    /// These can be introduces using either `#![rustc_coherence_is_core]`
+    /// or `#[rustc_allow_incoherent_impl]`.
+    incoherent_impls: FxHashMap<SimplifiedType, Lazy<[DefIndex]>>,
     /// Proc macro descriptions for this crate, if it's a proc macro crate.
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
@@ -1327,10 +1332,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
     /// Decodes all trait impls in the crate (for rustdoc).
     fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a {
-        self.cdata.trait_impls.iter().flat_map(move |((trait_cnum_raw, trait_index), impls)| {
+        self.cdata.trait_impls.iter().flat_map(move |(&(trait_cnum_raw, trait_index), impls)| {
             let trait_def_id = DefId {
-                krate: self.cnum_map[CrateNum::from_u32(*trait_cnum_raw)],
-                index: *trait_index,
+                krate: self.cnum_map[CrateNum::from_u32(trait_cnum_raw)],
+                index: trait_index,
             };
             impls.decode(self).map(move |(impl_index, simplified_self_ty)| {
                 (trait_def_id, self.local_def_id(impl_index), simplified_self_ty)
@@ -1338,6 +1343,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         })
     }
 
+    fn get_incoherent_impls(self, tcx: TyCtxt<'tcx>, simp: SimplifiedType) -> &'tcx [DefId] {
+        if let Some(impls) = self.cdata.incoherent_impls.get(&simp) {
+            tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx)))
+        } else {
+            &[]
+        }
+    }
+
     fn get_implementations_of_trait(
         self,
         tcx: TyCtxt<'tcx>,
@@ -1754,6 +1767,11 @@ impl CrateMetadata {
             .decode((&blob, sess))
             .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
             .collect();
+        let incoherent_impls = root
+            .incoherent_impls
+            .decode((&blob, sess))
+            .map(|incoherent_impls| (incoherent_impls.self_ty, incoherent_impls.impls))
+            .collect();
         let alloc_decoding_state =
             AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
         let dependencies = Lock::new(cnum_map.iter().cloned().collect());
@@ -1766,6 +1784,7 @@ impl CrateMetadata {
             blob,
             root,
             trait_impls,
+            incoherent_impls,
             raw_proc_macros,
             source_map_import_info: OnceCell::new(),
             def_path_hash_map,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 5ae965ff7fa..7fac668f072 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -81,30 +81,42 @@ macro_rules! provide {
 // small trait to work around different signature queries all being defined via
 // the macro above.
 trait IntoArgs {
-    fn into_args(self) -> (DefId, DefId);
+    type Other;
+    fn into_args(self) -> (DefId, Self::Other);
 }
 
 impl IntoArgs for DefId {
-    fn into_args(self) -> (DefId, DefId) {
-        (self, self)
+    type Other = ();
+    fn into_args(self) -> (DefId, ()) {
+        (self, ())
     }
 }
 
 impl IntoArgs for CrateNum {
-    fn into_args(self) -> (DefId, DefId) {
-        (self.as_def_id(), self.as_def_id())
+    type Other = ();
+    fn into_args(self) -> (DefId, ()) {
+        (self.as_def_id(), ())
     }
 }
 
 impl IntoArgs for (CrateNum, DefId) {
+    type Other = DefId;
     fn into_args(self) -> (DefId, DefId) {
         (self.0.as_def_id(), self.1)
     }
 }
 
 impl<'tcx> IntoArgs for ty::InstanceDef<'tcx> {
-    fn into_args(self) -> (DefId, DefId) {
-        (self.def_id(), self.def_id())
+    type Other = ();
+    fn into_args(self) -> (DefId, ()) {
+        (self.def_id(), ())
+    }
+}
+
+impl IntoArgs for (CrateNum, SimplifiedType) {
+    type Other = SimplifiedType;
+    fn into_args(self) -> (DefId, SimplifiedType) {
+        (self.0.as_def_id(), self.1)
     }
 }
 
@@ -199,6 +211,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
 
     traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
     implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
+    crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) }
 
     dep_kind => {
         let r = *cdata.dep_kind.lock();
@@ -371,7 +384,6 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                 .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
         },
         crates: |tcx, ()| tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).crates_untracked()),
-
         ..*providers
     };
 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 924e5f92103..a219b9eb2be 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -2,8 +2,9 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
 use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
 use crate::rmeta::*;
 
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_data_structures::stable_hasher::StableHasher;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -578,6 +579,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
+        let tcx = self.tcx;
         let mut i = self.position();
 
         // Encode the crate deps
@@ -623,8 +625,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let impls = self.encode_impls();
         let impls_bytes = self.position() - i;
 
-        let tcx = self.tcx;
-
+        i = self.position();
+        let incoherent_impls = self.encode_incoherent_impls();
+        let incoherent_impls_bytes = self.position() - i;
         // Encode MIR.
         i = self.position();
         self.encode_mir();
@@ -734,6 +737,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             source_map,
             traits,
             impls,
+            incoherent_impls,
             exported_symbols,
             interpret_alloc_index,
             tables,
@@ -762,6 +766,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             eprintln!("      source_map bytes: {}", source_map_bytes);
             eprintln!("          traits bytes: {}", traits_bytes);
             eprintln!("           impls bytes: {}", impls_bytes);
+            eprintln!("incoherent_impls bytes: {}", incoherent_impls_bytes);
             eprintln!("    exp. symbols bytes: {}", exported_symbols_bytes);
             eprintln!("  def-path table bytes: {}", def_path_table_bytes);
             eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes);
@@ -1813,6 +1818,33 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy(&all_impls)
     }
 
+    fn encode_incoherent_impls(&mut self) -> Lazy<[IncoherentImpls]> {
+        debug!("EncodeContext::encode_traits_and_impls()");
+        empty_proc_macro!(self);
+        let tcx = self.tcx;
+        let mut ctx = tcx.create_stable_hashing_context();
+        let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect();
+        all_impls.sort_by_cached_key(|&(&simp, _)| {
+            let mut hasher = StableHasher::new();
+            simp.hash_stable(&mut ctx, &mut hasher);
+            hasher.finish::<Fingerprint>();
+        });
+        let all_impls: Vec<_> = all_impls
+            .into_iter()
+            .map(|(&simp, impls)| {
+                let mut impls: Vec<_> =
+                    impls.into_iter().map(|def_id| def_id.local_def_index).collect();
+                impls.sort_by_cached_key(|&local_def_index| {
+                    tcx.hir().def_path_hash(LocalDefId { local_def_index })
+                });
+
+                IncoherentImpls { self_ty: simp, impls: self.lazy(impls) }
+            })
+            .collect();
+
+        self.lazy(&all_impls)
+    }
+
     // Encodes all symbols exported from this crate into the metadata.
     //
     // This pass is seeded off the reachability list calculated in the
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a30cc034c4a..204284ffaa3 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -212,6 +212,7 @@ crate struct CrateRoot<'tcx> {
     foreign_modules: Lazy<[ForeignModule]>,
     traits: Lazy<[DefIndex]>,
     impls: Lazy<[TraitImpls]>,
+    incoherent_impls: Lazy<[IncoherentImpls]>,
     interpret_alloc_index: Lazy<[u32]>,
     proc_macro_data: Option<ProcMacroData>,
 
@@ -251,6 +252,12 @@ crate struct TraitImpls {
     impls: Lazy<[(DefIndex, Option<SimplifiedType>)]>,
 }
 
+#[derive(MetadataEncodable, MetadataDecodable)]
+crate struct IncoherentImpls {
+    self_ty: SimplifiedType,
+    impls: Lazy<[DefIndex]>,
+}
+
 /// Define `LazyTables` and `TableBuilders` at the same time.
 macro_rules! define_tables {
     ($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => {
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index ec20e888333..8afa6e70e41 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -579,6 +579,10 @@ impl<'hir> Map<'hir> {
         self.attrs(CRATE_HIR_ID)
     }
 
+    pub fn rustc_coherence_is_core(self) -> bool {
+        self.krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core))
+    }
+
     pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
         let hir_id = HirId::make_owner(module);
         match self.tcx.hir_owner(module).map(|o| o.node) {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 95260e9e917..6d7e7ef0cb0 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -684,6 +684,10 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    query incoherent_impls(key: SimplifiedType) -> &'tcx [DefId] {
+        desc { |tcx| "collecting all inherent impls for `{:?}`", key }
+    }
+
     /// The result of unsafety-checking this `LocalDefId`.
     query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
         desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
@@ -1469,6 +1473,15 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    /// Collects all incoherent impls for the given crate and type.
+    ///
+    /// Do not call this directly, but instead use the `incoherent_impls` query.
+    /// This query is only used to get the data necessary for that query.
+    query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> &'tcx [DefId] {
+        desc { |tcx| "collecting all impls for a type in a crate" }
+        separate_provide_extern
+    }
+
     query is_dllimport_foreign_item(def_id: DefId) -> bool {
         desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
     }
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 54a345daec8..2009364b24e 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -4,6 +4,7 @@
 use crate::middle::region;
 use crate::mir;
 use crate::ty;
+use crate::ty::fast_reject::SimplifiedType;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::HashingControls;
@@ -55,6 +56,18 @@ where
     }
 }
 
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for SimplifiedType {
+    type KeyType = Fingerprint;
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint {
+        let mut hasher = StableHasher::new();
+        let mut hcx: StableHashingContext<'a> = hcx.clone();
+        self.hash_stable(&mut hcx, &mut hasher);
+        hasher.finish()
+    }
+}
+
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArg<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         self.unpack().hash_stable(hcx, hasher);
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 44c190e459c..dfc405b1195 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -25,6 +25,7 @@ use crate::middle::privacy::AccessLevels;
 use crate::mir::{Body, GeneratorLayout};
 use crate::traits::{self, Reveal};
 use crate::ty;
+use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::util::Discr;
 use rustc_ast as ast;
@@ -2335,6 +2336,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
     super::middle::provide(providers);
     *providers = ty::query::Providers {
         trait_impls_of: trait_def::trait_impls_of_provider,
+        incoherent_impls: trait_def::incoherent_impls_provider,
         type_uninhabited_from: inhabitedness::type_uninhabited_from,
         const_param_default: consts::const_param_default,
         vtable_allocation: vtable::vtable_allocation_provider,
@@ -2350,6 +2352,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
 #[derive(Clone, Debug, Default, HashStable)]
 pub struct CrateInherentImpls {
     pub inherent_impls: LocalDefIdMap<Vec<DefId>>,
+    pub incoherent_impls: FxHashMap<SimplifiedType, Vec<LocalDefId>>,
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 8ebeca50c41..943f610cc0d 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -2,9 +2,11 @@ use crate::traits::specialization_graph;
 use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{Ident, Ty, TyCtxt};
+use hir::def_id::LOCAL_CRATE;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::DefPathHash;
+use std::iter;
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
@@ -257,3 +259,19 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
 
     impls
 }
+
+// Query provider for `incoherent_impls`.
+#[instrument(level = "debug", skip(tcx))]
+pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
+    let mut impls = Vec::new();
+
+    for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) {
+        for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) {
+            impls.push(impl_def_id)
+        }
+    }
+
+    debug!(?impls);
+
+    tcx.arena.alloc_slice(&impls)
+}
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 4f9e1d3fa3b..8aa659fa6ac 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -120,6 +120,9 @@ impl CheckAttrVisitor<'_> {
                 sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
                 sym::must_use => self.check_must_use(hir_id, &attr, span, target),
                 sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
+                sym::rustc_allow_incoherent_impl => {
+                    self.check_allow_incoherent_impl(&attr, span, target)
+                }
                 sym::rustc_const_unstable
                 | sym::rustc_const_stable
                 | sym::unstable
@@ -1080,6 +1083,24 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    /// Warns against some misuses of `#[pass_by_value]`
+    fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+        match target {
+            Target::Method(MethodKind::Inherent) => true,
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(
+                        attr.span,
+                        "`rustc_allow_incoherent_impl` attribute should be applied to impl items.",
+                    )
+                    .span_label(span, "the only currently supported targets are inherent methods")
+                    .emit();
+                false
+            }
+        }
+    }
+
     /// Warns against some misuses of `#[must_use]`
     fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
         let node = self.tcx.hir().get(hir_id);
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 84de31a194d..f1f83a7299c 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -141,6 +141,16 @@ impl Key for ty::WithOptConstParam<LocalDefId> {
     }
 }
 
+impl Key for SimplifiedType {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl Key for (DefId, DefId) {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
@@ -215,6 +225,16 @@ impl Key for (CrateNum, DefId) {
     }
 }
 
+impl Key for (CrateNum, SimplifiedType) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0 == LOCAL_CRATE
+    }
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl Key for (DefId, SimplifiedType) {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 5cf362bfa7e..6dd9b8e44dd 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1160,10 +1160,12 @@ symbols! {
         rustc_allocator,
         rustc_allocator_nounwind,
         rustc_allow_const_fn_unstable,
+        rustc_allow_incoherent_impl,
         rustc_attrs,
         rustc_builtin_macro,
         rustc_capture_analysis,
         rustc_clean,
+        rustc_coherence_is_core,
         rustc_const_stable,
         rustc_const_unstable,
         rustc_conversion_suggestion,
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index ed20e5a4869..5d91b3b46a1 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -18,6 +18,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_middle::middle::stability;
+use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable};
@@ -613,9 +614,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
     fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) {
         debug!("assemble_probe: self_ty={:?}", self_ty);
-        let lang_items = self.tcx.lang_items();
-
-        match *self_ty.value.value.kind() {
+        let raw_self_ty = self_ty.value.value;
+        match *raw_self_ty.kind() {
             ty::Dynamic(data, ..) if let Some(p) = data.principal() => {
                 // Subtle: we can't use `instantiate_query_response` here: using it will
                 // commit to all of the type equalities assumed by inference going through
@@ -650,83 +650,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             ty::Param(p) => {
                 self.assemble_inherent_candidates_from_param(p);
             }
-            ty::Bool => {
-                let lang_def_id = lang_items.bool_impl();
-                self.assemble_inherent_impl_for_primitive(lang_def_id);
-            }
-            ty::Char => {
-                let lang_def_id = lang_items.char_impl();
-                self.assemble_inherent_impl_for_primitive(lang_def_id);
-            }
-            ty::Str => {
-                let lang_def_id = lang_items.str_impl();
-                self.assemble_inherent_impl_for_primitive(lang_def_id);
-
-                let lang_def_id = lang_items.str_alloc_impl();
-                self.assemble_inherent_impl_for_primitive(lang_def_id);
-            }
-            ty::Slice(_) => {
-                for lang_def_id in [
-                    lang_items.slice_impl(),
-                    lang_items.slice_u8_impl(),
-                    lang_items.slice_alloc_impl(),
-                    lang_items.slice_u8_alloc_impl(),
-                ] {
-                    self.assemble_inherent_impl_for_primitive(lang_def_id);
-                }
-            }
-            ty::Array(_, _) => {
-                let lang_def_id = lang_items.array_impl();
-                self.assemble_inherent_impl_for_primitive(lang_def_id);
-            }
-            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl }) => {
-                let (lang_def_id1, lang_def_id2) = match mutbl {
-                    hir::Mutability::Not => {
-                        (lang_items.const_ptr_impl(), lang_items.const_slice_ptr_impl())
-                    }
-                    hir::Mutability::Mut => {
-                        (lang_items.mut_ptr_impl(), lang_items.mut_slice_ptr_impl())
-                    }
-                };
-                self.assemble_inherent_impl_for_primitive(lang_def_id1);
-                self.assemble_inherent_impl_for_primitive(lang_def_id2);
-            }
-            ty::Int(i) => {
-                let lang_def_id = match i {
-                    ty::IntTy::I8 => lang_items.i8_impl(),
-                    ty::IntTy::I16 => lang_items.i16_impl(),
-                    ty::IntTy::I32 => lang_items.i32_impl(),
-                    ty::IntTy::I64 => lang_items.i64_impl(),
-                    ty::IntTy::I128 => lang_items.i128_impl(),
-                    ty::IntTy::Isize => lang_items.isize_impl(),
-                };
-                self.assemble_inherent_impl_for_primitive(lang_def_id);
-            }
-            ty::Uint(i) => {
-                let lang_def_id = match i {
-                    ty::UintTy::U8 => lang_items.u8_impl(),
-                    ty::UintTy::U16 => lang_items.u16_impl(),
-                    ty::UintTy::U32 => lang_items.u32_impl(),
-                    ty::UintTy::U64 => lang_items.u64_impl(),
-                    ty::UintTy::U128 => lang_items.u128_impl(),
-                    ty::UintTy::Usize => lang_items.usize_impl(),
-                };
-                self.assemble_inherent_impl_for_primitive(lang_def_id);
-            }
-            ty::Float(f) => {
-                let (lang_def_id1, lang_def_id2) = match f {
-                    ty::FloatTy::F32 => (lang_items.f32_impl(), lang_items.f32_runtime_impl()),
-                    ty::FloatTy::F64 => (lang_items.f64_impl(), lang_items.f64_runtime_impl()),
-                };
-                self.assemble_inherent_impl_for_primitive(lang_def_id1);
-                self.assemble_inherent_impl_for_primitive(lang_def_id2);
-            }
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Array(..)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(..)
+            | ty::Never
+            | ty::Tuple(..) => self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty),
             _ => {}
         }
     }
 
-    fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option<DefId>) {
-        if let Some(impl_def_id) = lang_def_id {
+    fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
+        let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsPlaceholders) else {
+            bug!("unexpected incoherent type: {:?}", self_ty)
+        };
+        for &impl_def_id in self.tcx.incoherent_impls(simp) {
             self.assemble_inherent_impl_probe(impl_def_id);
         }
     }
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 303ec910a9f..573d072da4b 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -9,10 +9,11 @@
 
 use rustc_errors::{pluralize, struct_span_err};
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::ty::{self, CrateInherentImpls, TyCtxt};
-
+use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
+use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 
 /// On-demand query: yields a map containing all types mapped to their inherent impls.
@@ -22,6 +23,13 @@ pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
     collect.impls_map
 }
 
+pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, (_, simp): (CrateNum, SimplifiedType)) -> &[DefId] {
+    let crate_map = tcx.crate_inherent_impls(());
+    tcx.arena.alloc_from_iter(
+        crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()),
+    )
+}
+
 /// On-demand query: yields a vector of the inherent impls for a specific type.
 pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: DefId) -> &[DefId] {
     let ty_def_id = ty_def_id.expect_local();
@@ -40,12 +48,11 @@ struct InherentCollect<'tcx> {
 
 impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, items: assoc_items, .. }) = item.kind else {
+        let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, ref items, .. }) = item.kind else {
             return;
         };
 
         let self_ty = self.tcx.type_of(item.def_id);
-        let lang_items = self.tcx.lang_items();
         match *self_ty.kind() {
             ty::Adt(def, _) => {
                 self.check_def_id(item, def.did());
@@ -67,274 +74,18 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
                 .note("define and implement a new trait or type instead")
                 .emit();
             }
-            ty::Bool => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.bool_impl(),
-                    None,
-                    "bool",
-                    "bool",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Char => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.char_impl(),
-                    None,
-                    "char",
-                    "char",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Str => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.str_impl(),
-                    lang_items.str_alloc_impl(),
-                    "str",
-                    "str",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.slice_u8_impl(),
-                    lang_items.slice_u8_alloc_impl(),
-                    "slice_u8",
-                    "[u8]",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Slice(_) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.slice_impl(),
-                    lang_items.slice_alloc_impl(),
-                    "slice",
-                    "[T]",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Array(_, _) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.array_impl(),
-                    None,
-                    "array",
-                    "[T; N]",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not })
-                if matches!(inner.kind(), ty::Slice(_)) =>
-            {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.const_slice_ptr_impl(),
-                    None,
-                    "const_slice_ptr",
-                    "*const [T]",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut })
-                if matches!(inner.kind(), ty::Slice(_)) =>
-            {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.mut_slice_ptr_impl(),
-                    None,
-                    "mut_slice_ptr",
-                    "*mut [T]",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.const_ptr_impl(),
-                    None,
-                    "const_ptr",
-                    "*const T",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.mut_ptr_impl(),
-                    None,
-                    "mut_ptr",
-                    "*mut T",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Int(ty::IntTy::I8) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.i8_impl(),
-                    None,
-                    "i8",
-                    "i8",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Int(ty::IntTy::I16) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.i16_impl(),
-                    None,
-                    "i16",
-                    "i16",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Int(ty::IntTy::I32) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.i32_impl(),
-                    None,
-                    "i32",
-                    "i32",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Int(ty::IntTy::I64) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.i64_impl(),
-                    None,
-                    "i64",
-                    "i64",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Int(ty::IntTy::I128) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.i128_impl(),
-                    None,
-                    "i128",
-                    "i128",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Int(ty::IntTy::Isize) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.isize_impl(),
-                    None,
-                    "isize",
-                    "isize",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Uint(ty::UintTy::U8) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.u8_impl(),
-                    None,
-                    "u8",
-                    "u8",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Uint(ty::UintTy::U16) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.u16_impl(),
-                    None,
-                    "u16",
-                    "u16",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Uint(ty::UintTy::U32) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.u32_impl(),
-                    None,
-                    "u32",
-                    "u32",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Uint(ty::UintTy::U64) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.u64_impl(),
-                    None,
-                    "u64",
-                    "u64",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Uint(ty::UintTy::U128) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.u128_impl(),
-                    None,
-                    "u128",
-                    "u128",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Uint(ty::UintTy::Usize) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.usize_impl(),
-                    None,
-                    "usize",
-                    "usize",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Float(ty::FloatTy::F32) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.f32_impl(),
-                    lang_items.f32_runtime_impl(),
-                    "f32",
-                    "f32",
-                    item.span,
-                    assoc_items,
-                );
-            }
-            ty::Float(ty::FloatTy::F64) => {
-                self.check_primitive_impl(
-                    item.def_id,
-                    lang_items.f64_impl(),
-                    lang_items.f64_runtime_impl(),
-                    "f64",
-                    "f64",
-                    item.span,
-                    assoc_items,
-                );
-            }
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Array(..)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(..)
+            | ty::Never
+            | ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
             ty::Error(_) => {}
             _ => {
                 let mut err = struct_span_err!(
@@ -390,60 +141,41 @@ impl<'tcx> InherentCollect<'tcx> {
     }
 
     fn check_primitive_impl(
-        &self,
+        &mut self,
         impl_def_id: LocalDefId,
-        lang_def_id: Option<DefId>,
-        lang_def_id2: Option<DefId>,
-        lang: &str,
-        ty: &str,
+        ty: Ty<'tcx>,
+        items: &[hir::ImplItemRef],
         span: Span,
-        assoc_items: &[hir::ImplItemRef],
     ) {
-        match (lang_def_id, lang_def_id2) {
-            (Some(lang_def_id), _) if lang_def_id == impl_def_id.to_def_id() => {
-                // OK
-            }
-            (_, Some(lang_def_id)) if lang_def_id == impl_def_id.to_def_id() => {
-                // OK
-            }
-            _ => {
-                let to_implement = if assoc_items.is_empty() {
-                    String::new()
-                } else {
-                    let assoc_items_kind = {
-                        let item_types = assoc_items.iter().map(|x| x.kind);
-                        if item_types.clone().all(|x| x == hir::AssocItemKind::Const) {
-                            "constant"
-                        } else if item_types
-                            .clone()
-                            .all(|x| matches! {x, hir::AssocItemKind::Fn{ .. } })
-                        {
-                            "method"
-                        } else {
-                            "associated item"
-                        }
-                    };
-
-                    format!(
-                        " to implement {} {}{}",
-                        pluralize!("this", assoc_items.len()),
-                        assoc_items_kind,
-                        pluralize!(assoc_items.len()),
-                    )
-                };
-
-                struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0390,
-                    "only a single inherent implementation marked with `#[lang = \
-                                  \"{}\"]` is allowed for the `{}` primitive",
-                    lang,
-                    ty
-                )
-                .help(&format!("consider using a trait{}", to_implement))
-                .emit();
+        const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
+        const ADD_ATTR: &str =
+            "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
+        if !self.tcx.hir().rustc_coherence_is_core() {
+            for item in items {
+                if !self.tcx.has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+                {
+                    let mut err = struct_span_err!(
+                        self.tcx.sess,
+                        span,
+                        E0390,
+                        "cannot define inherent `impl` for primitive types",
+                    );
+
+                    if self.tcx.features().rustc_attrs {
+                        err.help(INTO_CORE).span_help(item.span, ADD_ATTR);
+                    } else {
+                        err.help("consider using a trait instead");
+                    }
+                    err.emit();
+                    return;
+                }
             }
         }
+
+        let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsPlaceholders) else {
+            bug!("unexpected primitive type: {:?}", ty);
+        };
+        self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
+        return;
     }
 }
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 055818f55f0..3f1b4828d1a 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -144,13 +144,14 @@ fn enforce_empty_impls_for_marker_traits(
 
 pub fn provide(providers: &mut Providers) {
     use self::builtin::coerce_unsized_info;
-    use self::inherent_impls::{crate_inherent_impls, inherent_impls};
+    use self::inherent_impls::{crate_incoherent_impls, crate_inherent_impls, inherent_impls};
     use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
     use self::orphan::orphan_check_crate;
 
     *providers = Providers {
         coherent_trait,
         crate_inherent_impls,
+        crate_incoherent_impls,
         inherent_impls,
         crate_inherent_impls_overlap_check,
         coerce_unsized_info,
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index f52871c73d9..111c57e884b 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -267,6 +267,7 @@ impl<T> [T] {
     /// assert!(v == [-5, -3, 1, 2, 4]);
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sort(&mut self)
@@ -322,6 +323,7 @@ impl<T> [T] {
     /// assert!(v == [5, 4, 3, 2, 1]);
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sort_by<F>(&mut self, mut compare: F)
@@ -363,6 +365,7 @@ impl<T> [T] {
     /// assert!(v == [1, 2, -3, 4, -5]);
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "slice_sort_by_key", since = "1.7.0")]
     #[inline]
     pub fn sort_by_key<K, F>(&mut self, mut f: F)
@@ -409,6 +412,7 @@ impl<T> [T] {
     ///
     /// [pdqsort]: https://github.com/orlp/pdqsort
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "slice_sort_by_cached_key", since = "1.34.0")]
     #[inline]
     pub fn sort_by_cached_key<K, F>(&mut self, f: F)
@@ -467,6 +471,7 @@ impl<T> [T] {
     /// // Here, `s` and `x` can be modified independently.
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[rustc_conversion_suggestion]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -491,6 +496,7 @@ impl<T> [T] {
     /// // Here, `s` and `x` can be modified independently.
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
@@ -515,6 +521,7 @@ impl<T> [T] {
     ///
     /// assert_eq!(x, vec![10, 40, 30]);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
@@ -542,6 +549,7 @@ impl<T> [T] {
     /// // this will panic at runtime
     /// b"0123456789abcdef".repeat(usize::MAX);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "repeat_generic_slice", since = "1.40.0")]
     pub fn repeat(&self, n: usize) -> Vec<T>
@@ -610,6 +618,7 @@ impl<T> [T] {
     /// assert_eq!(["hello", "world"].concat(), "helloworld");
     /// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn concat<Item: ?Sized>(&self) -> <Self as Concat<Item>>::Output
     where
@@ -628,6 +637,7 @@ impl<T> [T] {
     /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
     /// assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "rename_connect_to_join", since = "1.3.0")]
     pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
     where
@@ -646,6 +656,7 @@ impl<T> [T] {
     /// assert_eq!(["hello", "world"].connect(" "), "hello world");
     /// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")]
     pub fn connect<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
@@ -669,6 +680,7 @@ impl [u8] {
     ///
     /// [`make_ascii_uppercase`]: slice::make_ascii_uppercase
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "this returns the uppercase bytes as a new Vec, \
                   without modifying the original"]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
@@ -689,6 +701,7 @@ impl [u8] {
     ///
     /// [`make_ascii_lowercase`]: slice::make_ascii_lowercase
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "this returns the lowercase bytes as a new Vec, \
                   without modifying the original"]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 69495f31c32..bf70363258c 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -250,6 +250,7 @@ impl str {
     /// let boxed_bytes = boxed_str.into_boxed_bytes();
     /// assert_eq!(*boxed_bytes, *s.as_bytes());
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "str_box_extras", since = "1.20.0")]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
@@ -280,6 +281,7 @@ impl str {
     /// assert_eq!(s, s.replace("cookie monster", "little lamb"));
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "this returns the replaced string as a new allocation, \
                   without modifying the original"]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -320,6 +322,7 @@ impl str {
     /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10));
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "this returns the replaced string as a new allocation, \
                   without modifying the original"]
     #[stable(feature = "str_replacen", since = "1.16.0")]
@@ -376,6 +379,7 @@ impl str {
     /// assert_eq!(new_year, new_year.to_lowercase());
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "this returns the lowercase string as a new String, \
                   without modifying the original"]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
@@ -458,6 +462,7 @@ impl str {
     /// assert_eq!("TSCHÜSS", s.to_uppercase());
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "this returns the uppercase string as a new String, \
                   without modifying the original"]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
@@ -493,6 +498,7 @@ impl str {
     /// assert_eq!(boxed_str.into_string(), string);
     /// ```
     #[stable(feature = "box_str", since = "1.4.0")]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
     pub fn into_string(self: Box<str>) -> String {
@@ -521,6 +527,7 @@ impl str {
     /// let huge = "0123456789abcdef".repeat(usize::MAX);
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use]
     #[stable(feature = "repeat_str", since = "1.16.0")]
     pub fn repeat(&self, n: usize) -> String {
@@ -549,6 +556,7 @@ impl str {
     /// [`make_ascii_uppercase`]: str::make_ascii_uppercase
     /// [`to_uppercase`]: #method.to_uppercase
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase()`"]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
@@ -581,6 +589,7 @@ impl str {
     /// [`make_ascii_lowercase`]: str::make_ascii_lowercase
     /// [`to_lowercase`]: #method.to_lowercase
     #[cfg(not(no_global_oom_handling))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase()`"]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 5c16346cbd1..445a7ba6e2d 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -84,6 +84,7 @@
     target_has_atomic_load_store = "ptr",
 ))]
 #![no_core]
+#![cfg_attr(not(bootstrap), rustc_coherence_is_core)]
 //
 // Lints:
 #![deny(rust_2021_incompatible_or_patterns)]
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index d23f5244d88..1faf57e13db 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -43,6 +43,7 @@ impl f32 {
     /// assert_eq!(g.floor(), 3.0);
     /// assert_eq!(h.floor(), -4.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -61,6 +62,7 @@ impl f32 {
     /// assert_eq!(f.ceil(), 4.0);
     /// assert_eq!(g.ceil(), 4.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -80,6 +82,7 @@ impl f32 {
     /// assert_eq!(f.round(), 3.0);
     /// assert_eq!(g.round(), -3.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -100,6 +103,7 @@ impl f32 {
     /// assert_eq!(g.trunc(), 3.0);
     /// assert_eq!(h.trunc(), -3.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -120,6 +124,7 @@ impl f32 {
     /// assert!(abs_difference_x <= f32::EPSILON);
     /// assert!(abs_difference_y <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -144,6 +149,7 @@ impl f32 {
     ///
     /// assert!(f32::NAN.abs().is_nan());
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -167,6 +173,7 @@ impl f32 {
     ///
     /// assert!(f32::NAN.signum().is_nan());
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -193,6 +200,7 @@ impl f32 {
     ///
     /// assert!(f32::NAN.copysign(1.0).is_nan());
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[inline]
     #[stable(feature = "copysign", since = "1.35.0")]
@@ -220,6 +228,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -244,6 +253,7 @@ impl f32 {
     /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
     /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[inline]
     #[stable(feature = "euclidean_division", since = "1.38.0")]
@@ -278,6 +288,7 @@ impl f32 {
     /// // limitation due to round-off error
     /// assert!((-f32::EPSILON).rem_euclid(3.0) != 0.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[inline]
     #[stable(feature = "euclidean_division", since = "1.38.0")]
@@ -298,6 +309,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -315,6 +327,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -339,6 +352,7 @@ impl f32 {
     /// assert!(negative.sqrt().is_nan());
     /// assert!(negative_zero.sqrt() == negative_zero);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -360,6 +374,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -379,6 +394,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -400,6 +416,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -423,6 +440,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -442,6 +460,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -464,6 +483,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -488,6 +508,7 @@ impl f32 {
     /// assert!(abs_difference_x <= f32::EPSILON);
     /// assert!(abs_difference_y <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -517,6 +538,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -538,6 +560,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -556,6 +579,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -574,6 +598,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -591,6 +616,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -612,6 +638,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -633,6 +660,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -653,6 +681,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -686,6 +715,7 @@ impl f32 {
     /// assert!(abs_difference_1 <= f32::EPSILON);
     /// assert!(abs_difference_2 <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -708,6 +738,7 @@ impl f32 {
     /// assert!(abs_difference_0 <= f32::EPSILON);
     /// assert!(abs_difference_1 <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sin_cos(self) -> (f32, f32) {
@@ -728,6 +759,7 @@ impl f32 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -749,6 +781,7 @@ impl f32 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -771,6 +804,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -793,6 +827,7 @@ impl f32 {
     /// // Same result
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -815,6 +850,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -834,6 +870,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -853,6 +890,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -872,6 +910,7 @@ impl f32 {
     ///
     /// assert!(abs_difference <= 1e-5);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 55e17b47190..22d58ab84cf 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -43,6 +43,7 @@ impl f64 {
     /// assert_eq!(g.floor(), 3.0);
     /// assert_eq!(h.floor(), -4.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -61,6 +62,7 @@ impl f64 {
     /// assert_eq!(f.ceil(), 4.0);
     /// assert_eq!(g.ceil(), 4.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -80,6 +82,7 @@ impl f64 {
     /// assert_eq!(f.round(), 3.0);
     /// assert_eq!(g.round(), -3.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -100,6 +103,7 @@ impl f64 {
     /// assert_eq!(g.trunc(), 3.0);
     /// assert_eq!(h.trunc(), -3.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -120,6 +124,7 @@ impl f64 {
     /// assert!(abs_difference_x < 1e-10);
     /// assert!(abs_difference_y < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -144,6 +149,7 @@ impl f64 {
     ///
     /// assert!(f64::NAN.abs().is_nan());
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -167,6 +173,7 @@ impl f64 {
     ///
     /// assert!(f64::NAN.signum().is_nan());
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -193,6 +200,7 @@ impl f64 {
     ///
     /// assert!(f64::NAN.copysign(1.0).is_nan());
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "copysign", since = "1.35.0")]
     #[inline]
@@ -220,6 +228,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -244,6 +253,7 @@ impl f64 {
     /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
     /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[inline]
     #[stable(feature = "euclidean_division", since = "1.38.0")]
@@ -278,6 +288,7 @@ impl f64 {
     /// // limitation due to round-off error
     /// assert!((-f64::EPSILON).rem_euclid(3.0) != 0.0);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[inline]
     #[stable(feature = "euclidean_division", since = "1.38.0")]
@@ -298,6 +309,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -315,6 +327,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -339,6 +352,7 @@ impl f64 {
     /// assert!(negative.sqrt().is_nan());
     /// assert!(negative_zero.sqrt() == negative_zero);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -360,6 +374,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -379,6 +394,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -400,6 +416,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -423,6 +440,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -442,6 +460,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -466,6 +485,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -490,6 +510,7 @@ impl f64 {
     /// assert!(abs_difference_x < 1e-10);
     /// assert!(abs_difference_y < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -519,6 +540,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -540,6 +562,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -558,6 +581,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -576,6 +600,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -593,6 +618,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-14);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -614,6 +640,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -635,6 +662,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -655,6 +683,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -688,6 +717,7 @@ impl f64 {
     /// assert!(abs_difference_1 < 1e-10);
     /// assert!(abs_difference_2 < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -710,6 +740,7 @@ impl f64 {
     /// assert!(abs_difference_0 < 1e-10);
     /// assert!(abs_difference_1 < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sin_cos(self) -> (f64, f64) {
@@ -730,6 +761,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-20);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -751,6 +783,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-20);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -773,6 +806,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -795,6 +829,7 @@ impl f64 {
     /// // Same result
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -817,6 +852,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -836,6 +872,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -855,6 +892,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -874,6 +912,7 @@ impl f64 {
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -884,6 +923,7 @@ impl f64 {
     // Solaris/Illumos requires a wrapper around log, log2, and log10 functions
     // because of their non-standard behavior (e.g., log(-n) returns -Inf instead
     // of expected NaN).
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
     fn log_wrapper<F: Fn(f64) -> f64>(self, log_fn: F) -> f64 {
         if !cfg!(any(target_os = "solaris", target_os = "illumos")) {
             log_fn(self)