rework implementation for inherent impls for builtin types

This commit is contained in:
lcnr 2022-03-15 16:30:30 +01:00
parent 4558a125b6
commit bef6f3e895
21 changed files with 364 additions and 413 deletions

View file

@ -636,6 +636,14 @@ pub struct 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,

View file

@ -95,6 +95,11 @@ fn deref(&self) -> &[u8] {
/// 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 @@ fn get_traits(self) -> impl Iterator<Item = DefId> + '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 @@ fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<Simplifie
})
}
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,

View file

@ -81,30 +81,42 @@ pub fn provide_extern(providers: &mut ExternProviders) {
// 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 @@ fn into_args(self) -> (DefId, DefId) {
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
};
}

View file

@ -2,8 +2,9 @@
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 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
}
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 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'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 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
source_map,
traits,
impls,
incoherent_impls,
exported_symbols,
interpret_alloc_index,
tables,
@ -762,6 +766,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'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 @@ fn encode_impls(&mut self) -> Lazy<[TraitImpls]> {
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

View file

@ -212,6 +212,7 @@ macro_rules! Lazy {
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 @@ macro_rules! Lazy {
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>),+ $(,)?) => {

View file

@ -579,6 +579,10 @@ pub fn krate_attrs(self) -> &'hir [ast::Attribute] {
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) {

View file

@ -684,6 +684,10 @@
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 @@
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) }
}

View file

@ -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 @@ fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint {
}
}
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);

View file

@ -25,6 +25,7 @@
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)]

View file

@ -2,9 +2,11 @@
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)
}

View file

@ -120,6 +120,9 @@ fn check_attributes(
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 @@ fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) -> b
}
}
/// 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);

View file

@ -141,6 +141,16 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
}
}
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 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
}
}
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 {

View file

@ -1160,10 +1160,12 @@
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,

View file

@ -18,6 +18,7 @@
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 @@ fn assemble_inherent_candidates(&mut self) {
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 @@ fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'t
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);
}
}

View file

@ -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 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
.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 @@ fn check_def_id(&mut self, item: &hir::Item<'_>, def_id: DefId) {
}
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"
}
};
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",
);
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();
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;
}
}

View file

@ -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,

View file

@ -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 @@ pub fn sort(&mut self)
/// 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 @@ pub fn sort_by<F>(&mut self, mut compare: F)
/// 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 @@ pub fn sort_by_key<K, F>(&mut self, mut f: F)
///
/// [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 @@ macro_rules! sort_by_key {
/// // 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 @@ pub fn to_vec(&self) -> Vec<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 @@ pub fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
///
/// 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 @@ pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
/// // 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 @@ pub fn repeat(&self, n: usize) -> Vec<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 @@ pub fn concat<Item: ?Sized>(&self) -> <Self as Concat<Item>>::Output
/// 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 @@ pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Outp
/// 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 @@ pub fn to_ascii_uppercase(&self) -> Vec<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")]

View file

@ -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 @@ pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
/// 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 @@ pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
/// 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 @@ pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) ->
/// 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 @@ fn case_ignoreable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
/// 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 @@ pub fn to_uppercase(&self) -> String {
/// 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 @@ pub fn into_string(self: Box<str>) -> String {
/// 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 @@ pub fn repeat(&self, n: usize) -> String {
/// [`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 @@ pub fn to_ascii_uppercase(&self) -> String {
/// [`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]

View file

@ -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)]

View file

@ -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 @@ pub fn floor(self) -> 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 @@ pub fn ceil(self) -> 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 @@ pub fn round(self) -> 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 @@ pub fn trunc(self) -> 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 @@ pub fn fract(self) -> 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 @@ pub fn abs(self) -> 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 @@ pub fn signum(self) -> 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 @@ pub fn copysign(self, sign: f32) -> 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 @@ pub fn mul_add(self, a: f32, b: f32) -> 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 @@ pub fn div_euclid(self, rhs: f32) -> 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 @@ pub fn rem_euclid(self, rhs: f32) -> 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 @@ pub fn powi(self, n: i32) -> 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 @@ pub fn powf(self, n: f32) -> 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 @@ pub fn sqrt(self) -> 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 @@ pub fn exp(self) -> 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 @@ pub fn exp2(self) -> 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 @@ pub fn ln(self) -> 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 @@ pub fn log(self, base: f32) -> 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 @@ pub fn log2(self) -> 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 @@ pub fn log10(self) -> 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 @@ pub fn abs_sub(self, other: f32) -> 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 @@ pub fn cbrt(self) -> 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 @@ pub fn hypot(self, other: f32) -> 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 @@ pub fn sin(self) -> 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 @@ pub fn cos(self) -> 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 @@ pub fn tan(self) -> 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 @@ pub fn asin(self) -> 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 @@ pub fn acos(self) -> 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 @@ pub fn atan(self) -> 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 @@ pub fn atan2(self, other: f32) -> 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 @@ pub fn sin_cos(self) -> (f32, 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 @@ pub fn exp_m1(self) -> 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 @@ pub fn ln_1p(self) -> 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 @@ pub fn sinh(self) -> 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 @@ pub fn cosh(self) -> 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 @@ pub fn tanh(self) -> 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 @@ pub fn asinh(self) -> 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 @@ pub fn acosh(self) -> 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]

View file

@ -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 @@ pub fn floor(self) -> 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 @@ pub fn ceil(self) -> 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 @@ pub fn round(self) -> 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 @@ pub fn trunc(self) -> 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 @@ pub fn fract(self) -> 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 @@ pub fn abs(self) -> 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 @@ pub fn signum(self) -> 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 @@ pub fn copysign(self, sign: f64) -> 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 @@ pub fn mul_add(self, a: f64, b: f64) -> 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 @@ pub fn div_euclid(self, rhs: f64) -> 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 @@ pub fn rem_euclid(self, rhs: f64) -> 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 @@ pub fn powi(self, n: i32) -> 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 @@ pub fn powf(self, n: f64) -> 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 @@ pub fn sqrt(self) -> 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 @@ pub fn exp(self) -> 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 @@ pub fn exp2(self) -> 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 @@ pub fn ln(self) -> 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 @@ pub fn log(self, base: f64) -> 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 @@ pub fn log2(self) -> 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 @@ pub fn log10(self) -> 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 @@ pub fn abs_sub(self, other: f64) -> 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 @@ pub fn cbrt(self) -> 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 @@ pub fn hypot(self, other: f64) -> 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 @@ pub fn sin(self) -> 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 @@ pub fn cos(self) -> 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 @@ pub fn tan(self) -> 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 @@ pub fn asin(self) -> 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 @@ pub fn acos(self) -> 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 @@ pub fn atan(self) -> 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 @@ pub fn atan2(self, other: f64) -> 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 @@ pub fn sin_cos(self) -> (f64, 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 @@ pub fn exp_m1(self) -> 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 @@ pub fn ln_1p(self) -> 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 @@ pub fn sinh(self) -> 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 @@ pub fn cosh(self) -> 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 @@ pub fn tanh(self) -> 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 @@ pub fn asinh(self) -> 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 @@ pub fn acosh(self) -> 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 @@ pub fn atanh(self) -> 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)